diff options
264 files changed, 12285 insertions, 8559 deletions
@@ -9,4 +9,5 @@ gen/ /tests/local.properties /tests/private.properties /cgeo-calendar/local.properties -/cgeo-calendar/private.properties
\ No newline at end of file +/cgeo-calendar/private.properties +.directory
\ No newline at end of file diff --git a/cgeo-calendar/.settings/org.eclipse.jdt.core.prefs b/cgeo-calendar/.settings/org.eclipse.jdt.core.prefs index 31c9aa4..78a085f 100644 --- a/cgeo-calendar/.settings/org.eclipse.jdt.core.prefs +++ b/cgeo-calendar/.settings/org.eclipse.jdt.core.prefs @@ -1,354 +1,353 @@ -#Fri Nov 18 10:12:43 CET 2011
-eclipse.preferences.version=1
-org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
-org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=1.6
-org.eclipse.jdt.core.compiler.debug.lineNumber=generate
-org.eclipse.jdt.core.compiler.debug.localVariable=generate
-org.eclipse.jdt.core.compiler.debug.sourceFile=generate
-org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
-org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
-org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
-org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
-org.eclipse.jdt.core.compiler.problem.deadCode=warning
-org.eclipse.jdt.core.compiler.problem.deprecation=warning
-org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
-org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
-org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
-org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
-org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
-org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
-org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
-org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
-org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
-org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
-org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
-org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled
-org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
-org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning
-org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning
-org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
-org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
-org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning
-org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=warning
-org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning
-org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=disabled
-org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
-org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=warning
-org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
-org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
-org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
-org.eclipse.jdt.core.compiler.problem.nullReference=warning
-org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
-org.eclipse.jdt.core.compiler.problem.parameterAssignment=warning
-org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning
-org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning
-org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
-org.eclipse.jdt.core.compiler.problem.redundantNullCheck=warning
-org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=warning
-org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=warning
-org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=warning
-org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=warning
-org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
-org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
-org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
-org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
-org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
-org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
-org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled
-org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
-org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
-org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
-org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
-org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning
-org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
-org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning
-org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
-org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
-org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
-org.eclipse.jdt.core.compiler.problem.unusedImport=warning
-org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
-org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
-org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=warning
-org.eclipse.jdt.core.compiler.problem.unusedParameter=warning
-org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
-org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
-org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
-org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
-org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
-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=0
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=0
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=0
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=0
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=0
-org.eclipse.jdt.core.formatter.alignment_for_assignment=0
-org.eclipse.jdt.core.formatter.alignment_for_binary_expression=0
-org.eclipse.jdt.core.formatter.alignment_for_compact_if=0
-org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=0
-org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
-org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=0
-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=0
-org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=0
-org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=0
-org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=0
-org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=0
-org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=0
-org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=0
-org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=0
-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
-org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
-org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
-org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
-org.eclipse.jdt.core.formatter.blank_lines_before_method=1
-org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
-org.eclipse.jdt.core.formatter.blank_lines_before_package=0
-org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
-org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
-org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
-org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
-org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
-org.eclipse.jdt.core.formatter.comment.format_block_comments=true
-org.eclipse.jdt.core.formatter.comment.format_header=true
-org.eclipse.jdt.core.formatter.comment.format_html=true
-org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
-org.eclipse.jdt.core.formatter.comment.format_line_comments=false
-org.eclipse.jdt.core.formatter.comment.format_source_code=true
-org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
-org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
-org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
-org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert
-org.eclipse.jdt.core.formatter.comment.line_length=120
-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
-org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
-org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
-org.eclipse.jdt.core.formatter.indent_empty_lines=false
-org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
-org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
-org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
-org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true
-org.eclipse.jdt.core.formatter.indentation.size=4
-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=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
-org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
-org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
-org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
-org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
-org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
-org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
-org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
-org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
-org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
-org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
-org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
-org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
-org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
-org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
-org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
-org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
-org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
-org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
-org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
-org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
-org.eclipse.jdt.core.formatter.join_lines_in_comments=false
-org.eclipse.jdt.core.formatter.join_wrapped_lines=false
-org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
-org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
-org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
-org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
-org.eclipse.jdt.core.formatter.lineSplit=120
-org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
-org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
-org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
-org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
-org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
-org.eclipse.jdt.core.formatter.tabulation.char=space
-org.eclipse.jdt.core.formatter.tabulation.size=4
-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_outer_expressions_when_nested=true
+eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.autoboxing=ignore +org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning +org.eclipse.jdt.core.compiler.problem.deadCode=warning +org.eclipse.jdt.core.compiler.problem.deprecation=warning +org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled +org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled +org.eclipse.jdt.core.compiler.problem.discouragedReference=warning +org.eclipse.jdt.core.compiler.problem.emptyStatement=warning +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning +org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled +org.eclipse.jdt.core.compiler.problem.fieldHiding=warning +org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning +org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning +org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled +org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning +org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning +org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning +org.eclipse.jdt.core.compiler.problem.localVariableHiding=warning +org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning +org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=warning +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=disabled +org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning +org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=warning +org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning +org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning +org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore +org.eclipse.jdt.core.compiler.problem.nullReference=warning +org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning +org.eclipse.jdt.core.compiler.problem.parameterAssignment=warning +org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning +org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning +org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning +org.eclipse.jdt.core.compiler.problem.redundantNullCheck=warning +org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=warning +org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=warning +org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=warning +org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=warning +org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled +org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning +org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled +org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled +org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore +org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning +org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled +org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning +org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore +org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning +org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled +org.eclipse.jdt.core.compiler.problem.unusedImport=warning +org.eclipse.jdt.core.compiler.problem.unusedLabel=warning +org.eclipse.jdt.core.compiler.problem.unusedLocal=warning +org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=warning +org.eclipse.jdt.core.compiler.problem.unusedParameter=warning +org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled +org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning +org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning +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=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=0 +org.eclipse.jdt.core.formatter.alignment_for_assignment=0 +org.eclipse.jdt.core.formatter.alignment_for_binary_expression=0 +org.eclipse.jdt.core.formatter.alignment_for_compact_if=0 +org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=0 +org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0 +org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=0 +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=0 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=0 +org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=0 +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 +org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0 +org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1 +org.eclipse.jdt.core.formatter.blank_lines_before_method=1 +org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 +org.eclipse.jdt.core.formatter.blank_lines_before_package=0 +org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1 +org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 +org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false +org.eclipse.jdt.core.formatter.comment.format_block_comments=true +org.eclipse.jdt.core.formatter.comment.format_header=true +org.eclipse.jdt.core.formatter.comment.format_html=true +org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true +org.eclipse.jdt.core.formatter.comment.format_line_comments=false +org.eclipse.jdt.core.formatter.comment.format_source_code=true +org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true +org.eclipse.jdt.core.formatter.comment.indent_root_tags=true +org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert +org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert +org.eclipse.jdt.core.formatter.comment.line_length=120 +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 +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true +org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_empty_lines=false +org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true +org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true +org.eclipse.jdt.core.formatter.indentation.size=4 +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=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert +org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.join_lines_in_comments=false +org.eclipse.jdt.core.formatter.join_wrapped_lines=false +org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false +org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false +org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false +org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false +org.eclipse.jdt.core.formatter.lineSplit=120 +org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false +org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false +org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 +org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1 +org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true +org.eclipse.jdt.core.formatter.tabulation.char=space +org.eclipse.jdt.core.formatter.tabulation.size=4 +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_outer_expressions_when_nested=true diff --git a/cgeo-calendar/src/cgeo/calendar/CalendarActivity.java b/cgeo-calendar/src/cgeo/calendar/CalendarActivity.java index 226b486..15b5872 100644 --- a/cgeo-calendar/src/cgeo/calendar/CalendarActivity.java +++ b/cgeo-calendar/src/cgeo/calendar/CalendarActivity.java @@ -12,14 +12,13 @@ import android.text.Html; import android.text.Spanned; import android.text.style.ImageSpan; import android.util.Log; +import android.util.SparseArray; import android.view.Gravity; import android.widget.Toast; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.util.Date; -import java.util.HashMap; -import java.util.Map; public final class CalendarActivity extends Activity { private static final String LOG_TAG = "cgeo.calendar"; @@ -62,7 +61,6 @@ public final class CalendarActivity extends Activity { } catch (Exception e) { Log.e(LOG_TAG, e.getMessage(), e); finish(); - return; } } @@ -93,7 +91,7 @@ public final class CalendarActivity extends Activity { return; } - final Map<Integer, String> calendars = new HashMap<Integer, String>(); + final SparseArray<String> calendars = new SparseArray<String>(); cursor.moveToFirst(); final int indexId = cursor.getColumnIndex("_id"); @@ -115,20 +113,22 @@ public final class CalendarActivity extends Activity { } } while (cursor.moveToNext()); - if (calendars.isEmpty()) { + if (calendars.size() == 0) { showToast(getResources().getString(R.string.event_fail)); finish(); return; } - final CharSequence[] items = calendars.values().toArray(new CharSequence[calendars.size()]); + final String[] items = new String[calendars.size()]; + for (int i = 0; i < calendars.size(); i++) { + items[i] = calendars.valueAt(i); + } final AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(R.string.calendars); builder.setItems(items, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int item) { - final Integer[] keys = calendars.keySet().toArray(new Integer[calendars.size()]); - final Integer calendarId = keys[item]; + final int calendarId = calendars.keyAt(item); addToCalendar(calendarId); finish(); } @@ -209,13 +209,13 @@ public final class CalendarActivity extends Activity { * @param calendarId * The selected calendar */ - private void addToCalendar(Integer calendarId) { + private void addToCalendar(int calendarId) { try { final Uri calendarProvider = Compatibility.getCalendarEventsProviderURI(); final Date eventDate = parseDate(); final String description = parseDescription(); - final String location = parseLocation(); + final String eventLocation = parseLocation(); // values final ContentValues event = new ContentValues(); @@ -226,8 +226,8 @@ public final class CalendarActivity extends Activity { event.put("title", Html.fromHtml(name).toString()); event.put("description", description); - if (location.length() > 0) { - event.put("eventLocation", location); + if (eventLocation.length() > 0) { + event.put("eventLocation", eventLocation); } event.put("allDay", 1); event.put("hasAlarm", 0); @@ -251,7 +251,7 @@ public final class CalendarActivity extends Activity { try { final Date eventDate = parseDate(); final String description = parseDescription(); - final String location = parseLocation(); + final String eventLocation = parseLocation(); /* * TODO These strings are available as constants starting with API 14 and can be used when @@ -266,7 +266,7 @@ public final class CalendarActivity extends Activity { .putExtra("description", description) .putExtra("hasAlarm", false) .putExtra("eventTimezone", "UTC") - .putExtra("eventLocation", location); + .putExtra("eventLocation", eventLocation); startActivity(intent); } catch (Exception e) { showToast(getResources().getString(R.string.event_fail)); diff --git a/main/.settings/org.eclipse.jdt.core.prefs b/main/.settings/org.eclipse.jdt.core.prefs index 31c9aa4..169f171 100644 --- a/main/.settings/org.eclipse.jdt.core.prefs +++ b/main/.settings/org.eclipse.jdt.core.prefs @@ -1,354 +1,353 @@ -#Fri Nov 18 10:12:43 CET 2011
-eclipse.preferences.version=1
-org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
-org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=1.6
-org.eclipse.jdt.core.compiler.debug.lineNumber=generate
-org.eclipse.jdt.core.compiler.debug.localVariable=generate
-org.eclipse.jdt.core.compiler.debug.sourceFile=generate
-org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
-org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
-org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
-org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
-org.eclipse.jdt.core.compiler.problem.deadCode=warning
-org.eclipse.jdt.core.compiler.problem.deprecation=warning
-org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
-org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
-org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
-org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
-org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
-org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
-org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
-org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
-org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
-org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
-org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
-org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled
-org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
-org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning
-org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning
-org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
-org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
-org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning
-org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=warning
-org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning
-org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=disabled
-org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
-org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=warning
-org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
-org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
-org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
-org.eclipse.jdt.core.compiler.problem.nullReference=warning
-org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
-org.eclipse.jdt.core.compiler.problem.parameterAssignment=warning
-org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning
-org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning
-org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
-org.eclipse.jdt.core.compiler.problem.redundantNullCheck=warning
-org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=warning
-org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=warning
-org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=warning
-org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=warning
-org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
-org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
-org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
-org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
-org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
-org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
-org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled
-org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
-org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
-org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
-org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
-org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning
-org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
-org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning
-org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
-org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
-org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
-org.eclipse.jdt.core.compiler.problem.unusedImport=warning
-org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
-org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
-org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=warning
-org.eclipse.jdt.core.compiler.problem.unusedParameter=warning
-org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
-org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
-org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
-org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
-org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
-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=0
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=0
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=0
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=0
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=0
-org.eclipse.jdt.core.formatter.alignment_for_assignment=0
-org.eclipse.jdt.core.formatter.alignment_for_binary_expression=0
-org.eclipse.jdt.core.formatter.alignment_for_compact_if=0
-org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=0
-org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
-org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=0
-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=0
-org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=0
-org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=0
-org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=0
-org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=0
-org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=0
-org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=0
-org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=0
-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
-org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
-org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
-org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
-org.eclipse.jdt.core.formatter.blank_lines_before_method=1
-org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
-org.eclipse.jdt.core.formatter.blank_lines_before_package=0
-org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
-org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
-org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
-org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
-org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
-org.eclipse.jdt.core.formatter.comment.format_block_comments=true
-org.eclipse.jdt.core.formatter.comment.format_header=true
-org.eclipse.jdt.core.formatter.comment.format_html=true
-org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
-org.eclipse.jdt.core.formatter.comment.format_line_comments=false
-org.eclipse.jdt.core.formatter.comment.format_source_code=true
-org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
-org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
-org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
-org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert
-org.eclipse.jdt.core.formatter.comment.line_length=120
-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
-org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
-org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
-org.eclipse.jdt.core.formatter.indent_empty_lines=false
-org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
-org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
-org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
-org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true
-org.eclipse.jdt.core.formatter.indentation.size=4
-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=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
-org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
-org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
-org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
-org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
-org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
-org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
-org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
-org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
-org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
-org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
-org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
-org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
-org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
-org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
-org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
-org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
-org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
-org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
-org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
-org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
-org.eclipse.jdt.core.formatter.join_lines_in_comments=false
-org.eclipse.jdt.core.formatter.join_wrapped_lines=false
-org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
-org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
-org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
-org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
-org.eclipse.jdt.core.formatter.lineSplit=120
-org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
-org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
-org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
-org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
-org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
-org.eclipse.jdt.core.formatter.tabulation.char=space
-org.eclipse.jdt.core.formatter.tabulation.size=4
-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_outer_expressions_when_nested=true
+eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.autoboxing=ignore +org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning +org.eclipse.jdt.core.compiler.problem.deadCode=warning +org.eclipse.jdt.core.compiler.problem.deprecation=warning +org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled +org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled +org.eclipse.jdt.core.compiler.problem.discouragedReference=warning +org.eclipse.jdt.core.compiler.problem.emptyStatement=warning +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning +org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled +org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore +org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning +org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning +org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled +org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning +org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning +org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning +org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore +org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning +org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=warning +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=disabled +org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning +org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=warning +org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning +org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning +org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore +org.eclipse.jdt.core.compiler.problem.nullReference=warning +org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning +org.eclipse.jdt.core.compiler.problem.parameterAssignment=warning +org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning +org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning +org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning +org.eclipse.jdt.core.compiler.problem.redundantNullCheck=warning +org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=warning +org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=warning +org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=warning +org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=warning +org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled +org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning +org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled +org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled +org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore +org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning +org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled +org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning +org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore +org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning +org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled +org.eclipse.jdt.core.compiler.problem.unusedImport=warning +org.eclipse.jdt.core.compiler.problem.unusedLabel=warning +org.eclipse.jdt.core.compiler.problem.unusedLocal=warning +org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=warning +org.eclipse.jdt.core.compiler.problem.unusedParameter=warning +org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled +org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning +org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning +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=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=0 +org.eclipse.jdt.core.formatter.alignment_for_assignment=0 +org.eclipse.jdt.core.formatter.alignment_for_binary_expression=0 +org.eclipse.jdt.core.formatter.alignment_for_compact_if=0 +org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=0 +org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0 +org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=0 +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=0 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=0 +org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=0 +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 +org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0 +org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1 +org.eclipse.jdt.core.formatter.blank_lines_before_method=1 +org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 +org.eclipse.jdt.core.formatter.blank_lines_before_package=0 +org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1 +org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 +org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false +org.eclipse.jdt.core.formatter.comment.format_block_comments=true +org.eclipse.jdt.core.formatter.comment.format_header=true +org.eclipse.jdt.core.formatter.comment.format_html=true +org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true +org.eclipse.jdt.core.formatter.comment.format_line_comments=false +org.eclipse.jdt.core.formatter.comment.format_source_code=true +org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true +org.eclipse.jdt.core.formatter.comment.indent_root_tags=true +org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert +org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert +org.eclipse.jdt.core.formatter.comment.line_length=120 +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 +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true +org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_empty_lines=false +org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true +org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true +org.eclipse.jdt.core.formatter.indentation.size=4 +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=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert +org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.join_lines_in_comments=false +org.eclipse.jdt.core.formatter.join_wrapped_lines=false +org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false +org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false +org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false +org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false +org.eclipse.jdt.core.formatter.lineSplit=120 +org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false +org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false +org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 +org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1 +org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true +org.eclipse.jdt.core.formatter.tabulation.char=space +org.eclipse.jdt.core.formatter.tabulation.size=4 +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_outer_expressions_when_nested=true diff --git a/main/AndroidManifest.xml b/main/AndroidManifest.xml index ba0c442..9be66db 100644 --- a/main/AndroidManifest.xml +++ b/main/AndroidManifest.xml @@ -22,7 +22,7 @@ android:label="@string/app_name" android:icon="@drawable/cgeo" android:backupAgent="cgeo.geocaching.backup.CentralBackupAgent" > - <uses-library android:name="com.google.android.maps" /> + <uses-library android:name="com.google.android.maps" android:required="false" /> <meta-data android:name="android.app.default_searchable" android:value=".cgeoadvsearch" /> @@ -143,11 +143,6 @@ android:configChanges="keyboardHidden|orientation" > </activity> <activity - android:name=".cgeologs" - android:label="@string/app_name" - android:configChanges="keyboardHidden|orientation" > - </activity> - <activity android:name=".VisitCacheActivity" android:label="@string/app_name" android:configChanges="keyboardHidden|orientation" > diff --git a/main/libs/android-support-v4.jar b/main/libs/android-support-v4.jar Binary files differindex d006198..99e063b 100644 --- a/main/libs/android-support-v4.jar +++ b/main/libs/android-support-v4.jar diff --git a/main/proguard.cfg b/main/proguard.cfg index 74e71cf..5c21420 100644 --- a/main/proguard.cfg +++ b/main/proguard.cfg @@ -14,6 +14,7 @@ -keep public class * extends android.content.BroadcastReceiver -keep public class * extends android.content.ContentProvider -keep public class cgeo.geocaching.* +-keep class android.support.v4.os.** { *; } -keepclasseswithmembers class * { public <init>(android.content.Context, android.util.AttributeSet); diff --git a/main/project/eclipse installation/cgeo eclipse components.p2f b/main/project/eclipse installation/cgeo eclipse components.p2f index a0ac12c..2ecc593 100644 --- a/main/project/eclipse installation/cgeo eclipse components.p2f +++ b/main/project/eclipse installation/cgeo eclipse components.p2f @@ -1,25 +1,25 @@ <?xml version='1.0' encoding='UTF-8'?>
<?p2f version='1.0.0'?>
<p2f version='1.0.0'>
- <ius size='16'>
- <iu id='com.android.ide.eclipse.ddms.feature.group' name='Android DDMS' version='12.0.0.v201106281929-138431'>
+ <ius size='20'>
+ <iu id='com.android.ide.eclipse.ddms.feature.group' name='Android DDMS' version='17.0.0.v201203161636-291853'>
<repositories size='1'>
- <repository location='https://dl-ssl.google.com/android/eclipse/'/>
+ <repository location='https://dl-ssl.google.com/android/eclipse'/>
</repositories>
</iu>
- <iu id='com.android.ide.eclipse.adt.feature.group' name='Android Development Tools' version='12.0.0.v201106281929-138431'>
+ <iu id='com.android.ide.eclipse.adt.feature.group' name='Android Development Tools' version='17.0.0.v201203161636-291853'>
<repositories size='1'>
- <repository location='https://dl-ssl.google.com/android/eclipse/'/>
+ <repository location='https://dl-ssl.google.com/android/eclipse'/>
</repositories>
</iu>
- <iu id='com.android.ide.eclipse.hierarchyviewer.feature.group' name='Android Hierarchy Viewer' version='12.0.0.v201106281929-138431'>
+ <iu id='com.android.ide.eclipse.hierarchyviewer.feature.group' name='Android Hierarchy Viewer' version='17.0.0.v201203161636-291853'>
<repositories size='1'>
- <repository location='https://dl-ssl.google.com/android/eclipse/'/>
+ <repository location='https://dl-ssl.google.com/android/eclipse'/>
</repositories>
</iu>
- <iu id='com.android.ide.eclipse.traceview.feature.group' name='Android Traceview' version='12.0.0.v201106281929-138431'>
+ <iu id='com.android.ide.eclipse.traceview.feature.group' name='Android Traceview' version='17.0.0.v201203161636-291853'>
<repositories size='1'>
- <repository location='https://dl-ssl.google.com/android/eclipse/'/>
+ <repository location='https://dl-ssl.google.com/android/eclipse'/>
</repositories>
</iu>
<iu id='com.instantiations.assist.eclipse.audit.feature.group' name='CodePro - Audit' version='7.1.0.r37x201109091206'>
@@ -32,56 +32,91 @@ <repository location='http://dl.google.com/eclipse/inst/codepro/latest/3.7'/>
</repositories>
</iu>
- <iu id='org.eclipse.egit.feature.group' name='Eclipse EGit' version='1.1.0.201109151100-r'>
- <repositories size='1'>
+ <iu id='org.eclipse.egit.feature.group' name='Eclipse EGit' version='1.3.0.201202151440-r'>
+ <repositories size='3'>
<repository location='http://download.eclipse.org/releases/indigo'/>
+ <repository location='http://marketplace.eclipse.org/repo/'/>
+ <repository location='http://download.eclipse.org/egit/updates'/>
</repositories>
</iu>
- <iu id='org.eclipse.mylyn.github.feature.feature.group' name='Eclipse EGit Mylyn GitHub Feature' version='1.1.0.201109151100-r'>
- <repositories size='1'>
+ <iu id='org.eclipse.mylyn.github.feature.feature.group' name='Eclipse EGit Mylyn GitHub Feature' version='1.3.0.201202151440-r'>
+ <repositories size='3'>
+ <repository location='http://download.eclipse.org/egit/github/updates'/>
<repository location='http://download.eclipse.org/releases/indigo'/>
+ <repository location='http://marketplace.eclipse.org/repo/'/>
</repositories>
</iu>
- <iu id='org.eclipse.jdt.feature.group' name='Eclipse Java Development Tools' version='3.7.1.r371_v20110810-0800-7z8gFcoFMLfTabvKsR5Qm9rBGEBK'>
- <repositories size='2'>
- <repository location='http://download.eclipse.org/eclipse/updates/3.7'/>
+ <iu id='org.eclipse.jdt.feature.group' name='Eclipse Java Development Tools' version='3.7.2.v20120120-1414-7z8gFcuFMP7BW5XTz0jLTnz0l9B1'>
+ <repositories size='3'>
<repository location='http://download.eclipse.org/releases/indigo'/>
+ <repository location='http://download.eclipse.org/eclipse/updates/3.7'/>
+ <repository location='http://marketplace.eclipse.org/repo/'/>
</repositories>
</iu>
- <iu id='org.eclipse.platform.ide' name='Eclipse Platform' version='3.7.1.M20110909-1335'>
- <repositories size='2'>
- <repository location='http://download.eclipse.org/eclipse/updates/3.7'/>
+ <iu id='org.eclipse.platform.ide' name='Eclipse Platform' version='3.7.2.M20120208-0800'>
+ <repositories size='3'>
<repository location='http://download.eclipse.org/releases/indigo'/>
+ <repository location='http://download.eclipse.org/eclipse/updates/3.7'/>
+ <repository location='http://marketplace.eclipse.org/repo/'/>
</repositories>
</iu>
- <iu id='org.eclipse.egit.mylyn.feature.group' name='EGit Mylyn' version='1.1.0.201109151100-r'>
+ <iu id='EclipseRegExFeature.feature.group' name='Eclipse_RegEx_Feature' version='1.3.1'>
<repositories size='1'>
+ <repository location='http://brosinski.com/regex/update'/>
+ </repositories>
+ </iu>
+ <iu id='org.eclipse.egit.mylyn.feature.group' name='EGit Mylyn' version='1.3.0.201202151440-r'>
+ <repositories size='3'>
<repository location='http://download.eclipse.org/releases/indigo'/>
+ <repository location='http://marketplace.eclipse.org/repo/'/>
+ <repository location='http://download.eclipse.org/egit/updates'/>
</repositories>
</iu>
- <iu id='org.eclipse.mylyn.ide_feature.feature.group' name='Mylyn Context Connector: Eclipse IDE' version='3.6.2.v20110908-0706'>
+ <iu id='edu.umd.cs.findbugs.plugin.eclipse.feature.group' name='FindBugs Feature' version='2.0.0.20111221'>
<repositories size='1'>
+ <repository location='http://findbugs.cs.umd.edu/eclipse'/>
+ </repositories>
+ </iu>
+ <iu id='org.eclipse.wst.jsdt.feature.feature.group' name='JavaScript Development Tools' version='1.3.2.v201201112313-7G78FZvFC7sRekSz-g-nAlz'>
+ <repositories size='2'>
<repository location='http://download.eclipse.org/releases/indigo'/>
+ <repository location='http://marketplace.eclipse.org/repo/'/>
</repositories>
</iu>
- <iu id='org.eclipse.mylyn.java_feature.feature.group' name='Mylyn Context Connector: Java Development' version='3.6.2.v20110908-0706'>
- <repositories size='1'>
+ <iu id='org.eclipse.epp.mpc.feature.group' name='Marketplace Client' version='1.1.1.I20110907-0947'>
+ <repositories size='2'>
<repository location='http://download.eclipse.org/releases/indigo'/>
+ <repository location='http://marketplace.eclipse.org/repo/'/>
</repositories>
</iu>
- <iu id='org.eclipse.mylyn.team_feature.feature.group' name='Mylyn Context Connector: Team Support' version='3.6.2.v20110908-0706'>
- <repositories size='1'>
+ <iu id='org.eclipse.mylyn.ide_feature.feature.group' name='Mylyn Context Connector: Eclipse IDE' version='3.6.5.v20120215-0100'>
+ <repositories size='2'>
<repository location='http://download.eclipse.org/releases/indigo'/>
+ <repository location='http://marketplace.eclipse.org/repo/'/>
</repositories>
</iu>
- <iu id='org.eclipse.mylyn_feature.feature.group' name='Mylyn Task List' version='3.6.2.v20110908-0706'>
- <repositories size='1'>
+ <iu id='org.eclipse.mylyn.java_feature.feature.group' name='Mylyn Context Connector: Java Development' version='3.6.5.v20120215-0100'>
+ <repositories size='2'>
<repository location='http://download.eclipse.org/releases/indigo'/>
+ <repository location='http://marketplace.eclipse.org/repo/'/>
</repositories>
</iu>
- <iu id='org.eclipse.mylyn.context_feature.feature.group' name='Mylyn Task-Focused Interface' version='3.6.2.v20110908-0706'>
- <repositories size='1'>
+ <iu id='org.eclipse.mylyn.team_feature.feature.group' name='Mylyn Context Connector: Team Support' version='3.6.5.v20120215-0100'>
+ <repositories size='2'>
+ <repository location='http://download.eclipse.org/releases/indigo'/>
+ <repository location='http://marketplace.eclipse.org/repo/'/>
+ </repositories>
+ </iu>
+ <iu id='org.eclipse.mylyn_feature.feature.group' name='Mylyn Task List' version='3.6.5.v20120215-0100'>
+ <repositories size='2'>
+ <repository location='http://download.eclipse.org/releases/indigo'/>
+ <repository location='http://marketplace.eclipse.org/repo/'/>
+ </repositories>
+ </iu>
+ <iu id='org.eclipse.mylyn.context_feature.feature.group' name='Mylyn Task-Focused Interface' version='3.6.5.v20120215-0100'>
+ <repositories size='2'>
<repository location='http://download.eclipse.org/releases/indigo'/>
+ <repository location='http://marketplace.eclipse.org/repo/'/>
</repositories>
</iu>
</ius>
diff --git a/main/project/localization/findextratranslations.sh b/main/project/localization/findextratranslations.sh index 8e2898d..8e2898d 100644..100755 --- a/main/project/localization/findextratranslations.sh +++ b/main/project/localization/findextratranslations.sh diff --git a/main/project/localization/findmissingtranslations.sh b/main/project/localization/findmissingtranslations.sh index 4c47cbd..420f6f9 100644..100755 --- a/main/project/localization/findmissingtranslations.sh +++ b/main/project/localization/findmissingtranslations.sh @@ -9,11 +9,11 @@ finddiffs () { diff -y en.str $1.str > tmp.str echo "Only in values/strings.xml:" >> $1.missing grep "<\||" tmp.str | cut -d " " -f 1 | while read s; do - grep "<string" ../../res/values/strings.xml | grep "name=\"$s\"" + egrep "<(string|plurals)" ../../res/values/strings.xml | grep "name=\"$s\"" done | egrep -v '<string name="(contributors|changelog)">'>> $1.missing echo "Only in values-$1/strings.xml:" >> $1.missing grep ">\||" tmp.str | sed "s/^/x/;s/\s\s*/ /g" | cut -d " " -f 3 | while read s; do - grep "<string" ../../res/values-$1/strings.xml | grep "name=\"$s\"" + egrep "<(string|plurals)" ../../res/values-$1/strings.xml | grep "name=\"$s\"" done >> $1.missing rm tmp.str } diff --git a/main/project/localization/funcs.sh b/main/project/localization/funcs.sh index f54dccd..198fbae 100644 --- a/main/project/localization/funcs.sh +++ b/main/project/localization/funcs.sh @@ -1,5 +1,5 @@ # Utility functions for location-aware programs getnames () { - sed -ne 's/^.*<string\s*name\s*=\s*"\([^\"]*\)".*$/\1/p' $1 + sed -ne 's/^.*<\(string\|plurals\)\s*name\s*=\s*"\([^\"]*\)".*$/\2/p' $1 } diff --git a/main/project/rawimages/c_geo_icon_512.png b/main/project/rawimages/c_geo_icon_512.png Binary files differnew file mode 100644 index 0000000..86cce19 --- /dev/null +++ b/main/project/rawimages/c_geo_icon_512.png diff --git a/main/project/rawimages/cgeo-calendar_ic_512x512.psd b/main/project/rawimages/cgeo-calendar_ic_512x512.psd Binary files differnew file mode 100644 index 0000000..a862a1e --- /dev/null +++ b/main/project/rawimages/cgeo-calendar_ic_512x512.psd diff --git a/main/project/rawimages/play_feature_graphic.jpg b/main/project/rawimages/play_feature_graphic.jpg Binary files differnew file mode 100644 index 0000000..f7e2784 --- /dev/null +++ b/main/project/rawimages/play_feature_graphic.jpg diff --git a/main/res/layout/caches.xml b/main/res/layout/caches.xml index 924651d..6e39fee 100644 --- a/main/res/layout/caches.xml +++ b/main/res/layout/caches.xml @@ -22,10 +22,23 @@ android:src="@drawable/actionbar_manual" android:onClick="goManual" /> </LinearLayout> + <include layout="@layout/filter_bar"/> + + <RelativeLayout android:id="@+id/loading" + android:layout_width="fill_parent" + android:layout_height="fill_parent"> + <ProgressBar style="@android:style/Widget.ProgressBar.Large" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_centerInParent="true" + android:gravity="center" + android:indeterminate="true" + android:indeterminateOnly="true" /> + </RelativeLayout> + <ListView android:id="@android:id/list" android:visibility="gone" - android:layout_above="@+id/counter" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_margin="0dip" @@ -33,15 +46,4 @@ android:dividerHeight="1dip" android:background="?background_color" android:cacheColorHint="?background_color" /> - <RelativeLayout android:id="@+id/loading" - android:layout_width="fill_parent" - android:layout_height="fill_parent" - android:padding="5dip" > - <ProgressBar style="@android:style/Widget.ProgressBar.Large.Inverse" - android:layout_width="76dip" - android:layout_height="76dip" - android:layout_centerInParent="true" - android:gravity="center" - android:indeterminate="true" /> - </RelativeLayout> </LinearLayout>
\ No newline at end of file diff --git a/main/res/layout/cacheview_description.xml b/main/res/layout/cacheview_description.xml index 83d4e49..c985bfb 100644 --- a/main/res/layout/cacheview_description.xml +++ b/main/res/layout/cacheview_description.xml @@ -52,12 +52,13 @@ android:visibility="gone" >
<ProgressBar
- style="@android:style/Widget.ProgressBar.Large.Inverse"
- android:layout_width="76dip"
- android:layout_height="76dip"
+ style="?progressSpinnerLarge"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:gravity="center"
- android:indeterminate="true" />
+ android:indeterminate="true"
+ android:indeterminateOnly="true" />
</RelativeLayout>
<!-- Hint and spoiler-images box -->
diff --git a/main/res/layout/fieldnote_export_dialog.xml b/main/res/layout/fieldnote_export_dialog.xml new file mode 100644 index 0000000..f897985 --- /dev/null +++ b/main/res/layout/fieldnote_export_dialog.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:padding="3dip" >
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/export_fieldnotes_info" />
+
+ <CheckBox
+ android:id="@+id/upload"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:enabled="false"
+ android:text="@string/export_fieldnotes_upload" />
+
+ <CheckBox
+ android:id="@+id/onlynew"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:enabled="false"
+ android:text="@string/export_fieldnotes_onlynew" />
+
+ <Button
+ android:id="@+id/export"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="3dip"
+ android:text="@string/export" />
+
+</LinearLayout>
\ No newline at end of file diff --git a/main/res/layout/init.xml b/main/res/layout/init.xml index e9d28a6..dd2ed0d 100644 --- a/main/res/layout/init.xml +++ b/main/res/layout/init.xml @@ -869,6 +869,46 @@ android:textColorLink="?text_color_link" android:linksClickable="true" android:text="@string/init_backup_note" /> +<!-- ** --> + <RelativeLayout style="@style/separator_horizontal_layout" > + <View style="@style/separator_horizontal" /> + <TextView + style="@style/separator_horizontal_headline" + android:text="@string/init_debug_title" /> + </RelativeLayout> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="10dip" + android:layout_marginRight="10dip" + android:layout_marginBottom="5dip" + android:layout_gravity="left" + android:padding="3dip" + android:textSize="14dip" + android:textColor="?text_color" + android:textColorLink="?text_color_link" + android:linksClickable="true" + android:text="@string/init_debug_note" /> + <LinearLayout + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" > + <CheckBox android:id="@+id/debug" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="left" + android:padding="1px" + android:gravity="center" /> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:gravity="left" + android:paddingRight="3dip" + android:textSize="14dip" + android:textColor="?text_color" + android:text="@string/init_debug" /> + </LinearLayout> </LinearLayout> </ScrollView> </LinearLayout> diff --git a/main/res/layout/main.xml b/main/res/layout/main.xml index e1c25cf..2f0b1d8 100644 --- a/main/res/layout/main.xml +++ b/main/res/layout/main.xml @@ -167,7 +167,8 @@ android:layout_alignParentBottom="true" android:layout_marginRight="6dip" android:layout_marginLeft="6dip" - android:orientation="vertical"> + android:orientation="vertical" + android:onClick="cgeoNavSettings"> <TextView android:id="@+id/user_info" style="@style/location_current" android:text="@string/init_login_popup_working"/> @@ -185,4 +186,4 @@ style="@style/location_current_satellites" /> </RelativeLayout> </LinearLayout> -</RelativeLayout>
\ No newline at end of file +</RelativeLayout> diff --git a/main/res/layout/map_static_item.xml b/main/res/layout/map_static_item.xml index 057ff72..3416e65 100644 --- a/main/res/layout/map_static_item.xml +++ b/main/res/layout/map_static_item.xml @@ -4,6 +4,7 @@ android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" + android:layout_marginBottom="10dip" android:scaleType="centerCrop" android:padding="3dip" android:gravity="center" />
\ No newline at end of file diff --git a/main/res/values-cs/strings.xml b/main/res/values-cs/strings.xml index 8759093..0c744f6 100644 --- a/main/res/values-cs/strings.xml +++ b/main/res/values-cs/strings.xml @@ -206,6 +206,7 @@ <string name="caches_refresh_selected">aktualizovat vybrané</string> <string name="caches_refresh_all">aktualizovat vše</string> <string name="caches_map_locus">Locus</string> + <string name="caches_map_locus_export">Exportovat do Locusu</string> <string name="caches_recaptcha_title">reCAPTCHA</string> <string name="caches_recaptcha_explanation">Opište text z obrázků. Je to důležité pro stažení souřadnic keší.</string> <string name="caches_recaptcha_hint">Text z obrázku</string> diff --git a/main/res/values-de/strings.xml b/main/res/values-de/strings.xml index 354d56d..95f414a 100644 --- a/main/res/values-de/strings.xml +++ b/main/res/values-de/strings.xml @@ -10,7 +10,7 @@ <string name="settings">Einstellungen</string> <string name="helpers">Nützliche Apps</string> <string name="about">Über c:geo</string> - <string name="helper">Du willst mehr über <b>c:geo</b> erfahren?\nSchaue in die Bedienungsanleitung.</string> + <string name="helper">Um mehr über <b>c:geo</b> zu erfahren\neinfach die Bedienungsanleitung öffnen.</string> <string name="latitude">Breitengrad</string> <string name="longitude">Längengrad</string> @@ -127,12 +127,12 @@ <string name="err_server">Verbindung zu Geocaching.com konnte nicht hergestellt werden (Server oder Verbindung inaktiv?)</string> <string name="err_login">Keine Anmeldedaten gespeichert.</string> <string name="err_login_failed">Login fehlgeschlagen.</string> - <string name="err_login_failed_toast">c:geo konnte sich nicht einloggen und arbeitet im Offline-Modus. Überprüfe deine Login-Daten in den Einstellungen oder stelle eine Internetverbindung her.</string> + <string name="err_login_failed_toast">c:geo konnte sich nicht einloggen und arbeitet im Offline-Modus. Bitte die Login-Daten in den Einstellungen überprüfen oder eine Internetverbindung herstellen.</string> <string name="err_unknown">Unbekannter Fehler</string> <string name="err_comm">Unbekannter Kommunikationsfehler</string> <string name="err_missing_auth">Benutzername oder Passwort nicht gesetzt.</string> <string name="err_wrong">Falsche Anmeldedaten</string> - <string name="err_maintenance">Geocaching.com wird zur Zeit gewartet, bitte versuche es später erneut. c:geo arbeitet im Offline-Modus.</string> + <string name="err_maintenance">Geocaching.com wird zur Zeit gewartet, bitte später erneut versuchen. c:geo arbeitet im Offline-Modus.</string> <string name="err_license">Die Geocaching.com Nutzungsbedingungen wurden nicht akzeptiert. c:geo kann deshalb keine Koordinaten laden.</string> <string name="err_unpublished">Der aufgerufene Cache ist noch nicht veröffentlicht</string> <string name="err_premium_only">Der Cache ist nur für Premium Mitglieder von Geocaching.com verfügbar</string> @@ -145,13 +145,13 @@ <string name="err_detail_cache_find_any">c:geo konnte keine Caches finden.</string> <string name="err_detail_cache_find_next">c:geo konnte die nächsten Caches nicht finden.</string> <string name="err_detail_cache_forgot">c:geo hat vergessen, welcher Cache aufgerufen werden sollte.</string> - <string name="err_detail_cache_forgot_visit">c:geo hat vergessen, welchen Cache du besucht hast.</string> + <string name="err_detail_cache_forgot_visit">c:geo hat vergessen, welcher Cache besucht werden sollte.</string> <string name="err_detail_no_spoiler">c:geo hat kein Hinweisbild für diesen Cache gefunden.</string> <string name="err_detail_no_map_static">c:geo hat keine statische Karte für diesen Cache gefunden.</string> <string name="err_detail_not_load_map_static">c:geo konnte die statische Karte nicht laden.</string> <string name="err_detail_ask_store_map_static">c:geo konnte die statische Karte nicht laden. Jetzt speichern?</string> <string name="err_detail_still_working">Arbeite noch an anderer Aufgabe.</string> - <string name="err_watchlist_still_managing">c:geo versucht noch immer deine Watchlist zu aktualisieren.</string> + <string name="err_watchlist_still_managing">c:geo versucht noch immer die Watchlist zu aktualisieren.</string> <string name="err_watchlist_failed">Ändern der Watchlist nicht erfolgreich.</string> <string name="err_navigation_no">c:geo konnte keine unterstützte Art der Navigation finden.</string> <string name="err_application_no">c:geo konnte keine passende Anwendung finden.</string> @@ -166,23 +166,23 @@ <string name="err_dwld_details_failed">Download der Cache-Details fehlgeschlagen.</string> <string name="err_load_descr_failed">Laden der Cachebeschreibung fehlgeschlagen.</string> <string name="err_location_unknown">c:geo erkennt die Position des Caches nicht.</string> - <string name="err_missing_device_name">Bitte lege einen Namen für dein Handy fest, bevor du dich registrierst.</string> + <string name="err_missing_device_name">Vor der Registrierung muss ein Name für das Endgerät festlegt werden.</string> <string name="err_tb_display">"c:geo kann den gewünschten Trackable nicht anzeigen. Ist es wirklich einer?</string> <string name="err_tb_details_open">c:geo konnte die Details des Trackables nicht öffnen.</string> <string name="err_tb_details_download">c:geo konnte die Details des Trackables nicht laden, weil</string> - <string name="err_tb_forgot">c:geo hat den gewünschten Trackable vergessen.</string> - <string name="err_tb_forgot_saw">c:geo hat vergessen, welchen Trackable du gesehen hast.</string> + <string name="err_tb_forgot">c:geo hat vergessen, welcher Trackable geöffnet werden sollte.</string> + <string name="err_tb_forgot_saw">c:geo hat vergessen, welcher Trackable gesehen wurde.</string> <string name="err_tb_find">c:geo findet den Trackable nicht</string> <string name="err_tb_find_that">c:geo konnte diesen Trackable nicht finden.</string> <string name="err_waypoint_cache_unknown">c:geo weiß nicht, zu welchem Cache der Wegpunkt hinzugefügt werden soll.</string> - <string name="err_waypoint_unknown">c:geo hat vergessen, welchen Wegpunkt du ansehen wolltest.</string> + <string name="err_waypoint_unknown">c:geo hat vergessen, welcher Wegpunkt angesehen werden sollte.</string> <string name="err_waypoint_add_failed">c:geo konnte den Wegpunkt nicht hinzufügen.</string> <string name="err_waypoint_load_failed">c:geo konnte den Wegpunkt nicht laden.</string> <string name="err_waypoint_delete_failed">c:geo konnte den Wegpunkt nicht löschen.</string> <string name="err_waypoint_open_cache_failed">c:geo konnte die Cachedetails nicht laden.</string> - <string name="err_point_unknown_position">c:geo konnte deinen Standort nicht bestimmen.</string> + <string name="err_point_unknown_position">c:geo konnte den aktuellen Standort nicht bestimmen.</string> <string name="err_point_no_position_given_title">Info benötigt</string> <string name="err_point_no_position_given">Mindestens Längen- und Breitengrad oder Entfernung und Richtung angeben. Auch alle Angaben sind möglich.</string> <string name="err_point_curr_position_unavailable">c:geo hat noch keine aktuelle Koordinaten. Bitte einen Moment warten…</string> @@ -197,7 +197,7 @@ <string name="err_log_post_failed">c:geo konnte Log nicht absenden.</string> <string name="err_search_address_no_match">Keinen passenden Ort gefunden.</string> - <string name="err_search_address_forgot">c:geo hat die Adresse vergessen, die du suchst.</string> + <string name="err_search_address_forgot">c:geo hat die Adresse vergessen, die gesucht wurde.</string> <string name="err_parse_lat">c:geo konnte den Breitengrad nicht verarbeiten.</string> <string name="err_parse_lon">c:geo konnte den Längengrad nicht verarbeiten.</string> <string name="err_parse_dist">c:geo konnte die Entfernung nicht verarbeiten.</string> @@ -218,7 +218,7 @@ <string name="warn_search_help_tb">Code des Trackables eingeben, z.B. \"TB29QMZ\".</string> <string name="warn_log_text_fill">Bitte Text einfügen.</string> <string name="warn_load_images">c:geo konnte die Bilder nicht laden.</string> - + <string name="warn_invalid_mapfile">Die gewählte Datei ist keine gültige Mapsforge-Karte in der Version 0.2.4.\nOffline Karte ist nicht verfügbar.</string> <string name="info_log_posted">Log erfolgreich gesendet.</string> <string name="info_log_saved">Log erfolgreich gespeichert.</string> @@ -235,6 +235,7 @@ <string name="loc_sat">SAT</string> <string name="loc_trying">Lokalisierung</string> <string name="loc_no_addr">Adresse unbekannt</string> + <string name="loc_gps_disabled">GPS nicht aktiv</string> <!-- standard menu --> <string name="menu_about">über c:geo</string> @@ -287,9 +288,9 @@ <string name="caches_nearby">In der Nähe</string> <string name="caches_manage">Verwalten</string> <string name="caches_drop_selected">Ausgewählte löschen</string> - <string name="caches_drop_selected_ask">Bist du sicher, dass die ausgewählten Caches vom Gerät gelöscht werden sollen?</string> + <string name="caches_drop_selected_ask">Sollen die ausgewählten Caches wirklich vom Gerät gelöscht werden?</string> <string name="caches_drop_all">Alle löschen</string> - <string name="caches_drop_all_ask">Bist du sicher, dass alle Caches von dieser Liste gelöscht werden sollen?</string> + <string name="caches_drop_all_ask">Sollen wirklich alle Caches von dieser Liste gelöscht werden?</string> <string name="caches_drop_stored">Gespeicherte löschen</string> <string name="caches_drop_progress">Entferne Caches…</string> <string name="caches_drop_all_and_list">Alle und Liste löschen</string> @@ -299,7 +300,7 @@ <string name="caches_move_all">Alle verschieben</string> <string name="caches_map_locus">Locus</string> <string name="caches_recaptcha_title">reCAPTCHA</string> - <string name="caches_recaptcha_explanation">Bitte Text vom Bild abschreiben. Wichtig, um Koordinaten des Caches laden zu können. Optional, kann in den Einstellungen deaktiviert werden.</string> + <string name="caches_recaptcha_explanation">Bitte Text vom Bild abschreiben. Wichtig, um Koordinaten des Caches laden zu können. Dies ist optional und kann in den Einstellungen deaktiviert werden.</string> <string name="caches_recaptcha_hint">Text vom Bild</string> <string name="caches_recaptcha_continue">Fortfahren</string> <string name="caches_filter">Filter</string> @@ -309,7 +310,7 @@ <string name="caches_filter_track">Mit Trackables</string> <string name="caches_filter_clear">Filter zurücksetzen</string> <string name="caches_filter_size_title">Größe wählen</string> - <string name="caches_filter_type_title">Wähle den Typ</string> + <string name="caches_filter_type_title">Typ wählen</string> <string name="caches_filter_modified">Mit geänderten Koordinaten</string> <string name="caches_exporting_fieldnote">Exportiere als Field-Notes…</string> <string name="caches_removing_from_history">Lösche aus Verlauf…</string> @@ -328,7 +329,7 @@ <string name="list_dialog_create_ok">Neue Liste wurde erstellt</string> <string name="list_dialog_create_err">c:geo konnte die neue Liste nicht erstellen</string> <string name="list_dialog_remove_title">Liste entfernen</string> - <string name="list_dialog_remove_description">Aktuelle Liste löschen? Alle Caches dieser Liste werden in die Standardliste verschoben.</string> + <string name="list_dialog_remove_description">Soll die aktuelle Liste gelöscht werden? Alle Caches dieser Liste werden in die Standardliste verschoben.</string> <string name="list_dialog_remove">Entfernen</string> <string name="list_dialog_remove_ok">Liste wurde gelöscht</string> <string name="list_dialog_remove_err">c:geo konnte die Liste nicht löschen</string> @@ -362,7 +363,7 @@ <string name="init_signature">Signatur</string> <string name="init_signature_help_button">Hilfe</string> <string name="init_signature_help_title">Tipps und Tricks für die Signatur</string> - <string name="init_signature_help_text">Verfasse eine Signatur für deinen Logtext.\nErlaubte Platzhalter sind: [DATE], [TIME], [DATETIME], [USER] & [NUMBER]. Diese werden beim Einfügen der Signatur durch ihre Werte ersetzt.</string> + <string name="init_signature_help_text">Verwendete Signatur für Logtexte.\nErlaubte Platzhalter sind: [DATE], [TIME], [DATETIME], [USER] & [NUMBER]. Diese werden beim Einfügen der Signatur durch die entsprechenden Werte ersetzt.</string> <string name="init_signature_template_button">Platzhalter einfügen</string> <string name="init_signature_template_date">Datum</string> <string name="init_signature_template_time">Zeit</string> @@ -392,7 +393,7 @@ <string name="init_log_offline">Offline loggen (Dialog für Online-Log nicht anzeigen)</string> <string name="init_livelist">Richtung zum Cache in der Cache-Liste anzeigen</string> <string name="init_altitude">Höhenkorrektur</string> - <string name="init_altitude_description">Falls das GPS eine falsche Höhe ermittelt, kannst du sie durch Angabe eines positiven oder negativen Wertes in Metern korrigieren.</string> + <string name="init_altitude_description">Falls das GPS eine falsche Höhe ermittelt, kann dies durch Angabe eines positiven oder negativen Wertes in Metern korrigiert werden.</string> <string name="init_clear">Login zurücksetzen</string> <string name="init_cleared">c:geo hat die Anmeldedaten gelöscht.</string> <string name="init_backup">Sicherung</string> @@ -406,21 +407,24 @@ <string name="init_restore_success">Wiederherstellung beendet.</string> <string name="init_restore_failed">Wiederherstellung fehlgeschlagen.</string> <string name="init_restore_running">Wiederherstellung der Cache-Datenbank…</string> - <string name="init_restore_confirm">Die Cache-Datenbank ist leer. Möchtest du die vorhandene Sicherung wiederherstellen?</string> + <string name="init_restore_confirm">Die Cache-Datenbank ist leer. Soll die vorhandene Sicherung wiederhergestellt werden?</string> <string name="init_backup_last">Backup verfügbar von</string> <string name="init_backup_last_no">Keine Datei mit Datenbanksicherung gefunden.</string> <string name="init_mapsources">Kartenherkunft</string> - <string name="init_mapsources_description">Hier kannst du die Quelle für deine Karte wählen. Alternativ zu Google Maps stehen verschiedene OpenStreetMap-Stile zur Verfügung und daneben auch Karten-Dateien für die Offline-Nutzung (siehe http://code.google.com/p/mapsforge/ für die Details).</string> - <string name="init_mapsource_select">Wähle eine Kartenquelle</string> + <string name="init_mapsources_description">Hier kann die Quelle der benutzen Karte gewählt werden. Alternativ zu Google Maps stehen verschiedene OpenStreetMap-Stile zur Verfügung und daneben auch Karten-Dateien für die Offline-Nutzung (siehe http://code.google.com/p/mapsforge/ für die Details).</string> + <string name="init_mapsource_select">Kartenquelle wählen</string> <string name="init_select_mapfile">…</string> <string name="init_maptrail">Zeige Spur auf Karte</string> <string name="init_trackautovisit">Trackables automatisch auf \"besuchen\" setzen</string> <string name="init_sigautoinsert">Signatur automatisch einfügen</string> <string name="init_loaddirectionimg">Richtungs-Grafik laden wenn nötig (nur Basic Member)</string> <string name="init_default_navigation_tool">Standardnavigation</string> - <string name="init_default_navigation_tool_description">Hier kannst du dein bevorzugtes Navigationswerkzeug festlegen.</string> + <string name="init_default_navigation_tool_description">Hier kann das bevorzugte Navigationswerkzeug festgelegt werden.</string> <string name="init_default_navigation_tool_select">Wähle Werkzeug</string> - <string name="init_default_navigation_tool_2_description">Hier kannst du dein zweites bevorzugtes Navigationswerkzeug festlegen. Es ist durch langen Klick auf das Navigationssymbol in der Titelzeile eines Caches erreichbar.</string> + <string name="init_default_navigation_tool_2_description">Hier kannst das zweite bevorzugte Navigationswerkzeug festgelegt werden. Es ist durch langen Klick auf das Navigationssymbol in der Titelzeile eines Caches erreichbar.</string> + <string name="init_debug_title">Fehlersuche</string> + <string name="init_debug_note">c:geo kann bei Bedarf viele Debuginformationen speichern. Im Normalfall ist dies nicht notwendig, jedoch kann es den Entwicklern bei der Fehlersuche helfen. In diesem Fall wird der Benutzer gebeten diese Einstellung zu aktivieren und später das Log-File zuzusenden.</string> + <string name="init_debug">Debug-Log aktivieren</string> <!-- map sources --> <string name="map_source_google_map">Google: Karte</string> @@ -428,11 +432,11 @@ <string name="map_source_osm_cyclemap">OSM: Radfahrerkarte</string> <string name="init_sendToCgeo">Send to c:geo</string> - <string name="init_sendToCgeo_name">Der Name deines Handys:</string> - <string name="init_sendToCgeo_description">Send to c:geo erlaubt es, mit einem speziellen Plugin für Firefox oder Chrome, Caches direkt von der Geocachingseite zu empfangen. Bitte lies dir die Details vor einer Registrierung auf <a href="http://send2.cgeo.org/">http://send2.cgeo.org/</a> durch.</string> + <string name="init_sendToCgeo_name">Name des Endgerätes:</string> + <string name="init_sendToCgeo_description">Send to c:geo erlaubt es, mit einem speziellen Plugin für Firefox oder Chrome, Caches direkt von der Geocachingseite zu empfangen. Bitte dazu die Details vor einer Registrierung auf <a href="http://send2.cgeo.org/">http://send2.cgeo.org/</a> durchlesen.</string> <string name="init_sendToCgeo_register">Registrierung anfordern</string> - <string name="init_sendToCgeo_registering">Registriere dein Handy für "Send to c:geo"…</string> - <string name="init_sendToCgeo_register_ok">Registrierung erfolgreich. Dein PIN code ist ####. Benutze diesen auf der c:geo website, um dein Handy im Browser hinzuzufügen.</string> + <string name="init_sendToCgeo_registering">Das Gerät wird für "Send to c:geo" registriert…</string> + <string name="init_sendToCgeo_register_ok">Registrierung erfolgreich. Der PIN Code ist ####. Bitte diesen auf der der c:geo Website angeben, um das Endgerät im Browser hinzuzufügen.</string> <string name="init_sendToCgeo_register_fail">Registrierung fehlgeschlagen.</string> <string name="sendToCgeo_download_fail">c:geo konnte Caches nicht laden. Entweder besteht keine Internetverbindung oder send2c:geo funktioniert nicht.</string> <string name="sendToCgeo_no_registration">c:geo konnte Caches nicht laden. Registrierung für send2c:geo ungültig. Bitte in Einstellungen neu registrieren.</string> @@ -590,12 +594,12 @@ <string name="gpx_import_canceled">Der GPX-Import wurde abgebrochen</string> <!-- map file select --> - <string name="map_file_select_title">Wähle eine Kartendatei</string> + <string name="map_file_select_title">Kartendatei wählen</string> <!-- import --> <string name="import_title">Importiere…</string> <string name="web_import_title">Aus dem Internet importieren</string> - <string name="web_import_waiting">Erwarte neue Caches aus dem Internet…</string> + <string name="web_import_waiting">Warte auf neue Caches aus dem Internet…</string> <string name="web_downloading">Lade herunter</string> <string name="web_downloaded">Heruntergeladen</string> @@ -654,7 +658,7 @@ <string name="map_strategy_fast">Schnell</string> <string name="map_strategy_auto">Geschwindigkeitsabhängig</string> <string name="map_strategy_detailed">Detailliert</string> - <string name="live_map_notification">Auf der neuen Live-Karte sind die Koordinaten nicht immer genau. Eventuell ungenaue Koordinaten sind mit einem orangen Kreis markiert.\nDas Öffnen der Cache-Details oder das Speichern des Cache liefert immer genaue Koordinaten.\n\nMehr Informationen über alle Änderungen findet ihr auf der \"Über c:geo\"-Seite in der App.</string> + <string name="live_map_notification">Auf der neuen Live-Karte sind die Koordinaten nicht immer genau. Eventuell ungenaue Koordinaten sind mit einem orangen Kreis markiert.\nDas Öffnen der Cache-Details oder das Speichern des Cache liefert immer genaue Koordinaten.\n\nMehr Informationen über alle Änderungen befinden sich auf der \"Über c:geo\"-Seite in der App.</string> <string name="live_map_note_close">Schließen</string> <string name="live_map_note_dontshow">Nicht mehr anzeigen</string> @@ -748,6 +752,18 @@ <string name="addon_missing_title">Add-On fehlt</string> <string name="addon_download_prompt">Jetzt im Google Play Store herunterladen</string> + <!-- export --> + <string name="export">Exportieren</string> + <string name="export_as">Exportieren als…</string> + <string name="export_exportedto">exportiert nach</string> + <string name="export_failed">Exportieren fehlgeschlagen</string> + <string name="export_fieldnotes">Field Notes</string> + <string name="export_fieldnotes_info">Field Notes werden nach /sdcard/field-notes mit dem aktuellen Datum und Zeit als Dateiname exportiert.</string> + <string name="export_fieldnotes_upload">Hochladen auf geocaching.com</string> + <string name="export_fieldnotes_uploading">Hochladen…</string> + <string name="export_fieldnotes_onlynew">Nur seit letztem Export</string> + <string name="export_gpx">GPX</string> + <!-- attributes (permissions -> allowed, not allowed) --> <string name="attribute_dogs_yes">Hunde erlaubt</string> <string name="attribute_dogs_no">Hunde nicht erlaubt</string> @@ -897,7 +913,7 @@ <string name="facebook">Facebook: <a href="http://www.facebook.com/pages/cgeo/297269860090">c:geo page</a></string> <string name="twitter">Twitter: <a href="http://twitter.com/android_gc">@android_GC</a></string> <string name="nutshellmanual">Benutzung: <a href="http://manual.cgeo.org/">c:geo Kurzanleitung</a></string> - <string name="about_go4cache">Der Service <b>Go 4 cache</b> ermöglicht es, andere Geocacher in Echtzeit auf der Karte zu sehen (in <b>c:geo</b> oder im Browser). Es kann auch angezeigt werden, welchen Cache du suchst. Wenn <b>c:geo</b> mit <b>Go 4 cache</b> verbunden wird, kann <b>c:geo</b> die aktuelle Position veröffentlichen (nur während <b>c:geo</b> ausgeführt wird).</string> + <string name="about_go4cache">Der Service <b>Go 4 cache</b> ermöglicht es, andere Geocacher in Echtzeit auf der Karte zu sehen (in <b>c:geo</b> oder im Browser). Es kann auch angezeigt werden, welcher Cache gerade gesucht wird. Wenn <b>c:geo</b> mit <b>Go 4 cache</b> verbunden wird, kann <b>c:geo</b> die aktuelle Position veröffentlichen (nur während <b>c:geo</b> ausgeführt wird).</string> <string name="about_twitter">Soll jeder neue Fund auf Twitter veröffentlicht werden, wenn er über <b>c:geo</b> geloggt wird?</string> <string name="about_auth_1">Der folgende Prozess erlaubt es <b>c:geo</b> auf den persönlichen Twitter-Account zuzugreifen, wenn zugestimmt wird.</string> <string name="about_auth_2">Ein Klick auf \"Starte Autorisierung\" öffnet eine Twitter-Seite in einem Browserfenster. Durch die Anmeldung und die Bestätigung wird <b>c:geo</b> ermöglicht, auf den persönlichen Twitter-Account zuzugreifen. Wird dies bestätigt, nennt Twitter eine numerische PIN, diese muss kopiert und in <b>c:geo</b> eingefügt werden. Das ist alles.</string> @@ -910,4 +926,6 @@ <item quantity="one">vor einer Minute</item> <item quantity="other">vor %d Minuten</item> </plurals> + + <string name="clipboard_copy_ok">In Zwischenablage kopiert</string> </resources> diff --git a/main/res/values-fr/strings.xml b/main/res/values-fr/strings.xml index c77d682..587ef3f 100644 --- a/main/res/values-fr/strings.xml +++ b/main/res/values-fr/strings.xml @@ -218,7 +218,7 @@ <string name="warn_search_help_tb">Veuillez remplir le code de l\'objet voyageur. Par exemple \"TB29QMZ\".</string> <string name="warn_log_text_fill">Merci de saisir un texte pour votre visite.</string> <string name="warn_load_images">c:geo n\'a pas pu charger les images.</string> - + <string name="warn_invalid_mapfile">Le fichier sélectionné n\'est pas un fichier de carte mapsforge version 0.2.4.\nLes cartes hors-lignes ne sont pas disponibles.</string> <string name="info_log_posted">Envoi de la visite réussi.</string> <string name="info_log_saved">Sauvegarde de la visite réussie.</string> @@ -235,6 +235,7 @@ <string name="loc_sat">Satellites</string> <string name="loc_trying">Localisation en cours…</string> <string name="loc_no_addr">Adresse inconnue</string> + <string name="loc_gps_disabled">GPS désactivé</string> <!-- standard menu --> <string name="menu_about">À propos de c:geo</string> @@ -298,6 +299,7 @@ <string name="caches_move_selected">Déplacer les caches sélectionnées</string> <string name="caches_move_all">Tout déplacer</string> <string name="caches_map_locus">Locus</string> + <string name="caches_map_locus_export">Exporter vers Locus</string> <string name="caches_recaptcha_title">reCAPTCHA</string> <string name="caches_recaptcha_explanation">Recopier le texte se trouvant dans l\'image pour charger les coordonnées des caches. Cette étape peut être désactivée dans les Paramètres.</string> <string name="caches_recaptcha_hint">Texte de l\'image</string> @@ -421,6 +423,9 @@ <string name="init_default_navigation_tool_description">Vous pouvez choisir ici l\'outil de navigation à utiliser par défaut.</string> <string name="init_default_navigation_tool_select">Sélectionner l\'outil</string> <string name="init_default_navigation_tool_2_description">Vous pouvez choisir ici votre deuxième outil de navigation préféré. Il sera activé par un appui long sur l\'icône de navigation situé près du nom de la cache.</string> + <string name="init_debug_title">Déverminage</string> + <string name="init_debug_note">c:geo est capable de générer beaucoup d\'informations peu utiles pour des utilisateurs normaux. Cependant, en cas de problème, les développeurs en charge de c:geo peuvent avoir besoin de cette information pour pouvoir l\'identifier. Dans ce cas, ils vous demanderont d\'activer cette option et d\'envoyer les fichiers de journaux.</string> + <string name="init_debug">Générer les informations</string> <!-- map sources --> <string name="map_source_google_map">Google Maps : plan</string> @@ -485,6 +490,10 @@ <string name="cache_watchlist_add">Ajouter à votre liste de suivi</string> <string name="cache_watchlist_remove">Retirer de votre liste de suivi</string> <string name="cache_waypoints">Étapes</string> + <plurals name="waypoints"> + <item quantity="one">1 étape</item> + <item quantity="other">%d étapes</item> + </plurals> <string name="cache_waypoints_add">Ajouter une étape</string> <string name="cache_hint">Indice</string> <string name="cache_logs">Carnet de bord</string> @@ -755,6 +764,18 @@ <string name="addon_missing_title">Module complémentaire manquant</string> <string name="addon_download_prompt">Le télécharger sur Google Play.</string> + <!-- export --> + <string name="export">Exporter</string> + <string name="export_as">Exporter en tant que…</string> + <string name="export_exportedto">exporté vers</string> + <string name="export_failed">Échec de l\'exportation</string> + <string name="export_fieldnotes">Notes de terrain</string> + <string name="export_fieldnotes_info">Les notes de terrain seront sauvées dans le dossier /sdcard/field-notes avec, comme nom de fichier, la date et l\'heure courantes.</string> + <string name="export_fieldnotes_upload">Envoyer vers geocaching.com</string> + <string name="export_fieldnotes_uploading">Envoi en cours…</string> + <string name="export_fieldnotes_onlynew">Uniquement les nouveautés depuis le dernier envoi</string> + <string name="export_gpx">GPX</string> + <!-- attributes (permissions -> allowed, not allowed) --> <string name="attribute_dogs_yes">Chiens autorisés</string> <string name="attribute_dogs_no">Chiens interdits</string> @@ -914,5 +935,11 @@ <string name="go4cache_looking_around">En balade</string> <string name="go4cache_tweeting">En train de tweeter</string> <string name="go4cache_heading_to">En direction de</string> + <plurals name="go4cache_time_minutes"> + <item quantity="one">il y a une minute</item> + <item quantity="other">il y a %d minutes</item> + </plurals> + + <string name="clipboard_copy_ok">Copié dans le presse-papiers</string> </resources> diff --git a/main/res/values-it/strings.xml b/main/res/values-it/strings.xml index 9759db9..2e33988 100644 --- a/main/res/values-it/strings.xml +++ b/main/res/values-it/strings.xml @@ -26,15 +26,15 @@ <string name="event">Event cache</string> <string name="mega">Mega-event cache</string> <string name="earth">Earthcache</string> - <string name="cito">Cache in trash out event</string> + <string name="cito">Evento Cache in trash out</string> <string name="webcam">Webcam cache</string> <string name="virtual">Virtual cache</string> <string name="wherigo">Wherigo cache</string> <string name="lostfound">Lost & found</string> <string name="ape">Project ape cache</string> <string name="gchq">Groundspeak hq</string> - <string name="gps">GPS cache exhibit</string> - <string name="unknown">Unknown type</string> + <string name="gps">Fiera GPS cache</string> + <string name="unknown">Tipo sconosciuto</string> <!-- cache sizes --> <string name="cache_size_micro">micro</string> @@ -57,7 +57,7 @@ <!-- logs --> <string name="log_found">Trovata</string> <string name="log_dnf">Non trovata (DNF)</string> - <string name="log_note">Scrivi Nota</string> + <string name="log_note">Note</string> <string name="log_published">Pubblicata</string> <string name="log_enabled">Attiva</string> <string name="log_disabled">Non attiva</string> @@ -69,7 +69,7 @@ <string name="log_movecollection">Sposta in collezione</string> <string name="log_moveinventory">Sposta in inventario</string> <string name="log_maintained">Manutenzione effettuata</string> - <string name="log_maintenance_needed">Necessita manutenzione</string> + <string name="log_maintenance_needed">Richiede manutenzione</string> <string name="log_update">Coordinate aggiornate</string> <string name="log_archived">Archiviata</string> <string name="log_needs_archived">Necessita archiviazione</string> @@ -218,7 +218,7 @@ <string name="warn_search_help_tb">Inserisci il codice del trackable. Per esempio \"TB29QMZ\".</string> <string name="warn_log_text_fill">Prego, inserire del testo nel log.</string> <string name="warn_load_images">c:geo non riesce a caricare immagini.</string> - + <string name="warn_invalid_mapfile">La mappa selezionata non è mapsforge versione 0.2.4.\nMappa offline non disponibile.</string> <string name="info_log_posted">c:geo ha inviato il log con successo.</string> <string name="info_log_saved">c:geo ha salvato il log.</string> @@ -235,9 +235,10 @@ <string name="loc_sat">Sat</string> <string name="loc_trying">Localizzazione in corso</string> <string name="loc_no_addr">Indirizzo sconosciuto</string> + <string name="loc_gps_disabled">GPS non attivo</string> <!-- standard menu --> - <string name="menu_about">About c:geo</string> + <string name="menu_about">Info c:geo</string> <string name="menu_helpers">Programmi utili</string> <string name="menu_settings">Settaggi</string> <string name="menu_history">Cronologia</string> @@ -268,19 +269,19 @@ <string name="caches_on_map">Visualizza sulla mappa</string> <string name="caches_sort">Ordina</string> <string name="caches_sort_title">Ordina per</string> - <string name="caches_sort_distance">distanza</string> - <string name="caches_sort_difficulty">difficoltà</string> - <string name="caches_sort_terrain">terreno</string> - <string name="caches_sort_size">dimensione</string> - <string name="caches_sort_favorites">popolarità</string> - <string name="caches_sort_name">nome</string> + <string name="caches_sort_distance">Distanza</string> + <string name="caches_sort_difficulty">Difficoltà</string> + <string name="caches_sort_terrain">Terreno</string> + <string name="caches_sort_size">Dimensione</string> + <string name="caches_sort_favorites">Popolarità</string> + <string name="caches_sort_name">Nome</string> <string name="caches_sort_gccode">GC-code</string> - <string name="caches_sort_rating">voto</string> - <string name="caches_sort_vote">il tuo voto</string> - <string name="caches_sort_inventory">oggetti contenuti</string> - <string name="caches_sort_date">data</string> - <string name="caches_sort_finds">numero ritrovamenti</string> - <string name="caches_sort_state">stato</string> + <string name="caches_sort_rating">Voto</string> + <string name="caches_sort_vote">Il tuo voto</string> + <string name="caches_sort_inventory">Oggetti trackables</string> + <string name="caches_sort_date">Data</string> + <string name="caches_sort_finds">Numero ritrovamenti</string> + <string name="caches_sort_state">Stato</string> <string name="caches_select_mode">Modo Selezione</string> <string name="caches_select_mode_exit">Esci dal modo Selezione</string> <string name="caches_select_invert">Inverti selezione</string> @@ -298,20 +299,21 @@ <string name="caches_move_selected">Muovi le cache selezionate</string> <string name="caches_move_all">Muovi tutte</string> <string name="caches_map_locus">Locus</string> + <string name="caches_map_locus_export">Esporta in Locus</string> <string name="caches_recaptcha_title">reCAPTCHA</string> <string name="caches_recaptcha_explanation">Per cortesia riporta il testo letto sull\'immagine. È importante per scaricare le coordinate delle cache. È tuttavia opzionale e può essere disattivato nei settaggi.</string> <string name="caches_recaptcha_hint">Testo da immagine</string> <string name="caches_recaptcha_continue">Continua</string> <string name="caches_filter">Filtra</string> <string name="caches_filter_title">Filtra per</string> - <string name="caches_filter_size">dimensione</string> - <string name="caches_filter_type">tipo</string> - <string name="caches_filter_track">con oggetti trackables</string> - <string name="caches_filter_clear">senza filtri</string> + <string name="caches_filter_size">Dimensione</string> + <string name="caches_filter_type">Tipo</string> + <string name="caches_filter_track">Con oggetti trackables</string> + <string name="caches_filter_clear">Rimuovi filtri</string> <string name="caches_filter_size_title">Scegli dimensione</string> <string name="caches_filter_type_title">Scegli tipo</string> <string name="caches_filter_modified">Con coordinate modificate</string> - <string name="caches_exporting_fieldnote">Esportando le note…</string> + <string name="caches_exporting_fieldnote">Esportazione Field Notes…</string> <string name="caches_removing_from_history">Rimozione dalla cronologia…</string> <!-- caches lists --> @@ -378,12 +380,12 @@ <string name="init_other">Altre opzioni</string> <string name="init_skin">Tema chiaro\n(richiede riavvio di c:geo)</string> <string name="init_address">Visualizza indirizzo su pagina principale</string> - <string name="init_captcha">Visualizza CAPTCHA se necessario (solo membri Basic)</string> + <string name="init_captcha">Visualizza CAPTCHA se necessario (solo utenti base, non Premium)</string> <string name="init_useenglish">Usa sempre English in c:geo\n(richiede riavvio)</string> - <string name="init_exclude">Escludi le mie cache e quelle trovate</string> + <string name="init_exclude">Escludi le mie cache e quelle che ho già trovato</string> <string name="init_showwaypoints">Mostra waypoints sulla mappa</string> - <string name="init_showwaypoint_description">Se sulla mappa sono mostrate meno cache di quelle indicate, saranno mostrati anche i waypoints.</string> - <string name="init_disabled">Escludi cache non attive</string> + <string name="init_showwaypoint_description">Se sulla mappa sono mostrate meno cache di quelle indicate, saranno mostrati anche i relativi waypoints.</string> + <string name="init_disabled">Escludi cache disattivate</string> <string name="init_offline">Salva le mappe per uso offline</string> <string name="init_offline_wp">Salva i waypoints delle mappe per uso offline</string> <string name="init_save_log_img">Salva immagini contenute nei log</string> @@ -414,17 +416,21 @@ <string name="init_mapsource_select">Seleziona il tipo di mappa</string> <string name="init_select_mapfile">…</string> <string name="init_maptrail">Mostra la scia nella Mappa</string> - <string name="init_trackautovisit">Setta i miei oggetti trackables automaticamente su \"visit\" quando invio log</string> + <string name="init_trackautovisit">Setta i miei oggetti Trackables automaticamente su \"visit\" quando invio log</string> <string name="init_sigautoinsert">Inserisce la firma automaticamente</string> <string name="init_loaddirectionimg">Carica le immagini di direzione se necessario</string> <string name="init_default_navigation_tool">Navigatore preferito</string> - <string name="init_default_navigation_tool_description">Qui puoi scegliere il tuo strumento di navigazione preferito.</string> + <string name="init_default_navigation_tool_description">Qui puoi scegliere il tuo strumento di navigazione preferito. Sarà attivato cliccando l\'icona di navigazione vicino al titolo della cache.</string> <string name="init_default_navigation_tool_select">Scegli navigatore</string> <string name="init_default_navigation_tool_2_description">Qui puoi scegliere il tuo secondo navigatore preferito. Sarà attivato tenendo premuto l\'icona di navigazione vicino al titolo della cache.</string> + <string name="init_debug_title">Informazioni di Debug</string> + <string name="init_debug_note">c:geo può generare molte informazioni di debug. Per quanto queste informazioni non sono generalmente utili agli utenti di c:geo, gli sviluppatori potrebbero averne bisogno per analizzare un eventuale problema. In questo case, vi sarà chiesto di settare l\'opzione sottostante ed inviare il log.</string> + <string name="init_debug">Genera informazioni di debug</string> + <string name="init_sendToCgeo">Send to c:geo</string> <string name="init_sendToCgeo_name">Nome dispositivo:</string> - <string name="init_sendToCgeo_description">\"Send to c:geo\" permette di ricevere cache direttamente dal sito geocaching.com tramite un plugin speciale per Firefox o Chrome. Prima della registrazione leggere <a href="http://send2.cgeo.org/">http://send2.cgeo.org/</a>. È necessario registrare il dispositivo solo se intendi usare send2cgeo. C:geo funzionerà anche senza registrazione e senza send2cgeo.</string> + <string name="init_sendToCgeo_description">\"Send to c:geo\" permette di ricevere cache direttamente dal sito geocaching.com tramite un plugin speciale per Firefox o Chrome. Prima della registrazione leggere <a href="http://send2.cgeo.org/">http://send2.cgeo.org/</a>. È necessario registrare questo dispositivo solo se intendi usare send2cgeo. C:geo funzionerà anche senza questa registrazione e senza send2cgeo.</string> <string name="init_sendToCgeo_register">Richiedi registrazione</string> <string name="init_sendToCgeo_registering">Registrazione in corso a \"Send to c:geo\"…</string> <string name="init_sendToCgeo_register_ok">Registrazione terminata. Il tuo PIN code è ####. Usalo sul sito di c:geo per aggiungere il dispositivo al tuo browser Firefox o Chrome.</string> @@ -485,7 +491,7 @@ <item quantity="other">%d Waypoint</item> </plurals> <string name="cache_waypoints_add">Aggiungi waypoint</string> - <string name="cache_hint">Aiuto</string> + <string name="cache_hint">Aiuto (spoiler)</string> <string name="cache_logs">Logbook</string> <string name="cache_logsfriends">Log amici</string> <string name="cache_dialog_loading_details">Caricamento dettagli cache…</string> @@ -554,7 +560,7 @@ <string name="cache_spoiler_images_loading">Caricamento immagini spoiler…</string> <string name="cache_log_types">Tipi di Log</string> <string name="cache_coordinates_no">Questa cache non ha coordinate.</string> - <string name="cache_export_fieldnote">Esporta le note (Field notes)</string> + <string name="cache_export_fieldnote">Esporta le note (Field Notes)</string> <string name="cache_clear_history">Cancella cronologia</string> <string name="cache_remove_from_history">Rimuovi dalla cronologia</string> <string name="cache_license">Licenza</string> @@ -573,6 +579,7 @@ <!-- gpx --> <string name="gpx_import_loading_caches">Caricamento caches da file GPX</string> <string name="gpx_import_loading_waypoints">Caricamento file waypoints</string> + <string name="gpx_import_store_static_maps">Salvataggio mappe statiche</string> <string name="gpx_import_storing">Salvataggio delle cache nel database</string> <string name="gpx_import_caches_imported">cache importate</string> <string name="gpx_import_static_maps_skipped">Download mappe statiche interrotto</string> @@ -641,19 +648,28 @@ <!-- map --> <string name="map_map">Mappa</string> - <string name="map_live">Mappa online</string> + <string name="map_live">Mappa Live</string> <string name="map_view_map">Scegli mappa</string> <string name="map_trail_show">Mostra scia</string> <string name="map_trail_hide">Nasconde scia</string> - <string name="map_circles_show">Mostra cerchie</string> - <string name="map_circles_hide">Nascondi cerchie</string> + <string name="map_circles_show">Mostra area cache</string> + <string name="map_circles_hide">Nascondi area cache</string> <string name="map_live_enable">Attiva online</string> <string name="map_live_disable">Disattiva online</string> <string name="map_static_title">Mappe statiche</string> <string name="map_static_loading">Caricamento mappe statiche…</string> <string name="map_token_err">Dato che c:geo riesce a scaricare solo dati parziali, le coordinate delle cache potrebbero non essere accurate.</string> - <string name="map_as_list">Mostra come lista</string> - + <string name="map_as_list">Mostra lista cache</string> + <string name="map_strategy">Strategia</string> + <string name="map_strategy_title">Strategia mappa Live</string> + <string name="map_strategy_fastest">La più veloce</string> + <string name="map_strategy_fast">Veloce</string> + <string name="map_strategy_auto">In base alla tua velocità</string> + <string name="map_strategy_detailed">Dettagliata</string> + <string name="live_map_notification">Nella nuova Mappa Live le coordinate potrebbero non essere sempre precise. Coordinate possibilmente imprecise sono marcate da un cerchio arancione.\nAprendo i dettagli della cache o salvando la cache per uso offline farà calcolare sempre coordinate precise.\n\nInformazioni addizionali su tutte le modifiche si possono trovare nel menu \"Info c:geo\" sulla pagina principale di questa app.</string> + <string name="live_map_note_close">Chiudi</string> + <string name="live_map_note_dontshow">Non mostrare ancora</string> + <!-- search --> <string name="search_bar_hint">Cerca caches</string> <string name="search_bar_desc">Cache (GC-code, parole chiave), Oggetti trackables (TB-code)</string> @@ -736,7 +752,7 @@ <string name="helper_gpsstatus_title">GPS Status</string> <string name="helper_gpsstatus_description">Puoi usare il radar di questa applicazione con c:geo. Offre inoltre molte informazioni addizionali legate al GPS.</string> <string name="helper_bluetoothgps_title">Bluetooth GPS</string> - <string name="helper_bluetoothgps_description">Permette di utilizzare un GPS esterno, garantendo maggiore precisione, migliore ricezione e prolungando la durata della batteria del telefono.</string> + <string name="helper_bluetoothgps_description">Permette di utilizzare un GPS esterno, garantendo maggiore precisione, migliore ricezione e prolungando la durata della batteria del dispositivo.</string> <string name="helper_barcode_title">Barcode Scanner</string> <string name="helper_barcode_description">Ci sono script Greasemonkey e siti web che consentono di visualizzare un geocode come codice a barre. Con questa app c:geo può leggere il geocode direttamente dallo schermo del tuo computer.</string> @@ -744,6 +760,18 @@ <string name="addon_missing_title">Add-On mancante</string> <string name="addon_download_prompt">Scaricalo ora da Google Play.</string> + <!-- export --> + <string name="export">Esporta</string> + <string name="export_as">Esporta come…</string> + <string name="export_exportedto">esportato in</string> + <string name="export_failed">Esportazione fallita</string> + <string name="export_fieldnotes">Field Notes</string> + <string name="export_fieldnotes_info">Field Notes saranno esportate in /sdcard/field-notes con data e ora corrente nel nome file.</string> + <string name="export_fieldnotes_upload">Carica su geocaching.com</string> + <string name="export_fieldnotes_uploading">Caricamento…</string> + <string name="export_fieldnotes_onlynew">Solo quelli nuovi rispetto all\'ultima esportazione</string> + <string name="export_gpx">GPX</string> + <!-- attributes (permissions -> allowed, not allowed) --> <string name="attribute_dogs_yes">Cani permessi</string> <string name="attribute_dogs_no">Cani NON permessi</string> @@ -759,8 +787,8 @@ <string name="attribute_snowmobiles_no">Motoslitte NON permesse</string> <string name="attribute_horses_yes">Cavalli permessi</string> <string name="attribute_horses_no">Cavalli NON permessi</string> - <string name="attribute_campfires_yes">Piccoli fuochi permessi</string> - <string name="attribute_campfires_no">Piccoli fuochi NON permessi</string> + <string name="attribute_campfires_yes">Fuochi da campo permessi</string> + <string name="attribute_campfires_no">Fuochi da campo NON permessi</string> <string name="attribute_rv_yes">Camper/roulotte permessi</string> <string name="attribute_rv_no">Camper/roulotte NON permessi</string> @@ -795,7 +823,7 @@ <string name="attribute_field_puzzle_no">Terreno non accidentato</string> <string name="attribute_nightcache_yes">Cache notturna</string> <string name="attribute_nightcache_no">Cache non notturna</string> - <string name="attribute_parkngrab_yes">Parcheggio vicino</string> + <string name="attribute_parkngrab_yes">Parcheggia e trova!</string> <string name="attribute_parkngrab_no">Parcheggio lontano</string> <string name="attribute_abandonedbuilding_yes">Struttura abbandonata</string> <string name="attribute_abandonedbuilding_no">Struttura non abbandonata</string> @@ -905,6 +933,8 @@ <string name="go4cache_heading_to">Puntando a</string> <plurals name="go4cache_time_minutes"> <item quantity="one">un minuto fa</item> - <item quantity="other">%d minuti fa</item> - </plurals> + <item quantity="other">%d minuti fa</item> + </plurals> + + <string name="clipboard_copy_ok">Copiato nella clipboard</string> </resources> diff --git a/main/res/values-sk/strings.xml b/main/res/values-sk/strings.xml index c4865f9..33a5610 100644 --- a/main/res/values-sk/strings.xml +++ b/main/res/values-sk/strings.xml @@ -235,6 +235,7 @@ <string name="loc_sat">sat</string> <string name="loc_trying">zisťovanie pozície</string> <string name="loc_no_addr">neznáma adresa</string> + <string name="loc_gps_disabled">GPS zakázaná</string> <!-- standard menu --> <string name="menu_about">O aplikácii</string> @@ -298,6 +299,7 @@ <string name="caches_move_selected">Presunúť vybrané</string> <string name="caches_move_all">Presunúť všetky</string> <string name="caches_map_locus">Locus</string> + <string name="caches_map_locus_export">Exportovať do Locus</string> <string name="caches_recaptcha_title">reCAPTCHA</string> <string name="caches_recaptcha_explanation">Opíšte text z obrázku. Je to dôležité pre stiahnutie súradníc skrýš. Túto vlastnosť je možné vypnúť v Nastaveniach.</string> <string name="caches_recaptcha_hint">Text z obrázku</string> @@ -421,6 +423,9 @@ <string name="init_default_navigation_tool_description">Môžete si vybrať preferovaný nástroj pre navigáciu.</string> <string name="init_default_navigation_tool_select">Vyberte nástroj</string> <string name="init_default_navigation_tool_2_description">Môžete vybrať druhý preferovaný nástroj pre navigáciu. Spustíte ho dlhým držaním ikony navigácia vedľa názvu skrýše.</string> + <string name="init_debug_title">Ladiace informácie</string> + <string name="init_debug_note">c:geo môže vytvárať generovať množstvo ladiacich informácií. Aj keď tieto informácie nie sú pre používateľov zvyčajne použiteľné, vývojári ich môžu potrebovať pre analýzu chyby. V tomto prípade vás požiadajú začiarknuť políčko nižšie a poslať vytvorený log súbor.</string> + <string name="init_debug">Generovanie ladiacich informácií</string> <!-- map sources --> <string name="map_source_google_map">Google: Mapa</string> @@ -584,8 +589,10 @@ <string name="gpx_import_store_static_maps">Ukladanie statických máp</string> <string name="gpx_import_storing">Zapisovanie skrýš do databázy\nZapísané:</string> <string name="gpx_import_caches_imported">skrýše importované</string> - <string name="gpx_import_title">Import GPX</string> + <string name="gpx_import_static_maps_skipped">Preberanie statických máp zrušené</string> + <string name="gpx_import_title_static_maps">Uloženie statických máp</string> <string name="gpx_import_title_reading_file">Čítanie súboru</string> + <string name="gpx_import_title">Import GPX</string> <string name="gpx_import_title_caches_imported">Výsledok</string> <string name="gpx_import_title_caches_import_failed">Import zlyhal</string> <string name="gpx_import_error_io">Nedá sa prečítať súbor</string> @@ -636,6 +643,13 @@ <string name="waypoint_coordinate_formats_plain">Iba text</string> + <!-- distance units --> + <string name="unit_m">m</string> + <string name="unit_km">km</string> + <string name="unit_ft">ft</string> + <string name="unit_yd">yd</string> + <string name="unit_mi">mi</string> + <!-- visit --> <string name="visit_tweet">informovať o nájdení na Twitteri</string> @@ -659,6 +673,10 @@ <string name="map_strategy_fast">Rýchla</string> <string name="map_strategy_auto">Podľa rýchlosti</string> <string name="map_strategy_detailed">Podrobná</string> + <string name="live_map_notification">Na novej aktívnej mape nemusia byť súradnice vždy presné. Súradnice, ktoré môžu byť nepresné, sú označené oranžovým krúžkom.\nPo otvorení detailu skrýše, alebo po jej uložení pre použitie offline, sú získané vždy presné súradnice.\n\nViac informácií ku všetkým zmenám sa nachádzajú na stránke „O c:geo“ v aplikácii.</string> + <string name="live_map_note_close">Zatvoriť</string> + <string name="live_map_note_dontshow">Nabudúce nezobrazovať</string> + <!-- search --> <string name="search_bar_hint">Hľadanie skrýš</string> diff --git a/main/res/values-sv/strings.xml b/main/res/values-sv/strings.xml index e32a818..ed1d696 100644 --- a/main/res/values-sv/strings.xml +++ b/main/res/values-sv/strings.xml @@ -218,7 +218,7 @@ <string name="warn_search_help_tb">Ange koden för en trackable. Tex \"TB29QMZ\".</string> <string name="warn_log_text_fill">Vänligen skriv någon text i loggen.</string> <string name="warn_load_images">Tyvärr misslyckades c:geo att ladda ner bilder.</string> - + <string name="warn_invalid_mapfile">Den valda kartfilen är inte en korrekt Mapsforge version 0.2.4 kartfile.\nOffline kartan är inte tillgänglig.</string> <string name="info_log_posted">c:geo har postat din logg.</string> <string name="info_log_saved">c:geo har sparat din logg.</string> @@ -235,6 +235,7 @@ <string name="loc_sat">Sat</string> <string name="loc_trying">Försöker hitta plats</string> <string name="loc_no_addr">Okänd adress</string> + <string name="loc_gps_disabled">GPS avstängd</string> <!-- standard menu --> <string name="menu_about">Om c:geo</string> @@ -422,6 +423,9 @@ <string name="init_default_navigation_tool_description">Här kan du välja ditt förvalda navigeringsprogram.</string> <string name="init_default_navigation_tool_select">Välj program</string> <string name="init_default_navigation_tool_2_description">Här kan du välja ditt andra förvalda navigeringsprogram. Det kan aktiveras genom att klicka länge på navigationsikonen i listen överst i en cachebeskrivning.</string> + <string name="init_debug_title">Debug information</string> + <string name="init_debug_note">c:geo kan generera mycket debug information. Denna information är normalt inte användbar för användare av c:geo. Vid eventuella problem kan dock utvecklare behöva den här informationen för att analysera problemet. Om så är fallet kommer du att ombedjas att markera rutan nedan och sedan skicka loggfilen till dem.</string> + <string name="init_debug">Generera debug information</string> <!-- map sources --> <string name="map_source_google_map">Google: Map</string> @@ -662,6 +666,9 @@ <string name="map_strategy_fast">Snabbt</string> <string name="map_strategy_auto">Hastighetsberoende (gps)</string> <string name="map_strategy_detailed">Exakta positioner</string> + <string name="live_map_notification">I den nya Live kartan så är koordinaterna inte alltid exakta. En cache med potentiellt oexakta koordinater är markerad med en orange cirkel.\nGenom att visa detaljer för cachen eller genom att spara cachen för offline kommer alltid exakta koordinater att hämtas.\n\nMer information om alla förändringar finns på \"Om c:geo\" sidan, som kan nås från c:geo\'s startsida.</string> + <string name="live_map_note_close">Stäng</string> + <string name="live_map_note_dontshow">Visa inte mer</string> <!-- search --> <string name="search_bar_hint">Sök cache/TB</string> @@ -745,7 +752,7 @@ <string name="helper_gpsstatus_title">GPS Status</string> <string name="helper_gpsstatus_description">Erbjuder många GPS-relaterade funktioner. Radar-funktionen i detta program kan användas i c:geo.</string> <string name="helper_bluetoothgps_title">Bluetooth GPS</string> - <string name="helper_bluetoothgps_description">Gör det möjligt att använda en extern GPS enhet för att få bättre mottagning, mer exakt position och kan även spara på batteriet i telefonen.</string> + <string name="helper_bluetoothgps_description">Gör det möjligt att använda en extern GPS enhet för att få mer exakt position och även spara på enhetens batteri.</string> <string name="helper_barcode_title">Streckkodsläsare</string> <string name="helper_barcode_description">Det finns Greasemonkey-script och hemsidor som visar GC-koder som streckkoder/QR-koder. Med den här appen kan c:geo scanna in GC-koden direkt från skärmen på din dator.</string> @@ -753,6 +760,18 @@ <string name="addon_missing_title">Tillägg saknas</string> <string name="addon_download_prompt">Hämta det nu från Google Play.</string> + <!-- export --> + <string name="export">Exportera</string> + <string name="export_as">Exportera som…</string> + <string name="export_exportedto">exporterat till</string> + <string name="export_failed">Exporteringen misslyckades</string> + <string name="export_fieldnotes">Field Notes</string> + <string name="export_fieldnotes_info">Field Notes kommer att exporteras till /sdcard/field-notes med aktuellt datum och tid som filnamn.</string> + <string name="export_fieldnotes_upload">Uppladdat till geocaching.com</string> + <string name="export_fieldnotes_uploading">Laddar upp…</string> + <string name="export_fieldnotes_onlynew">Bara sedan senaste exporteringen</string> + <string name="export_gpx">GPX</string> + <!-- next things --> <string name="legal_note">För att använda tjänster hos Geocaching.com, måste regler och villkor i <a href="http://www.geocaching.com/about/termsofuse.aspx">Groundspeaks avtal</a> godkännas.</string> <string name="author">Upphovsman: <a href="http://carnero.cc/">carnero</a></string> diff --git a/main/res/values/attrs.xml b/main/res/values/attrs.xml index 187d4cb..0f22ee4 100644 --- a/main/res/values/attrs.xml +++ b/main/res/values/attrs.xml @@ -31,4 +31,6 @@ <!-- others --> <attr name="compass" format="integer" /> + <attr name="progressSpinnerLarge" format="integer" /> + </resources> diff --git a/main/res/values/strings.xml b/main/res/values/strings.xml index 9af5294..ca15692 100644 --- a/main/res/values/strings.xml +++ b/main/res/values/strings.xml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="UTF-8"?> +<?xml version="1.0" encoding="UTF-8"?> <resources> <string name="app_name">c:geo</string> <string name="app_name_compass">c:geo compass</string> @@ -218,7 +218,7 @@ <string name="warn_search_help_tb">Enter the code for a trackable. For example \"TB29QMZ\".</string> <string name="warn_log_text_fill">Please fill in text for your log.</string> <string name="warn_load_images">c:geo failed to load images.</string> - + <string name="warn_invalid_mapfile">The selected map file is not a valid mapsforge version 0.2.4 map file.\nOffline maps are not available.</string> <string name="info_log_posted">c:geo successfully submitted the log.</string> <string name="info_log_saved">c:geo successfully saved the log.</string> @@ -235,6 +235,7 @@ <string name="loc_sat">Sat</string> <string name="loc_trying">Trying to Locate</string> <string name="loc_no_addr">Unknown address</string> + <string name="loc_gps_disabled">GPS disabled</string> <!-- standard menu --> <string name="menu_about">About c:geo</string> @@ -298,6 +299,7 @@ <string name="caches_move_selected">Move selected</string> <string name="caches_move_all">Move all</string> <string name="caches_map_locus">Locus</string> + <string name="caches_map_locus_export">Export to Locus</string> <string name="caches_recaptcha_title">reCAPTCHA</string> <string name="caches_recaptcha_explanation">Please, write text from image. It\'s important to download coordinates of caches. It\'s optional and can be switched off in Settings.</string> <string name="caches_recaptcha_hint">Text from image</string> @@ -421,7 +423,10 @@ <string name="init_default_navigation_tool_description">Here you can select your preferred navigation tool.</string> <string name="init_default_navigation_tool_select">Select tool</string> <string name="init_default_navigation_tool_2_description">Here you can select your second preferred navigation tool. It\'s activated by long clicking the navigation icon next to the title of the cache.</string> - + <string name="init_debug_title">Debug information</string> + <string name="init_debug_note">c:geo can generate a lot of debugging information. While this information is generally not useful for c:geo users, developers may need to generate this information in order to analyze a bug. In this case, they will ask you to check the box below and send them the log file.</string> + <string name="init_debug">Generate debug information</string> + <!-- map sources --> <string-array name="map_sources"> <item>@string/map_source_google_map</item> @@ -774,14 +779,26 @@ <string name="helper_gpsstatus_title">GPS Status</string> <string name="helper_gpsstatus_description">You can use radar from this application with c:geo. It also offers a lot of other GPS-related information.</string> <string name="helper_bluetoothgps_title">Bluetooth GPS</string> - <string name="helper_bluetoothgps_description">Allows you to use external GPS device to get better reception, more precise location and can spare battery of your phone.</string> + <string name="helper_bluetoothgps_description">Allows you to use an external GPS receiver to get more precise location and can spare battery of your device.</string> <string name="helper_barcode_title">Barcode Scanner</string> <string name="helper_barcode_description">There are Greasemonkey scripts and websites which allow to display a geocode as barcode. With this app c:geo can read that geocode directly from the screen of your computer.</string> <!-- add-ons --> <string name="addon_missing_title">Missing Add-On</string> <string name="addon_download_prompt">Get it now from Google Play.</string> - + + <!-- export --> + <string name="export">Export</string> + <string name="export_as">Export as…</string> + <string name="export_exportedto">exported to</string> + <string name="export_failed">Exported failed</string> + <string name="export_fieldnotes">Field Notes</string> + <string name="export_fieldnotes_info">Field Notes will be exported into /sdcard/field-notes with current date and time as file name.</string> + <string name="export_fieldnotes_upload">Upload to geocaching.com</string> + <string name="export_fieldnotes_uploading">Uploading…</string> + <string name="export_fieldnotes_onlynew">Only since last export</string> + <string name="export_gpx">GPX</string> + <!-- attributes (permissions -> allowed, not allowed) --> <string name="attribute_dogs_yes">Dogs allowed</string> <string name="attribute_dogs_no">Dogs not allowed</string> @@ -945,6 +962,8 @@ <item quantity="one">one Minute ago</item> <item quantity="other">%d Minutes ago</item> </plurals> + + <string name="clipboard_copy_ok">Copied to clipboard</string> <!-- ====== please, do not translate (and include in translation) things below this line ====== --> @@ -979,6 +998,7 @@ · Pascal (localization NL)\n · Pavol Babinčák (code, loc. SK)\n · Peter (localization HU)\n + · <a href="https://github.com/Portree-Kid">Portree Kid</a> (code)\n · Rainer S. (code)\n · Ray (code, loc. JA)\n · <a href="http://seromenho.com/">Ricardo Seromenho</a> (localization PT)\n @@ -986,7 +1006,7 @@ · <a href="http://www.blueskysoftware.it/">RomNexus6</a> (localization IT)\n · <a href="http://www.sammyshp.de/">SammysHP</a> (code, localization DE)\n · <a href="http://www.rfc1149.net/sam.html">Samuel Tardieu</a> (code, localization FR)\n - · serenity (localization FR)\n + · serenity (localization DE)\n · Shan, a.k.a. ShakurNO (localization NO)\n · Shizo87 (tester)\n · stephanme/Geoteufel (code)\n @@ -1003,51 +1023,22 @@ <!-- changelog --> <string name="changelog">\n - <b>27.04.2012</b>\n\n - <b>Bugfixing:</b>\n - · Distance information in nearby search corrected\n - \n - <b>24.04.2012</b>\n\n - <b>Bugfixing:</b>\n - · Adapt to gc.com changes\n - · Some small bugs fixed\n - \n - <b>02.04.2012</b>\n\n + <b>Next release</b>\n\n <b>New Features/Functions:</b>\n - · Live Map re-implementation with selectable strategy:\n - Fastest: Load approximated cache coords only\n - Fast: Same as fastest but try to identify the cache type\n - Detailed: Same as fast but load details for 20 caches around your position\n - Speed dependent: Automatic switch from detailed to fast at 30kmh\n - · New markers in map and partly in lists:\n - Personal Note available(Pen icon)\n - Modified coordinates available (Flagpost icon)\n - Caches is saved on device (Disk icon)\n - Offline log is stored (Red smiley)\n - Cache coords are approximated (Encircled in Orange)\n - · Calendar operations moved to calendar add-on (Android Market)\n - c:geo doesn\'t require calendar permissions anymore\n - · Login status and find count shown on main screen\n - · Copy, translate, forward with long press for cache- and log-text\n - · Two preferred navigation tools selectable\n - · Type of waypoint can be selected on creation\n - · Day of week shown for event-caches\n - · Static maps can be saved for waypoints\n - · Static maps saved while importing GPX-files\n - · Quick access to navigation in waypoints\n\n - <b>Bugfixing:</b>\n - · Deletion of outdated caches improved\n - · Changed internal caching for better performance\n - · Caches with modified coords are displayed at the modified coords\n - · Improved consistency for offline logging\n - · Removed OSM:Osmarender as it is no longer available\n - · Find-count not working in signature\n - · Keep screen on while viewing cache-lists\n - · TB-icons now shown in correct size\n - · Cache count on live map corrected\n - · Improved GPX import for non-GC GPX files\n + · Export caches as GPX file\n + · Field notes can now be uploaded to the website\n + · Filter for D/T in lists\n + · Allow close of popup by click on map\n \n - <a href="https://github.com/cgeo/c-geo-opensource/issues?milestone=3&state=closed">Detailed list of all changes</a>\n + <b>Bugfixing:</b>\n + · Static maps download for waypoints now off by default\n + · Waypoints on map do no longer disappear when moving map\n + · Static map download improved\n + · Distance information in nearby search corrected\n + · Adaption to changes on geocaching.com\n + · Warning displayed for incompatible map file\n + \n + <a href="https://github.com/cgeo/c-geo-opensource/issues?milestone=6&state=closed">Detailed list of all changes</a>\n \n <b>Known Limitations/Bugs:</b>\n · Live map:\n @@ -1055,8 +1046,6 @@ Be aware: If navigation is started directly from live map it may also use the approximated coords!\n In fast mode the cache type might be wrong in rare cases\n Fast mode only detectes Tradi, Multi, Mystery, Event caches\n - Waypoints on map might disappear when moving the map\n - (Workaround: Increase waypoint limit in settings)\n · Other:\n Log images with huge size will cause a long loading time\n OSM:Offline does only support map-files with version 0.2.4\n\n\n diff --git a/main/res/values/themes.xml b/main/res/values/themes.xml index ba07eb2..75986de 100644 --- a/main/res/values/themes.xml +++ b/main/res/values/themes.xml @@ -48,6 +48,8 @@ <item name="favourite_g">@drawable/favourite_background_green_dark</item> <item name="close">@drawable/map_close_dark</item> <item name="log_img_icon">@drawable/log_img_dark</item> + + <item name="progressSpinnerLarge">@android:style/Widget.ProgressBar.Large</item> <!-- own values: other --> <item name="compass">0</item> @@ -81,7 +83,9 @@ <item name="close">@drawable/map_close_light</item> <item name="log_img_icon">@drawable/log_img_light</item> - <!-- own values: other --> + <item name="progressSpinnerLarge">@android:style/Widget.ProgressBar.Large.Inverse</item> + + <!-- own values: other --> <item name="compass">1</item> </style> @@ -113,7 +117,9 @@ <item name="close">@drawable/map_close_dark</item> <item name="log_img_icon">@drawable/log_img_dark</item> - <!-- own values: other --> + <item name="progressSpinnerLarge">@android:style/Widget.ProgressBar.Large</item> + + <!-- own values: other --> <item name="compass">0</item> </style> </resources> diff --git a/main/src/cgeo/geocaching/AdressListActivity.java b/main/src/cgeo/geocaching/AdressListActivity.java index 5357e9a..a67f4a2 100644 --- a/main/src/cgeo/geocaching/AdressListActivity.java +++ b/main/src/cgeo/geocaching/AdressListActivity.java @@ -2,6 +2,7 @@ package cgeo.geocaching; import cgeo.geocaching.activity.AbstractListActivity; import cgeo.geocaching.ui.AddressListAdapter; +import cgeo.geocaching.utils.Log; import org.apache.commons.collections.CollectionUtils; @@ -10,7 +11,6 @@ import android.location.Address; import android.location.Geocoder; import android.os.AsyncTask; import android.os.Bundle; -import android.util.Log; import java.util.List; import java.util.Locale; @@ -49,7 +49,7 @@ public class AdressListActivity extends AbstractListActivity { try { return geocoder.getFromLocationName(keyword, 20); } catch (Exception e) { - Log.e(Settings.tag, "AdressListActivity.doInBackground", e); + Log.e("AdressListActivity.doInBackground", e); return null; } } @@ -57,18 +57,13 @@ public class AdressListActivity extends AbstractListActivity { @Override protected void onPostExecute(final List<Address> addresses) { waitDialog.dismiss(); - try { - if (CollectionUtils.isEmpty(addresses)) { - showToast(res.getString(R.string.err_search_address_no_match)); - finish(); - return; - } else { - for (Address address : addresses) { - adapter.add(address); // don't use addAll, it's only available with API >= 11 - } + if (CollectionUtils.isNotEmpty(addresses)) { + for (final Address address : addresses) { + adapter.add(address); // don't use addAll, it's only available with API >= 11 } - } catch (Exception e) { - Log.e(Settings.tag, "AdressListActivity.onPostExecute", e); + } else { + showToast(res.getString(R.string.err_search_address_no_match)); + finish(); } } diff --git a/main/src/cgeo/geocaching/CacheCache.java b/main/src/cgeo/geocaching/CacheCache.java index a2b5324..1ada88c 100644 --- a/main/src/cgeo/geocaching/CacheCache.java +++ b/main/src/cgeo/geocaching/CacheCache.java @@ -1,10 +1,18 @@ package cgeo.geocaching; import cgeo.geocaching.cgData.StorageLocation; -import cgeo.geocaching.utils.LeastRecentlyUsedCache; +import cgeo.geocaching.connector.gc.GCBase; +import cgeo.geocaching.enumerations.CacheType; +import cgeo.geocaching.geopoint.Viewport; +import cgeo.geocaching.utils.LeastRecentlyUsedMap; +import cgeo.geocaching.utils.LeastRecentlyUsedMap.RemoveHandler; +import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; +import java.util.HashSet; +import java.util.Set; + /** * Cache for Caches. Every cache is stored in memory while c:geo is active to * speed up the app and to minimize network request - which are slow. @@ -14,12 +22,13 @@ import org.apache.commons.lang3.StringUtils; public class CacheCache { private static final int MAX_CACHED_CACHES = 1000; - final private LeastRecentlyUsedCache<String, cgCache> cachesCache; + final private LeastRecentlyUsedMap<String, cgCache> cachesCache; private static CacheCache instance = null; private CacheCache() { - cachesCache = new LeastRecentlyUsedCache<String, cgCache>(MAX_CACHED_CACHES); + cachesCache = new LeastRecentlyUsedMap.LruCache<String, cgCache>(MAX_CACHED_CACHES); + cachesCache.setRemoveHandler(new CacheRemoveHandler()); } public static CacheCache getInstance() { @@ -74,9 +83,33 @@ public class CacheCache { return cachesCache.get(geocode); } + public Set<String> getInViewport(final Viewport viewport, final CacheType cacheType) { + final Set<String> geocodes = new HashSet<String>(); + for (final cgCache cache : cachesCache.values()) { + if (cache.getCoords() == null) { + // FIXME: this kludge must be removed, it is only present to help us debug the cases where + // caches contain null coordinates. + Log.e("CacheCache.getInViewport: got cache with null coordinates: " + cache.getGeocode()); + continue; + } + if ((CacheType.ALL == cacheType || cache.getType() == cacheType) && viewport.contains(cache)) { + geocodes.add(cache.getGeocode()); + } + } + return geocodes; + } + @Override public String toString() { return StringUtils.join(cachesCache.keySet(), ' '); } + private static class CacheRemoveHandler implements RemoveHandler<cgCache> { + + @Override + public void onRemove(cgCache removed) { + GCBase.removeFromTileCache(removed); + } + } + } diff --git a/main/src/cgeo/geocaching/CacheDetailActivity.java b/main/src/cgeo/geocaching/CacheDetailActivity.java index 1be9ed6..54943f9 100644 --- a/main/src/cgeo/geocaching/CacheDetailActivity.java +++ b/main/src/cgeo/geocaching/CacheDetailActivity.java @@ -7,8 +7,9 @@ import cgeo.geocaching.apps.cache.GeneralAppsFactory; import cgeo.geocaching.apps.cache.navi.NavigationAppFactory; import cgeo.geocaching.connector.ConnectorFactory; import cgeo.geocaching.connector.IConnector; +import cgeo.geocaching.connector.gc.GCParser; +import cgeo.geocaching.enumerations.CacheAttribute; import cgeo.geocaching.enumerations.LoadFlags; -import cgeo.geocaching.enumerations.LoadFlags.RemoveFlag; import cgeo.geocaching.enumerations.LoadFlags.SaveFlag; import cgeo.geocaching.enumerations.LogType; import cgeo.geocaching.enumerations.WaypointType; @@ -16,7 +17,6 @@ import cgeo.geocaching.geopoint.GeopointFormatter; import cgeo.geocaching.geopoint.HumanDistance; import cgeo.geocaching.geopoint.IConversion; import cgeo.geocaching.network.HtmlImage; -import cgeo.geocaching.network.Network; import cgeo.geocaching.network.Parameters; import cgeo.geocaching.ui.DecryptTextClickListener; import cgeo.geocaching.ui.Formatter; @@ -24,12 +24,12 @@ import cgeo.geocaching.utils.BaseUtils; import cgeo.geocaching.utils.CancellableHandler; import cgeo.geocaching.utils.ClipboardUtils; import cgeo.geocaching.utils.CryptUtils; +import cgeo.geocaching.utils.Log; import cgeo.geocaching.utils.TranslationUtils; import cgeo.geocaching.utils.UnknownTagsHandler; import com.viewpagerindicator.TitlePageIndicator; import com.viewpagerindicator.TitleProvider; - import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringEscapeUtils; import org.apache.commons.lang3.StringUtils; @@ -39,6 +39,8 @@ import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; import android.graphics.Bitmap; import android.graphics.Typeface; import android.graphics.drawable.BitmapDrawable; @@ -61,7 +63,6 @@ import android.text.method.LinkMovementMethod; import android.text.style.StrikethroughSpan; import android.text.style.StyleSpan; import android.util.DisplayMetrics; -import android.util.Log; import android.view.ContextMenu; import android.view.Menu; import android.view.MenuItem; @@ -122,7 +123,6 @@ public class CacheDetailActivity extends AbstractActivity { private static final String CALENDAR_ADDON_URI = "market://details?id=cgeo.calendar"; - private cgGeo geolocation; private cgCache cache; private final Progress progress = new Progress(); private SearchResult search; @@ -186,10 +186,6 @@ public class CacheDetailActivity extends AbstractActivity { setContentView(R.layout.cacheview); setTitle(res.getString(R.string.cache)); - if (geolocation == null) { - geolocation = app.startGeo(locationUpdater); - } - String geocode = null; String guid = null; String name = null; @@ -220,9 +216,9 @@ public class CacheDetailActivity extends AbstractActivity { String uriQuery = uri.getQuery(); if (uriQuery != null) { - Log.i(Settings.tag, "Opening URI: " + uriHost + uriPath + "?" + uriQuery); + Log.i("Opening URI: " + uriHost + uriPath + "?" + uriQuery); } else { - Log.i(Settings.tag, "Opening URI: " + uriHost + uriPath); + Log.i("Opening URI: " + uriHost + uriPath); } if (uriHost.contains("geocaching.com")) { @@ -328,9 +324,7 @@ public class CacheDetailActivity extends AbstractActivity { public void onResume() { super.onResume(); - if (geolocation == null) { - geolocation = app.startGeo(locationUpdater); - } + app.addGeoObserver(locationUpdater); if (refreshOnResume) { notifyDataSetChanged(); refreshOnResume = false; @@ -339,19 +333,11 @@ public class CacheDetailActivity extends AbstractActivity { @Override public void onDestroy() { - if (geolocation != null) { - geolocation = app.removeGeo(); - } - super.onDestroy(); } @Override public void onStop() { - if (geolocation != null) { - geolocation = app.removeGeo(); - } - if (cache != null) { cache.setChangeNotificationHandler(null); } @@ -361,9 +347,7 @@ public class CacheDetailActivity extends AbstractActivity { @Override public void onPause() { - if (geolocation != null) { - geolocation = app.removeGeo(); - } + app.deleteGeoObserver(locationUpdater); super.onPause(); } @@ -468,6 +452,7 @@ public class CacheDetailActivity extends AbstractActivity { switch (index) { case MENU_FIELD_COPY: ClipboardUtils.copyToClipboard(clickedItemText); + showToast(res.getString(R.string.clipboard_copy_ok)); return true; case MENU_FIELD_TRANSLATE: TranslationUtils.startActivityTranslate(this, Locale.getDefault().getLanguage(), clickedItemText.toString()); @@ -486,15 +471,16 @@ public class CacheDetailActivity extends AbstractActivity { } break; - case CONTEXT_MENU_WAYPOINT_EDIT: - if (cache.hasWaypoints() && index < cache.getWaypoints().size()) { - final cgWaypoint waypoint = cache.getWaypoints().get(index); + case CONTEXT_MENU_WAYPOINT_EDIT: { + final cgWaypoint waypoint = cache.getWaypoint(index); + if (waypoint != null) { Intent editIntent = new Intent(this, cgeowaypointadd.class); editIntent.putExtra("waypoint", waypoint.getId()); startActivity(editIntent); refreshOnResume = true; } break; + } case CONTEXT_MENU_WAYPOINT_DUPLICATE: if (cache.duplicateWaypoint(index)) { app.saveCache(cache, EnumSet.of(SaveFlag.SAVE_DB)); @@ -510,14 +496,14 @@ public class CacheDetailActivity extends AbstractActivity { case CONTEXT_MENU_WAYPOINT_DEFAULT_NAVIGATION: { final cgWaypoint waypoint = cache.getWaypoint(index); if (waypoint != null) { - NavigationAppFactory.startDefaultNavigationApplication(geolocation, this, null, waypoint, null); + NavigationAppFactory.startDefaultNavigationApplication(app.currentGeo(), this, null, waypoint, null); } } break; case CONTEXT_MENU_WAYPOINT_NAVIGATE: { final cgWaypoint waypoint = cache.getWaypoint(contextMenuWPIndex); if (waypoint != null) { - NavigationAppFactory.showNavigationMenu(geolocation, this, null, waypoint, null); + NavigationAppFactory.showNavigationMenu(app.currentGeo(), this, null, waypoint, null); } } break; @@ -565,50 +551,48 @@ public class CacheDetailActivity extends AbstractActivity { public boolean onOptionsItemSelected(MenuItem item) { final int menuItem = item.getItemId(); - // no menu selected, but a new sub menu shown - if (menuItem == 0) { - return false; - } - - if (menuItem == MENU_DEFAULT_NAVIGATION) { - startDefaultNavigation(); - return true; - } else if (menuItem == MENU_LOG_VISIT) { - refreshOnResume = true; - cache.logVisit(this); - return true; - } else if (menuItem == MENU_BROWSER) { - cache.openInBrowser(this); - return true; - } else if (menuItem == MENU_CACHES_AROUND) { - cachesAround(); - return true; - } else if (menuItem == MENU_CALENDAR) { - addToCalendarWithIntent(); - return true; - } else if (menuItem == MENU_SHARE) { - if (cache != null) { - cache.shareCache(this, res); + switch(menuItem) { + case 0: + // no menu selected, but a new sub menu shown + return false; + case MENU_DEFAULT_NAVIGATION: + startDefaultNavigation(); return true; - } - return false; + case MENU_LOG_VISIT: + refreshOnResume = true; + cache.logVisit(this); + return true; + case MENU_BROWSER: + cache.openInBrowser(this); + return true; + case MENU_CACHES_AROUND: + cgeocaches.startActivityCachesAround(this, cache.getCoords()); + return true; + case MENU_CALENDAR: + addToCalendarWithIntent(); + return true; + case MENU_SHARE: + if (cache != null) { + cache.shareCache(this, res); + return true; + } + return false; } - if (NavigationAppFactory.onMenuItemSelected(item, geolocation, this, cache, null, null)) { + if (NavigationAppFactory.onMenuItemSelected(item, app.currentGeo(), this, cache, null, null)) { return true; } if (GeneralAppsFactory.onMenuItemSelected(item, this, cache)) { return true; } - int logType = menuItem - MENU_LOG_VISIT_OFFLINE; - cache.logOffline(this, LogType.getById(logType)); + cache.logOffline(this, LogType.getById(menuItem - MENU_LOG_VISIT_OFFLINE)); return true; } private class LoadCacheHandler extends CancellableHandler { @Override public void handleRegularMessage(final Message msg) { - if (cgBase.UPDATE_LOAD_PROGRESS_DETAIL == msg.what && msg.obj instanceof String) { + if (UPDATE_LOAD_PROGRESS_DETAIL == msg.what && msg.obj instanceof String) { updateStatusMsg((String) msg.obj); } else { if (search == null) { @@ -706,12 +690,9 @@ public class CacheDetailActivity extends AbstractActivity { progress.dismiss(); } - private class LocationUpdater implements UpdateLocationCallback { + private class LocationUpdater extends GeoObserver { @Override - public void updateLocation(cgGeo geo) { - if (geo == null) { - return; - } + public void updateLocation(final IGeoData geo) { if (cacheDistanceView == null) { return; } @@ -719,13 +700,13 @@ public class CacheDetailActivity extends AbstractActivity { try { StringBuilder dist = new StringBuilder(); - if (geo.coordsNow != null && cache != null && cache.getCoords() != null) { - dist.append(HumanDistance.getHumanDistance(geo.coordsNow.distanceTo(cache.getCoords()))); + if (geo.getCoords() != null && cache != null && cache.getCoords() != null) { + dist.append(HumanDistance.getHumanDistance(geo.getCoords().distanceTo(cache.getCoords()))); } if (cache != null && cache.getElevation() != null) { - if (geo.altitudeNow != null) { - double diff = (cache.getElevation() - geo.altitudeNow); + if (geo.getAltitude() != 0.0) { + double diff = cache.getElevation() - geo.getAltitude(); if (diff >= 0) { dist.append(" ↗"); } else if (diff < 0) { @@ -744,7 +725,7 @@ public class CacheDetailActivity extends AbstractActivity { cacheDistanceView.setText(dist.toString()); cacheDistanceView.bringToFront(); } catch (Exception e) { - Log.w(Settings.tag, "Failed to update location."); + Log.w("Failed to update location."); } } } @@ -774,25 +755,43 @@ public class CacheDetailActivity extends AbstractActivity { @Override public void run() { - search = cgBase.searchByGeocode(geocode, StringUtils.isBlank(geocode) ? guid : null, 0, false, handler); + search = cgCache.searchByGeocode(geocode, StringUtils.isBlank(geocode) ? guid : null, 0, false, handler); handler.sendMessage(Message.obtain()); } } /** - * Starts activity to search for caches near this cache. + * Indicates whether the specified action can be used as an intent. This + * method queries the package manager for installed packages that can + * respond to an intent with the specified action. If no suitable package is + * found, this method returns false. + * + * @param context + * The application's environment. + * @param action + * The Intent action to check for availability. + * @param uri + * The Intent URI to check for availability. * - * Also finishes this activity. + * @return True if an Intent with the specified action can be sent and + * responded to, false otherwise. */ - private void cachesAround() { - cgeocaches.startActivityCachesAround(this, cache.getCoords()); - - finish(); + private static boolean isIntentAvailable(Context context, String action, Uri uri) { + final PackageManager packageManager = context.getPackageManager(); + final Intent intent; + if (uri == null) { + intent = new Intent(action); + } else { + intent = new Intent(action, uri); + } + List<ResolveInfo> list = packageManager.queryIntentActivities(intent, + PackageManager.MATCH_DEFAULT_ONLY); + return list.size() > 0; } private void addToCalendarWithIntent() { - final boolean calendarAddOnAvailable = cgBase.isIntentAvailable(this, ICalendar.INTENT, Uri.parse(ICalendar.URI_SCHEME + "://" + ICalendar.URI_HOST)); + final boolean calendarAddOnAvailable = isIntentAvailable(this, ICalendar.INTENT, Uri.parse(ICalendar.URI_SCHEME + "://" + ICalendar.URI_HOST)); if (calendarAddOnAvailable) { final Parameters params = new Parameters( @@ -833,49 +832,6 @@ public class CacheDetailActivity extends AbstractActivity { } /** - * Creates a {@link List} of all coordinates (cache and waypoints) for the current cache. - * - * @return A {@link List} of all coordinates - */ - public List<cgCoord> getCoordinates() { - List<cgCoord> coordinates = new ArrayList<cgCoord>(); - - // cache - try { - final cgCoord coords = new cgCoord(); - coords.setCoordType("cache"); - if (StringUtils.isNotBlank(cache.getName())) { - coords.setName(cache.getName()); - } else { - coords.setName(cache.getGeocode().toUpperCase()); - } - coords.setCoords(cache.getCoords()); - coordinates.add(coords); - } catch (Exception e) { - Log.e(Settings.tag, "CacheDetailActivity.getCoordinates (cache)", e); - } - - // waypoints - try { - if (cache.hasWaypoints()) { - for (cgWaypoint waypoint : cache.getWaypoints()) { - if (null != waypoint.getCoords()) { - final cgCoord coords = new cgCoord(); - coords.setCoordType("waypoint"); - coords.setName(waypoint.getName()); - coords.setCoords(waypoint.getCoords()); - coordinates.add(coords); - } - } - } - } catch (Exception e) { - Log.e(Settings.tag, "CacheDetailActivity.getCoordinates (waypoint)", e); - } - - return coordinates; - } - - /** * Tries to navigate to the {@link cgCache} of this activity. */ private void startDefaultNavigation() { @@ -885,7 +841,7 @@ public class CacheDetailActivity extends AbstractActivity { } //TODO: previously this used also the search argument "search". check if still needed - NavigationAppFactory.startDefaultNavigationApplication(geolocation, this, cache, null, null); + NavigationAppFactory.startDefaultNavigationApplication(app.currentGeo(), this, cache, null, null); } /** @@ -898,7 +854,7 @@ public class CacheDetailActivity extends AbstractActivity { } //TODO: previously this used also the search argument "search". check if still needed - NavigationAppFactory.startDefaultNavigationApplication2(geolocation, this, cache, null, null); + NavigationAppFactory.startDefaultNavigationApplication2(app.currentGeo(), this, cache, null, null); } /** @@ -916,7 +872,7 @@ public class CacheDetailActivity extends AbstractActivity { } private void showNavigationMenu() { - NavigationAppFactory.showNavigationMenu(geolocation, this, cache, null, null); + NavigationAppFactory.showNavigationMenu(app.currentGeo(), this, cache, null, null); } /** @@ -969,7 +925,7 @@ public class CacheDetailActivity extends AbstractActivity { res.getString(R.string.user_menu_open_browser) }; - AlertDialog.Builder builder = new AlertDialog.Builder(CacheDetailActivity.this); + AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(res.getString(R.string.user_menu_title) + " " + name); builder.setItems(items, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int item) { @@ -1063,7 +1019,7 @@ public class CacheDetailActivity extends AbstractActivity { ((ViewPager) container).addView(view, 0); } } catch (Exception e) { - Log.e(Settings.tag, "ViewPagerAdapter.instantiateItem ", e); + Log.e("ViewPagerAdapter.instantiateItem ", e); } return view; @@ -1102,7 +1058,7 @@ public class CacheDetailActivity extends AbstractActivity { } // show number of waypoints directly in waypoint title if (page == Page.WAYPOINTS) { - int waypointCount = (cache.hasWaypoints() ? cache.getWaypoints().size() : 0); + final int waypointCount = cache.getWaypoints().size(); return res.getQuantityString(R.plurals.waypoints, waypointCount, waypointCount); } return res.getString(page.titleStringId); @@ -1182,7 +1138,7 @@ public class CacheDetailActivity extends AbstractActivity { } /** - * lazy-creates the layout holding the icons of the chaches attributes + * lazy-creates the layout holding the icons of the caches attributes * and makes it visible */ private void showAttributeIcons(LinearLayout attribBox, int parentWidth) { @@ -1200,7 +1156,7 @@ public class CacheDetailActivity extends AbstractActivity { } /** - * lazy-creates the layout holding the discriptions of the chaches attributes + * lazy-creates the layout holding the descriptions of the caches attributes * and makes it visible */ private void showAttributeDescriptions(LinearLayout attribBox) { @@ -1230,7 +1186,7 @@ public class CacheDetailActivity extends AbstractActivity { } private ViewGroup createAttributeIconsLayout(int parentWidth) { - LinearLayout rows = new LinearLayout(CacheDetailActivity.this); + final LinearLayout rows = new LinearLayout(CacheDetailActivity.this); rows.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT)); rows.setOrientation(LinearLayout.VERTICAL); @@ -1239,13 +1195,7 @@ public class CacheDetailActivity extends AbstractActivity { noAttributeIconsFound = true; - final String packageName = cgeoapplication.getInstance().getBaseContext().getPackageName(); for (String attributeName : cache.getAttributes()) { - boolean strikethru = attributeName.endsWith("_no"); - // cut off _yes / _no - if (attributeName.endsWith("_no") || attributeName.endsWith("_yes")) { - attributeName = attributeName.substring(0, attributeName.lastIndexOf('_')); - } // check if another attribute icon fits in this row attributeRow.measure(0, 0); int rowWidth = attributeRow.getMeasuredWidth(); @@ -1257,12 +1207,11 @@ public class CacheDetailActivity extends AbstractActivity { rows.addView(attributeRow); } - // dynamically search icon of the attribute - Drawable d = null; - int id = res.getIdentifier("attribute_" + attributeName, "drawable", packageName); - if (id > 0) { + final boolean strikethru = !CacheAttribute.isEnabled(attributeName); + final CacheAttribute attrib = CacheAttribute.getByGcRawName(CacheAttribute.trimAttributeName(attributeName)); + if (attrib != CacheAttribute.UNKNOWN) { noAttributeIconsFound = false; - d = res.getDrawable(id); + Drawable d = res.getDrawable(attrib.drawableId); iv.setImageDrawable(d); // strike through? if (strikethru) { @@ -1274,7 +1223,7 @@ public class CacheDetailActivity extends AbstractActivity { fl.addView(strikethruImage); } } else { - d = res.getDrawable(R.drawable.attribute_icon_not_found); + Drawable d = res.getDrawable(R.drawable.attribute_icon_not_found); iv.setImageDrawable(d); } @@ -1295,25 +1244,22 @@ public class CacheDetailActivity extends AbstractActivity { private ViewGroup createAttributeDescriptionsLayout() { final LinearLayout descriptions = (LinearLayout) getLayoutInflater().inflate( R.layout.attribute_descriptions, null); - TextView attribView = (TextView) descriptions.getChildAt(0); + final TextView attribView = (TextView) descriptions.getChildAt(0); - StringBuilder buffer = new StringBuilder(); - final String packageName = cgeoapplication.getInstance().getBaseContext().getPackageName(); + final StringBuilder buffer = new StringBuilder(); final List<String> attributes = cache.getAttributes(); - for (String attribute : attributes) { - // dynamically search for a translation of the attribute - int id = res.getIdentifier("attribute_" + attribute, "string", packageName); - if (id > 0) { - String translated = res.getString(id); - if (StringUtils.isNotBlank(translated)) { - attribute = translated; - } + for (String attributeName : attributes) { + final boolean enabled = CacheAttribute.isEnabled(attributeName); + // search for a translation of the attribute + CacheAttribute attrib = CacheAttribute.getByGcRawName(CacheAttribute.trimAttributeName(attributeName)); + if (attrib != CacheAttribute.UNKNOWN) { + attributeName = attrib.getL10n(enabled); } if (buffer.length() > 0) { buffer.append('\n'); } - buffer.append(attribute); + buffer.append(attributeName); } if (noAttributeIconsFound) { @@ -1482,7 +1428,7 @@ public class CacheDetailActivity extends AbstractActivity { if (cache.getHiddenDate() != null) { long time = cache.getHiddenDate().getTime(); if (time > 0) { - String dateString = cgBase.formatFullDate(time); + String dateString = Formatter.formatFullDate(time); if (cache.isEventCache()) { dateString = DateUtils.formatDateTime(cgeoapplication.getInstance().getBaseContext(), time, DateUtils.FORMAT_SHOW_WEEKDAY) + ", " + dateString; } @@ -1548,10 +1494,6 @@ public class CacheDetailActivity extends AbstractActivity { } } - if (geolocation != null) { - locationUpdater.updateLocation(geolocation); - } - return view; } @@ -1581,20 +1523,11 @@ public class CacheDetailActivity extends AbstractActivity { private class StoreCacheHandler extends CancellableHandler { @Override public void handleRegularMessage(Message msg) { - if (cgBase.UPDATE_LOAD_PROGRESS_DETAIL == msg.what && msg.obj instanceof String) { + if (UPDATE_LOAD_PROGRESS_DETAIL == msg.what && msg.obj instanceof String) { updateStatusMsg((String) msg.obj); } else { storeThread = null; - - try { - cache = search.getFirstCacheFromResult(LoadFlags.LOAD_ALL_DB_ONLY); // reload cache details - } catch (Exception e) { - showToast(res.getString(R.string.err_store_failed)); - - Log.e(Settings.tag, "CacheDetailActivity.storeCacheHandler: " + e.toString()); - } - - CacheDetailActivity.this.notifyDataSetChanged(); + CacheDetailActivity.this.notifyDataSetChanged(); // reload cache details } } @@ -1608,20 +1541,11 @@ public class CacheDetailActivity extends AbstractActivity { private class RefreshCacheHandler extends CancellableHandler { @Override public void handleRegularMessage(Message msg) { - if (cgBase.UPDATE_LOAD_PROGRESS_DETAIL == msg.what && msg.obj instanceof String) { + if (UPDATE_LOAD_PROGRESS_DETAIL == msg.what && msg.obj instanceof String) { updateStatusMsg((String) msg.obj); } else { refreshThread = null; - - try { - cache = search.getFirstCacheFromResult(LoadFlags.LOAD_ALL_DB_ONLY); // reload cache details - } catch (Exception e) { - showToast(res.getString(R.string.err_refresh_failed)); - - Log.e(Settings.tag, "CacheDetailActivity.refreshCacheHandler: " + e.toString()); - } - - CacheDetailActivity.this.notifyDataSetChanged(); + CacheDetailActivity.this.notifyDataSetChanged(); // reload cache details } } @@ -1701,8 +1625,7 @@ public class CacheDetailActivity extends AbstractActivity { @Override public void run() { - app.removeCache(cache.getGeocode(), EnumSet.of(RemoveFlag.REMOVE_CACHE)); - search = cgBase.searchByGeocode(cache.getGeocode(), null, 0, true, handler); + cache.refresh(CacheDetailActivity.this, cache.getListId(), handler); handler.sendEmptyMessage(0); } @@ -1732,7 +1655,7 @@ public class CacheDetailActivity extends AbstractActivity { @Override public void run() { - cgBase.dropCache(cache, handler); + cache.drop(handler); } } @@ -1788,7 +1711,7 @@ public class CacheDetailActivity extends AbstractActivity { @Override public void run() { - handler.sendEmptyMessage(cgBase.addToWatchlist(cache)); + handler.sendEmptyMessage(GCParser.addToWatchlist(cache)); } } @@ -1802,7 +1725,7 @@ public class CacheDetailActivity extends AbstractActivity { @Override public void run() { - handler.sendEmptyMessage(cgBase.removeFromWatchlist(cache)); + handler.sendEmptyMessage(GCParser.removeFromWatchlist(cache)); } } @@ -1856,7 +1779,7 @@ public class CacheDetailActivity extends AbstractActivity { if (cache.getListId() >= StoredList.STANDARD_LIST_ID) { long diff = (System.currentTimeMillis() / (60 * 1000)) - (cache.getDetailedUpdate() / (60 * 1000)); // minutes - String ago = ""; + String ago; if (diff < 15) { ago = res.getString(R.string.cache_offline_time_mins_few); } else if (diff < 50) { @@ -1889,9 +1812,7 @@ public class CacheDetailActivity extends AbstractActivity { private class PreviewMapTask extends AsyncTask<Void, Void, BitmapDrawable> { @Override - protected BitmapDrawable doInBackground(Void... params) { - BitmapDrawable image = null; - + protected BitmapDrawable doInBackground(Void... parameters) { try { final String latlonMap = cache.getCoords().format(GeopointFormatter.Format.LAT_LON_DECDEGREE_COMMA); @@ -1902,15 +1823,15 @@ public class CacheDetailActivity extends AbstractActivity { final int height = (int) (110 * metrics.density); // TODO move this code to StaticMapProvider and use its constant values - final String markerUrl = Network.urlencode_rfc3986("http://cgeo.carnero.cc/_markers/my_location_mdpi.png"); + final String markerUrl = "http://cgeo.carnero.cc/_markers/my_location_mdpi.png"; final HtmlImage mapGetter = new HtmlImage(CacheDetailActivity.this, cache.getGeocode(), false, 0, false); - image = mapGetter.getDrawable("http://maps.google.com/maps/api/staticmap?zoom=15&size=" + width + "x" + height + "&maptype=roadmap&markers=icon%3A" + markerUrl + "%7Cshadow:false%7C" + latlonMap + "&sensor=false"); + final Parameters params = new Parameters("zoom", "15", "size", width + "x" + height, "maptype", "roadmap", "markers", "icon:" + markerUrl + "|shadow:false|" + latlonMap, "sensor", "false"); + return mapGetter.getDrawable("http://maps.google.com/maps/api/staticmap?" + params); } catch (Exception e) { - Log.w(Settings.tag, "CacheDetailActivity.PreviewMapTask", e); + Log.w("CacheDetailActivity.PreviewMapTask", e); + return null; } - - return image; } @Override @@ -2109,7 +2030,7 @@ public class CacheDetailActivity extends AbstractActivity { // if description has HTML table, add a note at the end of the long description if (unknownTagsHandler.isTableDetected() && descriptionView == view.findViewById(R.id.longdesc)) { final int startPos = description.length(); - ((Editable) description).append("\n\n" + res.getString(R.string.cache_description_table_note)); + ((Editable) description).append("\n\n").append(res.getString(R.string.cache_description_table_note)); ((Editable) description).setSpan(new StyleSpan(Typeface.ITALIC), startPos, description.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); publishProgress(); } @@ -2234,7 +2155,7 @@ public class CacheDetailActivity extends AbstractActivity { } } - view.setAdapter(new ArrayAdapter<cgLog>(CacheDetailActivity.this, R.layout.cacheview_logs_item, cache.getLogs(allLogs)) { + view.setAdapter(new ArrayAdapter<LogEntry>(CacheDetailActivity.this, R.layout.cacheview_logs_item, cache.getLogs(allLogs)) { final UserActionsClickListener userActionsClickListener = new UserActionsClickListener(); final DecryptTextClickListener decryptTextClickListener = new DecryptTextClickListener(); @@ -2250,10 +2171,10 @@ public class CacheDetailActivity extends AbstractActivity { rowView.setTag(holder); } - final cgLog log = getItem(position); + final LogEntry log = getItem(position); if (log.date > 0) { - holder.date.setText(cgBase.formatShortDate(log.date)); + holder.date.setText(Formatter.formatShortDate(log.date)); holder.date.setVisibility(View.VISIBLE); } else { holder.date.setVisibility(View.GONE); @@ -2283,10 +2204,10 @@ public class CacheDetailActivity extends AbstractActivity { } // images - if (CollectionUtils.isNotEmpty(log.logImages)) { + if (log.hasLogImages()) { List<String> titles = new ArrayList<String>(5); - for (cgImage image : log.logImages) { + for (cgImage image : log.getLogImages()) { if (StringUtils.isNotBlank(image.getTitle())) { titles.add(image.getTitle()); } @@ -2300,7 +2221,7 @@ public class CacheDetailActivity extends AbstractActivity { holder.images.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - cgeoimages.startActivityLogImages(CacheDetailActivity.this, cache.getGeocode(), new ArrayList<cgImage>(log.logImages)); + cgeoimages.startActivityLogImages(CacheDetailActivity.this, cache.getGeocode(), new ArrayList<cgImage>(log.getLogImages())); } }); } else { @@ -2391,92 +2312,88 @@ public class CacheDetailActivity extends AbstractActivity { view = (ScrollView) getLayoutInflater().inflate(R.layout.cacheview_waypoints, null); - LinearLayout waypoints = (LinearLayout) view.findViewById(R.id.waypoints); + final LinearLayout waypoints = (LinearLayout) view.findViewById(R.id.waypoints); - if (cache.hasWaypoints()) { - LinearLayout waypointView; + // sort waypoints: PP, Sx, FI, OWN + final List<cgWaypoint> sortedWaypoints = new ArrayList<cgWaypoint>(cache.getWaypoints()); + Collections.sort(sortedWaypoints); - // sort waypoints: PP, Sx, FI, OWN - List<cgWaypoint> sortedWaypoints = new ArrayList<cgWaypoint>(cache.getWaypoints()); - Collections.sort(sortedWaypoints); + for (final cgWaypoint wpt : sortedWaypoints) { + final LinearLayout waypointView = (LinearLayout) getLayoutInflater().inflate(R.layout.waypoint_item, null); - for (final cgWaypoint wpt : sortedWaypoints) { - waypointView = (LinearLayout) getLayoutInflater().inflate(R.layout.waypoint_item, null); + // coordinates + if (null != wpt.getCoords()) { + final TextView coordinatesView = (TextView) waypointView.findViewById(R.id.coordinates); + coordinatesView.setText(wpt.getCoords().toString()); + coordinatesView.setVisibility(View.VISIBLE); + } - // coordinates - if (null != wpt.getCoords()) { - final TextView coordinatesView = (TextView) waypointView.findViewById(R.id.coordinates); - coordinatesView.setText(wpt.getCoords().toString()); - coordinatesView.setVisibility(View.VISIBLE); + // info + final List<String> infoTextList = new ArrayList<String>(3); + if (WaypointType.ALL_TYPES_EXCEPT_OWN.contains(wpt.getWaypointType())) { + infoTextList.add(wpt.getWaypointType().getL10n()); + } + if (cgWaypoint.PREFIX_OWN.equalsIgnoreCase(wpt.getPrefix())) { + infoTextList.add(res.getString(R.string.waypoint_custom)); + } else { + if (StringUtils.isNotBlank(wpt.getPrefix())) { + infoTextList.add(wpt.getPrefix()); } - - // info - final List<String> infoTextList = new ArrayList<String>(3); - if (WaypointType.ALL_TYPES_EXCEPT_OWN.containsKey(wpt.getWaypointType())) { - infoTextList.add(wpt.getWaypointType().getL10n()); + if (StringUtils.isNotBlank(wpt.getLookup())) { + infoTextList.add(wpt.getLookup()); } - if (cgWaypoint.PREFIX_OWN.equalsIgnoreCase(wpt.getPrefix())) { - infoTextList.add(res.getString(R.string.waypoint_custom)); - } else { - if (StringUtils.isNotBlank(wpt.getPrefix())) { - infoTextList.add(wpt.getPrefix()); - } - if (StringUtils.isNotBlank(wpt.getLookup())) { - infoTextList.add(wpt.getLookup()); - } + } + if (CollectionUtils.isNotEmpty(infoTextList)) { + final TextView infoView = (TextView) waypointView.findViewById(R.id.info); + infoView.setText(StringUtils.join(infoTextList, Formatter.SEPARATOR)); + infoView.setVisibility(View.VISIBLE); + } + + // title + final TextView nameView = (TextView) waypointView.findViewById(R.id.name); + if (StringUtils.isNotBlank(wpt.getName())) { + nameView.setText(StringEscapeUtils.unescapeHtml4(wpt.getName())); + } else if (null != wpt.getCoords()) { + nameView.setText(wpt.getCoords().toString()); + } else { + nameView.setText(res.getString(R.string.waypoint)); + } + wpt.setIcon(res, nameView); + + // note + if (StringUtils.isNotBlank(wpt.getNote())) { + final TextView noteView = (TextView) waypointView.findViewById(R.id.note); + noteView.setVisibility(View.VISIBLE); + if (BaseUtils.containsHtml(wpt.getNote())) { + noteView.setText(Html.fromHtml(wpt.getNote()), TextView.BufferType.SPANNABLE); } - if (CollectionUtils.isNotEmpty(infoTextList)) { - final TextView infoView = (TextView) waypointView.findViewById(R.id.info); - infoView.setText(StringUtils.join(infoTextList, Formatter.SEPARATOR)); - infoView.setVisibility(View.VISIBLE); + else { + noteView.setText(wpt.getNote()); } + } - // title - TextView nameView = (TextView) waypointView.findViewById(R.id.name); - if (StringUtils.isNotBlank(wpt.getName())) { - nameView.setText(StringEscapeUtils.unescapeHtml4(wpt.getName())); - } else if (null != wpt.getCoords()) { - nameView.setText(wpt.getCoords().toString()); - } else { - nameView.setText(res.getString(R.string.waypoint)); + final View wpNavView = waypointView.findViewById(R.id.wpDefaultNavigation); + wpNavView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + NavigationAppFactory.startDefaultNavigationApplication(app.currentGeo(), CacheDetailActivity.this, null, wpt, null); } - wpt.setIcon(res, nameView); - - // note - if (StringUtils.isNotBlank(wpt.getNote())) { - final TextView noteView = (TextView) waypointView.findViewById(R.id.note); - noteView.setVisibility(View.VISIBLE); - if (BaseUtils.containsHtml(wpt.getNote())) { - noteView.setText(Html.fromHtml(wpt.getNote()), TextView.BufferType.SPANNABLE); - } - else { - noteView.setText(wpt.getNote()); - } + }); + wpNavView.setOnLongClickListener(new View.OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + NavigationAppFactory.startDefaultNavigationApplication2(app.currentGeo(), CacheDetailActivity.this, null, wpt, null); + return true; } + }); - View wpNavView = waypointView.findViewById(R.id.wpDefaultNavigation); - wpNavView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - NavigationAppFactory.startDefaultNavigationApplication(geolocation, CacheDetailActivity.this, null, wpt, null); - } - }); - wpNavView.setOnLongClickListener(new View.OnLongClickListener() { - @Override - public boolean onLongClick(View v) { - NavigationAppFactory.startDefaultNavigationApplication2(geolocation, CacheDetailActivity.this, null, wpt, null); - return true; - } - }); - - registerForContextMenu(waypointView); - waypointView.setOnClickListener(new WaypointInfoClickListener()); + registerForContextMenu(waypointView); + waypointView.setOnClickListener(new WaypointInfoClickListener()); - waypoints.addView(waypointView); - } + waypoints.addView(waypointView); } - Button addWaypoint = (Button) view.findViewById(R.id.add_waypoint); + final Button addWaypoint = (Button) view.findViewById(R.id.add_waypoint); addWaypoint.setClickable(true); addWaypoint.setOnClickListener(new AddWaypointClickListener()); @@ -2485,16 +2402,9 @@ public class CacheDetailActivity extends AbstractActivity { private class AddWaypointClickListener implements View.OnClickListener { - public void onClick(View view) { - Intent addWptIntent = new Intent(CacheDetailActivity.this, cgeowaypointadd.class); - - addWptIntent.putExtra("geocode", cache.getGeocode()); - int wpCount = 0; - if (cache.hasWaypoints()) { - wpCount = cache.getWaypoints().size(); - } - addWptIntent.putExtra("count", wpCount); - + public void onClick(final View view) { + final Intent addWptIntent = new Intent(CacheDetailActivity.this, cgeowaypointadd.class); + addWptIntent.putExtra("geocode", cache.getGeocode()).putExtra("count", cache.getWaypoints().size()); startActivity(addWptIntent); refreshOnResume = true; } @@ -2550,4 +2460,18 @@ public class CacheDetailActivity extends AbstractActivity { return view; } } + + public static void startActivity(final Context context, final String geocode, final String cacheName) { + final Intent cachesIntent = new Intent(context, CacheDetailActivity.class); + cachesIntent.putExtra("geocode", geocode); + cachesIntent.putExtra("name", cacheName); + context.startActivity(cachesIntent); + } + + public static void startActivityGuid(final Context context, final String guid, final String cacheName) { + final Intent cacheIntent = new Intent(context, CacheDetailActivity.class); + cacheIntent.putExtra("guid", guid); + cacheIntent.putExtra("name", cacheName); + context.startActivity(cacheIntent); + } } diff --git a/main/src/cgeo/geocaching/Destination.java b/main/src/cgeo/geocaching/Destination.java new file mode 100644 index 0000000..441e959 --- /dev/null +++ b/main/src/cgeo/geocaching/Destination.java @@ -0,0 +1,44 @@ +package cgeo.geocaching; + +import cgeo.geocaching.geopoint.Geopoint; + +public final class Destination implements ICoordinates { + + final private long id; + final private long date; + final private Geopoint coords; + + public Destination(long id, long date, final Geopoint coords) { + this.id = id; + this.date = date; + this.coords = coords; + } + + public Destination(final Geopoint coords) { + this(0, System.currentTimeMillis(), coords); + } + + public long getDate() { + return date; + } + + @Override + public Geopoint getCoords() { + return coords; + } + + @Override + public int hashCode() { + return coords.hashCode(); + } + + @Override + public boolean equals(final Object obj) { + return obj != null && obj instanceof Destination && ((Destination) obj).coords.equals(coords); + } + + public long getId() { + return id; + } + +} diff --git a/main/src/cgeo/geocaching/GeoDataProvider.java b/main/src/cgeo/geocaching/GeoDataProvider.java new file mode 100644 index 0000000..58b0696 --- /dev/null +++ b/main/src/cgeo/geocaching/GeoDataProvider.java @@ -0,0 +1,305 @@ +package cgeo.geocaching; + +import cgeo.geocaching.enumerations.LocationProviderType; +import cgeo.geocaching.geopoint.Geopoint; +import cgeo.geocaching.go4cache.Go4Cache; +import cgeo.geocaching.utils.Log; +import cgeo.geocaching.utils.MemorySubject; + +import android.content.Context; +import android.location.GpsSatellite; +import android.location.GpsStatus; +import android.location.Location; +import android.location.LocationListener; +import android.location.LocationManager; +import android.os.Bundle; + +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.TimeUnit; + +/** + * Provide information about the user location. This class should be instantiated only once per application. + */ +class GeoDataProvider extends MemorySubject<IGeoData> { + + private static final String LAST_LOCATION_PSEUDO_PROVIDER = "last"; + private final LocationManager geoManager; + private final GpsStatus.Listener gpsStatusListener = new GpsStatusListener(); + private final LocationData gpsLocation = new LocationData(); + private final LocationData netLocation = new LocationData(); + private final Listener networkListener = new Listener(LocationManager.NETWORK_PROVIDER, netLocation); + private final Listener gpsListener = new Listener(LocationManager.GPS_PROVIDER, gpsLocation); + private final Unregisterer unregisterer = new Unregisterer(); + public boolean gpsEnabled = false; + public int satellitesVisible = 0; + public int satellitesFixed = 0; + + private static class LocationData { + public Location location; + public long timestamp = 0; + + public void update(final Location location) { + this.location = location; + timestamp = System.currentTimeMillis(); + } + + public boolean isRecent() { + return isValid() && System.currentTimeMillis() < timestamp + 30000; + } + + public boolean isValid() { + return location != null; + } + } + + private static class GeoData extends Location implements IGeoData { + public boolean gpsEnabled = false; + public int satellitesVisible = 0; + public int satellitesFixed = 0; + + GeoData(final Location location, final boolean gpsEnabled, final int satellitesVisible, final int satellitesFixed) { + super(location); + this.gpsEnabled = gpsEnabled; + this.satellitesVisible = satellitesVisible; + this.satellitesFixed = satellitesFixed; + } + + @Override + public Location getLocation() { + return this; + } + + private static LocationProviderType getLocationProviderType(final String provider) { + if (provider.equals(LocationManager.GPS_PROVIDER)) { + return LocationProviderType.GPS; + } + if (provider.equals(LocationManager.NETWORK_PROVIDER)) { + return LocationProviderType.NETWORK; + } + return LocationProviderType.LAST; + } + + @Override + public LocationProviderType getLocationProvider() { + return getLocationProviderType(getProvider()); + } + + @Override + public Geopoint getCoords() { + return new Geopoint(this); + } + + @Override + public boolean getGpsEnabled() { + return gpsEnabled; + } + + @Override + public int getSatellitesVisible() { + return satellitesVisible; + } + + @Override + public int getSatellitesFixed() { + return satellitesFixed; + } + } + + private class Unregisterer extends Thread { + + private boolean unregisterRequested = false; + private final ArrayBlockingQueue<Boolean> queue = new ArrayBlockingQueue<Boolean>(1); + + public void cancelUnregister() { + try { + queue.put(false); + } catch (final InterruptedException e) { + // Do nothing + } + } + + public void lateUnregister() { + try { + queue.put(true); + } catch (final InterruptedException e) { + // Do nothing + } + } + + @Override + public void run() { + try { + while (true) { + if (unregisterRequested) { + final Boolean element = queue.poll(2500, TimeUnit.MILLISECONDS); + if (element == null) { + // Timeout + unregisterListeners(); + unregisterRequested = false; + } else { + unregisterRequested = element; + } + } else { + unregisterRequested = queue.take(); + } + } + } catch (final InterruptedException e) { + // Do nothing + } + } + + } + + /** + * Build a new geo data provider object. + * <p/> + * There is no need to instantiate more than one such object in an application, as observers can be added + * at will. + * + * @param context the context used to retrieve the system services + */ + GeoDataProvider(final Context context) { + geoManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); + unregisterer.start(); + // Start with an empty GeoData just in case someone queries it before we get + // a chance to get any information. + notifyObservers(new GeoData(new Location(LAST_LOCATION_PSEUDO_PROVIDER), false, 0, 0)); + } + + private void registerListeners() { + geoManager.addGpsStatusListener(gpsStatusListener); + + for (final Listener listener : new Listener[] { networkListener, gpsListener }) { + try { + geoManager.requestLocationUpdates(listener.locationProvider, 0, 0, listener); + } catch (final Exception e) { + Log.w("There is no location provider " + listener.locationProvider); + } + } + } + + private synchronized void unregisterListeners() { + // This method must be synchronized because it will be called asynchronously from the Unregisterer thread. + // We check that no observers have been re-added to prevent a race condition. + if (sizeObservers() == 0) { + geoManager.removeUpdates(networkListener); + geoManager.removeUpdates(gpsListener); + geoManager.removeGpsStatusListener(gpsStatusListener); + } + } + + @Override + protected void onFirstObserver() { + unregisterer.cancelUnregister(); + registerListeners(); + } + + @Override + protected void onLastObserver() { + unregisterer.lateUnregister(); + } + + private class Listener implements LocationListener { + private final String locationProvider; + private final LocationData locationData; + + Listener(final String locationProvider, final LocationData locationData) { + this.locationProvider = locationProvider; + this.locationData = locationData; + } + + @Override + public void onStatusChanged(final String provider, final int status, final Bundle extras) { + // nothing + } + + @Override + public void onProviderDisabled(final String provider) { + // nothing + } + + @Override + public void onProviderEnabled(final String provider) { + // nothing + } + + @Override + public void onLocationChanged(final Location location) { + locationData.update(location); + selectBest(); + } + } + + private final class GpsStatusListener implements GpsStatus.Listener { + + @Override + public void onGpsStatusChanged(final int event) { + boolean changed = false; + switch (event) { + case GpsStatus.GPS_EVENT_SATELLITE_STATUS: { + final GpsStatus status = geoManager.getGpsStatus(null); + int visible = 0; + int fixed = 0; + for (final GpsSatellite satellite : status.getSatellites()) { + if (satellite.usedInFix()) { + fixed++; + } + visible++; + } + if (visible != satellitesVisible || fixed != satellitesFixed) { + satellitesVisible = visible; + satellitesFixed = fixed; + changed = true; + } + break; + } + case GpsStatus.GPS_EVENT_STARTED: + if (!gpsEnabled) { + gpsEnabled = true; + changed = true; + } + break; + case GpsStatus.GPS_EVENT_STOPPED: + if (gpsEnabled) { + gpsEnabled = false; + satellitesFixed = 0; + satellitesVisible = 0; + changed = true; + } + break; + } + + if (changed) { + selectBest(); + } + } + } + + private LocationData best() { + if (gpsLocation.isRecent() || !netLocation.isValid()) { + return gpsLocation.isValid() ? gpsLocation : null; + } + if (!gpsLocation.isValid()) { + return netLocation; + } + return gpsLocation.timestamp > netLocation.timestamp ? gpsLocation : netLocation; + } + + private void selectBest() { + assign(best()); + } + + private void assign(final LocationData locationData) { + if (locationData == null) { + return; + } + + // We do not necessarily get signalled when satellites go to 0/0. + final int visible = gpsLocation.isRecent() ? satellitesVisible : 0; + final IGeoData current = new GeoData(locationData.location, gpsEnabled, visible, satellitesFixed); + notifyObservers(current); + + Go4Cache.signalCoordinates(current.getCoords()); + } + +} diff --git a/main/src/cgeo/geocaching/GeoObserver.java b/main/src/cgeo/geocaching/GeoObserver.java new file mode 100644 index 0000000..8d5475f --- /dev/null +++ b/main/src/cgeo/geocaching/GeoObserver.java @@ -0,0 +1,13 @@ +package cgeo.geocaching; + +import cgeo.geocaching.utils.IObserver; + +public abstract class GeoObserver implements IObserver<IGeoData> { + + abstract protected void updateLocation(final IGeoData geo); + + @Override + public void update(final IGeoData geo) { + updateLocation(geo); + } +} diff --git a/main/src/cgeo/geocaching/IBasicCache.java b/main/src/cgeo/geocaching/IBasicCache.java index 5e67b2d..195572b 100644 --- a/main/src/cgeo/geocaching/IBasicCache.java +++ b/main/src/cgeo/geocaching/IBasicCache.java @@ -11,7 +11,7 @@ import cgeo.geocaching.enumerations.CacheType; * @author blafoo * */ -public interface IBasicCache extends ILogable { +public interface IBasicCache extends ILogable, ICoordinates { public abstract String getGuid(); diff --git a/main/src/cgeo/geocaching/ICache.java b/main/src/cgeo/geocaching/ICache.java index b6a809f..dccdb85 100644 --- a/main/src/cgeo/geocaching/ICache.java +++ b/main/src/cgeo/geocaching/ICache.java @@ -28,16 +28,6 @@ public interface ICache extends IBasicCache { public String getOwnerReal(); /** - * @return Latitude, e.g. N 52° 12.345 - */ - public String getLatitude(); - - /** - * @return Longitude, e.g. E 9° 34.567 - */ - public String getLongitude(); - - /** * @return true if the user is the owner of the cache, false else */ public boolean isOwn(); diff --git a/main/src/cgeo/geocaching/ICoordinates.java b/main/src/cgeo/geocaching/ICoordinates.java new file mode 100644 index 0000000..b70e4ac --- /dev/null +++ b/main/src/cgeo/geocaching/ICoordinates.java @@ -0,0 +1,9 @@ +package cgeo.geocaching; + +import cgeo.geocaching.geopoint.Geopoint; + +public interface ICoordinates { + + public abstract Geopoint getCoords(); + +} diff --git a/main/src/cgeo/geocaching/IGeoData.java b/main/src/cgeo/geocaching/IGeoData.java new file mode 100644 index 0000000..9696b27 --- /dev/null +++ b/main/src/cgeo/geocaching/IGeoData.java @@ -0,0 +1,21 @@ +package cgeo.geocaching; + +import cgeo.geocaching.enumerations.LocationProviderType; +import cgeo.geocaching.geopoint.Geopoint; + +import android.location.Location; + +public interface IGeoData { + + public Location getLocation(); + public LocationProviderType getLocationProvider(); + public Geopoint getCoords(); + public double getAltitude(); + public float getBearing(); + public float getSpeed(); + public float getAccuracy(); + public boolean getGpsEnabled(); + public int getSatellitesVisible(); + public int getSatellitesFixed(); + +} diff --git a/main/src/cgeo/geocaching/IWaypoint.java b/main/src/cgeo/geocaching/IWaypoint.java index 870fb12..ad12d48 100644 --- a/main/src/cgeo/geocaching/IWaypoint.java +++ b/main/src/cgeo/geocaching/IWaypoint.java @@ -4,18 +4,17 @@ package cgeo.geocaching; import cgeo.geocaching.enumerations.WaypointType; -import cgeo.geocaching.geopoint.Geopoint; /** * @author blafoo * */ -public interface IWaypoint extends ILogable { +public interface IWaypoint extends ILogable, ICoordinates { public abstract int getId(); - public abstract Geopoint getCoords(); - public abstract WaypointType getWaypointType(); + public abstract String getCoordType(); + } diff --git a/main/src/cgeo/geocaching/LiveMapInfo.java b/main/src/cgeo/geocaching/LiveMapInfo.java index 3d6d110..822fbf6 100644 --- a/main/src/cgeo/geocaching/LiveMapInfo.java +++ b/main/src/cgeo/geocaching/LiveMapInfo.java @@ -9,8 +9,6 @@ import android.widget.CheckBox; public class LiveMapInfo extends AbstractActivity { - private int showCount; - @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -18,7 +16,7 @@ public class LiveMapInfo extends AbstractActivity { setTheme(R.style.transparent); setContentView(R.layout.livemapinfo); - showCount = Settings.getLiveMapHintShowCount(); + final int showCount = Settings.getLiveMapHintShowCount(); if (showCount > 2) { final CheckBox cb = (CheckBox) findViewById(R.id.live_map_hint_hide); diff --git a/main/src/cgeo/geocaching/LogEntry.java b/main/src/cgeo/geocaching/LogEntry.java new file mode 100644 index 0000000..9864f89 --- /dev/null +++ b/main/src/cgeo/geocaching/LogEntry.java @@ -0,0 +1,86 @@ +package cgeo.geocaching; + +import cgeo.geocaching.enumerations.LogType; + +import org.apache.commons.collections.CollectionUtils; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collections; +import java.util.List; + +public final class LogEntry { + /** + * avoid creating new empty lists all the time using this constant. We could also return Collections.EMPTY_LIST + * using a cast, but that might trigger static code analysis tools. + */ + private static final List<cgImage> EMPTY_LIST = Collections.emptyList(); + + public int id = 0; + public LogType type = LogType.LOG_NOTE; // note + public String author = ""; + public String log = ""; + public long date = 0; + public int found = -1; + /** Friend's log entry */ + public boolean friend = false; + private List<cgImage> logImages = null; + public String cacheName = ""; // used for trackables + public String cacheGuid = ""; // used for trackables + + public LogEntry(final Calendar date, final LogType type, final String text) { + this(Settings.getUsername(), date.getTimeInMillis(), type, text); + } + + public LogEntry(final long dateInMilliSeconds, final LogType type, final String text) { + this(Settings.getUsername(), dateInMilliSeconds, type, text); + } + + public LogEntry(final String author, long dateInMilliSeconds, final LogType type, final String text) { + this.author = author; + this.date = dateInMilliSeconds; + this.type = type; + this.log = text; + } + + @Override + public int hashCode() { + return (int) date * type.hashCode() * author.hashCode() * log.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof LogEntry)) { + return false; + } + final LogEntry otherLog = (LogEntry) obj; + return date == otherLog.date && + type == otherLog.type && + author.compareTo(otherLog.author) == 0 && + log.compareTo(otherLog.log) == 0; + } + + public void addLogImage(final cgImage image) { + if (logImages == null) { + logImages = new ArrayList<cgImage>(); + } + logImages.add(image); + } + + /** + * @return the log images or an empty list, never <code>null</code> + */ + public List<cgImage> getLogImages() { + if (logImages == null) { + return EMPTY_LIST; + } + return logImages; + } + + public boolean hasLogImages() { + return CollectionUtils.isNotEmpty(logImages); + } +} diff --git a/main/src/cgeo/geocaching/SearchResult.java b/main/src/cgeo/geocaching/SearchResult.java index bac9c23..2e56c7c 100644 --- a/main/src/cgeo/geocaching/SearchResult.java +++ b/main/src/cgeo/geocaching/SearchResult.java @@ -1,5 +1,6 @@ package cgeo.geocaching; +import cgeo.geocaching.connector.gc.Login; import cgeo.geocaching.enumerations.CacheType; import cgeo.geocaching.enumerations.LoadFlags; import cgeo.geocaching.enumerations.LoadFlags.LoadFlag; @@ -7,7 +8,6 @@ import cgeo.geocaching.enumerations.LoadFlags.SaveFlag; import cgeo.geocaching.enumerations.StatusCode; import cgeo.geocaching.gcvote.GCVote; -import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import android.os.Parcel; @@ -22,10 +22,10 @@ import java.util.Set; public class SearchResult implements Parcelable { final private Set<String> geocodes; - public StatusCode error = null; + private StatusCode error = null; private String url = ""; public String[] viewstates = null; - public int totalCnt = 0; + private int totalCnt = 0; final public static Parcelable.Creator<SearchResult> CREATOR = new Parcelable.Creator<SearchResult>() { public SearchResult createFromParcel(Parcel in) { @@ -47,19 +47,24 @@ public class SearchResult implements Parcelable { this.error = searchResult.error; this.url = searchResult.url; this.viewstates = searchResult.viewstates; - this.totalCnt = searchResult.totalCnt; + this.setTotal(searchResult.getTotal()); } else { this.geocodes = new HashSet<String>(); } } - public SearchResult(final Set<String> geocodes) { + public SearchResult(final Set<String> geocodes, final int total) { if (geocodes == null) { this.geocodes = new HashSet<String>(); } else { this.geocodes = new HashSet<String>(geocodes.size()); this.geocodes.addAll(geocodes); } + this.setTotal(total); + } + + public SearchResult(final Set<String> geocodes) { + this(geocodes, geocodes == null ? 0 : geocodes.size()); } public SearchResult(final Parcel in) { @@ -73,7 +78,7 @@ public class SearchResult implements Parcelable { viewstates = new String[length]; in.readStringArray(viewstates); } - totalCnt = in.readInt(); + setTotal(in.readInt()); } @Override @@ -87,7 +92,7 @@ public class SearchResult implements Parcelable { out.writeInt(viewstates.length); out.writeStringArray(viewstates); } - out.writeInt(totalCnt); + out.writeInt(getTotal()); } @Override @@ -124,7 +129,7 @@ public class SearchResult implements Parcelable { } public void setViewstates(String[] viewstates) { - if (cgBase.isEmpty(viewstates)) { + if (Login.isEmpty(viewstates)) { return; } @@ -135,6 +140,10 @@ public class SearchResult implements Parcelable { return totalCnt; } + public void setTotal(int totalCnt) { + this.totalCnt = totalCnt; + } + /** * @param excludeDisabled * @param excludeMine @@ -192,14 +201,8 @@ public class SearchResult implements Parcelable { return cgeoapplication.getInstance().saveCache(cache, EnumSet.of(SaveFlag.SAVE_CACHE)); } - /** Add the cache geocodes to the search and store them in the CacheCache */ - public void addCaches(final Set<cgCache> caches) { - if (CollectionUtils.isEmpty(caches)) { - return; - } - - for (final cgCache cache : caches) { - addCache(cache); - } + public boolean isEmpty() { + return geocodes.isEmpty(); } + } diff --git a/main/src/cgeo/geocaching/Settings.java b/main/src/cgeo/geocaching/Settings.java index f2ec497..3b36b23 100644 --- a/main/src/cgeo/geocaching/Settings.java +++ b/main/src/cgeo/geocaching/Settings.java @@ -5,17 +5,19 @@ import cgeo.geocaching.enumerations.LiveMapStrategy.Strategy; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.maps.MapProviderFactory; import cgeo.geocaching.maps.interfaces.MapProvider; +import cgeo.geocaching.maps.mapsforge.MapsforgeMapProvider; import cgeo.geocaching.utils.CryptUtils; +import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.ImmutablePair; -import org.mapsforge.android.maps.MapDatabase; import android.content.Context; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.content.res.Configuration; import android.content.res.Resources; +import android.preference.PreferenceManager; import java.util.Locale; @@ -79,11 +81,12 @@ public final class Settings { private static final String KEY_DEFAULT_NAVIGATION_TOOL = "defaultNavigationTool"; private static final String KEY_DEFAULT_NAVIGATION_TOOL_2 = "defaultNavigationTool2"; private static final String KEY_LIVE_MAP_STRATEGY = "livemapstrategy"; + private static final String KEY_DEBUG = "debug"; private static final String KEY_HIDE_LIVE_MAP_HINT = "hidelivemaphint"; private static final String KEY_LIVE_MAP_HINT_SHOW_COUNT = "livemaphintshowcount"; + private static final String KEY_SETTINGS_VERSION = "settingsversion"; private final static int unitsMetric = 1; - private final static int unitsImperial = 2; // twitter api keys private final static String keyConsumerPublic = CryptUtils.rot13("ESnsCvAv3kEupF1GCR3jGj"); @@ -101,24 +104,22 @@ public final class Settings { static coordInputFormatEnum fromInt(int id) { final coordInputFormatEnum[] values = coordInputFormatEnum.values(); - if (id >= 0 && id < values.length) { - return values[id]; - } else { + if (id < 0 || id >= values.length) { return Min; } + return values[id]; } } - // usable values - public static final String tag = "cgeo"; - - /** Name of the preferences file */ - public static final String preferences = "cgeo.pref"; - - private static final SharedPreferences sharedPrefs = cgeoapplication.getInstance().getSharedPreferences(Settings.preferences, Context.MODE_PRIVATE); private static String username = null; private static String password = null; + private static final SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(cgeoapplication.getInstance().getBaseContext()); + static { + migrateSettings(); + Log.setDebugUnsaved(sharedPrefs.getBoolean(KEY_DEBUG, false)); + } + // maps private static MapProvider mapProvider = null; @@ -126,6 +127,77 @@ public final class Settings { // this class is not to be instantiated; } + private static void migrateSettings() { + // migrate from non standard file location and integer based boolean types + if (sharedPrefs.getInt(KEY_SETTINGS_VERSION, 0) < 1) { + final String oldPreferencesName = "cgeo.pref"; + final SharedPreferences old = cgeoapplication.getInstance().getSharedPreferences(oldPreferencesName, Context.MODE_PRIVATE); + final Editor e = sharedPrefs.edit(); + + e.putString(KEY_TEMP_TOKEN_SECRET, old.getString(KEY_TEMP_TOKEN_SECRET, null)); + e.putString(KEY_TEMP_TOKEN_PUBLIC, old.getString(KEY_TEMP_TOKEN_PUBLIC, null)); + e.putBoolean(KEY_HELP_SHOWN, old.getInt(KEY_HELP_SHOWN, 0) != 0); + e.putFloat(KEY_ANYLONGITUDE, old.getFloat(KEY_ANYLONGITUDE, 0)); + e.putFloat(KEY_ANYLATITUDE, old.getFloat(KEY_ANYLATITUDE, 0)); + e.putBoolean(KEY_PUBLICLOC, 0 != old.getInt(KEY_PUBLICLOC, 0)); + e.putBoolean(KEY_USE_OFFLINEMAPS, 0 != old.getInt(KEY_USE_OFFLINEMAPS, 1)); + e.putBoolean(KEY_USE_OFFLINEWPMAPS, 0 != old.getInt(KEY_USE_OFFLINEWPMAPS, 0)); + e.putString(KEY_WEB_DEVICE_CODE, old.getString(KEY_WEB_DEVICE_CODE, null)); + e.putString(KEY_WEBDEVICE_NAME, old.getString(KEY_WEBDEVICE_NAME, null)); + e.putBoolean(KEY_MAP_LIVE, old.getInt(KEY_MAP_LIVE, 1) != 0); + e.putInt(KEY_MAP_SOURCE, old.getInt(KEY_MAP_SOURCE, 0)); + e.putBoolean(KEY_USE_TWITTER, 0 != old.getInt(KEY_USE_TWITTER, 0)); + e.putBoolean(KEY_SHOW_ADDRESS, 0 != old.getInt(KEY_SHOW_ADDRESS, 1)); + e.putBoolean(KEY_SHOW_CAPTCHA, old.getBoolean(KEY_SHOW_CAPTCHA, false)); + e.putBoolean(KEY_MAP_TRAIL, old.getInt(KEY_MAP_TRAIL, 1) != 0); + e.putInt(KEY_LAST_MAP_ZOOM, old.getInt(KEY_LAST_MAP_ZOOM, 14)); + e.putBoolean(KEY_LIVE_LIST, 0 != old.getInt(KEY_LIVE_LIST, 1)); + e.putBoolean(KEY_METRIC_UNITS, old.getInt(KEY_METRIC_UNITS, unitsMetric) == unitsMetric); + e.putBoolean(KEY_SKIN, old.getInt(KEY_SKIN, 0) != 0); + e.putInt(KEY_LAST_USED_LIST, old.getInt(KEY_LAST_USED_LIST, StoredList.STANDARD_LIST_ID)); + e.putString(KEY_CACHE_TYPE, old.getString(KEY_CACHE_TYPE, CacheType.ALL.id)); + e.putString(KEY_TWITTER_TOKEN_SECRET, old.getString(KEY_TWITTER_TOKEN_SECRET, null)); + e.putString(KEY_TWITTER_TOKEN_PUBLIC, old.getString(KEY_TWITTER_TOKEN_PUBLIC, null)); + e.putInt(KEY_VERSION, old.getInt(KEY_VERSION, 0)); + e.putBoolean(KEY_LOAD_DESCRIPTION, 0 != old.getInt(KEY_LOAD_DESCRIPTION, 0)); + e.putBoolean(KEY_RATING_WANTED, old.getBoolean(KEY_RATING_WANTED, true)); + e.putBoolean(KEY_ELEVATION_WANTED, old.getBoolean(KEY_ELEVATION_WANTED, true)); + e.putBoolean(KEY_FRIENDLOGS_WANTED, old.getBoolean(KEY_FRIENDLOGS_WANTED, true)); + e.putBoolean(KEY_USE_ENGLISH, old.getBoolean(KEY_USE_ENGLISH, false)); + e.putBoolean(KEY_USE_COMPASS, 0 != old.getInt(KEY_USE_COMPASS, 1)); + e.putBoolean(KEY_AUTO_VISIT_TRACKABLES, old.getBoolean(KEY_AUTO_VISIT_TRACKABLES, false)); + e.putBoolean(KEY_AUTO_INSERT_SIGNATURE, old.getBoolean(KEY_AUTO_INSERT_SIGNATURE, false)); + e.putInt(KEY_ALTITUDE_CORRECTION, old.getInt(KEY_ALTITUDE_CORRECTION, 0)); + e.putBoolean(KEY_USE_GOOGLE_NAVIGATION, 0 != old.getInt(KEY_USE_GOOGLE_NAVIGATION, 1)); + e.putBoolean(KEY_STORE_LOG_IMAGES, old.getBoolean(KEY_STORE_LOG_IMAGES, false)); + e.putBoolean(KEY_EXCLUDE_DISABLED, 0 != old.getInt(KEY_EXCLUDE_DISABLED, 0)); + e.putBoolean(KEY_EXCLUDE_OWN, 0 != old.getInt(KEY_EXCLUDE_OWN, 0)); + e.putString(KEY_MAPFILE, old.getString(KEY_MAPFILE, null)); + e.putString(KEY_SIGNATURE, old.getString(KEY_SIGNATURE, null)); + e.putString(KEY_GCVOTE_PASSWORD, old.getString(KEY_GCVOTE_PASSWORD, null)); + e.putString(KEY_PASSWORD, old.getString(KEY_PASSWORD, null)); + e.putString(KEY_USERNAME, old.getString(KEY_USERNAME, null)); + e.putString(KEY_MEMBER_STATUS, old.getString(KEY_MEMBER_STATUS, "")); + e.putInt(KEY_COORD_INPUT_FORMAT, old.getInt(KEY_COORD_INPUT_FORMAT, 0)); + e.putBoolean(KEY_LOG_OFFLINE, old.getBoolean(KEY_LOG_OFFLINE, false)); + e.putBoolean(KEY_LOAD_DIRECTION_IMG, old.getBoolean(KEY_LOAD_DIRECTION_IMG, true)); + e.putString(KEY_GC_CUSTOM_DATE, old.getString(KEY_GC_CUSTOM_DATE, null)); + e.putInt(KEY_SHOW_WAYPOINTS_THRESHOLD, old.getInt(KEY_SHOW_WAYPOINTS_THRESHOLD, 0)); + e.putString(KEY_COOKIE_STORE, old.getString(KEY_COOKIE_STORE, null)); + e.putBoolean(KEY_OPEN_LAST_DETAILS_PAGE, old.getBoolean(KEY_OPEN_LAST_DETAILS_PAGE, false)); + e.putInt(KEY_LAST_DETAILS_PAGE, old.getInt(KEY_LAST_DETAILS_PAGE, 1)); + e.putInt(KEY_DEFAULT_NAVIGATION_TOOL, old.getInt(KEY_DEFAULT_NAVIGATION_TOOL, 0)); + e.putInt(KEY_DEFAULT_NAVIGATION_TOOL_2, old.getInt(KEY_DEFAULT_NAVIGATION_TOOL_2, 0)); + e.putInt(KEY_LIVE_MAP_STRATEGY, old.getInt(KEY_LIVE_MAP_STRATEGY, Strategy.AUTO.id)); + e.putBoolean(KEY_DEBUG, old.getBoolean(KEY_DEBUG, false)); + e.putBoolean(KEY_HIDE_LIVE_MAP_HINT, old.getInt(KEY_HIDE_LIVE_MAP_HINT, 0) != 0); + e.putInt(KEY_LIVE_MAP_HINT_SHOW_COUNT, old.getInt(KEY_LIVE_MAP_HINT_SHOW_COUNT, 0)); + + e.putInt(KEY_SETTINGS_VERSION, 1) ; // mark migrated + e.commit(); + } + } + public static void setLanguage(boolean useEnglish) { final Configuration config = new Configuration(); config.locale = useEnglish ? new Locale("en") : Locale.getDefault(); @@ -161,11 +233,7 @@ public final class Settings { } public static String getUsername() { - if (null == username) { - return sharedPrefs.getString(KEY_USERNAME, null); - } else { - return username; - } + return username != null ? username : sharedPrefs.getString(KEY_USERNAME, null); } public static boolean setLogin(final String username, final String password) { @@ -311,15 +379,13 @@ public final class Settings { @Override public void edit(Editor edit) { - edit.putInt(KEY_MAP_LIVE, live ? 1 : 0); + edit.putBoolean(KEY_MAP_LIVE, live); } }); } public static int getLastList() { - final int listId = sharedPrefs.getInt(KEY_LAST_USED_LIST, StoredList.STANDARD_LIST_ID); - - return listId; + return sharedPrefs.getInt(KEY_LAST_USED_LIST, StoredList.STANDARD_LIST_ID); } public static void saveLastList(final int listId) { @@ -356,26 +422,16 @@ public final class Settings { } public static boolean setMapFile(final String mapFile) { - final boolean commitResult = editSharedSettings(new PrefRunnable() { - + return editSharedSettings(new PrefRunnable() { @Override public void edit(Editor edit) { edit.putString(KEY_MAPFILE, mapFile); } }); - - return commitResult; } - public static boolean isValidMapFile() { - return checkMapfile(getMapFile()); - } - - private static boolean checkMapfile(final String mapFileIn) { - if (null == mapFileIn) { - return false; - } - return MapDatabase.isValidMapFile(mapFileIn); + public static boolean isValidMapFile(final String mapFileIn) { + return MapsforgeMapProvider.isValidMapFile(mapFileIn); } public static coordInputFormatEnum getCoordInputFormat() { @@ -417,7 +473,7 @@ public final class Settings { } public static boolean getLoadDirImg() { - return isPremiumMember() ? false : sharedPrefs.getBoolean(KEY_LOAD_DIRECTION_IMG, true); + return !isPremiumMember() && sharedPrefs.getBoolean(KEY_LOAD_DIRECTION_IMG, true); } public static void setGcCustomDate(final String format) { @@ -439,7 +495,7 @@ public final class Settings { } public static boolean isExcludeMyCaches() { - return 0 != sharedPrefs.getInt(KEY_EXCLUDE_OWN, 0); + return sharedPrefs.getBoolean(KEY_EXCLUDE_OWN, false); } /** @@ -459,7 +515,7 @@ public final class Settings { @Override public void edit(Editor edit) { - edit.putInt(KEY_EXCLUDE_OWN, exclude ? 1 : 0); + edit.putBoolean(KEY_EXCLUDE_OWN, exclude); } }); } @@ -479,7 +535,7 @@ public final class Settings { } public static boolean isShowAddress() { - return 0 != sharedPrefs.getInt(KEY_SHOW_ADDRESS, 1); + return sharedPrefs.getBoolean(KEY_SHOW_ADDRESS, true); } public static void setShowAddress(final boolean showAddress) { @@ -487,13 +543,13 @@ public final class Settings { @Override public void edit(Editor edit) { - edit.putInt(KEY_SHOW_ADDRESS, showAddress ? 1 : 0); + edit.putBoolean(KEY_SHOW_ADDRESS, showAddress); } }); } public static boolean isShowCaptcha() { - return isPremiumMember() ? false : sharedPrefs.getBoolean(KEY_SHOW_CAPTCHA, false); + return !isPremiumMember() && sharedPrefs.getBoolean(KEY_SHOW_CAPTCHA, false); } public static void setShowCaptcha(final boolean showCaptcha) { @@ -507,7 +563,7 @@ public final class Settings { } public static boolean isExcludeDisabledCaches() { - return 0 != sharedPrefs.getInt(KEY_EXCLUDE_DISABLED, 0); + return sharedPrefs.getBoolean(KEY_EXCLUDE_DISABLED, false); } public static void setExcludeDisabledCaches(final boolean exclude) { @@ -515,13 +571,13 @@ public final class Settings { @Override public void edit(Editor edit) { - edit.putInt(KEY_EXCLUDE_DISABLED, exclude ? 1 : 0); + edit.putBoolean(KEY_EXCLUDE_DISABLED, exclude); } }); } public static boolean isStoreOfflineMaps() { - return 0 != sharedPrefs.getInt(KEY_USE_OFFLINEMAPS, 1); + return sharedPrefs.getBoolean(KEY_USE_OFFLINEMAPS, true); } public static void setStoreOfflineMaps(final boolean offlineMaps) { @@ -529,13 +585,13 @@ public final class Settings { @Override public void edit(Editor edit) { - edit.putInt(KEY_USE_OFFLINEMAPS, offlineMaps ? 1 : 0); + edit.putBoolean(KEY_USE_OFFLINEMAPS, offlineMaps); } }); } public static boolean isStoreOfflineWpMaps() { - return 0 != sharedPrefs.getInt(KEY_USE_OFFLINEWPMAPS, 0); + return sharedPrefs.getBoolean(KEY_USE_OFFLINEWPMAPS, false); } public static void setStoreOfflineWpMaps(final boolean offlineMaps) { @@ -543,7 +599,7 @@ public final class Settings { @Override public void edit(Editor edit) { - edit.putInt(KEY_USE_OFFLINEWPMAPS, offlineMaps ? 1 : 0); + edit.putBoolean(KEY_USE_OFFLINEWPMAPS, offlineMaps); } }); } @@ -563,7 +619,7 @@ public final class Settings { } public static boolean isUseGoogleNavigation() { - return 0 != sharedPrefs.getInt(KEY_USE_GOOGLE_NAVIGATION, 1); + return sharedPrefs.getBoolean(KEY_USE_GOOGLE_NAVIGATION, true); } public static void setUseGoogleNavigation(final boolean useGoogleNavigation) { @@ -571,13 +627,13 @@ public final class Settings { @Override public void edit(Editor edit) { - edit.putInt(KEY_USE_GOOGLE_NAVIGATION, useGoogleNavigation ? 1 : 0); + edit.putBoolean(KEY_USE_GOOGLE_NAVIGATION, useGoogleNavigation); } }); } public static boolean isAutoLoadDescription() { - return 0 != sharedPrefs.getInt(KEY_LOAD_DESCRIPTION, 0); + return sharedPrefs.getBoolean(KEY_LOAD_DESCRIPTION, false); } public static void setAutoLoadDesc(final boolean autoLoad) { @@ -585,7 +641,7 @@ public final class Settings { @Override public void edit(Editor edit) { - edit.putInt(KEY_LOAD_DESCRIPTION, autoLoad ? 1 : 0); + edit.putBoolean(KEY_LOAD_DESCRIPTION, autoLoad); } }); } @@ -637,7 +693,7 @@ public final class Settings { } public static boolean isLiveList() { - return 0 != sharedPrefs.getInt(KEY_LIVE_LIST, 1); + return sharedPrefs.getBoolean(KEY_LIVE_LIST, true); } public static void setLiveList(final boolean liveList) { @@ -645,13 +701,13 @@ public final class Settings { @Override public void edit(Editor edit) { - edit.putInt(KEY_LIVE_LIST, liveList ? 1 : 0); + edit.putBoolean(KEY_LIVE_LIST, liveList); } }); } public static boolean isPublicLoc() { - return 0 != sharedPrefs.getInt(KEY_PUBLICLOC, 0); + return sharedPrefs.getBoolean(KEY_PUBLICLOC, false); } public static void setPublicLoc(final boolean publicLocation) { @@ -659,7 +715,7 @@ public final class Settings { @Override public void edit(Editor edit) { - edit.putInt(KEY_PUBLICLOC, publicLocation ? 1 : 0); + edit.putBoolean(KEY_PUBLICLOC, publicLocation); } }); } @@ -693,7 +749,7 @@ public final class Settings { } public static boolean isUseMetricUnits() { - return sharedPrefs.getInt(KEY_METRIC_UNITS, unitsMetric) == unitsMetric; + return sharedPrefs.getBoolean(KEY_METRIC_UNITS, true); } public static void setUseMetricUnits(final boolean metric) { @@ -701,17 +757,17 @@ public final class Settings { @Override public void edit(Editor edit) { - edit.putInt(KEY_METRIC_UNITS, metric ? unitsMetric : unitsImperial); + edit.putBoolean(KEY_METRIC_UNITS, metric); } }); } public static boolean isLiveMap() { - return sharedPrefs.getInt(KEY_MAP_LIVE, 1) != 0; + return sharedPrefs.getBoolean(KEY_MAP_LIVE, true); } public static boolean isMapTrail() { - return sharedPrefs.getInt(KEY_MAP_TRAIL, 1) != 0; + return sharedPrefs.getBoolean(KEY_MAP_TRAIL, true); } public static void setMapTrail(final boolean showTrail) { @@ -719,7 +775,7 @@ public final class Settings { @Override public void edit(Editor edit) { - edit.putInt(KEY_MAP_TRAIL, showTrail ? 1 : 0); + edit.putBoolean(KEY_MAP_TRAIL, showTrail); } }); } @@ -782,7 +838,7 @@ public final class Settings { } public static boolean isUseCompass() { - return 0 != sharedPrefs.getInt(KEY_USE_COMPASS, 1); + return sharedPrefs.getBoolean(KEY_USE_COMPASS, true); } public static void setUseCompass(final boolean useCompass) { @@ -790,13 +846,13 @@ public final class Settings { @Override public void edit(Editor edit) { - edit.putInt(KEY_USE_COMPASS, useCompass ? 1 : 0); + edit.putBoolean(KEY_USE_COMPASS, useCompass); } }); } public static boolean isHelpShown() { - return sharedPrefs.getInt(KEY_HELP_SHOWN, 0) != 0; + return sharedPrefs.getBoolean(KEY_HELP_SHOWN, false); } public static void setHelpShown() { @@ -804,13 +860,13 @@ public final class Settings { @Override public void edit(Editor edit) { - edit.putInt(KEY_HELP_SHOWN, 1); + edit.putBoolean(KEY_HELP_SHOWN, true); } }); } public static boolean isLightSkin() { - return sharedPrefs.getInt(KEY_SKIN, 0) != 0; + return sharedPrefs.getBoolean(KEY_SKIN, false); } public static void setLightSkin(final boolean lightSkin) { @@ -818,7 +874,7 @@ public final class Settings { @Override public void edit(Editor edit) { - edit.putInt(KEY_SKIN, lightSkin ? 1 : 0); + edit.putBoolean(KEY_SKIN, lightSkin); } }); } @@ -860,6 +916,12 @@ public final class Settings { return CacheType.getById(sharedPrefs.getString(KEY_CACHE_TYPE, CacheType.ALL.id)); } + /** + * The Threshold for the showing of child waypoints + * + * @return + */ + public static int getWayPointsThreshold() { return sharedPrefs.getInt(KEY_SHOW_WAYPOINTS_THRESHOLD, 0); } @@ -875,7 +937,7 @@ public final class Settings { } public static boolean isUseTwitter() { - return 0 != sharedPrefs.getInt(KEY_USE_TWITTER, 0); + return sharedPrefs.getBoolean(KEY_USE_TWITTER, false); } public static void setUseTwitter(final boolean useTwitter) { @@ -883,7 +945,7 @@ public final class Settings { @Override public void edit(Editor edit) { - edit.putInt(KEY_USE_TWITTER, useTwitter ? 1 : 0); + edit.putBoolean(KEY_USE_TWITTER, useTwitter); } }); } @@ -1017,8 +1079,23 @@ public final class Settings { }); } + + public static boolean isDebug() { + return Log.isDebug(); + } + + public static void setDebug(final boolean debug) { + editSharedSettings(new PrefRunnable() { + + @Override public void edit(Editor edit) { + edit.putBoolean(KEY_DEBUG, debug); + } + }); + Log.setDebugUnsaved(debug); + } + public static boolean getHideLiveMapHint() { - return sharedPrefs.getInt(KEY_HIDE_LIVE_MAP_HINT, 0) == 0 ? false : true; + return sharedPrefs.getBoolean(KEY_HIDE_LIVE_MAP_HINT, false); } public static void setHideLiveHint(final boolean hide) { @@ -1026,7 +1103,7 @@ public final class Settings { @Override public void edit(Editor edit) { - edit.putInt(KEY_HIDE_LIVE_MAP_HINT, hide ? 1 : 0); + edit.putBoolean(KEY_HIDE_LIVE_MAP_HINT, hide); } }); } @@ -1044,4 +1121,9 @@ public final class Settings { } }); } + + public static String getPreferencesName() { + // there is currently no Android API to get the file name of the shared preferences + return cgeoapplication.getInstance().getPackageName() + "_preferences"; + } } diff --git a/main/src/cgeo/geocaching/StaticMapsActivity.java b/main/src/cgeo/geocaching/StaticMapsActivity.java index e7c975c..2e5f423 100644 --- a/main/src/cgeo/geocaching/StaticMapsActivity.java +++ b/main/src/cgeo/geocaching/StaticMapsActivity.java @@ -2,6 +2,7 @@ package cgeo.geocaching; import cgeo.geocaching.activity.AbstractActivity; import cgeo.geocaching.enumerations.LoadFlags; +import cgeo.geocaching.utils.Log; import org.apache.commons.collections.CollectionUtils; @@ -13,7 +14,6 @@ import android.graphics.BitmapFactory; import android.os.Bundle; import android.os.Handler; import android.os.Message; -import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; @@ -37,26 +37,20 @@ public class StaticMapsActivity extends AbstractActivity { @Override public void handleMessage(Message msg) { + if (waitDialog != null) { + waitDialog.dismiss(); + } try { if (CollectionUtils.isEmpty(maps)) { - if (waitDialog != null) { - waitDialog.dismiss(); - } - if ((waypoint_id != null && Settings.isStoreOfflineWpMaps()) || (waypoint_id == null && Settings.isStoreOfflineMaps())) { - AlertDialog.Builder builder = new AlertDialog.Builder(StaticMapsActivity.this); + final AlertDialog.Builder builder = new AlertDialog.Builder(StaticMapsActivity.this); builder.setMessage(R.string.err_detail_ask_store_map_static).setPositiveButton(android.R.string.yes, dialogClickListener) .setNegativeButton(android.R.string.no, dialogClickListener).show(); } else { showToast(res.getString(R.string.err_detail_not_load_map_static)); finish(); } - return; } else { - if (waitDialog != null) { - waitDialog.dismiss(); - } - if (inflater == null) { inflater = getLayoutInflater(); } @@ -66,7 +60,7 @@ public class StaticMapsActivity extends AbstractActivity { } smapsView.removeAllViews(); - for (Bitmap image : maps) { + for (final Bitmap image : maps) { if (image != null) { final ImageView map = (ImageView) inflater.inflate(R.layout.map_static_item, null); map.setImageBitmap(image); @@ -75,10 +69,7 @@ public class StaticMapsActivity extends AbstractActivity { } } } catch (Exception e) { - if (waitDialog != null) { - waitDialog.dismiss(); - } - Log.e(Settings.tag, "StaticMapsActivity.loadMapsHandler: " + e.toString()); + Log.e("StaticMapsActivity.loadMapsHandler: " + e.toString()); } } }; @@ -160,7 +151,7 @@ public class StaticMapsActivity extends AbstractActivity { } } } catch (Exception e) { - Log.e(Settings.tag, "StaticMapsActivity.LoadMapsThread.run.1: " + e.toString()); + Log.e("StaticMapsActivity.LoadMapsThread.run.1: " + e.toString()); } } @@ -179,14 +170,14 @@ public class StaticMapsActivity extends AbstractActivity { } } } catch (Exception e) { - Log.e(Settings.tag, "StaticMapsActivity.LoadMapsThread.run.2: " + e.toString()); + Log.e("StaticMapsActivity.LoadMapsThread.run.2: " + e.toString()); } } } loadMapsHandler.sendMessage(Message.obtain()); } catch (Exception e) { - Log.e(Settings.tag, "StaticMapsActivity.LoadMapsThread.run: " + e.toString()); + Log.e("StaticMapsActivity.LoadMapsThread.run: " + e.toString()); } } } diff --git a/main/src/cgeo/geocaching/StaticMapsProvider.java b/main/src/cgeo/geocaching/StaticMapsProvider.java index fcb8ed9..9fbf429 100644 --- a/main/src/cgeo/geocaching/StaticMapsProvider.java +++ b/main/src/cgeo/geocaching/StaticMapsProvider.java @@ -1,10 +1,11 @@ package cgeo.geocaching; import cgeo.geocaching.concurrent.BlockingThreadPool; -import cgeo.geocaching.concurrent.Task; import cgeo.geocaching.files.LocalStorage; import cgeo.geocaching.geopoint.GeopointFormatter.Format; import cgeo.geocaching.network.Network; +import cgeo.geocaching.network.Parameters; +import cgeo.geocaching.utils.Log; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -12,7 +13,6 @@ import org.apache.http.HttpResponse; import android.app.Activity; import android.content.Context; -import android.util.Log; import android.view.Display; import android.view.WindowManager; @@ -30,28 +30,43 @@ public class StaticMapsProvider { return LocalStorage.getStorageFile(geocode, "map_" + prefix + level, false, createDirs); } - private static void downloadDifferentZooms(final cgCache cache, String markerUrl, String prefix, String latlonMap, int edge, String waypoints) { - downloadMap(cache, 20, "satellite", markerUrl, prefix, 1, latlonMap, edge, waypoints); - downloadMap(cache, 18, "satellite", markerUrl, prefix, 2, latlonMap, edge, waypoints); - downloadMap(cache, 16, "roadmap", markerUrl, prefix, 3, latlonMap, edge, waypoints); - downloadMap(cache, 14, "roadmap", markerUrl, prefix, 4, latlonMap, edge, waypoints); - downloadMap(cache, 11, "roadmap", markerUrl, prefix, 5, latlonMap, edge, waypoints); - } - - private static void downloadMap(cgCache cache, int zoom, String mapType, String markerUrl, String prefix, int level, String latlonMap, int edge, String waypoints) { - final String mapUrl = "http://maps.google.com/maps/api/staticmap?center=" + latlonMap; - final String url = mapUrl + "&zoom=" + zoom + "&size=" + edge + "x" + edge + "&maptype=" + mapType + "&markers=icon%3A" + markerUrl + "%7C" + latlonMap + waypoints + "&sensor=false"; - final File file = getMapFile(cache.getGeocode(), prefix, level, true); - final HttpResponse httpResponse = Network.request(url, null, false); + private static void downloadDifferentZooms(final String geocode, String markerUrl, String prefix, String latlonMap, int edge, final Parameters waypoints) { + downloadMap(geocode, 20, "satellite", markerUrl, prefix, 1, latlonMap, edge, waypoints); + downloadMap(geocode, 18, "satellite", markerUrl, prefix, 2, latlonMap, edge, waypoints); + downloadMap(geocode, 16, "roadmap", markerUrl, prefix, 3, latlonMap, edge, waypoints); + downloadMap(geocode, 14, "roadmap", markerUrl, prefix, 4, latlonMap, edge, waypoints); + downloadMap(geocode, 11, "roadmap", markerUrl, prefix, 5, latlonMap, edge, waypoints); + } + + private static void downloadMap(String geocode, int zoom, String mapType, String markerUrl, String prefix, int level, String latlonMap, int edge, final Parameters waypoints) { + final String mapUrl = "http://maps.google.com/maps/api/staticmap"; + final Parameters params = new Parameters( + "center", latlonMap, + "zoom", String.valueOf(zoom), + "size", edge + "x" + edge, + "maptype", mapType, + "markers", "icon:" + markerUrl + '|' + latlonMap, + "sensor", "false"); + if (waypoints != null) { + params.addAll(waypoints); + } + final HttpResponse httpResponse = Network.getRequest(mapUrl, params); if (httpResponse != null) { - if (LocalStorage.saveEntityToFile(httpResponse, file)) { - // Delete image if it has no contents - final long fileSize = file.length(); - if (fileSize < MIN_MAP_IMAGE_BYTES) { - file.delete(); + if (httpResponse.getStatusLine().getStatusCode() == 200) { + final File file = getMapFile(geocode, prefix, level, true); + if (LocalStorage.saveEntityToFile(httpResponse, file)) { + // Delete image if it has no contents + final long fileSize = file.length(); + if (fileSize < MIN_MAP_IMAGE_BYTES) { + file.delete(); + } } + } else { + Log.d("StaticMapsProvider.downloadMap: httpResponseCode = " + httpResponse.getStatusLine().getStatusCode()); } + } else { + Log.e("StaticMapsProvider.downloadMap: httpResponse is null"); } } @@ -79,24 +94,24 @@ public class StaticMapsProvider { // download static map for current waypoints if (Settings.isStoreOfflineWpMaps() && CollectionUtils.isNotEmpty(cache.getWaypoints())) { for (cgWaypoint waypoint : cache.getWaypoints()) { - storeWaypointStaticMap(cache, edge, waypoint, false); + storeWaypointStaticMap(cache.getGeocode(), edge, waypoint, false); } } } public static void storeWaypointStaticMap(cgCache cache, Activity activity, cgWaypoint waypoint, boolean waitForResult) { int edge = StaticMapsProvider.guessMinDisplaySide(activity); - storeWaypointStaticMap(cache, edge, waypoint, waitForResult); + storeWaypointStaticMap(cache.getGeocode(), edge, waypoint, waitForResult); } - private static void storeWaypointStaticMap(cgCache cache, int edge, cgWaypoint waypoint, final boolean waitForResult) { + private static void storeWaypointStaticMap(final String geocode, int edge, cgWaypoint waypoint, final boolean waitForResult) { if (waypoint.getCoords() == null) { return; } String wpLatlonMap = waypoint.getCoords().format(Format.LAT_LON_DECDEGREE_COMMA); String wpMarkerUrl = getWpMarkerUrl(waypoint); // download map images in separate background thread for higher performance - downloadMaps(cache, wpMarkerUrl, "wp" + waypoint.getId() + "_", wpLatlonMap, edge, "", waitForResult); + downloadMaps(geocode, wpMarkerUrl, "wp" + waypoint.getId() + "_", wpLatlonMap, edge, null, waitForResult); } public static void storeCacheStaticMap(cgCache cache, Activity activity, final boolean waitForResult) { @@ -104,30 +119,25 @@ public class StaticMapsProvider { storeCacheStaticMap(cache, edge, waitForResult); } - private static void storeCacheStaticMap(cgCache cache, int edge, final boolean waitForResult) { + private static void storeCacheStaticMap(final cgCache cache, final int edge, final boolean waitForResult) { final String latlonMap = cache.getCoords().format(Format.LAT_LON_DECDEGREE_COMMA); - final StringBuilder waypoints = new StringBuilder(); - if (cache.hasWaypoints()) { - for (cgWaypoint waypoint : cache.getWaypoints()) { - if (waypoint.getCoords() == null) { - continue; - } - String wpMarkerUrl = getWpMarkerUrl(waypoint); - waypoints.append("&markers=icon%3A"); - waypoints.append(wpMarkerUrl); - waypoints.append("%7C"); - waypoints.append(waypoint.getCoords().format(Format.LAT_LON_DECDEGREE_COMMA)); + final Parameters waypoints = new Parameters(); + for (final cgWaypoint waypoint : cache.getWaypoints()) { + if (waypoint.getCoords() == null) { + continue; } + final String wpMarkerUrl = getWpMarkerUrl(waypoint); + waypoints.put("markers", "icon:" + wpMarkerUrl + "|" + waypoint.getCoords().format(Format.LAT_LON_DECDEGREE_COMMA)); } // download map images in separate background thread for higher performance final String cacheMarkerUrl = getCacheMarkerUrl(cache); - downloadMaps(cache, cacheMarkerUrl, "", latlonMap, edge, waypoints.toString(), waitForResult); + downloadMaps(cache.getGeocode(), cacheMarkerUrl, "", latlonMap, edge, waypoints, waitForResult); } private static int guessMinDisplaySide(Display display) { final int maxWidth = display.getWidth() - 25; final int maxHeight = display.getHeight() - 25; - int edge = 0; + int edge; if (maxWidth > maxHeight) { edge = maxWidth; } else { @@ -140,22 +150,22 @@ public class StaticMapsProvider { return guessMinDisplaySide(((WindowManager) activity.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay()); } - private static void downloadMaps(final cgCache cache, final String markerUrl, final String prefix, final String latlonMap, final int edge, - final String waypoints, boolean waitForResult) { + private static void downloadMaps(final String geocode, final String markerUrl, final String prefix, final String latlonMap, final int edge, + final Parameters waypoints, boolean waitForResult) { if (waitForResult) { - downloadDifferentZooms(cache, markerUrl, prefix, latlonMap, edge, waypoints); + downloadDifferentZooms(geocode, markerUrl, prefix, latlonMap, edge, waypoints); } else { - Task currentTask = new Task("getting static map") { + final Runnable currentTask = new Runnable() { @Override public void run() { - downloadDifferentZooms(cache, markerUrl, prefix, latlonMap, edge, waypoints); + downloadDifferentZooms(geocode, markerUrl, prefix, latlonMap, edge, waypoints); } }; try { pool.add(currentTask, 20, TimeUnit.SECONDS); } catch (InterruptedException e) { - Log.e(Settings.tag, "StaticMapsProvider.downloadMaps error adding task: " + e.toString()); + Log.e("StaticMapsProvider.downloadMaps error adding task: " + e.toString()); } } } @@ -168,12 +178,12 @@ public class StaticMapsProvider { type += "_disabled"; } - return Network.urlencode_rfc3986(MARKERS_URL + "marker_cache_" + type + ".png"); + return MARKERS_URL + "marker_cache_" + type + ".png"; } private static String getWpMarkerUrl(final cgWaypoint waypoint) { String type = waypoint.getWaypointType() != null ? waypoint.getWaypointType().id : null; - return Network.urlencode_rfc3986(MARKERS_URL + "marker_waypoint_" + type + ".png"); + return MARKERS_URL + "marker_waypoint_" + type + ".png"; } public static void removeWpStaticMaps(int wp_id, String geocode) { @@ -183,7 +193,7 @@ public class StaticMapsProvider { StaticMapsProvider.getMapFile(geocode, "wp" + wp_id + "_", level, false).delete(); } } catch (Exception e) { - Log.e(Settings.tag, "StaticMapsProvider.removeWpStaticMaps: " + e.toString()); + Log.e("StaticMapsProvider.removeWpStaticMaps: " + e.toString()); } } } diff --git a/main/src/cgeo/geocaching/StoredList.java b/main/src/cgeo/geocaching/StoredList.java index 3b5a47a..eaf677d 100644 --- a/main/src/cgeo/geocaching/StoredList.java +++ b/main/src/cgeo/geocaching/StoredList.java @@ -1,5 +1,19 @@ package cgeo.geocaching; +import cgeo.geocaching.activity.IAbstractActivity; +import cgeo.geocaching.utils.RunnableWithArgument; + +import org.apache.commons.lang3.StringUtils; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.content.res.Resources; +import android.view.View; +import android.widget.EditText; + +import java.util.ArrayList; +import java.util.List; public class StoredList { public static final int TEMPORARY_LIST_ID = 0; @@ -18,4 +32,108 @@ public class StoredList { public String getTitleAndCount() { return title + " [" + count + "]"; } + + public static class UserInterface { + private final IAbstractActivity activity; + private final cgeoapplication app; + private final Resources res; + + public UserInterface(final IAbstractActivity activity) { + this.activity = activity; + app = cgeoapplication.getInstance(); + res = app.getResources(); + } + + public void promptForListSelection(final int titleId, final RunnableWithArgument<Integer> runAfterwards) { + final List<StoredList> lists = app.getLists(); + + if (lists == null) { + return; + } + + final List<CharSequence> listsTitle = new ArrayList<CharSequence>(); + for (StoredList list : lists) { + listsTitle.add(list.getTitleAndCount()); + } + listsTitle.add("<" + res.getString(R.string.list_menu_create) + ">"); + + final CharSequence[] items = new CharSequence[listsTitle.size()]; + + AlertDialog.Builder builder = new AlertDialog.Builder((Activity) activity); + builder.setTitle(res.getString(titleId)); + builder.setItems(listsTitle.toArray(items), new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialogInterface, int itemId) { + if (itemId >= lists.size()) { + // create new list on the fly + promptForListCreation(runAfterwards); + } + else { + if (runAfterwards != null) { + runAfterwards.run(lists.get(itemId).id); + } + } + } + }); + builder.create().show(); + } + + public void promptForListCreation(final RunnableWithArgument<Integer> runAfterwards) { + handleListNameInput("", R.string.list_dialog_create_title, R.string.list_dialog_create, new RunnableWithArgument<String>() { + + @Override + public void run(final String listName) { + final int newId = app.createList(listName); + + if (newId >= cgData.customListIdOffset) { + activity.showToast(res.getString(R.string.list_dialog_create_ok)); + if (runAfterwards != null) { + runAfterwards.run(newId); + } + } else { + activity.showToast(res.getString(R.string.list_dialog_create_err)); + } + } + }); + } + + private void handleListNameInput(final String defaultValue, int dialogTitle, int buttonTitle, final RunnableWithArgument<String> runnable) { + final AlertDialog.Builder alert = new AlertDialog.Builder((Activity) activity); + final View view = ((Activity) activity).getLayoutInflater().inflate(R.layout.list_create_dialog, null); + final EditText input = (EditText) view.findViewById(R.id.text); + input.setText(defaultValue); + + alert.setTitle(dialogTitle); + alert.setView(view); + alert.setPositiveButton(buttonTitle, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + // remove whitespaces added by autocompletion of Android keyboard + String listName = StringUtils.trim(input.getText().toString()); + if (StringUtils.isNotBlank(listName)) { + runnable.run(listName); + } + } + }); + alert.setNegativeButton(res.getString(R.string.list_dialog_cancel), new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + dialog.dismiss(); + } + }); + + alert.show(); + } + + public void promptForListRename(final int listId, final Runnable runAfterRename) { + final StoredList list = app.getList(listId); + handleListNameInput(list.title, R.string.list_dialog_rename_title, R.string.list_dialog_rename, new RunnableWithArgument<String>() { + + @Override + public void run(final String listName) { + app.renameList(listId, listName); + if (runAfterRename != null) { + runAfterRename.run(); + } + } + }); + } + } } diff --git a/main/src/cgeo/geocaching/TrackableLog.java b/main/src/cgeo/geocaching/TrackableLog.java new file mode 100644 index 0000000..8e2ad90 --- /dev/null +++ b/main/src/cgeo/geocaching/TrackableLog.java @@ -0,0 +1,18 @@ +package cgeo.geocaching; + +import cgeo.geocaching.enumerations.LogTypeTrackable; + +public final class TrackableLog { + public TrackableLog(String trackCode, String name, int id, int ctl) { + this.trackCode = trackCode; + this.name = name; + this.id = id; + this.ctl = ctl; + } + + public final int ctl; + public final int id; + public final String trackCode; + public final String name; + public LogTypeTrackable action = LogTypeTrackable.DO_NOTHING; // base.logTrackablesAction - no action +} diff --git a/main/src/cgeo/geocaching/UpdateLocationCallback.java b/main/src/cgeo/geocaching/UpdateLocationCallback.java deleted file mode 100644 index f0334a1..0000000 --- a/main/src/cgeo/geocaching/UpdateLocationCallback.java +++ /dev/null @@ -1,5 +0,0 @@ -package cgeo.geocaching; - -public interface UpdateLocationCallback { - public void updateLocation(cgGeo geo); -} diff --git a/main/src/cgeo/geocaching/VisitCacheActivity.java b/main/src/cgeo/geocaching/VisitCacheActivity.java index f0acd97..72e70e9 100644 --- a/main/src/cgeo/geocaching/VisitCacheActivity.java +++ b/main/src/cgeo/geocaching/VisitCacheActivity.java @@ -1,18 +1,20 @@ package cgeo.geocaching; import cgeo.geocaching.activity.AbstractActivity; +import cgeo.geocaching.connector.gc.GCParser; +import cgeo.geocaching.connector.gc.Login; import cgeo.geocaching.enumerations.LoadFlags; -import cgeo.geocaching.enumerations.LoadFlags.RemoveFlag; import cgeo.geocaching.enumerations.LoadFlags.SaveFlag; import cgeo.geocaching.enumerations.LogType; import cgeo.geocaching.enumerations.LogTypeTrackable; import cgeo.geocaching.enumerations.StatusCode; import cgeo.geocaching.gcvote.GCVote; -import cgeo.geocaching.network.Login; import cgeo.geocaching.network.Network; import cgeo.geocaching.network.Parameters; import cgeo.geocaching.twitter.Twitter; import cgeo.geocaching.ui.DateDialog; +import cgeo.geocaching.ui.Formatter; +import cgeo.geocaching.utils.Log; import cgeo.geocaching.utils.LogTemplateProvider; import cgeo.geocaching.utils.LogTemplateProvider.LogTemplate; @@ -26,7 +28,6 @@ import android.content.res.Configuration; import android.os.Bundle; import android.os.Handler; import android.os.Message; -import android.util.Log; import android.view.ContextMenu; import android.view.LayoutInflater; import android.view.Menu; @@ -64,12 +65,11 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D private List<LogType> possibleLogTypes = new ArrayList<LogType>(); private String[] viewstates = null; private boolean gettingViewstate = true; - private List<cgTrackableLog> trackables = null; + private List<TrackableLog> trackables = null; private Calendar date = Calendar.getInstance(); private LogType typeSelected = LogType.LOG_UNKNOWN; private int attempts = 0; private Button postButton = null; - private Button saveButton = null; private Button clearButton = null; private CheckBox tweetCheck = null; private LinearLayout tweetBox = null; @@ -88,16 +88,13 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D showToast(res.getString(R.string.info_log_type_changed)); } - if (cgBase.isEmpty(viewstates) && attempts < 2) { - final LoadDataThread thread; - thread = new LoadDataThread(); - thread.start(); - - return; - } else if (cgBase.isEmpty(viewstates) && attempts >= 2) { - showToast(res.getString(R.string.err_log_load_data)); - showProgress(false); - + if (Login.isEmpty(viewstates)) { + if (attempts < 2) { + new LoadDataThread().start(); + } else { + showToast(res.getString(R.string.err_log_load_data)); + showProgress(false); + } return; } @@ -114,7 +111,7 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D final LinearLayout inventoryView = (LinearLayout) findViewById(R.id.inventory); inventoryView.removeAllViews(); - for (cgTrackableLog tb : trackables) { + for (TrackableLog tb : trackables) { LinearLayout inventoryItem = (LinearLayout) inflater.inflate(R.layout.visit_trackable, null); ((TextView) inventoryItem.findViewById(R.id.trackcode)).setText(tb.trackCode); @@ -295,7 +292,7 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D @Override public boolean onCreateOptionsMenu(Menu menu) { - SubMenu menuLog = null; + SubMenu menuLog; menuLog = menu.addSubMenu(0, 0, 0, res.getString(R.string.log_add)).setIcon(android.R.drawable.ic_menu_add); for (LogTemplate template : LogTemplateProvider.getTemplates()) { @@ -336,7 +333,9 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D if (id == MENU_SIGNATURE) { insertIntoLog(LogTemplateProvider.applyTemplates(Settings.getSignature(), false), true); return true; - } else if (id >= 10 && id <= 19) { + } + + if (id >= 10 && id <= 19) { rating = (id - 9) / 2.0; if (rating < 1) { rating = 0; @@ -344,12 +343,13 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D updatePostButtonText(); return true; } + final LogTemplate template = LogTemplateProvider.getTemplate(id); if (template != null) { - final String newText = template.getValue(false); - insertIntoLog(newText, true); + insertIntoLog(template.getValue(false), true); return true; } + return false; } @@ -370,7 +370,7 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D if (viewId == R.id.type) { for (final LogType typeOne : possibleLogTypes) { menu.add(viewId, typeOne.id, 0, typeOne.getL10n()); - Log.w(Settings.tag, "Adding " + typeOne + " " + typeOne.getL10n()); + Log.w("Adding " + typeOne + " " + typeOne.getL10n()); } } else if (viewId == R.id.changebutton) { final int textId = ((TextView) findViewById(viewId)).getId(); @@ -382,7 +382,7 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D } else { final int realViewId = ((LinearLayout) findViewById(viewId)).getId(); - for (final cgTrackableLog tb : trackables) { + for (final TrackableLog tb : trackables) { if (tb.id == realViewId) { menu.setHeaderTitle(tb.name); } @@ -400,9 +400,10 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D if (group == R.id.type) { setType(LogType.getById(id)); - return true; - } else if (group == R.id.changebutton) { + } + + if (group == R.id.changebutton) { try { final LogTypeTrackable logType = LogTypeTrackable.findById(id); if (logType != null) { @@ -419,14 +420,14 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D } tbText.setText(res.getString(logType.resourceId) + " ▼"); } - for (cgTrackableLog tb : trackables) { + for (TrackableLog tb : trackables) { tb.action = logType; } tbChanged = true; return true; } } catch (Exception e) { - Log.e(Settings.tag, "cgeovisit.onContextItemSelected: " + e.toString()); + Log.e("cgeovisit.onContextItemSelected: " + e.toString()); } } else { try { @@ -442,21 +443,21 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D return false; } - for (cgTrackableLog tb : trackables) { + for (TrackableLog tb : trackables) { if (tb.id == group) { tbChanged = true; tb.action = logType; tbText.setText(res.getString(logType.resourceId) + " ▼"); - Log.i(Settings.tag, "Trackable " + tb.trackCode + " (" + tb.name + ") has new action: #" + id); + Log.i("Trackable " + tb.trackCode + " (" + tb.name + ") has new action: #" + id); } } return true; } } catch (Exception e) { - Log.e(Settings.tag, "cgeovisit.onContextItemSelected: " + e.toString()); + Log.e("cgeovisit.onContextItemSelected: " + e.toString()); } } @@ -471,11 +472,11 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D tweetBox = (LinearLayout) findViewById(R.id.tweet_box); tweetCheck = (CheckBox) findViewById(R.id.tweet); clearButton = (Button) findViewById(R.id.clear); - saveButton = (Button) findViewById(R.id.save); + final Button saveButton = (Button) findViewById(R.id.save); possibleLogTypes = cache.getPossibleLogTypes(); - final cgLog log = app.loadLogOffline(geocode); + final LogEntry log = app.loadLogOffline(geocode); if (log != null) { typeSelected = log.type; date.setTime(new Date(log.date)); @@ -507,7 +508,7 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D }); final Button dateButton = (Button) findViewById(R.id.date); - dateButton.setText(cgBase.formatShortDate(date.getTime().getTime())); + dateButton.setText(Formatter.formatShortDate(date.getTime().getTime())); dateButton.setOnClickListener(new DateListener()); final EditText logView = (EditText) findViewById(R.id.log); @@ -522,7 +523,7 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D lastState.restore(this); } - if (cgBase.isEmpty(viewstates)) { + if (Login.isEmpty(viewstates)) { enablePostButton(false); new LoadDataThread().start(); } else { @@ -545,7 +546,7 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D date = dateIn; final Button dateButton = (Button) findViewById(R.id.date); - dateButton.setText(cgBase.formatShortDate(date.getTime().getTime())); + dateButton.setText(Formatter.formatShortDate(date.getTime().getTime())); } public void setType(LogType type) { @@ -609,7 +610,7 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D setType(typeSelected); final Button dateButton = (Button) findViewById(R.id.date); - dateButton.setText(cgBase.formatShortDate(date.getTime().getTime())); + dateButton.setText(Formatter.formatShortDate(date.getTime().getTime())); dateButton.setOnClickListener(new DateListener()); final EditText logView = (EditText) findViewById(R.id.log); @@ -633,7 +634,6 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D } if (!Settings.isLogin()) { // allow offline logging showToast(res.getString(R.string.err_login)); - return; } } @@ -656,19 +656,19 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D return; } - final String page = Network.getResponseData(Network.request("http://www.geocaching.com/seek/log.aspx", params, false, false, false)); + final String page = Network.getResponseData(Network.getRequest("http://www.geocaching.com/seek/log.aspx", params)); viewstates = Login.getViewstates(page); - trackables = cgBase.parseTrackableLog(page); + trackables = GCParser.parseTrackableLog(page); - final List<LogType> typesPre = cgBase.parseTypes(page); + final List<LogType> typesPre = GCParser.parseTypes(page); if (CollectionUtils.isNotEmpty(typesPre)) { possibleLogTypes.clear(); possibleLogTypes.addAll(typesPre); possibleLogTypes.remove(LogType.LOG_UPDATE_COORDINATES); } } catch (Exception e) { - Log.e(Settings.tag, "cgeovisit.loadData.run: " + e.toString()); + Log.e("cgeovisit.loadData.run: " + e.toString()); } loadDataHandler.sendEmptyMessage(0); @@ -695,34 +695,21 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D public StatusCode postLogFn(String log) { try { - final StatusCode status = cgBase.postLog(geocode, cacheid, viewstates, typeSelected, + final StatusCode status = GCParser.postLog(geocode, cacheid, viewstates, typeSelected, date.get(Calendar.YEAR), (date.get(Calendar.MONTH) + 1), date.get(Calendar.DATE), log, trackables); if (status == StatusCode.NO_ERROR) { - final cgLog logNow = new cgLog(); - logNow.author = Settings.getUsername(); - logNow.date = date.getTimeInMillis(); - logNow.type = typeSelected; - logNow.log = log; - - if (cache != null) { - cache.prependLog(logNow); - } - app.addLog(geocode, logNow); + final LogEntry logNow = new LogEntry(date, typeSelected, log); + + cache.prependLog(logNow); + // app.saveLogs(cache); if (typeSelected == LogType.LOG_FOUND_IT) { - app.markFound(geocode); - if (cache != null) { - cache.setFound(true); - } + cache.setFound(true); } - if (cache != null) { - app.saveCache(cache, EnumSet.of(SaveFlag.SAVE_CACHE)); - } else { - app.removeCache(geocode, EnumSet.of(RemoveFlag.REMOVE_CACHE)); - } + app.saveCache(cache, EnumSet.of(SaveFlag.SAVE_CACHE)); } if (status == StatusCode.NO_ERROR) { @@ -741,7 +728,7 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D return status; } catch (Exception e) { - Log.e(Settings.tag, "cgeovisit.postLogFn: " + e.toString()); + Log.e("cgeovisit.postLogFn: " + e.toString()); } return StatusCode.LOG_POST_ERROR; @@ -765,7 +752,7 @@ public class VisitCacheActivity extends AbstractActivity implements DateDialog.D private class ActivityState { private final String[] viewstates; - private final List<cgTrackableLog> trackables; + private final List<TrackableLog> trackables; private final int attempts; private final List<LogType> possibleLogTypes; private final LogType typeSelected; diff --git a/main/src/cgeo/geocaching/activity/AbstractActivity.java b/main/src/cgeo/geocaching/activity/AbstractActivity.java index 8e8ad9d..8ddd21a 100644 --- a/main/src/cgeo/geocaching/activity/AbstractActivity.java +++ b/main/src/cgeo/geocaching/activity/AbstractActivity.java @@ -2,11 +2,10 @@ package cgeo.geocaching.activity; import cgeo.geocaching.R; import cgeo.geocaching.Settings; -import cgeo.geocaching.cgBase; import cgeo.geocaching.cgCache; import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.compatibility.Compatibility; -import cgeo.geocaching.network.Network; +import cgeo.geocaching.network.Cookies; import android.app.Activity; import android.content.Context; @@ -85,10 +84,8 @@ public abstract class AbstractActivity extends Activity implements IAbstractActi res = this.getResources(); app = (cgeoapplication) this.getApplication(); - cgBase.initialize(app); - // Restore cookie store if needed - Network.restoreCookieStore(Settings.getCookieStore()); + Cookies.restoreCookieStore(Settings.getCookieStore()); ActivityMixin.keepScreenOn(this, keepScreenOn); } @@ -131,7 +128,7 @@ public abstract class AbstractActivity extends Activity implements IAbstractActi /** * insert text into the EditText at the current cursor position - * + * * @param editText * @param insertText * @param moveCursor diff --git a/main/src/cgeo/geocaching/activity/AbstractListActivity.java b/main/src/cgeo/geocaching/activity/AbstractListActivity.java index b3bbb3f..7af75b8 100644 --- a/main/src/cgeo/geocaching/activity/AbstractListActivity.java +++ b/main/src/cgeo/geocaching/activity/AbstractListActivity.java @@ -1,6 +1,5 @@ package cgeo.geocaching.activity; -import cgeo.geocaching.cgBase; import cgeo.geocaching.cgCache; import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.compatibility.Compatibility; @@ -73,7 +72,6 @@ public abstract class AbstractListActivity extends ListActivity implements // init res = this.getResources(); app = (cgeoapplication) this.getApplication(); - cgBase.initialize(app); ActivityMixin.keepScreenOn(this, keepScreenOn); } diff --git a/main/src/cgeo/geocaching/activity/ActivityMixin.java b/main/src/cgeo/geocaching/activity/ActivityMixin.java index 0e0041a..9b1bd2a 100644 --- a/main/src/cgeo/geocaching/activity/ActivityMixin.java +++ b/main/src/cgeo/geocaching/activity/ActivityMixin.java @@ -40,7 +40,7 @@ public final class ActivityMixin { fromActivity.finish(); } - public final static void goManual(final Context context, final String helpTopic) { + public static void goManual(final Context context, final String helpTopic) { if (StringUtils.isBlank(helpTopic)) { return; } @@ -55,7 +55,7 @@ public final class ActivityMixin { } } - public final static void setTitle(final Activity activity, final String text) { + public static void setTitle(final Activity activity, final String text) { if (StringUtils.isBlank(text)) { return; } @@ -66,7 +66,7 @@ public final class ActivityMixin { } } - public final static void showProgress(final Activity activity, final boolean show) { + public static void showProgress(final Activity activity, final boolean show) { if (activity == null) { return; } @@ -79,7 +79,7 @@ public final class ActivityMixin { } } - public final static void setTheme(final Activity activity) { + public static void setTheme(final Activity activity) { if (Settings.isLightSkin()) { activity.setTheme(R.style.light); } else { @@ -87,7 +87,7 @@ public final class ActivityMixin { } } - public final static void showToast(final Activity activity, final String text) { + public static void showToast(final Activity activity, final String text) { if (StringUtils.isNotBlank(text)) { Toast toast = Toast.makeText(activity, text, Toast.LENGTH_LONG); @@ -96,7 +96,7 @@ public final class ActivityMixin { } } - public final static void showShortToast(final Activity activity, final String text) { + public static void showShortToast(final Activity activity, final String text) { if (StringUtils.isNotBlank(text)) { Toast toast = Toast.makeText(activity, text, Toast.LENGTH_SHORT); @@ -105,7 +105,7 @@ public final class ActivityMixin { } } - public static final void helpDialog(final Activity activity, final String title, final String message, final Drawable icon) { + public static void helpDialog(final Activity activity, final String title, final String message, final Drawable icon) { if (StringUtils.isBlank(message)) { return; } diff --git a/main/src/cgeo/geocaching/activity/IAbstractActivity.java b/main/src/cgeo/geocaching/activity/IAbstractActivity.java index dd22cff..2503b99 100644 --- a/main/src/cgeo/geocaching/activity/IAbstractActivity.java +++ b/main/src/cgeo/geocaching/activity/IAbstractActivity.java @@ -1,8 +1,5 @@ package cgeo.geocaching.activity; -import cgeo.geocaching.cgCache; - -import android.view.Menu; import android.view.View; public interface IAbstractActivity { @@ -13,19 +10,11 @@ public interface IAbstractActivity { public void goManual(View view); - public void showProgress(final boolean show); - - public void setTheme(); - public void showToast(String text); public void showShortToast(String text); public void helpDialog(String title, String message); - public void setTitle(final String title); - - void addVisitMenu(Menu menu, cgCache cache); - public void invalidateOptionsMenuCompatible(); } diff --git a/main/src/cgeo/geocaching/activity/Progress.java b/main/src/cgeo/geocaching/activity/Progress.java index 70f829d..dbe4700 100644 --- a/main/src/cgeo/geocaching/activity/Progress.java +++ b/main/src/cgeo/geocaching/activity/Progress.java @@ -13,6 +13,7 @@ public class Progress { private ProgressDialog dialog; private int progress = 0; + private int progressDivider = 1; public synchronized void dismiss() { if (dialog != null && dialog.isShowing()) { @@ -65,16 +66,19 @@ public class Progress { public synchronized void setMaxProgressAndReset(final int max) { if (dialog != null && dialog.isShowing()) { - dialog.setMax(max); + final int modMax = max / this.progressDivider; + dialog.setMax(modMax); dialog.setProgress(0); } + this.progress = 0; } public synchronized void setProgress(final int progress) { + final int modProgress = progress / this.progressDivider; if (dialog != null && dialog.isShowing()) { - dialog.setProgress(progress); + dialog.setProgress(modProgress); } - this.progress = progress; + this.progress = modProgress; } public synchronized int getProgress() { @@ -83,4 +87,8 @@ public class Progress { } return this.progress; } + + public synchronized void setProgressDivider(final int progressDivider) { + this.progressDivider = progressDivider; + } } diff --git a/main/src/cgeo/geocaching/apps/AbstractApp.java b/main/src/cgeo/geocaching/apps/AbstractApp.java index 1161a05..f79afe0 100644 --- a/main/src/cgeo/geocaching/apps/AbstractApp.java +++ b/main/src/cgeo/geocaching/apps/AbstractApp.java @@ -33,8 +33,7 @@ public abstract class AbstractApp implements App { try { // This can throw an exception where the exception type is only defined on API Level > 3 // therefore surround with try-catch - final Intent intent = packageManager.getLaunchIntentForPackage(packageName); - return intent; + return packageManager.getLaunchIntentForPackage(packageName); } catch (Exception e) { return null; } diff --git a/main/src/cgeo/geocaching/apps/AbstractLocusApp.java b/main/src/cgeo/geocaching/apps/AbstractLocusApp.java index 46105cd..6a239a6 100644 --- a/main/src/cgeo/geocaching/apps/AbstractLocusApp.java +++ b/main/src/cgeo/geocaching/apps/AbstractLocusApp.java @@ -1,7 +1,6 @@ package cgeo.geocaching.apps; import cgeo.geocaching.R; -import cgeo.geocaching.Settings; import cgeo.geocaching.cgCache; import cgeo.geocaching.cgWaypoint; import cgeo.geocaching.enumerations.CacheSize; @@ -37,6 +36,10 @@ public abstract class AbstractLocusApp extends AbstractApp { super(getString(R.string.caches_map_locus), INTENT); } + protected AbstractLocusApp(final String text, final String intent) { + super(text, intent); + } + @Override public boolean isInstalled(Context context) { return LocusUtils.isLocusAvailable(context); @@ -52,7 +55,7 @@ public abstract class AbstractLocusApp extends AbstractApp { * @param activity * @author koem */ - protected static boolean showInLocus(final List<? extends Object> objectsToShow, final boolean withCacheWaypoints, + protected static boolean showInLocus(final List<?> objectsToShow, final boolean withCacheWaypoints, final boolean export, final Activity activity) { if (objectsToShow == null || objectsToShow.isEmpty()) { return false; @@ -78,13 +81,13 @@ public abstract class AbstractLocusApp extends AbstractApp { } if (pd.getPoints().size() <= 1000) { - DisplayData.sendData(activity, pd, false); + DisplayData.sendData(activity, pd, export); } else { final ArrayList<PointsData> data = new ArrayList<PointsData>(); data.add(pd); DisplayData.sendDataCursor(activity, data, "content://" + LocusDataStorageProvider.class.getCanonicalName().toLowerCase(), - false); + export); } return true; @@ -108,7 +111,7 @@ public abstract class AbstractLocusApp extends AbstractApp { } // create one simple point with location - final Location loc = new Location(Settings.tag); + final Location loc = new Location("cgeo"); loc.setLatitude(cache.getCoords().getLatitude()); loc.setLongitude(cache.getCoords().getLongitude()); @@ -124,7 +127,7 @@ public abstract class AbstractLocusApp extends AbstractApp { pg.name = cache.getName(); pg.placedBy = cache.getOwner(); if (cache.getHiddenDate() != null) { - pg.hidden = ISO8601DATE.format(Long.valueOf(cache.getHiddenDate().getTime())); + pg.hidden = ISO8601DATE.format(cache.getHiddenDate().getTime()); } int locusId = toLocusType(cache.getType()); if (locusId != NO_LOCUS_ID) { @@ -187,7 +190,7 @@ public abstract class AbstractLocusApp extends AbstractApp { } // create one simple point with location - final Location loc = new Location(Settings.tag); + final Location loc = new Location("cgeo"); loc.setLatitude(waypoint.getCoords().getLatitude()); loc.setLongitude(waypoint.getCoords().getLongitude()); diff --git a/main/src/cgeo/geocaching/apps/cache/GeneralAppsFactory.java b/main/src/cgeo/geocaching/apps/cache/GeneralAppsFactory.java index a845108..49db025 100644 --- a/main/src/cgeo/geocaching/apps/cache/GeneralAppsFactory.java +++ b/main/src/cgeo/geocaching/apps/cache/GeneralAppsFactory.java @@ -1,13 +1,12 @@ package cgeo.geocaching.apps.cache; -import cgeo.geocaching.Settings; import cgeo.geocaching.cgCache; import cgeo.geocaching.apps.AbstractAppFactory; +import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.ArrayUtils; import android.app.Activity; -import android.util.Log; import android.view.Menu; import android.view.MenuItem; @@ -37,7 +36,7 @@ public final class GeneralAppsFactory extends AbstractAppFactory { try { return app.invoke(activity, cache); } catch (Exception e) { - Log.e(Settings.tag, "GeneralAppsFactory.onMenuItemSelected: " + e.toString()); + Log.e("GeneralAppsFactory.onMenuItemSelected: " + e.toString()); } } return false; diff --git a/main/src/cgeo/geocaching/apps/cache/navi/AbstractPointNavigationApp.java b/main/src/cgeo/geocaching/apps/cache/navi/AbstractPointNavigationApp.java index bf7ebb1..16b641e 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/AbstractPointNavigationApp.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/AbstractPointNavigationApp.java @@ -1,7 +1,7 @@ package cgeo.geocaching.apps.cache.navi; +import cgeo.geocaching.IGeoData; import cgeo.geocaching.cgCache; -import cgeo.geocaching.cgGeo; import cgeo.geocaching.cgWaypoint; import cgeo.geocaching.geopoint.Geopoint; @@ -24,7 +24,7 @@ abstract class AbstractPointNavigationApp extends AbstractNavigationApp { } @Override - public final boolean invoke(cgGeo geo, Activity activity, cgCache cache, cgWaypoint waypoint, Geopoint coords) { + public final boolean invoke(IGeoData geo, Activity activity, cgCache cache, cgWaypoint waypoint, Geopoint coords) { if (cache == null && waypoint == null && coords == null) { return false; } @@ -46,13 +46,24 @@ abstract class AbstractPointNavigationApp extends AbstractNavigationApp { protected abstract void navigate(Activity activity, Geopoint point); - private static Geopoint getCoordinates(cgCache cache, cgWaypoint waypoint, Geopoint coords) { + /** + * Return the first of the cache coordinates, the waypoint coordinates or the extra coordinates. <code>null</code> + * entities are skipped. + * + * @param cache a cache + * @param waypoint a waypoint + * @param coords extra coordinates + * @return the first non-null coordinates, or null if none are set + */ + private static Geopoint getCoordinates(final cgCache cache, final cgWaypoint waypoint, final Geopoint coords) { if (cache != null && cache.getCoords() != null) { return cache.getCoords(); } - else if (waypoint != null && waypoint.getCoords() != null) { + + if (waypoint != null && waypoint.getCoords() != null) { return waypoint.getCoords(); } + return coords; } }
\ No newline at end of file diff --git a/main/src/cgeo/geocaching/apps/cache/navi/CompassApp.java b/main/src/cgeo/geocaching/apps/cache/navi/CompassApp.java index 3d804d9..720b85a 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/CompassApp.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/CompassApp.java @@ -1,8 +1,8 @@ package cgeo.geocaching.apps.cache.navi; +import cgeo.geocaching.IGeoData; import cgeo.geocaching.R; import cgeo.geocaching.cgCache; -import cgeo.geocaching.cgGeo; import cgeo.geocaching.cgWaypoint; import cgeo.geocaching.cgeonavigate; import cgeo.geocaching.geopoint.Geopoint; @@ -22,7 +22,7 @@ class CompassApp extends AbstractNavigationApp { } @Override - public boolean invoke(cgGeo geo, Activity activity, cgCache cache, + public boolean invoke(IGeoData geo, Activity activity, cgCache cache, cgWaypoint waypoint, final Geopoint coords) { if (cache != null && cache.getGeocode() != null) { diff --git a/main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsApp.java b/main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsApp.java index 649823a..24aa693 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsApp.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsApp.java @@ -1,15 +1,14 @@ package cgeo.geocaching.apps.cache.navi; import cgeo.geocaching.R; -import cgeo.geocaching.Settings; import cgeo.geocaching.activity.ActivityMixin; import cgeo.geocaching.geopoint.Geopoint; +import cgeo.geocaching.utils.Log; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.net.Uri; -import android.util.Log; class GoogleMapsApp extends AbstractPointNavigationApp { @@ -32,7 +31,7 @@ class GoogleMapsApp extends AbstractPointNavigationApp { } catch (Exception e) { // nothing } - Log.i(Settings.tag, "cgBase.runExternalMap: No maps application available."); + Log.i("cgBase.runExternalMap: No maps application available."); ActivityMixin.showToast(activity, getString(R.string.err_application_no)); } diff --git a/main/src/cgeo/geocaching/apps/cache/navi/GoogleNavigationApp.java b/main/src/cgeo/geocaching/apps/cache/navi/GoogleNavigationApp.java index f94a623..fb72157 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/GoogleNavigationApp.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/GoogleNavigationApp.java @@ -1,18 +1,18 @@ package cgeo.geocaching.apps.cache.navi; +import cgeo.geocaching.IGeoData; import cgeo.geocaching.R; import cgeo.geocaching.Settings; +import cgeo.geocaching.activity.ActivityMixin; import cgeo.geocaching.cgCache; -import cgeo.geocaching.cgGeo; import cgeo.geocaching.cgWaypoint; -import cgeo.geocaching.activity.ActivityMixin; import cgeo.geocaching.geopoint.Geopoint; +import cgeo.geocaching.utils.Log; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.net.Uri; -import android.util.Log; class GoogleNavigationApp extends AbstractNavigationApp { @@ -26,7 +26,7 @@ class GoogleNavigationApp extends AbstractNavigationApp { } @Override - public boolean invoke(final cgGeo geo, final Activity activity, final cgCache cache, final cgWaypoint waypoint, final Geopoint coords) { + public boolean invoke(final IGeoData geo, final Activity activity, final cgCache cache, final cgWaypoint waypoint, final Geopoint coords) { if (activity == null) { return false; } @@ -50,8 +50,8 @@ class GoogleNavigationApp extends AbstractNavigationApp { return true; } - private static boolean navigateToCoordinates(cgGeo geo, Activity activity, final Geopoint coords) { - final Geopoint coordsNow = geo == null ? null : geo.coordsNow; + private static boolean navigateToCoordinates(IGeoData geo, Activity activity, final Geopoint coords) { + final Geopoint coordsNow = geo == null ? null : geo.getCoords(); // Google Navigation if (Settings.isUseGoogleNavigation()) { @@ -84,8 +84,7 @@ class GoogleNavigationApp extends AbstractNavigationApp { // nothing } - Log.i(Settings.tag, - "cgBase.runNavigation: No navigation application available."); + Log.i("cgBase.runNavigation: No navigation application available."); return false; } diff --git a/main/src/cgeo/geocaching/apps/cache/navi/InternalMap.java b/main/src/cgeo/geocaching/apps/cache/navi/InternalMap.java index 44f151e..2f05459 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/InternalMap.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/InternalMap.java @@ -1,8 +1,8 @@ package cgeo.geocaching.apps.cache.navi; +import cgeo.geocaching.IGeoData; import cgeo.geocaching.R; import cgeo.geocaching.cgCache; -import cgeo.geocaching.cgGeo; import cgeo.geocaching.cgWaypoint; import cgeo.geocaching.enumerations.WaypointType; import cgeo.geocaching.geopoint.Geopoint; @@ -18,7 +18,7 @@ class InternalMap extends AbstractNavigationApp { } @Override - public boolean invoke(cgGeo geo, Activity activity, cgCache cache, + public boolean invoke(IGeoData geo, Activity activity, cgCache cache, cgWaypoint waypoint, final Geopoint coords) { if (cache != null) { CGeoMap.startActivityGeoCode(activity, cache.getGeocode()); diff --git a/main/src/cgeo/geocaching/apps/cache/navi/LocusApp.java b/main/src/cgeo/geocaching/apps/cache/navi/LocusApp.java index 260d933..60e3315 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/LocusApp.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/LocusApp.java @@ -1,9 +1,9 @@ package cgeo.geocaching.apps.cache.navi; +import cgeo.geocaching.IGeoData; +import cgeo.geocaching.apps.AbstractLocusApp; import cgeo.geocaching.cgCache; -import cgeo.geocaching.cgGeo; import cgeo.geocaching.cgWaypoint; -import cgeo.geocaching.apps.AbstractLocusApp; import cgeo.geocaching.geopoint.Geopoint; import android.app.Activity; @@ -20,7 +20,7 @@ class LocusApp extends AbstractLocusApp implements NavigationApp { * @author koem */ @Override - public boolean invoke(cgGeo geo, Activity activity, cgCache cache, cgWaypoint waypoint, final Geopoint coords) { + public boolean invoke(IGeoData geo, Activity activity, cgCache cache, cgWaypoint waypoint, final Geopoint coords) { final ArrayList<Object> points = new ArrayList<Object>(); @@ -34,7 +34,7 @@ class LocusApp extends AbstractLocusApp implements NavigationApp { points.add(waypoint); } - return showInLocus(points, true, activity); + return showInLocus(points, true, false, activity); } } diff --git a/main/src/cgeo/geocaching/apps/cache/navi/NavigationApp.java b/main/src/cgeo/geocaching/apps/cache/navi/NavigationApp.java index 119d27b..62629de 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/NavigationApp.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/NavigationApp.java @@ -1,15 +1,15 @@ package cgeo.geocaching.apps.cache.navi; +import cgeo.geocaching.IGeoData; +import cgeo.geocaching.apps.App; import cgeo.geocaching.cgCache; -import cgeo.geocaching.cgGeo; import cgeo.geocaching.cgWaypoint; -import cgeo.geocaching.apps.App; import cgeo.geocaching.geopoint.Geopoint; import android.app.Activity; public interface NavigationApp extends App { - public boolean invoke(final cgGeo geo, final Activity activity, + public boolean invoke(final IGeoData geo, final Activity activity, final cgCache cache, final cgWaypoint waypoint, final Geopoint coords); } diff --git a/main/src/cgeo/geocaching/apps/cache/navi/NavigationAppFactory.java b/main/src/cgeo/geocaching/apps/cache/navi/NavigationAppFactory.java index e2a1fc1..6f179ab 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/NavigationAppFactory.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/NavigationAppFactory.java @@ -1,28 +1,24 @@ package cgeo.geocaching.apps.cache.navi; +import cgeo.geocaching.IGeoData; import cgeo.geocaching.R; -import cgeo.geocaching.SearchResult; import cgeo.geocaching.Settings; import cgeo.geocaching.StaticMapsProvider; +import cgeo.geocaching.apps.AbstractAppFactory; import cgeo.geocaching.cgCache; -import cgeo.geocaching.cgGeo; import cgeo.geocaching.cgWaypoint; import cgeo.geocaching.cgeoapplication; -import cgeo.geocaching.apps.AbstractAppFactory; import cgeo.geocaching.geopoint.Geopoint; +import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; -import android.util.Log; import android.view.Menu; import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; import android.widget.ArrayAdapter; -import android.widget.TextView; import java.util.ArrayList; import java.util.List; @@ -66,6 +62,16 @@ public final class NavigationAppFactory extends AbstractAppFactory { * The id - used in c:geo settings */ public final int id; + + /* + * display app name in array adapter + * + * @see java.lang.Enum#toString() + */ + @Override + public String toString() { + return app.getName(); + } } /** @@ -73,7 +79,7 @@ public final class NavigationAppFactory extends AbstractAppFactory { * A dialog is created for tool selection and the selected tool is started afterwards. * <p /> * Delegates to - * {@link #showNavigationMenu(cgGeo, Activity, cgCache, SearchResult, cgWaypoint, Geopoint, boolean, boolean)} with + * {@link #showNavigationMenu(IGeoData, Activity, cgCache, cgWaypoint, Geopoint, boolean, boolean)} with * <code>showInternalMap = true</code> and <code>showDefaultNavigation = false</code> * * @param geo @@ -82,7 +88,7 @@ public final class NavigationAppFactory extends AbstractAppFactory { * @param waypoint * @param destination */ - public static void showNavigationMenu(final cgGeo geo, final Activity activity, + public static void showNavigationMenu(final IGeoData geo, final Activity activity, final cgCache cache, final cgWaypoint waypoint, final Geopoint destination) { showNavigationMenu(geo, activity, cache, waypoint, destination, true, false); } @@ -104,9 +110,9 @@ public final class NavigationAppFactory extends AbstractAppFactory { * @param showDefaultNavigation * should be <code>false</code> by default * - * @see #showNavigationMenu(cgGeo, Activity, cgCache, cgWaypoint, Geopoint) + * @see #showNavigationMenu(IGeoData, Activity, cgCache, cgWaypoint, Geopoint) */ - public static void showNavigationMenu(final cgGeo geo, final Activity activity, + public static void showNavigationMenu(final IGeoData geo, final Activity activity, final cgCache cache, final cgWaypoint waypoint, final Geopoint destination, final boolean showInternalMap, final boolean showDefaultNavigation) { final AlertDialog.Builder builder = new AlertDialog.Builder(activity); @@ -127,24 +133,9 @@ public final class NavigationAppFactory extends AbstractAppFactory { } /* * Using an ArrayAdapter with list of NavigationAppsEnum items avoids - * handling between mapping list positions allows us to do dynamic filtering of the list based on usecase. + * handling between mapping list positions allows us to do dynamic filtering of the list based on use case. */ - final ArrayAdapter<NavigationAppsEnum> adapter = new ArrayAdapter<NavigationAppsEnum>(activity, android.R.layout.select_dialog_item, items) { - @Override - public View getView(int position, View convertView, ViewGroup parent) { - TextView textView = (TextView) super.getView(position, convertView, parent); - textView.setText(getItem(position).app.getName()); - return textView; - } - - @Override - public View getDropDownView(int position, View convertView, ViewGroup parent) { - TextView textView = (TextView) super.getDropDownView(position, convertView, parent); - textView.setText(getItem(position).app.getName()); - return textView; - } - }; - adapter.setDropDownViewResource(android.R.layout.select_dialog_item); + final ArrayAdapter<NavigationAppsEnum> adapter = new ArrayAdapter<NavigationAppsEnum>(activity, android.R.layout.select_dialog_item, items); builder.setAdapter(adapter, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int item) { @@ -196,10 +187,10 @@ public final class NavigationAppFactory extends AbstractAppFactory { /** * Adds the installed navigation tools to the given menu. - * Use {@link #onMenuItemSelected(MenuItem, cgGeo, Activity, cgCache, SearchResult, cgWaypoint, Geopoint)} on + * Use {@link #onMenuItemSelected(MenuItem, IGeoData, Activity, cgCache, cgWaypoint, Geopoint)} on * selection event to start the selected navigation tool. * - * <b>Only use this way if {@link #showNavigationMenu(cgGeo, Activity, cgCache, SearchResult, cgWaypoint, Geopoint)} + * <b>Only use this way if {@link #showNavigationMenu(IGeoData, Activity, cgCache, cgWaypoint, Geopoint)} * is not suitable for the given usecase.</b> * * @param menu @@ -211,11 +202,11 @@ public final class NavigationAppFactory extends AbstractAppFactory { /** * Adds the installed navigation tools to the given menu. - * Use {@link #onMenuItemSelected(MenuItem, cgGeo, Activity, cgCache, cgWaypoint, Geopoint)} on + * Use {@link #onMenuItemSelected(MenuItem, IGeoData, Activity, cgCache, cgWaypoint, Geopoint)} on * selection event to start the selected navigation tool. * * <b>Only use this way if - * {@link #showNavigationMenu(cgGeo, Activity, cgCache, cgWaypoint, Geopoint, boolean, boolean)} is + * {@link #showNavigationMenu(IGeoData, Activity, cgCache, cgWaypoint, Geopoint, boolean, boolean)} is * not suitable for the given usecase.</b> * * @param menu @@ -247,7 +238,7 @@ public final class NavigationAppFactory extends AbstractAppFactory { * @return */ public static boolean onMenuItemSelected(final MenuItem item, - final cgGeo geo, Activity activity, cgCache cache, cgWaypoint waypoint, final Geopoint destination) { + final IGeoData geo, Activity activity, cgCache cache, cgWaypoint waypoint, final Geopoint destination) { if (cache == null && waypoint == null && destination == null) { return false; } @@ -257,7 +248,7 @@ public final class NavigationAppFactory extends AbstractAppFactory { try { return app.invoke(geo, activity, cache, waypoint, destination); } catch (Exception e) { - Log.e(Settings.tag, "NavigationAppFactory.onMenuItemSelected: " + e.toString()); + Log.e("NavigationAppFactory.onMenuItemSelected: " + e.toString()); } } return false; @@ -279,11 +270,10 @@ public final class NavigationAppFactory extends AbstractAppFactory { * @param geo * @param activity * @param cache - * @param search * @param waypoint * @param destination */ - public static void startDefaultNavigationApplication(final cgGeo geo, Activity activity, cgCache cache, + public static void startDefaultNavigationApplication(final IGeoData geo, Activity activity, cgCache cache, cgWaypoint waypoint, final Geopoint destination) { final NavigationApp app = getDefaultNavigationApplication(activity); @@ -291,22 +281,21 @@ public final class NavigationAppFactory extends AbstractAppFactory { try { app.invoke(geo, activity, cache, waypoint, destination); } catch (Exception e) { - Log.e(Settings.tag, "NavigationAppFactory.startDefaultNavigationApplication: " + e.toString()); + Log.e("NavigationAppFactory.startDefaultNavigationApplication: " + e.toString()); } } } /** * Starts the second default navigation tool if correctly set and installed or the compass app as default fallback. - * + * * @param geo * @param activity * @param cache - * @param search * @param waypoint * @param destination */ - public static void startDefaultNavigationApplication2(final cgGeo geo, Activity activity, cgCache cache, + public static void startDefaultNavigationApplication2(final IGeoData geo, Activity activity, cgCache cache, cgWaypoint waypoint, final Geopoint destination) { final NavigationApp app = getDefaultNavigationApplication2(activity); @@ -314,14 +303,14 @@ public final class NavigationAppFactory extends AbstractAppFactory { try { app.invoke(geo, activity, cache, waypoint, destination); } catch (Exception e) { - Log.e(Settings.tag, "NavigationAppFactory.startDefaultNavigationApplication2: " + e.toString()); + Log.e("NavigationAppFactory.startDefaultNavigationApplication2: " + e.toString()); } } } /** * Returns the default navigation tool if correctly set and installed or the compass app as default fallback - * + * * @param activity * @return never <code>null</code> */ @@ -341,7 +330,7 @@ public final class NavigationAppFactory extends AbstractAppFactory { /** * Returns the second default navigation tool if correctly set and installed or the compass app as default fallback - * + * * @param activity * @return never <code>null</code> */ diff --git a/main/src/cgeo/geocaching/apps/cache/navi/RMapsApp.java b/main/src/cgeo/geocaching/apps/cache/navi/RMapsApp.java index a87e61b..9af90ac 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/RMapsApp.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/RMapsApp.java @@ -1,8 +1,8 @@ package cgeo.geocaching.apps.cache.navi; +import cgeo.geocaching.IGeoData; import cgeo.geocaching.R; import cgeo.geocaching.cgCache; -import cgeo.geocaching.cgGeo; import cgeo.geocaching.cgWaypoint; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.geopoint.GeopointFormatter.Format; @@ -21,7 +21,7 @@ class RMapsApp extends AbstractNavigationApp { } @Override - public boolean invoke(cgGeo geo, Activity activity, cgCache cache, cgWaypoint waypoint, final Geopoint coords) { + public boolean invoke(IGeoData geo, Activity activity, cgCache cache, cgWaypoint waypoint, final Geopoint coords) { try { final ArrayList<String> locations = new ArrayList<String>(); if (cache != null && cache.getCoords() != null) { diff --git a/main/src/cgeo/geocaching/apps/cache/navi/StaticMapApp.java b/main/src/cgeo/geocaching/apps/cache/navi/StaticMapApp.java index a0eb5a1..d8b66c2 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/StaticMapApp.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/StaticMapApp.java @@ -1,11 +1,12 @@ package cgeo.geocaching.apps.cache.navi; +import cgeo.geocaching.IGeoData; +import cgeo.geocaching.ILogable; import cgeo.geocaching.R; import cgeo.geocaching.StaticMapsActivity; +import cgeo.geocaching.activity.ActivityMixin; import cgeo.geocaching.cgCache; -import cgeo.geocaching.cgGeo; import cgeo.geocaching.cgWaypoint; -import cgeo.geocaching.activity.ActivityMixin; import cgeo.geocaching.geopoint.Geopoint; import android.app.Activity; @@ -24,26 +25,21 @@ class StaticMapApp extends AbstractNavigationApp { } @Override - public boolean invoke(cgGeo geo, Activity activity, cgCache cache, cgWaypoint waypoint, final Geopoint coords) { - - String geocode = null; - if (cache != null && cache.getListId() != 0) { - geocode = cache.getGeocode().toUpperCase(); - } - if (waypoint != null) { - geocode = waypoint.getGeocode().toUpperCase(); - } + public boolean invoke(IGeoData geo, Activity activity, cgCache cache, cgWaypoint waypoint, final Geopoint coords) { + final ILogable logable = cache != null && cache.getListId() != 0 ? cache : waypoint; + final String geocode = logable.getGeocode().toUpperCase(); if (geocode == null) { ActivityMixin.showToast(activity, getString(R.string.err_detail_no_map_static)); return true; - } else { - final Intent intent = new Intent(activity, StaticMapsActivity.class); - intent.putExtra("geocode", geocode); - if (waypoint != null) { - intent.putExtra("waypoint", waypoint.getId()); - } - activity.startActivity(intent); - return true; } + + final Intent intent = new Intent(activity, StaticMapsActivity.class); + intent.putExtra("geocode", geocode); + if (waypoint != null) { + intent.putExtra("waypoint", waypoint.getId()); + } + activity.startActivity(intent); + + return true; } } diff --git a/main/src/cgeo/geocaching/apps/cachelist/CacheListApp.java b/main/src/cgeo/geocaching/apps/cachelist/CacheListApp.java index 621aea4..45ebaff 100644 --- a/main/src/cgeo/geocaching/apps/cachelist/CacheListApp.java +++ b/main/src/cgeo/geocaching/apps/cachelist/CacheListApp.java @@ -1,9 +1,9 @@ package cgeo.geocaching.apps.cachelist; +import cgeo.geocaching.IGeoData; import cgeo.geocaching.SearchResult; -import cgeo.geocaching.cgCache; -import cgeo.geocaching.cgGeo; import cgeo.geocaching.apps.App; +import cgeo.geocaching.cgCache; import android.app.Activity; @@ -11,7 +11,7 @@ import java.util.List; interface CacheListApp extends App { - boolean invoke(final cgGeo geo, final List<cgCache> caches, + boolean invoke(final IGeoData geo, final List<cgCache> caches, final Activity activity, final SearchResult search); } diff --git a/main/src/cgeo/geocaching/apps/cachelist/CacheListAppFactory.java b/main/src/cgeo/geocaching/apps/cachelist/CacheListAppFactory.java index fd19353..fef9d2d 100644 --- a/main/src/cgeo/geocaching/apps/cachelist/CacheListAppFactory.java +++ b/main/src/cgeo/geocaching/apps/cachelist/CacheListAppFactory.java @@ -1,18 +1,15 @@ package cgeo.geocaching.apps.cachelist; +import cgeo.geocaching.IGeoData; import cgeo.geocaching.R; import cgeo.geocaching.SearchResult; -import cgeo.geocaching.Settings; -import cgeo.geocaching.cgCache; -import cgeo.geocaching.cgGeo; import cgeo.geocaching.activity.IAbstractActivity; import cgeo.geocaching.apps.AbstractAppFactory; - -import org.apache.commons.lang3.ArrayUtils; +import cgeo.geocaching.cgCache; +import cgeo.geocaching.utils.Log; import android.app.Activity; import android.content.res.Resources; -import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.SubMenu; @@ -21,15 +18,12 @@ import java.util.ArrayList; import java.util.List; public final class CacheListAppFactory extends AbstractAppFactory { - private static CacheListApp[] apps = new CacheListApp[] {}; - - private static CacheListApp[] getMultiPointNavigationApps() { - if (ArrayUtils.isEmpty(apps)) { - apps = new CacheListApp[] { - new InternalCacheListMap(), - new LocusCacheListApp() }; - } - return apps; + private static class LazyHolder { + public static final CacheListApp[] apps = { + new InternalCacheListMap(), + new LocusCacheListApp(false), + new LocusCacheListApp(true) + }; } /** @@ -38,41 +32,41 @@ public final class CacheListAppFactory extends AbstractAppFactory { * @param res * @return the added menu item (also for a sub menu, then the menu item in the parent menu is returned) */ - public static MenuItem addMenuItems(Menu menu, - Activity activity, Resources res) { - List<CacheListApp> activeApps = new ArrayList<CacheListApp>(); - for (CacheListApp app : getMultiPointNavigationApps()) { + public static MenuItem addMenuItems(final Menu menu, final Activity activity, final Resources res) { + final List<CacheListApp> activeApps = new ArrayList<CacheListApp>(LazyHolder.apps.length); + for (final CacheListApp app : LazyHolder.apps) { if (app.isInstalled(activity)) { activeApps.add(app); } } // use a new sub menu, if more than one app is available - if (activeApps.size() > 1) { - SubMenu subMenu = menu.addSubMenu(0, 101, 0, - res.getString(R.string.caches_on_map)).setIcon( - android.R.drawable.ic_menu_mapmode); - for (CacheListApp app : activeApps) { - subMenu.add(0, app.getId(), 0, app.getName()); - } - return subMenu.getItem(); - } else if (activeApps.size() == 1) { - return menu.add(0, activeApps.get(0).getId(), 0, - activeApps.get(0).getName()).setIcon(android.R.drawable.ic_menu_mapmode); + switch (activeApps.size()) { + case 0: + return null; + case 1: + return menu.add(0, activeApps.get(0).getId(), 0, + activeApps.get(0).getName()).setIcon(android.R.drawable.ic_menu_mapmode); + default: + final SubMenu subMenu = menu.addSubMenu(0, 101, 0, + res.getString(R.string.caches_on_map)).setIcon(android.R.drawable.ic_menu_mapmode); + for (final CacheListApp app : activeApps) { + subMenu.add(0, app.getId(), 0, app.getName()); + } + return subMenu.getItem(); } - return null; } public static boolean onMenuItemSelected(final MenuItem item, - final cgGeo geo, final List<cgCache> caches, final IAbstractActivity activity, + final IGeoData geo, final List<cgCache> caches, final IAbstractActivity activity, final SearchResult search) { - CacheListApp app = (CacheListApp) getAppFromMenuItem(item, apps); + final CacheListApp app = (CacheListApp) getAppFromMenuItem(item, LazyHolder.apps); if (app != null) { try { boolean result = app.invoke(geo, caches, (Activity) activity, search); activity.invalidateOptionsMenuCompatible(); return result; } catch (Exception e) { - Log.e(Settings.tag, "CacheListAppFactory.onMenuItemSelected: " + e.toString()); + Log.e("CacheListAppFactory.onMenuItemSelected: " + e.toString()); } } return false; diff --git a/main/src/cgeo/geocaching/apps/cachelist/InternalCacheListMap.java b/main/src/cgeo/geocaching/apps/cachelist/InternalCacheListMap.java index 5eaefc9..f450bbc 100644 --- a/main/src/cgeo/geocaching/apps/cachelist/InternalCacheListMap.java +++ b/main/src/cgeo/geocaching/apps/cachelist/InternalCacheListMap.java @@ -1,10 +1,10 @@ package cgeo.geocaching.apps.cachelist; +import cgeo.geocaching.IGeoData; import cgeo.geocaching.R; import cgeo.geocaching.SearchResult; -import cgeo.geocaching.cgCache; -import cgeo.geocaching.cgGeo; import cgeo.geocaching.apps.AbstractApp; +import cgeo.geocaching.cgCache; import cgeo.geocaching.maps.CGeoMap; import android.app.Activity; @@ -24,7 +24,7 @@ class InternalCacheListMap extends AbstractApp implements CacheListApp { } @Override - public boolean invoke(cgGeo geo, List<cgCache> caches, Activity activity, final SearchResult search) { + public boolean invoke(IGeoData geo, List<cgCache> caches, Activity activity, final SearchResult search) { CGeoMap.startActivitySearch(activity, search, null); return true; } diff --git a/main/src/cgeo/geocaching/apps/cachelist/LocusCacheListApp.java b/main/src/cgeo/geocaching/apps/cachelist/LocusCacheListApp.java index 0c5455c..b7557c3 100644 --- a/main/src/cgeo/geocaching/apps/cachelist/LocusCacheListApp.java +++ b/main/src/cgeo/geocaching/apps/cachelist/LocusCacheListApp.java @@ -1,18 +1,27 @@ package cgeo.geocaching.apps.cachelist; +import cgeo.geocaching.IGeoData; +import cgeo.geocaching.R; import cgeo.geocaching.SearchResult; -import cgeo.geocaching.cgCache; -import cgeo.geocaching.cgGeo; import cgeo.geocaching.apps.AbstractLocusApp; +import cgeo.geocaching.cgCache; import org.apache.commons.collections.CollectionUtils; import android.app.Activity; +import android.content.Intent; import java.util.List; class LocusCacheListApp extends AbstractLocusApp implements CacheListApp { + private boolean export; + + public LocusCacheListApp(boolean export) { + super(getString(export ? R.string.caches_map_locus_export : R.string.caches_map_locus), Intent.ACTION_VIEW); + this.export = export; + } + /** * show caches in Locus * @@ -20,12 +29,12 @@ class LocusCacheListApp extends AbstractLocusApp implements CacheListApp { * @author koem */ @Override - public boolean invoke(cgGeo geo, List<cgCache> cacheList, Activity activity, final SearchResult search) { + public boolean invoke(IGeoData geo, List<cgCache> cacheList, Activity activity, final SearchResult search) { if (CollectionUtils.isEmpty(cacheList)) { return false; } - showInLocus(cacheList, false, activity); + showInLocus(cacheList, false, export, activity); return true; } diff --git a/main/src/cgeo/geocaching/backup/CentralBackupAgent.java b/main/src/cgeo/geocaching/backup/CentralBackupAgent.java index 28b9e4b..aef2b7b 100644 --- a/main/src/cgeo/geocaching/backup/CentralBackupAgent.java +++ b/main/src/cgeo/geocaching/backup/CentralBackupAgent.java @@ -7,11 +7,11 @@ import android.app.backup.SharedPreferencesBackupHelper; public class CentralBackupAgent extends BackupAgentHelper { - static final String PREFS_BACKUP_KEY = "prefs"; + private static final String PREFS_BACKUP_KEY = "prefs"; @Override public void onCreate() { - SharedPreferencesBackupHelper helper = new SharedPreferencesBackupHelper(this, Settings.preferences); + final SharedPreferencesBackupHelper helper = new SharedPreferencesBackupHelper(this, Settings.getPreferencesName()); addHelper(PREFS_BACKUP_KEY, helper); } diff --git a/main/src/cgeo/geocaching/cgCache.java b/main/src/cgeo/geocaching/cgCache.java index b7f49e1..a426614 100644 --- a/main/src/cgeo/geocaching/cgCache.java +++ b/main/src/cgeo/geocaching/cgCache.java @@ -9,13 +9,15 @@ import cgeo.geocaching.connector.gc.GCConnector; import cgeo.geocaching.connector.gc.Tile; import cgeo.geocaching.enumerations.CacheSize; import cgeo.geocaching.enumerations.CacheType; +import cgeo.geocaching.enumerations.LoadFlags; import cgeo.geocaching.enumerations.LoadFlags.RemoveFlag; +import cgeo.geocaching.enumerations.LoadFlags.SaveFlag; import cgeo.geocaching.enumerations.LogType; import cgeo.geocaching.enumerations.WaypointType; import cgeo.geocaching.geopoint.Geopoint; -import cgeo.geocaching.geopoint.GeopointFormatter; -import cgeo.geocaching.geopoint.GeopointParser; +import cgeo.geocaching.network.HtmlImage; import cgeo.geocaching.utils.CancellableHandler; +import cgeo.geocaching.utils.Log; import cgeo.geocaching.utils.LogTemplateProvider; import org.apache.commons.collections.CollectionUtils; @@ -26,8 +28,9 @@ import android.content.Intent; import android.content.res.Resources; import android.net.Uri; import android.os.Handler; +import android.os.Message; +import android.text.Html; import android.text.Spannable; -import android.util.Log; import java.util.ArrayList; import java.util.Calendar; @@ -43,7 +46,7 @@ import java.util.regex.Pattern; /** * Internal c:geo representation of a "cache" */ -public class cgCache implements ICache { +public class cgCache implements ICache, IWaypoint { private long updated = 0; private long detailedUpdate = 0; @@ -88,7 +91,7 @@ public class cgCache implements ICache { private List<String> attributes = null; private List<cgWaypoint> waypoints = null; private ArrayList<cgImage> spoilers = null; - private List<cgLog> logs = null; + private List<LogEntry> logs = null; private List<cgTrackable> inventory = null; private Map<LogType, Integer> logCounts = new HashMap<LogType, Integer>(); private boolean logOffline = false; @@ -100,7 +103,7 @@ public class cgCache implements ICache { private String nameForSorting; private final EnumSet<StorageLocation> storageLocation = EnumSet.of(StorageLocation.HEAP); private boolean finalDefined = false; - private int zoomlevel = Tile.ZOOMLEVEL_MAX; + private int zoomlevel = Tile.ZOOMLEVEL_MAX + 1; private static final Pattern NUMBER_PATTERN = Pattern.compile("\\d+"); @@ -295,7 +298,7 @@ public class cgCache implements ICache { /** * Compare two caches quickly. For map and list fields only the references are compared ! * - * @param other + * @param other the other cache to compare this one to * @return true if both caches have the same content */ private boolean isEqualTo(final cgCache other) { @@ -309,7 +312,7 @@ public class cgCache implements ICache { premiumMembersOnly == other.premiumMembersOnly && difficulty == other.difficulty && terrain == other.terrain && - (coords != null ? coords.isEqualTo(other.coords) : null == other.coords) && + (coords != null ? coords.equals(other.coords) : null == other.coords) && reliableLatLon == other.reliableLatLon && disabled == other.disabled && archived == other.archived && @@ -366,50 +369,33 @@ public class cgCache implements ICache { cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); cal.set(Calendar.MILLISECOND, 0); - if (hidden.compareTo(cal.getTime()) < 0) { - return false; - } - return true; + return hidden.compareTo(cal.getTime()) >= 0; } /** - * checks if a page contains the guid of a cache + * Checks if a page contains the guid of a cache * - * @param cache - * the cache to look for * @param page - * the page to search in - * - * @return true: page contains guid of cache, false: otherwise + * the page to search in, may be null + * @return true if the page contains the guid of the cache, false otherwise */ - boolean isGuidContainedInPage(final String page) { - if (StringUtils.isBlank(page)) { - return false; - } - // check if the guid of the cache is anywhere in the page - if (StringUtils.isBlank(guid)) { - return false; - } - Pattern patternOk = Pattern.compile(guid, Pattern.CASE_INSENSITIVE); - Matcher matcherOk = patternOk.matcher(page); - if (matcherOk.find()) { - Log.i(Settings.tag, "cgCache.isGuidContainedInPage: guid '" + guid + "' found"); - return true; - } else { - Log.i(Settings.tag, "cgCache.isGuidContainedInPage: guid '" + guid + "' not found"); + public boolean isGuidContainedInPage(final String page) { + if (StringUtils.isBlank(page) || StringUtils.isBlank(guid)) { return false; } + final Boolean found = Pattern.compile(guid, Pattern.CASE_INSENSITIVE).matcher(page).find(); + Log.i("cgCache.isGuidContainedInPage: guid '" + guid + "' " + (found ? "" : "not ") + "found"); + return found; } public boolean isEventCache() { - return CacheType.EVENT == cacheType || CacheType.MEGA_EVENT == cacheType - || CacheType.CITO == cacheType || CacheType.LOSTANDFOUND == cacheType; + return cacheType.isEvent(); } - public boolean logVisit(IAbstractActivity fromActivity) { + public void logVisit(final IAbstractActivity fromActivity) { if (StringUtils.isBlank(cacheId)) { fromActivity.showToast(((Activity) fromActivity).getResources().getString(R.string.err_cannot_log_visit)); - return true; + return; } Intent logVisitIntent = new Intent((Activity) fromActivity, VisitCacheActivity.class); logVisitIntent.putExtra(VisitCacheActivity.EXTRAS_ID, cacheId); @@ -417,18 +403,12 @@ public class cgCache implements ICache { logVisitIntent.putExtra(VisitCacheActivity.EXTRAS_FOUND, found); ((Activity) fromActivity).startActivity(logVisitIntent); - - return true; } - public boolean logOffline(final IAbstractActivity fromActivity, final LogType logType) { - String log = ""; - if (StringUtils.isNotBlank(Settings.getSignature()) - && Settings.isAutoInsertSignature()) { - log = LogTemplateProvider.applyTemplates(Settings.getSignature(), true); - } - logOffline(fromActivity, log, Calendar.getInstance(), logType); - return true; + public void logOffline(final IAbstractActivity fromActivity, final LogType logType) { + final boolean mustIncludeSignature = StringUtils.isNotBlank(Settings.getSignature()) && Settings.isAutoInsertSignature(); + final String initial = mustIncludeSignature ? LogTemplateProvider.applyTemplates(Settings.getSignature(), true) : ""; + logOffline(fromActivity, initial, Calendar.getInstance(), logType); } void logOffline(final IAbstractActivity fromActivity, final String log, Calendar date, final LogType logType) { @@ -523,16 +503,6 @@ public class cgCache implements ICache { } @Override - public String getLatitude() { - return coords != null ? coords.format(GeopointFormatter.Format.LAT_DECMINUTE) : null; - } - - @Override - public String getLongitude() { - return coords != null ? coords.format(GeopointFormatter.Format.LON_DECMINUTE) : null; - } - - @Override public String getOwner() { return owner; } @@ -938,14 +908,10 @@ public class cgCache implements ICache { } } - if (saveToDatabase) { - return cgeoapplication.getInstance().saveWaypoints(geocode, waypoints, false); - } - - return false; + return saveToDatabase && cgeoapplication.getInstance().saveWaypoints(this); } - public List<cgLog> getLogs() { + public List<LogEntry> getLogs() { return getLogs(true); } @@ -954,15 +920,15 @@ public class cgCache implements ICache { * true for all logs, false for friend logs only * @return the logs with all entries or just the entries of the friends, never <code>null</code> */ - public List<cgLog> getLogs(boolean allLogs) { + public List<LogEntry> getLogs(boolean allLogs) { if (logs == null) { return Collections.emptyList(); } if (allLogs) { return logs; } - ArrayList<cgLog> friendLogs = new ArrayList<cgLog>(); - for (cgLog log : logs) { + ArrayList<LogEntry> friendLogs = new ArrayList<LogEntry>(); + for (LogEntry log : logs) { if (log.friend) { friendLogs.add(log); } @@ -974,7 +940,7 @@ public class cgCache implements ICache { * @param logs * the log entries */ - public void setLogs(List<cgLog> logs) { + public void setLogs(List<LogEntry> logs) { this.logs = logs; } @@ -1133,8 +1099,8 @@ public class cgCache implements ICache { * @param storageLocation * the storageLocation to set */ - public void addStorageLocation(StorageLocation sl) { - this.storageLocation.add(sl); + public void addStorageLocation(final StorageLocation storageLocation) { + this.storageLocation.add(storageLocation); } /** @@ -1167,11 +1133,7 @@ public class cgCache implements ICache { resetFinalDefined(); } - if (saveToDatabase) { - return cgeoapplication.getInstance().saveOwnWaypoint(waypoint.getId(), geocode, waypoint); - } - - return false; + return saveToDatabase && cgeoapplication.getInstance().saveOwnWaypoint(waypoint.getId(), geocode, waypoint); } public boolean hasWaypoints() { @@ -1209,30 +1171,23 @@ public class cgCache implements ICache { } /** - * @param index - * @return <code>true</code>, if the waypoint was duplicated + * Duplicate a waypoint. + * + * @param index the waypoint to duplicate + * @return <code>true</code> if the waypoint was duplicated, <code>false</code> otherwise (invalid index) */ - public boolean duplicateWaypoint(int index) { - if (!isValidWaypointIndex(index)) { + public boolean duplicateWaypoint(final int index) { + final cgWaypoint original = getWaypoint(index); + if (original == null) { return false; } - final cgWaypoint copy = new cgWaypoint(waypoints.get(index)); + final cgWaypoint copy = new cgWaypoint(original); copy.setUserDefined(); copy.setName(cgeoapplication.getInstance().getString(R.string.waypoint_copy_of) + " " + copy.getName()); waypoints.add(index + 1, copy); return cgeoapplication.getInstance().saveOwnWaypoint(-1, geocode, copy); } - private boolean isValidWaypointIndex(int index) { - if (!hasWaypoints()) { - return false; - } - if (index < 0 || index >= waypoints.size()) { - return false; - } - return true; - } - /** * delete a user defined waypoint * @@ -1240,11 +1195,11 @@ public class cgCache implements ICache { * of the waypoint in cache's waypoint list * @return <code>true</code>, if the waypoint was deleted */ - public boolean deleteWaypoint(int index) { - if (!isValidWaypointIndex(index)) { + public boolean deleteWaypoint(final int index) { + final cgWaypoint waypoint = getWaypoint(index); + if (waypoint == null) { return false; } - final cgWaypoint waypoint = waypoints.get(index); if (waypoint.isUserDefined()) { waypoints.remove(index); cgeoapplication.getInstance().deleteWaypoint(waypoint.getId()); @@ -1265,17 +1220,13 @@ public class cgCache implements ICache { * to be removed from cache * @return <code>true</code>, if the waypoint was deleted */ - public boolean deleteWaypoint(cgWaypoint waypoint) { + public boolean deleteWaypoint(final cgWaypoint waypoint) { if (waypoint.getId() <= 0) { return false; } final int index = getWaypointIndex(waypoint); - if (index >= 0) { - return deleteWaypoint(index); - } - - return false; + return index >= 0 && deleteWaypoint(index); } /** @@ -1283,38 +1234,36 @@ public class cgCache implements ICache { * * @param waypoint * to find index for - * @return index in <code>waypoints</code> if found, else -1 + * @return index in <code>waypoints</code> if found, -1 otherwise */ - private int getWaypointIndex(cgWaypoint waypoint) { - int index = 0; - - for (cgWaypoint wp : waypoints) { - if (wp.getId() == waypoint.getId()) { + private int getWaypointIndex(final cgWaypoint waypoint) { + final int id = waypoint.getId(); + for (int index = 0; index < waypoints.size(); index++) { + if (waypoints.get(index).getId() == id) { return index; } - index++; } - return -1; } /** - * @param index - * @return waypoint or <code>null</code> + * Retrieve a given waypoint. + * + * @param index the index of the waypoint + * @return waypoint or <code>null</code> if index is out of range */ - public cgWaypoint getWaypoint(int index) { - if (!isValidWaypointIndex(index)) { - return null; - } - return waypoints.get(index); + public cgWaypoint getWaypoint(final int index) { + return waypoints != null && index >= 0 && index < waypoints.size() ? waypoints.get(index) : null; } /** - * @param index + * Lookup a waypoint by its id. + * + * @param id the id of the waypoint to look for * @return waypoint or <code>null</code> */ - public cgWaypoint getWaypointById(int id) { - for (cgWaypoint waypoint : waypoints) { + public cgWaypoint getWaypointById(final int id) { + for (final cgWaypoint waypoint : waypoints) { if (waypoint.getId() == id) { return waypoint; } @@ -1333,16 +1282,16 @@ public class cgCache implements ICache { Matcher matcher = coordPattern.matcher(note); while (matcher.find()) { try { - final Geopoint point = GeopointParser.parse(note.substring(matcher.start())); + final Geopoint point = new Geopoint(note.substring(matcher.start())); // coords must have non zero latitude and longitude and at least one part shall have fractional degrees - if (point != null && point.getLatitudeE6() != 0 && point.getLongitudeE6() != 0 && ((point.getLatitudeE6() % 1000) != 0 || (point.getLongitudeE6() % 1000) != 0)) { + if (point.getLatitudeE6() != 0 && point.getLongitudeE6() != 0 && ((point.getLatitudeE6() % 1000) != 0 || (point.getLongitudeE6() % 1000) != 0)) { final String name = cgeoapplication.getInstance().getString(R.string.cache_personal_note) + " " + count; final cgWaypoint waypoint = new cgWaypoint(name, WaypointType.WAYPOINT, false); waypoint.setCoords(point); addWaypoint(waypoint, false); count++; } - } catch (GeopointParser.ParseException e) { + } catch (Geopoint.ParseException e) { // ignore } @@ -1350,7 +1299,7 @@ public class cgCache implements ICache { matcher = coordPattern.matcher(note); } } catch (Exception e) { - Log.e(Settings.tag, "cgCache.parseWaypointsFromNote: " + e.toString()); + Log.e("cgCache.parseWaypointsFromNote: " + e.toString()); } } @@ -1365,16 +1314,16 @@ public class cgCache implements ICache { return attributes != null && attributes.size() > 0; } - public void prependLog(final cgLog log) { + public void prependLog(final LogEntry log) { if (logs == null) { - logs = new ArrayList<cgLog>(); + logs = new ArrayList<LogEntry>(); } logs.add(0, log); } - public void appendLog(final cgLog log) { + public void appendLog(final LogEntry log) { if (logs == null) { - logs = new ArrayList<cgLog>(); + logs = new ArrayList<LogEntry>(); } logs.add(log); } @@ -1403,20 +1352,198 @@ public class cgCache implements ICache { if (!(obj instanceof cgCache)) { return false; } - // just compare the geocode even if that is not what "equals" normaly does - return geocode != null ? geocode.compareTo(((cgCache) obj).geocode) == 0 : false; + // just compare the geocode even if that is not what "equals" normally does + return StringUtils.isNotBlank(geocode) && geocode.equals(((cgCache) obj).geocode); } public void store(Activity activity, CancellableHandler handler) { final int listId = Math.max(getListId(), StoredList.STANDARD_LIST_ID); - cgBase.storeCache(activity, this, null, listId, handler); - } - - public int getZoomlevel() { - return this.zoomlevel; + storeCache(activity, this, null, listId, false, handler); } public void setZoomlevel(int zoomlevel) { this.zoomlevel = zoomlevel; } + + @Override + public int getId() { + return 0; + } + + @Override + public WaypointType getWaypointType() { + return null; + } + + @Override + public String getCoordType() { + return "cache"; + } + + public void drop(Handler handler) { + try { + cgeoapplication.getInstance().markDropped(Collections.singletonList(this)); + cgeoapplication.getInstance().removeCache(getGeocode(), EnumSet.of(RemoveFlag.REMOVE_CACHE)); + + handler.sendMessage(Message.obtain()); + } catch (Exception e) { + Log.e("cache.drop: ", e); + } + } + + public void checkFields() { + if (StringUtils.isBlank(getGeocode())) { + Log.e("cgBase.loadLogsFromDetails: geo code not parsed correctly"); + } + if (StringUtils.isBlank(getName())) { + Log.e("name not parsed correctly"); + } + if (StringUtils.isBlank(getGuid())) { + Log.e("guid not parsed correctly"); + } + if (getTerrain() == 0.0) { + Log.e("terrain not parsed correctly"); + } + if (getDifficulty() == 0.0) { + Log.e("difficulty not parsed correctly"); + } + if (StringUtils.isBlank(getOwner())) { + Log.e("owner not parsed correctly"); + } + if (StringUtils.isBlank(getOwnerReal())) { + Log.e("owner real not parsed correctly"); + } + if (getHiddenDate() == null) { + Log.e("hidden not parsed correctly"); + } + if (getFavoritePoints() < 0) { + Log.e("favoriteCount not parsed correctly"); + } + if (getSize() == null) { + Log.e("size not parsed correctly"); + } + if (getType() == null || getType() == CacheType.UNKNOWN) { + Log.e("type not parsed correctly"); + } + if (getCoords() == null) { + Log.e("coordinates not parsed correctly"); + } + if (StringUtils.isBlank(getLocation())) { + Log.e("location not parsed correctly"); + } + } + + public void refresh(Activity activity, int newListId, CancellableHandler handler) { + cgeoapplication.getInstance().removeCache(geocode, EnumSet.of(RemoveFlag.REMOVE_CACHE)); + storeCache(activity, null, geocode, newListId, true, handler); + } + + public static void storeCache(Activity activity, cgCache origCache, String geocode, int listId, boolean forceRedownload, CancellableHandler handler) { + try { + cgCache cache; + // get cache details, they may not yet be complete + if (origCache != null) { + // only reload the cache if it was already stored or doesn't have full details (by checking the description) + if (origCache.getListId() >= StoredList.STANDARD_LIST_ID || StringUtils.isBlank(origCache.getDescription())) { + final SearchResult search = searchByGeocode(origCache.getGeocode(), null, listId, false, handler); + cache = search.getFirstCacheFromResult(LoadFlags.LOAD_CACHE_OR_DB); + } else { + cache = origCache; + } + } else if (StringUtils.isNotBlank(geocode)) { + final SearchResult search = searchByGeocode(geocode, null, listId, forceRedownload, handler); + cache = search.getFirstCacheFromResult(LoadFlags.LOAD_CACHE_OR_DB); + } else { + cache = null; + } + + if (cache == null) { + if (handler != null) { + handler.sendMessage(Message.obtain()); + } + + return; + } + + if (CancellableHandler.isCancelled(handler)) { + return; + } + + final HtmlImage imgGetter = new HtmlImage(activity, cache.getGeocode(), false, listId, true); + + // store images from description + if (StringUtils.isNotBlank(cache.getDescription())) { + Html.fromHtml(cache.getDescription(), imgGetter, null); + } + + if (CancellableHandler.isCancelled(handler)) { + return; + } + + // store spoilers + if (CollectionUtils.isNotEmpty(cache.getSpoilers())) { + for (cgImage oneSpoiler : cache.getSpoilers()) { + imgGetter.getDrawable(oneSpoiler.getUrl()); + } + } + + if (CancellableHandler.isCancelled(handler)) { + return; + } + + // store images from logs + if (Settings.isStoreLogImages()) { + for (LogEntry log : cache.getLogs(true)) { + if (log.hasLogImages()) { + for (cgImage oneLogImg : log.getLogImages()) { + imgGetter.getDrawable(oneLogImg.getUrl()); + } + } + } + } + + if (CancellableHandler.isCancelled(handler)) { + return; + } + + // store map previews + StaticMapsProvider.downloadMaps(cache, activity); + + if (CancellableHandler.isCancelled(handler)) { + return; + } + + cache.setListId(listId); + cgeoapplication.getInstance().saveCache(cache, EnumSet.of(SaveFlag.SAVE_DB)); + + if (handler != null) { + handler.sendMessage(Message.obtain()); + } + } catch (Exception e) { + Log.e("cgBase.storeCache"); + } + } + + public static SearchResult searchByGeocode(final String geocode, final String guid, final int listId, final boolean forceReload, final CancellableHandler handler) { + if (StringUtils.isBlank(geocode) && StringUtils.isBlank(guid)) { + Log.e("cgeoBase.searchByGeocode: No geocode nor guid given"); + return null; + } + + cgeoapplication app = cgeoapplication.getInstance(); + if (!forceReload && listId == StoredList.TEMPORARY_LIST_ID && (app.isOffline(geocode, guid) || app.isThere(geocode, guid, true, true))) { + final SearchResult search = new SearchResult(); + final String realGeocode = StringUtils.isNotBlank(geocode) ? geocode : app.getGeocode(guid); + search.addGeocode(realGeocode); + return search; + } + + // if we have no geocode, we can't dynamically select the handler, but must explicitly use GC + if (geocode == null && guid != null) { + return GCConnector.getInstance().searchByGeocode(null, guid, app, handler); + } + + return ConnectorFactory.getConnector(geocode).searchByGeocode(geocode, guid, app, handler); + } + } diff --git a/main/src/cgeo/geocaching/cgCoord.java b/main/src/cgeo/geocaching/cgCoord.java deleted file mode 100644 index 236b8f5..0000000 --- a/main/src/cgeo/geocaching/cgCoord.java +++ /dev/null @@ -1,168 +0,0 @@ -package cgeo.geocaching; - -import cgeo.geocaching.enumerations.CacheSize; -import cgeo.geocaching.enumerations.CacheType; -import cgeo.geocaching.enumerations.WaypointType; -import cgeo.geocaching.geopoint.Geopoint; - -public class cgCoord implements IBasicCache, IWaypoint { - - private int id = 0; // only valid if constructed with a waypoint - private WaypointType waypointType = null; // only valid if constructed with a waypoint - private String guid = null; // only valid if constructed with a cache - private CacheType cacheType = null; // only valid if constructed with a cache - private String geocode = ""; - private String coordType = "cache"; // used values: { cache, waypoint } - private String typeSpec = CacheType.TRADITIONAL.id; - private String name = ""; - private boolean found = false; - private boolean disabled = false; - private Geopoint coords = new Geopoint(0, 0); - private float difficulty = 0; - private float terrain = 0; - private CacheSize size = CacheSize.UNKNOWN; - - public cgCoord() { - } - - public cgCoord(cgCache cache) { - guid = cache.getGuid(); - disabled = cache.isDisabled(); - found = cache.isFound(); - geocode = cache.getGeocode(); - coords = cache.getCoords(); - name = cache.getName(); - coordType = "cache"; - typeSpec = cache.getType().id; - difficulty = cache.getDifficulty(); - terrain = cache.getTerrain(); - size = cache.getSize(); - cacheType = cache.getType(); - } - - public cgCoord(cgWaypoint waypoint) { - id = waypoint.getId(); - disabled = false; - found = false; - geocode = waypoint.getGeocode(); - coords = waypoint.getCoords(); - name = waypoint.getName(); - coordType = "waypoint"; - typeSpec = waypoint.getWaypointType() != null ? waypoint.getWaypointType().id : null; - waypointType = waypoint.getWaypointType(); - } - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - @Override - public String getGeocode() { - return geocode; - } - - public void setGeocode(String geocode) { - this.geocode = geocode; - } - - public String getCoordType() { - return coordType; - } - - public void setCoordType(String type) { - this.coordType = type; - } - - public String getTypeSpec() { - return typeSpec; - } - - public void setTypeSpec(String typeSpec) { - this.typeSpec = typeSpec; - } - - @Override - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - @Override - public boolean isFound() { - return found; - } - - public void setFound(boolean found) { - this.found = found; - } - - @Override - public boolean isDisabled() { - return disabled; - } - - public void setDisabled(boolean disabled) { - this.disabled = disabled; - } - - public Geopoint getCoords() { - return coords; - } - - public void setCoords(Geopoint coords) { - this.coords = coords; - } - - @Override - public float getDifficulty() { - return difficulty; - } - - public void setDifficulty(float difficulty) { - this.difficulty = difficulty; - } - - @Override - public float getTerrain() { - return terrain; - } - - public void setTerrain(float terrain) { - this.terrain = terrain; - } - - @Override - public CacheSize getSize() { - return size; - } - - public void setSize(CacheSize size) { - this.size = size; - } - - public void setGuid(String guid) { - this.guid = guid; - } - - @Override - public String getGuid() { - return guid; - } - - @Override - public WaypointType getWaypointType() { - return waypointType; - } - - @Override - public CacheType getType() { - return cacheType; - } -} diff --git a/main/src/cgeo/geocaching/cgData.java b/main/src/cgeo/geocaching/cgData.java index 3f48b07..fd90a02 100644 --- a/main/src/cgeo/geocaching/cgData.java +++ b/main/src/cgeo/geocaching/cgData.java @@ -10,6 +10,8 @@ import cgeo.geocaching.enumerations.LogType; import cgeo.geocaching.enumerations.WaypointType; import cgeo.geocaching.files.LocalStorage; import cgeo.geocaching.geopoint.Geopoint; +import cgeo.geocaching.geopoint.Viewport; +import cgeo.geocaching.utils.Log; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; @@ -24,7 +26,6 @@ import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDoneException; import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteStatement; -import android.util.Log; import java.io.File; import java.util.ArrayList; @@ -57,6 +58,8 @@ public class cgData { "inventoryunknown", "onWatchlist", "personal_note", "reliable_latlon", "coordsChanged", "finalDefined" // reason is replaced by listId in cgCache }; + /** The list of fields needed for mapping. */ + private static final String[] WAYPOINT_COLUMNS = new String[] { "_id", "geocode", "updated", "type", "prefix", "lookup", "name", "latlon", "latitude", "longitude", "note", "own" }; /** Number of days (as ms) after temporarily saved caches are deleted */ private static long DAYS_AFTER_CACHE_IS_DELETED = 3 * 24 * 60 * 60 * 1000; @@ -68,11 +71,11 @@ public class cgData { private Context context = null; private CacheCache cacheCache = null; private String path = null; - private cgDbHelper dbHelper = null; + private DbHelper dbHelper = null; private SQLiteDatabase databaseRO = null; private SQLiteDatabase databaseRW = null; private static final int dbVersion = 62; - private static final int customListIdOffset = 10; + public static final int customListIdOffset = 10; private static final String dbName = "data"; private static final String dbTableCaches = "cg_caches"; private static final String dbTableLists = "cg_lists"; @@ -260,28 +263,28 @@ public class cgData { if (databaseRW == null || !databaseRW.isOpen()) { try { if (dbHelper == null) { - dbHelper = new cgDbHelper(context); + dbHelper = new DbHelper(context); } databaseRW = dbHelper.getWritableDatabase(); if (databaseRW != null && databaseRW.isOpen()) { - Log.i(Settings.tag, "Connection to RW database established."); + Log.i("Connection to RW database established."); } else { - Log.e(Settings.tag, "Failed to open connection to RW database."); + Log.e("Failed to open connection to RW database."); } if (databaseRW != null && databaseRW.inTransaction()) { databaseRW.endTransaction(); } } catch (Exception e) { - Log.e(Settings.tag, "cgData.openDb.RW: " + e.toString()); + Log.e("cgData.openDb.RW: " + e.toString()); } } if (databaseRO == null || !databaseRO.isOpen()) { try { if (dbHelper == null) { - dbHelper = new cgDbHelper(context); + dbHelper = new DbHelper(context); } databaseRO = dbHelper.getReadableDatabase(); @@ -290,16 +293,16 @@ public class cgData { } if (databaseRO != null && databaseRO.isOpen()) { - Log.i(Settings.tag, "Connection to RO database established."); + Log.i("Connection to RO database established."); } else { - Log.e(Settings.tag, "Failed to open connection to RO database."); + Log.e("Failed to open connection to RO database."); } if (databaseRO != null && databaseRO.inTransaction()) { databaseRO.endTransaction(); } } catch (Exception e) { - Log.e(Settings.tag, "cgData.openDb.RO: " + e.toString()); + Log.e("cgData.openDb.RO: " + e.toString()); } } @@ -324,7 +327,7 @@ public class cgData { databaseRO = null; SQLiteDatabase.releaseMemory(); - Log.d(Settings.tag, "Closing RO database"); + Log.d("Closing RO database"); } if (databaseRW != null) { @@ -338,7 +341,7 @@ public class cgData { databaseRW = null; SQLiteDatabase.releaseMemory(); - Log.d(Settings.tag, "Closing RW database"); + Log.d("Closing RW database"); } if (dbHelper != null) { @@ -359,7 +362,7 @@ public class cgData { public String backupDatabase() { if (!LocalStorage.isExternalStorageAvailable()) { - Log.w(Settings.tag, "Database wasn't backed up: no external memory"); + Log.w("Database wasn't backed up: no external memory"); return null; } @@ -368,27 +371,23 @@ public class cgData { final boolean backupDone = LocalStorage.copy(new File(path), target); init(); - if (backupDone) { - Log.i(Settings.tag, "Database was copied to " + target); - return target.getPath(); - } else { - Log.e(Settings.tag, "Database could not be copied to " + target); + if (!backupDone) { + Log.e("Database could not be copied to " + target); return null; } + + Log.i("Database was copied to " + target); + return target.getPath(); } public static File isRestoreFile() { final File fileSourceFile = backupFile(); - if (fileSourceFile.exists()) { - return fileSourceFile; - } else { - return null; - } + return fileSourceFile.exists() ? fileSourceFile : null; } public boolean restoreDatabase() { if (!LocalStorage.isExternalStorageAvailable()) { - Log.w(Settings.tag, "Database wasn't restored: no external memory"); + Log.w("Database wasn't restored: no external memory"); return false; } @@ -398,17 +397,17 @@ public class cgData { init(); if (restoreDone) { - Log.i(Settings.tag, "Database succesfully restored from " + sourceFile.getPath()); + Log.i("Database succesfully restored from " + sourceFile.getPath()); } else { - Log.e(Settings.tag, "Could not restore database from " + sourceFile.getPath()); + Log.e("Could not restore database from " + sourceFile.getPath()); } return restoreDone; } - private static class cgDbHelper extends SQLiteOpenHelper { + private static class DbHelper extends SQLiteOpenHelper { - cgDbHelper(Context context) { + DbHelper(Context context) { super(context, dbName, null, dbVersion); } @@ -451,7 +450,7 @@ public class cgData { @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - Log.i(Settings.tag, "Upgrade database from ver. " + oldVersion + " to ver. " + newVersion + ": start"); + Log.i("Upgrade database from ver. " + oldVersion + " to ver. " + newVersion + ": start"); try { if (db.isReadOnly()) { @@ -464,284 +463,19 @@ public class cgData { dropDatabase(db); onCreate(db); - Log.i(Settings.tag, "Database structure created."); + Log.i("Database structure created."); } if (oldVersion > 0) { db.execSQL("delete from " + dbTableCaches + " where reason = 0"); - if (oldVersion < 34) { // upgrade to 34 - try { - db.execSQL("create index if not exists in_a on " + dbTableCaches + " (geocode)"); - db.execSQL("create index if not exists in_b on " + dbTableCaches + " (guid)"); - db.execSQL("create index if not exists in_c on " + dbTableCaches + " (reason)"); - db.execSQL("create index if not exists in_d on " + dbTableCaches + " (detailed)"); - db.execSQL("create index if not exists in_e on " + dbTableCaches + " (type)"); - db.execSQL("create index if not exists in_a on " + dbTableAttributes + " (geocode)"); - db.execSQL("create index if not exists in_a on " + dbTableWaypoints + " (geocode)"); - db.execSQL("create index if not exists in_b on " + dbTableWaypoints + " (geocode, type)"); - db.execSQL("create index if not exists in_a on " + dbTableSpoilers + " (geocode)"); - db.execSQL("create index if not exists in_a on " + dbTableLogs + " (geocode)"); - db.execSQL("create index if not exists in_a on " + dbTableTrackables + " (geocode)"); - - Log.i(Settings.tag, "Indexes added."); - } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 34: " + e.toString()); - } - } - - if (oldVersion < 37) { // upgrade to 37 - try { - db.execSQL("alter table " + dbTableCaches + " add column direction text"); - db.execSQL("alter table " + dbTableCaches + " add column distance double"); - - Log.i(Settings.tag, "Columns direction and distance added to " + dbTableCaches + "."); - } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 37: " + e.toString()); - } - } - - if (oldVersion < 38) { // upgrade to 38 - try { - db.execSQL("drop table " + dbTableLogs); - db.execSQL(dbCreateLogs); - - Log.i(Settings.tag, "Changed type column in " + dbTableLogs + " to integer."); - } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 38: " + e.toString()); - } - } - - if (oldVersion < 39) { // upgrade to 39 - try { - db.execSQL(dbCreateLists); - - Log.i(Settings.tag, "Created lists table."); - } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 39: " + e.toString()); - } - } - - if (oldVersion < 40) { // upgrade to 40 - try { - db.execSQL("drop table " + dbTableTrackables); - db.execSQL(dbCreateTrackables); - - Log.i(Settings.tag, "Changed type of geocode column in trackables table."); - } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 40: " + e.toString()); - } - } - - if (oldVersion < 41) { // upgrade to 41 - try { - db.execSQL("alter table " + dbTableCaches + " add column rating float"); - db.execSQL("alter table " + dbTableCaches + " add column votes integer"); - db.execSQL("alter table " + dbTableCaches + " add column vote integer"); - - Log.i(Settings.tag, "Added columns for GCvote."); - } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 41: " + e.toString()); - } - } - - if (oldVersion < 42) { // upgrade to 42 - try { - db.execSQL(dbCreateLogsOffline); - - Log.i(Settings.tag, "Added table for offline logs"); - } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 42: " + e.toString()); - } - } - - if (oldVersion < 43) { // upgrade to 43 - try { - final String dbTableCachesTemp = dbTableCaches + "_temp"; - final String dbCreateCachesTemp = "" - + "create temporary table " + dbTableCachesTemp + " (" - + "_id integer primary key autoincrement, " - + "updated long not null, " - + "detailed integer not null default 0, " - + "detailedupdate long, " - + "geocode text unique not null, " - + "reason integer not null default 0, " // cached, favourite... - + "cacheid text, " - + "guid text, " - + "type text, " - + "name text, " - + "owner text, " - + "hidden long, " - + "hint text, " - + "size text, " - + "difficulty float, " - + "terrain float, " - + "latlon text, " - + "latitude_string text, " - + "longitude_string text, " - + "location text, " - + "distance double, " - + "latitude double, " - + "longitude double, " - + "shortdesc text, " - + "description text, " - + "rating float, " - + "votes integer, " - + "vote integer, " - + "disabled integer not null default 0, " - + "archived integer not null default 0, " - + "members integer not null default 0, " - + "found integer not null default 0, " - + "favourite integer not null default 0, " - + "inventorycoins integer default 0, " - + "inventorytags integer default 0, " - + "inventoryunknown integer default 0 " - + "); "; - final String dbCreateCachesNew = "" - + "create table " + dbTableCaches + " (" - + "_id integer primary key autoincrement, " - + "updated long not null, " - + "detailed integer not null default 0, " - + "detailedupdate long, " - + "geocode text unique not null, " - + "reason integer not null default 0, " // cached, favourite... - + "cacheid text, " - + "guid text, " - + "type text, " - + "name text, " - + "owner text, " - + "hidden long, " - + "hint text, " - + "size text, " - + "difficulty float, " - + "terrain float, " - + "latlon text, " - + "latitude_string text, " - + "longitude_string text, " - + "location text, " - + "direction double, " - + "distance double, " - + "latitude double, " - + "longitude double, " - + "shortdesc text, " - + "description text, " - + "rating float, " - + "votes integer, " - + "vote integer, " - + "disabled integer not null default 0, " - + "archived integer not null default 0, " - + "members integer not null default 0, " - + "found integer not null default 0, " - + "favourite integer not null default 0, " - + "inventorycoins integer default 0, " - + "inventorytags integer default 0, " - + "inventoryunknown integer default 0 " - + "); "; - - db.beginTransaction(); - db.execSQL(dbCreateCachesTemp); - db.execSQL("insert into " + dbTableCachesTemp + " select _id, updated, detailed, detailedupdate, geocode, reason, cacheid, guid, type, name, owner, hidden, hint, size, difficulty, terrain, latlon, latitude_string, longitude_string, location, distance, latitude, longitude, shortdesc, description, rating, votes, vote, disabled, archived, members, found, favourite, inventorycoins, inventorytags, inventoryunknown from " + dbTableCaches); - db.execSQL("drop table " + dbTableCaches); - db.execSQL(dbCreateCachesNew); - db.execSQL("insert into " + dbTableCaches + " select _id, updated, detailed, detailedupdate, geocode, reason, cacheid, guid, type, name, owner, hidden, hint, size, difficulty, terrain, latlon, latitude_string, longitude_string, location, null, distance, latitude, longitude, shortdesc, description, rating, votes, vote, disabled, archived, members, found, favourite, inventorycoins, inventorytags, inventoryunknown from " + dbTableCachesTemp); - db.execSQL("drop table " + dbTableCachesTemp); - db.setTransactionSuccessful(); - - Log.i(Settings.tag, "Changed direction column"); - } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 43: " + e.toString()); - } finally { - db.endTransaction(); - } - } - - if (oldVersion < 44) { // upgrade to 44 - try { - db.execSQL("alter table " + dbTableCaches + " add column favourite_cnt integer"); - - Log.i(Settings.tag, "Column favourite_cnt added to " + dbTableCaches + "."); - } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 44: " + e.toString()); - } - } - - if (oldVersion < 45) { // upgrade to 45 - try { - db.execSQL("alter table " + dbTableCaches + " add column owner_real text"); - - Log.i(Settings.tag, "Column owner_real added to " + dbTableCaches + "."); - } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 45: " + e.toString()); - } - } - - if (oldVersion < 46) { // upgrade to 46 - try { - db.execSQL("alter table " + dbTableCaches + " add column visiteddate long"); - db.execSQL("create index if not exists in_f on " + dbTableCaches + " (visiteddate, detailedupdate)"); - - Log.i(Settings.tag, "Added column for date of visit."); - } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 46: " + e.toString()); - } - } - if (oldVersion < 47) { // upgrade to 47 - try { - db.execSQL("alter table " + dbTableCaches + " add column own integer not null default 0"); - - Log.i(Settings.tag, "Added column own."); - } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 47: " + e.toString()); - } - } - - if (oldVersion < 48) { // upgrade to 48 - try { - db.execSQL("alter table " + dbTableCaches + " add column elevation double"); - - Log.i(Settings.tag, "Column elevation added to " + dbTableCaches + "."); - } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 48: " + e.toString()); - } - } - - if (oldVersion < 49) { // upgrade to 49 - try { - db.execSQL(dbCreateLogCount); - - Log.i(Settings.tag, "Created table " + dbTableLogCount + "."); - } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 49: " + e.toString()); - } - } - - if (oldVersion < 50) { // upgrade to 50 - try { - db.execSQL("alter table " + dbTableCaches + " add column myvote float"); - - Log.i(Settings.tag, "Added float column for votes to " + dbTableCaches + "."); - } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 50: " + e.toString()); - } - } - - if (oldVersion < 51) { // upgrade to 51 - try { - db.execSQL("alter table " + dbTableCaches + " add column reliable_latlon integer"); - - Log.i(Settings.tag, "Column reliable_latlon added to " + dbTableCaches + "."); - } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 51: " + e.toString()); - } - } - if (oldVersion < 52) { // upgrade to 52 try { db.execSQL(dbCreateSearchDestinationHistory); - Log.i(Settings.tag, "Added table " + dbTableSearchDestionationHistory + "."); + Log.i("Added table " + dbTableSearchDestionationHistory + "."); } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 52", e); + Log.e("Failed to upgrade to ver. 52", e); } } @@ -749,9 +483,9 @@ public class cgData { try { db.execSQL("alter table " + dbTableCaches + " add column onWatchlist integer"); - Log.i(Settings.tag, "Column onWatchlist added to " + dbTableCaches + "."); + Log.i("Column onWatchlist added to " + dbTableCaches + "."); } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 53", e); + Log.e("Failed to upgrade to ver. 53", e); } } @@ -759,7 +493,7 @@ public class cgData { try { db.execSQL(dbCreateLogImages); } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 54: " + e.toString()); + Log.e("Failed to upgrade to ver. 54: " + e.toString()); } } @@ -768,7 +502,7 @@ public class cgData { try { db.execSQL("alter table " + dbTableCaches + " add column personal_note text"); } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 55: " + e.toString()); + Log.e("Failed to upgrade to ver. 55: " + e.toString()); } } @@ -780,7 +514,7 @@ public class cgData { "lower(attribute) where attribute like \"%_yes\" " + "or attribute like \"%_no\""); } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 56: " + e.toString()); + Log.e("Failed to upgrade to ver. 56: " + e.toString()); } } @@ -795,7 +529,7 @@ public class cgData { db.execSQL("drop index in_f"); createIndices(db); } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 57: " + e.toString()); + Log.e("Failed to upgrade to ver. 57: " + e.toString()); } } @@ -883,9 +617,9 @@ public class cgData { db.setTransactionSuccessful(); - Log.i(Settings.tag, "Removed latitude_string and longitude_string columns"); + Log.i("Removed latitude_string and longitude_string columns"); } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 58", e); + Log.e("Failed to upgrade to ver. 58", e); } finally { db.endTransaction(); } @@ -897,7 +631,7 @@ public class cgData { createIndices(db); removeObsoleteCacheDirectories(db); } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 59", e); + Log.e("Failed to upgrade to ver. 59", e); } } @@ -905,7 +639,7 @@ public class cgData { try { removeSecEmptyDirs(); } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 60", e); + Log.e("Failed to upgrade to ver. 60", e); } } if (oldVersion < 61) { @@ -913,7 +647,7 @@ public class cgData { db.execSQL("alter table " + dbTableLogs + " add column friend integer"); db.execSQL("alter table " + dbTableCaches + " add column coordsChanged integer default 0"); } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 61: " + e.toString()); + Log.e("Failed to upgrade to ver. 61: " + e.toString()); } } @@ -924,7 +658,7 @@ public class cgData { db.execSQL("alter table " + dbTableWaypoints + " add column own integer default 0"); db.execSQL("update " + dbTableWaypoints + " set own = 1 where type = 'own'"); } catch (Exception e) { - Log.e(Settings.tag, "Failed to upgrade to ver. 62: " + e.toString()); + Log.e("Failed to upgrade to ver. 62: " + e.toString()); } } @@ -935,7 +669,7 @@ public class cgData { db.endTransaction(); } - Log.i(Settings.tag, "Upgrade database from ver. " + oldVersion + " to ver. " + newVersion + ": completed"); + Log.i("Upgrade database from ver. " + oldVersion + " to ver. " + newVersion + ": completed"); } } @@ -968,7 +702,7 @@ public class cgData { @Override public void run() { for (final File dir : toRemove) { - Log.i(Settings.tag, "Removing obsolete cache directory for " + dir.getName()); + Log.i("Removing obsolete cache directory for " + dir.getName()); LocalStorage.deleteDirectory(dir); } } @@ -1017,7 +751,7 @@ public class cgData { "100"); if (cursor != null) { - int index = 0; + int index; if (cursor.getCount() > 0) { cursor.moveToFirst(); @@ -1032,7 +766,7 @@ public class cgData { } } } catch (Exception e) { - Log.e(Settings.tag, "cgData.allDetailedThere: " + e.toString()); + Log.e("cgData.allDetailedThere: " + e.toString()); } if (cursor != null) { @@ -1078,7 +812,7 @@ public class cgData { } if (cursor != null) { - int index = 0; + int index; cnt = cursor.getCount(); if (cnt > 0) { @@ -1093,7 +827,7 @@ public class cgData { } } } catch (Exception e) { - Log.e(Settings.tag, "cgData.isThere: " + e.toString()); + Log.e("cgData.isThere: " + e.toString()); } if (cursor != null) { @@ -1129,7 +863,7 @@ public class cgData { public boolean isOffline(String geocode, String guid) { init(); - Cursor cursor = null; + Cursor cursor; long listId = StoredList.TEMPORARY_LIST_ID; try { @@ -1159,7 +893,7 @@ public class cgData { if (cursor != null) { final int cnt = cursor.getCount(); - int index = 0; + int index; if (cnt > 0) { cursor.moveToFirst(); @@ -1171,7 +905,7 @@ public class cgData { cursor.close(); } } catch (Exception e) { - Log.e(Settings.tag, "cgData.isOffline: " + e.toString()); + Log.e("cgData.isOffline: " + e.toString()); } return listId >= StoredList.STANDARD_LIST_ID; @@ -1192,7 +926,7 @@ public class cgData { } catch (SQLiteDoneException e) { // Do nothing, it only means we have no information on the cache } catch (Exception e) { - Log.e(Settings.tag, "cgData.getGeocodeForGuid", e); + Log.e("cgData.getGeocodeForGuid", e); } return null; @@ -1213,7 +947,7 @@ public class cgData { } catch (SQLiteDoneException e) { // Do nothing, it only means we have no information on the cache } catch (Exception e) { - Log.e(Settings.tag, "cgData.getCacheidForGeocode", e); + Log.e("cgData.getCacheidForGeocode", e); } return null; @@ -1254,7 +988,7 @@ public class cgData { cache.addStorageLocation(StorageLocation.DATABASE); cacheCache.putCacheInCache(cache); - Log.d(Settings.tag, "Saving " + cache.toString() + " (" + cache.getListId() + ") to DB"); + Log.d("Saving " + cache.toString() + " (" + cache.getListId() + ") to DB"); ContentValues values = new ContentValues(); @@ -1308,55 +1042,20 @@ public class cgData { values.put("coordsChanged", cache.hasUserModifiedCoords() ? 1 : 0); values.put("finalDefined", cache.hasFinalDefined() ? 1 : 0); - boolean statusOk = true; - - if (cache.hasAttributes()) { - if (!saveAttributes(cache.getGeocode(), cache.getAttributes())) { - statusOk = false; - } - } - - if (cache.hasWaypoints()) { - if (!saveWaypoints(cache.getGeocode(), cache.getWaypoints(), true)) { - statusOk = false; - } - } - - if (cache.getSpoilers() != null) { - if (!saveSpoilers(cache.getGeocode(), cache.getSpoilers())) { - statusOk = false; - } - } - - if (CollectionUtils.isNotEmpty(cache.getLogs())) { - if (!saveLogs(cache.getGeocode(), cache.getLogs())) { - statusOk = false; - } - } - - if (MapUtils.isNotEmpty(cache.getLogCounts())) { - if (!saveLogCount(cache.getGeocode(), cache.getLogCounts())) { - statusOk = false; - } - } - - if (cache.getInventory() != null) { - if (!saveInventory(cache.getGeocode(), cache.getInventory())) { - statusOk = false; - } - } - - if (!statusOk) { - cache.setDetailed(false); - cache.setDetailedUpdate(0L); - } - + boolean result = false; init(); //try to update record else insert fresh.. - boolean result = false; databaseRW.beginTransaction(); + try { + saveAttributesWithoutTransaction(cache); + saveWaypointsWithoutTransaction(cache); + saveSpoilersWithoutTransaction(cache); + saveLogsWithoutTransaction(cache.getGeocode(), cache.getLogs()); + saveLogCountsWithoutTransaction(cache); + saveInventoryWithoutTransaction(cache.getGeocode(), cache.getInventory()); + int rows = databaseRW.update(dbTableCaches, values, "geocode = ?", new String[] { cache.getGeocode() }); if (rows == 0) { // cache is not in the DB, insert it @@ -1370,129 +1069,102 @@ public class cgData { databaseRW.endTransaction(); } - values = null; return result; } - public boolean saveAttributes(String geocode, List<String> attributes) { - if (StringUtils.isBlank(geocode) || attributes == null) { - return false; - } + private void saveAttributesWithoutTransaction(final cgCache cache) { + String geocode = cache.getGeocode(); + databaseRW.delete(dbTableAttributes, "geocode = ?", new String[] { geocode }); - init(); + final List<String> attributes = cache.getAttributes(); + if (CollectionUtils.isNotEmpty(attributes)) { - databaseRW.beginTransaction(); - try { - databaseRW.delete(dbTableAttributes, "geocode = ?", new String[] { geocode }); - - if (!attributes.isEmpty()) { - - InsertHelper helper = new InsertHelper(databaseRW, dbTableAttributes); - long timeStamp = System.currentTimeMillis(); + InsertHelper helper = new InsertHelper(databaseRW, dbTableAttributes); + long timeStamp = System.currentTimeMillis(); - for (String attribute : attributes) { - helper.prepareForInsert(); + for (String attribute : attributes) { + helper.prepareForInsert(); - helper.bind(ATTRIBUTES_GEOCODE, geocode); - helper.bind(ATTRIBUTES_UPDATED, timeStamp); - helper.bind(ATTRIBUTES_ATTRIBUTE, attribute); + helper.bind(ATTRIBUTES_GEOCODE, geocode); + helper.bind(ATTRIBUTES_UPDATED, timeStamp); + helper.bind(ATTRIBUTES_ATTRIBUTE, attribute); - helper.execute(); - } - helper.close(); + helper.execute(); } - databaseRW.setTransactionSuccessful(); - } finally { - databaseRW.endTransaction(); + helper.close(); } - - return true; } /** * Persists the given <code>destination</code> into the database. * - * @param destinations - * @return <code>true</code> if the given destination was successfully - * persisted <code>false</code> otherwise. + * @param destination + * a destination to save */ - public boolean saveSearchedDestination(cgDestination destination) { - boolean success = true; - - if (destination == null) { - success = false; - } else { - init(); - - databaseRW.beginTransaction(); + public void saveSearchedDestination(final Destination destination) { + init(); - try { - ContentValues values = new ContentValues(); - values.put("date", destination.getDate()); - putCoords(values, destination.getCoords()); + databaseRW.beginTransaction(); - long id = databaseRW.insert(dbTableSearchDestionationHistory, null, values); - destination.setId(id); - databaseRW.setTransactionSuccessful(); - } catch (Exception e) { - success = false; - Log.e(Settings.tag, "Updating searchedDestinations db failed", e); - } finally { - databaseRW.endTransaction(); - } + try { + ContentValues values = new ContentValues(); + values.put("date", destination.getDate()); + putCoords(values, destination.getCoords()); + databaseRW.insert(dbTableSearchDestionationHistory, null, values); + databaseRW.setTransactionSuccessful(); + } catch (Exception e) { + Log.e("Updating searchedDestinations db failed", e); + } finally { + databaseRW.endTransaction(); } - - return success; } - public boolean saveWaypoints(String geocode, List<cgWaypoint> waypoints, boolean drop) { - if (StringUtils.isBlank(geocode) || waypoints == null) { - return false; - } - + public boolean saveWaypoints(final cgCache cache) { + boolean result = false; init(); - - Log.d(Settings.tag, "cgData.saveWaypoints(drop=" + drop + ")"); - - boolean ok = false; databaseRW.beginTransaction(); - try { - if (drop) { - databaseRW.delete(dbTableWaypoints, "geocode = ? and type <> ? and own = 0", new String[] { geocode, "own" }); - } - - if (!waypoints.isEmpty()) { - ContentValues values = new ContentValues(); - long timeStamp = System.currentTimeMillis(); - for (cgWaypoint oneWaypoint : waypoints) { - if (oneWaypoint.isUserDefined()) { - continue; - } - - values.clear(); - values.put("geocode", geocode); - values.put("updated", timeStamp); - values.put("type", oneWaypoint.getWaypointType() != null ? oneWaypoint.getWaypointType().id : null); - values.put("prefix", oneWaypoint.getPrefix()); - values.put("lookup", oneWaypoint.getLookup()); - values.put("name", oneWaypoint.getName()); - values.put("latlon", oneWaypoint.getLatlon()); - putCoords(values, oneWaypoint.getCoords()); - values.put("note", oneWaypoint.getNote()); - values.put("own", oneWaypoint.isUserDefined() ? 1 : 0); - - final long rowId = databaseRW.insert(dbTableWaypoints, null, values); - oneWaypoint.setId((int) rowId); - } - } + try { + saveWaypointsWithoutTransaction(cache); databaseRW.setTransactionSuccessful(); - ok = true; + result = true; + } catch (Exception e) { + Log.e("saveWaypoints", e); } finally { databaseRW.endTransaction(); } + return result; + } - return ok; + private void saveWaypointsWithoutTransaction(final cgCache cache) { + String geocode = cache.getGeocode(); + databaseRW.delete(dbTableWaypoints, "geocode = ? and type <> ? and own = 0", new String[] { geocode, "own" }); + + List<cgWaypoint> waypoints = cache.getWaypoints(); + if (CollectionUtils.isNotEmpty(waypoints)) { + ContentValues values = new ContentValues(); + long timeStamp = System.currentTimeMillis(); + for (cgWaypoint oneWaypoint : waypoints) { + if (oneWaypoint.isUserDefined()) { + continue; + } + + values.clear(); + values.put("geocode", geocode); + values.put("updated", timeStamp); + values.put("type", oneWaypoint.getWaypointType() != null ? oneWaypoint.getWaypointType().id : null); + values.put("prefix", oneWaypoint.getPrefix()); + values.put("lookup", oneWaypoint.getLookup()); + values.put("name", oneWaypoint.getName()); + values.put("latlon", oneWaypoint.getLatlon()); + putCoords(values, oneWaypoint.getCoords()); + values.put("note", oneWaypoint.getNote()); + values.put("own", oneWaypoint.isUserDefined() ? 1 : 0); + + final long rowId = databaseRW.insert(dbTableWaypoints, null, values); + oneWaypoint.setId((int) rowId); + } + } } /** @@ -1555,11 +1227,7 @@ public class cgData { ok = true; } else { final int rows = databaseRW.update(dbTableWaypoints, values, "_id = " + id, null); - if (rows > 0) { - ok = true; - } else { - ok = false; - } + ok = rows > 0; } databaseRW.setTransactionSuccessful(); } finally { @@ -1576,121 +1244,72 @@ public class cgData { init(); - int deleted = databaseRW.delete(dbTableWaypoints, "_id = " + id, null); - - if (deleted > 0) { - return true; - } - - return false; + return databaseRW.delete(dbTableWaypoints, "_id = " + id, null) > 0; } - public boolean saveSpoilers(String geocode, List<cgImage> spoilers) { - if (StringUtils.isBlank(geocode) || spoilers == null) { - return false; - } - - init(); - - databaseRW.beginTransaction(); - try { - databaseRW.delete(dbTableSpoilers, "geocode = ?", new String[] { geocode }); + private void saveSpoilersWithoutTransaction(final cgCache cache) { + String geocode = cache.getGeocode(); + databaseRW.delete(dbTableSpoilers, "geocode = ?", new String[] { geocode }); - if (!spoilers.isEmpty()) { - ContentValues values = new ContentValues(); - long timeStamp = System.currentTimeMillis(); - for (cgImage oneSpoiler : spoilers) { - values.clear(); - values.put("geocode", geocode); - values.put("updated", timeStamp); - values.put("url", oneSpoiler.getUrl()); - values.put("title", oneSpoiler.getTitle()); - values.put("description", oneSpoiler.getDescription()); + List<cgImage> spoilers = cache.getSpoilers(); + if (CollectionUtils.isNotEmpty(spoilers)) { + ContentValues values = new ContentValues(); + long timeStamp = System.currentTimeMillis(); + for (cgImage spoiler : spoilers) { + values.clear(); + values.put("geocode", geocode); + values.put("updated", timeStamp); + values.put("url", spoiler.getUrl()); + values.put("title", spoiler.getTitle()); + values.put("description", spoiler.getDescription()); - databaseRW.insert(dbTableSpoilers, null, values); - } + databaseRW.insert(dbTableSpoilers, null, values); } - databaseRW.setTransactionSuccessful(); - } finally { - databaseRW.endTransaction(); } - - return true; } - public boolean saveLogs(String geocode, List<cgLog> logs) { - return saveLogs(geocode, logs, true); - } + private void saveLogsWithoutTransaction(final String geocode, final List<LogEntry> logs) { + // TODO delete logimages referring these logs + databaseRW.delete(dbTableLogs, "geocode = ?", new String[] { geocode }); - public boolean saveLogs(String geocode, List<cgLog> logs, boolean drop) { - if (StringUtils.isBlank(geocode) || logs == null) { - return false; - } - - init(); - - databaseRW.beginTransaction(); - try { - if (drop) { - // TODO delete logimages referring these logs - databaseRW.delete(dbTableLogs, "geocode = ?", new String[] { geocode }); - } - - if (!logs.isEmpty()) { - InsertHelper helper = new InsertHelper(databaseRW, dbTableLogs); - long timeStamp = System.currentTimeMillis(); - for (cgLog log : logs) { - helper.prepareForInsert(); - - helper.bind(LOGS_GEOCODE, geocode); - helper.bind(LOGS_UPDATED, timeStamp); - helper.bind(LOGS_TYPE, log.type.id); - helper.bind(LOGS_AUTHOR, log.author); - helper.bind(LOGS_LOG, log.log); - helper.bind(LOGS_DATE, log.date); - helper.bind(LOGS_FOUND, log.found); - helper.bind(LOGS_FRIEND, log.friend); - - long log_id = helper.execute(); - - if (CollectionUtils.isNotEmpty(log.logImages)) { - ContentValues values = new ContentValues(); - for (cgImage img : log.logImages) { - values.clear(); - values.put("log_id", log_id); - values.put("title", img.getTitle()); - values.put("url", img.getUrl()); - databaseRW.insert(dbTableLogImages, null, values); - } + if (CollectionUtils.isNotEmpty(logs)) { + InsertHelper helper = new InsertHelper(databaseRW, dbTableLogs); + long timeStamp = System.currentTimeMillis(); + for (LogEntry log : logs) { + helper.prepareForInsert(); + + helper.bind(LOGS_GEOCODE, geocode); + helper.bind(LOGS_UPDATED, timeStamp); + helper.bind(LOGS_TYPE, log.type.id); + helper.bind(LOGS_AUTHOR, log.author); + helper.bind(LOGS_LOG, log.log); + helper.bind(LOGS_DATE, log.date); + helper.bind(LOGS_FOUND, log.found); + helper.bind(LOGS_FRIEND, log.friend); + + long log_id = helper.execute(); + + if (log.hasLogImages()) { + ContentValues values = new ContentValues(); + for (cgImage img : log.getLogImages()) { + values.clear(); + values.put("log_id", log_id); + values.put("title", img.getTitle()); + values.put("url", img.getUrl()); + databaseRW.insert(dbTableLogImages, null, values); } } - helper.close(); } - databaseRW.setTransactionSuccessful(); - } finally { - databaseRW.endTransaction(); + helper.close(); } - - return true; - } - - public boolean saveLogCount(String geocode, Map<LogType, Integer> logCounts) { - return saveLogCount(geocode, logCounts, true); } - public boolean saveLogCount(String geocode, Map<LogType, Integer> logCounts, boolean drop) { - if (StringUtils.isBlank(geocode) || MapUtils.isEmpty(logCounts)) { - return false; - } - - init(); - - databaseRW.beginTransaction(); - try { - if (drop) { - databaseRW.delete(dbTableLogCount, "geocode = ?", new String[] { geocode }); - } + private void saveLogCountsWithoutTransaction(final cgCache cache) { + String geocode = cache.getGeocode(); + databaseRW.delete(dbTableLogCount, "geocode = ?", new String[] { geocode }); + Map<LogType, Integer> logCounts = cache.getLogCounts(); + if (MapUtils.isNotEmpty(logCounts)) { ContentValues values = new ContentValues(); Set<Entry<LogType, Integer>> logCountsItems = logCounts.entrySet(); @@ -1704,6 +1323,15 @@ public class cgData { databaseRW.insert(dbTableLogCount, null, values); } + } + } + + public boolean saveTrackable(final cgTrackable trackable) { + init(); + + databaseRW.beginTransaction(); + try { + saveInventoryWithoutTransaction(null, Collections.singletonList(trackable)); databaseRW.setTransactionSuccessful(); } finally { databaseRW.endTransaction(); @@ -1712,81 +1340,46 @@ public class cgData { return true; } - public boolean saveInventory(String geocode, List<cgTrackable> trackables) { - if (trackables == null) { - return false; + private void saveInventoryWithoutTransaction(final String geocode, final List<cgTrackable> trackables) { + if (geocode != null) { + databaseRW.delete(dbTableTrackables, "geocode = ?", new String[] { geocode }); } - init(); - - databaseRW.beginTransaction(); - try { - if (geocode != null) { - databaseRW.delete(dbTableTrackables, "geocode = ?", new String[] { geocode }); - } - - if (!trackables.isEmpty()) { - ContentValues values = new ContentValues(); - long timeStamp = System.currentTimeMillis(); - for (cgTrackable oneTrackable : trackables) { - values.clear(); - if (geocode != null) { - values.put("geocode", geocode); - } - values.put("updated", timeStamp); - values.put("tbcode", oneTrackable.getGeocode()); - values.put("guid", oneTrackable.getGuid()); - values.put("title", oneTrackable.getName()); - values.put("owner", oneTrackable.getOwner()); - if (oneTrackable.getReleased() != null) { - values.put("released", oneTrackable.getReleased().getTime()); - } else { - values.put("released", 0L); - } - values.put("goal", oneTrackable.getGoal()); - values.put("description", oneTrackable.getDetails()); + if (CollectionUtils.isNotEmpty(trackables)) { + ContentValues values = new ContentValues(); + long timeStamp = System.currentTimeMillis(); + for (cgTrackable trackable : trackables) { + values.clear(); + if (geocode != null) { + values.put("geocode", geocode); + } + values.put("updated", timeStamp); + values.put("tbcode", trackable.getGeocode()); + values.put("guid", trackable.getGuid()); + values.put("title", trackable.getName()); + values.put("owner", trackable.getOwner()); + if (trackable.getReleased() != null) { + values.put("released", trackable.getReleased().getTime()); + } else { + values.put("released", 0L); + } + values.put("goal", trackable.getGoal()); + values.put("description", trackable.getDetails()); - databaseRW.insert(dbTableTrackables, null, values); + databaseRW.insert(dbTableTrackables, null, values); - saveLogs(oneTrackable.getGeocode(), oneTrackable.getLogs()); - } + saveLogsWithoutTransaction(trackable.getGeocode(), trackable.getLogs()); } - databaseRW.setTransactionSuccessful(); - } finally { - databaseRW.endTransaction(); } - - return true; } - public List<Number> getBounds(Set<String> geocodes) { + public Viewport getBounds(final Set<String> geocodes) { if (CollectionUtils.isEmpty(geocodes)) { return null; } final Set<cgCache> caches = loadCaches(geocodes, LoadFlags.LOAD_CACHE_OR_DB); - - double latMin = 360.0; - double latMax = -360.0; - double lonMin = 360.0; - double lonMax = -360.0; - for (cgCache cache : caches) { - final Geopoint coords = cache.getCoords(); - double latitude = coords.getLatitude(); - latMin = Math.min(latitude, latMin); - latMax = Math.max(latitude, latMax); - double longitude = coords.getLongitude(); - lonMin = Math.min(longitude, lonMin); - lonMax = Math.max(longitude, lonMax); - } - - final List<Number> viewport = new ArrayList<Number>(); - viewport.add(caches.size()); - viewport.add(latMin); - viewport.add(latMax); - viewport.add(lonMin); - viewport.add(lonMax); - return viewport; + return Viewport.containing(caches); } /** @@ -1837,12 +1430,10 @@ public class cgData { loadFlags.contains(LoadFlag.LOAD_INVENTORY) || loadFlags.contains(LoadFlag.LOAD_OFFLINE_LOG)) { - Set<cgCache> cachesFromDB = loadCaches(remaining, null, null, null, null, loadFlags); - if (cachesFromDB != null) { - result.addAll(cachesFromDB); - for (cgCache cache : cachesFromDB) { - remaining.remove(cache.getGeocode()); - } + final Set<cgCache> cachesFromDB = loadCachesFromGeocodes(remaining, loadFlags); + result.addAll(cachesFromDB); + for (final cgCache cache : cachesFromDB) { + remaining.remove(cache.getGeocode()); } } @@ -1857,7 +1448,7 @@ public class cgData { } if (remaining.size() >= 1) { - Log.e(Settings.tag, "cgData.loadCaches(" + remaining.toString() + ") failed"); + Log.e("cgData.loadCaches(" + remaining.toString() + ") failed"); } return result; } @@ -1866,150 +1457,107 @@ public class cgData { * Load caches. * * @param geocodes - * OR - * @param centerLat - * @param centerLon - * @param spanLat - * @param spanLon * @param loadFlags * @return Set of loaded caches. Never null. */ - public Set<cgCache> loadCaches(final Set<String> geocodes, final Long centerLat, final Long centerLon, final Long spanLat, final Long spanLon, final EnumSet<LoadFlag> loadFlags) { - final Set<cgCache> caches = new HashSet<cgCache>(); + private Set<cgCache> loadCachesFromGeocodes(final Set<String> geocodes, final EnumSet<LoadFlag> loadFlags) { if (CollectionUtils.isEmpty(geocodes)) { - return caches; - } - // Using more than one of the parametersets results in overly comlex wheres - if (CollectionUtils.isNotEmpty(geocodes) - && centerLat != null - && centerLon != null - && spanLat != null - && spanLon != null) { - throw new IllegalArgumentException("Please use only one parameter"); + return Collections.emptySet(); } - Log.d(Settings.tag, "cgData.loadCaches(" + geocodes.toString() + ") from DB"); + + Log.d("cgData.loadCachesFromGeocodes(" + geocodes.toString() + ") from DB"); init(); - Cursor cursor = null; + final Cursor cursor = databaseRO.query( + dbTableCaches, + CACHE_COLUMNS, + cgData.whereGeocodeIn(geocodes), + null, + null, + null, + null, + null); try { - StringBuilder where = cgData.whereGeocodeIn(geocodes); - - // viewport limitation - if (centerLat != null && centerLon != null && spanLat != null && spanLon != null) { - double latMin = (centerLat / 1e6) - ((spanLat / 1e6) / 2) - ((spanLat / 1e6) / 4); - double latMax = (centerLat / 1e6) + ((spanLat / 1e6) / 2) + ((spanLat / 1e6) / 4); - double lonMin = (centerLon / 1e6) - ((spanLon / 1e6) / 2) - ((spanLon / 1e6) / 4); - double lonMax = (centerLon / 1e6) + ((spanLon / 1e6) / 2) + ((spanLon / 1e6) / 4); - double llCache; - - if (latMin > latMax) { - llCache = latMax; - latMax = latMin; - latMin = llCache; - } - if (lonMin > lonMax) { - llCache = lonMax; - lonMax = lonMin; - lonMin = llCache; - } - - if (where.length() > 0) { - where.append(" and "); - } - where.append("(latitude >= "); - where.append(String.format((Locale) null, "%.6f", latMin)); - where.append(" and latitude <= "); - where.append(String.format((Locale) null, "%.6f", latMax)); - where.append(" and longitude >= "); - where.append(String.format((Locale) null, "%.6f", lonMin)); - where.append(" and longitude <= "); - where.append(String.format((Locale) null, "%.6f", lonMax)); - where.append(')'); + if (!cursor.moveToFirst()) { + return Collections.emptySet(); } - cursor = databaseRO.query( - dbTableCaches, - CACHE_COLUMNS, - where.toString(), - null, - null, - null, - null, - null); - if (cursor != null) { - if (cursor.getCount() > 0) { - cursor.moveToFirst(); - - do { - //Extracted Method = LOADDBMINIMAL - cgCache cache = cgData.createCacheFromDatabaseContent(cursor); - - if (loadFlags.contains(LoadFlag.LOAD_ATTRIBUTES)) { - cache.setAttributes(loadAttributes(cache.getGeocode())); - } + final Set<cgCache> caches = new HashSet<cgCache>(); + do { + //Extracted Method = LOADDBMINIMAL + cgCache cache = cgData.createCacheFromDatabaseContent(cursor); - if (loadFlags.contains(LoadFlag.LOAD_WAYPOINTS)) { - final List<cgWaypoint> waypoints = loadWaypoints(cache.getGeocode()); - if (CollectionUtils.isNotEmpty(waypoints)) { - cache.setWaypoints(waypoints, false); - } - } + if (loadFlags.contains(LoadFlag.LOAD_ATTRIBUTES)) { + cache.setAttributes(loadAttributes(cache.getGeocode())); + } - if (loadFlags.contains(LoadFlag.LOAD_SPOILERS)) { - final List<cgImage> spoilers = loadSpoilers(cache.getGeocode()); - if (CollectionUtils.isNotEmpty(spoilers)) { - if (cache.getSpoilers() == null) { - cache.setSpoilers(new ArrayList<cgImage>()); - } else { - cache.getSpoilers().clear(); - } - cache.getSpoilers().addAll(spoilers); - } - } + if (loadFlags.contains(LoadFlag.LOAD_WAYPOINTS)) { + final List<cgWaypoint> waypoints = loadWaypoints(cache.getGeocode()); + if (CollectionUtils.isNotEmpty(waypoints)) { + cache.setWaypoints(waypoints, false); + } + } - if (loadFlags.contains(LoadFlag.LOAD_LOGS)) { - cache.setLogs(loadLogs(cache.getGeocode())); - final Map<LogType, Integer> logCounts = loadLogCounts(cache.getGeocode()); - if (MapUtils.isNotEmpty(logCounts)) { - cache.getLogCounts().clear(); - cache.getLogCounts().putAll(logCounts); - } + if (loadFlags.contains(LoadFlag.LOAD_SPOILERS)) { + final List<cgImage> spoilers = loadSpoilers(cache.getGeocode()); + if (CollectionUtils.isNotEmpty(spoilers)) { + if (cache.getSpoilers() == null) { + cache.setSpoilers(new ArrayList<cgImage>()); + } else { + cache.getSpoilers().clear(); } + cache.getSpoilers().addAll(spoilers); + } + } - if (loadFlags.contains(LoadFlag.LOAD_INVENTORY)) { - final List<cgTrackable> inventory = loadInventory(cache.getGeocode()); - if (CollectionUtils.isNotEmpty(inventory)) { - if (cache.getInventory() == null) { - cache.setInventory(new ArrayList<cgTrackable>()); - } else { - cache.getInventory().clear(); - } - cache.getInventory().addAll(inventory); - } - } + if (loadFlags.contains(LoadFlag.LOAD_LOGS)) { + cache.setLogs(loadLogs(cache.getGeocode())); + final Map<LogType, Integer> logCounts = loadLogCounts(cache.getGeocode()); + if (MapUtils.isNotEmpty(logCounts)) { + cache.getLogCounts().clear(); + cache.getLogCounts().putAll(logCounts); + } + } - if (loadFlags.contains(LoadFlag.LOAD_OFFLINE_LOG)) { - cache.setLogOffline(hasLogOffline(cache.getGeocode())); + if (loadFlags.contains(LoadFlag.LOAD_INVENTORY)) { + final List<cgTrackable> inventory = loadInventory(cache.getGeocode()); + if (CollectionUtils.isNotEmpty(inventory)) { + if (cache.getInventory() == null) { + cache.setInventory(new ArrayList<cgTrackable>()); + } else { + cache.getInventory().clear(); } - cache.addStorageLocation(StorageLocation.DATABASE); - cacheCache.putCacheInCache(cache); + cache.getInventory().addAll(inventory); + } + } - caches.add(cache); - } while (cursor.moveToNext()); + if (loadFlags.contains(LoadFlag.LOAD_OFFLINE_LOG)) { + cache.setLogOffline(hasLogOffline(cache.getGeocode())); } - } - } catch (Exception e) { - Log.e(Settings.tag, "cgData.getCaches: " + e.toString()); - } + cache.addStorageLocation(StorageLocation.DATABASE); + cacheCache.putCacheInCache(cache); - if (cursor != null) { + caches.add(cache); + } while (cursor.moveToNext()); + return caches; + } finally { cursor.close(); } + } - return caches; + /** + * Builds a where for a viewport with the size enhanced by 50%. + * + * @param dbTable + * @param viewport + * @return + */ + + private static String buildCoordinateWhere(final String dbTable, final Viewport viewport) { + return viewport.resize(1.5).sqlWhere(dbTable); } /** @@ -2128,7 +1676,7 @@ public class cgData { cache.setUserModifiedCoords(cursor.getInt(cacheColumnIndex[37]) > 0); cache.setFinalDefined(cursor.getInt(cacheColumnIndex[40]) > 0); - Log.d(Settings.tag, "Loading " + cache.toString() + " (" + cache.getListId() + ") from DB"); + Log.d("Loading " + cache.toString() + " (" + cache.getListId() + ") from DB"); return cache; } @@ -2179,7 +1727,7 @@ public class cgData { Cursor cursor = databaseRO.query( dbTableWaypoints, - new String[] { "_id", "geocode", "updated", "type", "prefix", "lookup", "name", "latlon", "latitude", "longitude", "note", "own" }, + WAYPOINT_COLUMNS, "_id = ?", new String[] { Integer.toString(id) }, null, @@ -2187,7 +1735,7 @@ public class cgData { null, "1"); - Log.d(Settings.tag, "cgData.loadWaypoint(" + id + ")"); + Log.d("cgData.loadWaypoint(" + id + ")"); if (cursor != null && cursor.getCount() > 0) { cursor.moveToFirst(); @@ -2213,7 +1761,7 @@ public class cgData { Cursor cursor = databaseRO.query( dbTableWaypoints, - new String[] { "_id", "geocode", "updated", "type", "prefix", "lookup", "name", "latlon", "latitude", "longitude", "note", "own" }, + WAYPOINT_COLUMNS, "geocode = ?", new String[] { geocode }, null, @@ -2256,7 +1804,7 @@ public class cgData { return waypoint; } - public List<cgImage> loadSpoilers(String geocode) { + private List<cgImage> loadSpoilers(String geocode) { if (StringUtils.isBlank(geocode)) { return null; } @@ -2301,7 +1849,7 @@ public class cgData { * * @return A list of previously entered destinations or an empty list. */ - public List<cgDestination> loadHistoryOfSearchedLocations() { + public List<Destination> loadHistoryOfSearchedLocations() { init(); Cursor cursor = databaseRO.query(dbTableSearchDestionationHistory, @@ -2313,7 +1861,7 @@ public class cgData { "date desc", "100"); - final List<cgDestination> destinations = new LinkedList<cgDestination>(); + final List<Destination> destinations = new LinkedList<Destination>(); if (cursor != null && cursor.getCount() > 0) { cursor.moveToFirst(); @@ -2323,10 +1871,7 @@ public class cgData { int indexLongitude = cursor.getColumnIndex("longitude"); do { - final cgDestination dest = new cgDestination(); - dest.setId(cursor.getLong(indexId)); - dest.setDate(cursor.getLong(indexDate)); - dest.setCoords(getCoords(cursor, indexLatitude, indexLongitude)); + final Destination dest = new Destination(cursor.getLong(indexId), cursor.getLong(indexDate), getCoords(cursor, indexLatitude, indexLongitude)); // If coordinates are non-existent or invalid, do not consider // this point. @@ -2353,7 +1898,7 @@ public class cgData { databaseRW.setTransactionSuccessful(); } catch (Exception e) { success = false; - Log.e(Settings.tag, "Unable to clear searched destinations", e); + Log.e("Unable to clear searched destinations", e); } finally { databaseRW.endTransaction(); } @@ -2361,14 +1906,14 @@ public class cgData { return success; } - public List<cgLog> loadLogs(String geocode) { + public List<LogEntry> loadLogs(String geocode) { if (StringUtils.isBlank(geocode)) { return null; } init(); - List<cgLog> logs = new ArrayList<cgLog>(); + List<LogEntry> logs = new ArrayList<LogEntry>(); Cursor cursor = databaseRO.rawQuery( "SELECT cg_logs._id as cg_logs_id, type, author, log, date, found, friend, " + dbTableLogImages + "._id as cg_logImages_id, log_id, title, url FROM " @@ -2376,7 +1921,7 @@ public class cgData { + " ON ( cg_logs._id = log_id ) WHERE geocode = ? ORDER BY date desc, cg_logs._id asc", new String[] { geocode }); if (cursor != null && cursor.getCount() > 0) { - cgLog log = null; + LogEntry log = null; int indexLogsId = cursor.getColumnIndex("cg_logs_id"); int indexType = cursor.getColumnIndex("type"); int indexAuthor = cursor.getColumnIndex("author"); @@ -2389,24 +1934,20 @@ public class cgData { int indexUrl = cursor.getColumnIndex("url"); while (cursor.moveToNext() && logs.size() < 100) { if (log == null || log.id != cursor.getInt(indexLogsId)) { - log = new cgLog(); + log = new LogEntry( + cursor.getString(indexAuthor), + cursor.getLong(indexDate), + LogType.getById(cursor.getInt(indexType)), + cursor.getString(indexLog)); log.id = cursor.getInt(indexLogsId); - log.type = LogType.getById(cursor.getInt(indexType)); - log.author = cursor.getString(indexAuthor); - log.log = cursor.getString(indexLog); - log.date = cursor.getLong(indexDate); log.found = cursor.getInt(indexFound); - log.friend = cursor.getInt(indexFriend) == 1 ? true : false; + log.friend = cursor.getInt(indexFriend) == 1; logs.add(log); } if (!cursor.isNull(indexLogImagesId)) { String title = cursor.getString(indexTitle); String url = cursor.getString(indexUrl); - if (log.logImages == null) { - log.logImages = new ArrayList<cgImage>(); - } - final cgImage log_img = new cgImage(url, title); - log.logImages.add(log_img); + log.addLogImage(new cgImage(url, title)); } } } @@ -2457,7 +1998,7 @@ public class cgData { return logCounts; } - public List<cgTrackable> loadInventory(String geocode) { + private List<cgTrackable> loadInventory(String geocode) { if (StringUtils.isBlank(geocode)) { return null; } @@ -2530,11 +2071,14 @@ public class cgData { trackable.setGuid(cursor.getString(cursor.getColumnIndex("guid"))); trackable.setName(cursor.getString(cursor.getColumnIndex("title"))); trackable.setOwner(cursor.getString(cursor.getColumnIndex("owner"))); - String releasedPre = cursor.getString(cursor.getColumnIndex("released")); - if (releasedPre != null && Long.getLong(releasedPre) != null) { - trackable.setReleased(new Date(Long.getLong(releasedPre))); - } else { - trackable.setReleased(null); + String released = cursor.getString(cursor.getColumnIndex("released")); + if (released != null) { + try { + long releaseMilliSeconds = Long.parseLong(released); + trackable.setReleased(new Date(releaseMilliSeconds)); + } catch (NumberFormatException e) { + Log.e("createTrackableFromDatabaseContent", e); + } } trackable.setGoal(cursor.getString(cursor.getColumnIndex("goal"))); trackable.setDetails(cursor.getString(cursor.getColumnIndex("description"))); @@ -2543,22 +2087,22 @@ public class cgData { } /** - * Number of caches stored. The number is shown on the starting activitiy of c:geo + * Number of caches stored. The number is shown on the starting activity of c:geo * * @param detailedOnly * @param cacheType * @param list * @return */ - public int getAllStoredCachesCount(final boolean detailedOnly, final CacheType cacheType, final Integer list) { + public int getAllStoredCachesCount(final boolean detailedOnly, final CacheType cacheType, final int list) { if (cacheType == null) { throw new IllegalArgumentException("cacheType must not be null"); } init(); - String listSql = null; - String listSqlW = null; - if (list == null) { + String listSql; + String listSqlW; + if (list == 0) { listSql = " where reason >= 1"; listSqlW = " and reason >= 1"; } else if (list >= 1) { @@ -2570,7 +2114,7 @@ public class cgData { int count = 0; try { - String sql = "select count(_id) from " + dbTableCaches; // this default is not used, but we like to have variables initialized + String sql; // this default is not used, but we like to have variables initialized if (!detailedOnly) { if (cacheType == CacheType.ALL) { sql = "select count(_id) from " + dbTableCaches + listSql; @@ -2588,7 +2132,7 @@ public class cgData { count = (int) compiledStmnt.simpleQueryForLong(); compiledStmnt.close(); } catch (Exception e) { - Log.e(Settings.tag, "cgData.loadAllStoredCachesCount: " + e.toString()); + Log.e("cgData.loadAllStoredCachesCount: " + e.toString()); } return count; @@ -2604,16 +2148,23 @@ public class cgData { count = (int) sqlCount.simpleQueryForLong(); sqlCount.close(); } catch (Exception e) { - Log.e(Settings.tag, "cgData.getAllHistoricCachesCount: " + e.toString()); + Log.e("cgData.getAllHistoricCachesCount: " + e.toString()); } return count; } + /** + * Return a batch of stored geocodes. + * + * @param detailedOnly + * @param coords + * the current coordinates to sort by distance, or null to sort by geocode + * @param cacheType + * @param listId + * @return + */ public Set<String> loadBatchOfStoredGeocodes(final boolean detailedOnly, final Geopoint coords, final CacheType cacheType, final int listId) { - if (coords == null) { - throw new IllegalArgumentException("coords must not be null"); - } if (cacheType == null) { throw new IllegalArgumentException("cacheType must not be null"); } @@ -2637,7 +2188,9 @@ public class cgData { } try { - Cursor cursor = databaseRO.query( + Cursor cursor; + if (coords != null) { + cursor = databaseRO.query( dbTableCaches, new String[] { "geocode", "(abs(latitude-" + String.format((Locale) null, "%.6f", coords.getLatitude()) + ") + abs(longitude-" + String.format((Locale) null, "%.6f", coords.getLongitude()) + ")) as dif" }, @@ -2647,22 +2200,29 @@ public class cgData { null, "dif", null); + } else { + cursor = databaseRO.query( + dbTableCaches, + new String[] { "geocode" }, + specifySql.toString(), + null, + null, + null, + "geocode"); + } - if (cursor != null) { - if (cursor.getCount() > 0) { - cursor.moveToFirst(); - int index = cursor.getColumnIndex("geocode"); - - do { - geocodes.add(cursor.getString(index)); - } while (cursor.moveToNext()); - } + if (cursor.moveToFirst()) { + final int index = cursor.getColumnIndex("geocode"); - cursor.close(); + do { + geocodes.add(cursor.getString(index)); + } while (cursor.moveToNext()); } + cursor.close(); + } catch (Exception e) { - Log.e(Settings.tag, "cgData.loadBatchOfStoredGeocodes: " + e.toString()); + Log.e("cgData.loadBatchOfStoredGeocodes: " + e.toString()); } return geocodes; @@ -2712,58 +2272,46 @@ public class cgData { cursor.close(); } } catch (Exception e) { - Log.e(Settings.tag, "cgData.loadBatchOfHistoricGeocodes: " + e.toString()); + Log.e("cgData.loadBatchOfHistoricGeocodes: " + e.toString()); } return geocodes; } /** Retrieve all stored caches from DB */ - public Set<String> loadCachedInViewport(final Long centerLat, final Long centerLon, final Long spanLat, final Long spanLon, final CacheType cacheType) { - return loadInViewport(false, centerLat, centerLon, spanLat, spanLon, cacheType); + public Set<String> loadCachedInViewport(final Viewport viewport, final CacheType cacheType) { + return loadInViewport(false, viewport, cacheType); } /** Retrieve stored caches from DB with listId >= 1 */ - public Set<String> loadStoredInViewport(final Long centerLat, final Long centerLon, final Long spanLat, final Long spanLon, final CacheType cacheType) { - return loadInViewport(true, centerLat, centerLon, spanLat, spanLon, cacheType); + public Set<String> loadStoredInViewport(final Viewport viewport, final CacheType cacheType) { + return loadInViewport(true, viewport, cacheType); } - public Set<String> loadInViewport(final boolean stored, final Long centerLat, final Long centerLon, final Long spanLat, final Long spanLon, final CacheType cacheType) { - if (centerLat == null || centerLon == null || spanLat == null || spanLon == null) { - return null; - } - + /** + * Loads the geocodes of caches in a viewport from CacheCache and/or Database + * + * @param stored + * True - query only stored caches, False - query cached ones as well + * @param centerLat + * @param centerLon + * @param spanLat + * @param spanLon + * @param cacheType + * @return Set with geocodes + */ + private Set<String> loadInViewport(final boolean stored, final Viewport viewport, final CacheType cacheType) { init(); - Set<String> geocodes = new HashSet<String>(); + final Set<String> geocodes = new HashSet<String>(); + + // if not stored only, get codes from CacheCache as well + if (!stored) { + geocodes.addAll(CacheCache.getInstance().getInViewport(viewport, cacheType)); + } // viewport limitation - double latMin = (centerLat / 1e6) - ((spanLat / 1e6) / 2) - ((spanLat / 1e6) / 4); - double latMax = (centerLat / 1e6) + ((spanLat / 1e6) / 2) + ((spanLat / 1e6) / 4); - double lonMin = (centerLon / 1e6) - ((spanLon / 1e6) / 2) - ((spanLon / 1e6) / 4); - double lonMax = (centerLon / 1e6) + ((spanLon / 1e6) / 2) + ((spanLon / 1e6) / 4); - double llCache; - - if (latMin > latMax) { - llCache = latMax; - latMax = latMin; - latMin = llCache; - } - if (lonMin > lonMax) { - llCache = lonMax; - lonMax = lonMin; - lonMin = llCache; - } - - StringBuilder where = new StringBuilder(); - where.append("latitude >= "); - where.append(String.format((Locale) null, "%.6f", latMin)); - where.append(" and latitude <= "); - where.append(String.format((Locale) null, "%.6f", latMax)); - where.append(" and longitude >= "); - where.append(String.format((Locale) null, "%.6f", lonMin)); - where.append(" and longitude <= "); - where.append(String.format((Locale) null, "%.6f", lonMax)); + final StringBuilder where = new StringBuilder(buildCoordinateWhere(dbTableCaches, viewport)); // cacheType limitation if (cacheType != CacheType.ALL) { @@ -2778,7 +2326,7 @@ public class cgData { } try { - Cursor cursor = databaseRO.query( + final Cursor cursor = databaseRO.query( dbTableCaches, new String[] { "geocode" }, where.toString(), @@ -2788,110 +2336,21 @@ public class cgData { null, "500"); - if (cursor != null) { - if (cursor.getCount() > 0) { - cursor.moveToFirst(); - int index = cursor.getColumnIndex("geocode"); - - do { - geocodes.add(cursor.getString(index)); - } while (cursor.moveToNext()); - } else { - cursor.close(); - return null; - } - - cursor.close(); - } - } catch (Exception e) { - Log.e(Settings.tag, "cgData.loadInViewport: " + e.toString()); - } - - return geocodes; - } - - public List<String> getOfflineAll(CacheType cacheType) { - init(); - - List<String> geocodes = new ArrayList<String>(); - - StringBuilder where = new StringBuilder(); - - // cacheType limitation - if (cacheType != CacheType.ALL) { - where.append(cacheType); - where.append('"'); - } - - // offline caches only - if (where.length() > 0) { - where.append(" and "); - } - where.append("reason >= 1"); - - try { - Cursor cursor = databaseRO.query( - dbTableCaches, - new String[] { "geocode" }, - where.toString(), - null, - null, - null, - null, - "5000"); - - if (cursor != null) { - if (cursor.getCount() > 0) { - cursor.moveToFirst(); - int index = cursor.getColumnIndex("geocode"); - - do { - geocodes.add(cursor.getString(index)); - } while (cursor.moveToNext()); - } else { - cursor.close(); - return null; - } + if (cursor.moveToFirst()) { + final int index = cursor.getColumnIndex("geocode"); - cursor.close(); + do { + geocodes.add(cursor.getString(index)); + } while (cursor.moveToNext()); } + cursor.close(); } catch (Exception e) { - Log.e(Settings.tag, "cgData.getOfflineAll: " + e.toString()); + Log.e("cgData.loadInViewport: " + e.toString()); } return geocodes; } - public boolean markFound(String geocode) { - if (StringUtils.isBlank(geocode)) { - return false; - } - - init(); - - boolean result = false; - databaseRW.beginTransaction(); - try { - ContentValues values = new ContentValues(); - values.put("found", 1); - int rows = databaseRW.update(dbTableCaches, values, "geocode = ?", new String[] { geocode }); - if (rows > 0) { - // update CacheCache - cgCache cache = cacheCache.getCacheFromCache(geocode); - if (cache != null) { - cache.setFound(true); - cacheCache.putCacheInCache(cache); - } - result = true; - } - databaseRW.setTransactionSuccessful(); - } finally { - databaseRW.endTransaction(); - } - - return result; - } - /** delete caches from the DB store 3 days or more before */ public void clean() { clean(false); @@ -2906,9 +2365,9 @@ public class cgData { public void clean(boolean more) { init(); - Log.d(Settings.tag, "Database clean: started"); + Log.d("Database clean: started"); - Cursor cursor = null; + Cursor cursor; Set<String> geocodes = new HashSet<String>(); try { @@ -2951,7 +2410,7 @@ public class cgData { final int size = geocodes.size(); if (size > 0) { - Log.d(Settings.tag, "Database clean: removing " + size + " geocaches from listId=0"); + Log.d("Database clean: removing " + size + " geocaches from listId=0"); removeCaches(geocodes, LoadFlags.REMOVE_ALL); } @@ -2959,13 +2418,13 @@ public class cgData { final SQLiteStatement countSql = databaseRO.compileStatement("select count(_id) from " + dbTableCaches + " where reason = 0"); final int count = (int) countSql.simpleQueryForLong(); countSql.close(); - Log.d(Settings.tag, "Database clean: " + count + " geocaches remaining for listId=0"); + Log.d("Database clean: " + count + " geocaches remaining for listId=0"); } catch (Exception e) { - Log.w(Settings.tag, "cgData.clean: " + e.toString()); + Log.w("cgData.clean: " + e.toString()); } - Log.d(Settings.tag, "Database clean: finished"); + Log.d("Database clean: finished"); } /** @@ -2981,7 +2440,7 @@ public class cgData { values.put("reason", StoredList.TEMPORARY_LIST_ID); databaseRW.update(dbTableCaches, values, "reason = ?", new String[] { Integer.toString(listId) }); } catch (Exception e) { - Log.e(Settings.tag, "cgData.dropList: error when updating reason", e); + Log.e("cgData.dropList: error when updating reason", e); } } @@ -3078,20 +2537,20 @@ public class cgData { } } } catch (Exception e) { - Log.e(Settings.tag, "cgData.saveLogOffline: " + e.toString()); + Log.e("cgData.saveLogOffline: " + e.toString()); } return status; } - public cgLog loadLogOffline(String geocode) { + public LogEntry loadLogOffline(String geocode) { if (StringUtils.isBlank(geocode)) { return null; } init(); - cgLog log = null; + LogEntry log = null; Cursor cursor = databaseRO.query( dbTableLogsOffline, @@ -3106,11 +2565,11 @@ public class cgData { if (cursor != null && cursor.getCount() > 0) { cursor.moveToFirst(); - log = new cgLog(); + log = new LogEntry( + cursor.getLong(cursor.getColumnIndex("date")), + LogType.getById(cursor.getInt(cursor.getColumnIndex("type"))), + cursor.getString(cursor.getColumnIndex("log"))); log.id = cursor.getInt(cursor.getColumnIndex("_id")); - log.type = LogType.getById(cursor.getInt(cursor.getColumnIndex("type"))); - log.log = cursor.getString(cursor.getColumnIndex("log")); - log.date = cursor.getLong(cursor.getColumnIndex("date")); } if (cursor != null) { @@ -3160,7 +2619,7 @@ public class cgData { return logCount.simpleQueryForLong() > 0; } } catch (Exception e) { - Log.e(Settings.tag, "cgData.hasLogOffline", e); + Log.e("cgData.hasLogOffline", e); } return false; @@ -3203,7 +2662,7 @@ public class cgData { lists.addAll(storedLists); } catch (Exception e) { - Log.e(Settings.tag, "cgData.readLists: " + e.toString()); + Log.e("cgData.readLists: " + e.toString()); } return lists; } @@ -3282,11 +2741,7 @@ public class cgData { databaseRW.endTransaction(); } - if (id < 0) { - return -1; - } else { - return (id + customListIdOffset); - } + return id >= 0 ? id + customListIdOffset : -1; } /** @@ -3347,40 +2802,33 @@ public class cgData { return status; } - public void moveToList(String geocode, int listId) { - if (StringUtils.isBlank(geocode)) { + public void moveToList(final List<cgCache> caches, final int listId) { + if (caches.isEmpty()) { return; } - init(); - ContentValues values = new ContentValues(); + final ContentValues values = new ContentValues(); values.put("reason", listId); + databaseRW.beginTransaction(); try { - databaseRW.update(dbTableCaches, values, "geocode = ?", new String[] { geocode }); + for (cgCache cache : caches) { + databaseRW.update(dbTableCaches, values, "geocode = ?", new String[] { cache.getGeocode() }); + cache.setListId(listId); + } databaseRW.setTransactionSuccessful(); } finally { databaseRW.endTransaction(); } - - // update CacheCache - cgCache cache = cacheCache.getCacheFromCache(geocode); - if (cache != null) { - cache.setListId(listId); - cacheCache.putCacheInCache(cache); - } } public synchronized boolean status() { - if (databaseRO == null || databaseRW == null || !initialized) { - return false; - } + return databaseRO != null && databaseRW != null && initialized; - return true; } - public boolean removeSearchedDestination(cgDestination destination) { + public boolean removeSearchedDestination(Destination destination) { boolean success = true; if (destination == null) { success = false; @@ -3392,7 +2840,7 @@ public class cgData { databaseRW.delete(dbTableSearchDestionationHistory, "_id = " + destination.getId(), null); databaseRW.setTransactionSuccessful(); } catch (Exception e) { - Log.e(Settings.tag, "Unable to remove searched destination", e); + Log.e("Unable to remove searched destination", e); success = false; } finally { databaseRW.endTransaction(); @@ -3429,7 +2877,7 @@ public class cgData { } catch (SQLiteDoneException e) { // Do nothing, it only means we have no information on the cache } catch (Exception e) { - Log.e(Settings.tag, "cgData.getCacheDescription", e); + Log.e("cgData.getCacheDescription", e); } return null; @@ -3451,7 +2899,7 @@ public class cgData { newlyCreatedDatabase = false; } - private static StringBuilder whereGeocodeIn(Set<String> geocodes) { + private static String whereGeocodeIn(Set<String> geocodes) { final StringBuilder where = new StringBuilder(); if (geocodes != null && geocodes.size() > 0) { @@ -3470,7 +2918,51 @@ public class cgData { where.append(')'); } - return where; + return where.toString(); + } + + /** + * Loads all Waypoints in the coordinate rectangle. + * + * @param centerLat + * @param centerLon + * @param spanLat + * @param spanLon + * @param excludeDisabled + * @param excludeMine + * @return + */ + + public Set<cgWaypoint> loadWaypoints(final Viewport viewport, boolean excludeMine, boolean excludeDisabled) { + final StringBuilder where = new StringBuilder(buildCoordinateWhere(dbTableWaypoints, viewport)); + if (excludeMine) { + where.append(" and ").append(dbTableCaches).append(".own == 0 and ").append(dbTableCaches).append(".found == 0"); + } + if (excludeDisabled) { + where.append(" and ").append(dbTableCaches).append(".disabled == 0"); + } + init(); + + final StringBuilder query = new StringBuilder("SELECT "); + for (int i = 0; i < WAYPOINT_COLUMNS.length; i++) { + query.append(i > 0 ? ", " : "").append(dbTableWaypoints).append('.').append(WAYPOINT_COLUMNS[i]).append(' '); + } + query.append(" FROM ").append(dbTableWaypoints).append(", ").append(dbTableCaches).append(" WHERE ").append(dbTableWaypoints).append("._id == ").append(dbTableCaches).append("._id and ").append(where); + + final Cursor cursor = databaseRO.rawQuery(query.toString(), null); + try { + if (!cursor.moveToFirst()) { + return Collections.emptySet(); + } + + final Set<cgWaypoint> waypoints = new HashSet<cgWaypoint>(); + do { + waypoints.add(createWaypointFromDatabaseContent(cursor)); + } while (cursor.moveToNext()); + return waypoints; + } finally { + cursor.close(); + } } } diff --git a/main/src/cgeo/geocaching/cgDestination.java b/main/src/cgeo/geocaching/cgDestination.java deleted file mode 100644 index cf9a8ef..0000000 --- a/main/src/cgeo/geocaching/cgDestination.java +++ /dev/null @@ -1,74 +0,0 @@ -package cgeo.geocaching; - -import cgeo.geocaching.geopoint.Geopoint; - -public class cgDestination { - - private long id; - - private long date; - - private Geopoint coords; - - public cgDestination() { - } - - public cgDestination(long id, long date, final Geopoint coords) { - super(); - this.id = id; - this.date = date; - this.coords = coords; - } - - public long getDate() { - return date; - } - - public void setDate(long date) { - this.date = date; - } - - public Geopoint getCoords() { - return coords; - } - - public void setCoords(final Geopoint coords) { - this.coords = coords; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - long temp; - temp = Double.doubleToLongBits(coords.getLatitude()); - result = prime * result + (int) (temp ^ (temp >>> 32)); - temp = Double.doubleToLongBits(coords.getLongitude()); - result = prime * result + (int) (temp ^ (temp >>> 32)); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (!(obj instanceof cgDestination)) { - return false; - } - cgDestination other = (cgDestination) obj; - return coords.isEqualTo(other.coords); - } - - public long getId() { - return id; - } - - public void setId(long id) { - this.id = id; - } - -} diff --git a/main/src/cgeo/geocaching/cgGeo.java b/main/src/cgeo/geocaching/cgGeo.java deleted file mode 100644 index dcad1ba..0000000 --- a/main/src/cgeo/geocaching/cgGeo.java +++ /dev/null @@ -1,252 +0,0 @@ -package cgeo.geocaching; - -import cgeo.geocaching.enumerations.LocationProviderType; -import cgeo.geocaching.geopoint.Geopoint; -import cgeo.geocaching.go4cache.Go4Cache; - -import android.content.Context; -import android.location.GpsSatellite; -import android.location.GpsStatus; -import android.location.Location; -import android.location.LocationListener; -import android.location.LocationManager; -import android.os.Bundle; -import android.util.Log; - -import java.util.Iterator; - -public class cgGeo { - - private static final String LAST_LOCATION_PSEUDO_PROVIDER = "last"; - private final LocationManager geoManager = (LocationManager) cgeoapplication.getInstance().getSystemService(Context.LOCATION_SERVICE); - private UpdateLocationCallback updateLocationCallback = null; - private final AbstractLocationListener networkListener = new NetworkLocationListener(); - private final AbstractLocationListener gpsListener = new GpsLocationListener(); - private final GpsStatusListener gpsStatusListener = new GpsStatusListener(); - private Location locGps = null; - private Location locNet = null; - private long locGpsLast = 0L; - public Location location = null; - public LocationProviderType locationProvider = LocationProviderType.LAST; - public Geopoint coordsNow = null; - public Double altitudeNow = null; - public float bearingNow = 0; - public float speedNow = 0; - public float accuracyNow = -1f; - public int satellitesVisible = 0; - public int satellitesFixed = 0; - - public cgGeo() { - restoreLastLocation(); - - geoManager.addGpsStatusListener(gpsStatusListener); - - for (AbstractLocationListener listener : new AbstractLocationListener[] { networkListener, gpsListener }) { - try { - geoManager.requestLocationUpdates(listener.locationProvider, 0, 0, listener); - } catch (Exception e) { - Log.w(Settings.tag, "There is no location provider " + listener.locationProvider); - } - } - } - - public void closeGeo() { - geoManager.removeUpdates(networkListener); - geoManager.removeUpdates(gpsListener); - geoManager.removeGpsStatusListener(gpsStatusListener); - } - - public void replaceUpdate(UpdateLocationCallback callback) { - updateLocationCallback = callback; - fireLocationCallback(); - } - - private void fireLocationCallback() { - if (updateLocationCallback != null) { - updateLocationCallback.updateLocation(this); - } - } - - private static abstract class AbstractLocationListener implements LocationListener { - private final String locationProvider; - - protected AbstractLocationListener(String provider) { - this.locationProvider = provider; - } - - @Override - public void onStatusChanged(String provider, int status, Bundle extras) { - // nothing - } - - @Override - public void onProviderDisabled(String provider) { - // nothing - } - - @Override - public void onProviderEnabled(String provider) { - // nothing - } - } - - private final class GpsLocationListener extends AbstractLocationListener { - - public GpsLocationListener() { - super(LocationManager.GPS_PROVIDER); - } - - @Override - public void onLocationChanged(Location location) { - locGps = location; - locGpsLast = System.currentTimeMillis(); - selectBest(location.getProvider()); - } - } - - private final class NetworkLocationListener extends AbstractLocationListener { - - protected NetworkLocationListener() { - super(LocationManager.NETWORK_PROVIDER); - } - - @Override - public void onLocationChanged(Location location) { - locNet = location; - selectBest(location.getProvider()); - } - - } - - private final class GpsStatusListener implements GpsStatus.Listener { - - @Override - public void onGpsStatusChanged(int event) { - if (event == GpsStatus.GPS_EVENT_SATELLITE_STATUS) { - final GpsStatus status = geoManager.getGpsStatus(null); - final Iterator<GpsSatellite> statusIterator = status.getSatellites().iterator(); - - int satellites = 0; - int fixed = 0; - - while (statusIterator.hasNext()) { - GpsSatellite sat = statusIterator.next(); - if (sat.usedInFix()) { - fixed++; - } - satellites++; - } - - boolean changed = false; - if (satellites != satellitesVisible) { - satellitesVisible = satellites; - changed = true; - } - if (fixed != satellitesFixed) { - satellitesFixed = fixed; - changed = true; - } - - if (changed) { - selectBest(null); - } - } - } - } - - private void selectBest(final String signallingProvider) { - if (locNet != null && locGps == null) { // we have only NET - assign(locNet); - } - else if ((locNet == null && locGps != null) // we have only GPS - || (satellitesFixed > 0) // GPS seems to be fixed - || (signallingProvider != null && signallingProvider.equals(LocationManager.GPS_PROVIDER)) // we have new location from GPS - || locGpsLast > (System.currentTimeMillis() - 30 * 1000) // GPS was working in last 30 seconds - ) { - assign(locGps); - } - else { - assign(locNet); // nothing else, using NET - } - } - - private void assignLastLocation(final Geopoint coords) { - if (coords == null) { - return; - } - - locationProvider = LocationProviderType.LAST; - coordsNow = coords; - altitudeNow = null; - bearingNow = 0f; - speedNow = 0f; - accuracyNow = 999f; - - fireLocationCallback(); - } - - private void assign(final Location loc) { - if (loc == null) { - locationProvider = LocationProviderType.LAST; - return; - } - - location = loc; - - final String provider = location.getProvider(); - if (provider.equals(LocationManager.GPS_PROVIDER)) { - locationProvider = LocationProviderType.GPS; - } else if (provider.equals(LocationManager.NETWORK_PROVIDER)) { - locationProvider = LocationProviderType.NETWORK; - } else if (provider.equalsIgnoreCase(LAST_LOCATION_PSEUDO_PROVIDER)) { - locationProvider = LocationProviderType.LAST; - } - - coordsNow = new Geopoint(location.getLatitude(), location.getLongitude()); - cgeoapplication.getInstance().setLastCoords(coordsNow); - - if (location.hasAltitude() && locationProvider != LocationProviderType.LAST) { - altitudeNow = location.getAltitude() + Settings.getAltCorrection(); - } else { - altitudeNow = null; - } - if (location.hasBearing() && locationProvider != LocationProviderType.LAST) { - bearingNow = location.getBearing(); - } else { - bearingNow = 0f; - } - if (location.hasSpeed() && locationProvider != LocationProviderType.LAST) { - speedNow = location.getSpeed(); - } else { - speedNow = 0f; - } - if (location.hasAccuracy() && locationProvider != LocationProviderType.LAST) { - accuracyNow = location.getAccuracy(); - } else { - accuracyNow = 999f; - } - - fireLocationCallback(); - - if (locationProvider == LocationProviderType.GPS || locationProvider == LocationProviderType.NETWORK) { - Go4Cache.signalCoordinates(coordsNow); - } - } - - private void restoreLastLocation() { - // restore from last location (stored by app) - assignLastLocation(cgeoapplication.getInstance().getLastCoords()); - - // restore from last location (stored by device sensors) - for (String provider : new String[] { LocationManager.GPS_PROVIDER, LocationManager.NETWORK_PROVIDER }) { - final Location lastLocation = geoManager.getLastKnownLocation(provider); - if (lastLocation != null) { - lastLocation.setProvider(LAST_LOCATION_PSEUDO_PROVIDER); - assign(lastLocation); - - Log.i(Settings.tag, "Using last location from " + provider); - break; - } - } - } -} diff --git a/main/src/cgeo/geocaching/cgLog.java b/main/src/cgeo/geocaching/cgLog.java deleted file mode 100644 index 2b3568d..0000000 --- a/main/src/cgeo/geocaching/cgLog.java +++ /dev/null @@ -1,39 +0,0 @@ -package cgeo.geocaching; - -import cgeo.geocaching.enumerations.LogType; - -import java.util.List; - -public class cgLog { - public int id = 0; - public LogType type = LogType.LOG_NOTE; // note - public String author = ""; - public String log = ""; - public long date = 0; - public int found = -1; - /** Friend's logentry */ - public boolean friend = false; - public List<cgImage> logImages = null; - public String cacheName = ""; // used for trackables - public String cacheGuid = ""; // used for trackables - - @Override - public int hashCode() { - return (int) date * type.hashCode() * author.hashCode() * log.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (!(obj instanceof cgLog)) { - return false; - } - final cgLog otherLog = (cgLog) obj; - return date == otherLog.date && - type == otherLog.type && - author.compareTo(otherLog.author) == 0 && - log.compareTo(otherLog.log) == 0 ? true : false; - } -} diff --git a/main/src/cgeo/geocaching/cgSearchHandler.java b/main/src/cgeo/geocaching/cgSearchHandler.java index 8e8dffd..6d38ea1 100644 --- a/main/src/cgeo/geocaching/cgSearchHandler.java +++ b/main/src/cgeo/geocaching/cgSearchHandler.java @@ -1,5 +1,7 @@ package cgeo.geocaching; +import cgeo.geocaching.utils.Log; + import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; @@ -8,7 +10,6 @@ import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Handler; import android.os.Message; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.widget.EditText; @@ -98,7 +99,7 @@ public class cgSearchHandler extends Handler { imgHandler.sendEmptyMessage(0); } catch (IOException e) { - Log.e(Settings.tag, "Failed to download reCAPTCHA image"); + Log.e("Failed to download reCAPTCHA image"); } } } diff --git a/main/src/cgeo/geocaching/cgSearchThread.java b/main/src/cgeo/geocaching/cgSearchThread.java index 3daddc5..ff73a66 100644 --- a/main/src/cgeo/geocaching/cgSearchThread.java +++ b/main/src/cgeo/geocaching/cgSearchThread.java @@ -1,7 +1,8 @@ package cgeo.geocaching; +import cgeo.geocaching.utils.Log; + import android.os.Handler; -import android.util.Log; abstract public class cgSearchThread extends Thread { private Handler recaptchaHandler = null; @@ -22,7 +23,7 @@ abstract public class cgSearchThread extends Thread { try { wait(); } catch (InterruptedException e) { - Log.w(Settings.tag, "searchThread is not waiting for user..."); + Log.w("searchThread is not waiting for user..."); } } diff --git a/main/src/cgeo/geocaching/cgTrackable.java b/main/src/cgeo/geocaching/cgTrackable.java index b5fc215..ff84833 100644 --- a/main/src/cgeo/geocaching/cgTrackable.java +++ b/main/src/cgeo/geocaching/cgTrackable.java @@ -1,9 +1,10 @@ package cgeo.geocaching; +import cgeo.geocaching.utils.Log; + import org.apache.commons.lang3.StringUtils; import android.text.Html; -import android.util.Log; import java.util.ArrayList; import java.util.Date; @@ -16,7 +17,6 @@ public class cgTrackable implements ILogable { static final public int SPOTTED_UNKNOWN = 3; static final public int SPOTTED_OWNER = 4; - private String error = ""; private String guid = ""; private String geocode = ""; private String iconUrl = ""; @@ -33,7 +33,7 @@ public class cgTrackable implements ILogable { private String goal = null; private String details = null; private String image = null; - private List<cgLog> logs = new ArrayList<cgLog>(); + private List<LogEntry> logs = new ArrayList<LogEntry>(); private String trackingcode = null; public String getUrl() { @@ -43,17 +43,13 @@ public class cgTrackable implements ILogable { int id = Integer.parseInt(hex, 16); return "http://geokrety.org/konkret.php?id=" + id; } catch (NumberFormatException e) { - Log.e(Settings.tag, "cgTrackable.getUrl", e); + Log.e("cgTrackable.getUrl", e); return null; } } return "http://coord.info/" + geocode.toUpperCase(); } - public String getError() { - return error; - } - public String getGuid() { return guid; } @@ -187,11 +183,11 @@ public class cgTrackable implements ILogable { this.image = image; } - public List<cgLog> getLogs() { + public List<LogEntry> getLogs() { return logs; } - public void setLogs(List<cgLog> logs) { + public void setLogs(List<LogEntry> logs) { this.logs = logs; } @@ -209,10 +205,7 @@ public class cgTrackable implements ILogable { } public boolean isLoggable() { - if (StringUtils.startsWithIgnoreCase(geocode, "GK")) { - return false; - } - return true; + return !StringUtils.startsWithIgnoreCase(geocode, "GK"); } public String getTrackingcode() { diff --git a/main/src/cgeo/geocaching/cgTrackableLog.java b/main/src/cgeo/geocaching/cgTrackableLog.java deleted file mode 100644 index ee134da..0000000 --- a/main/src/cgeo/geocaching/cgTrackableLog.java +++ /dev/null @@ -1,11 +0,0 @@ -package cgeo.geocaching; - -import cgeo.geocaching.enumerations.LogTypeTrackable; - -public class cgTrackableLog { - public int ctl = -1; - public int id = -1; - public String trackCode = null; - public String name = null; - public LogTypeTrackable action = LogTypeTrackable.DO_NOTHING; // base.logTrackablesAction - no action -} diff --git a/main/src/cgeo/geocaching/cgWaypoint.java b/main/src/cgeo/geocaching/cgWaypoint.java index b13c141..ee865ee 100644 --- a/main/src/cgeo/geocaching/cgWaypoint.java +++ b/main/src/cgeo/geocaching/cgWaypoint.java @@ -179,10 +179,6 @@ public class cgWaypoint implements IWaypoint, Comparable<cgWaypoint> { return waypointType; } - public void setWaypointType(WaypointType type) { - this.waypointType = type; - } - public String getLookup() { return lookup; } @@ -223,14 +219,6 @@ public class cgWaypoint implements IWaypoint, Comparable<cgWaypoint> { this.note = note; } - public int getCachedOrder() { - return cachedOrder; - } - - public void setCachedOrder(int cachedOrder) { - this.cachedOrder = cachedOrder; - } - @Override public String toString() { return name + " " + waypointType.getL10n(); @@ -244,4 +232,9 @@ public class cgWaypoint implements IWaypoint, Comparable<cgWaypoint> { public boolean isFinalWithCoords() { return WaypointType.FINAL == waypointType && null != coords; } + + @Override + public String getCoordType() { + return "waypoint"; + } }
\ No newline at end of file diff --git a/main/src/cgeo/geocaching/cgeo.java b/main/src/cgeo/geocaching/cgeo.java index 7367d82..019d217 100644 --- a/main/src/cgeo/geocaching/cgeo.java +++ b/main/src/cgeo/geocaching/cgeo.java @@ -2,18 +2,16 @@ package cgeo.geocaching; import cgeo.geocaching.activity.AbstractActivity; import cgeo.geocaching.activity.ActivityMixin; -import cgeo.geocaching.enumerations.CacheSize; +import cgeo.geocaching.connector.gc.Login; import cgeo.geocaching.enumerations.CacheType; -import cgeo.geocaching.enumerations.LiveMapStrategy.Strategy; -import cgeo.geocaching.enumerations.LogType; import cgeo.geocaching.enumerations.StatusCode; -import cgeo.geocaching.enumerations.WaypointType; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.geopoint.HumanDistance; import cgeo.geocaching.geopoint.IConversion; import cgeo.geocaching.maps.CGeoMap; -import cgeo.geocaching.network.Login; import cgeo.geocaching.ui.Formatter; +import cgeo.geocaching.utils.IObserver; +import cgeo.geocaching.utils.Log; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -25,6 +23,7 @@ import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.content.res.Configuration; import android.location.Address; @@ -32,7 +31,6 @@ import android.location.Geocoder; import android.os.Bundle; import android.os.Handler; import android.os.Message; -import android.util.Log; import android.view.ContextMenu; import android.view.Menu; import android.view.MenuItem; @@ -60,8 +58,6 @@ public class cgeo extends AbstractActivity { public static final int SEARCH_REQUEST_CODE = 2; private int version = 0; - private cgGeo geo = null; - private UpdateLocationCallback geoUpdate = null; private TextView filterTitle = null; private boolean cleanupRunning = false; private int countBubbleCnt = 0; @@ -70,6 +66,8 @@ public class cgeo extends AbstractActivity { private boolean addressObtaining = false; private boolean initialized = false; + final private UpdateLocation locationUpdater = new UpdateLocation(); + private Handler updateUserInfoHandler = new Handler() { @Override @@ -115,9 +113,7 @@ public class cgeo extends AbstractActivity { addText.append(address.getAdminArea()); } - if (geo != null) { - addCoords = geo.coordsNow; - } + addCoords = app.currentGeo().getCoords(); TextView navLocation = (TextView) findViewById(R.id.nav_location); navLocation.setText(addText.toString()); @@ -130,6 +126,44 @@ public class cgeo extends AbstractActivity { } }; + private class SatellitesHandler extends Handler implements IObserver<IGeoData> { + + private boolean gpsEnabled = false; + private int satellitesFixed = 0; + private int satellitesVisible = 0; + + @Override + public void handleMessage(final Message msg) { + final IGeoData data = (IGeoData) msg.obj; + if (data.getGpsEnabled() == gpsEnabled && + data.getSatellitesFixed() == satellitesFixed && + data.getSatellitesVisible() == satellitesVisible) { + return; + } + gpsEnabled = data.getGpsEnabled(); + satellitesFixed = data.getSatellitesFixed(); + satellitesVisible = data.getSatellitesVisible(); + + final TextView navSatellites = (TextView) findViewById(R.id.nav_satellites); + if (gpsEnabled) { + if (satellitesFixed > 0) { + navSatellites.setText(res.getString(R.string.loc_sat) + ": " + satellitesFixed + '/' + satellitesVisible); + } else if (satellitesVisible >= 0) { + navSatellites.setText(res.getString(R.string.loc_sat) + ": 0/" + satellitesVisible); + } + } else { + navSatellites.setText(res.getString(R.string.loc_gps_disabled)); + } + } + + @Override + public void update(final IGeoData data) { + obtainMessage(0, data).sendToTarget(); + } + } + + private SatellitesHandler satellitesHandler = new SatellitesHandler(); + private Handler firstLoginHandler = new Handler() { @Override @@ -141,7 +175,7 @@ public class cgeo extends AbstractActivity { showToast(res.getString(reason == StatusCode.MAINTENANCE ? reason.getErrorString() : R.string.err_login_failed_toast)); } } catch (Exception e) { - Log.w(Settings.tag, "cgeo.fisrtLoginHander: " + e.toString()); + Log.w("cgeo.firstLoginHander: " + e.toString()); } } }; @@ -156,29 +190,22 @@ public class cgeo extends AbstractActivity { app.setAction(null); - app.cleanGeo(); app.cleanDir(); setContentView(R.layout.main); setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL); // type to search try { - PackageManager manager = this.getPackageManager(); - PackageInfo info = manager.getPackageInfo(this.getPackageName(), 0); - + final PackageInfo info = getPackageManager().getPackageInfo(this.getPackageName(), 0); version = info.versionCode; - - Log.i(Settings.tag, "Starting " + info.packageName + " " + info.versionCode + " a.k.a " + info.versionName + "..."); - - info = null; - manager = null; - } catch (Exception e) { - Log.i(Settings.tag, "No info."); + Log.i("Starting " + info.packageName + " " + info.versionCode + " a.k.a " + info.versionName + "…"); + } catch (final NameNotFoundException e) { + Log.i("No info."); } try { if (!Settings.isHelpShown()) { - RelativeLayout helper = (RelativeLayout) findViewById(R.id.helper); + final RelativeLayout helper = (RelativeLayout) findViewById(R.id.helper); if (helper != null) { helper.setVisibility(View.VISIBLE); helper.setClickable(true); @@ -209,9 +236,9 @@ public class cgeo extends AbstractActivity { @Override public void onResume() { super.onResume(); - + app.addGeoObserver(locationUpdater); + app.addGeoObserver(satellitesHandler); updateUserInfoHandler.sendEmptyMessage(-1); - init(); } @@ -220,32 +247,20 @@ public class cgeo extends AbstractActivity { initialized = false; app.showLoginToast = true; - if (geo != null) { - geo = app.removeGeo(); - } - super.onDestroy(); } @Override public void onStop() { initialized = false; - - if (geo != null) { - geo = app.removeGeo(); - } - super.onStop(); } @Override public void onPause() { initialized = false; - - if (geo != null) { - geo = app.removeGeo(); - } - + app.deleteGeoObserver(locationUpdater); + app.deleteGeoObserver(satellitesHandler); super.onPause(); } @@ -345,11 +360,8 @@ public class cgeo extends AbstractActivity { // context menu for offline button if (v.getId() == R.id.search_offline) { - List<StoredList> cacheLists = app.getLists(); - int listCount = cacheLists.size(); menu.setHeaderTitle(res.getString(R.string.list_title)); - for (int i = 0; i < listCount; i++) { - StoredList list = cacheLists.get(i); + for (final StoredList list : app.getLists()) { menu.add(Menu.NONE, MENU_OPEN_LIST + list.id, Menu.NONE, list.getTitleAndCount()); } return; @@ -398,23 +410,22 @@ public class cgeo extends AbstractActivity { } @Override - public boolean onContextItemSelected(MenuItem item) { + public boolean onContextItemSelected(final MenuItem item) { final int id = item.getItemId(); + if (id < 0) { + return false; + } if (id == 0) { Settings.setCacheType(CacheType.ALL); setFilterTitle(); - - return true; } else if (id > MENU_OPEN_LIST) { - int listId = id - MENU_OPEN_LIST; - Settings.saveLastList(listId); + Settings.saveLastList(id - MENU_OPEN_LIST); cgeocaches.startActivityOffline(this); - return true; - } else if (id > 0) { + } else { final String itemTitle = item.getTitle().toString(); CacheType cacheType = CacheType.ALL; - for (CacheType ct : CacheType.values()) { + for (final CacheType ct : CacheType.values()) { if (ct.getL10n().equalsIgnoreCase(itemTitle)) { cacheType = ct; break; @@ -422,11 +433,9 @@ public class cgeo extends AbstractActivity { } Settings.setCacheType(cacheType); setFilterTitle(); - - return true; } - return false; + return true; } private void setFilterTitle() { @@ -452,40 +461,12 @@ public class cgeo extends AbstractActivity { initialized = true; Settings.setLanguage(Settings.isUseEnglish()); - - /* - * "update" the cache size/type. For a better performance - * the resource strings are stored in the enum's. In case of a - * locale change the resource strings don't get updated automatically. - * That's why we have to do it on our own. - */ - for (CacheSize cacheSize : CacheSize.values()) { - cacheSize.setL10n(); - } - for (CacheType cacheType : CacheType.values()) { - cacheType.setL10n(); - } - for (LogType logType : LogType.values()) { - logType.setL10n(); - } - for (WaypointType waypointType : WaypointType.values()) { - waypointType.setL10n(); - } - for (Strategy strategy : Strategy.values()) { - strategy.setL10n(); - } - Settings.getLogin(); if (app.firstRun) { (new firstLogin()).start(); } - if (geo == null) { - geoUpdate = new UpdateLocation(); - geo = app.startGeo(geoUpdate); - } - final View findOnMap = findViewById(R.id.map); findOnMap.setClickable(true); findOnMap.setOnClickListener(new OnClickListener() { @@ -565,22 +546,16 @@ public class cgeo extends AbstractActivity { .show(); } - private class UpdateLocation implements UpdateLocationCallback { - - private final View nearestView = findViewById(R.id.nearest); - private final TextView navType = (TextView) findViewById(R.id.nav_type); - private final TextView navAccuracy = (TextView) findViewById(R.id.nav_accuracy); - private final TextView navSatellites = (TextView) findViewById(R.id.nav_satellites); - private final TextView navLocation = (TextView) findViewById(R.id.nav_location); + private class UpdateLocation extends GeoObserver { @Override - public void updateLocation(cgGeo geo) { - if (geo == null) { - return; - } - + public void updateLocation(final IGeoData geo) { + final View nearestView = findViewById(R.id.nearest); + final TextView navType = (TextView) findViewById(R.id.nav_type); + final TextView navAccuracy = (TextView) findViewById(R.id.nav_accuracy); + final TextView navLocation = (TextView) findViewById(R.id.nav_location); try { - if (geo.coordsNow != null) { + if (geo.getCoords() != null) { if (!nearestView.isClickable()) { nearestView.setFocusable(true); nearestView.setClickable(true); @@ -592,23 +567,14 @@ public class cgeo extends AbstractActivity { nearestView.setBackgroundResource(R.drawable.main_nearby); } - String satellites = null; - if (geo.satellitesFixed > 0) { - satellites = res.getString(R.string.loc_sat) + ": " + geo.satellitesFixed + "/" + geo.satellitesVisible; - } else if (geo.satellitesVisible >= 0) { - satellites = res.getString(R.string.loc_sat) + ": 0/" + geo.satellitesVisible; - } else { - satellites = ""; - } - navSatellites.setText(satellites); - navType.setText(res.getString(geo.locationProvider.resourceId)); + navType.setText(res.getString(geo.getLocationProvider().resourceId)); - if (geo.accuracyNow >= 0) { - int speed = Math.round(geo.speedNow) * 60 * 60 / 1000; + if (geo.getAccuracy() >= 0) { + int speed = Math.round(geo.getSpeed()) * 60 * 60 / 1000; if (Settings.isUseMetricUnits()) { - navAccuracy.setText("±" + Math.round(geo.accuracyNow) + " m" + Formatter.SEPARATOR + speed + " km/h"); + navAccuracy.setText("±" + Math.round(geo.getAccuracy()) + " m" + Formatter.SEPARATOR + speed + " km/h"); } else { - navAccuracy.setText("±" + Math.round(geo.accuracyNow * IConversion.METERS_TO_FEET) + " ft" + Formatter.SEPARATOR + speed / IConversion.MILES_TO_KILOMETER + " mph"); + navAccuracy.setText("±" + Math.round(geo.getAccuracy() * IConversion.METERS_TO_FEET) + " ft" + Formatter.SEPARATOR + speed / IConversion.MILES_TO_KILOMETER + " mph"); } } else { navAccuracy.setText(null); @@ -618,15 +584,15 @@ public class cgeo extends AbstractActivity { if (addCoords == null) { navLocation.setText(res.getString(R.string.loc_no_addr)); } - if (addCoords == null || (geo.coordsNow.distanceTo(addCoords) > 0.5 && !addressObtaining)) { + if (addCoords == null || (geo.getCoords().distanceTo(addCoords) > 0.5 && !addressObtaining)) { (new ObtainAddressThread()).start(); } } else { - if (geo.altitudeNow != null) { - final String humanAlt = HumanDistance.getHumanDistance(geo.altitudeNow.floatValue() / 1000); - navLocation.setText(geo.coordsNow + " | " + humanAlt); + if (geo.getAltitude() != 0.0) { + final String humanAlt = HumanDistance.getHumanDistance((float) geo.getAltitude() / 1000); + navLocation.setText(geo.getCoords() + " | " + humanAlt); } else { - navLocation.setText(geo.coordsNow.toString()); + navLocation.setText(geo.getCoords().toString()); } } } else { @@ -641,7 +607,7 @@ public class cgeo extends AbstractActivity { navLocation.setText(res.getString(R.string.loc_trying)); } } catch (Exception e) { - Log.w(Settings.tag, "Failed to update location."); + Log.w("Failed to update location."); } } } @@ -660,12 +626,12 @@ public class cgeo extends AbstractActivity { * unused here but needed since this method is referenced from XML layout */ public void cgeoFindNearest(View v) { - if (geo == null || geo.coordsNow == null) { + if (app.currentGeo().getCoords() == null) { return; } findViewById(R.id.nearest).setPressed(true); - cgeocaches.startActivityNearest(this, geo.coordsNow); + cgeocaches.startActivityNearest(this, app.currentGeo().getCoords()); } /** @@ -704,6 +670,14 @@ public class cgeo extends AbstractActivity { findViewById(R.id.filter_button).performClick(); } + /** + * @param v + * unused here but needed since this method is referenced from XML layout + */ + public void cgeoNavSettings(View v) { + startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS)); + } + private class CountBubbleUpdateThread extends Thread { private Handler countBubbleHandler = new Handler() { private TextView countBubble = null; @@ -723,7 +697,7 @@ public class cgeo extends AbstractActivity { countBubble.setVisibility(View.VISIBLE); } } catch (Exception e) { - Log.w(Settings.tag, "cgeo.countBubbleHander: " + e.toString()); + Log.w("cgeo.countBubbleHander: " + e.toString()); } } }; @@ -748,7 +722,7 @@ public class cgeo extends AbstractActivity { } } - countBubbleCnt = app.getAllStoredCachesCount(true, CacheType.ALL, null); + countBubbleCnt = app.getAllStoredCachesCount(true, CacheType.ALL); countBubbleHandler.sendEmptyMessage(0); } @@ -767,7 +741,7 @@ public class cgeo extends AbstractActivity { boolean more = false; if (version != Settings.getVersion()) { - Log.i(Settings.tag, "Initializing hard cleanup - version changed from " + Settings.getVersion() + " to " + version + "."); + Log.i("Initializing hard cleanup - version changed from " + Settings.getVersion() + " to " + version + "."); more = true; } @@ -805,9 +779,7 @@ public class cgeo extends AbstractActivity { // invoke settings activity to insert login details if (status == StatusCode.NO_LOGIN_INFO_STORED) { - final Context context = cgeo.this; - final Intent initIntent = new Intent(context, cgeoinit.class); - context.startActivity(initIntent); + cgeoinit.startActivity(cgeo.this); } } } @@ -821,9 +793,6 @@ public class cgeo extends AbstractActivity { @Override public void run() { - if (geo == null) { - return; - } if (addressObtaining) { return; } @@ -831,10 +800,10 @@ public class cgeo extends AbstractActivity { try { final Geocoder geocoder = new Geocoder(cgeo.this, Locale.getDefault()); - - addresses = geocoder.getFromLocation(geo.coordsNow.getLatitude(), geo.coordsNow.getLongitude(), 1); + final Geopoint coords = app.currentGeo().getCoords(); + addresses = geocoder.getFromLocation(coords.getLatitude(), coords.getLongitude(), 1); } catch (Exception e) { - Log.i(Settings.tag, "Failed to obtain address"); + Log.i("Failed to obtain address"); } obtainAddressHandler.sendEmptyMessage(0); diff --git a/main/src/cgeo/geocaching/cgeoabout.java b/main/src/cgeo/geocaching/cgeoabout.java index 1fc6605..f112539 100644 --- a/main/src/cgeo/geocaching/cgeoabout.java +++ b/main/src/cgeo/geocaching/cgeoabout.java @@ -1,14 +1,13 @@ package cgeo.geocaching; import cgeo.geocaching.activity.AbstractActivity; +import cgeo.geocaching.utils.Log; import android.content.Intent; import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; import android.net.Uri; import android.os.Bundle; import android.text.method.LinkMovementMethod; -import android.util.Log; import android.view.View; import android.widget.TextView; @@ -27,17 +26,13 @@ public class cgeoabout extends AbstractActivity { private void init() { try { - PackageManager manager = this.getPackageManager(); - PackageInfo info = manager.getPackageInfo(this.getPackageName(), 0); + final PackageInfo info = getPackageManager().getPackageInfo(this.getPackageName(), 0); setTitle(res.getString(R.string.about) + " (ver. " + info.versionName + ")"); - - manager = null; - ((TextView) findViewById(R.id.contributors)).setMovementMethod(LinkMovementMethod.getInstance()); ((TextView) findViewById(R.id.changelog)).setMovementMethod(LinkMovementMethod.getInstance()); } catch (Exception e) { - Log.e(Settings.tag, "cgeoabout.init: Failed to obtain package version."); + Log.e("cgeoabout.init: Failed to obtain package version."); } } diff --git a/main/src/cgeo/geocaching/cgeoadvsearch.java b/main/src/cgeo/geocaching/cgeoadvsearch.java index db0088c..4fac391 100644 --- a/main/src/cgeo/geocaching/cgeoadvsearch.java +++ b/main/src/cgeo/geocaching/cgeoadvsearch.java @@ -4,9 +4,10 @@ import cgeo.geocaching.activity.AbstractActivity; import cgeo.geocaching.connector.gc.GCConstants; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.geopoint.GeopointFormatter; -import cgeo.geocaching.geopoint.GeopointParser; import cgeo.geocaching.utils.BaseUtils; import cgeo.geocaching.utils.EditUtils; +import cgeo.geocaching.utils.IObserver; +import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; @@ -14,7 +15,6 @@ import android.app.SearchManager; import android.content.Intent; import android.content.res.Configuration; import android.os.Bundle; -import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; @@ -24,16 +24,13 @@ import android.widget.AutoCompleteTextView; import android.widget.Button; import android.widget.EditText; -public class cgeoadvsearch extends AbstractActivity { +public class cgeoadvsearch extends AbstractActivity implements IObserver<IGeoData> { public static final String EXTRAS_KEYWORDSEARCH = "keywordsearch"; private static final int MENU_SEARCH_OWN_CACHES = 1; - private cgGeo geo = null; - private UpdateLocationCallback geoUpdate = new update(); private EditText latEdit = null; private EditText lonEdit = null; - private String[] geocodesInCache = null; public cgeoadvsearch() { super("c:geo-search"); @@ -80,34 +77,13 @@ public class cgeoadvsearch extends AbstractActivity { @Override public void onResume() { super.onResume(); - + app.addGeoObserver(this); init(); } @Override - public void onDestroy() { - if (geo != null) { - geo = app.removeGeo(); - } - - super.onDestroy(); - } - - @Override - public void onStop() { - if (geo != null) { - geo = app.removeGeo(); - } - - super.onStop(); - } - - @Override public void onPause() { - if (geo != null) { - geo = app.removeGeo(); - } - + app.deleteGeoObserver(this); super.onPause(); } @@ -121,32 +97,25 @@ public class cgeoadvsearch extends AbstractActivity { * @return true if a search was performed, else false */ private boolean instantSearch(final String query, final boolean keywordSearch) { - try { - String result = BaseUtils.getMatch(query, GCConstants.PATTERN_GC_CODE, true, 0, "", false); - if (StringUtils.isNotBlank(result)) { - final Intent cachesIntent = new Intent(this, CacheDetailActivity.class); - cachesIntent.putExtra("geocode", result.toUpperCase()); - startActivity(cachesIntent); + final String geocode = BaseUtils.getMatch(query, GCConstants.PATTERN_GC_CODE, true, 0, "", false); + if (StringUtils.isNotBlank(geocode)) { + final Intent cachesIntent = new Intent(this, CacheDetailActivity.class); + cachesIntent.putExtra("geocode", geocode.toUpperCase()); + startActivity(cachesIntent); + return true; + } - return true; - } else { - result = BaseUtils.getMatch(query, GCConstants.PATTERN_TB_CODE, true, 0, "", false); - if (StringUtils.isNotBlank(result)) { - final Intent trackablesIntent = new Intent(this, cgeotrackable.class); - trackablesIntent.putExtra("geocode", result.toUpperCase()); - startActivity(trackablesIntent); - - return true; - } else if (keywordSearch) { // keyword fallback, if desired by caller - cgeocaches.startActivityKeyword(this, query.trim()); - return true; - } else { - return false; - } + final String trackable = BaseUtils.getMatch(query, GCConstants.PATTERN_TB_CODE, true, 0, "", false); + if (StringUtils.isNotBlank(trackable)) { + final Intent trackablesIntent = new Intent(this, cgeotrackable.class); + trackablesIntent.putExtra("geocode", trackable.toUpperCase()); + startActivity(trackablesIntent); + return true; + } - } - } catch (Exception e) { - Log.w(Settings.tag, "cgeoadvsearch.instantSearch: " + e.toString()); + if (keywordSearch) { // keyword fallback, if desired by caller + cgeocaches.startActivityKeyword(this, query.trim()); + return true; } return false; @@ -155,10 +124,6 @@ public class cgeoadvsearch extends AbstractActivity { private void init() { Settings.getLogin(); - if (geo == null) { - geo = app.startGeo(geoUpdate); - } - ((Button) findViewById(R.id.buttonLatitude)).setOnClickListener(new findByCoordsAction()); ((Button) findViewById(R.id.buttonLongitude)).setOnClickListener(new findByCoordsAction()); @@ -184,7 +149,7 @@ public class cgeoadvsearch extends AbstractActivity { findByGeocodeFn(); } }); - geocodesInCache = app.geocodesInCache(); + final String[] geocodesInCache = app.geocodesInCache(); if (geocodesInCache != null) { final ArrayAdapter<String> geocodesAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line, geocodesInCache); geocodeEdit.setAdapter(geocodesAdapter); @@ -246,33 +211,26 @@ public class cgeoadvsearch extends AbstractActivity { displayTrackable.setOnClickListener(new findTrackableListener()); } - private class update implements UpdateLocationCallback { - - @Override - public void updateLocation(cgGeo geo) { - if (geo == null) { - return; + @Override + public void update(final IGeoData geo) { + try { + if (latEdit == null) { + latEdit = (EditText) findViewById(R.id.latitude); + } + if (lonEdit == null) { + lonEdit = (EditText) findViewById(R.id.longitude); } - try { - if (latEdit == null) { - latEdit = (EditText) findViewById(R.id.latitude); - } - if (lonEdit == null) { - lonEdit = (EditText) findViewById(R.id.longitude); + if (geo.getCoords() != null) { + if (latEdit != null) { + latEdit.setHint(geo.getCoords().format(GeopointFormatter.Format.LAT_DECMINUTE_RAW)); } - - if (geo.coordsNow != null) { - if (latEdit != null) { - latEdit.setHint(geo.coordsNow.format(GeopointFormatter.Format.LAT_DECMINUTE_RAW)); - } - if (lonEdit != null) { - lonEdit.setHint(geo.coordsNow.format(GeopointFormatter.Format.LON_DECMINUTE_RAW)); - } + if (lonEdit != null) { + lonEdit.setHint(geo.getCoords().format(GeopointFormatter.Format.LON_DECMINUTE_RAW)); } - } catch (Exception e) { - Log.w(Settings.tag, "Failed to update location."); } + } catch (Exception e) { + Log.w("Failed to update location."); } } @@ -280,7 +238,7 @@ public class cgeoadvsearch extends AbstractActivity { @Override public void onClick(View arg0) { - cgeocoords coordsDialog = new cgeocoords(cgeoadvsearch.this, null, null, geo); + cgeocoords coordsDialog = new cgeocoords(cgeoadvsearch.this, null, null, app.currentGeo()); coordsDialog.setCancelable(true); coordsDialog.setOnCoordinateUpdate(new cgeocoords.CoordinateUpdate() { @Override @@ -307,14 +265,15 @@ public class cgeoadvsearch extends AbstractActivity { final String lonText = lonView.getText().toString(); if (StringUtils.isEmpty(latText) || StringUtils.isEmpty(lonText)) { - if (geo.coordsNow != null) { - latView.setText(geo.coordsNow.format(GeopointFormatter.Format.LAT_DECMINUTE)); - lonView.setText(geo.coordsNow.format(GeopointFormatter.Format.LON_DECMINUTE)); + final IGeoData geo = app.currentGeo(); + if (geo.getCoords() != null) { + latView.setText(geo.getCoords().format(GeopointFormatter.Format.LAT_DECMINUTE)); + lonView.setText(geo.getCoords().format(GeopointFormatter.Format.LON_DECMINUTE)); } } else { try { - cgeocaches.startActivityCoordinates(this, GeopointParser.parseLatitude(latText), GeopointParser.parseLongitude(lonText)); - } catch (GeopointParser.ParseException e) { + cgeocaches.startActivityCoordinates(this, new Geopoint(latText, lonText)); + } catch (Geopoint.ParseException e) { showToast(res.getString(e.resource)); } } diff --git a/main/src/cgeo/geocaching/cgeoapplication.java b/main/src/cgeo/geocaching/cgeoapplication.java index e2b39d8..d0ee5c3 100644 --- a/main/src/cgeo/geocaching/cgeoapplication.java +++ b/main/src/cgeo/geocaching/cgeoapplication.java @@ -7,6 +7,9 @@ import cgeo.geocaching.enumerations.LoadFlags.LoadFlag; import cgeo.geocaching.enumerations.LoadFlags.RemoveFlag; import cgeo.geocaching.enumerations.LogType; import cgeo.geocaching.geopoint.Geopoint; +import cgeo.geocaching.geopoint.Viewport; +import cgeo.geocaching.utils.IObserver; +import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; @@ -17,13 +20,11 @@ import android.content.Context; import android.content.res.Resources; import android.os.Handler; import android.os.Message; -import android.util.Log; import java.io.File; -import java.util.ArrayList; +import java.util.Collections; import java.util.Date; import java.util.EnumSet; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -33,9 +34,7 @@ public class cgeoapplication extends Application { private cgData storage = null; private String action = null; - private Geopoint lastCoords = null; - private cgGeo geo = null; - private boolean geoInUse = false; + private volatile GeoDataProvider geo; private cgDirection dir = null; private boolean dirInUse = false; public boolean firstRun = true; // c:geo is just launched @@ -54,16 +53,15 @@ public class cgeoapplication extends Application { @Override public void onLowMemory() { - Log.i(Settings.tag, "Cleaning applications cache."); + Log.i("Cleaning applications cache."); storage.removeAllFromCache(); } @Override public void onTerminate() { - Log.d(Settings.tag, "Terminating c:geo..."); + Log.d("Terminating c:geo..."); - cleanGeo(); cleanDir(); if (storage != null) { @@ -114,73 +112,45 @@ public class cgeoapplication extends Application { restoreThread.start(); } - public void cleanGeo() { - if (geo != null) { - geo.closeGeo(); - geo = null; - } - } - - public void cleanDir() { - if (dir != null) { - dir.closeDir(); - dir = null; - } + public void addGeoObserver(final IObserver<? super IGeoData> observer) { + currentGeoObject().addObserver(observer); } - public boolean storageStatus() { - return storage.status(); + public void deleteGeoObserver(final IObserver<? super IGeoData> observer) { + currentGeoObject().deleteObserver(observer); } - public cgGeo startGeo(UpdateLocationCallback geoUpdate) { + private GeoDataProvider currentGeoObject() { if (geo == null) { - geo = new cgGeo(); - Log.i(Settings.tag, "Location service started"); + synchronized(this) { + if (geo == null) { + geo = new GeoDataProvider(this); + } + } } - - geo.replaceUpdate(geoUpdate); - geoInUse = true; - return geo; } - public float getSpeedFromGeo() { - return geo != null ? geo.speedNow : 0f; + public IGeoData currentGeo() { + return currentGeoObject().getMemory(); } - public cgGeo removeGeo() { - if (geo != null) { - geo.replaceUpdate(null); + public void cleanDir() { + if (dir != null) { + dir.closeDir(); + dir = null; } - geoInUse = false; - - (new removeGeoThread()).start(); - - return null; } - private class removeGeoThread extends Thread { - - @Override - public void run() { - try { - sleep(2500); - } catch (Exception e) { - // nothing - } - - if (!geoInUse && geo != null) { - cleanGeo(); - Log.i(Settings.tag, "Location service stopped"); - } - } + public boolean storageStatus() { + return storage.status(); } public cgDirection startDir(Context context, UpdateDirectionCallback dirUpdate) { if (dir == null) { dir = new cgDirection(context, dirUpdate); - Log.i(Settings.tag, "Direction service started"); + Log.i("Direction service started"); } dir.replaceUpdate(dirUpdate); @@ -212,7 +182,7 @@ public class cgeoapplication extends Application { if (!dirInUse && dir != null) { cleanDir(); - Log.i(Settings.tag, "Direction service stopped"); + Log.i("Direction service stopped"); } } } @@ -264,10 +234,7 @@ public class cgeoapplication extends Application { return null; } - cgTrackable trackable = null; - trackable = storage.loadTrackable(geocode); - - return trackable; + return storage.loadTrackable(geocode); } /** {@link cgData#allDetailedThere()} */ @@ -275,56 +242,53 @@ public class cgeoapplication extends Application { return storage.allDetailedThere(); } - public List<Number> getBounds(String geocode) { + public Viewport getBounds(String geocode) { if (geocode == null) { return null; } - Set<String> geocodeList = new HashSet<String>(); - geocodeList.add(geocode); - - return getBounds(geocodeList); + return getBounds(Collections.singleton(geocode)); } /** {@link cgData#getBounds(Set)} */ - public List<Number> getBounds(final Set<String> geocodes) { + public Viewport getBounds(final Set<String> geocodes) { return storage.getBounds(geocodes); } /** {@link cgData#loadBatchOfStoredGeocodes(boolean, Geopoint, CacheType, int)} */ public SearchResult getBatchOfStoredCaches(final boolean detailedOnly, final Geopoint coords, final CacheType cacheType, final int listId) { final Set<String> geocodes = storage.loadBatchOfStoredGeocodes(detailedOnly, coords, cacheType, listId); - final SearchResult search = new SearchResult(geocodes); - search.totalCnt = getAllStoredCachesCount(true, cacheType, listId); - return search; + return new SearchResult(geocodes, getAllStoredCachesCount(true, cacheType, listId)); } /** {@link cgData#loadHistoryOfSearchedLocations()} */ - public List<cgDestination> getHistoryOfSearchedLocations() { + public List<Destination> getHistoryOfSearchedLocations() { return storage.loadHistoryOfSearchedLocations(); } public SearchResult getHistoryOfCaches(final boolean detailedOnly, final CacheType cacheType) { final Set<String> geocodes = storage.loadBatchOfHistoricGeocodes(detailedOnly, cacheType); - final SearchResult search = new SearchResult(geocodes); - - search.totalCnt = getAllHistoricCachesCount(); - return search; + return new SearchResult(geocodes, getAllHistoricCachesCount()); } - /** {@link cgData#loadCachedInViewport(Long, Long, Long, Long, CacheType)} */ - public SearchResult getCachedInViewport(final Long centerLat, final Long centerLon, final Long spanLat, final Long spanLon, final CacheType cacheType) { - final Set<String> geocodes = storage.loadCachedInViewport(centerLat, centerLon, spanLat, spanLon, cacheType); + /** {@link cgData#loadCachedInViewport(Viewport, CacheType)} */ + public SearchResult getCachedInViewport(final Viewport viewport, final CacheType cacheType) { + final Set<String> geocodes = storage.loadCachedInViewport(viewport, cacheType); return new SearchResult(geocodes); } - /** {@link cgData#loadStoredInViewport(Long, Long, Long, Long, CacheType)} */ - public SearchResult getStoredInViewport(final Long centerLat, final Long centerLon, final Long spanLat, final Long spanLon, final CacheType cacheType) { - final Set<String> geocodes = storage.loadStoredInViewport(centerLat, centerLon, spanLat, spanLon, cacheType); + /** {@link cgData#loadStoredInViewport(Viewport, CacheType)} */ + public SearchResult getStoredInViewport(final Viewport viewport, final CacheType cacheType) { + final Set<String> geocodes = storage.loadStoredInViewport(viewport, cacheType); return new SearchResult(geocodes); } - /** {@link cgData#getAllStoredCachesCount(boolean, CacheType, Integer)} */ + /** {@link cgData#getAllStoredCachesCount(boolean, CacheType, int)} */ + public int getAllStoredCachesCount(final boolean detailedOnly, final CacheType cacheType) { + return storage.getAllStoredCachesCount(detailedOnly, cacheType, 0); + } + + /** {@link cgData#getAllStoredCachesCount(boolean, CacheType, int)} */ public int getAllStoredCachesCount(final boolean detailedOnly, final CacheType cacheType, final Integer list) { return storage.getAllStoredCachesCount(detailedOnly, cacheType, list); } @@ -335,18 +299,13 @@ public class cgeoapplication extends Application { } /** {@link cgData#moveToList(String, int)} */ - public void markStored(String geocode, int listId) { - storage.moveToList(geocode, listId); + public void markStored(List<cgCache> caches, int listId) { + storage.moveToList(caches, listId); } /** {@link cgData#moveToList(String, int)} */ - public void markDropped(String geocode) { - storage.moveToList(geocode, StoredList.TEMPORARY_LIST_ID); - } - - /** {@link cgData#markFound(String)} */ - public boolean markFound(String geocode) { - return storage.markFound(geocode); + public void markDropped(List<cgCache> caches) { + storage.moveToList(caches, StoredList.TEMPORARY_LIST_ID); } /** {@link cgData#clearSearchedDestinations()} */ @@ -354,14 +313,14 @@ public class cgeoapplication extends Application { return storage.clearSearchedDestinations(); } - /** {@link cgData#saveSearchedDestination(cgDestination)} */ - public boolean saveSearchedDestination(cgDestination destination) { - return storage.saveSearchedDestination(destination); + /** {@link cgData#saveSearchedDestination(Destination)} */ + public void saveSearchedDestination(Destination destination) { + storage.saveSearchedDestination(destination); } /** {@link cgData#saveWaypoints(String, List, boolean)} */ - public boolean saveWaypoints(String geocode, List<cgWaypoint> waypoints, boolean drop) { - return storage.saveWaypoints(geocode, waypoints, drop); + public boolean saveWaypoints(final cgCache cache) { + return storage.saveWaypoints(cache); } public boolean saveOwnWaypoint(int id, String geocode, cgWaypoint waypoint) { @@ -378,10 +337,7 @@ public class cgeoapplication extends Application { } public boolean saveTrackable(cgTrackable trackable) { - final List<cgTrackable> list = new ArrayList<cgTrackable>(); - list.add(trackable); - - return storage.saveInventory("---", list); + return storage.saveTrackable(trackable); } /** {@link cgData#dropList(int)} **/ @@ -389,21 +345,11 @@ public class cgeoapplication extends Application { storage.dropList(listId); } - /** {@link cgData#loadInventory(String)} */ - public List<cgTrackable> loadInventory(String geocode) { - return storage.loadInventory(geocode); - } - /** {@link cgData#loadLogCounts(String)} */ public Map<LogType, Integer> loadLogCounts(String geocode) { return storage.loadLogCounts(geocode); } - /** {@link cgData#loadSpoilers(String)} */ - public List<cgImage> loadSpoilers(String geocode) { - return storage.loadSpoilers(geocode); - } - /** {@link cgData#loadWaypoint(int)} */ public cgWaypoint loadWaypoint(int id) { return storage.loadWaypoint(id); @@ -428,35 +374,13 @@ public class cgeoapplication extends Application { return StringUtils.defaultString(action); } - public boolean addLog(String geocode, cgLog log) { - if (StringUtils.isBlank(geocode)) { - return false; - } - if (log == null) { - return false; - } - - List<cgLog> list = new ArrayList<cgLog>(); - list.add(log); - - return storage.saveLogs(geocode, list, false); - } - - public void setLastCoords(final Geopoint coords) { - lastCoords = coords; - } - - public Geopoint getLastCoords() { - return lastCoords; - } - /** {@link cgData#saveLogOffline(String, Date, LogType, String)} */ public boolean saveLogOffline(String geocode, Date date, LogType logtype, String log) { return storage.saveLogOffline(geocode, date, logtype, log); } /** {@link cgData#loadLogOffline(String)} */ - public cgLog loadLogOffline(String geocode) { + public LogEntry loadLogOffline(String geocode) { return storage.loadLogOffline(geocode); } @@ -500,14 +424,14 @@ public class cgeoapplication extends Application { return storage.removeList(id); } - /** {@link cgData#removeSearchedDestination(cgDestination)} */ - public boolean removeSearchedDestinations(cgDestination destination) { + /** {@link cgData#removeSearchedDestination(Destination)} */ + public boolean removeSearchedDestinations(Destination destination) { return storage.removeSearchedDestination(destination); } /** {@link cgData#moveToList(String, int)} */ - public void moveToList(String geocode, int listId) { - storage.moveToList(geocode, listId); + public void moveToList(List<cgCache> caches, int listId) { + storage.moveToList(caches, listId); } /** {@link cgData#getCacheDescription(String)} */ @@ -525,11 +449,6 @@ public class cgeoapplication extends Application { return storage.loadCaches(geocodes, loadFlags); } - /** {@link cgData#loadCaches} */ - public Set<cgCache> loadCaches(Long centerLat, Long centerLon, Long spanLat, Long spanLon, final EnumSet<LoadFlag> loadFlags) { - return storage.loadCaches(null, centerLat, centerLon, spanLat, spanLon, loadFlags); - } - /** {@link cgData#saveCache} */ public boolean saveCache(cgCache cache, EnumSet<LoadFlags.SaveFlag> saveFlags) { return storage.saveCache(cache, saveFlags); @@ -545,4 +464,8 @@ public class cgeoapplication extends Application { storage.removeCaches(geocodes, removeFlags); } + public Set<cgWaypoint> getWaypointsInViewport(final Viewport viewport, boolean excludeMine, boolean excludeDisabled) { + return storage.loadWaypoints(viewport, excludeMine, excludeDisabled); + } + } diff --git a/main/src/cgeo/geocaching/cgeocaches.java b/main/src/cgeo/geocaching/cgeocaches.java index 21ecb5e..db44e16 100644 --- a/main/src/cgeo/geocaching/cgeocaches.java +++ b/main/src/cgeo/geocaching/cgeocaches.java @@ -6,21 +6,19 @@ import cgeo.geocaching.activity.ActivityMixin; import cgeo.geocaching.activity.Progress; import cgeo.geocaching.apps.cache.navi.NavigationAppFactory; import cgeo.geocaching.apps.cachelist.CacheListAppFactory; +import cgeo.geocaching.connector.gc.GCParser; import cgeo.geocaching.enumerations.CacheListType; import cgeo.geocaching.enumerations.CacheType; import cgeo.geocaching.enumerations.LoadFlags; import cgeo.geocaching.enumerations.LogType; import cgeo.geocaching.enumerations.StatusCode; +import cgeo.geocaching.export.ExportFactory; import cgeo.geocaching.files.GPXImporter; -import cgeo.geocaching.filter.AttributeFilter; +import cgeo.geocaching.filter.FilterUserInterface; import cgeo.geocaching.filter.IFilter; -import cgeo.geocaching.filter.ModifiedFilter; -import cgeo.geocaching.filter.SizeFilter; -import cgeo.geocaching.filter.StateFilter; -import cgeo.geocaching.filter.TrackablesFilter; -import cgeo.geocaching.filter.TypeFilter; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.maps.CGeoMap; +import cgeo.geocaching.network.Cookies; import cgeo.geocaching.network.Network; import cgeo.geocaching.network.Parameters; import cgeo.geocaching.sorting.CacheComparator; @@ -39,6 +37,8 @@ import cgeo.geocaching.sorting.TerrainComparator; import cgeo.geocaching.sorting.VisitComparator; import cgeo.geocaching.sorting.VoteComparator; import cgeo.geocaching.ui.CacheListAdapter; +import cgeo.geocaching.utils.IObserver; +import cgeo.geocaching.utils.Log; import cgeo.geocaching.utils.RunnableWithArgument; import org.apache.commons.collections.CollectionUtils; @@ -50,13 +50,10 @@ import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; -import android.content.res.Configuration; import android.net.Uri; import android.os.Bundle; -import android.os.Environment; import android.os.Handler; import android.os.Message; -import android.util.Log; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.KeyEvent; @@ -66,31 +63,22 @@ import android.view.MenuItem; import android.view.SubMenu; import android.view.View; import android.widget.AdapterView.AdapterContextMenuInfo; -import android.widget.EditText; import android.widget.ListView; -import android.widget.RelativeLayout; import android.widget.TextView; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.Writer; -import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collections; -import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; -public class cgeocaches extends AbstractListActivity { +public class cgeocaches extends AbstractListActivity implements IObserver<IGeoData> { private static final int MAX_LIST_ITEMS = 1000; private static final String EXTRAS_LIST_TYPE = "type"; + private static final String EXTRAS_COORDS = "coords"; private static final int MENU_REFRESH_STORED = 2; private static final int MENU_CACHE_DETAILS = 4; private static final int MENU_DROP_CACHES = 5; @@ -110,21 +98,15 @@ public class cgeocaches extends AbstractListActivity { private static final int MENU_SORT_VOTE = 19; private static final int MENU_SORT_INVENTORY = 20; private static final int MENU_IMPORT_WEB = 21; - private static final int MENU_EXPORT_NOTES = 22; + private static final int MENU_EXPORT = 22; private static final int MENU_REMOVE_FROM_HISTORY = 23; private static final int MENU_DROP_CACHE = 24; private static final int MENU_MOVE_TO_LIST = 25; - private static final int MENU_FILTER_CLEAR = 26; - private static final int MENU_FILTER_TRACKABLES = 27; - private static final int SUBMENU_FILTER_SIZE = 28; - private static final int SUBMENU_FILTER_TYPE = 29; private static final int MENU_SWITCH_SELECT_MODE = 52; private static final int SUBMENU_SHOW_MAP = 54; private static final int SUBMENU_MANAGE_LISTS = 55; private static final int SUBMENU_MANAGE_OFFLINE = 56; private static final int SUBMENU_SORT = 57; - private static final int SUBMENU_FILTER = 58; - private static final int SUBMENU_IMPORT = 59; private static final int SUBMENU_MANAGE_HISTORY = 60; private static final int MENU_SORT_DATE = 61; private static final int MENU_SORT_FINDS = 62; @@ -132,12 +114,12 @@ public class cgeocaches extends AbstractListActivity { private static final int MENU_RENAME_LIST = 64; private static final int MENU_DROP_CACHES_AND_LIST = 65; private static final int MENU_DEFAULT_NAVIGATION = 66; - private static final int SUBMENU_FILTER_ATTRIBUTES = 67; - private static final int SUBMENU_FILTER_STATE = 68; private static final int MENU_NAVIGATION = 69; - private static final int MENU_FILTER_MODIFIED = 70; + private static final int MENU_STORE_CACHE = 73; + private static final int MENU_FILTER = 74; private static final int MSG_DONE = -1; + private static final int MSG_RESTART_GEO_AND_DIR = -2; private static final int MSG_CANCEL = -99; private String action = null; @@ -155,9 +137,7 @@ public class cgeocaches extends AbstractListActivity { private TextView listFooterText = null; private Progress progress = new Progress(); private Float northHeading = 0f; - private cgGeo geo = null; private cgDirection dir = null; - private UpdateLocationCallback geoUpdate = new UpdateLocation(); private UpdateDirectionCallback dirUpdate = new UpdateDirection(); private String title = ""; private int detailTotal = 0; @@ -165,11 +145,8 @@ public class cgeocaches extends AbstractListActivity { private long detailProgressTime = 0L; private LoadDetailsThread threadDetails = null; private LoadFromWebThread threadWeb = null; - private DropDetailsThread threadR = null; - private ExportFieldNotesThread threadF = null; private RemoveFromHistoryThread threadH = null; private int listId = StoredList.TEMPORARY_LIST_ID; - private List<StoredList> lists = null; private GeocodeComparator gcComparator = new GeocodeComparator(); private Handler loadCachesHandler = new Handler() { @@ -177,7 +154,7 @@ public class cgeocaches extends AbstractListActivity { public void handleMessage(Message msg) { try { if (search != null) { - setTitle(title + " [" + search.getCount() + "]"); + setTitle(title + " [" + search.getCount() + ']'); cacheList.clear(); final Set<cgCache> caches = search.getCachesFromSearchResult(LoadFlags.LOAD_CACHE_OR_DB); @@ -206,14 +183,14 @@ public class cgeocaches extends AbstractListActivity { dialog.setNegativeButton(res.getString(R.string.license_dismiss), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { - Network.clearCookies(); + Cookies.clearCookies(); dialog.cancel(); } }); dialog.setPositiveButton(res.getString(R.string.license_show), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { - Network.clearCookies(); + Cookies.clearCookies(); startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/software/agreement.aspx?ID=0"))); } }); @@ -221,7 +198,7 @@ public class cgeocaches extends AbstractListActivity { AlertDialog alert = dialog.create(); alert.show(); } else if (app != null && search != null && search.getError() != null) { - showToast(res.getString(R.string.err_download_fail) + " " + search.getError().getErrorString(res) + "."); + showToast(res.getString(R.string.err_download_fail) + ' ' + search.getError().getErrorString(res) + '.'); hideLoading(); showProgress(false); @@ -230,13 +207,14 @@ public class cgeocaches extends AbstractListActivity { return; } - if (geo != null && geo.coordsNow != null) { - adapter.setActualCoordinates(geo.coordsNow); + final Geopoint coordsNow = app.currentGeo().getCoords(); + if (coordsNow != null) { + adapter.setActualCoordinates(coordsNow); adapter.setActualHeading(northHeading); } } catch (Exception e) { showToast(res.getString(R.string.err_detail_cache_find_any)); - Log.e(Settings.tag, "cgeocaches.loadCachesHandler: " + e.toString()); + Log.e("cgeocaches.loadCachesHandler: " + e.toString()); hideLoading(); showProgress(false); @@ -249,7 +227,7 @@ public class cgeocaches extends AbstractListActivity { hideLoading(); showProgress(false); } catch (Exception e2) { - Log.e(Settings.tag, "cgeocaches.loadCachesHandler.2: " + e2.toString()); + Log.e("cgeocaches.loadCachesHandler.2: " + e2.toString()); } if (adapter != null) { @@ -297,13 +275,14 @@ public class cgeocaches extends AbstractListActivity { return; } - if (geo != null && geo.coordsNow != null) { - adapter.setActualCoordinates(geo.coordsNow); + final Geopoint coordsNow = app.currentGeo().getCoords(); + if (coordsNow != null) { + adapter.setActualCoordinates(coordsNow); adapter.setActualHeading(northHeading); } } catch (Exception e) { showToast(res.getString(R.string.err_detail_cache_find_next)); - Log.e(Settings.tag, "cgeocaches.loadNextPageHandler: " + e.toString()); + Log.e("cgeocaches.loadNextPageHandler: " + e.toString()); } hideLoading(); @@ -342,6 +321,8 @@ public class cgeocaches extends AbstractListActivity { if (threadDetails != null) { threadDetails.kill(); } + } else if (msg.what == MSG_RESTART_GEO_AND_DIR) { + startGeoAndDir(); } else { if (cacheList != null && search != null) { final Set<cgCache> cacheListTmp = search.getCachesFromSearchResult(LoadFlags.LOAD_CACHE_OR_DB); @@ -353,8 +334,9 @@ public class cgeocaches extends AbstractListActivity { } } - if (geo != null && geo.coordsNow != null) { - adapter.setActualCoordinates(geo.coordsNow); + final Geopoint coordsNow = app.currentGeo().getCoords(); + if (coordsNow != null) { + adapter.setActualCoordinates(coordsNow); adapter.setActualHeading(northHeading); } @@ -383,12 +365,10 @@ public class cgeocaches extends AbstractListActivity { refreshCurrentList(); } else if (msg.what == -2) { progress.dismiss(); - startGeoAndDir(); showToast(res.getString(R.string.sendToCgeo_download_fail)); finish(); } else if (msg.what == -3) { progress.dismiss(); - startGeoAndDir(); showToast(res.getString(R.string.sendToCgeo_no_registration)); finish(); } else if (msg.what == MSG_CANCEL) { @@ -410,7 +390,6 @@ public class cgeocaches extends AbstractListActivity { Collections.sort(cacheList, gcComparator); } - startGeoAndDir(); progress.dismiss(); } } @@ -419,11 +398,7 @@ public class cgeocaches extends AbstractListActivity { @Override public void handleMessage(Message msg) { - if (msg.what == MSG_CANCEL) { - if (threadR != null) { - threadR.kill(); - } - } else { + if (msg.what != MSG_CANCEL) { if (adapter != null) { adapter.setSelectMode(false, true); } @@ -469,39 +444,6 @@ public class cgeocaches extends AbstractListActivity { } } }; - private Handler exportFieldNotesHandler = new Handler() { - - @Override - public void handleMessage(Message msg) - { - setAdapter(); - - if (msg.what > -1) - { - cacheList.get(msg.what).setStatusChecked(false); - progress.setProgress(detailProgress); - } - else if (-2 == msg.what) - { - showToast(res.getString(R.string.info_fieldnotes_exported_to) + ": " + msg.obj.toString()); - } - else if (-3 == msg.what) - { - showToast(res.getString(R.string.err_fieldnotes_export_failed)); - } else if (msg.what == MSG_CANCEL) { - if (threadF != null) { - threadF.kill(); - } - } else { - if (adapter != null) - { - adapter.setSelectMode(false, true); - } - - progress.dismiss(); - } - } - }; private Handler importGpxAttachementFinishedHandler = new Handler() { @Override @@ -526,6 +468,13 @@ public class cgeocaches extends AbstractListActivity { super.onCreate(savedInstanceState); // init + if (CollectionUtils.isNotEmpty(cacheList)) { + setMoreCaches(); + } + + setTitle(title); + setAdapter(); + app.setAction(action); setTheme(); @@ -537,7 +486,7 @@ public class cgeocaches extends AbstractListActivity { if (extras != null) { Object typeObject = extras.get(EXTRAS_LIST_TYPE); type = (typeObject instanceof CacheListType) ? (CacheListType) typeObject : CacheListType.OFFLINE; - coords = new Geopoint(extras.getDouble("latitude"), extras.getDouble("longitude")); + coords = (Geopoint) extras.getParcelable(EXTRAS_COORDS); cacheType = Settings.getCacheType(); keyword = extras.getString("keyword"); address = extras.getString("address"); @@ -546,12 +495,10 @@ public class cgeocaches extends AbstractListActivity { if (Intent.ACTION_VIEW.equals(getIntent().getAction())) { type = CacheListType.OFFLINE; if (coords == null) { - coords = new Geopoint(0, 0); + coords = new Geopoint(0.0, 0.0); } } - init(); - Thread threadPure; cgSearchThread thread; @@ -666,7 +613,7 @@ public class cgeocaches extends AbstractListActivity { default: title = "caches"; setTitle(title); - Log.e(Settings.tag, "cgeocaches.onCreate: No action or unknown action specified"); + Log.e("cgeocaches.onCreate: No action or unknown action specified"); break; } prepareFilterBar(); @@ -696,27 +643,18 @@ public class cgeocaches extends AbstractListActivity { } @Override - public void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - - init(); - } - - @Override public void onResume() { super.onResume(); init(); - if (adapter != null && geo != null && geo.coordsNow != null) { - adapter.setActualCoordinates(geo.coordsNow); - adapter.setActualHeading(northHeading); - } - if (adapter != null) { adapter.setSelectMode(false, true); - if (geo != null && geo.coordsNow != null) { - adapter.forceSort(geo.coordsNow); + final Geopoint coordsNow = app.currentGeo().getCoords(); + if (coordsNow != null) { + adapter.setActualCoordinates(coordsNow); + adapter.setActualHeading(northHeading); + adapter.forceSort(coordsNow); } } @@ -726,8 +664,8 @@ public class cgeocaches extends AbstractListActivity { // refresh standard list if it has changed (new caches downloaded) if (type == CacheListType.OFFLINE && listId >= StoredList.STANDARD_LIST_ID && search != null) { - SearchResult newSearch = cgBase.searchByStored(coords, cacheType, listId); - if (newSearch != null && newSearch.totalCnt != search.totalCnt) { + SearchResult newSearch = cgeoapplication.getInstance().getBatchOfStoredCaches(true, coords, cacheType, listId); + if (newSearch != null && newSearch.getTotal() != search.getTotal()) { refreshCurrentList(); } } @@ -739,15 +677,11 @@ public class cgeocaches extends AbstractListActivity { adapter = null; } - removeGeoAndDir(); - super.onDestroy(); } @Override public void onStop() { - removeGeoAndDir(); - super.onStop(); } @@ -760,17 +694,7 @@ public class cgeocaches extends AbstractListActivity { @Override public boolean onCreateOptionsMenu(Menu menu) { - SubMenu subMenuFilter = menu.addSubMenu(0, SUBMENU_FILTER, 0, res.getString(R.string.caches_filter)).setIcon(R.drawable.ic_menu_filter); - subMenuFilter.setHeaderTitle(res.getString(R.string.caches_filter_title)); - if (Settings.getCacheType() == CacheType.ALL) { - subMenuFilter.add(0, SUBMENU_FILTER_TYPE, 0, res.getString(R.string.caches_filter_type)); - } - subMenuFilter.add(0, SUBMENU_FILTER_SIZE, 0, res.getString(R.string.caches_filter_size)); - subMenuFilter.add(0, SUBMENU_FILTER_ATTRIBUTES, 0, res.getString(R.string.cache_attributes)); - subMenuFilter.add(0, SUBMENU_FILTER_STATE, 0, res.getString(R.string.cache_status)); - subMenuFilter.add(0, MENU_FILTER_TRACKABLES, 0, res.getString(R.string.caches_filter_track)); - subMenuFilter.add(0, MENU_FILTER_MODIFIED, 0, res.getString(R.string.caches_filter_modified)); - subMenuFilter.add(0, MENU_FILTER_CLEAR, 0, res.getString(R.string.caches_filter_clear)); + menu.add(0, MENU_FILTER, 0, res.getString(R.string.caches_filter)).setIcon(R.drawable.ic_menu_filter); SubMenu subMenuSort = menu.addSubMenu(0, SUBMENU_SORT, 0, res.getString(R.string.caches_sort)).setIcon(android.R.drawable.ic_menu_sort_alphabetically); subMenuSort.setHeaderTitle(res.getString(R.string.caches_sort_title)); @@ -795,7 +719,7 @@ public class cgeocaches extends AbstractListActivity { Collections.sort(sortedLabels); for (String label : sortedLabels) { Integer id = comparators.get(label); - subMenuSort.add(1, id.intValue(), 0, label).setCheckable(true).setChecked(id.intValue() == MENU_SORT_DISTANCE); + subMenuSort.add(1, id, 0, label).setCheckable(true).setChecked(id == MENU_SORT_DISTANCE); } subMenuSort.setGroupCheckable(1, true, true); @@ -808,21 +732,19 @@ public class cgeocaches extends AbstractListActivity { subMenu.add(0, MENU_DROP_CACHES_AND_LIST, 0, res.getString(R.string.caches_drop_all_and_list)); subMenu.add(0, MENU_REFRESH_STORED, 0, res.getString(R.string.cache_offline_refresh)); // download details for all caches subMenu.add(0, MENU_MOVE_TO_LIST, 0, res.getString(R.string.cache_menu_move_list)); - subMenu.add(0, MENU_EXPORT_NOTES, 0, res.getString(R.string.cache_export_fieldnote)); // export field notes - if (Settings.getWebDeviceCode() == null) - { - menu.add(0, MENU_IMPORT_GPX, 0, res.getString(R.string.gpx_import_title)).setIcon(android.R.drawable.ic_menu_upload); // import gpx file - } else { - SubMenu subMenuImport = menu.addSubMenu(0, SUBMENU_IMPORT, 0, res.getString(R.string.import_title)).setIcon(android.R.drawable.ic_menu_upload); // import - subMenuImport.add(1, MENU_IMPORT_GPX, 0, res.getString(R.string.gpx_import_title)).setCheckable(false).setChecked(false); - subMenuImport.add(1, MENU_IMPORT_WEB, 0, res.getString(R.string.web_import_title)).setCheckable(false).setChecked(false); + + //TODO: add submenu/AlertDialog and use R.string.gpx_import_title + subMenu.add(0, MENU_IMPORT_GPX, 0, res.getString(R.string.gpx_import_title)); + if (Settings.getWebDeviceCode() != null) { + subMenu.add(0, MENU_IMPORT_WEB, 0, res.getString(R.string.web_import_title)); } + + subMenu.add(0, MENU_EXPORT, 0, res.getString(R.string.export)); // export caches } else { - if (type == CacheListType.HISTORY) - { + if (type == CacheListType.HISTORY) { SubMenu subMenu = menu.addSubMenu(0, SUBMENU_MANAGE_HISTORY, 0, res.getString(R.string.caches_manage)).setIcon(android.R.drawable.ic_menu_save); subMenu.add(0, MENU_REMOVE_FROM_HISTORY, 0, res.getString(R.string.cache_clear_history)); // remove from history - subMenu.add(0, MENU_EXPORT_NOTES, 0, res.getString(R.string.cache_export_fieldnote)); // export field notes + subMenu.add(0, MENU_EXPORT, 0, res.getString(R.string.export)); // export caches } menu.add(0, MENU_REFRESH_STORED, 0, res.getString(R.string.caches_store_offline)).setIcon(android.R.drawable.ic_menu_set_as); // download details for all caches } @@ -859,40 +781,27 @@ public class cgeocaches extends AbstractListActivity { boolean isNonDefaultList = listId != StoredList.STANDARD_LIST_ID; if (type == CacheListType.OFFLINE) { // only offline list - if (hasSelection) { - menu.findItem(MENU_DROP_CACHES).setTitle(res.getString(R.string.caches_drop_selected) + " (" + adapter.getChecked() + ")"); - } else { - menu.findItem(MENU_DROP_CACHES).setTitle(res.getString(R.string.caches_drop_all)); - } + setMenuItemLabel(menu, MENU_DROP_CACHES, R.string.caches_drop_selected, R.string.caches_drop_all); menu.findItem(MENU_DROP_CACHES_AND_LIST).setVisible(!hasSelection && isNonDefaultList); - - if (hasSelection) { - menu.findItem(MENU_REFRESH_STORED).setTitle(res.getString(R.string.caches_refresh_selected) + " (" + adapter.getChecked() + ")"); - } else { - menu.findItem(MENU_REFRESH_STORED).setTitle(res.getString(R.string.caches_refresh_all)); - } - - if (hasSelection) { - menu.findItem(MENU_MOVE_TO_LIST).setTitle(res.getString(R.string.caches_move_selected) + " (" + adapter.getChecked() + ")"); - } else { - menu.findItem(MENU_MOVE_TO_LIST).setTitle(res.getString(R.string.caches_move_all)); - } + setMenuItemLabel(menu, MENU_REFRESH_STORED, R.string.caches_refresh_selected, R.string.caches_refresh_all); + setMenuItemLabel(menu, MENU_MOVE_TO_LIST, R.string.caches_move_selected, R.string.caches_move_all); } else { // search and history list (all other than offline) - if (hasSelection) { - menu.findItem(MENU_REFRESH_STORED).setTitle(res.getString(R.string.caches_store_selected) + " (" + adapter.getChecked() + ")"); - } else { - menu.findItem(MENU_REFRESH_STORED).setTitle(res.getString(R.string.caches_store_offline)); - } + setMenuItemLabel(menu, MENU_REFRESH_STORED, R.string.caches_store_selected, R.string.caches_store_offline); } // Hide menus if cache-list is empty int[] hideIfEmptyList = new int[] { MENU_SWITCH_SELECT_MODE, - SUBMENU_MANAGE_OFFLINE, SUBMENU_MANAGE_HISTORY, SUBMENU_SHOW_MAP, SUBMENU_SORT, - MENU_REFRESH_STORED }; + MENU_REFRESH_STORED, + MENU_DROP_CACHES, + MENU_DROP_CACHES_AND_LIST, + MENU_MOVE_TO_LIST, + MENU_EXPORT, + MENU_REMOVE_FROM_HISTORY + }; boolean menuVisible = cacheList.size() > 0; for (int itemId : hideIfEmptyList) { @@ -922,42 +831,31 @@ public class cgeocaches extends AbstractListActivity { } item = menu.findItem(MENU_MOVE_TO_LIST); if (item != null) { - item.setVisible(multipleLists); - } - - item = menu.findItem(MENU_REMOVE_FROM_HISTORY); - if (null != item) { - if (hasSelection) { - item.setTitle(res.getString(R.string.cache_remove_from_history) + " (" + adapter.getChecked() + ")"); - } else { - item.setTitle(res.getString(R.string.cache_clear_history)); - } - } - - item = menu.findItem(MENU_EXPORT_NOTES); - if (null != item) { - // Hide Field Notes export if there are no caches with logs - item.setVisible(false); - for (cgCache cache : cacheList) { - if (cache.isLogOffline()) { - item.setVisible(true); - if (hasSelection) { - item.setTitle(res.getString(R.string.cache_export_fieldnote) + " (" + adapter.getChecked() + ")"); - } else { - item.setTitle(res.getString(R.string.cache_export_fieldnote)); - } - break; - } - } + item.setVisible(multipleLists && cacheList.size() > 0); } + setMenuItemLabel(menu, MENU_REMOVE_FROM_HISTORY, R.string.cache_remove_from_history, R.string.cache_clear_history); + setMenuItemLabel(menu, MENU_EXPORT, R.string.export, R.string.export); } catch (Exception e) { - Log.e(Settings.tag, "cgeocaches.onPrepareOptionsMenu: " + e.toString()); + Log.e("cgeocaches.onPrepareOptionsMenu", e); } return true; } + private void setMenuItemLabel(final Menu menu, final int menuId, final int resIdSelection, final int resId) { + final MenuItem menuItem = menu.findItem(menuId); + if (menuItem == null) { + return; + } + boolean hasSelection = adapter != null && adapter.getChecked() > 0; + if (hasSelection) { + menuItem.setTitle(res.getString(resIdSelection) + " (" + adapter.getChecked() + ")"); + } else { + menuItem.setTitle(res.getString(resId)); + } + } + @Override public boolean onOptionsItemSelected(MenuItem item) { int itemId = item.getItemId(); @@ -985,7 +883,7 @@ public class cgeocaches extends AbstractListActivity { invalidateOptionsMenuCompatible(); return false; case MENU_CREATE_LIST: - createList(null); + new StoredList.UserInterface(this).promptForListCreation(null); invalidateOptionsMenuCompatible(); return false; case MENU_DROP_LIST: @@ -1044,34 +942,27 @@ public class cgeocaches extends AbstractListActivity { case MENU_SORT_STATE: setComparator(item, new StateComparator()); return true; - case SUBMENU_FILTER_TYPE: - showFilterMenu(TypeFilter.getAllFilters(), res.getString(R.string.caches_filter_type_title)); - return true; - case SUBMENU_FILTER_SIZE: - showFilterMenu(SizeFilter.getAllFilters(), res.getString(R.string.caches_filter_size_title)); - return true; - case SUBMENU_FILTER_ATTRIBUTES: - showFilterMenu(AttributeFilter.getAllFilters(), res.getString(R.string.cache_attributes)); - return true; - case SUBMENU_FILTER_STATE: - showFilterMenu(StateFilter.getAllFilters(), res.getString(R.string.cache_status)); - return true; - case MENU_FILTER_TRACKABLES: - setFilter(new TrackablesFilter(res.getString(R.string.caches_filter_track))); - return true; - case MENU_FILTER_MODIFIED: - setFilter(new ModifiedFilter(res.getString(R.string.caches_filter_modified))); + case MENU_FILTER: + new FilterUserInterface(this).selectFilter(new RunnableWithArgument<IFilter>() { + @Override + public void run(IFilter selectedFilter) { + if (selectedFilter != null) { + setFilter(selectedFilter); + } + else { + // clear filter + if (adapter != null) { + setFilter(null); + } + } + } + }); return true; - case MENU_FILTER_CLEAR: - if (adapter != null) { - setFilter(null); - } - return false; case MENU_IMPORT_WEB: importWeb(); return false; - case MENU_EXPORT_NOTES: - exportFieldNotes(); + case MENU_EXPORT: + exportCaches(); return false; case MENU_REMOVE_FROM_HISTORY: removeFromHistoryCheck(); @@ -1083,24 +974,7 @@ public class cgeocaches extends AbstractListActivity { return true; } - return CacheListAppFactory.onMenuItemSelected(item, geo, cacheList, this, search); - } - - private void showFilterMenu(final IFilter[] filters, final String menuTitle) { - final AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(menuTitle); - - final String[] names = new String[filters.length]; - for (int i = 0; i < filters.length; i++) { - names[i] = filters[i].getName(); - } - builder.setItems(names, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int item) { - setFilter(filters[item]); - } - }); - - builder.create().show(); + return CacheListAppFactory.onMenuItemSelected(item, app.currentGeo(), cacheList, this, search); } private void setComparator(MenuItem item, @@ -1123,7 +997,7 @@ public class cgeocaches extends AbstractListActivity { try { adapterInfo = (AdapterContextMenuInfo) info; } catch (Exception e) { - Log.w(Settings.tag, "cgeocaches.onCreateContextMenu: " + e.toString()); + Log.w("cgeocaches.onCreateContextMenu: " + e.toString()); } if (adapterInfo == null || adapterInfo.position >= adapter.getCount()) { @@ -1153,41 +1027,33 @@ public class cgeocaches extends AbstractListActivity { menu.add(0, MENU_MOVE_TO_LIST, 0, res.getString(R.string.cache_menu_move_list)); } } + else { + menu.add(0, MENU_STORE_CACHE, 0, res.getString(R.string.cache_offline_store)); + } } private void moveCachesToOtherList() { - final List<StoredList> cacheLists = app.getLists(); - ArrayList<String> listNames = new ArrayList<String>(); - for (StoredList list : cacheLists) { - listNames.add(list.getTitleAndCount()); - } + new StoredList.UserInterface(this).promptForListSelection(R.string.cache_menu_move_list, new RunnableWithArgument<Integer>() { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(res.getString(R.string.cache_menu_move_list)); - builder.setItems(listNames.toArray(new String[listNames.size()]), new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int item) { - moveCachesToList(cacheLists.get(item)); - } - }); - builder.create().show(); - } + @Override + public void run(Integer newListId) { + List<cgCache> selected; + final boolean moveAll = adapter.getChecked() == 0; + if (moveAll) { + selected = new ArrayList<cgCache>(cacheList); + } else { + selected = adapter.getCheckedCaches(); + } + app.moveToList(selected, newListId); + adapter.resetChecks(); - private void moveCachesToList(final StoredList list) { - int newListId = list.id; - final boolean moveAll = adapter.getChecked() == 0; - for (final cgCache c : Collections.unmodifiableList(cacheList)) { - if (moveAll || c.isStatusChecked()) { - app.moveToList(c.getGeocode(), newListId); + refreshCurrentList(); } - } - adapter.resetChecks(); - - refreshCurrentList(); + }); } @Override public boolean onContextItemSelected(MenuItem item) { - final int id = item.getItemId(); ContextMenu.ContextMenuInfo info = item.getMenuInfo(); // restore menu info for sub menu items, see @@ -1201,69 +1067,62 @@ public class cgeocaches extends AbstractListActivity { try { adapterInfo = (AdapterContextMenuInfo) info; } catch (Exception e) { - Log.w(Settings.tag, "cgeocaches.onContextItemSelected: " + e.toString()); + Log.w("cgeocaches.onContextItemSelected: " + e.toString()); } - if (id == MENU_DEFAULT_NAVIGATION) { - final cgCache cache = getCacheFromAdapter(adapterInfo); - NavigationAppFactory.startDefaultNavigationApplication(geo, this, cache, null, null); - return true; - } else if (id == MENU_NAVIGATION) { - final cgCache cache = getCacheFromAdapter(adapterInfo); - NavigationAppFactory.showNavigationMenu(geo, this, cache, null, null); - return true; - } else if (id == MENU_LOG_VISIT) { - return getCacheFromAdapter(adapterInfo).logVisit(this); - } else if (id == MENU_CACHE_DETAILS) { - final Intent cachesIntent = new Intent(this, CacheDetailActivity.class); - final cgCache cache = getCacheFromAdapter(adapterInfo); - cachesIntent.putExtra("geocode", cache.getGeocode().toUpperCase()); - cachesIntent.putExtra("name", cache.getName()); - startActivity(cachesIntent); + final cgCache cache = adapterInfo != null ? getCacheFromAdapter(adapterInfo) : null; - return true; - } else if (id == MENU_DROP_CACHE) { - cgBase.dropCache(getCacheFromAdapter(adapterInfo), new Handler() { - @Override - public void handleMessage(Message msg) { - refreshCurrentList(); - } - }); - return true; - } else if (id == MENU_MOVE_TO_LIST) { - final String geocode = getCacheFromAdapter(adapterInfo).getGeocode(); - final List<StoredList> cacheLists = app.getLists(); - ArrayList<String> listNames = new ArrayList<String>(); - for (StoredList list : cacheLists) { - listNames.add(list.getTitleAndCount()); - } + final int id = item.getItemId(); + switch (id) { + case MENU_DEFAULT_NAVIGATION: + NavigationAppFactory.startDefaultNavigationApplication(app.currentGeo(), this, cache, null, null); + break; + case MENU_NAVIGATION: + NavigationAppFactory.showNavigationMenu(app.currentGeo(), this, cache, null, null); + break; + case MENU_LOG_VISIT: + cache.logVisit(this); + break; + case MENU_CACHE_DETAILS: + final Intent cachesIntent = new Intent(this, CacheDetailActivity.class); + cachesIntent.putExtra("geocode", cache.getGeocode().toUpperCase()); + cachesIntent.putExtra("name", cache.getName()); + startActivity(cachesIntent); + break; + case MENU_DROP_CACHE: + cache.drop(new Handler() { + @Override + public void handleMessage(Message msg) { + refreshCurrentList(); + } + }); + break; + case MENU_MOVE_TO_LIST: + new StoredList.UserInterface(this).promptForListSelection(R.string.cache_menu_move_list, new RunnableWithArgument<Integer>() { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(res.getString(R.string.cache_menu_move_list)); - builder.setItems(listNames.toArray(new String[listNames.size()]), new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int item) { - final int newListId = cacheLists.get(item).id; - app.moveToList(geocode, newListId); - adapter.resetChecks(); - refreshCurrentList(); + @Override + public void run(Integer newListId) { + app.moveToList(Collections.singletonList(cache), newListId); + adapter.resetChecks(); + refreshCurrentList(); + } + }); + break; + case MENU_STORE_CACHE: + //FIXME: this must use the same handler like in the CacheDetailActivity. Will be done by moving the handler into the store method. + cache.store(this, null); + break; + default: + // we must remember the menu info for the sub menu, there is a bug + // in Android: + // https://code.google.com/p/android/issues/detail?id=7139 + lastMenuInfo = info; + if (cache != null) { + // create a search for a single cache (as if in details view) + cache.logOffline(this, LogType.getById(id - MENU_LOG_VISIT_OFFLINE)); } - }); - builder.create().show(); - return true; } - // we must remember the menu info for the sub menu, there is a bug - // in Android: - // https://code.google.com/p/android/issues/detail?id=7139 - lastMenuInfo = info; - - if (adapterInfo != null) { - // create a search for a single cache (as if in details view) - final cgCache cache = getCacheFromAdapter(adapterInfo); - - int logType = id - MENU_LOG_VISIT_OFFLINE; - cache.logOffline(this, LogType.getById(logType)); - } return true; } @@ -1336,9 +1195,8 @@ public class cgeocaches extends AbstractListActivity { } adapter.reFilter(); - if (geo != null) { - adapter.setActualCoordinates(geo.coordsNow); - } + adapter.setActualCoordinates(app.currentGeo().getCoords()); + if (dir != null) { adapter.setActualHeading(dir.directionNow); } @@ -1388,38 +1246,22 @@ public class cgeocaches extends AbstractListActivity { private void init() { startGeoAndDir(); - if (CollectionUtils.isNotEmpty(cacheList)) { - setMoreCaches(); - } - - setTitle(title); - setAdapter(); - - if (geo != null) { - geoUpdate.updateLocation(geo); - } if (dir != null) { dirUpdate.updateDirection(dir); } } - // sensor & geolocation manager + // Sensor & geolocation manager. This must be called from the UI thread as it may + // cause the system listeners to start if nobody else required them before. private void startGeoAndDir() { - if (geo == null) { - geo = app.startGeo(geoUpdate); - } + app.addGeoObserver(this); if (Settings.isLiveList() && Settings.isUseCompass() && dir == null) { dir = app.startDir(this, dirUpdate); } } private void removeGeoAndDir() { - if (dir != null) { - dir = app.removeDir(); - } - if (geo != null) { - geo = app.removeGeo(); - } + app.deleteGeoObserver(this); } private void importGpx() { @@ -1463,8 +1305,7 @@ public class cgeocaches extends AbstractListActivity { threadDetails.start(); } - public void removeFromHistoryCheck() - { + public void removeFromHistoryCheck() { AlertDialog.Builder dialog = new AlertDialog.Builder(this); dialog.setCancelable(true); dialog.setTitle(res.getString(R.string.caches_removing_from_history)); @@ -1486,8 +1327,7 @@ public class cgeocaches extends AbstractListActivity { alert.show(); } - public void removeFromHistory() - { + public void removeFromHistory() { if (adapter != null && adapter.getChecked() > 0) { // there are some checked caches @@ -1508,27 +1348,17 @@ public class cgeocaches extends AbstractListActivity { threadH.start(); } - public void exportFieldNotes() - { - if (adapter != null && adapter.getChecked() > 0) - { - // there are some checked caches - detailTotal = adapter.getChecked(); - } - else - { - // no checked caches, export all - detailTotal = cacheList.size(); + public void exportCaches() { + List<cgCache> caches; + if (adapter != null && adapter.getChecked() > 0) { + // there are some caches checked + caches = adapter.getCheckedCaches(); + } else { + // no caches checked, export all + caches = cacheList; } - detailProgress = 0; - - showProgress(false); - - progress.show(this, null, res.getString(R.string.caches_exporting_fieldnote), ProgressDialog.STYLE_HORIZONTAL, exportFieldNotesHandler.obtainMessage(MSG_CANCEL)); - progress.setMaxProgressAndReset(detailTotal); - threadF = new ExportFieldNotesThread(exportFieldNotesHandler); - threadF.start(); + ExportFactory.showExportMenu(caches, this); } public void importWeb() { @@ -1574,38 +1404,30 @@ public class cgeocaches extends AbstractListActivity { public void dropSelected() { progress.show(this, null, res.getString(R.string.caches_drop_progress), true, dropDetailsHandler.obtainMessage(MSG_CANCEL)); - - threadR = new DropDetailsThread(dropDetailsHandler); - threadR.start(); + new DropDetailsThread(dropDetailsHandler).start(); } - private class UpdateLocation implements UpdateLocationCallback { + @Override + public void update(final IGeoData geo) { + if (adapter == null) { + return; + } - @Override - public void updateLocation(cgGeo geo) { - if (geo == null) { - return; - } - if (adapter == null) { - return; + try { + if (cacheList != null && geo.getCoords() != null) { + adapter.setActualCoordinates(geo.getCoords()); } - try { - if (cacheList != null && geo.coordsNow != null) { - adapter.setActualCoordinates(geo.coordsNow); + if (!Settings.isUseCompass() || geo.getSpeed() > 5) { // use GPS when speed is higher than 18 km/h + if (!Settings.isUseCompass()) { + adapter.setActualHeading(geo.getBearing()); } - - if (!Settings.isUseCompass() || geo.speedNow > 5) { // use GPS when speed is higher than 18 km/h - if (!Settings.isUseCompass()) { - adapter.setActualHeading(geo.bearingNow); - } - if (northHeading != null) { - adapter.setActualHeading(northHeading); - } + if (northHeading != null) { + adapter.setActualHeading(northHeading); } - } catch (Exception e) { - Log.w(Settings.tag, "Failed to UpdateLocation location."); } + } catch (Exception e) { + Log.w("Failed to UpdateLocation location."); } } @@ -1621,7 +1443,7 @@ public class cgeocaches extends AbstractListActivity { } northHeading = dir.directionNow; - if (northHeading != null && adapter != null && (geo == null || geo.speedNow <= 5)) { // use compass when speed is lower than 18 km/h) { + if (northHeading != null && adapter != null && (app.currentGeo().getSpeed() <= 5)) { // use compass when speed is lower than 18 km/h) { adapter.setActualHeading(northHeading); } } @@ -1641,7 +1463,7 @@ public class cgeocaches extends AbstractListActivity { @Override public void run() { - search = cgBase.searchByStored(coords, Settings.getCacheType(), listId); + search = cgeoapplication.getInstance().getBatchOfStoredCaches(true, coords, Settings.getCacheType(), listId); handler.sendMessage(Message.obtain()); } } @@ -1671,7 +1493,7 @@ public class cgeocaches extends AbstractListActivity { @Override public void run() { - search = cgBase.searchByNextPage(this, search, Settings.isShowCaptcha()); + search = GCParser.searchByNextPage(this, search, Settings.isShowCaptcha()); handler.sendMessage(Message.obtain()); } @@ -1692,13 +1514,12 @@ public class cgeocaches extends AbstractListActivity { showToast(res.getString(R.string.warn_no_coordinates)); finish(); - return; } } @Override public void run() { - search = cgBase.searchByCoords(this, coords, cacheType, Settings.isShowCaptcha()); + search = GCParser.searchByCoords(this, coords, cacheType, Settings.isShowCaptcha()); handler.sendMessage(Message.obtain()); } @@ -1719,13 +1540,12 @@ public class cgeocaches extends AbstractListActivity { showToast(res.getString(R.string.warn_no_keyword)); finish(); - return; } } @Override public void run() { - search = cgBase.searchByKeyword(this, keyword, cacheType, Settings.isShowCaptcha()); + search = GCParser.searchByKeyword(this, keyword, cacheType, Settings.isShowCaptcha()); handler.sendMessage(Message.obtain()); } } @@ -1745,13 +1565,12 @@ public class cgeocaches extends AbstractListActivity { showToast(res.getString(R.string.warn_no_username)); finish(); - return; } } @Override public void run() { - search = cgBase.searchByUsername(this, username, cacheType, Settings.isShowCaptcha()); + search = GCParser.searchByUsername(this, username, cacheType, Settings.isShowCaptcha()); handler.sendMessage(Message.obtain()); } } @@ -1771,20 +1590,12 @@ public class cgeocaches extends AbstractListActivity { showToast(res.getString(R.string.warn_no_username)); finish(); - return; } } @Override public void run() { - Map<String, String> params = new HashMap<String, String>(); - params.put("username", username); - if (cacheType != null) { - params.put("cacheType", cacheType.id); - } - - search = cgBase.searchByOwner(this, username, cacheType, Settings.isShowCaptcha()); - + search = GCParser.searchByOwner(this, username, cacheType, Settings.isShowCaptcha()); handler.sendMessage(Message.obtain()); } } @@ -1829,7 +1640,7 @@ public class cgeocaches extends AbstractListActivity { try { if (needToStop) { - Log.i(Settings.tag, "Stopped storing process."); + Log.i("Stopped storing process."); break; } @@ -1840,32 +1651,33 @@ public class cgeocaches extends AbstractListActivity { delay = 500; } - Log.i(Settings.tag, "Waiting for next cache " + delay + " ms"); + Log.i("Waiting for next cache " + delay + " ms"); sleep(delay); } catch (Exception e) { - Log.e(Settings.tag, "cgeocaches.LoadDetailsThread.sleep: " + e.toString()); + Log.e("cgeocaches.LoadDetailsThread.sleep: " + e.toString()); } } if (needToStop) { - Log.i(Settings.tag, "Stopped storing process."); + Log.i("Stopped storing process."); break; } detailProgress++; - cgBase.storeCache(cgeocaches.this, cache, null, listIdLD, null); + cache.refresh(cgeocaches.this, listIdLD, null); handler.sendEmptyMessage(cacheList.indexOf(cache)); yield(); } catch (Exception e) { - Log.e(Settings.tag, "cgeocaches.LoadDetailsThread: " + e.toString()); + Log.e("cgeocaches.LoadDetailsThread: " + e.toString()); } last = System.currentTimeMillis(); } cacheListTemp.clear(); + handler.sendEmptyMessage(MSG_RESTART_GEO_AND_DIR); handler.sendEmptyMessage(MSG_DONE); } } @@ -1904,21 +1716,18 @@ public class cgeocaches extends AbstractListActivity { deviceCode = ""; } final Parameters params = new Parameters("code", deviceCode); - HttpResponse responseFromWeb = Network.request("http://send2.cgeo.org/read.html", params, true); + HttpResponse responseFromWeb = Network.getRequest("http://send2.cgeo.org/read.html", params); if (responseFromWeb != null && responseFromWeb.getStatusLine().getStatusCode() == 200) { final String response = Network.getResponseData(responseFromWeb); if (response.length() > 2) { - - String GCcode = response; - delay = 1; - handler.sendMessage(handler.obtainMessage(1, GCcode)); + handler.sendMessage(handler.obtainMessage(1, response)); yield(); - cgBase.storeCache(cgeocaches.this, null, GCcode, listIdLFW, null); + cgCache.storeCache(cgeocaches.this, null, response, listIdLFW, false, null); - handler.sendMessage(handler.obtainMessage(2, GCcode)); + handler.sendMessage(handler.obtainMessage(2, response)); yield(); } else if ("RG".equals(response)) { //Server returned RG (registration) and this device no longer registered. @@ -1949,58 +1758,42 @@ public class cgeocaches extends AbstractListActivity { times = 0; } } catch (InterruptedException e) { - Log.e(Settings.tag, "cgeocaches.LoadFromWebThread.sleep: " + e.toString()); + Log.e("cgeocaches.LoadFromWebThread.sleep: " + e.toString()); } } handler.sendEmptyMessage(ret); + + startGeoAndDir(); } } private class DropDetailsThread extends Thread { final private Handler handler; - private volatile boolean needToStop = false; - private int checked = 0; + private List<cgCache> selected = new ArrayList<cgCache>(); public DropDetailsThread(Handler handlerIn) { setPriority(Thread.MIN_PRIORITY); handler = handlerIn; - if (adapter != null) { - checked = adapter.getChecked(); + int checked = adapter.getChecked(); + if (checked == 0) { + selected = new ArrayList<cgCache>(cacheList); + } + else { + selected = adapter.getCheckedCaches(); } - } - - public void kill() { - needToStop = true; } @Override public void run() { removeGeoAndDir(); - - final List<cgCache> cacheListTemp = new ArrayList<cgCache>(cacheList); - for (cgCache cache : cacheListTemp) { - if (checked > 0 && !cache.isStatusChecked()) { - continue; - } - - try { - if (needToStop) { - Log.i(Settings.tag, "Stopped dropping process."); - break; - } - - app.markDropped(cache.getGeocode()); - } catch (Exception e) { - Log.e(Settings.tag, "cgeocaches.DropDetailsThread: " + e.toString()); - } - } - cacheListTemp.clear(); - + app.markDropped(selected); handler.sendEmptyMessage(MSG_DONE); + + startGeoAndDir(); } } @@ -2036,7 +1829,7 @@ public class cgeocaches extends AbstractListActivity { try { if (needToStop) { - Log.i(Settings.tag, "Stopped removing process."); + Log.i("Stopped removing process."); break; } @@ -2047,128 +1840,7 @@ public class cgeocaches extends AbstractListActivity { yield(); } catch (Exception e) { - Log.e(Settings.tag, "cgeocaches.RemoveFromHistoryThread: " + e.toString()); - } - } - - handler.sendEmptyMessage(MSG_DONE); - } - } - - private class ExportFieldNotesThread extends Thread - { - private final Handler handler; - private volatile boolean needToStop = false; - private int checked = 0; - - public ExportFieldNotesThread(Handler handlerIn) - { - setPriority(Thread.MIN_PRIORITY); - - handler = handlerIn; - - if (adapter != null) - { - checked = adapter.getChecked(); - } - } - - public void kill() - { - needToStop = true; - } - - @Override - public void run() - { - SimpleDateFormat fieldNoteDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); - StringBuilder fieldNoteBuffer = new StringBuilder(500); - - // We need our own HashMap because LogType will give us localized and maybe - // different strings than gc.com expects in the field note - // We only need such logtypes that are possible to log via c:geo - Map<LogType, String> logTypes = new HashMap<LogType, String>(); - logTypes.put(LogType.LOG_FOUND_IT, "Found it"); - logTypes.put(LogType.LOG_DIDNT_FIND_IT, "Didn't find it"); - logTypes.put(LogType.LOG_NOTE, "Write Note"); - logTypes.put(LogType.LOG_NEEDS_ARCHIVE, "Needs archived"); - logTypes.put(LogType.LOG_NEEDS_MAINTENANCE, "Needs Maintenance"); - logTypes.put(LogType.LOG_WILL_ATTEND, "Will Attend"); - logTypes.put(LogType.LOG_ATTENDED, "Attended"); - logTypes.put(LogType.LOG_WEBCAM_PHOTO_TAKEN, "Webcam Photo Taken"); - - for (cgCache cache : cacheList) { - if (checked > 0 && !cache.isStatusChecked()) { - handler.sendEmptyMessage(0); - - yield(); - continue; - } - - try { - if (needToStop) - { - Log.i(Settings.tag, "Stopped exporting process."); - break; - } - - if (cache.isLogOffline()) - { - cgLog log = app.loadLogOffline(cache.getGeocode()); - - if (null != logTypes.get(log.type)) - { - fieldNoteBuffer.append(cache.getGeocode()) - .append(',') - .append(fieldNoteDateFormat.format(new Date(log.date))) - .append(',') - .append(logTypes.get(log.type)) - .append(",\"") - .append(StringUtils.replaceChars(log.log, '"', '\'')) - .append("\"\n"); - } - } - - detailProgress++; - - handler.sendEmptyMessage(cacheList.indexOf(cache)); - - yield(); - } catch (Exception e) { - Log.e(Settings.tag, "cgeocaches.ExportFieldNotesThread: " + e.toString()); - } - } - - if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) - { - File exportLocation = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/field-notes"); - exportLocation.mkdirs(); - - SimpleDateFormat fileNameDateFormat = new SimpleDateFormat("yyyyMMddHHmmss"); - File exportFile = new File(exportLocation + "/" + fileNameDateFormat.format(new Date()) + ".txt"); - - OutputStream os = null; - Writer fw = null; - try - { - os = new FileOutputStream(exportFile); - fw = new OutputStreamWriter(os, "ISO-8859-1"); // TODO: gc.com doesn't support UTF-8 - fw.write(fieldNoteBuffer.toString()); - - Message.obtain(handler, -2, exportFile).sendToTarget(); - } catch (IOException e) { - Log.e(Settings.tag, "cgeocaches.ExportFieldNotesThread: " + e.toString()); - handler.sendEmptyMessage(-3); - } finally - { - if (fw != null) - { - try { - fw.close(); - } catch (IOException e) { - Log.e(Settings.tag, "cgeocaches.ExportFieldNotesThread: " + e.toString()); - } - } + Log.e("cgeocaches.RemoveFromHistoryThread: " + e.toString()); } } @@ -2193,7 +1865,7 @@ public class cgeocaches extends AbstractListActivity { private void hideLoading() { final ListView list = getListView(); - final RelativeLayout loading = (RelativeLayout) findViewById(R.id.loading); + final View loading = findViewById(R.id.loading); if (list.getVisibility() == View.GONE) { list.setVisibility(View.VISIBLE); @@ -2209,41 +1881,13 @@ public class cgeocaches extends AbstractListActivity { if (type != CacheListType.OFFLINE) { return; } + new StoredList.UserInterface(this).promptForListSelection(R.string.list_title, new RunnableWithArgument<Integer>() { - lists = app.getLists(); - - if (lists == null) { - return; - } - - final List<CharSequence> listsTitle = new ArrayList<CharSequence>(); - for (StoredList list : lists) { - listsTitle.add(list.getTitleAndCount()); - } - listsTitle.add("<" + res.getString(R.string.list_menu_create) + ">"); - - final CharSequence[] items = new CharSequence[listsTitle.size()]; - - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(res.getString(R.string.list_title)); - builder.setItems(listsTitle.toArray(items), new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialogInterface, int itemId) { - if (itemId >= lists.size()) { - // create new list on the fly - createList(new RunnableWithArgument<Integer>() { - - @Override - public void run(final Integer arg) { - switchListById(arg.intValue()); - } - }); - } - else { - switchListById(lists.get(itemId).id); - } + @Override + public void run(final Integer selectedListId) { + switchListById(selectedListId); } }); - builder.create().show(); } public void switchListById(int id) { @@ -2287,72 +1931,17 @@ public class cgeocaches extends AbstractListActivity { @Override public void run() { - int checked = adapter.getChecked(); - if (checked > 0) { - final List<cgCache> cacheListTemp = new ArrayList<cgCache>(cacheList); - for (cgCache cache : cacheListTemp) { - if (cache.isStatusChecked()) { - app.moveToList(cache.getGeocode(), listId); - } - } - } - + final List<cgCache> caches = adapter.getCheckedCaches(); + app.moveToList(caches, listId); handler.sendEmptyMessage(listId); } } - private void handleListNameInput(final String defaultValue, int dialogTitle, int buttonTitle, final RunnableWithArgument<String> runnable) { - final AlertDialog.Builder alert = new AlertDialog.Builder(this); - final View view = inflater.inflate(R.layout.list_create_dialog, null); - final EditText input = (EditText) view.findViewById(R.id.text); - input.setText(defaultValue); - - alert.setTitle(dialogTitle); - alert.setView(view); - alert.setPositiveButton(buttonTitle, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - // remove whitespaces added by autocompletion of Android keyboard - String listName = StringUtils.trim(input.getText().toString()); - if (StringUtils.isNotBlank(listName)) { - runnable.run(listName); - } - } - }); - alert.setNegativeButton(res.getString(R.string.list_dialog_cancel), new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - dialog.dismiss(); - } - }); - - alert.show(); - } - - private void createList(final RunnableWithArgument<Integer> runAfterwards) { - handleListNameInput("", R.string.list_dialog_create_title, R.string.list_dialog_create, new RunnableWithArgument<String>() { - - @Override - public void run(final String listName) { - final int newId = app.createList(listName); - - if (newId >= 10) { - showToast(res.getString(R.string.list_dialog_create_ok)); - if (runAfterwards != null) { - runAfterwards.run(newId); - } - } else { - showToast(res.getString(R.string.list_dialog_create_err)); - } - } - }); - } - private void renameList() { - final StoredList list = app.getList(listId); - handleListNameInput(list.title, R.string.list_dialog_rename_title, R.string.list_dialog_rename, new RunnableWithArgument<String>() { + new StoredList.UserInterface(this).promptForListRename(listId, new Runnable() { @Override - public void run(final String listName) { - app.renameList(listId, listName); + public void run() { refreshCurrentList(); } }); @@ -2461,8 +2050,7 @@ public class cgeocaches extends AbstractListActivity { Intent cachesIntent = new Intent(context, cachesActivity.getClass()); cachesIntent.putExtra(EXTRAS_LIST_TYPE, CacheListType.COORDINATE); - cachesIntent.putExtra("latitude", coords.getLatitude()); - cachesIntent.putExtra("longitude", coords.getLongitude()); + cachesIntent.putExtra(EXTRAS_COORDS, coords); context.startActivity(cachesIntent); } @@ -2529,8 +2117,7 @@ public class cgeocaches extends AbstractListActivity { public static void startActivityNearest(final Context context, final Geopoint coordsNow) { final Intent cachesIntent = new Intent(context, cgeocaches.class); cachesIntent.putExtra(EXTRAS_LIST_TYPE, CacheListType.NEAREST); - cachesIntent.putExtra("latitude", coordsNow.getLatitude()); - cachesIntent.putExtra("longitude", coordsNow.getLongitude()); + cachesIntent.putExtra(EXTRAS_COORDS, coordsNow); context.startActivity(cachesIntent); } @@ -2540,20 +2127,18 @@ public class cgeocaches extends AbstractListActivity { context.startActivity(cachesIntent); } - public static void startActivityAddress(Context context, double latitude, double longitude, String address) { + public static void startActivityAddress(final Context context, final Geopoint coords, final String address) { Intent addressIntent = new Intent(context, cgeocaches.class); addressIntent.putExtra(EXTRAS_LIST_TYPE, CacheListType.ADDRESS); - addressIntent.putExtra("latitude", latitude); - addressIntent.putExtra("longitude", longitude); + addressIntent.putExtra(EXTRAS_COORDS, coords); addressIntent.putExtra("address", address); context.startActivity(addressIntent); } - public static void startActivityCoordinates(final Context context, double latitude, double longitude) { + public static void startActivityCoordinates(final Context context, final Geopoint coords) { final Intent cachesIntent = new Intent(context, cgeocaches.class); cachesIntent.putExtra(EXTRAS_LIST_TYPE, CacheListType.COORDINATE); - cachesIntent.putExtra("latitude", latitude); - cachesIntent.putExtra("longitude", longitude); + cachesIntent.putExtra(EXTRAS_COORDS, coords); context.startActivity(cachesIntent); } diff --git a/main/src/cgeo/geocaching/cgeocoords.java b/main/src/cgeo/geocaching/cgeocoords.java index b4868ce..0ad2e81 100644 --- a/main/src/cgeo/geocaching/cgeocoords.java +++ b/main/src/cgeo/geocaching/cgeocoords.java @@ -5,12 +5,11 @@ import cgeo.geocaching.activity.AbstractActivity; import cgeo.geocaching.activity.ActivityMixin; import cgeo.geocaching.compatibility.Compatibility; import cgeo.geocaching.geopoint.Geopoint; -import cgeo.geocaching.geopoint.Geopoint.DDD; -import cgeo.geocaching.geopoint.Geopoint.DMM; -import cgeo.geocaching.geopoint.Geopoint.DMS; -import cgeo.geocaching.geopoint.Geopoint.Direction; import cgeo.geocaching.geopoint.GeopointFormatter; -import cgeo.geocaching.geopoint.GeopointParser.ParseException; +import cgeo.geocaching.geopoint.direction.DDD; +import cgeo.geocaching.geopoint.direction.DMM; +import cgeo.geocaching.geopoint.direction.DMS; +import cgeo.geocaching.geopoint.direction.Direction; import org.apache.commons.lang3.StringUtils; @@ -32,7 +31,7 @@ import android.widget.TextView; public class cgeocoords extends Dialog { final private AbstractActivity context; - final private cgGeo geo; + final private IGeoData geo; final private cgCache cache; private Geopoint gp; @@ -43,13 +42,11 @@ public class cgeocoords extends Dialog { private TextView tLatSep1, tLatSep2, tLatSep3; private TextView tLonSep1, tLonSep2, tLonSep3; - private Spinner spinner; - private CoordinateUpdate cuListener; private coordInputFormatEnum currentFormat = null; - public cgeocoords(final AbstractActivity context, final cgCache cache, final Geopoint gp, final cgGeo geo) { + public cgeocoords(final AbstractActivity context, final cgCache cache, final Geopoint gp, final IGeoData geo) { super(context); this.context = context; this.geo = geo; @@ -57,8 +54,8 @@ public class cgeocoords extends Dialog { if (gp != null) { this.gp = gp; - } else if (geo != null && geo.coordsNow != null) { - this.gp = geo.coordsNow; + } else if (geo != null && geo.getCoords() != null) { + this.gp = geo.getCoords(); } else { this.gp = new Geopoint(0.0, 0.0); } @@ -84,7 +81,7 @@ public class cgeocoords extends Dialog { } }); - spinner = (Spinner) findViewById(R.id.spinnerCoordinateFormats); + final Spinner spinner = (Spinner) findViewById(R.id.spinnerCoordinateFormats); final ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(context, R.array.waypoint_coordinate_formats, @@ -352,7 +349,7 @@ public class cgeocoords extends Dialog { if (currentFormat == coordInputFormatEnum.Plain) { try { gp = new Geopoint(eLat.getText().toString(), eLon.getText().toString()); - } catch (ParseException e) { + } catch (Geopoint.ParseException e) { if (signalError) { context.showToast(context.getResources().getString(R.string.err_parse_lat_lon)); } @@ -416,10 +413,10 @@ public class cgeocoords extends Dialog { // Start new format with an acceptable value: either the current one // entered by the user, else our current coordinates, else (0,0). if (!calc(false)) { - if (geo != null && geo.coordsNow != null) { - gp = geo.coordsNow; + if (geo != null && geo.getCoords() != null) { + gp = geo.getCoords(); } else { - gp = new Geopoint(0, 0); + gp = new Geopoint(0.0, 0.0); } } } @@ -439,12 +436,12 @@ public class cgeocoords extends Dialog { @Override public void onClick(View v) { - if (geo == null || geo.coordsNow == null) { + if (geo == null || geo.getCoords() == null) { context.showToast(context.getResources().getString(R.string.err_point_unknown_position)); return; } - gp = geo.coordsNow; + gp = geo.getCoords(); updateGUI(); } } diff --git a/main/src/cgeo/geocaching/cgeoimages.java b/main/src/cgeo/geocaching/cgeoimages.java index 79c0e24..7145d59 100644 --- a/main/src/cgeo/geocaching/cgeoimages.java +++ b/main/src/cgeo/geocaching/cgeoimages.java @@ -3,6 +3,7 @@ package cgeo.geocaching; import cgeo.geocaching.activity.AbstractActivity; import cgeo.geocaching.files.LocalStorage; import cgeo.geocaching.network.HtmlImage; +import cgeo.geocaching.utils.Log; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -18,7 +19,7 @@ import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.text.Html; -import android.util.Log; +import android.util.SparseArray; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.LayoutInflater; @@ -34,7 +35,6 @@ import java.io.FileOutputStream; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.List; public class cgeoimages extends AbstractActivity { @@ -51,7 +51,7 @@ public class cgeoimages extends AbstractActivity { private LinearLayout imagesView = null; private int count = 0; private int countDone = 0; - private final HashMap<Integer, cgImage> images = new HashMap<Integer, cgImage>(); + private final SparseArray<cgImage> images = new SparseArray<cgImage>(); private BitmapDrawable currentDrawable; private cgImage currentImage; @@ -60,14 +60,14 @@ public class cgeoimages extends AbstractActivity { private void loadImages(final List<cgImage> images, final int progressMessage, final boolean offline) { count = images.size(); - progressDialog = new ProgressDialog(cgeoimages.this); + progressDialog = new ProgressDialog(this); progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); progressDialog.setMessage(res.getString(progressMessage)); progressDialog.setCancelable(true); progressDialog.setMax(count); progressDialog.show(); - LinearLayout rowView = null; + LinearLayout rowView; for (final cgImage img : images) { rowView = (LinearLayout) inflater.inflate(R.layout.cache_image_item, null); @@ -207,7 +207,7 @@ public class cgeoimages extends AbstractActivity { image.getBitmap().compress(CompressFormat.JPEG, 100, fos); fos.close(); } catch (Exception e) { - Log.e(Settings.tag, "cgeoimages.handleMessage.onClick: " + e.toString()); + Log.e("cgeoimages.handleMessage.onClick: " + e.toString()); return; } diff --git a/main/src/cgeo/geocaching/cgeoinit.java b/main/src/cgeo/geocaching/cgeoinit.java index a8e660a..0aeed10 100644 --- a/main/src/cgeo/geocaching/cgeoinit.java +++ b/main/src/cgeo/geocaching/cgeoinit.java @@ -4,13 +4,16 @@ import cgeo.geocaching.activity.AbstractActivity; import cgeo.geocaching.apps.cache.navi.NavigationAppFactory; import cgeo.geocaching.apps.cache.navi.NavigationAppFactory.NavigationAppsEnum; import cgeo.geocaching.compatibility.Compatibility; +import cgeo.geocaching.connector.gc.Login; import cgeo.geocaching.enumerations.CacheType; import cgeo.geocaching.enumerations.StatusCode; import cgeo.geocaching.maps.MapProviderFactory; -import cgeo.geocaching.network.Login; +import cgeo.geocaching.network.Cookies; import cgeo.geocaching.network.Network; import cgeo.geocaching.network.Parameters; import cgeo.geocaching.twitter.TwitterAuthorizationActivity; +import cgeo.geocaching.ui.Formatter; +import cgeo.geocaching.utils.Log; import cgeo.geocaching.utils.LogTemplateProvider; import cgeo.geocaching.utils.LogTemplateProvider.LogTemplate; @@ -19,6 +22,7 @@ import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.http.HttpResponse; import android.app.ProgressDialog; +import android.content.Context; import android.content.Intent; import android.content.res.Configuration; import android.graphics.drawable.Drawable; @@ -26,7 +30,6 @@ import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.Message; -import android.util.Log; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.Menu; @@ -45,7 +48,6 @@ import android.widget.TextView; import java.io.File; import java.util.Collection; import java.util.List; -import java.util.concurrent.atomic.AtomicReference; public class cgeoinit extends AbstractActivity { @@ -73,7 +75,7 @@ public class cgeoinit extends AbstractActivity { } catch (Exception e) { showToast(res.getString(R.string.err_login_failed)); - Log.e(Settings.tag, "cgeoinit.logInHandler: " + e.toString()); + Log.e("cgeoinit.logInHandler: " + e.toString()); } if (loginDialog != null && loginDialog.isShowing()) { @@ -101,7 +103,7 @@ public class cgeoinit extends AbstractActivity { } catch (Exception e) { showToast(res.getString(R.string.init_sendToCgeo_register_fail)); - Log.e(Settings.tag, "cgeoinit.webHandler: " + e.toString()); + Log.e("cgeoinit.webHandler: " + e.toString()); } if (webDialog != null && webDialog.isShowing()) { @@ -173,7 +175,7 @@ public class cgeoinit extends AbstractActivity { @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == 0) { - boolean status = false; + boolean status; ((EditText) findViewById(R.id.username)).setText(""); ((EditText) findViewById(R.id.password)).setText(""); @@ -669,6 +671,17 @@ public class cgeoinit extends AbstractActivity { refreshBackupLabel(); + // Debug settings + final CheckBox debugButton = (CheckBox) findViewById(R.id.debug); + debugButton.setChecked(Settings.isDebug()); + debugButton.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View v) { + Settings.setDebug(!Settings.isDebug()); + debugButton.setChecked(Settings.isDebug()); + } + }); } private void initMapfileEdittext(boolean setFocus) { @@ -685,42 +698,34 @@ public class cgeoinit extends AbstractActivity { */ public void backup(View view) { // avoid overwriting an existing backup with an empty database (can happen directly after reinstalling the app) - if (app.getAllStoredCachesCount(true, CacheType.ALL, null) == 0) { + if (app.getAllStoredCachesCount(true, CacheType.ALL) == 0) { helpDialog(res.getString(R.string.init_backup), res.getString(R.string.init_backup_unnecessary)); return; } - final AtomicReference<String> fileRef = new AtomicReference<String>(null); final ProgressDialog dialog = ProgressDialog.show(this, res.getString(R.string.init_backup), res.getString(R.string.init_backup_running), true, false); - Thread backupThread = new Thread() { - final Handler handler = new Handler() { - @Override - public void handleMessage(Message msg) { - dialog.dismiss(); - final String file = fileRef.get(); - if (file != null) { - helpDialog(res.getString(R.string.init_backup_backup), res.getString(R.string.init_backup_success) + "\n" + file); - } else { - helpDialog(res.getString(R.string.init_backup_backup), res.getString(R.string.init_backup_failed)); - } - refreshBackupLabel(); - } - }; - + new Thread() { @Override public void run() { - fileRef.set(app.backupDatabase()); - handler.sendMessage(handler.obtainMessage()); + final String backupFileName = app.backupDatabase(); + runOnUiThread(new Runnable() { + @Override + public void run() { + dialog.dismiss(); + helpDialog(res.getString(R.string.init_backup_backup), + backupFileName != null ? res.getString(R.string.init_backup_success) + "\n" + backupFileName : res.getString(R.string.init_backup_failed)); + refreshBackupLabel(); + } + }); } - }; - backupThread.start(); + }.start(); } private void refreshBackupLabel() { TextView lastBackup = (TextView) findViewById(R.id.backup_last); File lastBackupFile = cgeoapplication.isRestoreFile(); if (lastBackupFile != null) { - lastBackup.setText(res.getString(R.string.init_backup_last) + " " + cgBase.formatTime(lastBackupFile.lastModified()) + ", " + cgBase.formatDate(lastBackupFile.lastModified())); + lastBackup.setText(res.getString(R.string.init_backup_last) + " " + Formatter.formatTime(lastBackupFile.lastModified()) + ", " + Formatter.formatDate(lastBackupFile.lastModified())); } else { lastBackup.setText(res.getString(R.string.init_backup_last_no)); } @@ -810,7 +815,7 @@ public class cgeoinit extends AbstractActivity { loginDialog.setCancelable(false); Settings.setLogin(username, password); - Network.clearCookies(); + Cookies.clearCookies(); (new Thread() { @@ -852,7 +857,7 @@ public class cgeoinit extends AbstractActivity { final String cod = StringUtils.defaultString(deviceCode); final Parameters params = new Parameters("name", nam, "code", cod); - HttpResponse response = Network.request("http://send2.cgeo.org/auth.html", params, true); + HttpResponse response = Network.getRequest("http://send2.cgeo.org/auth.html", params); if (response != null && response.getStatusLine().getStatusCode() == 200) { @@ -861,7 +866,7 @@ public class cgeoinit extends AbstractActivity { try { pin = Integer.parseInt(strings[1].trim()); } catch (Exception e) { - Log.e(Settings.tag, "webDialog: " + e.toString()); + Log.e("webDialog: " + e.toString()); } String code = strings[0]; Settings.setWebNameCode(nam, code); @@ -881,9 +886,18 @@ public class cgeoinit extends AbstractActivity { if (resultCode == RESULT_OK) { if (data.hasExtra("mapfile")) { Settings.setMapFile(data.getStringExtra("mapfile")); + if (!Settings.isValidMapFile(Settings.getMapFile())) { + showToast(res.getString(R.string.warn_invalid_mapfile)); + } } } initMapfileEdittext(true); } } + + public static void startActivity(Context fromActivity) { + final Intent initIntent = new Intent(fromActivity, cgeoinit.class); + fromActivity.startActivity(initIntent); + } + } diff --git a/main/src/cgeo/geocaching/cgeonavigate.java b/main/src/cgeo/geocaching/cgeonavigate.java index 01a9e74..9e903b6 100644 --- a/main/src/cgeo/geocaching/cgeonavigate.java +++ b/main/src/cgeo/geocaching/cgeonavigate.java @@ -6,16 +6,16 @@ import cgeo.geocaching.geopoint.HumanDistance; import cgeo.geocaching.geopoint.IConversion; import cgeo.geocaching.maps.CGeoMap; import cgeo.geocaching.ui.CompassView; +import cgeo.geocaching.utils.Log; +import cgeo.geocaching.utils.IObserver; +import cgeo.geocaching.utils.PeriodicHandler; import org.apache.commons.lang3.StringUtils; import android.content.Context; import android.content.Intent; import android.os.Bundle; -import android.os.Handler; -import android.os.Message; import android.os.PowerManager; -import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.SubMenu; @@ -25,19 +25,16 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; -public class cgeonavigate extends AbstractActivity { +public class cgeonavigate extends AbstractActivity implements IObserver<IGeoData> { - private static final String EXTRAS_LONGITUDE = "longitude"; - private static final String EXTRAS_LATITUDE = "latitude"; + private static final String EXTRAS_COORDS = "coords"; private static final String EXTRAS_NAME = "name"; private static final String EXTRAS_GEOCODE = "geocode"; - private static final List<cgCoord> coordinates = new ArrayList<cgCoord>(); + private static final List<IWaypoint> coordinates = new ArrayList<IWaypoint>(); private static final int MENU_MAP = 0; private static final int MENU_SWITCH_COMPASS_GPS = 1; private PowerManager pm = null; - private cgGeo geo = null; private cgDirection dir = null; - private UpdateLocationCallback geoUpdate = new update(); private UpdateDirectionCallback dirUpdate = new UpdateDirection(); private Geopoint dstCoords = null; private float cacheHeading = 0; @@ -51,19 +48,15 @@ public class cgeonavigate extends AbstractActivity { private TextView distanceView = null; private TextView headingView = null; private CompassView compassView = null; - private updaterThread updater = null; - private Handler updaterHandler = new Handler() { + private PeriodicHandler updaterHandler = new PeriodicHandler(20) { @Override - public void handleMessage(Message msg) { - try { - if (compassView != null && northHeading != null) { - compassView.updateNorth(northHeading, cacheHeading); - } - } catch (Exception e) { - Log.e(Settings.tag, "cgeonavigate.updaterHandler: " + e.toString()); + public void act() { + if (compassView != null && northHeading != null) { + compassView.updateNorth(northHeading, cacheHeading); } } + }; private String geocode; @@ -80,9 +73,6 @@ public class cgeonavigate extends AbstractActivity { setTitle(res.getString(R.string.compass_title)); // sensor & geolocation manager - if (geo == null) { - geo = app.startGeo(geoUpdate); - } if (Settings.isUseCompass() && dir == null) { dir = app.startDir(this, dirUpdate); } @@ -93,7 +83,7 @@ public class cgeonavigate extends AbstractActivity { geocode = extras.getString(EXTRAS_GEOCODE); title = geocode; name = extras.getString(EXTRAS_NAME); - dstCoords = new Geopoint(extras.getDouble(EXTRAS_LATITUDE), extras.getDouble(EXTRAS_LONGITUDE)); + dstCoords = (Geopoint) extras.getParcelable(EXTRAS_COORDS); if (StringUtils.isNotBlank(name)) { if (StringUtils.isNotBlank(title)) { @@ -116,19 +106,18 @@ public class cgeonavigate extends AbstractActivity { setTitle(); setDestCoords(); - if (geo != null) { - geoUpdate.updateLocation(geo); - } if (dir != null) { dirUpdate.updateDirection(dir); } // get textviews once compassView = (CompassView) findViewById(R.id.rose); + } - // start updater thread - updater = new updaterThread(updaterHandler); - updater.start(); + @Override + public void onStart() { + super.onStart(); + updaterHandler.start(); } @Override @@ -138,9 +127,7 @@ public class cgeonavigate extends AbstractActivity { setGo4CacheAction(); // sensor & geolocation manager - if (geo == null) { - geo = app.startGeo(geoUpdate); - } + app.addGeoObserver(this); if (Settings.isUseCompass() && dir == null) { dir = app.startDir(this, dirUpdate); } @@ -149,12 +136,6 @@ public class cgeonavigate extends AbstractActivity { if (pm == null) { pm = (PowerManager) getSystemService(Context.POWER_SERVICE); } - - // updater thread - if (updater == null) { - updater = new updaterThread(updaterHandler); - updater.start(); - } } private void setGo4CacheAction() { @@ -167,21 +148,18 @@ public class cgeonavigate extends AbstractActivity { @Override public void onStop() { - if (geo != null) { - geo = app.removeGeo(); - } if (dir != null) { dir = app.removeDir(); } + updaterHandler.stop(); + super.onStop(); } @Override public void onPause() { - if (geo != null) { - geo = app.removeGeo(); - } + app.deleteGeoObserver(this); if (dir != null) { dir = app.removeDir(); } @@ -191,9 +169,6 @@ public class cgeonavigate extends AbstractActivity { @Override public void onDestroy() { - if (geo != null) { - geo = app.removeGeo(); - } if (dir != null) { dir = app.removeDir(); } @@ -205,42 +180,27 @@ public class cgeonavigate extends AbstractActivity { } @Override - public boolean onCreateOptionsMenu(Menu menu) { - if (Settings.isUseCompass()) { - menu.add(0, MENU_SWITCH_COMPASS_GPS, 0, res.getString(R.string.use_gps)).setIcon(android.R.drawable.ic_menu_compass); - } else { - menu.add(0, MENU_SWITCH_COMPASS_GPS, 0, res.getString(R.string.use_compass)).setIcon(android.R.drawable.ic_menu_compass); - } + public boolean onCreateOptionsMenu(final Menu menu) { + menu.add(0, MENU_SWITCH_COMPASS_GPS, 0, res.getString(Settings.isUseCompass() ? R.string.use_gps : R.string.use_compass)).setIcon(android.R.drawable.ic_menu_compass); menu.add(0, MENU_MAP, 0, res.getString(R.string.caches_on_map)).setIcon(android.R.drawable.ic_menu_mapmode); menu.add(0, 2, 0, res.getString(R.string.destination_set)).setIcon(android.R.drawable.ic_menu_edit); if (coordinates.size() > 1) { - SubMenu subMenu = menu.addSubMenu(0, 3, 0, res.getString(R.string.destination_select)).setIcon(android.R.drawable.ic_menu_myplaces); - + final SubMenu subMenu = menu.addSubMenu(0, 3, 0, res.getString(R.string.destination_select)).setIcon(android.R.drawable.ic_menu_myplaces); int cnt = 4; - for (cgCoord coordinate : coordinates) { + for (final IWaypoint coordinate : coordinates) { subMenu.add(0, cnt, 0, coordinate.getName() + " (" + coordinate.getCoordType() + ")"); cnt++; } - - return true; } else { menu.add(0, 3, 0, res.getString(R.string.destination_select)).setIcon(android.R.drawable.ic_menu_myplaces).setEnabled(false); - - return true; } + return true; } @Override public boolean onPrepareOptionsMenu(Menu menu) { super.onPrepareOptionsMenu(menu); - - MenuItem item = menu.findItem(MENU_SWITCH_COMPASS_GPS); - if (Settings.isUseCompass()) { - item.setTitle(res.getString(R.string.use_gps)); - } else { - item.setTitle(res.getString(R.string.use_compass)); - } - + menu.findItem(MENU_SWITCH_COMPASS_GPS).setTitle(res.getString(Settings.isUseCompass() ? R.string.use_gps : R.string.use_compass)); return true; } @@ -270,15 +230,15 @@ public class cgeonavigate extends AbstractActivity { finish(); return true; } else if (id > 3 && coordinates.get(id - 4) != null) { - cgCoord coordinate = coordinates.get(id - 4); + final IWaypoint coordinate = coordinates.get(id - 4); title = coordinate.getName(); dstCoords = coordinate.getCoords(); setTitle(); setDestCoords(); - updateDistanceInfo(); + updateDistanceInfo(app.currentGeo()); - Log.d(Settings.tag, "destination set: " + title + " (" + dstCoords + ")"); + Log.d("destination set: " + title + " (" + dstCoords + ")"); return true; } @@ -301,25 +261,8 @@ public class cgeonavigate extends AbstractActivity { ((TextView) findViewById(R.id.destination)).setText(dstCoords.toString()); } - public void setDest(final Geopoint coords) { - if (coords == null) { - return; - } - - title = "some place"; - setTitle(); - setDestCoords(); - - dstCoords = coords; - updateDistanceInfo(); - } - - public Geopoint getCoordinatesNow() { - return geo.coordsNow; - } - - private void updateDistanceInfo() { - if (geo == null || geo.coordsNow == null || dstCoords == null) { + private void updateDistanceInfo(final IGeoData geo) { + if (geo.getCoords() == null || dstCoords == null) { return; } @@ -330,69 +273,62 @@ public class cgeonavigate extends AbstractActivity { headingView = (TextView) findViewById(R.id.heading); } - cacheHeading = geo.coordsNow.bearingTo(dstCoords); - distanceView.setText(HumanDistance.getHumanDistance(geo.coordsNow.distanceTo(dstCoords))); + cacheHeading = geo.getCoords().bearingTo(dstCoords); + distanceView.setText(HumanDistance.getHumanDistance(geo.getCoords().distanceTo(dstCoords))); headingView.setText(Math.round(cacheHeading) + "°"); } - private class update implements UpdateLocationCallback { - - @Override - public void updateLocation(cgGeo geo) { - if (geo == null) { - return; + @Override + public void update(final IGeoData geo) { + try { + if (navType == null || navLocation == null || navAccuracy == null) { + navType = (TextView) findViewById(R.id.nav_type); + navAccuracy = (TextView) findViewById(R.id.nav_accuracy); + navSatellites = (TextView) findViewById(R.id.nav_satellites); + navLocation = (TextView) findViewById(R.id.nav_location); } - try { - if (navType == null || navLocation == null || navAccuracy == null) { - navType = (TextView) findViewById(R.id.nav_type); - navAccuracy = (TextView) findViewById(R.id.nav_accuracy); - navSatellites = (TextView) findViewById(R.id.nav_satellites); - navLocation = (TextView) findViewById(R.id.nav_location); + if (geo.getCoords() != null) { + String satellites; + if (geo.getSatellitesFixed() > 0) { + satellites = res.getString(R.string.loc_sat) + ": " + geo.getSatellitesFixed() + "/" + geo.getSatellitesVisible(); + } else if (geo.getSatellitesVisible() >= 0) { + satellites = res.getString(R.string.loc_sat) + ": 0/" + geo.getSatellitesVisible(); + } else { + satellites = ""; } + navSatellites.setText(satellites); + navType.setText(res.getString(geo.getLocationProvider().resourceId)); - if (geo.coordsNow != null) { - String satellites = null; - if (geo.satellitesFixed > 0) { - satellites = res.getString(R.string.loc_sat) + ": " + geo.satellitesFixed + "/" + geo.satellitesVisible; - } else if (geo.satellitesVisible >= 0) { - satellites = res.getString(R.string.loc_sat) + ": 0/" + geo.satellitesVisible; + if (geo.getAccuracy() >= 0) { + if (Settings.isUseMetricUnits()) { + navAccuracy.setText("±" + Math.round(geo.getAccuracy()) + " m"); } else { - satellites = ""; + navAccuracy.setText("±" + Math.round(geo.getAccuracy() * IConversion.METERS_TO_FEET) + " ft"); } - navSatellites.setText(satellites); - navType.setText(res.getString(geo.locationProvider.resourceId)); - - if (geo.accuracyNow >= 0) { - if (Settings.isUseMetricUnits()) { - navAccuracy.setText("±" + Math.round(geo.accuracyNow) + " m"); - } else { - navAccuracy.setText("±" + Math.round(geo.accuracyNow * IConversion.METERS_TO_FEET) + " ft"); - } - } else { - navAccuracy.setText(null); - } - - if (geo.altitudeNow != null) { - final String humanAlt = HumanDistance.getHumanDistance(geo.altitudeNow.floatValue() / 1000); - navLocation.setText(geo.coordsNow + " | " + humanAlt); - } else { - navLocation.setText(geo.coordsNow.toString()); - } - - updateDistanceInfo(); } else { - navType.setText(null); navAccuracy.setText(null); - navLocation.setText(res.getString(R.string.loc_trying)); } - if (!Settings.isUseCompass() || geo.speedNow > 5) { // use GPS when speed is higher than 18 km/h - northHeading = geo.bearingNow; + if (geo.getAltitude() != 0.0f) { + final String humanAlt = HumanDistance.getHumanDistance((float) geo.getAltitude() / 1000); + navLocation.setText(geo.getCoords() + " | " + humanAlt); + } else { + navLocation.setText(geo.getCoords().toString()); } - } catch (Exception e) { - Log.w(Settings.tag, "Failed to update location."); + + updateDistanceInfo(geo); + } else { + navType.setText(null); + navAccuracy.setText(null); + navLocation.setText(res.getString(R.string.loc_trying)); + } + + if (!Settings.isUseCompass() || geo.getSpeed() > 5) { // use GPS when speed is higher than 18 km/h + northHeading = geo.getBearing(); } + } catch (Exception e) { + Log.w("Failed to LocationUpdater location."); } } @@ -404,45 +340,20 @@ public class cgeonavigate extends AbstractActivity { return; } - if (geo == null || geo.speedNow <= 5) { // use compass when speed is lower than 18 km/h + if (app.currentGeo().getSpeed() <= 5) { // use compass when speed is lower than 18 km/h northHeading = dir.directionNow; } } } - private static class updaterThread extends Thread { - - private Handler handler = null; - - public updaterThread(Handler handlerIn) { - handler = handlerIn; - } - - @Override - public void run() { - while (!Thread.currentThread().isInterrupted()) { - if (handler != null) { - handler.sendMessage(Message.obtain()); - } - - try { - Thread.sleep(20); - } catch (Exception e) { - Thread.currentThread().interrupt(); - } - } - } - } - - public static void startActivity(final Context context, final String geocode, final String displayedName, final Geopoint coords, final Collection<cgCoord> coordinatesWithType) { + public static void startActivity(final Context context, final String geocode, final String displayedName, final Geopoint coords, final Collection<IWaypoint> coordinatesWithType) { coordinates.clear(); if (coordinatesWithType != null) { // avoid possible NPE coordinates.addAll(coordinatesWithType); } final Intent navigateIntent = new Intent(context, cgeonavigate.class); - navigateIntent.putExtra(EXTRAS_LATITUDE, coords.getLatitude()); - navigateIntent.putExtra(EXTRAS_LONGITUDE, coords.getLongitude()); + navigateIntent.putExtra(EXTRAS_COORDS, coords); navigateIntent.putExtra(EXTRAS_GEOCODE, geocode.toUpperCase()); if (null != displayedName) { navigateIntent.putExtra(EXTRAS_NAME, displayedName); diff --git a/main/src/cgeo/geocaching/cgeopoint.java b/main/src/cgeo/geocaching/cgeopoint.java index 890f396..e85b27d 100644 --- a/main/src/cgeo/geocaching/cgeopoint.java +++ b/main/src/cgeo/geocaching/cgeopoint.java @@ -5,7 +5,9 @@ import cgeo.geocaching.apps.cache.navi.NavigationAppFactory; import cgeo.geocaching.geopoint.DistanceParser; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.geopoint.GeopointFormatter; -import cgeo.geocaching.geopoint.GeopointParser; +import cgeo.geocaching.ui.Formatter; +import cgeo.geocaching.utils.Log; +import cgeo.geocaching.utils.IObserver; import org.apache.commons.lang3.StringUtils; @@ -13,7 +15,6 @@ import android.app.Activity; import android.content.Context; import android.content.res.Configuration; import android.os.Bundle; -import android.util.Log; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.LayoutInflater; @@ -34,24 +35,24 @@ import android.widget.TextView; import java.util.List; -public class cgeopoint extends AbstractActivity { +public class cgeopoint extends AbstractActivity implements IObserver<IGeoData> { private static final int MENU_DEFAULT_NAVIGATION = 2; private static final int MENU_NAVIGATE = 0; private static final int MENU_CACHES_AROUND = 5; private static final int MENU_CLEAR_HISTORY = 6; - private static class DestinationHistoryAdapter extends ArrayAdapter<cgDestination> { + private static class DestinationHistoryAdapter extends ArrayAdapter<Destination> { private LayoutInflater inflater = null; public DestinationHistoryAdapter(Context context, - List<cgDestination> objects) { + List<Destination> objects) { super(context, 0, objects); } @Override public View getView(final int position, final View convertView, final ViewGroup parent) { - cgDestination loc = getItem(position); + Destination loc = getItem(position); View v = convertView; @@ -70,7 +71,7 @@ public class cgeopoint extends AbstractActivity { longitude.setText(lonString); latitude.setText(latString); - date.setText(cgBase.formatShortDateTime(getContext(), loc.getDate())); + date.setText(Formatter.formatShortDateTime(getContext(), loc.getDate())); return v; } @@ -84,12 +85,10 @@ public class cgeopoint extends AbstractActivity { } } - private cgGeo geo = null; - private UpdateLocationCallback geoUpdate = new update(); private Button latButton = null; private Button lonButton = null; private boolean changed = false; - private List<cgDestination> historyOfSearchedLocations; + private List<Destination> historyOfSearchedLocations; private DestinationHistoryAdapter destionationHistoryAdapter; private ListView historyListView; private TextView historyFooter; @@ -137,8 +136,8 @@ public class cgeopoint extends AbstractActivity { public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { final Object selection = arg0.getItemAtPosition(arg2); - if (selection instanceof cgDestination) { - navigateTo(((cgDestination) selection).getCoords()); + if (selection instanceof Destination) { + navigateTo(((Destination) selection).getCoords()); } } }); @@ -146,7 +145,7 @@ public class cgeopoint extends AbstractActivity { historyListView.setOnCreateContextMenuListener(new OnCreateContextMenuListener() { @Override public void onCreateContextMenu(ContextMenu menu, View v, - ContextMenuInfo menuInfo) { + ContextMenuInfo menuInfo) { menu.add(Menu.NONE, CONTEXT_MENU_NAVIGATE, Menu.NONE, res.getString(R.string.cache_menu_navigate)); menu.add(Menu.NONE, CONTEXT_MENU_EDIT_WAYPOINT, Menu.NONE, R.string.waypoint_edit); menu.add(Menu.NONE, CONTEXT_MENU_DELETE_WAYPOINT, Menu.NONE, R.string.waypoint_delete); @@ -163,21 +162,21 @@ public class cgeopoint extends AbstractActivity { switch (item.getItemId()) { case CONTEXT_MENU_NAVIGATE: contextMenuItemPosition = position; - if (destination instanceof cgDestination) { - NavigationAppFactory.showNavigationMenu(geo, this, null, null, ((cgDestination) destination).getCoords()); + if (destination instanceof Destination) { + NavigationAppFactory.showNavigationMenu(app.currentGeo(), this, null, null, ((Destination) destination).getCoords()); return true; } break; case CONTEXT_MENU_DELETE_WAYPOINT: - if (destination instanceof cgDestination) { - removeFromHistory((cgDestination) destination); + if (destination instanceof Destination) { + removeFromHistory((Destination) destination); } return true; case CONTEXT_MENU_EDIT_WAYPOINT: - if (destination instanceof cgDestination) { - final Geopoint gp = ((cgDestination) destination).getCoords(); + if (destination instanceof Destination) { + final Geopoint gp = ((Destination) destination).getCoords(); latButton.setText(gp.format(GeopointFormatter.Format.LAT_DECMINUTE)); lonButton.setText(gp.format(GeopointFormatter.Format.LON_DECMINUTE)); } @@ -205,7 +204,7 @@ public class cgeopoint extends AbstractActivity { return destionationHistoryAdapter; } - private List<cgDestination> getHistoryOfSearchedLocations() { + private List<Destination> getHistoryOfSearchedLocations() { if (historyOfSearchedLocations == null) { // Load from database historyOfSearchedLocations = app.getHistoryOfSearchedLocations(); @@ -224,42 +223,27 @@ public class cgeopoint extends AbstractActivity { @Override public void onResume() { super.onResume(); - + app.addGeoObserver(this); init(); } @Override public void onDestroy() { - if (geo != null) { - geo = app.removeGeo(); - } - super.onDestroy(); } @Override public void onStop() { - if (geo != null) { - geo = app.removeGeo(); - } - super.onStop(); } @Override public void onPause() { - if (geo != null) { - geo = app.removeGeo(); - } - + app.deleteGeoObserver(this); super.onPause(); } private void init() { - if (geo == null) { - geo = app.startGeo(geoUpdate); - } - latButton = (Button) findViewById(R.id.buttonLatitude); lonButton = (Button) findViewById(R.id.buttonLongitude); @@ -305,7 +289,7 @@ public class cgeopoint extends AbstractActivity { if (latButton.getText().length() > 0 && lonButton.getText().length() > 0) { gp = new Geopoint(latButton.getText().toString() + " " + lonButton.getText().toString()); } - cgeocoords coordsDialog = new cgeocoords(cgeopoint.this, null, gp, geo); + cgeocoords coordsDialog = new cgeocoords(cgeopoint.this, null, gp, app.currentGeo()); coordsDialog.setCancelable(true); coordsDialog.setOnCoordinateUpdate(new cgeocoords.CoordinateUpdate() { @Override @@ -382,8 +366,7 @@ public class cgeopoint extends AbstractActivity { final Geopoint coords = getDestination(); - if (coords != null) - { + if (coords != null) { addToHistory(coords); } @@ -401,7 +384,7 @@ public class cgeopoint extends AbstractActivity { return true; case MENU_NAVIGATE: - NavigationAppFactory.showNavigationMenu(geo, this, null, null, coords); + NavigationAppFactory.showNavigationMenu(app.currentGeo(), this, null, null, coords); return true; default: return false; @@ -410,12 +393,9 @@ public class cgeopoint extends AbstractActivity { private void addToHistory(final Geopoint coords) { // Add locations to history - cgDestination loc = new cgDestination(); - loc.setCoords(coords); + final Destination loc = new Destination(coords); - if (!getHistoryOfSearchedLocations().contains(loc)) - { - loc.setDate(System.currentTimeMillis()); + if (!getHistoryOfSearchedLocations().contains(loc)) { getHistoryOfSearchedLocations().add(0, loc); // Save location @@ -426,7 +406,7 @@ public class cgeopoint extends AbstractActivity { } } - private void removeFromHistory(cgDestination destination) { + private void removeFromHistory(Destination destination) { if (getHistoryOfSearchedLocations().contains(destination)) { getHistoryOfSearchedLocations().remove(destination); @@ -472,7 +452,7 @@ public class cgeopoint extends AbstractActivity { return; } - NavigationAppFactory.startDefaultNavigationApplication(geo, this, null, null, geopoint); + NavigationAppFactory.startDefaultNavigationApplication(app.currentGeo(), this, null, null, geopoint); } private void cachesAround() { @@ -483,46 +463,40 @@ public class cgeopoint extends AbstractActivity { return; } - cgeocaches.startActivityCoordinates(this, coords.getLatitude(), coords.getLongitude()); + cgeocaches.startActivityCoordinates(this, coords); finish(); } - private class update implements UpdateLocationCallback { - - @Override - public void updateLocation(cgGeo geo) { - if (geo == null) { - return; - } - - try { - latButton.setHint(geo.coordsNow.format(GeopointFormatter.Format.LAT_DECMINUTE_RAW)); - lonButton.setHint(geo.coordsNow.format(GeopointFormatter.Format.LON_DECMINUTE_RAW)); - } catch (Exception e) { - Log.w(Settings.tag, "Failed to update location."); - } + @Override + public void update(final IGeoData geo) { + try { + latButton.setHint(geo.getCoords().format(GeopointFormatter.Format.LAT_DECMINUTE_RAW)); + lonButton.setHint(geo.getCoords().format(GeopointFormatter.Format.LON_DECMINUTE_RAW)); + } catch (final Exception e) { + Log.w("Failed to update location."); } } private class currentListener implements View.OnClickListener { public void onClick(View arg0) { - if (geo == null || geo.coordsNow == null) { + final Geopoint coords = app.currentGeo().getCoords(); + if (coords == null) { showToast(res.getString(R.string.err_point_unknown_position)); return; } - latButton.setText(geo.coordsNow.format(GeopointFormatter.Format.LAT_DECMINUTE)); - lonButton.setText(geo.coordsNow.format(GeopointFormatter.Format.LON_DECMINUTE)); + latButton.setText(coords.format(GeopointFormatter.Format.LAT_DECMINUTE)); + lonButton.setText(coords.format(GeopointFormatter.Format.LON_DECMINUTE)); changed = false; } } private Geopoint getDestination() { - Geopoint result = null; - Geopoint coords = null; + Geopoint result; + Geopoint coords; String bearingText = ((EditText) findViewById(R.id.bearing)).getText().toString(); // combine distance from EditText and distanceUnit saved from Spinner @@ -538,23 +512,23 @@ public class cgeopoint extends AbstractActivity { if (StringUtils.isNotBlank(latText) && StringUtils.isNotBlank(lonText)) { try { - coords = GeopointParser.parse(latText, lonText); - } catch (GeopointParser.ParseException e) { + coords = new Geopoint(latText, lonText); + } catch (Geopoint.ParseException e) { showToast(res.getString(e.resource)); return null; } } else { - if (geo == null || geo.coordsNow == null) { + if (app.currentGeo().getCoords() == null) { showToast(res.getString(R.string.err_point_curr_position_unavailable)); return null; } - coords = geo.coordsNow; + coords = app.currentGeo().getCoords(); } if (StringUtils.isNotBlank(bearingText) && StringUtils.isNotBlank(distanceText)) { // bearing & distance - double bearing = 0; + double bearing; try { bearing = Double.parseDouble(bearingText); } catch (NumberFormatException e) { diff --git a/main/src/cgeo/geocaching/cgeopopup.java b/main/src/cgeo/geocaching/cgeopopup.java index afc7df6..dc98928 100644 --- a/main/src/cgeo/geocaching/cgeopopup.java +++ b/main/src/cgeo/geocaching/cgeopopup.java @@ -11,20 +11,23 @@ import cgeo.geocaching.gcvote.GCVote; import cgeo.geocaching.gcvote.GCVoteRating; import cgeo.geocaching.geopoint.HumanDistance; import cgeo.geocaching.utils.CancellableHandler; +import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; import android.app.ProgressDialog; +import android.content.Context; import android.content.Intent; import android.content.res.Configuration; +import android.graphics.Rect; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.Message; -import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; +import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnLongClickListener; @@ -42,8 +45,7 @@ public class cgeopopup extends AbstractActivity { private LayoutInflater inflater = null; private String geocode = null; private cgCache cache = null; - private cgGeo geo = null; - private UpdateLocationCallback geoUpdate = new update(); + private GeoObserver geoUpdate = new UpdateLocation(); private ProgressDialog storeDialog = null; private ProgressDialog dropDialog = null; private TextView cacheDistance = null; @@ -74,7 +76,7 @@ public class cgeopopup extends AbstractActivity { } catch (Exception e) { showToast(res.getString(R.string.err_store)); - Log.e(Settings.tag, "cgeopopup.storeCacheHandler: " + e.toString()); + Log.e("cgeopopup.storeCacheHandler: " + e.toString()); } if (storeDialog != null) { @@ -97,7 +99,7 @@ public class cgeopopup extends AbstractActivity { } catch (Exception e) { showToast(res.getString(R.string.err_drop)); - Log.e(Settings.tag, "cgeopopup.dropCacheHandler: " + e.toString()); + Log.e("cgeopopup.dropCacheHandler: " + e.toString()); } if (dropDialog != null) { @@ -145,6 +147,19 @@ public class cgeopopup extends AbstractActivity { } @Override + public boolean onTouchEvent(final MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_UP) { + final Rect r = new Rect(0, 0, 0, 0); + getWindow().getDecorView().getHitRect(r); + if (!r.contains((int) event.getX(), (int) event.getY())) { + finish(); + return true; + } + } + return super.onTouchEvent(event); + } + + @Override public boolean onCreateOptionsMenu(Menu menu) { menu.add(0, 2, 0, NavigationAppFactory.getDefaultNavigationApplication(this).getName()).setIcon(android.R.drawable.ic_menu_compass); // default navigation tool menu.add(0, 3, 0, res.getString(R.string.cache_menu_navigate)).setIcon(android.R.drawable.ic_menu_mapmode); @@ -182,34 +197,31 @@ public class cgeopopup extends AbstractActivity { public boolean onOptionsItemSelected(MenuItem item) { final int menuItem = item.getItemId(); - if (menuItem == 2) { - navigateTo(); - return true; - } else if (menuItem == 3) { - NavigationAppFactory.showNavigationMenu(geo, this, cache, null, null); - return true; - } else if (menuItem == 5) { - cachesAround(); - return true; - } else if (menuItem == MENU_LOG_VISIT) { - cache.logVisit(this); - finish(); - return true; - } else if (menuItem == 7) { - startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/seek/cache_details.aspx?wp=" + cache.getGeocode()))); - return true; + switch (menuItem) { + case 2: + navigateTo(); + break; + case 3: + NavigationAppFactory.showNavigationMenu(app.currentGeo(), this, cache, null, null); + break; + case 5: + cachesAround(); + break; + case MENU_LOG_VISIT: + cache.logVisit(this); + finish(); + break; + case 7: + startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/seek/cache_details.aspx?wp=" + cache.getGeocode()))); + break; + default: + cache.logOffline(this, LogType.getById(menuItem - MENU_LOG_VISIT_OFFLINE)); } - int logType = menuItem - MENU_LOG_VISIT_OFFLINE; - cache.logOffline(this, LogType.getById(logType)); return true; } private void init() { - if (geo == null) { - geo = app.startGeo(geoUpdate); - } - app.setAction(geocode); cache = app.loadCache(geocode, LoadFlags.LOAD_CACHE_OR_DB); @@ -278,7 +290,7 @@ public class cgeopopup extends AbstractActivity { itemName.setText(res.getString(R.string.cache_status)); - StringBuilder state = new StringBuilder(); + final StringBuilder state = new StringBuilder(); if (cache.isFound()) { if (state.length() > 0) { state.append(", "); @@ -306,8 +318,6 @@ public class cgeopopup extends AbstractActivity { itemValue.setText(state.toString()); detailsList.addView(itemLayout); - - state = null; } // distance @@ -403,7 +413,6 @@ public class cgeopopup extends AbstractActivity { startActivity(cachesIntent); finish(); - return; } }); @@ -417,7 +426,7 @@ public class cgeopopup extends AbstractActivity { if (cache.getListId() > 0) { long diff = (System.currentTimeMillis() / (60 * 1000)) - (cache.getDetailedUpdate() / (60 * 1000)); // minutes - String ago = ""; + String ago; if (diff < 15) { ago = res.getString(R.string.cache_offline_time_mins_few); } else if (diff < 50) { @@ -452,11 +461,7 @@ public class cgeopopup extends AbstractActivity { offlineStore.setOnClickListener(new storeCache()); } } catch (Exception e) { - Log.e(Settings.tag, "cgeopopup.init: " + e.toString()); - } - - if (geo != null) { - geoUpdate.updateLocation(geo); + Log.e("cgeopopup.init: " + e.toString()); } } @@ -470,52 +475,37 @@ public class cgeopopup extends AbstractActivity { @Override public void onResume() { super.onResume(); - + app.addGeoObserver(geoUpdate); init(); } @Override public void onDestroy() { - if (geo != null) { - geo = app.removeGeo(); - } - super.onDestroy(); } @Override public void onStop() { - if (geo != null) { - geo = app.removeGeo(); - } - super.onStop(); } @Override public void onPause() { - if (geo != null) { - geo = app.removeGeo(); - } - + app.deleteGeoObserver(geoUpdate); super.onPause(); } - private class update implements UpdateLocationCallback { + private class UpdateLocation extends GeoObserver { @Override - public void updateLocation(cgGeo geo) { - if (geo == null) { - return; - } - + protected void updateLocation(final IGeoData geo) { try { - if (geo.coordsNow != null && cache != null && cache.getCoords() != null) { - cacheDistance.setText(HumanDistance.getHumanDistance(geo.coordsNow.distanceTo(cache.getCoords()))); + if (geo.getCoords() != null && cache != null && cache.getCoords() != null) { + cacheDistance.setText(HumanDistance.getHumanDistance(geo.getCoords().distanceTo(cache.getCoords()))); cacheDistance.bringToFront(); } } catch (Exception e) { - Log.w(Settings.tag, "Failed to update location."); + Log.w("Failed to UpdateLocation location."); } } } @@ -526,7 +516,7 @@ public class cgeopopup extends AbstractActivity { return; } - NavigationAppFactory.startDefaultNavigationApplication(geo, this, cache, null, null); + NavigationAppFactory.startDefaultNavigationApplication(app.currentGeo(), this, cache, null, null); } private void cachesAround() { @@ -595,7 +585,7 @@ public class cgeopopup extends AbstractActivity { @Override public void run() { - cgBase.dropCache(cache, handler); + cache.drop(handler); } } @@ -636,7 +626,7 @@ public class cgeopopup extends AbstractActivity { showToast(res.getString(R.string.cache_coordinates_no)); return; } - NavigationAppFactory.startDefaultNavigationApplication(geo, this, cache, null, null); + NavigationAppFactory.startDefaultNavigationApplication(app.currentGeo(), this, cache, null, null); finish(); } @@ -648,7 +638,7 @@ public class cgeopopup extends AbstractActivity { showToast(res.getString(R.string.cache_coordinates_no)); return; } - NavigationAppFactory.startDefaultNavigationApplication2(geo, this, cache, null, null); + NavigationAppFactory.startDefaultNavigationApplication2(app.currentGeo(), this, cache, null, null); finish(); } @@ -657,4 +647,10 @@ public class cgeopopup extends AbstractActivity { super.goManual(view); finish(); } + + public static void startActivity(final Context context, final String geocode) { + final Intent popupIntent = new Intent(context, cgeopopup.class); + popupIntent.putExtra("geocode", geocode); + context.startActivity(popupIntent); + } } diff --git a/main/src/cgeo/geocaching/cgeotouch.java b/main/src/cgeo/geocaching/cgeotouch.java index e5af4d3..5a3ed7b 100644 --- a/main/src/cgeo/geocaching/cgeotouch.java +++ b/main/src/cgeo/geocaching/cgeotouch.java @@ -1,13 +1,16 @@ package cgeo.geocaching; import cgeo.geocaching.activity.AbstractActivity; +import cgeo.geocaching.connector.gc.GCParser; +import cgeo.geocaching.connector.gc.Login; import cgeo.geocaching.enumerations.LogType; import cgeo.geocaching.enumerations.StatusCode; -import cgeo.geocaching.network.Login; import cgeo.geocaching.network.Network; import cgeo.geocaching.network.Parameters; import cgeo.geocaching.twitter.Twitter; import cgeo.geocaching.ui.DateDialog; +import cgeo.geocaching.ui.Formatter; +import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; @@ -17,7 +20,6 @@ import android.content.res.Configuration; import android.os.Bundle; import android.os.Handler; import android.os.Message; -import android.util.Log; import android.view.ContextMenu; import android.view.Menu; import android.view.MenuItem; @@ -34,7 +36,6 @@ import java.util.Calendar; import java.util.List; public class cgeotouch extends AbstractActivity implements DateDialog.DateDialogParent { - private cgTrackable trackable = null; private List<LogType> logTypes = new ArrayList<LogType>(); private ProgressDialog waitDialog = null; private String guid = null; @@ -58,33 +59,28 @@ public class cgeotouch extends AbstractActivity implements DateDialog.DateDialog private Handler loadDataHandler = new Handler() { @Override - public void handleMessage(Message msg) { - if (MSG_UPDATE_TYPE == msg.what) { + public void handleMessage(final Message msg) { + if (msg.what == MSG_UPDATE_TYPE) { setType((LogType) msg.obj); showToast(res.getString(R.string.info_log_type_changed)); } else { - if (cgBase.isEmpty(viewstates) && attempts < 2) { - showToast(res.getString(R.string.err_log_load_data_again)); + if (Login.isEmpty(viewstates)) { + if (attempts < 2) { + showToast(res.getString(R.string.err_log_load_data_again)); + new loadData(guid).start(); + } else { + showToast(res.getString(R.string.err_log_load_data)); + showProgress(false); + } + } else { + gettingViewstate = false; // we're done, user can post log - loadData thread; - thread = new loadData(guid); - thread.start(); + final Button buttonPost = (Button) findViewById(R.id.post); + buttonPost.setEnabled(true); + buttonPost.setOnClickListener(new postListener()); - return; - } else if (cgBase.isEmpty(viewstates) && attempts >= 2) { - showToast(res.getString(R.string.err_log_load_data)); showProgress(false); - - return; } - - gettingViewstate = false; // we're done, user can post log - - Button buttonPost = (Button) findViewById(R.id.post); - buttonPost.setEnabled(true); - buttonPost.setOnClickListener(new postListener()); - - showProgress(false); } } }; @@ -129,7 +125,7 @@ public class cgeotouch extends AbstractActivity implements DateDialog.DateDialog } } - trackable = app.getTrackableByGeocode("logging trackable"); + final cgTrackable trackable = app.getTrackableByGeocode("logging trackable"); if (StringUtils.isNotBlank(trackable.getName())) { setTitle(res.getString(R.string.trackable_touch) + trackable.getName()); @@ -139,7 +135,7 @@ public class cgeotouch extends AbstractActivity implements DateDialog.DateDialog app.setAction("logging trackable"); - if (trackable == null || guid == null) { + if (guid == null) { showToast(res.getString(R.string.err_tb_forgot_saw)); finish(); @@ -192,10 +188,10 @@ public class cgeotouch extends AbstractActivity implements DateDialog.DateDialog public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); - EditText text = null; - String textContent = null; - String dateString = null; - String timeString = null; + EditText text; + String textContent; + String dateString; + String timeString; String addText = ""; if ((id >= 0x1 && id <= 0x7)) { @@ -203,8 +199,8 @@ public class cgeotouch extends AbstractActivity implements DateDialog.DateDialog textContent = text.getText().toString(); final long now = System.currentTimeMillis(); - dateString = cgBase.formatDate(now); - timeString = cgBase.formatTime(now); + dateString = Formatter.formatDate(now); + timeString = Formatter.formatTime(now); if ((id & 0x4) == 0x4) { addText += dateString; @@ -287,7 +283,7 @@ public class cgeotouch extends AbstractActivity implements DateDialog.DateDialog }); Button dateButton = (Button) findViewById(R.id.date); - dateButton.setText(cgBase.formatShortDate(date.getTime().getTime())); + dateButton.setText(Formatter.formatShortDate(date.getTime().getTime())); dateButton.setOnClickListener(new cgeotouchDateListener()); if (tweetBox == null) { @@ -299,7 +295,7 @@ public class cgeotouch extends AbstractActivity implements DateDialog.DateDialog tweetCheck.setChecked(true); Button buttonPost = (Button) findViewById(R.id.post); - if (cgBase.isEmpty(viewstates)) { + if (Login.isEmpty(viewstates)) { buttonPost.setEnabled(false); buttonPost.setOnTouchListener(null); buttonPost.setOnClickListener(null); @@ -319,7 +315,7 @@ public class cgeotouch extends AbstractActivity implements DateDialog.DateDialog date = dateIn; final Button dateButton = (Button) findViewById(R.id.date); - dateButton.setText(cgBase.formatShortDate(date.getTime().getTime())); + dateButton.setText(Formatter.formatShortDate(date.getTime().getTime())); } public void setType(LogType type) { @@ -372,7 +368,6 @@ public class cgeotouch extends AbstractActivity implements DateDialog.DateDialog showToast(res.getString(R.string.err_tb_forgot_saw)); finish(); - return; } } @@ -392,11 +387,11 @@ public class cgeotouch extends AbstractActivity implements DateDialog.DateDialog return; } - final String page = Network.getResponseData(Network.request("http://www.geocaching.com/track/log.aspx", params, false, false, false)); + final String page = Network.getResponseData(Network.getRequest("http://www.geocaching.com/track/log.aspx", params)); viewstates = Login.getViewstates(page); - final List<LogType> typesPre = cgBase.parseTypes(page); + final List<LogType> typesPre = GCParser.parseTypes(page); if (typesPre.size() > 0) { logTypes.clear(); logTypes.addAll(typesPre); @@ -408,7 +403,7 @@ public class cgeotouch extends AbstractActivity implements DateDialog.DateDialog loadDataHandler.obtainMessage(MSG_UPDATE_TYPE, typeSelected).sendToTarget(); } } catch (Exception e) { - Log.e(Settings.tag, "cgeotouch.loadData.run: " + e.toString()); + Log.e("cgeotouch.loadData.run: " + e.toString()); } loadDataHandler.sendEmptyMessage(0); @@ -442,7 +437,7 @@ public class cgeotouch extends AbstractActivity implements DateDialog.DateDialog tweetCheck = (CheckBox) findViewById(R.id.tweet); } - final StatusCode status = cgBase.postLogTrackable(guid, tracking, viewstates, typeSelected, date.get(Calendar.YEAR), (date.get(Calendar.MONTH) + 1), date.get(Calendar.DATE), log); + final StatusCode status = GCParser.postLogTrackable(guid, tracking, viewstates, typeSelected, date.get(Calendar.YEAR), (date.get(Calendar.MONTH) + 1), date.get(Calendar.DATE), log); if (status == StatusCode.NO_ERROR && Settings.isUseTwitter() && Settings.isTwitterLoginValid() && @@ -452,7 +447,7 @@ public class cgeotouch extends AbstractActivity implements DateDialog.DateDialog return status; } catch (Exception e) { - Log.e(Settings.tag, "cgeotouch.postLogFn: " + e.toString()); + Log.e("cgeotouch.postLogFn: " + e.toString()); } return StatusCode.LOG_POST_ERROR; diff --git a/main/src/cgeo/geocaching/cgeotrackable.java b/main/src/cgeo/geocaching/cgeotrackable.java index 1d5b5db..2a0a017 100644 --- a/main/src/cgeo/geocaching/cgeotrackable.java +++ b/main/src/cgeo/geocaching/cgeotrackable.java @@ -1,10 +1,12 @@ package cgeo.geocaching; import cgeo.geocaching.activity.AbstractActivity; +import cgeo.geocaching.connector.gc.GCParser; import cgeo.geocaching.geopoint.HumanDistance; import cgeo.geocaching.network.HtmlImage; +import cgeo.geocaching.ui.Formatter; +import cgeo.geocaching.utils.Log; -import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import android.app.ProgressDialog; @@ -16,7 +18,6 @@ import android.os.Handler; import android.os.Message; import android.text.Html; import android.text.method.LinkMovementMethod; -import android.util.Log; import android.view.ContextMenu; import android.view.LayoutInflater; import android.view.Menu; @@ -48,13 +49,6 @@ public class cgeotrackable extends AbstractActivity { @Override public void handleMessage(Message msg) { - if (trackable != null && StringUtils.isNotBlank(trackable.getError())) { - showToast(res.getString(R.string.err_tb_details_download) + " " + trackable.getError() + "."); - - finish(); - return; - } - if (trackable == null) { if (waitDialog != null) { waitDialog.dismiss(); @@ -94,7 +88,7 @@ public class cgeotrackable extends AbstractActivity { addDetail(R.string.trackable_name, StringUtils.isNotBlank(trackable.getName()) ? Html.fromHtml(trackable.getName()).toString() : res.getString(R.string.trackable_unknown)); // trackable type - String tbType = null; + String tbType; if (StringUtils.isNotBlank(trackable.getType())) { tbType = Html.fromHtml(trackable.getType()).toString(); } else { @@ -117,7 +111,7 @@ public class cgeotrackable extends AbstractActivity { trackable.getSpottedType() == cgTrackable.SPOTTED_UNKNOWN || trackable.getSpottedType() == cgTrackable.SPOTTED_OWNER ) { - String text = null; + String text; if (trackable.getSpottedType() == cgTrackable.SPOTTED_CACHE) { text = res.getString(R.string.trackable_spotted_in_cache) + " " + Html.fromHtml(trackable.getSpottedName()).toString(); @@ -155,7 +149,7 @@ public class cgeotrackable extends AbstractActivity { // trackable released if (trackable.getReleased() != null) { - addDetail(R.string.trackable_released, cgBase.formatDate(trackable.getReleased().getTime())); + addDetail(R.string.trackable_released, Formatter.formatDate(trackable.getReleased().getTime())); } // trackable distance @@ -213,7 +207,7 @@ public class cgeotrackable extends AbstractActivity { @Override public void run() { - BitmapDrawable image = null; + BitmapDrawable image; try { HtmlImage imgGetter = new HtmlImage(cgeotrackable.this, geocode, true, 0, false); @@ -221,7 +215,7 @@ public class cgeotrackable extends AbstractActivity { Message message = handler.obtainMessage(0, image); handler.sendMessage(message); } catch (Exception e) { - Log.e(Settings.tag, "cgeospoilers.onCreate.onClick.run: " + e.toString()); + Log.e("cgeospoilers.onCreate.onClick.run: " + e.toString()); } } }.start(); @@ -229,7 +223,7 @@ public class cgeotrackable extends AbstractActivity { imgView.addView(trackableImage); } } catch (Exception e) { - Log.e(Settings.tag, "cgeotrackable.loadTrackableHandler: " + e.toString() + Arrays.toString(e.getStackTrace())); + Log.e("cgeotrackable.loadTrackableHandler: " + e.toString() + Arrays.toString(e.getStackTrace())); } displayLogs(); @@ -356,21 +350,20 @@ public class cgeotrackable extends AbstractActivity { } @Override - public boolean onContextItemSelected(MenuItem item) { - final int id = item.getItemId(); - - if (id == 1) { - cgeocaches.startActivityOwner(this, contextMenuUser); - return true; - } else if (id == 2) { - cgeocaches.startActivityUserName(this, contextMenuUser); - return true; - } else if (id == 3) { - startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/profile/?u=" + URLEncoder.encode(contextMenuUser)))); - - return true; + public boolean onContextItemSelected(final MenuItem item) { + switch (item.getItemId()) { + case 1: + cgeocaches.startActivityOwner(this, contextMenuUser); + return true; + case 2: + cgeocaches.startActivityUserName(this, contextMenuUser); + return true; + case 3: + startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/profile/?u=" + URLEncoder.encode(contextMenuUser)))); + return true; + default: + return false; } - return false; } @Override @@ -418,7 +411,6 @@ public class cgeotrackable extends AbstractActivity { stop(); finish(); - return; } } @@ -428,7 +420,7 @@ public class cgeotrackable extends AbstractActivity { trackable = cgeoapplication.getInstance().getTrackableByGeocode(geocode); if ((trackable == null || trackable.isLoggable()) && !StringUtils.startsWithIgnoreCase(geocode, "GK")) { - trackable = cgBase.searchTrackable(geocode, guid, id); + trackable = GCParser.searchTrackable(geocode, guid, id); } handler.sendMessage(Message.obtain()); } @@ -442,11 +434,11 @@ public class cgeotrackable extends AbstractActivity { RelativeLayout rowView; if (trackable != null && trackable.getLogs() != null) { - for (cgLog log : trackable.getLogs()) { + for (LogEntry log : trackable.getLogs()) { rowView = (RelativeLayout) inflater.inflate(R.layout.trackable_logs_item, null); if (log.date > 0) { - ((TextView) rowView.findViewById(R.id.added)).setText(cgBase.formatShortDate(log.date)); + ((TextView) rowView.findViewById(R.id.added)).setText(Formatter.formatShortDate(log.date)); } ((TextView) rowView.findViewById(R.id.type)).setText(log.type.getL10n()); @@ -460,24 +452,21 @@ public class cgeotrackable extends AbstractActivity { final String cacheName = log.cacheName; ((TextView) rowView.findViewById(R.id.location)).setOnClickListener(new View.OnClickListener() { public void onClick(View arg0) { - Intent cacheIntent = new Intent(cgeotrackable.this, CacheDetailActivity.class); - cacheIntent.putExtra("guid", cacheGuid); - cacheIntent.putExtra("name", Html.fromHtml(cacheName).toString()); - startActivity(cacheIntent); + CacheDetailActivity.startActivityGuid(cgeotrackable.this, cacheGuid, Html.fromHtml(cacheName).toString()); } }); } TextView logView = (TextView) rowView.findViewById(R.id.log); logView.setMovementMethod(LinkMovementMethod.getInstance()); - logView.setText(Html.fromHtml(log.log, new HtmlImage(cgeotrackable.this, null, false, StoredList.TEMPORARY_LIST_ID, false), null), TextView.BufferType.SPANNABLE); + logView.setText(Html.fromHtml(log.log, new HtmlImage(this, null, false, StoredList.TEMPORARY_LIST_ID, false), null), TextView.BufferType.SPANNABLE); // add LogImages LinearLayout logLayout = (LinearLayout) rowView.findViewById(R.id.log_layout); - if (CollectionUtils.isNotEmpty(log.logImages)) { + if (log.hasLogImages()) { - final ArrayList<cgImage> logImages = new ArrayList<cgImage>(log.logImages); + final ArrayList<cgImage> logImages = new ArrayList<cgImage>(log.getLogImages()); final View.OnClickListener listener = new View.OnClickListener() { @Override @@ -487,8 +476,8 @@ public class cgeotrackable extends AbstractActivity { }; ArrayList<String> titles = new ArrayList<String>(); - for (int i_img_cnt = 0; i_img_cnt < log.logImages.size(); i_img_cnt++) { - String img_title = log.logImages.get(i_img_cnt).getTitle(); + for (cgImage image : log.getLogImages()) { + String img_title = image.getTitle(); if (!StringUtils.isBlank(img_title)) { titles.add(img_title); } @@ -525,7 +514,7 @@ public class cgeotrackable extends AbstractActivity { registerForContextMenu(view); openContextMenu(view); } catch (Exception e) { - Log.e(Settings.tag, "cgeotrackable.userActions.onClick ", e); + Log.e("cgeotrackable.userActions.onClick ", e); } } } @@ -565,7 +554,7 @@ public class cgeotrackable extends AbstractActivity { return; } - BitmapDrawable image = null; + BitmapDrawable image; try { HtmlImage imgGetter = new HtmlImage(cgeotrackable.this, trackable.getGeocode(), false, 0, false); @@ -573,7 +562,7 @@ public class cgeotrackable extends AbstractActivity { Message message = handler.obtainMessage(0, image); handler.sendMessage(message); } catch (Exception e) { - Log.e(Settings.tag, "cgeotrackable.tbIconThread.run: " + e.toString()); + Log.e("cgeotrackable.tbIconThread.run: " + e.toString()); } } } diff --git a/main/src/cgeo/geocaching/cgeowaypoint.java b/main/src/cgeo/geocaching/cgeowaypoint.java index 453308e..e8aa770 100644 --- a/main/src/cgeo/geocaching/cgeowaypoint.java +++ b/main/src/cgeo/geocaching/cgeowaypoint.java @@ -4,16 +4,18 @@ import cgeo.geocaching.activity.AbstractActivity; import cgeo.geocaching.apps.cache.navi.NavigationAppFactory; import cgeo.geocaching.enumerations.LoadFlags; import cgeo.geocaching.enumerations.LoadFlags.SaveFlag; +import cgeo.geocaching.utils.IObserver; +import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; import android.app.ProgressDialog; +import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.text.Html; -import android.util.Log; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.Menu; @@ -26,7 +28,7 @@ import android.widget.TextView; import java.util.EnumSet; -public class cgeowaypoint extends AbstractActivity { +public class cgeowaypoint extends AbstractActivity implements IObserver<IGeoData> { private static final int MENU_ID_NAVIGATION = 0; private static final int MENU_ID_CACHES_AROUND = 5; @@ -35,83 +37,67 @@ public class cgeowaypoint extends AbstractActivity { private cgWaypoint waypoint = null; private int id = -1; private ProgressDialog waitDialog = null; - private cgGeo geo = null; - private UpdateLocationCallback geoUpdate = new update(); private Handler loadWaypointHandler = new Handler() { @Override public void handleMessage(Message msg) { - try { - if (waypoint == null) { - if (waitDialog != null) { - waitDialog.dismiss(); - waitDialog = null; - } + if (waitDialog != null) { + waitDialog.dismiss(); + waitDialog = null; + } - showToast(res.getString(R.string.err_waypoint_load_failed)); + if (waypoint == null) { + showToast(res.getString(R.string.err_waypoint_load_failed)); + finish(); + return; + } - finish(); - return; - } else { - final TextView identification = (TextView) findViewById(R.id.identification); - final TextView coords = (TextView) findViewById(R.id.coordinates); - final ImageView defaultNavigation = (ImageView) findViewById(R.id.defaultNavigation); - final View separator = findViewById(R.id.separator); + final TextView identification = (TextView) findViewById(R.id.identification); + final TextView coords = (TextView) findViewById(R.id.coordinates); + final ImageView defaultNavigation = (ImageView) findViewById(R.id.defaultNavigation); + final View separator = findViewById(R.id.separator); - final View headline = findViewById(R.id.headline); - registerNavigationMenu(headline); + final View headline = findViewById(R.id.headline); + registerNavigationMenu(headline); - if (StringUtils.isNotBlank(waypoint.getName())) { - setTitle(Html.fromHtml(waypoint.getName()).toString()); - } else { - setTitle(res.getString(R.string.waypoint_title)); - } + if (StringUtils.isNotBlank(waypoint.getName())) { + setTitle(Html.fromHtml(waypoint.getName()).toString()); + } else { + setTitle(res.getString(R.string.waypoint_title)); + } - if (!waypoint.getPrefix().equalsIgnoreCase("OWN")) { - identification.setText(waypoint.getPrefix() + "/" + waypoint.getLookup()); - } else { - identification.setText(res.getString(R.string.waypoint_custom)); - } - registerNavigationMenu(identification); - waypoint.setIcon(res, identification); - - if (waypoint.getCoords() != null) { - coords.setText(Html.fromHtml(waypoint.getCoords().toString()), TextView.BufferType.SPANNABLE); - defaultNavigation.setVisibility(View.VISIBLE); - separator.setVisibility(View.VISIBLE); - } else { - coords.setText(res.getString(R.string.waypoint_unknown_coordinates)); - defaultNavigation.setVisibility(View.GONE); - separator.setVisibility(View.GONE); - } - registerNavigationMenu(coords); + if (!waypoint.getPrefix().equalsIgnoreCase("OWN")) { + identification.setText(waypoint.getPrefix() + "/" + waypoint.getLookup()); + } else { + identification.setText(res.getString(R.string.waypoint_custom)); + } + registerNavigationMenu(identification); + waypoint.setIcon(res, identification); - if (StringUtils.isNotBlank(waypoint.getNote())) { - final TextView note = (TextView) findViewById(R.id.note); - note.setText(Html.fromHtml(waypoint.getNote()), TextView.BufferType.SPANNABLE); - registerNavigationMenu(note); - } + if (waypoint.getCoords() != null) { + coords.setText(Html.fromHtml(waypoint.getCoords().toString()), TextView.BufferType.SPANNABLE); + defaultNavigation.setVisibility(View.VISIBLE); + separator.setVisibility(View.VISIBLE); + } else { + coords.setText(res.getString(R.string.waypoint_unknown_coordinates)); + defaultNavigation.setVisibility(View.GONE); + separator.setVisibility(View.GONE); + } + registerNavigationMenu(coords); - Button buttonEdit = (Button) findViewById(R.id.edit); - buttonEdit.setOnClickListener(new editWaypointListener()); + if (StringUtils.isNotBlank(waypoint.getNote())) { + final TextView note = (TextView) findViewById(R.id.note); + note.setText(Html.fromHtml(waypoint.getNote()), TextView.BufferType.SPANNABLE); + registerNavigationMenu(note); + } - Button buttonDelete = (Button) findViewById(R.id.delete); - if (waypoint.isUserDefined()) { - buttonDelete.setOnClickListener(new deleteWaypointListener()); - buttonDelete.setVisibility(View.VISIBLE); - } + final Button buttonEdit = (Button) findViewById(R.id.edit); + buttonEdit.setOnClickListener(new editWaypointListener()); - if (waitDialog != null) { - waitDialog.dismiss(); - waitDialog = null; - } - } - } catch (Exception e) { - if (waitDialog != null) { - waitDialog.dismiss(); - waitDialog = null; - } - Log.e(Settings.tag, "cgeowaypoint.loadWaypointHandler: " + e.toString()); + if (waypoint.isUserDefined()) { + final Button buttonDelete = (Button) findViewById(R.id.delete); + buttonDelete.setOnClickListener(new deleteWaypointListener()); + buttonDelete.setVisibility(View.VISIBLE); } } @@ -155,10 +141,6 @@ public class cgeowaypoint extends AbstractActivity { return; } - if (geo == null) { - geo = app.startGeo(geoUpdate); - } - waitDialog = ProgressDialog.show(this, null, res.getString(R.string.waypoint_loading), true); waitDialog.setCancelable(true); @@ -178,10 +160,7 @@ public class cgeowaypoint extends AbstractActivity { public void onResume() { super.onResume(); - - if (geo == null) { - geo = app.startGeo(geoUpdate); - } + app.addGeoObserver(this); if (waitDialog == null) { waitDialog = ProgressDialog.show(this, null, res.getString(R.string.waypoint_loading), true); @@ -193,28 +172,17 @@ public class cgeowaypoint extends AbstractActivity { @Override public void onDestroy() { - if (geo != null) { - geo = app.removeGeo(); - } - super.onDestroy(); } @Override public void onStop() { - if (geo != null) { - geo = app.removeGeo(); - } - super.onStop(); } @Override public void onPause() { - if (geo != null) { - geo = app.removeGeo(); - } - + app.deleteGeoObserver(this); super.onPause(); } @@ -249,21 +217,22 @@ public class cgeowaypoint extends AbstractActivity { @Override public boolean onOptionsItemSelected(MenuItem item) { - final int menuItem = item.getItemId(); - if (menuItem == MENU_ID_DEFAULT_NAVIGATION) { - goDefaultNavigation(null); - return true; - } else if (menuItem == MENU_ID_CACHES_AROUND) { - cachesAround(); - return true; - } else if (menuItem == MENU_ID_OPEN_GEOCACHE) { - goToGeocache(); - return true; - } else if (menuItem == MENU_ID_NAVIGATION) { - NavigationAppFactory.showNavigationMenu(geo, this, null, waypoint, null); - return true; + switch (item.getItemId()) { + case MENU_ID_DEFAULT_NAVIGATION: + goDefaultNavigation(null); + return true; + case MENU_ID_CACHES_AROUND: + cachesAround(); + return true; + case MENU_ID_OPEN_GEOCACHE: + goToGeocache(); + return true; + case MENU_ID_NAVIGATION: + NavigationAppFactory.showNavigationMenu(app.currentGeo(), this, null, waypoint, null); + return true; + default: + return false; } - return false; } private void cachesAround() { @@ -295,17 +264,14 @@ public class cgeowaypoint extends AbstractActivity { loadWaypointHandler.sendMessage(Message.obtain()); } catch (Exception e) { - Log.e(Settings.tag, "cgeowaypoint.loadWaypoint.run: " + e.toString()); + Log.e("cgeowaypoint.loadWaypoint.run: " + e.toString()); } } } - private static class update implements UpdateLocationCallback { - - @Override - public void updateLocation(cgGeo geo) { - // nothing - } + @Override + public void update(final IGeoData geo) { + // nothing } private class editWaypointListener implements View.OnClickListener { @@ -328,7 +294,6 @@ public class cgeowaypoint extends AbstractActivity { StaticMapsProvider.removeWpStaticMaps(id, geocode); finish(); - return; } else { showToast(res.getString(R.string.err_waypoint_delete_failed)); } @@ -344,7 +309,7 @@ public class cgeowaypoint extends AbstractActivity { return; } - NavigationAppFactory.startDefaultNavigationApplication(geo, this, null, waypoint, null); + NavigationAppFactory.startDefaultNavigationApplication(app.currentGeo(), this, null, waypoint, null); } /** @@ -355,7 +320,7 @@ public class cgeowaypoint extends AbstractActivity { return; } - NavigationAppFactory.startDefaultNavigationApplication2(geo, this, null, waypoint, null); + NavigationAppFactory.startDefaultNavigationApplication2(app.currentGeo(), this, null, waypoint, null); } private boolean navigationPossible() { @@ -381,6 +346,12 @@ public class cgeowaypoint extends AbstractActivity { if (handled) { return true; } - return NavigationAppFactory.onMenuItemSelected(item, geo, this, null, waypoint, null); + return NavigationAppFactory.onMenuItemSelected(item, app.currentGeo(), this, null, waypoint, null); + } + + public static void startActivity(final Context context, final int waypointId) { + Intent popupIntent = new Intent(context, cgeowaypoint.class); + popupIntent.putExtra("waypoint", waypointId); + context.startActivity(popupIntent); } } diff --git a/main/src/cgeo/geocaching/cgeowaypointadd.java b/main/src/cgeo/geocaching/cgeowaypointadd.java index 9c00241..9c02eef 100644 --- a/main/src/cgeo/geocaching/cgeowaypointadd.java +++ b/main/src/cgeo/geocaching/cgeowaypointadd.java @@ -8,7 +8,9 @@ import cgeo.geocaching.enumerations.WaypointType; import cgeo.geocaching.geopoint.DistanceParser; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.geopoint.GeopointFormatter; -import cgeo.geocaching.geopoint.GeopointParser; +import cgeo.geocaching.utils.BaseUtils; +import cgeo.geocaching.utils.IObserver; +import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; @@ -17,7 +19,6 @@ import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.text.Html; -import android.util.Log; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemSelectedListener; @@ -31,12 +32,10 @@ import java.util.ArrayList; import java.util.EnumSet; import java.util.List; -public class cgeowaypointadd extends AbstractActivity { +public class cgeowaypointadd extends AbstractActivity implements IObserver<IGeoData> { private String geocode = null; private int id = -1; - private cgGeo geo = null; - private UpdateLocationCallback geoUpdate = new update(); private ProgressDialog waitDialog = null; private cgWaypoint waypoint = null; private Geopoint gpTemp = null; @@ -72,7 +71,12 @@ public class cgeowaypointadd extends AbstractActivity { ((Button) findViewById(R.id.buttonLongitude)).setText(waypoint.getCoords().format(GeopointFormatter.Format.LON_DECMINUTE)); } ((EditText) findViewById(R.id.name)).setText(Html.fromHtml(StringUtils.trimToEmpty(waypoint.getName())).toString()); - ((EditText) findViewById(R.id.note)).setText(Html.fromHtml(StringUtils.trimToEmpty(waypoint.getNote())).toString()); + if (BaseUtils.containsHtml(waypoint.getNote())) { + ((EditText) findViewById(R.id.note)).setText(Html.fromHtml(StringUtils.trimToEmpty(waypoint.getNote())).toString()); + } + else { + ((EditText) findViewById(R.id.note)).setText(StringUtils.trimToEmpty(waypoint.getNote())); + } } if (own) { @@ -81,7 +85,7 @@ public class cgeowaypointadd extends AbstractActivity { initializeDistanceUnitSelector(); } catch (Exception e) { - Log.e(Settings.tag, "cgeowaypointadd.loadWaypointHandler: " + e.toString()); + Log.e("cgeowaypointadd.loadWaypointHandler: " + e.toString()); } finally { if (waitDialog != null) { waitDialog.dismiss(); @@ -99,10 +103,6 @@ public class cgeowaypointadd extends AbstractActivity { setContentView(R.layout.waypoint_new); setTitle("waypoint"); - if (geo == null) { - geo = app.startGeo(geoUpdate); - } - // get parameters Bundle extras = getIntent().getExtras(); if (extras != null) { @@ -136,7 +136,10 @@ public class cgeowaypointadd extends AbstractActivity { Button addWaypoint = (Button) findViewById(R.id.add_waypoint); addWaypoint.setOnClickListener(new coordsListener()); - List<String> wayPointNames = new ArrayList<String>(WaypointType.ALL_TYPES_EXCEPT_OWN.values()); + List<String> wayPointNames = new ArrayList<String>(); + for (WaypointType wpt : WaypointType.ALL_TYPES_EXCEPT_OWN) { + wayPointNames.add(wpt.getL10n()); + } AutoCompleteTextView textView = (AutoCompleteTextView) findViewById(R.id.name); ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line, wayPointNames); textView.setAdapter(adapter); @@ -162,10 +165,7 @@ public class cgeowaypointadd extends AbstractActivity { public void onResume() { super.onResume(); - - if (geo == null) { - geo = app.startGeo(geoUpdate); - } + app.addGeoObserver(this); if (id > 0) { if (waitDialog == null) { @@ -179,28 +179,17 @@ public class cgeowaypointadd extends AbstractActivity { @Override public void onDestroy() { - if (geo != null) { - geo = app.removeGeo(); - } - super.onDestroy(); } @Override public void onStop() { - if (geo != null) { - geo = app.removeGeo(); - } - super.onStop(); } @Override public void onPause() { - if (geo != null) { - geo = app.removeGeo(); - } - + app.deleteGeoObserver(this); super.onPause(); } @@ -208,7 +197,7 @@ public class cgeowaypointadd extends AbstractActivity { Spinner waypointTypeSelector = (Spinner) findViewById(R.id.type); - wpTypes = new ArrayList<WaypointType>(WaypointType.ALL_TYPES_EXCEPT_OWN.keySet()); + wpTypes = new ArrayList<WaypointType>(WaypointType.ALL_TYPES_EXCEPT_OWN); ArrayAdapter<WaypointType> wpAdapter = new ArrayAdapter<WaypointType>(this, android.R.layout.simple_spinner_item, wpTypes.toArray(new WaypointType[wpTypes.size()])); wpAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); waypointTypeSelector.setAdapter(wpAdapter); @@ -241,23 +230,20 @@ public class cgeowaypointadd extends AbstractActivity { distanceUnitSelector.setOnItemSelectedListener(new changeDistanceUnit(this)); } - private class update implements UpdateLocationCallback { - - @Override - public void updateLocation(cgGeo geo) { - Log.d(Settings.tag, "cgeowaypointadd.updateLocation called"); - if (geo == null || geo.coordsNow == null) { - return; - } + @Override + public void update(final IGeoData geo) { + Log.d("cgeowaypointadd.updateLocation called"); + if (geo.getCoords() == null) { + return; + } - try { - Button bLat = (Button) findViewById(R.id.buttonLatitude); - Button bLon = (Button) findViewById(R.id.buttonLongitude); - bLat.setHint(geo.coordsNow.format(GeopointFormatter.Format.LAT_DECMINUTE_RAW)); - bLon.setHint(geo.coordsNow.format(GeopointFormatter.Format.LON_DECMINUTE_RAW)); - } catch (Exception e) { - Log.w(Settings.tag, "Failed to update location."); - } + try { + Button bLat = (Button) findViewById(R.id.buttonLatitude); + Button bLon = (Button) findViewById(R.id.buttonLongitude); + bLat.setHint(geo.getCoords().format(GeopointFormatter.Format.LAT_DECMINUTE_RAW)); + bLon.setHint(geo.getCoords().format(GeopointFormatter.Format.LON_DECMINUTE_RAW)); + } catch (Exception e) { + Log.w("Failed to update location."); } } @@ -270,7 +256,7 @@ public class cgeowaypointadd extends AbstractActivity { loadWaypointHandler.sendMessage(Message.obtain()); } catch (Exception e) { - Log.e(Settings.tag, "cgeowaypoint.loadWaypoint.run: " + e.toString()); + Log.e("cgeowaypoint.loadWaypoint.run: " + e.toString()); } } } @@ -285,7 +271,7 @@ public class cgeowaypointadd extends AbstractActivity { gp = gpTemp; } cgCache cache = app.loadCache(geocode, LoadFlags.LOAD_WAYPOINTS); - cgeocoords coordsDialog = new cgeocoords(cgeowaypointadd.this, cache, gp, geo); + cgeocoords coordsDialog = new cgeocoords(cgeowaypointadd.this, cache, gp, app.currentGeo()); coordsDialog.setCancelable(true); coordsDialog.setOnCoordinateUpdate(new cgeocoords.CoordinateUpdate() { @Override @@ -361,31 +347,27 @@ public class cgeowaypointadd extends AbstractActivity { return; } - double latitude; - double longitude; + Geopoint coords; if (StringUtils.isNotBlank(latText) && StringUtils.isNotBlank(lonText)) { try { - latitude = GeopointParser.parseLatitude(latText); - longitude = GeopointParser.parseLongitude(lonText); - } catch (GeopointParser.ParseException e) { + coords = new Geopoint(latText, lonText); + } catch (Geopoint.ParseException e) { showToast(res.getString(e.resource)); return; } } else { - if (geo == null || geo.coordsNow == null) { + final IGeoData geo = app.currentGeo(); + if (geo.getCoords() == null) { showToast(res.getString(R.string.err_point_curr_position_unavailable)); return; } - - latitude = geo.coordsNow.getLatitude(); - longitude = geo.coordsNow.getLongitude(); + coords = geo.getCoords(); } - Geopoint coords = null; if (StringUtils.isNotBlank(bearingText) && StringUtils.isNotBlank(distanceText)) { // bearing & distance - double bearing = 0; + double bearing; try { bearing = Double.parseDouble(bearingText); } catch (NumberFormatException e) { @@ -401,9 +383,7 @@ public class cgeowaypointadd extends AbstractActivity { return; } - coords = new Geopoint(latitude, longitude).project(bearing, distance); - } else { - coords = new Geopoint(latitude, longitude); + coords = coords.project(bearing, distance); } String name = ((EditText) findViewById(R.id.name)).getText().toString().trim(); @@ -429,7 +409,6 @@ public class cgeowaypointadd extends AbstractActivity { StaticMapsProvider.storeWaypointStaticMap(cache, cgeowaypointadd.this, waypoint, false); } finish(); - return; } else { showToast(res.getString(R.string.err_waypoint_add_failed)); } diff --git a/main/src/cgeo/geocaching/compatibility/AndroidLevel8.java b/main/src/cgeo/geocaching/compatibility/AndroidLevel8.java index 6d01e55..0fc9624 100644 --- a/main/src/cgeo/geocaching/compatibility/AndroidLevel8.java +++ b/main/src/cgeo/geocaching/compatibility/AndroidLevel8.java @@ -1,10 +1,9 @@ package cgeo.geocaching.compatibility; -import cgeo.geocaching.Settings; +import cgeo.geocaching.utils.Log; import android.app.Activity; import android.app.backup.BackupManager; -import android.util.Log; import android.view.Display; public class AndroidLevel8 implements AndroidLevel8Interface { @@ -15,7 +14,7 @@ public class AndroidLevel8 implements AndroidLevel8Interface { } public void dataChanged(final String name) { - Log.i(Settings.tag, "Requesting settings backup with settings manager"); + Log.i("Requesting settings backup with settings manager"); BackupManager.dataChanged(name); } } diff --git a/main/src/cgeo/geocaching/compatibility/Compatibility.java b/main/src/cgeo/geocaching/compatibility/Compatibility.java index 344ff6a..6086604 100644 --- a/main/src/cgeo/geocaching/compatibility/Compatibility.java +++ b/main/src/cgeo/geocaching/compatibility/Compatibility.java @@ -1,7 +1,9 @@ package cgeo.geocaching.compatibility; -import cgeo.geocaching.Settings; import cgeo.geocaching.activity.AbstractActivity; +import cgeo.geocaching.utils.Log; + +import org.apache.commons.lang3.reflect.MethodUtils; import android.app.Activity; import android.content.Intent; @@ -9,13 +11,10 @@ import android.content.res.Configuration; import android.net.Uri; import android.os.Build; import android.text.InputType; -import android.util.Log; import android.view.Display; import android.view.Surface; import android.widget.EditText; -import java.lang.reflect.Method; - public final class Compatibility { private final static int sdkVersion = Integer.parseInt(Build.VERSION.SDK); @@ -25,16 +24,7 @@ public final class Compatibility { private final static AndroidLevel8Interface level8; private final static AndroidLevel11Interface level11; - private static Method overridePendingTransitionMethod = null; - static { - if (isLevel5) { - try { - overridePendingTransitionMethod = Activity.class.getMethod("overridePendingTransition", Integer.TYPE, Integer.TYPE); - } catch (Exception e) { - Log.e(Settings.tag, "cannot get overridePendingTransition", e); - } - } if (isLevel8) { level8 = new AndroidLevel8(); } @@ -63,7 +53,7 @@ public final class Compatibility { } } catch (final Exception e) { // This should never happen: IllegalArgumentException, IllegalAccessException or InvocationTargetException - Log.e(Settings.tag, "Cannot call getRotation()", e); + Log.e("Cannot call getRotation()", e); } } else { final Display display = activity.getWindowManager() @@ -102,9 +92,9 @@ public final class Compatibility { private static void overridePendingTransition(final Activity activity, int enterAnim, int exitAnim) { try { - overridePendingTransitionMethod.invoke(activity, enterAnim, exitAnim); + MethodUtils.invokeMethod(activity, "overridePendingTransition", enterAnim, exitAnim); } catch (Exception e) { - Log.e(Settings.tag, "cannot call overridePendingTransition", e); + Log.e("cannot call overridePendingTransition", e); } } diff --git a/main/src/cgeo/geocaching/concurrent/Task.java b/main/src/cgeo/geocaching/concurrent/Task.java deleted file mode 100644 index 2472538..0000000 --- a/main/src/cgeo/geocaching/concurrent/Task.java +++ /dev/null @@ -1,16 +0,0 @@ -package cgeo.geocaching.concurrent; - -/** - * Basic class for Runnables added to ThreadPool. - */ -public abstract class Task implements Runnable { - private String name = null; - - public Task(String name) { - this.name = name; - } - - public String getName() { - return this.name; - } -} diff --git a/main/src/cgeo/geocaching/connector/OXConnector.java b/main/src/cgeo/geocaching/connector/OXConnector.java index 755dbaa..cfde92f 100644 --- a/main/src/cgeo/geocaching/connector/OXConnector.java +++ b/main/src/cgeo/geocaching/connector/OXConnector.java @@ -32,4 +32,10 @@ public class OXConnector extends AbstractConnector { return "www.opencaching.com"; } + @Override + public String getLicenseText(cgCache cache) { + // NOT TO BE TRANSLATED + return "<a href=\"" + getCacheUrl(cache) + "\">" + getName() + "</a> data licensed under the Creative Commons BY-SA 3.0 License"; + } + } diff --git a/main/src/cgeo/geocaching/connector/gc/GCBase.java b/main/src/cgeo/geocaching/connector/gc/GCBase.java index 7c56583..d7f6241 100644 --- a/main/src/cgeo/geocaching/connector/gc/GCBase.java +++ b/main/src/cgeo/geocaching/connector/gc/GCBase.java @@ -1,8 +1,8 @@ package cgeo.geocaching.connector.gc; +import cgeo.geocaching.ICoordinates; import cgeo.geocaching.SearchResult; import cgeo.geocaching.Settings; -import cgeo.geocaching.cgBase; import cgeo.geocaching.cgCache; import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.enumerations.CacheSize; @@ -13,11 +13,12 @@ import cgeo.geocaching.enumerations.StatusCode; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.geopoint.IConversion; import cgeo.geocaching.geopoint.Viewport; -import cgeo.geocaching.network.Login; import cgeo.geocaching.network.Network; +import cgeo.geocaching.network.Parameters; import cgeo.geocaching.ui.Formatter; import cgeo.geocaching.utils.BaseUtils; -import cgeo.geocaching.utils.LeastRecentlyUsedCache; +import cgeo.geocaching.utils.LeastRecentlyUsedMap; +import cgeo.geocaching.utils.Log; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -27,10 +28,10 @@ import org.json.JSONException; import org.json.JSONObject; import android.graphics.Bitmap; -import android.util.Log; import java.text.ParseException; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -52,6 +53,9 @@ public class GCBase { protected final static long GC_BASE31 = 31; protected final static long GC_BASE16 = 16; + private final static LeastRecentlyUsedMap<Integer, Tile> tileCache = new LeastRecentlyUsedMap.LruCache<Integer, Tile>(64); + private static Viewport lastSearchViewport = null; + /** * Searches the view port on the live map with Strategy.AUTO * @@ -64,7 +68,7 @@ public class GCBase { public static SearchResult searchByViewport(final Viewport viewport, final String[] tokens) { Strategy strategy = Settings.getLiveMapStrategy(); if (strategy == Strategy.AUTO) { - float speedNow = cgeoapplication.getInstance().getSpeedFromGeo(); + float speedNow = cgeoapplication.getInstance().currentGeo().getSpeed(); strategy = speedNow >= 8 ? Strategy.FAST : Strategy.DETAILED; // 8 m/s = 30 km/h } // return searchByViewport(viewport, tokens, strategy); @@ -73,7 +77,7 @@ public class GCBase { { SearchResult result = searchByViewport(viewport, tokens, strategy); String text = Formatter.SEPARATOR + strategy.getL10n() + Formatter.SEPARATOR; - int speed = (int) cgeoapplication.getInstance().getSpeedFromGeo(); + int speed = (int) cgeoapplication.getInstance().currentGeo().getSpeed(); if (Settings.isUseMetricUnits()) { text += speed + " km/h"; } else { @@ -84,6 +88,17 @@ public class GCBase { } } + public static void removeFromTileCache(final ICoordinates point) { + if (point != null) { + Collection<Tile> tiles = new ArrayList<Tile>(tileCache.values()); + for (Tile tile : tiles) { + if (tile.containsPoint(point)) { + tileCache.remove(tile.hashCode()); + } + } + } + } + /** * Searches the view port on the live map for caches. * The strategy dictates if only live map information is used or if an additional @@ -98,7 +113,7 @@ public class GCBase { * @return */ private static SearchResult searchByViewport(final Viewport viewport, final String[] tokens, Strategy strategy) { - Log.d(Settings.tag, "GCBase.searchByViewport" + viewport.toString()); + Log.d("GCBase.searchByViewport" + viewport.toString()); String referer = GCConstants.URL_LIVE_MAP; @@ -110,58 +125,76 @@ public class GCBase { for (Tile tile : tiles) { - StringBuilder url = new StringBuilder(); - url.append("?x=").append(tile.getX()) // x tile - .append("&y=").append(tile.getY()) // y tile - .append("&z=").append(tile.getZoomlevel()); // zoom level - if (tokens != null) { - url.append("&k=").append(tokens[0]); // user session - url.append("&st=").append(tokens[1]); // session token - } - url.append("&ep=1"); - if (Settings.isExcludeMyCaches()) { - url.append("&hf=1").append("&hh=1"); // hide found, hide hidden - } - if (Settings.getCacheType() == CacheType.TRADITIONAL) { - url.append("&ect=9,5,3,6,453,13,1304,137,11,4,8,1858"); // 2 = tradi 3 = multi 8 = mystery - } - if (Settings.getCacheType() == CacheType.MULTI) { - url.append("&ect=9,5,2,6,453,13,1304,137,11,4,8,1858"); - } - if (Settings.getCacheType() == CacheType.MYSTERY) { - url.append("&ect=9,5,3,6,453,13,1304,137,11,4,2,1858"); - } - if (tile.getZoomlevel() != 14) { - url.append("&_=").append(String.valueOf(System.currentTimeMillis())); - } - // other types t.b.d - final String urlString = url.toString(); + if (!tileCache.containsKey(tile.hashCode())) { + final Parameters params = new Parameters( + "x", String.valueOf(tile.getX()), + "y", String.valueOf(tile.getY()), + "z", String.valueOf(tile.getZoomlevel()), + "ep", "1"); + if (tokens != null) { + params.put("k", tokens[0], "st", tokens[1]); + } + if (Settings.isExcludeMyCaches()) { + params.put("hf", "1", "hh", "1"); // hide found, hide hidden + } + if (Settings.getCacheType() == CacheType.TRADITIONAL) { + params.put("ect", "9,5,3,6,453,13,1304,137,11,4,8,1858"); // 2 = tradi 3 = multi 8 = mystery + } else if (Settings.getCacheType() == CacheType.MULTI) { + params.put("ect", "9,5,2,6,453,13,1304,137,11,4,8,1858"); + } else if (Settings.getCacheType() == CacheType.MYSTERY) { + params.put("ect", "9,5,3,6,453,13,1304,137,11,4,2,1858"); + } + if (tile.getZoomlevel() != 14) { + params.put("_", String.valueOf(System.currentTimeMillis())); + } + // TODO: other types t.b.d - // The PNG must be request before ! Else the following request would return with 204 - No Content - Bitmap bitmap = Tile.requestMapTile(GCConstants.URL_MAP_TILE + urlString, referer); + // The PNG must be requested first, otherwise the following request would always return with 204 - No Content + Bitmap bitmap = Tile.requestMapTile(GCConstants.URL_MAP_TILE, params, referer); - assert bitmap.getWidth() == Tile.TILE_SIZE : "Bitmap has wrong width"; - assert bitmap.getHeight() == Tile.TILE_SIZE : "Bitmap has wrong height"; + // Check bitmap size + if (bitmap != null && (bitmap.getWidth() != Tile.TILE_SIZE || + bitmap.getHeight() != Tile.TILE_SIZE)) { + bitmap.recycle(); + bitmap = null; + } - String data = Tile.requestMapInfo(GCConstants.URL_MAP_INFO + urlString, referer); - if (StringUtils.isEmpty(data)) { - Log.e(Settings.tag, "GCBase.searchByViewport: No data from server for tile (" + tile.getX() + "/" + tile.getY() + ")"); - } else { - final SearchResult search = parseMapJSON(data, tile, bitmap, strategy); - if (search == null || CollectionUtils.isEmpty(search.getGeocodes())) { - Log.e(Settings.tag, "GCBase.searchByViewport: No cache parsed for viewport " + viewport); + String data = Tile.requestMapInfo(GCConstants.URL_MAP_INFO, params, referer); + if (StringUtils.isEmpty(data)) { + Log.e("GCBase.searchByViewport: No data from server for tile (" + tile.getX() + "/" + tile.getY() + ")"); + } else { + final SearchResult search = parseMapJSON(data, tile, bitmap, strategy); + if (search == null || CollectionUtils.isEmpty(search.getGeocodes())) { + Log.e("GCBase.searchByViewport: No cache parsed for viewport " + viewport); + } + else { + searchResult.addGeocodes(search.getGeocodes()); + } + tileCache.put(tile.hashCode(), tile); } - else { - searchResult.addGeocodes(search.getGeocodes()); + + // release native bitmap memory + if (bitmap != null) { + bitmap.recycle(); } + } } } if (strategy.flags.contains(StrategyFlag.SEARCH_NEARBY)) { - SearchResult search = cgBase.searchByCoords(null, viewport.getCenter(), Settings.getCacheType(), false); - if (search != null) { - searchResult.addGeocodes(search.getGeocodes()); + final Geopoint center = viewport.getCenter(); + if ((lastSearchViewport == null) || !lastSearchViewport.contains(center)) { + SearchResult search = GCParser.searchByCoords(null, center, Settings.getCacheType(), false); + if (search != null && !search.isEmpty()) { + final Set<String> geocodes = search.getGeocodes(); + if (Settings.isPremiumMember()) { + lastSearchViewport = cgeoapplication.getInstance().getBounds(geocodes); + } else { + lastSearchViewport = new Viewport(center, 0.01, 0.01); + } + searchResult.addGeocodes(geocodes); + } } } @@ -180,7 +213,7 @@ public class GCBase { try { - final LeastRecentlyUsedCache<String, String> nameCache = new LeastRecentlyUsedCache<String, String>(2000); // JSON id, cache name + final LeastRecentlyUsedMap<String, String> nameCache = new LeastRecentlyUsedMap.LruCache<String, String>(2000); // JSON id, cache name if (StringUtils.isEmpty(data)) { throw new JSONException("No page given"); @@ -265,7 +298,7 @@ public class GCBase { cache.setName(nameCache.get(id)); cache.setZoomlevel(tile.getZoomlevel()); cache.setCoords(tile.getCoord(xy)); - if (strategy.flags.contains(StrategyFlag.PARSE_TILES) && positions.size() < 64) { + if (strategy.flags.contains(StrategyFlag.PARSE_TILES) && positions.size() < 64 && bitmap != null) { // don't parse if there are too many caches. The decoding would return too much wrong results IconDecoder.parseMapPNG(cache, bitmap, xy, tile.getZoomlevel()); } else { @@ -273,10 +306,10 @@ public class GCBase { } searchResult.addCache(cache); } - Log.d(Settings.tag, "Retrieved " + searchResult.getCount() + " caches for tile " + tile.toString()); + Log.d("Retrieved " + searchResult.getCount() + " caches for tile " + tile.toString()); } catch (Exception e) { - Log.e(Settings.tag, "GCBase.parseMapJSON", e); + Log.e("GCBase.parseMapJSON", e); } return searchResult; @@ -325,65 +358,9 @@ public class GCBase { return gcid; } - private static String modulo(final long value, final long base, final String sequence) { - String result = ""; - long rest = 0; - long divResult = value; - do - { - rest = divResult % base; - divResult = (int) Math.floor(divResult / base); - result = sequence.charAt((int) rest) + result; - } while (divResult != 0); - return result; - } - - /** - * Convert (old) GCIds to GCCode (geocode) - * - * Based on http://www.geoclub.de/viewtopic.php?f=111&t=54859&start=40 - */ - public static String gcidToGCCode(final long gcid) { - String gccode = modulo(gcid + 411120, GC_BASE31, SEQUENCE_GCID); - if ((gccode.length() < 4) || (gccode.length() == 4 && SEQUENCE_GCID.indexOf(gccode.charAt(0)) < 16)) { - gccode = modulo(gcid, GC_BASE16, SEQUENCE_GCID); - } - return "GC" + gccode; - } - - /** - * Convert ids from the live map to (old) GCIds - * - * Based on http://www.geoclub.de/viewtopic.php?f=111&t=54859&start=40 - */ - public static long newidToGCId(final String newid) { - long gcid = 0; - for (int p = 0; p < newid.length(); p++) { - gcid = GC_BASE57 * gcid + SEQUENCE_NEWID.indexOf(newid.charAt(p)); - } - return gcid; - } - - /** - * Convert (old) GCIds to ids used in the live map - * - * Based on http://www.geoclub.de/viewtopic.php?f=111&t=54859&start=40 - */ - public static String gcidToNewId(final long gcid) { - return modulo(gcid, GC_BASE57, SEQUENCE_NEWID); - } - - /** - * Convert ids from the live map into GCCode (geocode) - */ - public static String newidToGeocode(final String newid) { - long gcid = GCBase.newidToGCId(newid); - return GCBase.gcidToGCCode(gcid); - } - /** Get user session & session token from the Live Map. Needed for following requests */ public static String[] getTokens() { - final HttpResponse response = Network.request(GCConstants.URL_LIVE_MAP, null, false); + final HttpResponse response = Network.getRequest(GCConstants.URL_LIVE_MAP); final String data = Network.getResponseData(response); String userSession = BaseUtils.getMatch(data, GCConstants.PATTERN_USERSESSION, ""); String sessionToken = BaseUtils.getMatch(data, GCConstants.PATTERN_SESSIONTOKEN, ""); @@ -392,18 +369,14 @@ public class GCBase { public static SearchResult searchByGeocodes(final Set<String> geocodes) { - SearchResult result = new SearchResult(); + final SearchResult result = new SearchResult(); final String geocodeList = StringUtils.join(geocodes.toArray(), "|"); - - String referer = GCConstants.URL_LIVE_MAP_DETAILS; - - StringBuilder url = new StringBuilder(); - url.append("?i=").append(geocodeList).append("&_=").append(String.valueOf(System.currentTimeMillis())); - final String urlString = url.toString(); + final String referer = GCConstants.URL_LIVE_MAP_DETAILS; try { - String data = Tile.requestMapInfo(referer + urlString, referer); + final Parameters params = new Parameters("i", geocodeList, "_", String.valueOf(System.currentTimeMillis())); + final String data = StringUtils.defaultString(Tile.requestMapInfo(referer, params, referer)); // Example JSON information // {"status":"success", diff --git a/main/src/cgeo/geocaching/connector/gc/GCConnector.java b/main/src/cgeo/geocaching/connector/gc/GCConnector.java index 1c57508..b461cc2 100644 --- a/main/src/cgeo/geocaching/connector/gc/GCConnector.java +++ b/main/src/cgeo/geocaching/connector/gc/GCConnector.java @@ -3,21 +3,18 @@ package cgeo.geocaching.connector.gc; import cgeo.geocaching.R; import cgeo.geocaching.SearchResult; import cgeo.geocaching.Settings; -import cgeo.geocaching.cgBase; import cgeo.geocaching.cgCache; import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.connector.AbstractConnector; import cgeo.geocaching.enumerations.StatusCode; import cgeo.geocaching.geopoint.Viewport; -import cgeo.geocaching.network.Network; import cgeo.geocaching.network.Parameters; import cgeo.geocaching.utils.CancellableHandler; +import cgeo.geocaching.utils.Log; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; -import android.util.Log; - import java.util.Set; import java.util.regex.Pattern; @@ -90,7 +87,7 @@ public class GCConnector extends AbstractConnector { public SearchResult searchByGeocode(final String geocode, final String guid, final cgeoapplication app, final CancellableHandler handler) { if (app == null) { - Log.e(Settings.tag, "cgeoBase.searchByGeocode: No application found"); + Log.e("cgeoBase.searchByGeocode: No application found"); return null; } @@ -103,39 +100,37 @@ public class GCConnector extends AbstractConnector { params.put("log", "y"); params.put("numlogs", String.valueOf(GCConstants.NUMBER_OF_LOGS)); - cgBase.sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_loadpage); + CancellableHandler.sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_loadpage); - final String page = Network.requestLogged("http://www.geocaching.com/seek/cache_details.aspx", params, false, false, false); + final String page = Login.getRequestLogged("http://www.geocaching.com/seek/cache_details.aspx", params); if (StringUtils.isEmpty(page)) { final SearchResult search = new SearchResult(); if (app.isThere(geocode, guid, true, false)) { if (StringUtils.isBlank(geocode) && StringUtils.isNotBlank(guid)) { - Log.i(Settings.tag, "Loading old cache from cache."); + Log.i("Loading old cache from cache."); search.addGeocode(app.getGeocode(guid)); } else { search.addGeocode(geocode); } - search.error = StatusCode.NO_ERROR; + search.setError(StatusCode.NO_ERROR); return search; } - Log.e(Settings.tag, "cgeoBase.searchByGeocode: No data from server"); - search.error = StatusCode.COMMUNICATION_ERROR; + Log.e("cgeoBase.searchByGeocode: No data from server"); + search.setError(StatusCode.COMMUNICATION_ERROR); return search; } - final SearchResult searchResult = cgBase.parseCache(page, handler); + final SearchResult searchResult = GCParser.parseCache(page, handler); if (searchResult == null || CollectionUtils.isEmpty(searchResult.getGeocodes())) { - Log.e(Settings.tag, "cgeoBase.searchByGeocode: No cache parsed"); + Log.e("cgeoBase.searchByGeocode: No cache parsed"); return searchResult; } - final SearchResult search = searchResult.filterSearchResults(false, false, Settings.getCacheType()); - - return search; + return searchResult.filterSearchResults(false, false, Settings.getCacheType()); } @Override diff --git a/main/src/cgeo/geocaching/cgBase.java b/main/src/cgeo/geocaching/connector/gc/GCParser.java index 0d39608..e0cb70f 100644 --- a/main/src/cgeo/geocaching/cgBase.java +++ b/main/src/cgeo/geocaching/connector/gc/GCParser.java @@ -1,14 +1,19 @@ -// $codepro.audit.disable logExceptions -package cgeo.geocaching; - -import cgeo.geocaching.activity.ActivityMixin; -import cgeo.geocaching.connector.ConnectorFactory; -import cgeo.geocaching.connector.gc.GCConnector; -import cgeo.geocaching.connector.gc.GCConstants; +package cgeo.geocaching.connector.gc; + +import cgeo.geocaching.LogEntry; +import cgeo.geocaching.R; +import cgeo.geocaching.SearchResult; +import cgeo.geocaching.Settings; +import cgeo.geocaching.TrackableLog; +import cgeo.geocaching.cgCache; +import cgeo.geocaching.cgImage; +import cgeo.geocaching.cgSearchThread; +import cgeo.geocaching.cgTrackable; +import cgeo.geocaching.cgWaypoint; +import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.enumerations.CacheSize; import cgeo.geocaching.enumerations.CacheType; import cgeo.geocaching.enumerations.LoadFlags; -import cgeo.geocaching.enumerations.LoadFlags.RemoveFlag; import cgeo.geocaching.enumerations.LoadFlags.SaveFlag; import cgeo.geocaching.enumerations.LogType; import cgeo.geocaching.enumerations.LogTypeTrackable; @@ -19,13 +24,12 @@ import cgeo.geocaching.gcvote.GCVote; import cgeo.geocaching.gcvote.GCVoteRating; import cgeo.geocaching.geopoint.DistanceParser; import cgeo.geocaching.geopoint.Geopoint; -import cgeo.geocaching.network.HtmlImage; -import cgeo.geocaching.network.Login; import cgeo.geocaching.network.Network; import cgeo.geocaching.network.Parameters; import cgeo.geocaching.ui.DirectionImage; import cgeo.geocaching.utils.BaseUtils; import cgeo.geocaching.utils.CancellableHandler; +import cgeo.geocaching.utils.Log; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.ArrayUtils; @@ -35,101 +39,35 @@ import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; -import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.content.res.Resources; import android.net.Uri; -import android.os.Handler; -import android.os.Message; import android.text.Html; import android.text.Spannable; import android.text.Spanned; -import android.text.format.DateUtils; import android.text.style.StrikethroughSpan; -import android.util.Log; import java.net.URLDecoder; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; +import java.util.Collections; import java.util.EnumSet; import java.util.List; import java.util.Locale; import java.util.Set; import java.util.regex.Matcher; -public class cgBase { - +public abstract class GCParser { private final static SimpleDateFormat dateTbIn1 = new SimpleDateFormat("EEEEE, dd MMMMM yyyy", Locale.ENGLISH); // Saturday, 28 March 2009 private final static SimpleDateFormat dateTbIn2 = new SimpleDateFormat("EEEEE, MMMMM dd, yyyy", Locale.ENGLISH); // Saturday, March 28, 2009 - public static String version = null; - - private static Context context; - public static Resources res; - - public static final int UPDATE_LOAD_PROGRESS_DETAIL = 42186; - - private cgBase() { - //initialize(app); - throw new UnsupportedOperationException(); // static class, not to be instantiated - } - - /** - * Called from AbstractActivity.onCreate() and AbstractListActivity.onCreate() - * - * @param app - */ - public static void initialize(final cgeoapplication app) { - context = app.getBaseContext(); - res = app.getBaseContext().getResources(); - - try { - final PackageManager manager = app.getPackageManager(); - final PackageInfo info = manager.getPackageInfo(app.getPackageName(), 0); - version = info.versionName; - } catch (PackageManager.NameNotFoundException e) { - Log.e(Settings.tag, "unable to get version information", e); - version = null; - } - } - - public static void sendLoadProgressDetail(final Handler handler, final int str) { - if (null != handler) { - handler.obtainMessage(UPDATE_LOAD_PROGRESS_DETAIL, cgeoapplication.getInstance().getString(str)).sendToTarget(); - } - } - - /** - * checks if an Array of Strings is empty or not. Empty means: - * - Array is null - * - or all elements are null or empty strings - */ - public static boolean isEmpty(String[] a) { - if (a == null) { - return true; - } - - for (String s : a) { - if (StringUtils.isNotEmpty(s)) { - return false; - } - } - return true; - } private static SearchResult parseSearch(final cgSearchThread thread, final String url, final String pageContent, final boolean showCaptcha) { if (StringUtils.isBlank(pageContent)) { - Log.e(Settings.tag, "cgeoBase.parseSearch: No page given"); + Log.e("cgeoBase.parseSearch: No page given"); return null; } final List<String> cids = new ArrayList<String>(); - final List<String> guids = new ArrayList<String>(); String recaptchaChallenge = null; String recaptchaText = null; String page = pageContent; @@ -144,7 +82,7 @@ public class cgBase { if (recaptchaJsParam != null) { final Parameters params = new Parameters("k", recaptchaJsParam.trim()); - final String recaptchaJs = Network.getResponseData(Network.request("http://www.google.com/recaptcha/api/challenge", params, true)); + final String recaptchaJs = Network.getResponseData(Network.getRequest("http://www.google.com/recaptcha/api/challenge", params)); if (StringUtils.isNotBlank(recaptchaJs)) { recaptchaChallenge = BaseUtils.getMatch(recaptchaJs, GCConstants.PATTERN_SEARCH_RECAPTCHACHALLENGE, true, 1, null, true); @@ -163,7 +101,7 @@ public class cgBase { int startPos = page.indexOf("<div id=\"ctl00_ContentBody_ResultsPanel\""); if (startPos == -1) { - Log.e(Settings.tag, "cgeoBase.parseSearch: ID \"ctl00_ContentBody_dlResults\" not found on page"); + Log.e("cgeoBase.parseSearch: ID \"ctl00_ContentBody_dlResults\" not found on page"); return null; } @@ -172,7 +110,7 @@ public class cgBase { startPos = page.indexOf('>'); int endPos = page.indexOf("ctl00_ContentBody_UnitTxt"); if (startPos == -1 || endPos == -1) { - Log.e(Settings.tag, "cgeoBase.parseSearch: ID \"ctl00_ContentBody_UnitTxt\" not found on page"); + Log.e("cgeoBase.parseSearch: ID \"ctl00_ContentBody_UnitTxt\" not found on page"); return null; } @@ -195,8 +133,6 @@ public class cgBase { while (matcherGuidAndDisabled.find()) { if (matcherGuidAndDisabled.groupCount() > 0) { - guids.add(matcherGuidAndDisabled.group(1)); - cache.setGuid(matcherGuidAndDisabled.group(1)); if (matcherGuidAndDisabled.group(4) != null) { cache.setName(Html.fromHtml(matcherGuidAndDisabled.group(4).trim()).toString()); @@ -215,7 +151,7 @@ public class cgBase { } } catch (Exception e) { // failed to parse GUID and/or Disabled - Log.w(Settings.tag, "cgeoBase.parseSearch: Failed to parse GUID and/or Disabled data"); + Log.w("cgeoBase.parseSearch: Failed to parse GUID and/or Disabled data"); } if (Settings.isExcludeDisabledCaches() && (cache.isDisabled() || cache.isArchived())) { @@ -247,15 +183,11 @@ public class cgBase { if (StringUtils.isNotBlank(inventoryPre)) { final Matcher matcherTbsInside = GCConstants.PATTERN_SEARCH_TRACKABLESINSIDE.matcher(inventoryPre); while (matcherTbsInside.find()) { - if (matcherTbsInside.groupCount() == 2 && matcherTbsInside.group(2) != null) { - final String inventoryItem = matcherTbsInside.group(2).toLowerCase(); - if (inventoryItem.equals("premium member only cache")) { - continue; - } else { - if (cache.getInventoryItems() <= 0) { - cache.setInventoryItems(1); - } - } + if (matcherTbsInside.groupCount() == 2 && + matcherTbsInside.group(2) != null && + !matcherTbsInside.group(2).equalsIgnoreCase("premium member only cache") && + cache.getInventoryItems() <= 0) { + cache.setInventoryItems(1); } } } @@ -276,14 +208,14 @@ public class cgBase { cids.add(cache.getCacheId()); } - // favourite count + // favorite count try { result = BaseUtils.getMatch(row, GCConstants.PATTERN_SEARCH_FAVORITE, false, 1, null, true); if (null != result) { cache.setFavoritePoints(Integer.parseInt(result)); } } catch (NumberFormatException e) { - Log.w(Settings.tag, "cgeoBase.parseSearch: Failed to parse favourite count"); + Log.w("cgeoBase.parseSearch: Failed to parse favourite count"); } if (cache.getNameSp() == null) { @@ -300,10 +232,10 @@ public class cgBase { try { String result = BaseUtils.getMatch(page, GCConstants.PATTERN_SEARCH_TOTALCOUNT, false, 1, null, true); if (null != result) { - searchResult.totalCnt = Integer.parseInt(result); + searchResult.setTotal(Integer.parseInt(result)); } } catch (NumberFormatException e) { - Log.w(Settings.tag, "cgeoBase.parseSearch: Failed to parse cache count"); + Log.w("cgeoBase.parseSearch: Failed to parse cache count"); } if (thread != null && recaptchaChallenge != null) { @@ -315,7 +247,7 @@ public class cgBase { } if (cids.size() > 0 && (Settings.isPremiumMember() || showCaptcha) && (recaptchaChallenge == null || StringUtils.isNotBlank(recaptchaText))) { - Log.i(Settings.tag, "Trying to get .loc for " + cids.size() + " caches"); + Log.i("Trying to get .loc for " + cids.size() + " caches"); try { // get coordinates for parsed caches @@ -345,9 +277,9 @@ public class cgBase { if (StringUtils.isNotBlank(coordinates)) { if (coordinates.contains("You have not agreed to the license agreement. The license agreement is required before you can start downloading GPX or LOC files from Geocaching.com")) { - Log.i(Settings.tag, "User has not agreed to the license agreement. Can\'t download .loc file."); + Log.i("User has not agreed to the license agreement. Can\'t download .loc file."); - searchResult.error = StatusCode.UNAPPROVED_LICENSE; + searchResult.setError(StatusCode.UNAPPROVED_LICENSE); return searchResult; } @@ -356,7 +288,7 @@ public class cgBase { LocParser.parseLoc(searchResult, coordinates); } catch (Exception e) { - Log.e(Settings.tag, "cgBase.parseSearch.CIDs: " + e.toString()); + Log.e("cgBase.parseSearch.CIDs: " + e.toString()); } } @@ -384,6 +316,9 @@ public class cgBase { if (CancellableHandler.isCancelled(handler)) { return null; } + // update progress message so user knows we're still working. Otherwise it will remain on whatever was set + // in getExtraOnlineInfo (which could be logs, gcvote, or elevation) + CancellableHandler.sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_render); // save full detailed caches cgeoapplication.getInstance().saveCache(cache, EnumSet.of(SaveFlag.SAVE_DB)); } @@ -391,33 +326,33 @@ public class cgBase { } static SearchResult parseCacheFromText(final String page, final CancellableHandler handler) { - sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_details); + CancellableHandler.sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_details); if (StringUtils.isBlank(page)) { - Log.e(Settings.tag, "cgeoBase.parseCache: No page given"); + Log.e("cgeoBase.parseCache: No page given"); return null; } final SearchResult searchResult = new SearchResult(); if (page.contains("Cache is Unpublished") || page.contains("you cannot view this cache listing until it has been published")) { - searchResult.error = StatusCode.UNPUBLISHED_CACHE; + searchResult.setError(StatusCode.UNPUBLISHED_CACHE); return searchResult; } if (page.contains("Sorry, the owner of this listing has made it viewable to Premium Members only.")) { - searchResult.error = StatusCode.PREMIUM_ONLY; + searchResult.setError(StatusCode.PREMIUM_ONLY); return searchResult; } if (page.contains("has chosen to make this cache listing visible to Premium Members only.")) { - searchResult.error = StatusCode.PREMIUM_ONLY; + searchResult.setError(StatusCode.PREMIUM_ONLY); return searchResult; } final String cacheName = Html.fromHtml(BaseUtils.getMatch(page, GCConstants.PATTERN_NAME, true, "")).toString(); if ("An Error Has Occurred".equalsIgnoreCase(cacheName)) { - searchResult.error = StatusCode.UNKNOWN_ERROR; + searchResult.setError(StatusCode.UNKNOWN_ERROR); return searchResult; } @@ -454,7 +389,7 @@ public class cgBase { int pos = tableInside.indexOf("id=\"cacheDetails\""); if (pos == -1) { - Log.e(Settings.tag, "cgeoBase.parseCache: ID \"cacheDetails\" not found on page"); + Log.e("cgeoBase.parseCache: ID \"cacheDetails\" not found on page"); return null; } @@ -462,7 +397,7 @@ public class cgBase { pos = tableInside.indexOf("<div class=\"CacheInformationTable\""); if (pos == -1) { - Log.e(Settings.tag, "cgeoBase.parseCache: class \"CacheInformationTable\" not found on page"); + Log.e("cgeoBase.parseCache: class \"CacheInformationTable\" not found on page"); return null; } @@ -499,7 +434,7 @@ public class cgBase { } } catch (ParseException e) { // failed to parse cache hidden date - Log.w(Settings.tag, "cgeoBase.parseCache: Failed to parse cache hidden (event) date"); + Log.w("cgeoBase.parseCache: Failed to parse cache hidden (event) date"); } // favourite @@ -525,7 +460,7 @@ public class cgBase { cache.setCoords(new Geopoint(cache.getLatlon())); cache.setReliableLatLon(true); } catch (Geopoint.GeopointException e) { - Log.w(Settings.tag, "cgeoBase.parseCache: Failed to parse cache coordinates: " + e.toString()); + Log.w("cgeoBase.parseCache: Failed to parse cache coordinates: " + e.toString()); } } @@ -542,7 +477,7 @@ public class cgBase { } } - checkFields(cache); + cache.checkFields(); // cache personal note cache.setPersonalNote(BaseUtils.getMatch(page, GCConstants.PATTERN_PERSONALNOTE, true, cache.getPersonalNote())); @@ -579,7 +514,7 @@ public class cgBase { } } catch (Exception e) { // failed to parse cache attributes - Log.w(Settings.tag, "cgeoBase.parseCache: Failed to parse cache attributes"); + Log.w("cgeoBase.parseCache: Failed to parse cache attributes"); } // cache spoilers @@ -589,7 +524,7 @@ public class cgBase { if (CancellableHandler.isCancelled(handler)) { return null; } - sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_spoilers); + CancellableHandler.sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_spoilers); final Matcher matcherSpoilersInside = GCConstants.PATTERN_SPOILERSINSIDE.matcher(spoilers); @@ -616,7 +551,7 @@ public class cgBase { } } catch (Exception e) { // failed to parse cache spoilers - Log.w(Settings.tag, "cgeoBase.parseCache: Failed to parse cache spoilers"); + Log.w("cgeoBase.parseCache: Failed to parse cache spoilers"); } // cache inventory @@ -650,7 +585,7 @@ public class cgBase { } } catch (Exception e) { // failed to parse cache inventory - Log.w(Settings.tag, "cgeoBase.parseCache: Failed to parse cache inventory (2)"); + Log.w("cgeoBase.parseCache: Failed to parse cache inventory (2)"); } // cache logs counts @@ -675,7 +610,7 @@ public class cgBase { } catch (Exception e) { // failed to parse logs - Log.w(Settings.tag, "cgeoBase.parseCache: Failed to parse cache log count"); + Log.w("cgeoBase.parseCache: Failed to parse cache log count"); } // add waypoint for original coordinates in case of user-modified listing-coordinates @@ -683,8 +618,7 @@ public class cgBase { final String originalCoords = BaseUtils.getMatch(page, GCConstants.PATTERN_LATLON_ORIG, false, null); if (null != originalCoords) { - // res is null during the unit tests - final cgWaypoint waypoint = new cgWaypoint(res != null ? res.getString(R.string.cache_coordinates_original) : "res = null", WaypointType.WAYPOINT, false); + final cgWaypoint waypoint = new cgWaypoint(cgeoapplication.getInstance().getString(R.string.cache_coordinates_original), WaypointType.WAYPOINT, false); waypoint.setCoords(new Geopoint(originalCoords)); cache.addWaypoint(waypoint, false); cache.setUserModifiedCoords(true); @@ -693,16 +627,15 @@ public class cgBase { } // waypoints - int wpBegin = 0; - int wpEnd = 0; + int wpBegin; + int wpEnd; wpBegin = page.indexOf("<table class=\"Table\" id=\"ctl00_ContentBody_Waypoints\">"); if (wpBegin != -1) { // parse waypoints if (CancellableHandler.isCancelled(handler)) { return null; } - sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_waypoints); - + CancellableHandler.sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_waypoints); String wpList = page.substring(wpBegin); @@ -729,7 +662,7 @@ public class cgBase { // waypoint name // res is null during the unit tests - final String name = BaseUtils.getMatch(wp[6], GCConstants.PATTERN_WPNAME, true, 1, res != null ? res.getString(R.string.waypoint) : "res = null", true); + final String name = BaseUtils.getMatch(wp[6], GCConstants.PATTERN_WPNAME, true, 1, cgeoapplication.getInstance().getString(R.string.waypoint), true); // waypoint type final String resulttype = BaseUtils.getMatch(wp[3], GCConstants.PATTERN_WPTYPE, null); @@ -769,7 +702,7 @@ public class cgBase { // last check for necessary cache conditions if (StringUtils.isBlank(cache.getGeocode())) { - searchResult.error = StatusCode.UNKNOWN_ERROR; + searchResult.setError(StatusCode.UNKNOWN_ERROR); return searchResult; } @@ -777,485 +710,6 @@ public class cgBase { return searchResult; } - private static void getExtraOnlineInfo(final cgCache cache, final String page, final CancellableHandler handler) { - if (CancellableHandler.isCancelled(handler)) { - return; - } - - //cache.setLogs(loadLogsFromDetails(page, cache, false)); - if (Settings.isFriendLogsWanted()) { - sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_logs); - List<cgLog> allLogs = cache.getLogs(); - List<cgLog> friendLogs = loadLogsFromDetails(page, cache, true, false); - if (friendLogs != null) { - for (cgLog log : friendLogs) { - if (allLogs.contains(log)) { - allLogs.get(allLogs.indexOf(log)).friend = true; - } else { - allLogs.add(log); - } - } - } - } - - if (Settings.isElevationWanted()) { - if (CancellableHandler.isCancelled(handler)) { - return; - } - sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_elevation); - if (cache.getCoords() != null) { - cache.setElevation(cache.getCoords().getElevation()); - } - } - - if (Settings.isRatingWanted()) { - if (CancellableHandler.isCancelled(handler)) { - return; - } - sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_gcvote); - final GCVoteRating rating = GCVote.getRating(cache.getGuid(), cache.getGeocode()); - if (rating != null) { - cache.setRating(rating.getRating()); - cache.setVotes(rating.getVotes()); - cache.setMyVote(rating.getMyVote()); - } - } - } - - /** - * Load logs from a cache details page. - * - * @param page - * the text of the details page - * @param cache - * the cache object to put the logs in - * @param friends - * retrieve friend logs - */ - private static List<cgLog> loadLogsFromDetails(final String page, final cgCache cache, final boolean friends, final boolean getDataFromPage) { - String rawResponse = null; - - if (!getDataFromPage) { - final Matcher userTokenMatcher = GCConstants.PATTERN_USERTOKEN2.matcher(page); - if (!userTokenMatcher.find()) { - Log.e(Settings.tag, "cgBase.loadLogsFromDetails: unable to extract userToken"); - return null; - } - - final String userToken = userTokenMatcher.group(1); - final Parameters params = new Parameters( - "tkn", userToken, - "idx", "1", - "num", String.valueOf(GCConstants.NUMBER_OF_LOGS), - "decrypt", "true", - // "sp", Boolean.toString(personal), // personal logs - "sf", Boolean.toString(friends)); - - final HttpResponse response = Network.request("http://www.geocaching.com/seek/geocache.logbook", params, false, false, false); - if (response == null) { - Log.e(Settings.tag, "cgBase.loadLogsFromDetails: cannot log logs, response is null"); - return null; - } - final int statusCode = response.getStatusLine().getStatusCode(); - if (statusCode != 200) { - Log.e(Settings.tag, "cgBase.loadLogsFromDetails: error " + statusCode + " when requesting log information"); - return null; - } - rawResponse = Network.getResponseData(response); - if (rawResponse == null) { - Log.e(Settings.tag, "cgBase.loadLogsFromDetails: unable to read whole response"); - return null; - } - } else { - // extract embedded JSON data from page - rawResponse = BaseUtils.getMatch(page, GCConstants.PATTERN_LOGBOOK, ""); - } - - List<cgLog> logs = new ArrayList<cgLog>(); - - try { - final JSONObject resp = new JSONObject(rawResponse); - if (!resp.getString("status").equals("success")) { - Log.e(Settings.tag, "cgBase.loadLogsFromDetails: status is " + resp.getString("status")); - return null; - } - - final JSONArray data = resp.getJSONArray("data"); - - for (int index = 0; index < data.length(); index++) { - final JSONObject entry = data.getJSONObject(index); - final cgLog logDone = new cgLog(); - logDone.friend = friends; - - // FIXME: use the "LogType" field instead of the "LogTypeImage" one. - final String logIconNameExt = entry.optString("LogTypeImage", ".gif"); - final String logIconName = logIconNameExt.substring(0, logIconNameExt.length() - 4); - logDone.type = LogType.getByIconName(logIconName); - - try { - logDone.date = Login.parseGcCustomDate(entry.getString("Visited")).getTime(); - } catch (ParseException e) { - Log.e(Settings.tag, "cgBase.loadLogsFromDetails: failed to parse log date."); - } - - logDone.author = entry.getString("UserName"); - logDone.found = entry.getInt("GeocacheFindCount"); - logDone.log = entry.getString("LogText"); - - final JSONArray images = entry.getJSONArray("Images"); - for (int i = 0; i < images.length(); i++) { - final JSONObject image = images.getJSONObject(i); - String url = "http://img.geocaching.com/cache/log/" + image.getString("FileName"); - String title = image.getString("Name"); - final cgImage logImage = new cgImage(url, title); - if (logDone.logImages == null) { - logDone.logImages = new ArrayList<cgImage>(); - } - logDone.logImages.add(logImage); - } - - logs.add(logDone); - } - } catch (JSONException e) { - // failed to parse logs - Log.w(Settings.tag, "cgBase.loadLogsFromDetails: Failed to parse cache logs", e); - } - - return logs; - } - - private static void checkFields(cgCache cache) { - if (StringUtils.isBlank(cache.getGeocode())) { - Log.e(Settings.tag, "cgBase.loadLogsFromDetails: geo code not parsed correctly"); - } - if (StringUtils.isBlank(cache.getName())) { - Log.e(Settings.tag, "name not parsed correctly"); - } - if (StringUtils.isBlank(cache.getGuid())) { - Log.e(Settings.tag, "guid not parsed correctly"); - } - if (cache.getTerrain() == 0.0) { - Log.e(Settings.tag, "terrain not parsed correctly"); - } - if (cache.getDifficulty() == 0.0) { - Log.e(Settings.tag, "difficulty not parsed correctly"); - } - if (StringUtils.isBlank(cache.getOwner())) { - Log.e(Settings.tag, "owner not parsed correctly"); - } - if (StringUtils.isBlank(cache.getOwnerReal())) { - Log.e(Settings.tag, "owner real not parsed correctly"); - } - if (cache.getHiddenDate() == null) { - Log.e(Settings.tag, "hidden not parsed correctly"); - } - if (cache.getFavoritePoints() < 0) { - Log.e(Settings.tag, "favoriteCount not parsed correctly"); - } - if (cache.getSize() == null) { - Log.e(Settings.tag, "size not parsed correctly"); - } - if (cache.getType() == null || cache.getType() == CacheType.UNKNOWN) { - Log.e(Settings.tag, "type not parsed correctly"); - } - if (cache.getCoords() == null) { - Log.e(Settings.tag, "coordinates not parsed correctly"); - } - if (StringUtils.isBlank(cache.getLocation())) { - Log.e(Settings.tag, "location not parsed correctly"); - } - } - - /** - * Parse a trackable HTML description into a cgTrackable object - * - * @param page - * the HTML page to parse, already processed through {@link BaseUtils#replaceWhitespace} - * @param app - * if not null, the application to use to save the trackable - * @return the parsed trackable, or null if none could be parsed - */ - public static cgTrackable parseTrackable(final String page, final cgeoapplication app, final String possibleTrackingcode) { - if (StringUtils.isBlank(page)) { - Log.e(Settings.tag, "cgeoBase.parseTrackable: No page given"); - return null; - } - - final cgTrackable trackable = new cgTrackable(); - - // trackable geocode - trackable.setGeocode(BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_GEOCODE, true, trackable.getGeocode()).toUpperCase()); - - // trackable id - trackable.setGuid(BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_GUID, true, trackable.getGuid())); - - // trackable icon - trackable.setIconUrl(BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_ICON, true, trackable.getIconUrl())); - - // trackable name - trackable.setName(BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_NAME, true, trackable.getName())); - - // trackable type - if (StringUtils.isNotBlank(trackable.getName())) { - trackable.setType(BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_TYPE, true, trackable.getType())); - } - - // trackable owner name - try { - final Matcher matcherOwner = GCConstants.PATTERN_TRACKABLE_OWNER.matcher(page); - if (matcherOwner.find() && matcherOwner.groupCount() > 0) { - trackable.setOwnerGuid(matcherOwner.group(1)); - trackable.setOwner(matcherOwner.group(2).trim()); - } - } catch (Exception e) { - // failed to parse trackable owner name - Log.w(Settings.tag, "cgeoBase.parseTrackable: Failed to parse trackable owner name"); - } - - // trackable origin - trackable.setOrigin(BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_ORIGIN, true, trackable.getOrigin())); - - // trackable spotted - try { - final Matcher matcherSpottedCache = GCConstants.PATTERN_TRACKABLE_SPOTTEDCACHE.matcher(page); - if (matcherSpottedCache.find() && matcherSpottedCache.groupCount() > 0) { - trackable.setSpottedGuid(matcherSpottedCache.group(1)); - trackable.setSpottedName(matcherSpottedCache.group(2).trim()); - trackable.setSpottedType(cgTrackable.SPOTTED_CACHE); - } - - final Matcher matcherSpottedUser = GCConstants.PATTERN_TRACKABLE_SPOTTEDUSER.matcher(page); - if (matcherSpottedUser.find() && matcherSpottedUser.groupCount() > 0) { - trackable.setSpottedGuid(matcherSpottedUser.group(1)); - trackable.setSpottedName(matcherSpottedUser.group(2).trim()); - trackable.setSpottedType(cgTrackable.SPOTTED_USER); - } - - if (BaseUtils.matches(page, GCConstants.PATTERN_TRACKABLE_SPOTTEDUNKNOWN)) { - trackable.setSpottedType(cgTrackable.SPOTTED_UNKNOWN); - } - - if (BaseUtils.matches(page, GCConstants.PATTERN_TRACKABLE_SPOTTEDOWNER)) { - trackable.setSpottedType(cgTrackable.SPOTTED_OWNER); - } - } catch (Exception e) { - // failed to parse trackable last known place - Log.w(Settings.tag, "cgeoBase.parseTrackable: Failed to parse trackable last known place"); - } - - // released date - can be missing on the page - try { - String releaseString = BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_RELEASES, false, null); - if (releaseString != null) { - trackable.setReleased(dateTbIn1.parse(releaseString)); - if (trackable.getReleased() == null) { - trackable.setReleased(dateTbIn2.parse(releaseString)); - } - } - } catch (ParseException e1) { - trackable.setReleased(null); - } - - - // trackable distance - try { - final String distance = BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_DISTANCE, false, null); - if (null != distance) { - trackable.setDistance(DistanceParser.parseDistance(distance, Settings.isUseMetricUnits())); - } - } catch (NumberFormatException e) { - throw e; - } - - // trackable goal - trackable.setGoal(BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_GOAL, true, trackable.getGoal())); - - // trackable details & image - try { - final Matcher matcherDetailsImage = GCConstants.PATTERN_TRACKABLE_DETAILSIMAGE.matcher(page); - if (matcherDetailsImage.find() && matcherDetailsImage.groupCount() > 0) { - final String image = StringUtils.trim(matcherDetailsImage.group(3)); - final String details = StringUtils.trim(matcherDetailsImage.group(4)); - - if (StringUtils.isNotEmpty(image)) { - trackable.setImage(image); - } - if (StringUtils.isNotEmpty(details) && !StringUtils.equals(details, "No additional details available.")) { - trackable.setDetails(details); - } - } - } catch (Exception e) { - // failed to parse trackable details & image - Log.w(Settings.tag, "cgeoBase.parseTrackable: Failed to parse trackable details & image"); - } - - // trackable logs - try - { - final Matcher matcherLogs = GCConstants.PATTERN_TRACKABLE_LOG.matcher(page); - /* - * 1. Type (img) - * 2. Date - * 3. Author - * 4. Cache-GUID - * 5. <ignored> (strike-through property for ancien caches) - * 6. Cache-name - * 7. Logtext - */ - while (matcherLogs.find()) - { - final cgLog logDone = new cgLog(); - - logDone.type = LogType.getByIconName(matcherLogs.group(1)); - logDone.author = Html.fromHtml(matcherLogs.group(3)).toString().trim(); - - try - { - logDone.date = Login.parseGcCustomDate(matcherLogs.group(2)).getTime(); - } catch (ParseException e) { - } - - logDone.log = matcherLogs.group(7).trim(); - - if (matcherLogs.group(4) != null && matcherLogs.group(6) != null) - { - logDone.cacheGuid = matcherLogs.group(4); - logDone.cacheName = matcherLogs.group(6); - } - - // Apply the pattern for images in a trackable log entry against each full log (group(0)) - final Matcher matcherLogImages = GCConstants.PATTERN_TRACKABLE_LOG_IMAGES.matcher(matcherLogs.group(0)); - /* - * 1. Image URL - * 2. Image title - */ - while (matcherLogImages.find()) - { - final cgImage logImage = new cgImage(matcherLogImages.group(1), matcherLogImages.group(2)); - if (logDone.logImages == null) { - logDone.logImages = new ArrayList<cgImage>(); - } - logDone.logImages.add(logImage); - } - - trackable.getLogs().add(logDone); - } - } catch (Exception e) { - // failed to parse logs - Log.w(Settings.tag, "cgeoBase.parseCache: Failed to parse cache logs" + e.toString()); - } - - // trackingcode - if (!StringUtils.equalsIgnoreCase(trackable.getGeocode(), possibleTrackingcode)) { - trackable.setTrackingcode(possibleTrackingcode); - } - - if (app != null) { - app.saveTrackable(trackable); - } - - return trackable; - } - - public static List<LogType> parseTypes(String page) { - if (StringUtils.isEmpty(page)) { - return null; - } - - final List<LogType> types = new ArrayList<LogType>(); - - final Matcher typeBoxMatcher = GCConstants.PATTERN_TYPEBOX.matcher(page); - String typesText = null; - if (typeBoxMatcher.find()) { - if (typeBoxMatcher.groupCount() > 0) { - typesText = typeBoxMatcher.group(1); - } - } - - if (typesText != null) { - - final Matcher typeMatcher = GCConstants.PATTERN_TYPE2.matcher(typesText); - while (typeMatcher.find()) { - if (typeMatcher.groupCount() > 1) { - final int type = Integer.parseInt(typeMatcher.group(2)); - - if (type > 0) { - types.add(LogType.getById(type)); - } - } - } - } - - return types; - } - - public static List<cgTrackableLog> parseTrackableLog(final String page) { - if (StringUtils.isEmpty(page)) { - return null; - } - - final List<cgTrackableLog> trackables = new ArrayList<cgTrackableLog>(); - - String table = StringUtils.substringBetween(page, "<table id=\"tblTravelBugs\"", "</table>"); - - // if no trackables are currently in the account, the table is not available, so return an empty list instead of null - if (StringUtils.isBlank(table)) { - return trackables; - } - - table = StringUtils.substringBetween(table, "<tbody>", "</tbody>"); - if (StringUtils.isBlank(table)) { - Log.e(Settings.tag, "cgeoBase.parseTrackableLog: tbody not found on page"); - return null; - } - - final Matcher trackableMatcher = GCConstants.PATTERN_TRACKABLE.matcher(page); - while (trackableMatcher.find()) { - if (trackableMatcher.groupCount() > 0) { - final cgTrackableLog trackableLog = new cgTrackableLog(); - - if (trackableMatcher.group(1) != null) { - trackableLog.trackCode = trackableMatcher.group(1); - } else { - continue; - } - if (trackableMatcher.group(2) != null) { - trackableLog.name = Html.fromHtml(trackableMatcher.group(2)).toString(); - } else { - continue; - } - if (trackableMatcher.group(3) != null) { - trackableLog.ctl = Integer.valueOf(trackableMatcher.group(3)); - } else { - continue; - } - if (trackableMatcher.group(5) != null) { - trackableLog.id = Integer.valueOf(trackableMatcher.group(5)); - } else { - continue; - } - - Log.i(Settings.tag, "Trackable in inventory (#" + trackableLog.ctl + "/" + trackableLog.id + "): " + trackableLog.trackCode + " - " + trackableLog.name); - - trackables.add(trackableLog); - } - } - - return trackables; - } - - /** - * Insert the right cache type restriction in parameters - * - * @param params - * the parameters to insert the restriction into - * @param cacheType - * the type of cache, or null to include everything - */ - static private void insertCacheType(final Parameters params, final CacheType cacheType) { - params.put("tx", cacheType.guid); - } - public static SearchResult searchByNextPage(cgSearchThread thread, final SearchResult search, boolean showCaptcha) { if (search == null) { return search; @@ -1265,12 +719,12 @@ public class cgBase { final String url = search.getUrl(); if (StringUtils.isBlank(url)) { - Log.e(Settings.tag, "cgeoBase.searchByNextPage: No url found"); + Log.e("cgeoBase.searchByNextPage: No url found"); return search; } - if (isEmpty(viewstates)) { - Log.e(Settings.tag, "cgeoBase.searchByNextPage: No viewstate given"); + if (Login.isEmpty(viewstates)) { + Log.e("cgeoBase.searchByNextPage: No viewstate given"); return search; } @@ -1282,33 +736,25 @@ public class cgBase { "__EVENTARGUMENT", ""); Login.putViewstates(params, viewstates); - String page = Network.getResponseData(Network.postRequest(uri, params)); + final String page = Login.postRequestLogged(uri, params); if (!Login.getLoginStatus(page)) { - final StatusCode loginState = Login.login(); - if (loginState == StatusCode.NO_ERROR) { - page = Network.getResponseData(Network.postRequest(uri, params)); - } else if (loginState == StatusCode.NO_LOGIN_INFO_STORED) { - Log.i(Settings.tag, "Working as guest."); - } else { - search.setError(loginState); - Log.e(Settings.tag, "cgeoBase.searchByNextPage: Can not log in geocaching"); - return search; - } + Log.e("cgeoBase.postLogTrackable: Can not log in geocaching"); + return search; } if (StringUtils.isBlank(page)) { - Log.e(Settings.tag, "cgeoBase.searchByNextPage: No data from server"); + Log.e("cgeoBase.searchByNextPage: No data from server"); return search; } final SearchResult searchResult = parseSearch(thread, url, page, showCaptcha); if (searchResult == null || CollectionUtils.isEmpty(searchResult.getGeocodes())) { - Log.e(Settings.tag, "cgeoBase.searchByNextPage: No cache parsed"); + Log.e("cgeoBase.searchByNextPage: No cache parsed"); return search; } // save to application - search.setError(searchResult.error); + search.setError(searchResult.getError()); search.setViewstates(searchResult.viewstates); for (String geocode : searchResult.getGeocodes()) { search.addGeocode(geocode); @@ -1316,30 +762,25 @@ public class cgBase { return search; } - public static SearchResult searchByGeocode(final String geocode, final String guid, final int listId, final boolean forceReload, final CancellableHandler handler) { - if (StringUtils.isBlank(geocode) && StringUtils.isBlank(guid)) { - Log.e(Settings.tag, "cgeoBase.searchByGeocode: No geocode nor guid given"); - return null; - } - - cgeoapplication app = cgeoapplication.getInstance(); - if (!forceReload && listId == StoredList.TEMPORARY_LIST_ID && (app.isOffline(geocode, guid) || app.isThere(geocode, guid, true, true))) { - final SearchResult search = new SearchResult(); - final String realGeocode = StringUtils.isNotBlank(geocode) ? geocode : app.getGeocode(guid); - search.addGeocode(realGeocode); - return search; - } - - // if we have no geocode, we can't dynamically select the handler, but must explicitly use GC - if (geocode == null && guid != null) { - return GCConnector.getInstance().searchByGeocode(null, guid, app, handler); + /** + * Possibly hide caches found or hidden by user. This mutates its params argument when possible. + * + * @param params + * the parameters to mutate, or null to create a new Parameters if needed + * @param my + * @param addF + * @return the original params if not null, maybe augmented with f=1, or a new Parameters with f=1 or null otherwise + */ + public static Parameters addFToParams(final Parameters params, final boolean my, final boolean addF) { + if (!my && Settings.isExcludeMyCaches() && addF) { + if (params == null) { + return new Parameters("f", "1"); + } + params.put("f", "1"); + Log.i("Skipping caches found or hidden by user."); } - return ConnectorFactory.getConnector(geocode).searchByGeocode(geocode, guid, app, handler); - } - - public static SearchResult searchByStored(final Geopoint coords, final CacheType cacheType, final int list) { - return cgeoapplication.getInstance().getBatchOfStoredCaches(true, coords, cacheType, list); + return params; } /** @@ -1357,16 +798,16 @@ public class cgBase { final String uri = "http://www.geocaching.com/seek/nearest.aspx"; final String fullUri = uri + "?" + addFToParams(params, false, true); - String page = Network.requestLogged(uri, params, false, my, true); + final String page = Login.getRequestLogged(uri, addFToParams(params, my, true)); if (StringUtils.isBlank(page)) { - Log.e(Settings.tag, "cgeoBase.searchByAny: No data from server"); + Log.e("cgeoBase.searchByAny: No data from server"); return null; } final SearchResult searchResult = parseSearch(thread, fullUri, page, showCaptcha); if (searchResult == null || CollectionUtils.isEmpty(searchResult.getGeocodes())) { - Log.e(Settings.tag, "cgeoBase.searchByAny: No cache parsed"); + Log.e("cgeoBase.searchByAny: No cache parsed"); return searchResult; } @@ -1384,7 +825,7 @@ public class cgBase { public static SearchResult searchByKeyword(final cgSearchThread thread, final String keyword, final CacheType cacheType, final boolean showCaptcha) { if (StringUtils.isBlank(keyword)) { - Log.e(Settings.tag, "cgeoBase.searchByKeyword: No keyword given"); + Log.e("cgeoBase.searchByKeyword: No keyword given"); return null; } @@ -1394,7 +835,7 @@ public class cgBase { public static SearchResult searchByUsername(final cgSearchThread thread, final String userName, final CacheType cacheType, final boolean showCaptcha) { if (StringUtils.isBlank(userName)) { - Log.e(Settings.tag, "cgeoBase.searchByUsername: No user name given"); + Log.e("cgeoBase.searchByUsername: No user name given"); return null; } @@ -1403,7 +844,7 @@ public class cgBase { boolean my = false; if (userName.equalsIgnoreCase(Settings.getLogin().left)) { my = true; - Log.i(Settings.tag, "cgBase.searchByUsername: Overriding users choice, downloading all caches."); + Log.i("cgBase.searchByUsername: Overriding users choice, downloading all caches."); } return searchByAny(thread, cacheType, my, showCaptcha, params); @@ -1411,7 +852,7 @@ public class cgBase { public static SearchResult searchByOwner(final cgSearchThread thread, final String userName, final CacheType cacheType, final boolean showCaptcha) { if (StringUtils.isBlank(userName)) { - Log.e(Settings.tag, "cgeoBase.searchByOwner: No user name given"); + Log.e("cgeoBase.searchByOwner: No user name given"); return null; } @@ -1421,7 +862,7 @@ public class cgBase { public static cgTrackable searchTrackable(final String geocode, final String guid, final String id) { if (StringUtils.isBlank(geocode) && StringUtils.isBlank(guid) && StringUtils.isBlank(id)) { - Log.w(Settings.tag, "cgeoBase.searchTrackable: No geocode nor guid nor id given"); + Log.w("cgeoBase.searchTrackable: No geocode nor guid nor id given"); return null; } @@ -1437,16 +878,16 @@ public class cgBase { params.put("id", id); } - String page = Network.requestLogged("http://www.geocaching.com/track/details.aspx", params, false, false, false); + final String page = Login.getRequestLogged("http://www.geocaching.com/track/details.aspx", params); if (StringUtils.isBlank(page)) { - Log.e(Settings.tag, "cgeoBase.searchTrackable: No data from server"); + Log.e("cgeoBase.searchTrackable: No data from server"); return trackable; } trackable = parseTrackable(page, cgeoapplication.getInstance(), geocode); if (trackable == null) { - Log.e(Settings.tag, "cgeoBase.searchTrackable: No trackable parsed"); + Log.e("cgeoBase.searchTrackable: No trackable parsed"); return null; } @@ -1455,14 +896,14 @@ public class cgBase { public static StatusCode postLog(final String geocode, final String cacheid, final String[] viewstates, final LogType logType, final int year, final int month, final int day, - final String log, final List<cgTrackableLog> trackables) { - if (isEmpty(viewstates)) { - Log.e(Settings.tag, "cgeoBase.postLog: No viewstate given"); + final String log, final List<TrackableLog> trackables) { + if (Login.isEmpty(viewstates)) { + Log.e("cgeoBase.postLog: No viewstate given"); return StatusCode.LOG_POST_ERROR; } if (StringUtils.isBlank(log)) { - Log.e(Settings.tag, "cgeoBase.postLog: No log text given"); + Log.e("cgeoBase.postLog: No log text given"); return StatusCode.NO_LOG_TEXT; } @@ -1485,9 +926,9 @@ public class cgBase { final String logInfo = logUpdated.toString().replace("\n", "\r\n").trim(); // windows' eol and remove leading and trailing whitespaces if (trackables != null) { - Log.i(Settings.tag, "Trying to post log for cache #" + cacheid + " - action: " + logType + "; date: " + year + "." + month + "." + day + ", log: " + logInfo + "; trackables: " + trackables.size()); + Log.i("Trying to post log for cache #" + cacheid + " - action: " + logType + "; date: " + year + "." + month + "." + day + ", log: " + logInfo + "; trackables: " + trackables.size()); } else { - Log.i(Settings.tag, "Trying to post log for cache #" + cacheid + " - action: " + logType + "; date: " + year + "." + month + "." + day + ", log: " + logInfo + "; trackables: 0"); + Log.i("Trying to post log for cache #" + cacheid + " - action: " + logType + "; date: " + year + "." + month + "." + day + ", log: " + logInfo + "; trackables: 0"); } final Parameters params = new Parameters( @@ -1506,7 +947,7 @@ public class cgBase { if (trackables != null && !trackables.isEmpty()) { // we have some trackables to proceed final StringBuilder hdnSelected = new StringBuilder(); - for (final cgTrackableLog tb : trackables) { + for (final TrackableLog tb : trackables) { if (tb.action != LogTypeTrackable.DO_NOTHING) { hdnSelected.append(Integer.toString(tb.id)); hdnSelected.append(tb.action.action); @@ -1519,20 +960,10 @@ public class cgBase { } final String uri = new Uri.Builder().scheme("http").authority("www.geocaching.com").path("/seek/log.aspx").encodedQuery("ID=" + cacheid).build().toString(); - String page = Network.getResponseData(Network.postRequest(uri, params)); + String page = Login.postRequestLogged(uri, params); if (!Login.getLoginStatus(page)) { - final StatusCode loginState = Login.login(); - if (loginState == StatusCode.NO_ERROR) { - page = Network.getResponseData(Network.postRequest(uri, params)); - } else { - Log.e(Settings.tag, "cgeoBase.postLog: Can not log in geocaching (error: " + loginState + ")"); - return loginState; - } - } - - if (StringUtils.isBlank(page)) { - Log.e(Settings.tag, "cgeoBase.postLog: No data from server"); - return StatusCode.NO_DATA_FROM_SERVER; + Log.e("cgeoBase.postLogTrackable: Can not log in geocaching"); + return StatusCode.NOT_LOGGED_IN; } // maintenance, archived needs to be confirmed @@ -1543,8 +974,8 @@ public class cgBase { if (matcher.find() && matcher.groupCount() > 0) { final String[] viewstatesConfirm = Login.getViewstates(page); - if (isEmpty(viewstatesConfirm)) { - Log.e(Settings.tag, "cgeoBase.postLog: No viewstate for confirm log"); + if (Login.isEmpty(viewstatesConfirm)) { + Log.e("cgeoBase.postLog: No viewstate for confirm log"); return StatusCode.LOG_POST_ERROR; } @@ -1559,8 +990,8 @@ public class cgBase { if (trackables != null && !trackables.isEmpty()) { // we have some trackables to proceed final StringBuilder hdnSelected = new StringBuilder(); - for (cgTrackableLog tb : trackables) { - String ctl = null; + for (TrackableLog tb : trackables) { + String ctl; final String action = Integer.toString(tb.id) + tb.action.action; if (tb.ctl < 10) { @@ -1583,14 +1014,14 @@ public class cgBase { page = Network.getResponseData(Network.postRequest(uri, params)); } } catch (Exception e) { - Log.e(Settings.tag, "cgeoBase.postLog.confim: " + e.toString()); + Log.e("cgeoBase.postLog.confim: " + e.toString()); } try { final Matcher matcherOk = GCConstants.PATTERN_OK1.matcher(page); if (matcherOk.find()) { - Log.i(Settings.tag, "Log successfully posted to cache #" + cacheid); + Log.i("Log successfully posted to cache #" + cacheid); if (geocode != null) { cgeoapplication.getInstance().saveVisitDate(geocode); @@ -1604,26 +1035,26 @@ public class cgBase { return StatusCode.NO_ERROR; } } catch (Exception e) { - Log.e(Settings.tag, "cgeoBase.postLog.check: " + e.toString()); + Log.e("cgeoBase.postLog.check: " + e.toString()); } - Log.e(Settings.tag, "cgeoBase.postLog: Failed to post log because of unknown error"); + Log.e("cgeoBase.postLog: Failed to post log because of unknown error"); return StatusCode.LOG_POST_ERROR; } public static StatusCode postLogTrackable(final String tbid, final String trackingCode, final String[] viewstates, final LogType logType, final int year, final int month, final int day, final String log) { - if (isEmpty(viewstates)) { - Log.e(Settings.tag, "cgeoBase.postLogTrackable: No viewstate given"); + if (Login.isEmpty(viewstates)) { + Log.e("cgeoBase.postLogTrackable: No viewstate given"); return StatusCode.LOG_POST_ERROR; } if (StringUtils.isBlank(log)) { - Log.e(Settings.tag, "cgeoBase.postLogTrackable: No log text given"); + Log.e("cgeoBase.postLogTrackable: No log text given"); return StatusCode.NO_LOG_TEXT; } - Log.i(Settings.tag, "Trying to post log for trackable #" + trackingCode + " - action: " + logType + "; date: " + year + "." + month + "." + day + ", log: " + log); + Log.i("Trying to post log for trackable #" + trackingCode + " - action: " + logType + "; date: " + year + "." + month + "." + day + ", log: " + log); final String logInfo = log.replace("\n", "\r\n"); // windows' eol @@ -1649,34 +1080,24 @@ public class cgBase { "ctl00$ContentBody$uxVistOtherListingGC", ""); final String uri = new Uri.Builder().scheme("http").authority("www.geocaching.com").path("/track/log.aspx").encodedQuery("wid=" + tbid).build().toString(); - String page = Network.getResponseData(Network.postRequest(uri, params)); + final String page = Login.postRequestLogged(uri, params); if (!Login.getLoginStatus(page)) { - final StatusCode loginState = Login.login(); - if (loginState == StatusCode.NO_ERROR) { - page = Network.getResponseData(Network.postRequest(uri, params)); - } else { - Log.e(Settings.tag, "cgeoBase.postLogTrackable: Can not log in geocaching (error: " + loginState + ")"); - return loginState; - } - } - - if (StringUtils.isBlank(page)) { - Log.e(Settings.tag, "cgeoBase.postLogTrackable: No data from server"); - return StatusCode.NO_DATA_FROM_SERVER; + Log.e("cgeoBase.postLogTrackable: Can not log in geocaching"); + return StatusCode.NOT_LOGGED_IN; } try { final Matcher matcherOk = GCConstants.PATTERN_OK2.matcher(page); if (matcherOk.find()) { - Log.i(Settings.tag, "Log successfully posted to trackable #" + trackingCode); + Log.i("Log successfully posted to trackable #" + trackingCode); return StatusCode.NO_ERROR; } } catch (Exception e) { - Log.e(Settings.tag, "cgeoBase.postLogTrackable.check: " + e.toString()); + Log.e("cgeoBase.postLogTrackable.check: " + e.toString()); } - Log.e(Settings.tag, "cgeoBase.postLogTrackable: Failed to post log because of unknown error"); + Log.e("cgeoBase.postLogTrackable: Failed to post log because of unknown error"); return StatusCode.LOG_POST_ERROR; } @@ -1689,19 +1110,19 @@ public class cgBase { */ public static int addToWatchlist(final cgCache cache) { final String uri = "http://www.geocaching.com/my/watchlist.aspx?w=" + cache.getCacheId(); - String page = Network.postRequestLogged(uri); + String page = Login.postRequestLogged(uri, null); if (StringUtils.isBlank(page)) { - Log.e(Settings.tag, "cgBase.addToWatchlist: No data from server"); + Log.e("cgBase.addToWatchlist: No data from server"); return -1; // error } boolean guidOnPage = cache.isGuidContainedInPage(page); if (guidOnPage) { - Log.i(Settings.tag, "cgBase.addToWatchlist: cache is on watchlist"); + Log.i("cgBase.addToWatchlist: cache is on watchlist"); cache.setOnWatchlist(true); } else { - Log.e(Settings.tag, "cgBase.addToWatchlist: cache is not on watchlist"); + Log.e("cgBase.addToWatchlist: cache is not on watchlist"); } return guidOnPage ? 1 : -1; // on watchlist (=added) / else: error } @@ -1715,10 +1136,10 @@ public class cgBase { */ public static int removeFromWatchlist(final cgCache cache) { final String uri = "http://www.geocaching.com/my/watchlist.aspx?ds=1&action=rem&id=" + cache.getCacheId(); - String page = Network.postRequestLogged(uri); + String page = Login.postRequestLogged(uri, null); if (StringUtils.isBlank(page)) { - Log.e(Settings.tag, "cgBase.removeFromWatchlist: No data from server"); + Log.e("cgBase.removeFromWatchlist: No data from server"); return -1; // error } @@ -1732,273 +1153,424 @@ public class cgBase { page = Network.getResponseData(Network.postRequest(uri, params)); boolean guidOnPage = cache.isGuidContainedInPage(page); if (!guidOnPage) { - Log.i(Settings.tag, "cgBase.removeFromWatchlist: cache removed from watchlist"); + Log.i("cgBase.removeFromWatchlist: cache removed from watchlist"); cache.setOnWatchlist(false); } else { - Log.e(Settings.tag, "cgBase.removeFromWatchlist: cache not removed from watchlist"); + Log.e("cgBase.removeFromWatchlist: cache not removed from watchlist"); } return guidOnPage ? -1 : 0; // on watchlist (=error) / not on watchlist } /** - * Possibly hide caches found or hidden by user. This mutates its params argument when possible. + * Parse a trackable HTML description into a cgTrackable object * - * @param params - * the parameters to mutate, or null to create a new Parameters if needed - * @param my - * @param addF - * @return the original params if not null, maybe augmented with f=1, or a new Parameters with f=1 or null otherwise + * @param page + * the HTML page to parse, already processed through {@link BaseUtils#replaceWhitespace} + * @param app + * if not null, the application to use to save the trackable + * @return the parsed trackable, or null if none could be parsed */ - public static Parameters addFToParams(final Parameters params, final boolean my, final boolean addF) { - if (!my && Settings.isExcludeMyCaches() && addF) { - if (params == null) { - return new Parameters("f", "1"); - } - params.put("f", "1"); - Log.i(Settings.tag, "Skipping caches found or hidden by user."); + public static cgTrackable parseTrackable(final String page, final cgeoapplication app, final String possibleTrackingcode) { + if (StringUtils.isBlank(page)) { + Log.e("cgeoBase.parseTrackable: No page given"); + return null; } - return params; - } + final cgTrackable trackable = new cgTrackable(); + + // trackable geocode + trackable.setGeocode(BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_GEOCODE, true, trackable.getGeocode()).toUpperCase()); - public static void storeCache(Activity activity, cgCache origCache, String geocode, int listId, CancellableHandler handler) { + // trackable id + trackable.setGuid(BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_GUID, true, trackable.getGuid())); + + // trackable icon + trackable.setIconUrl(BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_ICON, true, trackable.getIconUrl())); + + // trackable name + trackable.setName(BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_NAME, true, trackable.getName())); + + // trackable type + if (StringUtils.isNotBlank(trackable.getName())) { + trackable.setType(BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_TYPE, true, trackable.getType())); + } + + // trackable owner name try { - cgCache cache; - // get cache details, they may not yet be complete - if (origCache != null) { - // only reload the cache, if it was already stored or has not all details (by checking the description) - if (origCache.getListId() >= StoredList.STANDARD_LIST_ID || StringUtils.isBlank(origCache.getDescription())) { - final SearchResult search = searchByGeocode(origCache.getGeocode(), null, listId, false, null); - cache = search.getFirstCacheFromResult(LoadFlags.LOAD_CACHE_OR_DB); - } else { - cache = origCache; - } - } else if (StringUtils.isNotBlank(geocode)) { - final SearchResult search = searchByGeocode(geocode, null, listId, false, null); - cache = search.getFirstCacheFromResult(LoadFlags.LOAD_CACHE_OR_DB); - } else { - cache = null; + final Matcher matcherOwner = GCConstants.PATTERN_TRACKABLE_OWNER.matcher(page); + if (matcherOwner.find() && matcherOwner.groupCount() > 0) { + trackable.setOwnerGuid(matcherOwner.group(1)); + trackable.setOwner(matcherOwner.group(2).trim()); } + } catch (Exception e) { + // failed to parse trackable owner name + Log.w("cgeoBase.parseTrackable: Failed to parse trackable owner name"); + } - if (cache == null) { - if (handler != null) { - handler.sendMessage(Message.obtain()); - } + // trackable origin + trackable.setOrigin(BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_ORIGIN, true, trackable.getOrigin())); - return; + // trackable spotted + try { + final Matcher matcherSpottedCache = GCConstants.PATTERN_TRACKABLE_SPOTTEDCACHE.matcher(page); + if (matcherSpottedCache.find() && matcherSpottedCache.groupCount() > 0) { + trackable.setSpottedGuid(matcherSpottedCache.group(1)); + trackable.setSpottedName(matcherSpottedCache.group(2).trim()); + trackable.setSpottedType(cgTrackable.SPOTTED_CACHE); } - if (CancellableHandler.isCancelled(handler)) { - return; + final Matcher matcherSpottedUser = GCConstants.PATTERN_TRACKABLE_SPOTTEDUSER.matcher(page); + if (matcherSpottedUser.find() && matcherSpottedUser.groupCount() > 0) { + trackable.setSpottedGuid(matcherSpottedUser.group(1)); + trackable.setSpottedName(matcherSpottedUser.group(2).trim()); + trackable.setSpottedType(cgTrackable.SPOTTED_USER); } - final HtmlImage imgGetter = new HtmlImage(activity, cache.getGeocode(), false, listId, true); - - // store images from description - if (StringUtils.isNotBlank(cache.getDescription())) { - Html.fromHtml(cache.getDescription(), imgGetter, null); + if (BaseUtils.matches(page, GCConstants.PATTERN_TRACKABLE_SPOTTEDUNKNOWN)) { + trackable.setSpottedType(cgTrackable.SPOTTED_UNKNOWN); } - if (CancellableHandler.isCancelled(handler)) { - return; + if (BaseUtils.matches(page, GCConstants.PATTERN_TRACKABLE_SPOTTEDOWNER)) { + trackable.setSpottedType(cgTrackable.SPOTTED_OWNER); } + } catch (Exception e) { + // failed to parse trackable last known place + Log.w("cgeoBase.parseTrackable: Failed to parse trackable last known place"); + } - // store spoilers - if (CollectionUtils.isNotEmpty(cache.getSpoilers())) { - for (cgImage oneSpoiler : cache.getSpoilers()) { - imgGetter.getDrawable(oneSpoiler.getUrl()); + // released date - can be missing on the page + try { + String releaseString = BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_RELEASES, false, null); + if (releaseString != null) { + trackable.setReleased(dateTbIn1.parse(releaseString)); + if (trackable.getReleased() == null) { + trackable.setReleased(dateTbIn2.parse(releaseString)); } } + } catch (ParseException e1) { + trackable.setReleased(null); + } - if (CancellableHandler.isCancelled(handler)) { - return; - } + // trackable distance + final String distance = BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_DISTANCE, false, null); + if (null != distance) { + trackable.setDistance(DistanceParser.parseDistance(distance, Settings.isUseMetricUnits())); + } - // store images from logs - if (Settings.isStoreLogImages()) { - for (cgLog log : cache.getLogs(true)) { - if (CollectionUtils.isNotEmpty(log.logImages)) { - for (cgImage oneLogImg : log.logImages) { - imgGetter.getDrawable(oneLogImg.getUrl()); - } - } + // trackable goal + trackable.setGoal(BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_GOAL, true, trackable.getGoal())); + + // trackable details & image + try { + final Matcher matcherDetailsImage = GCConstants.PATTERN_TRACKABLE_DETAILSIMAGE.matcher(page); + if (matcherDetailsImage.find() && matcherDetailsImage.groupCount() > 0) { + final String image = StringUtils.trim(matcherDetailsImage.group(3)); + final String details = StringUtils.trim(matcherDetailsImage.group(4)); + + if (StringUtils.isNotEmpty(image)) { + trackable.setImage(image); + } + if (StringUtils.isNotEmpty(details) && !StringUtils.equals(details, "No additional details available.")) { + trackable.setDetails(details); } } + } catch (Exception e) { + // failed to parse trackable details & image + Log.w("cgeoBase.parseTrackable: Failed to parse trackable details & image"); + } - if (CancellableHandler.isCancelled(handler)) { - return; - } + // trackable logs + try { + final Matcher matcherLogs = GCConstants.PATTERN_TRACKABLE_LOG.matcher(page); + /* + * 1. Type (img) + * 2. Date + * 3. Author + * 4. Cache-GUID + * 5. <ignored> (strike-through property for ancien caches) + * 6. Cache-name + * 7. Logtext + */ + while (matcherLogs.find()) { + long date = 0; + try { + date = Login.parseGcCustomDate(matcherLogs.group(2)).getTime(); + } catch (ParseException e) { + } - // store map previews - StaticMapsProvider.downloadMaps(cache, activity); + final LogEntry logDone = new LogEntry( + Html.fromHtml(matcherLogs.group(3)).toString().trim(), + date, + LogType.getByIconName(matcherLogs.group(1)), + matcherLogs.group(7).trim()); - if (CancellableHandler.isCancelled(handler)) { - return; - } + if (matcherLogs.group(4) != null && matcherLogs.group(6) != null) { + logDone.cacheGuid = matcherLogs.group(4); + logDone.cacheName = matcherLogs.group(6); + } - cache.setListId(listId); - cgeoapplication.getInstance().saveCache(cache, EnumSet.of(SaveFlag.SAVE_DB)); + // Apply the pattern for images in a trackable log entry against each full log (group(0)) + final Matcher matcherLogImages = GCConstants.PATTERN_TRACKABLE_LOG_IMAGES.matcher(matcherLogs.group(0)); + /* + * 1. Image URL + * 2. Image title + */ + while (matcherLogImages.find()) { + final cgImage logImage = new cgImage(matcherLogImages.group(1), matcherLogImages.group(2)); + logDone.addLogImage(logImage); + } - if (handler != null) { - handler.sendMessage(Message.obtain()); + trackable.getLogs().add(logDone); } } catch (Exception e) { - Log.e(Settings.tag, "cgBase.storeCache"); + // failed to parse logs + Log.w("cgeoBase.parseCache: Failed to parse cache logs" + e.toString()); + } + + // trackingcode + if (!StringUtils.equalsIgnoreCase(trackable.getGeocode(), possibleTrackingcode)) { + trackable.setTrackingcode(possibleTrackingcode); } + + if (app != null) { + app.saveTrackable(trackable); + } + + return trackable; } - public static void dropCache(final cgCache cache, final Handler handler) { + /** + * Load logs from a cache details page. + * + * @param page + * the text of the details page + * @param cache + * the cache object to put the logs in + * @param friends + * retrieve friend logs + */ + private static List<LogEntry> loadLogsFromDetails(final String page, final cgCache cache, final boolean friends, final boolean getDataFromPage) { + String rawResponse; + + if (!getDataFromPage) { + final Matcher userTokenMatcher = GCConstants.PATTERN_USERTOKEN2.matcher(page); + if (!userTokenMatcher.find()) { + Log.e("cgBase.loadLogsFromDetails: unable to extract userToken"); + return null; + } + + final String userToken = userTokenMatcher.group(1); + final Parameters params = new Parameters( + "tkn", userToken, + "idx", "1", + "num", String.valueOf(GCConstants.NUMBER_OF_LOGS), + "decrypt", "true", + // "sp", Boolean.toString(personal), // personal logs + "sf", Boolean.toString(friends)); + + final HttpResponse response = Network.getRequest("http://www.geocaching.com/seek/geocache.logbook", params); + if (response == null) { + Log.e("cgBase.loadLogsFromDetails: cannot log logs, response is null"); + return null; + } + final int statusCode = response.getStatusLine().getStatusCode(); + if (statusCode != 200) { + Log.e("cgBase.loadLogsFromDetails: error " + statusCode + " when requesting log information"); + return null; + } + rawResponse = Network.getResponseData(response); + if (rawResponse == null) { + Log.e("cgBase.loadLogsFromDetails: unable to read whole response"); + return null; + } + } else { + // extract embedded JSON data from page + rawResponse = BaseUtils.getMatch(page, GCConstants.PATTERN_LOGBOOK, ""); + } + + List<LogEntry> logs = new ArrayList<LogEntry>(); + try { - cgeoapplication.getInstance().markDropped(cache.getGeocode()); - cgeoapplication.getInstance().removeCache(cache.getGeocode(), EnumSet.of(RemoveFlag.REMOVE_CACHE)); + final JSONObject resp = new JSONObject(rawResponse); + if (!resp.getString("status").equals("success")) { + Log.e("cgBase.loadLogsFromDetails: status is " + resp.getString("status")); + return null; + } - handler.sendMessage(Message.obtain()); - } catch (Exception e) { - Log.e(Settings.tag, "cgBase.dropCache: " + e.toString()); + final JSONArray data = resp.getJSONArray("data"); + + for (int index = 0; index < data.length(); index++) { + final JSONObject entry = data.getJSONObject(index); + + // FIXME: use the "LogType" field instead of the "LogTypeImage" one. + final String logIconNameExt = entry.optString("LogTypeImage", ".gif"); + final String logIconName = logIconNameExt.substring(0, logIconNameExt.length() - 4); + + long date = 0; + try { + date = Login.parseGcCustomDate(entry.getString("Visited")).getTime(); + } catch (ParseException e) { + Log.e("GCParser.loadLogsFromDetails: failed to parse log date."); + } + + final LogEntry logDone = new LogEntry( + entry.getString("UserName"), + date, + LogType.getByIconName(logIconName), + entry.getString("LogText")); + logDone.found = entry.getInt("GeocacheFindCount"); + logDone.friend = friends; + + final JSONArray images = entry.getJSONArray("Images"); + for (int i = 0; i < images.length(); i++) { + final JSONObject image = images.getJSONObject(i); + String url = "http://img.geocaching.com/cache/log/" + image.getString("FileName"); + String title = image.getString("Name"); + final cgImage logImage = new cgImage(url, title); + logDone.addLogImage(logImage); + } + + logs.add(logDone); + } + } catch (JSONException e) { + // failed to parse logs + Log.w("cgBase.loadLogsFromDetails: Failed to parse cache logs", e); } - } - public static boolean runNavigation(Activity activity, Resources res, Settings settings, final Geopoint coords) { - return runNavigation(activity, res, settings, coords, null); + return logs; } - public static boolean runNavigation(Activity activity, Resources res, Settings settings, final Geopoint coords, final Geopoint coordsNow) { - if (activity == null) { - return false; - } - if (settings == null) { - return false; + public static List<LogType> parseTypes(String page) { + if (StringUtils.isEmpty(page)) { + return null; } - // Google Navigation - if (Settings.isUseGoogleNavigation()) { - try { - activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("google.navigation:ll=" + coords.getLatitude() + "," + coords.getLongitude()))); + final List<LogType> types = new ArrayList<LogType>(); - return true; - } catch (Exception e) { - // nothing + final Matcher typeBoxMatcher = GCConstants.PATTERN_TYPEBOX.matcher(page); + String typesText = null; + if (typeBoxMatcher.find()) { + if (typeBoxMatcher.groupCount() > 0) { + typesText = typeBoxMatcher.group(1); } } - // Google Maps Directions - try { - if (coordsNow != null) { - activity.startActivity(new Intent(Intent.ACTION_VIEW, - Uri.parse("http://maps.google.com/maps?f=d&saddr=" + coordsNow.getLatitude() + "," + coordsNow.getLongitude() + - "&daddr=" + coords.getLatitude() + "," + coords.getLongitude()))); - } else { - activity.startActivity(new Intent(Intent.ACTION_VIEW, - Uri.parse("http://maps.google.com/maps?f=d&daddr=" + coords.getLatitude() + "," + coords.getLongitude()))); + if (typesText != null) { + + final Matcher typeMatcher = GCConstants.PATTERN_TYPE2.matcher(typesText); + while (typeMatcher.find()) { + if (typeMatcher.groupCount() > 1) { + final int type = Integer.parseInt(typeMatcher.group(2)); + + if (type > 0) { + types.add(LogType.getById(type)); + } + } } + } - return true; - } catch (Exception e) { - // nothing + return types; + } + + public static List<TrackableLog> parseTrackableLog(final String page) { + if (StringUtils.isEmpty(page)) { + return null; } - Log.i(Settings.tag, "cgBase.runNavigation: No navigation application available."); + String table = StringUtils.substringBetween(page, "<table id=\"tblTravelBugs\"", "</table>"); - if (res != null) { - ActivityMixin.showToast(activity, res.getString(R.string.err_navigation_no)); + // if no trackables are currently in the account, the table is not available, so return an empty list instead of null + if (StringUtils.isBlank(table)) { + return Collections.emptyList(); } - return false; - } + table = StringUtils.substringBetween(table, "<tbody>", "</tbody>"); + if (StringUtils.isBlank(table)) { + Log.e("cgeoBase.parseTrackableLog: tbody not found on page"); + return null; + } - /** - * Generate a time string according to system-wide settings (locale, 12/24 hour) - * such as "13:24". - * - * @param date - * milliseconds since the epoch - * @return the formatted string - */ - public static String formatTime(long date) { - return DateUtils.formatDateTime(context, date, DateUtils.FORMAT_SHOW_TIME); - } + final List<TrackableLog> trackableLogs = new ArrayList<TrackableLog>(); - /** - * Generate a date string according to system-wide settings (locale, date format) - * such as "20 December" or "20 December 2010". The year will only be included when necessary. - * - * @param date - * milliseconds since the epoch - * @return the formatted string - */ - public static String formatDate(long date) { - return DateUtils.formatDateTime(context, date, DateUtils.FORMAT_SHOW_DATE); - } + final Matcher trackableMatcher = GCConstants.PATTERN_TRACKABLE.matcher(page); + while (trackableMatcher.find()) { + if (trackableMatcher.groupCount() > 0) { - /** - * Generate a date string according to system-wide settings (locale, date format) - * such as "20 December 2010". The year will always be included, making it suitable - * to generate long-lived log entries. - * - * @param date - * milliseconds since the epoch - * @return the formatted string - */ - public static String formatFullDate(long date) { - return DateUtils.formatDateTime(context, date, DateUtils.FORMAT_SHOW_DATE - | DateUtils.FORMAT_SHOW_YEAR); - } + final String trackCode = trackableMatcher.group(1); + final String name = Html.fromHtml(trackableMatcher.group(2)).toString(); + try { + final Integer ctl = Integer.valueOf(trackableMatcher.group(3)); + final Integer id = Integer.valueOf(trackableMatcher.group(5)); + if (trackCode != null && name != null && ctl != null && id != null) { + final TrackableLog entry = new TrackableLog(trackCode, name, id, ctl); - /** - * Generate a numeric date string according to system-wide settings (locale, date format) - * such as "10/20/2010". - * - * @param date - * milliseconds since the epoch - * @return the formatted string - */ - public static String formatShortDate(long date) { - return DateUtils.formatDateTime(context, date, DateUtils.FORMAT_SHOW_DATE - | DateUtils.FORMAT_NUMERIC_DATE); + Log.i("Trackable in inventory (#" + entry.ctl + "/" + entry.id + "): " + entry.trackCode + " - " + entry.name); + trackableLogs.add(entry); + } + } catch (NumberFormatException e) { + Log.e("GCParser.parseTrackableLog", e); + } + } + } + + return trackableLogs; } /** - * Generate a numeric date and time string according to system-wide settings (locale, - * date format) such as "7 sept. at 12:35". + * Insert the right cache type restriction in parameters * - * @param context - * a Context - * @param date - * milliseconds since the epoch - * @return the formatted string + * @param params + * the parameters to insert the restriction into + * @param cacheType + * the type of cache, or null to include everything */ - public static String formatShortDateTime(Context context, long date) { - return DateUtils.formatDateTime(context, date, DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_ABBREV_ALL); + static private void insertCacheType(final Parameters params, final CacheType cacheType) { + params.put("tx", cacheType.guid); } - /** - * Indicates whether the specified action can be used as an intent. This - * method queries the package manager for installed packages that can - * respond to an intent with the specified action. If no suitable package is - * found, this method returns false. - * - * @param context - * The application's environment. - * @param action - * The Intent action to check for availability. - * @param uri - * The Intent URI to check for availability. - * - * @return True if an Intent with the specified action can be sent and - * responded to, false otherwise. - */ - public static boolean isIntentAvailable(Context context, String action, Uri uri) { - final PackageManager packageManager = context.getPackageManager(); - final Intent intent; - if (uri == null) { - intent = new Intent(action); - } else { - intent = new Intent(action, uri); + private static void getExtraOnlineInfo(final cgCache cache, final String page, final CancellableHandler handler) { + if (CancellableHandler.isCancelled(handler)) { + return; + } + + //cache.setLogs(loadLogsFromDetails(page, cache, false)); + if (Settings.isFriendLogsWanted()) { + CancellableHandler.sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_logs); + List<LogEntry> allLogs = cache.getLogs(); + List<LogEntry> friendLogs = loadLogsFromDetails(page, cache, true, false); + if (friendLogs != null) { + for (LogEntry log : friendLogs) { + if (allLogs.contains(log)) { + allLogs.get(allLogs.indexOf(log)).friend = true; + } else { + allLogs.add(log); + } + } + } + } + + if (Settings.isElevationWanted()) { + if (CancellableHandler.isCancelled(handler)) { + return; + } + CancellableHandler.sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_elevation); + if (cache.getCoords() != null) { + cache.setElevation(cache.getCoords().getElevation()); + } + } + + if (Settings.isRatingWanted()) { + if (CancellableHandler.isCancelled(handler)) { + return; + } + CancellableHandler.sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_gcvote); + final GCVoteRating rating = GCVote.getRating(cache.getGuid(), cache.getGeocode()); + if (rating != null) { + cache.setRating(rating.getRating()); + cache.setVotes(rating.getVotes()); + cache.setMyVote(rating.getMyVote()); + } } - List<ResolveInfo> list = packageManager.queryIntentActivities(intent, - PackageManager.MATCH_DEFAULT_ONLY); - return list.size() > 0; } } - diff --git a/main/src/cgeo/geocaching/connector/gc/IconDecoder.java b/main/src/cgeo/geocaching/connector/gc/IconDecoder.java index 43ca2ce..74e78cc 100644 --- a/main/src/cgeo/geocaching/connector/gc/IconDecoder.java +++ b/main/src/cgeo/geocaching/connector/gc/IconDecoder.java @@ -153,12 +153,10 @@ public abstract class IconDecoder { } if ((bitmap.getPixel(x + POSX_FOUND, y + POSY_FOUND) & 0x00FFFFFF) == COLOR_FOUND) { cache.setFound(true); - return; } } catch (IllegalArgumentException e) { // intentionally left blank } - return; } } diff --git a/main/src/cgeo/geocaching/network/Login.java b/main/src/cgeo/geocaching/connector/gc/Login.java index be80a19..28b2c6a 100644 --- a/main/src/cgeo/geocaching/network/Login.java +++ b/main/src/cgeo/geocaching/connector/gc/Login.java @@ -1,11 +1,15 @@ -package cgeo.geocaching.network; +package cgeo.geocaching.connector.gc; import cgeo.geocaching.R; import cgeo.geocaching.Settings; -import cgeo.geocaching.cgBase; -import cgeo.geocaching.connector.gc.GCConstants; +import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.enumerations.StatusCode; +import cgeo.geocaching.network.Cookies; +import cgeo.geocaching.network.HtmlImage; +import cgeo.geocaching.network.Network; +import cgeo.geocaching.network.Parameters; import cgeo.geocaching.utils.BaseUtils; +import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; @@ -14,7 +18,6 @@ import org.apache.http.HttpResponse; import android.content.Context; import android.graphics.drawable.BitmapDrawable; -import android.util.Log; import java.text.ParseException; import java.text.SimpleDateFormat; @@ -32,7 +35,6 @@ public abstract class Login { // false = not logged in private static boolean actualLoginStatus = false; private static String actualUserName = ""; - private static String actualMemberStatus = ""; private static int actualCachesFound = -1; private static String actualStatus = ""; @@ -61,33 +63,30 @@ public abstract class Login { final ImmutablePair<String, String> login = Settings.getLogin(); if (login == null || StringUtils.isEmpty(login.left) || StringUtils.isEmpty(login.right)) { - Login.setActualStatus(cgBase.res.getString(R.string.err_login)); - Log.e(Settings.tag, "cgeoBase.login: No login information stored"); + Login.setActualStatus(cgeoapplication.getInstance().getString(R.string.err_login)); + Log.e("cgeoBase.login: No login information stored"); return StatusCode.NO_LOGIN_INFO_STORED; } - // res is null during the unit tests - if (cgBase.res != null) { - Login.setActualStatus(cgBase.res.getString(R.string.init_login_popup_working)); - } - HttpResponse loginResponse = Network.request("https://www.geocaching.com/login/default.aspx", null, false, false, false); + Login.setActualStatus(cgeoapplication.getInstance().getString(R.string.init_login_popup_working)); + HttpResponse loginResponse = Network.getRequest("https://www.geocaching.com/login/default.aspx"); String loginData = Network.getResponseData(loginResponse); if (loginResponse != null && loginResponse.getStatusLine().getStatusCode() == 503 && BaseUtils.matches(loginData, GCConstants.PATTERN_MAINTENANCE)) { return StatusCode.MAINTENANCE; } if (StringUtils.isBlank(loginData)) { - Log.e(Settings.tag, "cgeoBase.login: Failed to retrieve login page (1st)"); + Log.e("cgeoBase.login: Failed to retrieve login page (1st)"); return StatusCode.CONNECTION_FAILED; // no loginpage } if (Login.getLoginStatus(loginData)) { - Log.i(Settings.tag, "Already logged in Geocaching.com as " + login.left + " (" + getActualMemberStatus() + ')'); + Log.i("Already logged in Geocaching.com as " + login.left + " (" + Settings.getMemberStatus() + ')'); Login.switchToEnglish(loginData); return StatusCode.NO_ERROR; // logged in } - Network.clearCookies(); + Cookies.clearCookies(); Settings.setCookieStore(null); final Parameters params = new Parameters( @@ -98,8 +97,8 @@ public abstract class Login { "ctl00$ContentBody$cbRememberMe", "on", "ctl00$ContentBody$btnSignIn", "Login"); final String[] viewstates = Login.getViewstates(loginData); - if (cgBase.isEmpty(viewstates)) { - Log.e(Settings.tag, "cgeoBase.login: Failed to find viewstates"); + if (isEmpty(viewstates)) { + Log.e("cgeoBase.login: Failed to find viewstates"); return StatusCode.LOGIN_PARSE_ERROR; // no viewstates } Login.putViewstates(params, viewstates); @@ -107,38 +106,38 @@ public abstract class Login { loginResponse = Network.postRequest("https://www.geocaching.com/login/default.aspx", params); loginData = Network.getResponseData(loginResponse); - if (StringUtils.isNotBlank(loginData)) { - if (Login.getLoginStatus(loginData)) { - Log.i(Settings.tag, "Successfully logged in Geocaching.com as " + login.left + " (" + getActualMemberStatus() + ')'); - - Login.switchToEnglish(loginData); - Settings.setCookieStore(Network.dumpCookieStore()); - - return StatusCode.NO_ERROR; // logged in - } else { - if (loginData.contains("Your username/password combination does not match.")) { - Log.i(Settings.tag, "Failed to log in Geocaching.com as " + login.left + " because of wrong username/password"); - return StatusCode.WRONG_LOGIN_DATA; // wrong login - } else { - Log.i(Settings.tag, "Failed to log in Geocaching.com as " + login.left + " for some unknown reason"); - return StatusCode.UNKNOWN_ERROR; // can't login - } - } - } else { - Log.e(Settings.tag, "cgeoBase.login: Failed to retrieve login page (2nd)"); + if (StringUtils.isBlank(loginData)) { + Log.e("cgeoBase.login: Failed to retrieve login page (2nd)"); // FIXME: should it be CONNECTION_FAILED to match the first attempt? return StatusCode.COMMUNICATION_ERROR; // no login page } + + if (Login.getLoginStatus(loginData)) { + Log.i("Successfully logged in Geocaching.com as " + login.left + " (" + Settings.getMemberStatus() + ')'); + + Login.switchToEnglish(loginData); + Settings.setCookieStore(Cookies.dumpCookieStore()); + + return StatusCode.NO_ERROR; // logged in + } + + if (loginData.contains("Your username/password combination does not match.")) { + Log.i("Failed to log in Geocaching.com as " + login.left + " because of wrong username/password"); + return StatusCode.WRONG_LOGIN_DATA; // wrong login + } + + Log.i("Failed to log in Geocaching.com as " + login.left + " for some unknown reason"); + return StatusCode.UNKNOWN_ERROR; // can't login } public static StatusCode logout() { - HttpResponse logoutResponse = Network.request("https://www.geocaching.com/login/default.aspx?RESET=Y&redir=http%3a%2f%2fwww.geocaching.com%2fdefault.aspx%3f", null, false, false, false); + HttpResponse logoutResponse = Network.getRequest("https://www.geocaching.com/login/default.aspx?RESET=Y&redir=http%3a%2f%2fwww.geocaching.com%2fdefault.aspx%3f"); String logoutData = Network.getResponseData(logoutResponse); if (logoutResponse != null && logoutResponse.getStatusLine().getStatusCode() == 503 && BaseUtils.matches(logoutData, GCConstants.PATTERN_MAINTENANCE)) { return StatusCode.MAINTENANCE; } - Network.clearCookies(); + Cookies.clearCookies(); Settings.setCookieStore(null); return StatusCode.NO_ERROR; } @@ -171,14 +170,6 @@ public abstract class Login { actualUserName = userName; } - public static String getActualMemberStatus() { - return actualMemberStatus; - } - - public static void setActualMemberStatus(final String memberStatus) { - actualMemberStatus = memberStatus; - } - public static int getActualCachesFound() { return actualCachesFound; } @@ -191,21 +182,18 @@ public abstract class Login { */ public static boolean getLoginStatus(final String page) { if (StringUtils.isBlank(page)) { - Log.e(Settings.tag, "cgeoBase.checkLogin: No page given"); + Log.e("cgeoBase.checkLogin: No page given"); return false; } - // res is null during the unit tests - if (cgBase.res != null) { - setActualStatus(cgBase.res.getString(R.string.init_login_popup_ok)); - } + setActualStatus(cgeoapplication.getInstance().getString(R.string.init_login_popup_ok)); // on every page except login page setActualLoginStatus(BaseUtils.matches(page, GCConstants.PATTERN_LOGIN_NAME)); if (isActualLoginStatus()) { setActualUserName(BaseUtils.getMatch(page, GCConstants.PATTERN_LOGIN_NAME, true, "???")); - setActualMemberStatus(BaseUtils.getMatch(page, GCConstants.PATTERN_MEMBER_STATUS, true, "???")); setActualCachesFound(Integer.parseInt(BaseUtils.getMatch(page, GCConstants.PATTERN_CACHES_FOUND, true, "0").replaceAll("[,.]", ""))); + Settings.setMemberStatus(BaseUtils.getMatch(page, GCConstants.PATTERN_MEMBER_STATUS, true, null)); return true; } @@ -213,28 +201,24 @@ public abstract class Login { setActualLoginStatus(BaseUtils.matches(page, GCConstants.PATTERN_LOGIN_NAME_LOGIN_PAGE)); if (isActualLoginStatus()) { setActualUserName(Settings.getUsername()); - setActualMemberStatus(Settings.getMemberStatus()); // number of caches found is not part of this page return true; } - // res is null during the unit tests - if (cgBase.res != null) { - setActualStatus(cgBase.res.getString(R.string.init_login_popup_failed)); - } + setActualStatus(cgeoapplication.getInstance().getString(R.string.init_login_popup_failed)); return false; } private static void switchToEnglish(String previousPage) { - if (previousPage != null && previousPage.indexOf(ENGLISH) >= 0) { - Log.i(Settings.tag, "Geocaching.com language already set to English"); + if (previousPage != null && previousPage.contains(ENGLISH)) { + Log.i("Geocaching.com language already set to English"); // get find count - getLoginStatus(Network.getResponseData(Network.request("http://www.geocaching.com/email/", null, false))); + getLoginStatus(Network.getResponseData(Network.getRequest("http://www.geocaching.com/email/"))); } else { - final String page = Network.getResponseData(Network.request("http://www.geocaching.com/default.aspx", null, false)); + final String page = Network.getResponseData(Network.getRequest("http://www.geocaching.com/default.aspx")); getLoginStatus(page); if (page == null) { - Log.e(Settings.tag, "Failed to read viewstates to set geocaching.com language"); + Log.e("Failed to read viewstates to set geocaching.com language"); } final Parameters params = new Parameters( "__EVENTTARGET", "ctl00$uxLocaleList$uxLocaleList$ctl00$uxLocaleItem", // switch to english @@ -242,14 +226,14 @@ public abstract class Login { Login.transferViewstates(page, params); final HttpResponse response = Network.postRequest("http://www.geocaching.com/default.aspx", params); if (!Network.isSuccess(response)) { - Log.e(Settings.tag, "Failed to set geocaching.com language to English"); + Log.e("Failed to set geocaching.com language to English"); } } } public static BitmapDrawable downloadAvatarAndGetMemberStatus(final Context context) { try { - final String profile = BaseUtils.replaceWhitespace(Network.getResponseData(Network.request("http://www.geocaching.com/my/", null, false))); + final String profile = BaseUtils.replaceWhitespace(Network.getResponseData(Network.getRequest("http://www.geocaching.com/my/"))); Settings.setMemberStatus(BaseUtils.getMatch(profile, GCConstants.PATTERN_MEMBER_STATUS, true, null)); @@ -261,9 +245,9 @@ public abstract class Login { return imgGetter.getDrawable(avatarURL); } // No match? There may be no avatar set by user. - Log.d(Settings.tag, "No avatar set for user"); + Log.d("No avatar set for user"); } catch (Exception e) { - Log.w(Settings.tag, "Error when retrieving user avatar", e); + Log.w("Error when retrieving user avatar", e); } return null; } @@ -273,10 +257,10 @@ public abstract class Login { */ public static void detectGcCustomDate() { - final String result = Network.getResponseData(Network.request("http://www.geocaching.com/account/ManagePreferences.aspx", null, false, false, false)); + final String result = Network.getResponseData(Network.getRequest("http://www.geocaching.com/account/ManagePreferences.aspx")); if (null == result) { - Log.w(Settings.tag, "cgeoBase.detectGcCustomDate: result is null"); + Log.w("cgeoBase.detectGcCustomDate: result is null"); return; } @@ -315,6 +299,24 @@ public abstract class Login { } /** + * checks if an Array of Strings is empty or not. Empty means: + * - Array is null + * - or all elements are null or empty strings + */ + public static boolean isEmpty(String[] a) { + if (a == null) { + return true; + } + + for (String s : a) { + if (StringUtils.isNotEmpty(s)) { + return false; + } + } + return true; + } + + /** * read all viewstates from page * * @return String[] with all view states @@ -333,7 +335,7 @@ public abstract class Login { try { count = Integer.parseInt(matcherViewstateCount.group(1)); } catch (NumberFormatException e) { - Log.e(Settings.tag, "getViewStates", e); + Log.e("getViewStates", e); } } @@ -351,7 +353,7 @@ public abstract class Login { try { no = Integer.parseInt(sno); } catch (NumberFormatException e) { - Log.e(Settings.tag, "getViewStates", e); + Log.e("getViewStates", e); no = 0; } } @@ -389,10 +391,47 @@ public abstract class Login { putViewstates(params, getViewstates(page)); } - static public String[] requestViewstates(final String uri, final Parameters params, boolean xContentType, boolean my) { - final HttpResponse response = Network.request(uri, params, xContentType, my, false); + /** + * POST HTTP request. Do the request a second time if the user is not logged in + * + * @param uri + * @return + */ + public static String postRequestLogged(final String uri, final Parameters params) { + HttpResponse response = Network.postRequest(uri, params); + String data = Network.getResponseData(response); + + if (!getLoginStatus(data)) { + if (login() == StatusCode.NO_ERROR) { + response = Network.postRequest(uri, params); + data = Network.getResponseData(response); + } else { + Log.i("Working as guest."); + } + } + return data; + } + + /** + * GET HTTP request. Do the request a second time if the user is not logged in + * + * @param uri + * @param params + * @return + */ + public static String getRequestLogged(final String uri, final Parameters params) { + final String data = Network.getResponseData(Network.getRequest(uri, params)); + + if (getLoginStatus(data)) { + return data; + } + + if (login() == StatusCode.NO_ERROR) { + return Network.getResponseData(Network.getRequest(uri, params)); + } - return getViewstates(Network.getResponseData(response)); + Log.w("Working as guest."); + return data; } } diff --git a/main/src/cgeo/geocaching/connector/gc/Tile.java b/main/src/cgeo/geocaching/connector/gc/Tile.java index 8613787..692f28b 100644 --- a/main/src/cgeo/geocaching/connector/gc/Tile.java +++ b/main/src/cgeo/geocaching/connector/gc/Tile.java @@ -1,15 +1,16 @@ package cgeo.geocaching.connector.gc; -import cgeo.geocaching.Settings; +import cgeo.geocaching.ICoordinates; import cgeo.geocaching.geopoint.Geopoint; +import cgeo.geocaching.geopoint.Viewport; import cgeo.geocaching.network.Network; +import cgeo.geocaching.network.Parameters; +import cgeo.geocaching.utils.Log; import org.apache.http.HttpResponse; -import org.apache.http.client.methods.HttpGet; import android.graphics.Bitmap; import android.graphics.BitmapFactory; -import android.util.Log; import java.io.IOException; @@ -45,22 +46,16 @@ public class Tile { private final int tileX; private final int tileY; private final int zoomlevel; + private final Viewport viewPort; public Tile(Geopoint origin, int zoomlevel) { - assert zoomlevel >= ZOOMLEVEL_MIN && zoomlevel <= ZOOMLEVEL_MAX : "zoomlevel out of range"; this.zoomlevel = Math.max(Math.min(zoomlevel, ZOOMLEVEL_MAX), ZOOMLEVEL_MIN); tileX = calcX(origin); tileY = calcY(origin); - } - - public Tile(int tileX, int tileY, int zoomlevel) { - assert zoomlevel >= ZOOMLEVEL_MIN && zoomlevel <= ZOOMLEVEL_MAX : "zoomlevel out of range"; - this.zoomlevel = zoomlevel; - this.tileX = tileX; - this.tileY = tileY; + viewPort = new Viewport(getCoord(new UTFGridPosition(0, 0)), getCoord(new UTFGridPosition(63, 63))); } public int getZoomlevel() { @@ -141,7 +136,7 @@ public class Tile { Tile tileRight = new Tile(right, zoom); if (tileLeft.tileX == tileRight.tileX) { - zoom = zoom + 1; + zoom += 1; } return Math.min(zoom, ZOOMLEVEL_MAX); @@ -161,7 +156,7 @@ public class Tile { public static int calcZoomLat(final Geopoint bottom, final Geopoint top) { int zoom = (int) Math.ceil( - Math.log(2 * Math.PI / + Math.log(2.0 * Math.PI / Math.abs( asinh(tanGrad(bottom.getLatitude())) - asinh(tanGrad(top.getLatitude())) @@ -173,7 +168,7 @@ public class Tile { Tile tileTop = new Tile(top, zoom); if (Math.abs(tileBottom.tileY - tileTop.tileY) > 1) { - zoom = zoom - 1; + zoom -= 1; } return Math.min(zoom, ZOOMLEVEL_MAX); @@ -213,26 +208,22 @@ public class Tile { } /** Request JSON informations for a tile */ - public static String requestMapInfo(final String url, final String referer) { - final HttpGet request = new HttpGet(url); - request.addHeader("Accept", "application/json, text/javascript, */*; q=0.01"); - request.addHeader("Referer", referer); - request.addHeader("X-Requested-With", "XMLHttpRequest"); - return Network.getResponseData(Network.request(request), false); + public static String requestMapInfo(final String url, final Parameters params, final String referer) { + return Network.getResponseData(Network.getRequest(url, params, new Parameters("Referer", referer))); } /** Request .png image for a tile. */ - public static Bitmap requestMapTile(final String url, final String referer) { - final HttpGet request = new HttpGet(url); - request.addHeader("Accept", "image/png,image/*;q=0.8,*/*;q=0.5"); - request.addHeader("Referer", referer); - request.addHeader("X-Requested-With", "XMLHttpRequest"); - final HttpResponse response = Network.request(request); + public static Bitmap requestMapTile(final String url, final Parameters params, final String referer) { + final HttpResponse response = Network.getRequest(url, params, new Parameters("Referer", referer)); try { return response != null ? BitmapFactory.decodeStream(response.getEntity().getContent()) : null; } catch (IOException e) { - Log.e(Settings.tag, "cgBase.requestMapTile() " + e.getMessage()); + Log.e("cgBase.requestMapTile() " + e.getMessage()); } return null; } + + public boolean containsPoint(final ICoordinates point) { + return viewPort.contains(point); + } } diff --git a/main/src/cgeo/geocaching/connector/opencaching/ApiOpenCachingConnector.java b/main/src/cgeo/geocaching/connector/opencaching/ApiOpenCachingConnector.java index 8ed6acd..e4f382b 100644 --- a/main/src/cgeo/geocaching/connector/opencaching/ApiOpenCachingConnector.java +++ b/main/src/cgeo/geocaching/connector/opencaching/ApiOpenCachingConnector.java @@ -40,8 +40,6 @@ public class ApiOpenCachingConnector extends OpenCachingConnector { } final SearchResult searchResult = new SearchResult(); searchResult.addCache(cache); - - final SearchResult search = searchResult.filterSearchResults(false, false, Settings.getCacheType()); - return search; + return searchResult.filterSearchResults(false, false, Settings.getCacheType()); } } diff --git a/main/src/cgeo/geocaching/connector/opencaching/OkapiClient.java b/main/src/cgeo/geocaching/connector/opencaching/OkapiClient.java index 9c3ab4a..165e277 100644 --- a/main/src/cgeo/geocaching/connector/opencaching/OkapiClient.java +++ b/main/src/cgeo/geocaching/connector/opencaching/OkapiClient.java @@ -1,19 +1,20 @@ package cgeo.geocaching.connector.opencaching; -import cgeo.geocaching.Settings; +import cgeo.geocaching.LogEntry; import cgeo.geocaching.cgCache; import cgeo.geocaching.cgImage; -import cgeo.geocaching.cgLog; +import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.connector.ConnectorFactory; import cgeo.geocaching.connector.IConnector; import cgeo.geocaching.enumerations.CacheSize; import cgeo.geocaching.enumerations.CacheType; +import cgeo.geocaching.enumerations.LoadFlags.SaveFlag; import cgeo.geocaching.enumerations.LogType; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.geopoint.GeopointFormatter; -import cgeo.geocaching.geopoint.GeopointParser; import cgeo.geocaching.network.Network; import cgeo.geocaching.network.Parameters; +import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; import org.json.JSONArray; @@ -22,12 +23,12 @@ import org.json.JSONObject; import android.net.Uri; import android.text.Html; -import android.util.Log; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; +import java.util.EnumSet; import java.util.List; import java.util.Locale; @@ -75,13 +76,7 @@ final public class OkapiClient { return null; } - final cgCache cache = parseCache(data); - - long time = new Date().getTime(); - cache.setUpdated(time); - cache.setDetailedUpdate(time); - - return cache; + return parseCache(data); } public static List<cgCache> getCachesAround(final Geopoint center, IConnector connector) { @@ -117,7 +112,7 @@ final public class OkapiClient { return caches; } } catch (JSONException e) { - Log.e(Settings.tag, "OkapiClient.parseCaches", e); + Log.e("OkapiClient.parseCaches", e); } return null; } @@ -177,8 +172,14 @@ final public class OkapiClient { cache.setLogs(parseLogs(response.getJSONArray(CACHE_LATEST_LOGS))); cache.setHidden(parseDate(response.getString(CACHE_HIDDEN))); + cache.setUpdated(System.currentTimeMillis()); + cache.setDetailedUpdate(cache.getUpdated()); + cache.setDetailed(true); + + // save full detailed caches + cgeoapplication.getInstance().saveCache(cache, EnumSet.of(SaveFlag.SAVE_DB)); } catch (JSONException e) { - Log.e(Settings.tag, "OkapiClient.parseCache", e); + Log.e("OkapiClient.parseCache", e); } return cache; } @@ -200,22 +201,22 @@ final public class OkapiClient { return user.getString(USER_USERNAME); } - private static List<cgLog> parseLogs(JSONArray logsJSON) { - List<cgLog> result = null; + private static List<LogEntry> parseLogs(JSONArray logsJSON) { + List<LogEntry> result = null; for (int i = 0; i < logsJSON.length(); i++) { try { JSONObject logResponse = logsJSON.getJSONObject(i); - cgLog log = new cgLog(); - log.date = parseDate(logResponse.getString(LOG_DATE)).getTime(); - log.log = logResponse.getString(LOG_COMMENT).trim(); - log.type = parseLogType(logResponse.getString(LOG_TYPE)); - log.author = parseUser(logResponse.getJSONObject(LOG_USER)); + LogEntry log = new LogEntry( + parseUser(logResponse.getJSONObject(LOG_USER)), + parseDate(logResponse.getString(LOG_DATE)).getTime(), + parseLogType(logResponse.getString(LOG_TYPE)), + logResponse.getString(LOG_COMMENT).trim()); if (result == null) { - result = new ArrayList<cgLog>(); + result = new ArrayList<LogEntry>(); } result.add(log); } catch (JSONException e) { - Log.e(Settings.tag, "OkapiClient.parseLogs", e); + Log.e("OkapiClient.parseLogs", e); } } return result; @@ -225,7 +226,7 @@ final public class OkapiClient { if ("Found it".equalsIgnoreCase(logType)) { return LogType.LOG_FOUND_IT; } - else if ("Didn't find it".equalsIgnoreCase(logType)) { + if ("Didn't find it".equalsIgnoreCase(logType)) { return LogType.LOG_DIDNT_FIND_IT; } return LogType.LOG_NOTE; @@ -237,7 +238,7 @@ final public class OkapiClient { try { return ISO8601DATEFORMAT.parse(strippedDate); } catch (ParseException e) { - Log.e(Settings.tag, "OkapiClient.parseDate", e); + Log.e("OkapiClient.parseDate", e); } return null; } @@ -246,7 +247,7 @@ final public class OkapiClient { final String latitude = StringUtils.substringBefore(location, "|"); final String longitude = StringUtils.substringAfter(location, "|"); // FIXME: the next line should be a setter at cgCache - cache.setCoords(GeopointParser.parse(latitude, longitude)); + cache.setCoords(new Geopoint(latitude, longitude)); } private static CacheSize getCacheSize(final JSONObject response) { @@ -257,7 +258,7 @@ final public class OkapiClient { try { size = response.getDouble(CACHE_SIZE); } catch (JSONException e) { - Log.e(Settings.tag, "OkapiClient.getCacheSize", e); + Log.e("OkapiClient.getCacheSize", e); } switch ((int) Math.round(size)) { case 1: @@ -279,11 +280,14 @@ final public class OkapiClient { private static CacheType getCacheType(final String cacheType) { if (cacheType.equalsIgnoreCase("Traditional")) { return CacheType.TRADITIONAL; - } else if (cacheType.equalsIgnoreCase("Multi")) { + } + if (cacheType.equalsIgnoreCase("Multi")) { return CacheType.MULTI; - } else if (cacheType.equalsIgnoreCase("Quiz")) { + } + if (cacheType.equalsIgnoreCase("Quiz")) { return CacheType.MYSTERY; - } else if (cacheType.equalsIgnoreCase("Virtual")) { + } + if (cacheType.equalsIgnoreCase("Virtual")) { return CacheType.VIRTUAL; } return CacheType.UNKNOWN; diff --git a/main/src/cgeo/geocaching/enumerations/CacheAttribute.java b/main/src/cgeo/geocaching/enumerations/CacheAttribute.java new file mode 100644 index 0000000..4a502fb --- /dev/null +++ b/main/src/cgeo/geocaching/enumerations/CacheAttribute.java @@ -0,0 +1,140 @@ +package cgeo.geocaching.enumerations; + +import cgeo.geocaching.R; +import cgeo.geocaching.cgeoapplication; + +import org.apache.commons.lang3.StringUtils; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + + +public enum CacheAttribute { + UNKNOWN(0, "", R.drawable.attribute__strikethru, 0, 0), + DOGS(1, "dogs", R.drawable.attribute_dogs, R.string.attribute_dogs_yes, R.string.attribute_dogs_no), + FEE(2, "fee", R.drawable.attribute_fee, R.string.attribute_fee_yes, R.string.attribute_fee_no), + RAPPELLING(3, "rappelling", R.drawable.attribute_rappelling, R.string.attribute_rappelling_yes, R.string.attribute_rappelling_no), + BOAT(4, "boat", R.drawable.attribute_boat, R.string.attribute_boat_yes, R.string.attribute_boat_no), + SCUBA(5, "scuba", R.drawable.attribute_scuba, R.string.attribute_scuba_yes, R.string.attribute_scuba_no), + KIDS(6, "kids", R.drawable.attribute_kids, R.string.attribute_kids_yes, R.string.attribute_kids_no), + ONEHOUR(7, "onehour", R.drawable.attribute_onehour, R.string.attribute_onehour_yes, R.string.attribute_onehour_no), + SCENIC(8, "scenic", R.drawable.attribute_scenic, R.string.attribute_scenic_yes, R.string.attribute_scenic_no), + HIKING(9, "hiking", R.drawable.attribute_hiking, R.string.attribute_hiking_yes, R.string.attribute_hiking_no), + CLIMBING(10, "climbing", R.drawable.attribute_climbing, R.string.attribute_climbing_yes, R.string.attribute_climbing_no), + WADING(11, "wading", R.drawable.attribute_wading, R.string.attribute_wading_yes, R.string.attribute_wading_no), + SWIMMING(12, "swimming", R.drawable.attribute_swimming, R.string.attribute_swimming_yes, R.string.attribute_swimming_no), + AVAILABLE(13, "available", R.drawable.attribute_available, R.string.attribute_available_yes, R.string.attribute_available_no), + NIGHT(14, "night", R.drawable.attribute_night, R.string.attribute_night_yes, R.string.attribute_night_no), + WINTER(15, "winter", R.drawable.attribute_winter, R.string.attribute_winter_yes, R.string.attribute_winter_no), + POISONOAK(17, "poisonoak", R.drawable.attribute_poisonoak, R.string.attribute_poisonoak_yes, R.string.attribute_poisonoak_no), + DANGEROUSANIMALS(18, "dangerousanimals", R.drawable.attribute_dangerousanimals, R.string.attribute_dangerousanimals_yes, R.string.attribute_dangerousanimals_no), + TICKS(19, "ticks", R.drawable.attribute_ticks, R.string.attribute_ticks_yes, R.string.attribute_ticks_no), + MINE(29, "mine", R.drawable.attribute_mine, R.string.attribute_mine_yes, R.string.attribute_mine_no), + CLIFF(21, "cliff", R.drawable.attribute_cliff, R.string.attribute_cliff_yes, R.string.attribute_cliff_no), + HUNTING(22, "hunting", R.drawable.attribute_hunting, R.string.attribute_hunting_yes, R.string.attribute_hunting_no), + DANGER(23, "danger", R.drawable.attribute_danger, R.string.attribute_danger_yes, R.string.attribute_danger_no), + WHEELCHAIR(24, "wheelchair", R.drawable.attribute_wheelchair, R.string.attribute_wheelchair_yes, R.string.attribute_wheelchair_no), + PARKING(25, "parking", R.drawable.attribute_parking, R.string.attribute_parking_yes, R.string.attribute_parking_no), + PUBLIC(26, "public", R.drawable.attribute_public, R.string.attribute_public_yes, R.string.attribute_public_no), + WATER(27, "water", R.drawable.attribute_water, R.string.attribute_water_yes, R.string.attribute_water_no), + RESTROOMS(28, "restrooms", R.drawable.attribute_restrooms, R.string.attribute_restrooms_yes, R.string.attribute_restrooms_no), + PHONE(29, "phone", R.drawable.attribute_phone, R.string.attribute_phone_yes, R.string.attribute_phone_no), + PICNIC(30, "picnic", R.drawable.attribute_picnic, R.string.attribute_picnic_yes, R.string.attribute_picnic_no), + CAMPING(31, "camping", R.drawable.attribute_camping, R.string.attribute_camping_yes, R.string.attribute_camping_no), + BICYCLES(32, "bicycles", R.drawable.attribute_bicycles, R.string.attribute_bicycles_yes, R.string.attribute_bicycles_no), + MOTORCYCLES(33, "motorcycles", R.drawable.attribute_motorcycles, R.string.attribute_motorcycles_yes, R.string.attribute_motorcycles_no), + QUADS(34, "quads", R.drawable.attribute_quads, R.string.attribute_quads_yes, R.string.attribute_quads_no), + JEEPS(35, "jeeps", R.drawable.attribute_jeeps, R.string.attribute_jeeps_yes, R.string.attribute_jeeps_no), + SNOWMOBILES(36, "snowmobiles", R.drawable.attribute_snowmobiles, R.string.attribute_snowmobiles_yes, R.string.attribute_snowmobiles_no), + HORSES(37, "horses", R.drawable.attribute_horses, R.string.attribute_horses_yes, R.string.attribute_horses_no), + CAMPFIRES(38, "campfires", R.drawable.attribute_campfires, R.string.attribute_campfires_yes, R.string.attribute_campfires_no), + THORN(39, "thorn", R.drawable.attribute_thorn, R.string.attribute_thorn_yes, R.string.attribute_thorn_no), + STEALTH(40, "stealth", R.drawable.attribute_stealth, R.string.attribute_stealth_yes, R.string.attribute_stealth_no), + STROLLER(41, "stroller", R.drawable.attribute_stroller, R.string.attribute_stroller_yes, R.string.attribute_stroller_no), + FIRSTAID(42, "firstaid", R.drawable.attribute_firstaid, R.string.attribute_firstaid_yes, R.string.attribute_firstaid_no), + COW(43, "cow", R.drawable.attribute_cow, R.string.attribute_cow_yes, R.string.attribute_cow_no), + FLASHLIGHT(44, "flashlight", R.drawable.attribute_flashlight, R.string.attribute_flashlight_yes, R.string.attribute_flashlight_no), + LANDF(45, "landf", R.drawable.attribute_landf, R.string.attribute_landf_yes, R.string.attribute_landf_no), + RV(46, "rv", R.drawable.attribute_rv, R.string.attribute_rv_yes, R.string.attribute_rv_no), + FIELD_PUZZLE(47, "field_puzzle", R.drawable.attribute_field_puzzle, R.string.attribute_field_puzzle_yes, R.string.attribute_field_puzzle_no), + UV(48, "uv", R.drawable.attribute_uv, R.string.attribute_uv_yes, R.string.attribute_uv_no), + SNOWSHOES(49, "snowshoes", R.drawable.attribute_snowshoes, R.string.attribute_snowshoes_yes, R.string.attribute_snowshoes_no), + SKIIS(50, "skiis", R.drawable.attribute_skiis, R.string.attribute_skiis_yes, R.string.attribute_skiis_no), + SPECIAL_TOOLS(51, "s_tool", R.drawable.attribute_s_tool, R.string.attribute_s_tool_yes, R.string.attribute_s_tool_no), + NIGHTCACHE(52, "nightcache", R.drawable.attribute_nightcache, R.string.attribute_nightcache_yes, R.string.attribute_nightcache_no), + PARKNGRAB(53, "parkngrab", R.drawable.attribute_parkngrab, R.string.attribute_parkngrab_yes, R.string.attribute_parkngrab_no), + ABANDONED_BUILDING(54, "abandonedbuilding", R.drawable.attribute_abandonedbuilding, R.string.attribute_abandonedbuilding_yes, R.string.attribute_abandonedbuilding_no), + HIKE_SHORT(55, "hike_short", R.drawable.attribute_hike_short, R.string.attribute_hike_short_yes, R.string.attribute_hike_short_no), + HIKE_MED(56, "hike_med", R.drawable.attribute_hike_med, R.string.attribute_hike_med_yes, R.string.attribute_hike_med_no), + HIKE_LONG(57, "hike_long", R.drawable.attribute_hike_long, R.string.attribute_hike_long_yes, R.string.attribute_hike_long_no), + FUEL(58, "fuel", R.drawable.attribute_fuel, R.string.attribute_fuel_yes, R.string.attribute_fuel_no), + FOOD(59, "food", R.drawable.attribute_food, R.string.attribute_food_yes, R.string.attribute_food_no), + WIRELESS_BEACON(60, "wirelessbeacon", R.drawable.attribute_wirelessbeacon, R.string.attribute_wirelessbeacon_yes, R.string.attribute_wirelessbeacon_no), + PARTNERSHIP(61, "partnership", R.drawable.attribute_partnership, R.string.attribute_partnership_yes, R.string.attribute_partnership_no), + SEASONAL(62, "seasonal", R.drawable.attribute_seasonal, R.string.attribute_seasonal_yes, R.string.attribute_seasonal_no), + TOURIST_OK(63, "touristok", R.drawable.attribute_touristok, R.string.attribute_touristok_yes, R.string.attribute_touristok_no), + TREECLIMBING(64, "treeclimbing", R.drawable.attribute_treeclimbing, R.string.attribute_treeclimbing_yes, R.string.attribute_treeclimbing_no), + FRONTYARD(65, "frontyard", R.drawable.attribute_frontyard, R.string.attribute_frontyard_yes, R.string.attribute_frontyard_no), + TEAMWORK(66, "teamwork", R.drawable.attribute_teamwork, R.string.attribute_teamwork_yes, R.string.attribute_teamwork_no); + + private static final String INTERNAL_PRE = "attribute_"; + private static final String INTERNAL_YES = "_yes"; + private static final String INTERNAL_NO = "_no"; + + public final int id; + public final String gcRawName; + public final int drawableId; + public final int stringIdYes; + public final int stringIdNo; + + private CacheAttribute(final int id, final String gcRawName, final int drawableId, final int stringIdYes, final int stringIdNo) { + this.id = id; + this.gcRawName = gcRawName; + this.drawableId = drawableId; + this.stringIdYes = stringIdYes; + this.stringIdNo = stringIdNo; + } + + public String getL10n(final boolean enabled) { + return cgeoapplication.getInstance().getResources().getString(enabled ? stringIdYes : stringIdNo); + } + + private final static Map<String, CacheAttribute> FIND_BY_GCRAWNAME; + + static { + final HashMap<String, CacheAttribute> mapGcRawNames = new HashMap<String, CacheAttribute>(); + for (CacheAttribute attr : values()) { + mapGcRawNames.put(attr.gcRawName, attr); + } + FIND_BY_GCRAWNAME = Collections.unmodifiableMap(mapGcRawNames); + } + + public static CacheAttribute getById(final int id) { + for (CacheAttribute attr : values()) { + if (attr.id == id) { + return attr; + } + } + return UNKNOWN; + } + + public static CacheAttribute getByGcRawName(final String gcRawName) { + final CacheAttribute result = gcRawName != null ? FIND_BY_GCRAWNAME.get(gcRawName) : null; + if (result == null) { + return UNKNOWN; + } + return result; + } + + public static String trimAttributeName(String attributeName) { + if (null == attributeName) { + return ""; + } + return attributeName.replace(INTERNAL_PRE, "").replace(INTERNAL_YES, "").replace(INTERNAL_NO, "").trim(); + } + + public static boolean isEnabled(final String attributeName) { + return !StringUtils.endsWithIgnoreCase(attributeName, INTERNAL_NO); + } +} diff --git a/main/src/cgeo/geocaching/enumerations/CacheSize.java b/main/src/cgeo/geocaching/enumerations/CacheSize.java index 9b0a559..6fffcdb 100644 --- a/main/src/cgeo/geocaching/enumerations/CacheSize.java +++ b/main/src/cgeo/geocaching/enumerations/CacheSize.java @@ -25,13 +25,11 @@ public enum CacheSize { public final String id; public final int comparable; private final int stringId; - private String l10n; // not final because the locale can be changed private CacheSize(String id, int comparable, int stringId) { this.id = id; this.comparable = comparable; this.stringId = stringId; - setL10n(); } final private static Map<String, CacheSize> FIND_BY_ID; @@ -43,7 +41,7 @@ public enum CacheSize { FIND_BY_ID = Collections.unmodifiableMap(mapping); } - public final static CacheSize getById(final String id) { + public static CacheSize getById(final String id) { if (id == null) { return UNKNOWN; } @@ -61,12 +59,7 @@ public enum CacheSize { } public final String getL10n() { - return l10n; + return cgeoapplication.getInstance().getBaseContext().getResources().getString(stringId); } - - public void setL10n() { - this.l10n = cgeoapplication.getInstance().getBaseContext().getResources().getString(stringId); - } - } diff --git a/main/src/cgeo/geocaching/enumerations/CacheType.java b/main/src/cgeo/geocaching/enumerations/CacheType.java index 96e7eb5..9667911 100644 --- a/main/src/cgeo/geocaching/enumerations/CacheType.java +++ b/main/src/cgeo/geocaching/enumerations/CacheType.java @@ -37,7 +37,6 @@ public enum CacheType { public final String pattern; public final String guid; private final int stringId; - private String l10n; // not final because the locale can be changed public final int markerId; private CacheType(String id, String pattern, String guid, int stringId, int markerId) { @@ -45,7 +44,6 @@ public enum CacheType { this.pattern = pattern; this.guid = guid; this.stringId = stringId; - setL10n(); this.markerId = markerId; } @@ -62,16 +60,16 @@ public enum CacheType { FIND_BY_PATTERN = Collections.unmodifiableMap(mappingPattern); } - public final static CacheType getById(final String id) { - final CacheType result = id != null ? CacheType.FIND_BY_ID.get(id.toLowerCase().trim()) : null; + public static CacheType getById(final String id) { + final CacheType result = (id != null) ? CacheType.FIND_BY_ID.get(id.toLowerCase().trim()) : null; if (result == null) { return UNKNOWN; } return result; } - public final static CacheType getByPattern(final String pattern) { - final CacheType result = pattern != null ? CacheType.FIND_BY_PATTERN.get(pattern.toLowerCase().trim()) : null; + public static CacheType getByPattern(final String pattern) { + final CacheType result = (pattern != null) ? CacheType.FIND_BY_PATTERN.get(pattern.toLowerCase().trim()) : null; if (result == null) { return UNKNOWN; } @@ -79,11 +77,10 @@ public enum CacheType { } public final String getL10n() { - return l10n; + return cgeoapplication.getInstance().getBaseContext().getResources().getString(stringId); } - public void setL10n() { - this.l10n = cgeoapplication.getInstance().getBaseContext().getResources().getString(this.stringId); + public boolean isEvent() { + return CacheType.EVENT == this || CacheType.MEGA_EVENT == this || CacheType.CITO == this || CacheType.LOSTANDFOUND == this; } - } diff --git a/main/src/cgeo/geocaching/enumerations/LiveMapStrategy.java b/main/src/cgeo/geocaching/enumerations/LiveMapStrategy.java index 0f0b721..5cc7efc 100644 --- a/main/src/cgeo/geocaching/enumerations/LiveMapStrategy.java +++ b/main/src/cgeo/geocaching/enumerations/LiveMapStrategy.java @@ -28,16 +28,14 @@ public interface LiveMapStrategy { public final int id; public final EnumSet<StrategyFlag> flags; private final int stringId; - private String l10n; // not final because the locale can be changed private Strategy(int id, EnumSet<StrategyFlag> flags, int stringId) { this.id = id; this.flags = flags; this.stringId = stringId; - setL10n(); } - public final static Strategy getById(final int id) { + public static Strategy getById(final int id) { for (Strategy strategy : Strategy.values()) { if (strategy.id == id) { return strategy; @@ -47,12 +45,7 @@ public interface LiveMapStrategy { } public final String getL10n() { - return l10n; - } - - public void setL10n() { - this.l10n = cgeoapplication.getInstance().getBaseContext().getResources().getString(this.stringId); + return cgeoapplication.getInstance().getBaseContext().getResources().getString(stringId); } } - } diff --git a/main/src/cgeo/geocaching/enumerations/LogType.java b/main/src/cgeo/geocaching/enumerations/LogType.java index aab4196..e4add78 100644 --- a/main/src/cgeo/geocaching/enumerations/LogType.java +++ b/main/src/cgeo/geocaching/enumerations/LogType.java @@ -42,17 +42,15 @@ public enum LogType { LOG_UNKNOWN(0, "unknown", "", R.string.err_unknown); // LogType not init. yet public final int id; - private final String iconName; - private final String type; + public final String iconName; + public final String type; private final int stringId; - private String l10n; // not final because the locale can be changed private LogType(int id, String iconName, String type, int stringId) { this.id = id; this.iconName = iconName; this.type = type; this.stringId = stringId; - setL10n(); } private final static Map<String, LogType> FIND_BY_ICONNAME; @@ -68,7 +66,7 @@ public enum LogType { FIND_BY_TYPE = Collections.unmodifiableMap(mappingType); } - public final static LogType getById(final int id) { + public static LogType getById(final int id) { for (LogType logType : values()) { if (logType.id == id) { return logType; @@ -94,12 +92,6 @@ public enum LogType { } public final String getL10n() { - return l10n; + return cgeoapplication.getInstance().getBaseContext().getResources().getString(stringId); } - - public void setL10n() { - this.l10n = cgeoapplication.getInstance().getBaseContext().getResources().getString(this.stringId); - } - } - diff --git a/main/src/cgeo/geocaching/enumerations/StatusCode.java b/main/src/cgeo/geocaching/enumerations/StatusCode.java index d49acb2..1a1f05d 100644 --- a/main/src/cgeo/geocaching/enumerations/StatusCode.java +++ b/main/src/cgeo/geocaching/enumerations/StatusCode.java @@ -2,41 +2,34 @@ package cgeo.geocaching.enumerations; import cgeo.geocaching.R; -import android.content.Context; import android.content.res.Resources; public enum StatusCode { - COMMUNICATION_NOT_STARTED(0, R.string.err_start), - NO_ERROR(1, R.string.err_none), - LOG_SAVED(2, R.string.info_log_saved), - LOGIN_PARSE_ERROR(-1, R.string.err_parse), - CONNECTION_FAILED(-2, R.string.err_server), - NO_LOGIN_INFO_STORED(-3, R.string.err_login), - UNKNOWN_ERROR(-4, R.string.err_unknown), - COMMUNICATION_ERROR(-5, R.string.err_comm), - WRONG_LOGIN_DATA(-6, R.string.err_wrong), - UNAPPROVED_LICENSE(-7, R.string.err_license), - UNPUBLISHED_CACHE(-8, R.string.err_unpublished), - PREMIUM_ONLY(-9, R.string.err_premium_only), - MAINTENANCE(-10, R.string.err_maintenance), - LOG_POST_ERROR(1000, R.string.err_log_post_failed), - NO_LOG_TEXT(1001, R.string.warn_log_text_fill), - NO_DATA_FROM_SERVER(1002, R.string.err_log_failed_server), - NOT_LOGGED_IN(-11, R.string.init_login_popup_failed); - - final private int error_code; + COMMUNICATION_NOT_STARTED(R.string.err_start), + NO_ERROR(R.string.err_none), + LOG_SAVED(R.string.info_log_saved), + LOGIN_PARSE_ERROR(R.string.err_parse), + CONNECTION_FAILED(R.string.err_server), + NO_LOGIN_INFO_STORED(R.string.err_login), + UNKNOWN_ERROR(R.string.err_unknown), + COMMUNICATION_ERROR(R.string.err_comm), + WRONG_LOGIN_DATA(R.string.err_wrong), + UNAPPROVED_LICENSE(R.string.err_license), + UNPUBLISHED_CACHE(R.string.err_unpublished), + PREMIUM_ONLY(R.string.err_premium_only), + MAINTENANCE(R.string.err_maintenance), + LOG_POST_ERROR(R.string.err_log_post_failed), + NO_LOG_TEXT(R.string.warn_log_text_fill), + NO_DATA_FROM_SERVER(R.string.err_log_failed_server), + NOT_LOGGED_IN(R.string.init_login_popup_failed); + final private int error_string; - StatusCode(int error_code, int error_string) { - this.error_code = error_code; + StatusCode(int error_string) { this.error_string = error_string; } - public int getCode() { - return error_code; - } - public int getErrorString() { return error_string; } @@ -45,8 +38,4 @@ public enum StatusCode { return res.getString(error_string); } - public String getErrorString(final Context context) { - return getErrorString(context.getResources()); - } - } diff --git a/main/src/cgeo/geocaching/enumerations/WaypointType.java b/main/src/cgeo/geocaching/enumerations/WaypointType.java index 78e5ceb..44004c0 100644 --- a/main/src/cgeo/geocaching/enumerations/WaypointType.java +++ b/main/src/cgeo/geocaching/enumerations/WaypointType.java @@ -5,7 +5,9 @@ import cgeo.geocaching.cgeoapplication; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; /** * Enum listing waypoint types @@ -23,13 +25,11 @@ public enum WaypointType { public final String id; public final int stringId; - private String l10n; // not final because the locale can be changed public final int markerId; private WaypointType(String id, int stringId, int markerId) { this.id = id; this.stringId = stringId; - setL10n(); this.markerId = markerId; } @@ -38,13 +38,13 @@ public enum WaypointType { * non public so that <code>null</code> handling can be handled centrally in the enum type itself */ private static final Map<String, WaypointType> FIND_BY_ID; - public static final Map<WaypointType, String> ALL_TYPES_EXCEPT_OWN = new HashMap<WaypointType, String>(); + public static final Set<WaypointType> ALL_TYPES_EXCEPT_OWN = new HashSet<WaypointType>(); static { final HashMap<String, WaypointType> mapping = new HashMap<String, WaypointType>(); for (WaypointType wt : values()) { mapping.put(wt.id, wt); if (wt != WaypointType.OWN) { - ALL_TYPES_EXCEPT_OWN.put(wt, wt.getL10n()); + ALL_TYPES_EXCEPT_OWN.add(wt); } } FIND_BY_ID = Collections.unmodifiableMap(mapping); @@ -66,15 +66,9 @@ public enum WaypointType { } public final String getL10n() { - return l10n; + return cgeoapplication.getInstance().getBaseContext().getResources().getString(stringId); } - public void setL10n() { - this.l10n = cgeoapplication.getInstance().getBaseContext().getResources().getString(this.stringId); - if (WaypointType.ALL_TYPES_EXCEPT_OWN != null && WaypointType.ALL_TYPES_EXCEPT_OWN.containsKey(this)) { - WaypointType.ALL_TYPES_EXCEPT_OWN.put(this, this.getL10n()); - } - } @Override public final String toString() { diff --git a/main/src/cgeo/geocaching/export/AbstractExport.java b/main/src/cgeo/geocaching/export/AbstractExport.java new file mode 100644 index 0000000..85b060b --- /dev/null +++ b/main/src/cgeo/geocaching/export/AbstractExport.java @@ -0,0 +1,32 @@ +package cgeo.geocaching.export; + +import cgeo.geocaching.cgeoapplication; + +abstract class AbstractExport implements Export { + private final String name; + + protected AbstractExport(final String name) { + this.name = name; + } + + public String getName() { + return name; + } + + /** + * Generates a localized string from a resource id. + * + * @param resourceId + * the resource id of the string + * @return localized string + */ + protected static String getString(int resourceId) { + return cgeoapplication.getInstance().getString(resourceId); + } + + @Override + public String toString() { + // used in the array adapter of the dialog showing the exports + return getName(); + } +} diff --git a/main/src/cgeo/geocaching/export/Export.java b/main/src/cgeo/geocaching/export/Export.java new file mode 100644 index 0000000..7a2b075 --- /dev/null +++ b/main/src/cgeo/geocaching/export/Export.java @@ -0,0 +1,29 @@ +package cgeo.geocaching.export; + +import cgeo.geocaching.cgCache; + +import android.app.Activity; + +import java.util.List; + +/** + * Represents an exporter to export a {@link List} of {@link cgCache} to various formats. + */ +interface Export { + /** + * Export a {@link List} of {@link cgCache} to various formats. + * + * @param caches + * The {@link List} of {@link cgCache} to be exported + * @param activity + * optional: Some exporters might have an UI which requires an {@link Activity} + */ + public void export(List<cgCache> caches, Activity activity); + + /** + * Get the localized name of this exporter. + * + * @return localized name + */ + public String getName(); +} diff --git a/main/src/cgeo/geocaching/export/ExportFactory.java b/main/src/cgeo/geocaching/export/ExportFactory.java new file mode 100644 index 0000000..8b3df58 --- /dev/null +++ b/main/src/cgeo/geocaching/export/ExportFactory.java @@ -0,0 +1,65 @@ +package cgeo.geocaching.export; + +import cgeo.geocaching.R; +import cgeo.geocaching.cgCache; +import cgeo.geocaching.utils.Log; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.widget.ArrayAdapter; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Factory to create a dialog with all available exporters. + */ +public abstract class ExportFactory { + + /** + * Contains instances of all available exporter classes. + */ + private static final List<Class<? extends Export>> exporterClasses; + + static { + final ArrayList<Class<? extends Export>> temp = new ArrayList<Class<? extends Export>>(); + temp.add(FieldnoteExport.class); + temp.add(GpxExport.class); + exporterClasses = Collections.unmodifiableList(temp); + } + + /** + * Creates a dialog so that the user can select an exporter. + * + * @param caches + * The {@link List} of {@link cgCache} to be exported + * @param activity + * The {@link Activity} in whose context the dialog should be shown + */ + public static void showExportMenu(final List<cgCache> caches, final Activity activity) { + final AlertDialog.Builder builder = new AlertDialog.Builder(activity); + builder.setTitle(R.string.export).setIcon(android.R.drawable.ic_menu_share); + + final ArrayList<Export> export = new ArrayList<Export>(); + for (Class<? extends Export> exporterClass : exporterClasses) { + try { + export.add(exporterClass.newInstance()); + } catch (Exception ex) { + Log.e("showExportMenu", ex); + } + } + + final ArrayAdapter<Export> adapter = new ArrayAdapter<Export>(activity, android.R.layout.select_dialog_item, export); + + builder.setAdapter(adapter, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int item) { + final Export selectedExport = adapter.getItem(item); + selectedExport.export(caches, activity); + } + }); + + builder.create().show(); + } +}
\ No newline at end of file diff --git a/main/src/cgeo/geocaching/export/FieldnoteExport.java b/main/src/cgeo/geocaching/export/FieldnoteExport.java new file mode 100644 index 0000000..babc4b6 --- /dev/null +++ b/main/src/cgeo/geocaching/export/FieldnoteExport.java @@ -0,0 +1,257 @@ +package cgeo.geocaching.export; + +import cgeo.geocaching.LogEntry; +import cgeo.geocaching.R; +import cgeo.geocaching.cgCache; +import cgeo.geocaching.cgeoapplication; +import cgeo.geocaching.activity.ActivityMixin; +import cgeo.geocaching.activity.Progress; +import cgeo.geocaching.enumerations.LogType; +import cgeo.geocaching.utils.Log; + +import org.apache.commons.lang3.StringUtils; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.ProgressDialog; +import android.os.AsyncTask; +import android.os.Environment; +import android.view.View; +import android.widget.Button; +import android.widget.CheckBox; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Exports offline-logs in the Groundspeak Field Note format.<br> + * <br> + * + * Field Notes are simple plain text files, but poorly documented. Syntax:<br> + * <code>GCxxxxx,yyyy-mm-ddThh:mm:ssZ,Found it,"logtext"</code> + */ +class FieldnoteExport extends AbstractExport { + private static final File exportLocation = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/field-notes"); + private static final SimpleDateFormat fieldNoteDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); + + protected FieldnoteExport() { + super(getString(R.string.export_fieldnotes)); + } + + /** + * A dialog to allow the user to set options for the export. + * + * Currently available options are: upload field notes, only new logs since last export/upload + */ + private class ExportOptionsDialog extends AlertDialog { + public ExportOptionsDialog(final List<cgCache> caches, final Activity activity) { + super(activity); + + View layout = activity.getLayoutInflater().inflate(R.layout.fieldnote_export_dialog, null); + setView(layout); + + ((Button) layout.findViewById(R.id.export)).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + dismiss(); + new ExportTask( + caches, + activity, + ((CheckBox) findViewById(R.id.upload)).isChecked(), + ((CheckBox) findViewById(R.id.onlynew)).isChecked()) + .execute((Void) null); + } + }); + } + } + + @Override + public void export(final List<cgCache> caches, final Activity activity) { + if (null == activity) { + // No activity given, so no user interaction possible. + // Start export with default parameters. + new ExportTask(caches, null, false, false).execute((Void) null); + } else { + // Show configuration dialog + new ExportOptionsDialog(caches, activity).show(); + } + } + + private class ExportTask extends AsyncTask<Void, Integer, Boolean> { + private final List<cgCache> caches; + private final Activity activity; + private final boolean onlyNew; + private final Progress progress = new Progress(); + private File exportFile; + + private static final int STATUS_UPLOAD = -1; + + /** + * Instantiates and configurates the task for exporting field notes. + * + * @param caches + * The {@link List} of {@link cgCache} to be exported + * @param activity + * optional: Show a progress bar and toasts + * @param upload + * Upload the Field Note to geocaching.com + * @param onlyNew + * Upload/export only new logs since last export + */ + public ExportTask(final List<cgCache> caches, final Activity activity, final boolean upload, final boolean onlyNew) { + this.caches = caches; + this.activity = activity; + this.onlyNew = onlyNew; + } + + @Override + protected void onPreExecute() { + if (null != activity) { + progress.show(activity, null, getString(R.string.export) + ": " + getName(), ProgressDialog.STYLE_HORIZONTAL, null); + progress.setMaxProgressAndReset(caches.size()); + } + } + + @Override + protected Boolean doInBackground(Void... params) { + final StringBuilder fieldNoteBuffer = new StringBuilder(); + + // We need our own HashMap because LogType will give us localized and maybe + // different strings than gc.com expects in the field note + // We only need such logtypes that are possible to log via c:geo + Map<LogType, String> logTypes = new HashMap<LogType, String>(); + logTypes.put(LogType.LOG_FOUND_IT, "Found it"); + logTypes.put(LogType.LOG_DIDNT_FIND_IT, "Didn't find it"); + logTypes.put(LogType.LOG_NOTE, "Write Note"); + logTypes.put(LogType.LOG_NEEDS_ARCHIVE, "Needs archived"); + logTypes.put(LogType.LOG_NEEDS_MAINTENANCE, "Needs Maintenance"); + logTypes.put(LogType.LOG_WILL_ATTEND, "Will Attend"); + logTypes.put(LogType.LOG_ATTENDED, "Attended"); + logTypes.put(LogType.LOG_WEBCAM_PHOTO_TAKEN, "Webcam Photo Taken"); + + for (int i = 0; i < caches.size(); i++) { + try { + final cgCache cache = caches.get(i); + if (cache.isLogOffline()) { + LogEntry log = cgeoapplication.getInstance().loadLogOffline(cache.getGeocode()); + if (null != logTypes.get(log.type)) { + fieldNoteBuffer.append(cache.getGeocode()) + .append(',') + .append(fieldNoteDateFormat.format(new Date(log.date))) + .append(',') + .append(logTypes.get(log.type)) + .append(",\"") + .append(StringUtils.replaceChars(log.log, '"', '\'')) + .append("\"\n"); + } + } + publishProgress(i + 1); + } catch (Exception e) { + Log.e("FieldnoteExport.ExportTask generation", e); + return false; + } + } + + fieldNoteBuffer.append('\n'); + + if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { + exportLocation.mkdirs(); + + SimpleDateFormat fileNameDateFormat = new SimpleDateFormat("yyyyMMddHHmmss"); + exportFile = new File(exportLocation.toString() + '/' + fileNameDateFormat.format(new Date()) + ".txt"); + + OutputStream os; + Writer fw = null; + try { + os = new FileOutputStream(exportFile); + fw = new OutputStreamWriter(os, "ISO-8859-1"); // TODO: gc.com doesn't support UTF-8 + fw.write(fieldNoteBuffer.toString()); + } catch (IOException e) { + Log.e("FieldnoteExport.ExportTask export", e); + return false; + } finally { + if (fw != null) { + try { + fw.close(); + } catch (IOException e) { + Log.e("FieldnoteExport.ExportTask export", e); + return false; + } + } + } + } else { + return false; + } + + /* + * if (upload) { + * TODO Use multipart POST request for uploading + * publishProgress(STATUS_UPLOAD); + * + * final Parameters uploadParams = new Parameters( + * "__EVENTTARGET", "", + * "__EVENTARGUMENT", "", + * "__VIEWSTATE", "", + * //TODO "ctl00$ContentBody$chkSuppressDate", "on", + * "ctl00$ContentBody$FieldNoteLoader", fieldNoteBuffer.toString(), + * "ctl00$ContentBody$btnUpload", "Upload Field Note"); + * final String uri = "http://www.geocaching.com/my/uploadfieldnotes.aspx"; + * + * String page = Network.getResponseData(Network.postRequest(uri, uploadParams)); + * if (!Login.getLoginStatus(page)) { + * final StatusCode loginState = Login.login(); + * if (loginState == StatusCode.NO_ERROR) { + * page = Network.getResponseData(Network.postRequest(uri, uploadParams)); + * } else { + * Log.e(Settings.tag, "FieldnoteExport.ExportTask upload: No login (error: " + loginState + ")"); + * return false; + * } + * } + * + * if (StringUtils.isBlank(page)) { + * Log.e(Settings.tag, "FieldnoteExport.ExportTask upload: No data from server"); + * return false; + * } + * } + */ + + return true; + } + + @Override + protected void onPostExecute(Boolean result) { + if (null != activity) { + progress.dismiss(); + + if (result) { + if (onlyNew) { + // update last export time in settings + } + ActivityMixin.showToast(activity, getName() + ' ' + getString(R.string.export_exportedto) + ": " + exportFile.toString()); + } else { + ActivityMixin.showToast(activity, getString(R.string.export_failed)); + } + } + } + + @Override + protected void onProgressUpdate(Integer... status) { + if (null != activity) { + if (STATUS_UPLOAD == status[0]) { + progress.setMessage(getString(R.string.export_fieldnotes_uploading)); + } else { + progress.setProgress(status[0]); + } + } + } + } +} diff --git a/main/src/cgeo/geocaching/export/GpxExport.java b/main/src/cgeo/geocaching/export/GpxExport.java new file mode 100644 index 0000000..e7579f3 --- /dev/null +++ b/main/src/cgeo/geocaching/export/GpxExport.java @@ -0,0 +1,328 @@ +package cgeo.geocaching.export; + +import cgeo.geocaching.LogEntry; +import cgeo.geocaching.R; +import cgeo.geocaching.cgCache; +import cgeo.geocaching.cgWaypoint; +import cgeo.geocaching.cgeoapplication; +import cgeo.geocaching.activity.ActivityMixin; +import cgeo.geocaching.activity.Progress; +import cgeo.geocaching.enumerations.CacheAttribute; +import cgeo.geocaching.enumerations.LoadFlags; +import cgeo.geocaching.utils.BaseUtils; +import cgeo.geocaching.utils.Log; + +import org.apache.commons.lang3.StringEscapeUtils; + +import android.app.Activity; +import android.app.ProgressDialog; +import android.os.AsyncTask; +import android.os.Environment; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.Writer; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; + +class GpxExport extends AbstractExport { + private static final File exportLocation = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/gpx"); + private static final SimpleDateFormat dateFormatZ = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); + + protected GpxExport() { + super(getString(R.string.export_gpx)); + } + + @Override + public void export(final List<cgCache> caches, final Activity activity) { + new ExportTask(caches, activity).execute((Void) null); + } + + private class ExportTask extends AsyncTask<Void, Integer, Boolean> { + private final List<cgCache> caches; + private final Activity activity; + private final Progress progress = new Progress(); + private File exportFile; + + /** + * Instantiates and configures the task for exporting field notes. + * + * @param caches + * The {@link List} of {@link cgCache} to be exported + * @param activity + * optional: Show a progress bar and toasts + */ + public ExportTask(final List<cgCache> caches, final Activity activity) { + this.caches = caches; + this.activity = activity; + } + + @Override + protected void onPreExecute() { + if (null != activity) { + progress.show(activity, null, getString(R.string.export) + ": " + getName(), ProgressDialog.STYLE_HORIZONTAL, null); + progress.setMaxProgressAndReset(caches.size()); + } + } + + @Override + protected Boolean doInBackground(Void... params) { + // quick check for being able to write the GPX file + if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { + return false; + } + + Writer gpx = null; + + try { + exportLocation.mkdirs(); + + final SimpleDateFormat fileNameDateFormat = new SimpleDateFormat("yyyyMMddHHmmss"); + exportFile = new File(exportLocation.toString() + File.separatorChar + "export_" + fileNameDateFormat.format(new Date()) + ".gpx"); + + gpx = new BufferedWriter(new FileWriter(exportFile)); + + gpx.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); + gpx.write("<gpx version=\"1.0\" creator=\"c:geo - http://www.cgeo.org\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://www.topografix.com/GPX/1/0\" xsi:schemaLocation=\"http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd http://www.groundspeak.com/cache/1/0/1 http://www.groundspeak.com/cache/1/0/1/cache.xsd\">"); + + + for (int i = 0; i < caches.size(); i++) { + cgCache cache = caches.get(i); + + if (!cache.isDetailed()) { + cache = cgeoapplication.getInstance().loadCache(caches.get(i).getGeocode(), LoadFlags.LOAD_ALL_DB_ONLY); + } + + gpx.write("<wpt "); + gpx.write("lat=\""); + gpx.write(Double.toString(cache.getCoords().getLatitude())); + gpx.write("\" "); + gpx.write("lon=\""); + gpx.write(Double.toString(cache.getCoords().getLongitude())); + gpx.write("\">"); + + gpx.write("<time>"); + gpx.write(StringEscapeUtils.escapeXml(dateFormatZ.format(cache.getHiddenDate()))); + gpx.write("</time>"); + + gpx.write("<name>"); + gpx.write(StringEscapeUtils.escapeXml(cache.getGeocode())); + gpx.write("</name>"); + + gpx.write("<desc>"); + gpx.write(StringEscapeUtils.escapeXml(cache.getName())); + gpx.write("</desc>"); + + gpx.write("<sym>"); + gpx.write(cache.isFound() ? "Geocache Found" : "Geocache"); + gpx.write("</sym>"); + + gpx.write("<type>"); + gpx.write(StringEscapeUtils.escapeXml("Geocache|" + cache.getType().toString())); //TODO: Correct (english) string + gpx.write("</type>"); + + gpx.write("<groundspeak:cache "); + gpx.write("available=\""); + gpx.write(!cache.isDisabled() ? "True" : "False"); + gpx.write("\" archived=\""); + gpx.write(cache.isArchived() ? "True" : "False"); + gpx.write("\" "); + gpx.write("xmlns:groundspeak=\"http://www.groundspeak.com/cache/1/0/1\">"); + + gpx.write("<groundspeak:name>"); + gpx.write(StringEscapeUtils.escapeXml(cache.getName())); + gpx.write("</groundspeak:name>"); + + gpx.write("<groundspeak:placed_by>"); + gpx.write(StringEscapeUtils.escapeXml(cache.getOwner())); + gpx.write("</groundspeak:placed_by>"); + + gpx.write("<groundspeak:owner>"); + gpx.write(StringEscapeUtils.escapeXml(cache.getOwnerReal())); + gpx.write("</groundspeak:owner>"); + + gpx.write("<groundspeak:type>"); + gpx.write(StringEscapeUtils.escapeXml(cache.getType().toString())); //TODO: Correct (english) string + gpx.write("</groundspeak:type>"); + + gpx.write("<groundspeak:container>"); + gpx.write(StringEscapeUtils.escapeXml(cache.getSize().toString())); //TODO: Correct (english) string + gpx.write("</groundspeak:container>"); + + if (cache.hasAttributes()) { + //TODO: Attribute conversion required: English verbose name, gpx-id + gpx.write("<groundspeak:attributes>"); + + for (String attribute : cache.getAttributes()) { + final CacheAttribute attr = CacheAttribute.getByGcRawName(CacheAttribute.trimAttributeName(attribute)); + final boolean enabled = CacheAttribute.isEnabled(attribute); + + gpx.write("<groundspeak:attribute id=\""); + gpx.write(Integer.toString(attr.id)); + gpx.write("\" inc=\""); + if (enabled) { + gpx.write('1'); + } else { + gpx.write('0'); + } + gpx.write("\">"); + gpx.write(StringEscapeUtils.escapeXml(attr.getL10n(enabled))); + gpx.write("</groundspeak:attribute>"); + } + + gpx.write("</groundspeak:attributes>"); + } + + gpx.write("<groundspeak:difficulty>"); + gpx.write(Float.toString(cache.getDifficulty())); + gpx.write("</groundspeak:difficulty>"); + + gpx.write("<groundspeak:terrain>"); + gpx.write(Float.toString(cache.getTerrain())); + gpx.write("</groundspeak:terrain>"); + + gpx.write("<groundspeak:country>"); + gpx.write(StringEscapeUtils.escapeXml(cache.getLocation())); + gpx.write("</groundspeak:country>"); + + gpx.write("<groundspeak:state>"); + gpx.write(StringEscapeUtils.escapeXml(cache.getLocation())); + gpx.write("</groundspeak:state>"); + + gpx.write("<groundspeak:short_description html=\""); + if (BaseUtils.containsHtml(cache.getShortDescription())) { + gpx.write("True"); + } else { + gpx.write("False"); + } + gpx.write("\">"); + gpx.write(StringEscapeUtils.escapeXml(cache.getShortDescription())); + gpx.write("</groundspeak:short_description>"); + + gpx.write("<groundspeak:long_description html=\""); + if (BaseUtils.containsHtml(cache.getDescription())) { + gpx.write("True"); + } else { + gpx.write("False"); + } + gpx.write("\">"); + gpx.write(StringEscapeUtils.escapeXml(cache.getDescription())); + gpx.write("</groundspeak:long_description>"); + + gpx.write("<groundspeak:encoded_hints>"); + gpx.write(StringEscapeUtils.escapeXml(cache.getHint())); + gpx.write("</groundspeak:encoded_hints>"); + + gpx.write("</groundspeak:cache>"); + + if (cache.getLogs().size() > 0) { + gpx.write("<groundspeak:logs>"); + + for (LogEntry log : cache.getLogs()) { + gpx.write("<groundspeak:log id=\""); + gpx.write(Integer.toString(log.id)); + gpx.write("\">"); + + gpx.write("<groundspeak:date>"); + gpx.write(StringEscapeUtils.escapeXml(dateFormatZ.format(new Date(log.date)))); + gpx.write("</groundspeak:date>"); + + gpx.write("<groundspeak:type>"); + gpx.write(StringEscapeUtils.escapeXml(log.type.type)); + gpx.write("</groundspeak:type>"); + + gpx.write("<groundspeak:finder id=\"\">"); + gpx.write(StringEscapeUtils.escapeXml(log.author)); + gpx.write("</groundspeak:finder>"); + + gpx.write("<groundspeak:text encoded=\"False\">"); + gpx.write(StringEscapeUtils.escapeXml(log.log)); + gpx.write("</groundspeak:text>"); + + gpx.write("</groundspeak:log>"); + } + + gpx.write("</groundspeak:logs>"); + } + + gpx.write("</wpt>"); + + for (cgWaypoint wp : cache.getWaypoints()) { + gpx.write("<wpt lat=\""); + gpx.write(Double.toString(wp.getCoords().getLatitude())); + gpx.write("\" lon=\""); + gpx.write(Double.toString(wp.getCoords().getLongitude())); + gpx.write("\">"); + + gpx.write("<name>"); + gpx.write(StringEscapeUtils.escapeXml(wp.getPrefix())); + gpx.write(StringEscapeUtils.escapeXml(cache.getGeocode().substring(2))); + gpx.write("</name>"); + + gpx.write("<cmt />"); + + gpx.write("<desc>"); + gpx.write(StringEscapeUtils.escapeXml(wp.getNote())); + gpx.write("</desc>"); + + gpx.write("<sym>"); + gpx.write(StringEscapeUtils.escapeXml(wp.getWaypointType().toString())); + gpx.write("</sym>"); + + gpx.write("<type>Waypoint|"); + gpx.write(StringEscapeUtils.escapeXml(wp.getWaypointType().toString())); + gpx.write("</type>"); + + gpx.write("</wpt>"); + } + + publishProgress(i + 1); + } + + gpx.write("</gpx>"); + + gpx.close(); + } catch (Exception e) { + Log.e("GpxExport.ExportTask export", e); + + if (gpx != null) { + try { + gpx.close(); + } catch (IOException ee) { + } + } + + // delete partial gpx file on error + if (exportFile.exists()) { + exportFile.delete(); + } + + return false; + } + + return true; + } + + @Override + protected void onPostExecute(Boolean result) { + if (null != activity) { + progress.dismiss(); + if (result) { + ActivityMixin.showToast(activity, getName() + ' ' + getString(R.string.export_exportedto) + ": " + exportFile.toString()); + } else { + ActivityMixin.showToast(activity, getString(R.string.export_failed)); + } + } + } + + @Override + protected void onProgressUpdate(Integer... status) { + if (null != activity) { + progress.setProgress(status[0]); + } + } + } +} diff --git a/main/src/cgeo/geocaching/files/FileList.java b/main/src/cgeo/geocaching/files/FileList.java index cef7b89..2fa4e5d 100644 --- a/main/src/cgeo/geocaching/files/FileList.java +++ b/main/src/cgeo/geocaching/files/FileList.java @@ -1,9 +1,9 @@ package cgeo.geocaching.files; import cgeo.geocaching.R; -import cgeo.geocaching.Settings; import cgeo.geocaching.StoredList; import cgeo.geocaching.activity.AbstractListActivity; +import cgeo.geocaching.utils.Log; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.ArrayUtils; @@ -15,7 +15,6 @@ import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.Message; -import android.util.Log; import android.widget.ArrayAdapter; import java.io.File; @@ -64,30 +63,14 @@ public abstract class FileList<T extends ArrayAdapter<File>> extends AbstractLis @Override public void handleMessage(Message msg) { - try { - if (CollectionUtils.isEmpty(files)) { - if (waitDialog != null) { - waitDialog.dismiss(); - } - - showToast(res.getString(R.string.file_list_no_files)); - - finish(); - return; - } else { - if (adapter != null) { - adapter.notifyDataSetChanged(); - } - } - - if (waitDialog != null) { - waitDialog.dismiss(); - } - } catch (Exception e) { - if (waitDialog != null) { - waitDialog.dismiss(); - } - Log.e(Settings.tag, "cgFileList.loadFilesHandler: " + e.toString()); + if (waitDialog != null) { + waitDialog.dismiss(); + } + if (CollectionUtils.isEmpty(files)) { + showToast(res.getString(R.string.file_list_no_files)); + finish(); + } else if (adapter != null) { + adapter.notifyDataSetChanged(); } } }; @@ -188,10 +171,10 @@ public abstract class FileList<T extends ArrayAdapter<File>> extends AbstractLis listDir(list, Environment.getExternalStorageDirectory()); } } else { - Log.w(Settings.tag, "No external media mounted."); + Log.w("No external media mounted."); } } catch (Exception e) { - Log.e(Settings.tag, "cgFileList.loadFiles.run: " + e.toString()); + Log.e("cgFileList.loadFiles.run: " + e.toString()); } changeWaitDialogHandler.sendMessage(Message.obtain(changeWaitDialogHandler, 0, "loaded directories")); @@ -237,7 +220,6 @@ public abstract class FileList<T extends ArrayAdapter<File>> extends AbstractLis } } - return; } /** diff --git a/main/src/cgeo/geocaching/files/FileParser.java b/main/src/cgeo/geocaching/files/FileParser.java index 20e757c..090573a 100644 --- a/main/src/cgeo/geocaching/files/FileParser.java +++ b/main/src/cgeo/geocaching/files/FileParser.java @@ -52,7 +52,7 @@ public abstract class FileParser { final BufferedReader input = new BufferedReader(new InputStreamReader(progressInputStream)); try { - String line = null; + String line; while ((line = input.readLine()) != null) { buffer.append(line); showProgressMessage(progressHandler, progressInputStream.getProgress()); diff --git a/main/src/cgeo/geocaching/files/GPXImporter.java b/main/src/cgeo/geocaching/files/GPXImporter.java index 4697a62..c669dcb 100644 --- a/main/src/cgeo/geocaching/files/GPXImporter.java +++ b/main/src/cgeo/geocaching/files/GPXImporter.java @@ -11,6 +11,7 @@ import cgeo.geocaching.activity.Progress; import cgeo.geocaching.enumerations.LoadFlags;
import cgeo.geocaching.enumerations.LoadFlags.SaveFlag;
import cgeo.geocaching.utils.CancellableHandler;
+import cgeo.geocaching.utils.Log;
import org.apache.commons.lang3.StringUtils;
@@ -23,7 +24,6 @@ import android.content.res.Resources; import android.net.Uri;
import android.os.Handler;
import android.os.Message;
-import android.util.Log;
import java.io.File;
import java.io.FileInputStream;
@@ -34,7 +34,6 @@ import java.util.Collection; import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
-import java.util.Set;
import java.util.concurrent.CancellationException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
@@ -56,8 +55,8 @@ public class GPXImporter { public static final String WAYPOINTS_FILE_SUFFIX = "-wpts";
public static final String WAYPOINTS_FILE_SUFFIX_AND_EXTENSION = WAYPOINTS_FILE_SUFFIX + GPX_FILE_EXTENSION;
- private static final List<String> GPX_MIME_TYPES = Arrays.asList(new String[] { "text/xml", "application/xml" });
- private static final List<String> ZIP_MIME_TYPES = Arrays.asList(new String[] { "application/zip", "application/x-compressed", "application/x-zip-compressed", "application/x-zip", "application/octet-stream" });
+ private static final List<String> GPX_MIME_TYPES = Arrays.asList("text/xml", "application/xml");
+ private static final List<String> ZIP_MIME_TYPES = Arrays.asList("application/zip", "application/x-compressed", "application/x-zip-compressed", "application/x-zip", "application/octet-stream");
private Progress progress = new Progress();
@@ -113,7 +112,7 @@ public class GPXImporter { }
}
- Log.i(Settings.tag, "importGPX: " + uri + ", mimetype=" + mimeType);
+ Log.i("importGPX: " + uri + ", mimetype=" + mimeType);
if (GPX_MIME_TYPES.contains(mimeType)) {
new ImportGpxAttachmentThread(uri, contentResolver, listId, importStepHandler, progressHandler).start();
} else if (ZIP_MIME_TYPES.contains(mimeType)) {
@@ -143,25 +142,29 @@ public class GPXImporter { importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_STORE_CACHES, R.string.gpx_import_storing, caches.size()));
SearchResult search = storeParsedCaches(caches);
- Log.i(Settings.tag, "Imported successfully " + caches.size() + " caches.");
+ Log.i("Imported successfully " + caches.size() + " caches.");
if (Settings.isStoreOfflineMaps() || Settings.isStoreOfflineWpMaps()) {
importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_STORE_STATIC_MAPS, R.string.gpx_import_store_static_maps, search.getCount()));
- importStaticMaps(search);
+ boolean finishedWithoutCancel = importStaticMaps(search);
+ // Skip last message if static maps where canceled
+ if (!finishedWithoutCancel) {
+ return;
+ }
}
importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_FINISHED, search.getCount(), 0, search));
} catch (IOException e) {
- Log.i(Settings.tag, "Importing caches failed - error reading data: " + e.getMessage());
+ Log.i("Importing caches failed - error reading data: " + e.getMessage());
importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_FINISHED_WITH_ERROR, R.string.gpx_import_error_io, 0, e.getLocalizedMessage()));
} catch (ParserException e) {
- Log.i(Settings.tag, "Importing caches failed - data format error" + e.getMessage());
+ Log.i("Importing caches failed - data format error" + e.getMessage());
importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_FINISHED_WITH_ERROR, R.string.gpx_import_error_parser, 0, e.getLocalizedMessage()));
} catch (CancellationException e) {
- Log.i(Settings.tag, "Importing caches canceled");
+ Log.i("Importing caches canceled");
importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_CANCELED));
} catch (Exception e) {
- Log.e(Settings.tag, "Importing caches failed - unknown error: ", e);
+ Log.e("Importing caches failed - unknown error: ", e);
importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_FINISHED_WITH_ERROR, R.string.gpx_import_error_unexpected, 0, e.getLocalizedMessage()));
}
}
@@ -186,19 +189,20 @@ public class GPXImporter { return search;
}
- private void importStaticMaps(final SearchResult importedCaches) {
+ private boolean importStaticMaps(final SearchResult importedCaches) {
final cgeoapplication app = cgeoapplication.getInstance();
- Set<cgCache> caches = importedCaches.getCachesFromSearchResult(LoadFlags.LOAD_WAYPOINTS);
int storedCacheMaps = 0;
- for (cgCache cache : caches) {
- Log.d(Settings.tag, "GPXImporter.ImportThread.importStaticMaps start downloadMaps");
+ for (String geocode : importedCaches.getGeocodes()) {
+ cgCache cache = app.loadCache(geocode, LoadFlags.LOAD_WAYPOINTS);
+ Log.d("GPXImporter.ImportThread.importStaticMaps start downloadMaps for cache " + geocode);
StaticMapsProvider.downloadMaps(cache, app);
storedCacheMaps++;
if (progressHandler.isCancelled()) {
- return;
+ return false;
}
progressHandler.sendMessage(progressHandler.obtainMessage(0, storedCacheMaps, 0));
}
+ return true;
}
}
@@ -212,7 +216,7 @@ public class GPXImporter { @Override
protected Collection<cgCache> doImport() throws IOException, ParserException {
- Log.i(Settings.tag, "Import LOC file: " + file.getAbsolutePath());
+ Log.i("Import LOC file: " + file.getAbsolutePath());
importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_READ_FILE, R.string.gpx_import_loading_caches, (int) file.length()));
LocParser parser = new LocParser(listId);
return parser.parse(file, progressHandler);
@@ -249,7 +253,7 @@ public class GPXImporter { @Override
protected Collection<cgCache> doImport(GPXParser parser) throws IOException, ParserException {
- Log.i(Settings.tag, "Import GPX file: " + cacheFile.getAbsolutePath());
+ Log.i("Import GPX file: " + cacheFile.getAbsolutePath());
importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_READ_FILE, R.string.gpx_import_loading_caches, (int) cacheFile.length()));
Collection<cgCache> caches = parser.parse(cacheFile, progressHandler);
@@ -257,7 +261,7 @@ public class GPXImporter { if (wptsFilename != null) {
final File wptsFile = new File(cacheFile.getParentFile(), wptsFilename);
if (wptsFile.canRead()) {
- Log.i(Settings.tag, "Import GPX waypoint file: " + wptsFile.getAbsolutePath());
+ Log.i("Import GPX waypoint file: " + wptsFile.getAbsolutePath());
importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_READ_WPT_FILE, R.string.gpx_import_loading_waypoints, (int) wptsFile.length()));
caches = parser.parse(wptsFile, progressHandler);
}
@@ -278,7 +282,7 @@ public class GPXImporter { @Override
protected Collection<cgCache> doImport(GPXParser parser) throws IOException, ParserException {
- Log.i(Settings.tag, "Import GPX from uri: " + uri);
+ Log.i("Import GPX from uri: " + uri);
importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_READ_FILE, R.string.gpx_import_loading_caches, -1));
InputStream is = contentResolver.openInputStream(uri);
try {
@@ -343,7 +347,7 @@ public class GPXImporter { public ImportGpxZipFileThread(final File file, int listId, Handler importStepHandler, CancellableHandler progressHandler) {
super(listId, importStepHandler, progressHandler);
this.cacheFile = file;
- Log.i(Settings.tag, "Import zipped GPX: " + file);
+ Log.i("Import zipped GPX: " + file);
}
@Override
@@ -360,7 +364,7 @@ public class GPXImporter { super(listId, importStepHandler, progressHandler);
this.uri = uri;
this.contentResolver = contentResolver;
- Log.i(Settings.tag, "Import zipped GPX from uri: " + uri);
+ Log.i("Import zipped GPX from uri: " + uri);
}
@Override
@@ -377,6 +381,8 @@ public class GPXImporter { };
final private Handler importStepHandler = new Handler() {
+ private boolean showProgressAfterCancel = false;
+
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
@@ -387,9 +393,16 @@ public class GPXImporter { case IMPORT_STEP_READ_FILE:
case IMPORT_STEP_READ_WPT_FILE:
+ progress.setProgressDivider(1024);
+ progress.setMessage(res.getString(msg.arg1));
+ progress.setMaxProgressAndReset(msg.arg2);
+ break;
+
case IMPORT_STEP_STORE_CACHES:
+ progress.setProgressDivider(1);
progress.setMessage(res.getString(msg.arg1));
progress.setMaxProgressAndReset(msg.arg2);
+ showProgressAfterCancel = true;
break;
case IMPORT_STEP_STORE_STATIC_MAPS:
@@ -401,6 +414,7 @@ public class GPXImporter { case IMPORT_STEP_STATIC_MAPS_SKIPPED:
progress.dismiss();
+ progressHandler.cancel();
StringBuilder bufferSkipped = new StringBuilder(20);
bufferSkipped.append(res.getString(R.string.gpx_import_static_maps_skipped)).append(", ").append(msg.arg1).append(' ').append(res.getString(R.string.gpx_import_caches_imported));
fromActivity.helpDialog(res.getString(R.string.gpx_import_title_caches_imported), bufferSkipped.toString());
@@ -426,7 +440,10 @@ public class GPXImporter { case IMPORT_STEP_CANCELED:
StringBuilder bufferCanceled = new StringBuilder(20);
- bufferCanceled.append(res.getString(R.string.gpx_import_canceled)).append(", ").append(progress.getProgress()).append(' ').append(res.getString(R.string.gpx_import_caches_imported));
+ bufferCanceled.append(res.getString(R.string.gpx_import_canceled));
+ if (showProgressAfterCancel) {
+ bufferCanceled.append(", ").append(progress.getProgress()).append(' ').append(res.getString(R.string.gpx_import_caches_imported));
+ }
fromActivity.showShortToast(bufferCanceled.toString());
importFinished();
break;
diff --git a/main/src/cgeo/geocaching/files/GPXParser.java b/main/src/cgeo/geocaching/files/GPXParser.java index e4e4e3a..7870a16 100644 --- a/main/src/cgeo/geocaching/files/GPXParser.java +++ b/main/src/cgeo/geocaching/files/GPXParser.java @@ -1,10 +1,9 @@ package cgeo.geocaching.files; +import cgeo.geocaching.LogEntry; import cgeo.geocaching.R; -import cgeo.geocaching.Settings; import cgeo.geocaching.StoredList; import cgeo.geocaching.cgCache; -import cgeo.geocaching.cgLog; import cgeo.geocaching.cgTrackable; import cgeo.geocaching.cgWaypoint; import cgeo.geocaching.cgeoapplication; @@ -15,6 +14,7 @@ import cgeo.geocaching.enumerations.LogType; import cgeo.geocaching.enumerations.WaypointType; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.utils.CancellableHandler; +import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; import org.xml.sax.Attributes; @@ -25,7 +25,6 @@ import android.sax.EndElementListener; import android.sax.EndTextElementListener; import android.sax.RootElement; import android.sax.StartElementListener; -import android.util.Log; import android.util.Xml; import java.io.IOException; @@ -77,7 +76,7 @@ public abstract class GPXParser extends FileParser { private cgCache cache; private cgTrackable trackable = new cgTrackable(); - private cgLog log = new cgLog(); + private LogEntry log = null; private String type = null; private String sym = null; @@ -194,7 +193,7 @@ public abstract class GPXParser extends FileParser { return null; // id not found } // get text for string - String stringName = null; + String stringName; try { stringName = cgeoapplication.getInstance().getResources().getResourceName(stringId); } catch (NullPointerException e) { @@ -259,7 +258,7 @@ public abstract class GPXParser extends FileParser { Double.valueOf(attrs.getValue("lon")))); } } catch (Exception e) { - Log.w(Settings.tag, "Failed to parse waypoint's latitude and/or longitude."); + Log.w("Failed to parse waypoint's latitude and/or longitude."); } } }); @@ -295,7 +294,7 @@ public abstract class GPXParser extends FileParser { final String key = cache.getGeocode(); if (result.containsKey(key)) { - Log.w(Settings.tag, "Duplicate geocode during GPX import: " + key); + Log.w("Duplicate geocode during GPX import: " + key); } result.put(key, cache); showProgressMessage(progressHandler, progressStream.getProgress()); @@ -346,7 +345,7 @@ public abstract class GPXParser extends FileParser { try { cache.setHidden(parseDate(body)); } catch (Exception e) { - Log.w(Settings.tag, "Failed to parse cache date: " + e.toString()); + Log.w("Failed to parse cache date: " + e.toString()); } } }); @@ -437,7 +436,7 @@ public abstract class GPXParser extends FileParser { @Override public void end(String watchList) { - cache.setOnWatchlist(Boolean.valueOf(watchList.trim()).booleanValue()); + cache.setOnWatchlist(Boolean.valueOf(watchList.trim())); } }); @@ -468,7 +467,7 @@ public abstract class GPXParser extends FileParser { cache.setDisabled(!attrs.getValue("available").equalsIgnoreCase("true")); } } catch (Exception e) { - Log.w(Settings.tag, "Failed to parse cache attributes."); + Log.w("Failed to parse cache attributes."); } } }); @@ -548,7 +547,7 @@ public abstract class GPXParser extends FileParser { try { cache.setDifficulty(Float.parseFloat(body)); } catch (NumberFormatException e) { - Log.w(Settings.tag, "Failed to parse difficulty: " + e.toString()); + Log.w("Failed to parse difficulty: " + e.toString()); } } }); @@ -561,7 +560,7 @@ public abstract class GPXParser extends FileParser { try { cache.setTerrain(Float.parseFloat(body)); } catch (NumberFormatException e) { - Log.w(Settings.tag, "Failed to parse terrain: " + e.toString()); + Log.w("Failed to parse terrain: " + e.toString()); } } }); @@ -675,7 +674,7 @@ public abstract class GPXParser extends FileParser { @Override public void start(Attributes attrs) { - log = new cgLog(); + log = new LogEntry("", 0, LogType.LOG_UNKNOWN, ""); try { if (attrs.getIndex("id") > -1) { @@ -705,7 +704,7 @@ public abstract class GPXParser extends FileParser { try { log.date = parseDate(body).getTime(); } catch (Exception e) { - Log.w(Settings.tag, "Failed to parse log date: " + e.toString()); + Log.w("Failed to parse log date: " + e.toString()); } } }); @@ -744,7 +743,7 @@ public abstract class GPXParser extends FileParser { Xml.parse(progressStream, Xml.Encoding.UTF_8, root.getContentHandler()); return result.values(); } catch (SAXException e) { - Log.e(Settings.tag, "Cannot parse .gpx file as GPX " + version + ": could not parse XML - " + e.toString()); + Log.e("Cannot parse .gpx file as GPX " + version + ": could not parse XML - " + e.toString()); throw new ParserException("Cannot parse .gpx file as GPX " + version + ": could not parse XML", e); } } @@ -821,9 +820,9 @@ public abstract class GPXParser extends FileParser { private void createNoteFromGSAKUserdata() { if (StringUtils.isBlank(cache.getPersonalNote())) { final StringBuilder buffer = new StringBuilder(); - for (int i = 0; i < userData.length; i++) { - if (StringUtils.isNotBlank(userData[i])) { - buffer.append(' ').append(userData[i]); + for (final String anUserData : userData) { + if (StringUtils.isNotBlank(anUserData)) { + buffer.append(' ').append(anUserData); } } final String note = buffer.toString().trim(); diff --git a/main/src/cgeo/geocaching/files/LocParser.java b/main/src/cgeo/geocaching/files/LocParser.java index 029d049..b17b203 100644 --- a/main/src/cgeo/geocaching/files/LocParser.java +++ b/main/src/cgeo/geocaching/files/LocParser.java @@ -1,21 +1,17 @@ package cgeo.geocaching.files; import cgeo.geocaching.SearchResult; -import cgeo.geocaching.Settings; import cgeo.geocaching.cgCache; -import cgeo.geocaching.cgCoord; import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.enumerations.CacheSize; import cgeo.geocaching.enumerations.CacheType; import cgeo.geocaching.enumerations.LoadFlags; import cgeo.geocaching.geopoint.Geopoint; -import cgeo.geocaching.geopoint.GeopointParser; import cgeo.geocaching.utils.CancellableHandler; +import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; -import android.util.Log; - import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; @@ -30,6 +26,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; public final class LocParser extends FileParser { + private static final Pattern patternGeocode = Pattern .compile("name id=\"([^\"]+)\""); private static final Pattern patternLat = Pattern @@ -45,10 +42,21 @@ public final class LocParser extends FileParser { .compile("<container>([^<]+)</container>"); private static final Pattern patternName = Pattern.compile("CDATA\\[([^\\]]+)\\]"); + private static final CacheSize[] SIZES = { + CacheSize.NOT_CHOSEN, // 1 + CacheSize.MICRO, // 2 + CacheSize.REGULAR, // 3 + CacheSize.LARGE, // 4 + CacheSize.VIRTUAL, // 5 + CacheSize.OTHER, // 6 + CacheSize.UNKNOWN, // 7 + CacheSize.SMALL, // 8 + }; + private int listId; public static void parseLoc(final SearchResult searchResult, final String fileContent) { - final Map<String, cgCoord> cidCoords = parseCoordinates(fileContent); + final Map<String, cgCache> cidCoords = parseCoordinates(fileContent); // save found cache coordinates final HashSet<String> contained = new HashSet<String>(); @@ -59,12 +67,12 @@ public final class LocParser extends FileParser { } Set<cgCache> caches = cgeoapplication.getInstance().loadCaches(contained, LoadFlags.LOAD_CACHE_OR_DB); for (cgCache cache : caches) { - cgCoord coord = cidCoords.get(cache.getGeocode()); + cgCache coord = cidCoords.get(cache.getGeocode()); copyCoordToCache(coord, cache); } } - private static void copyCoordToCache(final cgCoord coord, final cgCache cache) { + private static void copyCoordToCache(final cgCache coord, final cgCache cache) { cache.setCoords(coord.getCoords()); cache.setDifficulty(coord.getDifficulty()); cache.setTerrain(coord.getTerrain()); @@ -76,9 +84,8 @@ public final class LocParser extends FileParser { } } - static Map<String, cgCoord> parseCoordinates( - final String fileContent) { - final Map<String, cgCoord> coords = new HashMap<String, cgCoord>(); + static Map<String, cgCache> parseCoordinates(final String fileContent) { + final Map<String, cgCache> coords = new HashMap<String, cgCache>(); if (StringUtils.isBlank(fileContent)) { return coords; } @@ -88,76 +95,25 @@ public final class LocParser extends FileParser { // parse coordinates for (String pointString : points) { - final cgCoord pointCoord = new cgCoord(); - - final Matcher matcherGeocode = patternGeocode.matcher(pointString); - if (matcherGeocode.find()) { - String geocode = matcherGeocode.group(1).trim().toUpperCase(); - pointCoord.setName(geocode); - pointCoord.setGeocode(geocode); - } - final Matcher matcherName = patternName.matcher(pointString); - if (matcherName.find()) { - String name = matcherName.group(1).trim(); - pointCoord.setName(StringUtils.substringBeforeLast(name, " by ").trim()); - // owner = StringUtils.substringAfterLast(" by ").trim(); - } - final Matcher matcherLat = patternLat.matcher(pointString); - final Matcher matcherLon = patternLon.matcher(pointString); - if (matcherLat.find() && matcherLon.find()) { - pointCoord.setCoords(parsePoint(matcherLat.group(1).trim(), matcherLon.group(1).trim())); - } - final Matcher matcherDifficulty = patternDifficulty.matcher(pointString); - if (matcherDifficulty.find()) { - pointCoord.setDifficulty(Float.parseFloat(matcherDifficulty.group(1).trim())); - } - final Matcher matcherTerrain = patternTerrain.matcher(pointString); - if (matcherTerrain.find()) { - pointCoord.setTerrain(Float.parseFloat(matcherTerrain.group(1).trim())); - } - final Matcher matcherContainer = patternContainer.matcher(pointString); - if (matcherContainer.find()) { - final int size = Integer.parseInt(matcherContainer.group(1) - .trim()); - - if (size == 1) { - pointCoord.setSize(CacheSize.NOT_CHOSEN); - } else if (size == 2) { - pointCoord.setSize(CacheSize.MICRO); - } else if (size == 3) { - pointCoord.setSize(CacheSize.REGULAR); - } else if (size == 4) { - pointCoord.setSize(CacheSize.LARGE); - } else if (size == 5) { - pointCoord.setSize(CacheSize.VIRTUAL); - } else if (size == 6) { - pointCoord.setSize(CacheSize.OTHER); - } else if (size == 8) { - pointCoord.setSize(CacheSize.SMALL); - } else { - pointCoord.setSize(CacheSize.UNKNOWN); - } - } - + final cgCache pointCoord = parseCache(pointString); if (StringUtils.isNotBlank(pointCoord.getGeocode())) { coords.put(pointCoord.getGeocode(), pointCoord); } } - Log.i(Settings.tag, - "Coordinates found in .loc file: " + coords.size()); + Log.i("Coordinates found in .loc file: " + coords.size()); return coords; } - private static Geopoint parsePoint(String latitude, String longitude) { + public static Geopoint parsePoint(final String latitude, final String longitude) { // the loc file contains the coordinates as plain floating point values, therefore avoid using the GeopointParser try { return new Geopoint(Double.valueOf(latitude), Double.valueOf(longitude)); } catch (NumberFormatException e) { - Log.e(Settings.tag, "LOC format has changed"); + Log.e("LOC format has changed"); } // fall back to parser, just in case the format changes - return GeopointParser.parse(latitude, longitude); + return new Geopoint(latitude, longitude); } public LocParser(int listId) { @@ -168,10 +124,10 @@ public final class LocParser extends FileParser { public Collection<cgCache> parse(InputStream stream, CancellableHandler progressHandler) throws IOException, ParserException { // TODO: progress reporting happens during reading stream only, not during parsing String streamContent = readStream(stream, progressHandler).toString(); - final Map<String, cgCoord> coords = parseCoordinates(streamContent); + final Map<String, cgCache> coords = parseCoordinates(streamContent); final List<cgCache> caches = new ArrayList<cgCache>(); - for (Entry<String, cgCoord> entry : coords.entrySet()) { - cgCoord coord = entry.getValue(); + for (Entry<String, cgCache> entry : coords.entrySet()) { + cgCache coord = entry.getValue(); if (StringUtils.isBlank(coord.getGeocode()) || StringUtils.isBlank(coord.getName())) { continue; } @@ -185,7 +141,50 @@ public final class LocParser extends FileParser { cache.setListId(listId); cache.setDetailed(true); } - Log.i(Settings.tag, "Caches found in .loc file: " + caches.size()); + Log.i("Caches found in .loc file: " + caches.size()); return caches; } + + public static cgCache parseCache(final String pointString) { + final cgCache cache = new cgCache(); + final Matcher matcherGeocode = patternGeocode.matcher(pointString); + if (matcherGeocode.find()) { + final String geocode = matcherGeocode.group(1).trim().toUpperCase(); + cache.setGeocode(geocode.toUpperCase()); + } + + final Matcher matcherName = patternName.matcher(pointString); + if (matcherName.find()) { + final String name = matcherName.group(1).trim(); + cache.setName(StringUtils.substringBeforeLast(name, " by ").trim()); + } else { + cache.setName(cache.getGeocode()); + } + + final Matcher matcherLat = patternLat.matcher(pointString); + final Matcher matcherLon = patternLon.matcher(pointString); + if (matcherLat.find() && matcherLon.find()) { + cache.setCoords(parsePoint(matcherLat.group(1).trim(), matcherLon.group(1).trim())); + } + + final Matcher matcherDifficulty = patternDifficulty.matcher(pointString); + if (matcherDifficulty.find()) { + cache.setDifficulty(Float.parseFloat(matcherDifficulty.group(1).trim())); + } + + final Matcher matcherTerrain = patternTerrain.matcher(pointString); + if (matcherTerrain.find()) { + cache.setTerrain(Float.parseFloat(matcherTerrain.group(1).trim())); + } + + final Matcher matcherContainer = patternContainer.matcher(pointString); + if (matcherContainer.find()) { + final int size = Integer.parseInt(matcherContainer.group(1).trim()); + if (size >= 1 && size <= 8) { + cache.setSize(SIZES[size - 1]); + } + } + + return cache; + } } diff --git a/main/src/cgeo/geocaching/files/LocalStorage.java b/main/src/cgeo/geocaching/files/LocalStorage.java index b5fa5f6..6853c08 100644 --- a/main/src/cgeo/geocaching/files/LocalStorage.java +++ b/main/src/cgeo/geocaching/files/LocalStorage.java @@ -1,18 +1,20 @@ package cgeo.geocaching.files; -import cgeo.geocaching.Settings; import cgeo.geocaching.utils.CryptUtils; +import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; +import org.apache.http.Header; import org.apache.http.HttpResponse; import android.os.Environment; -import android.util.Log; +import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; +import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -59,12 +61,7 @@ public class LocalStorage { */ static String getExtension(final String url) { final String urlExt = StringUtils.substringAfterLast(url, "."); - if (urlExt.length() > 4) { - return ""; - } else if (urlExt.length() > 0) { - return "." + urlExt; - } - return ""; + return urlExt.length() >= 1 && urlExt.length() <= 4 ? "." + urlExt : ""; } /** @@ -143,7 +140,7 @@ public class LocalStorage { * the entity whose content will be saved * @param targetFile * the target file, which will be created if necessary - * @return true if the operation was successful, false otherwise + * @return true if the operation was successful, false otherwise, in which case the file will not exist */ public static boolean saveEntityToFile(final HttpResponse response, final File targetFile) { if (response == null) { @@ -151,16 +148,65 @@ public class LocalStorage { } try { - return saveToFile(response.getEntity().getContent(), targetFile); + final boolean saved = saveToFile(response.getEntity().getContent(), targetFile); + saveHeader("etag", saved ? response : null, targetFile); + saveHeader("last-modified", saved ? response : null, targetFile); + return saved; } catch (IOException e) { - Log.e(Settings.tag, "LocalStorage.saveEntityToFile", e); + Log.e("LocalStorage.saveEntityToFile", e); } return false; } + private static void saveHeader(final String name, final HttpResponse response, final File baseFile) { + final Header header = response != null ? response.getFirstHeader(name) : null; + final File file = filenameForHeader(baseFile, name); + if (header == null) { + file.delete(); + } else { + saveToFile(new ByteArrayInputStream(header.getValue().getBytes()), file); + } + } + + private static File filenameForHeader(final File baseFile, final String name) { + return new File(baseFile.getAbsolutePath() + "-" + name); + } + + /** + * Get the saved header value for this file. + * + * @param baseFile + * the name of the cached resource + * @param name + * the name of the header ("etag" or "last-modified") + * @return null if no value has been cached, the value otherwise + */ + public static String getSavedHeader(final File baseFile, final String name) { + try { + final File file = filenameForHeader(baseFile, name); + final FileReader f = new FileReader(file); + try { + // No header will be more than 256 bytes + final char[] value = new char[256]; + final int count = f.read(value); + return new String(value, 0, count); + } finally { + f.close(); + } + } catch (final FileNotFoundException e) { + // Do nothing, the file does not exist + } catch (final Exception e) { + Log.w("could not read saved header " + name + " for " + baseFile, e); + } + return null; + } + /** * Save an HTTP response to a file. + * <p/> + * If the response could not be saved to the file due, for example, to a network error, + * the file will not exist when this method returns. * * @param entity * the entity whose content will be saved @@ -176,16 +222,18 @@ public class LocalStorage { try { try { final FileOutputStream fos = new FileOutputStream(targetFile); - try { - return copy(inputStream, fos); - } finally { - fos.close(); + final boolean written = copy(inputStream, fos); + fos.close(); + if (!written) { + targetFile.delete(); } + return written; } finally { inputStream.close(); } } catch (IOException e) { - Log.e(Settings.tag, "LocalStorage.saveToFile", e); + Log.e("LocalStorage.saveToFile", e); + targetFile.delete(); } return false; } @@ -208,7 +256,7 @@ public class LocalStorage { input = new FileInputStream(source); output = new FileOutputStream(destination); } catch (FileNotFoundException e) { - Log.e(Settings.tag, "LocalStorage.copy: could not open file", e); + Log.e("LocalStorage.copy: could not open file", e); if (input != null) { try { input.close(); @@ -225,7 +273,7 @@ public class LocalStorage { input.close(); output.close(); } catch (IOException e) { - Log.e(Settings.tag, "LocalStorage.copy: could not close file", e); + Log.e("LocalStorage.copy: could not close file", e); return false; } @@ -233,15 +281,16 @@ public class LocalStorage { } private static boolean copy(final InputStream input, final OutputStream output) { - byte[] buffer = new byte[4096]; + final byte[] buffer = new byte[4096]; int length; try { while ((length = input.read(buffer)) > 0) { output.write(buffer, 0, length); } - output.flush(); // FIXME: is that necessary? + // Flushing is only necessary if the stream is not immediately closed afterwards. + // We rely on all callers to do that correctly outside of this method } catch (IOException e) { - Log.e(Settings.tag, "LocalStorage.copy: error when copying data", e); + Log.e("LocalStorage.copy: error when copying data", e); return false; } @@ -267,7 +316,7 @@ public class LocalStorage { } } } - + return path.delete(); } diff --git a/main/src/cgeo/geocaching/filter/AbstractFilter.java b/main/src/cgeo/geocaching/filter/AbstractFilter.java index 49cf84a..e9f9003 100644 --- a/main/src/cgeo/geocaching/filter/AbstractFilter.java +++ b/main/src/cgeo/geocaching/filter/AbstractFilter.java @@ -26,4 +26,14 @@ abstract class AbstractFilter implements IFilter { public String getName() { return name; } + + /* + * show name in array adapter + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return getName(); + } } diff --git a/main/src/cgeo/geocaching/filter/AbstractRangeFilter.java b/main/src/cgeo/geocaching/filter/AbstractRangeFilter.java new file mode 100644 index 0000000..ff3fce5 --- /dev/null +++ b/main/src/cgeo/geocaching/filter/AbstractRangeFilter.java @@ -0,0 +1,16 @@ +package cgeo.geocaching.filter; + +import cgeo.geocaching.cgeoapplication; + + +abstract class AbstractRangeFilter extends AbstractFilter { + + protected final float rangeMin; + protected final float rangeMax; + + public AbstractRangeFilter(int ressourceId, int range) { + super(cgeoapplication.getInstance().getResources().getString(ressourceId) + ' ' + (range == 5 ? '5' : String.valueOf(range) + " + " + String.format("%.1f", range + 0.5))); + this.rangeMin = range; + rangeMax = rangeMin + 1f; + } +}
\ No newline at end of file diff --git a/main/src/cgeo/geocaching/filter/AttributeFilter.java b/main/src/cgeo/geocaching/filter/AttributeFilter.java index 7b8992b..2565178 100644 --- a/main/src/cgeo/geocaching/filter/AttributeFilter.java +++ b/main/src/cgeo/geocaching/filter/AttributeFilter.java @@ -11,7 +11,7 @@ import android.content.res.Resources; import java.util.EnumSet; -public class AttributeFilter extends AbstractFilter { +class AttributeFilter extends AbstractFilter { private final String attribute; @@ -41,16 +41,20 @@ public class AttributeFilter extends AbstractFilter { return fullCache.getAttributes().contains(attribute); } - public static IFilter[] getAllFilters() { - final String packageName = cgeoapplication.getInstance().getBaseContext().getPackageName(); - final Resources res = cgeoapplication.getInstance().getResources(); + public static class Factory implements IFilterFactory { - final String[] ids = res.getStringArray(R.array.attribute_ids); - final IFilter[] filters = new IFilter[ids.length]; - for (int i = 0; i < ids.length; i++) { - filters[i] = new AttributeFilter(getName("attribute_" + ids[i], res, packageName), ids[i]); + @Override + public IFilter[] getFilters() { + final String packageName = cgeoapplication.getInstance().getBaseContext().getPackageName(); + final Resources res = cgeoapplication.getInstance().getResources(); + + final String[] ids = res.getStringArray(R.array.attribute_ids); + final IFilter[] filters = new IFilter[ids.length]; + for (int i = 0; i < ids.length; i++) { + filters[i] = new AttributeFilter(getName("attribute_" + ids[i], res, packageName), ids[i]); + } + return filters; } - return filters; - } + } } diff --git a/main/src/cgeo/geocaching/filter/DifficultyFilter.java b/main/src/cgeo/geocaching/filter/DifficultyFilter.java new file mode 100644 index 0000000..368c20f --- /dev/null +++ b/main/src/cgeo/geocaching/filter/DifficultyFilter.java @@ -0,0 +1,31 @@ +package cgeo.geocaching.filter; + +import cgeo.geocaching.R; +import cgeo.geocaching.cgCache; + +import java.util.ArrayList; + +class DifficultyFilter extends AbstractRangeFilter { + + public DifficultyFilter(int difficulty) { + super(R.string.cache_difficulty, difficulty); + } + + @Override + public boolean accepts(cgCache cache) { + return rangeMin <= cache.getDifficulty() && cache.getDifficulty() < rangeMax; + } + + public static class Factory implements IFilterFactory { + + @Override + public IFilter[] getFilters() { + final ArrayList<IFilter> filters = new ArrayList<IFilter>(5); + for (int difficulty = 1; difficulty <= 5; difficulty++) { + filters.add(new DifficultyFilter(difficulty)); + } + return filters.toArray(new IFilter[filters.size()]); + } + + } +} diff --git a/main/src/cgeo/geocaching/filter/FilterUserInterface.java b/main/src/cgeo/geocaching/filter/FilterUserInterface.java new file mode 100644 index 0000000..1d22e52 --- /dev/null +++ b/main/src/cgeo/geocaching/filter/FilterUserInterface.java @@ -0,0 +1,122 @@ +package cgeo.geocaching.filter; + +import cgeo.geocaching.R; +import cgeo.geocaching.Settings; +import cgeo.geocaching.cgeoapplication; +import cgeo.geocaching.activity.IAbstractActivity; +import cgeo.geocaching.enumerations.CacheType; +import cgeo.geocaching.utils.Log; +import cgeo.geocaching.utils.RunnableWithArgument; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.content.res.Resources; +import android.widget.ArrayAdapter; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; + +public final class FilterUserInterface { + + private static class FactoryEntry { + private final String name; + private final Class<? extends IFilterFactory> filterFactory; + + public FactoryEntry(final String name, final Class<? extends IFilterFactory> filterFactory) { + this.name = name; + this.filterFactory = filterFactory; + } + + @Override + public String toString() { + return name; + } + } + + private final IAbstractActivity activity; + private final ArrayList<FactoryEntry> registry; + private final Resources res; + + public FilterUserInterface(final IAbstractActivity activity) { + this.activity = activity; + this.res = cgeoapplication.getInstance().getResources(); + + registry = new ArrayList<FactoryEntry>(); + if (Settings.getCacheType() == CacheType.ALL) { + register(R.string.caches_filter_type, TypeFilter.Factory.class); + } + register(R.string.caches_filter_size, SizeFilter.Factory.class); + register(R.string.cache_terrain, TerrainFilter.Factory.class); + register(R.string.cache_difficulty, DifficultyFilter.Factory.class); + register(R.string.cache_attributes, AttributeFilter.Factory.class); + register(R.string.cache_status, StateFilter.Factory.class); + register(R.string.caches_filter_track, TrackablesFilter.class); + register(R.string.caches_filter_modified, ModifiedFilter.class); + + // sort by localized names + Collections.sort(registry, new Comparator<FactoryEntry>() { + + @Override + public int compare(FactoryEntry lhs, FactoryEntry rhs) { + return lhs.name.compareToIgnoreCase(rhs.name); + } + }); + + // reset shall be last + register(R.string.caches_filter_clear, null); + } + + private void register(int resourceId, Class<? extends IFilterFactory> factoryClass) { + registry.add(new FactoryEntry(res.getString(resourceId), factoryClass)); + } + + public void selectFilter(final RunnableWithArgument<IFilter> runAfterwards) { + final AlertDialog.Builder builder = new AlertDialog.Builder((Activity) activity); + builder.setTitle(R.string.caches_filter); + + final ArrayAdapter<FactoryEntry> adapter = new ArrayAdapter<FactoryEntry>((Activity) activity, android.R.layout.select_dialog_item, registry); + + builder.setAdapter(adapter, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int itemIndex) { + FactoryEntry entry = adapter.getItem(itemIndex); + // reset? + if (entry.filterFactory == null) { + runAfterwards.run(null); + } + else { + try { + IFilterFactory factoryInstance = entry.filterFactory.newInstance(); + selectFromFactory(factoryInstance, entry.name, runAfterwards); + } catch (Exception e) { + Log.e("selectFilter", e); + } + } + } + }); + + builder.create().show(); + } + + private void selectFromFactory(final IFilterFactory factory, final String menuTitle, final RunnableWithArgument<IFilter> runAfterwards) { + final IFilter[] filters = factory.getFilters(); + if (filters.length == 1) { + runAfterwards.run(filters[0]); + return; + } + + final AlertDialog.Builder builder = new AlertDialog.Builder((Activity) activity); + builder.setTitle(menuTitle); + + final ArrayAdapter<IFilter> adapter = new ArrayAdapter<IFilter>((Activity) activity, android.R.layout.select_dialog_item, filters); + builder.setAdapter(adapter, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int item) { + runAfterwards.run(filters[item]); + } + }); + + builder.create().show(); + } + +} diff --git a/main/src/cgeo/geocaching/filter/IFilterFactory.java b/main/src/cgeo/geocaching/filter/IFilterFactory.java new file mode 100644 index 0000000..3491fd7 --- /dev/null +++ b/main/src/cgeo/geocaching/filter/IFilterFactory.java @@ -0,0 +1,5 @@ +package cgeo.geocaching.filter; + +interface IFilterFactory { + public IFilter[] getFilters(); +} diff --git a/main/src/cgeo/geocaching/filter/ModifiedFilter.java b/main/src/cgeo/geocaching/filter/ModifiedFilter.java index 6063f58..f74bb4d 100644 --- a/main/src/cgeo/geocaching/filter/ModifiedFilter.java +++ b/main/src/cgeo/geocaching/filter/ModifiedFilter.java @@ -1,11 +1,13 @@ package cgeo.geocaching.filter; +import cgeo.geocaching.R; import cgeo.geocaching.cgCache; +import cgeo.geocaching.cgeoapplication; -public class ModifiedFilter extends AbstractFilter { +class ModifiedFilter extends AbstractFilter implements IFilterFactory { - public ModifiedFilter(String name) { - super(name); + public ModifiedFilter() { + super(cgeoapplication.getInstance().getString(R.string.caches_filter_modified)); } @Override @@ -13,4 +15,9 @@ public class ModifiedFilter extends AbstractFilter { // modified on GC return cache.hasUserModifiedCoords() || cache.hasFinalDefined(); } + + @Override + public IFilter[] getFilters() { + return new IFilter[] { this }; + } } diff --git a/main/src/cgeo/geocaching/filter/SizeFilter.java b/main/src/cgeo/geocaching/filter/SizeFilter.java index 4f0d830..b08c2ae 100644 --- a/main/src/cgeo/geocaching/filter/SizeFilter.java +++ b/main/src/cgeo/geocaching/filter/SizeFilter.java @@ -5,7 +5,7 @@ import cgeo.geocaching.enumerations.CacheSize; import java.util.ArrayList; -public class SizeFilter extends AbstractFilter { +class SizeFilter extends AbstractFilter { private final CacheSize cacheSize; public SizeFilter(CacheSize cacheSize) { @@ -23,14 +23,19 @@ public class SizeFilter extends AbstractFilter { return cacheSize.getL10n(); } - public static AbstractFilter[] getAllFilters() { - final CacheSize[] cacheSizes = CacheSize.values(); - ArrayList<SizeFilter> filters = new ArrayList<SizeFilter>(); - for (CacheSize cacheSize : cacheSizes) { - if (cacheSize != CacheSize.UNKNOWN) { - filters.add(new SizeFilter(cacheSize)); + public static class Factory implements IFilterFactory { + + @Override + public IFilter[] getFilters() { + final CacheSize[] cacheSizes = CacheSize.values(); + final ArrayList<SizeFilter> filters = new ArrayList<SizeFilter>(); + for (CacheSize cacheSize : cacheSizes) { + if (cacheSize != CacheSize.UNKNOWN) { + filters.add(new SizeFilter(cacheSize)); + } } + return filters.toArray(new SizeFilter[filters.size()]); } - return filters.toArray(new SizeFilter[filters.size()]); + } } diff --git a/main/src/cgeo/geocaching/filter/StateFilter.java b/main/src/cgeo/geocaching/filter/StateFilter.java index 454cc92..b086477 100644 --- a/main/src/cgeo/geocaching/filter/StateFilter.java +++ b/main/src/cgeo/geocaching/filter/StateFilter.java @@ -10,16 +10,18 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; -public abstract class StateFilter extends AbstractFilter { +abstract class StateFilter extends AbstractFilter { - public StateFilter(String name) { + final static Resources res = cgeoapplication.getInstance().getResources(); + + protected StateFilter(String name) { super(name); } - private static class StateFoundFilter extends StateFilter { + static class StateFoundFilter extends StateFilter { - public StateFoundFilter(String name) { - super(name); + public StateFoundFilter() { + super(res.getString(R.string.cache_status_found)); } @Override @@ -29,9 +31,9 @@ public abstract class StateFilter extends AbstractFilter { } - private static class StateArchivedFilter extends StateFilter { - public StateArchivedFilter(String name) { - super(name); + static class StateArchivedFilter extends StateFilter { + public StateArchivedFilter() { + super(res.getString(R.string.cache_status_archived)); } @Override @@ -40,9 +42,9 @@ public abstract class StateFilter extends AbstractFilter { } } - private static class StateDisabledFilter extends StateFilter { - public StateDisabledFilter(String name) { - super(name); + static class StateDisabledFilter extends StateFilter { + public StateDisabledFilter() { + super(res.getString(R.string.cache_status_disabled)); } @Override @@ -51,9 +53,9 @@ public abstract class StateFilter extends AbstractFilter { } } - private static class StatePremiumFilter extends StateFilter { - public StatePremiumFilter(String name) { - super(name); + static class StatePremiumFilter extends StateFilter { + public StatePremiumFilter() { + super(res.getString(R.string.cache_status_premium)); } @Override @@ -63,8 +65,8 @@ public abstract class StateFilter extends AbstractFilter { } private static class StateOfflineLogFilter extends StateFilter { - public StateOfflineLogFilter(String name) { - super(name); + public StateOfflineLogFilter() { + super(res.getString(R.string.cache_status_offline_log)); } @Override @@ -73,24 +75,28 @@ public abstract class StateFilter extends AbstractFilter { } } - public static AbstractFilter[] getAllFilters() { - final Resources res = cgeoapplication.getInstance().getResources(); - final ArrayList<StateFilter> filters = new ArrayList<StateFilter>(); - filters.add(new StateFoundFilter(res.getString(R.string.cache_status_found))); - filters.add(new StateArchivedFilter(res.getString(R.string.cache_status_archived))); - filters.add(new StateDisabledFilter(res.getString(R.string.cache_status_disabled))); - filters.add(new StatePremiumFilter(res.getString(R.string.cache_status_premium))); - filters.add(new StateOfflineLogFilter(res.getString(R.string.cache_status_offline_log))); - - Collections.sort(filters, new Comparator<StateFilter>() { + public static class Factory implements IFilterFactory { - @Override - public int compare(StateFilter filter1, StateFilter filter2) { - return filter1.getName().compareToIgnoreCase(filter2.getName()); - } - }); + @Override + public IFilter[] getFilters() { + final ArrayList<StateFilter> filters = new ArrayList<StateFilter>(); + filters.add(new StateFoundFilter()); + filters.add(new StateArchivedFilter()); + filters.add(new StateDisabledFilter()); + filters.add(new StatePremiumFilter()); + filters.add(new StateOfflineLogFilter()); + + Collections.sort(filters, new Comparator<StateFilter>() { + + @Override + public int compare(StateFilter filter1, StateFilter filter2) { + return filter1.getName().compareToIgnoreCase(filter2.getName()); + } + }); + + return filters.toArray(new StateFilter[filters.size()]); + } - return filters.toArray(new StateFilter[filters.size()]); } } diff --git a/main/src/cgeo/geocaching/filter/TerrainFilter.java b/main/src/cgeo/geocaching/filter/TerrainFilter.java new file mode 100644 index 0000000..5cee87e --- /dev/null +++ b/main/src/cgeo/geocaching/filter/TerrainFilter.java @@ -0,0 +1,31 @@ +package cgeo.geocaching.filter; + + +import cgeo.geocaching.R; +import cgeo.geocaching.cgCache; + +import java.util.ArrayList; + +class TerrainFilter extends AbstractRangeFilter { + + public TerrainFilter(int terrain) { + super(R.string.cache_terrain, terrain); + } + + @Override + public boolean accepts(cgCache cache) { + return rangeMin <= cache.getTerrain() && cache.getTerrain() < rangeMax; + } + + public static class Factory implements IFilterFactory { + @Override + public IFilter[] getFilters() { + final ArrayList<IFilter> filters = new ArrayList<IFilter>(5); + for (int terrain = 1; terrain <= 5; terrain++) { + filters.add(new TerrainFilter(terrain)); + } + return filters.toArray(new IFilter[filters.size()]); + } + } + +} diff --git a/main/src/cgeo/geocaching/filter/TrackablesFilter.java b/main/src/cgeo/geocaching/filter/TrackablesFilter.java index 99d888b..90def5b 100644 --- a/main/src/cgeo/geocaching/filter/TrackablesFilter.java +++ b/main/src/cgeo/geocaching/filter/TrackablesFilter.java @@ -1,14 +1,22 @@ package cgeo.geocaching.filter; +import cgeo.geocaching.R; import cgeo.geocaching.cgCache; +import cgeo.geocaching.cgeoapplication; -public class TrackablesFilter extends AbstractFilter { - public TrackablesFilter(String name) { - super(name); +class TrackablesFilter extends AbstractFilter implements IFilterFactory { + public TrackablesFilter() { + super(cgeoapplication.getInstance().getString(R.string.caches_filter_track)); } @Override public boolean accepts(cgCache cache) { return cache.hasTrackables(); } + + @Override + public IFilter[] getFilters() { + return new IFilter[] { this }; + } + } diff --git a/main/src/cgeo/geocaching/filter/TypeFilter.java b/main/src/cgeo/geocaching/filter/TypeFilter.java index bb32fdd..05b97e0 100644 --- a/main/src/cgeo/geocaching/filter/TypeFilter.java +++ b/main/src/cgeo/geocaching/filter/TypeFilter.java @@ -5,7 +5,7 @@ import cgeo.geocaching.enumerations.CacheType; import java.util.ArrayList; -public class TypeFilter extends AbstractFilter { +class TypeFilter extends AbstractFilter { private final CacheType cacheType; public TypeFilter(final CacheType cacheType) { @@ -23,14 +23,19 @@ public class TypeFilter extends AbstractFilter { return cacheType.getL10n(); } - public static IFilter[] getAllFilters() { - final CacheType[] types = CacheType.values(); - ArrayList<IFilter> filters = new ArrayList<IFilter>(types.length); - for (CacheType cacheType : types) { - if (cacheType != CacheType.ALL) { - filters.add(new TypeFilter(cacheType)); + public static class Factory implements IFilterFactory { + + @Override + public IFilter[] getFilters() { + final CacheType[] types = CacheType.values(); + final ArrayList<IFilter> filters = new ArrayList<IFilter>(types.length); + for (CacheType cacheType : types) { + if (cacheType != CacheType.ALL) { + filters.add(new TypeFilter(cacheType)); + } } + return filters.toArray(new IFilter[filters.size()]); } - return filters.toArray(new TypeFilter[filters.size()]); + } } diff --git a/main/src/cgeo/geocaching/gcvote/GCVote.java b/main/src/cgeo/geocaching/gcvote/GCVote.java index fa2af0d..5a00009 100644 --- a/main/src/cgeo/geocaching/gcvote/GCVote.java +++ b/main/src/cgeo/geocaching/gcvote/GCVote.java @@ -4,19 +4,17 @@ import cgeo.geocaching.Settings; import cgeo.geocaching.cgCache; import cgeo.geocaching.network.Network; import cgeo.geocaching.network.Parameters; -import cgeo.geocaching.utils.LeastRecentlyUsedCache; +import cgeo.geocaching.utils.LeastRecentlyUsedMap; +import cgeo.geocaching.utils.Log; import org.apache.commons.collections.MapUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.ImmutablePair; -import android.util.Log; - import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Map.Entry; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -29,7 +27,7 @@ public final class GCVote { private static final Pattern patternVoteElement = Pattern.compile("<vote ([^>]+)>", Pattern.CASE_INSENSITIVE); private static final int MAX_CACHED_RATINGS = 1000; - private static LeastRecentlyUsedCache<String, GCVoteRating> ratingsCache = new LeastRecentlyUsedCache<String, GCVoteRating>(MAX_CACHED_RATINGS); + private static LeastRecentlyUsedMap<String, GCVoteRating> ratingsCache = new LeastRecentlyUsedMap.LruCache<String, GCVoteRating>(MAX_CACHED_RATINGS); /** * Get user rating for a given guid or geocode. For a guid first the ratings cache is checked @@ -59,13 +57,12 @@ public final class GCVote { } final Map<String, GCVoteRating> ratings = getRating(guids, geocodes); - if (ratings != null) { - for (Entry<String, GCVoteRating> entry : ratings.entrySet()) { - return entry.getValue(); - } + + if (MapUtils.isEmpty(ratings)) { + return null; } - return null; + return ratings.values().iterator().next(); } /** @@ -96,12 +93,12 @@ public final class GCVote { params.put("waypoints", StringUtils.join(geocodes.toArray(), ',')); } params.put("version", "cgeo"); - final String page = Network.getResponseData(Network.request("http://gcvote.com/getVotes.php", params, false, false, false)); + final String page = Network.getResponseData(Network.getRequest("http://gcvote.com/getVotes.php", params)); if (page == null) { return null; } - String voteData = null; + String voteData; final Matcher matcherVoteElement = patternVoteElement.matcher(page); while (matcherVoteElement.find()) { voteData = matcherVoteElement.group(1); @@ -118,7 +115,7 @@ public final class GCVote { } } } catch (Exception e) { - Log.w(Settings.tag, "GCVote.getRating: Failed to parse guid"); + Log.w("GCVote.getRating: Failed to parse guid"); } if (guid == null) { continue; @@ -135,7 +132,7 @@ public final class GCVote { } } } catch (Exception e) { - Log.w(Settings.tag, "GCVote.getRating: Failed to parse loggedIn"); + Log.w("GCVote.getRating: Failed to parse loggedIn"); } float rating = 0; @@ -145,7 +142,7 @@ public final class GCVote { rating = Float.parseFloat(matcherRating.group(1)); } } catch (Exception e) { - Log.w(Settings.tag, "GCVote.getRating: Failed to parse rating"); + Log.w("GCVote.getRating: Failed to parse rating"); } if (rating <= 0) { continue; @@ -158,7 +155,7 @@ public final class GCVote { votes = Integer.parseInt(matcherVotes.group(1)); } } catch (Exception e) { - Log.w(Settings.tag, "GCVote.getRating: Failed to parse vote count"); + Log.w("GCVote.getRating: Failed to parse vote count"); } if (votes < 0) { continue; @@ -172,7 +169,7 @@ public final class GCVote { myVote = Float.parseFloat(matcherVote.group(1)); } } catch (Exception e) { - Log.w(Settings.tag, "GCVote.getRating: Failed to parse user's vote"); + Log.w("GCVote.getRating: Failed to parse user's vote"); } } @@ -183,7 +180,7 @@ public final class GCVote { } } } catch (Exception e) { - Log.e(Settings.tag, "GCVote.getRating: " + e.toString()); + Log.e("GCVote.getRating: " + e.toString()); } return ratings; @@ -220,7 +217,7 @@ public final class GCVote { "voteUser", String.format("%.1f", vote).replace(',', '.'), "version", "cgeo"); - final String result = Network.getResponseData(Network.request("http://gcvote.com/setVote.php", params, false, false, false)); + final String result = Network.getResponseData(Network.getRequest("http://gcvote.com/setVote.php", params)); return result.trim().equalsIgnoreCase("ok"); } @@ -258,7 +255,7 @@ public final class GCVote { } } } catch (Exception e) { - Log.e(Settings.tag, "GCvote.loadRatings: " + e.toString()); + Log.e("GCvote.loadRatings: " + e.toString()); } } } diff --git a/main/src/cgeo/geocaching/geopoint/Geopoint.java b/main/src/cgeo/geocaching/geopoint/Geopoint.java index be4a622..974c902 100644 --- a/main/src/cgeo/geocaching/geopoint/Geopoint.java +++ b/main/src/cgeo/geocaching/geopoint/Geopoint.java @@ -1,25 +1,28 @@ package cgeo.geocaching.geopoint; -import cgeo.geocaching.Settings; +import cgeo.geocaching.ICoordinates; +import cgeo.geocaching.R; import cgeo.geocaching.geopoint.GeopointFormatter.Format; +import cgeo.geocaching.geopoint.direction.DDD; +import cgeo.geocaching.geopoint.direction.DMM; +import cgeo.geocaching.geopoint.direction.DMS; +import cgeo.geocaching.geopoint.direction.Direction; import cgeo.geocaching.network.Network; import cgeo.geocaching.network.Parameters; +import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; import org.json.JSONArray; import org.json.JSONObject; import android.location.Location; -import android.util.Log; - -import java.math.BigDecimal; -import java.math.RoundingMode; +import android.os.Parcel; +import android.os.Parcelable; /** * Abstraction of geographic point. */ -public final class Geopoint -{ +public final class Geopoint implements ICoordinates, Parcelable { public static final double deg2rad = Math.PI / 180; public static final double rad2deg = 180 / Math.PI; public static final float erad = 6371.0f; @@ -47,29 +50,18 @@ public final class Geopoint } /** - * Creates new Geopoint with given latitude and longitude (both microdegree). - * - * @param lat - * latitude - * @param lon - * longitude - */ - public Geopoint(final int lat, final int lon) - { - this(lat / 1e6, lon / 1e6); - } - - /** * Creates new Geopoint with latitude and longitude parsed from string. * * @param text * string to parse - * @throws GeopointParser.ParseException + * @throws Geopoint.ParseException * if the string cannot be parsed - * @see GeopointParser.parse() + * @see GeopointParser#parse(String) */ public Geopoint(final String text) { - this(GeopointParser.parseLatitude(text), GeopointParser.parseLongitude(text)); + final Geopoint parsed = GeopointParser.parse(text); + this.latitude = parsed.latitude; + this.longitude = parsed.longitude; } /** @@ -79,9 +71,9 @@ public final class Geopoint * latitude string to parse * @param lonText * longitude string to parse - * @throws GeopointParser.ParseException + * @throws Geopoint.ParseException * if any argument string cannot be parsed - * @see GeopointParser.parse() + * @see GeopointParser#parse(String, String) */ public Geopoint(final String latText, final String lonText) { this(GeopointParser.parseLatitude(latText), GeopointParser.parseLongitude(lonText)); @@ -90,7 +82,7 @@ public final class Geopoint /** * Creates new Geopoint with given Location. * - * @param gp + * @param loc * the Location to clone */ public Geopoint(final Location loc) { @@ -98,6 +90,17 @@ public final class Geopoint } /** + * Create new Geopoint from Parcel. + * + * @param in + * a Parcel to read the saved data from + */ + public Geopoint(final Parcel in) { + latitude = in.readDouble(); + longitude = in.readDouble(); + } + + /** * Get latitude in degree. * * @return latitude @@ -114,7 +117,7 @@ public final class Geopoint */ public int getLatitudeE6() { - return (int) (latitude * 1E6); + return (int) Math.round(latitude * 1E6); } /** @@ -134,7 +137,7 @@ public final class Geopoint */ public int getLongitudeE6() { - return (int) (longitude * 1E6); + return (int) Math.round(longitude * 1E6); } /** @@ -200,16 +203,21 @@ public final class Geopoint return new Geopoint(rlat * rad2deg, rlon * rad2deg); } - /** - * Checks if given Geopoint is identical with this Geopoint. - * - * @param gp - * Geopoint to check - * @return true if identical, false otherwise - */ - public boolean isEqualTo(Geopoint gp) - { - return null != gp && gp.latitude == latitude && gp.longitude == longitude; + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null || !(obj instanceof Geopoint)) { + return false; + } + final Geopoint gp = (Geopoint) obj; + return getLatitudeE6() == gp.getLatitudeE6() && getLongitudeE6() == gp.getLongitudeE6(); + } + + @Override + public int hashCode() { + return getLatitudeE6() ^ getLongitudeE6(); } /** @@ -242,7 +250,7 @@ public final class Geopoint /** * Returns formatted coordinates with default format. * Default format is decimalminutes, e.g. N 52° 36.123 E 010° 03.456 - * + * * @return formatted coordinates */ @Override @@ -299,188 +307,27 @@ public final class Geopoint return dms; } - /* Constant values needed for calculation */ - private static final double D60 = 60.0d; - private static final double D1000 = 1000.0d; - private static final double D3600 = 3600.0d; - private static final BigDecimal BD_SIXTY = BigDecimal.valueOf(D60); - private static final BigDecimal BD_THOUSAND = BigDecimal.valueOf(D1000); - private static final BigDecimal BD_ONEHOUNDREDTHOUSAND = BigDecimal.valueOf(100000.0d); - - /** - * Value type for the direction. - */ - public static class Direction { - /** latitude direction, 'N' or 'S' */ - public final char latDir; - /** longitude direction, 'E' or 'W' */ - public final char lonDir; - - private Direction(final double latSigned, final double lonSigned) { - latDir = latSigned < 0 ? 'S' : 'N'; - lonDir = lonSigned < 0 ? 'W' : 'E'; - } - - protected static String addZeros(final int value, final int len) { - return StringUtils.leftPad(Integer.toString(value), len, '0'); - } - } - - /** - * Value type for the DDD.DDDDD format. - */ - public static final class DDD extends Direction { - - /** latitude degree value */ - public final int latDeg; - /** fractional part of the latitude degree value */ - public final int latDegFrac; - - public final int lonDeg; - public final int lonDegFrac; - - private DDD(final double latSigned, final double lonSigned) { - super(latSigned, lonSigned); - BigDecimal bdLat = BigDecimal.valueOf(latSigned).abs(); - latDeg = bdLat.intValue(); - BigDecimal bdLatFrac = bdLat.subtract(BigDecimal.valueOf(latDeg)).multiply(BD_ONEHOUNDREDTHOUSAND); - latDegFrac = bdLatFrac.setScale(0, RoundingMode.HALF_UP).intValue(); - - BigDecimal bdlon = BigDecimal.valueOf(lonSigned).abs(); - lonDeg = bdlon.intValue(); - BigDecimal bdLonFrac = bdlon.subtract(BigDecimal.valueOf(lonDeg)).multiply(BD_ONEHOUNDREDTHOUSAND); - lonDegFrac = bdLonFrac.setScale(0, RoundingMode.HALF_UP).intValue(); - } - - public static Geopoint createGeopoint(final String latDir, final String latDeg, final String latDegFrac, - final String lonDir, final String lonDeg, final String lonDegFrac) { - double lat = 0.0d; - double lon = 0.0d; - try { - lat = Double.parseDouble(latDeg + "." + addZeros(Integer.parseInt(latDegFrac), 5)); - lon = Double.parseDouble(lonDeg + "." + addZeros(Integer.parseInt(lonDegFrac), 5)); - } catch (NumberFormatException e) { - } - lat *= "S".equalsIgnoreCase(latDir) ? -1 : 1; - lon *= "W".equalsIgnoreCase(lonDir) ? -1 : 1; - return new Geopoint(lat, lon); - } - } - - public static final class DMM extends Direction { - - public final int latDeg; - public final double latMinRaw; - public final int latMin; - public final int latMinFrac; - - public final int lonDeg; - public final double lonMinRaw; - public final int lonMin; - public final int lonMinFrac; - - private DMM(final double latSigned, final double lonSigned) { - super(latSigned, lonSigned); - BigDecimal bdLat = BigDecimal.valueOf(latSigned).abs(); - latDeg = bdLat.intValue(); - BigDecimal bdLatMin = bdLat.subtract(BigDecimal.valueOf(latDeg)).multiply(BD_SIXTY); - // Rounding here ... - bdLatMin = bdLatMin.setScale(3, RoundingMode.HALF_UP); - latMinRaw = bdLatMin.doubleValue(); - latMin = bdLatMin.intValue(); - BigDecimal bdLatMinFrac = bdLatMin.subtract(BigDecimal.valueOf(latMin)).multiply(BD_THOUSAND); - latMinFrac = bdLatMinFrac.setScale(0, RoundingMode.HALF_UP).intValue(); - - BigDecimal bdlon = BigDecimal.valueOf(lonSigned).abs(); - lonDeg = bdlon.intValue(); - BigDecimal bdLonMin = bdlon.subtract(BigDecimal.valueOf(lonDeg)).multiply(BD_SIXTY); - // Rounding here ... - bdLonMin = bdLonMin.setScale(3, RoundingMode.HALF_UP); - lonMinRaw = bdLonMin.doubleValue(); - lonMin = bdLonMin.intValue(); - BigDecimal bdLonMinFrac = bdLonMin.subtract(BigDecimal.valueOf(lonMin)).multiply(BD_THOUSAND); - lonMinFrac = bdLonMinFrac.setScale(0, RoundingMode.HALF_UP).intValue(); - } - - public static Geopoint createGeopoint(final String latDir, final String latDeg, final String latMin, final String latMinFrac, - final String lonDir, final String lonDeg, final String lonMin, final String lonMinFrac) { - double lat = 0.0d; - double lon = 0.0d; - try { - lat = Double.parseDouble(latDeg) + Double.parseDouble(latMin + "." + addZeros(Integer.parseInt(latMinFrac), 3)) / D60; - lon = Double.parseDouble(lonDeg) + Double.parseDouble(lonMin + "." + addZeros(Integer.parseInt(lonMinFrac), 3)) / D60; - } catch (NumberFormatException e) { - } - lat *= "S".equalsIgnoreCase(latDir) ? -1 : 1; - lon *= "W".equalsIgnoreCase(lonDir) ? -1 : 1; - return new Geopoint(lat, lon); - } - } - - public static final class DMS extends Direction { - - public final int latDeg; - public final int latMin; - public final double latSecRaw; - public final int latSec; - public final int latSecFrac; - - public final int lonDeg; - public final int lonMin; - public final double lonSecRaw; - public final int lonSec; - public final int lonSecFrac; - - private DMS(final double latSigned, final double lonSigned) { - super(latSigned, lonSigned); - BigDecimal bdLat = BigDecimal.valueOf(latSigned).abs(); - latDeg = bdLat.intValue(); - BigDecimal bdLatMin = bdLat.subtract(BigDecimal.valueOf(latDeg)).multiply(BD_SIXTY); - latMin = bdLatMin.intValue(); - BigDecimal bdLatSec = bdLatMin.subtract(BigDecimal.valueOf(latMin)).multiply(BD_SIXTY); - // Rounding here ... - bdLatSec = bdLatSec.setScale(3, RoundingMode.HALF_UP); - latSecRaw = bdLatSec.doubleValue(); - latSec = bdLatSec.intValue(); - BigDecimal bdLatSecFrac = bdLatSec.subtract(BigDecimal.valueOf(latSec)).multiply(BD_THOUSAND); - latSecFrac = bdLatSecFrac.setScale(0, RoundingMode.HALF_UP).intValue(); - - BigDecimal bdlon = BigDecimal.valueOf(lonSigned).abs(); - lonDeg = bdlon.intValue(); - BigDecimal bdLonMin = bdlon.subtract(BigDecimal.valueOf(lonDeg)).multiply(BD_SIXTY); - lonMin = bdLonMin.intValue(); - BigDecimal bdLonSec = bdLonMin.subtract(BigDecimal.valueOf(lonMin)).multiply(BD_SIXTY); - // Rounding here ... - bdLonSec = bdLonSec.setScale(3, RoundingMode.HALF_UP); - lonSecRaw = bdLonSec.doubleValue(); - lonSec = bdLonSec.intValue(); - BigDecimal bdLonSecFrac = bdLonSec.subtract(BigDecimal.valueOf(lonSec)).multiply(BD_THOUSAND); - lonSecFrac = bdLonSecFrac.setScale(0, RoundingMode.HALF_UP).intValue(); - } + abstract public static class GeopointException + extends RuntimeException + { + private static final long serialVersionUID = 1L; - public static Geopoint createGeopoint(final String latDir, final String latDeg, final String latMin, final String latSec, final String latSecFrac, - final String lonDir, final String lonDeg, final String lonMin, final String lonSec, final String lonSecFrac) { - double lat = 0.0d; - double lon = 0.0d; - try { - lat = Double.parseDouble(latDeg) + Double.parseDouble(latMin) / D60 + Double.parseDouble(latSec + "." + addZeros(Integer.parseInt(latSecFrac), 3)) / D3600; - lon = Double.parseDouble(lonDeg) + Double.parseDouble(lonMin) / D60 + Double.parseDouble(lonSec + "." + addZeros(Integer.parseInt(lonSecFrac), 3)) / D3600; - } catch (NumberFormatException e) { - } - lat *= "S".equalsIgnoreCase(latDir) ? -1 : 1; - lon *= "W".equalsIgnoreCase(lonDir) ? -1 : 1; - return new Geopoint(lat, lon); + public GeopointException(String msg) + { + super(msg); } } - abstract public static class GeopointException - extends RuntimeException + public static class ParseException + extends GeopointException { private static final long serialVersionUID = 1L; + public final int resource; - public GeopointException(String msg) + public ParseException(final String msg, final GeopointParser.LatLon faulty) { super(msg); + resource = faulty == GeopointParser.LatLon.LAT ? R.string.err_parse_lat : R.string.err_parse_lon; } } @@ -506,10 +353,38 @@ public final class Geopoint return result.getDouble("elevation"); } } catch (Exception e) { - Log.w(Settings.tag, "cgBase.getElevation: " + e.toString()); + Log.w("cgBase.getElevation: " + e.toString()); } return null; } + //FIXME: this interface implementation is totally confusing as it returns the class itself. + // it can therefore be removed completely (and any invocation of it) without any disadvantages + @Override + public Geopoint getCoords() { + return this; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(final Parcel dest, final int flags) { + dest.writeDouble(latitude); + dest.writeDouble(longitude); + } + + public static final Parcelable.Creator<Geopoint> CREATOR = new Parcelable.Creator<Geopoint>() { + public Geopoint createFromParcel(final Parcel in) { + return new Geopoint(in); + } + + public Geopoint[] newArray(final int size) { + return new Geopoint[size]; + } + }; + } diff --git a/main/src/cgeo/geocaching/geopoint/GeopointFormatter.java b/main/src/cgeo/geocaching/geopoint/GeopointFormatter.java index d0baee9..43f83a3 100644 --- a/main/src/cgeo/geocaching/geopoint/GeopointFormatter.java +++ b/main/src/cgeo/geocaching/geopoint/GeopointFormatter.java @@ -1,7 +1,7 @@ package cgeo.geocaching.geopoint; -import cgeo.geocaching.geopoint.Geopoint.DMM; -import cgeo.geocaching.geopoint.Geopoint.DMS; +import cgeo.geocaching.geopoint.direction.DMM; +import cgeo.geocaching.geopoint.direction.DMS; import java.util.Locale; diff --git a/main/src/cgeo/geocaching/geopoint/GeopointParser.java b/main/src/cgeo/geocaching/geopoint/GeopointParser.java index ad5d6ba..7604b9d 100644 --- a/main/src/cgeo/geocaching/geopoint/GeopointParser.java +++ b/main/src/cgeo/geocaching/geopoint/GeopointParser.java @@ -1,7 +1,5 @@ package cgeo.geocaching.geopoint; -import cgeo.geocaching.R; -import cgeo.geocaching.geopoint.Geopoint.GeopointException; import org.apache.commons.lang3.StringUtils; @@ -11,8 +9,7 @@ import java.util.regex.Pattern; /** * Parse coordinates. */ -public class GeopointParser -{ +class GeopointParser { private static class ResultWrapper { final double result; final int matcherPos; @@ -29,7 +26,7 @@ public class GeopointParser private static final Pattern patternLat = Pattern.compile("\\b([NS])\\s*(\\d+)°?(?:\\s*(\\d+)(?:[.,](\\d+)|'?\\s*(\\d+(?:[.,]\\d+)?)(?:''|\")?)?)?", Pattern.CASE_INSENSITIVE); private static final Pattern patternLon = Pattern.compile("\\b([WE])\\s*(\\d+)°?(?:\\s*(\\d+)(?:[.,](\\d+)|'?\\s*(\\d+(?:[.,]\\d+)?)(?:''|\")?)?)?", Pattern.CASE_INSENSITIVE); - private enum LatLon + enum LatLon { LAT, LON @@ -52,7 +49,7 @@ public class GeopointParser * @param text * the string to parse * @return an Geopoint with parsed latitude and longitude - * @throws ParseException + * @throws Geopoint.ParseException * if lat or lon could not be parsed */ public static Geopoint parse(final String text) @@ -63,7 +60,7 @@ public class GeopointParser final ResultWrapper longitudeWrapper = parseHelper(text.substring(latitudeWrapper.matcherPos + latitudeWrapper.matcherLength), LatLon.LON); if (longitudeWrapper.matcherPos - (latitudeWrapper.matcherPos + latitudeWrapper.matcherLength) >= 10) { - throw new ParseException("Distance between latitude and longitude text is to large.", LatLon.LON); + throw new Geopoint.ParseException("Distance between latitude and longitude text is to large.", LatLon.LON); } final double lon = longitudeWrapper.result; @@ -89,7 +86,7 @@ public class GeopointParser * @param longitude * the longitude string to parse * @return an Geopoint with parsed latitude and longitude - * @throws ParseException + * @throws Geopoint.ParseException * if lat or lon could not be parsed */ public static Geopoint parse(final String latitude, final String longitude) @@ -129,32 +126,31 @@ public class GeopointParser return new ResultWrapper(sign * (degree + minutes / 60.0 + seconds / 3600.0), matcher.start(), matcher.group().length()); - } else { + } - // Nothing found with "N 52...", try to match string as decimaldegree - try { - final String[] items = StringUtils.split(text.trim()); - if (items.length > 0) { - final int index = (latlon == LatLon.LON ? items.length - 1 : 0); - final int pos = (latlon == LatLon.LON ? text.lastIndexOf(items[index]) : text.indexOf(items[index])); - return new ResultWrapper(Double.parseDouble(items[index]), pos, items[index].length()); - } - } catch (NumberFormatException e) { - // The right exception will be raised below. + // Nothing found with "N 52...", try to match string as decimaldegree + try { + final String[] items = StringUtils.split(text.trim()); + if (items.length > 0) { + final int index = (latlon == LatLon.LON ? items.length - 1 : 0); + final int pos = (latlon == LatLon.LON ? text.lastIndexOf(items[index]) : text.indexOf(items[index])); + return new ResultWrapper(Double.parseDouble(items[index]), pos, items[index].length()); } + } catch (NumberFormatException e) { + // The right exception will be raised below. } - throw new ParseException("Could not parse coordinates as " + latlon + ": \"" + text + "\"", latlon); + throw new Geopoint.ParseException("Could not parse coordinates as " + latlon + ": \"" + text + "\"", latlon); } /** * Parses latitude out of a given string. * - * @see parse() + * @see #parse(String) * @param text * the string to be parsed * @return the latitude as decimal degree - * @throws ParseException + * @throws Geopoint.ParseException * if latitude could not be parsed */ public static double parseLatitude(final String text) @@ -165,28 +161,15 @@ public class GeopointParser /** * Parses longitude out of a given string. * - * @see parse() + * @see #parse(String) * @param text * the string to be parsed * @return the longitude as decimal degree - * @throws ParseException + * @throws Geopoint.ParseException * if longitude could not be parsed */ public static double parseLongitude(final String text) { return parseHelper(text, LatLon.LON).result; } - - public static class ParseException - extends GeopointException - { - private static final long serialVersionUID = 1L; - public final int resource; - - public ParseException(final String msg, final LatLon faulty) - { - super(msg); - resource = faulty == LatLon.LAT ? R.string.err_parse_lat : R.string.err_parse_lon; - } - } } diff --git a/main/src/cgeo/geocaching/geopoint/HumanDistance.java b/main/src/cgeo/geocaching/geopoint/HumanDistance.java index 278bb7b..25d1bb7 100644 --- a/main/src/cgeo/geocaching/geopoint/HumanDistance.java +++ b/main/src/cgeo/geocaching/geopoint/HumanDistance.java @@ -2,41 +2,48 @@ package cgeo.geocaching.geopoint; import cgeo.geocaching.Settings; +import org.apache.commons.lang3.tuple.ImmutablePair; + public class HumanDistance { - public static String getHumanDistance(final Float distanceKilometers) { - if (distanceKilometers == null) { - return "?"; - } + public static ImmutablePair<Double, String> scaleUnit(final double distanceKilometers) { + double distance; + String units; if (Settings.isUseMetricUnits()) { - if (distanceKilometers > 100) { - return String.format("%d", Math.round(distanceKilometers)) + " km"; - } else if (distanceKilometers > 10) { - return String.format("%.1f", Double.valueOf(Math.round(distanceKilometers * 10.0) / 10.0)) + " km"; - } else if (distanceKilometers > 1) { - return String.format("%.2f", Double.valueOf(Math.round(distanceKilometers * 100.0) / 100.0)) + " km"; - } else if (distanceKilometers > 0.1) { - return String.format("%d", Math.round(distanceKilometers * 1000.0)) + " m"; - } else if (distanceKilometers > 0.01) { - return String.format("%.1f", Double.valueOf(Math.round(distanceKilometers * 1000.0 * 10.0) / 10.0)) + " m"; + if (distanceKilometers >= 1) { + distance = distanceKilometers; + units = "km"; } else { - return String.format("%.2f", Double.valueOf(Math.round(distanceKilometers * 1000.0 * 100.0) / 100.0)) + " m"; + distance = distanceKilometers * 1000; + units = "m"; } } else { - final float miles = distanceKilometers / IConversion.MILES_TO_KILOMETER; - if (distanceKilometers > 100) { - return String.format("%d", Math.round(miles)) + " mi"; - } else if (distanceKilometers > 0.5) { - return String.format("%.1f", Double.valueOf(Math.round(miles * 10.0) / 10.0)) + " mi"; - } else if (distanceKilometers > 0.1) { - return String.format("%.2f", Double.valueOf(Math.round(miles * 100.0) / 100.0)) + " mi"; - } else if (distanceKilometers > 0.05) { - return String.format("%d", Math.round(miles * 5280.0)) + " ft"; - } else if (distanceKilometers > 0.01) { - return String.format("%.1f", Double.valueOf(Math.round(miles * 5280 * 10.0) / 10.0)) + " ft"; + distance = distanceKilometers / IConversion.MILES_TO_KILOMETER; + if (distance >= 0.1) { + units = "mi"; } else { - return String.format("%.2f", Double.valueOf(Math.round(miles * 5280 * 100.0) / 100.0)) + " ft"; + distance *= 5280; + units = "ft"; } } + return new ImmutablePair<Double, String>(distance, units); + } + + public static String getHumanDistance(final Float distanceKilometers) { + if (distanceKilometers == null) { + return "?"; + } + + final ImmutablePair<Double, String> scaled = scaleUnit(distanceKilometers); + String formatString; + if (scaled.left >= 100) { + formatString = "%.0f"; + } else if (scaled.left >= 10) { + formatString = "%.1f"; + } else { + formatString = "%.2f"; + } + + return String.format(formatString + " %s", scaled.left, scaled.right); } } diff --git a/main/src/cgeo/geocaching/geopoint/Viewport.java b/main/src/cgeo/geocaching/geopoint/Viewport.java index 4d46970..1eeadce 100644 --- a/main/src/cgeo/geocaching/geopoint/Viewport.java +++ b/main/src/cgeo/geocaching/geopoint/Viewport.java @@ -1,8 +1,11 @@ package cgeo.geocaching.geopoint; -import cgeo.geocaching.Settings; +import cgeo.geocaching.ICoordinates; + +import java.util.Locale; +import java.util.Set; + -import android.util.Log; public class Viewport { @@ -10,19 +13,25 @@ public class Viewport { public final Geopoint bottomLeft; public final Geopoint topRight; - public Viewport(final Geopoint bottomLeft, final Geopoint topRight) { - this.bottomLeft = bottomLeft; - this.topRight = topRight; - this.center = new Geopoint((bottomLeft.getLatitude() + topRight.getLatitude()) / 2, - (bottomLeft.getLongitude() + topRight.getLongitude()) / 2); + public Viewport(final ICoordinates point1, final ICoordinates point2) { + final Geopoint gp1 = point1.getCoords(); + final Geopoint gp2 = point2.getCoords(); + this.bottomLeft = new Geopoint(Math.min(gp1.getLatitude(), gp2.getLatitude()), + Math.min(gp1.getLongitude(), gp2.getLongitude())); + this.topRight = new Geopoint(Math.max(gp1.getLatitude(), gp2.getLatitude()), + Math.max(gp1.getLongitude(), gp2.getLongitude())); + this.center = new Geopoint((gp1.getLatitude() + gp2.getLatitude()) / 2, + (gp1.getLongitude() + gp2.getLongitude()) / 2); } - public Viewport(final Geopoint center, final double latSpan, final double lonSpan) { - this.center = center; - final double centerLat = center.getLatitude(); - final double centerLon = center.getLongitude(); - bottomLeft = new Geopoint(centerLat - latSpan / 2, centerLon - lonSpan / 2); - topRight = new Geopoint(centerLat + latSpan / 2, centerLon + lonSpan / 2); + public Viewport(final ICoordinates center, final double latSpan, final double lonSpan) { + this.center = center.getCoords(); + final double centerLat = this.center.getLatitude(); + final double centerLon = this.center.getLongitude(); + final double latHalfSpan = Math.abs(latSpan) / 2; + final double lonHalfSpan = Math.abs(lonSpan) / 2; + bottomLeft = new Geopoint(centerLat - latHalfSpan, centerLon - lonHalfSpan); + topRight = new Geopoint(centerLat + latHalfSpan, centerLon + lonHalfSpan); } public double getLatitudeMin() { @@ -45,78 +54,125 @@ public class Viewport { return center; } + public double getLatitudeSpan() { + return getLatitudeMax() - getLatitudeMin(); + } + + public double getLongitudeSpan() { + return getLongitudeMax() - getLongitudeMin(); + } + + /** + * Check whether a point is contained in this viewport. + * + * @param point + * the coordinates to check + * @return true if the point is contained in this viewport, false otherwise + */ + public boolean contains(final ICoordinates point) { + final Geopoint coords = point.getCoords(); + return coords.getLongitudeE6() >= bottomLeft.getLongitudeE6() + && coords.getLongitudeE6() <= topRight.getLongitudeE6() + && coords.getLatitudeE6() >= bottomLeft.getLatitudeE6() + && coords.getLatitudeE6() <= topRight.getLatitudeE6(); + } + @Override public String toString() { return "(" + bottomLeft.toString() + "," + topRight.toString() + ")"; } /** - * Check if coordinates are located in a viewport (defined by its center and span - * in each direction). + * Check whether another viewport is fully included into the current one. * - * @param centerLat - * the viewport center latitude - * @param centerLon - * the viewport center longitude - * @param spanLat - * the latitude span - * @param spanLon - * the longitude span - * @param coords - * the coordinates to check - * @return true if the coordinates are in the viewport + * @param vp + * the other viewport + * @return true if the vp is fully included into this one, false otherwise */ - public static boolean isCacheInViewPort(int centerLat, int centerLon, int spanLat, int spanLon, final Geopoint coords) { - return 2 * Math.abs(coords.getLatitudeE6() - centerLat) <= Math.abs(spanLat) && - 2 * Math.abs(coords.getLongitudeE6() - centerLon) <= Math.abs(spanLon); + public boolean includes(final Viewport vp) { + return contains(vp.bottomLeft) && contains(vp.topRight); } /** - * Check if an area is located in a viewport (defined by its center and span - * in each direction). + * Return the "where" part of the string appropriate for a SQL query. * - * expects coordinates in E6 format + * @param dbTable + * the database table to use as prefix, or null if no prefix is required + * @return the string without the "where" keyword + */ + public String sqlWhere(final String dbTable) { + final String prefix = dbTable == null ? "" : (dbTable + "."); + return String.format((Locale) null, + "%slatitude >= %s and %slatitude <= %s and %slongitude >= %s and %slongitude <= %s", + prefix, getLatitudeMin(), prefix, getLatitudeMax(), prefix, getLongitudeMin(), prefix, getLongitudeMax()); + } + + /** + * Return a widened or shrunk viewport. * - * @param centerLat1 - * @param centerLon1 - * @param centerLat2 - * @param centerLon2 - * @param spanLat1 - * @param spanLon1 - * @param spanLat2 - * @param spanLon2 - * @return + * @param factor + * multiplicative factor for the latitude and longitude span (> 1 to widen, < 1 to shrink) + * @return a widened or shrunk viewport */ - public static boolean isInViewPort(int centerLat1, int centerLon1, int centerLat2, int centerLon2, int spanLat1, int spanLon1, int spanLat2, int spanLon2) { - try { - final int left1 = centerLat1 - (spanLat1 / 2); - final int left2 = centerLat2 - (spanLat2 / 2); - if (left2 <= left1) { - return false; - } + public Viewport resize(final double factor) { + return new Viewport(getCenter(), getLatitudeSpan() * factor, getLongitudeSpan() * factor); + } - final int right1 = centerLat1 + (spanLat1 / 2); - final int right2 = centerLat2 + (spanLat2 / 2); - if (right2 >= right1) { - return false; - } + /** + * Return a viewport that contains the current viewport as well as another point. + * + * @param coords + * the point we want in the viewport + * @return either the same or an expanded viewport + */ + public Viewport expand(final ICoordinates point) { + if (contains(point)) { + return this; + } - final int top1 = centerLon1 + (spanLon1 / 2); - final int top2 = centerLon2 + (spanLon2 / 2); - if (top2 >= top1) { - return false; - } + final Geopoint coords = point.getCoords(); + final double latitude = coords.getLatitude(); + final double longitude = coords.getLongitude(); + final double latMin = Math.min(getLatitudeMin(), latitude); + final double latMax = Math.max(getLatitudeMax(), latitude); + final double lonMin = Math.min(getLongitudeMin(), longitude); + final double lonMax = Math.max(getLongitudeMax(), longitude); + return new Viewport(new Geopoint(latMin, lonMin), new Geopoint(latMax, lonMax)); + } - final int bottom1 = centerLon1 - (spanLon1 / 2); - final int bottom2 = centerLon2 - (spanLon2 / 2); - if (bottom2 <= bottom1) { - return false; + /** + * Return the smallest viewport containing all the given points. + * + * @param points + * a set of points. Point with null coordinates (or null themselves) will be ignored + * @return the smallest viewport containing the non-null coordinates, or null if no coordinates are non-null + */ + static public Viewport containing(final Set<? extends ICoordinates> points) { + Viewport viewport = null; + for (final ICoordinates point : points) { + if (point != null && point.getCoords() != null) { + if (viewport == null) { + viewport = new Viewport(point, point); + } else { + viewport = viewport.expand(point); + } } + } + return viewport; + } - return true; - } catch (Exception e) { - Log.e(Settings.tag, "Viewport.isInViewPort: " + e.toString()); + @Override + public boolean equals(final Object other) { + if (other == null || !(other instanceof Viewport)) { return false; } + final Viewport vp = (Viewport) other; + return bottomLeft.equals(vp.bottomLeft) && topRight.equals(vp.topRight); } + + @Override + public int hashCode() { + return bottomLeft.hashCode() ^ topRight.hashCode(); + } + } diff --git a/main/src/cgeo/geocaching/geopoint/direction/DDD.java b/main/src/cgeo/geocaching/geopoint/direction/DDD.java new file mode 100644 index 0000000..939d6ca --- /dev/null +++ b/main/src/cgeo/geocaching/geopoint/direction/DDD.java @@ -0,0 +1,47 @@ +package cgeo.geocaching.geopoint.direction; + +import cgeo.geocaching.geopoint.Geopoint; + +import java.math.BigDecimal; +import java.math.RoundingMode; + +/** + * Value type for the DDD.DDDDD format. + */ +public final class DDD extends Direction { + + /** latitude degree value */ + public final int latDeg; + /** fractional part of the latitude degree value */ + public final int latDegFrac; + + public final int lonDeg; + public final int lonDegFrac; + + public DDD(final double latSigned, final double lonSigned) { + super(latSigned, lonSigned); + BigDecimal bdLat = BigDecimal.valueOf(latSigned).abs(); + latDeg = bdLat.intValue(); + BigDecimal bdLatFrac = bdLat.subtract(BigDecimal.valueOf(latDeg)).multiply(BD_ONEHOUNDREDTHOUSAND); + latDegFrac = bdLatFrac.setScale(0, RoundingMode.HALF_UP).intValue(); + + BigDecimal bdlon = BigDecimal.valueOf(lonSigned).abs(); + lonDeg = bdlon.intValue(); + BigDecimal bdLonFrac = bdlon.subtract(BigDecimal.valueOf(lonDeg)).multiply(BD_ONEHOUNDREDTHOUSAND); + lonDegFrac = bdLonFrac.setScale(0, RoundingMode.HALF_UP).intValue(); + } + + public static Geopoint createGeopoint(final String latDir, final String latDeg, final String latDegFrac, + final String lonDir, final String lonDeg, final String lonDegFrac) { + double lat = 0.0d; + double lon = 0.0d; + try { + lat = Double.parseDouble(latDeg + "." + addZeros(Integer.parseInt(latDegFrac), 5)); + lon = Double.parseDouble(lonDeg + "." + addZeros(Integer.parseInt(lonDegFrac), 5)); + } catch (NumberFormatException e) { + } + lat *= "S".equalsIgnoreCase(latDir) ? -1 : 1; + lon *= "W".equalsIgnoreCase(lonDir) ? -1 : 1; + return new Geopoint(lat, lon); + } +}
\ No newline at end of file diff --git a/main/src/cgeo/geocaching/geopoint/direction/DMM.java b/main/src/cgeo/geocaching/geopoint/direction/DMM.java new file mode 100644 index 0000000..7426f28 --- /dev/null +++ b/main/src/cgeo/geocaching/geopoint/direction/DMM.java @@ -0,0 +1,56 @@ +package cgeo.geocaching.geopoint.direction; + +import cgeo.geocaching.geopoint.Geopoint; + +import java.math.BigDecimal; +import java.math.RoundingMode; + +public final class DMM extends Direction { + + public final int latDeg; + public final double latMinRaw; + public final int latMin; + public final int latMinFrac; + + public final int lonDeg; + public final double lonMinRaw; + public final int lonMin; + public final int lonMinFrac; + + public DMM(final double latSigned, final double lonSigned) { + super(latSigned, lonSigned); + BigDecimal bdLat = BigDecimal.valueOf(latSigned).abs(); + latDeg = bdLat.intValue(); + BigDecimal bdLatMin = bdLat.subtract(BigDecimal.valueOf(latDeg)).multiply(BD_SIXTY); + // Rounding here ... + bdLatMin = bdLatMin.setScale(3, RoundingMode.HALF_UP); + latMinRaw = bdLatMin.doubleValue(); + latMin = bdLatMin.intValue(); + BigDecimal bdLatMinFrac = bdLatMin.subtract(BigDecimal.valueOf(latMin)).multiply(BD_THOUSAND); + latMinFrac = bdLatMinFrac.setScale(0, RoundingMode.HALF_UP).intValue(); + + BigDecimal bdlon = BigDecimal.valueOf(lonSigned).abs(); + lonDeg = bdlon.intValue(); + BigDecimal bdLonMin = bdlon.subtract(BigDecimal.valueOf(lonDeg)).multiply(BD_SIXTY); + // Rounding here ... + bdLonMin = bdLonMin.setScale(3, RoundingMode.HALF_UP); + lonMinRaw = bdLonMin.doubleValue(); + lonMin = bdLonMin.intValue(); + BigDecimal bdLonMinFrac = bdLonMin.subtract(BigDecimal.valueOf(lonMin)).multiply(BD_THOUSAND); + lonMinFrac = bdLonMinFrac.setScale(0, RoundingMode.HALF_UP).intValue(); + } + + public static Geopoint createGeopoint(final String latDir, final String latDeg, final String latMin, final String latMinFrac, + final String lonDir, final String lonDeg, final String lonMin, final String lonMinFrac) { + double lat = 0.0d; + double lon = 0.0d; + try { + lat = Double.parseDouble(latDeg) + Double.parseDouble(latMin + "." + addZeros(Integer.parseInt(latMinFrac), 3)) / D60; + lon = Double.parseDouble(lonDeg) + Double.parseDouble(lonMin + "." + addZeros(Integer.parseInt(lonMinFrac), 3)) / D60; + } catch (NumberFormatException e) { + } + lat *= "S".equalsIgnoreCase(latDir) ? -1 : 1; + lon *= "W".equalsIgnoreCase(lonDir) ? -1 : 1; + return new Geopoint(lat, lon); + } +}
\ No newline at end of file diff --git a/main/src/cgeo/geocaching/geopoint/direction/DMS.java b/main/src/cgeo/geocaching/geopoint/direction/DMS.java new file mode 100644 index 0000000..34a9a3d --- /dev/null +++ b/main/src/cgeo/geocaching/geopoint/direction/DMS.java @@ -0,0 +1,62 @@ +package cgeo.geocaching.geopoint.direction; + +import cgeo.geocaching.geopoint.Geopoint; + +import java.math.BigDecimal; +import java.math.RoundingMode; + +public final class DMS extends Direction { + + public final int latDeg; + public final int latMin; + public final double latSecRaw; + public final int latSec; + public final int latSecFrac; + + public final int lonDeg; + public final int lonMin; + public final double lonSecRaw; + public final int lonSec; + public final int lonSecFrac; + + public DMS(final double latSigned, final double lonSigned) { + super(latSigned, lonSigned); + BigDecimal bdLat = BigDecimal.valueOf(latSigned).abs(); + latDeg = bdLat.intValue(); + BigDecimal bdLatMin = bdLat.subtract(BigDecimal.valueOf(latDeg)).multiply(BD_SIXTY); + latMin = bdLatMin.intValue(); + BigDecimal bdLatSec = bdLatMin.subtract(BigDecimal.valueOf(latMin)).multiply(BD_SIXTY); + // Rounding here ... + bdLatSec = bdLatSec.setScale(3, RoundingMode.HALF_UP); + latSecRaw = bdLatSec.doubleValue(); + latSec = bdLatSec.intValue(); + BigDecimal bdLatSecFrac = bdLatSec.subtract(BigDecimal.valueOf(latSec)).multiply(BD_THOUSAND); + latSecFrac = bdLatSecFrac.setScale(0, RoundingMode.HALF_UP).intValue(); + + BigDecimal bdlon = BigDecimal.valueOf(lonSigned).abs(); + lonDeg = bdlon.intValue(); + BigDecimal bdLonMin = bdlon.subtract(BigDecimal.valueOf(lonDeg)).multiply(BD_SIXTY); + lonMin = bdLonMin.intValue(); + BigDecimal bdLonSec = bdLonMin.subtract(BigDecimal.valueOf(lonMin)).multiply(BD_SIXTY); + // Rounding here ... + bdLonSec = bdLonSec.setScale(3, RoundingMode.HALF_UP); + lonSecRaw = bdLonSec.doubleValue(); + lonSec = bdLonSec.intValue(); + BigDecimal bdLonSecFrac = bdLonSec.subtract(BigDecimal.valueOf(lonSec)).multiply(BD_THOUSAND); + lonSecFrac = bdLonSecFrac.setScale(0, RoundingMode.HALF_UP).intValue(); + } + + public static Geopoint createGeopoint(final String latDir, final String latDeg, final String latMin, final String latSec, final String latSecFrac, + final String lonDir, final String lonDeg, final String lonMin, final String lonSec, final String lonSecFrac) { + double lat = 0.0d; + double lon = 0.0d; + try { + lat = Double.parseDouble(latDeg) + Double.parseDouble(latMin) / D60 + Double.parseDouble(latSec + "." + addZeros(Integer.parseInt(latSecFrac), 3)) / D3600; + lon = Double.parseDouble(lonDeg) + Double.parseDouble(lonMin) / D60 + Double.parseDouble(lonSec + "." + addZeros(Integer.parseInt(lonSecFrac), 3)) / D3600; + } catch (NumberFormatException e) { + } + lat *= "S".equalsIgnoreCase(latDir) ? -1 : 1; + lon *= "W".equalsIgnoreCase(lonDir) ? -1 : 1; + return new Geopoint(lat, lon); + } +}
\ No newline at end of file diff --git a/main/src/cgeo/geocaching/geopoint/direction/Direction.java b/main/src/cgeo/geocaching/geopoint/direction/Direction.java new file mode 100644 index 0000000..ad91516 --- /dev/null +++ b/main/src/cgeo/geocaching/geopoint/direction/Direction.java @@ -0,0 +1,29 @@ +package cgeo.geocaching.geopoint.direction; + +import org.apache.commons.lang3.StringUtils; + +import java.math.BigDecimal; + +public class Direction { + /* Constant values needed for calculation */ + static final double D60 = 60.0d; + private static final double D1000 = 1000.0d; + static final double D3600 = 3600.0d; + static final BigDecimal BD_SIXTY = BigDecimal.valueOf(D60); + static final BigDecimal BD_THOUSAND = BigDecimal.valueOf(D1000); + static final BigDecimal BD_ONEHOUNDREDTHOUSAND = BigDecimal.valueOf(100000.0d); + + /** latitude direction, 'N' or 'S' */ + public final char latDir; + /** longitude direction, 'E' or 'W' */ + public final char lonDir; + + public Direction(final double latSigned, final double lonSigned) { + latDir = latSigned < 0 ? 'S' : 'N'; + lonDir = lonSigned < 0 ? 'W' : 'E'; + } + + protected static String addZeros(final int value, final int len) { + return StringUtils.leftPad(Integer.toString(value), len, '0'); + } +}
\ No newline at end of file diff --git a/main/src/cgeo/geocaching/go4cache/Go4Cache.java b/main/src/cgeo/geocaching/go4cache/Go4Cache.java index fb53c27..b0a7b35 100644 --- a/main/src/cgeo/geocaching/go4cache/Go4Cache.java +++ b/main/src/cgeo/geocaching/go4cache/Go4Cache.java @@ -1,7 +1,6 @@ package cgeo.geocaching.go4cache; import cgeo.geocaching.Settings; -import cgeo.geocaching.cgBase; import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.geopoint.GeopointFormatter.Format; @@ -9,13 +8,15 @@ import cgeo.geocaching.geopoint.Viewport; import cgeo.geocaching.network.Network; import cgeo.geocaching.network.Parameters; import cgeo.geocaching.utils.CryptUtils; +import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; -import android.util.Log; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; import java.text.ParseException; import java.text.SimpleDateFormat; @@ -41,6 +42,7 @@ public final class Go4Cache extends Thread { private final static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 2010-07-25 14:44:01 final private ArrayBlockingQueue<Geopoint> queue = new ArrayBlockingQueue<Geopoint>(1); + private String packageVersion; public static Go4Cache getInstance() { // no need to be synchronized return InstanceHolder.INSTANCE; @@ -48,10 +50,22 @@ public final class Go4Cache extends Thread { private Go4Cache() { // private singleton constructor super("Go4Cache"); + initializeVersion(); setPriority(Thread.MIN_PRIORITY); start(); } + private void initializeVersion() { + try { + final PackageManager manager = cgeoapplication.getInstance().getPackageManager(); + final PackageInfo info = manager.getPackageInfo(cgeoapplication.getInstance().getPackageName(), 0); + packageVersion = info.versionName; + } catch (PackageManager.NameNotFoundException e) { + Log.e("unable to get version information", e); + packageVersion = null; + } + } + /** * Send the coordinates to go4cache.com if the user opted in to do so. * @@ -68,7 +82,7 @@ public final class Go4Cache extends Thread { @Override public void run() { - Log.d(Settings.tag, "Go4Cache task started"); + Log.d("Go4Cache task started"); Geopoint latestCoords = null; String latestAction = null; @@ -96,8 +110,8 @@ public final class Go4Cache extends Thread { "ln", lonStr, "a", currentAction, "s", (CryptUtils.sha1(username + "|" + latStr + "|" + lonStr + "|" + currentAction + "|" + CryptUtils.md5("carnero: developing your dreams"))).toLowerCase()); - if (null != cgBase.version) { - params.put("v", cgBase.version); + if (null != packageVersion) { + params.put("v", packageVersion); } Network.postRequest("http://api.go4cache.com/", params); @@ -108,7 +122,7 @@ public final class Go4Cache extends Thread { latestAction = currentAction; } } catch (InterruptedException e) { - Log.e(Settings.tag, "Go4Cache.run: interrupted", e); + Log.e("Go4Cache.run: interrupted", e); } } @@ -138,7 +152,7 @@ public final class Go4Cache extends Thread { final String data = Network.getResponseData(Network.postRequest("http://api.go4cache.com/get.php", params)); if (StringUtils.isBlank(data)) { - Log.e(Settings.tag, "cgeoBase.getGeocachersInViewport: No data from server"); + Log.e("cgeoBase.getGeocachersInViewport: No data from server"); return null; } @@ -150,7 +164,7 @@ public final class Go4Cache extends Thread { users.add(parseUser(oneUser)); } } catch (Exception e) { - Log.e(Settings.tag, "cgBase.getGeocachersInViewport: " + e.toString()); + Log.e("cgBase.getGeocachersInViewport: " + e.toString()); } return Collections.unmodifiableList(users); diff --git a/main/src/cgeo/geocaching/go4cache/Go4CacheUser.java b/main/src/cgeo/geocaching/go4cache/Go4CacheUser.java index 606d8f3..08fd02e 100644 --- a/main/src/cgeo/geocaching/go4cache/Go4CacheUser.java +++ b/main/src/cgeo/geocaching/go4cache/Go4CacheUser.java @@ -44,14 +44,16 @@ public class Go4CacheUser { } public int getIconId() { - if (null == client) { + if (client == null) { return -1; } if (client.equalsIgnoreCase("c:geo")) { return R.drawable.client_cgeo; - } else if (client.equalsIgnoreCase("preCaching")) { + } + if (client.equalsIgnoreCase("preCaching")) { return R.drawable.client_precaching; - } else if (client.equalsIgnoreCase("Handy Geocaching")) { + } + if (client.equalsIgnoreCase("Handy Geocaching")) { return R.drawable.client_handygeocaching; } return -1; diff --git a/main/src/cgeo/geocaching/maps/CGeoMap.java b/main/src/cgeo/geocaching/maps/CGeoMap.java index a1f703d..18815af 100644 --- a/main/src/cgeo/geocaching/maps/CGeoMap.java +++ b/main/src/cgeo/geocaching/maps/CGeoMap.java @@ -1,23 +1,23 @@ package cgeo.geocaching.maps; +import cgeo.geocaching.GeoObserver; +import cgeo.geocaching.IGeoData; +import cgeo.geocaching.IWaypoint; import cgeo.geocaching.LiveMapInfo; import cgeo.geocaching.R; import cgeo.geocaching.SearchResult; import cgeo.geocaching.Settings; import cgeo.geocaching.StoredList; import cgeo.geocaching.UpdateDirectionCallback; -import cgeo.geocaching.UpdateLocationCallback; -import cgeo.geocaching.cgBase; +import cgeo.geocaching.activity.ActivityMixin; import cgeo.geocaching.cgCache; -import cgeo.geocaching.cgCoord; import cgeo.geocaching.cgDirection; -import cgeo.geocaching.cgGeo; import cgeo.geocaching.cgWaypoint; import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.cgeocaches; -import cgeo.geocaching.activity.ActivityMixin; import cgeo.geocaching.connector.ConnectorFactory; import cgeo.geocaching.connector.gc.GCBase; +import cgeo.geocaching.connector.gc.Login; import cgeo.geocaching.enumerations.CacheType; import cgeo.geocaching.enumerations.LiveMapStrategy.Strategy; import cgeo.geocaching.enumerations.LoadFlags; @@ -35,9 +35,9 @@ import cgeo.geocaching.maps.interfaces.MapProvider; import cgeo.geocaching.maps.interfaces.MapViewImpl; import cgeo.geocaching.maps.interfaces.OnMapDragListener; import cgeo.geocaching.maps.interfaces.OtherCachersOverlayItemImpl; -import cgeo.geocaching.network.Login; import cgeo.geocaching.utils.CancellableHandler; -import cgeo.geocaching.utils.LRUList; +import cgeo.geocaching.utils.LeastRecentlyUsedSet; +import cgeo.geocaching.utils.Log; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -54,7 +54,7 @@ import android.graphics.drawable.LayerDrawable; import android.os.Bundle; import android.os.Handler; import android.os.Message; -import android.util.Log; +import android.util.SparseArray; import android.view.Menu; import android.view.MenuItem; import android.view.SubMenu; @@ -67,10 +67,8 @@ import android.widget.TextView; import android.widget.ViewSwitcher.ViewFactory; import java.util.ArrayList; -import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Set; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; @@ -95,8 +93,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto //Menu private static final String EXTRAS_GEOCODE = "geocode"; - private static final String EXTRAS_LONGITUDE = "longitude"; - private static final String EXTRAS_LATITUDE = "latitude"; + private static final String EXTRAS_COORDS = "coords"; private static final String EXTRAS_WPTTYPE = "wpttype"; private static final String EXTRAS_MAPSTATE = "mapstate"; private static final String EXTRAS_SEARCH = "search"; @@ -116,6 +113,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto private static final String EXTRAS_MAP_TITLE = "mapTitle"; private static final String BUNDLE_MAP_SOURCE = "mapSource"; + private static final String BUNDLE_MAP_STATE = "mapState"; private Resources res = null; private MapProvider mapProvider = null; @@ -123,9 +121,8 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto private MapViewImpl mapView = null; private MapControllerImpl mapController = null; private cgeoapplication app = null; - private cgGeo geo = null; private cgDirection dir = null; - private UpdateLocationCallback geoUpdate = new UpdateLoc(); + final private GeoObserver geoUpdate = new UpdateLoc(); private UpdateDirectionCallback dirUpdate = new UpdateDir(); private SearchResult searchIntent = null; private String geocodeIntent = null; @@ -138,14 +135,8 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto private boolean noMapTokenShowed = false; // map status data private boolean followMyLocation = false; - private Integer centerLatitude = null; - private Integer centerLongitude = null; - private Integer spanLatitude = null; - private Integer spanLongitude = null; - private Integer centerLatitudeUsers = null; - private Integer centerLongitudeUsers = null; - private Integer spanLatitudeUsers = null; - private Integer spanLongitudeUsers = null; + private Viewport viewport = null; + private Viewport viewportUsers = null; private int zoom = -100; // threads private LoadTimer loadTimer = null; @@ -170,10 +161,12 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto private static final int[][] INSET_USERMODIFIEDCOORDS = { { 21, 28, 0, 0 }, { 19, 25, 0, 0 } }; // bottom right, 12x12 / 26x26 private static final int[][] INSET_PERSONALNOTE = { { 0, 28, 21, 0 }, { 0, 25, 19, 0 } }; // bottom left, 12x12 / 26x26 - private static Map<Integer, LayerDrawable> overlaysCache = new HashMap<Integer, LayerDrawable>(); + private static SparseArray<LayerDrawable> overlaysCache = new SparseArray<LayerDrawable>(); private int cachesCnt = 0; /** List of caches in the viewport */ - private final LRUList<cgCache> caches = new LRUList<cgCache>(MAX_CACHES); + private final LeastRecentlyUsedSet<cgCache> caches = new LeastRecentlyUsedSet<cgCache>(MAX_CACHES); + /** List of waypoints in the viewport */ + private final LeastRecentlyUsedSet<cgWaypoint> waypoints = new LeastRecentlyUsedSet<cgWaypoint>(MAX_CACHES); // storing for offline private ProgressDialog waitDialog = null; private int detailTotal = 0; @@ -289,9 +282,6 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto waitDialog.setOnCancelListener(null); } - if (geo == null) { - geo = app.startGeo(geoUpdate); - } if (Settings.isUseCompass() && dir == null) { dir = app.startDir(activity, dirUpdate); } @@ -304,9 +294,6 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto loadDetailsThread.stopIt(); } - if (geo == null) { - geo = app.startGeo(geoUpdate); - } if (Settings.isUseCompass() && dir == null) { dir = app.startDir(activity, dirUpdate); } @@ -337,19 +324,15 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto } protected void countVisibleCaches() { - final ArrayList<cgCache> protectedCaches = new ArrayList<cgCache>(caches); + final List<cgCache> protectedCaches = caches.getAsList(); int count = 0; if (protectedCaches.size() > 0) { - final GeoPointImpl mapCenter = mapView.getMapViewCenter(); - final int mapCenterLat = mapCenter.getLatitudeE6(); - final int mapCenterLon = mapCenter.getLongitudeE6(); - final int mapSpanLat = mapView.getLatitudeSpan(); - final int mapSpanLon = mapView.getLongitudeSpan(); + final Viewport viewport = mapView.getViewport(); - for (cgCache cache : protectedCaches) { + for (final cgCache cache : protectedCaches) { if (cache != null && cache.getCoords() != null) { - if (Viewport.isCacheInViewPort(mapCenterLat, mapCenterLon, mapSpanLat, mapSpanLon, cache.getCoords())) { + if (viewport.contains(cache)) { count++; } } @@ -361,6 +344,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto @Override public void onSaveInstanceState(final Bundle outState) { outState.putInt(BUNDLE_MAP_SOURCE, currentSourceId); + outState.putIntArray(BUNDLE_MAP_STATE, currentMapState()); } @Override @@ -373,34 +357,29 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto app = (cgeoapplication) activity.getApplication(); mapProvider = Settings.getMapProvider(); - // Restore previously saved map source if any - if (savedInstanceState != null) { - currentSourceId = savedInstanceState.getInt(BUNDLE_MAP_SOURCE, Settings.getMapSource()); - } else { - currentSourceId = Settings.getMapSource(); - } - // get parameters - Bundle extras = activity.getIntent().getExtras(); + // Get parameters from the intent + final Bundle extras = activity.getIntent().getExtras(); if (extras != null) { searchIntent = (SearchResult) extras.getParcelable(EXTRAS_SEARCH); geocodeIntent = extras.getString(EXTRAS_GEOCODE); - final double latitudeIntent = extras.getDouble(EXTRAS_LATITUDE); - final double longitudeIntent = extras.getDouble(EXTRAS_LONGITUDE); - coordsIntent = new Geopoint(latitudeIntent, longitudeIntent); + coordsIntent = (Geopoint) extras.getParcelable(EXTRAS_COORDS); waypointTypeIntent = WaypointType.findById(extras.getString(EXTRAS_WPTTYPE)); mapStateIntent = extras.getIntArray(EXTRAS_MAPSTATE); mapTitle = extras.getString(EXTRAS_MAP_TITLE); - - if (coordsIntent.getLatitude() == 0.0 || coordsIntent.getLongitude() == 0.0) { - coordsIntent = null; - } } - if (StringUtils.isBlank(mapTitle)) { mapTitle = res.getString(R.string.map_map); } + // Get fresh map information from the bundle if any + if (savedInstanceState != null) { + currentSourceId = savedInstanceState.getInt(BUNDLE_MAP_SOURCE, Settings.getMapSource()); + mapStateIntent = savedInstanceState.getIntArray(BUNDLE_MAP_STATE); + } else { + currentSourceId = Settings.getMapSource(); + } + // If recreating from an obsolete map source, we may need a restart if (changeMapSource(Settings.getMapSource())) { return; @@ -416,9 +395,6 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto activity.setContentView(mapProvider.getMapLayoutId()); ActivityMixin.setTitle(activity, res.getString(R.string.map_map)); - if (geo == null) { - geo = app.startGeo(geoUpdate); - } if (Settings.isUseCompass() && dir == null) { dir = app.startDir(activity, dirUpdate); } @@ -456,9 +432,6 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto mapController.setZoom(Settings.getMapZoom()); // start location and directory services - if (geo != null) { - geoUpdate.updateLocation(geo); - } if (dir != null) { dirUpdate.updateDirection(dir); } @@ -470,7 +443,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto if (null == mapStateIntent) { followMyLocation = live; } else { - followMyLocation = 1 == mapStateIntent[3] ? true : false; + followMyLocation = 1 == mapStateIntent[3]; } if (geocodeIntent != null || searchIntent != null || coordsIntent != null || mapStateIntent != null) { centerMap(geocodeIntent, searchIntent, coordsIntent, mapStateIntent); @@ -512,15 +485,11 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto } app.setAction(StringUtils.defaultIfBlank(geocodeIntent, null)); - if (geo == null) { - geo = app.startGeo(geoUpdate); - } + app.addGeoObserver(geoUpdate); if (Settings.isUseCompass() && dir == null) { dir = app.startDir(activity, dirUpdate); } - geoUpdate.updateLocation(geo); - if (dir != null) { dirUpdate.updateDirection(dir); } @@ -534,12 +503,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto } dirtyCaches.clear(); // Update display - GeoPointImpl mapCenterNow = mapView.getMapViewCenter(); - int centerLatitudeNow = mapCenterNow.getLatitudeE6(); - int centerLongitudeNow = mapCenterNow.getLongitudeE6(); - int spanLatitudeNow = mapView.getLatitudeSpan(); - int spanLongitudeNow = mapView.getLongitudeSpan(); - displayExecutor.execute(new DisplayRunnable(centerLatitudeNow, centerLongitudeNow, spanLatitudeNow, spanLongitudeNow)); + displayExecutor.execute(new DisplayRunnable(mapView.getViewport())); } startTimer(); @@ -560,9 +524,6 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto if (dir != null) { dir = app.removeDir(); } - if (geo != null) { - geo = app.removeGeo(); - } savePrefs(); @@ -588,9 +549,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto if (dir != null) { dir = app.removeDir(); } - if (geo != null) { - geo = app.removeGeo(); - } + app.deleteGeoObserver(geoUpdate); savePrefs(); @@ -616,9 +575,6 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto if (dir != null) { dir = app.removeDir(); } - if (geo != null) { - geo = app.removeGeo(); - } savePrefs(); @@ -698,7 +654,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto menu.findItem(SUBMENU_STRATEGY).setEnabled(live); } catch (Exception e) { - Log.e(Settings.tag, "cgeomap.onPrepareOptionsMenu: " + e.toString()); + Log.e("cgeomap.onPrepareOptionsMenu: " + e.toString()); } return true; @@ -723,25 +679,22 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto if (live && !isLoading() && CollectionUtils.isNotEmpty(caches)) { final List<String> geocodes = new ArrayList<String>(); - List<cgCache> cachesProtected = new ArrayList<cgCache>(caches); + final List<cgCache> cachesProtected = caches.getAsList(); + try { if (cachesProtected.size() > 0) { - final GeoPointImpl mapCenter = mapView.getMapViewCenter(); - final int mapCenterLat = mapCenter.getLatitudeE6(); - final int mapCenterLon = mapCenter.getLongitudeE6(); - final int mapSpanLat = mapView.getLatitudeSpan(); - final int mapSpanLon = mapView.getLongitudeSpan(); + final Viewport viewport = mapView.getViewport(); - for (cgCache cache : cachesProtected) { + for (final cgCache cache : cachesProtected) { if (cache != null && cache.getCoords() != null) { - if (Viewport.isCacheInViewPort(mapCenterLat, mapCenterLon, mapSpanLat, mapSpanLon, cache.getCoords()) && !app.isOffline(cache.getGeocode(), null)) { + if (viewport.contains(cache) && !app.isOffline(cache.getGeocode(), null)) { geocodes.add(cache.getGeocode()); } } } } } catch (Exception e) { - Log.e(Settings.tag, "cgeomap.onOptionsItemSelected.#4: " + e.toString()); + Log.e("cgeomap.onOptionsItemSelected.#4: " + e.toString()); } detailTotal = geocodes.size(); @@ -768,14 +721,11 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto loadDetailsThread.stopIt(); } - if (geo == null) { - geo = app.startGeo(geoUpdate); - } if (Settings.isUseCompass() && dir == null) { dir = app.startDir(activity, dirUpdate); } } catch (Exception e) { - Log.e(Settings.tag, "cgeocaches.onPrepareOptionsMenu.onCancel: " + e.toString()); + Log.e("cgeocaches.onPrepareOptionsMenu.onCancel: " + e.toString()); } } }); @@ -806,11 +756,6 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto ActivityMixin.invalidateOptionsMenu(activity); return true; case MENU_AS_LIST: { - final SearchResult searchResult = new SearchResult(); - search.totalCnt = caches.size(); - for (cgCache cache : caches) { - searchResult.addCache(cache); - } cgeocaches.startActivityMap(activity, search); return true; } @@ -882,19 +827,13 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto mapIntent.putExtra(EXTRAS_SEARCH, searchIntent); mapIntent.putExtra(EXTRAS_GEOCODE, geocodeIntent); if (coordsIntent != null) { - mapIntent.putExtra(EXTRAS_LATITUDE, coordsIntent.getLatitude()); - mapIntent.putExtra(EXTRAS_LONGITUDE, coordsIntent.getLongitude()); + mapIntent.putExtra(EXTRAS_COORDS, coordsIntent); } mapIntent.putExtra(EXTRAS_WPTTYPE, waypointTypeIntent != null ? waypointTypeIntent.id : null); mapIntent.putExtra(EXTRAS_MAP_TITLE, mapTitle); - if (mapView != null) { - int[] mapState = new int[4]; - GeoPointImpl mapCenter = mapView.getMapViewCenter(); - mapState[0] = mapCenter.getLatitudeE6(); - mapState[1] = mapCenter.getLongitudeE6(); - mapState[2] = mapView.getMapZoomLevel(); - mapState[3] = followMyLocation ? 1 : 0; + final int[] mapState = currentMapState(); + if (mapState != null) { mapIntent.putExtra(EXTRAS_MAPSTATE, mapState); } @@ -902,6 +841,25 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto activity.startActivity(mapIntent); } + /** + * Get the current map state from the map view if it exists or from the mapStateIntent field otherwise. + * + * @return the current map state as an array of int, or null if no map state is available + */ + private int[] currentMapState() { + if (mapView == null) { + return mapStateIntent; + } + + final GeoPointImpl mapCenter = mapView.getMapViewCenter(); + return new int[] { + mapCenter.getLatitudeE6(), + mapCenter.getLongitudeE6(), + mapView.getMapZoomLevel(), + followMyLocation ? 1 : 0 + }; + } + private void savePrefs() { if (mapView == null) { return; @@ -911,21 +869,17 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto } // Set center of map to my location if appropriate. - private void myLocationInMiddle() { - if (followMyLocation && geo != null) { - centerMap(geo.coordsNow); + private void myLocationInMiddle(final IGeoData geo) { + if (followMyLocation) { + centerMap(geo.getCoords()); } } // class: update location - private class UpdateLoc implements UpdateLocationCallback { + private class UpdateLoc extends GeoObserver { @Override - public void updateLocation(cgGeo geo) { - if (geo == null) { - return; - } - + protected void updateLocation(final IGeoData geo) { try { boolean repaintRequired = false; @@ -933,20 +887,20 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto overlayPosition = mapView.createAddPositionOverlay(activity); } - if (overlayPosition != null && geo.location != null) { - overlayPosition.setCoordinates(geo.location); + if (overlayPosition != null && geo.getLocation() != null) { + overlayPosition.setCoordinates(geo.getLocation()); } - if (geo.coordsNow != null) { + if (geo.getCoords() != null) { if (followMyLocation) { - myLocationInMiddle(); + myLocationInMiddle(geo); } else { repaintRequired = true; } } - if (!Settings.isUseCompass() || geo.speedNow > 5) { // use GPS when speed is higher than 18 km/h - overlayPosition.setHeading(geo.bearingNow); + if (!Settings.isUseCompass() || geo.getSpeed() > 5) { // use GPS when speed is higher than 18 km/h + overlayPosition.setHeading(geo.getBearing()); repaintRequired = true; } @@ -955,7 +909,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto } } catch (Exception e) { - Log.w(Settings.tag, "Failed to update location."); + Log.w("Failed to update location."); } } } @@ -969,7 +923,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto return; } - if (overlayPosition != null && mapView != null && (geo == null || geo.speedNow <= 5)) { // use compass when speed is lower than 18 km/h + if (overlayPosition != null && mapView != null && (app.currentGeo().getSpeed() <= 5)) { // use compass when speed is lower than 18 km/h overlayPosition.setHeading(dir.directionNow); mapView.repaintRequired(overlayPosition); } @@ -1028,11 +982,8 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto if (mapView != null) { // get current viewport - GeoPointImpl mapCenterNow = mapView.getMapViewCenter(); - int centerLatitudeNow = mapCenterNow.getLatitudeE6(); - int centerLongitudeNow = mapCenterNow.getLongitudeE6(); - int spanLatitudeNow = mapView.getLatitudeSpan(); - int spanLongitudeNow = mapView.getLongitudeSpan(); + final Viewport viewportNow = mapView.getViewport(); + int zoomNow = mapView.getMapZoomLevel(); // check if map moved or zoomed //TODO Portree Use Rectangle inside with bigger search window. That will stop reloading on every move @@ -1042,20 +993,16 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto moved = true; } else if (live && Settings.isLiveMap() && !downloaded) { moved = true; - } else if (centerLatitude == null || centerLongitude == null) { + } else if (viewport == null) { moved = true; - } else if (spanLatitude == null || spanLongitude == null) { + } else if (zoomNow != zoom) { moved = true; - } else if (((Math.abs(spanLatitudeNow - spanLatitude) > 50) || (Math.abs(spanLongitudeNow - spanLongitude) > 50) || // changed zoom - (Math.abs(centerLatitudeNow - centerLatitude) > (spanLatitudeNow / 4)) || (Math.abs(centerLongitudeNow - centerLongitude) > (spanLongitudeNow / 4)) // map moved - ) && (cachesCnt <= 0 || CollectionUtils.isEmpty(caches) - || !Viewport.isInViewPort(centerLatitude, centerLongitude, centerLatitudeNow, centerLongitudeNow, spanLatitude, spanLongitude, spanLatitudeNow, spanLongitudeNow))) { + } else if (mapMoved(viewport, viewportNow) && (cachesCnt <= 0 || CollectionUtils.isEmpty(caches) || !viewport.includes(viewportNow))) { moved = true; } // update title on any change - int zoomNow = mapView.getMapZoomLevel(); - if (moved || zoomNow != zoom || spanLatitudeNow != spanLatitude || spanLongitudeNow != spanLongitude || centerLatitudeNow != centerLatitude || centerLongitudeNow != centerLongitude) { + if (moved || zoomNow != zoom || !viewportNow.equals(viewport)) { displayHandler.sendEmptyMessage(UPDATE_TITLE); } zoom = zoomNow; @@ -1067,19 +1014,15 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto long currentTime = System.currentTimeMillis(); if (1000 < (currentTime - loadThreadRun)) { - centerLatitude = centerLatitudeNow; - centerLongitude = centerLongitudeNow; - spanLatitude = spanLatitudeNow; - spanLongitude = spanLongitudeNow; - - loadExecutor.execute(new LoadRunnable(centerLatitude, centerLongitude, spanLatitude, spanLongitude)); + viewport = viewportNow; + loadExecutor.execute(new LoadRunnable(viewport)); } } } yield(); } catch (Exception e) { - Log.w(Settings.tag, "cgeomap.LoadTimer.run: " + e.toString()); + Log.w("cgeomap.LoadTimer.run: " + e.toString()); } } } @@ -1116,11 +1059,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto if (mapView != null) { // get current viewport - GeoPointImpl mapCenterNow = mapView.getMapViewCenter(); - int centerLatitudeNow = mapCenterNow.getLatitudeE6(); - int centerLongitudeNow = mapCenterNow.getLongitudeE6(); - int spanLatitudeNow = mapView.getLatitudeSpan(); - int spanLongitudeNow = mapView.getLongitudeSpan(); + final Viewport viewportNow = mapView.getViewport(); // check if map moved or zoomed boolean moved = false; @@ -1129,30 +1068,22 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto if (60000 < (currentTime - go4CacheThreadRun)) { moved = true; - } else if (centerLatitudeUsers == null || centerLongitudeUsers == null) { - moved = true; - } else if (spanLatitudeUsers == null || spanLongitudeUsers == null) { + } else if (viewportUsers == null) { moved = true; - } else if (((Math.abs(spanLatitudeNow - spanLatitudeUsers) > 50) || (Math.abs(spanLongitudeNow - spanLongitudeUsers) > 50) || // changed zoom - (Math.abs(centerLatitudeNow - centerLatitudeUsers) > (spanLatitudeNow / 4)) || (Math.abs(centerLongitudeNow - centerLongitudeUsers) > (spanLongitudeNow / 4)) // map moved - ) && !Viewport.isInViewPort(centerLatitudeUsers, centerLongitudeUsers, centerLatitudeNow, centerLongitudeNow, spanLatitudeUsers, spanLongitudeUsers, spanLatitudeNow, spanLongitudeNow)) { + } else if (mapMoved(viewportUsers, viewportNow) && !viewportUsers.includes(viewportNow)) { moved = true; } // save new values if (moved && (1000 < (currentTime - go4CacheThreadRun))) { - centerLatitudeUsers = centerLatitudeNow; - centerLongitudeUsers = centerLongitudeNow; - spanLatitudeUsers = spanLatitudeNow; - spanLongitudeUsers = spanLongitudeNow; - - Go4CacheExecutor.execute(new Go4CacheRunnable(centerLatitudeNow, centerLongitudeNow, spanLatitudeNow, spanLongitudeNow)); + viewportUsers = viewportNow; + Go4CacheExecutor.execute(new Go4CacheRunnable(viewportUsers)); } } yield(); } catch (Exception e) { - Log.w(Settings.tag, "cgeomap.LoadUsersTimer.run: " + e.toString()); + Log.w("cgeomap.LoadUsersTimer.run: " + e.toString()); } } } @@ -1165,8 +1096,8 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto private class LoadRunnable extends DoRunnable { - public LoadRunnable(long centerLatIn, long centerLonIn, long spanLatIn, long spanLonIn) { - super(centerLatIn, centerLonIn, spanLatIn, spanLonIn); + public LoadRunnable(final Viewport viewport) { + super(viewport); } @Override @@ -1185,34 +1116,50 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto } else { // live map if (!live || !Settings.isLiveMap()) { - search = new SearchResult(app.getStoredInViewport(centerLat, centerLon, spanLat, spanLon, Settings.getCacheType())); + search = new SearchResult(app.getStoredInViewport(viewport, Settings.getCacheType())); } else { - search = new SearchResult(app.getCachedInViewport(centerLat, centerLon, spanLat, spanLon, Settings.getCacheType())); + search = new SearchResult(app.getCachedInViewport(viewport, Settings.getCacheType())); } } if (search != null) { downloaded = true; - caches.addAll(search.getCachesFromSearchResult(LoadFlags.LOAD_WAYPOINTS)); + Set<cgCache> cachesFromSearchResult = search.getCachesFromSearchResult(LoadFlags.LOAD_WAYPOINTS); + caches.addAll(cachesFromSearchResult); } if (live) { final boolean excludeMine = Settings.isExcludeMyCaches(); final boolean excludeDisabled = Settings.isExcludeDisabledCaches(); - final ArrayList<cgCache> tempList = new ArrayList<cgCache>(caches); + final List<cgCache> tempList = caches.getAsList(); + for (cgCache cache : tempList) { if ((cache.isFound() && excludeMine) || (cache.isOwn() && excludeMine) || (cache.isDisabled() && excludeDisabled)) { caches.remove(cache); } } } + countVisibleCaches(); + if (cachesCnt < Settings.getWayPointsThreshold()) + { + waypoints.clear(); + if (searchIntent == null && geocodeIntent == null) { + //All visible waypoints + waypoints.addAll(app.getWaypointsInViewport(viewport, Settings.isExcludeMyCaches(), Settings.isExcludeDisabledCaches())); + } else { + //All waypoints from the viewed caches + for (cgCache c : caches.getAsList()) { + waypoints.addAll(c.getWaypoints()); + } + } + } //render - displayExecutor.execute(new DisplayRunnable(centerLat, centerLon, spanLat, spanLon)); + displayExecutor.execute(new DisplayRunnable(viewport)); if (live && Settings.isLiveMap()) { - downloadExecutor.execute(new DownloadRunnable(centerLat, centerLon, spanLat, spanLon)); + downloadExecutor.execute(new DownloadRunnable(viewport)); } } finally { showProgressHandler.sendEmptyMessage(HIDE_PROGRESS); // hide progress @@ -1227,8 +1174,8 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto private class DownloadRunnable extends DoRunnable { - public DownloadRunnable(long centerLatIn, long centerLonIn, long spanLatIn, long spanLonIn) { - super(centerLatIn, centerLonIn, spanLatIn, spanLonIn); + public DownloadRunnable(final Viewport viewport) { + super(viewport); } @Override @@ -1246,11 +1193,10 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto } } - final Viewport viewport = new Viewport(new Geopoint(centerLat / 1e6, centerLon / 1e6), 0.8 * spanLat / 1e6, 0.8 * spanLon / 1e6); - search = ConnectorFactory.searchByViewport(viewport, tokens); + search = ConnectorFactory.searchByViewport(viewport.resize(0.8), tokens); if (search != null) { downloaded = true; - if (search.error == StatusCode.NOT_LOGGED_IN) { + if (search.getError() == StatusCode.NOT_LOGGED_IN) { Login.login(); tokens = null; } else { @@ -1269,10 +1215,10 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto } //render - displayExecutor.execute(new DisplayRunnable(centerLat, centerLon, spanLat, spanLon)); + displayExecutor.execute(new DisplayRunnable(viewport)); } catch (ThreadDeath e) { - Log.d(Settings.tag, "DownloadThread stopped"); + Log.d("DownloadThread stopped"); displayHandler.sendEmptyMessage(UPDATE_TITLE); } finally { showProgressHandler.sendEmptyMessage(HIDE_PROGRESS); // hide progress @@ -1285,8 +1231,8 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto */ private class DisplayRunnable extends DoRunnable { - public DisplayRunnable(long centerLatIn, long centerLonIn, long spanLatIn, long spanLonIn) { - super(centerLatIn, centerLonIn, spanLatIn, spanLonIn); + public DisplayRunnable(final Viewport viewport) { + super(viewport); } @Override @@ -1298,30 +1244,29 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto } // display caches - final List<cgCache> cachesToDisplay = new ArrayList<cgCache>(caches); + final List<cgCache> cachesToDisplay = caches.getAsList(); + final List<cgWaypoint> waypointsToDisplay = new ArrayList<cgWaypoint>(waypoints); final List<CachesOverlayItemImpl> itemsToDisplay = new ArrayList<CachesOverlayItemImpl>(); if (!cachesToDisplay.isEmpty()) { + // Only show waypoints for single view or setting + // when less than showWaypointsthreshold Caches shown + if (cachesToDisplay.size() == 1 || (cachesCnt < Settings.getWayPointsThreshold())) { + for (cgWaypoint waypoint : waypointsToDisplay) { + + if (waypoint.getCoords() == null) { + continue; + } + + itemsToDisplay.add(getItem(waypoint, null, waypoint)); + } + } for (cgCache cache : cachesToDisplay) { if (cache.getCoords() == null) { continue; } - - // display cache waypoints - if (cache.hasWaypoints() - // Only show waypoints for single view or setting - // when less than showWaypointsthreshold Caches shown - && (cachesToDisplay.size() == 1 || (cachesToDisplay.size() < Settings.getWayPointsThreshold()))) { - for (cgWaypoint waypoint : cache.getWaypoints()) { - if (waypoint.getCoords() == null) { - continue; - } - - itemsToDisplay.add(getItem(new cgCoord(waypoint), null, waypoint)); - } - } - itemsToDisplay.add(getItem(new cgCoord(cache), cache, null)); + itemsToDisplay.add(getItem(cache, cache, null)); } overlayCaches.updateItems(itemsToDisplay); @@ -1336,7 +1281,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto displayHandler.sendEmptyMessage(UPDATE_TITLE); } catch (ThreadDeath e) { - Log.d(Settings.tag, "DisplayThread stopped"); + Log.d("DisplayThread stopped"); displayHandler.sendEmptyMessage(UPDATE_TITLE); } finally { showProgressHandler.sendEmptyMessage(HIDE_PROGRESS); @@ -1350,21 +1295,15 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto private class Go4CacheRunnable extends DoRunnable { - public Go4CacheRunnable(long centerLatIn, long centerLonIn, long spanLatIn, long spanLonIn) { - super(centerLatIn, centerLonIn, spanLatIn, spanLonIn); + public Go4CacheRunnable(final Viewport viewport) { + super(viewport); } @Override public void run() { - final Geopoint center = new Geopoint((int) centerLat, (int) centerLon); - final Viewport viewport = new Viewport(center, spanLat / 1e6 * 1.5, spanLon / 1e6 * 1.5); - - try { - go4CacheThreadRun = System.currentTimeMillis(); - List<Go4CacheUser> go4CacheUsers = Go4Cache.getGeocachersInViewport(Settings.getUsername(), viewport); - go4CacheDisplayExecutor.execute(new Go4CacheDisplayRunnable(go4CacheUsers, centerLat, centerLon, spanLat, spanLon)); - } finally { - } + go4CacheThreadRun = System.currentTimeMillis(); + List<Go4CacheUser> go4CacheUsers = Go4Cache.getGeocachersInViewport(Settings.getUsername(), viewport.resize(1.5)); + go4CacheDisplayExecutor.execute(new Go4CacheDisplayRunnable(go4CacheUsers, viewport)); } } @@ -1375,42 +1314,39 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto private List<Go4CacheUser> users = null; - public Go4CacheDisplayRunnable(List<Go4CacheUser> usersIn, long centerLatIn, long centerLonIn, long spanLatIn, long spanLonIn) { - super(centerLatIn, centerLonIn, spanLatIn, spanLonIn); + public Go4CacheDisplayRunnable(List<Go4CacheUser> usersIn, final Viewport viewport) { + super(viewport); users = usersIn; } @Override public void run() { - try { - if (mapView == null || CollectionUtils.isEmpty(users)) { - return; - } + if (mapView == null || CollectionUtils.isEmpty(users)) { + return; + } - // display users - List<OtherCachersOverlayItemImpl> items = new ArrayList<OtherCachersOverlayItemImpl>(); + // display users + List<OtherCachersOverlayItemImpl> items = new ArrayList<OtherCachersOverlayItemImpl>(); - int counter = 0; - OtherCachersOverlayItemImpl item = null; + int counter = 0; + OtherCachersOverlayItemImpl item; - for (Go4CacheUser userOne : users) { - if (userOne.getCoords() == null) { - continue; - } + for (Go4CacheUser userOne : users) { + if (userOne.getCoords() == null) { + continue; + } - item = mapProvider.getOtherCachersOverlayItemBase(activity, userOne); - items.add(item); + item = mapProvider.getOtherCachersOverlayItemBase(activity, userOne); + items.add(item); - counter++; - if ((counter % 10) == 0) { - overlayGo4Cache.updateItems(items); - displayHandler.sendEmptyMessage(INVALIDATE_MAP); - } + counter++; + if ((counter % 10) == 0) { + overlayGo4Cache.updateItems(items); + displayHandler.sendEmptyMessage(INVALIDATE_MAP); } - - overlayGo4Cache.updateItems(items); - } finally { } + + overlayGo4Cache.updateItems(items); } } @@ -1426,14 +1362,10 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto } if (coordsIntent != null) { - final cgCoord coord = new cgCoord(); - coord.setCoordType("waypoint"); - coord.setCoords(coordsIntent); - coord.setName("some place"); - final cgWaypoint waypoint = new cgWaypoint("some place", waypointTypeIntent != null ? waypointTypeIntent : WaypointType.WAYPOINT, false); + waypoint.setCoords(coordsIntent); - final CachesOverlayItemImpl item = getItem(coord, null, waypoint); + final CachesOverlayItemImpl item = getItem(waypoint, null, waypoint); overlayCaches.updateItems(item); displayHandler.sendEmptyMessage(INVALIDATE_MAP); @@ -1446,18 +1378,12 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto } } - private abstract class DoRunnable implements Runnable { + private static abstract class DoRunnable implements Runnable { - protected long centerLat = 0L; - protected long centerLon = 0L; - protected long spanLat = 0L; - protected long spanLon = 0L; + final protected Viewport viewport; - public DoRunnable(long centerLatIn, long centerLonIn, long spanLatIn, long spanLonIn) { - centerLat = centerLatIn; - centerLon = centerLonIn; - spanLat = spanLatIn; - spanLon = spanLonIn; + public DoRunnable(final Viewport viewport) { + this.viewport = viewport; } public abstract void run(); @@ -1504,11 +1430,10 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto if (dir != null) { dir = app.removeDir(); } - if (geo != null) { - geo = app.removeGeo(); - } - for (String geocode : geocodes) { + app.deleteGeoObserver(geoUpdate); + + for (final String geocode : geocodes) { try { if (handler.isCancelled()) { break; @@ -1529,15 +1454,15 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto } if (handler.isCancelled()) { - Log.i(Settings.tag, "Stopped storing process."); + Log.i("Stopped storing process."); break; } - cgBase.storeCache(activity, null, geocode, StoredList.STANDARD_LIST_ID, handler); + cgCache.storeCache(activity, null, geocode, StoredList.STANDARD_LIST_ID, false, handler); } } catch (Exception e) { - Log.e(Settings.tag, "cgeocaches.LoadDetails.run: " + e.toString()); + Log.e("cgeocaches.LoadDetails.run: " + e.toString()); } finally { // one more cache over detailProgress++; @@ -1552,9 +1477,17 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto // we're done handler.sendEmptyMessage(FINISHED_LOADING_DETAILS); + app.addGeoObserver(geoUpdate); } } + private static boolean mapMoved(final Viewport referenceViewport, final Viewport newViewport) { + return Math.abs(newViewport.getLatitudeSpan() - referenceViewport.getLatitudeSpan()) > 50e-6 || + Math.abs(newViewport.getLongitudeSpan() - referenceViewport.getLongitudeSpan()) > 50e-6 || + Math.abs(newViewport.center.getLatitude() - referenceViewport.center.getLatitude()) > referenceViewport.getLatitudeSpan() / 4 || + Math.abs(newViewport.center.getLongitude() - referenceViewport.center.getLongitude()) > referenceViewport.getLongitudeSpan() / 4; + } + // center map to desired location private void centerMap(final Geopoint coords) { if (coords == null) { @@ -1588,46 +1521,21 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto alreadyCentered = true; } else if (!centered && (geocodeCenter != null || searchIntent != null)) { try { - List<Number> viewport = null; + Viewport viewport = null; if (geocodeCenter != null) { viewport = app.getBounds(geocodeCenter); - } else { - if (searchCenter != null) { - viewport = app.getBounds(searchCenter.getGeocodes()); - } - } - - if (viewport == null || viewport.size() < 5) { - return; + } else if (searchCenter != null) { + viewport = app.getBounds(searchCenter.getGeocodes()); } - int cnt = (Integer) viewport.get(0); - if (cnt <= 0) { + if (viewport == null) { return; } - int minLat = (int) ((Double) viewport.get(1) * 1e6); - int maxLat = (int) ((Double) viewport.get(2) * 1e6); - int maxLon = (int) ((Double) viewport.get(3) * 1e6); - int minLon = (int) ((Double) viewport.get(4) * 1e6); - - int centerLat = 0; - int centerLon = 0; - if ((Math.abs(maxLat) - Math.abs(minLat)) != 0) { - centerLat = minLat + ((maxLat - minLat) / 2); - } else { - centerLat = maxLat; - } - if ((Math.abs(maxLon) - Math.abs(minLon)) != 0) { - centerLon = minLon + ((maxLon - minLon) / 2); - } else { - centerLon = maxLon; - } - - mapController.setCenter(mapProvider.getGeoPointBase(new Geopoint(centerLat, centerLon))); - if (Math.abs(maxLat - minLat) != 0 && Math.abs(maxLon - minLon) != 0) { - mapController.zoomToSpan(Math.abs(maxLat - minLat), Math.abs(maxLon - minLon)); + mapController.setCenter(mapProvider.getGeoPointBase(viewport.center)); + if (viewport.getLatitudeSpan() != 0 && viewport.getLongitudeSpan() != 0) { + mapController.zoomToSpan((int) (viewport.getLatitudeSpan() * 1e6), (int) (viewport.getLongitudeSpan() * 1e6)); } } catch (Exception e) { // nothing at all @@ -1651,7 +1559,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto private void switchMyLocationButton() { if (followMyLocation) { myLocSwitch.setImageResource(R.drawable.actionbar_mylocation_on); - myLocationInMiddle(); + myLocationInMiddle(app.currentGeo()); } else { myLocSwitch.setImageResource(R.drawable.actionbar_mylocation_off); } @@ -1717,8 +1625,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto public static void startActivityCoords(final Activity fromActivity, final Geopoint coords, final WaypointType type, final String title) { final Intent mapIntent = newIntent(fromActivity); - mapIntent.putExtra(EXTRAS_LATITUDE, coords.getLatitude()); - mapIntent.putExtra(EXTRAS_LONGITUDE, coords.getLongitude()); + mapIntent.putExtra(EXTRAS_COORDS, coords); if (type != null) { mapIntent.putExtra(EXTRAS_WPTTYPE, type.id); } @@ -1753,12 +1660,10 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto * Waypoint. Mutally exclusive with cache * @return */ - private CachesOverlayItemImpl getItem(cgCoord coord, cgCache cache, cgWaypoint waypoint) { + private CachesOverlayItemImpl getItem(final IWaypoint coord, final cgCache cache, final cgWaypoint waypoint) { if (cache != null) { - - CachesOverlayItemImpl item = mapProvider.getCachesOverlayItem(coord, cache.getType()); - - int hashcode = new HashCodeBuilder() + final CachesOverlayItemImpl item = mapProvider.getCachesOverlayItem(coord, cache.getType()); + final int hashcode = new HashCodeBuilder() .append(cache.isReliableLatLon()) .append(cache.getType().id) .append(cache.isDisabled() || cache.isArchived()) @@ -1770,23 +1675,20 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto .append(cache.getListId() > 0) .toHashCode(); - LayerDrawable ldFromCache = CGeoMap.overlaysCache.get(hashcode); + final LayerDrawable ldFromCache = CGeoMap.overlaysCache.get(hashcode); if (ldFromCache != null) { item.setMarker(ldFromCache); return item; } - ArrayList<Drawable> layers = new ArrayList<Drawable>(); - ArrayList<int[]> insets = new ArrayList<int[]>(); - + // Set initial capacities to the maximum of layers and insets to avoid dynamic reallocation + final ArrayList<Drawable> layers = new ArrayList<Drawable>(9); + final ArrayList<int[]> insets = new ArrayList<int[]>(8); // background: disabled or not - Drawable marker = getResources().getDrawable(R.drawable.marker); - if (cache.isDisabled() || cache.isArchived()) { - marker = getResources().getDrawable(R.drawable.marker_disabled); - } + final Drawable marker = getResources().getDrawable(cache.isDisabled() || cache.isArchived() ? R.drawable.marker_disabled : R.drawable.marker); layers.add(marker); - int resolution = marker.getIntrinsicWidth() > 40 ? 1 : 0; + final int resolution = marker.getIntrinsicWidth() > 40 ? 1 : 0; // reliable or not if (!cache.isReliableLatLon()) { insets.add(INSET_RELIABLE[resolution]); @@ -1796,7 +1698,7 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto layers.add(getResources().getDrawable(cache.getType().markerId)); insets.add(INSET_TYPE[resolution]); // own - if ( cache.isOwn() ) { + if (cache.isOwn()) { layers.add(getResources().getDrawable(R.drawable.marker_own)); insets.add(INSET_OWN[resolution]); // if not, checked if stored @@ -1824,11 +1726,10 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto insets.add(INSET_PERSONALNOTE[resolution]); } - - LayerDrawable ld = new LayerDrawable(layers.toArray(new Drawable[layers.size()])); + final LayerDrawable ld = new LayerDrawable(layers.toArray(new Drawable[layers.size()])); int index = 1; - for ( int[] inset : insets) { + for (final int[] inset : insets) { ld.setLayerInset(index++, inset[0], inset[1], inset[2], inset[3]); } @@ -1836,10 +1737,10 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto item.setMarker(ld); return item; + } - } else if (waypoint != null) { - - CachesOverlayItemImpl item = mapProvider.getCachesOverlayItem(coord, null); + if (waypoint != null) { + final CachesOverlayItemImpl item = mapProvider.getCachesOverlayItem(coord, null); Drawable[] layers = new Drawable[2]; layers[0] = getResources().getDrawable(R.drawable.marker); layers[1] = getResources().getDrawable(waypoint.getWaypointType().markerId); @@ -1855,7 +1756,6 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto } return null; - } } diff --git a/main/src/cgeo/geocaching/maps/CachesOverlay.java b/main/src/cgeo/geocaching/maps/CachesOverlay.java index 0a952bc..d3a7865 100644 --- a/main/src/cgeo/geocaching/maps/CachesOverlay.java +++ b/main/src/cgeo/geocaching/maps/CachesOverlay.java @@ -1,7 +1,7 @@ package cgeo.geocaching.maps; +import cgeo.geocaching.IWaypoint; import cgeo.geocaching.Settings; -import cgeo.geocaching.cgCoord; import cgeo.geocaching.cgeopopup; import cgeo.geocaching.cgeowaypoint; import cgeo.geocaching.enumerations.CacheType; @@ -12,12 +12,12 @@ import cgeo.geocaching.maps.interfaces.ItemizedOverlayImpl; import cgeo.geocaching.maps.interfaces.MapProjectionImpl; import cgeo.geocaching.maps.interfaces.MapProvider; import cgeo.geocaching.maps.interfaces.MapViewImpl; +import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; import android.app.ProgressDialog; import android.content.Context; -import android.content.Intent; import android.graphics.Canvas; import android.graphics.DashPathEffect; import android.graphics.Paint; @@ -25,7 +25,6 @@ import android.graphics.Paint.Style; import android.graphics.PaintFlagsDrawFilter; import android.graphics.Point; import android.location.Location; -import android.util.Log; import java.util.ArrayList; import java.util.List; @@ -36,11 +35,9 @@ public class CachesOverlay extends AbstractItemizedOverlay { private Context context = null; private boolean displayCircles = false; private ProgressDialog waitDialog = null; - private Point center = new Point(); - private Point left = new Point(); private Paint blockedCircle = null; - private PaintFlagsDrawFilter setfil = null; - private PaintFlagsDrawFilter remfil = null; + private PaintFlagsDrawFilter setFilter = null; + private PaintFlagsDrawFilter removeFilter = null; private MapProvider mapProvider = null; public CachesOverlay(ItemizedOverlayImpl ovlImpl, Context contextIn) { @@ -107,65 +104,90 @@ public class CachesOverlay extends AbstractItemizedOverlay { } private void drawInternal(Canvas canvas, MapProjectionImpl projection) { + if (!displayCircles || items.isEmpty()) { + return; + } // prevent content changes getOverlayImpl().lock(); try { - if (displayCircles) { - if (blockedCircle == null) { - blockedCircle = new Paint(); - blockedCircle.setAntiAlias(true); - blockedCircle.setStrokeWidth(2.0f); - blockedCircle.setARGB(127, 0, 0, 0); - blockedCircle.setPathEffect(new DashPathEffect(new float[] { 3, 2 }, 0)); + lazyInitializeDrawingObjects(); + canvas.setDrawFilter(setFilter); + + final int radius = calculateDrawingRadius(projection); + final Point center = new Point(); + + for (CachesOverlayItemImpl item : items) { + final Geopoint itemCoord = item.getCoord().getCoords(); + final GeoPointImpl itemGeo = mapProvider.getGeoPointBase(itemCoord); + projection.toPixels(itemGeo, center); + + final CacheType type = item.getType(); + if (type == null || type == CacheType.MULTI || type == CacheType.MYSTERY || type == CacheType.VIRTUAL || type.isEvent()) { + blockedCircle.setColor(0x66000000); + blockedCircle.setStyle(Style.STROKE); + canvas.drawCircle(center.x, center.y, radius, blockedCircle); + } else { + blockedCircle.setColor(0x66BB0000); + blockedCircle.setStyle(Style.STROKE); + canvas.drawCircle(center.x, center.y, radius, blockedCircle); + + blockedCircle.setColor(0x44BB0000); + blockedCircle.setStyle(Style.FILL); + canvas.drawCircle(center.x, center.y, radius, blockedCircle); } + } + canvas.setDrawFilter(removeFilter); + } finally { + getOverlayImpl().unlock(); + } + } - if (setfil == null) { - setfil = new PaintFlagsDrawFilter(0, Paint.FILTER_BITMAP_FLAG); - } - if (remfil == null) { - remfil = new PaintFlagsDrawFilter(Paint.FILTER_BITMAP_FLAG, 0); - } + /** + * calculate the radius of the circle to be drawn for the first item only. Those circles are only 161 meters in + * reality and therefore the minor changes due to the projection will not make any visible difference at the zoom + * levels which are used to see the circles. + * + * @param projection + * @return + */ + private int calculateDrawingRadius(MapProjectionImpl projection) { + float[] distanceArray = new float[1]; + final Geopoint itemCoord = items.get(0).getCoord().getCoords(); - canvas.setDrawFilter(setfil); + Location.distanceBetween(itemCoord.getLatitude(), itemCoord.getLongitude(), + itemCoord.getLatitude(), itemCoord.getLongitude() + 1, distanceArray); + final float longitudeLineDistance = distanceArray[0]; - for (CachesOverlayItemImpl item : items) { - final cgCoord itemCoord = item.getCoord(); - float[] result = new float[1]; + final GeoPointImpl itemGeo = mapProvider.getGeoPointBase(itemCoord); - Location.distanceBetween(itemCoord.getCoords().getLatitude(), itemCoord.getCoords().getLongitude(), - itemCoord.getCoords().getLatitude(), itemCoord.getCoords().getLongitude() + 1, result); - final float longitudeLineDistance = result[0]; + final Geopoint leftCoords = new Geopoint(itemCoord.getLatitude(), + itemCoord.getLongitude() - 161 / longitudeLineDistance); + final GeoPointImpl leftGeo = mapProvider.getGeoPointBase(leftCoords); - GeoPointImpl itemGeo = mapProvider.getGeoPointBase(itemCoord.getCoords()); + final Point center = new Point(); + projection.toPixels(itemGeo, center); - final Geopoint leftCoords = new Geopoint(itemCoord.getCoords().getLatitude(), - itemCoord.getCoords().getLongitude() - 161 / longitudeLineDistance); - GeoPointImpl leftGeo = mapProvider.getGeoPointBase(leftCoords); + final Point left = new Point(); + projection.toPixels(leftGeo, left); - projection.toPixels(itemGeo, center); - projection.toPixels(leftGeo, left); - int radius = center.x - left.x; + return center.x - left.x; + } - final CacheType type = item.getType(); - if (type == null || type == CacheType.MULTI || type == CacheType.MYSTERY || type == CacheType.VIRTUAL) { - blockedCircle.setColor(0x66000000); - blockedCircle.setStyle(Style.STROKE); - canvas.drawCircle(center.x, center.y, radius, blockedCircle); - } else { - blockedCircle.setColor(0x66BB0000); - blockedCircle.setStyle(Style.STROKE); - canvas.drawCircle(center.x, center.y, radius, blockedCircle); + private void lazyInitializeDrawingObjects() { + if (blockedCircle == null) { + blockedCircle = new Paint(); + blockedCircle.setAntiAlias(true); + blockedCircle.setStrokeWidth(2.0f); + blockedCircle.setARGB(127, 0, 0, 0); + blockedCircle.setPathEffect(new DashPathEffect(new float[] { 3, 2 }, 0)); + } - blockedCircle.setColor(0x44BB0000); - blockedCircle.setStyle(Style.FILL); - canvas.drawCircle(center.x, center.y, radius, blockedCircle); - } - } - canvas.setDrawFilter(remfil); - } - } finally { - getOverlayImpl().unlock(); + if (setFilter == null) { + setFilter = new PaintFlagsDrawFilter(0, Paint.FILTER_BITMAP_FLAG); + } + if (removeFilter == null) { + removeFilter = new PaintFlagsDrawFilter(Paint.FILTER_BITMAP_FLAG, 0); } } @@ -200,22 +222,14 @@ public class CachesOverlay extends AbstractItemizedOverlay { return false; } - cgCoord coordinate = item.getCoord(); + final IWaypoint coordinate = item.getCoord(); if (StringUtils.isNotBlank(coordinate.getCoordType()) && coordinate.getCoordType().equalsIgnoreCase("cache") && StringUtils.isNotBlank(coordinate.getGeocode())) { - Intent popupIntent = new Intent(context, cgeopopup.class); - - popupIntent.putExtra("geocode", coordinate.getGeocode()); - CGeoMap.markCacheAsDirty(coordinate.getGeocode()); - context.startActivity(popupIntent); + cgeopopup.startActivity(context, coordinate.getGeocode()); } else if (coordinate.getCoordType() != null && coordinate.getCoordType().equalsIgnoreCase("waypoint") && coordinate.getId() > 0) { - Intent popupIntent = new Intent(context, cgeowaypoint.class); - - popupIntent.putExtra("waypoint", coordinate.getId()); - CGeoMap.markCacheAsDirty(coordinate.getGeocode()); - context.startActivity(popupIntent); + cgeowaypoint.startActivity(context, coordinate.getId()); } else { waitDialog.dismiss(); return false; @@ -223,7 +237,7 @@ public class CachesOverlay extends AbstractItemizedOverlay { waitDialog.dismiss(); } catch (Exception e) { - Log.e(Settings.tag, "cgMapOverlay.onTap: " + e.toString()); + Log.e("cgMapOverlay.onTap: " + e.toString()); } return false; @@ -234,7 +248,7 @@ public class CachesOverlay extends AbstractItemizedOverlay { try { return items.get(index); } catch (Exception e) { - Log.e(Settings.tag, "cgMapOverlay.createItem: " + e.toString()); + Log.e("cgMapOverlay.createItem: " + e.toString()); } return null; @@ -245,7 +259,7 @@ public class CachesOverlay extends AbstractItemizedOverlay { try { return items.size(); } catch (Exception e) { - Log.e(Settings.tag, "cgMapOverlay.size: " + e.toString()); + Log.e("cgMapOverlay.size: " + e.toString()); } return 0; diff --git a/main/src/cgeo/geocaching/maps/MapProviderFactory.java b/main/src/cgeo/geocaching/maps/MapProviderFactory.java index c7865f3..3509209 100644 --- a/main/src/cgeo/geocaching/maps/MapProviderFactory.java +++ b/main/src/cgeo/geocaching/maps/MapProviderFactory.java @@ -16,11 +16,24 @@ public class MapProviderFactory { private static MapProviderFactory instance = null; - private MapProvider[] mapProviders; + private final MapProvider[] mapProviders; private SortedMap<Integer, String> mapSources; private MapProviderFactory() { - mapProviders = new MapProvider[] { new GoogleMapProvider(GOOGLEMAP_BASEID), new MapsforgeMapProvider(MFMAP_BASEID) }; + // add GoogleMapProvider only if google api is available in order to support x86 android emulator + boolean googleMaps = true; + try { + Class.forName("com.google.android.maps.MapActivity"); + } catch (ClassNotFoundException e) { + googleMaps = false; + } + if (googleMaps) { + mapProviders = new MapProvider[] { new GoogleMapProvider(GOOGLEMAP_BASEID), new MapsforgeMapProvider(MFMAP_BASEID) }; + } + else { + mapProviders = new MapProvider[] { new MapsforgeMapProvider(MFMAP_BASEID) }; + } + mapSources = new TreeMap<Integer, String>(); for (MapProvider mp : mapProviders) { mapSources.putAll(mp.getMapSources()); diff --git a/main/src/cgeo/geocaching/maps/OtherCachersOverlay.java b/main/src/cgeo/geocaching/maps/OtherCachersOverlay.java index 4dd217b..6ca050e 100644 --- a/main/src/cgeo/geocaching/maps/OtherCachersOverlay.java +++ b/main/src/cgeo/geocaching/maps/OtherCachersOverlay.java @@ -1,21 +1,19 @@ package cgeo.geocaching.maps; import cgeo.geocaching.CacheDetailActivity; -import cgeo.geocaching.Settings; import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.go4cache.Go4CacheUser; import cgeo.geocaching.maps.interfaces.ItemizedOverlayImpl; import cgeo.geocaching.maps.interfaces.MapViewImpl; import cgeo.geocaching.maps.interfaces.OtherCachersOverlayItemImpl; +import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; -import android.content.Intent; import android.graphics.Canvas; -import android.util.Log; import java.util.ArrayList; import java.util.List; @@ -92,7 +90,7 @@ public class OtherCachersOverlay extends AbstractItemizedOverlay { return true; } catch (Exception e) { - Log.e(Settings.tag, "cgUsersOverlay.onTap: " + e.toString()); + Log.e("cgUsersOverlay.onTap: " + e.toString()); } return false; @@ -108,7 +106,7 @@ public class OtherCachersOverlay extends AbstractItemizedOverlay { try { return items.get(index); } catch (Exception e) { - Log.e(Settings.tag, "cgUsersOverlay.createItem: " + e.toString()); + Log.e("cgUsersOverlay.createItem: " + e.toString()); } return null; @@ -119,7 +117,7 @@ public class OtherCachersOverlay extends AbstractItemizedOverlay { try { return items.size(); } catch (Exception e) { - Log.e(Settings.tag, "cgUsersOverlay.size: " + e.toString()); + Log.e("cgUsersOverlay.size: " + e.toString()); } return 0; @@ -135,9 +133,7 @@ public class OtherCachersOverlay extends AbstractItemizedOverlay { public void onClick(DialogInterface dialog, int id) { if (geocode != null) { - final Intent detailIntent = new Intent(context, CacheDetailActivity.class); - detailIntent.putExtra("geocode", geocode); - context.startActivity(detailIntent); + CacheDetailActivity.startActivity(context, geocode); } dialog.cancel(); diff --git a/main/src/cgeo/geocaching/maps/OtherCachersOverlayItem.java b/main/src/cgeo/geocaching/maps/OtherCachersOverlayItem.java index d71bbcf..9844e83 100644 --- a/main/src/cgeo/geocaching/maps/OtherCachersOverlayItem.java +++ b/main/src/cgeo/geocaching/maps/OtherCachersOverlayItem.java @@ -16,7 +16,7 @@ public class OtherCachersOverlayItem { } public Drawable getMarker() { - Drawable marker = null; + Drawable marker; if (user != null && user.getDate() != null && user.getDate().getTime() >= (System.currentTimeMillis() - (20 * 60 * 1000))) { marker = context.getResources().getDrawable(R.drawable.user_location_active); diff --git a/main/src/cgeo/geocaching/maps/PositionOverlay.java b/main/src/cgeo/geocaching/maps/PositionOverlay.java index a09b6de..9099498 100644 --- a/main/src/cgeo/geocaching/maps/PositionOverlay.java +++ b/main/src/cgeo/geocaching/maps/PositionOverlay.java @@ -150,7 +150,7 @@ public class PositionOverlay implements GeneralOverlay { if (Settings.isMapTrail()) { int size = history.size(); if (size > 1) { - int alpha = 0; + int alpha; int alphaCnt = size - 201; if (alphaCnt < 1) { alphaCnt = 1; @@ -210,7 +210,7 @@ public class PositionOverlay implements GeneralOverlay { marginTop = center.y - heightArrowHalf; Matrix matrix = new Matrix(); - matrix.setRotate(heading.floatValue(), widthArrowHalf, heightArrowHalf); + matrix.setRotate(heading, widthArrowHalf, heightArrowHalf); matrix.postTranslate(marginLeft, marginTop); canvas.drawBitmap(arrow, matrix, null); diff --git a/main/src/cgeo/geocaching/maps/ScaleOverlay.java b/main/src/cgeo/geocaching/maps/ScaleOverlay.java index f43ba25..321624d 100644 --- a/main/src/cgeo/geocaching/maps/ScaleOverlay.java +++ b/main/src/cgeo/geocaching/maps/ScaleOverlay.java @@ -1,14 +1,15 @@ package cgeo.geocaching.maps; -import cgeo.geocaching.Settings; import cgeo.geocaching.geopoint.Geopoint; -import cgeo.geocaching.geopoint.IConversion; +import cgeo.geocaching.geopoint.HumanDistance; import cgeo.geocaching.maps.interfaces.GeneralOverlay; import cgeo.geocaching.maps.interfaces.GeoPointImpl; import cgeo.geocaching.maps.interfaces.MapProjectionImpl; import cgeo.geocaching.maps.interfaces.MapViewImpl; import cgeo.geocaching.maps.interfaces.OverlayImpl; +import org.apache.commons.lang3.tuple.ImmutablePair; + import android.app.Activity; import android.graphics.BlurMaskFilter; import android.graphics.Canvas; @@ -25,11 +26,6 @@ public class ScaleOverlay implements GeneralOverlay { private Paint scaleShadow = null; private BlurMaskFilter blur = null; private float pixelDensity = 0; - private double pixels = 0d; - private int bottom = 0; - private double distance = 0d; - private double distanceRound = 0d; - private String units = null; private OverlayImpl ovlImpl = null; public ScaleOverlay(Activity activity, OverlayImpl overlayImpl) { @@ -51,64 +47,25 @@ public class ScaleOverlay implements GeneralOverlay { drawInternal(canvas, mapView); } + static private double keepSignificantDigit(final double distance) { + final double scale = Math.pow(10, Math.floor(Math.log10(distance))); + return scale * Math.floor(distance / scale); + } + private void drawInternal(Canvas canvas, MapViewImpl mapView) { final double span = mapView.getLongitudeSpan() / 1e6; final GeoPointImpl center = mapView.getMapViewCenter(); - pixels = mapView.getWidth() * SCALE_WIDTH_FACTOR; // pixels related to following latitude span - bottom = mapView.getHeight() - 14; // pixels from bottom side of screen + final int bottom = mapView.getHeight() - 14; // pixels from bottom side of screen final Geopoint leftCoords = new Geopoint(center.getLatitudeE6() / 1e6, center.getLongitudeE6() / 1e6 - span / 2); final Geopoint rightCoords = new Geopoint(center.getLatitudeE6() / 1e6, center.getLongitudeE6() / 1e6 + span / 2); - distance = leftCoords.distanceTo(rightCoords) * SCALE_WIDTH_FACTOR; - distanceRound = 0d; - - //FIXME: merge with getHumanDistance() - if (Settings.isUseMetricUnits()) { - if (distance > 100) { // 100+ km > 1xx km - distanceRound = Math.floor(distance / 100) * 100; - units = "km"; - } else if (distance > 10) { // 10 - 100 km > 1x km - distanceRound = Math.floor(distance / 10) * 10; - units = "km"; - } else if (distance > 1) { // 1 - 10 km > 1.x km - distanceRound = Math.floor(distance); - units = "km"; - } else if (distance > 0.1) { // 100 m - 1 km > 1xx m - distance *= 1000; - distanceRound = Math.floor(distance / 100) * 100; - units = "m"; - } else { // 1 - 100 m > 1x m - distance *= 1000; - distanceRound = Math.round(distance / 10) * 10; - units = "m"; - } - } else { - distance /= IConversion.MILES_TO_KILOMETER; - - if (distance > 100) { // 100+ mi > 1xx mi - distanceRound = Math.floor(distance / 100) * 100; - units = "mi"; - } else if (distance > 10) { // 10 - 100 mi > 1x mi - distanceRound = Math.floor(distance / 10) * 10; - units = "mi"; - } else if (distance > 1) { // 1 - 10 mi > 1.x mi - distanceRound = Math.floor(distance); - units = "mi"; - } else if (distance > 0.1) { // 0.1 mi - 1.0 mi > 1xx ft - distance *= 5280; - distanceRound = Math.floor(distance / 100) * 100; - units = "ft"; - } else { // 1 - 100 ft > 1x ft - distance *= 5280; - distanceRound = Math.round(distance / 10) * 10; - units = "ft"; - } - } + final ImmutablePair<Double, String> scaled = HumanDistance.scaleUnit(leftCoords.distanceTo(rightCoords) * SCALE_WIDTH_FACTOR); - pixels = Math.round((pixels / distance) * distanceRound); + final double distanceRound = keepSignificantDigit(scaled.left); + final double pixels = Math.round((mapView.getWidth() * SCALE_WIDTH_FACTOR / scaled.left) * distanceRound); if (blur == null) { blur = new BlurMaskFilter(3, BlurMaskFilter.Blur.NORMAL); @@ -139,15 +96,17 @@ public class ScaleOverlay implements GeneralOverlay { scale.setColor(0xFF000000); } + final String formatString = distanceRound >= 1 ? "%.0f" : "%.1f"; + canvas.drawLine(10, bottom, 10, (bottom - (8 * pixelDensity)), scaleShadow); canvas.drawLine((int) (pixels + 10), bottom, (int) (pixels + 10), (bottom - (8 * pixelDensity)), scaleShadow); canvas.drawLine(8, bottom, (int) (pixels + 12), bottom, scaleShadow); - canvas.drawText(String.format("%.0f", distanceRound) + " " + units, (float) (pixels - (10 * pixelDensity)), (bottom - (10 * pixelDensity)), scaleShadow); + canvas.drawText(String.format(formatString, distanceRound) + " " + scaled.right, (float) (pixels - (10 * pixelDensity)), (bottom - (10 * pixelDensity)), scaleShadow); canvas.drawLine(11, bottom, 11, (bottom - (6 * pixelDensity)), scale); canvas.drawLine((int) (pixels + 9), bottom, (int) (pixels + 9), (bottom - (6 * pixelDensity)), scale); canvas.drawLine(10, bottom, (int) (pixels + 10), bottom, scale); - canvas.drawText(String.format("%.0f", distanceRound) + " " + units, (float) (pixels - (10 * pixelDensity)), (bottom - (10 * pixelDensity)), scale); + canvas.drawText(String.format(formatString, distanceRound) + " " + scaled.right, (float) (pixels - (10 * pixelDensity)), (bottom - (10 * pixelDensity)), scale); } @Override diff --git a/main/src/cgeo/geocaching/maps/google/GoogleCacheOverlayItem.java b/main/src/cgeo/geocaching/maps/google/GoogleCacheOverlayItem.java index 5f41c54..27a1b56 100644 --- a/main/src/cgeo/geocaching/maps/google/GoogleCacheOverlayItem.java +++ b/main/src/cgeo/geocaching/maps/google/GoogleCacheOverlayItem.java @@ -1,6 +1,6 @@ package cgeo.geocaching.maps.google; -import cgeo.geocaching.cgCoord; +import cgeo.geocaching.IWaypoint; import cgeo.geocaching.enumerations.CacheType; import cgeo.geocaching.maps.interfaces.CachesOverlayItemImpl; @@ -9,16 +9,16 @@ import com.google.android.maps.OverlayItem; public class GoogleCacheOverlayItem extends OverlayItem implements CachesOverlayItemImpl { final private CacheType cacheType; - final private cgCoord coord; + final private IWaypoint coord; - public GoogleCacheOverlayItem(final cgCoord coordinate, final CacheType type) { + public GoogleCacheOverlayItem(final IWaypoint coordinate, final CacheType type) { super(new GeoPoint(coordinate.getCoords().getLatitudeE6(), coordinate.getCoords().getLongitudeE6()), coordinate.getName(), ""); this.cacheType = type; this.coord = coordinate; } - public cgCoord getCoord() { + public IWaypoint getCoord() { return coord; } diff --git a/main/src/cgeo/geocaching/maps/google/GoogleGeoPoint.java b/main/src/cgeo/geocaching/maps/google/GoogleGeoPoint.java index 56bc40c..d5f6385 100644 --- a/main/src/cgeo/geocaching/maps/google/GoogleGeoPoint.java +++ b/main/src/cgeo/geocaching/maps/google/GoogleGeoPoint.java @@ -1,5 +1,6 @@ package cgeo.geocaching.maps.google; +import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.maps.interfaces.GeoPointImpl; import com.google.android.maps.GeoPoint; @@ -10,4 +11,9 @@ public class GoogleGeoPoint extends GeoPoint implements GeoPointImpl { super(latitudeE6, longitudeE6); } + @Override + public Geopoint getCoords() { + return new Geopoint(getLatitudeE6() / 1e6, getLongitudeE6() / 1e6); + } + } diff --git a/main/src/cgeo/geocaching/maps/google/GoogleMapProvider.java b/main/src/cgeo/geocaching/maps/google/GoogleMapProvider.java index 7191428..b659042 100644 --- a/main/src/cgeo/geocaching/maps/google/GoogleMapProvider.java +++ b/main/src/cgeo/geocaching/maps/google/GoogleMapProvider.java @@ -1,7 +1,7 @@ package cgeo.geocaching.maps.google; +import cgeo.geocaching.IWaypoint; import cgeo.geocaching.R; -import cgeo.geocaching.cgCoord; import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.enumerations.CacheType; import cgeo.geocaching.geopoint.Geopoint; @@ -81,15 +81,13 @@ public class GoogleMapProvider implements MapProvider { } @Override - public CachesOverlayItemImpl getCachesOverlayItem(final cgCoord coordinate, final CacheType type) { - GoogleCacheOverlayItem baseItem = new GoogleCacheOverlayItem(coordinate, type); - return baseItem; + public CachesOverlayItemImpl getCachesOverlayItem(final IWaypoint coordinate, final CacheType type) { + return new GoogleCacheOverlayItem(coordinate, type); } @Override public OtherCachersOverlayItemImpl getOtherCachersOverlayItemBase(Context context, Go4CacheUser userOne) { - GoogleOtherCachersOverlayItem baseItem = new GoogleOtherCachersOverlayItem(context, userOne); - return baseItem; + return new GoogleOtherCachersOverlayItem(context, userOne); } } diff --git a/main/src/cgeo/geocaching/maps/google/GoogleMapView.java b/main/src/cgeo/geocaching/maps/google/GoogleMapView.java index 8afba89..8bf7deb 100644 --- a/main/src/cgeo/geocaching/maps/google/GoogleMapView.java +++ b/main/src/cgeo/geocaching/maps/google/GoogleMapView.java @@ -3,6 +3,7 @@ package cgeo.geocaching.maps.google; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import cgeo.geocaching.Settings; +import cgeo.geocaching.geopoint.Viewport; import cgeo.geocaching.maps.CachesOverlay; import cgeo.geocaching.maps.OtherCachersOverlay; import cgeo.geocaching.maps.PositionOverlay; @@ -15,6 +16,7 @@ import cgeo.geocaching.maps.interfaces.MapViewImpl; import cgeo.geocaching.maps.interfaces.OnMapDragListener; import cgeo.geocaching.maps.interfaces.OverlayImpl; import cgeo.geocaching.maps.interfaces.OverlayImpl.overlayType; +import cgeo.geocaching.utils.Log; import com.google.android.maps.GeoPoint; import com.google.android.maps.MapView; @@ -25,7 +27,6 @@ import android.content.Context; import android.graphics.Canvas; import android.graphics.drawable.Drawable; import android.util.AttributeSet; -import android.util.Log; import android.view.GestureDetector; import android.view.GestureDetector.SimpleOnGestureListener; import android.view.Gravity; @@ -60,7 +61,7 @@ public class GoogleMapView extends MapView implements MapViewImpl { super.draw(canvas); } catch (Exception e) { - Log.e(Settings.tag, "GoogleMapView.draw: " + e.toString()); + Log.e("GoogleMapView.draw: " + e.toString()); } } @@ -74,7 +75,7 @@ public class GoogleMapView extends MapView implements MapViewImpl { super.displayZoomControls(takeFocus); } catch (Exception e) { - Log.e(Settings.tag, "GoogleMapView.displayZoomControls: " + e.toString()); + Log.e("GoogleMapView.displayZoomControls: " + e.toString()); } } @@ -90,6 +91,11 @@ public class GoogleMapView extends MapView implements MapViewImpl { } @Override + public Viewport getViewport() { + return new Viewport(getMapViewCenter(), getLatitudeSpan() / 1e6, getLongitudeSpan() / 1e6); + } + + @Override public void addOverlay(OverlayImpl ovl) { getOverlays().add((Overlay) ovl); } diff --git a/main/src/cgeo/geocaching/maps/interfaces/CachesOverlayItemImpl.java b/main/src/cgeo/geocaching/maps/interfaces/CachesOverlayItemImpl.java index e2bf552..1afc120 100644 --- a/main/src/cgeo/geocaching/maps/interfaces/CachesOverlayItemImpl.java +++ b/main/src/cgeo/geocaching/maps/interfaces/CachesOverlayItemImpl.java @@ -1,6 +1,6 @@ package cgeo.geocaching.maps.interfaces; -import cgeo.geocaching.cgCoord; +import cgeo.geocaching.IWaypoint; import cgeo.geocaching.enumerations.CacheType; /** @@ -12,7 +12,7 @@ import cgeo.geocaching.enumerations.CacheType; */ public interface CachesOverlayItemImpl extends OverlayItemImpl { - public cgCoord getCoord(); + public IWaypoint getCoord(); public CacheType getType(); diff --git a/main/src/cgeo/geocaching/maps/interfaces/GeoPointImpl.java b/main/src/cgeo/geocaching/maps/interfaces/GeoPointImpl.java index 55f014b..5636da2 100644 --- a/main/src/cgeo/geocaching/maps/interfaces/GeoPointImpl.java +++ b/main/src/cgeo/geocaching/maps/interfaces/GeoPointImpl.java @@ -1,5 +1,7 @@ package cgeo.geocaching.maps.interfaces; +import cgeo.geocaching.ICoordinates; + /** * Defines the common functions of the provider-specific * GeoPoint implementations @@ -7,7 +9,7 @@ package cgeo.geocaching.maps.interfaces; * @author rsudev * */ -public interface GeoPointImpl { +public interface GeoPointImpl extends ICoordinates { int getLatitudeE6(); diff --git a/main/src/cgeo/geocaching/maps/interfaces/MapProvider.java b/main/src/cgeo/geocaching/maps/interfaces/MapProvider.java index c2c46ac..dd935c4 100644 --- a/main/src/cgeo/geocaching/maps/interfaces/MapProvider.java +++ b/main/src/cgeo/geocaching/maps/interfaces/MapProvider.java @@ -1,6 +1,6 @@ package cgeo.geocaching.maps.interfaces; -import cgeo.geocaching.cgCoord; +import cgeo.geocaching.IWaypoint; import cgeo.geocaching.enumerations.CacheType; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.go4cache.Go4CacheUser; @@ -31,7 +31,7 @@ public interface MapProvider { public GeoPointImpl getGeoPointBase(final Geopoint coords); - public CachesOverlayItemImpl getCachesOverlayItem(final cgCoord coordinate, final CacheType type); + public CachesOverlayItemImpl getCachesOverlayItem(final IWaypoint iWaypoint, final CacheType type); public OtherCachersOverlayItemImpl getOtherCachersOverlayItemBase(Context context, Go4CacheUser userOne); diff --git a/main/src/cgeo/geocaching/maps/interfaces/MapViewImpl.java b/main/src/cgeo/geocaching/maps/interfaces/MapViewImpl.java index 08e04f1..c567cf2 100644 --- a/main/src/cgeo/geocaching/maps/interfaces/MapViewImpl.java +++ b/main/src/cgeo/geocaching/maps/interfaces/MapViewImpl.java @@ -1,5 +1,6 @@ package cgeo.geocaching.maps.interfaces; +import cgeo.geocaching.geopoint.Viewport; import cgeo.geocaching.maps.CachesOverlay; import cgeo.geocaching.maps.OtherCachersOverlay; import cgeo.geocaching.maps.PositionOverlay; @@ -78,4 +79,6 @@ public interface MapViewImpl { */ boolean needsInvertedColors(); + Viewport getViewport(); + } diff --git a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeCacheOverlayItem.java b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeCacheOverlayItem.java index ccc0e78..f2ffae7 100644 --- a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeCacheOverlayItem.java +++ b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeCacheOverlayItem.java @@ -1,6 +1,6 @@ package cgeo.geocaching.maps.mapsforge; -import cgeo.geocaching.cgCoord; +import cgeo.geocaching.IWaypoint; import cgeo.geocaching.enumerations.CacheType; import cgeo.geocaching.maps.interfaces.CachesOverlayItemImpl; @@ -11,16 +11,16 @@ import android.graphics.drawable.Drawable; public class MapsforgeCacheOverlayItem extends OverlayItem implements CachesOverlayItemImpl { final private CacheType cacheType; - final private cgCoord coord; + final private IWaypoint coord; - public MapsforgeCacheOverlayItem(cgCoord coordinate, final CacheType type) { + public MapsforgeCacheOverlayItem(IWaypoint coordinate, final CacheType type) { super(new GeoPoint(coordinate.getCoords().getLatitudeE6(), coordinate.getCoords().getLongitudeE6()), coordinate.getName(), ""); this.cacheType = type; this.coord = coordinate; } - public cgCoord getCoord() { + public IWaypoint getCoord() { return coord; } diff --git a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeGeoPoint.java b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeGeoPoint.java index 19dc7c5..490822b 100644 --- a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeGeoPoint.java +++ b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeGeoPoint.java @@ -1,5 +1,6 @@ package cgeo.geocaching.maps.mapsforge; +import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.maps.interfaces.GeoPointImpl; import org.mapsforge.android.maps.GeoPoint; @@ -9,4 +10,9 @@ public class MapsforgeGeoPoint extends GeoPoint implements GeoPointImpl { public MapsforgeGeoPoint(int latitudeE6, int longitudeE6) { super(latitudeE6, longitudeE6); } + + @Override + public Geopoint getCoords() { + return new Geopoint(getLatitudeE6() / 1e6, getLongitudeE6() / 1e6); + } } diff --git a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapProvider.java b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapProvider.java index 19c1335..c119fd0 100644 --- a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapProvider.java +++ b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapProvider.java @@ -1,7 +1,7 @@ package cgeo.geocaching.maps.mapsforge; +import cgeo.geocaching.IWaypoint; import cgeo.geocaching.R; -import cgeo.geocaching.cgCoord; import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.enumerations.CacheType; import cgeo.geocaching.geopoint.Geopoint; @@ -12,6 +12,8 @@ import cgeo.geocaching.maps.interfaces.GeoPointImpl; import cgeo.geocaching.maps.interfaces.MapProvider; import cgeo.geocaching.maps.interfaces.OtherCachersOverlayItemImpl; +import org.mapsforge.android.maps.MapDatabase; + import android.app.Activity; import android.content.Context; import android.content.res.Resources; @@ -80,15 +82,17 @@ public class MapsforgeMapProvider implements MapProvider { } @Override - public CachesOverlayItemImpl getCachesOverlayItem(final cgCoord coordinate, final CacheType type) { - MapsforgeCacheOverlayItem baseItem = new MapsforgeCacheOverlayItem(coordinate, type); - return baseItem; + public CachesOverlayItemImpl getCachesOverlayItem(final IWaypoint coordinate, final CacheType type) { + return new MapsforgeCacheOverlayItem(coordinate, type); } @Override public OtherCachersOverlayItemImpl getOtherCachersOverlayItemBase(Context context, Go4CacheUser userOne) { - MapsforgeOtherCachersOverlayItem baseItem = new MapsforgeOtherCachersOverlayItem(context, userOne); - return baseItem; + return new MapsforgeOtherCachersOverlayItem(context, userOne); + } + + public static boolean isValidMapFile(String mapFileIn) { + return MapDatabase.isValidMapFile(mapFileIn); } } diff --git a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapView.java b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapView.java index d14ea8c..aaede4d 100644 --- a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapView.java +++ b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapView.java @@ -1,6 +1,8 @@ package cgeo.geocaching.maps.mapsforge; +import cgeo.geocaching.R; import cgeo.geocaching.Settings; +import cgeo.geocaching.geopoint.Viewport; import cgeo.geocaching.maps.CachesOverlay; import cgeo.geocaching.maps.OtherCachersOverlay; import cgeo.geocaching.maps.PositionOverlay; @@ -13,9 +15,9 @@ import cgeo.geocaching.maps.interfaces.MapViewImpl; import cgeo.geocaching.maps.interfaces.OnMapDragListener; import cgeo.geocaching.maps.interfaces.OverlayImpl; import cgeo.geocaching.maps.interfaces.OverlayImpl.overlayType; +import cgeo.geocaching.utils.Log; import org.mapsforge.android.maps.GeoPoint; -import org.mapsforge.android.maps.MapDatabase; import org.mapsforge.android.maps.MapView; import org.mapsforge.android.maps.MapViewMode; import org.mapsforge.android.maps.Overlay; @@ -26,10 +28,10 @@ import android.content.Context; import android.graphics.Canvas; import android.graphics.drawable.Drawable; import android.util.AttributeSet; -import android.util.Log; import android.view.GestureDetector; import android.view.GestureDetector.SimpleOnGestureListener; import android.view.MotionEvent; +import android.widget.Toast; public class MapsforgeMapView extends MapView implements MapViewImpl { private GestureDetector gestureDetector; @@ -49,7 +51,7 @@ public class MapsforgeMapView extends MapView implements MapViewImpl { super.draw(canvas); } catch (Exception e) { - Log.e(Settings.tag, "MapsforgeMapView.draw: " + e.toString()); + Log.e("MapsforgeMapView.draw: " + e.toString()); } } @@ -70,6 +72,11 @@ public class MapsforgeMapView extends MapView implements MapViewImpl { } @Override + public Viewport getViewport() { + return new Viewport(getMapViewCenter(), getLatitudeSpan() / 1e6, getLongitudeSpan() / 1e6); + } + + @Override public void addOverlay(OverlayImpl ovl) { getOverlays().add((Overlay) ovl); } @@ -170,11 +177,14 @@ public class MapsforgeMapView extends MapView implements MapViewImpl { setMapViewMode(MapViewMode.OPENCYCLEMAP_TILE_DOWNLOAD); break; case MapsforgeMapProvider.OFFLINE: - if (MapDatabase.isValidMapFile(Settings.getMapFile())) { - setMapViewMode(MapViewMode.CANVAS_RENDERER); - super.setMapFile(Settings.getMapFile()); - } else { - setMapViewMode(MapViewMode.MAPNIK_TILE_DOWNLOAD); + setMapViewMode(MapViewMode.CANVAS_RENDERER); + super.setMapFile(Settings.getMapFile()); + if (!Settings.isValidMapFile(Settings.getMapFile())) { + Toast.makeText( + getContext(), + getContext().getResources().getString(R.string.warn_invalid_mapfile), + Toast.LENGTH_LONG) + .show(); } break; default: @@ -196,7 +206,7 @@ public class MapsforgeMapView extends MapView implements MapViewImpl { } } catch (Exception e) { - Log.e(Settings.tag, "MapsforgeMapView.repaintRequired: " + e.toString()); + Log.e("MapsforgeMapView.repaintRequired: " + e.toString()); } } } diff --git a/main/src/cgeo/geocaching/network/Cookies.java b/main/src/cgeo/geocaching/network/Cookies.java new file mode 100644 index 0000000..68310e6 --- /dev/null +++ b/main/src/cgeo/geocaching/network/Cookies.java @@ -0,0 +1,47 @@ +package cgeo.geocaching.network; + +import org.apache.commons.lang3.StringUtils; +import org.apache.http.client.CookieStore; +import org.apache.http.cookie.Cookie; +import org.apache.http.impl.client.BasicCookieStore; +import org.apache.http.impl.cookie.BasicClientCookie; + +public abstract class Cookies { + + private static boolean cookieStoreRestored = false; + final static CookieStore cookieStore = new BasicCookieStore(); + + public static void restoreCookieStore(final String oldCookies) { + if (!cookieStoreRestored) { + clearCookies(); + if (oldCookies != null) { + for (final String cookie : StringUtils.split(oldCookies, ';')) { + final String[] split = StringUtils.split(cookie, "=", 3); + if (split.length == 3) { + final BasicClientCookie newCookie = new BasicClientCookie(split[0], split[1]); + newCookie.setDomain(split[2]); + cookieStore.addCookie(newCookie); + } + } + } + cookieStoreRestored = true; + } + } + + public static String dumpCookieStore() { + StringBuilder cookies = new StringBuilder(); + for (final Cookie cookie : cookieStore.getCookies()) { + cookies.append(cookie.getName()); + cookies.append('='); + cookies.append(cookie.getValue()); + cookies.append('='); + cookies.append(cookie.getDomain()); + cookies.append(';'); + } + return cookies.toString(); + } + + public static void clearCookies() { + cookieStore.clear(); + } +} diff --git a/main/src/cgeo/geocaching/network/HtmlImage.java b/main/src/cgeo/geocaching/network/HtmlImage.java index 1811110..7e4143e 100644 --- a/main/src/cgeo/geocaching/network/HtmlImage.java +++ b/main/src/cgeo/geocaching/network/HtmlImage.java @@ -1,10 +1,10 @@ package cgeo.geocaching.network; import cgeo.geocaching.R; -import cgeo.geocaching.Settings; import cgeo.geocaching.StoredList; import cgeo.geocaching.connector.ConnectorFactory; import cgeo.geocaching.files.LocalStorage; +import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; import org.apache.http.HttpResponse; @@ -16,7 +16,6 @@ import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.net.Uri; import android.text.Html; -import android.util.Log; import android.view.Display; import android.view.WindowManager; @@ -72,26 +71,26 @@ public class HtmlImage implements Html.ImageGetter { return new BitmapDrawable(getTransparent1x1Image()); } - Bitmap imagePre = null; - - // Load image from cache - if (!onlySave) { - imagePre = loadImageFromStorage(url); - } + Bitmap imagePre = loadImageFromStorage(url); // Download image and save it to the cache - if (imagePre == null || onlySave) { + if (imagePre == null) { final String absoluteURL = makeAbsoluteURL(url); if (absoluteURL != null) { try { - final HttpResponse httpResponse = Network.request(absoluteURL, null, false); + final File file = LocalStorage.getStorageFile(geocode, url, true, true); + final HttpResponse httpResponse = Network.getRequest(absoluteURL, null, file); if (httpResponse != null) { - final File file = LocalStorage.getStorageFile(geocode, url, true, true); - LocalStorage.saveEntityToFile(httpResponse, file); + final int statusCode = httpResponse.getStatusLine().getStatusCode(); + if (statusCode == 200) { + LocalStorage.saveEntityToFile(httpResponse, file); + } else if (statusCode == 304) { + file.setLastModified(System.currentTimeMillis()); + } } } catch (Exception e) { - Log.e(Settings.tag, "HtmlImage.getDrawable (downloading from web)", e); + Log.e("HtmlImage.getDrawable (downloading from web)", e); } } } @@ -107,7 +106,7 @@ public class HtmlImage implements Html.ImageGetter { // get image and return if (imagePre == null) { - Log.d(Settings.tag, "HtmlImage.getDrawable: Failed to obtain image"); + Log.d("HtmlImage.getDrawable: Failed to obtain image"); if (returnErrorImage) { imagePre = BitmapFactory.decodeResource(context.getResources(), R.drawable.image_not_loaded); @@ -130,7 +129,7 @@ public class HtmlImage implements Html.ImageGetter { try { imagePre = Bitmap.createScaledBitmap(imagePre, width, height, true); } catch (Exception e) { - Log.d(Settings.tag, "HtmlImage.getDrawable: Failed to scale image"); + Log.d("HtmlImage.getDrawable: Failed to scale image"); return null; } } else { @@ -158,32 +157,31 @@ public class HtmlImage implements Html.ImageGetter { final File fileSec = LocalStorage.getStorageSecFile(geocode, url, true); return loadCachedImage(fileSec); } catch (Exception e) { - Log.w(Settings.tag, "HtmlImage.getDrawable (reading cache): " + e.toString()); + Log.w("HtmlImage.getDrawable (reading cache): " + e.toString()); } return null; } - private final String makeAbsoluteURL(final String url) { - try { - // Check if uri is absolute or not, if not attach the connector hostname - // FIXME: that should also include the scheme - if (Uri.parse(url).isAbsolute()) { - return url; - } else { - final String host = ConnectorFactory.getConnector(geocode).getHost(); - if (StringUtils.isNotEmpty(host)) { - StringBuilder builder = new StringBuilder("http://"); - builder.append(host); - if (!StringUtils.startsWith(url, "/")) { - builder.append('/'); - } - builder.append(url); - return builder.toString(); - } + private String makeAbsoluteURL(final String url) { + // Check if uri is absolute or not, if not attach the connector hostname + // FIXME: that should also include the scheme + if (Uri.parse(url).isAbsolute()) { + return url; + } + + final String host = ConnectorFactory.getConnector(geocode).getHost(); + if (StringUtils.isNotEmpty(host)) { + final StringBuilder builder = new StringBuilder("http://"); + builder.append(host); + if (!StringUtils.startsWith(url, "/")) { + // FIXME: explain why the result URL would be valid if the path does not start with + // a '/', or signal an error. + builder.append('/'); } - } catch (Exception e) { - Log.e(Settings.tag, "HtmlImage.makeAbsoluteURL (parse URL)", e); + builder.append(url); + return builder.toString(); } + return null; } @@ -207,7 +205,7 @@ public class HtmlImage implements Html.ImageGetter { fis = new FileInputStream(file); BitmapFactory.decodeStream(fis, null, options); } catch (FileNotFoundException e) { - Log.e(Settings.tag, "HtmlImage.setSampleSize", e); + Log.e("HtmlImage.setSampleSize", e); } finally { if (fis != null) { try { diff --git a/main/src/cgeo/geocaching/network/Network.java b/main/src/cgeo/geocaching/network/Network.java index 0afe095..39c0cf5 100644 --- a/main/src/cgeo/geocaching/network/Network.java +++ b/main/src/cgeo/geocaching/network/Network.java @@ -1,11 +1,9 @@ package cgeo.geocaching.network; -import cgeo.geocaching.Settings; -import cgeo.geocaching.cgBase; -import cgeo.geocaching.enumerations.StatusCode; +import cgeo.geocaching.files.LocalStorage; import cgeo.geocaching.utils.BaseUtils; +import cgeo.geocaching.utils.Log; -import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.apache.http.Header; import org.apache.http.HeaderElement; @@ -16,17 +14,13 @@ import org.apache.http.HttpRequestInterceptor; import org.apache.http.HttpResponse; import org.apache.http.HttpResponseInterceptor; import org.apache.http.NameValuePair; -import org.apache.http.client.CookieStore; import org.apache.http.client.HttpClient; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpRequestBase; -import org.apache.http.cookie.Cookie; import org.apache.http.entity.HttpEntityWrapper; -import org.apache.http.impl.client.BasicCookieStore; import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.impl.cookie.BasicClientCookie; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.CoreConnectionPNames; import org.apache.http.params.CoreProtocolPNames; @@ -38,15 +32,14 @@ import org.json.JSONException; import org.json.JSONObject; import android.net.Uri; -import android.util.Log; +import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.io.UnsupportedEncodingException; import java.net.URLEncoder; -import java.util.List; import java.util.zip.GZIPInputStream; - public abstract class Network { static class GzipDecompressingEntity extends HttpEntityWrapper { @@ -57,13 +50,12 @@ public abstract class Network { @Override public InputStream getContent() throws IOException, IllegalStateException { // the wrapped entity's getContent() decides about repeatability - InputStream wrappedin = wrappedEntity.getContent(); - return new GZIPInputStream(wrappedin); + return new GZIPInputStream(wrappedEntity.getContent()); } @Override public long getContentLength() { - // length of ungzipped content is not known + // length of gunzipped content is not known return -1; } } @@ -74,8 +66,6 @@ public abstract class Network { private static final String PATTERN_PASSWORD = "(?<=[\\?&])[Pp]ass(w(or)?d)?=[^&#$]+"; private final static HttpParams clientParams = new BasicHttpParams(); - private static boolean cookieStoreRestored = false; - private final static CookieStore cookieStore = new BasicCookieStore(); static { Network.clientParams.setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET, HTTP.UTF_8); @@ -89,7 +79,7 @@ public abstract class Network { private static HttpClient getHttpClient() { final DefaultHttpClient client = new DefaultHttpClient(); - client.setCookieStore(cookieStore); + client.setCookieStore(Cookies.cookieStore); client.setParams(clientParams); client.addRequestInterceptor(new HttpRequestInterceptor() { @@ -108,16 +98,14 @@ public abstract class Network { public void process( final HttpResponse response, final HttpContext context) throws HttpException, IOException { - HttpEntity entity = response.getEntity(); - if (null != entity) { - Header ceheader = entity.getContentEncoding(); - if (ceheader != null) { - HeaderElement[] codecs = ceheader.getElements(); - for (int i = 0; i < codecs.length; i++) { - if (codecs[i].getName().equalsIgnoreCase("gzip")) { - Log.d(Settings.tag, "Decompressing response"); - response.setEntity( - new Network.GzipDecompressingEntity(response.getEntity())); + final HttpEntity entity = response.getEntity(); + if (entity != null) { + final Header contentEncoding = entity.getContentEncoding(); + if (contentEncoding != null) { + for (final HeaderElement codec : contentEncoding.getElements()) { + if (codec.getName().equalsIgnoreCase("gzip")) { + Log.d("Decompressing response"); + response.setEntity(new GzipDecompressingEntity(response.getEntity())); return; } } @@ -130,127 +118,80 @@ public abstract class Network { return client; } - public static void restoreCookieStore(final String oldCookies) { - if (!cookieStoreRestored) { - Network.clearCookies(); - if (oldCookies != null) { - for (final String cookie : StringUtils.split(oldCookies, ';')) { - final String[] split = StringUtils.split(cookie, "=", 3); - if (split.length == 3) { - final BasicClientCookie newCookie = new BasicClientCookie(split[0], split[1]); - newCookie.setDomain(split[2]); - cookieStore.addCookie(newCookie); - } - } - } - cookieStoreRestored = true; - } - } - - public static String dumpCookieStore() { - StringBuilder cookies = new StringBuilder(); - for (final Cookie cookie : cookieStore.getCookies()) { - cookies.append(cookie.getName()); - cookies.append('='); - cookies.append(cookie.getValue()); - cookies.append('='); - cookies.append(cookie.getDomain()); - cookies.append(';'); - } - return cookies.toString(); - } - - public static void clearCookies() { - cookieStore.clear(); - } - /** * POST HTTP request * - * @param uri - * @param params - * @return - */ - public static HttpResponse postRequest(final String uri, final List<? extends NameValuePair> params) { - try { - HttpPost request = new HttpPost(uri); - if (params != null) { - request.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8)); - } - request.setHeader("X-Requested-With", "XMLHttpRequest"); - return Network.request(request); - } catch (Exception e) { - // Can be UnsupportedEncodingException, ClientProtocolException or IOException - Log.e(Settings.tag, "postRequest", e); - return null; - } - } - - /** - * GET HTTP request - * - * @param uri - * @param params - * @param xContentType - * @param my - * @param addF - * @return + * @param uri the URI to request + * @param params the parameters to add to the POST request + * @return the HTTP response, or null in case of an encoding error params */ - public static HttpResponse request(final String uri, final Parameters params, boolean xContentType, boolean my, boolean addF) { - return Network.request(uri, cgBase.addFToParams(params, my, addF), xContentType); + public static HttpResponse postRequest(final String uri, final Parameters params) { + return request("POST", uri, params, null, null); } /** - * GET HTTP request + * Make an HTTP request * + * @param method + * the HTTP method to use ("GET" or "POST") * @param uri + * the URI to request * @param params - * @param xContentType - * @return + * the parameters to add the the GET request + * @param headers + * the headers to add to the GET request + * @param cacheFile + * the cache file used to cache this query + * @return the HTTP response, or null in case of an encoding error in a POST request arguments */ - public static HttpResponse request(final String uri, final Parameters params, final boolean xContentType) { - final String fullUri = params == null ? uri : Uri.parse(uri).buildUpon().encodedQuery(params.toString()).build().toString(); - final HttpRequestBase request = new HttpGet(fullUri); - - request.setHeader("X-Requested-With", "XMLHttpRequest"); - - if (xContentType) { - request.setHeader("Content-Type", "application/x-www-form-urlencoded"); + private static HttpResponse request(final String method, final String uri, final Parameters params, final Parameters headers, final File cacheFile) { + HttpRequestBase request; + if (method.equals("GET")) { + final String fullUri = params == null ? uri : Uri.parse(uri).buildUpon().encodedQuery(params.toString()).build().toString(); + request = new HttpGet(fullUri); + } else { + request = new HttpPost(uri); + if (params != null) { + try { + ((HttpPost) request).setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8)); + } catch (final UnsupportedEncodingException e) { + Log.e("request", e); + return null; + } + } } - return Network.request(request); - } + for (final NameValuePair header : Parameters.extend(Parameters.merge(headers, cacheHeaders(cacheFile)), + "Accept-Charset", "utf-8,iso-8859-1;q=0.8,utf-16;q=0.8,*;q=0.7", + "Accept-Language", "en-US,*;q=0.9", + "X-Requested-With", "XMLHttpRequest")) { + request.setHeader(header.getName(), header.getValue()); + } - public static HttpResponse request(final HttpRequestBase request) { - request.setHeader("Accept-Charset", "utf-8,iso-8859-1;q=0.8,utf-16;q=0.8,*;q=0.7"); - request.setHeader("Accept-Language", "en-US,*;q=0.9"); - request.getParams().setParameter(CoreProtocolPNames.USER_AGENT, USER_AGENT); - return Network.doRequest(request); - } + request.getParams().setParameter(CoreProtocolPNames.USER_AGENT, Network.USER_AGENT); - private static HttpResponse doRequest(final HttpRequestBase request) { - final String reqLogStr = request.getMethod() + " " + hidePassword(request.getURI().toString()); - Log.d(Settings.tag, reqLogStr); + final String reqLogStr = request.getMethod() + " " + Network.hidePassword(request.getURI().toString()); + Log.d(reqLogStr); - final HttpClient client = getHttpClient(); - for (int i = 0; i <= NB_DOWNLOAD_RETRIES; i++) { + final HttpClient client = Network.getHttpClient(); + for (int i = 0; i <= Network.NB_DOWNLOAD_RETRIES; i++) { final long before = System.currentTimeMillis(); try { final HttpResponse response = client.execute(request); int status = response.getStatusLine().getStatusCode(); if (status == 200) { - Log.d(Settings.tag, status + Network.formatTimeSpan(before) + reqLogStr); + Log.d(status + Network.formatTimeSpan(before) + reqLogStr); } else { - Log.w(Settings.tag, status + " [" + response.getStatusLine().getReasonPhrase() + "]" + Network.formatTimeSpan(before) + reqLogStr); + Log.w(status + " [" + response.getStatusLine().getReasonPhrase() + "]" + Network.formatTimeSpan(before) + reqLogStr); } return response; } catch (IOException e) { final String timeSpan = Network.formatTimeSpan(before); - final String tries = (i + 1) + "/" + (NB_DOWNLOAD_RETRIES + 1); - if (i == NB_DOWNLOAD_RETRIES) { - Log.e(Settings.tag, "Failure " + tries + timeSpan + reqLogStr, e); + final String tries = (i + 1) + "/" + (Network.NB_DOWNLOAD_RETRIES + 1); + if (i == Network.NB_DOWNLOAD_RETRIES) { + Log.e("Failure " + tries + timeSpan + reqLogStr, e); } else { - Log.e(Settings.tag, "Failure " + tries + " (" + e.toString() + ")" + timeSpan + "- retrying " + reqLogStr); + Log.e("Failure " + tries + " (" + e.toString() + ")" + timeSpan + "- retrying " + reqLogStr); } } } @@ -258,6 +199,79 @@ public abstract class Network { return null; } + private static Parameters cacheHeaders(final File cacheFile) { + if (cacheFile == null || !cacheFile.exists()) { + return null; + } + + final String etag = LocalStorage.getSavedHeader(cacheFile, "etag"); + if (etag != null) { + return new Parameters("If-None-Match", etag); + } + + final String lastModified = LocalStorage.getSavedHeader(cacheFile, "last-modified"); + if (lastModified != null) { + return new Parameters("If-Modified-Since", lastModified); + } + + return null; + } + + /** + * GET HTTP request + * + * @param uri + * the URI to request + * @param params + * the parameters to add the the GET request + * @param cacheFile + * the name of the file storing the cached resource, or null not to use one + * @return the HTTP response + */ + public static HttpResponse getRequest(final String uri, final Parameters params, final File cacheFile) { + return request("GET", uri, params, null, cacheFile); + } + + + /** + * GET HTTP request + * + * @param uri + * the URI to request + * @param params + * the parameters to add the the GET request + * @return the HTTP response + */ + public static HttpResponse getRequest(final String uri, final Parameters params) { + return request("GET", uri, params, null, null); + } + + /** + * GET HTTP request + * + * @param uri + * the URI to request + * @param params + * the parameters to add the the GET request + * @param headers + * the headers to add to the GET request + * @return the HTTP response + */ + public static HttpResponse getRequest(final String uri, final Parameters params, final Parameters headers) { + return request("GET", uri, params, headers, null); + } + + /** + * GET HTTP request + * + * @param uri + * the URI to request + * @return the HTTP response + */ + public static HttpResponse getRequest(final String uri) { + return request("GET", uri, null, null, null); + } + private static String formatTimeSpan(final long before) { // don't use String.format in a pure logging routine, it has very bad performance return " (" + (System.currentTimeMillis() - before) + " ms) "; @@ -268,33 +282,24 @@ public abstract class Network { } public static JSONObject requestJSON(final String uri, final Parameters params) { - final HttpGet request = new HttpGet(Network.prepareParameters(uri, params)); - request.setHeader("Accept", "application/json, text/javascript, */*; q=0.01"); - request.setHeader("Content-Type", "application/json; charset=UTF-8"); - request.setHeader("X-Requested-With", "XMLHttpRequest"); - - final HttpResponse response = doRequest(request); - if (response != null && response.getStatusLine().getStatusCode() == 200) { + final HttpResponse response = request("GET", uri, params, new Parameters("Accept", "application/json, text/javascript, */*; q=0.01"), null); + if (isSuccess(response)) { try { return new JSONObject(Network.getResponseData(response)); - } catch (JSONException e) { - Log.e(Settings.tag, "Network.requestJSON", e); + } catch (final JSONException e) { + Log.e("Network.requestJSON", e); } } return null; } - private static String prepareParameters(final String baseUri, final Parameters params) { - return CollectionUtils.isNotEmpty(params) ? baseUri + "?" + params.toString() : baseUri; - } - private static String getResponseDataNoError(final HttpResponse response, boolean replaceWhitespace) { try { String data = EntityUtils.toString(response.getEntity(), HTTP.UTF_8); return replaceWhitespace ? BaseUtils.replaceWhitespace(data) : data; } catch (Exception e) { - Log.e(Settings.tag, "getResponseData", e); + Log.e("getResponseData", e); return null; } } @@ -303,62 +308,15 @@ public abstract class Network { return Network.getResponseData(response, true); } - static public String getResponseData(final HttpResponse response, boolean replaceWhitespace) { + public static String getResponseData(final HttpResponse response, boolean replaceWhitespace) { if (!isSuccess(response)) { return null; } return getResponseDataNoError(response, replaceWhitespace); } - /** - * POST HTTP request. Do the request a second time if the user is not logged in - * - * @param uri - * @return - */ - public static String postRequestLogged(final String uri) { - HttpResponse response = postRequest(uri, null); - String data = getResponseData(response); - - if (!Login.getLoginStatus(data)) { - if (Login.login() == StatusCode.NO_ERROR) { - response = postRequest(uri, null); - data = getResponseData(response); - } else { - Log.i(Settings.tag, "Working as guest."); - } - } - return data; - } - - /** - * GET HTTP request. Do the request a second time if the user is not logged in - * - * @param uri - * @param params - * @param xContentType - * @param my - * @param addF - * @return - */ - public static String requestLogged(final String uri, final Parameters params, boolean xContentType, boolean my, boolean addF) { - HttpResponse response = request(uri, params, xContentType, my, addF); - String data = getResponseData(response); - - if (!Login.getLoginStatus(data)) { - if (Login.login() == StatusCode.NO_ERROR) { - response = request(uri, params, xContentType, my, addF); - data = getResponseData(response); - } else { - Log.i(Settings.tag, "Working as guest."); - } - } - return data; + public static String rfc3986URLEncode(String text) { + return StringUtils.replace(URLEncoder.encode(text).replace("+", "%20"), "%7E", "~"); } - public static String urlencode_rfc3986(String text) { - final String encoded = StringUtils.replace(URLEncoder.encode(text).replace("+", "%20"), "%7E", "~"); - - return encoded; - } } diff --git a/main/src/cgeo/geocaching/network/OAuth.java b/main/src/cgeo/geocaching/network/OAuth.java index cefa90d..8cecb22 100644 --- a/main/src/cgeo/geocaching/network/OAuth.java +++ b/main/src/cgeo/geocaching/network/OAuth.java @@ -23,11 +23,11 @@ public class OAuth { final List<String> paramsEncoded = new ArrayList<String>(); for (final NameValuePair nameValue : params) { - paramsEncoded.add(nameValue.getName() + "=" + Network.urlencode_rfc3986(nameValue.getValue())); + paramsEncoded.add(nameValue.getName() + "=" + Network.rfc3986URLEncode(nameValue.getValue())); } final String keysPacked = Settings.getKeyConsumerSecret() + "&" + StringUtils.defaultString(tokenSecret); // both even if empty some of them! - final String requestPacked = method + "&" + Network.urlencode_rfc3986((https ? "https" : "http") + "://" + host + path) + "&" + Network.urlencode_rfc3986(StringUtils.join(paramsEncoded.toArray(), '&')); + final String requestPacked = method + "&" + Network.rfc3986URLEncode((https ? "https" : "http") + "://" + host + path) + "&" + Network.rfc3986URLEncode(StringUtils.join(paramsEncoded.toArray(), '&')); params.put("oauth_signature", CryptUtils.base64Encode(CryptUtils.hashHmac(requestPacked, keysPacked))); } } diff --git a/main/src/cgeo/geocaching/network/Parameters.java b/main/src/cgeo/geocaching/network/Parameters.java index e65bec2..90965e4 100644 --- a/main/src/cgeo/geocaching/network/Parameters.java +++ b/main/src/cgeo/geocaching/network/Parameters.java @@ -12,7 +12,7 @@ import java.util.Comparator; /** * List of key/values pairs to be used in a GET or POST request. - * + * */ public class Parameters extends ArrayList<NameValuePair> { @@ -44,14 +44,16 @@ public class Parameters extends ArrayList<NameValuePair> { * list of key/value pairs * @throws InvalidParameterException * if the number of key/values is unbalanced + * @return the object itself to facilitate chaining */ - public void put(final String... keyValues) { + public Parameters put(final String... keyValues) { if (keyValues.length % 2 == 1) { throw new InvalidParameterException("odd number of parameters"); } for (int i = 0; i < keyValues.length; i += 2) { add(new BasicNameValuePair(keyValues[i], keyValues[i + 1])); } + return this; } /** @@ -63,12 +65,43 @@ public class Parameters extends ArrayList<NameValuePair> { Collections.sort(this, comparator); } - /** - * @return the URL encoded string corresponding to those parameters - */ @Override public String toString() { return URLEncodedUtils.format(this, HTTP.UTF_8); } + /** + * Extend or create a Parameters object with new key/value pairs. + * + * @param params + * an existing object or null to create a new one + * @param keyValues + * list of key/value pair + * @throws InvalidParameterException + * if the number of key/values is unbalanced + * @return the object itself if it is non-null, a new one otherwise + */ + public static Parameters extend(final Parameters params, final String... keyValues) { + return params == null ? new Parameters(keyValues) : params.put(keyValues); + } + + /** + * Merge two (possibly null) Parameters object. + * + * @param params + * the object to merge into if non-null + * @param extra + * the object to merge from if non-null + * @return params with extra data if params was non-null, extra otherwise + */ + public static Parameters merge(final Parameters params, final Parameters extra) { + if (params == null) { + return extra; + } + if (extra != null) { + params.addAll(extra); + } + return params; + } + } diff --git a/main/src/cgeo/geocaching/sorting/AbstractCacheComparator.java b/main/src/cgeo/geocaching/sorting/AbstractCacheComparator.java index bc93d3b..2015375 100644 --- a/main/src/cgeo/geocaching/sorting/AbstractCacheComparator.java +++ b/main/src/cgeo/geocaching/sorting/AbstractCacheComparator.java @@ -1,9 +1,8 @@ package cgeo.geocaching.sorting; import cgeo.geocaching.cgCache; -import cgeo.geocaching.Settings; +import cgeo.geocaching.utils.Log; -import android.util.Log; /** * abstract super implementation for all cache comparators @@ -12,7 +11,7 @@ import android.util.Log; public abstract class AbstractCacheComparator implements CacheComparator { @Override - public final int compare(cgCache cache1, cgCache cache2) { + public final int compare(final cgCache cache1, final cgCache cache2) { try { // first check that we have all necessary data for the comparison if (!canCompare(cache1, cache2)) { @@ -20,13 +19,13 @@ public abstract class AbstractCacheComparator implements CacheComparator { } return compareCaches(cache1, cache2); } catch (Exception e) { - Log.e(Settings.tag, "AbstractCacheComparator.compare: " + e.toString()); + Log.e("AbstractCacheComparator.compare: " + e.toString()); } return 0; } /** - * check necessary preconditions (like missing fields) before running the comparison itself + * Check necessary preconditions (like missing fields) before running the comparison itself * * @param cache1 * @param cache2 @@ -35,7 +34,10 @@ public abstract class AbstractCacheComparator implements CacheComparator { protected abstract boolean canCompare(final cgCache cache1, final cgCache cache2); /** - * compares two caches. Logging and exception handling is implemented outside this method already. + * Compares two caches. Logging and exception handling is implemented outside this method already. + * <p/> + * A cache is smaller than another cache if it is desirable to show it first when presented to the user. + * For example, a highly rated cache must be considered smaller than a poorly rated one. * * @param cache1 * @param cache2 diff --git a/main/src/cgeo/geocaching/sorting/DifficultyComparator.java b/main/src/cgeo/geocaching/sorting/DifficultyComparator.java index 0d65660..123bab9 100644 --- a/main/src/cgeo/geocaching/sorting/DifficultyComparator.java +++ b/main/src/cgeo/geocaching/sorting/DifficultyComparator.java @@ -15,11 +15,6 @@ public class DifficultyComparator extends AbstractCacheComparator { @Override protected int compareCaches(final cgCache cache1, final cgCache cache2) { - if (cache1.getDifficulty() > cache2.getDifficulty()) { - return 1; - } else if (cache2.getDifficulty() > cache1.getDifficulty()) { - return -1; - } - return 0; + return Float.compare(cache1.getDifficulty(), cache2.getDifficulty()); } }
\ No newline at end of file diff --git a/main/src/cgeo/geocaching/sorting/EventDateComparator.java b/main/src/cgeo/geocaching/sorting/EventDateComparator.java index 0092901..ac49e66 100644 --- a/main/src/cgeo/geocaching/sorting/EventDateComparator.java +++ b/main/src/cgeo/geocaching/sorting/EventDateComparator.java @@ -1,8 +1,5 @@ package cgeo.geocaching.sorting; -import cgeo.geocaching.cgCache; - - /** * Compares caches by date. Used only for event caches. * @@ -11,13 +8,4 @@ import cgeo.geocaching.cgCache; */ public class EventDateComparator extends DateComparator { - @Override - protected boolean canCompare(cgCache cache1, cgCache cache2) { - return super.canCompare(cache1, cache2); - } - - @Override - protected int compareCaches(cgCache cache1, cgCache cache2) { - return super.compareCaches(cache1, cache2); - } } diff --git a/main/src/cgeo/geocaching/sorting/FindsComparator.java b/main/src/cgeo/geocaching/sorting/FindsComparator.java index 7a1555e..98fe1dd 100644 --- a/main/src/cgeo/geocaching/sorting/FindsComparator.java +++ b/main/src/cgeo/geocaching/sorting/FindsComparator.java @@ -31,7 +31,7 @@ public class FindsComparator extends AbstractCacheComparator { } Integer logged = cache.getLogCounts().get(LogType.LOG_FOUND_IT); if (logged != null) { - finds = logged.intValue(); + finds = logged; } return finds; } diff --git a/main/src/cgeo/geocaching/sorting/GeocodeComparator.java b/main/src/cgeo/geocaching/sorting/GeocodeComparator.java index 1377cce..fb93c0e 100644 --- a/main/src/cgeo/geocaching/sorting/GeocodeComparator.java +++ b/main/src/cgeo/geocaching/sorting/GeocodeComparator.java @@ -17,12 +17,8 @@ public class GeocodeComparator extends AbstractCacheComparator { } @Override - protected int compareCaches(cgCache cache1, cgCache cache2) { - if (cache1.getGeocode().length() > cache2.getGeocode().length()) { - return 1; - } else if (cache2.getGeocode().length() > cache1.getGeocode().length()) { - return -1; - } - return cache1.getGeocode().compareToIgnoreCase(cache2.getGeocode()); + protected int compareCaches(final cgCache cache1, final cgCache cache2) { + final int lengthDiff = cache1.getGeocode().length() - cache2.getGeocode().length(); + return lengthDiff != 0 ? lengthDiff : cache1.getGeocode().compareToIgnoreCase(cache2.getGeocode()); } } diff --git a/main/src/cgeo/geocaching/sorting/InventoryComparator.java b/main/src/cgeo/geocaching/sorting/InventoryComparator.java index b1842d7..d4e9f5e 100644 --- a/main/src/cgeo/geocaching/sorting/InventoryComparator.java +++ b/main/src/cgeo/geocaching/sorting/InventoryComparator.java @@ -11,19 +11,12 @@ import cgeo.geocaching.cgCache; public class InventoryComparator extends AbstractCacheComparator { @Override - protected boolean canCompare(cgCache cache1, cgCache cache2) { + protected boolean canCompare(final cgCache cache1, final cgCache cache2) { return true; } @Override - protected int compareCaches(cgCache cache1, cgCache cache2) { - int itemCount1 = cache1.getInventoryItems(); - int itemCount2 = cache2.getInventoryItems(); - if (itemCount1 < itemCount2) { - return 1; - } else if (itemCount2 < itemCount1) { - return -1; - } - return 0; + protected int compareCaches(final cgCache cache1, final cgCache cache2) { + return cache2.getInventoryItems() - cache1.getInventoryItems(); } } diff --git a/main/src/cgeo/geocaching/sorting/PopularityComparator.java b/main/src/cgeo/geocaching/sorting/PopularityComparator.java index 9fe254a..62ad9a9 100644 --- a/main/src/cgeo/geocaching/sorting/PopularityComparator.java +++ b/main/src/cgeo/geocaching/sorting/PopularityComparator.java @@ -9,17 +9,12 @@ import cgeo.geocaching.cgCache; public class PopularityComparator extends AbstractCacheComparator { @Override - protected boolean canCompare(cgCache cache1, cgCache cache2) { + protected boolean canCompare(final cgCache cache1, final cgCache cache2) { return true; } @Override - protected int compareCaches(cgCache cache1, cgCache cache2) { - if (cache1.getFavoritePoints() < cache2.getFavoritePoints()) { - return 1; - } else if (cache2.getFavoritePoints() < cache1.getFavoritePoints()) { - return -1; - } - return 0; + protected int compareCaches(final cgCache cache1, final cgCache cache2) { + return cache2.getFavoritePoints() - cache1.getFavoritePoints(); } } diff --git a/main/src/cgeo/geocaching/sorting/RatingComparator.java b/main/src/cgeo/geocaching/sorting/RatingComparator.java index 935ccd8..be071c5 100644 --- a/main/src/cgeo/geocaching/sorting/RatingComparator.java +++ b/main/src/cgeo/geocaching/sorting/RatingComparator.java @@ -9,28 +9,15 @@ import cgeo.geocaching.cgCache; public class RatingComparator extends AbstractCacheComparator { @Override - protected boolean canCompare(cgCache cache1, cgCache cache2) { + protected boolean canCompare(final cgCache cache1, final cgCache cache2) { return true; } @Override - protected int compareCaches(cgCache cache1, cgCache cache2) { - float rating1 = cache1.getRating(); - float rating2 = cache2.getRating(); - - // voting can be disabled for caches, then assume an average rating instead - if (rating1 == 0.0) { - rating1 = 2.5f; - } - if (rating2 == 0.0) { - rating2 = 2.5f; - } - - if (rating1 < rating2) { - return 1; - } else if (rating2 < rating1) { - return -1; - } - return 0; + protected int compareCaches(final cgCache cache1, final cgCache cache2) { + final float rating1 = cache1.getRating(); + final float rating2 = cache2.getRating(); + // Voting can be disabled for caches, then assume an average rating instead + return Float.compare(rating2 != 0.0 ? rating2 : 2.5f, rating1 != 0.0 ? rating1 : 2.5f); } }
\ No newline at end of file diff --git a/main/src/cgeo/geocaching/sorting/TerrainComparator.java b/main/src/cgeo/geocaching/sorting/TerrainComparator.java index c0590cb..9058a3c 100644 --- a/main/src/cgeo/geocaching/sorting/TerrainComparator.java +++ b/main/src/cgeo/geocaching/sorting/TerrainComparator.java @@ -9,17 +9,12 @@ import cgeo.geocaching.cgCache; public class TerrainComparator extends AbstractCacheComparator { @Override - protected boolean canCompare(cgCache cache1, cgCache cache2) { + protected boolean canCompare(final cgCache cache1, final cgCache cache2) { return cache1.getTerrain() != 0.0 && cache2.getTerrain() != 0.0; } @Override - protected int compareCaches(cgCache cache1, cgCache cache2) { - if (cache1.getTerrain() > cache2.getTerrain()) { - return 1; - } else if (cache2.getTerrain() > cache1.getTerrain()) { - return -1; - } - return 0; + protected int compareCaches(final cgCache cache1, final cgCache cache2) { + return Float.compare(cache1.getTerrain(), cache2.getTerrain()); } } diff --git a/main/src/cgeo/geocaching/sorting/VisitComparator.java b/main/src/cgeo/geocaching/sorting/VisitComparator.java index a580f2a..548ec7a 100644 --- a/main/src/cgeo/geocaching/sorting/VisitComparator.java +++ b/main/src/cgeo/geocaching/sorting/VisitComparator.java @@ -9,17 +9,12 @@ import cgeo.geocaching.cgCache; public class VisitComparator extends AbstractCacheComparator { @Override - protected boolean canCompare(cgCache cache1, cgCache cache2) { + protected boolean canCompare(final cgCache cache1, final cgCache cache2) { return cache1.getVisitedDate() > 0 && cache2.getVisitedDate() > 0; } @Override - protected int compareCaches(cgCache cache1, cgCache cache2) { - if (cache1.getVisitedDate() > cache2.getVisitedDate()) { - return -1; - } else if (cache1.getVisitedDate() < cache2.getVisitedDate()) { - return 1; - } - return 0; + protected int compareCaches(final cgCache cache1, final cgCache cache2) { + return Long.valueOf(cache2.getVisitedDate()).compareTo(cache1.getVisitedDate()); } } diff --git a/main/src/cgeo/geocaching/sorting/VoteComparator.java b/main/src/cgeo/geocaching/sorting/VoteComparator.java index 82ebdd3..8d9f907 100644 --- a/main/src/cgeo/geocaching/sorting/VoteComparator.java +++ b/main/src/cgeo/geocaching/sorting/VoteComparator.java @@ -18,15 +18,6 @@ public class VoteComparator extends AbstractCacheComparator { @Override protected int compareCaches(cgCache cache1, cgCache cache2) { // if there is no vote available, put that cache at the end of the list - float vote1 = cache1.getMyVote(); - float vote2 = cache2.getMyVote(); - - // compare - if (vote1 < vote2) { - return 1; - } else if (vote2 < vote1) { - return -1; - } - return 0; + return Float.compare(cache2.getMyVote(), cache1.getMyVote()); } } diff --git a/main/src/cgeo/geocaching/twitter/Twitter.java b/main/src/cgeo/geocaching/twitter/Twitter.java index fa1a39d..4a10046 100644 --- a/main/src/cgeo/geocaching/twitter/Twitter.java +++ b/main/src/cgeo/geocaching/twitter/Twitter.java @@ -10,10 +10,10 @@ import cgeo.geocaching.geopoint.GeopointFormatter.Format; import cgeo.geocaching.network.Network; import cgeo.geocaching.network.OAuth; import cgeo.geocaching.network.Parameters; +import cgeo.geocaching.utils.Log; import org.apache.http.HttpResponse; -import android.util.Log; public final class Twitter { public static final int MAX_TWEET_SIZE = 140; @@ -38,12 +38,12 @@ public final class Twitter { OAuth.signOAuth("api.twitter.com", "/1/statuses/update.json", "POST", false, parameters, Settings.getTokenPublic(), Settings.getTokenSecret()); final HttpResponse httpResponse = Network.postRequest("http://api.twitter.com/1/statuses/update.json", parameters); if (httpResponse != null && httpResponse.getStatusLine().getStatusCode() == 200) { - Log.i(Settings.tag, "Tweet posted"); + Log.i("Tweet posted"); } else { - Log.e(Settings.tag, "Tweet could not be posted"); + Log.e("Tweet could not be posted"); } } catch (Exception e) { - Log.e(Settings.tag, "cgBase.postTweet: " + e.toString()); + Log.e("cgBase.postTweet: " + e.toString()); } } diff --git a/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java b/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java index fffe12e..86db2d2 100644 --- a/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java +++ b/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java @@ -6,6 +6,7 @@ import cgeo.geocaching.activity.AbstractActivity; import cgeo.geocaching.network.Network; import cgeo.geocaching.network.OAuth; import cgeo.geocaching.network.Parameters; +import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.ImmutablePair; @@ -18,7 +19,6 @@ import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.Message; -import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; @@ -141,7 +141,7 @@ public class TwitterAuthorizationActivity extends AbstractActivity { try { final Parameters params = new Parameters(); OAuth.signOAuth(host, pathRequest, method, true, params, null, null); - final String line = Network.getResponseData(Network.request("https://" + host + pathRequest, params, false)); + final String line = Network.getResponseData(Network.getRequest("https://" + host + pathRequest, params)); if (StringUtils.isNotBlank(line)) { @@ -164,12 +164,12 @@ public class TwitterAuthorizationActivity extends AbstractActivity { startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://" + host + pathAuthorize + "?" + encodedParams))); status = 1; } catch (Exception e) { - Log.e(Settings.tag, "TwitterAuthorizationActivity.requestToken(2): " + e.toString()); + Log.e("TwitterAuthorizationActivity.requestToken(2): " + e.toString()); } } } } catch (Exception e) { - Log.e(Settings.tag, "TwitterAuthorizationActivity.requestToken(1): " + e.toString()); + Log.e("TwitterAuthorizationActivity.requestToken(1): " + e.toString()); } requestTokenHandler.sendEmptyMessage(status); @@ -209,7 +209,7 @@ public class TwitterAuthorizationActivity extends AbstractActivity { status = 1; } } catch (Exception e) { - Log.e(Settings.tag, "TwitterAuthorizationActivity.changeToken: " + e.toString()); + Log.e("TwitterAuthorizationActivity.changeToken: " + e.toString()); } changeTokensHandler.sendEmptyMessage(status); diff --git a/main/src/cgeo/geocaching/ui/AddressListAdapter.java b/main/src/cgeo/geocaching/ui/AddressListAdapter.java index e557882..327b71d 100644 --- a/main/src/cgeo/geocaching/ui/AddressListAdapter.java +++ b/main/src/cgeo/geocaching/ui/AddressListAdapter.java @@ -21,24 +21,23 @@ import java.util.ArrayList; public class AddressListAdapter extends ArrayAdapter<Address> { - private LayoutInflater inflater; - private AddressListView holder; - private Geopoint location; + final private LayoutInflater inflater; + final private Geopoint location; public AddressListAdapter(final Context context) { super(context, 0); + inflater = ((Activity) context).getLayoutInflater(); + location = cgeoapplication.getInstance().currentGeo().getCoords(); } @Override - public View getView(int position, View convertView, ViewGroup parent) { - if (inflater == null) { - inflater = ((Activity) getContext()).getLayoutInflater(); - } - + public View getView(final int position, final View convertView, final ViewGroup parent) { final Address address = getItem(position); // holder pattern implementation + final AddressListView holder; View view = convertView; + if (view == null) { view = inflater.inflate(R.layout.addresses_item, null); @@ -54,9 +53,9 @@ public class AddressListAdapter extends ArrayAdapter<Address> { view.setOnClickListener(new View.OnClickListener() { @Override - public void onClick(View v) { - Activity activity = (Activity) v.getContext(); - cgeocaches.startActivityAddress(activity, address.getLatitude(), address.getLongitude(), StringUtils.defaultString(address.getAddressLine(0))); + public void onClick(final View v) { + final Activity activity = (Activity) v.getContext(); + cgeocaches.startActivityAddress(activity, new Geopoint(address.getLatitude(), address.getLongitude()), StringUtils.defaultString(address.getAddressLine(0))); activity.finish(); } }); @@ -68,10 +67,6 @@ public class AddressListAdapter extends ArrayAdapter<Address> { } private CharSequence getDistanceText(final Address address) { - if (location == null) { - location = cgeoapplication.getInstance().getLastCoords(); - } - if (location != null && address.hasLatitude() && address.hasLongitude()) { return HumanDistance.getHumanDistance(location.distanceTo(new Geopoint(address.getLatitude(), address.getLongitude()))); } @@ -83,7 +78,7 @@ public class AddressListAdapter extends ArrayAdapter<Address> { final int maxIndex = address.getMaxAddressLineIndex(); final ArrayList<String> lines = new ArrayList<String>(); for (int i = 0; i <= maxIndex; i++) { - String line = address.getAddressLine(i); + final String line = address.getAddressLine(i); if (StringUtils.isNotBlank(line)) { lines.add(line); } diff --git a/main/src/cgeo/geocaching/ui/CacheListAdapter.java b/main/src/cgeo/geocaching/ui/CacheListAdapter.java index 57e2a94..bda53d7 100644 --- a/main/src/cgeo/geocaching/ui/CacheListAdapter.java +++ b/main/src/cgeo/geocaching/ui/CacheListAdapter.java @@ -3,7 +3,6 @@ package cgeo.geocaching.ui; import cgeo.geocaching.CacheDetailActivity; import cgeo.geocaching.R; import cgeo.geocaching.Settings; -import cgeo.geocaching.cgBase; import cgeo.geocaching.cgCache; import cgeo.geocaching.enumerations.CacheListType; import cgeo.geocaching.enumerations.CacheSize; @@ -13,13 +12,13 @@ import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.sorting.CacheComparator; import cgeo.geocaching.sorting.DistanceComparator; import cgeo.geocaching.sorting.VisitComparator; +import cgeo.geocaching.utils.Log; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.builder.HashCodeBuilder; import android.app.Activity; -import android.content.Intent; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; @@ -29,14 +28,13 @@ import android.text.Spannable; import android.text.Spanned; import android.text.style.StrikethroughSpan; import android.util.DisplayMetrics; -import android.util.Log; +import android.util.SparseArray; import android.view.GestureDetector; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.animation.AccelerateDecelerateInterpolator; -import android.view.animation.AlphaAnimation; import android.view.animation.Animation; import android.view.animation.AnimationSet; import android.view.animation.TranslateAnimation; @@ -48,10 +46,8 @@ import android.widget.TextView; import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; -import java.util.Map; import java.util.Set; public class CacheListAdapter extends ArrayAdapter<cgCache> { @@ -68,7 +64,7 @@ public class CacheListAdapter extends ArrayAdapter<cgCache> { private boolean sort = true; private int checked = 0; private boolean selectMode = false; - final private static Map<Integer, Drawable> gcIconDrawables = new HashMap<Integer, Drawable>(); + final private static SparseArray<Drawable> gcIconDrawables = new SparseArray<Drawable>(); final private Set<CompassMiniView> compasses = new LinkedHashSet<CompassMiniView>(); final private Set<DistanceView> distances = new LinkedHashSet<DistanceView>(); final private int[] ratingBcgs = new int[3]; @@ -76,7 +72,6 @@ public class CacheListAdapter extends ArrayAdapter<cgCache> { private static final int SWIPE_MIN_DISTANCE = 60; private static final int SWIPE_MAX_OFF_PATH = 100; private static final int SWIPE_DISTANCE = 80; - private static final float SWIPE_OPACITY = 0.5f; /** * time in milliseconds after which the list may be resorted due to position updates */ @@ -195,17 +190,6 @@ public class CacheListAdapter extends ArrayAdapter<cgCache> { notifyDataSetChanged(); } - public void clearFilter() { - if (originalList != null) { - list.clear(); - list.addAll(originalList); - - currentFilter = null; - } - - notifyDataSetChanged(); - } - public boolean isFilter() { return currentFilter != null; } @@ -375,7 +359,7 @@ public class CacheListAdapter extends ArrayAdapter<cgCache> { } if (position > getCount()) { - Log.w(Settings.tag, "CacheListAdapter.getView: Attempt to access missing item #" + position); + Log.w("CacheListAdapter.getView: Attempt to access missing item #" + position); return null; } @@ -486,7 +470,7 @@ public class CacheListAdapter extends ArrayAdapter<cgCache> { holder.inventory.removeAllViews(); } - ImageView tbIcon = null; + ImageView tbIcon; if (cache.getInventoryItems() > 0) { tbIcon = (ImageView) inflater.inflate(R.layout.trackable_icon, null); tbIcon.setImageResource(R.drawable.trackable_all); @@ -590,8 +574,8 @@ public class CacheListAdapter extends ArrayAdapter<cgCache> { if (cacheListType == CacheListType.HISTORY && cache.getVisitedDate() > 0) { ArrayList<String> infos = new ArrayList<String>(); infos.add(StringUtils.upperCase(cache.getGeocode())); - infos.add(cgBase.formatDate(cache.getVisitedDate())); - infos.add(cgBase.formatTime(cache.getVisitedDate())); + infos.add(Formatter.formatDate(cache.getVisitedDate())); + infos.add(Formatter.formatTime(cache.getVisitedDate())); holder.info.setText(StringUtils.join(infos, Formatter.SEPARATOR)); } else { ArrayList<String> infos = new ArrayList<String>(); @@ -609,7 +593,7 @@ public class CacheListAdapter extends ArrayAdapter<cgCache> { if (cache.getSize() != CacheSize.UNKNOWN && cache.showSize()) { infos.add(cache.getSize().getL10n()); } else if (cache.isEventCache() && cache.getHiddenDate() != null) { - infos.add(cgBase.formatShortDate(cache.getHiddenDate().getTime())); + infos.add(Formatter.formatShortDate(cache.getHiddenDate().getTime())); } if (cache.isPremiumMembersOnly()) { @@ -626,11 +610,13 @@ public class CacheListAdapter extends ArrayAdapter<cgCache> { private static Drawable getCacheIcon(cgCache cache) { int hashCode = getIconHashCode(cache.getType(), cache.hasUserModifiedCoords() || cache.hasFinalDefined()); - if (!gcIconDrawables.containsKey(hashCode)) { - // fallback to mystery icon - hashCode = getIconHashCode(CacheType.MYSTERY, cache.hasUserModifiedCoords() || cache.hasFinalDefined()); + Drawable drawable = gcIconDrawables.get(hashCode); + if (drawable != null) { + return drawable; } + // fallback to mystery icon + hashCode = getIconHashCode(CacheType.MYSTERY, cache.hasUserModifiedCoords() || cache.hasFinalDefined()); return gcIconDrawables.get(hashCode); } @@ -699,10 +685,7 @@ public class CacheListAdapter extends ArrayAdapter<cgCache> { } // load cache details - Intent cachesIntent = new Intent(getContext(), CacheDetailActivity.class); - cachesIntent.putExtra("geocode", geocode); - cachesIntent.putExtra("name", name); - getContext().startActivity(cachesIntent); + CacheDetailActivity.startActivity(getContext(), geocode, name); } // long tap on item @@ -781,7 +764,7 @@ public class CacheListAdapter extends ArrayAdapter<cgCache> { return true; } } catch (Exception e) { - Log.w(Settings.tag, "CacheListAdapter.detectGesture.onFling: " + e.toString()); + Log.w("CacheListAdapter.detectGesture.onFling: " + e.toString()); } return false; @@ -813,21 +796,12 @@ public class CacheListAdapter extends ArrayAdapter<cgCache> { showCheckbox.setFillAfter(true); showCheckbox.setInterpolator(new AccelerateDecelerateInterpolator()); - // dim cache info - final Animation dimInfo = new AlphaAnimation(1.0f, SWIPE_OPACITY); - dimInfo.setRepeatCount(0); - dimInfo.setDuration(force ? 0 : 400); - dimInfo.setFillEnabled(true); - dimInfo.setFillAfter(true); - dimInfo.setInterpolator(new AccelerateDecelerateInterpolator()); - // animation set (container) final AnimationSet selectAnimation = new AnimationSet(true); selectAnimation.setFillEnabled(true); selectAnimation.setFillAfter(true); selectAnimation.addAnimation(showCheckbox); - selectAnimation.addAnimation(dimInfo); holder.oneInfo.startAnimation(selectAnimation); cache.setStatusCheckedView(true); @@ -848,21 +822,12 @@ public class CacheListAdapter extends ArrayAdapter<cgCache> { hideCheckbox.setFillAfter(true); hideCheckbox.setInterpolator(new AccelerateDecelerateInterpolator()); - // brighten cache info - final Animation brightenInfo = new AlphaAnimation(SWIPE_OPACITY, 1.0f); - brightenInfo.setRepeatCount(0); - brightenInfo.setDuration(force ? 0 : 400); - brightenInfo.setFillEnabled(true); - brightenInfo.setFillAfter(true); - brightenInfo.setInterpolator(new AccelerateDecelerateInterpolator()); - // animation set (container) final AnimationSet selectAnimation = new AnimationSet(true); selectAnimation.setFillEnabled(true); selectAnimation.setFillAfter(true); selectAnimation.addAnimation(hideCheckbox); - selectAnimation.addAnimation(brightenInfo); holder.oneInfo.startAnimation(selectAnimation); cache.setStatusCheckedView(false); @@ -871,4 +836,17 @@ public class CacheListAdapter extends ArrayAdapter<cgCache> { public List<cgCache> getFilteredList() { return list; } + + public List<cgCache> getCheckedCaches() { + ArrayList<cgCache> result = new ArrayList<cgCache>(); + int checked = getChecked(); + if (checked > 0) { + for (cgCache cache : list) { + if (cache.isStatusChecked()) { + result.add(cache); + } + } + } + return result; + } } diff --git a/main/src/cgeo/geocaching/ui/CompassMiniView.java b/main/src/cgeo/geocaching/ui/CompassMiniView.java index 1fa4cfb..b51b7a2 100644 --- a/main/src/cgeo/geocaching/ui/CompassMiniView.java +++ b/main/src/cgeo/geocaching/ui/CompassMiniView.java @@ -111,8 +111,8 @@ public class CompassMiniView extends View { // compass margins canvas.setDrawFilter(setfil); - int marginLeft = 0; - int marginTop = 0; + int marginLeft; + int marginTop; int compassArrowWidth = compassArrow.getWidth(); int compassArrowHeight = compassArrow.getWidth(); @@ -136,7 +136,7 @@ public class CompassMiniView extends View { } private int measureWidth(int measureSpec) { - int result = 0; + int result; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); @@ -154,7 +154,7 @@ public class CompassMiniView extends View { } private int measureHeight(int measureSpec) { - int result = 0; + int result; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); diff --git a/main/src/cgeo/geocaching/ui/CompassView.java b/main/src/cgeo/geocaching/ui/CompassView.java index 6fc576f..8a295c3 100644 --- a/main/src/cgeo/geocaching/ui/CompassView.java +++ b/main/src/cgeo/geocaching/ui/CompassView.java @@ -1,7 +1,7 @@ package cgeo.geocaching.ui; import cgeo.geocaching.R; -import cgeo.geocaching.Settings; +import cgeo.geocaching.utils.Log; import android.content.Context; import android.graphics.Bitmap; @@ -12,12 +12,10 @@ import android.graphics.PaintFlagsDrawFilter; import android.os.Handler; import android.os.Message; import android.util.AttributeSet; -import android.util.Log; import android.view.View; public class CompassView extends View { - private changeThread watchdog = null; private volatile boolean wantStop = false; private Context context = null; private Bitmap compassUnderlay = null; @@ -58,7 +56,7 @@ public class CompassView extends View { try { invalidate(); } catch (Exception e) { - Log.e(Settings.tag, "CompassView.changeHandler: " + e.toString()); + Log.e("CompassView.changeHandler: " + e.toString()); } } }; @@ -95,8 +93,7 @@ public class CompassView extends View { initialDisplay = true; wantStop = false; - watchdog = new changeThread(); - watchdog.start(); + new changeThread().start(); } @Override @@ -212,8 +209,8 @@ public class CompassView extends View { int canvasCenterX = (compassRoseWidth / 2) + ((getWidth() - compassRoseWidth) / 2); int canvasCenterY = (compassRoseHeight / 2) + ((getHeight() - compassRoseHeight) / 2); - int marginLeftTemp = 0; - int marginTopTemp = 0; + int marginLeftTemp; + int marginTopTemp; super.onDraw(canvas); @@ -254,7 +251,7 @@ public class CompassView extends View { } private int measureWidth(int measureSpec) { - int result = 0; + int result; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); @@ -272,7 +269,7 @@ public class CompassView extends View { } private int measureHeight(int measureSpec) { - int result = 0; + int result; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); diff --git a/main/src/cgeo/geocaching/ui/DirectionImage.java b/main/src/cgeo/geocaching/ui/DirectionImage.java index aa01b97..b246718 100644 --- a/main/src/cgeo/geocaching/ui/DirectionImage.java +++ b/main/src/cgeo/geocaching/ui/DirectionImage.java @@ -17,7 +17,7 @@ public class DirectionImage { } final HttpResponse httpResponse = - Network.request("http://www.geocaching.com/ImgGen/seek/CacheDir.ashx", new Parameters("k", code), false); + Network.getRequest("http://www.geocaching.com/ImgGen/seek/CacheDir.ashx", new Parameters("k", code)); if (httpResponse != null) { LocalStorage.saveEntityToFile(httpResponse, getDirectionFile(geocode, true)); } diff --git a/main/src/cgeo/geocaching/ui/Formatter.java b/main/src/cgeo/geocaching/ui/Formatter.java index 661a9a0..6ee1a65 100644 --- a/main/src/cgeo/geocaching/ui/Formatter.java +++ b/main/src/cgeo/geocaching/ui/Formatter.java @@ -1,8 +1,80 @@ package cgeo.geocaching.ui; -public interface Formatter { +import cgeo.geocaching.cgeoapplication; + +import android.content.Context; +import android.text.format.DateUtils; + +public abstract class Formatter { /** Text separator used for formatting texts */ public static final String SEPARATOR = " · "; + private static final Context context = cgeoapplication.getInstance().getBaseContext(); + + /** + * Generate a time string according to system-wide settings (locale, 12/24 hour) + * such as "13:24". + * + * @param date + * milliseconds since the epoch + * @return the formatted string + */ + public static String formatTime(long date) { + return DateUtils.formatDateTime(context, date, DateUtils.FORMAT_SHOW_TIME); + } + + /** + * Generate a date string according to system-wide settings (locale, date format) + * such as "20 December" or "20 December 2010". The year will only be included when necessary. + * + * @param date + * milliseconds since the epoch + * @return the formatted string + */ + public static String formatDate(long date) { + return DateUtils.formatDateTime(context, date, DateUtils.FORMAT_SHOW_DATE); + } + + /** + * Generate a date string according to system-wide settings (locale, date format) + * such as "20 December 2010". The year will always be included, making it suitable + * to generate long-lived log entries. + * + * @param date + * milliseconds since the epoch + * @return the formatted string + */ + public static String formatFullDate(long date) { + return DateUtils.formatDateTime(context, date, DateUtils.FORMAT_SHOW_DATE + | DateUtils.FORMAT_SHOW_YEAR); + } + + /** + * Generate a numeric date string according to system-wide settings (locale, date format) + * such as "10/20/2010". + * + * @param date + * milliseconds since the epoch + * @return the formatted string + */ + public static String formatShortDate(long date) { + return DateUtils.formatDateTime(context, date, DateUtils.FORMAT_SHOW_DATE + | DateUtils.FORMAT_NUMERIC_DATE); + } + + /** + * Generate a numeric date and time string according to system-wide settings (locale, + * date format) such as "7 sept. at 12:35". + * + * @param context + * a Context + * @param date + * milliseconds since the epoch + * @return the formatted string + */ + public static String formatShortDateTime(Context context, long date) { + return DateUtils.formatDateTime(context, date, DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_ABBREV_ALL); + } + } diff --git a/main/src/cgeo/geocaching/ui/GPXListAdapter.java b/main/src/cgeo/geocaching/ui/GPXListAdapter.java index 2ebb893..76dc10e 100644 --- a/main/src/cgeo/geocaching/ui/GPXListAdapter.java +++ b/main/src/cgeo/geocaching/ui/GPXListAdapter.java @@ -1,12 +1,11 @@ package cgeo.geocaching.ui; import cgeo.geocaching.R; -import cgeo.geocaching.Settings; import cgeo.geocaching.cgeogpxes; import cgeo.geocaching.files.GPXImporter; +import cgeo.geocaching.utils.Log; import android.app.Activity; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -17,7 +16,6 @@ import java.io.File; import java.util.List; public class GPXListAdapter extends ArrayAdapter<File> { - private GPXListView holder = null; private cgeogpxes activity = null; private LayoutInflater inflater = null; @@ -34,13 +32,14 @@ public class GPXListAdapter extends ArrayAdapter<File> { } if (position > getCount()) { - Log.w(Settings.tag, "cgGPXListAdapter.getView: Attempt to access missing item #" + position); + Log.w("cgGPXListAdapter.getView: Attempt to access missing item #" + position); return null; } final File file = getItem(position); View v = rowView; + GPXListView holder; if (v == null) { v = inflater.inflate(R.layout.gpx_item, null); diff --git a/main/src/cgeo/geocaching/ui/MapfileListAdapter.java b/main/src/cgeo/geocaching/ui/MapfileListAdapter.java index 9196a41..a14d120 100644 --- a/main/src/cgeo/geocaching/ui/MapfileListAdapter.java +++ b/main/src/cgeo/geocaching/ui/MapfileListAdapter.java @@ -1,12 +1,11 @@ package cgeo.geocaching.ui; import cgeo.geocaching.R; -import cgeo.geocaching.Settings; import cgeo.geocaching.cgSelectMapfile; +import cgeo.geocaching.utils.Log; import android.app.Activity; import android.graphics.Typeface; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -20,7 +19,6 @@ public class MapfileListAdapter extends ArrayAdapter<File> { private cgSelectMapfile parentView; private LayoutInflater inflater; - private MapfileView holder; public MapfileListAdapter(cgSelectMapfile parentIn, List<File> listIn) { super(parentIn, 0, listIn); @@ -35,13 +33,14 @@ public class MapfileListAdapter extends ArrayAdapter<File> { } if (position > getCount()) { - Log.w(Settings.tag, "cgGPXListAdapter.getView: Attempt to access missing item #" + position); + Log.w("cgGPXListAdapter.getView: Attempt to access missing item #" + position); return null; } File file = getItem(position); View v = rowView; + MapfileView holder; if (v == null) { v = inflater.inflate(R.layout.mapfile_item, null); diff --git a/main/src/cgeo/geocaching/utils/BaseUtils.java b/main/src/cgeo/geocaching/utils/BaseUtils.java index 44c35a1..d468fc9 100644 --- a/main/src/cgeo/geocaching/utils/BaseUtils.java +++ b/main/src/cgeo/geocaching/utils/BaseUtils.java @@ -3,8 +3,6 @@ */ package cgeo.geocaching.utils; -import java.util.ArrayList; -import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -84,17 +82,6 @@ public final class BaseUtils { return BaseUtils.getMatch(data, p, true, 1, defaultValue, false); } - public static List<String> getMatches(final String data, final Pattern p, int count) { - ArrayList<String> result = new ArrayList<String>(); - final Matcher matcher = p.matcher(data); - while (matcher.find()) { - for (int i = 0; i < count; i++) { - result.add(matcher.group(i)); - } - } - return result; - } - /** * Searches for the pattern p in the data. * diff --git a/main/src/cgeo/geocaching/utils/CancellableHandler.java b/main/src/cgeo/geocaching/utils/CancellableHandler.java index d4915eb..8cf8f28 100644 --- a/main/src/cgeo/geocaching/utils/CancellableHandler.java +++ b/main/src/cgeo/geocaching/utils/CancellableHandler.java @@ -1,5 +1,7 @@ package cgeo.geocaching.utils; +import cgeo.geocaching.cgeoapplication; + import android.os.Handler; import android.os.Message; @@ -9,6 +11,7 @@ import android.os.Message; */ public abstract class CancellableHandler extends Handler { + protected static final int UPDATE_LOAD_PROGRESS_DETAIL = 42186; private volatile boolean cancelled = false; private static class CancelHolder { @@ -109,4 +112,9 @@ public abstract class CancellableHandler extends Handler { return handler != null && handler.isCancelled(); } + public static void sendLoadProgressDetail(final Handler handler, final int resourceId) { + if (null != handler) { + handler.obtainMessage(UPDATE_LOAD_PROGRESS_DETAIL, cgeoapplication.getInstance().getString(resourceId)).sendToTarget(); + } + } } diff --git a/main/src/cgeo/geocaching/utils/ClipboardUtils.java b/main/src/cgeo/geocaching/utils/ClipboardUtils.java index 865d8d6..e6779ad 100644 --- a/main/src/cgeo/geocaching/utils/ClipboardUtils.java +++ b/main/src/cgeo/geocaching/utils/ClipboardUtils.java @@ -10,6 +10,7 @@ import android.text.ClipboardManager; * This class uses the deprecated function ClipboardManager.setText(CharSequence). * API 11 introduced setPrimaryClip(ClipData) */ +@SuppressWarnings("deprecation") public final class ClipboardUtils { /** diff --git a/main/src/cgeo/geocaching/utils/CryptUtils.java b/main/src/cgeo/geocaching/utils/CryptUtils.java index 907fa1f..f04327e 100644 --- a/main/src/cgeo/geocaching/utils/CryptUtils.java +++ b/main/src/cgeo/geocaching/utils/CryptUtils.java @@ -1,10 +1,8 @@ package cgeo.geocaching.utils; -import cgeo.geocaching.Settings; import android.text.Spannable; import android.text.SpannableStringBuilder; -import android.util.Log; import java.math.BigInteger; import java.security.MessageDigest; @@ -75,7 +73,7 @@ public final class CryptUtils { digest.update(text.getBytes(), 0, text.length()); hashed = new BigInteger(1, digest.digest()).toString(16); } catch (Exception e) { - Log.e(Settings.tag, "cgBase.md5: " + e.toString()); + Log.e("cgBase.md5: " + e.toString()); } return hashed; @@ -89,7 +87,7 @@ public final class CryptUtils { digest.update(text.getBytes(), 0, text.length()); hashed = new BigInteger(1, digest.digest()).toString(16); } catch (Exception e) { - Log.e(Settings.tag, "cgBase.sha1: " + e.toString()); + Log.e("cgBase.sha1: " + e.toString()); } return hashed; @@ -104,7 +102,7 @@ public final class CryptUtils { mac.init(secretKeySpec); macBytes = mac.doFinal(text.getBytes()); } catch (Exception e) { - Log.e(Settings.tag, "cgBase.hashHmac: " + e.toString()); + Log.e("cgBase.hashHmac: " + e.toString()); } return macBytes; @@ -137,49 +135,6 @@ public final class CryptUtils { return buffer; } - public static byte[] base64Decode(String text) { - char[] in = text.toCharArray(); - - int iLen = in.length; - if (iLen % 4 != 0) { - throw new IllegalArgumentException("Length of Base64 encoded input string is not a multiple of 4."); - } - while (iLen > 0 && in[iLen - 1] == '=') { - iLen--; - } - int oLen = (iLen * 3) / 4; - byte[] out = new byte[oLen]; - int ip = 0; - int op = 0; - while (ip < iLen) { - int i0 = in[ip++]; - int i1 = in[ip++]; - int i2 = ip < iLen ? in[ip++] : 'A'; - int i3 = ip < iLen ? in[ip++] : 'A'; - if (i0 > 127 || i1 > 127 || i2 > 127 || i3 > 127) { - throw new IllegalArgumentException("Illegal character in Base64 encoded data."); - } - int b0 = base64map2[i0]; - int b1 = base64map2[i1]; - int b2 = base64map2[i2]; - int b3 = base64map2[i3]; - if (b0 < 0 || b1 < 0 || b2 < 0 || b3 < 0) { - throw new IllegalArgumentException("Illegal character in Base64 encoded data."); - } - int o0 = (b0 << 2) | (b1 >>> 4); - int o1 = ((b1 & 0xf) << 4) | (b2 >>> 2); - int o2 = ((b2 & 3) << 6) | b3; - out[op++] = (byte) o0; - if (op < oLen) { - out[op++] = (byte) o1; - } - if (op < oLen) { - out[op++] = (byte) o2; - } - } - return out; - } - public static String base64Encode(byte[] in) { int iLen = in.length; int oDataLen = (iLen * 4 + 2) / 3; // output length without padding diff --git a/main/src/cgeo/geocaching/utils/IObserver.java b/main/src/cgeo/geocaching/utils/IObserver.java new file mode 100644 index 0000000..c7842aa --- /dev/null +++ b/main/src/cgeo/geocaching/utils/IObserver.java @@ -0,0 +1,22 @@ +package cgeo.geocaching.utils; + +/** + * Observer interface. + * <p/> + * An observer will receive updates about the observed object (implementing the {@link ISubject} interface) + * through its {@link #update(T)} method. + * + * @param <T> + * the kind of data to observe + */ +public interface IObserver<T> { + + /** + * Called when an observed object has updated its data. + * + * @param data + * the updated data + */ + void update(final T data); + +} diff --git a/main/src/cgeo/geocaching/utils/ISubject.java b/main/src/cgeo/geocaching/utils/ISubject.java new file mode 100644 index 0000000..f332ee8 --- /dev/null +++ b/main/src/cgeo/geocaching/utils/ISubject.java @@ -0,0 +1,57 @@ +package cgeo.geocaching.utils; + +/** + * Interface for subjects objects. Those can be observed by objects implementing the {@link IObserver} interface. + * + * @param <T> + * the kind of data to observe + */ + +public interface ISubject<T> { + + /** + * Add an observer to the observers list. + * <p/> + * Observers will be notified with no particular order. + * + * @param observer + * the observer to add + * @return true if the observer has been added, false if it was present already + */ + public boolean addObserver(final IObserver<? super T> observer); + + /** + * Delete an observer from the observers list. + * + * @param observer + * the observer to remove + * @return true if the observer has been removed, false if it was not in the list of observers + */ + public boolean deleteObserver(final IObserver<? super T> observer); + + /** + * Number of observers currently observing the object. + * + * @return the number of observers + */ + public int sizeObservers(); + + /** + * Notify all the observers that new data is available. + * <p/> + * The {@link IObserver#update(T)} method of each observer will be called with no particular order. + * + * @param data + * the updated data + * @return true if at least one observer was notified, false if there were no observers + */ + public boolean notifyObservers(final T data); + + /** + * Clear the observers list. + * + * @return true if there were observers before calling this method, false if the observers list was empty + */ + public boolean clearObservers(); + +} diff --git a/main/src/cgeo/geocaching/utils/LRUList.java b/main/src/cgeo/geocaching/utils/LRUList.java deleted file mode 100644 index 13596b1..0000000 --- a/main/src/cgeo/geocaching/utils/LRUList.java +++ /dev/null @@ -1,46 +0,0 @@ -package cgeo.geocaching.utils; - -import java.util.ArrayList; -import java.util.Collection; - -/** - * Base class for a limited list. - * - * @author blafoo - */ -public class LRUList<T> extends ArrayList<T> { - - private static final long serialVersionUID = -5077882607489806620L; - private final int maxEntries; - - public LRUList(int maxEntries) { - this.maxEntries = maxEntries; - } - - private void removeElements(int count) { - for (int i = 0; i < count; i++) { - this.remove(0); - } - } - - @Override - public boolean add(T item) { - removeElements(this.size() + 1 - maxEntries); - return super.add(item); - } - - @Override - public boolean addAll(Collection<? extends T> collection) { - if (collection.size() > this.size()) { - this.clear(); - for (T item : collection) { - this.add(item); - } - return false; - } else { - removeElements(this.size() + collection.size() - maxEntries); - return super.addAll(collection); - } - } - -} diff --git a/main/src/cgeo/geocaching/utils/LeastRecentlyUsedCache.java b/main/src/cgeo/geocaching/utils/LeastRecentlyUsedCache.java deleted file mode 100644 index 6d18cf5..0000000 --- a/main/src/cgeo/geocaching/utils/LeastRecentlyUsedCache.java +++ /dev/null @@ -1,24 +0,0 @@ -package cgeo.geocaching.utils; - -import java.util.LinkedHashMap; - -/** - * Base class for a caching cache. Don't mix up with a geocache ! - * - * @author blafoo - */ -public class LeastRecentlyUsedCache<K, V> extends LinkedHashMap<K, V> { - - private static final long serialVersionUID = -5077882607489806620L; - private final int maxEntries; - - public LeastRecentlyUsedCache(int maxEntries) { - this.maxEntries = maxEntries; - } - - @Override - protected boolean removeEldestEntry(java.util.Map.Entry<K, V> eldest) { - return size() > maxEntries; - } - -} diff --git a/main/src/cgeo/geocaching/utils/LeastRecentlyUsedMap.java b/main/src/cgeo/geocaching/utils/LeastRecentlyUsedMap.java new file mode 100644 index 0000000..953fc47 --- /dev/null +++ b/main/src/cgeo/geocaching/utils/LeastRecentlyUsedMap.java @@ -0,0 +1,139 @@ +package cgeo.geocaching.utils; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Base class for caching objects. Don't mix up with a geocache ! + * + * The LeastRecentlyUsedMap is basically a LinkedHashMap which can be configured to have certain modes of operation: + * <ul> + * <li> LRU_CACHE means that the elements are updated in the LinkedList on every get() access, + * so the objects that are dropped are the ones that haven't been used the longest</li> + * <li> BOUNDED means that objects are updated only when they are put, + * so the objects that are dropped are the ones that haven't been written the longest</li> + * </ul> + * + * @author blafoo + * @author Teschi + */ +public abstract class LeastRecentlyUsedMap<K, V> extends LinkedHashMap<K, V> { + + private static enum OperationModes { + LRU_CACHE, BOUNDED + } + + private static final long serialVersionUID = -5077882607489806620L; + + private final int maxEntries; + private final OperationModes opMode; + private RemoveHandler<V> removeHandler; + + // store the HashMap parameters for serialization, as we can't access the originals in the LinkedHashMap + final int initialCapacity; + final float loadFactor; + + protected LeastRecentlyUsedMap(int maxEntries, int initialCapacity, float loadFactor, OperationModes opMode) { + super(initialCapacity, loadFactor, (opMode==OperationModes.LRU_CACHE)); + this.initialCapacity = initialCapacity; + this.loadFactor = loadFactor; + this.maxEntries = maxEntries; + this.opMode = opMode; + } + + protected LeastRecentlyUsedMap(int maxEntries, OperationModes opMode) { + this(maxEntries, 16, 0.75f, opMode); + } + + @Override + public V put(K key, V value) { + // in case the underlying Map is not running with accessOrder==true, the map won't notice any changes + // of existing keys, so for the normal BOUNDED mode we remove and put the value to get its order updated. + if (opMode == OperationModes.BOUNDED && containsKey(key)) { + // avoid trigger the remove notification + final V oldVal = super.remove(key); + put(key, value); + return oldVal; + } + + return super.put(key, value); + } + + @Override + protected boolean removeEldestEntry(Map.Entry<K, V> eldest) { + return size() > maxEntries; + } + + public int getMaxEntries() { + return maxEntries; + } + + @Override + public V remove(Object key) { + + V removed = super.remove(key); + + if (removed != null && removeHandler != null) { + removeHandler.onRemove(removed); + } + + return removed; + } + + /** + * Sets a handler for remove notifications. Currently only one handler + * instance is supported + * + * @param removeHandler + * The new handler to receive notifications or null to remove a handler + */ + public void setRemoveHandler(RemoveHandler<V> removeHandler) { + this.removeHandler = removeHandler; + } + + public static class LruCache<K, V> extends LeastRecentlyUsedMap<K, V> { + private static final long serialVersionUID = 9028478916221334454L; + + public LruCache(int maxEntries, int initialCapacity, float loadFactor) { + super(maxEntries, initialCapacity, loadFactor, OperationModes.LRU_CACHE); + } + + public LruCache(int maxEntries) { + super(maxEntries, OperationModes.LRU_CACHE); + } + } + + public static class Bounded<K, V> extends LeastRecentlyUsedMap<K, V> { + + private static final long serialVersionUID = -1476389304214398315L; + + public Bounded(int maxEntries, int initialCapacity, float loadFactor) { + super(maxEntries, initialCapacity, loadFactor, OperationModes.BOUNDED); + } + + public Bounded(int maxEntries) { + super(maxEntries, OperationModes.BOUNDED); + } + } + + /** + * Interface for handlers that wish to get notified when items are + * removed from the LRUMap + * + * @author rsudev + * + * @param <V> + */ + public interface RemoveHandler<V> { + + /** + * Method will be called on remove + * + * @param removed + * Item that has been removed + */ + void onRemove(V removed); + + } + +} diff --git a/main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java b/main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java new file mode 100644 index 0000000..986087f --- /dev/null +++ b/main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java @@ -0,0 +1,198 @@ +package cgeo.geocaching.utils; + +import java.util.AbstractSet; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; + +/** + * Synchronized set wrapper for the LeastRecentlyUsedMap. + * + * This code is heavily based on the HashSet code that represent Map as a Set. + * Unfortunately HashSet does not allow to use a custom Map as its Storage. + * Therefore overriding removeEldestEntry() is impossible for a normal LinkedHashSet. + * + * Synchronization is added to guard against concurrent modification. Iterator + * access has to be guarded externally or the synchronized getAsList method can be used + * to get a clone for iteration + * + * @author Teschi + */ +public class LeastRecentlyUsedSet<E> extends AbstractSet<E> + implements Cloneable, java.io.Serializable { + + private static final long serialVersionUID = -1942301031191419547L; + + private transient LeastRecentlyUsedMap<E, Object> map; + private static final Object PRESENT = new Object(); + + public LeastRecentlyUsedSet(int maxEntries, int initialCapacity, float loadFactor) { + // because we don't use any Map.get() methods from the Set, BOUNDED and LRU_CACHE have the exact same Behaviour + // So we useLRU_CACHE mode because it should perform a bit better (as it doesn't re-add explicitly) + map = new LeastRecentlyUsedMap.LruCache<E, Object>(maxEntries, initialCapacity, loadFactor); + } + + public LeastRecentlyUsedSet(int maxEntries) { + map = new LeastRecentlyUsedMap.LruCache<E, Object>(maxEntries); + } + + /** + * Copy of the HashSet code if iterator() + * Iterator access has to be synchronized externally! + * + * @see HashSet + */ + @Override + public Iterator<E> iterator() { + return map.keySet().iterator(); + } + + /** + * Synchronized access to set size + * Copy of the HashSet code if size() + * + * @see HashSet + */ + @Override + public synchronized int size() { + return map.size(); + } + + /** + * Synchronized check of set emptiness + * Copy of the HashSet code if isEmpty() + * + * @see HashSet + */ + @Override + public synchronized boolean isEmpty() { + return map.isEmpty(); + } + + /** + * Synchronized check for containment + * Copy of the HashSet code if contains() + * + * @see HashSet + */ + @Override + public synchronized boolean contains(Object o) { + return map.containsKey(o); + } + + /** + * Synchronized addition of an item + * Copy of the HashSet code if add() + * + * @see HashSet + */ + @Override + public synchronized boolean add(E e) { + return map.put(e, PRESENT) == null; + } + + /** + * Synchronized removal of a contained item + * Copy of the HashSet code if remove() + * + * @see HashSet + */ + @Override + public synchronized boolean remove(Object o) { + return map.remove(o) == PRESENT; + } + + /** + * Synchronized clearing of the set + * Copy of the HashSet code if clear() + * + * @see HashSet + */ + @Override + public synchronized void clear() { + map.clear(); + } + + /** + * (synchronized) Clone of the set + * Copy of the HashSet code if clone() + * + * @see HashSet + */ + @Override + @SuppressWarnings("unchecked") + public Object clone() { + try { + synchronized (this) { + final LeastRecentlyUsedSet<E> newSet = (LeastRecentlyUsedSet<E>) super.clone(); + newSet.map = (LeastRecentlyUsedMap<E, Object>) map.clone(); + return newSet; + } + } catch (CloneNotSupportedException e) { + throw new InternalError(); + } + } + + /** + * Creates a clone as a list in a synchronized fashion. + * + * @return List based clone of the set + */ + public synchronized List<E> getAsList() { + return new ArrayList<E>(this); + } + + /** + * Serialization version of HashSet with the additional parameters for the custom Map + * + * @see HashSet + */ + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + // Write out any hidden serialization magic + s.defaultWriteObject(); + + // Write out HashMap capacity and load factor + s.writeInt(map.initialCapacity); + s.writeFloat(map.loadFactor); + s.writeInt(map.getMaxEntries()); + + // Write out size + s.writeInt(map.size()); + + // Write out all elements in the proper order. + for (final E e : map.keySet()) { + s.writeObject(e); + } + } + + /** + * Serialization version of HashSet with the additional parameters for the custom Map + * + * @see HashSet + */ + @SuppressWarnings("unchecked") + private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + // Read in any hidden serialization magic + s.defaultReadObject(); + + // Read in HashMap capacity and load factor and create backing HashMap + final int capacity = s.readInt(); + final float loadFactor = s.readFloat(); + final int maxEntries = s.readInt(); + + map = new LeastRecentlyUsedMap.LruCache<E, Object>(maxEntries, capacity, loadFactor); + + // Read in size + final int size = s.readInt(); + + // Read in all elements in the proper order. + for (int i = 0; i < size; i++) { + E e = (E) s.readObject(); + map.put(e, PRESENT); + } + } + +} diff --git a/main/src/cgeo/geocaching/utils/Log.java b/main/src/cgeo/geocaching/utils/Log.java new file mode 100644 index 0000000..9f5bd3d --- /dev/null +++ b/main/src/cgeo/geocaching/utils/Log.java @@ -0,0 +1,69 @@ +package cgeo.geocaching.utils; + + +final public class Log { + + private static final String TAG = "cgeo"; + + private static boolean isDebug = true; + + public static boolean isDebug() { + return isDebug; + } + + public static void setDebugUnsaved(boolean isDebug) { + Log.isDebug = isDebug; + } + + public static void v(final String msg) { + if (isDebug) { + android.util.Log.v(TAG, msg); + } + } + + public static void v(final String msg, final Throwable t) { + if (isDebug) { + android.util.Log.v(TAG, msg, t); + } + } + + public static void d(final String msg) { + if (isDebug) { + android.util.Log.d(TAG, msg); + } + } + + public static void d(final String msg, final Throwable t) { + if (isDebug) { + android.util.Log.d(TAG, msg, t); + } + } + + public static void i(final String msg) { + if (isDebug) { + android.util.Log.i(TAG, msg); + } + } + + public static void i(final String msg, final Throwable t) { + if (isDebug) { + android.util.Log.i(TAG, msg, t); + } + } + + public static void w(final String msg) { + android.util.Log.w(TAG, msg); + } + + public static void w(final String msg, final Throwable t) { + android.util.Log.w(TAG, msg, t); + } + + public static void e(final String msg) { + android.util.Log.e(TAG, msg); + } + + public static void e(final String msg, final Throwable t) { + android.util.Log.e(TAG, msg, t); + } +} diff --git a/main/src/cgeo/geocaching/utils/LogTemplateProvider.java b/main/src/cgeo/geocaching/utils/LogTemplateProvider.java index b9bebc9..60866e0 100644 --- a/main/src/cgeo/geocaching/utils/LogTemplateProvider.java +++ b/main/src/cgeo/geocaching/utils/LogTemplateProvider.java @@ -2,14 +2,13 @@ package cgeo.geocaching.utils; import cgeo.geocaching.R; import cgeo.geocaching.Settings; -import cgeo.geocaching.cgBase; import cgeo.geocaching.connector.gc.GCConstants; -import cgeo.geocaching.network.Login; +import cgeo.geocaching.connector.gc.Login; import cgeo.geocaching.network.Network; +import cgeo.geocaching.ui.Formatter; import org.apache.commons.lang3.StringUtils; -import android.util.Log; /** * provides all the available templates for logging @@ -56,14 +55,14 @@ public class LogTemplateProvider { @Override public String getValue(final boolean offline) { - return cgBase.formatFullDate(System.currentTimeMillis()); + return Formatter.formatFullDate(System.currentTimeMillis()); } }, new LogTemplate("TIME", R.string.init_signature_template_time) { @Override public String getValue(final boolean offline) { - return cgBase.formatTime(System.currentTimeMillis()); + return Formatter.formatTime(System.currentTimeMillis()); } }, new LogTemplate("DATETIME", R.string.init_signature_template_datetime) { @@ -71,7 +70,7 @@ public class LogTemplateProvider { @Override public String getValue(final boolean offline) { final long currentTime = System.currentTimeMillis(); - return cgBase.formatFullDate(currentTime) + " " + cgBase.formatTime(currentTime); + return Formatter.formatFullDate(currentTime) + " " + Formatter.formatTime(currentTime); } }, new LogTemplate("USER", R.string.init_signature_template_user) { @@ -90,7 +89,7 @@ public class LogTemplateProvider { if (offline) { return ""; } - final String page = Network.getResponseData(Network.request("http://www.geocaching.com/email/", null, false, false, false)); + final String page = Network.getResponseData(Network.getRequest("http://www.geocaching.com/email/")); current = parseFindCount(page); } @@ -134,7 +133,7 @@ public class LogTemplateProvider { try { return Integer.parseInt(BaseUtils.getMatch(page, GCConstants.PATTERN_CACHES_FOUND, true, "-1").replaceAll("[,.]", "")); } catch (NumberFormatException e) { - Log.e(Settings.tag, "parseFindCount", e); + Log.e("parseFindCount", e); return -1; } } diff --git a/main/src/cgeo/geocaching/utils/MemorySubject.java b/main/src/cgeo/geocaching/utils/MemorySubject.java new file mode 100644 index 0000000..c424528 --- /dev/null +++ b/main/src/cgeo/geocaching/utils/MemorySubject.java @@ -0,0 +1,45 @@ +package cgeo.geocaching.utils; + +/** + * Synchronized implementation of the {@link ISubject} interface with an added pull interface. + * + * @param <T> + * the kind of data to observe + */ +public class MemorySubject<T> extends Subject<T> { + + /** + * The latest version of the observed data. + * <p/> + * A child class implementation may want to set this field from its constructors, in case early observers request + * the data before it got a chance to get updated. Otherwise, <code>null</code> will be returned until updated + * data is available. + */ + private T memory; + + @Override + public synchronized boolean addObserver(final IObserver<? super T> observer) { + final boolean added = super.addObserver(observer); + if (added && memory != null) { + observer.update(memory); + } + return added; + } + + @Override + public synchronized boolean notifyObservers(final T data) { + memory = data; + return super.notifyObservers(data); + } + + /** + * Get the memorized version of the data. + * + * @return the initial data set by the subject (which may be <code>null</code>), + * or the updated data if it is available + */ + public synchronized T getMemory() { + return memory; + } + +} diff --git a/main/src/cgeo/geocaching/utils/PeriodicHandler.java b/main/src/cgeo/geocaching/utils/PeriodicHandler.java new file mode 100644 index 0000000..3f6c345 --- /dev/null +++ b/main/src/cgeo/geocaching/utils/PeriodicHandler.java @@ -0,0 +1,74 @@ +package cgeo.geocaching.utils; + +import android.os.Handler; +import android.os.Message; + +/** + * A PeriodicHandler class helps with the implementation of a periodic + * action embedded in a thread with a looper such as the UI thread. + * The act() method will be called periodically. The clock may drift + * as the implementation does not target real-time actions. + * + * The handler will be interrupted if the device goes to sleep. + * + */ +abstract public class PeriodicHandler extends Handler { + + final static private int START = 0; + final static private int STOP = 1; + final static private int ACT = 2; + + final private long period; + + /** + * Create a new PeriodicHandler object. + * + * @param period + * The period in milliseconds. + */ + public PeriodicHandler(final long period) { + this.period = period; + } + + /** + * Subclasses of PeriodicHandler must implement this method. + */ + abstract public void act(); + + @Override + public void handleMessage(final Message msg) { + switch (msg.what) { + case START: + removeMessages(ACT); + sendEmptyMessage(ACT); + break; + case STOP: + removeMessages(ACT); + break; + case ACT: + sendEmptyMessageDelayed(ACT, period); + act(); + } + } + + /** + * Start the periodic handler. + * + * Restarting a handler that is already started will only + * reset its clock. + */ + public void start() { + sendEmptyMessage(START); + } + + /** + * Stop the periodic handler. + * + * If this method is called from the looper thread, this call is + * guaranteed to be synchronous. + */ + public void stop() { + sendMessageAtFrontOfQueue(obtainMessage(STOP)); + } + +} diff --git a/main/src/cgeo/geocaching/utils/Subject.java b/main/src/cgeo/geocaching/utils/Subject.java new file mode 100644 index 0000000..b1754cc --- /dev/null +++ b/main/src/cgeo/geocaching/utils/Subject.java @@ -0,0 +1,76 @@ +package cgeo.geocaching.utils; + +import java.util.LinkedHashSet; +import java.util.Set; + +/** + * Synchronized implementation of the {@link ISubject} interface. + * + * @param <T> + * the kind of data to observe + */ +public class Subject<T> implements ISubject<T> { + + /** + * Collection of observers. + */ + protected final Set<IObserver<? super T>> observers = new LinkedHashSet<IObserver<? super T>>(); + + @Override + public synchronized boolean addObserver(final IObserver<? super T> observer) { + final boolean added = observers.add(observer); + if (added && observers.size() == 1) { + onFirstObserver(); + } + return added; + } + + @Override + public synchronized boolean deleteObserver(final IObserver<? super T> observer) { + final boolean removed = observers.remove(observer); + if (removed && observers.isEmpty()) { + onLastObserver(); + } + return removed; + } + + @Override + public synchronized boolean notifyObservers(final T arg) { + final boolean nonEmpty = !observers.isEmpty(); + for (final IObserver<? super T> observer : observers) { + observer.update(arg); + } + return nonEmpty; + } + + @Override + public synchronized int sizeObservers() { + return observers.size(); + } + + @Override + public synchronized boolean clearObservers() { + final boolean nonEmpty = !observers.isEmpty(); + for (final IObserver<? super T> observer : observers) { + deleteObserver(observer); + } + return nonEmpty; + } + + /** + * Method called when the collection of observers goes from empty to non-empty. + * <p/> + * The default implementation does nothing and may be overwritten by child classes. + */ + protected void onFirstObserver() { + } + + /** + * Method called when the collection of observers goes from non-empty to empty. + * <p/> + * The default implementation does nothing and may be overwritten by child classes. + */ + protected void onLastObserver() { + } + +} diff --git a/main/src/com/viewpagerindicator/TitlePageIndicator.java b/main/src/com/viewpagerindicator/TitlePageIndicator.java index 49b158a..a181fed 100644 --- a/main/src/com/viewpagerindicator/TitlePageIndicator.java +++ b/main/src/com/viewpagerindicator/TitlePageIndicator.java @@ -508,8 +508,7 @@ public class TitlePageIndicator extends View implements PageIndicator { case MotionEventCompat.ACTION_POINTER_DOWN: { final int index = MotionEventCompat.getActionIndex(ev); - final float x = MotionEventCompat.getX(ev, index); - mLastMotionX = x; + mLastMotionX = MotionEventCompat.getX(ev, index); mActivePointerId = MotionEventCompat.getPointerId(ev, index); break; } @@ -687,7 +686,7 @@ public class TitlePageIndicator extends View implements PageIndicator { * @return The width of the view, honoring constraints from measureSpec */ private int measureWidth(int measureSpec) { - int result = 0; + int result; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); @@ -706,7 +705,7 @@ public class TitlePageIndicator extends View implements PageIndicator { * @return The height of the view, honoring constraints from measureSpec */ private int measureHeight(int measureSpec) { - float result = 0; + float result; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); diff --git a/main/support/proguard.jar b/main/support/proguard.jar Binary files differindex f688284..56d68ba 100644 --- a/main/support/proguard.jar +++ b/main/support/proguard.jar diff --git a/tests/.settings/org.eclipse.jdt.core.prefs b/tests/.settings/org.eclipse.jdt.core.prefs index 8dcff6e..eb2d3aa 100644 --- a/tests/.settings/org.eclipse.jdt.core.prefs +++ b/tests/.settings/org.eclipse.jdt.core.prefs @@ -1,354 +1,353 @@ -#Fri Nov 18 10:06:05 CET 2011
-eclipse.preferences.version=1
-org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
-org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=1.6
-org.eclipse.jdt.core.compiler.debug.lineNumber=generate
-org.eclipse.jdt.core.compiler.debug.localVariable=generate
-org.eclipse.jdt.core.compiler.debug.sourceFile=generate
-org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
-org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
-org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
-org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
-org.eclipse.jdt.core.compiler.problem.deadCode=warning
-org.eclipse.jdt.core.compiler.problem.deprecation=warning
-org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
-org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
-org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
-org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
-org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
-org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
-org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
-org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
-org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
-org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
-org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
-org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled
-org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
-org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning
-org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning
-org.eclipse.jdt.core.compiler.problem.localVariableHiding=warning
-org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
-org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning
-org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=warning
-org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning
-org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=disabled
-org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
-org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=warning
-org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
-org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
-org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
-org.eclipse.jdt.core.compiler.problem.nullReference=warning
-org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
-org.eclipse.jdt.core.compiler.problem.parameterAssignment=warning
-org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning
-org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning
-org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
-org.eclipse.jdt.core.compiler.problem.redundantNullCheck=warning
-org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=warning
-org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=warning
-org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=warning
-org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=warning
-org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
-org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
-org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
-org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
-org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
-org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
-org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled
-org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
-org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=warning
-org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
-org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning
-org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning
-org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
-org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning
-org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
-org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
-org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
-org.eclipse.jdt.core.compiler.problem.unusedImport=warning
-org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
-org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
-org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=warning
-org.eclipse.jdt.core.compiler.problem.unusedParameter=warning
-org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
-org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
-org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
-org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
-org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
-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=0
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=0
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=0
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=0
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=0
-org.eclipse.jdt.core.formatter.alignment_for_assignment=0
-org.eclipse.jdt.core.formatter.alignment_for_binary_expression=0
-org.eclipse.jdt.core.formatter.alignment_for_compact_if=0
-org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=0
-org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
-org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=0
-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=0
-org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=0
-org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=0
-org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=0
-org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=0
-org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=0
-org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=0
-org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=0
-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
-org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
-org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
-org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
-org.eclipse.jdt.core.formatter.blank_lines_before_method=1
-org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
-org.eclipse.jdt.core.formatter.blank_lines_before_package=0
-org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
-org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
-org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
-org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
-org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
-org.eclipse.jdt.core.formatter.comment.format_block_comments=true
-org.eclipse.jdt.core.formatter.comment.format_header=true
-org.eclipse.jdt.core.formatter.comment.format_html=true
-org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
-org.eclipse.jdt.core.formatter.comment.format_line_comments=false
-org.eclipse.jdt.core.formatter.comment.format_source_code=true
-org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
-org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
-org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
-org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert
-org.eclipse.jdt.core.formatter.comment.line_length=120
-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
-org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
-org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
-org.eclipse.jdt.core.formatter.indent_empty_lines=false
-org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
-org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
-org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
-org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true
-org.eclipse.jdt.core.formatter.indentation.size=4
-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=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
-org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
-org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
-org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
-org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
-org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
-org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
-org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
-org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
-org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
-org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
-org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
-org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
-org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
-org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
-org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
-org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
-org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
-org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
-org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
-org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
-org.eclipse.jdt.core.formatter.join_lines_in_comments=false
-org.eclipse.jdt.core.formatter.join_wrapped_lines=false
-org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
-org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
-org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
-org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
-org.eclipse.jdt.core.formatter.lineSplit=120
-org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
-org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
-org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
-org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
-org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
-org.eclipse.jdt.core.formatter.tabulation.char=space
-org.eclipse.jdt.core.formatter.tabulation.size=4
-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_outer_expressions_when_nested=true
+eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.autoboxing=ignore +org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning +org.eclipse.jdt.core.compiler.problem.deadCode=warning +org.eclipse.jdt.core.compiler.problem.deprecation=warning +org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled +org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled +org.eclipse.jdt.core.compiler.problem.discouragedReference=warning +org.eclipse.jdt.core.compiler.problem.emptyStatement=warning +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning +org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled +org.eclipse.jdt.core.compiler.problem.fieldHiding=warning +org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning +org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning +org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled +org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning +org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning +org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning +org.eclipse.jdt.core.compiler.problem.localVariableHiding=warning +org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning +org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=warning +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=disabled +org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning +org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=warning +org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning +org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning +org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore +org.eclipse.jdt.core.compiler.problem.nullReference=warning +org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning +org.eclipse.jdt.core.compiler.problem.parameterAssignment=warning +org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning +org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning +org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning +org.eclipse.jdt.core.compiler.problem.redundantNullCheck=warning +org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=warning +org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=warning +org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=warning +org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=warning +org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled +org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning +org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled +org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled +org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore +org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning +org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled +org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning +org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=warning +org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning +org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled +org.eclipse.jdt.core.compiler.problem.unusedImport=warning +org.eclipse.jdt.core.compiler.problem.unusedLabel=warning +org.eclipse.jdt.core.compiler.problem.unusedLocal=warning +org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=warning +org.eclipse.jdt.core.compiler.problem.unusedParameter=warning +org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled +org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning +org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning +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=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=0 +org.eclipse.jdt.core.formatter.alignment_for_assignment=0 +org.eclipse.jdt.core.formatter.alignment_for_binary_expression=0 +org.eclipse.jdt.core.formatter.alignment_for_compact_if=0 +org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=0 +org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0 +org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=0 +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=0 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=0 +org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=0 +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 +org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0 +org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1 +org.eclipse.jdt.core.formatter.blank_lines_before_method=1 +org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 +org.eclipse.jdt.core.formatter.blank_lines_before_package=0 +org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1 +org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 +org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false +org.eclipse.jdt.core.formatter.comment.format_block_comments=true +org.eclipse.jdt.core.formatter.comment.format_header=true +org.eclipse.jdt.core.formatter.comment.format_html=true +org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true +org.eclipse.jdt.core.formatter.comment.format_line_comments=false +org.eclipse.jdt.core.formatter.comment.format_source_code=true +org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true +org.eclipse.jdt.core.formatter.comment.indent_root_tags=true +org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert +org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert +org.eclipse.jdt.core.formatter.comment.line_length=120 +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 +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true +org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_empty_lines=false +org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true +org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true +org.eclipse.jdt.core.formatter.indentation.size=4 +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=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert +org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.join_lines_in_comments=false +org.eclipse.jdt.core.formatter.join_wrapped_lines=false +org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false +org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false +org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false +org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false +org.eclipse.jdt.core.formatter.lineSplit=120 +org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false +org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false +org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 +org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1 +org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true +org.eclipse.jdt.core.formatter.tabulation.char=space +org.eclipse.jdt.core.formatter.tabulation.size=4 +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_outer_expressions_when_nested=true diff --git a/tests/res/raw/gc2cjpf_html b/tests/res/raw/gc2cjpf_html new file mode 100644 index 0000000..5fc0e3f --- /dev/null +++ b/tests/res/raw/gc2cjpf_html @@ -0,0 +1,2522 @@ +
+<!DOCTYPE html>
+<html lang="en" class="no-js">
+<head id="ctl00_Head1"><meta charset="utf-8" />
+ <!--[if IE]><![endif]-->
+ <title>
+ GC2CJPF Kinderwald KiC (Multi-cache) in Niedersachsen, Germany created by Tom03
+</title><meta name="DC.title" content="Geocaching - The Official Global GPS Cache Hunt Site" /><meta name="author" content="Groundspeak, Inc." /><meta name="DC.creator" content="Groundspeak, Inc." /><meta name="Copyright" content="Copyright (c) 2000-2012 Groundspeak, Inc. All Rights Reserved." /><!-- Copyright (c) 2000-2012 Groundspeak, Inc. All Rights Reserved. --><meta name="description" content="Geocaching is a treasure hunting game where you use a GPS to hide and seek containers with other participants in the activity. Geocaching.com is the listing service for geocaches around the world." /><meta name="DC.subject" content="Geocaching is a treasure hunting game where you use a GPS to hide and seek containers with other participants in the activity. Geocaching.com is the listing service for geocaches around the world." /><meta http-equiv="imagetoolbar" content="no" /><meta name="distribution" content="global" /><meta name="MSSmartTagsPreventParsing" content="true" /><meta name="rating" content="general" /><meta name="revisit-after" content="1 days" /><meta name="robots" content="all" /><meta http-equiv="X-UA-Compatible" content="IE=8" /><link rel="icon" href="/favicon.ico" /><link rel="shortcut icon" href="/favicon.ico" /><link rel="apple-touch-icon" href="/apple-touch-icon.png" /><link rel="stylesheet" type="text/css" media="all" href="../css/blueprint/src/reset.css" /><link rel="stylesheet" type="text/css" media="all" href="../css/blueprint/src/typography.css" /><link rel="stylesheet" type="text/css" media="screen,projection" href="../css/blueprint/src/grid.css" />
+ <!--[if lt IE 8]>
+ <link rel="stylesheet" type="text/css" media="all" href="../css/blueprint/ie.css" />
+ <![endif]-->
+ <link id="uxCssMaster" rel="stylesheet" type="text/css" media="screen,projection" href="../css/tlnMasterScreen.css?r=1" /><link id="uxCssMain" rel="stylesheet" type="text/css" media="all" href="../css/tlnMain.css?r=1" /><link rel="Stylesheet" type="text/css" media="all" href="../css/jqueryui1810/jquery-ui-1.8.10.custom.css" /><link rel="stylesheet" type="text/css" media="all" href="/js/jquery_plugins/jquery.jgrowl.css" /><link rel="stylesheet" type="text/css" media="print" href="../css/tlnMasterPrint.css" />
+ <script type="text/javascript" src="/js/modernizr-1.7.min.js"></script>
+ <script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
+ <script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jqueryui/1.8.17/jquery-ui.min.js"></script>
+ <script type="text/javascript" src="/js/jquery.truncate.min.js"></script>
+
+
+
+ <link href="/css/fancybox/jquery.fancybox.css" rel="stylesheet" type="text/css" />
+ <link href="/js/jquery_plugins/icalendar/jquery.icalendar.css" rel="stylesheet" type="text/css" />
+ <link href="/js/jquery_plugins/tipTip/tipTip.css" rel="stylesheet" type="text/css" />
+ <link href="/js/jquery_plugins/qtip/jquery.qtip.css" rel="stylesheet" type="text/css" />
+ <!--[if lte IE 8]>
+ <style type="text/css" media="all">
+ legend{
+ position: absolute;
+ top: -.6em;
+ left: 1em;
+ line-height: 1.3;
+ }
+ fieldset p{
+ margin-top:1em;
+ }
+ img.CacheNoteHelpImg{
+ top:-.2em;
+ }
+ </style>
+ <![endif]-->
+ <style type="text/css" media="screen,projection">
+ #otherSearchOptions li
+ {
+ list-style-image: none;
+ list-style-position: outside;
+ list-style-type: none;
+ }
+ .ff
+ {
+ font-family: "Andale Mono" , "Courier New" ,Courier,monospace;
+ }
+ .fr
+ {
+ margin-top: 1.5em;
+ float: right;
+ }
+ .fl
+ {
+ float: left;
+ }
+ .clsCell
+ {
+ border: 1px solid #c0cee3;
+ font-size: 80%;
+ background-color: #fff;
+ }
+ .clsResultTitle, .clsResultTitleNoBold
+ {
+ color: #0000de;
+ }
+ .clsResultDescription
+ {
+ color: #333;
+ }
+ .clsURL
+ {
+ color: #999;
+ }
+ a.title:link, a.title:visited, a.title:hover, a.title:active
+ {
+ color: #000;
+ text-decoration: underline;
+ }
+ a.title
+ {
+ text-align: right;
+ font-size: 10px;
+ font-family: arial,sans-serif;
+ padding: 0 1px 0 0;
+ }
+ #mapSizePager a:hover
+ {
+ font-weight: bold;
+ }
+ #mapSizePager ul
+ {
+ width: 100%;
+ margin: 0;
+ padding: 0;
+ list-style: none;
+ }
+ #mapSizePager li
+ {
+ float: left;
+ list-style: none;
+ }
+ #mapSizePager li a
+ {
+ font-family: verdana,sans-serif;
+ font-size: x-small;
+ display: block;
+ margin: 0 2px 0 0;
+ padding: 4px;
+ text-decoration: none;
+ border: solid 1px #c0c0c0;
+ height: 10px;
+ min-width: 10px;
+ cursor: pointer;
+ }
+ #mapPrintingNotes
+ {
+ width: 280px;
+ text-align: left;
+ overflow: auto;
+ }
+ .inplace_field {
+ width:100%;
+ resize: none;
+ }
+ legend.note{
+ background:url('../images/silk/note.png') no-repeat 0 0;
+ padding-left:18px;
+ }
+ legend.warning{
+ background:url('../images/silk/exclamation.png') no-repeat 0 0;
+ padding-left:18px;
+ }
+ fieldset.CacheNote{
+ border-color: #e9a24c !important;
+ background-color:#ffffde;
+ position:relative;
+ }
+ .CacheNoteHelpImg{
+ position:relative;
+ cursor:pointer;
+ top:-1em;
+ right:-.75em;
+ float:right;
+ }
+ .InformationWidget h3{
+ margin-bottom:.5em;
+ }
+ .InformationWidget .AlignRight{
+ font-size:.8em;
+ }
+ #tiptip_content{
+ *background-color:#000;
+ }
+ .maxed{
+ color:#992a2a;
+ }
+
+
+ span.ccu-parseverify-distance img{
+ text-align:center !important;
+ vertical-align:text-bottom !important;
+ }
+ .edit-cache-coordinates{
+ text-decoration: none;
+ color: #000 !important;
+ background: url(/images/silk/pencil.png) no-repeat right 0;
+ padding:2px 20px 2px 0px;
+ margin-right:4px;
+ }
+ .ccc-coord{
+ cursor: text;
+ font-family: Courier New, Sans-Serif;
+ }
+ .ccu-update dl {
+ margin-bottom:.25em;
+ }
+ .ccu-update dt{
+ float:left;
+ min-width:90px;
+ }
+ .ccu-update .ui-button-text-only .ui-button-text{
+ padding:.3em .75em;
+ }
+ .ccu-parseverify-coords{
+ font-style:italic;
+ margin-right:.25em;
+ }
+ .ccu-parseverify-accept, .ccu-parseverify-cancel{
+ margin-top:-5px;
+ }
+ .ui-tooltip-widget .ui-tooltip-content{
+ border-width:1px;
+ background-color:#fff;
+ border-color:#c0cee3;
+ color:#594a42;
+ padding:1em;
+ width:420px;
+ }
+ .myLatLon { border-bottom:2px solid #c0cee3;font-style:italic; }
+ .leaflet-control-attribution
+ {
+ font-size:8px !important;
+ font-family: "Helvetica Neue",Arial,Helvetica,sans-serif !important;
+ }
+ </style>
+ <link rel="stylesheet" type="text/css" media="all" href="/js/leaflet/dist/leaflet.css" />
+ <!--[if IE]>
+ <link rel="stylesheet" type="text/css" media="all" href="/js/leaflet/dist/leaflet.ie.css" />
+ <![endif]-->
+ <script type="text/javascript" language="javascript" src="/js/leaflet/dist/leaflet.js"></script>
+ <script type="text/javascript">
+ var userToken = null,
+ urlParams = {},
+ mapLatLng = null,
+ cmapAdditionalWaypoints = [],
+ initalLogs = null, totalLogs = 0, includeAvatars = false;
+
+ (function () {
+ var e,
+ d = function (s) { return decodeURIComponent(s.replace(/\+/g, " ")); },
+ q = window.location.search.substring(1),
+ r = /([^&=]+)=?([^&]*)/g;
+
+ while (e = r.exec(q)) {
+ urlParams[d(e[1])] = d(e[2]);
+ }
+ })();
+ </script>
+<meta name="og:site_name" content="Geocaching.com" property="og:site_name" /><meta name="og:type" content="article" property="og:type" /><meta name="fb:app_id" content="100167303362705" property="fb:app_id" /><meta name="og:url" content="http://coord.info/GC2CJPF" property="og:url" /><meta name="og:description" content="Von Nachwuchs-Cachern für Nachwuchs-Cacher." property="og:description" /><meta name="og:image" content="http://www.geocaching.com/images/facebook/wpttypes/3.png" property="og:image" /><meta name="og:title" content="Kinderwald KiC" property="og:title" /><meta name="description" content="Kinderwald KiC (GC2CJPF) was created by Tom03 on 07/31/2010. It's a Small size geocache, with difficulty of 2.5, terrain of 2. It's located in Niedersachsen, Germany. Von Nachwuchs-Cachern für Nachwuchs-Cacher. Kleiner Multi über 7 Stationen. Länge ca. 1 km + 1km für den Rückweg. Die ZS befinden sich alle am KLEINEN BACH innerhalb des Kinderwaldes." /><link rel="alternate" href="../datastore/rss_galleryimages.ashx?guid=73246a5a-ebb9-4d4f-8db9-a951036f5376" type="application/rss+xml" title="[Gallery Images]" id="GalleryImages" /></head>
+<body background="http://www.blafoo.de/images/Kinderwald.jpg" class="CacheDetailsPage">
+ <form name="aspnetForm" method="post" action="cache_details.aspx?log=y&wp=GC2CJPF&numlogs=35&decrypt=y" id="aspnetForm">
+<div>
+<input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" />
+<input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" />
+<input type="hidden" name="__VIEWSTATEFIELDCOUNT" id="__VIEWSTATEFIELDCOUNT" value="3" />
+<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwULLTE3MDQ4NTMzNDQPFgIeBEMuSUQoKVlTeXN0ZW0uSW50NjQsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQcxODExNDA5FgJmD2QWBmYPZBYKAgYPFgIeBFRleHQFYjxtZXRhIG5hbWU9IkNvcHlyaWdodCIgY29udGVudD0iQ29weXJpZ2h0IChjKSAyMDAwLTIwMTIgR3JvdW5kc3BlYWssIEluYy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC4iIC8+ZAIHDxYCHwEFRzwhLS0gQ29weXJpZ2h0IChjKSAyMDAwLTIwMTIgR3JvdW5kc3BlYWssIEluYy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC4gLS0+ZAIaDxYCHgRocmVmBR1+L2Nzcy90bG5NYXN0ZXJTY3JlZW4uY3NzP3I9MWQCGw8WAh8CBRV+L2Nzcy90bG5NYWluLmNzcz9yPTFkAiAPFgIeB1Zpc2libGVoZAIBD2QWDgIFDxYCHwFkZAIIDxYCHwNnFgoCAQ8PFgIeCEltYWdlVXJsBU5odHRwOi8vaW1nLmdlb2NhY2hpbmcuY29tL3VzZXIvYXZhdGFyLzUwZjgzMTIzLTI3ZDgtNGRjZi05ZmRlLTJhZjAwNmVmYWYyYi5qcGdkZAIDDxYCHwEFaEhlbGxvLCA8YSBocmVmPSIvbXkvZGVmYXVsdC5hc3B4IiB0aXRsZT0iVmlldyBQcm9maWxlIGZvciBibGFmb28iIGNsYXNzPSJTaWduZWRJblByb2ZpbGVMaW5rIj5ibGFmb288L2E+ZAIFDw8WAh4LTmF2aWdhdGVVcmwFrQFodHRwczovL3d3dy5nZW9jYWNoaW5nLmNvbS9sb2dpbi9kZWZhdWx0LmFzcHg/UkVTRVQ9WSZyZWRpcj1odHRwJTNhJTJmJTJmd3d3Lmdlb2NhY2hpbmcuY29tJTJmc2VlayUyZmNhY2hlX2RldGFpbHMuYXNweCUzZmxvZyUzZHklMjZ3cCUzZEdDMkNKUEYlMjZudW1sb2dzJTNkMzUlMjZkZWNyeXB0JTNkeWRkAgcPFgIfAQWtATxpbWcgc3JjPSIvaW1hZ2VzL2ljb25zL2ljb25fc21pbGUucG5nIiB0aXRsZT0iQ2FjaGVzIEZvdW5kIiAvPiA1MTMmbmJzcDsmbWlkZG90OyZuYnNwOzxpbWcgc3JjPSIvaW1hZ2VzL2NoYWxsZW5nZXMvdHlwZXMvc20vY2hhbGxlbmdlLnBuZyIgdGl0bGU9IkNoYWxsZW5nZXMgQ29tcGxldGVkIiAvPiAyZAILDxYCHwNnZAINDxYCHwNnFgICDQ8PFgIfBQVAfi90cmFjay9zZWFyY2guYXNweD9vPTEmdWlkPTA1NjRhOTQwLTgzMTEtNDBlZS04ZTc2LTdlOTFiMmNmNjI4NGRkAhAPDxYCHwNnZGQCLA8WAh4FY2xhc3MFDHNwYW4tMjQgbGFzdBYCAgEPZBZQAgEPZBYCZg9kFgICAQ8PFgIfAQUHR0MyQ0pQRmRkAgIPFgIfAQWxATxhIGhyZWY9Ii9hYm91dC9jYWNoZV90eXBlcy5hc3B4IiB0YXJnZXQ9Il9ibGFuayIgdGl0bGU9IkFib3V0IENhY2hlIFR5cGVzIj48aW1nIHNyYz0iL2ltYWdlcy9XcHRUeXBlcy8zLmdpZiIgYWx0PSJNdWx0aS1jYWNoZSIgdGl0bGU9Ik11bHRpLWNhY2hlIiB3aWR0aD0iMzIiIGhlaWdodD0iMzIiIC8+PC9hPmQCBQ8WAh8BBQFBZAIHDxYCHwNnZAIKDxYCHwNoZAIRD2QWBAIBDxYCHwEFATdkAgMPDxYCHwUFRC9zZWVrL2NhY2hlX2Zhdm9yaXRlZC5hc3B4P2d1aWQ9NzMyNDZhNWEtZWJiOS00ZDRmLThkYjktYTk1MTAzNmY1Mzc2ZGQCEg8PFgIfBQUZaHR0cDovL3d3dy5raW5kZXJ3YWxkLmRlL2RkAhUPFgIfA2hkAhYPFgIfA2hkAhgPFgIeBXN0eWxlBQ9kaXNwbGF5OmlubGluZTsWAgIBDxYCHwEFG1VUTTogMzJVIEUgNTQ1MTY0IE4gNTgwODUyNGQCHQ8PFgIfBQUzY2RwZi5hc3B4P2d1aWQ9NzMyNDZhNWEtZWJiOS00ZDRmLThkYjktYTk1MTAzNmY1Mzc2ZGQCHg8PFgIfBQU4Y2RwZi5hc3B4P2d1aWQ9NzMyNDZhNWEtZWJiOS00ZDRmLThkYjktYTk1MTAzNmY1Mzc2JmxjPTVkZAIfDw8WAh8FBTljZHBmLmFzcHg/Z3VpZD03MzI0NmE1YS1lYmI5LTRkNGYtOGRiOS1hOTUxMDM2ZjUzNzYmbGM9MTBkZAIgDw8WBB8FBXNodHRwOi8vbWFwcy5nb29nbGUuY29tL21hcHM/Zj1kJmhsPWVuJnNhZGRyPTUyLjQxNjIsOS41OTQxMTcgKEhvbWUgTG9jYXRpb24pJmRhZGRyPTUyLjQyNTA2Nyw5LjY2NDIoS2luZGVyd2FsZCtLaUMpHgZUYXJnZXQFBl9ibGFua2RkAiQPZBYIAgEPDxYEHglGb3JlQ29sb3IMHgRfIVNCAgRkZAIDDw8WBB8JDB8KAgRkZAIFDw8WAh8DZxYCHgdvbmNsaWNrBTtzMmdwcygnNzMyNDZhNWEtZWJiOS00ZDRmLThkYjktYTk1MTAzNmY1Mzc2Jyk7cmV0dXJuIGZhbHNlO2QCBw8PFgIfA2cWAh8LBSBzMnBob25lKCdHQzJDSlBGJyk7cmV0dXJuIGZhbHNlO2QCJg8WAh8DZ2QCKQ9kFghmDxYCHwNoZAIBDw8WAh8DaGRkAgIPDxYCHwNoZGQCAw8WAh8DaGQCKw8PFgIfAQUHRW5jcnlwdGRkAiwPFgIfAQUbRGFzIEZpbmFsIGlzdCB1bnRlciBTdGVpbmVuZAIvD2QWBAIBDw8WBB4IQ3NzQ2xhc3NkHwoCAmRkAgQPFgIfAQUCMjJkAjAPZBYCAgEPFgIfA2cWAgIBDw8WAh8FBTgvc2Vlay9sb2cuYXNweD9MVUlEPTdjNmYwODkxLTcwMDMtNGFlNS05MjMxLWMyZTQxN2QxYzVlNGRkAjEPFgIfA2dkAjIPFgIfA2hkAjYPZBYCAgEPZBYEAgEPDxYCHwEF/wM8aWZyYW1lIHR5cGU9ImlmcmFtZSIgc3JjPSJodHRwOi8vYWRzLmdyb3VuZHNwZWFrLmNvbS9hLmFzcHg/Wm9uZUlEPTkmVGFzaz1HZXQmU2l0ZUlEPTEmWD0nZTgyYTJkNTM1ZWFmNDRlYWIzZjNjZDNlMDAyMThlNmEnIiB3aWR0aD0iMTIwIiBoZWlnaHQ9IjI0MCIgTWFyZ2lud2lkdGg9IjAiIE1hcmdpbmhlaWdodD0iMCIgSHNwYWNlPSIwIiBWc3BhY2U9IjAiIEZyYW1lYm9yZGVyPSIwIiBTY3JvbGxpbmc9Im5vIiBzdHlsZT0id2lkdGg6MTIwcHg7SGVpZ2h0OjI0MHB4OyI+PGEgaHJlZj0iaHR0cDovL2Fkcy5ncm91bmRzcGVhay5jb20vYS5hc3B4P1pvbmVJRD05JlRhc2s9Q2xpY2smO01vZGU9SFRNTCZTaXRlSUQ9MSIgdGFyZ2V0PSJfYmxhbmsiPjxpbWcgc3JjPSJodHRwOi8vYWRzLmdyb3VuZHNwZWFrLmNvbS9hLmFzcHg/Wm9uZUlEPTkmVGFzaz1HZXQmTW9kZT1IVE1MJlNpdGVJRD0xIiB3aWR0aD0iMTIwIiBoZWlnaHQ9IjI0MCIgYm9yZGVyPSIwIiBhbHQ9IiIgLz48L2E+PC9pZnJhbWU+ZGQCAw8WAh4JaW5uZXJodG1sBRNBZHZlcnRpc2luZyB3aXRoIFVzZAI6D2QWBgIFDxYCHgtfIUl0ZW1Db3VudAIBFgICAQ9kFgJmDxUDVmh0dHA6Ly93d3cuZ2VvY2FjaGluZy5jb20vdHJhY2svZGV0YWlscy5hc3B4P2d1aWQ9NGMzYmIyOTYtNGMzMC00NjU3LWIxMTAtYjczNzBkZmFmNTRkM2h0dHA6Ly93d3cuZ2VvY2FjaGluZy5jb20vaW1hZ2VzL3dwdHR5cGVzL3NtLzIxLmdpZhhUcmF2ZWxpbmcgQnJ1dHVzIEJ1Y2tleWVkAgkPDxYCHwNnZBYCAgEPDxYEHwEFE1ZpZXcgYWxsIFRyYWNrYWJsZXMfBQVJfi90cmFjay9zZWFyY2guYXNweD93aWQ9NzMyNDZhNWEtZWJiOS00ZDRmLThkYjktYTk1MTAzNmY1Mzc2JmNjaWQ9MTgxMTQwOWRkAgsPDxYCHwUFPH4vdHJhY2svc2VhcmNoLmFzcHg/d2lkPTczMjQ2YTVhLWViYjktNGQ0Zi04ZGI5LWE5NTEwMzZmNTM3NmRkAjsPDxYCHwNnZBYCZg8WAh8OAgEWAgIBD2QWBGYPFQMAV2h0dHA6Ly93d3cuZ2VvY2FjaGluZy5jb20vYm9va21hcmtzL3ZpZXcuYXNweD9ndWlkPTNlZWVhMDU3LWY2MDUtNDg1YS1hNDVhLWY1ZmVhMTQyNjYxMhJLaW5kZXJjYWNoZXMgKEtpQylkAgIPFQJMaHR0cDovL3d3dy5nZW9jYWNoaW5nLmNvbS9wcm9maWxlLz9ndWlkPTA1NjRhOTQwLTgzMTEtNDBlZS04ZTc2LTdlOTFiMmNmNjI4NAZibGFmb29kAjwPDxYCHwNnZBYCZg8WAh8OAgEWAgIBD2QWBGYPFQMAV2h0dHA6Ly93d3cuZ2VvY2FjaGluZy5jb20vYm9va21hcmtzL3ZpZXcuYXNweD9ndWlkPTNlZWVhMDU3LWY2MDUtNDg1YS1hNDVhLWY1ZmVhMTQyNjYxMhJLaW5kZXJjYWNoZXMgKEtpQylkAgIPFQJMaHR0cDovL3d3dy5nZW9jYWNoaW5nLmNvbS9wcm9maWxlLz9ndWlkPTA1NjRhOTQwLTgzMTEtNDBlZS04ZTc2LTdlOTFiMmNm" />
+<input type="hidden" name="__VIEWSTATE1" id="__VIEWSTATE1" value="NjI4NAZibGFmb29kAj4PZBYCAgEPDxYCHwUFRS9oaWRlL3dwdGxpc3QuYXNweD9SZWZXcHRJRD03MzI0NmE1YS1lYmI5LTRkNGYtOGRiOS1hOTUxMDM2ZjUzNzYmRFM9MWRkAkAPDxYEHgZSRFMuSUQLKXZHcm91bmRzcGVhay5XZWIuR1BYLldwdERhdGFTb3VyY2VzLCBUdWNzb24uQ29tbW9uLkxlZ2FjeSwgVmVyc2lvbj0zLjAuNDQyNi4yNDg1MSwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1udWxsAR4HUldQVC5JRCgrBAcxODExNDA5ZBYCZg8WAh8OAgQWCmYPZBYCZg8PFgIfA2hkZAIBD2QWDGYPFQIABWZhbHNlZAICDxUJdDxpbWcgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2IiBzcmM9Ii9pbWFnZXMvaWNvbnMvaWNvbl9ub2Nvb3Jkcy5qcGciIGFsdD0iSGlkZSBDb29yZGluYXRlcyIgdGl0bGU9IkhpZGUgQ29vcmRpbmF0ZXMiIC8+NWh0dHA6Ly93d3cuZ2VvY2FjaGluZy5jb20vaW1hZ2VzL3dwdHR5cGVzL3NtL2ZsYWcuanBnDkZpbmFsIExvY2F0aW9uDkZpbmFsIExvY2F0aW9uAkZOAkZOBUZJTkFMsAE8YSBocmVmPSJodHRwOi8vd3d3Lmdlb2NhY2hpbmcuY29tL3NlZWsvd3B0LmFzcHg/V0lEPTMwZjFiMzdjLWQzOTUtNGM3YS05NGUyLTBjNjQ5ZDVmMjMxYiZSZWZJRD03MzI0NmE1YS1lYmI5LTRkNGYtOGRiOS1hOTUxMDM2ZjUzNzYmUmVmRFM9MSI+R0MyQ0pQRiBGaW5hbDwvYT4gKEZpbmFsIExvY2F0aW9uKQM/Pz9kAgUPDxYCHgdUb29sVGlwBQRFZGl0ZGQCBw8PFgIfEQUDTWFwZGQCCw8PFgIeDUFsdGVybmF0ZVRleHQFBlJlbW92ZRYCHwsFQHJldHVybiBjb25maXJtKCdBcmUgeW91IHN1cmUgeW91IHdhbnQgdG8gcmVtb3ZlIHRoaXMgd2F5cG9pbnQ/JylkAgwPFQIAAGQCAg9kFgxmDxUCDkFsdGVybmF0aW5nUm93BWZhbHNlZAICDxUJYjxpbWcgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2IiBzcmM9Ii9pbWFnZXMvaWNvbnMvaWNvbl92aWV3YWJsZS5qcGciIGFsdD0iVmlzaWJsZSIgdGl0bGU9IlZpc2libGUiIC8+NGh0dHA6Ly93d3cuZ2VvY2FjaGluZy5jb20vaW1hZ2VzL3dwdHR5cGVzL3NtL3BrZy5qcGcMUGFya2luZyBBcmVhDFBhcmtpbmcgQXJlYQJQSwJQSwZQQVJLTkewATxhIGhyZWY9Imh0dHA6Ly93d3cuZ2VvY2FjaGluZy5jb20vc2Vlay93cHQuYXNweD9XSUQ9OThjYjEzODctNDljZS00Zjk0LTliMDUtNWNiMDc5ZDMzMmIxJlJlZklEPTczMjQ2YTVhLWViYjktNGQ0Zi04ZGI5LWE5NTEwMzZmNTM3NiZSZWZEUz0xIj5HQzJDSlBGIFBhcmtpbmc8L2E+IChQYXJraW5nIEFyZWEpHE4gNTLCsCAyNS4zODQgRSAwMDnCsCAzOS4wMjNkAgUPDxYCHxEFBEVkaXRkZAIHDw8WAh8RBQNNYXBkZAILDw8WAh8SBQZSZW1vdmUWAh8LBUByZXR1cm4gY29uZmlybSgnQXJlIHlvdSBzdXJlIHlvdSB3YW50IHRvIHJlbW92ZSB0aGlzIHdheXBvaW50PycpZAIMDxUCDkFsdGVybmF0aW5nUm93N0tlaW4gIm9mZml6aWVsbGVyIiBQYXJrcGxhdHosIFBhcmtlbiB0cm90emRlbSBtw7ZnbGljaC5kAgMPZBYMZg8VAgAFZmFsc2VkAgIPFQliPGltZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHNyYz0iL2ltYWdlcy9pY29ucy9pY29uX3ZpZXdhYmxlLmpwZyIgYWx0PSJWaXNpYmxlIiB0aXRsZT0iVmlzaWJsZSIgLz43aHR0cDovL3d3dy5nZW9jYWNoaW5nLmNvbS9pbWFnZXMvd3B0dHlwZXMvc20vcHV6emxlLmpwZxJRdWVzdGlvbiB0byBBbnN3ZXISUXVlc3Rpb24gdG8gQW5zd2VyAlNUAlNUBVNUQVJUtAE8YSBocmVmPSJodHRwOi8vd3d3Lmdlb2NhY2hpbmcuY29tL3NlZWsvd3B0LmFzcHg/V0lEPTA0MTEzYmFkLTY0Y2EtNDk5YS05ODQ4LWI1OTM3ZTEzZGExYiZSZWZJRD03MzI0NmE1YS1lYmI5LTRkNGYtOGRiOS1hOTUxMDM2ZjUzNzYmUmVmRFM9MSI+R0MyQ0pQRiBTdGFydDwvYT4gKFF1ZXN0aW9uIHRvIEFuc3dlcikcTiA1MsKwIDI1LjUwNCBFIDAwOcKwIDM5Ljg1MmQCBQ8PFgIfEQUERWRpdGRkAgcPDxYCHxEFA01hcGRkAgsPDxYCHxIFBlJlbW92ZRYCHwsFQHJldHVybiBjb25maXJtKCdBcmUgeW91IHN1cmUgeW91IHdhbnQgdG8gcmVtb3ZlIHRoaXMgd2F5cG9pbnQ/JylkAgwPFQIAAGQCBA9kFgxmDxUCDkFsdGVybmF0aW5nUm93BWZhbHNlZAICDxUJYjxpbWcgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2IiBzcmM9Ii9pbWFnZXMvaWNvbnMvaWNvbl92aWV3YWJsZS5qcGciIGFsdD0iVmlzaWJsZSIgdGl0bGU9IlZpc2libGUiIC8+OWh0dHA6Ly93d3cuZ2VvY2FjaGluZy5jb20vaW1hZ2VzL3dwdHR5cGVzL3NtL3dheXBvaW50LmpwZw9SZWZlcmVuY2UgUG9pbnQPUmVmZXJlbmNlIFBvaW50AldPAldPBlNDRU5JQ7IBPGEgaHJlZj0iaHR0cDovL3d3dy5nZW9jYWNoaW5nLmNvbS9zZWVrL3dwdC5hc3B4P1dJRD1iMjhjNTg3OS0zMTgxLTQ1MTAtOTRmYS02ZWM1ZTMwZmQwNTYmUmVmSUQ9NzMyNDZhNWEtZWJiOS00ZDRmLThkYjktYTk1MTAzNmY1Mzc2JlJlZkRTPTEiPkF1c3NpY2h0c3B1bmt0PC9hPiAoUmVmZXJlbmNlIFBvaW50KRxOIDUywrAgMjUuNDg4IEUgMDA5wrAgMzkuNDMyZAIFDw8WAh8RBQRFZGl0ZGQCBw8PFgIfEQUDTWFwZGQCCw8PFgIfEgUGUmVtb3ZlFgIfCwVAcmV0dXJuIGNvbmZpcm0oJ0FyZSB5b3Ugc3VyZSB5b3Ugd2FudCB0byByZW1vdmUgdGhpcyB3YXlwb2ludD8nKWQCDA8VAg5BbHRlcm5hdGluZ1Jvd09FaGVtYWxpZ2UgRmluYWxsb2NhdGlvbiB3byBlcyBnZWJyYW5udCBoYXQuIEdsZWljaHplaXRpZyBuZXR0ZXIgQXVzc2ljaHRzcHVua3QuZAJBDw8WAh8DZ2QWAgIBDw8WBB8FBSovbWFwL2RlZmF1bHQuYXNweD9sYXQ9NTIuNDI1MDY3JmxuZz05LjY2NDIfA2dkZAJFDw8WAh8FBRovc2Vlay9uZWFyZXN0LmFzcHg/dT1Ub20wM2RkAkcPDxYCHwUFGy9zZWVrL25lYXJlc3QuYXNweD91bD1Ub20wM2RkAkkPZBYKAgMPDxYCHwUFVS9zZWVrL25lYXJlc3QuYXNweD90eD1hNWY2ZDBhZC1kMmYyLTQwMTEtOGMxNC05NDBhOWViZjNjNzQmbGF0PTUyLjQyNTA2NyZsbmc9OS42NjQyMDBkZAIFDw8WAh8FBVkvc2Vlay9uZWFyZXN0LmFzcHg/dHg9YTVmNmQwYWQtZDJmMi00MDExLThjMTQtOTQwYTllYmYzYzc0JmxhdD01Mi40MjUwNjcmbG5nPTkuNjY0MjAwJmY9MWRkAgkPDxYCHwUFLS9zZWVrL25lYXJlc3QuYXNweD9sYXQ9NTIuNDI1MDY3JmxuZz05LjY2NDIwMGRkAgsPDxYCHwUFMS9zZWVrL25lYXJlc3QuYXNweD9sYXQ9NTIuNDI1MDY3JmxuZz05LjY2NDIwMCZmPTFkZAIPDw8WAh8FBUdodHRwOi8vd3d3LndheW1hcmtpbmcuY29tL2RpcmVjdG9yeS5hc3B4P2Y9MSZsYXQ9NTIuNDI1MDY3Jmxvbj05LjY2NDIwMGRkAkoPFgIfA2hkAkwPDxYCHwUFJS9yZXZpZXdzL2hvdGVscy1jb29yZHMtNTIuNDI1MSw5LjY2NDJkZAJOD2QWAgIBDw8WBB8BBZAHPGxpPjxhIGhyZWY9Imh0dHA6Ly93d3cuZ2VvY2FjaGluZy5jb20vbWFwL2RlZmF1bHQuYXNweD9sYXQ9NTIuNDI1MDY3JmxuZz05LjY2NDIiIHRhcmdldD0iX2JsYW5rIj5HZW9jYWNoaW5nLmNvbSBHb29nbGUgTWFwPC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHA6Ly9tYXBzLmdvb2dsZS5jb20vbWFwcz9xPU4rNTIlYzIlYjArMjUuNTA0K0UrMDA5JWMyJWIwKzM5Ljg1MisoR0MyQ0pQRikrIiB0YXJnZXQ9Il9ibGFuayI+R29vZ2xlIE1hcHM8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cDovL3d3dy5tYXBxdWVzdC5jb20vbWFwcy9tYXAuYWRwP3NlYXJjaHR5cGU9YWRkcmVzcyZmb3JtdHlwZT1sYXRsb25nJmxhdGxvbmd0eXBlPWRlY2ltYWwmbGF0aXR1ZGU9NTIuNDI1MDY3JmxvbmdpdHVkZT05LjY2NDImem9vbT0xMCIgdGFyZ2V0PSJfYmxhbmsiPk1hcFF1ZXN0PC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHA6Ly9tYXBzLnlhaG9vLmNvbS9tYXBzX3Jlc3VsdD9sYXQ9NTIuNDI1" />
+<input type="hidden" name="__VIEWSTATE2" id="__VIEWSTATE2" value="MDY3Jmxvbj05LjY2NDIiIHRhcmdldD0iX2JsYW5rIj5ZYWhvbyBNYXBzPC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHA6Ly93d3cuYmluZy5jb20vbWFwcy9kZWZhdWx0LmFzcHg/dj0yJnNwPXBvaW50LjUyLjQyNTA2N185LjY2NDJfR0MyQ0pQRiIgdGFyZ2V0PSJfYmxhbmsiPkJpbmcgTWFwczwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwOi8vd3d3Lm9wZW5jeWNsZW1hcC5vcmcvP3pvb209MTImbGF0PTUyLjQyNTA2NyZsb249OS42NjQyIiB0YXJnZXQ9Il9ibGFuayI+T3BlbiBDeWNsZSBNYXBzPC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHA6Ly93d3cub3BlbnN0cmVldG1hcC5vcmcvP21sYXQ9NTIuNDI1MDY3Jm1sb249OS42NjQyJnpvb209MTIiIHRhcmdldD0iX2JsYW5rIj5PcGVuIFN0cmVldCBNYXBzPC9hPjwvbGk+HwNnZGQCUA9kFgYCAQ8WAh8BBRA4MyBMb2dnZWQgVmlzaXRzZAIHDw8WAh8FBUN+L3NlZWsvY2FjaGVfbG9nYm9vay5hc3B4P2d1aWQ9NzMyNDZhNWEtZWJiOS00ZDRmLThkYjktYTk1MTAzNmY1Mzc2ZGQCCQ8PFgQfBQU9fi9zZWVrL2dhbGxlcnkuYXNweD9ndWlkPTczMjQ2YTVhLWViYjktNGQ0Zi04ZGI5LWE5NTEwMzZmNTM3Nh8BBSNWaWV3IHRoZSBJbWFnZSBHYWxsZXJ5IG9mIDE0IGltYWdlc2RkAlEPFgIfAQUEdHJ1ZWQCUg8WAh8BBUlsYXQ9NTIuNDI1MDY3OyBsbmc9OS42NjQyOyBndWlkPSc3MzI0NmE1YS1lYmI5LTRkNGYtOGRiOS1hOTUxMDM2ZjUzNzYnOw0KZAJTDxYCHwEFcXRyeSB7IF9nYXEucHVzaChbJ190cmFja0V2ZW50JywgJ0dlb2NhY2hpbmcnLCAnQ2FjaGVEZXRhaWxzTWVtYmVyVHlwZScsICdQcmVtaXVtJywgbnVsbCwgdHJ1ZV0pOyB9IGNhdGNoKGVycikgeyB9ZAItDxYCHwNoZAIuD2QWBAIBDxYCHwEFB0VuZ2xpc2hkAgMPFgIfDgIPFh5mD2QWAgIBDw8WCB4PQ29tbWFuZEFyZ3VtZW50BQVlbi1VUx4LQ29tbWFuZE5hbWUFDVNldFRlbXBMb2NhbGUfAQUHRW5nbGlzaB4QQ2F1c2VzVmFsaWRhdGlvbmhkZAIBD2QWAgIBDw8WCB8TBQVkZS1ERR8UBQ1TZXRUZW1wTG9jYWxlHwEFB0RldXRzY2gfFWhkZAICD2QWAgIBDw8WCB8TBQVmci1GUh8UBQ1TZXRUZW1wTG9jYWxlHwEFCUZyYW7Dp2Fpcx8VaGRkAgMPZBYCAgEPDxYIHxMFBXB0LVBUHxQFDVNldFRlbXBMb2NhbGUfAQUKUG9ydHVndcOqcx8VaGRkAgQPZBYCAgEPDxYIHxMFBWNzLUNaHxQFDVNldFRlbXBMb2NhbGUfAQUJxIxlxaF0aW5hHxVoZGQCBQ9kFgICAQ8PFggfEwUFc3YtU0UfFAUNU2V0VGVtcExvY2FsZR8BBQdTdmVuc2thHxVoZGQCBg9kFgICAQ8PFggfEwUFbmwtTkwfFAUNU2V0VGVtcExvY2FsZR8BBQpOZWRlcmxhbmRzHxVoZGQCBw9kFgICAQ8PFggfEwUFY2EtRVMfFAUNU2V0VGVtcExvY2FsZR8BBQdDYXRhbMOgHxVoZGQCCA9kFgICAQ8PFggfEwUFcGwtUEwfFAUNU2V0VGVtcExvY2FsZR8BBQZQb2xza2kfFWhkZAIJD2QWAgIBDw8WCB8TBQVldC1FRR8UBQ1TZXRUZW1wTG9jYWxlHwEFBUVlc3RpHxVoZGQCCg9kFgICAQ8PFggfEwUFbmItTk8fFAUNU2V0VGVtcExvY2FsZR8BBQ5Ob3JzaywgQm9rbcOlbB8VaGRkAgsPZBYCAgEPDxYIHxMFBWtvLUtSHxQFDVNldFRlbXBMb2NhbGUfAQUJ7ZWc6rWt7Ja0HxVoZGQCDA9kFgICAQ8PFggfEwUFZXMtRVMfFAUNU2V0VGVtcExvY2FsZR8BBQhFc3Bhw7FvbB8VaGRkAg0PZBYCAgEPDxYIHxMFBWh1LUhVHxQFDVNldFRlbXBMb2NhbGUfAQUGTWFneWFyHxVoZGQCDg9kFgICAQ8PFggfEwUFcm8tUk8fFAUNU2V0VGVtcExvY2FsZR8BBQhSb23Dom7Egx8VaGRkAgMPFgIfAQUrU2VydmVyOiBXRUIwMjsgQnVpbGQ6IFdlYi5Ib3RGaXhfMjAxMjAyMTMuNGRk1655JiA1P7FZXuMiqVUa4tv12I0=" />
+</div>
+
+<script type="text/javascript">
+//<![CDATA[
+var theForm = document.forms['aspnetForm'];
+if (!theForm) {
+ theForm = document.aspnetForm;
+}
+function __doPostBack(eventTarget, eventArgument) {
+ if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
+ theForm.__EVENTTARGET.value = eventTarget;
+ theForm.__EVENTARGUMENT.value = eventArgument;
+ theForm.submit();
+ }
+}
+//]]>
+</script>
+
+
+<script src="/WebResource.axd?d=Dh2VENdI9XyWNN0f7DnYfR8WWRCRIzdVqal2y0yjiQ5nC_eHhLchYgnQDHIk0d3RCcSUMVZ36ciRD0qmhXKmeu3S_RE1&t=634449413070371108" type="text/javascript"></script>
+
+
+<script src="/ScriptResource.axd?d=I9_m2Hb1Tv_B0qTMDG8bMbnkNSHUkv5oUaG9-V5NZ8qQ2VFlu60I8y8gfr3vPmZjbiPnu43MOQdFVDeYF-nDAEKBLmyxD3DCTGmes9NNbbvaDEHyEuuRWgccIkK3ik5TI48YGDxjHjqdn-gTK4Fkgd17LGw1&t=2610f696" type="text/javascript"></script>
+<script src="/ScriptResource.axd?d=8vNbe34dAujgZMPnfnacfjeoweX1vHgyns8KlAV4vpGpsZC9Cf3pro__lv8ekBa0NiCgXGMMolzOUNH__lrnEI_qjlNBIAuuLeemtAXV_i6E0QIMZa8nGSYmWGF5nQOJK3rmZzvTxsr2Mh4Ebdba_1ywGLUSH_U_XIe-jzecfRQwwvjZ0&t=2610f696" type="text/javascript"></script>
+<script src="/ScriptResource.axd?d=2jdNC2D7ot6lEFIEEJyYsOB9NSwVD5pdjWE2hpM8JhgGDEs_3zj3g0rJ9voFS7KLAH-Xe9jIZEeLZ4F0SZh_k1yfB7H2oxgLo3W8HwkqoAM6CTyvsrrAC6DYetsH1LLhhu8Cp-y2GGtVGeETjhtdngA9w7RKfkoa-NxeOXqAV-czoGhTf3xeYxhuZYV29YZj3Ax-Dv4_Au0l4_63VcimvxRXajk1" type="text/javascript"></script>
+<script src="/ScriptResource.axd?d=McH91wSR9oVNvyYD6Jh_rOa4m0RfzKuKVQ0t8QqGtHR6OPEN12p1eMHxh1hJom5pjb9g8WyfiSqnohH_KpKI15rPiYDzgdf5vMP3qDQ51FyzVQ-LOBQd20gPOn3DRK7_az8s5F3gI3sXQoPIXnlykFMypix1gDXdy0b5t3ANsiXlrCjA_4eslqBdKCYOy0iWV5SlfyS3yAV9lz5jBPGS8Zkg-tWFQohcChLQee3VS6l6ZDykIVMLsRgWVFWPrklSxJxMJkgrpD1VCxOdBB_NHIGUeQXMu0Ps9je8wOQ_Cb8NS9VGDPgzw6iQQ3g_KNEWthYIvkVRYTybcIStnZ4hXxyUBjM2UAJsB9d6D5IazMjKGXPr_HxSt-wu8XnpIiXeyrpTlKYVoeLejXRGdXXtEHt3OB0SQqCs7IXCrWbAenki_VLHoz5esmDp3sOOe_o2N1J6ajjj93C5fTmpI2VYYrFZhQvatw-uOJaB0FVyFi_W2wRSYyJmRJRwr1mKvz7eEkD6JWo4lpqKWzLvYBakOhTOrdejdk8j7BqSmrf0wA2D6v-8lpM53UR7gbLMdHrmjRGA7zqfapPmJnPW7v4_SjWL_IfIft5_0hFPdha4bnruJx76N5C588MriAohrBDM96Td2zO2zplDCkQ04kMnKUrdf9s_mzmzUP1drOpkcU-envXig2AY-1vb3IUc8wwr8ZACEFuCnUe53GxlrKzZhsFr388dhOOQr5w7XagSMB-5Yyet0" type="text/javascript"></script>
+<script src="js/cachedetails.js" type="text/javascript"></script>
+<script src="../js/latlng.js" type="text/javascript"></script>
+ <script type="text/javascript">
+//<![CDATA[
+Sys.WebForms.PageRequestManager._initialize('ctl00$uxMainScriptManager', 'aspnetForm', [], [], [], 90, 'ctl00');
+//]]>
+</script>
+
+ <div id="Top" class="SkipLinks">
+
+ <a id="ctl00_hlSkipLinksNavigation" accesskey="n" title="Skip to Navigation" href="#Navigation">Skip to Navigation</a>
+ <a id="ctl00_hlSkipLinksContent" accesskey="c" title="Skip to Content" href="#Content">Skip to Content</a>
+
+ </div>
+
+ <!--[if lte IE 6]>
+ <div class="WarningMessage PhaseOut">
+
+ <p>Groundspeak is phasing out support for older browsers. Visit the <a href="http://support.groundspeak.com/index.php?pg=kb.page&id=215" title="Browser Support Information">Help Center</a> for more information.</p>
+
+ </div>
+ <![endif]-->
+
+
+
+ <div class="PrintOnly">
+
+ <p>
+ <img src="/images/logo_print_bw.png" alt="Geocaching.com" /></p>
+ <hr />
+
+ </div>
+
+ <header>
+
+ <div class="container">
+
+ <h1 class="Logo span-16">
+ <a href="../default.aspx" id="ctl00_HDHomeLink" title="Geocaching" accesskey="h">Geocaching</a></h1>
+ <div class="ProfileWidget span-8 last">
+
+
+
+ <div id="ctl00_divSignedIn">
+
+ <p class="Avatar NoBottomSpacing">
+ <a id="ctl00_hlHeaderAvatar" accesskey="p" title="Your Profile" href="../my/default.aspx"><img title="Your Profile" src="http://img.geocaching.com/user/avatar/50f83123-27d8-4dcf-9fde-2af006efaf2b.jpg" alt="" style="border-width:0px;" /></a></p>
+ <p class="SignedInText">
+ <strong>
+ Hello, <a href="/my/default.aspx" title="View Profile for blafoo" class="SignedInProfileLink">blafoo</a></strong> (<a id="ctl00_hlSignOut" accesskey="s" title="Sign Out" href="https://www.geocaching.com/login/default.aspx?RESET=Y&redir=http%3a%2f%2fwww.geocaching.com%2fseek%2fcache_details.aspx%3flog%3dy%26wp%3dGC2CJPF%26numlogs%3d35%26decrypt%3dy">Sign Out</a>)<br />
+ <strong>
+ <img src="/images/icons/icon_smile.png" title="Caches Found" /> 513 · <img src="/images/challenges/types/sm/challenge.png" title="Challenges Completed" /> 2</strong>
+
+ <a id="ctl00_hlRenew" accesskey="a" title="Renew Your Membership!" href="../account/EditMembership.aspx" style="display: block;">Renew Your Membership!</a>
+ </p>
+
+ </div>
+
+
+ </div>
+
+ <nav id="Navigation" class="span-24 last">
+
+ <ul class="Menu">
+ <li>
+ <a id="ctl00_hlNavLearn" accesskey="1" title="Learn" href="../guide/default.aspx">Learn ▼</a>
+ <ul class="SubMenu">
+ <li>
+ <a id="ctl00_hlSubNavGeocaching101" accesskey="i" title="Geocaching 101" href="../guide/default.aspx">Geocaching 101</a></li>
+ <li>
+ <a id="ctl00_hlSubNavGeocaching2Minutes" title="Geocaching in 2 Minutes" href="../videos/default.aspx#cat=cat:newbies&vid=-4VFeYZTTYs">Geocaching in 2 Minutes</a></li>
+ </ul>
+ </li>
+
+ <li id="ctl00_liNavProfile">
+ <a id="ctl00_hlNavProfile" accesskey="2" title="Your Profile" title="[Your Profile ▼]" href="../my/default.aspx">Your Profile ▼</a>
+ <ul class="SubMenu">
+ <li>
+ <a id="ctl00_hlSubNavQuickView" accesskey="p" title="Quick View" href="../my/default.aspx">Quick View</a></li>
+ <li>
+ <a id="ctl00_hlSubNavLists" accesskey="q" title="Lists" href="../my/lists.aspx">Lists</a></li>
+ <li class="ExtraText">
+ <a id="ctl00_hlSubNavGeocaches" accesskey="m" title="Geocaches" class="NoRightPadding" href="../my/geocaches.aspx">Geocaches</a>
+ (<a id="ctl00_hlSubNavGeocachesYours" accesskey="y" title="Yours" class="NoSidePadding" href="../my/owned.aspx">Yours</a>)</li>
+ <li class="ExtraText">
+ <a id="ctl00_hlSubNavProfileTrackables" title="Trackables" class="NoRightPadding" href="../my/travelbugs.aspx">Trackables</a>
+ (<a id="ctl00_hlSubNavTrackablesYours" accesskey="8" title="Yours" class="NoSidePadding" href="../track/search.aspx?o=1&uid=0564a940-8311-40ee-8e76-7e91b2cf6284">Yours</a>)</li>
+ <li>
+ <a id="ctl00_hlSubNavPocketQueries" accesskey="9" title="Pocket Queries" href="../pocket/default.aspx">Pocket Queries</a></li>
+ <li>
+ <a id="ctl00_hlSubNavFieldNotes" accesskey="0" title="Field Notes" href="../my/fieldnotes.aspx">Field Notes</a></li>
+ <li>
+ <a id="ctl00_hlSubNavProfileChallenges" title="Challenges" href="../my/challenges.aspx">Challenges</a></li>
+ <li>
+ <a id="ctl00_hlSubNavAccount" accesskey="a" title="Account Details" href="../account/default.aspx">Account Details</a></li>
+ </ul>
+ </li>
+ <li>
+ <a id="ctl00_hlNavPlay" accesskey="3" title="Play" href="default.aspx">Play ▼</a>
+ <ul class="SubMenu">
+ <li>
+ <a id="ctl00_hlSubNavHide" accesskey="d" title="Hide & Seek a Cache" href="default.aspx">Hide & Seek a Cache</a></li>
+ <li>
+ <a id="ctl00_hlSubNavLogCache" title="Log a Cache" href="../my/recentlyviewedcaches.aspx">Log a Cache</a></li>
+ <li>
+ <a id="ctl00_hlSubNavChallenges" title="Find Challenges" href="../challenges/default.aspx">Find Challenges</a></li>
+ <li>
+ <a id="ctl00_hlSubNavTrackables" accesskey="e" title="Find Trackables" href="../track/default.aspx">Find Trackables</a></li>
+ <li>
+ <a id="ctl00_hlSubNavHelpCenter" title="Help Center" rel="external" href="http://support.groundspeak.com/index.php">Help Center</a></li>
+ </ul>
+ </li>
+ <li>
+ <a id="ctl00_hlNavCommunity" accesskey="6" title="Community" href="../forums/default.aspx">Community ▼</a>
+ <ul class="SubMenu">
+
+ <li>
+ <a id="ctl00_hlSubNavTellaFriend" accesskey="-" title="Tell a Friend" href="../account/SendReferral.aspx">Tell a Friend</a></li>
+
+ <li>
+ <a id="ctl00_hlSubNavLocal" accesskey="z" title="Local Organizations" href="../organizations/default.aspx">Local Organizations</a></li>
+ <li>
+ <a id="ctl00_hlSubNavDiscussionForums" accesskey="f" title="Discussion Forums" href="../forums/default.aspx">Discussion Forums</a></li>
+ <li>
+ <a id="ctl00_hlSubNavBlog" accesskey="b" title="Blog" rel="external" href="http://blog.geocaching.com/">Blog</a></li>
+ <li>
+ <a id="ctl00_hlSubNavEvents" accesskey="v" title="Events" href="../calendar/default.aspx">Events</a></li>
+ </ul>
+ </li>
+ <li>
+ <a id="ctl00_hlNavShop" accesskey="4" title="Shop" href="http://shop.geocaching.com/">Shop ▼</a>
+ <ul class="SubMenu">
+ <li>
+ <a id="ctl00_hlSubNavShop" accesskey="j" title="Shop Geocaching" rel="external" href="http://shop.geocaching.com/">Shop Geocaching</a></li>
+ <li>
+ <a id="ctl00_hlSubNavIntlRetailers" title="International Retailers" rel="external" href="http://shop.geocaching.com/default/international-retailers/">International Retailers</a></li>
+ <li>
+ <a id="ctl00_hlSubNavGPSReviews" accesskey="w" title="GPS Reviews" href="/reviews/gps">GPS Reviews</a></li>
+ <li>
+ <a id="ctl00_hlSubNavGPSGuide" accesskey="k" title="Guide to Buying a GPS Device" href="../about/buying.aspx">Guide to Buying a GPS Device</a></li>
+ </ul>
+ </li>
+ <li>
+ <a id="ctl00_hlNavPartnering" accesskey="5" title="Partnering" href="../travel/default.aspx">Partnering ▼</a>
+ <ul class="SubMenu">
+ <li>
+ <a id="ctl00_hlSubNavTravel" title="Travel and Tourism" href="../travel/default.aspx">Travel and Tourism</a></li>
+ <li>
+ <a id="ctl00_hlSubNavBrandedPromotions" title="Branded Promotions" href="../brandedpromotions/default.aspx">Branded Promotions</a></li>
+ <li>
+ <a id="ctl00_hlSubNavEducation" title="Geocaching and Education" href="../education/default.aspx">Geocaching and Education</a></li>
+ <li>
+ <a id="ctl00_hlSubNavAdvertisingWithUs" title="Advertising with Us" href="../about/advertising.aspx">Advertising with Us</a></li>
+ <li>
+ <a id="ctl00_hlSubNavAPIProgram" title="API Program" href="../live/default.aspx">API Program</a></li>
+ </ul>
+ </li>
+ <li>
+ <a id="ctl00_hlNavVideos" accesskey="7" title="Videos" href="../videos/default.aspx">Videos</a></li>
+ </ul>
+ <p class="SocialMediaIcons NoBottomSpacing right">
+ <a id="ctl00_hlFacebook" title="Follow Us on Facebook" href="http://www.facebook.com/pages/Geocachingcom/45625464679?ref=ts"><img id="ctl00_imgFacebook" title="Follow Us on Facebook" src="../images/home/icon_facebook.png" alt="Follow Us on Facebook" style="border-width:0px;" /></a> <a id="ctl00_hlTwitter" title="Follow Us on Twitter" href="http://twitter.com/GoGeocaching"><img id="ctl00_imgTwitter" title="Follow Us on Twitter" src="../images/home/icon_twitter.png" alt="Follow Us on Twitter" style="border-width:0px;" /></a> <a id="ctl00_hlFlickr" title="Follow Us on Flickr" href="http://www.flickr.com/photos/geocaching_com/"><img id="ctl00_imgFlickr" title="Follow Us on Flickr" src="../images/home/icon_flickr.png" alt="Follow Us on Flickr" style="border-width:0px;" /></a> <a id="ctl00_hlYouTube" title="Follow Us on YouTube" href="http://www.youtube.com/user/GoGeocaching"><img id="ctl00_imgYouTube" title="Follow Us on YouTube" src="../images/home/icon_youtube.png" alt="Follow Us on YouTube" style="border-width:0px;" /></a></p>
+
+ </nav>
+
+ </div>
+
+
+ </header>
+ <section id="Content">
+
+
+ <div class="container">
+
+ <div id="ctl00_divBreadcrumbs" class="BreadcrumbWidget span-24 last">
+
+ <p>
+ <span id="ctl00_Breadcrumbs"><span><a title="Geocaching - The Official Global GPS Cache Hunt Site" href="/">Geocaching</a></span><span> > </span><span><a title="Hide and Seek A Geocache" href="/seek/default.aspx">Hide and Seek A Geocache</a></span><span> > </span><span>Geocache Details</span></span>
+ </p>
+
+ </div>
+
+ <div id="ctl00_divContentMain" class="span-24 last">
+
+
+
+
+ <div id="ctl00_ContentBody_CoordInfoLinkControl1_uxCoordInfoLinkPanel" class="CoordInfoLinkWidget">
+
+ <p>
+ <a href="#" class="CoordInfoLink">
+ <span id="ctl00_ContentBody_CoordInfoLinkControl1_uxCoordInfoCode" class="CoordInfoCode">GC2CJPF</span>
+ <span class="arrow">▼</span> </a>
+ </p>
+
+</div>
+<div id="dlgClipboard">
+ <input type="text" class="TextFormat" />
+ <a href="#" onclick="$('#dlgClipboard').hide();return false;">
+ <img src="/images/stockholm/mini/close.gif" alt="Close" title="Close" /></a>
+</div>
+
+<script type="text/javascript">
+ $("a.CoordInfoLink").click(function (e) {
+ e.preventDefault();
+
+ $("#dlgClipboard")
+ .show()
+ .position({
+ of: $("a.CoordInfoLink"),
+ my: "right top",
+ at: "right bottom",
+ offset: "0 5"
+ })
+ .find("input")
+ .val('http://coord.info/' + $('.CoordInfoCode').text())
+ .focus()
+ .select();
+
+ });
+
+ $(document).mouseup(function (e) {
+ if ($(e.target).parent("div#dlgClipboard").length == 0) {
+ $("div#dlgClipboard").hide();
+ }
+ });
+</script>
+
+ <div class="span-17">
+
+ <div class="span-17 last BottomSpacing" id="cacheDetails">
+ <p class="cacheImage">
+ <a href="/about/cache_types.aspx" target="_blank" title="About Cache Types"><img src="/images/WptTypes/3.gif" alt="Multi-cache" title="Multi-cache" width="32" height="32" /></a>
+ </p>
+
+ <h2 class="NoBottomSpacing">
+ <span id="ctl00_ContentBody_CacheName">Kinderwald KiC</span></h2>
+ <span class="minorCacheDetails">
+ A
+ cache
+ by <a href="http://www.geocaching.com/profile/?guid=9a28b2fb-bce9-481f-87bc-7c5f4bafe723&wid=73246a5a-ebb9-4d4f-8db9-a951036f5376&ds=2">Tom03</a></span> <span class="minorCacheDetails">
+ Hidden
+ :
+ 31/07/2010</span>
+
+ </div>
+ <div class="CacheStarLabels span-3 BottomSpacing">
+
+ Difficulty:
+ <br />
+ Terrain:
+
+ </div>
+
+ <div class="CacheStarImgs span-2">
+
+ <span id="ctl00_ContentBody_uxLegendScale" title="(1 is easiest, 5 is hardest)"><img src="http://www.geocaching.com/images/stars/stars2_5.gif" alt="2.5 out of 5" /></span>
+ <span id="ctl00_ContentBody_Localize12" title="(1 is easiest, 5 is hardest)"><img src="http://www.geocaching.com/images/stars/stars2.gif" alt="2 out of 5" /></span>
+
+ </div>
+
+ <div class="CacheSize span-9">
+
+ <p style="text-align: center;">
+ Size: <span class="minorCacheDetails"><img src="/images/icons/container/small.gif" alt="Size: Small" title="Size: Small" /> <small>(Small)</small></span></p>
+
+ </div>
+
+ <div class="span-3 right last">
+
+
+ <div class="favorite" class="right">
+ <a id="uxFavContainerLink" href="javascript:void(0);">
+ <div class="favorite-container">
+ <span class="favorite-value">
+ 7</span><br />
+ Favorites
+ <img id="imgFavoriteArrow" src="/images/arrow-down.png" alt="Expand" title="Expand" />
+ </div>
+ </a>
+ <div class="favorite-dropdown">
+ <dl class="top">
+ <dt>
+ <img id="imgFavoriteScore" src="/images/loading3.gif" width="20" height="20" alt="Loading" title="Loading" /></dt>
+ <dd>
+ <span id="uxFavoriteScore"> </span></dd>
+ </dl>
+ <dl class="bottom">
+ <dt>
+ <img src="/images/silk/group_go.png" alt="View Who Favorited this Cache" title="View Who Favorited this Cache" /></dt>
+ <dd>
+ <a id="hlViewWhoFavorited" title="View Who Favorited this Cache" href="/seek/cache_favorited.aspx?guid=73246a5a-ebb9-4d4f-8db9-a951036f5376">View Who Favorited this Cache</a></dd>
+ <dt>
+ <img src="/images/silk/help.png" alt="About Favorites" title="About Favorites" /></dt>
+ <dd>
+ <a id="hlAboutFavorites" title="About Favorites" href="http://support.groundspeak.com/index.php?pg=kb.page&id=287" target="_blank">About Favorites</a>
+ </dd>
+ </dl>
+ </div>
+ </div>
+
+
+ </div>
+
+ <p class="Clear">
+ <a id="ctl00_ContentBody_uxCacheUrl" title="Related Web Page" href="http://www.kinderwald.de/">Related Web Page</a></p>
+
+
+
+
+ <div class="CacheInformationTable">
+ <div class="LocationData FloatContainer">
+ <div class="span-9">
+ <p class="NoBottomSpacing">
+ <a href="#" class="edit-cache-coordinates" id="uxLatLonLink" title="Correct these coordinates">
+ <span id="uxLatLon" style="font-weight:bold;">N 52° 25.504 E 009° 39.852</span>
+ </a>
+ <br />
+ <span id="ctl00_ContentBody_LocationSubPanel" style="display:inline;"><small>
+ UTM: 32U E 545164 N 5808524</small>
+ <br />
+ </span><small>
+ <a id="ctl00_ContentBody_lnkConversions" title="Other Conversions" href="/wpt/?lat=52.425067&lon=9.6642&detail=1" target="_blank">Other Conversions</a>
+ </small>
+ </p>
+ </div>
+ <div class="span-7 last AlignRight">
+ <span id="ctl00_ContentBody_Location">In Niedersachsen, Germany</span><br />
+ <span id="lblDistFromHome"><img src="/images/icons/compass/E.gif" alt="E" style="vertical-align:text-bottom" /> E 4.8 km from your home location</span>
+ </div>
+ </div>
+ <div id="Print">
+ <p class="NoBottomSpacing">
+ <span id="ctl00_ContentBody_uxPrintHeader" style="font-weight:bold;">Print</span>:
+ <br />
+ <small>
+ <a id="ctl00_ContentBody_lnkPrintFriendly" class="lnk" href="cdpf.aspx?guid=73246a5a-ebb9-4d4f-8db9-a951036f5376" target="_blank">
+ <img src="/images/silk/printer.png" alt="Print" title="Print" width="16" height="16" /> <span>
+ No Logs
+ </span>
+ </a>
+ <a id="ctl00_ContentBody_lnkPrintFriendly5Logs" href="cdpf.aspx?guid=73246a5a-ebb9-4d4f-8db9-a951036f5376&lc=5" target="_blank">5 Logs</a>
+ <a id="ctl00_ContentBody_lnkPrintFriendly10Logs" href="cdpf.aspx?guid=73246a5a-ebb9-4d4f-8db9-a951036f5376&lc=10" target="_blank">10 Logs</a> ·
+ <a id="ctl00_ContentBody_lnkPrintDirectionsSimple" class="lnk" href="http://maps.google.com/maps?f=d&hl=en&saddr=52.4162,9.594117 (Home Location)&daddr=52.425067,9.6642(Kinderwald+KiC)" target="_blank">
+ <img src="/images/silk/car.png" alt="Driving Directions" title="Driving Directions" width="16" height="16" /> <span>
+ Driving Directions
+ </span>
+ </a></small></p>
+ <div id="ctl00_ContentBody_uxPrintPDFSection" style="display: none;">
+ <p>
+ <img src="/images/pdf_icon.gif" width="16" height="16" alt="PDF" title="PDF" /> <small>[PDF:] <a id="ctl00_ContentBody_lnkPDFPrintNoLogs" href="javascript:pl(0);">No Logs</a> <a id="ctl00_ContentBody_lnkPDFPrint5Logs" href="javascript:pl(5);">5 Logs</a> <a id="ctl00_ContentBody_lnkPDFPrint10Logs" href="javascript:pl(10);">10 Logs</a></small></p>
+ </div>
+ </div>
+ <div id="Download">
+ <p class="NoBottomSpacing">
+ <span id="ctl00_ContentBody_uxDownloadLabel" style="font-weight:bold;">Download</span>:
+ <small>
+ <a id="ctl00_ContentBody_lnkDownloads" title="Read about waypoint downloads" href="/software/default.aspx">Read about waypoint downloads</a>
+ </small>
+ </p>
+
+ <p class="NoBottomSpacing TopSpacing">
+ <input type="submit" name="ctl00$ContentBody$btnLocDL" value="LOC waypoint file" id="ctl00_ContentBody_btnLocDL" />
+ |
+ <input type="submit" name="ctl00$ContentBody$btnGPXDL" value="GPX file" id="ctl00_ContentBody_btnGPXDL" />
+ |
+ <input type="submit" name="ctl00$ContentBody$btnSendToGPS" value="Send to My GPS" onclick="s2gps('73246a5a-ebb9-4d4f-8db9-a951036f5376');return false;" id="ctl00_ContentBody_btnSendToGPS" />
+ |
+ <input type="submit" name="ctl00$ContentBody$btnSendToPhone" value="Send to My Phone" onclick="s2phone('GC2CJPF');return false;" id="ctl00_ContentBody_btnSendToPhone" />
+ </p>
+
+ </div>
+ </div>
+
+ <fieldset class="DisclaimerWidget">
+ <legend class="warning">
+ Please note
+ </legend>
+ <p class="NoBottomSpacing">
+ Use of geocaching.com services is subject to the terms and conditions <a href="/about/disclaimer.aspx" title="Read Our Disclaimer">in our disclaimer</a>.
+ </p>
+ </fieldset>
+
+
+ <fieldset class="NotesWidget">
+ <legend class="note">
+ Personal Cache Note
+ </legend>
+ <img src="/images/silk/help.png" id="pcn_help" class="CacheNoteHelpImg" />
+ <p id="cache_note" class="NoBottomSpacing">
+ </p>
+ </fieldset>
+
+ <div class="UserSuppliedContent">
+
+ <span id="ctl00_ContentBody_ShortDescription">Von Nachwuchs-Cachern für Nachwuchs-Cacher.
+</span>
+
+ </div>
+
+ <br />
+ <div class="UserSuppliedContent">
+
+ <span id="ctl00_ContentBody_LongDescription">Kleiner Multi über 7 Stationen. Länge ca. 1 km + 1km für den Rückweg. Die ZS befinden sich alle am KLEINEN BACH innerhalb des Kinderwaldes. Die Fragen müssen nicht in der aufgeführten Reihenfolge beantwortet werden, ihr könnt auch mit der letzten Frage anfangen !<br />
+<br />
+Nähere Infos zum Kinderwald gibt es unter <a href="http://www.kinderwald.de/" target="_blank" rel="nofollow">www.kinderwald.de</a><br />
+<br />
+A. Am Start findet ihr einige Tiere. Wieviele blau-gelbe Punkte hat die grüne Eidechse ?<br />
+<br />
+B. Folgt dem Weg in Richtung Norden und biegt hinter der Brücke gleich links ab. Nach ein paar Metern<br />
+könnt ihr auf der rechten Seite mehrere Tipis sehen, an denen ihr aber vorbei geht. Überquert nun nach ein paar Metern links die Brücke und gelangt auf die kleine Insel wo das Wasser gestaut wird.<br />
+Auf der Insel könnt ihr beim großen Zelt einen "Marterpfahl" finden, dort seht ihr eine (lachende) Blume mit roten Blättern. Wieviele Blätter hat die Blume ?<br />
+<br />
+C. Verlasst die Insel. Auf dem Weg zur nächsten Station kommt ihr in der Kurve an einem großen, allein stehenden Baum vorbei. Was für ein Baum ist das (fünf Buchstaben) ? Hier wird der Buchstabenwert (A=1, B=2,...) des Anfangsbuchstaben benötigt. Evtl. könnt ihr noch die Traumfänger erkennen.<br />
+<br />
+D. Folgt dem Weg ein Stück. Ihr kommt nach kurzer Zeit zum Plumpsklo, der ehemaligen Villa Kunterbunt. Netterweise hat jemand meinen Namen am Eingang hingeschrieben.... Wieviele Personen können das Klo gleichzeitig benutzen ?<br />
+<br />
+E. Weiter geht es. Links findet ihr eine weitere (bunte) Brücke. Dort sind wieviele Kindergesichter zu finden ?<br />
+<br />
+F. Nach ca. 200 Metern kommt ihr zur Seilfähre. An der Seilfähre findet ihr die Antwort (GC= ?)<br />
+<br />
+G. Gegenüber der Seilfähre befindet sich ein Schaukasten mit Nisthilfen für Insekten. Wieviele rote, parallel zum Boden verlaufende Dachträger hat das Dach ?<br />
+<br />
+H. Nach weiteren 250 Metern gelangt ihr zur Schafherde. Aus wievielen Mitgliedern besteht die Schafherde ?<br />
+<br />
+Das Final könnt ihr nun unter<br />
+<br />
+N 52° 2A.(D+F)CE / E 009° 3(B+1).(F+1)E(G-1) finden.<br />
+<br />
+Kontrolle: Die Quersumme von ABCDEFGH beträgt 40.<br />
+<br />
+Die, die sich die Seilfähre nicht zutrauen (oder sie gerade nicht da ist), berechnen F. folgendermaßen:<br />
+<br />
+F=H+A-B-C<br />
+<br />
+Über Fotos würde ich mich freuen !<br />
+<br />
+Viel Spaß !<br />
+<br />
+P.S. An warmen Tagen Badesachen und Handtuch mitnehmen.</span>
+
+ </div>
+
+ <p>
+
+
+ </p>
+ <p>
+ <strong>
+ Additional Hints</strong>
+ (<a id="ctl00_ContentBody_lnkDH" onclick="dht(this);return false;" title="Decrypt" href="#">Encrypt</a>)</p>
+ <div id="div_hint" class="span-8 WrapFix">
+ Das Final ist unter Steinen</div>
+ <div id='dk' style="display: block;" class="span-9 last">
+ <span id="ctl00_ContentBody_EncryptionKey" class="right"></span>
+ </div>
+ <div class="Clear">
+ </div>
+
+ </div>
+
+
+ <div class="span-6 prepend-1 last">
+
+
+<div class="CacheDetailNavigationWidget NoPrint">
+
+ <h3 class="WidgetHeader">
+ <img id="ctl00_ContentBody_GeoNav2_uxHeaderImage" src="../images/stockholm/16x16/home.gif" alt="Navigation" style="border-width:0px;" />
+ Navigation
+ </h3>
+ <div class="WidgetBody">
+
+ <ul class="CacheDetailsNavLinks">
+ <li><a href="/seek/log.aspx?ID=1811409" class="lnk"><img src="/images/stockholm/16x16/comment_add.gif" /> <span>Log your visit</span></a></li>
+<li><a href="/seek/gallery.aspx?guid=73246a5a-ebb9-4d4f-8db9-a951036f5376" class="lnk"><img src="/images/stockholm/16x16/photos.gif" /> <span>View Gallery</span></a></li>
+<li><a href="/my/watchlist.aspx?w=1811409" class="lnk"><img src="/images/stockholm/16x16/icon_watchlist.gif" /> <span>Watch Listing</span></a></li>
+<li><a href="/bookmarks/ignore.aspx?guid=73246a5a-ebb9-4d4f-8db9-a951036f5376&WptTypeID=3" class="lnk"><img src="/images/stockholm/16x16/cross.gif" /> <span>Ignore Listing</span></a></li>
+<li><a href="/bookmarks/mark.aspx?guid=73246a5a-ebb9-4d4f-8db9-a951036f5376&WptTypeID=3" class="lnk"><img src="/images/stockholm/16x16/book_open_mark.gif" /> <span>Bookmark Listing</span></a></li>
+
+ </ul>
+
+ </div>
+
+
+</div>
+
+
+ <div class="StatusInformationWidget FavoriteWidget" style="font-size: 85%;">
+ <div id="pnlFavoriteCache">
+
+ <p>
+ <a href="javascript:void(0);" id="remove_from_favorites">
+ <img src="/images/icons/icon_favDelete.png" alt="Remove from your Favorites" title="Remove from your Favorites" />Remove from your Favorites</a>
+ </p>
+
+</div><div id="pnlNonfavoriteCache" class="hideMe">
+
+ <p>
+ <a href="javascript:void(0);" id="add_to_favorites">
+ <img src="/images/icons/icon_favAdd.png" alt="Add to your Favorites" title="Add to your Favorites" />Add to your Favorites</a></p>
+
+</div>
+ <p>
+ <span class="favorite-rank Clear">
+ 22
+ </span>
+ <a id="ctl00_ContentBody_hlFavoritePointsRemaining" href="/my/favorites.aspx">Favorite points remaining</a>
+ </p>
+ </div>
+
+ <div id="ctl00_ContentBody_uxStatusInformation" class="StatusInformationWidget">
+
+
+
+ <p>
+ <a id="ctl00_ContentBody_hlFoundItLog" href="/seek/log.aspx?LUID=7c6f0891-7003-4ae5-9231-c2e417d1c5e4">
+ <img src="/images/stockholm/16x16/check.gif" alt="Found It" title="Found It" />You logged this as Found on 19/08/2010.</a></p>
+
+ <div id="ctl00_ContentBody_pnlWatchedCount">
+
+ <p>
+ <img src="/images/icons/icon_watchlist.gif" alt="Watching" /> 2 user(s) watching this cache.</p>
+
+ </div>
+
+
+</div>
+
+ <p class="TopSpacing">
+
+ <div id="map_preview_canvas" style="border: solid 1px #B0B0B0; width: 228px; height: 175px;">
+ </div>
+
+ </p>
+
+
+ <div class="CacheDetailNavigationWidget BottomSpacing">
+
+ <h3 class="WidgetHeader">
+
+ <img src="/images/icon_Boardattention.gif" height="16" width="16" alt="Info" title="Info" />
+ Attributes</h3>
+ <div class="WidgetBody">
+ <img src="/images/attributes/motorcycles-no.gif" alt="no motorcycles" title="no motorcycles" width="30" height="30" /> <img src="/images/attributes/wheelchair-no.gif" alt="not wheelchair accessible" title="not wheelchair accessible" width="30" height="30" /> <img src="/images/attributes/winter-yes.gif" alt="available in winter" title="available in winter" width="30" height="30" /> <img src="/images/attributes/available-yes.gif" alt="available 24-7" title="available 24-7" width="30" height="30" /> <img src="/images/attributes/wading-yes.gif" alt="may require wading" title="may require wading" width="30" height="30" /> <img src="/images/attributes/scenic-yes.gif" alt="scenic view" title="scenic view" width="30" height="30" /> <img src="/images/attributes/onehour-yes.gif" alt="takes less than 1 hour" title="takes less than 1 hour" width="30" height="30" /> <img src="/images/attributes/kids-yes.gif" alt="kid friendly" title="kid friendly" width="30" height="30" /> <img src="/images/attributes/bicycles-yes.gif" alt="bikes allowed" title="bikes allowed" width="30" height="30" /> <img src="/images/attributes/dogs-yes.gif" alt="dogs allowed" title="dogs allowed" width="30" height="30" /> <img src="/images/attributes/attribute-blank.gif" alt="blank" title="blank" width="30" height="30" /> <img src="/images/attributes/attribute-blank.gif" alt="blank" title="blank" width="30" height="30" /> <p class="NoBottomSpacing"><small><a href="/about/icons.aspx" title="What are Attributes?">What are Attributes?</a></small></p>
+ </div>
+
+ </div>
+
+
+ <div id="ctl00_ContentBody_uxBanManWidget" class="CacheDetailPageAds clear">
+
+ <div id="ctl00_ContentBody_divContentSide">
+
+ <p class="NoBottomSpacing">
+ <span id="ctl00_ContentBody_ADModules_09"><iframe type="iframe" src="http://ads.groundspeak.com/a.aspx?ZoneID=9&Task=Get&SiteID=1&X='e82a2d535eaf44eab3f3cd3e00218e6a'" width="120" height="240" Marginwidth="0" Marginheight="0" Hspace="0" Vspace="0" Frameborder="0" Scrolling="no" style="width:120px;Height:240px;"><a href="http://ads.groundspeak.com/a.aspx?ZoneID=9&Task=Click&;Mode=HTML&SiteID=1" target="_blank"><img src="http://ads.groundspeak.com/a.aspx?ZoneID=9&Task=Get&Mode=HTML&SiteID=1" width="120" height="240" border="0" alt="" /></a></iframe></span>
+ </p>
+ <p class="AlignCenter">
+ <small><a href="../about/advertising.aspx" id="ctl00_ContentBody_advertisingWithUs" title="Advertising with Us">Advertising with Us</a></small></p>
+
+ </div>
+
+</div>
+
+
+
+ <div class="GoogleAds AlignCenter BottomSpacing">
+ </div>
+ <div class="clear">
+ </div>
+
+ <span id="ctl00_ContentBody_lnkTravelBugs"></span>
+
+
+<div class="CacheDetailNavigationWidget">
+
+ <h3 class="WidgetHeader">
+ <img id="ctl00_ContentBody_uxTravelBugList_uxInventoryIcon" src="../images/WptTypes/sm/tb_coin.gif" alt="Inventory" style="height:16px;width:16px;border-width:0px;" />
+ <span id="ctl00_ContentBody_uxTravelBugList_uxInventoryLabel">Inventory</span>
+ </h3>
+ <div class="WidgetBody">
+
+
+ <ul>
+
+ <li>
+ <a href="http://www.geocaching.com/track/details.aspx?guid=4c3bb296-4c30-4657-b110-b7370dfaf54d" class="lnk">
+ <img src="http://www.geocaching.com/images/wpttypes/sm/21.gif" width="16" /><span>Traveling Brutus Buckeye</span></a>
+ </li>
+
+ </ul>
+
+
+ <div class="TopSpacing">
+ <div id="ctl00_ContentBody_uxTravelBugList_uxTrackableItemsLinks">
+
+ <p class="NoBottomSpacing"><a id="ctl00_ContentBody_uxTravelBugList_uxViewAllTrackableItems" href="../track/search.aspx?wid=73246a5a-ebb9-4d4f-8db9-a951036f5376&ccid=1811409">View all Trackables</a></p>
+
+</div>
+ <p class="NoBottomSpacing"><a id="ctl00_ContentBody_uxTravelBugList_uxTrackableItemsHistory" href="../track/search.aspx?wid=73246a5a-ebb9-4d4f-8db9-a951036f5376">View past Trackables</a></p>
+ <p class="NoBottomSpacing"><a id="ctl00_ContentBody_uxTravelBugList_uxWhatAreTrackables" title="What are Trackable Items?" href="../track/default.aspx">What are Trackable Items?</a></p>
+ </div>
+
+
+ </div>
+
+
+</div>
+
+
+<div class="CacheDetailNavigationWidget">
+
+ <h3 class="WidgetHeader">
+ <img src="/images/stockholm/16x16/pages.gif" width="16" height="16" alt="" /> Bookmark Lists</h3>
+ <div class="WidgetBody">
+
+
+ <ul>
+
+ <li style='padding: .5em;' class=''>
+ <a href="http://www.geocaching.com/bookmarks/view.aspx?guid=3eeea057-f605-485a-a45a-f5fea1426612">
+ Kindercaches (KiC)</a><br />
+ <small><em>
+ by
+ <a href="http://www.geocaching.com/profile/?guid=0564a940-8311-40ee-8e76-7e91b2cf6284">
+ blafoo</a> </em></small>
+ </li>
+
+ </ul>
+
+ <p class="NoBottomSpacing">
+ <a href="/bookmarks/default.aspx?guid=73246a5a-ebb9-4d4f-8db9-a951036f5376&WptTypeID=3" title="View all bookmark lists...">View all bookmark lists...</a>
+ </p>
+
+ </div>
+
+
+</div>
+
+
+
+
+<div class="CacheDetailNavigationWidget">
+
+ <h3 class="WidgetHeader">
+ <img src="/images/stockholm/16x16/pages.gif" width="16" height="16" alt="" /> My Bookmark Lists</h3>
+ <div class="WidgetBody">
+
+
+ <ul>
+
+ <li style='padding: .5em;' class=''>
+ <a href="http://www.geocaching.com/bookmarks/view.aspx?guid=3eeea057-f605-485a-a45a-f5fea1426612">
+ Kindercaches (KiC)</a><br />
+ <small><em>
+ by
+ <a href="http://www.geocaching.com/profile/?guid=0564a940-8311-40ee-8e76-7e91b2cf6284">
+ blafoo</a> </em></small>
+ </li>
+
+ </ul>
+
+ <p class="NoBottomSpacing">
+
+ </p>
+
+ </div>
+
+
+</div>
+
+
+
+
+ </div>
+
+
+ <div class="span-24 last">
+
+ <p>
+ <span id="ctl00_ContentBody_WaypointsInfo" style="font-weight:bold;">Additional Waypoints</span>
+ <br />
+
+
+<script type="text/javascript">
+ <!--
+ var checkflag = false;
+ function checkAll(obj) {
+ if (checkflag == false) {
+ checkflag = true;
+ } else {
+ checkflag = false;
+ }
+ var arrInput = document.getElementsByTagName("input");
+ for (i = 0; i < arrInput.length; i++) {
+ if (arrInput[i].type == 'checkbox') {
+ arrInput[i].checked = checkflag;
+ }
+ }
+ }
+
+ // End -->
+</script>
+
+ <table class="Table" id="ctl00_ContentBody_Waypoints">
+ <thead>
+ <tr>
+ <th scope="col" class="AlignCenter">
+ <a href="javascript:checkAll(this);">
+ </a>
+ </th>
+ <th scope="col">
+
+ </th>
+ <th scope="col">
+
+ </th>
+ <th scope="col">
+ Prefix
+ </th>
+ <th scope="col">
+ Lookup
+ </th>
+ <th scope="col">
+ Name
+ </th>
+ <th scope="col">
+ Coordinate
+ </th>
+ <th scope="col">
+
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+
+ <tr class="BorderBottom " ishidden="false">
+ <td class="AlignCenter">
+
+ </td>
+ <td>
+ <img width="16" height="16" src="/images/icons/icon_nocoords.jpg" alt="Hide Coordinates" title="Hide Coordinates" />
+ </td>
+ <td>
+ <img src="http://www.geocaching.com/images/wpttypes/sm/flag.jpg" width="16" height="16" alt="Final Location" title="Final Location" />
+ </td>
+ <td>
+ <span id="awpt_FN">
+ FN</span>
+ </td>
+ <td>
+ FINAL
+ </td>
+ <td>
+ <a href="http://www.geocaching.com/seek/wpt.aspx?WID=30f1b37c-d395-4c7a-94e2-0c649d5f231b&RefID=73246a5a-ebb9-4d4f-8db9-a951036f5376&RefDS=1">GC2CJPF Final</a> (Final Location)
+ </td>
+ <td>
+ ???
+
+ </td>
+ <td>
+
+
+
+
+ </td>
+ </tr>
+ <tr class="BorderBottom ">
+ <td>
+
+ </td>
+ <td>
+ Note:
+ </td>
+ <td colspan="6">
+
+ </td>
+ </tr>
+
+ <tr class="BorderBottom AlternatingRow" ishidden="false">
+ <td class="AlignCenter">
+
+ </td>
+ <td>
+ <img width="16" height="16" src="/images/icons/icon_viewable.jpg" alt="Visible" title="Visible" />
+ </td>
+ <td>
+ <img src="http://www.geocaching.com/images/wpttypes/sm/pkg.jpg" width="16" height="16" alt="Parking Area" title="Parking Area" />
+ </td>
+ <td>
+ <span id="awpt_PK">
+ PK</span>
+ </td>
+ <td>
+ PARKNG
+ </td>
+ <td>
+ <a href="http://www.geocaching.com/seek/wpt.aspx?WID=98cb1387-49ce-4f94-9b05-5cb079d332b1&RefID=73246a5a-ebb9-4d4f-8db9-a951036f5376&RefDS=1">GC2CJPF Parking</a> (Parking Area)
+ </td>
+ <td>
+ N 52° 25.384 E 009° 39.023
+
+ </td>
+ <td>
+
+
+
+
+ </td>
+ </tr>
+ <tr class="BorderBottom AlternatingRow">
+ <td>
+
+ </td>
+ <td>
+ Note:
+ </td>
+ <td colspan="6">
+ Kein "offizieller" Parkplatz, Parken trotzdem möglich.
+ </td>
+ </tr>
+
+ <tr class="BorderBottom " ishidden="false">
+ <td class="AlignCenter">
+
+ </td>
+ <td>
+ <img width="16" height="16" src="/images/icons/icon_viewable.jpg" alt="Visible" title="Visible" />
+ </td>
+ <td>
+ <img src="http://www.geocaching.com/images/wpttypes/sm/puzzle.jpg" width="16" height="16" alt="Question to Answer" title="Question to Answer" />
+ </td>
+ <td>
+ <span id="awpt_ST">
+ ST</span>
+ </td>
+ <td>
+ START
+ </td>
+ <td>
+ <a href="http://www.geocaching.com/seek/wpt.aspx?WID=04113bad-64ca-499a-9848-b5937e13da1b&RefID=73246a5a-ebb9-4d4f-8db9-a951036f5376&RefDS=1">GC2CJPF Start</a> (Question to Answer)
+ </td>
+ <td>
+ N 52° 25.504 E 009° 39.852
+
+ </td>
+ <td>
+
+
+
+
+ </td>
+ </tr>
+ <tr class="BorderBottom ">
+ <td>
+
+ </td>
+ <td>
+ Note:
+ </td>
+ <td colspan="6">
+
+ </td>
+ </tr>
+
+ <tr class="BorderBottom AlternatingRow" ishidden="false">
+ <td class="AlignCenter">
+
+ </td>
+ <td>
+ <img width="16" height="16" src="/images/icons/icon_viewable.jpg" alt="Visible" title="Visible" />
+ </td>
+ <td>
+ <img src="http://www.geocaching.com/images/wpttypes/sm/waypoint.jpg" width="16" height="16" alt="Reference Point" title="Reference Point" />
+ </td>
+ <td>
+ <span id="awpt_WO">
+ WO</span>
+ </td>
+ <td>
+ SCENIC
+ </td>
+ <td>
+ <a href="http://www.geocaching.com/seek/wpt.aspx?WID=b28c5879-3181-4510-94fa-6ec5e30fd056&RefID=73246a5a-ebb9-4d4f-8db9-a951036f5376&RefDS=1">Aussichtspunkt</a> (Reference Point)
+ </td>
+ <td>
+ N 52° 25.488 E 009° 39.432
+
+ </td>
+ <td>
+
+
+
+
+ </td>
+ </tr>
+ <tr class="BorderBottom AlternatingRow">
+ <td>
+
+ </td>
+ <td>
+ Note:
+ </td>
+ <td colspan="6">
+ Ehemalige Finallocation wo es gebrannt hat. Gleichzeitig netter Aussichtspunkt.
+ </td>
+ </tr>
+
+ </tbody> </table>
+
+<p>
+
+ <span id="ShowHideLink">|
+ <a id="ctl00_ContentBody_Waypoints_uxShowHiddenCoordinates" href="../controls/#">Show Hidden Waypoints</a>
+ <a id="ctl00_ContentBody_Waypoints_uxHideHiddenCoordinates" href="../controls/#">Hide Hidden Waypoints</a></span>
+</p>
+
+<script type="text/javascript" language="javascript">
+ var hiddenLinkCookieName = "hiddenlinks";
+
+ jQuery(function () {
+ var $ = jQuery;
+ var hiddenLinkCookie = jQuery.cookie(hiddenLinkCookieName);
+
+ $('#ctl00_ContentBody_Waypoints_uxShowHiddenCoordinates').click(function (e) {
+ setHiddenCoordState(true);
+ return false;
+ });
+
+ $('#ctl00_ContentBody_Waypoints_uxHideHiddenCoordinates').click(function (e) {
+ setHiddenCoordState(false);
+ return false;
+ });
+
+ if ($("#ctl00_ContentBody_Waypoints tbody tr[ishidden='true']").length > 0) {
+ $("#ShowHideLink").show();
+ } else {
+ $("#ShowHideLink").hide();
+ }
+
+ if (hiddenLinkCookie == null || hiddenLinkCookie == "false") {
+ setHiddenCoordState(false);
+ } else {
+ setHiddenCoordState(true);
+ }
+
+ });
+
+
+
+ function setHiddenCoordState(show) {
+ var $ = jQuery;
+ if (show) {
+ $('#ctl00_ContentBody_Waypoints tbody')
+ .find("tr.AlternatingRow")
+ .removeClass("AlternatingRow")
+ .end()
+ .find("tr")
+ .show()
+ .end()
+ .find("tr:even:visible")
+ .each(function(i) {
+ if (i % 2 == 1)
+ $(this).addClass("AlternatingRow").next().addClass("AlternatingRow");
+ })
+ .end();
+
+ $("#ctl00_ContentBody_Waypoints_uxShowHiddenCoordinates").hide();
+ $("#ctl00_ContentBody_Waypoints_uxHideHiddenCoordinates").show();
+
+ $.cookie(hiddenLinkCookieName, "true");
+
+ } else {
+ $('#ctl00_ContentBody_Waypoints tbody')
+ .find("tr.AlternatingRow")
+ .removeClass("AlternatingRow")
+ .end()
+ .find("tr[ishidden='true']").each(function() {
+ $(this).hide().next().hide();
+ })
+ .end()
+ .find("tr:even:visible")
+ .each(function(i) {
+ if (i % 2 == 1)
+ $(this).addClass("AlternatingRow").next().addClass("AlternatingRow");
+ })
+ .end();
+
+ $("#ctl00_ContentBody_Waypoints_uxShowHiddenCoordinates").show();
+ $("#ctl00_ContentBody_Waypoints_uxHideHiddenCoordinates").hide();
+
+ $.cookie(hiddenLinkCookieName, "false");
+ }
+
+ return false;
+ }
+</script>
+
+ </p>
+
+ <div id="uxlrgMap" class="fr">
+
+ <div class="PageBreakBefore">
+ </div>
+ <div class="CDMapWidget">
+ <p class="WidgetHeader NoBottomSpacing">
+ <a id="ctl00_ContentBody_uxViewLargerMap" title="View Larger Map" class="lnk" href="/map/default.aspx?lat=52.425067&lng=9.6642" target="_blank"><img src="/images/silk/map_go.png" /> <span>View Larger Map</span></a>
+ | <a href="#" id="lnk_slippyMap">View Dynamic Map</a>
+ </p>
+ <div style="border: 1px solid #B0B0B0; width: 325px; height: 325px;">
+ <img id="staticMap" src="/images/blank.gif" style="width: 325px; height: 325px;" />
+ </div>
+ <div id="map_canvas" style="width: 325px; height: 325px; display: none;">
+ </div>
+ <p class="WidgetFooter">
+ <a id="ctl00_ContentBody_uxNotesAboutPrinting" href="#mapPrintingNotes" class="NoPrint">Notes about Printing Maps</a></p>
+ </div>
+ <div style="display: none;">
+ <div id="mapPrintingNotes">
+ To print the map in Firefox and Opera, enable background images in the print dialog.
+ <a href="#dlgMapPrintWarning" class="dialog" onclick="$.fancybox.close()">
+ Close
+ </a>
+ </div>
+ </div>
+
+</div>
+
+ <p class="NoPrint">
+ <span id="ctl00_ContentBody_uxFindLinksHeader" style="font-weight:bold;">Find...</span>
+ <br />
+ <span id="ctl00_ContentBody_FindText"></span>
+ </p>
+ <ul class="NoPrint">
+ <li>
+ ...other caches
+ <a id="ctl00_ContentBody_uxFindLinksHiddenByThisUser" href="/seek/nearest.aspx?u=Tom03">hidden</a>
+ or
+ <a id="ctl00_ContentBody_uxFindLinksFoundByThisUser" href="/seek/nearest.aspx?ul=Tom03">found</a>
+ by this user
+ </li>
+
+ <li>
+ ...nearby <a id="ctl00_ContentBody_uxFindLinksNearbyCachesOfType" href="/seek/nearest.aspx?tx=a5f6d0ad-d2f2-4011-8c14-940a9ebf3c74&lat=52.425067&lng=9.664200">caches of this type</a>,
+ <a id="ctl00_ContentBody_uxFindLinksNearbyNotFound" href="/seek/nearest.aspx?tx=a5f6d0ad-d2f2-4011-8c14-940a9ebf3c74&lat=52.425067&lng=9.664200&f=1">that I haven't found</a>
+ </li>
+ <li>
+ ...all nearby <a id="ctl00_ContentBody_uxFindLinksAllNearbyCaches" href="/seek/nearest.aspx?lat=52.425067&lng=9.664200">caches</a>,
+ <a id="ctl00_ContentBody_uxFindLinksAllNearbyNotFound" href="/seek/nearest.aspx?lat=52.425067&lng=9.664200&f=1">that I haven't found</a>
+ </li>
+ <li>
+ ...all nearby <a id="ctl00_ContentBody_uxFindLinksWaymarking" href="http://www.waymarking.com/directory.aspx?f=1&lat=52.425067&lon=9.664200">waymarks on Waymarking.com</a>
+ </li>
+
+
+ <li>
+ ...nearby <a id="ctl00_ContentBody_uxFindLinksHotels" href="/reviews/hotels-coords-52.4251,9.6642">Hotels</a>
+ </li>
+ </ul>
+ <p class="NoPrint">
+ <span id="ctl00_ContentBody_uxMapLinkHeader" style="font-weight:bold;">For online maps...</span>
+ </p>
+ <span class="NoPrint">
+
+<ul>
+ <span id="ctl00_ContentBody_MapLinks_MapLinks"><li><a href="http://www.geocaching.com/map/default.aspx?lat=52.425067&lng=9.6642" target="_blank">Geocaching.com Google Map</a></li><li><a href="http://maps.google.com/maps?q=N+52%c2%b0+25.504+E+009%c2%b0+39.852+(GC2CJPF)+" target="_blank">Google Maps</a></li><li><a href="http://www.mapquest.com/maps/map.adp?searchtype=address&formtype=latlong&latlongtype=decimal&latitude=52.425067&longitude=9.6642&zoom=10" target="_blank">MapQuest</a></li><li><a href="http://maps.yahoo.com/maps_result?lat=52.425067&lon=9.6642" target="_blank">Yahoo Maps</a></li><li><a href="http://www.bing.com/maps/default.aspx?v=2&sp=point.52.425067_9.6642_GC2CJPF" target="_blank">Bing Maps</a></li><li><a href="http://www.opencyclemap.org/?zoom=12&lat=52.425067&lon=9.6642" target="_blank">Open Cycle Maps</a></li><li><a href="http://www.openstreetmap.org/?mlat=52.425067&mlon=9.6642&zoom=12" target="_blank">Open Street Maps</a></li></span>
+</ul>
+
+ </span>
+ <p class="NoPrint">
+
+ </p>
+
+ <div class="InformationWidget Clear">
+ <h3>
+ 83 Logged Visits</h3>
+ <div class="EncryptDecrypt">
+ <a href="#" class="decrypt-link">
+ Decrypt
+ </a>
+ </div>
+ <span id="ctl00_ContentBody_lblFindCounts"><p class="LogTotals"><img src="/images/icons/icon_smile.gif" alt="Found it" title="Found it" /> 64 <img src="/images/icons/icon_sad.gif" alt="Didn't find it" title="Didn't find it" /> 3 <img src="/images/icons/icon_note.gif" alt="Write note" title="Write note" /> 6 <img src="/images/icons/icon_disabled.gif" alt="Temporarily Disable Listing" title="Temporarily Disable Listing" /> 2 <img src="/images/icons/icon_enabled.gif" alt="Enable Listing" title="Enable Listing" /> 2 <img src="/images/icons/icon_greenlight.gif" alt="Publish Listing" title="Publish Listing" /> 1 <img src="/images/icons/icon_needsmaint.gif" alt="Needs Maintenance" title="Needs Maintenance" /> 2 <img src="/images/icons/icon_maint.gif" alt="Owner Maintenance" title="Owner Maintenance" /> 3 </p></span>
+ <p class="HalfLeft">
+ <a id="ctl00_ContentBody_uxLogbookLink" href="cache_logbook.aspx?guid=73246a5a-ebb9-4d4f-8db9-a951036f5376">View Logbook</a> | <a id="ctl00_ContentBody_uxGalleryImagesLink" DisplayFormatPlural="View the Image Gallery of {0:#,###} images" DisplayFormatSingular="View the Image Gallery" href="gallery.aspx?guid=73246a5a-ebb9-4d4f-8db9-a951036f5376">View the Image Gallery of 14 images</a>
+ </p>
+ <p class="NoBottomSpacing AlignRight">
+ <span class="Warning">**Warning!</span> <a href="/about/glossary.aspx#spoiler" title="Spoilers">Spoilers</a> may be included in the descriptions or links.
+ </p>
+ </div>
+
+ <div id="cache_logs_container">
+ <table id="cache_logs_table" class="LogsTable NoBottomSpacing">
+ <tbody>
+ </tbody>
+ <tfoot>
+ <tr>
+ <td class="AlignCenter">
+ <div id="pnlLazyLoad" style="display: none;">
+ <img src="/images/loading2.gif" class="StatusIcon" alt="Loading" />
+ Loading Cache Logs...
+ </div>
+ <div id="pnlButtonLoad" style="display: none;">
+ <a class="MobileButton">
+ Load More Logs...</a>
+ </div>
+ </td>
+ </tr>
+ </tfoot>
+ </table>
+ </div>
+ <p>
+ <small>
+ Current Time: <time datetime="2012-02-14T14:51:47Z">02/14/2012 14:51:47 (UTC-08:00) Pacific Time (US & Canada) (22:51 GMT)</time><br/>Last Updated: <time class="timeago" datetime="2012-01-29T18:57:05Z">2012-01-29T18:57:05Z</time> on 01/29/2012 10:57:05 (UTC-08:00) Pacific Time (US & Canada) (18:57 GMT) <br/>Rendered From:Unknown<br />Coordinates are in the WGS84 datum
+ </small>
+ </p>
+
+
+ </div>
+ <script id="tmpl_CacheLogRow" type="text/x-jquery-tmpl">
+ <tr class="log-row" data-encoded="${IsEncoded}" >
+ <td>
+ <div class="FloatLeft LogDisplayLeft" >
+ <p class="logOwnerProfileName">
+ <strong><a id="143568283" href="/profile/?guid=${AccountGuid}">${UserName}</a></strong></p>
+ <p class="logOwnerBadge">
+ <img title="${creator.GroupTitle}" src="${creator.GroupImageUrl}" align="absmiddle" style="vertical-align:middle">${creator.GroupTitle}
+ </p>
+ <p class="logOwnerAvatar">
+ <a href="/profile/?guid=${AccountGuid}">
+ {{if includeAvatars && AvatarImage}}
+ <img width="48" height="48" src="http://img.geocaching.com/user/avatar/${AvatarImage}">
+ {{else includeAvatars }}
+ <img width="48" height="48" src="/images/default_avatar.jpg">
+ {{/if}}
+ </a></p>
+ <p class="logOwnerStats">
+
+ {{if GeocacheFindCount > 0 }}
+ <img title="Caches Found" src="/images/icons/icon_smile.png"> ${GeocacheFindCount}
+ {{/if}}
+ {{if GeocacheFindCount > 0 && ChallengesCompleted > 0 }}
+ ·
+ {{/if}}
+ {{if ChallengesCompleted > 0 }}
+ <img title="Challenges Completed" src="/images/challenges/types/sm/challenge.png"> ${ChallengesCompleted}
+ {{/if}}
+ </p>
+ </div>
+ <div class="FloatLeft LogDisplayRight">
+ <div class="HalfLeft LogType">
+ <strong>
+ <img title="${LogType}" alt="${LogType}" src="/images/icons/${LogTypeImage}"> ${LogType}</strong></div>
+ <div class="HalfRight AlignRight">
+ <span class="minorDetails LogDate">${Visited}</span></div>
+ <div class="Clear LogContent">
+ {{if LatLonString.length > 0}}
+ <strong>${LatLonString}</strong>
+ {{/if}}
+ <p class="LogText">{{html LogText}}</p>
+ {{if Images.length > 0}}
+ <table cellspacing="0" cellpadding="3" class="LogImagesTable">
+ {{tmpl(Images) "tmplCacheLogImages"}}
+ </table>
+ {{/if}}
+
+ <div class="AlignRight">
+ <small><a title="View Log" href="log.aspx?LUID=${LogGuid}" target="_blank">
+ {{if (userInfo.ID==AccountID)}}
+ View / Edit Log / Images
+ {{else}}
+ View Log
+ {{/if}}
+ </a></small>
+ {{if (userInfo.ID==AccountID)}}
+ <small><a title="Upload Image" href="upload.aspx?LID=${LogID}" target="_blank">Upload Image</a></small>
+ {{/if}}
+ </div>
+ </div>
+ </div>
+ </td>
+ </tr>
+ </script>
+ <script id="tmpl_CacheLogImages" type="text/x-jquery-tmpl">
+ <tr>
+ <td>
+ <a class="tb_images lnk" rel="tb_images[grp${LogID}]" href="http://img.geocaching.com/cache/log/large/${FileName}" data-title="{{tmpl "tmplCacheLogImagesTitle"}}">
+ <img title="Photo" alt="Photo" src="/images/silk/photo.png">
+ <span>${ $('<div />').text($('<div />').html($item.data.Name).text()).html() }</span>
+ </a>
+ </td>
+ </tr>
+ </script>
+ <script id="tmpl_CacheLogImagesTitle" type="text/x-jquery-tmpl">
+ <span class="LogImgTitle"> ${ $('<div />').text($('<div />').text($('<div />').html($item.data.Name).text()).html()).html() } </span><span class="LogImgLink">
+
+ <a target="_blank" href="log.aspx?LUID=${$item.parent.parent.data.LogGuid}&IID=${ImageGuid}">View Log</a>
+
+ <a href="http://img.geocaching.com/cache/log/large/${FileName}">Print Picture</a></span>
+
+ {{if (Descr && Descr.length > 0) }}
+ <br /><p class="LogImgDescription">${ $('<div />').text($('<div />').text($('<div />').html($item.data.Descr).text()).html()).html() }</p>
+ {{/if}}
+ </script>
+ <script id="tmpl_CacheCoordinateUpdate" type="text/x-jquery-tmpl">
+ <div class="ccu-update" data-lat="${ll[0]}" data-lng="${ll[1]}">
+ <h4 class="BottomSpacing">Corrected Coordinates (hidden from others)</h4>
+ <dl>
+ <dt>Original:</dt>
+ <dd>${ll_formatted} <a href="#" class="ccu-restore">Restore</a></dd>
+ </dl>
+ <dl class="ccu-parse">
+ <dt>Change To:</dt>
+ <dd>
+ <input type="text" max="40" size="35" class="cc-parse-text">
+ <button class="ccu-button ccu-parse">Submit</button>
+ </dd>
+ </dl>
+ <dl class="ccu-parseverify" style="display:none;">
+ <dt>Change To:</dt>
+ <dd>
+ <span class="ccu-parseverify-coords">N 32°38.880′, W 097°23.755′</span>
+
+ <button class="ccu-button ccu-parseverify-accept">Accept</button> <button class="ccu-button ccu-parseverify-cancel">Cancel</button>
+ </dd>
+ </dl>
+ </div>
+ <div class="Clear"></div>
+
+ </script>
+
+ <script type="text/javascript">
+ <!--
+ var dh, lat, lng, guid;
+
+ dh = 'true';
+
+ lat=52.425067; lng=9.6642; guid='73246a5a-ebb9-4d4f-8db9-a951036f5376';
+
+
+ function s2gps(guid) {
+ var w = window.open('sendtogps.aspx?guid=' + guid, 's2gps', config='width=450,height=450,toolbar=no,menubar=no,scrollbars=no,resizable=no,location=no,directories=no,status=no');
+ w.focus();
+ }
+
+ function s2phone(wpid) {
+ window.location.href='sendtophone.aspx?gc=' + wpid;
+ }
+
+ function pl(lc) {
+ document.location.href='cache_details_print.aspx?guid=' + guid + '&numlogs=' + lc +'&pt=full<=letter&decrypt='+ ((dh)?'y':'n');
+ }
+ function setNotification(id) {
+ //new Effect.Highlight(id, {startcolor:'#ffffff', endcolor:'#ffff99', restorecolor:'#ffff99', duration:3.0, queue:'front'});
+ //new Effect.Highlight(id, {startcolor:'#ffff99', endcolor:'#ffffff', restorecolor:'#ffffff', duration:5.0, queue:'end'});
+ }
+ function cmo(id) {
+ //new Effect.Fade(id);
+ Cookie.set('sn', true);
+ }
+ function pp(img) {
+ var w = window.open(img);
+ w.focus();
+ }
+
+ //-->
+ </script>
+ <script language="javascript" type="text/javascript">
+ var map, bounds;
+ var canUpdateFavoriteStatus = true;
+ var decryptLogs = (urlParams["decrypt"] && urlParams["decrypt"] == "y") ? true : false;
+ var logInitialLoaded = false;
+ var $tfoot = $("#cache_logs_table").find("tfoot");
+ var currentPageIdx = 1, totalPages = 1, pageSize = 10;
+ var isBusy = false;
+
+ var locString = {
+ decrypt: 'Decrypt',
+ encrypt: 'Encrypt'
+ };
+
+ $("#tmpl_CacheLogImagesTitle").template("tmplCacheLogImagesTitle");
+ $("#tmpl_CacheLogImages").template("tmplCacheLogImages");
+ $("#tmpl_CacheLogRow").template("tmplCacheLogRow");
+
+ $(".EncryptDecrypt")
+ .button({ icons: { secondary: 'ui-icon-arrowreturnthick-1-w'} })
+ .click(function (e) {
+ e.preventDefault();
+ $("tr.log-row").each(function (i, obj) {
+ var $obj = $(obj);
+ if ($obj.data("encoded") == true) {
+ var lt = $obj.find("p.LogText");
+ //var ltDecoded = $('<div />').html(lt.html()).text();
+ lt.html(convertROTStringWithBrackets(lt.html()));
+ }
+ });
+
+ decryptLogs = !decryptLogs;
+
+ $("a.decrypt-link").html(decryptLogs ? locString.encrypt : locString.decrypt);
+
+ return false;
+ });
+
+ function appendNewLogs(obj) {
+
+ totalPages = obj.pageInfo.totalPages;
+
+ var $newBody = $(document.createElement("TBODY"));
+
+ $("#tmpl_CacheLogRow").tmpl(obj.data,{includeAvatars: includeAvatars}).appendTo($newBody);
+
+ $newBody.find("a.tb_images").each(function()
+ {
+ var $this = $(this);
+ $this.fancybox({
+ 'type': 'image',
+ 'titlePosition': 'inside',
+ 'padding': 10,
+ titleFormat: function() { return $this.data('title'); }
+ });
+ });
+
+ $("#cache_logs_table")
+ .append($newBody.children());
+
+ currentPageIdx = obj.pageInfo.idx + 1;
+ pageSize = obj.pageInfo.size;
+ }
+
+ function callLogLoad(hideFooter) {
+ $.getJSON("/seek/geocache.logbook", { tkn: userToken, idx: currentPageIdx, num: pageSize, decrypt: decryptLogs },
+ function (response) {
+ if (response.status == "success") {
+ appendNewLogs(response);
+ if( hideFooter || (totalPages < currentPageIdx) ) {
+ $tfoot.hide();
+ }
+ } else if (response.status == "error" && response.value == "1") {
+ // reload the page since the data had expired.
+ window.location.reload();
+ }
+ isBusy = false;
+ });
+ }
+
+ $("#add_to_favorites").click(function () {
+
+ if (canUpdateFavoriteStatus) {
+ canUpdateFavoriteStatus = false;
+
+ var fv = parseInt($(".favorite-value").text());
+ fv++;
+ $(".favorite-value").text(fv);
+
+ var fr = parseInt($(".favorite-rank").text());
+ fr--;
+ $(".favorite-rank").text(fr);
+
+ $("#pnlNonfavoriteCache").fadeOut("fast", function () {
+ $("#pnlFavoriteCache").fadeIn("fast");
+ });
+
+ $.ajax({
+ type: "POST",
+ cache: false,
+ url: '/datastore/favorites.svc/update?u=' + userToken + '&f=true',
+ success: function () {
+ canUpdateFavoriteStatus = true;
+ gotScore = false;
+ showFavoriteScore();
+ }
+ });
+
+ return false;
+ }
+ });
+
+ $("#remove_from_favorites").click(function () {
+
+ if (canUpdateFavoriteStatus) {
+ canUpdateFavoriteStatus = false;
+
+ var fv = parseInt($(".favorite-value").text());
+ fv--;
+ $(".favorite-value").text(fv);
+
+ var fr = parseInt($(".favorite-rank").text());
+ fr++;
+ $(".favorite-rank").text(fr);
+
+ $("#pnlFavoriteCache").fadeOut("fast", function () {
+ $("#pnlNonfavoriteCache").fadeIn("fast");
+ });
+
+ $.ajax({
+ type: "POST",
+ cache: false,
+ url: '/datastore/favorites.svc/update?u=' + userToken + '&f=false',
+ success: function () {
+ canUpdateFavoriteStatus = true;
+ gotScore = false;
+ showFavoriteScore();
+ }
+ });
+
+ return false;
+ }
+ });
+
+ $(function () {
+
+ //override coords
+ if (typeof(userDefinedCoords) != "undefined") {
+ if (userDefinedCoords.status == "success" && userDefinedCoords.data.isUserDefined == true) {
+ mapLatLng = $.extend({}, mapLatLng, userDefinedCoords.data);
+ $("#uxLatLon")
+ .data("isOverridden", true)
+ .addClass("myLatLon");
+ } else if (userDefinedCoords.status == "success") {
+ mapLatLng = $.extend({}, mapLatLng, userDefinedCoords.data);
+ } else {
+ $("#uxLatLonLink").contents().unwrap();
+ }
+ } else {
+ $("#uxLatLonLink").contents().unwrap();
+ }
+
+
+ var cacheNoteText = {
+ DefaultText: 'Click to enter a note',
+ ErrorInSaving: 'There was an error saving page. Please refresh the page and try again.',
+ SavingText: 'Please wait, saving your note...'
+ };
+
+
+
+ $("time.timeago").timeago();
+
+ $(".button").button();
+
+ var sn = Cookie.get('sn');
+
+ if ($('#trNotPM').length > 0) {
+ $('#trNotPM').toggle(!sn);
+ }
+
+ $("#cache_note").editInPlace({
+ callback: function (unused, enteredText) {
+ var me = $(this);
+
+ var et = $.trim(enteredText);
+ if (et.length > 500)
+ et = et.substr(0, 500);
+
+ $.pageMethod("SetUserCacheNote", JSON.stringify({ dto: { et: et, ut: userToken} }), function (r) {
+ var r = JSON.parse(r.d);
+ if (r.success == true) {
+ if ($.trim(r.note) == "") {
+ $("#cache_note").text(cacheNoteText.DefaultText);
+ } else {
+ $("#cache_note").text(r.note);
+ }
+
+ me.effect('highlight', { color: '#ffb84c' }, 'slow');
+ } else {
+ alert(cacheNoteText.ErrorInSaving);
+ $("#cache_note").text(cacheNoteText.DefaultText);
+ }
+
+ });
+
+ return cacheNoteText.SavingText;
+ }
+ , default_text: cacheNoteText.DefaultText
+ , field_type: "textarea"
+ , textarea_rows: "7"
+ , textarea_cols: "65"
+ , show_buttons: true
+ , bg_over: "#FDEBBB"
+ //, callback_skip_dom_reset: true
+
+ });
+
+ $("#lnk_slippyMap").click(function(e) {
+ e.preventDefault();
+ loadDynamicMap();
+ return false;
+ });
+
+ $(".inplace_field").live("focus", function () {
+ if ($(this).data("created") == null) {
+ $(this).data("created", true)
+ $(this).countable({
+ maxLength: 500
+ });
+ }
+ });
+
+ $("#pcn_help").tipTip({ activation: 'hover', content: 'Enter your own notes here. No other user will be able to access them.' });
+
+ $("a.decrypt-link").html(decryptLogs ? locString.encrypt : locString.decrypt);
+
+ if ($("#cache_logs_container").length > 0) {
+
+
+
+ appendNewLogs(initalLogs);
+
+ if (DetectMobileQuick()) {
+ $("#pnlButtonLoad")
+ .show()
+ .find("a.MobileButton")
+ .click(function (e) {
+ e.preventDefault();
+ callLogLoad(false);
+ return false;
+ })
+ .button();
+ if(!DetectTierTablet()){
+ $("a.MobileButton").addClass("Phone");
+ }
+ } else {
+ $("#pnlLazyLoad").show();
+
+ $(window).endlessScroll({
+ fireOnce: true,
+ fireDelay: 500,
+ bottomPixels: ($(document).height() - $("#cache_logs_container").offset().top) + 50,
+ ceaseFire: function(){
+ // stop the scrolling if the last page is reached.
+ return (isLoggedIn == false) || (totalPages < currentPageIdx);
+ },
+ callback: function() {
+ if (!isBusy) {
+
+ isBusy = true;
+ $tfoot.show();
+ callLogLoad(true);
+ }
+ }
+ });
+ }
+ }
+
+ if (!isLoggedIn) {
+ $("#cache_logs_table").find("tfoot").hide();
+ }
+
+ if (mapLatLng != null) {
+
+
+
+ $("#uxLatLonLink").qtip({
+ suppress:false,
+ content: buildCacheCoordMenu(),
+ position: {
+ my: 'left top',
+ at: 'right top',
+ adjust: {
+ x: 10, y: -10
+ }
+ },
+ show: {
+ ready: false,
+ event: "click",
+ solo: true
+ }, hide: {
+ event: 'unfocus'
+ },
+ style: {
+ tip: {
+ corner: false
+ },
+ classes: 'ui-tooltip-widget'
+ },
+ events: {
+ show: function () {
+ if ($("#uxLatLon").data("isOverridden")) {
+ $("a.ccu-restore").show();
+ } else {
+ $("a.ccu-restore").hide();
+ }
+
+ if (userDefinedCoords.status != "success") {
+ $("div.ccu-update").hide();
+ } else {
+ $("div.ccu-update").show();
+ }
+ }
+ }
+ }).click(function (e) {
+ e.preventDefault();
+ return false;
+ });
+
+ setStaticMaps();
+ $("#staticMap").lazyload();
+ }
+ });
+
+ function setStaticMaps() {
+ var map = new L.Map('map_preview_canvas', {
+ center: new L.LatLng(mapLatLng.lat, mapLatLng.lng),
+ zoom: 10,
+ doubleClickZoom: false,
+ dragging: false,
+ touchZoom: false,
+ scrollWheelZoom: false,
+ zoomControl: false
+ });
+
+ var tileUrl = "http://otile{s}.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.png",
+ tLayer = new L.TileLayer(tileUrl,
+ {
+ name: "mpq",
+ alt: "MapQuest",
+ attribution: 'Data, imagery and map information provided by MapQuest, <a href="http://www.openstreetmap.org" target="_blank">Open Street Map</a> and contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA.</a>',
+ subdomains: "1234",
+ tileSize: 256,
+ minZoom: 0,
+ maxZoom: 20
+ });
+
+ map.addLayer(tLayer);
+
+ var pinIcon = L.Icon.extend({
+ iconSize: new L.Point(20, 23),
+ iconAnchor: new L.Point(10, 23),
+ shadowUrl: null
+ });
+
+ var mkA = new L.Marker(new L.LatLng(mapLatLng.lat, mapLatLng.lng), {
+ icon: new pinIcon('/images/wpttypes/pins/' + mapLatLng.type + '.png')
+ });
+
+ mkA.on("click", function () {
+ document.getElementById("uxlrgMap").scrollIntoView(true);
+ return false;
+ });
+
+ map.addLayer(mkA);
+
+ $("#ctl00_ContentBody_uxNotesAboutPrinting").fancybox({
+ overlayShow: false
+ });
+
+ var staticUrl = [];
+ var markers=[];
+
+ //$("#mapPreview").attr("src", "http://maps.google.com/maps/api/staticmap?zoom=10&size=228x150&sensor=false&markers=icon:http://www.geocaching.com/images/wpttypes/pins/" + mapLatLng.type + ".png|" + mapLatLng.lat + "," + mapLatLng.lng);
+
+ staticUrl.push("http://maps.google.com/maps/api/staticmap?size=325x325&sensor=false");
+ staticUrl.push("&markers=icon:http://www.geocaching.com/images/wpttypes/pins/" + mapLatLng.type + ".png|" + mapLatLng.lat + "," + mapLatLng.lng);
+ markers.push({lat:mapLatLng.lat, lng:mapLatLng.lng, marker:"http://www.geocaching.com/images/wpttypes/pins/" + mapLatLng.type + ".png", primary:true});
+ if (cmapAdditionalWaypoints != null && cmapAdditionalWaypoints.length > 0) {
+ for (var x = 0, len = cmapAdditionalWaypoints.length; x < len; x++) {
+ var item = cmapAdditionalWaypoints[x]
+ staticUrl.push("&markers=icon:http://www.geocaching.com/images/wpttypes/pins/" + item.type + ".png|" + item.lat + "," + item.lng);
+ markers.push({lat:item.lat, lng:item.lng, marker: "http://www.geocaching.com/images/wpttypes/pins/" + item.type + ".png",primary:false});
+ }
+ } else {
+ staticUrl.push("&zoom=14");
+ }
+
+ $("#staticMap")
+ .data("markers", markers )
+ .attr("data-original", staticUrl.join(""));
+ }
+
+ function loadDynamicMap() {
+ if (typeof google !== 'undefined' && typeof google.maps !== 'undefined') {
+ displayDynamicMap();
+ } else {
+ var script = document.createElement("script");
+ script.type = "text/javascript";
+ script.src = "http://maps.google.com/maps/api/js?v=3&sensor=false&indexing=false&callback=displayDynamicMap";
+ document.documentElement.firstChild.appendChild(script);
+ }
+ }
+
+ function displayDynamicMap() {
+ $sm = $("#staticMap");
+ $map = $('<div />').addClass('map').css({ height: 325, width: 325 });
+ $("#lnk_slippyMap").replaceWith($("<span>Showing Dynamic Map</span>"));
+
+ var items = $sm.data("markers");
+
+ // walk the array to find the full bounds
+ var bounds = new google.maps.LatLngBounds();
+ var markers = [];
+
+ for (var x = 0, len=items.length; x < len; x++) {
+ var item = items[x];
+ var ll = new google.maps.LatLng(item.lat, item.lng);
+ bounds.extend(ll);
+ markers.push(new google.maps.Marker( {
+ clickable:false,
+ icon: item.marker,
+ position: ll, zIndex: google.maps.Marker.MAX_ZINDEX + (item.primary ? 1 : 0)
+ }));
+ }
+
+ $sm.replaceWith($map);
+
+ var map = new google.maps.Map($map.get(0), {
+ zoom: 14,
+ center: bounds.getCenter(),
+ mapTypeId: google.maps.MapTypeId.ROADMAP,
+ mapTypeControl: true,
+ navigationControlOptions: {
+ style: google.maps.NavigationControlStyle.SMALL
+ }
+ });
+
+ for(var x=0, len=markers.length; x<len;x++) {
+ markers[x].setMap(map);
+ }
+
+ if (bounds.length>1)
+ map.fitBounds(bounds);
+ }
+
+ function dht() {
+ try {
+ $('#div_hint').html(convertROTStringWithBrackets($('#div_hint').html()));
+ var linkText = (($('#ctl00_ContentBody_lnkDH').attr('title') == 'Decrypt') ? 'Encrypt' : 'Decrypt');
+ $('#ctl00_ContentBody_lnkDH').text(linkText);
+ $('#ctl00_ContentBody_lnkDH').attr('title', linkText);
+ } catch (e) {
+ alert(e);
+ return false;
+ }
+ return false;
+ }
+
+ function buildCacheCoordMenu() {
+ var curLatLng = new LatLon(mapLatLng.lat, mapLatLng.lng)
+ $.template( "tmplCacheCoordinateUpdate_CoordItem", "<tr><td nowrap='nowrap'>${t}</td><td class='ccc-coord' nowrap='nowrap' dataum='${k}'>${v}</td></tr>" );
+
+ var $menu = $("<div></div>");
+
+ $( "#tmpl_CacheCoordinateUpdate" ).tmpl( {
+ ll: [mapLatLng.lat, mapLatLng.lng],
+ ll_formatted: mapLatLng.oldLatLngDisplay
+ } ).appendTo( $menu );
+
+ $menu.find("button.ccu-button").button();
+
+ $menu.delegate("button.ccu-parse", "click", function (e) {
+ e.preventDefault();
+ var $this = $(e.target),
+ $parse =$this.closest('dd').find(".cc-parse-text"),
+ parseCoords = $.trim($parse.val());
+
+ if (parseCoords.length == 0) {
+ alert('Please provide valid coordinates.');
+ } else {
+ $.getJSON("/challenges/location.search", { p: parseCoords }, function (response) {
+ if (response.status == "success") {
+ var newLatLng = new LatLon(response.data.lat, response.data.lng);
+
+ // update the displayed coords
+ var dist = curLatLng.rhumbDistanceTo(newLatLng);
+ var bearingTo = curLatLng.rhumbBearingTo(newLatLng);
+ var bearing = bearingTo >= 0 || bearingTo < 22.5 ? "N" : bearingTo >= 22.5 || bearingTo < 67.5 ? "NE" : bearingTo >= 67.5 || bearingTo < 112.5 ? "E" : bearingTo >= 112.5 || bearingTo < 157.5 ? "SE" : bearingTo >= 157.5 || bearingTo < 202.5 ? "S" : bearingTo >= 202.5 || bearingTo < 247.5 ? "SW" : bearingTo >= 247.5 || bearingTo < 292.5 ? "W" : bearingTo >= 292.5 || bearingTo < 337.5 ? "NW" : "N";
+
+ var formats = response.data.formats;
+ // all these finds, make me feel dirty
+ $menu
+ .find("span.ccu-parseverify-coords").text(formats.DM).end()
+ .find("dl.ccu-parse").hide().end()
+ .find("dl.ccu-parseverify").show().end()
+ .find("button.ccu-parseverify-accept")
+ .data("utm", formats.UTM)
+ .data("dm", formats.DM)
+ .data("lat", response.data.lat)
+ .data("lng", response.data.lng)
+ .end();
+ } else {
+ alert("Sorry unable to parse the coordinates you entered.");
+ }
+ });
+ }
+
+ return false;
+ });
+
+ $menu.delegate("button.ccu-parseverify-accept", "click", function (e) {
+ e.preventDefault();
+ var $this = $(this);
+ // update to webmethod
+ $.pageMethod("SetUserCoordinate", JSON.stringify({ dto: { data: {lat: $this.data("lat"), lng: $this.data("lng") }, ut: userToken } }), function (r) {
+ var r = JSON.parse(r.d);
+ if (r.status == "success") {
+ window.location.reload();
+ } else {
+ $("#uxLatLonLink").qtip('hide');
+ }
+
+ });
+
+ return false;
+ });
+
+ $menu.delegate("button.ccu-parseverify-cancel", "click", function (e) {
+ e.preventDefault();
+ $menu
+ .find("input.cc-parse-text").val('').end()
+ .find("dl.ccu-parse").show().end()
+ .find("dl.ccu-parseverify").hide().end();
+ return false;
+ });
+
+ $menu.delegate("a.ccu-restore", "click", function (e) {
+ e.preventDefault();
+
+ $.pageMethod("ResetUserCoordinate", JSON.stringify({ dto: { ut: userToken } }), function (r) {
+ var r = JSON.parse(r.d);
+ if (r.status == "success") {
+ window.location.reload();
+ }
+ });
+
+ return false;
+ });
+
+ return $menu;
+ }
+
+ GSPK = window.GSPK || {};
+ GSPK.Selector = {};
+ GSPK.Selector.getSelected = function(){
+ var t = null;
+ if ( window.getSelection ){
+ t = window.getSelection();
+ }else if(document.getSelection){
+ t = document.getSelection();
+ }else if(document.selection){
+ t = document.selection.createRange().text;
+ }
+ return t;
+ }
+
+ try { _gaq.push(['_trackEvent', 'Geocaching', 'CacheDetailsMemberType', 'Premium', null, true]); } catch(err) { }
+ </script>
+
+
+
+ </div>
+
+
+
+
+ </div>
+
+
+ </section>
+
+ <footer>
+
+ <div class="container">
+
+ <div class="span-24 last FooterTop">
+
+
+
+<div class="LocaleText">
+
+ <strong>Choose Your Language:</strong>
+
+</div>
+<div class="LocaleList">
+
+ <div id="selected_language">
+
+ <a href="#">English▼</a>
+
+ </div>
+ <ul id="locale_list">
+
+ <li><a id="ctl00_uxLocaleList_uxLocaleList_ctl00_uxLocaleItem" href="javascript:__doPostBack('ctl00$uxLocaleList$uxLocaleList$ctl00$uxLocaleItem','')">English</a></li>
+
+ <li><a id="ctl00_uxLocaleList_uxLocaleList_ctl01_uxLocaleItem" href="javascript:__doPostBack('ctl00$uxLocaleList$uxLocaleList$ctl01$uxLocaleItem','')">Deutsch</a></li>
+
+ <li><a id="ctl00_uxLocaleList_uxLocaleList_ctl02_uxLocaleItem" href="javascript:__doPostBack('ctl00$uxLocaleList$uxLocaleList$ctl02$uxLocaleItem','')">Français</a></li>
+
+ <li><a id="ctl00_uxLocaleList_uxLocaleList_ctl03_uxLocaleItem" href="javascript:__doPostBack('ctl00$uxLocaleList$uxLocaleList$ctl03$uxLocaleItem','')">Português</a></li>
+
+ <li><a id="ctl00_uxLocaleList_uxLocaleList_ctl04_uxLocaleItem" href="javascript:__doPostBack('ctl00$uxLocaleList$uxLocaleList$ctl04$uxLocaleItem','')">Čeština</a></li>
+
+ <li><a id="ctl00_uxLocaleList_uxLocaleList_ctl05_uxLocaleItem" href="javascript:__doPostBack('ctl00$uxLocaleList$uxLocaleList$ctl05$uxLocaleItem','')">Svenska</a></li>
+
+ <li><a id="ctl00_uxLocaleList_uxLocaleList_ctl06_uxLocaleItem" href="javascript:__doPostBack('ctl00$uxLocaleList$uxLocaleList$ctl06$uxLocaleItem','')">Nederlands</a></li>
+
+ <li><a id="ctl00_uxLocaleList_uxLocaleList_ctl07_uxLocaleItem" href="javascript:__doPostBack('ctl00$uxLocaleList$uxLocaleList$ctl07$uxLocaleItem','')">Català</a></li>
+
+ <li><a id="ctl00_uxLocaleList_uxLocaleList_ctl08_uxLocaleItem" href="javascript:__doPostBack('ctl00$uxLocaleList$uxLocaleList$ctl08$uxLocaleItem','')">Polski</a></li>
+
+ <li><a id="ctl00_uxLocaleList_uxLocaleList_ctl09_uxLocaleItem" href="javascript:__doPostBack('ctl00$uxLocaleList$uxLocaleList$ctl09$uxLocaleItem','')">Eesti</a></li>
+
+ <li><a id="ctl00_uxLocaleList_uxLocaleList_ctl10_uxLocaleItem" href="javascript:__doPostBack('ctl00$uxLocaleList$uxLocaleList$ctl10$uxLocaleItem','')">Norsk, Bokmål</a></li>
+
+ <li><a id="ctl00_uxLocaleList_uxLocaleList_ctl11_uxLocaleItem" href="javascript:__doPostBack('ctl00$uxLocaleList$uxLocaleList$ctl11$uxLocaleItem','')">한국어</a></li>
+
+ <li><a id="ctl00_uxLocaleList_uxLocaleList_ctl12_uxLocaleItem" href="javascript:__doPostBack('ctl00$uxLocaleList$uxLocaleList$ctl12$uxLocaleItem','')">Español</a></li>
+
+ <li><a id="ctl00_uxLocaleList_uxLocaleList_ctl13_uxLocaleItem" href="javascript:__doPostBack('ctl00$uxLocaleList$uxLocaleList$ctl13$uxLocaleItem','')">Magyar</a></li>
+
+ <li><a id="ctl00_uxLocaleList_uxLocaleList_ctl14_uxLocaleItem" href="javascript:__doPostBack('ctl00$uxLocaleList$uxLocaleList$ctl14$uxLocaleItem','')">Română</a></li>
+
+ </ul>
+
+</div>
+<script type="text/javascript">
+
+ jQuery(document).ready(function() {
+ jQuery("#selected_language a").click(function (e) {
+ e.preventDefault();
+ jQuery("#locale_list").show().position({
+ of: $("#selected_language"),
+ my: "left top",
+ at: "left bottom",
+ offset: "0 3",
+ collision: "fit fit"
+ });
+ jQuery(document).click(function () {
+ jQuery("#locale_list").fadeOut("fast");
+ });
+ return false;
+ });
+ });
+</script>
+
+ </div>
+
+ <div class="span-5">
+
+ <p class="FooterHeader">
+ <strong>
+ About</strong></p>
+ <ul class="FooterLinks">
+ <li>
+ <a id="ctl00_hlFooterGlossary" title="Glossary of Terms" href="../about/glossary.aspx">Glossary of Terms</a></li>
+ <li>
+ <a id="ctl00_hlFooterBrochures" title="Brochures" href="../tools/default.aspx#Guide">Brochures</a></li>
+ <li>
+ <a id="ctl00_hlFooterAbout" title="About Groundspeak" href="../about/groundspeak.aspx">About Groundspeak</a></li>
+ <li>
+ <a id="ctl00_hlFooterHistory" title="History" href="../about/history.aspx">History</a></li>
+ </ul>
+
+ </div>
+
+ <div class="span-5">
+
+ <p class="FooterHeader">
+ <strong>
+ Press</strong></p>
+ <ul class="FooterLinks">
+ <li>
+ <a id="ctl00_hlFooterNews" title="News Articles" href="../press/default.aspx">News Articles</a></li>
+ <li>
+ <a id="ctl00_hlFooterMediaFAQs" title="Media FAQs" rel="document" href="../articles/Brochures/footer/FAQ_Media.pdf">Media FAQs</a></li>
+ <li>
+ <a id="ctl00_hlFooterMediaInquiries" title="Media Inquiries" rel="external" href="http://support.groundspeak.com/index.php?pg=request&xCategory=11">Media Inquiries</a></li>
+ </ul>
+
+ </div>
+
+ <div class="span-7">
+
+ <p class="FooterHeader">
+ <strong>
+ Questions & Suggestions</strong></p>
+ <ul class="FooterLinks">
+ <li>
+ <a id="ctl00_hlFooterHelpCenterLink" title="Help Center" rel="external" href="http://support.groundspeak.com/index.php">Help Center</a></li>
+ <li>
+ <a id="ctl00_hlFooterDiscussionForums" accesskey="f" title="Discussion Forums" href="../forums/default.aspx">Discussion Forums</a></li>
+ <li>
+ <a id="ctl00_hlFooterParksPoliceLink" title="Land Management and Law Enforcement" href="../parksandpolice/default.aspx">Land Management and Law Enforcement</a></li>
+ <li>
+ <a id="ctl00_hlFooterContactUs" title="Contact Us" href="../contact/default.aspx">Contact Us</a></li>
+ </ul>
+
+ </div>
+
+ <div class="span-4 append-3 last">
+
+ <p class="FooterHeader">
+ <strong>
+ Resources</strong></p>
+ <ul class="FooterLinks">
+ <li>
+ <a id="ctl00_hlFooterTools" accesskey="o" title="Tools and Downloads" href="../tools/default.aspx">Tools and Downloads</a></li>
+ <li>
+ <a id="ctl00_hlFooterAPIProgram" title="API Program" href="../live/default.aspx">API Program</a></li>
+ <li>
+ <a id="ctl00_hlFooterBenchmarks" title="Find a Benchmark" href="../mark/default.aspx">Find a Benchmark</a></li>
+ </ul>
+
+ </div>
+
+ <p class="span-24 last FooterBottom">
+ Copyright
+ © 2000-2012
+ <a href="http://www.groundspeak.com/" title="Groundspeak, Inc." accesskey="g">Groundspeak, Inc.</a>
+ All Rights Reserved.<br />
+ <a id="ctl00_hlFooterTerms" accesskey="u" title="Groundspeak Terms of Use" href="../about/termsofuse.aspx">Groundspeak Terms of Use</a>
+ |
+ <a id="ctl00_hlFooterPrivacy" accesskey="x" title="Privacy Policy" href="../about/privacypolicy.aspx">Privacy Policy</a>
+ |
+ <a id="ctl00_hlFooterLogo" accesskey="l" title="Geocaching Logo Usage Guidelines" href="../about/logousage.aspx">Geocaching Logo Usage Guidelines</a>
+ |
+ <a id="ctl00_hlFooterAPI" accesskey="`" title="API License Agreement" href="../live/api_license_agreement.aspx">API License Agreement</a></p>
+
+ </div>
+
+
+ </footer>
+ <div class="SkipLinks">
+
+ <a id="ctl00_hlSkipLinksTop" accesskey="t" title="Return to the Top of the Page" href="#Top">Return to the Top of the Page</a>
+
+ </div>
+
+
+
+
+<script type="text/javascript">
+//<![CDATA[
+var uvtoken = 'DbFDfIrSTaXyfNf74lbdopy%2bTw%2fC84Gn87pU%2b3r69toc4lYTKyii0cXY42BXT7amAeAEUCcV1MyzYH%2f69bWOOJ%2bW7ADYGWn7OZhaDMq0PZnGZmCyc0nX7MX4qkdr6Pq7igxCBwv6DNAb8Ar2g98kkSqYtfidn21%2b0BITFaZC6SGczNMMHreAOP5lofIIKjlM1l%2bE31pP1e0b5Sk6AKZ%2bOYV9pAps4ii3Taltkd%2fO7Vve%2fsHuybarBpnW0VS5InTudsZ%2baoG%2bVrnoXLmwjItRUVp47RrUgx2SWkhpZTUp4%2bIr3PLaS8W3eeNk68hcIcQKcdCFWgFhKBhP%2fUMGT9jqDXrfCe00Bzv1zxSmuN2hdabPaGLYj5JvzzRlX1Wd01BRQfNeZS82I66wN5BYBGvV6Re5B8xzFyckKNZNokW9IzQ%3d';var isLoggedIn = true;
+var userDefinedCoords = {"status":"success","data":{"isUserDefined":false,"oldLatLngDisplay":"N 52° 25.504' E 009° 39.852'"}};
+cmapAdditionalWaypoints.push({ lat:52.423067, lng:9.650383, name:'GC2CJPF Parking', pf:'PK', type:217 });
+cmapAdditionalWaypoints.push({ lat:52.425067, lng:9.6642, name:'GC2CJPF Start', pf:'ST', type:218 });
+cmapAdditionalWaypoints.push({ lat:52.4248, lng:9.6572, name:'Aussichtspunkt', pf:'WO', type:452 });
+mapLatLng = { lat:52.425067, lng:9.664200, type:3 };
+var ccConversions = [{"t":"Decimal","k":"DD","d":"WGS84","v":"52.425067, 009.664200"},{"t":"DDD MM SS.SSS","k":"DMS","d":"WGS84","v":"N 52° 25' 30.241\" E 009° 39' 51.120\""},{"t":"UTM","k":"UTM","d":"WGS84","v":"32U E 545164 N 5808524"}];
+userInfo = {ID: 1912314};
+userToken = 'FOUTFKOKLELXOJAYT35WSZBNGADBNKFSYIMKJ2YI6247JORDCSRPR3LYUNKEOR2PQUOHC7OGY223V2X2ADNEDT25JD2QHOXIHYLH7J5XLOWJSK5WTLLQ5UJQMIZEGXYFSHPFRQQ5A374RP7GSKIVLW2RCI53UZFIABL6BZOMFKJVUGRZNB2WTXZKPVBKQDJB76DIMLU2RDXSFQWZF54YLIO2PFWFCDENOIQLJ7RWZGAS3TLHKQUQ';
+includeAvatars = true;
+initalLogs = {"status":"success", "data": [{"LogID":210544989,"CacheID":1811409,"LogGuid":"c3e61373-8bfd-486a-bd29-756ea2525645","Latitude":null,"Longitude":null,"LatLonString":"","LogType":"Found it","LogTypeImage":"icon_smile.gif","LogText":"-4°C. Aber ein sehr schöner Spaziergang und unsere kleinen hatten bei der klirrenden Kälte auch ohne Seilfähre ihren Spaß.<br />Eine sehr aufwendige Arbeit, die von jedem geschätzt werden sollte. <br />DFDC<br />A.Meise<br /><br />TB-Drop","Created":"29/01/2012","Visited":"29/01/2012","UserName":"a.meise","MembershipLevel":3,"AccountID":1405245,"AccountGuid":"df13f5d1-0d3a-49eb-a41d-725bb1664a88","Email":"","AvatarImage":"2ad84894-cb7c-4595-ac1e-1711873d0ca2.jpg","GeocacheFindCount":169,"GeocacheHideCount":6,"ChallengesCompleted":0,"IsEncoded":false,"creator":{"GroupTitle":"Premium Member","GroupImageUrl":"/images/icons/prem_user.gif"},"Images":[]},{"LogID":208289692,"CacheID":1811409,"LogGuid":"4bbce528-844a-41c8-a881-160f9d5abeb2","Latitude":null,"Longitude":null,"LatLonString":"","LogType":"Found it","LogTypeImage":"icon_smile.gif","LogText":"Hallo :-)<br />Danke für diesen schönen Cache !!!<br />War ja auch eine kleine Zeitreise in meine Kindheit obwohl es ja damals den Kinderwald noch nicht gab.<br />Es gab trotzdem viele \"Abenteuer\" im Forst ;-)<br />Jendopa","Created":"15/01/2012","Visited":"14/01/2012","UserName":"Jendopa","MembershipLevel":1,"AccountID":4179363,"AccountGuid":"16f7dc47-cdb7-464d-b8fe-85e4f979ac5a","Email":"","AvatarImage":"","GeocacheFindCount":45,"GeocacheHideCount":0,"ChallengesCompleted":0,"IsEncoded":false,"creator":{"GroupTitle":"Member","GroupImageUrl":"/images/icons/reg_user.gif"},"Images":[]},{"LogID":199083747,"CacheID":1811409,"LogGuid":"09c926b9-c545-4683-836e-c1bbfd04e553","Latitude":null,"Longitude":null,"LatLonString":"","LogType":"Found it","LogTypeImage":"icon_smile.gif","LogText":"Schade, ich habe den Aufstieg in die höheren Etagen vermisst (wie die zwei Cache vorher), aber der Cache ist trotzdem gut gemacht. 2 große Kinder sind heute duch den Kinderwald gestreift.<br />Vielen Dank für die Tour und Gruss vom PS","Created":"15/11/2011","Visited":"15/11/2011","UserName":"powersearcher","MembershipLevel":3,"AccountID":623231,"AccountGuid":"bf288d6d-c3a9-490b-a862-fe37d04a6dd4","Email":"","AvatarImage":"47be780e-8ee5-416b-9409-787c01463294.jpg","GeocacheFindCount":4447,"GeocacheHideCount":50,"ChallengesCompleted":0,"IsEncoded":false,"creator":{"GroupTitle":"Premium Member","GroupImageUrl":"/images/icons/prem_user.gif"},"Images":[]},{"LogID":199080920,"CacheID":1811409,"LogGuid":"1fd5a2e4-0fc8-44bc-a776-897973636926","Latitude":null,"Longitude":null,"LatLonString":"","LogType":"Found it","LogTypeImage":"icon_smile.gif","LogText":"hallo, hier konnten ps und ich heute muggelfrei die schoene runde drehen.vielen dank und gruss suchherby mit seiner suchnase eika","Created":"15/11/2011","Visited":"15/11/2011","UserName":"Suchherby","MembershipLevel":3,"AccountID":151548,"AccountGuid":"f16a8472-ebfa-4e37-b5a8-9bb2942026a3","Email":"","AvatarImage":"5031f093-c226-49ad-b282-deac1c4cfc45.jpg","GeocacheFindCount":4234,"GeocacheHideCount":116,"ChallengesCompleted":0,"IsEncoded":false,"creator":{"GroupTitle":"Premium Member","GroupImageUrl":"/images/icons/prem_user.gif"},"Images":[]},{"LogID":196670830,"CacheID":1811409,"LogGuid":"c827ae37-ba19-40b7-8898-df1e7aadafa0","Latitude":null,"Longitude":null,"LatLonString":"","LogType":"Found it","LogTypeImage":"icon_smile.gif","LogText":"Mit 5 Nachwuchscachern gut gefunden und trotz einbrechender Dunkelheit bis zum Ende mit Spaß dabei.<br />Coin out<br />TFTC","Created":"03/11/2011","Visited":"03/11/2011","UserName":"DK_fun","MembershipLevel":3,"AccountID":1620132,"AccountGuid":"c66d2a04-1642-4da6-9e95-0ac8b1b266b9","Email":"","AvatarImage":"","GeocacheFindCount":375,"GeocacheHideCount":0,"ChallengesCompleted":0,"IsEncoded":false,"creator":{"GroupTitle":"Premium Member","GroupImageUrl":"/images/icons/prem_user.gif"},"Images":[]},{"LogID":195643419,"CacheID":1811409,"LogGuid":"1c1a2d4a-fd0a-4462-9e39-aa6df4be0178","Latitude":null,"Longitude":null,"LatLonString":"","LogType":"Found it","LogTypeImage":"icon_smile.gif","LogText":"Heute zusammen mit Mr.+Mrs.High diesen schönen Multi gemacht. Diese Ecke kannte ich noch nicht und war begeistert. Die Seilfähre war das Highlight. Da komme ich doch glatt noch mal mit meine Enkelkinder wieder.<br />TFTC","Created":"30/10/2011","Visited":"29/10/2011","UserName":"CacheOma1939","MembershipLevel":1,"AccountID":5161579,"AccountGuid":"0044c291-6398-47d5-ba40-4b4c96d7d055","Email":"","AvatarImage":"","GeocacheFindCount":51,"GeocacheHideCount":0,"ChallengesCompleted":0,"IsEncoded":false,"creator":{"GroupTitle":"Member","GroupImageUrl":"/images/icons/reg_user.gif"},"Images":[]},{"LogID":195636911,"CacheID":1811409,"LogGuid":"103296cd-a78c-4dcf-8ee8-0ccbec2be18a","Latitude":null,"Longitude":null,"LatLonString":"","LogType":"Write note","LogTypeImage":"icon_note.gif","LogText":"TB hinterlegt.","Created":"30/10/2011","Visited":"29/10/2011","UserName":"mr.+mrs.high","MembershipLevel":3,"AccountID":2258748,"AccountGuid":"3fa5cc93-e4e5-4ea8-b88b-3056856a147f","Email":"","AvatarImage":"81b34943-cf75-40cb-a155-ff9c28599d9a.jpg","GeocacheFindCount":1414,"GeocacheHideCount":2,"ChallengesCompleted":0,"IsEncoded":false,"creator":{"GroupTitle":"Premium Member","GroupImageUrl":"/images/icons/prem_user.gif"},"Images":[]},{"LogID":195636607,"CacheID":1811409,"LogGuid":"b921ec7a-bb3c-4094-aee5-e6c3e07c6c4d","Latitude":null,"Longitude":null,"LatLonString":"","LogType":"Found it","LogTypeImage":"icon_smile.gif","LogText":"<b><font color=\"green\">Diese schöne Runde sind wir mit CacheOma 1939 abgegangen. Wir werden wohl mal mit den Nichten wieder kommen,weil da können sie sich mal richtig austoben.Danke fürs zeigen dieses tollen Waldes.<br />TFTC<br /><br />In: TB</font></b>","Created":"30/10/2011","Visited":"29/10/2011","UserName":"mr.+mrs.high","MembershipLevel":3,"AccountID":2258748,"AccountGuid":"3fa5cc93-e4e5-4ea8-b88b-3056856a147f","Email":"","AvatarImage":"81b34943-cf75-40cb-a155-ff9c28599d9a.jpg","GeocacheFindCount":1414,"GeocacheHideCount":2,"ChallengesCompleted":0,"IsEncoded":false,"creator":{"GroupTitle":"Premium Member","GroupImageUrl":"/images/icons/prem_user.gif"},"Images":[{"ImageID":12520555,"ImageGuid":"adc5f6e5-1094-4a82-9cd5-e4415ed0eefa","Name":"Dat war ne Gaudi","Descr":"","FileName":"adc5f6e5-1094-4a82-9cd5-e4415ed0eefa.jpg","Created":"07/11/2011","LogID":195636607,"CacheID":1811409,"ImageUrl":null}]},{"LogID":195374344,"CacheID":1811409,"LogGuid":"da7ed7e4-4eb2-4cbb-87ca-25ba5647e55b","Latitude":null,"Longitude":null,"LatLonString":"","LogType":"Found it","LogTypeImage":"icon_smile.gif","LogText":"Heute einfach nochmal mit den Hunden hin, ohne Kinder und mit etwas mehr Zeit und Ruhe vom Instinkt leiten lassen. Und siehe da: ein Döschen.<br /><br />Dfdc","Created":"29/10/2011","Visited":"29/10/2011","UserName":"ceewee","MembershipLevel":3,"AccountID":2828282,"AccountGuid":"f3b9e609-633b-43af-9e34-1f8f54b86a9e","Email":"","AvatarImage":"c66d884a-742f-4fc1-832b-0ebd2d9d7d7d.jpg","GeocacheFindCount":470,"GeocacheHideCount":2,"ChallengesCompleted":3,"IsEncoded":false,"creator":{"GroupTitle":"Premium Member","GroupImageUrl":"/images/icons/prem_user.gif"},"Images":[]},{"LogID":194769701,"CacheID":1811409,"LogGuid":"b61445ed-a6b7-44bc-af4e-1123ecd6dbb1","Latitude":null,"Longitude":null,"LatLonString":"","LogType":"Owner Maintenance","LogTypeImage":"icon_maint.gif","LogText":"So, am Wochenende alles kontrolliert. Die ehemalige Villa Kunterbunt scheint Vandalen zum Opfer gefallen zu sein, auch die Tipis sind nicht mehr wirklich gut zu erkennen. Die Fragen habe ich daher angepasst.<br />Sowohl die Blume als auch die Seilfähre sind ohne Probleme machbar. Da sich anscheinend nicht jeder die Seilfähre zutraut bzw. die Fähre im Winter abgebaut wird, können die Final-KOs jetzt auch ohne diese Station ermittelt werden <img src=\"/images/icons/icon_smile_big.gif\" border=\"0\" align=\"middle\" />","Created":"25/10/2011","Visited":"25/10/2011","UserName":"Tom03","MembershipLevel":1,"AccountID":2025274,"AccountGuid":"9a28b2fb-bce9-481f-87bc-7c5f4bafe723","Email":"","AvatarImage":"07375e3c-fdf0-4d4f-b4f6-34fc4c5c5a24.jpg","GeocacheFindCount":152,"GeocacheHideCount":2,"ChallengesCompleted":2,"IsEncoded":false,"creator":{"GroupTitle":"Member","GroupImageUrl":"/images/icons/reg_user.gif"},"Images":[]},{"LogID":193961644,"CacheID":1811409,"LogGuid":"a3767f1f-8b92-4153-9cc9-b645c058cdf4","Latitude":null,"Longitude":null,"LatLonString":"","LogType":"Didn't find it","LogTypeImage":"icon_sad.gif","LogText":"Wir konnten den Kindern hier heute leider auch keinen Schatz zeigen.<br />An der PlumklosVilla wurden Bretter ausgebessert und ich nehme an das viele Holzkreise fehlen, da es nach der Formel mehr sein sollten wie Schafe.<br />Die Fähre finde ich für Kinder auch zu tricky und trotz Quersumme, und verschiedene Finalanläufe konnte wir hier nicht zum Ziel gelangen, schade.","Created":"22/10/2011","Visited":"22/10/2011","UserName":"ceewee","MembershipLevel":3,"AccountID":2828282,"AccountGuid":"f3b9e609-633b-43af-9e34-1f8f54b86a9e","Email":"","AvatarImage":"c66d884a-742f-4fc1-832b-0ebd2d9d7d7d.jpg","GeocacheFindCount":470,"GeocacheHideCount":2,"ChallengesCompleted":3,"IsEncoded":false,"creator":{"GroupTitle":"Premium Member","GroupImageUrl":"/images/icons/prem_user.gif"},"Images":[]},{"LogID":192928382,"CacheID":1811409,"LogGuid":"ae235a1b-3bd1-4ffe-b281-ac4c75717b1f","Latitude":null,"Longitude":null,"LatLonString":"","LogType":"Didn't find it","LogTypeImage":"icon_sad.gif","LogText":"Zusammen mit TheUnforgiven81 sollte dieser Multi auf einer gemütlichen Fahrrad-Cachetour mitgenommen werden. Wir fingen von \"hinten\" an und mussten leider schon bei der Seilfähre aufgeben. Wir hatten wohl irgendwie Tomaten auf den Augen...<br />Litis","Created":"16/10/2011","Visited":"16/10/2011","UserName":"Litis","MembershipLevel":1,"AccountID":4360540,"AccountGuid":"5eb5d151-c902-4edf-ba5c-20f3024aa256","Email":"","AvatarImage":"80eb3f0d-e8b2-4ecb-b1fc-fd71b5cd1288.jpg","GeocacheFindCount":266,"GeocacheHideCount":1,"ChallengesCompleted":2,"IsEncoded":false,"creator":{"GroupTitle":"Member","GroupImageUrl":"/images/icons/reg_user.gif"},"Images":[]},{"LogID":190838992,"CacheID":1811409,"LogGuid":"aade0fb8-fc36-4fef-92d0-355f98d24012","Latitude":null,"Longitude":null,"LatLonString":"","LogType":"Found it","LogTypeImage":"icon_smile.gif","LogText":"Meinen 100. gefundenen Cache habe ich mir für einen Besuch bei guten Freunden aufgehoben. Mit den Kindern haben wir dieses schönes Multi gehoben. Eine Station hat mir ziemlich nasse Wanderstiefel eingebracht. Leider ist die Villa Kunterbunt arg mitgenommen und als solche nicht mehr zu erkennen. Außerdem fehlten die Holzscheiben komplett, sodass man das Ergebnis raten oder - besser - anhand eines der Fotos wenigstens ziemlich gut schätzen kann. Am Ende hatten wir ein Tippi zu wenig gezählt und eine Holzscheibe zu viel vermutet. Mit einer kleinen Korrektur war das Final kein Problem mehr.<br />Also lieber Owner: Wartung ist notwendig, ansonsten ein netter Multi. Danke!","Created":"05/10/2011","Visited":"03/10/2011","UserName":"Packapacka","MembershipLevel":1,"AccountID":1407315,"AccountGuid":"6a6bc47e-5b45-432c-9e83-bad2d74bfe2b","Email":"","AvatarImage":"","GeocacheFindCount":102,"GeocacheHideCount":7,"ChallengesCompleted":0,"IsEncoded":false,"creator":{"GroupTitle":"Member","GroupImageUrl":"/images/icons/reg_user.gif"},"Images":[]},{"LogID":190604619,"CacheID":1811409,"LogGuid":"1688c4f1-4884-410c-9bef-aba261848492","Latitude":null,"Longitude":null,"LatLonString":"","LogType":"Didn't find it","LogTypeImage":"icon_sad.gif","LogText":"Also das war leider ein Reinfall.<br />Wir waren mit 3 Erwachsenen und 2 hoch motivierten Kindern unterwegs. Leider gab es mit vielen Stationen Probleme. Das Zählen der Tipis ist stark mehrdeutig. Jeder von uns hatte eine andere Zahl ermittelt. Eine lachende Blume gibt es am Marterpfahl auch nicht mehr, weil hier jemand mit dem Messer rumgemetzelt hat. <br />Eine Villa Kunterbund haben wir so auch nicht gefunden. In dem Wegabschnitt gibt es eigentlich nur eine \"Donnerbalkenhütte\", sprich Plumsklo. Dort war keine Wand mit irgendwelchen runden Holzstücken zu finden.<br />Der Hinweis an der Seilfähre ist für einen Cache der sich Kindercache nennt ein paar Nummern zu anspruchsvoll.<br />Auf diese Art haben wir keine vernünftigen Koordinaten ermitteln können und die Kids waren schon recht traurig, dass wir keinen \"Schatz\" gefunden haben. <br />Ohne Vorinformation aus anderen Quellen lässt sich dieser Cache meines Erachtens nicht lösen. Schade!","Created":"04/10/2011","Visited":"03/10/2011","UserName":"AnDiLa","MembershipLevel":1,"AccountID":737513,"AccountGuid":"852f3105-639d-4f3b-a260-dcfbdab4b51f","Email":"","AvatarImage":"46b3f894-d5b1-45ce-89ee-200bb89ef838.jpg","GeocacheFindCount":330,"GeocacheHideCount":1,"ChallengesCompleted":0,"IsEncoded":false,"creator":{"GroupTitle":"Member","GroupImageUrl":"/images/icons/reg_user.gif"},"Images":[]},{"LogID":186141387,"CacheID":1811409,"LogGuid":"f5def3ff-daea-4810-8ba1-7db3a1774d5f","Latitude":null,"Longitude":null,"LatLonString":"","LogType":"Found it","LogTypeImage":"icon_smile.gif","LogText":"Ein wirklich schön gemachter Kindercache, der schon am anfang mit viel Spaß und Gelächter begann ( Seilfähre) wir hatten zum Glück noch Wechselkleidung dabei. Die ganze Familie hat bei diesen Cach viel Spaß gehabt. Und da wir mit W4-taem auf der suche wahren konnte sich der Cache auch nicht lange verbergen. <br />Ein toller Cache und ein sehr schönes Gelände;-))) <br />Danke <br />Vier????","Created":"12/09/2011","Visited":"12/09/2011","UserName":"vier????","MembershipLevel":1,"AccountID":3643149,"AccountGuid":"c1f4e8d3-b7be-4740-8891-3bc37ba0c506","Email":"","AvatarImage":"","GeocacheFindCount":346,"GeocacheHideCount":0,"ChallengesCompleted":1,"IsEncoded":false,"creator":{"GroupTitle":"Member","GroupImageUrl":"/images/icons/reg_user.gif"},"Images":[{"ImageID":12016097,"ImageGuid":"8e37c011-3e11-4333-b69c-56e990a6c13c","Name":"","Descr":"Ein wirklich schön gemachter Kindercache, der schon am anfang mit viel Spaß und Gelächter begann ( Seilfähre) wir hatten zum Glück noch Wechselkleidung dabei. Die ganze Familie hat bei diesen Cach viel Spaß gehabt. Und da wir mit W4-taem auf der suche wahren konnte sich der Cache auch nicht lange verbergen. \nEin toller Cache und ein sehr schönes Gelände;-))) \nDanke\nVier????","FileName":"8e37c011-3e11-4333-b69c-56e990a6c13c.jpg","Created":"12/09/2011","LogID":186141387,"CacheID":1811409,"ImageUrl":null}]},{"LogID":185911335,"CacheID":1811409,"LogGuid":"8dd5870e-46ef-4162-9897-62acc7a63717","Latitude":null,"Longitude":null,"LatLonString":"","LogType":"Found it","LogTypeImage":"icon_smile.gif","LogText":"Heute mit den vier???? diesen Multi gemacht. Der Start für uns, die Seilbahn hätte fast für einen Abbruch gesorgt. Haben dann, auch wenn etwas nass, trotzdem weiter gemacht<img src=\"/images/icons/icon_smile_big.gif\" border=\"0\" align=\"middle\" />. Bis auf eine Station alles leicht zu lösen. <br />Out: TB <br /><br />Vielen Dank für diesen tollen Multi,<br />sagt das W4-Team","Created":"11/09/2011","Visited":"11/09/2011","UserName":"w4-team","MembershipLevel":3,"AccountID":3663334,"AccountGuid":"445903eb-f768-4d74-b26d-f811ddc50bb7","Email":"","AvatarImage":"b6812751-9eeb-482f-8617-50c9ec47b90d.jpg","GeocacheFindCount":417,"GeocacheHideCount":0,"ChallengesCompleted":19,"IsEncoded":false,"creator":{"GroupTitle":"Premium Member","GroupImageUrl":"/images/icons/prem_user.gif"},"Images":[]},{"LogID":181250482,"CacheID":1811409,"LogGuid":"1b1a53e3-50df-4881-8700-1e9bbec50635","Latitude":null,"Longitude":null,"LatLonString":"","LogType":"Found it","LogTypeImage":"icon_smile.gif","LogText":"hab ihn mit der familie und freundin gefunden...<br />war echt toll...habe sogar einen kleinen tauchgang von der seilfähre runter gemacht <img src=\"/images/icons/icon_smile_big.gif\" border=\"0\" align=\"middle\" /> <br />DFDC !!!","Created":"21/08/2011","Visited":"21/08/2011","UserName":"L8aube","MembershipLevel":1,"AccountID":4939791,"AccountGuid":"6723adb7-2aff-4d9b-836b-87df888a61d0","Email":"","AvatarImage":"","GeocacheFindCount":5,"GeocacheHideCount":0,"ChallengesCompleted":0,"IsEncoded":false,"creator":{"GroupTitle":"Member","GroupImageUrl":"/images/icons/reg_user.gif"},"Images":[{"ImageID":11787263,"ImageGuid":"9ac96f8f-6e63-4087-be94-48a96ffaba67","Name":"seilfähre ","Descr":"kurz vorm tauchgang xD","FileName":"9ac96f8f-6e63-4087-be94-48a96ffaba67.jpg","Created":"21/08/2011","LogID":181250482,"CacheID":1811409,"ImageUrl":null}]},{"LogID":181220910,"CacheID":1811409,"LogGuid":"4b88db68-a5e8-4b37-9d5a-8cc406611457","Latitude":null,"Longitude":null,"LatLonString":"","LogType":"Found it","LogTypeImage":"icon_smile.gif","LogText":"den haben miss4tune und ich im team mit l8aube und gastcacher auf schöner kleiner vormittagsrunde gefunden und geloggt ;-)<br /><br />dfdc","Created":"21/08/2011","Visited":"21/08/2011","UserName":"Sir5al","MembershipLevel":3,"AccountID":3229535,"AccountGuid":"66de7735-1888-479b-8dbd-ada710747374","Email":"","AvatarImage":"9da1d6ed-3a3f-47cb-aba3-f5550abe7d11.jpg","GeocacheFindCount":624,"GeocacheHideCount":1,"ChallengesCompleted":0,"IsEncoded":false,"creator":{"GroupTitle":"Premium Member","GroupImageUrl":"/images/icons/prem_user.gif"},"Images":[{"ImageID":11785894,"ImageGuid":"bfda9eb7-a4ae-4b59-b4d3-7deb3e08cd79","Name":"Upside Down","Descr":"kein Spoiler ;-)","FileName":"bfda9eb7-a4ae-4b59-b4d3-7deb3e08cd79.jpg","Created":"21/08/2011","LogID":181220910,"CacheID":1811409,"ImageUrl":null}]},{"LogID":177793540,"CacheID":1811409,"LogGuid":"20b859cf-216f-48c2-a0b7-d63caadb8086","Latitude":null,"Longitude":null,"LatLonString":"","LogType":"Owner Maintenance","LogTypeImage":"icon_maint.gif","LogText":"So, das Final ist jetzt besser versteckt ! Keine Brennesseln mehr... Die Quersumme stimmt jetzt auch, danke für den Hinweis. Das Original-Logbuch ist jetzt auch wieder in der Dose.... Und um den Spaß-Faktor zu erhöhen habe ich Station F. überarbeitet, hehehe.","Created":"06/08/2011","Visited":"06/08/2011","UserName":"Tom03","MembershipLevel":1,"AccountID":2025274,"AccountGuid":"9a28b2fb-bce9-481f-87bc-7c5f4bafe723","Email":"","AvatarImage":"07375e3c-fdf0-4d4f-b4f6-34fc4c5c5a24.jpg","GeocacheFindCount":152,"GeocacheHideCount":2,"ChallengesCompleted":2,"IsEncoded":false,"creator":{"GroupTitle":"Member","GroupImageUrl":"/images/icons/reg_user.gif"},"Images":[]},{"LogID":175386549,"CacheID":1811409,"LogGuid":"673321ec-75e9-4b1f-89d3-1c568f2f1352","Latitude":null,"Longitude":null,"LatLonString":"","LogType":"Found it","LogTypeImage":"icon_smile.gif","LogText":"Kurzer Fahrradausflug mit Opa und den Kids (Schlenzer2000 und Sopranettchen). Wir haben gezählt, sind ins Wasser gefallen, haben uns nicht beirren lassen und am Final gesucht - nix. Tourdaten nochmal abgefahren, nachgerechnet - stimmt alles. Suchradius ausgeweitet und dann tatsächlich fündig geworden. Leider dem Regenguss nicht entkommen.<br />DFDC, Sopranette<br />#1008","Created":"26/07/2011","Visited":"26/07/2011","UserName":"Sopranette","MembershipLevel":3,"AccountID":1817201,"AccountGuid":"2cb6a31e-1da7-4b90-b844-962c5b76023f","Email":"","AvatarImage":"bd85f298-3276-4d19-a5f2-0cb8187a075c.jpg","GeocacheFindCount":1291,"GeocacheHideCount":18,"ChallengesCompleted":0,"IsEncoded":false,"creator":{"GroupTitle":"Premium Member","GroupImageUrl":"/images/icons/prem_user.gif"},"Images":[]},{"LogID":173168272,"CacheID":1811409,"LogGuid":"a3ec8dfc-fee3-4ea7-939d-147558f68c14","Latitude":null,"Longitude":null,"LatLonString":"","LogType":"Needs Maintenance","LogTypeImage":"icon_needsmaint.gif","LogText":"Ja, stimmt...hatte ich in meinem Log vergessen zu notieren. Ich fand auch nur einen Notizzettel mit diversen Einträgen. Kein Logbuch vorhanden. Wäre schön, wenn das nachgeholt werdenkönnte bzw. ein möglicherweise abhanden gekommenes ersetzt würde.<br /><br />MfG","Created":"16/07/2011","Visited":"16/07/2011","UserName":"euroberlin","MembershipLevel":1,"AccountID":1329392,"AccountGuid":"54b15127-29a6-4749-9a56-5a782a90954d","Email":"","AvatarImage":"d1ea7c15-cd92-417b-a33e-a6ba286ad04f.jpg","GeocacheFindCount":358,"GeocacheHideCount":5,"ChallengesCompleted":0,"IsEncoded":false,"creator":{"GroupTitle":"Member","GroupImageUrl":"/images/icons/reg_user.gif"},"Images":[]},{"LogID":173093539,"CacheID":1811409,"LogGuid":"c3858175-ba9d-47b2-a7f7-03bd22f510ff","Latitude":null,"Longitude":null,"LatLonString":"","LogType":"Found it","LogTypeImage":"icon_smile.gif","LogText":"Heute wollten wir mal Oma zeigen, was Geocachen ist... Dafür bot sich dieser Kindercache an und wir zogen los, diesen großen Spielplatz unsicher zu machen. Alles lief wie am Schnürchen - bis zum Finale. Die Quersumme stimmte, die Final-KO`s waren eingegeben, doch wo war die Dose??? Es brauchte einige Zeit bis diese ausgemacht war und einige Überwindung sich mit kurzen Hosen durch die Brennessel zu schlagen. Die Dose passte dann irgendwie nicht zu diesem wirklich schönen Cache. Für einen Kindercache war die Dose recht klein und ein richtiges Log-Buch war nicht vorhanden. Schade eigentlich. Daher kleine Abzüge in der B-Note. Trotzdem kommt Oma bestimmt nochmal mit ;-) ......<br /><br />Die LFW-Schnüffler","Created":"16/07/2011","Visited":"16/07/2011","UserName":"LFW-Schnüffler","MembershipLevel":3,"AccountID":2717413,"AccountGuid":"6062f301-7690-4f38-9772-4f94de5e5f56","Email":"","AvatarImage":"dd298bd3-1af9-4f3c-9d8b-ddfdfe746e56.jpg","GeocacheFindCount":325,"GeocacheHideCount":0,"ChallengesCompleted":2,"IsEncoded":false,"creator":{"GroupTitle":"Premium Member","GroupImageUrl":"/images/icons/prem_user.gif"},"Images":[]},{"LogID":173063969,"CacheID":1811409,"LogGuid":"2ac5515f-da8a-4e4f-9797-f682cf119f7a","Latitude":null,"Longitude":null,"LatLonString":"","LogType":"Found it","LogTypeImage":"icon_smile.gif","LogText":"Mhh Wochenende, gutes Wetter und Ferien...ja, das sind ja gleich drei Dinge auf einmal..das geht nun wirklich nicht - doch! geht wohl! Diesen wollte ich heute abgehen und bemerkte doch sogleich, dass sich eine Familie (Vater, Mutter, zwei Kinder) auffällig unauffällig in bester Geocacher Weise durch den Kinderwald bewegten. Ich tat dies in gebührendem Abstand ebenfalls und so unauffällig, dass die hier überall \"herumstreunenden\" Kinder nichts mitbekamen :) Am Final musste ich mit meinem zweirädrigen Cachemobil zunächst unauffällig weiterfahren, da besagte \"Konkurrenz\" wie wild in der Botanik am Suchen war :) ca. 20 Minuten später erfolgte ein erneutes Heranpirschen meinerseits, doch die Konkurrenz war noch nicht so weit - ich konnte aber schon das Eintragen ins Logbuch beobachten. Spätestens jetzt wusste ich, dass die errechneten KO´s stimmig sind (auch wenn meine Quersumme 48 ergibt!). Nach einer weiteren kurzen Wartezeit konnte ich das kleine Döschen dann auch endlich suchen. Und es war dank einer recht eindeutigen \"Cacherautobahn\" auch ganz fix gefunden. Ich habe die Tarnung ein bisschen verstärkt. Ein sehr angenehmer Multicache, der mir jedoch an der \"Villa Kunterbunt\"-Station ein bisschen Sorgen machte. Ich brauchte hier doch glatt drei Anläufe um besagte Villa als solche zu identifizieren. Ob der Name so passend ist...ich weiß nicht. Die Villa trägt ja noch einen anderen weit hin sichtbaren Namen, der ist viel passender und auch der Grund, warum ich die Villa nicht sofort erkannt habe :-)<br /><br />Vielen Dank für den Cache... endlich mal wieder einer hier... nachdem der NC, der hier mal lag, von mir leider nicht beendet werden konnte.<br /><br />Viele Grüße!","Created":"16/07/2011","Visited":"16/07/2011","UserName":"euroberlin","MembershipLevel":1,"AccountID":1329392,"AccountGuid":"54b15127-29a6-4749-9a56-5a782a90954d","Email":"","AvatarImage":"d1ea7c15-cd92-417b-a33e-a6ba286ad04f.jpg","GeocacheFindCount":358,"GeocacheHideCount":5,"ChallengesCompleted":0,"IsEncoded":false,"creator":{"GroupTitle":"Member","GroupImageUrl":"/images/icons/reg_user.gif"},"Images":[]},{"LogID":194857848,"CacheID":1811409,"LogGuid":"ea0cfc42-738a-4a5b-8b62-8bddf9d987d4","Latitude":null,"Longitude":null,"LatLonString":"","LogType":"Found it","LogTypeImage":"icon_smile.gif","LogText":"Habe jetzt endlich mein eigenes Konto und logge meine Fünde nach. Danke für den Cache! MitCacherTochter","Created":"25/10/2011","Visited":"22/06/2011","UserName":"MitCacherTochter","MembershipLevel":1,"AccountID":5172770,"AccountGuid":"fdd335f8-1c55-4f01-9218-5bc1ac6eefbd","Email":"","AvatarImage":"7d02f96f-98d3-4b14-a41d-644dc5272231.jpg","GeocacheFindCount":165,"GeocacheHideCount":0,"ChallengesCompleted":0,"IsEncoded":false,"creator":{"GroupTitle":"Member","GroupImageUrl":"/images/icons/reg_user.gif"},"Images":[]},{"LogID":168242205,"CacheID":1811409,"LogGuid":"e675ecb7-4527-444c-a20b-99ed331bff79","Latitude":null,"Longitude":null,"LatLonString":"","LogType":"Found it","LogTypeImage":"icon_smile.gif","LogText":"Wunderbar, ein echter Kindermulti, Kinder, sowie Erwachsene hatten viel Spaß auf dieser Runde! Schöne und gut erreichbare ZS, auch die Dose war gut für die Kinder zu finden und die Freude war groß;-) ein Erfolgserlebnis! DfdC ","Created":"22/06/2011","Visited":"22/06/2011","UserName":"-Sunrise-","MembershipLevel":1,"AccountID":4478343,"AccountGuid":"88965e17-b4d4-4c28-9359-170b72e8c9c8","Email":"","AvatarImage":"4d9018e7-66d9-4eed-a0b4-a9050242fcb2.jpg","GeocacheFindCount":664,"GeocacheHideCount":0,"ChallengesCompleted":1,"IsEncoded":false,"creator":{"GroupTitle":"Member","GroupImageUrl":"/images/icons/reg_user.gif"},"Images":[]}], "pageInfo": { "idx":1, "size": 25, "totalRows": 83, "rows": 83 } };
+//]]>
+</script>
+</form>
+ <script type="text/javascript">
+ var browserType = {
+ IE: !!(window.attachEvent && !window.opera),
+ Opera: !!window.opera,
+ WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
+ Gecko: navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1,
+ MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/)
+ };
+
+ $(function () {
+ // Make the menu system play nice with all browsers:
+ $('ul.Menu li').hover(function () {
+ $(this).addClass('hover');
+ $('ul:first', this).css('visibility', 'visible');
+ }, function () {
+ $(this).removeClass('hover');
+ $('ul:first', this).css('visibility', 'hidden');
+ });
+ if (!isiOS()) {
+ // Constructing a Twitter-esque Login:
+ $(".SignInLink").click(function (e) {
+ e.preventDefault();
+ $("#SignInWidget").toggle();
+ $(".ProfileWidget").toggleClass("WidgetOpen");
+ $(this).blur();
+ $("#ctl00_tbUsername").focus();
+ });
+ $(".SignInCloseLink").click(function () {
+ $("#SignInWidget").toggle();
+ $(".ProfileWidget").toggleClass("WidgetOpen");
+ });
+ }
+ $('.SignedInProfileLink').truncate({
+ width: 120,
+ after: '&hellip;',
+ center: false,
+ addclass: false,
+ addtitle: false
+ });
+ // Hide the warning message if the user closed it already
+ if ($.cookie('hide_warning') != null) {
+ $(".WarningMessage").hide();
+ }
+
+ function isiOS() {
+ return (
+ (navigator.userAgent.match(/(iPhone)|(iPod)|(iPad)/i))
+ );
+ }
+ });
+ </script>
+
+ <script id="loc_favPointsWhatsThisDesc" type="text/html">
+ Geocaching Favorites is a simple way to track and share the caches that you enjoyed the most. For every 10 distinct caches that you have found, you will be able to Favorite 1 exceptional cache in your find history. The Favorites accumulated by a cache are displayed in search results and on the cache page so everyone can see which caches stand above the rest.
+ </script>
+ <script id="loc_favPointsWhatsThisTitle" type="text/html">
+ About Favorite Points
+ </script>
+ <script id="loc_favPointsScoreDesc" type="text/html">
+ Favorites/Premium Logs
+ </script>
+ <script type="text/javascript" language="javascript">
+ <!--
+
+ $('#uxFavPointsWhatsThis').qtip({
+ content: {
+ text: $("#loc_favPointsWhatsThisDesc").html(),
+ title: {
+ text: $("#loc_favPointsWhatsThisTitle").html(),
+ button: true
+ }
+ },
+ position: {
+ my: 'top center',
+ at: 'bottom center'
+ },
+ show: {
+ event: 'click'
+ },
+ hide: 'click unfocus',
+ style: {
+ classes: 'ui-tooltip'
+ }
+ })
+
+ var gotScore = false;
+ var favDropDown = $('.favorite-dropdown');
+ var favContainer = $('.favorite-container');
+
+ function showFavoriteScore() {
+ $('#imgFavoriteScore').attr('src', '/images/loading3.gif');
+
+ $('#uxFavoriteScore').parent().fadeTo(200, .001, function () {
+ $.ajax({
+ type: "POST",
+ cache: false,
+ url: '/datastore/favorites.svc/score?u=' + userToken,
+ success: function (scoreResult) {
+ gotScore = true;
+
+ var score = 0;
+
+ if(scoreResult)
+ score = scoreResult;
+
+ if(score > 100)
+ score = 100;
+
+ $('#imgFavoriteScore').attr('src', '/images/favorites/piecharts/' + score + '.png');
+ var pieDesc = (score < 1 ? "<1" : score) + '% ' + $("#loc_favPointsScoreDesc").text().trim();
+ $('#imgFavoriteScore').attr('alt', pieDesc);
+ $('#imgFavoriteScore').attr('title', pieDesc);
+
+ $('#uxFavoriteScore').parent().fadeTo(1000, 1);
+ $('#uxFavoriteScore').html('<strong>' + (score < 1 ? "<1" : score) + '%</strong> ' + $("#loc_favPointsScoreDesc").html());
+ }
+ });
+ });
+ }
+
+
+
+ $(document).bind('mouseup', function (e) {
+ var $clicked = $(e.target);
+
+
+ if (!$clicked.parents().hasClass("favorite-dropdown") && !$clicked.parents().hasClass("FavoriteWidget")) {
+ favDropDown.hide(1, function () {
+ favContainer.addClass('favorite-container');
+ favContainer.removeClass('favorite-container-open');
+ $('#imgFavoriteArrow').attr('src', '/images/arrow-down.png');
+ });
+ }
+ });
+
+ $('#uxFavContainerLink').click(function () {
+ if ($(favDropDown).is(':visible')) {
+ favDropDown.hide(1, function(){
+ favContainer.addClass('favorite-container');
+ favContainer.removeClass('favorite-container-open');
+ $('#imgFavoriteArrow').attr('src', '/images/arrow-down.png');
+ });
+ }
+ else {
+ if (!gotScore) {
+ showFavoriteScore();
+ }
+
+ favContainer.addClass('favorite-container-open');
+ favContainer.removeClass('favorite-container');
+ $('#imgFavoriteArrow').attr('src', '/images/arrow-up.png');
+ favDropDown.show(1);
+ }
+ });
+ // End -->
+ </script>
+
+
+ <script type="text/javascript">
+ var _gaq = _gaq || [];
+ _gaq.push(['_setAccount', 'UA-2020240-1']);
+ _gaq.push(['_trackPageview']);
+ (function () {
+ var ga = document.createElement('script');
+ ga.src = ('https:' == document.location.protocol ?
+ 'https://ssl' : 'http://www') +
+ '.google-analytics.com/ga.js';
+ ga.setAttribute('async', 'true');
+ document.documentElement.firstChild.appendChild(ga);
+ })();
+ $(function () {
+ $("a.language").click(function (e) {
+ e.preventDefault();
+ window.location.replace(window.location.href + (window.location.search.indexOf("?") == -1 ? "?" : "&") + "lang=" + $(this).attr("lang"));
+ });
+ });
+ </script>
+
+
+ <!-- Quantcast Tag -->
+ <div id="Quantcast">
+ <script type="text/javascript">
+ var _qevents = _qevents || [];
+
+ (function () {
+ var elem = document.createElement('script');
+
+ elem.src = (document.location.protocol == "https:" ? "https://secure" : "http://edge") + ".quantserve.com/quant.js";
+ elem.async = true;
+ elem.type = "text/javascript";
+ var scpt = document.getElementsByTagName('script')[0];
+ scpt.parentNode.insertBefore(elem, scpt);
+ })();
+ </script>
+ <script type="text/javascript">
+ _qevents.push({ qacct: "p-f6VPrfmR4cujU" });
+ </script>
+ <noscript>
+ <div style="display: none;">
+ <img src="http://pixel.quantserve.com/pixel/p-f6VPrfmR4cujU.gif" height="1" width="1"
+ alt="Quantcast" /></div>
+ </noscript>
+ </div>
+ <!-- End Quantcast tag -->
+
+ <!-- Server: WEB02; Build: Web.HotFix_20120213.4 -->
+</body>
+</html>
diff --git a/tests/src/cgeo/CGeoTestCase.java b/tests/src/cgeo/CGeoTestCase.java new file mode 100644 index 0000000..31fde34 --- /dev/null +++ b/tests/src/cgeo/CGeoTestCase.java @@ -0,0 +1,19 @@ +package cgeo; + +import cgeo.geocaching.cgeoapplication; + +import android.test.ApplicationTestCase; + +public abstract class CGeoTestCase extends ApplicationTestCase<cgeoapplication> { + + public CGeoTestCase() { + super(cgeoapplication.class); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + createApplication(); + } + +} diff --git a/tests/src/cgeo/geocaching/CacheTest.java b/tests/src/cgeo/geocaching/CacheTest.java index a76764d..e1d6efb 100644 --- a/tests/src/cgeo/geocaching/CacheTest.java +++ b/tests/src/cgeo/geocaching/CacheTest.java @@ -25,4 +25,20 @@ public class CacheTest extends AndroidTestCase { assertFalse(cacheYesterday.canBeAddedToCalendar()); } + public static void testEquality() { + final cgCache one = new cgCache(); + final cgCache two = new cgCache(); + + // identity + assertTrue(one.equals(one)); + + // different objects without geocode shall not be equal + assertFalse(one.equals(two)); + + one.setGeocode("geocode"); + two.setGeocode("geocode"); + + // different objects with same geocode shall be equal + assertTrue(one.equals(two)); + } } diff --git a/tests/src/cgeo/geocaching/cgDestinationTest.java b/tests/src/cgeo/geocaching/DestinationTest.java index cb5fe45..26caacd 100644 --- a/tests/src/cgeo/geocaching/cgDestinationTest.java +++ b/tests/src/cgeo/geocaching/DestinationTest.java @@ -6,14 +6,14 @@ import android.test.AndroidTestCase; import junit.framework.Assert; -public class cgDestinationTest extends AndroidTestCase { +public class DestinationTest extends AndroidTestCase { - private cgDestination dest = null; + private Destination dest = null; @Override protected void setUp() throws Exception { super.setUp(); - dest = new cgDestination(1, 10000, new Geopoint(52.5, 9.33)); + dest = new Destination(1, 10000, new Geopoint(52.5, 9.33)); } public void testSomething() { diff --git a/tests/src/cgeo/geocaching/HtmlPerformanceTest.java b/tests/src/cgeo/geocaching/HtmlPerformanceTest.java index 735dc74..b08b06e 100644 --- a/tests/src/cgeo/geocaching/HtmlPerformanceTest.java +++ b/tests/src/cgeo/geocaching/HtmlPerformanceTest.java @@ -1,11 +1,12 @@ package cgeo.geocaching; +import cgeo.geocaching.utils.Log; + import org.apache.commons.lang3.StringEscapeUtils; import android.os.SystemClock; import android.test.AndroidTestCase; import android.text.Html; -import android.util.Log; public class HtmlPerformanceTest extends AndroidTestCase { private String input; @@ -55,7 +56,7 @@ public class HtmlPerformanceTest extends AndroidTestCase { final long start = SystemClock.elapsedRealtime(); runnable.run(); final long end = SystemClock.elapsedRealtime(); - Log.d(Settings.tag, label + ": " + (end - start) + " ms"); + Log.d(label + ": " + (end - start) + " ms"); return end - start; } } diff --git a/tests/src/cgeo/geocaching/SearchResultTest.java b/tests/src/cgeo/geocaching/SearchResultTest.java new file mode 100644 index 0000000..8fcd188 --- /dev/null +++ b/tests/src/cgeo/geocaching/SearchResultTest.java @@ -0,0 +1,17 @@ +package cgeo.geocaching; + +import android.test.AndroidTestCase; + +import java.util.HashSet; + +public class SearchResultTest extends AndroidTestCase { + public static void testCreateFromGeocodes() { + final HashSet<String> geocodes = new HashSet<String>(); + geocodes.add("GC12345"); + geocodes.add("GC23456"); + final SearchResult searchResult = new SearchResult(geocodes); + assertEquals(2, searchResult.getCount()); + assertEquals(2, searchResult.getTotal()); + assertTrue(searchResult.getGeocodes().contains("GC12345")); + } +} diff --git a/tests/src/cgeo/geocaching/SettingsTest.java b/tests/src/cgeo/geocaching/SettingsTest.java index c31e635..27395ec 100644 --- a/tests/src/cgeo/geocaching/SettingsTest.java +++ b/tests/src/cgeo/geocaching/SettingsTest.java @@ -1,7 +1,6 @@ package cgeo.geocaching; -import cgeo.geocaching.Settings; -import cgeo.geocaching.cgeo; +import org.mapsforge.android.maps.MapDatabase; import android.test.ActivityInstrumentationTestCase2; @@ -21,7 +20,9 @@ public class SettingsTest extends ActivityInstrumentationTestCase2<cgeo> { * this should work fine without an exception (once there was an exception because of the empty map file string) */ public static void testSettingsException() { - // asserts A OR NOT A, because we don't know what the settings are on any device or emulator - assertTrue(Settings.isValidMapFile() || !Settings.isValidMapFile()); + final String mapFile = Settings.getMapFile(); + assertNotNull(mapFile); + // We just want to ensure that it does not throw any exception but we do not know anything about the result + MapDatabase.isValidMapFile(mapFile); } } diff --git a/tests/src/cgeo/geocaching/TrackablesTest.java b/tests/src/cgeo/geocaching/TrackablesTest.java index 1d3d165..3cb34a6 100644 --- a/tests/src/cgeo/geocaching/TrackablesTest.java +++ b/tests/src/cgeo/geocaching/TrackablesTest.java @@ -1,5 +1,6 @@ package cgeo.geocaching; +import cgeo.geocaching.connector.gc.GCParser; import cgeo.geocaching.test.AbstractResourceInstrumentationTestCase; import cgeo.geocaching.test.R; import cgeo.geocaching.utils.BaseUtils; @@ -9,16 +10,16 @@ import java.util.List; public class TrackablesTest extends AbstractResourceInstrumentationTestCase { public void testLogPageWithTrackables() { - List<cgTrackableLog> tbLogs = cgBase.parseTrackableLog(getFileContent(R.raw.log_with_2tb)); + List<TrackableLog> tbLogs = GCParser.parseTrackableLog(getFileContent(R.raw.log_with_2tb)); assertNotNull(tbLogs); assertEquals(2, tbLogs.size()); - cgTrackableLog log = tbLogs.get(0); + TrackableLog log = tbLogs.get(0); assertEquals("Steffen's Kaiserwagen", log.name); assertEquals("1QG1EE", log.trackCode); } public void testLogPageWithoutTrackables() { - List<cgTrackableLog> tbLogs = cgBase.parseTrackableLog(getFileContent(R.raw.log_without_tb)); + List<TrackableLog> tbLogs = GCParser.parseTrackableLog(getFileContent(R.raw.log_without_tb)); assertNotNull(tbLogs); assertEquals(0, tbLogs.size()); } @@ -40,20 +41,20 @@ public class TrackablesTest extends AbstractResourceInstrumentationTestCase { final cgTrackable trackable = getTBXATG(); assertEquals("TBXATG", trackable.getGeocode()); - List<cgLog> log = trackable.getLogs(); + List<LogEntry> log = trackable.getLogs(); // second log entry has several images; just check first two - assertEquals("http://img.geocaching.com/track/log/large/f2e24c50-394c-4d74-8fb4-87298d8bff1d.jpg", log.get(1).logImages.get(0).getUrl()); - assertEquals("7b Welcome to Geowoodstock", log.get(1).logImages.get(0).getTitle()); - assertEquals("http://img.geocaching.com/track/log/large/b57c29c3-134e-4202-a2a1-69ce8920b055.jpg", log.get(1).logImages.get(1).getUrl()); - assertEquals("8 Crater Lake Natl Park Oregon", log.get(1).logImages.get(1).getTitle()); + assertEquals("http://img.geocaching.com/track/log/large/f2e24c50-394c-4d74-8fb4-87298d8bff1d.jpg", log.get(1).getLogImages().get(0).getUrl()); + assertEquals("7b Welcome to Geowoodstock", log.get(1).getLogImages().get(0).getTitle()); + assertEquals("http://img.geocaching.com/track/log/large/b57c29c3-134e-4202-a2a1-69ce8920b055.jpg", log.get(1).getLogImages().get(1).getUrl()); + assertEquals("8 Crater Lake Natl Park Oregon", log.get(1).getLogImages().get(1).getTitle()); // third log entry has one image - assertEquals("http://img.geocaching.com/track/log/large/0096b42d-4d10-45fa-9be2-2d08c0d5cc61.jpg", log.get(2).logImages.get(0).getUrl()); - assertEquals("Traverski's GC Univ coin on tour", log.get(2).logImages.get(0).getTitle()); + assertEquals("http://img.geocaching.com/track/log/large/0096b42d-4d10-45fa-9be2-2d08c0d5cc61.jpg", log.get(2).getLogImages().get(0).getUrl()); + assertEquals("Traverski's GC Univ coin on tour", log.get(2).getLogImages().get(0).getTitle()); } public void testParseTrackableWithoutReleaseDate() { - cgTrackable trackable = cgBase.parseTrackable(getFileContent(R.raw.tb14wfv), null, null); + cgTrackable trackable = GCParser.parseTrackable(getFileContent(R.raw.tb14wfv), null, null); assertNotNull(trackable); assertEquals("The Brickster", trackable.getName()); assertEquals("Adrian C", trackable.getOwner()); @@ -66,11 +67,11 @@ public class TrackablesTest extends AbstractResourceInstrumentationTestCase { } private cgTrackable getTB2R124() { - return cgBase.parseTrackable(BaseUtils.replaceWhitespace(getFileContent(R.raw.trackable_tb2r124)), null, null); + return GCParser.parseTrackable(BaseUtils.replaceWhitespace(getFileContent(R.raw.trackable_tb2r124)), null, null); } private cgTrackable getTBXATG() { - return cgBase.parseTrackable(BaseUtils.replaceWhitespace(getFileContent(R.raw.trackable_tbxatg)), null, null); + return GCParser.parseTrackable(BaseUtils.replaceWhitespace(getFileContent(R.raw.trackable_tbxatg)), null, null); } } diff --git a/tests/src/cgeo/geocaching/cgDataTest.java b/tests/src/cgeo/geocaching/cgDataTest.java index 0625585..3ce6431 100644 --- a/tests/src/cgeo/geocaching/cgDataTest.java +++ b/tests/src/cgeo/geocaching/cgDataTest.java @@ -1,26 +1,16 @@ package cgeo.geocaching; +import cgeo.CGeoTestCase; import cgeo.geocaching.enumerations.CacheType; import cgeo.geocaching.enumerations.LoadFlags; +import cgeo.geocaching.geopoint.Geopoint; +import cgeo.geocaching.geopoint.Viewport; -import android.test.ApplicationTestCase; - +import java.util.Collections; import java.util.HashSet; import java.util.Set; -public class cgDataTest extends ApplicationTestCase<cgeoapplication> { - - public cgDataTest() { - super(cgeoapplication.class); - } - - @Override - protected void setUp() throws Exception { - super.setUp(); - - // init environment - createApplication(); - } +public class cgDataTest extends CGeoTestCase { public static void testStoredLists() { @@ -29,9 +19,10 @@ public class cgDataTest extends ApplicationTestCase<cgeoapplication> { int listId2 = StoredList.STANDARD_LIST_ID; // create caches - final cgCache cache1 = cgBaseTest.createCache(0); - assertNotNull(cache1); - final cgCache cache2 = cgBaseTest.createCache(1); + final cgCache cache1 = new cgCache(); + cache1.setGeocode("Cache 1"); + final cgCache cache2 = new cgCache(); + cache2.setGeocode("Cache 2"); assertNotNull(cache2); try { @@ -51,7 +42,7 @@ public class cgDataTest extends ApplicationTestCase<cgeoapplication> { // save caches to DB (cache1=listId1, cache2=listId1) app.saveCache(cache1, LoadFlags.SAVE_ALL); app.saveCache(cache2, LoadFlags.SAVE_ALL); - assertTrue(app.getAllStoredCachesCount(false, CacheType.ALL, null) >= 2); + assertTrue(app.getAllStoredCachesCount(false, CacheType.ALL) >= 2); // rename list (cache1=listId1, cache2=listId1) assertEquals(1, app.renameList(listId1, "cgData Test (renamed)")); @@ -61,17 +52,17 @@ public class cgDataTest extends ApplicationTestCase<cgeoapplication> { assertEquals("cgData Test (renamed)", list1.title); // move to list (cache1=listId2, cache2=listId2) - app.moveToList(cache1.getGeocode(), listId2); + app.moveToList(Collections.singletonList(cache1), listId2); assertEquals(1, app.getAllStoredCachesCount(false, CacheType.ALL, listId2)); // remove list (cache1=listId2, cache2=listId2) assertTrue(app.removeList(listId1)); // mark dropped (cache1=1, cache2=0) - app.markDropped(cache2.getGeocode()); + app.markDropped(Collections.singletonList(cache2)); // mark stored (cache1=1, cache2=listId2) - app.markStored(cache2.getGeocode(), listId2); + app.markStored(Collections.singletonList(cache2), listId2); assertEquals(2, app.getAllStoredCachesCount(false, CacheType.ALL, listId2)); // drop stored (cache1=0, cache2=0) @@ -90,4 +81,14 @@ public class cgDataTest extends ApplicationTestCase<cgeoapplication> { app.removeList(listId2); } } -}
\ No newline at end of file + + // Check that queries don't throw an exception (see issue #1429). + public static void testLoadWaypoints() { + final Viewport viewport = new Viewport(new Geopoint(-1, -2), new Geopoint(3, 4)); + final cgeoapplication app = cgeoapplication.getInstance(); + app.getWaypointsInViewport(viewport, false, false); + app.getWaypointsInViewport(viewport, false, true); + app.getWaypointsInViewport(viewport, true, false); + app.getWaypointsInViewport(viewport, true, true); + } +} diff --git a/tests/src/cgeo/geocaching/cgeoApplicationTest.java b/tests/src/cgeo/geocaching/cgeoApplicationTest.java index 89c46c4..a754375 100644 --- a/tests/src/cgeo/geocaching/cgeoApplicationTest.java +++ b/tests/src/cgeo/geocaching/cgeoApplicationTest.java @@ -1,27 +1,29 @@ package cgeo.geocaching; +import cgeo.CGeoTestCase; import cgeo.geocaching.connector.ConnectorFactory; import cgeo.geocaching.connector.gc.GCBase; +import cgeo.geocaching.connector.gc.GCParser; +import cgeo.geocaching.connector.gc.Login; import cgeo.geocaching.enumerations.CacheType; import cgeo.geocaching.enumerations.LiveMapStrategy.Strategy; import cgeo.geocaching.enumerations.LoadFlags; import cgeo.geocaching.enumerations.StatusCode; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.geopoint.Viewport; -import cgeo.geocaching.network.Login; import cgeo.geocaching.test.RegExPerformanceTest; import cgeo.geocaching.test.mock.GC1ZXX2; import cgeo.geocaching.test.mock.GC2CJPF; import cgeo.geocaching.test.mock.GC2JVEH; import cgeo.geocaching.test.mock.MockedCache; import cgeo.geocaching.utils.CancellableHandler; +import cgeo.geocaching.utils.Log; +import cgeo.test.Compare; import org.apache.commons.lang3.tuple.ImmutablePair; -import android.test.ApplicationTestCase; import android.test.suitebuilder.annotation.MediumTest; import android.test.suitebuilder.annotation.SmallTest; -import android.util.Log; import java.util.Date; @@ -32,20 +34,7 @@ import junit.framework.Assert; * application and/or context. */ -public class cgeoApplicationTest extends ApplicationTestCase<cgeoapplication> { - - public cgeoApplicationTest() { - super(cgeoapplication.class); - } - - @Override - protected void setUp() throws Exception { - super.setUp(); - - // init environment - createApplication(); - cgBase.initialize(getApplication()); - } +public class cgeoApplicationTest extends CGeoTestCase { /** * The name 'test preconditions' is a convention to signal that if this test @@ -64,7 +53,7 @@ public class cgeoApplicationTest extends ApplicationTestCase<cgeoapplication> { */ @MediumTest public static void testSearchTrackableNotExisting() { - cgTrackable tb = cgBase.searchTrackable("123456", null, null); + cgTrackable tb = GCParser.searchTrackable("123456", null, null); assertNotNull(tb); } @@ -73,7 +62,7 @@ public class cgeoApplicationTest extends ApplicationTestCase<cgeoapplication> { */ @MediumTest public static void testSearchTrackable() { - cgTrackable tb = cgBase.searchTrackable("TB2J1VZ", null, null); + cgTrackable tb = GCParser.searchTrackable("TB2J1VZ", null, null); // fix data assertEquals("aefffb86-099f-444f-b132-605436163aa8", tb.getGuid()); assertEquals("TB2J1VZ", tb.getGeocode()); @@ -100,9 +89,9 @@ public class cgeoApplicationTest extends ApplicationTestCase<cgeoapplication> { */ @MediumTest public static cgCache testSearchByGeocode(final String geocode) { - final SearchResult search = cgBase.searchByGeocode(geocode, null, 0, true, null); + final SearchResult search = cgCache.searchByGeocode(geocode, null, 0, true, null); assertNotNull(search); - if (Settings.isPremiumMember() || search.error == null) { + if (Settings.isPremiumMember() || search.getError() == null) { assertEquals(1, search.getGeocodes().size()); assertTrue(search.getGeocodes().contains(geocode)); return cgeoapplication.getInstance().loadCache(geocode, LoadFlags.LOAD_CACHE_OR_DB); @@ -116,9 +105,9 @@ public class cgeoApplicationTest extends ApplicationTestCase<cgeoapplication> { */ @MediumTest public static void testSearchByGeocodeNotExisting() { - final SearchResult search = cgBase.searchByGeocode("GC123456", null, 0, true, null); + final SearchResult search = cgCache.searchByGeocode("GC123456", null, 0, true, null); assertNotNull(search); - assertEquals(search.error, StatusCode.UNPUBLISHED_CACHE); + assertEquals(StatusCode.UNPUBLISHED_CACHE, search.getError()); } /** @@ -135,7 +124,7 @@ public class cgeoApplicationTest extends ApplicationTestCase<cgeoapplication> { deleteCacheFromDBAndLogout(cache.getGeocode()); - SearchResult search = cgBase.searchByGeocode(cache.getGeocode(), null, StoredList.TEMPORARY_LIST_ID, true, null); + SearchResult search = cgCache.searchByGeocode(cache.getGeocode(), null, StoredList.TEMPORARY_LIST_ID, true, null); assertNotNull(search); assertEquals(1, search.getGeocodes().size()); assertTrue(search.getGeocodes().contains(cache.getGeocode())); @@ -148,7 +137,7 @@ public class cgeoApplicationTest extends ApplicationTestCase<cgeoapplication> { deleteCacheFromDBAndLogout(cache.getGeocode()); - search = cgBase.searchByGeocode(cache.getGeocode(), null, StoredList.TEMPORARY_LIST_ID, true, null); + search = cgCache.searchByGeocode(cache.getGeocode(), null, StoredList.TEMPORARY_LIST_ID, true, null); assertNotNull(search); assertEquals(0, search.getGeocodes().size()); @@ -174,7 +163,7 @@ public class cgeoApplicationTest extends ApplicationTestCase<cgeoapplication> { deleteCacheFromDBAndLogout(cache.getGeocode()); - SearchResult search = cgBase.searchByGeocode(cache.getGeocode(), null, StoredList.TEMPORARY_LIST_ID, true, null); + SearchResult search = cgCache.searchByGeocode(cache.getGeocode(), null, StoredList.TEMPORARY_LIST_ID, true, null); assertNotNull(search); assertEquals(0, search.getGeocodes().size()); @@ -191,7 +180,7 @@ public class cgeoApplicationTest extends ApplicationTestCase<cgeoapplication> { */ @MediumTest public static void testSearchByCoords() { - final SearchResult search = cgBase.searchByCoords(null, new Geopoint("N 52° 24.972 E 009° 35.647"), CacheType.MYSTERY, false); + final SearchResult search = GCParser.searchByCoords(null, new Geopoint("N 52° 24.972 E 009° 35.647"), CacheType.MYSTERY, false); assertNotNull(search); assertTrue(18 <= search.getGeocodes().size()); assertTrue(search.getGeocodes().contains("GC1RMM2")); @@ -202,7 +191,7 @@ public class cgeoApplicationTest extends ApplicationTestCase<cgeoapplication> { */ @MediumTest public static void testSearchByOwner() { - final SearchResult search = cgBase.searchByOwner(null, "blafoo", CacheType.MYSTERY, false); + final SearchResult search = GCParser.searchByOwner(null, "blafoo", CacheType.MYSTERY, false); assertNotNull(search); assertEquals(3, search.getGeocodes().size()); assertTrue(search.getGeocodes().contains("GC36RT6")); @@ -213,9 +202,9 @@ public class cgeoApplicationTest extends ApplicationTestCase<cgeoapplication> { */ @MediumTest public static void testSearchByUsername() { - final SearchResult search = cgBase.searchByUsername(null, "blafoo", CacheType.WEBCAM, false); + final SearchResult search = GCParser.searchByUsername(null, "blafoo", CacheType.WEBCAM, false); assertNotNull(search); - assertEquals(3, search.totalCnt); + assertEquals(3, search.getTotal()); assertTrue(search.getGeocodes().contains("GCP0A9")); } @@ -231,8 +220,8 @@ public class cgeoApplicationTest extends ApplicationTestCase<cgeoapplication> { GC2CJPF mockedCache = new GC2CJPF(); deleteCacheFromDB(mockedCache.getGeocode()); - final String tokens[] = GCBase.getTokens(); - final Viewport viewport = new Viewport(mockedCache.getCoords(), 0.003, 0.003); + final String[] tokens = GCBase.getTokens(); + final Viewport viewport = new Viewport(mockedCache, 0.003, 0.003); // check coords for DETAILED Settings.setLiveMapStrategy(Strategy.DETAILED); @@ -242,18 +231,20 @@ public class cgeoApplicationTest extends ApplicationTestCase<cgeoapplication> { cgCache parsedCache = cgeoapplication.getInstance().loadCache(mockedCache.getGeocode(), LoadFlags.LOAD_CACHE_OR_DB); - assertEquals(Settings.isPremiumMember(), mockedCache.getCoords().isEqualTo(parsedCache.getCoords())); + assertEquals(Settings.isPremiumMember(), mockedCache.getCoords().equals(parsedCache.getCoords())); assertEquals(Settings.isPremiumMember(), parsedCache.isReliableLatLon()); // check update after switch strategy to FAST Settings.setLiveMapStrategy(Strategy.FAST); + GCBase.removeFromTileCache(mockedCache); + search = ConnectorFactory.searchByViewport(viewport, tokens); assertNotNull(search); assertTrue(search.getGeocodes().contains(mockedCache.getGeocode())); parsedCache = cgeoapplication.getInstance().loadCache(mockedCache.getGeocode(), LoadFlags.LOAD_CACHE_OR_DB); - assertEquals(Settings.isPremiumMember(), mockedCache.getCoords().isEqualTo(parsedCache.getCoords())); + assertEquals(Settings.isPremiumMember(), mockedCache.getCoords().equals(parsedCache.getCoords())); assertEquals(Settings.isPremiumMember(), parsedCache.isReliableLatLon()); } finally { @@ -275,21 +266,22 @@ public class cgeoApplicationTest extends ApplicationTestCase<cgeoapplication> { try { - final String tokens[] = null; // without a valid token we are "logged off" + final String[] tokens = null; // without a valid token we are "logged off" // non premium cache MockedCache cache = new GC2CJPF(); deleteCacheFromDBAndLogout(cache.getGeocode()); + GCBase.removeFromTileCache(cache); - Viewport viewport = new Viewport(cache.getCoords(), 0.003, 0.003); + Viewport viewport = new Viewport(cache, 0.003, 0.003); SearchResult search = ConnectorFactory.searchByViewport(viewport, tokens); assertNotNull(search); assertTrue(search.getGeocodes().contains(cache.getGeocode())); // coords differ cgCache cacheFromViewport = cgeoapplication.getInstance().loadCache(cache.getGeocode(), LoadFlags.LOAD_CACHE_OR_DB); - Log.d(Settings.tag, "cgeoApplicationTest.testSearchByViewportNotLoggedIn: Coords expected = " + cache.getCoords()); - Log.d(Settings.tag, "cgeoApplicationTest.testSearchByViewportNotLoggedIn: Coords actual = " + cacheFromViewport.getCoords()); + Log.d("cgeoApplicationTest.testSearchByViewportNotLoggedIn: Coords expected = " + cache.getCoords()); + Log.d("cgeoApplicationTest.testSearchByViewportNotLoggedIn: Coords actual = " + cacheFromViewport.getCoords()); assertFalse(cache.getCoords().isEqualTo(cacheFromViewport.getCoords(), 1e-3)); // depending on the chosen strategy the coords can be reliable or not assertEquals(testStrategy == Strategy.DETAILED, cacheFromViewport.isReliableLatLon()); @@ -298,7 +290,7 @@ public class cgeoApplicationTest extends ApplicationTestCase<cgeoapplication> { cache = new GC2JVEH(); deleteCacheFromDBAndLogout(cache.getGeocode()); - viewport = new Viewport(cache.getCoords(), 0.003, 0.003); + viewport = new Viewport(cache, 0.003, 0.003); search = ConnectorFactory.searchByViewport(viewport, tokens); assertNotNull(search); @@ -319,10 +311,15 @@ public class cgeoApplicationTest extends ApplicationTestCase<cgeoapplication> { */ public static void testSearchByGeocodeBasis() { for (MockedCache mockedCache : RegExPerformanceTest.MOCKED_CACHES) { - mockedCache.setMockedDataUser(Settings.getUsername()); - cgCache parsedCache = cgeoApplicationTest.testSearchByGeocode(mockedCache.getGeocode()); - if (null != parsedCache) { - cgBaseTest.testCompareCaches(mockedCache, parsedCache, true); + String oldUser = mockedCache.getMockedDataUser(); + try { + mockedCache.setMockedDataUser(Settings.getUsername()); + cgCache parsedCache = cgeoApplicationTest.testSearchByGeocode(mockedCache.getGeocode()); + if (null != parsedCache) { + Compare.assertCompareCaches(mockedCache, parsedCache, true); + } + } finally { + mockedCache.setMockedDataUser(oldUser); } } } diff --git a/tests/src/cgeo/geocaching/connector/gc/AutoZoomTest.java b/tests/src/cgeo/geocaching/connector/gc/AutoZoomTest.java new file mode 100644 index 0000000..234ff26 --- /dev/null +++ b/tests/src/cgeo/geocaching/connector/gc/AutoZoomTest.java @@ -0,0 +1,25 @@ +package cgeo.geocaching.connector.gc; + +import cgeo.geocaching.geopoint.Geopoint; + +import junit.framework.TestCase; + +public class AutoZoomTest extends TestCase { + + public static void testZoom1() { + Geopoint bottomLeft = new Geopoint(49.3, 8.3); + Geopoint topRight = new Geopoint(49.4, 8.4); + + int zoom = Tile.calcZoomLat(bottomLeft, topRight); + + assertTrue(Math.abs(new Tile(bottomLeft, zoom).getY() - new Tile(topRight, zoom).getY()) == 1); + assertTrue(Math.abs(new Tile(bottomLeft, zoom + 1).getY() - new Tile(topRight, zoom + 1).getY()) > 1); + + zoom = Tile.calcZoomLon(bottomLeft, topRight); + + assertTrue(new Tile(bottomLeft, zoom).getX() + 1 == new Tile(topRight, zoom).getX()); + assertTrue(new Tile(bottomLeft, zoom + 1).getX() + 1 < new Tile(topRight, zoom + 1).getX()); + + } + +} diff --git a/tests/src/cgeo/geocaching/connector/gc/GCBaseTest.java b/tests/src/cgeo/geocaching/connector/gc/GCBaseTest.java index e6a2474..88873a1 100644 --- a/tests/src/cgeo/geocaching/connector/gc/GCBaseTest.java +++ b/tests/src/cgeo/geocaching/connector/gc/GCBaseTest.java @@ -1,11 +1,11 @@ package cgeo.geocaching.connector.gc; import cgeo.geocaching.SearchResult; -import cgeo.geocaching.cgBaseTest; import cgeo.geocaching.cgCache; import cgeo.geocaching.enumerations.LoadFlags; import cgeo.geocaching.test.mock.GC2CJPF; import cgeo.geocaching.test.mock.MockedCache; +import cgeo.test.Compare; import java.util.HashSet; import java.util.Set; @@ -37,7 +37,7 @@ public class GCBaseTest extends TestCase { SearchResult result = GCBase.searchByGeocodes(geocodes); cgCache parsedCache = result.getFirstCacheFromResult(LoadFlags.LOAD_CACHE_ONLY); - cgBaseTest.testCompareCaches(mockedCache, parsedCache, false); + Compare.assertCompareCaches(mockedCache, parsedCache, false); } } diff --git a/tests/src/cgeo/geocaching/connector/gc/GCConnectorTest.java b/tests/src/cgeo/geocaching/connector/gc/GCConnectorTest.java index dfa9a8b..f85a697 100644 --- a/tests/src/cgeo/geocaching/connector/gc/GCConnectorTest.java +++ b/tests/src/cgeo/geocaching/connector/gc/GCConnectorTest.java @@ -4,7 +4,6 @@ import cgeo.geocaching.SearchResult; import cgeo.geocaching.connector.ConnectorFactory; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.geopoint.Viewport; -import cgeo.geocaching.network.Login; import cgeo.geocaching.test.AbstractResourceInstrumentationTestCase; public class GCConnectorTest extends AbstractResourceInstrumentationTestCase { @@ -18,7 +17,7 @@ public class GCConnectorTest extends AbstractResourceInstrumentationTestCase { final Viewport viewport = new Viewport(new Geopoint("N 52° 25.369 E 9° 35.499"), new Geopoint("N 52° 25.600 E 9° 36.200")); SearchResult searchResult = ConnectorFactory.searchByViewport(viewport, tokens); assertNotNull(searchResult); - assertTrue(searchResult.getCount() >= 1); + assertFalse(searchResult.isEmpty()); assertTrue(searchResult.getGeocodes().contains("GC211WG")); // Spiel & Sport GC211WG N 52° 25.413 E 009° 36.049 } @@ -32,12 +31,7 @@ public class GCConnectorTest extends AbstractResourceInstrumentationTestCase { } public static void testBaseCodings() { - assertEquals(2045702, GCBase.newidToGCId("CpLB")); - assertEquals("CpLB", GCBase.gcidToNewId(2045702)); assertEquals(2045702, GCBase.gccodeToGCId("GC2MEGA")); - assertEquals("GC2MEGA", GCBase.gcidToGCCode(2045702)); - - assertEquals("GC211WG", GCBase.newidToGeocode("gEaR")); } /** Tile computation with different zoom levels */ diff --git a/tests/src/cgeo/geocaching/connector/gc/GCConstantsTest.java b/tests/src/cgeo/geocaching/connector/gc/GCConstantsTest.java index c930ab5..809318a 100644 --- a/tests/src/cgeo/geocaching/connector/gc/GCConstantsTest.java +++ b/tests/src/cgeo/geocaching/connector/gc/GCConstantsTest.java @@ -1,6 +1,5 @@ package cgeo.geocaching.connector.gc; -import cgeo.geocaching.connector.gc.GCConstants; import cgeo.geocaching.test.mock.MockedCache; import cgeo.geocaching.utils.BaseUtils; @@ -31,7 +30,11 @@ public class GCConstantsTest extends AndroidTestCase { } private static void assertCacheCount(final int count, final String html) { - assertEquals(count, Integer.parseInt(BaseUtils.getMatch(html, GCConstants.PATTERN_CACHES_FOUND, true, "0").replaceAll("[,.]", ""))); + try { + assertEquals(count, Integer.parseInt(BaseUtils.getMatch(html, GCConstants.PATTERN_CACHES_FOUND, true, "0").replaceAll("[,.]", ""))); + } catch (NumberFormatException e) { + fail(); + } } public static void testConstants() { diff --git a/tests/src/cgeo/geocaching/cgBaseTest.java b/tests/src/cgeo/geocaching/connector/gc/GCParserTest.java index 408cd94..54f69ce 100644 --- a/tests/src/cgeo/geocaching/cgBaseTest.java +++ b/tests/src/cgeo/geocaching/connector/gc/GCParserTest.java @@ -1,16 +1,18 @@ -package cgeo.geocaching; +package cgeo.geocaching.connector.gc; -import cgeo.geocaching.connector.gc.GCConstants; +import cgeo.geocaching.SearchResult; +import cgeo.geocaching.Settings; +import cgeo.geocaching.cgCache; +import cgeo.geocaching.cgWaypoint; import cgeo.geocaching.enumerations.LoadFlags; -import cgeo.geocaching.enumerations.LogType; import cgeo.geocaching.enumerations.StatusCode; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.test.AbstractResourceInstrumentationTestCase; import cgeo.geocaching.test.R; import cgeo.geocaching.test.RegExPerformanceTest; import cgeo.geocaching.test.mock.MockedCache; -import cgeo.geocaching.utils.BaseUtils; import cgeo.geocaching.utils.CancellableHandler; +import cgeo.test.Compare; import org.apache.commons.lang3.StringUtils; @@ -18,67 +20,34 @@ import android.test.suitebuilder.annotation.MediumTest; import java.util.ArrayList; -public class cgBaseTest extends AbstractResourceInstrumentationTestCase { - - public static void testRegEx() { - String page = MockedCache.readCachePage("GC2CJPF"); - assertEquals("blafoo", BaseUtils.getMatch(page, GCConstants.PATTERN_LOGIN_NAME, true, "???")); - assertTrue(page.contains("id=\"ctl00_hlRenew\"") || "Premium Member".equals(BaseUtils.getMatch(page, GCConstants.PATTERN_MEMBER_STATUS, true, "???"))); - int cachesFound = Integer.parseInt(BaseUtils.getMatch(page, GCConstants.PATTERN_CACHES_FOUND, true, "0").replaceAll("[,.]", "")); - assertTrue(cachesFound >= 491); - } - - public static void testReplaceWhitespaces() { - assertEquals("foo bar baz ", BaseUtils.replaceWhitespace(new String(" foo\n\tbar \r baz "))); - } - - public static void testElevation() { - assertEquals(125.663703918457, (new Geopoint(48.0, 2.0)).getElevation(), 0.1); +public class GCParserTest extends AbstractResourceInstrumentationTestCase { + public void testUnpublishedCache() { + final String page = getFileContent(R.raw.cache_unpublished); + SearchResult result = GCParser.parseCacheFromText(page, null); + assertNotNull(result); + assertTrue(result.isEmpty()); + assertEquals(StatusCode.UNPUBLISHED_CACHE, result.getError()); } - public static void testCompareCaches(ICache expected, cgCache actual, boolean all) { - assertEquals(expected.getGeocode(), actual.getGeocode()); - assertTrue(expected.getType() == actual.getType()); - assertEquals(expected.getOwner(), actual.getOwner()); - assertEquals(expected.getDifficulty(), actual.getDifficulty()); - assertEquals(expected.getTerrain(), actual.getTerrain()); - assertEquals(expected.isDisabled(), actual.isDisabled()); - assertEquals(expected.isArchived(), actual.isArchived()); - assertEquals(expected.getSize(), actual.getSize()); - assertEquals(expected.getName(), actual.getName()); - assertEquals(expected.getGuid(), actual.getGuid()); - assertTrue(expected.getFavoritePoints() <= actual.getFavoritePoints()); - assertEquals(expected.getHiddenDate().toString(), actual.getHiddenDate().toString()); - assertEquals(expected.isPremiumMembersOnly(), actual.isPremiumMembersOnly()); - - if (all) { - assertEquals(expected.getLatitude(), actual.getLatitude()); - assertEquals(expected.getLongitude(), actual.getLongitude()); - assertTrue(actual.isReliableLatLon()); - assertEquals(expected.isOwn(), actual.isOwn()); - assertEquals(expected.getOwnerReal(), actual.getOwnerReal()); - assertEquals(expected.getHint(), actual.getHint()); - assertTrue(actual.getDescription().startsWith(expected.getDescription())); - assertEquals(expected.getShortDescription(), actual.getShortDescription()); - assertEquals(expected.getCacheId(), actual.getCacheId()); - assertEquals(expected.getLocation(), actual.getLocation()); - assertEquals(expected.isFound(), actual.isFound()); - assertEquals(expected.isFavorite(), actual.isFavorite()); - assertEquals(expected.isWatchlist(), actual.isWatchlist()); + private static cgCache createCache(int index) { + final MockedCache mockedCache = RegExPerformanceTest.MOCKED_CACHES[index]; + // to get the same results we have to use the date format used when the mocked data was created + String oldCustomDate = Settings.getGcCustomDate(); - for (String attribute : expected.getAttributes()) { - assertTrue(actual.getAttributes().contains(attribute)); - } - for (LogType logType : expected.getLogCounts().keySet()) { - assertTrue(actual.getLogCounts().get(logType) >= expected.getLogCounts().get(logType)); - } + SearchResult searchResult; + try { + Settings.setGcCustomDate(MockedCache.getDateFormat()); + searchResult = GCParser.parseCacheFromText(mockedCache.getData(), null); + } finally { + Settings.setGcCustomDate(oldCustomDate); + } - // the inventory can differ to often, therefore we don't compare them + assertNotNull(searchResult); + assertEquals(1, searchResult.getCount()); - int actualSpoilersSize = null != actual.getSpoilers() ? actual.getSpoilers().size() : 0; - int expectedSpoilersSize = null != expected.getSpoilers() ? expected.getSpoilers().size() : 0; - assertEquals(expectedSpoilersSize, actualSpoilersSize); - } + final cgCache cache = searchResult.getFirstCacheFromResult(LoadFlags.LOAD_CACHE_OR_DB); + assertNotNull(cache); + return cache; } /** @@ -92,10 +61,10 @@ public class cgBaseTest extends AbstractResourceInstrumentationTestCase { for (MockedCache mockedCache : RegExPerformanceTest.MOCKED_CACHES) { // to get the same results we have to use the date format used when the mocked data was created Settings.setGcCustomDate(MockedCache.getDateFormat()); - SearchResult searchResult = cgBase.parseCacheFromText(mockedCache.getData(), null); + SearchResult searchResult = GCParser.parseCacheFromText(mockedCache.getData(), null); cgCache parsedCache = searchResult.getFirstCacheFromResult(LoadFlags.LOAD_CACHE_OR_DB); assertTrue(StringUtils.isNotBlank(mockedCache.getMockedDataUser())); - cgBaseTest.testCompareCaches(mockedCache, parsedCache, true); + Compare.assertCompareCaches(mockedCache, parsedCache, true); } } finally { Settings.setGcCustomDate(gcCustomDate); @@ -103,7 +72,7 @@ public class cgBaseTest extends AbstractResourceInstrumentationTestCase { } public static void testWaypointsFromNote() { - final cgCache cache = cgBaseTest.createCache(0); + final cgCache cache = createCache(0); final Geopoint[] empty = new Geopoint[] {}; final Geopoint[] one = new Geopoint[] { new Geopoint("N51 21.523", "E7 2.680") }; @@ -145,36 +114,8 @@ public class cgBaseTest extends AbstractResourceInstrumentationTestCase { cache.parseWaypointsFromNote(); assertEquals(expected.length, cache.getWaypoints().size()); for (int i = 0; i < expected.length; i++) { - assertTrue(expected[i].isEqualTo(cache.getWaypoint(i).getCoords())); - } - } - - public static cgCache createCache(int index) { - final MockedCache mockedCache = RegExPerformanceTest.MOCKED_CACHES.get(index); - // to get the same results we have to use the date format used when the mocked data was created - String oldCustomDate = Settings.getGcCustomDate(); - - SearchResult searchResult; - try { - Settings.setGcCustomDate(MockedCache.getDateFormat()); - searchResult = cgBase.parseCacheFromText(mockedCache.getData(), null); - } finally { - Settings.setGcCustomDate(oldCustomDate); + assertTrue(expected[i].equals(cache.getWaypoint(i).getCoords())); } - - assertNotNull(searchResult); - assertEquals(1, searchResult.getCount()); - - final cgCache cache = searchResult.getFirstCacheFromResult(LoadFlags.LOAD_CACHE_OR_DB); - assertNotNull(cache); - return cache; } - public void testUnpublishedCache() { - final String page = getFileContent(R.raw.cache_unpublished); - SearchResult result = cgBase.parseCacheFromText(page, null); - assertNotNull(result); - assertEquals(0, result.getCount()); - assertEquals(StatusCode.UNPUBLISHED_CACHE, result.getError()); - } -}
\ No newline at end of file +} diff --git a/tests/src/cgeo/geocaching/connector/gc/IconDecoderTest.java b/tests/src/cgeo/geocaching/connector/gc/IconDecoderTest.java index 74704b3..3fa17f8 100644 --- a/tests/src/cgeo/geocaching/connector/gc/IconDecoderTest.java +++ b/tests/src/cgeo/geocaching/connector/gc/IconDecoderTest.java @@ -1,20 +1,19 @@ package cgeo.geocaching.connector.gc; -import cgeo.geocaching.Settings; import cgeo.geocaching.cgCache; import cgeo.geocaching.enumerations.CacheType; import cgeo.geocaching.test.AbstractResourceInstrumentationTestCase; import cgeo.geocaching.test.R; +import cgeo.geocaching.utils.Log; import android.graphics.Bitmap; import android.graphics.BitmapFactory; -import android.util.Log; public class IconDecoderTest extends AbstractResourceInstrumentationTestCase { public void testparseMapPNG14() { final Bitmap bitmap = getBitmap(R.raw.tile14); - Log.d(Settings.tag, "Bitmap=" + bitmap.getWidth() + "x" + bitmap.getHeight()); + Log.d("Bitmap=" + bitmap.getWidth() + "x" + bitmap.getHeight()); assertEquals(CacheType.TRADITIONAL, parseMapPNG(bitmap, 97, 136, 14).getType()); assertEquals(CacheType.MYSTERY, parseMapPNG(bitmap, 226, 104, 14).getType()); diff --git a/tests/src/cgeo/geocaching/connector/opencaching/OkapiClientTest.java b/tests/src/cgeo/geocaching/connector/opencaching/OkapiClientTest.java index d5dfac1..608f728 100644 --- a/tests/src/cgeo/geocaching/connector/opencaching/OkapiClientTest.java +++ b/tests/src/cgeo/geocaching/connector/opencaching/OkapiClientTest.java @@ -1,10 +1,11 @@ package cgeo.geocaching.connector.opencaching; +import cgeo.CGeoTestCase; import cgeo.geocaching.cgCache; +import cgeo.geocaching.cgeoapplication; +import cgeo.geocaching.enumerations.LoadFlags; -import android.test.AndroidTestCase; - -public class OkapiClientTest extends AndroidTestCase { +public class OkapiClientTest extends CGeoTestCase { public static void testGetOCCache() { String geoCode = "OU0331"; @@ -12,6 +13,14 @@ public class OkapiClientTest extends AndroidTestCase { assertNotNull(cache); assertEquals(geoCode, cache.getGeocode()); assertEquals("Oshkosh Municipal Tank", cache.getName()); + assertTrue(cache.isDetailed()); + + // cache should be stored to DB (to listID 0) when loaded above + cache = cgeoapplication.getInstance().loadCache(geoCode, LoadFlags.LOAD_ALL_DB_ONLY); + assertNotNull(cache); + assertEquals(geoCode, cache.getGeocode()); + assertEquals("Oshkosh Municipal Tank", cache.getName()); + assertTrue(cache.isDetailed()); } } diff --git a/tests/src/cgeo/geocaching/enumerations/CacheAttributeTest.java b/tests/src/cgeo/geocaching/enumerations/CacheAttributeTest.java new file mode 100644 index 0000000..f369b0e --- /dev/null +++ b/tests/src/cgeo/geocaching/enumerations/CacheAttributeTest.java @@ -0,0 +1,23 @@ +package cgeo.geocaching.enumerations; + +import android.test.AndroidTestCase; + +public class CacheAttributeTest extends AndroidTestCase { + + public static void testTrimAttributeName() { + for (CacheAttribute attribute : CacheAttribute.values()) { + final String rawName = attribute.gcRawName; + assertTrue("bad attribute name " + rawName, CacheAttribute.trimAttributeName(rawName).equals(rawName)); + } + } + + public static void testIds() { + for (CacheAttribute attribute : CacheAttribute.values()) { + if (attribute != CacheAttribute.UNKNOWN) { + assertTrue(attribute.drawableId != 0); + assertTrue(attribute.stringIdYes != 0); + assertTrue(attribute.stringIdNo != 0); + } + } + } +} diff --git a/tests/src/cgeo/geocaching/files/GPXImporterTest.java b/tests/src/cgeo/geocaching/files/GPXImporterTest.java index 10d60b3..a0dd377 100644 --- a/tests/src/cgeo/geocaching/files/GPXImporterTest.java +++ b/tests/src/cgeo/geocaching/files/GPXImporterTest.java @@ -8,10 +8,10 @@ import cgeo.geocaching.enumerations.LoadFlags; import cgeo.geocaching.test.AbstractResourceInstrumentationTestCase; import cgeo.geocaching.test.R; import cgeo.geocaching.utils.CancellableHandler; +import cgeo.geocaching.utils.Log; import android.net.Uri; import android.os.Message; -import android.util.Log; import java.io.File; import java.io.IOException; @@ -82,7 +82,7 @@ public class GPXImporterTest extends AbstractResourceInstrumentationTestCase { try { importThread.join(); } catch (InterruptedException e) { - Log.e(Settings.tag, "GPXImporterTest.runImportThread", e); + Log.e("GPXImporterTest.runImportThread", e); } importStepHandler.waitForCompletion(); } @@ -231,7 +231,7 @@ public class GPXImporterTest extends AbstractResourceInstrumentationTestCase { @Override public synchronized void handleRegularMessage(Message msg) { - final Message msg1 = new Message(); + final Message msg1 = Message.obtain(); msg1.copyFrom(msg); messages.add(msg1); lastMessage = System.currentTimeMillis(); @@ -281,7 +281,7 @@ public class GPXImporterTest extends AbstractResourceInstrumentationTestCase { super.tearDown(); } - private void deleteDirectory(File dir) { + private static void deleteDirectory(File dir) { for (File f : dir.listFiles()) { if (f.isFile()) { f.delete(); diff --git a/tests/src/cgeo/geocaching/files/GPXParserTest.java b/tests/src/cgeo/geocaching/files/GPXParserTest.java index 3754af1..47975c9 100644 --- a/tests/src/cgeo/geocaching/files/GPXParserTest.java +++ b/tests/src/cgeo/geocaching/files/GPXParserTest.java @@ -1,13 +1,12 @@ package cgeo.geocaching.files; +import cgeo.geocaching.LogEntry; import cgeo.geocaching.cgCache; -import cgeo.geocaching.cgLog; import cgeo.geocaching.cgWaypoint; import cgeo.geocaching.enumerations.CacheSize; import cgeo.geocaching.enumerations.CacheType; import cgeo.geocaching.enumerations.WaypointType; import cgeo.geocaching.geopoint.Geopoint; -import cgeo.geocaching.geopoint.GeopointFormatter; import cgeo.geocaching.test.AbstractResourceInstrumentationTestCase; import cgeo.geocaching.test.R; @@ -43,7 +42,7 @@ public class GPXParserTest extends AbstractResourceInstrumentationTestCase { assertEquals(5.0f, cache.getTerrain()); assertEquals("Baden-Württemberg, Germany", cache.getLocation()); assertEquals("Ein alter Kindheitstraum, ein Schatz auf einer unbewohnten Insel.\nA old dream of my childhood, a treasure on a lonely island.", cache.getShortdesc()); - assertTrue(new Geopoint(48.859683, 9.1874).isEqualTo(cache.getCoords())); + assertEquals(new Geopoint(48.859683, 9.1874), cache.getCoords()); return cache; } @@ -67,7 +66,7 @@ public class GPXParserTest extends AbstractResourceInstrumentationTestCase { assertEquals(4.0f, cache.getTerrain()); assertEquals("Baden-Württemberg, Germany", cache.getLocation()); assertEquals("Ein alter Kindheitstraum, ein Schatz auf einer unbewohnten Insel. A old dream of my childhood, a treasure on a lonely is", cache.getShortdesc()); - assertTrue(new Geopoint(48.85968, 9.18740).isEqualTo(cache.getCoords())); + assertEquals(new Geopoint(48.85968, 9.18740), cache.getCoords()); assertTrue(cache.isReliableLatLon()); } @@ -117,8 +116,7 @@ public class GPXParserTest extends AbstractResourceInstrumentationTestCase { assertEquals(2.0f, cache.getDifficulty(), 0.01f); assertEquals(1.0f, cache.getTerrain(), 0.01f); final Geopoint refCoordinates = new Geopoint("N 49° 19.122", "E 008° 32.739"); - assertEquals(refCoordinates.format(GeopointFormatter.Format.LAT_DECMINUTE), cache.getLatitude()); - assertEquals(refCoordinates.format(GeopointFormatter.Format.LON_DECMINUTE), cache.getLongitude()); + assertEquals(refCoordinates, cache.getCoords()); assertEquals("vptsz", cache.getOwner()); assertEquals(CacheSize.SMALL, cache.getSize()); assertEquals(CacheType.MULTI, cache.getType()); @@ -131,7 +129,7 @@ public class GPXParserTest extends AbstractResourceInstrumentationTestCase { assertEquals("Station3: Der zerbrochene Stein zählt doppelt.\nFinal: Oben neben dem Tor", cache.getHint()); // logs assertEquals(6, cache.getLogs().size()); - final cgLog log = cache.getLogs().get(5); + final LogEntry log = cache.getLogs().get(5); assertEquals("Geoteufel", log.author); assertEquals(parseTime("2011-09-11T07:00:00Z"), log.date); assertEquals(-1, log.found); @@ -195,9 +193,8 @@ public class GPXParserTest extends AbstractResourceInstrumentationTestCase { } } - List<cgCache> cacheList = new ArrayList<cgCache>(caches); // TODO: may need to sort by geocode when a test imports more than one cache - return cacheList; + return new ArrayList<cgCache>(caches); } public static void testParseDateWithFractionalSeconds() { diff --git a/tests/src/cgeo/geocaching/files/LocParserTest.java b/tests/src/cgeo/geocaching/files/LocParserTest.java index 64ac7ad..7e7a1be 100644 --- a/tests/src/cgeo/geocaching/files/LocParserTest.java +++ b/tests/src/cgeo/geocaching/files/LocParserTest.java @@ -25,9 +25,8 @@ public class LocParserTest extends AbstractResourceInstrumentationTestCase { instream.close(); } - List<cgCache> cacheList = new ArrayList<cgCache>(caches); // TODO: may need to sort by geocode when a test imports more than one cache - return cacheList; + return new ArrayList<cgCache>(caches); } public void testOCLoc() throws IOException, ParserException { @@ -37,7 +36,7 @@ public class LocParserTest extends AbstractResourceInstrumentationTestCase { assertNotNull(cache); assertEquals("OC5952", cache.getGeocode()); assertEquals("Die Schatzinsel / treasure island", cache.getName()); - assertTrue(new Geopoint(48.85968, 9.18740).isEqualTo(cache.getCoords())); + assertEquals(new Geopoint(48.85968, 9.18740), cache.getCoords()); } public void testGCLoc() throws IOException, ParserException { @@ -47,7 +46,7 @@ public class LocParserTest extends AbstractResourceInstrumentationTestCase { assertNotNull(cache); assertEquals("GC1BKP3", cache.getGeocode()); assertEquals("Die Schatzinsel / treasure island", cache.getName()); - assertTrue(new Geopoint(48.859683, 9.1874).isEqualTo(cache.getCoords())); + assertEquals(new Geopoint(48.859683, 9.1874), cache.getCoords()); assertEquals(1.0f, cache.getDifficulty()); assertEquals(5.0f, cache.getTerrain()); assertEquals(CacheSize.MICRO, cache.getSize()); diff --git a/tests/src/cgeo/geocaching/filter/DifficultyFilterTest.java b/tests/src/cgeo/geocaching/filter/DifficultyFilterTest.java new file mode 100644 index 0000000..a24cf72 --- /dev/null +++ b/tests/src/cgeo/geocaching/filter/DifficultyFilterTest.java @@ -0,0 +1,24 @@ +package cgeo.geocaching.filter; + +import cgeo.CGeoTestCase; +import cgeo.geocaching.cgCache; + +public class DifficultyFilterTest extends CGeoTestCase { + + public static void testTerrainFilter() { + final cgCache easy = new cgCache(); + easy.setDifficulty(1.5f); + + final cgCache hard = new cgCache(); + hard.setDifficulty(5f); + + final DifficultyFilter easyFilter = new DifficultyFilter(1); + + assertTrue(easyFilter.accepts(easy)); + assertFalse(easyFilter.accepts(hard)); + } + + public static void testAllFilters() { + assertTrue(new DifficultyFilter.Factory().getFilters().length == 5); // difficulty ranges from 1 to 5 + } +} diff --git a/tests/src/cgeo/geocaching/filter/SizeFilterTest.java b/tests/src/cgeo/geocaching/filter/SizeFilterTest.java new file mode 100644 index 0000000..a641874 --- /dev/null +++ b/tests/src/cgeo/geocaching/filter/SizeFilterTest.java @@ -0,0 +1,49 @@ +package cgeo.geocaching.filter; + +import cgeo.CGeoTestCase; +import cgeo.geocaching.cgCache; +import cgeo.geocaching.enumerations.CacheSize; + +import java.util.ArrayList; + +public class SizeFilterTest extends CGeoTestCase { + + private cgCache micro; + private cgCache regular; + private SizeFilter microFilter; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + // cache initialization can only be done without errors after application setup + micro = new cgCache(); + micro.setSize(CacheSize.MICRO); + + regular = new cgCache(); + regular.setSize(CacheSize.REGULAR); + + microFilter = new SizeFilter(CacheSize.MICRO); + } + + public void testAccepts() { + assertTrue(microFilter.accepts(micro)); + assertFalse(microFilter.accepts(regular)); + } + + public static void testGetAllFilters() { + final int expectedSizes = CacheSize.values().length - 1; // hide "UNKNOWN" + assertEquals(expectedSizes, new SizeFilter.Factory().getFilters().length); + } + + public void testFilter() { + final ArrayList<cgCache> list = new ArrayList<cgCache>(); + list.add(regular); + list.add(micro); + assertEquals(2, list.size()); + + microFilter.filter(list); + assertEquals(1, list.size()); + } + +} diff --git a/tests/src/cgeo/geocaching/filter/StateArchivedFilterTest.java b/tests/src/cgeo/geocaching/filter/StateArchivedFilterTest.java new file mode 100644 index 0000000..9b40140 --- /dev/null +++ b/tests/src/cgeo/geocaching/filter/StateArchivedFilterTest.java @@ -0,0 +1,27 @@ +package cgeo.geocaching.filter; + +import cgeo.CGeoTestCase; +import cgeo.geocaching.cgCache; +import cgeo.geocaching.filter.StateFilter.StateArchivedFilter; + +public class StateArchivedFilterTest extends CGeoTestCase { + + private StateFilter.StateArchivedFilter archivedFilter; + private cgCache archivedCache; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + // members can only be setup here, after application is initialized + archivedFilter = new StateArchivedFilter(); + archivedCache = new cgCache(); + archivedCache.setArchived(true); + } + + public void testAccepts() { + assertTrue(archivedFilter.accepts(archivedCache)); + assertFalse(archivedFilter.accepts(new cgCache())); + } + +} diff --git a/tests/src/cgeo/geocaching/filter/StateDisabledFilterTest.java b/tests/src/cgeo/geocaching/filter/StateDisabledFilterTest.java new file mode 100644 index 0000000..e73f771 --- /dev/null +++ b/tests/src/cgeo/geocaching/filter/StateDisabledFilterTest.java @@ -0,0 +1,26 @@ +package cgeo.geocaching.filter; + +import cgeo.CGeoTestCase; +import cgeo.geocaching.cgCache; +import cgeo.geocaching.filter.StateFilter.StateDisabledFilter; + +public class StateDisabledFilterTest extends CGeoTestCase { + + private StateFilter.StateDisabledFilter disabledFilter; + private cgCache disabledCache; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + disabledFilter = new StateDisabledFilter(); + disabledCache = new cgCache(); + disabledCache.setDisabled(true); + } + + public void testAccepts() { + assertTrue(disabledFilter.accepts(disabledCache)); + assertFalse(disabledFilter.accepts(new cgCache())); + } + +} diff --git a/tests/src/cgeo/geocaching/filter/StateFoundFilterTest.java b/tests/src/cgeo/geocaching/filter/StateFoundFilterTest.java new file mode 100644 index 0000000..053363f --- /dev/null +++ b/tests/src/cgeo/geocaching/filter/StateFoundFilterTest.java @@ -0,0 +1,26 @@ +package cgeo.geocaching.filter; + +import cgeo.CGeoTestCase; +import cgeo.geocaching.cgCache; +import cgeo.geocaching.filter.StateFilter.StateFoundFilter; + +public class StateFoundFilterTest extends CGeoTestCase { + + private StateFilter.StateFoundFilter foundFilter; + private cgCache foundCache; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + foundFilter = new StateFoundFilter(); + foundCache = new cgCache(); + foundCache.setFound(true); + } + + public void testAccepts() { + assertTrue(foundFilter.accepts(foundCache)); + assertFalse(foundFilter.accepts(new cgCache())); + } + +} diff --git a/tests/src/cgeo/geocaching/filter/StatePremiumFilterTest.java b/tests/src/cgeo/geocaching/filter/StatePremiumFilterTest.java new file mode 100644 index 0000000..9221da0 --- /dev/null +++ b/tests/src/cgeo/geocaching/filter/StatePremiumFilterTest.java @@ -0,0 +1,26 @@ +package cgeo.geocaching.filter; + +import cgeo.CGeoTestCase; +import cgeo.geocaching.cgCache; +import cgeo.geocaching.filter.StateFilter.StatePremiumFilter; + +public class StatePremiumFilterTest extends CGeoTestCase { + + private StateFilter.StatePremiumFilter premiumFilter; + private cgCache premiumCache; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + premiumFilter = new StatePremiumFilter(); + premiumCache = new cgCache(); + premiumCache.setPremiumMembersOnly(true); + } + + public void testAccepts() { + assertTrue(premiumFilter.accepts(premiumCache)); + assertFalse(premiumFilter.accepts(new cgCache())); + } + +} diff --git a/tests/src/cgeo/geocaching/filter/TerrainFilterTest.java b/tests/src/cgeo/geocaching/filter/TerrainFilterTest.java new file mode 100644 index 0000000..9deea34 --- /dev/null +++ b/tests/src/cgeo/geocaching/filter/TerrainFilterTest.java @@ -0,0 +1,24 @@ +package cgeo.geocaching.filter; + +import cgeo.CGeoTestCase; +import cgeo.geocaching.cgCache; + +public class TerrainFilterTest extends CGeoTestCase { + + public static void testTerrainFilter() { + final cgCache easy = new cgCache(); + easy.setTerrain(1.5f); + + final cgCache hard = new cgCache(); + hard.setTerrain(5f); + + final AbstractRangeFilter easyFilter = new TerrainFilter(1); + + assertTrue(easyFilter.accepts(easy)); + assertFalse(easyFilter.accepts(hard)); + } + + public static void testAllFilters() { + assertTrue(new TerrainFilter.Factory().getFilters().length == 5); // terrain ranges from 1 to 5 + } +} diff --git a/tests/src/cgeo/geocaching/filter/TypeFilterTest.java b/tests/src/cgeo/geocaching/filter/TypeFilterTest.java new file mode 100644 index 0000000..5b2631c --- /dev/null +++ b/tests/src/cgeo/geocaching/filter/TypeFilterTest.java @@ -0,0 +1,52 @@ +package cgeo.geocaching.filter; + +import cgeo.CGeoTestCase; +import cgeo.geocaching.cgCache; +import cgeo.geocaching.enumerations.CacheType; + +import java.util.ArrayList; + +public class TypeFilterTest extends CGeoTestCase { + + private TypeFilter traditionalFilter; + private cgCache traditional; + private cgCache mystery; + + @Override + protected void setUp() throws Exception { + super.setUp(); + traditionalFilter = new TypeFilter(CacheType.TRADITIONAL); + + traditional = new cgCache(); + traditional.setType(CacheType.TRADITIONAL); + + mystery = new cgCache(); + mystery.setType(CacheType.MYSTERY); + } + + public void testAccepts() { + assertTrue(traditionalFilter.accepts(traditional)); + assertFalse(traditionalFilter.accepts(mystery)); + } + + public void testFilter() { + final ArrayList<cgCache> list = new ArrayList<cgCache>(); + traditionalFilter.filter(list); + assertEquals(0, list.size()); + + list.add(traditional); + list.add(mystery); + assertEquals(2, list.size()); + + traditionalFilter.filter(list); + assertEquals(1, list.size()); + assertTrue(list.contains(traditional)); + + } + + public static void testGetAllFilters() { + final int expectedEntries = CacheType.values().length - 1; // hide "all" + assertEquals(expectedEntries, new TypeFilter.Factory().getFilters().length); + } + +} diff --git a/tests/src/cgeo/geocaching/geopoint/GeoPointParserTest.java b/tests/src/cgeo/geocaching/geopoint/GeoPointParserTest.java index 661623e..44fbe18 100644 --- a/tests/src/cgeo/geocaching/geopoint/GeoPointParserTest.java +++ b/tests/src/cgeo/geocaching/geopoint/GeoPointParserTest.java @@ -1,7 +1,5 @@ package cgeo.geocaching.geopoint; -import cgeo.geocaching.geopoint.GeopointParser.ParseException; - import android.test.AndroidTestCase; public class GeoPointParserTest extends AndroidTestCase { @@ -27,7 +25,7 @@ public class GeoPointParserTest extends AndroidTestCase { Geopoint point = null; try { point = GeopointParser.parse("N 49° 56.031"); - } catch (ParseException e) { + } catch (Geopoint.ParseException e) { // expected } assertEquals(null, point); @@ -57,14 +55,14 @@ public class GeoPointParserTest extends AndroidTestCase { final Geopoint p2 = GeopointParser.parse("N51 21.523", "E07 02.680"); assertNotNull(p1); assertNotNull(p2); - assertTrue(p1.isEqualTo(p2)); + assertTrue(p1.equals(p2)); } public static void testUnrelatedParts() { Geopoint point = null; try { point = GeopointParser.parse("N51 21.523 and some words in between, so there is no relation E07 02.680"); - } catch (ParseException e) { + } catch (Geopoint.ParseException e) { // expected } assertEquals(null, point); @@ -77,6 +75,6 @@ public class GeoPointParserTest extends AndroidTestCase { "E 15° 53' 41.68''"); assertNotNull(pointComma); assertNotNull(pointDot); - assertTrue(pointComma.isEqualTo(pointDot)); + assertTrue(pointComma.equals(pointDot)); } } diff --git a/tests/src/cgeo/geocaching/geopoint/GeopointTest.java b/tests/src/cgeo/geocaching/geopoint/GeopointTest.java index 894b046..76a9496 100644 --- a/tests/src/cgeo/geocaching/geopoint/GeopointTest.java +++ b/tests/src/cgeo/geocaching/geopoint/GeopointTest.java @@ -1,9 +1,10 @@ package cgeo.geocaching.geopoint; -import cgeo.geocaching.geopoint.Geopoint.DDD; -import cgeo.geocaching.geopoint.Geopoint.DMM; -import cgeo.geocaching.geopoint.Geopoint.DMS; +import cgeo.geocaching.geopoint.direction.DDD; +import cgeo.geocaching.geopoint.direction.DMM; +import cgeo.geocaching.geopoint.direction.DMS; +import android.os.Bundle; import android.test.AndroidTestCase; import junit.framework.Assert; @@ -41,12 +42,6 @@ public class GeopointTest extends AndroidTestCase { Assert.assertFalse(gp1.equals(gp2)); } - public static void testCreateE6() { - final Geopoint gp1 = new Geopoint(48.2, 2.34); - final Geopoint gp2 = new Geopoint(48200000, 2340000); - Assert.assertTrue(gp1.isEqualTo(gp2, 1e-6)); - } - public static void testGetE6() { final Geopoint gp = new Geopoint(41.2, -3.4); Assert.assertEquals(41200000.0, gp.getLatitudeE6(), 1e-6); @@ -67,6 +62,14 @@ public class GeopointTest extends AndroidTestCase { Assert.assertEquals(107.715, gp2.bearingTo(gp1), 1e-3); } + public static void testParcelable() { + final Geopoint gp = new Geopoint(1.2, 3.4); + final String KEY = "geopoint"; + final Bundle bundle = new Bundle(); + bundle.putParcelable(KEY, gp); + assertEquals(gp, bundle.getParcelable(KEY)); + } + public static void testDDD() { // case 1 final Geopoint gp1 = new Geopoint(51.3d, 13.8d); @@ -77,7 +80,7 @@ public class GeopointTest extends AndroidTestCase { Geopoint gp1a = DDD.createGeopoint(String.valueOf(ddd1.latDir), String.valueOf(ddd1.latDeg), String.valueOf(ddd1.latDegFrac), String.valueOf(ddd1.lonDir), String.valueOf(ddd1.lonDeg), String.valueOf(ddd1.lonDegFrac)); - Assert.assertTrue(gp1a.isEqualTo(gp1)); + Assert.assertTrue(gp1a.equals(gp1)); // case 2 final Geopoint gp2 = new Geopoint(51.34567d, 13.87654d); @@ -88,7 +91,7 @@ public class GeopointTest extends AndroidTestCase { Geopoint gp2a = DDD.createGeopoint(String.valueOf(ddd2.latDir), String.valueOf(ddd2.latDeg), String.valueOf(ddd2.latDegFrac), String.valueOf(ddd2.lonDir), String.valueOf(ddd2.lonDeg), String.valueOf(ddd2.lonDegFrac)); - Assert.assertTrue(gp2a.isEqualTo(gp2)); + Assert.assertTrue(gp2a.equals(gp2)); // case 3 final Geopoint gp3 = new Geopoint(51.29999833333333d, 13.8d); @@ -137,7 +140,7 @@ public class GeopointTest extends AndroidTestCase { Geopoint gp1a = DMM.createGeopoint(String.valueOf(dmm1.latDir), String.valueOf(dmm1.latDeg), String.valueOf(dmm1.latMin), String.valueOf(dmm1.latMinFrac), String.valueOf(dmm1.lonDir), String.valueOf(dmm1.lonDeg), String.valueOf(dmm1.lonMin), String.valueOf(dmm1.lonMinFrac)); - Assert.assertTrue(gp1a.isEqualTo(gp1)); + Assert.assertTrue(gp1a.equals(gp1)); // case 2 final Geopoint gp2 = new Geopoint(51.34567d, 13.87654d); @@ -194,7 +197,7 @@ public class GeopointTest extends AndroidTestCase { Geopoint gp1a = DMS.createGeopoint(String.valueOf(dms1.latDir), String.valueOf(dms1.latDeg), String.valueOf(dms1.latMin), String.valueOf(dms1.latSec), String.valueOf(dms1.latSecFrac), String.valueOf(dms1.lonDir), String.valueOf(dms1.lonDeg), String.valueOf(dms1.lonMin), String.valueOf(dms1.lonSec), String.valueOf(dms1.lonSecFrac)); - Assert.assertTrue(gp1a.isEqualTo(gp1)); + Assert.assertTrue(gp1a.equals(gp1)); // case 2 final Geopoint gp2 = new Geopoint(51.34567d, 13.87654d); @@ -243,4 +246,8 @@ public class GeopointTest extends AndroidTestCase { Assert.assertEquals(lonSecFrac, dms.lonSecFrac); } + public static void testElevation() { + assertEquals(125.663703918457, (new Geopoint(48.0, 2.0)).getElevation(), 0.1); + } + } diff --git a/tests/src/cgeo/geocaching/geopoint/HumanDistanceTest.java b/tests/src/cgeo/geocaching/geopoint/HumanDistanceTest.java index 3c7cb98..c5fce00 100644 --- a/tests/src/cgeo/geocaching/geopoint/HumanDistanceTest.java +++ b/tests/src/cgeo/geocaching/geopoint/HumanDistanceTest.java @@ -1,19 +1,41 @@ package cgeo.geocaching.geopoint; +import cgeo.CGeoTestCase; import cgeo.geocaching.Settings; -import android.test.AndroidTestCase; +import java.util.regex.Pattern; -public class HumanDistanceTest extends AndroidTestCase { +public class HumanDistanceTest extends CGeoTestCase { - public static void testHumanDistance() { - assertEquals("?", HumanDistance.getHumanDistance(null)); - if (Settings.isUseMetricUnits()) { - assertEquals("123 km", HumanDistance.getHumanDistance(123.456f)); - assertEquals("123 m", HumanDistance.getHumanDistance(0.123456f)); + private static void assertMatch(final String ok, final float distance) { + final String humanDistance = HumanDistance.getHumanDistance(distance); + if (!Pattern.compile('^' + ok + '$').matcher(humanDistance).find()) { + fail("getHumanDistance(" + distance + + ") [metric: " + (Settings.isUseMetricUnits() ? "yes" : "no") + + "] fails to match " + ok + ": " + humanDistance); } - else { - assertEquals("77 mi", HumanDistance.getHumanDistance(123.456f)); + } + + // Make method non-static so that Settings is initialized + @SuppressWarnings("static-method") + public void testHumanDistance() { + assertEquals("?", HumanDistance.getHumanDistance(null)); + final boolean savedMetrics = Settings.isUseMetricUnits(); + try { + Settings.setUseMetricUnits(true); + assertMatch("123 km", 122.782f); + assertMatch("123 km", 123.456f); + assertMatch("12.3 km", 12.3456f); + assertMatch("1.23 km", 1.23456f); + assertMatch("123 m", 0.123456f); + Settings.setUseMetricUnits(false); + assertMatch("76.7 mi", 123.456f); + assertMatch("7.67 mi", 12.3456f); + assertMatch("0.77 mi", 1.23456f); + assertMatch("405 ft", 0.123456f); + assertMatch("40.5 ft", 0.0123456f); + } finally { + Settings.setUseMetricUnits(savedMetrics); } } } diff --git a/tests/src/cgeo/geocaching/geopoint/ViewportTest.java b/tests/src/cgeo/geocaching/geopoint/ViewportTest.java new file mode 100644 index 0000000..ac32468 --- /dev/null +++ b/tests/src/cgeo/geocaching/geopoint/ViewportTest.java @@ -0,0 +1,100 @@ +package cgeo.geocaching.geopoint; + +import cgeo.geocaching.ICoordinates; + +import android.test.AndroidTestCase; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +public class ViewportTest extends AndroidTestCase { + + final private static Viewport vpRef = new Viewport(new Geopoint(-1.0, -2.0), new Geopoint(3.0, 4.0)); + + public static void assertBounds(final Viewport vp) { + assertEquals(new Geopoint(1.0, 1.0), vp.center); + assertEquals(new Geopoint(3.0, 4.0), vp.topRight); + assertEquals(new Geopoint(-1.0, -2.0), vp.bottomLeft); + } + + public static void testCreationBounds() { + assertBounds(new Viewport(new Geopoint(-1.0, -2.0), new Geopoint(3.0, 4.0))); + assertBounds(new Viewport(new Geopoint(3.0, 4.0), new Geopoint(-1.0, -2.0))); + assertBounds(new Viewport(new Geopoint(-1.0, 4.0), new Geopoint(3.0, -2.0))); + assertBounds(new Viewport(new Geopoint(3.0, -2.0), new Geopoint(-1.0, 4.0))); + } + + public static void testCreationCenter() { + assertBounds(new Viewport(new Geopoint(1.0, 1.0), 4.0, 6.0)); + } + + public static void testCreationSeparate() { + assertBounds(vpRef); + } + + public static void testMinMax() { + assertEquals(-1.0, vpRef.getLatitudeMin()); + assertEquals(3.0, vpRef.getLatitudeMax()); + assertEquals(-2.0, vpRef.getLongitudeMin()); + assertEquals(4.0, vpRef.getLongitudeMax()); + } + + public static void testSpans() { + assertEquals(4.0, vpRef.getLatitudeSpan()); + assertEquals(6.0, vpRef.getLongitudeSpan()); + } + + public static void testInViewport() { + assertFalse(vpRef.contains(new Geopoint(-2.0, -2.0))); + assertFalse(vpRef.contains(new Geopoint(4.0, 4.0))); + assertTrue(vpRef.contains(new Geopoint(0.0, 0.0))); + assertTrue(vpRef.contains(new Geopoint(-1.0, -2.0))); + assertTrue(vpRef.contains(new Geopoint(3.0, 4.0))); + } + + public static void testSqlWhere() { + assertEquals("latitude >= -1.0 and latitude <= 3.0 and longitude >= -2.0 and longitude <= 4.0", vpRef.sqlWhere(null)); + assertEquals("t.latitude >= -1.0 and t.latitude <= 3.0 and t.longitude >= -2.0 and t.longitude <= 4.0", vpRef.sqlWhere("t")); + } + + public static void testEquals() { + assertEquals(vpRef, vpRef); + assertEquals(vpRef, new Viewport(vpRef.bottomLeft, vpRef.topRight)); + assertFalse(vpRef.equals(new Viewport(new Geopoint(0.0, 0.0), 1.0, 1.0))); + } + + public static void testResize() { + assertEquals(vpRef, vpRef.resize(1.0)); + assertEquals(new Viewport(new Geopoint(-3.0, -5.0), new Geopoint(5.0, 7.0)), vpRef.resize(2.0)); + assertEquals(new Viewport(new Geopoint(0.0, -0.5), new Geopoint(2.0, 2.5)), vpRef.resize(0.5)); + } + + public static void testIncludes() { + assertTrue(vpRef.includes(vpRef)); + assertTrue(vpRef.includes(vpRef.resize(0.5))); + assertFalse(vpRef.includes(vpRef.resize(2.0))); + } + + public static void testExpands() { + assertEquals(vpRef, vpRef.expand(new Geopoint(0, 0))); + final Viewport vp1 = vpRef.expand(new Geopoint(-4.0, 0.0)); + assertEquals(new Geopoint(-4.0, -2.0), vp1.bottomLeft); + assertEquals(new Geopoint(3.0, 4.0), vp1.topRight); + final Viewport vp2 = vpRef.expand(new Geopoint(-10.0, 10.0)); + assertEquals(new Geopoint(-10.0, -2.0), vp2.bottomLeft); + assertEquals(new Geopoint(3.0, 10.0), vp2.topRight); + } + + public static void testContaining() { + assertNull(Viewport.containing(Collections.singleton((ICoordinates) null))); + final Set<Geopoint> points = new HashSet<Geopoint>(); + points.add(vpRef.bottomLeft); + assertEquals(new Viewport(vpRef.bottomLeft, vpRef.bottomLeft), Viewport.containing(points)); + points.add(vpRef.topRight); + assertEquals(vpRef, Viewport.containing(points)); + points.add(vpRef.center); + assertEquals(vpRef, Viewport.containing(points)); + } + +} diff --git a/tests/src/cgeo/geocaching/network/ParametersTest.java b/tests/src/cgeo/geocaching/network/ParametersTest.java new file mode 100644 index 0000000..4c56f05 --- /dev/null +++ b/tests/src/cgeo/geocaching/network/ParametersTest.java @@ -0,0 +1,53 @@ +package cgeo.geocaching.network; + +import cgeo.geocaching.network.Parameters; + +import android.test.AndroidTestCase; + +import java.security.InvalidParameterException; + +import junit.framework.Assert; + +public class ParametersTest extends AndroidTestCase { + + public static void testException() { + try { + final Parameters params = new Parameters("aaa", "AAA", "bbb"); + params.clear(); // this will never be invoked, but suppresses warnings about unused objects + Assert.fail("Exception not raised"); + } catch (InvalidParameterException e) { + // Ok + } + try { + final Parameters params = new Parameters("aaa", "AAA"); + params.put("bbb", "BBB", "ccc"); + Assert.fail("Exception not raised"); + } catch (InvalidParameterException e) { + // Ok + } + } + + public static void testMultipleValues() { + final Parameters params = new Parameters("aaa", "AAA", "bbb", "BBB"); + params.put("ccc", "CCC", "ddd", "DDD"); + Assert.assertEquals("aaa=AAA&bbb=BBB&ccc=CCC&ddd=DDD", params.toString()); + } + + public static void testSort() { + final Parameters params = new Parameters(); + params.put("aaa", "AAA"); + params.put("ccc", "CCC"); + params.put("bbb", "BBB"); + Assert.assertEquals("aaa=AAA&ccc=CCC&bbb=BBB", params.toString()); + params.sort(); + Assert.assertEquals("aaa=AAA&bbb=BBB&ccc=CCC", params.toString()); + } + + public static void testToString() { + final Parameters params = new Parameters(); + params.put("name", "foo&bar"); + params.put("type", "moving"); + Assert.assertEquals("name=foo%26bar&type=moving", params.toString()); + } + +} diff --git a/tests/src/cgeo/geocaching/test/AbstractResourceInstrumentationTestCase.java b/tests/src/cgeo/geocaching/test/AbstractResourceInstrumentationTestCase.java index 906b414..e07a518 100644 --- a/tests/src/cgeo/geocaching/test/AbstractResourceInstrumentationTestCase.java +++ b/tests/src/cgeo/geocaching/test/AbstractResourceInstrumentationTestCase.java @@ -16,16 +16,23 @@ public abstract class AbstractResourceInstrumentationTestCase extends Instrument } protected String getFileContent(int resourceId) { - InputStream ins = getInstrumentation().getContext().getResources().openRawResource(resourceId); - return new Scanner(ins).useDelimiter("\\A").next(); + final InputStream ins = getResourceStream(resourceId); + final String result = new Scanner(ins).useDelimiter("\\A").next(); + try { + ins.close(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return result; } protected void copyResourceToFile(int resourceId, File file) throws IOException { final InputStream is = getResourceStream(resourceId); final FileOutputStream os = new FileOutputStream(file); - + try { - byte[] buffer = new byte[4096]; + final byte[] buffer = new byte[4096]; int byteCount; while ((byteCount = is.read(buffer)) >= 0) { os.write(buffer, 0, byteCount); diff --git a/tests/src/cgeo/geocaching/test/RegExPerformanceTest.java b/tests/src/cgeo/geocaching/test/RegExPerformanceTest.java index 0e2619d..3075d0e 100644 --- a/tests/src/cgeo/geocaching/test/RegExPerformanceTest.java +++ b/tests/src/cgeo/geocaching/test/RegExPerformanceTest.java @@ -68,12 +68,7 @@ public class RegExPerformanceTest extends TestCase { public final static Pattern PATTERN_DESCRIPTION = Pattern.compile("<span id=\"ctl00_ContentBody_LongDescription\">(.*?)</span>[^<]*</div>[^<]*<p>[^<]*</p>[^<]*<p>[^<]*<strong>\\W*Additional Hints</strong>"); - public final static List<MockedCache> MOCKED_CACHES = new ArrayList<MockedCache>(); - static { - MOCKED_CACHES.add(new GC2CJPF()); - MOCKED_CACHES.add(new GC1ZXX2()); - MOCKED_CACHES.add(new GC2JVEH()); - } + public final static MockedCache[] MOCKED_CACHES = { new GC2CJPF(), new GC1ZXX2(), new GC2JVEH() }; public static void testRegEx() { List<String> output = doTheTests(10); @@ -115,7 +110,7 @@ public class RegExPerformanceTest extends TestCase { diff2 = parse(page, p2, iterations); output.add("Time pattern 2:\t" + diff2 + " ms"); } - Float reduction = new Float((float) diff2 * 100 / diff1); + float reduction = (float) diff2 * 100 / diff1; output.add("New runtime:\t" + String.format("%.1f", reduction) + "%\n"); } diff --git a/tests/src/cgeo/geocaching/test/RegExRealPerformanceTest.java b/tests/src/cgeo/geocaching/test/RegExRealPerformanceTest.java index b920772..3867082 100644 --- a/tests/src/cgeo/geocaching/test/RegExRealPerformanceTest.java +++ b/tests/src/cgeo/geocaching/test/RegExRealPerformanceTest.java @@ -1,9 +1,9 @@ package cgeo.geocaching.test; -import cgeo.geocaching.Settings; + +import cgeo.geocaching.utils.Log; import android.test.AndroidTestCase; -import android.util.Log; import java.util.List; @@ -20,7 +20,7 @@ public class RegExRealPerformanceTest extends AndroidTestCase { List<String> output = RegExPerformanceTest.doTheTests(10); for (String s : output) { - Log.d(Settings.tag, s); + Log.d(s); } } diff --git a/tests/src/cgeo/geocaching/test/WhitespaceTest.java b/tests/src/cgeo/geocaching/test/WhitespaceTest.java index d2d21dc..a78f2fa 100644 --- a/tests/src/cgeo/geocaching/test/WhitespaceTest.java +++ b/tests/src/cgeo/geocaching/test/WhitespaceTest.java @@ -1,17 +1,11 @@ package cgeo.geocaching.test; -import cgeo.geocaching.Settings; import cgeo.geocaching.utils.BaseUtils; +import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; -import android.test.AndroidTestCase; -import android.util.Log; - -import java.io.BufferedReader; -import java.io.InputStream; -import java.io.InputStreamReader; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -20,25 +14,15 @@ import java.util.regex.Pattern; * It does not test semantical correctness. * */ -public class WhitespaceTest extends AndroidTestCase { +public class WhitespaceTest extends AbstractResourceInstrumentationTestCase { private final static int EXPECTED_SIZE = 122907; private String data; @Override protected void setUp() throws Exception { - final StringBuilder buffer = new StringBuilder(4096); - final InputStream is = this.getClass().getResourceAsStream("/cgeo/geocaching/test/mock/GC2CJPF.html"); - final BufferedReader br = new BufferedReader(new InputStreamReader(is), 4096); - - String line = null; - - while ((line = br.readLine()) != null) { - buffer.append(line).append('\n'); - } - data = buffer.toString(); - - br.close(); + super.setUp(); + data = getFileContent(R.raw.gc2cjpf_html); } /** @@ -79,7 +63,7 @@ public class WhitespaceTest extends AndroidTestCase { String result = matcher.replaceAll(" ").trim(); final long end = System.currentTimeMillis(); assertEquals(EXPECTED_SIZE - 1, result.length()); - Log.d(Settings.tag, (end - start) + " ms regex"); + Log.d((end - start) + " ms regex"); } public void testReplaceAll() { @@ -87,7 +71,7 @@ public class WhitespaceTest extends AndroidTestCase { String result = data.replaceAll("\\s+", " "); final long end = System.currentTimeMillis(); assertEquals(EXPECTED_SIZE + 1, result.length()); - Log.d(Settings.tag, (end - start) + " ms replaceAll"); + Log.d((end - start) + " ms replaceAll"); } public void testActualImplementation() { @@ -96,7 +80,7 @@ public class WhitespaceTest extends AndroidTestCase { result = BaseUtils.replaceWhitespace(data); final long end = System.currentTimeMillis(); assertEquals(EXPECTED_SIZE, result.length()); - Log.d(Settings.tag, (end - start) + " ms actual implementation"); + Log.d((end - start) + " ms actual implementation"); } public void testManually() { @@ -105,7 +89,7 @@ public class WhitespaceTest extends AndroidTestCase { result = replaceWhitespaceManually(data); final long end = System.currentTimeMillis(); assertEquals(EXPECTED_SIZE, result.length()); - Log.d(Settings.tag, (end - start) + " ms manually"); + Log.d((end - start) + " ms manually"); } public void testStringUtils() { @@ -114,6 +98,6 @@ public class WhitespaceTest extends AndroidTestCase { result = replaceWhitespaceStringUtils(data); final long end = System.currentTimeMillis(); assertEquals(EXPECTED_SIZE - 1, result.length()); - Log.d(Settings.tag, (end - start) + " ms StringUtils"); + Log.d((end - start) + " ms StringUtils"); } }
\ No newline at end of file diff --git a/tests/src/cgeo/geocaching/test/mock/GC1ZXX2.java b/tests/src/cgeo/geocaching/test/mock/GC1ZXX2.java index bf4d0cf..7376718 100644 --- a/tests/src/cgeo/geocaching/test/mock/GC1ZXX2.java +++ b/tests/src/cgeo/geocaching/test/mock/GC1ZXX2.java @@ -1,10 +1,10 @@ package cgeo.geocaching.test.mock; +import cgeo.geocaching.connector.gc.Login; import cgeo.geocaching.enumerations.CacheSize; import cgeo.geocaching.enumerations.CacheType; import cgeo.geocaching.enumerations.LogType; import cgeo.geocaching.geopoint.Geopoint; -import cgeo.geocaching.network.Login; import java.text.ParseException; import java.util.Arrays; @@ -17,7 +17,7 @@ import java.util.Map; public class GC1ZXX2 extends MockedCache { public GC1ZXX2() { - super(new Geopoint(52373217, 9710800)); + super(new Geopoint(52.373217, 9.710800)); } @Override diff --git a/tests/src/cgeo/geocaching/test/mock/GC2CJPF.java b/tests/src/cgeo/geocaching/test/mock/GC2CJPF.java index b97d2bc..670fee4 100644 --- a/tests/src/cgeo/geocaching/test/mock/GC2CJPF.java +++ b/tests/src/cgeo/geocaching/test/mock/GC2CJPF.java @@ -1,11 +1,11 @@ package cgeo.geocaching.test.mock; import cgeo.geocaching.Settings; +import cgeo.geocaching.connector.gc.Login; import cgeo.geocaching.enumerations.CacheSize; import cgeo.geocaching.enumerations.CacheType; import cgeo.geocaching.enumerations.LogType; import cgeo.geocaching.geopoint.Geopoint; -import cgeo.geocaching.network.Login; import java.text.ParseException; import java.util.Arrays; @@ -18,7 +18,7 @@ import java.util.Map; public class GC2CJPF extends MockedCache { public GC2CJPF() { - super(new Geopoint(52425067, 9664200)); + super(new Geopoint(52.425067, 9.664200)); } @Override diff --git a/tests/src/cgeo/geocaching/test/mock/GC2JVEH.java b/tests/src/cgeo/geocaching/test/mock/GC2JVEH.java index 43128cf..dd1f9be 100644 --- a/tests/src/cgeo/geocaching/test/mock/GC2JVEH.java +++ b/tests/src/cgeo/geocaching/test/mock/GC2JVEH.java @@ -2,11 +2,11 @@ package cgeo.geocaching.test.mock; import cgeo.geocaching.cgImage; import cgeo.geocaching.cgTrackable; +import cgeo.geocaching.connector.gc.Login; import cgeo.geocaching.enumerations.CacheSize; import cgeo.geocaching.enumerations.CacheType; import cgeo.geocaching.enumerations.LogType; import cgeo.geocaching.geopoint.Geopoint; -import cgeo.geocaching.network.Login; import java.text.ParseException; import java.util.ArrayList; @@ -24,7 +24,7 @@ public class GC2JVEH extends MockedCache { } public GC2JVEH() { - super(new Geopoint(52.37225, 9.73537)); + super(new Geopoint(52.37225, 9.735367)); } @Override diff --git a/tests/src/cgeo/geocaching/test/mock/MockedCache.java b/tests/src/cgeo/geocaching/test/mock/MockedCache.java index 61369ee..21f67e6 100644 --- a/tests/src/cgeo/geocaching/test/mock/MockedCache.java +++ b/tests/src/cgeo/geocaching/test/mock/MockedCache.java @@ -5,7 +5,6 @@ import cgeo.geocaching.cgImage; import cgeo.geocaching.cgTrackable; import cgeo.geocaching.connector.gc.GCConstants; import cgeo.geocaching.geopoint.Geopoint; -import cgeo.geocaching.geopoint.GeopointFormatter; import cgeo.geocaching.utils.BaseUtils; import org.apache.commons.lang3.StringUtils; @@ -60,7 +59,7 @@ public abstract class MockedCache implements ICache { final BufferedReader br = new BufferedReader(new InputStreamReader(is), 150000); final StringBuilder buffer = new StringBuilder(); - String line = null; + String line; while ((line = br.readLine()) != null) { buffer.append(line).append('\n'); @@ -75,16 +74,6 @@ public abstract class MockedCache implements ICache { } @Override - public String getLatitude() { - return coords.format(GeopointFormatter.Format.LAT_DECMINUTE); - } - - @Override - public String getLongitude() { - return coords.format(GeopointFormatter.Format.LON_DECMINUTE); - } - - @Override public boolean isArchived() { return false; } diff --git a/tests/src/cgeo/geocaching/utils/AbstractLRUTest.java b/tests/src/cgeo/geocaching/utils/AbstractLRUTest.java new file mode 100644 index 0000000..83a796b --- /dev/null +++ b/tests/src/cgeo/geocaching/utils/AbstractLRUTest.java @@ -0,0 +1,20 @@ +package cgeo.geocaching.utils; + +import org.apache.commons.lang3.StringUtils; + +import android.test.AndroidTestCase; + +import java.util.ArrayList; +import java.util.Collection; + +public abstract class AbstractLRUTest extends AndroidTestCase { + + protected static String colToStr(Collection<?> col) { + final ArrayList<String> list = new ArrayList<String>(col.size()); + for (Object o : col) { + list.add(o.toString()); + } + return StringUtils.join(list, ", "); + } + +}
\ No newline at end of file diff --git a/tests/src/cgeo/geocaching/utils/BaseUtilsTest.java b/tests/src/cgeo/geocaching/utils/BaseUtilsTest.java new file mode 100644 index 0000000..e174d1f --- /dev/null +++ b/tests/src/cgeo/geocaching/utils/BaseUtilsTest.java @@ -0,0 +1,26 @@ +package cgeo.geocaching.utils; + +import cgeo.geocaching.connector.gc.GCConstants; +import cgeo.geocaching.test.mock.MockedCache; + +import android.test.AndroidTestCase; + +public class BaseUtilsTest extends AndroidTestCase { + public static void testRegEx() { + String page = MockedCache.readCachePage("GC2CJPF"); + assertEquals("blafoo", BaseUtils.getMatch(page, GCConstants.PATTERN_LOGIN_NAME, true, "???")); + assertTrue(page.contains("id=\"ctl00_hlRenew\"") || "Premium Member".equals(BaseUtils.getMatch(page, GCConstants.PATTERN_MEMBER_STATUS, true, "???"))); + int cachesFound = 0; + try { + cachesFound = Integer.parseInt(BaseUtils.getMatch(page, GCConstants.PATTERN_CACHES_FOUND, true, "0").replaceAll("[,.]", "")); + } catch (NumberFormatException e) { + fail(); + } + assertTrue(cachesFound >= 491); + } + + public static void testReplaceWhitespaces() { + assertEquals("foo bar baz ", BaseUtils.replaceWhitespace(" foo\n\tbar \r baz ")); + } + +} diff --git a/tests/src/cgeo/geocaching/utils/LeastRecentlyUsedMapTest.java b/tests/src/cgeo/geocaching/utils/LeastRecentlyUsedMapTest.java new file mode 100644 index 0000000..723b7153 --- /dev/null +++ b/tests/src/cgeo/geocaching/utils/LeastRecentlyUsedMapTest.java @@ -0,0 +1,85 @@ +package cgeo.geocaching.utils; + +import cgeo.geocaching.cgCache; + +import java.util.Map; + +public class LeastRecentlyUsedMapTest extends AbstractLRUTest { + + public static void testLruMode() { + final Map<String, String> map = new LeastRecentlyUsedMap.LruCache<String, String>(4); + map.put("one", "1"); + map.put("two", "2"); + map.put("three", "3"); + // keep in cache + map.get("one"); + map.put("four", "4"); + map.put("five", "5"); + map.put("six", "6"); + // keep in cache + map.get("one"); + // re-add + map.put("five", "5"); + map.put("seven", "7"); + + assertEquals("six, one, five, seven", colToStr(map.keySet())); + } + + public static void testBoundedMode() { + final Map<String, String> map = new LeastRecentlyUsedMap.Bounded<String, String>(5); + map.put("one", "1"); + map.put("two", "2"); + map.put("three", "3"); + // read does not change anything + map.get("one"); + map.put("four", "4"); + // re-put should update the order + map.put("three", "3"); + map.put("five", "5"); + // read does not change anything + map.get("one"); + map.put("six", "6"); + map.put("seven", "7"); + + assertEquals("four, three, five, six, seven", colToStr(map.keySet())); + } + + public static void testRemoveEldestEntry() { + final LeastRecentlyUsedMap<String, cgCache> cache = new LeastRecentlyUsedMap.LruCache<String, cgCache>(10); + final cgCache first = new cgCache(); + assertNull(cache.put("1", first)); + + final cgCache second = new cgCache(); + assertNull(cache.put("2", second)); + + assertEquals(2, cache.size()); + assertTrue(cache.containsKey("1")); + assertTrue(cache.containsValue(first)); + assertTrue(cache.containsKey("2")); + assertTrue(cache.containsValue(second)); + + for (int i = 3; i <= 10; i++) { + assertNull(cache.put(Integer.toString(i), new cgCache())); + } + + assertEquals(10, cache.size()); + assertTrue(cache.containsKey("1")); + assertTrue(cache.containsValue(first)); + assertTrue(cache.containsKey("2")); + assertTrue(cache.containsValue(second)); + + assertNotNull(cache.remove("1")); // just replacing the old entry would not work + assertNull(cache.put("1", new cgCache())); + assertNull(cache.put("11", new cgCache())); + + assertEquals(10, cache.size()); + + // first has been overwritten by new value, but key must be in, because it is very new + assertTrue(cache.containsKey("1")); + + // second has been overwritten by 11 + assertFalse(cache.containsKey("2")); + assertTrue(cache.containsKey("11")); + } + +} diff --git a/tests/src/cgeo/geocaching/utils/LeastRecentlyUsedSetTest.java b/tests/src/cgeo/geocaching/utils/LeastRecentlyUsedSetTest.java new file mode 100644 index 0000000..4b4e5f7 --- /dev/null +++ b/tests/src/cgeo/geocaching/utils/LeastRecentlyUsedSetTest.java @@ -0,0 +1,66 @@ +package cgeo.geocaching.utils; + +import cgeo.geocaching.cgCache; + +import java.util.Set; + +public class LeastRecentlyUsedSetTest extends AbstractLRUTest { + + public static void testLruMode() { + final Set<String> set = new LeastRecentlyUsedSet<String>(5); + set.add("one"); + set.add("two"); + set.add("three"); + // read does not change anything + set.contains("one"); + set.add("four"); + // re-put should update the order + set.add("three"); + set.add("five"); + // read does not change anything + set.contains("one"); + set.add("six"); + set.add("seven"); + + assertEquals("four, three, five, six, seven", colToStr(set)); + } + + public static void testRemoveEldestEntry() { + final LeastRecentlyUsedSet<cgCache> caches = new LeastRecentlyUsedSet<cgCache>(10); + final cgCache first = new cgCache(); + first.setGeocode("1"); + assertTrue(caches.add(first)); + + final cgCache second = new cgCache(); + second.setGeocode("2"); + assertTrue(caches.add(second)); + + assertEquals(2, caches.size()); + assertTrue(caches.contains(first)); + assertTrue(caches.contains(second)); + + // adding first cache again does not change set + assertFalse(caches.add(first)); + assertEquals(2, caches.size()); + + for (int i = 3; i <= 10; i++) { + final cgCache cache = new cgCache(); + cache.setGeocode(Integer.toString(i)); + assertTrue(caches.add(cache)); + } + + assertEquals(10, caches.size()); + assertTrue(caches.contains(first)); + assertTrue(caches.contains(second)); + + final cgCache c11 = new cgCache(); + c11.setGeocode("11"); + assertTrue(caches.add(c11)); + + assertEquals(10, caches.size()); + + // first was used again, there second is the oldest and has been overwritten by 11 + assertTrue(caches.contains(first)); + assertFalse(caches.contains(second)); + } +}
\ No newline at end of file diff --git a/tests/src/cgeo/geocaching/utils/MemorySubjectTest.java b/tests/src/cgeo/geocaching/utils/MemorySubjectTest.java new file mode 100644 index 0000000..30e4f60 --- /dev/null +++ b/tests/src/cgeo/geocaching/utils/MemorySubjectTest.java @@ -0,0 +1,78 @@ +package cgeo.geocaching.utils; + +import android.test.AndroidTestCase; + +public class MemorySubjectTest extends AndroidTestCase { + + private static class Observer implements IObserver<Integer> { + public int times = 0; + public Integer value; + + @Override + public void update(final Integer data) { + value = data; + times++; + } + } + + private Observer observer; + private MemorySubject<Integer> memorySubject; + + @Override + public void setUp() { + observer = new Observer(); + memorySubject = new MemorySubject<Integer>(); + } + + public void testInitial() { + assertNull(observer.value); + assertEquals(0, observer.times); + assertNull(memorySubject.getMemory()); + } + + public void testMemory() { + memorySubject.addObserver(observer); + memorySubject.notifyObservers(10); + assertEquals(Integer.valueOf(10), observer.value); + assertEquals(1, observer.times); + assertEquals(Integer.valueOf(10), memorySubject.getMemory()); + memorySubject.notifyObservers(20); + assertEquals(Integer.valueOf(20), observer.value); + assertEquals(2, observer.times); + assertEquals(Integer.valueOf(20), memorySubject.getMemory()); + } + + public void testAttach() { + memorySubject.notifyObservers(10); + assertNull(observer.value); + assertEquals(0, observer.times); + memorySubject.addObserver(observer); + assertEquals(Integer.valueOf(10), observer.value); + assertEquals(1, observer.times); + memorySubject.notifyObservers(20); + assertEquals(Integer.valueOf(20), observer.value); + assertEquals(2, observer.times); + } + + public void testDetach() { + memorySubject.addObserver(observer); + memorySubject.notifyObservers(10); + assertEquals(Integer.valueOf(10), observer.value); + assertEquals(1, observer.times); + assertEquals(Integer.valueOf(10), memorySubject.getMemory()); + memorySubject.deleteObserver(observer); + memorySubject.notifyObservers(20); + assertEquals(Integer.valueOf(10), observer.value); + assertEquals(1, observer.times); + assertEquals(Integer.valueOf(20), memorySubject.getMemory()); + } + + public void testMultiple() { + final Observer otherObserver = new Observer(); + memorySubject.addObserver(otherObserver); + testDetach(); + assertEquals(Integer.valueOf(20), otherObserver.value); + assertEquals(2, otherObserver.times); + } + +} diff --git a/tests/src/cgeo/test/Compare.java b/tests/src/cgeo/test/Compare.java new file mode 100644 index 0000000..817addc --- /dev/null +++ b/tests/src/cgeo/test/Compare.java @@ -0,0 +1,57 @@ +package cgeo.test; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertTrue; + +import cgeo.geocaching.ICache; +import cgeo.geocaching.cgCache; +import cgeo.geocaching.enumerations.LogType; + +public abstract class Compare { + + public static void assertCompareCaches(ICache expected, cgCache actual, boolean all) { + assertEquals(expected.getGeocode(), actual.getGeocode()); + assertTrue(expected.getType() == actual.getType()); + assertEquals(expected.getOwner(), actual.getOwner()); + assertEquals(expected.getDifficulty(), actual.getDifficulty()); + assertEquals(expected.getTerrain(), actual.getTerrain()); + assertEquals(expected.isDisabled(), actual.isDisabled()); + assertEquals(expected.isArchived(), actual.isArchived()); + assertEquals(expected.getSize(), actual.getSize()); + assertEquals(expected.getName(), actual.getName()); + assertEquals(expected.getGuid(), actual.getGuid()); + assertTrue(expected.getFavoritePoints() <= actual.getFavoritePoints()); + assertEquals(expected.getHiddenDate().toString(), actual.getHiddenDate().toString()); + assertEquals(expected.isPremiumMembersOnly(), actual.isPremiumMembersOnly()); + + if (all) { + assertEquals(expected.getCoords(), actual.getCoords()); + assertTrue(actual.isReliableLatLon()); + assertEquals(expected.isOwn(), actual.isOwn()); + assertEquals(expected.getOwnerReal(), actual.getOwnerReal()); + assertEquals(expected.getHint(), actual.getHint()); + assertTrue(actual.getDescription().startsWith(expected.getDescription())); + assertEquals(expected.getShortDescription(), actual.getShortDescription()); + assertEquals(expected.getCacheId(), actual.getCacheId()); + assertEquals(expected.getLocation(), actual.getLocation()); + assertEquals(expected.isFound(), actual.isFound()); + assertEquals(expected.isFavorite(), actual.isFavorite()); + assertEquals(expected.isWatchlist(), actual.isWatchlist()); + + for (String attribute : expected.getAttributes()) { + assertTrue(actual.getAttributes().contains(attribute)); + } + for (LogType logType : expected.getLogCounts().keySet()) { + assertTrue(actual.getLogCounts().get(logType) >= expected.getLogCounts().get(logType)); + } + + // The inventories can differ too often, therefore we don't compare them. Also, the personal note + // cannot be expected to match with different tester accounts. + + int actualSpoilersSize = null != actual.getSpoilers() ? actual.getSpoilers().size() : 0; + int expectedSpoilersSize = null != expected.getSpoilers() ? expected.getSpoilers().size() : 0; + assertEquals(expectedSpoilersSize, actualSpoilersSize); + } + } + +} |
