diff --git a/.travis.yml b/.travis.yml index 663abd02df3..3a15e6569e2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -60,6 +60,7 @@ after_failure: branches: only: - master + - maintable-beta # cache gradle dependencies # https://docs.travis-ci.com/user/languages/java#Caching diff --git a/build.gradle b/build.gradle index b6247e819db..d9eae627627 100644 --- a/build.gradle +++ b/build.gradle @@ -81,6 +81,7 @@ configurations { } dependencies { + // Include all jar-files in the 'lib' folder as dependencies compile fileTree(dir: 'lib', includes: ['*.jar']) compile 'com.jgoodies:jgoodies-common:1.8.1' @@ -112,20 +113,21 @@ dependencies { // VersionEye states that 6.0.5 is the most recent version, but http://dev.mysql.com/downloads/connector/j/ shows that as "Development Release" compile 'mysql:mysql-connector-java:5.1.46' - compile 'com.impossibl.pgjdbc-ng:pgjdbc-ng:0.7.1' + compile 'org.postgresql:postgresql:42.2.2' compile 'net.java.dev.glazedlists:glazedlists_java15:1.9.1' compile 'com.google.guava:guava:25.1-jre' // JavaFX stuff - compile 'com.airhacks:afterburner.fx:1.7.0' - compile 'de.codecentric.centerdevice:javafxsvg:1.3.0' compile 'de.jensd:fontawesomefx-materialdesignfont:1.7.22-4' compile 'de.saxsys:mvvmfx-validation:1.7.0' + compile 'de.saxsys:mvvmfx:1.7.0' compile 'org.fxmisc.easybind:easybind:1.0.3' compile 'org.fxmisc.flowless:flowless:0.6.1' compile 'org.fxmisc.richtext:richtextfx:0.9.0' + compile 'com.sibvisions.external.jvxfx:dndtabpane:0.1' + compile 'javax.inject:javax.inject:1' // Cannot be updated to 9.*.* until Jabref works with Java 9 compile 'org.controlsfx:controlsfx:8.40.15-SNAPSHOT' @@ -165,7 +167,7 @@ dependencies { testCompile 'org.xmlunit:xmlunit-matchers:2.6.0' testCompile 'com.tngtech.archunit:archunit-junit:0.8.0' testCompile "org.testfx:testfx-core:4.0.+" - testCompile "org.testfx:testfx-junit:4.0.+" + testCompile "org.testfx:testfx-junit5:4.0.+" checkstyle 'com.puppycrawl.tools:checkstyle:8.10.1' } diff --git a/config/Eclipse Code Style.epf b/config/Eclipse Code Style.epf new file mode 100644 index 00000000000..f0a04dd9eb8 --- /dev/null +++ b/config/Eclipse Code Style.epf @@ -0,0 +1,328 @@ +#Fri Mar 09 22:05:27 CET 2018 +\!/= +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.codeComplete.argumentPrefixes= +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.codeComplete.argumentSuffixes= +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.codeComplete.fieldPrefixes= +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.codeComplete.fieldSuffixes= +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.codeComplete.localPrefixes= +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.codeComplete.localSuffixes= +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.codeComplete.staticFieldPrefixes= +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.codeComplete.staticFieldSuffixes= +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes= +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes= +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.align_type_members_on_columns=false +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=0 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_assignment=0 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_compact_if=16 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=0 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_enum_constants=48 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_module_statements=16 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=88 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=0 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.blank_lines_after_package=1 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.blank_lines_before_field=0 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=1 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.blank_lines_before_method=1 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.blank_lines_before_package=0 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position=false +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.comment.format_block_comments=false +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.comment.format_header=false +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.comment.format_html=true +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=false +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.comment.format_line_comments=false +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.comment.format_source_code=true +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.comment.indent_root_tags=true +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.comment.line_length=120 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.compact_else_if=true +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.continuation_indentation=2 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.indent_empty_lines=false +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.indentation.size=4 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.join_lines_in_comments=false +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.join_wrapped_lines=false +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.lineSplit=9999 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.tabulation.char=space +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.tabulation.size=4 +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.use_on_off_tags=true +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=true +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=false +/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true +/instance/org.eclipse.jdt.ui/formatter_profile=_eclipse-cs JabRef +/instance/org.eclipse.jdt.ui/formatter_settings_version=13 +/instance/org.eclipse.jdt.ui/org.eclipse.jdt.ui.cleanupprofiles=\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n +/instance/org.eclipse.jdt.ui/org.eclipse.jdt.ui.exception.name=e +/instance/org.eclipse.jdt.ui/org.eclipse.jdt.ui.formatterprofiles=\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n +/instance/org.eclipse.jdt.ui/org.eclipse.jdt.ui.formatterprofiles.version=13 +/instance/org.eclipse.jdt.ui/org.eclipse.jdt.ui.gettersetter.use.is=true +/instance/org.eclipse.jdt.ui/org.eclipse.jdt.ui.overrideannotation=true +/instance/org.eclipse.jdt.ui/org.eclipse.jdt.ui.text.custom_code_templates= +@org.eclipse.jdt.core=3.13.100.v20171123-1049 +@org.eclipse.jdt.ui=3.13.51.v20171122-0652 +file_export_version=3.0 diff --git a/config/README.md b/config/README.md index 76ec69f0770..4088be4eff3 100644 --- a/config/README.md +++ b/config/README.md @@ -15,3 +15,16 @@ Style-checks are done for each pull request and installing this cody style confi 10. Press "OK" * Please let `.editorconfig` override the settings of IntelliJ + + +# Eclipse: + +The Eclipse code formatter style is stored in the `eclipse.gradle` file and gets imported automatically. +In case the formatter style needs to be adapted, configure it and export in in eclipse. + +1. Right click on the eclipse project "JabRef" +2. Select "Export > General > Preferences" +3. Select "Java Code Style preferences" +4. Choose output file +5. Compare the formatter settings in the epf file with the ones in the eclipse.gradle file (`org.eclipse.jdt.core.formatter.`) +6. Replace the Eclipse Code Style.epf with the exported epf file diff --git a/config/eclipseJabRef.xml b/config/eclipseJabRef.xml deleted file mode 100644 index 55862811cd5..00000000000 --- a/config/eclipseJabRef.xml +++ /dev/null @@ -1,314 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/eclipse.gradle b/eclipse.gradle index e4ab6fbc1ae..8efd725e98e 100644 --- a/eclipse.gradle +++ b/eclipse.gradle @@ -136,295 +136,310 @@ tasks.eclipse.doFirst { org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=warning org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning - org.eclipse.jdt.core.formatter.align_type_members_on_columns=false - org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 - org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0 - org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=0 - org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16 - org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16 - org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16 - org.eclipse.jdt.core.formatter.alignment_for_assignment=0 - org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16 - org.eclipse.jdt.core.formatter.alignment_for_compact_if=16 - org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=0 - org.eclipse.jdt.core.formatter.alignment_for_enum_constants=48 - org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16 - org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0 - org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 - org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16 - org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16 - org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=88 - org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=80 - org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16 - org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=0 - org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16 - org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16 - org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16 - org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16 + org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert + org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert + org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert + org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert + org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert + org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines + org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true + org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert + org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert + org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert + org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines + org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert 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=1 + org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert + org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=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_before_comma_in_method_declaration_throws=do not insert + org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines + org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=false + org.eclipse.jdt.core.formatter.indentation.size=4 + org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert + org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines + org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert + org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert + org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert + org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert + org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert + org.eclipse.jdt.core.formatter.disabling_tag=@formatter\\:off + org.eclipse.jdt.core.formatter.continuation_indentation=1 + org.eclipse.jdt.core.formatter.alignment_for_enum_constants=48 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_after_package=1 + org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert + org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert + org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines + org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=0 + org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert + org.eclipse.jdt.core.formatter.comment.indent_root_tags=true + org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=false + org.eclipse.jdt.core.formatter.enabling_tag=@formatter\\:on + org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert + org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position=false + org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert + org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16 + org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert + org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false + org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=do not insert + org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert + org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert + org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert 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.insert_space_before_closing_brace_in_array_initializer=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_after_opening_paren_in_catch=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_new_line_after_annotation_on_method=insert + org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert + org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0 + org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert + org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert + org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert + org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false + org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert + org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert + org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true 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.insert_space_before_question_in_wildcard=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_comma_in_method_invocation_arguments=do not insert + org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert + org.eclipse.jdt.core.formatter.comment.line_length=9999 + org.eclipse.jdt.core.formatter.use_on_off_tags=true + org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert + org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert + org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert + org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert + org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert + org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert + org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false + org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert + org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line + org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert + org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=18 + org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert + org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 + org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert + org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false + org.eclipse.jdt.core.formatter.alignment_for_binary_expression=18 + org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines + org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert + org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert + org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert + org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert + org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=18 + org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true + org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert + org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert + org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert 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_lambda_body=end_of_line - org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line - org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line - org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line + org.eclipse.jdt.core.formatter.compact_else_if=true + org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=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_method_invocation=do not insert + org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true + org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=18 + org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0 + org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert + org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=18 + org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=18 org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false + org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert + org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert + org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false - org.eclipse.jdt.core.formatter.comment.format_block_comments=false - org.eclipse.jdt.core.formatter.comment.format_header=false - org.eclipse.jdt.core.formatter.comment.format_html=true - org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=false - 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=do not insert - org.eclipse.jdt.core.formatter.comment.line_length=9999 - 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.insert_space_after_comma_in_array_initializer=insert + org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert + org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert + org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=18 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=do not 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_after_type_annotation=do not insert - org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert - org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert - org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert - 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.number_of_empty_lines_to_preserve=1 + org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines 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_before_ellipsis=do not insert + org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert + org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert + org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=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_and_in_type_parameter=insert + org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert + org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert + org.eclipse.jdt.core.formatter.comment.format_line_comments=false 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_lambda_arrow=insert - org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert - org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert - org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert - org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=do not 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.align_type_members_on_columns=false + org.eclipse.jdt.core.formatter.alignment_for_assignment=2 + org.eclipse.jdt.core.formatter.alignment_for_module_statements=16 + org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert + org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true + org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_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.alignment_for_superinterfaces_in_type_declaration=16 + org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=1 + org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=2 + org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_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.format_guardian_clause_on_one_line=false + org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert + org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert + org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert + org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line + org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line + org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert + org.eclipse.jdt.core.formatter.comment.format_header=false + org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=18 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_before_opening_paren_in_while=insert + org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert + org.eclipse.jdt.core.formatter.alignment_for_method_declaration=16 + org.eclipse.jdt.core.formatter.join_wrapped_lines=false + org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert + org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=true + org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true + 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_paren_in_synchronized=do not insert + org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647 + org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true + org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line + org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert + org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=26 + org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false + org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines + org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=18 + org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert - org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert - org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert - org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert - org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert - org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert - org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert - org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert + org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert + org.eclipse.jdt.core.formatter.tabulation.size=4 + org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert + org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=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_colon_in_conditional=insert + org.eclipse.jdt.core.formatter.comment.format_source_code=true + org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert + org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert + org.eclipse.jdt.core.formatter.blank_lines_before_field=0 + org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert + org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=1 + org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert + org.eclipse.jdt.core.formatter.blank_lines_before_method=1 + org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16 + org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=0 + org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert + org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false + org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert + org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line + org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert + org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert + org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert + org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=do not insert + org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert + org.eclipse.jdt.core.formatter.comment.format_html=true + org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert + org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert + org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines + org.eclipse.jdt.core.formatter.alignment_for_compact_if=16 + org.eclipse.jdt.core.formatter.indent_empty_lines=false + org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0 + org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not 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_opening_paren_in_enum_constant=do not insert + org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0 + org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert + org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false + org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true + org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not 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_opening_paren_in_constructor_declaration=do not insert + org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 + org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert + org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true + 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_paren_in_constructor_declaration=do not insert + org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=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_comma_in_method_declaration_parameters=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=do not insert - org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert - org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert - org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert - org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert - org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert - org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert - org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert - org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert - org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert - org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert - org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert - org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert - org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert - org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert - org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert - org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert - org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert - org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert - org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert - org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert - org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert - org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert - org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert - org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert - org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert - org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert - org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert - org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert - org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert - org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert - org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert - org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert - org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert - org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert - org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert - org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert - org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert - org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert - org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert - org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert - org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert - org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert + org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1 + org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=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_closing_angle_bracket_in_parameterized_type_reference=do not insert + org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=18 + 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_in_empty_enum_declaration=insert + org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true + org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=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_before_semicolon=do not insert + org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert + org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert org.eclipse.jdt.core.formatter.insert_space_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_after_opening_paren_in_cast=do not insert + org.eclipse.jdt.core.formatter.comment.format_block_comments=false + org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert + org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert + org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false 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.alignment_for_parameters_in_method_declaration=18 + org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=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_semicolon_in_for=do not insert + org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert + org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true + org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 + org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert + org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert + org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line + org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true + org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert + org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=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_bracket_in_array_reference=do not insert + org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert + org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert + org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines + org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert + org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=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_opening_brace_in_annotation_type_declaration=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.wrap_outer_expressions_when_nested=true + org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert + org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line + org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line + org.eclipse.jdt.core.formatter.blank_lines_before_package=0 + org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert - org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert - org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert - org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert - org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert - org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert - org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert - org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert - org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert - org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert - org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert - org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert - org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert - org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert - org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert - org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert - org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert - org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert - org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert - org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert - org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert + org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=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.alignment_for_expressions_in_for_loop_header=0 + org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=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_comma_in_explicitconstructorcall_arguments=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_after_opening_angle_bracket_in_type_parameters=do not insert + org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true + org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert + org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert + org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=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=9999 - 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.parentheses_positions_in_for_statment=common_lines - org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocationc=common_lines - org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines - org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines - org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines + 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_question_in_conditional=insert + org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true + org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert 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=true - org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false - org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true - org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=false - org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true + org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert + org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1 + org.eclipse.jdt.core.formatter.lineSplit=9999 + org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert + org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter '''. stripIndent()) diff --git a/external-libraries.txt b/external-libraries.txt index 80992ae8e21..4bbbfcfb3cf 100644 --- a/external-libraries.txt +++ b/external-libraries.txt @@ -80,6 +80,11 @@ Project: Application Insights SDK for Java URL: https://github.com/Microsoft/ApplicationInsights-Java License: MIT +Id: com.sibvisions.external.jvxfx:DnDTabPane +Project: Drag'n'Drop TabPane +URL: https://github.com/sibvisions/javafx.DndTabPane +License: EPL-1.0 + Id: commons-cli:commons-cli Project: Apache Commons CLI URL: http://commons.apache.org/cli/ diff --git a/javafx/scene/control/annotations.xml b/javafx/scene/control/annotations.xml new file mode 100644 index 00000000000..240687d556c --- /dev/null +++ b/javafx/scene/control/annotations.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/lib/afterburner.fx.jar b/lib/afterburner.fx.jar new file mode 100644 index 00000000000..816b3e27f5d Binary files /dev/null and b/lib/afterburner.fx.jar differ diff --git a/lib/customjfx-1.0.0.jar b/lib/customjfx-1.0.0.jar deleted file mode 100644 index 4636cdd8975..00000000000 Binary files a/lib/customjfx-1.0.0.jar and /dev/null differ diff --git a/src/main/java/org/jabref/Globals.java b/src/main/java/org/jabref/Globals.java index b00066a86a4..4cc1cef90b6 100644 --- a/src/main/java/org/jabref/Globals.java +++ b/src/main/java/org/jabref/Globals.java @@ -5,12 +5,14 @@ import java.util.Optional; import java.util.UUID; +import org.jabref.gui.ClipBoardManager; import org.jabref.gui.GlobalFocusListener; import org.jabref.gui.StateManager; import org.jabref.gui.keyboard.KeyBindingRepository; import org.jabref.gui.util.DefaultFileUpdateMonitor; import org.jabref.gui.util.DefaultTaskExecutor; import org.jabref.gui.util.TaskExecutor; +import org.jabref.gui.util.ThemeLoader; import org.jabref.logic.exporter.ExporterFactory; import org.jabref.logic.importer.ImportFormatReader; import org.jabref.logic.journals.JournalAbbreviationLoader; @@ -49,6 +51,9 @@ public class Globals { /** * Manager for the state of the GUI. */ + + public static ClipBoardManager clipboardManager = new ClipBoardManager(); + public static StateManager stateManager = new StateManager(); public static ExporterFactory exportFactory; // Key binding preferences @@ -56,6 +61,7 @@ public class Globals { // Background tasks private static GlobalFocusListener focusListener; private static DefaultFileUpdateMonitor fileUpdateMonitor; + private static ThemeLoader themeLoader; private static TelemetryClient telemetryClient; private Globals() { @@ -69,7 +75,6 @@ public static synchronized KeyBindingRepository getKeyPrefs() { return keyBindingRepository; } - // Background tasks public static void startBackgroundTasks() { Globals.focusListener = new GlobalFocusListener(); @@ -77,6 +82,8 @@ public static void startBackgroundTasks() { Globals.fileUpdateMonitor = new DefaultFileUpdateMonitor(); JabRefExecutorService.INSTANCE.executeInterruptableTask(Globals.fileUpdateMonitor, "FileUpdateMonitor"); + themeLoader = new ThemeLoader(fileUpdateMonitor); + if (Globals.prefs.shouldCollectTelemetry() && !GraphicsEnvironment.isHeadless()) { startTelemetryClient(); } @@ -126,4 +133,8 @@ public static void stopBackgroundTasks() { public static Optional getTelemetryClient() { return Optional.ofNullable(telemetryClient); } + + public static ThemeLoader getThemeLoader() { + return themeLoader; + } } diff --git a/src/main/java/org/jabref/JabRefExecutorService.java b/src/main/java/org/jabref/JabRefExecutorService.java index 3f5aa22badc..df127df89f6 100644 --- a/src/main/java/org/jabref/JabRefExecutorService.java +++ b/src/main/java/org/jabref/JabRefExecutorService.java @@ -140,7 +140,7 @@ public void shutdownEverything() { this.lowPriorityExecutorService.shutdownNow(); // kill the remote thread stopRemoteThread(); - // timer doesn't need to be canceled as it is run in daemon mode, which ensures that it is stopped if the application is shut down + timer.cancel(); } private class NamedRunnable implements Runnable { diff --git a/src/main/java/org/jabref/JabRefGUI.java b/src/main/java/org/jabref/JabRefGUI.java index 47dab3221ae..fbde85a059f 100644 --- a/src/main/java/org/jabref/JabRefGUI.java +++ b/src/main/java/org/jabref/JabRefGUI.java @@ -1,7 +1,6 @@ package org.jabref; import java.awt.Font; -import java.awt.Frame; import java.io.File; import java.sql.SQLException; import java.util.ArrayList; @@ -10,16 +9,21 @@ import java.util.Iterator; import java.util.List; -import javax.swing.JOptionPane; import javax.swing.UIDefaults; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import javax.swing.plaf.FontUIResource; +import javafx.scene.Scene; +import javafx.stage.Stage; + import org.jabref.gui.BasePanel; +import org.jabref.gui.DialogService; +import org.jabref.gui.FXDialogService; import org.jabref.gui.GUIGlobals; import org.jabref.gui.JabRefFrame; import org.jabref.gui.dialogs.BackupUIManager; +import org.jabref.gui.icon.IconTheme; import org.jabref.gui.importer.ParserResultWarningDialog; import org.jabref.gui.importer.actions.OpenDatabaseAction; import org.jabref.gui.shared.SharedDatabaseUIManager; @@ -41,8 +45,10 @@ public class JabRefGUI { private static final String NIMBUS_LOOK_AND_FEEL = "javax.swing.plaf.nimbus.NimbusLookAndFeel"; + private static final String WINDOWS_LOOK_AND_FEEL = "com.sun.java.swing.plaf.windows.WindowsLookAndFeel"; + private static final String OSX_AQUA_LOOk_AND_FEEL = "apple.laf.AquaLookAndFeel"; + private static final Logger LOGGER = LoggerFactory.getLogger(JabRefGUI.class); - private static final String GTK_LF_CLASSNAME = "com.sun.java.swing.plaf.gtk.GTKLookAndFeel"; private static JabRefFrame mainFrame; @@ -50,21 +56,23 @@ public class JabRefGUI { private final boolean isBlank; private final List failed = new ArrayList<>(); private final List toOpenTab = new ArrayList<>(); + private final DialogService dialogService; private final String focusedFile; - public JabRefGUI(List argsDatabases, boolean isBlank) { + public JabRefGUI(Stage mainStage, List argsDatabases, boolean isBlank) { this.bibDatabases = argsDatabases; this.isBlank = isBlank; + this.dialogService = new FXDialogService(mainStage); // passed file (we take the first one) should be focused focusedFile = argsDatabases.stream() - .findFirst() - .flatMap(ParserResult::getFile) - .map(File::getAbsolutePath) - .orElse(Globals.prefs.get(JabRefPreferences.LAST_FOCUSED)); + .findFirst() + .flatMap(ParserResult::getFile) + .map(File::getAbsolutePath) + .orElse(Globals.prefs.get(JabRefPreferences.LAST_FOCUSED)); - openWindow(); + openWindow(mainStage); JabRefGUI.checkForNewVersion(false); } @@ -74,13 +82,7 @@ public static void checkForNewVersion(boolean manualExecution) { new VersionWorker(JabRefGUI.getMainFrame(), manualExecution, currentVersion, toBeIgnored).execute(); } - private void openWindow() { - - // This property is set to make the Mac OSX Java VM move the menu bar to the top of the screen - if (OS.OS_X) { - System.setProperty("apple.laf.useScreenMenuBar", "true"); - } - + private void openWindow(Stage mainStage) { // Set antialiasing on everywhere. This only works in JRE >= 1.5. // Or... it doesn't work, period. // TODO test and maybe remove this! I found this commented out with no additional info ( payload@lavabit.com ) @@ -101,7 +103,7 @@ private void openWindow() { GUIGlobals.init(); LOGGER.debug("Initializing frame"); - JabRefGUI.mainFrame = new JabRefFrame(); + JabRefGUI.mainFrame = new JabRefFrame(mainStage); // Add all bibDatabases databases to the frame: boolean first = false; @@ -120,14 +122,15 @@ private void openWindow() { try { new SharedDatabaseUIManager(mainFrame).openSharedDatabaseFromParserResult(pr); } catch (SQLException | DatabaseNotSupportedException | InvalidDBMSConnectionPropertiesException | - NotASharedDatabaseException e) { + NotASharedDatabaseException e) { pr.getDatabaseContext().clearDatabaseFile(); // do not open the original file pr.getDatabase().clearSharedDatabaseID(); LOGGER.error("Connection error", e); - JOptionPane.showMessageDialog(mainFrame, - e.getMessage() + "\n\n" + Localization.lang("A local copy will be opened."), - Localization.lang("Connection error"), JOptionPane.WARNING_MESSAGE); + dialogService.showErrorDialogAndWait( + Localization.lang("Connection error"), + Localization.lang("A local copy will be opened."), + e); } toOpenTab.add(pr); } else if (pr.toOpenTab()) { @@ -151,18 +154,29 @@ private void openWindow() { // state. This needs to be set after the window has been made visible, so we // do it here: if (Globals.prefs.getBoolean(JabRefPreferences.WINDOW_MAXIMISED)) { - JabRefGUI.getMainFrame().setExtendedState(Frame.MAXIMIZED_BOTH); + mainStage.setMaximized(true); } - JabRefGUI.getMainFrame().setVisible(true); + Scene scene = new Scene(JabRefGUI.mainFrame, 800, 800); + Globals.getThemeLoader().installBaseCss(scene); + mainStage.setTitle(JabRefFrame.FRAME_TITLE); + mainStage.getIcons().addAll(IconTheme.getLogoSetFX()); + mainStage.setScene(scene); + mainStage.show(); + + mainStage.setOnCloseRequest(event -> { + boolean reallyQuit = mainFrame.quit(); + if (!reallyQuit) { + event.consume(); + } + }); for (ParserResult pr : failed) { - String message = "" + Localization.lang("Error opening file '%0'.", pr.getFile().get().getName()) - + "

" - + pr.getErrorMessage() + ""; + String message = Localization.lang("Error opening file '%0'.", pr.getFile().get().getName()) + "\n" + + pr.getErrorMessage(); + + dialogService.showErrorDialogAndWait(Localization.lang("Error opening file"), message); - JOptionPane.showMessageDialog(JabRefGUI.getMainFrame(), message, Localization.lang("Error opening file"), - JOptionPane.ERROR_MESSAGE); } // Display warnings, if any @@ -187,10 +201,6 @@ private void openWindow() { } LOGGER.debug("Finished adding panels"); - - if (!bibDatabases.isEmpty()) { - JabRefGUI.getMainFrame().getCurrentBasePanel().getMainTable().requestFocus(); - } } private void openLastEditedDatabases() { @@ -208,11 +218,11 @@ private void openLastEditedDatabases() { } if (BackupManager.checkForBackupFile(dbFile.toPath())) { - BackupUIManager.showRestoreBackupDialog(mainFrame, dbFile.toPath()); + BackupUIManager.showRestoreBackupDialog(dialogService, dbFile.toPath()); } ParserResult parsedDatabase = OpenDatabase.loadDatabase(fileName, - Globals.prefs.getImportFormatPreferences(), Globals.getFileUpdateMonitor()); + Globals.prefs.getImportFormatPreferences(), Globals.getFileUpdateMonitor()); if (parsedDatabase.isEmpty()) { LOGGER.error(Localization.lang("Error opening file") + " '" + dbFile.getPath() + "'"); @@ -233,50 +243,30 @@ private boolean isLoaded(File fileToOpen) { private void setLookAndFeel() { try { - String lookFeel; - String systemLookFeel = UIManager.getSystemLookAndFeelClassName(); - - if (Globals.prefs.getBoolean(JabRefPreferences.USE_DEFAULT_LOOK_AND_FEEL)) { - // FIXME: Problems with GTK L&F on Linux and Mac. Needs reevaluation for Java9 - if (GTK_LF_CLASSNAME.equals(systemLookFeel)) { - lookFeel = NIMBUS_LOOK_AND_FEEL; - LOGGER.warn("There seems to be problems with GTK Look&Feel. Using Nimbus L&F instead. Change to another L&F with caution."); - } else { - lookFeel = systemLookFeel; - } - } else { - lookFeel = Globals.prefs.get(JabRefPreferences.WIN_LOOK_AND_FEEL); - } - //Prevent metal l&f - if (UIManager.getCrossPlatformLookAndFeelClassName().equals(lookFeel)) { - UIManager.setLookAndFeel(NIMBUS_LOOK_AND_FEEL); + if (OS.WINDOWS) { + UIManager.setLookAndFeel(WINDOWS_LOOK_AND_FEEL); + } + if (OS.OS_X) { + UIManager.setLookAndFeel(OSX_AQUA_LOOk_AND_FEEL); } else { - try { - UIManager.setLookAndFeel(lookFeel); - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | - UnsupportedLookAndFeelException e) { - // specified look and feel does not exist on the classpath, so use system l&f - UIManager.setLookAndFeel(systemLookFeel); - // also set system l&f as default - Globals.prefs.put(JabRefPreferences.WIN_LOOK_AND_FEEL, systemLookFeel); - // notify the user - JOptionPane.showMessageDialog(JabRefGUI.getMainFrame(), - Localization - .lang("Unable to find the requested look and feel and thus the default one is used."), - Localization.lang("Warning"), JOptionPane.WARNING_MESSAGE); - LOGGER.warn("Unable to find requested look and feel", e); - } + UIManager.setLookAndFeel(NIMBUS_LOOK_AND_FEEL); } - // On Linux, Java FX fonts look blurry per default. This can be improved by using a non-default rendering // setting. See https://github.com/woky/javafx-hates-linux if (Globals.prefs.getBoolean(JabRefPreferences.FX_FONT_RENDERING_TWEAK)) { System.setProperty("prism.text", "t2k"); System.setProperty("prism.lcdtext", "true"); } - } catch (Exception e) { - LOGGER.warn("Look and feel could not be set", e); + } catch (UnsupportedLookAndFeelException | ClassNotFoundException | InstantiationException | IllegalAccessException e) { + try { + LOGGER.warn("Setting Look and Feel to Nimbus", e); + + UIManager.setLookAndFeel(NIMBUS_LOOK_AND_FEEL); + } catch (Exception ex) { + LOGGER.warn("Look and feel could not be set", e); + } + } // In JabRef v2.8, we did it only on NON-Mac. Now, we try on all platforms diff --git a/src/main/java/org/jabref/JabRefMain.java b/src/main/java/org/jabref/JabRefMain.java index 4654655e860..fd4ffda4dde 100644 --- a/src/main/java/org/jabref/JabRefMain.java +++ b/src/main/java/org/jabref/JabRefMain.java @@ -4,7 +4,6 @@ import javax.swing.JFrame; import javax.swing.JOptionPane; -import javax.swing.SwingUtilities; import javafx.application.Application; import javafx.application.Platform; @@ -47,8 +46,39 @@ public static void main(String[] args) { @Override public void start(Stage mainStage) throws Exception { - Platform.setImplicitExit(false); - SwingUtilities.invokeLater(() -> start(arguments)); + // Fail on unsupported Java versions + ensureCorrectJavaVersion(); + FallbackExceptionHandler.installExceptionHandler(); + + // Init preferences + final JabRefPreferences preferences = JabRefPreferences.getInstance(); + Globals.prefs = preferences; + // Perform migrations + PreferencesMigrations.runMigrations(); + + configureProxy(preferences.getProxyPreferences()); + + Globals.startBackgroundTasks(); + + applyPreferences(preferences); + + // Process arguments + ArgumentProcessor argumentProcessor = new ArgumentProcessor(arguments, ArgumentProcessor.Mode.INITIAL_START); + + // Check for running JabRef + if (!handleMultipleAppInstances(arguments) || argumentProcessor.shouldShutDown()) { + shutdownCurrentInstance(); + return; + } + + // If not, start GUI + new JabRefGUI(mainStage, argumentProcessor.getParserResults(), argumentProcessor.isBlank()); + } + + @Override + public void stop() { + Platform.exit(); + System.exit(0); } /** @@ -73,11 +103,9 @@ private static void ensureCorrectJavaVersion() { if (java9Fail || versionFail) { StringBuilder versionError = new StringBuilder( - Localization.lang("Your current Java version (%0) is not supported. Please install version %1 or higher.", - checker.getJavaVersion(), - buildInfo.getMinRequiredJavaVersion() - ) - ); + Localization.lang("Your current Java version (%0) is not supported. Please install version %1 or higher.", + checker.getJavaVersion(), + buildInfo.getMinRequiredJavaVersion())); versionError.append("\n"); versionError.append(Localization.lang("Your Java Runtime Environment is located at %0.", checker.getJavaInstallationDirectory())); @@ -87,7 +115,7 @@ private static void ensureCorrectJavaVersion() { versionError.append(Localization.lang("Note that currently, JabRef does not run with Java 9.")); } final JFrame frame = new JFrame(); - JOptionPane.showMessageDialog(frame, versionError, Localization.lang("Error"), JOptionPane.ERROR_MESSAGE); + JOptionPane.showMessageDialog(null, versionError, Localization.lang("Error"), JOptionPane.ERROR_MESSAGE); frame.dispose(); // We exit on Java 9 error since this will definitely not work @@ -97,61 +125,31 @@ private static void ensureCorrectJavaVersion() { } } - private static void start(String[] args) { - // Fail on unsupported Java versions - ensureCorrectJavaVersion(); - FallbackExceptionHandler.installExceptionHandler(); - - // Init preferences - final JabRefPreferences preferences = JabRefPreferences.getInstance(); - Globals.prefs = preferences; - // Perform migrations - PreferencesMigrations.runMigrations(); - - configureProxy(preferences.getProxyPreferences()); - - Globals.startBackgroundTasks(); - - applyPreferences(preferences); - - // Process arguments - ArgumentProcessor argumentProcessor = new ArgumentProcessor(args, ArgumentProcessor.Mode.INITIAL_START); - - // Check for running JabRef - if (!handleMultipleAppInstances(args) || argumentProcessor.shouldShutDown()) { - shutdownCurrentInstance(); - return; - } - - // If not, start GUI - SwingUtilities - .invokeLater(() -> new JabRefGUI(argumentProcessor.getParserResults(), argumentProcessor.isBlank())); - } - private static boolean handleMultipleAppInstances(String[] args) { RemotePreferences remotePreferences = Globals.prefs.getRemotePreferences(); if (remotePreferences.useRemoteServer()) { - Globals.REMOTE_LISTENER.open(new JabRefMessageHandler(), remotePreferences.getPort()); - - if (!Globals.REMOTE_LISTENER.isOpen()) { - // we are not alone, there is already a server out there, try to contact already running JabRef: - if (new RemoteClient(remotePreferences.getPort()).sendCommandLineArguments(args)) { - // We have successfully sent our command line options through the socket to another JabRef instance. + // Try to contact already running JabRef + RemoteClient remoteClient = new RemoteClient(remotePreferences.getPort()); + if (remoteClient.ping()) { + // We are not alone, there is already a server out there, send command line arguments to other instance + if (remoteClient.sendCommandLineArguments(args)) { // So we assume it's all taken care of, and quit. LOGGER.info(Localization.lang("Arguments passed on to running JabRef instance. Shutting down.")); return false; } + } else { + // We are alone, so we start the server + Globals.REMOTE_LISTENER.openAndStart(new JabRefMessageHandler(), remotePreferences.getPort()); } - // we are alone, we start the server - Globals.REMOTE_LISTENER.start(); } return true; } private static void shutdownCurrentInstance() { + Globals.stopBackgroundTasks(); Globals.shutdownThreadPools(); - // needed to tell JavaFx to stop Platform.exit(); + System.exit(0); } private static void applyPreferences(JabRefPreferences preferences) { diff --git a/src/main/java/org/jabref/cli/JabRefCLI.java b/src/main/java/org/jabref/cli/JabRefCLI.java index ee79dee219d..83459c97e01 100644 --- a/src/main/java/org/jabref/cli/JabRefCLI.java +++ b/src/main/java/org/jabref/cli/JabRefCLI.java @@ -4,6 +4,7 @@ import org.jabref.Globals; import org.jabref.logic.l10n.Localization; +import org.jabref.model.database.BibDatabaseMode; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.DefaultParser; @@ -173,7 +174,7 @@ private Options getOptions() { options.addOption( Option.builder("ib") .longOpt("importBibtex") - .desc(String.format("%s: %s[,importBibtex bibtexString]", Localization.lang("Import") + " " + Localization.BIBTEX, Localization.lang("filename"))) + .desc(String.format("%s: %s[,importBibtex bibtexString]", Localization.lang("Import") + " " + BibDatabaseMode.BIBTEX.getFormattedName(), Localization.lang("filename"))) .hasArg() .argName("FILE") .build()); diff --git a/src/main/java/org/jabref/gui/AbstractController.java b/src/main/java/org/jabref/gui/AbstractController.java deleted file mode 100644 index 53ad25c113b..00000000000 --- a/src/main/java/org/jabref/gui/AbstractController.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.jabref.gui; - -import java.util.Objects; - -import javafx.fxml.FXML; -import javafx.fxml.FXMLLoader; -import javafx.stage.Stage; - -public class AbstractController { - - @FXML protected T viewModel; - private Stage stage; - - /** - * Gets the associated view model. - * - * Without this method the {@link FXMLLoader} is not able to resolve references in the fxml file of the form - * text="${controller.viewModel.someProperty}" - */ - public T getViewModel() { - return viewModel; - } - - /** - * Returns the stage where this controller is displayed. - * The stage can be used to e.g. close the dialog. - */ - public Stage getStage() { - return stage; - } - - public void setStage(Stage stage) { - this.stage = Objects.requireNonNull(stage); - } -} diff --git a/src/main/java/org/jabref/gui/AbstractDialogView.java b/src/main/java/org/jabref/gui/AbstractDialogView.java deleted file mode 100644 index d7880e3cd11..00000000000 --- a/src/main/java/org/jabref/gui/AbstractDialogView.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.jabref.gui; - -import java.util.function.Function; - -public abstract class AbstractDialogView extends AbstractView { - - public AbstractDialogView() { - super(); - } - - public AbstractDialogView(Function injectionContext) { - super(injectionContext); - } - - public abstract void show(); -} diff --git a/src/main/java/org/jabref/gui/AbstractView.java b/src/main/java/org/jabref/gui/AbstractView.java deleted file mode 100644 index 055d5a69d0e..00000000000 --- a/src/main/java/org/jabref/gui/AbstractView.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.jabref.gui; - -import java.util.Optional; -import java.util.function.Function; - -import javafx.scene.Parent; -import javafx.stage.Stage; - -import org.jabref.logic.l10n.Localization; - -import com.airhacks.afterburner.views.FXMLView; - -public class AbstractView extends FXMLView { - - public AbstractView() { - this(f -> null); - } - - public AbstractView(Function injectionContext) { - super(injectionContext); - - // Set resource bundle to internal localizations - bundle = Localization.getMessages(); - } - - @Override - public Parent getView() { - Parent view = super.getView(); - - // Add our base css file - view.getStylesheets().add(0, AbstractDialogView.class.getResource("Main.css").toExternalForm()); - - // Notify controller about the stage, where it is displayed - view.sceneProperty().addListener((observable, oldValue, newValue) -> { - if (newValue != null && newValue.getWindow() instanceof Stage) { - Stage stage = (Stage) newValue.getWindow(); - if (stage != null) { - getController().ifPresent(controller -> controller.setStage(stage)); - } - } - }); - return view; - } - - private Optional getController() { - return Optional.ofNullable(presenterProperty.get()).map( - presenter -> (AbstractController) presenter); - } -} diff --git a/src/main/java/org/jabref/gui/Base.css b/src/main/java/org/jabref/gui/Base.css new file mode 100644 index 00000000000..0032fb67f0b --- /dev/null +++ b/src/main/java/org/jabref/gui/Base.css @@ -0,0 +1,838 @@ +.root { + + /* + The theme color and some derived colors from it are used for icons, tab-headers, marking of selected inputs and + hover colors for the main menu. It generally defines the look of JabRef. The highlighting colors below should + work nicely with this base color + */ + + /* This theme is the original JabRef dark blue color */ + -jr-theme: #50618F; + -jr-accent: #a3b7e6; + -jr-selected: -jr-accent; + -jr-hover: #0002; + + /* The base gray. Most gray-tones in the application are derived from this color. */ + -jr-base: #ebebeb; + + -jr-white: #ffffff; + -jr-gray-0: #f2f2f2; + -jr-gray-1: #e6e6e6; + -jr-gray-2: #808080; + -jr-gray-3: #404040; + -jr-black: #000; + + /* Highlights */ + -jr-blue: #0abde3; + -jr-light-blue: #48dbfb; + -jr-purple: #f368e0; + -jr-light-purple: #ff9ff3; + -jr-green: #10ac84; + -jr-light-green: #1dd1a1; + -jr-red: #ee5253; + -jr-light-red: #ff6b6b; + -jr-yellow: #feca57; + -jr-orange: #ff9f43; + + /* Some blueish greys */ + -jr-blue-gray-1: #c8d6e5; + -jr-blue-gray-2: #8395a7; + -jr-blue-gray-3: #576574; + -jr-blue-gray-4: #222f3e; + + /* Background specs */ + -jr-background-alt: -fx-background; + -jr-text-area-background: derive(-jr-base, 80%); + -jr-search-background: -jr-text-area-background; + -jr-toolbar: derive(-jr-base, 46.4%); + -jr-menu-background: derive(-jr-base, 46.4%); + -jr-menu-background-active: -jr-hover; + + -jr-menu-foreground: -fx-dark-text-color; + -jr-menu-item-foreground: -fx-dark-text-color; + -jr-menu-forground-active: -fx-dark-text-color; + + -jr-drag-target: -jr-accent; + + -jr-head-fg: -fx-text-inner-color; + + /* All icons/text on toolbars */ + -jr-theme-text: -jr-theme; + + -jr-icon-background: transparent; + -jr-icon-background-active: #0001; + -jr-icon-background-armed: #0002; + + /* Colors for messages and errors */ + -jr-info: -jr-light-green; + -jr-warn: -jr-orange; + -jr-error: -jr-light-red; + + /* Color for the small group view indicator for the number of hits */ + -jr-group-hits-bg: derive(-jr-sidepane-background, -5%); + -jr-group-hits-fg: ladder( + -jr-group-hits-bg, + -fx-light-text-color 45%, + -fx-dark-text-color 46%, + -fx-dark-text-color 59%, + -fx-mid-text-color 60% + ); + + /* Specific color for general tooltips */ + -jr-tooltip-bg: -jr-accent; + -jr-tooltip-fg: -jr-black; + + /* Finally, some specific jr styles that depend on -fx definitions in *this* style */ + -jr-sidepane-background: -jr-gray-0; + -jr-sidepane-header-background: -jr-gray-0; + -jr-sidepane-header-color: -jr-theme-text; + + /* Specs for the scrollbars */ + -jr-scrollbar-thumb: -fx-outer-border; + -jr-scrollbar-track: -fx-control-inner-background; + + -jr-separator: derive(-fx-color, -5%); + + -jr-search-text: -fx-text-base-color; + + /* + Here are redefinitions of the default properties of modena. They should in principle all be derived from the + above colors. Goal should be to make as few as possible direct color-changes to elements and only do this for + very specific purposes. + */ + -fx-base: -jr-base; + + /* A very light grey used for the background of windows. See also + * -fx-text-background-color, which should be used as the -fx-text-fill + * value for text painted on top of backgrounds colored with -fx-background. + */ + -fx-background: derive(-fx-base, 26.4%); + + /* Used for the inside of text boxes, password boxes, lists, trees, and + * tables. See also -fx-text-inner-color, which should be used as the + * -fx-text-fill value for text painted on top of backgrounds colored + * with -fx-control-inner-background. + */ + -fx-control-inner-background: derive(-fx-base, 95%); + /* Version of -fx-control-inner-background for alternative rows */ + -fx-control-inner-background-alt: derive(-fx-control-inner-background, -2%); + + /* One of these colors will be chosen based upon a ladder calculation + * that uses the brightness of a background color. Instead of using these + * colors directly as -fx-text-fill values, the sections in this file should + * use a derived color to match the background in use. See also: + * + * -fx-text-base-color for text on top of -fx-base, -fx-color, and -fx-body-color + * -fx-text-background-color for text on top of -fx-background + * -fx-text-inner-color for text on top of -fx-control-inner-color + * -fx-selection-bar-text for text on top of -fx-selection-bar + */ + -fx-dark-text-color: -jr-black; + -fx-mid-text-color: -jr-gray-3; + -fx-light-text-color: -jr-white; + + /* We overwrite accents -> make old stick out */ + -fx-accent: red; + + /* Default buttons color, this is similar to accent but more subtle */ + -fx-default-button: derive(-jr-accent, 50%); + + /* A bright blue for the focus indicator of objects. Typically used as the + * first color in -fx-background-color for the "focused" pseudo-class. Also + * typically used with insets of -1.4 to provide a glowing effect. + */ + -fx-focus-color: -jr-accent; + -fx-faint-focus-color: derive(-jr-accent, 50%); + + /* The color that is used in styling controls. The default value is based + * on -fx-base, but is changed by pseudoclasses to change the base color. + * For example, the "hover" pseudoclass will typically set -fx-color to + * -fx-hover-base (see below) and the "armed" pseudoclass will typically + * set -fx-color to -fx-pressed-base. + */ + -fx-color: -fx-base; + + -fx-hover-base: derive(-fx-base,30%); + + /* A little darker than -fx-base and used as the -fx-color for the + * "armed" pseudoclass state. + * + * TODO: should this be renamed to -fx-armed-base? + */ + -fx-pressed-base: derive(-fx-base,-6%); + + /* A little darker than -fx-color and used to draw boxes around objects such + * as progress bars, scroll bars, scroll panes, trees, tables, and lists. + */ + -fx-box-border: derive(-fx-color,-5%); + + /* Darker than -fx-background and used to draw boxes around text boxes and + * password boxes. + */ + -fx-text-box-border: derive(-fx-background, -15%); + + /* Lighter than -fx-background and used to provide a small highlight when + * needed on top of -fx-background. This is never a shadow in Modena but + * keep -fx-shadow-highlight-color name to be compatible with Caspian. + */ + -fx-shadow-highlight-color: rgba(255,255,255,0.07) 70%; + + /* A gradient that goes from a little darker than -fx-color on the top to + * even more darker than -fx-color on the bottom. Typically is the second + * color in the -fx-background-color list as the small thin border around + * a control. It is typically the same size as the control (i.e., insets + * are 0). + */ + -fx-outer-border: derive(-fx-color,-5%); + + /* A gradient that goes from a bit lighter than -fx-color on the top to + * a little darker at the bottom. Typically is the third color in the + * -fx-background-color list as a thin highlight inside the outer border. + * Insets are typically 1. + */ + -fx-inner-border: derive(-fx-color,65%); + -fx-inner-border-horizontal: derive(-fx-color,65%); + -fx-inner-border-bottomup: derive(-fx-color,65%); + + /*-fx-inner-border: red;*/ + /*-fx-inner-border-horizontal: green;*/ + /*-fx-inner-border-bottomup: blue;*/ + + /* A gradient that goes from a little lighter than -fx-color at the top to + * a little darker than -fx-color at the bottom and is used to fill the + * body of many controls such as buttons. + */ + -fx-body-color: derive(-fx-color,20%); + -fx-body-color-bottomup: derive(-fx-color,20%); + -fx-body-color-to-right: derive(-fx-color,20%); + + /* The small thin light "shadow" for mark-like objects. Typically used in + * conjunction with -fx-mark-color with an insets of 1 0 -1 0. */ + -fx-mark-highlight-color: transparent; + /*-fx-mark-highlight-color: derive(-fx-color,80%);*/ + + /* Background for items in list like things such as menus, lists, trees, + * and tables. */ + -fx-selection-bar: -jr-accent; + + /* Background color to use for selection of list cells etc. This is when + * the control doesn't have focus or the row of a previously selected item. */ + -fx-selection-bar-non-focused: lightgrey; + + /* The color to use as -fx-text-fill when painting text on top of + * backgrounds filled with -fx-selection-bar. */ + -fx-selection-bar-text: -fx-text-background-color; + + /* These are needed for Popup */ + -fx-background-color: inherit; + -fx-background-radius: inherit; + -fx-background-insets: inherit; + -fx-padding: inherit; + + /** Focus line for keyboard focus traversal on cell based controls */ + -fx-cell-focus-inner-border: derive(-fx-selection-bar,30%); + + -fx-focused-mark-color : -fx-focused-text-base-color; + + /* Consistent size for headers of tab-pane and side-panels*/ + -jr-header-height: 3em; +} + +/* + * The base css file defining the style that is valid for every pane and dialog. + */ +.hyperlink { + -fx-padding: 0; + -fx-underline: false; + -fx-border-style: null; + -fx-border-color: null; +} + +.hyperlink:visited { + -fx-text-fill: -jr-accent; +} + +.glyph-icon { + /* This adjusts text alignment within the bounds of text nodes so that + the text is always vertically centered within the bounds. Based on + the cap height of the text. */ + -fx-bounds-type: logical_vertical_center; +} + +.tooltip { + -fx-background-color: -jr-tooltip-bg; + -fx-opacity: 95%; + -fx-text-fill: -jr-tooltip-fg; + -fx-font-size: 1em; +} + +.tooltip > TextFlow > Text { + -fx-font-size: 1em; +} + +.tooltip > TextFlow > .tooltip-text-bold { + -fx-font-weight: bold; +} + +.tooltip > TextFlow > .tooltip-text-italic { + -fx-font-style: italic; +} + +.tooltip > TextFlow > .tooltip-text-monospaced { + -fx-font-family: monospace; +} + +.flatButtonNoSpaceBottom, +.flatButtonNoSpaceTop, +.flatButton { + -fx-shadow-highlight-color: black; + -fx-outer-border: red; + -fx-inner-border: purple; + -fx-faint-focus-color: transparent; + -fx-background-color: -jr-icon-background; + -fx-text-background-color: blue; + -fx-padding: 0.5em; +} + +.flatButtonNoSpaceBottom:hover, +.flatButtonNoSpaceTop:hover, +.flatButton:hover { + -fx-background-color: -jr-icon-background-active; +} + +.flatButtonNoSpaceBottom:armed, +.flatButtonNoSpaceTop:armed, +.flatButton:armed { + -fx-background-color: -jr-icon-background-armed; +} + +.flatButton:selected { + -fx-background-color: -jr-icon-background-active; + -fx-text-fill: white; + -fx-fill: white; +} + +.flatButtonNoSpaceBottom { + -fx-padding: 0.5em 0.5em -0.1em 0.5em; +} + +.flatButtonNoSpaceTop { + -fx-padding: -0.1em 0.5em 0.5em 0.5em; +} + +.button, +.toggle-button, +.radio-button > .radio, +.check-box > .box, +.menu-button, +.choice-box, +.color-picker.split-button > .color-picker-label, +.combo-box-base, +.combo-box-base:editable > .arrow-button { + -fx-background-color: transparent; + -fx-background-insets: 0; + -fx-background-radius: 0; + -fx-text-fill: -fx-text-base-color; +} + +.menu-bar { + -fx-background-color: -jr-menu-background; + -fx-background-insets: 0; + -fx-background-radius: 0; +} + +.menu-bar > .container > .menu-button > .label { + -fx-padding: 0.41777em 0.41777em 0.41777em 0.41777em; +} + +.menu-bar > .menu { + -fx-padding: 0.0em 0.666667em 0.0em 0.666667em; +} + +.menu-item { + -fx-padding: 0.5em 0.41777em 0.5em 0.41777em; +} + +.tab-pane { + -fx-open-tab-animation: NONE; + -fx-close-tab-animation: NONE; +} + +.tab-pane > .tab-header-area > .headers-region > .tab { + -fx-background-insets: 0; + -fx-background-radius: 0; + -fx-background-color: -jr-background-alt; + -fx-border-color: -fx-outer-border; + -fx-border-width: 0.5 0.5 0.5 0.5; + -fx-padding: 0.3em 0.9em 0.3em 0.9em; + -fx-pref-height: -jr-header-height; +} + +.tab-pane > .tab-header-area > .headers-region > .tab .tab-label { + -fx-text-fill: -fx-mid-text-color; +} + +.tab-pane > .tab-header-area > .headers-region > .control-buttons-tab { + -fx-border-color: -jr-theme; + -fx-fill: -jr-theme-text; + -fx-text-fill: -jr-theme-text; +} + +.tab-pane > .tab-header-area > .headers-region > .tab:selected { + -fx-background-color: -fx-control-inner-background; + -fx-border-color: -jr-theme; + -fx-border-width: 3 0 0 0; +} + +.tab-pane > .tab-header-area > .headers-region > .tab:selected .tab-label{ + -fx-fill: -jr-theme-text; + -fx-text-fill: -jr-theme-text; +} + +.tab-pane > .tab-header-area > .headers-region > .tab:selected .tab-close-button { + -fx-background-color: -jr-theme-text; +} + +.tab-pane > .tab-header-area > .headers-region > .tab:selected .glyph-icon { + -fx-text-fill: -fx-mid-text-color; + -fx-fill: -fx-mid-text-color; +} + +.tab-pane:focused > .tab-header-area > .headers-region > .tab:selected .focus-indicator { + -fx-border-width: 0; + -fx-border-insets: 0; + -fx-border-radius: 0; +} + +.tab-pane > .tab-header-area > .tab-header-background { + -fx-background-color: -jr-background-alt; +} + +.tab-pane > .tab-header-area > .headers-region > .tab .glyph-icon { + -glyph-size: 13px; + -fx-text-fill: -fx-mid-text-color; + -fx-fill: -fx-mid-text-color; +} + +.tab-pane > .tab-header-area > .headers-region > .tab:selected .glyph-icon { + -fx-text-fill: -jr-theme-text; + -fx-fill: -jr-theme-text; +} + +.tab-pane > .tab-header-area { + -fx-padding: 0 0 0 0; +} + +.table-view { + -fx-background-insets: 0; + -fx-padding: 0; +} + +.table-view:focused { + -fx-background-insets: 0; +} + +.split-pane > .split-pane-divider { + -fx-background-color: -jr-sidepane-background; + -fx-padding: 0 .5 0 .5; +} + +.table-row-cell:hover, +.tree-table-row-cell:hover { + -fx-background-color: -jr-hover; + -fx-text-fill: -fx-focused-text-base-color; + -fx-fill: -fx-focused-text-base-color; +} + +.table-row-cell:hover, +.tree-table-row-cell:selected > .tree-table-cell > .glyph-icon { + -fx-fill: white; + -fx-text-fill: white; +} + +.table-view > .virtual-flow > .clipped-container > .sheet > .table-row-cell .table-cell:selected, +.tree-table-view > .virtual-flow > .clipped-container > .sheet > .tree-table-row-cell .tree-table-cell:selected { + -fx-border-color: transparent; + -fx-background-insets: 0; +} + +.scroll-pane:focused, +.split-pane:focused, +.list-view:focused, +.tree-view:focused, +.table-view:focused, +.tree-table-view:focused, +.html-editor:contains-focus { + -fx-background-color: -fx-outer-border, -fx-control-inner-background; + -fx-background-insets: 0, 1; + -fx-background-radius: 0, 0; +} + +/* Selected rows */ +.list-view:focused > .virtual-flow > .clipped-container > .sheet > .list-cell:filled:selected, +.tree-view:focused > .virtual-flow > .clipped-container > .sheet > .tree-cell:filled:selected, +.table-view:focused > .virtual-flow > .clipped-container > .sheet > .table-row-cell:filled:selected, +.tree-table-view:focused > .virtual-flow > .clipped-container > .sheet > .tree-table-row-cell:filled:selected, +.table-view:focused > .virtual-flow > .clipped-container > .sheet > .table-row-cell .table-cell:selected, +.tree-table-view:focused > .virtual-flow > .clipped-container > .sheet > .tree-table-row-cell .tree-table-cell:selected { + -fx-background: -jr-selected; + -fx-background-color: -jr-selected; + -fx-table-cell-border-color: transparent; +} + +/* Selected when control is not focused */ +.list-cell:filled:selected, +.tree-cell:filled:selected, +.table-row-cell:filled:selected, +.tree-table-row-cell:filled:selected, +.table-row-cell:filled > .table-cell:selected, +.tree-table-row-cell:filled > .tree-table-cell:selected { + -fx-background: -jr-selected; + -fx-background-color: -jr-selected; + -fx-table-cell-border-color: transparent; + -fx-fill: white; + -fx-text-fill: green; +} + +.combo-box-base { + -fx-background-color: -fx-outer-border, -fx-control-inner-background; + -fx-background-insets: 0, 1; + -fx-background-radius: 0, 0; +} + +.combo-box > .list-cell { + -fx-background-color: -fx-outer-border, -fx-control-inner-background; + -fx-background-insets: 0, 1 0 1 1; + -fx-text-fill: -fx-text-base-color; +} + +.combo-box-popup > .list-view { + -fx-background-color: -fx-control-inner-background; + -fx-background-insets: 0; + -fx-effect: null; +} + +.combo-box-popup > .list-view > .virtual-flow > .clipped-container > .sheet > .list-cell { + -fx-padding: 4 0 4 5; + /* No alternate highlighting */ + -fx-background: -fx-control-inner-background; +} + +.combo-box-popup > .list-view > .virtual-flow > .clipped-container > .sheet > .list-cell:filled:hover { + -fx-background: -fx-control-inner-background; + -fx-background-color: -jr-hover; +} + +.combo-box-popup > .list-view > .virtual-flow > .clipped-container > .sheet > .list-cell:filled:selected, +.combo-box-popup > .list-view > .virtual-flow > .clipped-container > .sheet > .list-cell:filled:selected:hover { + -fx-background: -fx-control-inner-background; + -fx-background-insets: 0; +} + +.combo-box-popup > .list-view > .placeholder > .label { + -fx-text-fill: -fx-text-base-color; +} + +.scroll-pane, +.split-pane { + -fx-background-insets: 0, 0; + -fx-padding: 0; +} + +.text-input { + -fx-background-color: -fx-outer-border, -fx-control-inner-background; + -fx-background-insets: 0, 1; + -fx-prompt-text-fill: -fx-mid-text-color; +} + +.text-input:focused { + -fx-background-color: -jr-accent, -fx-control-inner-background; + -fx-background-insets: 0, 2; +} + +.text-area { + -fx-background-color: -fx-control-inner-background; +} + +.text-area .content { + -fx-background-color: -fx-outer-border, -fx-control-inner-background; + -fx-background-insets: 0, 1; + -fx-padding: 0.333333em 0.583em 0.333333em 0.583em; + -fx-background-radius: 0; +} + +.text-area:focused .content { + -fx-background-color: -jr-accent, -fx-control-inner-background; + -fx-background-insets: 0, 2; + -fx-background-radius: 0; +} + +.text-area > .scroll-pane > .corner { + -fx-background-radius: 0 0 0 0; + -fx-background-color: -fx-background; +} + +.combo-box-base:editable > .text-field, +.date-picker > .text-field { + -fx-background-color: -fx-outer-border, -fx-control-inner-background; + -fx-background-insets: 0, 1; + -fx-background-radius: 0; +} + +.combo-box-base:editable:focused > .text-field, +.combo-box-base:editable > .text-field:focused, +.date-picker > .text-field:focused { + -fx-background-color: -jr-accent, -fx-control-inner-background; + -fx-background-insets: 0, 2; + -fx-background-radius: 0; +} + +.date-picker:focused > .text-field { + -fx-background-color: -fx-control-inner-background; + -fx-background-insets: 0; +} + +.scroll-bar { + -fx-background-color: transparent; + -fx-opacity: 0; +} + +.scroll-bar:horizontal .track, +.scroll-bar:vertical .track { + -fx-background-color: -jr-scrollbar-track; + -fx-opacity: 0.2; + -fx-background-radius: 0em; +} + +.scroll-bar:horizontal .thumb, +.scroll-bar:vertical .thumb { + -fx-background-color: -jr-scrollbar-thumb; + -fx-background-insets: 0, 0, 0; + -fx-background-radius: 0em; +} + +.scroll-bar .thumb:hover, +.scroll-bar .thumb:pressed { + -fx-background-color: derive(-jr-scrollbar-thumb, -20%); +} + +/* Hide increment and decrement buttons */ +.scroll-bar > .increment-button, +.scroll-bar > .decrement-button { + -fx-background-color: null; + -fx-background-radius: 0; + -fx-background-insets: 0; + -fx-padding: 0; +} + +/* Hide increment and decrement arrows */ +.scroll-bar:horizontal > .decrement-button > .decrement-arrow, +.scroll-bar:horizontal > .increment-button > .increment-arrow, +.scroll-bar:vertical > .decrement-button > .decrement-arrow, +.scroll-bar:vertical > .increment-button > .increment-arrow { + -fx-background-color: null; + -fx-background-radius: 0; + -fx-background-insets: 0; + -fx-shape: null; + -fx-padding: 0; +} + +/* Need some padding since otherwise no scroll-bar is displayed at all */ +.scroll-bar:horizontal > .decrement-button > .decrement-arrow { + -fx-padding: 0.333em 0.167em 0.333em 0.167em; /* 4 2 4 2 */ +} + +.scroll-bar:vertical > .decrement-button > .decrement-arrow { + -fx-padding: 0em 0.333em 0em 0.333em; /* 2 4 2 4 */ +} + +/* Only show scrollbars for hovered elements */ +.list-view:hover .scroll-bar, +.tree-view:hover .scroll-bar, +.table-view:hover .scroll-bar, +.tree-table-view:hover .scroll-bar, +.text-input:hover .scroll-bar { + -fx-opacity: 1; +} + +.sidePaneComponentHeader { + -fx-background-color: -jr-sidepane-header-background; + -fx-padding: 0.3em 0.9em 0.3em 0.9em; + -fx-pref-height: -jr-header-height; +} + +.sidePaneComponentHeader > .label { + -fx-text-fill: -jr-sidepane-header-color; + -fx-font-weight: bold; + -fx-padding: 0.3em 0.9em 0.3em 0.9em; +} + +.sidePaneComponentHeader .glyph-icon{ + -fx-fill: -jr-sidepane-header-color; + -fx-text-fill: -jr-sidepane-header-color; + -fx-font-size: 16px; +} + +.mainMenu { + -fx-background-color: -jr-menu-background; + -fx-background-insets: 0; +} + +.menu-bar > .container { + -fx-border-width: 0; +} + +.menu-bar > .container > .menu-button:hover, +.menu-bar > .container > .menu-button:focused, +.menu-bar > .container > .menu-button:showing { + -fx-background-color: -jr-menu-background-active; + -fx-background: -jr-menu-background-active; +} + +.menu-bar > .container > .menu-button:hover > .label, +.menu-bar > .container > .menu-button:focused > .label, +.menu-bar > .container > .menu-button:showing > .label { + -fx-text-fill: -jr-menu-forground-active; +} + +.mainMenu > .container > .menu-button > .label { + -fx-text-fill: -jr-menu-foreground; +} + +.menu-item > .label { + -fx-text-fill: -jr-menu-item-foreground; +} + +.menu-item:focused { + -fx-text-fill: -jr-menu-background-active; + -fx-background: -jr-menu-background-active; + -fx-background-color: -jr-menu-background-active; +} + +.menu-item:focused > .label { + -fx-text-fill: -jr-menu-forground-active; +} + +.menu-item .glyph-icon { + -fx-fill: -jr-menu-item-foreground; + -fx-text-fill: -jr-menu-item-foreground; +} + +.menu-item:focused .glyph-icon { + -fx-fill: -jr-menu-forground-active; + -fx-text-fill: -jr-menu-forground-active; +} + +.context-menu { + -fx-border-color: -fx-outer-border; + -fx-border-width: 1; +} + +.separator:horizontal .line { + -fx-border-color: -jr-separator; + -fx-border-width: 0; + -fx-border-insets: 1 0 0 0; +} + +.separator:vertical .line { + -fx-border-color: -jr-separator; + -fx-border-width: 1; + -fx-border-insets: 0 0 0 1; +} + +.mainToolbar { + -fx-background-color: -jr-toolbar; + -fx-border-color: derive(-jr-toolbar, 50%); + -fx-border-width: 0; +} + +.mainToolbar .glyph-icon { + -fx-font-size: 1.7em; + -fx-fill: -jr-theme-text; + -fx-text-fill: -jr-theme-text; +} + +.mainToolbar .search-field { + -fx-background-color: -jr-search-background; + -fx-border-width: 1; + -fx-border-color: -jr-separator; + -fx-border-radius: 2; + -fx-fill: -jr-search-text; +} + +.mainToolbar .search-field .glyph-icon { + -fx-fill: -jr-search-text; + -fx-text-fill: -jr-search-text; +} + +/* The little arrow that shows up when not all tool-bar icons fit into the tool-bar. +We want to have a look that matches our icons in the tool-bar */ +.mainToolbar .tool-bar-overflow-button > .arrow { + -fx-background-color: -jr-theme-text; +} + +.mainToolbar .tool-bar-overflow-button:hover > .arrow { + -fx-background-color: -fx-mark-highlight-color, derive(-jr-theme-text, -30%); +} + +.table-view { + -fx-border-width: 0; + -fx-padding: 0; + -fx-border-insets: 0; + -fx-table-cell-border-color: transparent; +} + +.table-view .column-header-background { + -fx-background-color: -fx-control-inner-background; + -fx-border-width: 0; +} + +.table-view .column-header-background:hover { + -fx-background-color: -fx-outer-border; +} + +.table-view .column-header, +.table-view .filler { + -fx-background-color: transparent, -fx-control-inner-background; + -fx-background-insets: 0, 0 0.02em 0 0.02em; + -fx-font-weight: bold; + -fx-size: 3em; + -fx-border-width: 0 0 1 0; + -fx-border-color: -fx-outer-border; +} + +.table-view .column-header > .label { + -fx-padding: 0 1em 0 1em; + -fx-alignment: center-left; + -fx-text-fill: -jr-head-fg; +} + +.table-view .column-header .glyph-icon { + -fx-alignment: baseline-center; + -fx-text-fill: -jr-head-fg; + -fx-fill: -jr-head-fg; +} + +.table-cell, .table-cell .glyph-icon{ + -fx-padding: 0.5em 1em 0.5em 1em; + -fx-cell-size: 4.0em; + -fx-text-fill: -fx-text-background-color; + -fx-fill: -fx-text-background-color; +} + +/* Improve the context menu of the main toolbar, when icons don't fit and you have to press the little arrow to see them */ +.mainToolbar .context-menu .glyph-icon { + -fx-fill: -jr-theme-text; +} + +.mainToolbar .context-menu .glyph-icon:hover { + -fx-fill: -jr-theme-active; + -fx-text-fill: -jr-theme-active; + -fx-background-color: -jr-icon-background-active; /* TODO: This has no effect */ +} + + +/* This is awful, but I don't know a better way*/ +.mainToolbar .context-menu * { + -fx-background-color: -fx-control-inner-background; +} diff --git a/src/main/java/org/jabref/gui/BasePanel.java b/src/main/java/org/jabref/gui/BasePanel.java index b201f5fb8ef..9dcfc93886a 100644 --- a/src/main/java/org/jabref/gui/BasePanel.java +++ b/src/main/java/org/jabref/gui/BasePanel.java @@ -1,14 +1,10 @@ package org.jabref.gui; -import java.awt.BorderLayout; import java.awt.Toolkit; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.ClipboardOwner; import java.awt.datatransfer.StringSelection; import java.awt.datatransfer.Transferable; -import java.awt.event.ActionEvent; -import java.awt.event.KeyAdapter; -import java.awt.event.KeyEvent; import java.io.File; import java.io.IOException; import java.io.StringReader; @@ -17,7 +13,6 @@ import java.nio.charset.UnsupportedCharsetException; import java.nio.file.Path; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -28,20 +23,19 @@ import java.util.Set; import java.util.stream.Collectors; -import javax.swing.AbstractAction; -import javax.swing.BorderFactory; -import javax.swing.JComponent; import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JSplitPane; import javax.swing.JTextArea; import javax.swing.SwingUtilities; import javax.swing.undo.CannotRedoException; import javax.swing.undo.CannotUndoException; -import javafx.application.Platform; -import javafx.embed.swing.JFXPanel; -import javafx.scene.Scene; +import javafx.beans.binding.Bindings; +import javafx.geometry.Orientation; +import javafx.scene.Node; +import javafx.scene.control.ScrollPane; +import javafx.scene.control.SplitPane; +import javafx.scene.layout.AnchorPane; +import javafx.scene.layout.StackPane; import org.jabref.Globals; import org.jabref.JabRefExecutorService; @@ -57,33 +51,25 @@ import org.jabref.gui.collab.DatabaseChangeMonitor; import org.jabref.gui.collab.FileUpdatePanel; import org.jabref.gui.contentselector.ContentSelectorDialog; -import org.jabref.gui.customjfx.CustomJFXPanel; import org.jabref.gui.desktop.JabRefDesktop; import org.jabref.gui.entryeditor.EntryEditor; import org.jabref.gui.exporter.ExportToClipboardAction; import org.jabref.gui.exporter.SaveDatabaseAction; import org.jabref.gui.externalfiles.FindFullTextAction; -import org.jabref.gui.externalfiles.SynchronizeFileField; -import org.jabref.gui.externalfiles.WriteXMPAction; +import org.jabref.gui.externalfiles.WriteXMPActionWorker; import org.jabref.gui.externalfiletype.ExternalFileMenuItem; import org.jabref.gui.externalfiletype.ExternalFileType; import org.jabref.gui.externalfiletype.ExternalFileTypes; -import org.jabref.gui.fieldeditors.FieldEditor; -import org.jabref.gui.filelist.AttachFileAction; import org.jabref.gui.filelist.FileListEntry; import org.jabref.gui.filelist.FileListTableModel; import org.jabref.gui.groups.GroupAddRemoveDialog; import org.jabref.gui.importer.actions.AppendDatabaseAction; import org.jabref.gui.journals.AbbreviateAction; import org.jabref.gui.journals.UnabbreviateAction; -import org.jabref.gui.keyboard.KeyBinding; import org.jabref.gui.maintable.MainTable; import org.jabref.gui.maintable.MainTableDataModel; -import org.jabref.gui.maintable.MainTableFormat; -import org.jabref.gui.maintable.MainTableSelectionListener; import org.jabref.gui.mergeentries.MergeEntriesDialog; import org.jabref.gui.mergeentries.MergeWithFetchedEntryAction; -import org.jabref.gui.plaintextimport.TextInputDialog; import org.jabref.gui.specialfields.SpecialFieldDatabaseChangeListener; import org.jabref.gui.specialfields.SpecialFieldValueViewModel; import org.jabref.gui.specialfields.SpecialFieldViewModel; @@ -96,11 +82,9 @@ import org.jabref.gui.undo.UndoableRemoveEntry; import org.jabref.gui.util.DefaultTaskExecutor; import org.jabref.gui.util.FileDialogConfiguration; -import org.jabref.gui.util.component.CheckBoxMessage; import org.jabref.gui.worker.AbstractWorker; import org.jabref.gui.worker.CallBack; import org.jabref.gui.worker.CitationStyleToClipboardWorker; -import org.jabref.gui.worker.MarkEntriesAction; import org.jabref.gui.worker.SendAsEMailAction; import org.jabref.logic.bibtexkeypattern.BibtexKeyGenerator; import org.jabref.logic.citationstyle.CitationStyleCache; @@ -135,6 +119,7 @@ import org.jabref.model.entry.EntryType; import org.jabref.model.entry.FieldName; import org.jabref.model.entry.InternalBibtexFields; +import org.jabref.model.entry.LinkedFile; import org.jabref.model.entry.event.EntryChangedEvent; import org.jabref.model.entry.event.EntryEventSource; import org.jabref.model.entry.specialfields.SpecialField; @@ -146,16 +131,15 @@ import com.google.common.eventbus.Subscribe; import com.jgoodies.forms.builder.FormBuilder; import com.jgoodies.forms.layout.FormLayout; +import org.fxmisc.easybind.EasyBind; +import org.fxmisc.easybind.Subscription; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class BasePanel extends JPanel implements ClipboardOwner { +public class BasePanel extends StackPane implements ClipboardOwner { private static final Logger LOGGER = LoggerFactory.getLogger(BasePanel.class); - // Divider size for BaseFrame split pane. 0 means non-resizable. - private static final int SPLIT_PANE_DIVIDER_SIZE = 4; - private final BibDatabaseContext bibDatabaseContext; private final MainTableDataModel tableModel; @@ -166,22 +150,20 @@ public class BasePanel extends JPanel implements ClipboardOwner { // The undo manager. private final UndoAction undoAction = new UndoAction(); private final RedoAction redoAction = new RedoAction(); - private final CountingUndoManager undoManager = new CountingUndoManager(); - private final List previousEntries = new ArrayList<>(); - private final List nextEntries = new ArrayList<>(); + private final CountingUndoManager undoManager; // Keeps track of the string dialog if it is open. - private final Map actions = new HashMap<>(); + private final Map actions = new HashMap<>(); private final SidePaneManager sidePaneManager; private final PreviewPanel preview; - private final JFXPanel previewContainer; + private final BasePanelPreferences preferences; + private final ExternalFileTypes externalFileTypes; + private final EntryEditor entryEditor; + private MainTable mainTable; // To contain instantiated entry editors. This is to save time // As most enums, this must not be null private BasePanelMode mode = BasePanelMode.SHOWING_NOTHING; - private final EntryEditor entryEditor; - private final JFXPanel entryEditorContainer; - private MainTableSelectionListener selectionListener; - private JSplitPane splitPane; + private SplitPane splitPane; private boolean saving; // AutoCompleter used in the search bar @@ -189,42 +171,36 @@ public class BasePanel extends JPanel implements ClipboardOwner { private boolean baseChanged; private boolean nonUndoableChange; // Used to track whether the base has changed since last save. - private MainTable mainTable; - private MainTableFormat tableFormat; private BibEntry showing; - // Variable to prevent erroneous update of back/forward histories at the time - // when a Back or Forward operation is being processed: - private boolean backOrForwardInProgress; - // in switching between entries. - private PreambleEditor preambleEditor; - // Keeps track of the preamble dialog if it is open. + private StringDialog stringDialog; private SuggestionProviders suggestionProviders; + @SuppressWarnings({"FieldCanBeLocal", "unused"}) private Subscription dividerPositionSubscription; + // the query the user searches when this BasePanel is active private Optional currentSearchQuery = Optional.empty(); private Optional changeMonitor = Optional.empty(); + private final DialogService dialogService; - public BasePanel(JabRefFrame frame, BibDatabaseContext bibDatabaseContext) { - Objects.requireNonNull(frame); - Objects.requireNonNull(bibDatabaseContext); + public BasePanel(JabRefFrame frame, BasePanelPreferences preferences, BibDatabaseContext bibDatabaseContext, ExternalFileTypes externalFileTypes) { + this.preferences = Objects.requireNonNull(preferences); + this.frame = Objects.requireNonNull(frame); + this.bibDatabaseContext = Objects.requireNonNull(bibDatabaseContext); + this.externalFileTypes = Objects.requireNonNull(externalFileTypes); + this.undoManager = frame.getUndoManager(); + this.dialogService = frame.getDialogService(); - this.bibDatabaseContext = bibDatabaseContext; bibDatabaseContext.getDatabase().registerListener(this); bibDatabaseContext.getMetaData().registerListener(this); this.sidePaneManager = frame.getSidePaneManager(); - this.frame = frame; this.tableModel = new MainTableDataModel(getBibDatabaseContext()); citationStyleCache = new CitationStyleCache(bibDatabaseContext); annotationCache = new FileAnnotationCache(bibDatabaseContext, Globals.prefs.getFileDirectoryPreferences()); - this.preview = new PreviewPanel(this, getBibDatabaseContext()); - DefaultTaskExecutor.runInJavaFXThread(() -> frame().getGlobalSearchBar().getSearchQueryHighlightObservable().addSearchListener(preview)); - this.previewContainer = CustomJFXPanel.wrap(new Scene(preview)); - setupMainPanel(); setupActions(); @@ -234,6 +210,8 @@ public BasePanel(JabRefFrame frame, BibDatabaseContext bibDatabaseContext) { // ensure that at each addition of a new entry, the entry is added to the groups interface this.bibDatabaseContext.getDatabase().registerListener(new GroupTreeListener()); + // ensure that all entry changes mark the panel as changed + this.bibDatabaseContext.getDatabase().registerListener(this); Optional file = bibDatabaseContext.getDatabaseFile(); if (file.isPresent()) { @@ -250,36 +228,10 @@ public BasePanel(JabRefFrame frame, BibDatabaseContext bibDatabaseContext) { this.getDatabase().registerListener(new UpdateTimestampListener(Globals.prefs)); - entryEditor = new EntryEditor(this); - entryEditorContainer = setupEntryEditor(entryEditor); - - } - - private static JFXPanel setupEntryEditor(EntryEditor entryEditor) { - JFXPanel container = CustomJFXPanel.wrap(new Scene(entryEditor)); - container.addKeyListener(new KeyAdapter() { + this.entryEditor = new EntryEditor(this, preferences.getEntryEditorPreferences(), Globals.getFileUpdateMonitor(), dialogService); - @Override - public void keyPressed(KeyEvent e) { - - //We need to consume this event here to prevent the propgation of keybinding events back to the JFrame - Optional keyBinding = Globals.getKeyPrefs().mapToKeyBinding(e); - if (keyBinding.isPresent()) { - switch (keyBinding.get()) { - case CUT: - case COPY: - case PASTE: - case DELETE_ENTRY: - case SELECT_ALL: - e.consume(); - break; - default: - //do nothing - } - } - } - }); - return container; + this.preview = new PreviewPanel(this, getBibDatabaseContext(), preferences.getKeyBindings(), preferences.getPreviewPreferences(), dialogService); + frame().getGlobalSearchBar().getSearchQueryHighlightObservable().addSearchListener(preview); } public static void runWorker(AbstractWorker worker) throws Exception { @@ -304,8 +256,7 @@ public static void runWorker(AbstractWorker worker) throws Exception { @Subscribe public void listen(BibDatabaseContextChangedEvent event) { - SwingUtilities.invokeLater(() -> this.markBaseChanged()); - + this.markBaseChanged(); } /** @@ -337,9 +288,7 @@ public String getTabTitle() { } } } else if (databaseLocation == DatabaseLocation.SHARED) { - title.append( - this.bibDatabaseContext.getDBMSSynchronizer().getDBName() + " [" + Localization.lang("shared") - + "]"); + title.append(this.bibDatabaseContext.getDBMSSynchronizer().getDBName() + " [" + Localization.lang("shared") + "]"); } return title.toString(); @@ -372,32 +321,23 @@ private void setupActions() { actions.put(Actions.UNDO, undoAction); actions.put(Actions.REDO, redoAction); - actions.put(Actions.FOCUS_TABLE, (BaseAction) () -> { - mainTable.requestFocus(); - }); - // The action for opening an entry editor. - actions.put(Actions.EDIT, (BaseAction) selectionListener::editSignalled); + actions.put(Actions.EDIT, (BaseAction) this::showAndEdit); // The action for saving a database. actions.put(Actions.SAVE, saveAction); actions.put(Actions.SAVE_AS, (BaseAction) saveAction::saveAs); - actions.put(Actions.SAVE_SELECTED_AS, new SaveSelectedAction(SavePreferences.DatabaseSaveType.ALL)); - - actions.put(Actions.SAVE_SELECTED_AS_PLAIN, - new SaveSelectedAction(SavePreferences.DatabaseSaveType.PLAIN_BIBTEX)); + actions.put(Actions.SAVE_SELECTED_AS_PLAIN, new SaveSelectedAction(SavePreferences.DatabaseSaveType.PLAIN_BIBTEX)); // The action for copying selected entries. - actions.put(Actions.COPY, (BaseAction) () -> copy()); + actions.put(Actions.COPY, (BaseAction) mainTable::copy); actions.put(Actions.PRINT_PREVIEW, new PrintPreviewAction()); - actions.put(Actions.CUT, (BaseAction) this::cut); + actions.put(Actions.CUT, (BaseAction) mainTable::cut); - //when you modify this action be sure to adjust Actions.CUT, - //they are the same except of the Localization, delete confirmation and Actions.COPY call actions.put(Actions.DELETE, (BaseAction) () -> delete(false)); // The action for pasting entries or cell contents. @@ -406,21 +346,9 @@ private void setupActions() { // This allows you to (a) paste entire bibtex entries from a text editor, web browser, etc // (b) copy and paste entries between multiple instances of JabRef (since // only the text representation seems to get as far as the X clipboard, at least on my system) - actions.put(Actions.PASTE, (BaseAction) () -> paste()); - - actions.put(Actions.SELECT_ALL, (BaseAction) mainTable::selectAll); + actions.put(Actions.PASTE, (BaseAction) mainTable::paste); - // The action for opening the preamble editor - actions.put(Actions.EDIT_PREAMBLE, (BaseAction) () -> { - if (preambleEditor == null) { - PreambleEditor form = new PreambleEditor(frame, BasePanel.this, bibDatabaseContext.getDatabase()); - form.setLocationRelativeTo(frame); - form.setVisible(true); - preambleEditor = form; - } else { - preambleEditor.setVisible(true); - } - }); + actions.put(Actions.SELECT_ALL, (BaseAction) mainTable.getSelectionModel()::selectAll); // The action for opening the string editor actions.put(Actions.EDIT_STRINGS, (BaseAction) () -> { @@ -433,12 +361,6 @@ private void setupActions() { } }); - actions.put(FindUnlinkedFilesDialog.ACTION_COMMAND, (BaseAction) () -> { - final FindUnlinkedFilesDialog dialog = new FindUnlinkedFilesDialog(frame, frame, BasePanel.this); - dialog.setLocationRelativeTo(frame); - dialog.setVisible(true); - }); - // The action for auto-generating keys. actions.put(Actions.MAKE_KEY, new AbstractWorker() { @@ -453,12 +375,10 @@ public void init() { numSelected = entries.size(); if (entries.isEmpty()) { // None selected. Inform the user to select entries first. - JOptionPane.showMessageDialog(frame, - Localization.lang("First select the entries you want keys to be generated for."), - Localization.lang("Autogenerate BibTeX keys"), JOptionPane.INFORMATION_MESSAGE); + dialogService.showWarningDialogAndWait(Localization.lang("Autogenerate BibTeX keys"), + Localization.lang("First select the entries you want keys to be generated for.")); return; } - frame.block(); output(formatOutputMessage(Localization.lang("Generating BibTeX key for"), numSelected)); } @@ -472,15 +392,17 @@ public void run() { // if we're going to override some cite keys warn the user about it } else if (Globals.prefs.getBoolean(JabRefPreferences.WARN_BEFORE_OVERWRITING_KEY)) { if (entries.parallelStream().anyMatch(BibEntry::hasCiteKey)) { - CheckBoxMessage cbm = new CheckBoxMessage( - Localization.lang("One or more keys will be overwritten. Continue?"), - Localization.lang("Disable this confirmation dialog"), false); - final int answer = JOptionPane.showConfirmDialog(frame, cbm, - Localization.lang("Overwrite keys"), JOptionPane.YES_NO_OPTION); - Globals.prefs.putBoolean(JabRefPreferences.WARN_BEFORE_OVERWRITING_KEY, !cbm.isSelected()); + + boolean overwriteKeysPressed = dialogService.showConfirmationDialogWithOptOutAndWait( + Localization.lang("Overwrite keys"), + Localization.lang("One or more keys will be overwritten. Continue?"), + Localization.lang("Overwrite keys"), + Localization.lang("Cancel"), + Localization.lang("Disable this confirmation dialog"), + optOut -> Globals.prefs.putBoolean(JabRefPreferences.WARN_BEFORE_OVERWRITING_KEY, !optOut)); // The user doesn't want to overide cite keys - if (answer == JOptionPane.NO_OPTION) { + if (!overwriteKeysPressed) { canceled = true; return; } @@ -506,33 +428,18 @@ public void run() { @Override public void update() { if (canceled) { - frame.unblock(); return; } markBaseChanged(); numSelected = entries.size(); - - //////////////////////////////////////////////////////////////////////////////// - // Prevent selection loss for autogenerated BibTeX-Keys - //////////////////////////////////////////////////////////////////////////////// - for (final BibEntry bibEntry : entries) { - SwingUtilities.invokeLater(() -> { - final int row = mainTable.findEntry(bibEntry); - if ((row >= 0) && (mainTable.getSelectedRowCount() < entries.size())) { - mainTable.addRowSelectionInterval(row, row); - } - }); - } - //////////////////////////////////////////////////////////////////////////////// output(formatOutputMessage(Localization.lang("Generated BibTeX key for"), numSelected)); - frame.unblock(); } }); // The action for cleaning up entry. actions.put(Actions.CLEANUP, cleanUpAction); - actions.put(Actions.MERGE_ENTRIES, (BaseAction) () -> new MergeEntriesDialog(BasePanel.this)); + actions.put(Actions.MERGE_ENTRIES, (BaseAction) () -> new MergeEntriesDialog(BasePanel.this, dialogService)); actions.put(Actions.SEARCH, (BaseAction) frame.getGlobalSearchBar()::focus); actions.put(Actions.GLOBAL_SEARCH, (BaseAction) frame.getGlobalSearchBar()::performGlobalSearch); @@ -549,29 +456,21 @@ public void update() { // The action for copying the BibTeX key and the title for the first selected entry actions.put(Actions.COPY_KEY_AND_TITLE, (BaseAction) () -> copyKeyAndTitle()); - actions.put(Actions.COPY_CITATION_ASCII_DOC, - (BaseAction) () -> copyCitationToClipboard(CitationStyleOutputFormat.ASCII_DOC)); - actions.put(Actions.COPY_CITATION_XSLFO, - (BaseAction) () -> copyCitationToClipboard(CitationStyleOutputFormat.XSL_FO)); - actions.put(Actions.COPY_CITATION_HTML, - (BaseAction) () -> copyCitationToClipboard(CitationStyleOutputFormat.HTML)); - actions.put(Actions.COPY_CITATION_RTF, - (BaseAction) () -> copyCitationToClipboard(CitationStyleOutputFormat.RTF)); - actions.put(Actions.COPY_CITATION_TEXT, - (BaseAction) () -> copyCitationToClipboard(CitationStyleOutputFormat.TEXT)); + actions.put(Actions.COPY_CITATION_ASCII_DOC, (BaseAction) () -> copyCitationToClipboard(CitationStyleOutputFormat.ASCII_DOC)); + actions.put(Actions.COPY_CITATION_XSLFO, (BaseAction) () -> copyCitationToClipboard(CitationStyleOutputFormat.XSL_FO)); + actions.put(Actions.COPY_CITATION_HTML, (BaseAction) () -> copyCitationToClipboard(CitationStyleOutputFormat.HTML)); + actions.put(Actions.COPY_CITATION_RTF, (BaseAction) () -> copyCitationToClipboard(CitationStyleOutputFormat.RTF)); + actions.put(Actions.COPY_CITATION_TEXT, (BaseAction) () -> copyCitationToClipboard(CitationStyleOutputFormat.TEXT)); // The action for copying the BibTeX keys as hyperlinks to the urls of the selected entries - actions.put(Actions.COPY_KEY_AND_LINK, new CopyBibTeXKeyAndLinkAction(mainTable)); + actions.put(Actions.COPY_KEY_AND_LINK, new CopyBibTeXKeyAndLinkAction(mainTable, Globals.clipboardManager)); actions.put(Actions.MERGE_DATABASE, new AppendDatabaseAction(frame, this)); - actions.put(Actions.ADD_FILE_LINK, new AttachFileAction(this)); - actions.put(Actions.OPEN_EXTERNAL_FILE, (BaseAction) () -> openExternalFile()); actions.put(Actions.OPEN_FOLDER, (BaseAction) () -> JabRefExecutorService.INSTANCE.execute(() -> { - final List files = FileUtil.getListOfLinkedFiles(mainTable.getSelectedEntries(), - bibDatabaseContext.getFileDirectoriesAsPaths(Globals.prefs.getFileDirectoryPreferences())); + final List files = FileUtil.getListOfLinkedFiles(mainTable.getSelectedEntries(), bibDatabaseContext.getFileDirectoriesAsPaths(Globals.prefs.getFileDirectoryPreferences())); for (final Path f : files) { try { JabRefDesktop.openFolderAndSelectFile(f.toAbsolutePath()); @@ -582,7 +481,7 @@ public void update() { })); actions.put(Actions.OPEN_CONSOLE, (BaseAction) () -> JabRefDesktop - .openConsole(frame.getCurrentBasePanel().getBibDatabaseContext().getDatabaseFile().orElse(null))); + .openConsole(frame.getCurrentBasePanel().getBibDatabaseContext().getDatabaseFile().orElse(null))); actions.put(Actions.PULL_CHANGES_FROM_SHARED_DATABASE, (BaseAction) () -> { DatabaseSynchronizer dbmsSynchronizer = frame.getCurrentBasePanel().getBibDatabaseContext().getDBMSSynchronizer(); @@ -591,7 +490,7 @@ public void update() { actions.put(Actions.OPEN_URL, new OpenURLAction()); - actions.put(Actions.MERGE_WITH_FETCHED_ENTRY, new MergeWithFetchedEntryAction(this)); + actions.put(Actions.MERGE_WITH_FETCHED_ENTRY, new MergeWithFetchedEntryAction(this, frame.getDialogService())); actions.put(Actions.REPLACE_ALL, (BaseAction) () -> { final ReplaceStringDialog rsd = new ReplaceStringDialog(frame); @@ -620,128 +519,54 @@ public void update() { } }); - actions.put(Actions.DUPLI_CHECK, - (BaseAction) () -> JabRefExecutorService.INSTANCE.execute(new DuplicateSearch(BasePanel.this))); - - actions.put(Actions.PLAIN_TEXT_IMPORT, (BaseAction) () -> { - // get Type of new entry - EntryTypeDialog etd = new EntryTypeDialog(frame); - etd.setLocationRelativeTo(BasePanel.this); - etd.setVisible(true); - EntryType tp = etd.getChoice(); - if (tp == null) { - return; - } - - BibEntry bibEntry = new BibEntry(tp.getName()); - TextInputDialog tidialog = new TextInputDialog(frame, bibEntry); - tidialog.setLocationRelativeTo(BasePanel.this); - tidialog.setVisible(true); + actions.put(new SpecialFieldValueViewModel(SpecialField.RELEVANCE.getValues().get(0)).getCommand(), + new SpecialFieldViewModel(SpecialField.RELEVANCE, undoManager).getSpecialFieldAction(SpecialField.RELEVANCE.getValues().get(0), frame)); - if (tidialog.okPressed()) { - UpdateField.setAutomaticFields(Collections.singletonList(bibEntry), false, false, - Globals.prefs.getUpdateFieldPreferences()); - insertEntry(bibEntry); - } - }); + actions.put(new SpecialFieldValueViewModel(SpecialField.QUALITY.getValues().get(0)).getCommand(), + new SpecialFieldViewModel(SpecialField.QUALITY, undoManager).getSpecialFieldAction(SpecialField.QUALITY.getValues().get(0), frame)); - actions.put(Actions.MARK_ENTRIES, new MarkEntriesAction(frame, 0)); - - actions.put(Actions.UNMARK_ENTRIES, (BaseAction) () -> { - try { - List bes = mainTable.getSelectedEntries(); - if (bes.isEmpty()) { - output(Localization.lang("This operation requires one or more entries to be selected.")); - return; - } - NamedCompound ce = new NamedCompound(Localization.lang("Unmark entries")); - for (BibEntry be : bes) { - EntryMarker.unmarkEntry(be, false, bibDatabaseContext.getDatabase(), ce); - } - ce.end(); - getUndoManager().addEdit(ce); - markBaseChanged(); - String outputStr; - if (bes.size() == 1) { - outputStr = Localization.lang("Unmarked selected entry"); - } else { - outputStr = Localization.lang("Unmarked all %0 selected entries", Integer.toString(bes.size())); - } - output(outputStr); - } catch (Throwable ex) { - LOGGER.warn("Could not unmark", ex); - } - }); - - actions.put(Actions.UNMARK_ALL, (BaseAction) () -> { - NamedCompound ce = new NamedCompound(Localization.lang("Unmark all")); - - for (BibEntry be : bibDatabaseContext.getDatabase().getEntries()) { - EntryMarker.unmarkEntry(be, false, bibDatabaseContext.getDatabase(), ce); - } - ce.end(); - getUndoManager().addEdit(ce); - markBaseChanged(); - output(Localization.lang("Unmarked all entries")); - }); - - // Note that we can't put the number of entries that have been reverted into the undoText as the concrete number cannot be injected - actions.put(new SpecialFieldValueViewModel(SpecialField.RELEVANCE.getValues().get(0)).getActionName(), - new SpecialFieldViewModel(SpecialField.RELEVANCE).getSpecialFieldAction( - SpecialField.RELEVANCE.getValues().get(0), frame)); - actions.put(new SpecialFieldValueViewModel(SpecialField.QUALITY.getValues().get(0)).getActionName(), - new SpecialFieldViewModel(SpecialField.QUALITY) - .getSpecialFieldAction(SpecialField.QUALITY.getValues().get(0), frame)); - actions.put(new SpecialFieldValueViewModel(SpecialField.PRINTED.getValues().get(0)).getActionName(), - new SpecialFieldViewModel(SpecialField.PRINTED).getSpecialFieldAction( - SpecialField.PRINTED.getValues().get(0), frame)); + actions.put(new SpecialFieldValueViewModel(SpecialField.PRINTED.getValues().get(0)).getCommand(), + new SpecialFieldViewModel(SpecialField.PRINTED, undoManager).getSpecialFieldAction(SpecialField.PRINTED.getValues().get(0), frame)); for (SpecialFieldValue prio : SpecialField.PRIORITY.getValues()) { - actions.put(new SpecialFieldValueViewModel(prio).getActionName(), - new SpecialFieldViewModel(SpecialField.PRIORITY).getSpecialFieldAction(prio, this.frame)); + actions.put(new SpecialFieldValueViewModel(prio).getCommand(), + new SpecialFieldViewModel(SpecialField.PRIORITY, undoManager).getSpecialFieldAction(prio, this.frame)); } for (SpecialFieldValue rank : SpecialField.RANKING.getValues()) { - actions.put(new SpecialFieldValueViewModel(rank).getActionName(), - new SpecialFieldViewModel(SpecialField.RANKING).getSpecialFieldAction(rank, this.frame)); + actions.put(new SpecialFieldValueViewModel(rank).getCommand(), + new SpecialFieldViewModel(SpecialField.RANKING, undoManager).getSpecialFieldAction(rank, this.frame)); } for (SpecialFieldValue status : SpecialField.READ_STATUS.getValues()) { - actions.put(new SpecialFieldValueViewModel(status).getActionName(), - new SpecialFieldViewModel(SpecialField.READ_STATUS).getSpecialFieldAction(status, this.frame)); + actions.put(new SpecialFieldValueViewModel(status).getCommand(), + new SpecialFieldViewModel(SpecialField.READ_STATUS, undoManager).getSpecialFieldAction(status, this.frame)); } actions.put(Actions.TOGGLE_PREVIEW, (BaseAction) () -> { PreviewPreferences previewPreferences = Globals.prefs.getPreviewPreferences(); boolean enabled = !previewPreferences.isPreviewPanelEnabled(); - PreviewPreferences newPreviewPreferences = previewPreferences - .getBuilder() - .withPreviewPanelEnabled(enabled) - .build(); + PreviewPreferences newPreviewPreferences = previewPreferences.getBuilder() + .withPreviewPanelEnabled(enabled) + .build(); Globals.prefs.storePreviewPreferences(newPreviewPreferences); - setPreviewActiveBasePanels(enabled); - frame.setPreviewToggle(enabled); + DefaultTaskExecutor.runInJavaFXThread(() -> setPreviewActiveBasePanels(enabled)); }); actions.put(Actions.NEXT_PREVIEW_STYLE, (BaseAction) this::nextPreviewStyle); actions.put(Actions.PREVIOUS_PREVIEW_STYLE, (BaseAction) this::previousPreviewStyle); actions.put(Actions.MANAGE_SELECTORS, (BaseAction) () -> { - ContentSelectorDialog csd = new ContentSelectorDialog(frame, frame, BasePanel.this, false, null); - csd.setLocationRelativeTo(frame); + ContentSelectorDialog csd = new ContentSelectorDialog(null, frame, BasePanel.this, false, null); csd.setVisible(true); }); actions.put(Actions.EXPORT_TO_CLIPBOARD, new ExportToClipboardAction(frame)); actions.put(Actions.SEND_AS_EMAIL, new SendAsEMailAction(frame)); - actions.put(Actions.WRITE_XMP, new WriteXMPAction(this)); + actions.put(Actions.WRITE_XMP, new WriteXMPActionWorker(this)); actions.put(Actions.ABBREVIATE_ISO, new AbbreviateAction(this, true)); actions.put(Actions.ABBREVIATE_MEDLINE, new AbbreviateAction(this, false)); actions.put(Actions.UNABBREVIATE, new UnabbreviateAction(this)); - actions.put(Actions.AUTO_SET_FILE, new SynchronizeFileField(this)); - - actions.put(Actions.BACK, (BaseAction) BasePanel.this::back); - actions.put(Actions.FORWARD, (BaseAction) BasePanel.this::forward); actions.put(Actions.RESOLVE_DUPLICATE_KEYS, new SearchFixDuplicateLabels(this)); @@ -749,7 +574,7 @@ public void update() { actions.put(Actions.REMOVE_FROM_GROUP, new GroupAddRemoveDialog(this, false, false)); actions.put(Actions.MOVE_TO_GROUP, new GroupAddRemoveDialog(this, true, true)); - actions.put(Actions.DOWNLOAD_FULL_TEXT, new FindFullTextAction(this)); + actions.put(Actions.DOWNLOAD_FULL_TEXT, new FindFullTextAction(frame.getDialogService(), this)); } /** @@ -761,45 +586,13 @@ private void copyCitationToClipboard(CitationStyleOutputFormat outputFormat) { new CitationStyleToClipboardWorker(this, outputFormat).execute(); } - private void copy() { - List bes = mainTable.getSelectedEntries(); - - if (bes.isEmpty()) { - // The user maybe selected a single cell. - // TODO: Check if this can actually happen - int[] rows = mainTable.getSelectedRows(); - int[] cols = mainTable.getSelectedColumns(); - if ((cols.length == 1) && (rows.length == 1)) { - // Copy single value. - Object o = mainTable.getValueAt(rows[0], cols[0]); - if (o != null) { - StringSelection ss = new StringSelection(o.toString()); - Toolkit.getDefaultToolkit().getSystemClipboard().setContents(ss, BasePanel.this); - - output(Localization.lang("Copied cell contents") + '.'); - } - } - } else { - TransferableBibtexEntry trbe = new TransferableBibtexEntry(bes); - // ! look at ClipBoardManager - Toolkit.getDefaultToolkit().getSystemClipboard().setContents(trbe, BasePanel.this); - output(formatOutputMessage(Localization.lang("Copied"), bes.size())); - } - } - - private void cut() { - runCommand(Actions.COPY); - // cannot call runCommand(Actions.DELETE), b/c it will call delete(false) with the wrong parameter - delete(true); - } - /** * Removes the selected entries from the database * * @param cut If false the user will get asked if he really wants to delete the entries, and it will be localized as * "deleted". If true the action will be localized as "cut" */ - private void delete(boolean cut) { + public void delete(boolean cut) { delete(cut, mainTable.getSelectedEntries()); } @@ -817,20 +610,11 @@ private void delete(boolean cut, List entries) { return; } - // select the next entry to stay at the same place as before (or the previous if we're already at the end) - if (mainTable.getSelectedRow() != (mainTable.getRowCount() - 1)) { - selectNextEntry(); - } else { - selectPreviousEntry(); - } - NamedCompound compound; if (cut) { - compound = new NamedCompound( - (entries.size() > 1 ? Localization.lang("cut entries") : Localization.lang("cut entry"))); + compound = new NamedCompound((entries.size() > 1 ? Localization.lang("cut entries") : Localization.lang("cut entry"))); } else { - compound = new NamedCompound( - (entries.size() > 1 ? Localization.lang("delete entries") : Localization.lang("delete entry"))); + compound = new NamedCompound((entries.size() > 1 ? Localization.lang("delete entries") : Localization.lang("delete entry"))); } for (BibEntry entry : entries) { compound.addEdit(new UndoableRemoveEntry(bibDatabaseContext.getDatabase(), entry, BasePanel.this)); @@ -841,8 +625,7 @@ private void delete(boolean cut, List entries) { getUndoManager().addEdit(compound); markBaseChanged(); - frame.output( - formatOutputMessage(cut ? Localization.lang("Cut") : Localization.lang("Deleted"), entries.size())); + frame.output(formatOutputMessage(cut ? Localization.lang("Cut") : Localization.lang("Deleted"), entries.size())); // prevent the main table from loosing focus mainTable.requestFocus(); @@ -852,62 +635,14 @@ public void delete(BibEntry entry) { delete(false, Collections.singletonList(entry)); } - private void paste() { - Collection bes = new ClipBoardManager().extractBibEntriesFromClipboard(); - - // finally we paste in the entries (if any), which either came from TransferableBibtexEntries - // or were parsed from a string - if (!bes.isEmpty()) { - - NamedCompound ce = new NamedCompound( - (bes.size() > 1 ? Localization.lang("paste entries") : Localization.lang("paste entry"))); - - // Store the first inserted bibtexentry. - // bes[0] does not work as bes[0] is first clonded, - // then inserted. - // This entry is used to open up an entry editor - // for the first inserted entry. - BibEntry firstBE = null; - - for (BibEntry be1 : bes) { - - BibEntry be = (BibEntry) be1.clone(); - if (firstBE == null) { - firstBE = be; - } - UpdateField.setAutomaticFields(be, Globals.prefs.getUpdateFieldPreferences()); - - // We have to clone the - // entries, since the pasted - // entries must exist - // independently of the copied - // ones. - bibDatabaseContext.getDatabase().insertEntry(be); - - ce.addEdit(new UndoableInsertEntry(bibDatabaseContext.getDatabase(), be, BasePanel.this)); - } - ce.end(); - getUndoManager().addEdit(ce); - output(formatOutputMessage(Localization.lang("Pasted"), bes.size())); - markBaseChanged(); - - highlightEntry(firstBE); - mainTable.requestFocus(); - - if (Globals.prefs.getBoolean(JabRefPreferences.AUTO_OPEN_FORM)) { - selectionListener.editSignalled(firstBE); - } - } - } - private void copyTitle() { List selectedBibEntries = mainTable.getSelectedEntries(); if (!selectedBibEntries.isEmpty()) { // Collect all non-null titles. List titles = selectedBibEntries.stream() - .filter(bibEntry -> bibEntry.getTitle().isPresent()) - .map(bibEntry -> bibEntry.getTitle().get()) - .collect(Collectors.toList()); + .filter(bibEntry -> bibEntry.getTitle().isPresent()) + .map(bibEntry -> bibEntry.getTitle().get()) + .collect(Collectors.toList()); if (titles.isEmpty()) { output(Localization.lang("None of the selected entries have titles.")); @@ -918,12 +653,9 @@ private void copyTitle() { if (titles.size() == selectedBibEntries.size()) { // All entries had titles. - output((selectedBibEntries.size() > 1 ? Localization.lang("Copied titles") : Localization - .lang("Copied title")) + '.'); + output((selectedBibEntries.size() > 1 ? Localization.lang("Copied titles") : Localization.lang("Copied title")) + '.'); } else { - output(Localization.lang("Warning: %0 out of %1 entries have undefined title.", - Integer.toString(selectedBibEntries.size() - titles.size()), - Integer.toString(selectedBibEntries.size()))); + output(Localization.lang("Warning: %0 out of %1 entries have undefined title.", Integer.toString(selectedBibEntries.size() - titles.size()), Integer.toString(selectedBibEntries.size()))); } } } @@ -943,8 +675,8 @@ private void copyCiteKey() { String sb = String.join(",", keys); String citeCommand = Optional.ofNullable(Globals.prefs.get(JabRefPreferences.CITE_COMMAND)) - .filter(cite -> cite.contains("\\")) // must contain \ - .orElse("\\cite"); + .filter(cite -> cite.contains("\\")) // must contain \ + .orElse("\\cite"); StringSelection ss = new StringSelection(citeCommand + "{" + sb + '}'); Toolkit.getDefaultToolkit().getSystemClipboard().setContents(ss, BasePanel.this); @@ -952,8 +684,7 @@ private void copyCiteKey() { // All entries had keys. output(bes.size() > 1 ? Localization.lang("Copied keys") : Localization.lang("Copied key") + '.'); } else { - output(Localization.lang("Warning: %0 out of %1 entries have undefined BibTeX key.", - Integer.toString(bes.size() - keys.size()), Integer.toString(bes.size()))); + output(Localization.lang("Warning: %0 out of %1 entries have undefined BibTeX key.", Integer.toString(bes.size() - keys.size()), Integer.toString(bes.size()))); } } } @@ -978,8 +709,7 @@ private void copyKey() { // All entries had keys. output((bes.size() > 1 ? Localization.lang("Copied keys") : Localization.lang("Copied key")) + '.'); } else { - output(Localization.lang("Warning: %0 out of %1 entries have undefined BibTeX key.", - Integer.toString(bes.size() - keys.size()), Integer.toString(bes.size()))); + output(Localization.lang("Warning: %0 out of %1 entries have undefined BibTeX key.", Integer.toString(bes.size() - keys.size()), Integer.toString(bes.size()))); } } } @@ -988,13 +718,11 @@ private void copyKeyAndTitle() { List bes = mainTable.getSelectedEntries(); if (!bes.isEmpty()) { // OK: in a future version, this string should be configurable to allow arbitrary exports - StringReader sr = new StringReader( - "\\bibtexkey - \\begin{title}\\format[RemoveBrackets]{\\title}\\end{title}\n"); + StringReader sr = new StringReader("\\bibtexkey - \\begin{title}\\format[RemoveBrackets]{\\title}\\end{title}\n"); Layout layout; try { - layout = new LayoutHelper(sr, - Globals.prefs.getLayoutFormatterPreferences(Globals.journalAbbreviationLoader)) - .getLayoutFromText(); + layout = new LayoutHelper(sr, Globals.prefs.getLayoutFormatterPreferences(Globals.journalAbbreviationLoader)) + .getLayoutFromText(); } catch (IOException e) { LOGGER.info("Could not get layout", e); return; @@ -1023,8 +751,7 @@ private void copyKeyAndTitle() { // All entries had keys. output((bes.size() > 1 ? Localization.lang("Copied keys") : Localization.lang("Copied key")) + '.'); } else { - output(Localization.lang("Warning: %0 out of %1 entries have undefined BibTeX key.", - Integer.toString(bes.size() - copied), Integer.toString(bes.size()))); + output(Localization.lang("Warning: %0 out of %1 entries have undefined BibTeX key.", Integer.toString(bes.size() - copied), Integer.toString(bes.size()))); } } } @@ -1051,8 +778,7 @@ private void openExternalFile() { return; } FileListEntry flEntry = fileListTableModel.getEntry(0); - ExternalFileMenuItem item = new ExternalFileMenuItem(frame(), entry, "", flEntry.getLink(), - flEntry.getType().get().getIcon(), bibDatabaseContext, flEntry.getType()); + ExternalFileMenuItem item = new ExternalFileMenuItem(frame(), "", flEntry.getLink(), flEntry.getType().get().getIcon().getSmallIcon(), bibDatabaseContext, flEntry.getType()); item.doClick(); }); } @@ -1061,15 +787,15 @@ private void openExternalFile() { * This method is called from JabRefFrame if a database specific action is requested by the user. Runs the command * if it is defined, or prints an error message to the standard error stream. * - * @param _command The name of the command to run. + * @param command The name of the command to run. */ - public void runCommand(final String _command) { - if (!actions.containsKey(_command)) { - LOGGER.info("No action defined for '" + _command + '\''); + public void runCommand(final Actions command) { + if (!actions.containsKey(command)) { + LOGGER.info("No action defined for '" + command + '\''); return; } - Object o = actions.get(_command); + Object o = actions.get(command); try { if (o instanceof BaseAction) { ((BaseAction) o).action(); @@ -1077,23 +803,21 @@ public void runCommand(final String _command) { runWorker((AbstractWorker) o); } } catch (Throwable ex) { - // If the action has blocked the JabRefFrame before crashing, we need to unblock it. - // The call to unblock will simply hide the glasspane, so there is no harm in calling - // it even if the frame hasn't been blocked. - frame.unblock(); LOGGER.error("runCommand error: " + ex.getMessage(), ex); } } - private boolean saveDatabase(File file, boolean selectedOnly, Charset enc, + /** + * FIXME: high code duplication with {@link SaveDatabaseAction#saveDatabase(File, boolean, Charset)} + */ + private boolean saveDatabase(File file, boolean selectedOnly, Charset encoding, SavePreferences.DatabaseSaveType saveType) throws SaveException { SaveSession session; - frame.block(); final String SAVE_DATABASE = Localization.lang("Save library"); try { SavePreferences prefs = Globals.prefs.loadForSaveFromPreferences() - .withEncoding(enc) + .withEncoding(encoding) .withSaveType(saveType); BibtexDatabaseWriter databaseWriter = new BibtexDatabaseWriter<>( FileSaveSession::new); @@ -1107,46 +831,38 @@ private boolean saveDatabase(File file, boolean selectedOnly, Charset enc, } // FIXME: not sure if this is really thrown anywhere catch (UnsupportedCharsetException ex) { - JOptionPane.showMessageDialog(frame, - Localization.lang("Could not save file.") + ' ' - + Localization.lang("Character encoding '%0' is not supported.", enc.displayName()), - SAVE_DATABASE, JOptionPane.ERROR_MESSAGE); + frame.getDialogService().showErrorDialogAndWait(Localization.lang("Save library"), Localization.lang("Could not save file.") + + Localization.lang("Character encoding '%0' is not supported.", encoding.displayName())); throw new SaveException("rt"); } catch (SaveException ex) { if (ex.specificEntry()) { // Error occurred during processing of the entry. Highlight it: - highlightEntry(ex.getEntry()); + clearAndSelect(ex.getEntry()); showAndEdit(ex.getEntry()); } else { LOGGER.warn("Could not save", ex); } - JOptionPane.showMessageDialog(frame, Localization.lang("Could not save file.") + "\n" + ex.getMessage(), - SAVE_DATABASE, JOptionPane.ERROR_MESSAGE); + dialogService.showErrorDialogAndWait(SAVE_DATABASE, Localization.lang("Could not save file."), ex); throw new SaveException("rt"); - } finally { - frame.unblock(); } boolean commit = true; if (!session.getWriter().couldEncodeAll()) { FormBuilder builder = FormBuilder.create() - .layout(new FormLayout("left:pref, 4dlu, fill:pref", "pref, 4dlu, pref")); + .layout(new FormLayout("left:pref, 4dlu, fill:pref", "pref, 4dlu, pref")); JTextArea ta = new JTextArea(session.getWriter().getProblemCharacters()); ta.setEditable(false); - builder.add(Localization.lang("The chosen encoding '%0' could not encode the following characters:", - session.getEncoding().displayName())).xy(1, 1); + builder.add(Localization.lang("The chosen encoding '%0' could not encode the following characters:", session.getEncoding().displayName())).xy(1, 1); builder.add(ta).xy(3, 1); builder.add(Localization.lang("What do you want to do?")).xy(1, 3); String tryDiff = Localization.lang("Try different encoding"); - int answer = JOptionPane.showOptionDialog(frame, builder.getPanel(), SAVE_DATABASE, - JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE, null, - new String[] {Localization.lang("Save"), tryDiff, Localization.lang("Cancel")}, tryDiff); + int answer = JOptionPane.showOptionDialog(null, builder.getPanel(), SAVE_DATABASE, JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE, null, new String[] {Localization.lang("Save"), tryDiff, Localization.lang("Cancel")}, tryDiff); if (answer == JOptionPane.NO_OPTION) { + // The user wants to use another encoding. - Object choice = JOptionPane.showInputDialog(frame, Localization.lang("Select encoding"), SAVE_DATABASE, - JOptionPane.QUESTION_MESSAGE, null, Encodings.ENCODINGS_DISPLAYNAMES, enc); + Object choice = JOptionPane.showInputDialog(null, Localization.lang("Select encoding"), SAVE_DATABASE, JOptionPane.QUESTION_MESSAGE, null, Encodings.ENCODINGS_DISPLAYNAMES, encoding); if (choice == null) { commit = false; } else { @@ -1160,7 +876,7 @@ private boolean saveDatabase(File file, boolean selectedOnly, Charset enc, if (commit) { session.commit(file.toPath()); - this.bibDatabaseContext.getMetaData().setEncoding(enc); // Make sure to remember which encoding we used. + this.bibDatabaseContext.getMetaData().setEncoding(encoding); // Make sure to remember which encoding we used. } else { session.cancel(); } @@ -1192,7 +908,6 @@ public BibEntry newEntry(EntryType type) { // Find out what type is wanted. final EntryTypeDialog etd = new EntryTypeDialog(frame); // We want to center the dialog, to make it look nicer. - etd.setLocationRelativeTo(frame); etd.setVisible(true); actualType = etd.getChoice(); } @@ -1206,7 +921,7 @@ public BibEntry newEntry(EntryType type) { UpdateField.setAutomaticFields(list, true, true, Globals.prefs.getUpdateFieldPreferences()); // Create an UndoableInsertEntry object. - getUndoManager().addEdit(new UndoableInsertEntry(bibDatabaseContext.getDatabase(), be, BasePanel.this)); + getUndoManager().addEdit(new UndoableInsertEntry(bibDatabaseContext.getDatabase(), be)); output(Localization.lang("Added new '%0' entry.", actualType.getName().toLowerCase(Locale.ROOT))); // We are going to select the new entry. Before that, make sure that we are in @@ -1217,7 +932,7 @@ public BibEntry newEntry(EntryType type) { mode = BasePanelMode.WILL_SHOW_EDITOR; } - highlightEntry(be); + clearAndSelect(be); // The database just changed. markBaseChanged(); @@ -1246,14 +961,14 @@ public void insertEntry(final BibEntry bibEntry) { UpdateField.setAutomaticFields(bibEntry, true, true, Globals.prefs.getUpdateFieldPreferences()); } // Create an UndoableInsertEntry object. - getUndoManager().addEdit(new UndoableInsertEntry(bibDatabaseContext.getDatabase(), bibEntry, BasePanel.this)); + getUndoManager().addEdit(new UndoableInsertEntry(bibDatabaseContext.getDatabase(), bibEntry)); output(Localization.lang("Added new '%0' entry.", bibEntry.getType())); markBaseChanged(); // The database just changed. if (Globals.prefs.getBoolean(JabRefPreferences.AUTO_OPEN_FORM)) { - selectionListener.editSignalled(bibEntry); + showAndEdit(bibEntry); } - highlightEntry(bibEntry); + clearAndSelect(bibEntry); } catch (KeyCollisionException ex) { LOGGER.info("Collision for bibtex key" + bibEntry.getId(), ex); } @@ -1262,8 +977,7 @@ public void insertEntry(final BibEntry bibEntry) { public void editEntryByIdAndFocusField(final String entryId, final String fieldName) { bibDatabaseContext.getDatabase().getEntryById(entryId).ifPresent(entry -> { - mainTable.setSelected(mainTable.findEntry(entry)); - selectionListener.editSignalled(); + clearAndSelect(entry); showAndEdit(entry); entryEditor.setFocusToField(fieldName); }); @@ -1274,24 +988,26 @@ public void updateTableFont() { } private void createMainTable() { - bibDatabaseContext.getDatabase().registerListener(tableModel.getListSynchronizer()); - bibDatabaseContext.getDatabase().registerListener(SpecialFieldDatabaseChangeListener.getInstance()); + bibDatabaseContext.getDatabase().registerListener(SpecialFieldDatabaseChangeListener.INSTANCE); - tableFormat = new MainTableFormat(bibDatabaseContext.getDatabase()); - tableFormat.updateTableFormat(); - mainTable = new MainTable(tableFormat, tableModel, frame, this); + mainTable = new MainTable(tableModel, frame, this, bibDatabaseContext, preferences.getTablePreferences(), externalFileTypes, preferences.getKeyBindings()); - selectionListener = new MainTableSelectionListener(this, mainTable); mainTable.updateFont(); - mainTable.addSelectionListener(selectionListener); - mainTable.addMouseListener(selectionListener); - mainTable.addKeyListener(selectionListener); - mainTable.addFocusListener(selectionListener); // Add the listener that binds selection to state manager (TODO: should be replaced by proper JavaFX binding as soon as table is implemented in JavaFX) - mainTable.addSelectionListener(listEvent -> Platform - .runLater(() -> Globals.stateManager.setSelectedEntries(mainTable.getSelectedEntries()))); - + mainTable.addSelectionListener(listEvent -> Globals.stateManager.setSelectedEntries(mainTable.getSelectedEntries())); + + // Update entry editor and preview according to selected entries + mainTable.addSelectionListener(event -> mainTable.getSelectedEntries() + .stream() + .findFirst() + .ifPresent(entry -> { + preview.setEntry(entry); + entryEditor.setEntry(entry); + })); + + // TODO: Register these actions globally + /* String clearSearch = "clearSearch"; mainTable.getInputMap().put(Globals.getKeyPrefs().getKey(KeyBinding.CLEAR_SEARCH), clearSearch); mainTable.getActionMap().put(clearSearch, new AbstractAction() { @@ -1350,68 +1066,24 @@ public void actionPerformed(ActionEvent e) { } } }); - - mainTable.addKeyListener(new KeyAdapter() { - - @Override - public void keyPressed(KeyEvent e) { - final int keyCode = e.getKeyCode(); - - if (e.isControlDown()) { - switch (keyCode) { - case KeyEvent.VK_PAGE_DOWN: - frame.nextTab.actionPerformed(null); - e.consume(); - break; - case KeyEvent.VK_PAGE_UP: - frame.prevTab.actionPerformed(null); - e.consume(); - break; - default: - break; - } - } else if (keyCode == KeyEvent.VK_ENTER) { - e.consume(); - try { - runCommand(Actions.EDIT); - } catch (Throwable ex) { - LOGGER.warn("Could not run action based on key press", ex); - } - } - } - }); + */ } public void setupMainPanel() { - splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT); - splitPane.setDividerSize(SPLIT_PANE_DIVIDER_SIZE); + splitPane = new SplitPane(); + splitPane.setOrientation(Orientation.VERTICAL); adjustSplitter(); // restore last splitting state (before mainTable is created as creation affects the stored size of the entryEditors) - // check whether a mainTable already existed and a floatSearch was active - boolean floatSearchActive = (mainTable != null) && (this.tableModel.getSearchState() == MainTableDataModel.DisplayOption.FLOAT); - createMainTable(); - splitPane.setTopComponent(mainTable.getPane()); - - // Remove borders - splitPane.setBorder(BorderFactory.createEmptyBorder()); - setBorder(BorderFactory.createEmptyBorder()); - - // If an entry is currently being shown, make sure it stays shown, - // otherwise set the bottom component to null. - if (mode == BasePanelMode.SHOWING_PREVIEW) { - mode = BasePanelMode.SHOWING_NOTHING; - highlightEntry(selectionListener.getPreview().getEntry()); - } else if (mode == BasePanelMode.SHOWING_EDITOR) { - mode = BasePanelMode.SHOWING_NOTHING; - } else { - splitPane.setBottomComponent(null); - } - - setLayout(new BorderLayout()); - removeAll(); - add(splitPane, BorderLayout.CENTER); + ScrollPane pane = mainTable.getPane(); + AnchorPane anchorPane = new AnchorPane(pane); + AnchorPane.setBottomAnchor(pane, 0.0); + AnchorPane.setTopAnchor(pane, 0.0); + AnchorPane.setLeftAnchor(pane, 0.0); + AnchorPane.setRightAnchor(pane, 0.0); + splitPane.getItems().add(anchorPane); + this.getChildren().setAll(splitPane); // Set up name autocompleter for search: instantiateSearchAutoCompleter(); @@ -1419,25 +1091,18 @@ public void setupMainPanel() { setupAutoCompletion(); - // restore floating search result - // (needed if preferences have been changed which causes a recreation of the main table) - if (floatSearchActive) { - mainTable.showFloatSearch(); - } - - splitPane.revalidate(); - revalidate(); - repaint(); - - // saves the divider position as soon as it changes - splitPane.addPropertyChangeListener(JSplitPane.DIVIDER_LOCATION_PROPERTY, event -> saveDividerLocation()); + // Saves the divider position as soon as it changes + // We need to keep a reference to the subscription, otherwise the binding gets garbage collected + dividerPositionSubscription = EasyBind.monadic(Bindings.valueAt(splitPane.getDividers(), 0)) + .flatMap(SplitPane.Divider::positionProperty) + .subscribe((observable, oldValue, newValue) -> saveDividerLocation(newValue)); } /** * Set up auto completion for this database */ private void setupAutoCompletion() { - AutoCompletePreferences autoCompletePreferences = Globals.prefs.getAutoCompletePreferences(); + AutoCompletePreferences autoCompletePreferences = preferences.getAutoCompletePreferences(); if (autoCompletePreferences.shouldAutoComplete()) { suggestionProviders = new SuggestionProviders(autoCompletePreferences, Globals.journalAbbreviationLoader); suggestionProviders.indexDatabase(getDatabase()); @@ -1461,12 +1126,6 @@ private void instantiateSearchAutoCompleter() { } } - public void updatePreamble() { - if (preambleEditor != null) { - preambleEditor.updatePreamble(); - } - } - public void assureStringDialogNotEditing() { if (stringDialog != null) { stringDialog.assureNotEditing(); @@ -1479,13 +1138,11 @@ public void updateStringDialog() { } } - public void adjustSplitter() { + private void adjustSplitter() { if (mode == BasePanelMode.SHOWING_PREVIEW) { - splitPane.setDividerLocation( - splitPane.getHeight() - Globals.prefs.getPreviewPreferences().getPreviewPanelHeight()); - } else { - splitPane.setDividerLocation( - splitPane.getHeight() - Globals.prefs.getInt(JabRefPreferences.ENTRY_EDITOR_HEIGHT)); + splitPane.setDividerPositions(Globals.prefs.getPreviewPreferences().getPreviewPanelDividerPosition().doubleValue()); + } else if (mode == BasePanelMode.SHOWING_EDITOR) { + splitPane.setDividerPositions(preferences.getEntryEditorDividerPosition()); } } @@ -1501,38 +1158,60 @@ public EntryEditor getEntryEditor() { * @param entry The entry to edit. */ public void showAndEdit(BibEntry entry) { - - if (mode == BasePanelMode.SHOWING_EDITOR) { - Globals.prefs.putInt(JabRefPreferences.ENTRY_EDITOR_HEIGHT, splitPane.getHeight() - splitPane.getDividerLocation()); - } - mode = BasePanelMode.SHOWING_EDITOR; - splitPane.setBottomComponent(entryEditorContainer); DefaultTaskExecutor.runInJavaFXThread(() -> { + + showBottomPane(BasePanelMode.SHOWING_EDITOR); + if (entry != getShowing()) { entryEditor.setEntry(entry); - newEntryShowing(entry); + showing = entry; } entryEditor.requestFocus(); }); + } + + private void showBottomPane(BasePanelMode newMode) { + Node pane; + switch (newMode) { + case SHOWING_PREVIEW: + pane = preview; + break; + case SHOWING_EDITOR: + pane = entryEditor; + break; + default: + throw new UnsupportedOperationException("new mode not recognized: " + newMode.name()); + } + if (splitPane.getItems().size() == 2) { + splitPane.getItems().set(1, pane); + } else { + splitPane.getItems().add(1, pane); + } + mode = newMode; adjustSplitter(); } + private void showAndEdit() { + if (!mainTable.getSelectedEntries().isEmpty()) { + showAndEdit(mainTable.getSelectedEntries().get(0)); + } + } + /** * Sets the given preview panel as the bottom component in the split panel. Updates the mode to SHOWING_PREVIEW. * * @param entry The entry to show in the preview. */ - public void showPreview(BibEntry entry) { + private void showPreview(BibEntry entry) { + showBottomPane(BasePanelMode.SHOWING_PREVIEW); + preview.setEntry(entry); - mode = BasePanelMode.SHOWING_PREVIEW; - splitPane.setBottomComponent(previewContainer); - adjustSplitter(); } private void showPreview() { - if (!mainTable.getSelected().isEmpty()) { - showPreview(mainTable.getSelected().get(0)); + if (!mainTable.getSelectedEntries().isEmpty()) { + showPreview(mainTable.getSelectedEntries().get(0)); } } @@ -1546,9 +1225,9 @@ public void previousPreviewStyle() { private void cyclePreview(int newPosition) { PreviewPreferences previewPreferences = Globals.prefs.getPreviewPreferences() - .getBuilder() - .withPreviewCyclePosition(newPosition) - .build(); + .getBuilder() + .withPreviewCyclePosition(newPosition) + .build(); Globals.prefs.storePreviewPreferences(previewPreferences); preview.updateLayout(previewPreferences); @@ -1557,44 +1236,49 @@ private void cyclePreview(int newPosition) { /** * Removes the bottom component. */ - public void hideBottomComponent() { + public void closeBottomPane() { mode = BasePanelMode.SHOWING_NOTHING; - splitPane.setBottomComponent(null); + splitPane.getItems().removeAll(entryEditor, preview); } /** * This method selects the given entry, and scrolls it into view in the table. If an entryEditor is shown, it is * given focus afterwards. */ - public void highlightEntry(final BibEntry bibEntry) { - highlightEntry(mainTable.findEntry(bibEntry)); + public void clearAndSelect(final BibEntry bibEntry) { + mainTable.clearAndSelect(bibEntry); } /** * This method selects the entry on the given position, and scrolls it into view in the table. * If an entryEditor is shown, it is given focus afterwards. + * + * @deprecated use select by entry not by row */ - public void highlightEntry(int pos) { - if ((pos >= 0) && (pos < mainTable.getRowCount())) { - mainTable.setRowSelectionInterval(pos, pos); - mainTable.ensureVisible(pos); + @Deprecated + private void clearAndSelect(int pos) { + if ((pos >= 0) && (pos < mainTable.getItems().size())) { + mainTable.getSelectionModel().clearAndSelect(pos); } } public void selectPreviousEntry() { - highlightEntry(((mainTable.getSelectedRow() - 1) + mainTable.getRowCount()) % mainTable.getRowCount()); + mainTable.getSelectionModel().clearSelection(); + mainTable.getSelectionModel().selectPrevious(); } public void selectNextEntry() { - highlightEntry((mainTable.getSelectedRow() + 1) % mainTable.getRowCount()); + mainTable.getSelectionModel().clearSelection(); + mainTable.getSelectionModel().selectNext(); } public void selectFirstEntry() { - highlightEntry(0); + clearAndSelect(0); } public void selectLastEntry() { - highlightEntry(mainTable.getRowCount() - 1); + mainTable.getSelectionModel().clearSelection(); + mainTable.getSelectionModel().selectLast(); } /** @@ -1604,10 +1288,12 @@ public void selectLastEntry() { * @param editor The entry editor to close. */ public void entryEditorClosing(EntryEditor editor) { - // Store divider location for next time: - Globals.prefs.putInt(JabRefPreferences.ENTRY_EDITOR_HEIGHT, - splitPane.getHeight() - splitPane.getDividerLocation()); - selectionListener.entryEditorClosing(editor); + if (Globals.prefs.getPreviewPreferences().isPreviewPanelEnabled()) { + showPreview(editor.getEntry()); + } else { + closeBottomPane(); + } + mainTable.requestFocus(); } /** @@ -1615,8 +1301,8 @@ public void entryEditorClosing(EntryEditor editor) { */ public void ensureNotShowingBottomPanel(BibEntry entry) { if (((mode == BasePanelMode.SHOWING_EDITOR) && (entryEditor.getEntry() == entry)) - || ((mode == BasePanelMode.SHOWING_PREVIEW) && (selectionListener.getPreview().getEntry() == entry))) { - hideBottomComponent(); + || ((mode == BasePanelMode.SHOWING_PREVIEW) && (preview.getEntry() == entry))) { + closeBottomPane(); } } @@ -1644,7 +1330,7 @@ public void markBaseChanged() { private void markBasedChangedInternal() { // Put an asterisk behind the filename to indicate the database has changed. frame.setWindowTitle(); - frame.updateAllTabTitles(); + DefaultTaskExecutor.runInJavaFXThread(frame::updateAllTabTitles); // If the status line states that the base has been saved, we // remove this message, since it is no longer relevant. If a // different message is shown, we leave it. @@ -1678,10 +1364,6 @@ public BibDatabase getDatabase() { return bibDatabaseContext.getDatabase(); } - public void preambleEditorClosing() { - preambleEditor = null; - } - public void stringsClosing() { stringDialog = null; } @@ -1698,10 +1380,8 @@ private void changeType(List entries, String newType) { } if (entries.size() > 1) { - int choice = JOptionPane.showConfirmDialog(this, - Localization.lang("Multiple entries selected. Do you want to change the type of all these to '%0'?", newType), - Localization.lang("Change entry type"), JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); - if (choice == JOptionPane.NO_OPTION) { + boolean proceed = dialogService.showConfirmationDialogAndWait(Localization.lang("Change entry type"), Localization.lang("Multiple entries selected. Do you want to change the type of all these to '%0'?")); + if (!proceed) { return; } } @@ -1723,22 +1403,23 @@ private void changeType(List entries, String newType) { public boolean showDeleteConfirmationDialog(int numberOfEntries) { if (Globals.prefs.getBoolean(JabRefPreferences.CONFIRM_DELETE)) { - String msg; - msg = Localization.lang("Really delete the selected entry?"); String title = Localization.lang("Delete entry"); + String message = Localization.lang("Really delete the selected entry?"); + String okButton = Localization.lang("Delete entry"); + String cancelButton = Localization.lang("Keep entry"); if (numberOfEntries > 1) { - msg = Localization.lang("Really delete the %0 selected entries?", Integer.toString(numberOfEntries)); title = Localization.lang("Delete multiple entries"); + message = Localization.lang("Really delete the %0 selected entries?", Integer.toString(numberOfEntries)); + okButton = Localization.lang("Delete entries"); + cancelButton = Localization.lang("Keep entries"); } - CheckBoxMessage cb = new CheckBoxMessage(msg, Localization.lang("Disable this confirmation dialog"), false); - - int answer = JOptionPane.showConfirmDialog(frame, cb, title, JOptionPane.YES_NO_OPTION, - JOptionPane.QUESTION_MESSAGE); - if (cb.isSelected()) { - Globals.prefs.putBoolean(JabRefPreferences.CONFIRM_DELETE, false); - } - return answer == JOptionPane.YES_OPTION; + return dialogService.showConfirmationDialogWithOptOutAndWait(title, + message, + okButton, + cancelButton, + Localization.lang("Disable this confirmation dialog"), + optOut -> Globals.prefs.putBoolean(JabRefPreferences.CONFIRM_DELETE, !optOut)); } else { return true; } @@ -1769,20 +1450,21 @@ public void autoGenerateKeysBeforeSaving() { } /** - * Depending on whether a preview or an entry editor is showing, save the current divider location in the correct - * preference setting. + * Depending on whether a preview or an entry editor is showing, save the current divider location in the correct preference setting. */ - public void saveDividerLocation() { + private void saveDividerLocation(Number position) { + if (position == null) { + return; + } + if (mode == BasePanelMode.SHOWING_PREVIEW) { - int previewPanelHeight = splitPane.getHeight() - splitPane.getDividerLocation(); PreviewPreferences previewPreferences = Globals.prefs.getPreviewPreferences() - .getBuilder() - .withPreviewPanelHeight(previewPanelHeight) - .build(); + .getBuilder() + .withPreviewPanelDividerPosition(position) + .build(); Globals.prefs.storePreviewPreferences(previewPreferences); } else if (mode == BasePanelMode.SHOWING_EDITOR) { - Globals.prefs.putInt(JabRefPreferences.ENTRY_EDITOR_HEIGHT, - splitPane.getHeight() - splitPane.getDividerLocation()); + preferences.setEntryEditorDividerPosition(position.doubleValue()); } } @@ -1798,12 +1480,11 @@ public void lostOwnership(Clipboard clipboard, Transferable contents) { public void cleanUp() { changeMonitor.ifPresent(DatabaseChangeMonitor::unregister); - // Check if there is a FileUpdatePanel for this BasePanel being shown. If so, - // remove it: - if (sidePaneManager.hasComponent(FileUpdatePanel.class)) { - FileUpdatePanel fup = (FileUpdatePanel) sidePaneManager.getComponent(FileUpdatePanel.class); + // Check if there is a FileUpdatePanel for this BasePanel being shown. If so remove it: + if (sidePaneManager.isComponentVisible(SidePaneType.FILE_UPDATE_NOTIFICATION)) { + FileUpdatePanel fup = (FileUpdatePanel) sidePaneManager.getComponent(SidePaneType.FILE_UPDATE_NOTIFICATION); if (fup.getPanel() == this) { - sidePaneManager.hideComponent(FileUpdatePanel.class); + sidePaneManager.hide(SidePaneType.FILE_UPDATE_NOTIFICATION); } } } @@ -1854,81 +1535,15 @@ private BibEntry getShowing() { return showing; } - /** - * Update the pointer to the currently shown entry in all cases where the user has moved to a new entry, except when - * using Back and Forward commands. Also updates history for Back command, and clears history for Forward command. - * - * @param entry The entry that is now to be shown. - */ - private void newEntryShowing(BibEntry entry) { - - // If this call is the result of a Back or Forward operation, we must take - // care not to make any history changes, since the necessary changes will - // already have been done in the back() or forward() method: - if (backOrForwardInProgress) { - showing = entry; - backOrForwardInProgress = false; - setBackAndForwardEnabledState(); - return; - } - nextEntries.clear(); - if (!Objects.equals(entry, showing)) { - // Add the entry we are leaving to the history: - if (showing != null) { - previousEntries.add(showing); - if (previousEntries.size() > GUIGlobals.MAX_BACK_HISTORY_SIZE) { - previousEntries.remove(0); - } - } - showing = entry; - setBackAndForwardEnabledState(); - } - } - - /** - * Go back (if there is any recorded history) and update the histories for the Back and Forward commands. - */ - private void back() { - if (!previousEntries.isEmpty()) { - BibEntry toShow = previousEntries.get(previousEntries.size() - 1); - previousEntries.remove(previousEntries.size() - 1); - // Add the entry we are going back from to the Forward history: - if (showing != null) { - nextEntries.add(showing); - } - backOrForwardInProgress = true; // to avoid the history getting updated erroneously - highlightEntry(toShow); - } - } - - private void forward() { - if (!nextEntries.isEmpty()) { - BibEntry toShow = nextEntries.get(nextEntries.size() - 1); - nextEntries.remove(nextEntries.size() - 1); - // Add the entry we are going forward from to the Back history: - if (showing != null) { - previousEntries.add(showing); - } - backOrForwardInProgress = true; // to avoid the history getting updated erroneously - highlightEntry(toShow); - } - } - - public void setBackAndForwardEnabledState() { - frame.getBackAction().setEnabled(!previousEntries.isEmpty()); - frame.getForwardAction().setEnabled(!nextEntries.isEmpty()); - } - - private String formatOutputMessage(String start, int count) { - return String.format("%s %d %s.", start, count, - (count > 1 ? Localization.lang("entries") : Localization.lang("entry"))); + public String formatOutputMessage(String start, int count) { + return String.format("%s %d %s.", start, count, (count > 1 ? Localization.lang("entries") : Localization.lang("entry"))); } /** * Set the preview active state for all BasePanel instances. */ private void setPreviewActiveBasePanels(boolean enabled) { - for (int i = 0; i < frame.getTabbedPane().getTabCount(); i++) { + for (int i = 0; i < frame.getTabbedPane().getTabs().size(); i++) { frame.getBasePanelAt(i).setPreviewActive(enabled); } } @@ -2050,15 +1665,7 @@ private class EntryRemovedListener { @Subscribe public void listen(EntryRemovedEvent entryRemovedEvent) { - // if the entry that is displayed in the current entry editor is removed, close the entry editor - if ((mode == BasePanelMode.SHOWING_EDITOR) && entryEditor.getEntry().equals(entryRemovedEvent.getBibEntry())) { - entryEditor.close(); - } - - BibEntry previewEntry = selectionListener.getPreview().getEntry(); - if ((previewEntry != null) && previewEntry.equals(entryRemovedEvent.getBibEntry())) { - preview.close(); - } + ensureNotShowingBottomPanel(entryRemovedEvent.getBibEntry()); } } @@ -2091,7 +1698,6 @@ public void listen(EntryAddedEvent addedEntryEvent) { @Subscribe public void listen(EntryChangedEvent entryChangedEvent) { - frame.getGlobalSearchBar().setDontSelectSearchBar(); frame.getGlobalSearchBar().performSearch(); } @@ -2102,21 +1708,16 @@ public void listen(EntryRemovedEvent removedEntryEvent) { } } + @Subscribe + public void listen(EntryChangedEvent entryChangedEvent) { + this.markBaseChanged(); + } + private class UndoAction implements BaseAction { @Override public void action() { try { - JComponent focused = Globals.getFocusListener().getFocused(); - if ((focused != null) && (focused instanceof FieldEditor) && focused.hasFocus()) { - // User is currently editing a field: - // Check if it is the preamble: - - FieldEditor fieldEditor = (FieldEditor) focused; - if ((preambleEditor != null) && (fieldEditor.equals(preambleEditor.getFieldEditor()))) { - preambleEditor.storeCurrentEdit(); - } - } getUndoManager().undo(); markBaseChanged(); frame.output(Localization.lang("Undo")); @@ -2151,29 +1752,30 @@ public void action() { } else { // No URL or DOI found in the "url" and "doi" fields. // Look for web links in the "file" field as a fallback: - FileListEntry entry = null; - FileListTableModel tm = new FileListTableModel(); - bes.get(0).getField(FieldName.FILE).ifPresent(tm::setContent); - for (int i = 0; i < tm.getRowCount(); i++) { - FileListEntry flEntry = tm.getEntry(i); - if (FieldName.URL.equalsIgnoreCase(flEntry.getType().get().getName()) - || FieldName.PS.equalsIgnoreCase(flEntry.getType().get().getName()) - || FieldName.PDF.equalsIgnoreCase(flEntry.getType().get().getName())) { - entry = flEntry; - break; - } - } - if (entry == null) { - output(Localization.lang("No URL defined") + '.'); - } else { + + List files = bes.get(0).getFiles(); + + Optional linkedFile = files.stream() + .filter(file -> (FieldName.URL.equalsIgnoreCase(file.getFileType()) + || FieldName.PS.equalsIgnoreCase(file.getFileType()) + || FieldName.PDF.equalsIgnoreCase(file.getFileType()))) + .findFirst(); + + if (linkedFile.isPresent()) { + try { - JabRefDesktop.openExternalFileAnyFormat(bibDatabaseContext, entry.getLink(), - entry.getType()); + + JabRefDesktop.openExternalFileAnyFormat(bibDatabaseContext, + linkedFile.get().getLink(), + ExternalFileTypes.getInstance().fromLinkedFile(linkedFile.get(), true)); + output(Localization.lang("External viewer called") + '.'); } catch (IOException e) { output(Localization.lang("Could not open link")); LOGGER.info("Could not open link", e); } + } else { + output(Localization.lang("No URL defined") + '.'); } } } else { @@ -2187,8 +1789,6 @@ private class RedoAction implements BaseAction { @Override public void action() { try { - - JComponent focused = Globals.getFocusListener().getFocused(); getUndoManager().redo(); markBaseChanged(); frame.output(Localization.lang("Redo")); @@ -2225,11 +1825,7 @@ public void action() throws SaveException { .withInitialDirectory(Globals.prefs.get(JabRefPreferences.WORKING_DIRECTORY)) .build(); - DialogService ds = new FXDialogService(); - - Optional chosenFile = DefaultTaskExecutor - .runInJavaFXThread(() -> ds.showFileSaveDialog(fileDialogConfiguration)); - + Optional chosenFile = dialogService.showFileSaveDialog(fileDialogConfiguration); if (chosenFile.isPresent()) { Path path = chosenFile.get(); saveDatabase(path.toFile(), true, Globals.prefs.getDefaultEncoding(), saveType); diff --git a/src/main/java/org/jabref/gui/BasePanelPreferences.java b/src/main/java/org/jabref/gui/BasePanelPreferences.java new file mode 100644 index 00000000000..c248f869dcc --- /dev/null +++ b/src/main/java/org/jabref/gui/BasePanelPreferences.java @@ -0,0 +1,80 @@ +package org.jabref.gui; + +import javafx.beans.property.DoubleProperty; +import javafx.beans.property.SimpleDoubleProperty; + +import org.jabref.Globals; +import org.jabref.gui.autocompleter.AutoCompletePreferences; +import org.jabref.gui.entryeditor.EntryEditorPreferences; +import org.jabref.gui.keyboard.KeyBindingRepository; +import org.jabref.gui.maintable.MainTablePreferences; +import org.jabref.preferences.JabRefPreferences; +import org.jabref.preferences.PreviewPreferences; + +import org.fxmisc.easybind.EasyBind; + +public class BasePanelPreferences { + private MainTablePreferences tablePreferences; + private AutoCompletePreferences autoCompletePreferences; + private EntryEditorPreferences entryEditorPreferences; + private KeyBindingRepository keyBindings; + private PreviewPreferences previewPreferences; + private DoubleProperty entryEditorDividerPosition = new SimpleDoubleProperty(); + + public BasePanelPreferences(MainTablePreferences tablePreferences, AutoCompletePreferences autoCompletePreferences, EntryEditorPreferences entryEditorPreferences, KeyBindingRepository keyBindings, PreviewPreferences previewPreferences, Double entryEditorDividerPosition) { + this.tablePreferences = tablePreferences; + this.autoCompletePreferences = autoCompletePreferences; + this.entryEditorPreferences = entryEditorPreferences; + this.keyBindings = keyBindings; + this.previewPreferences = previewPreferences; + this.entryEditorDividerPosition.setValue(entryEditorDividerPosition); + } + + public static BasePanelPreferences from(JabRefPreferences preferences) { + BasePanelPreferences basePanelPreferences = new BasePanelPreferences( + preferences.getMainTablePreferences(), + preferences.getAutoCompletePreferences(), + EntryEditorPreferences.from(preferences), + Globals.getKeyPrefs(), + preferences.getPreviewPreferences(), + preferences.getDouble(JabRefPreferences.ENTRY_EDITOR_HEIGHT)); + EasyBind.subscribe(basePanelPreferences.entryEditorDividerPosition, value -> preferences.putDouble(JabRefPreferences.ENTRY_EDITOR_HEIGHT, value.doubleValue())); + return basePanelPreferences; + } + + public double getEntryEditorDividerPosition() { + return entryEditorDividerPosition.get(); + } + + public void setEntryEditorDividerPosition(double entryEditorDividerPosition) { + this.entryEditorDividerPosition.set(entryEditorDividerPosition); + } + + public DoubleProperty entryEditorDividerPositionProperty() { + return entryEditorDividerPosition; + } + + public MainTablePreferences getTablePreferences() { + return tablePreferences; + } + + public AutoCompletePreferences getAutoCompletePreferences() { + return autoCompletePreferences; + } + + public void setAutoCompletePreferences(AutoCompletePreferences autoCompletePreferences) { + this.autoCompletePreferences = autoCompletePreferences; + } + + public EntryEditorPreferences getEntryEditorPreferences() { + return entryEditorPreferences; + } + + public KeyBindingRepository getKeyBindings() { + return keyBindings; + } + + public PreviewPreferences getPreviewPreferences() { + return previewPreferences; + } +} diff --git a/src/main/java/org/jabref/gui/ClipBoardManager.java b/src/main/java/org/jabref/gui/ClipBoardManager.java index a79eb860213..eddcd6a67de 100644 --- a/src/main/java/org/jabref/gui/ClipBoardManager.java +++ b/src/main/java/org/jabref/gui/ClipBoardManager.java @@ -11,13 +11,19 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; + +import javafx.scene.input.ClipboardContent; import org.jabref.Globals; +import org.jabref.logic.bibtex.BibEntryWriter; +import org.jabref.logic.bibtex.LatexFieldFormatter; import org.jabref.logic.importer.FetcherException; import org.jabref.logic.importer.ImportException; import org.jabref.logic.importer.ImportFormatReader; import org.jabref.logic.importer.ImportFormatReader.UnknownFormatImport; import org.jabref.logic.importer.fetcher.DoiFetcher; +import org.jabref.model.database.BibDatabaseMode; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.identifier.DOI; @@ -77,10 +83,40 @@ public String getClipboardContents() { return result; } + public void setClipboardHtmlContent(String html) { + // TODO: This works on Mac and Windows 10, but not on Ubuntu 16.04 + final javafx.scene.input.Clipboard clipboard = javafx.scene.input.Clipboard.getSystemClipboard(); + final ClipboardContent content = new ClipboardContent(); + content.putHtml(html); + clipboard.setContent(content); + } + + public void setClipboardContent(String string) { + // TODO: This works on Mac and Windows 10, but not on Ubuntu 16.04 + final javafx.scene.input.Clipboard clipboard = javafx.scene.input.Clipboard.getSystemClipboard(); + final ClipboardContent content = new ClipboardContent(); + content.putString(string); + clipboard.setContent(content); + } + + public void setClipboardContent(List entries) throws IOException { + // TODO: This works on Mac and Windows 10, but not on Ubuntu 16.04 + final javafx.scene.input.Clipboard clipboard = javafx.scene.input.Clipboard.getSystemClipboard(); + final ClipboardContent content = new ClipboardContent(); + BibEntryWriter writer = new BibEntryWriter(new LatexFieldFormatter(Globals.prefs.getLatexFieldFormatterPreferences()), false); + String serializedEntries = writer.serializeAll(entries, BibDatabaseMode.BIBTEX); + content.put(DragAndDropDataFormats.ENTRIES, serializedEntries); + content.putString(serializedEntries); + clipboard.setContent(content); + } + /** * Place a String on the clipboard, and make this class the * owner of the Clipboard's contents. + * + * @deprecated use {@link #setClipboardContent(String)} instead */ + @Deprecated public void setClipboardContents(String aString) { StringSelection stringSelection = new StringSelection(aString); clipboard.setContents(stringSelection, this); @@ -96,7 +132,8 @@ public List extractBibEntriesFromClipboard() { try { @SuppressWarnings("unchecked") List contents = (List) content.getTransferData(TransferableBibtexEntry.ENTRY_FLAVOR); - result = contents; + // We clone the entries to make sure we don't accidentally paste references + result = contents.stream().map(entry -> (BibEntry) entry.clone()).collect(Collectors.toList()); } catch (UnsupportedFlavorException | ClassCastException ex) { LOGGER.warn("Could not paste this type", ex); } catch (IOException ex) { diff --git a/src/main/java/org/jabref/gui/Dark.css b/src/main/java/org/jabref/gui/Dark.css new file mode 100644 index 00000000000..8df9935c460 --- /dev/null +++ b/src/main/java/org/jabref/gui/Dark.css @@ -0,0 +1,52 @@ +.root { + -jr-theme: #2c9490; + -jr-accent: #255652; + -jr-selected: -jr-accent; + -jr-hover: #fff1; + + + -jr-red: #b71c1f; + -jr-light-red: #db1d2b; + -jr-green: #1cb631; + -jr-light-green: #28d93c; + -jr-blue: #2c2cb7; + -jr-light-blue: #3a3ad9; + -jr-purple: #b72486; + -jr-light-purple: #d927a8; + -jr-yellow: #b5b021; + -jr-orange: #b77620; + + -jr-base: #141824; + + -jr-background-alt: #151924; + -jr-menu-background: #141824; + -jr-toolbar: -jr-menu-background; + -jr-sidepane-background: #212330; + -jr-search-background: #2c2e3b; + + -jr-sidepane-header-background: -jr-background-alt; + -jr-group-hits-bg: -jr-background-alt; + -jr-group-hits-fg: -fx-light-text-color; + -fx-control-inner-background: #272b38; + + -fx-control-inner-background-alt: -fx-control-inner-background; + + -fx-dark-text-color: black; + -fx-mid-text-color: #7d8591; + -fx-light-text-color: #9aa3af; + -jr-separator: #333744; + -fx-outer-border: #424758; + + -jr-icon: -fx-light-text-color; + -jr-icon-active: derive(-fx-light-text-color, 50%); + -jr-icon-background-active: -jr-hover; + -jr-icon-background-armed: #fff2; + + -jr-menu-foreground: -fx-light-text-color; + -jr-menu-item-foreground: -fx-light-text-color; + -jr-menu-forground-active: derive(-fx-light-text-color, 50%); + + -fx-focused-text-base-color: -fx-dark-text-color; + + -jr-tooltip-fg: derive(-fx-light-text-color, 50%); +} diff --git a/src/main/java/org/jabref/gui/DefaultInjector.java b/src/main/java/org/jabref/gui/DefaultInjector.java index ee81dd7072d..e94e6fe8697 100644 --- a/src/main/java/org/jabref/gui/DefaultInjector.java +++ b/src/main/java/org/jabref/gui/DefaultInjector.java @@ -38,6 +38,8 @@ private static Object createDependency(Class clazz) { return Globals.stateManager; } else if (clazz == FileUpdateMonitor.class) { return Globals.getFileUpdateMonitor(); + } else if (clazz == ClipBoardManager.class) { + return Globals.clipboardManager; } else { try { return clazz.newInstance(); @@ -57,4 +59,14 @@ public T instantiatePresenter(Class clazz, Function injec return Injector.instantiatePresenter(clazz, injectionContext); } + + @Override + public void injectMembers(Object instance, Function injectionContext) { + LOGGER.debug("Inject into " + instance.getClass().getName()); + + // Use our own method to construct dependencies + Injector.setInstanceSupplier(DefaultInjector::createDependency); + + Injector.injectMembers(instance, injectionContext); + } } diff --git a/src/main/java/org/jabref/gui/DialogService.java b/src/main/java/org/jabref/gui/DialogService.java index 1ddbe50a90c..a19f831470c 100644 --- a/src/main/java/org/jabref/gui/DialogService.java +++ b/src/main/java/org/jabref/gui/DialogService.java @@ -1,14 +1,18 @@ package org.jabref.gui; import java.nio.file.Path; +import java.util.Collection; import java.util.List; import java.util.Optional; +import java.util.function.Consumer; import javafx.concurrent.Task; import javafx.print.PrinterJob; import javafx.scene.control.Alert; import javafx.scene.control.ButtonType; +import javafx.scene.control.ChoiceDialog; import javafx.scene.control.DialogPane; +import javafx.scene.control.TextInputDialog; import org.jabref.gui.util.DirectoryDialogConfiguration; import org.jabref.gui.util.FileDialogConfiguration; @@ -21,6 +25,23 @@ */ public interface DialogService { + /** + * This will create and display new {@link ChoiceDialog} of type T with a default choice and a collection of possible choices + * + * @implNote The implementation should accept {@code null} for {@code defaultChoice}, but callers should use {@link #showChoiceDialogAndWait(String, String, String, Collection)}. + */ + Optional showChoiceDialogAndWait(String title, String content, String okButtonLabel, T defaultChoice, Collection choices); + + /** + * This will create and display new {@link ChoiceDialog} of type T with a collection of possible choices + */ + default Optional showChoiceDialogAndWait(String title, String content, String okButtonLabel, Collection choices) { + return showChoiceDialogAndWait(title, content, okButtonLabel, null, choices); + } + + /** + * This will create and display new {@link TextInputDialog} with a text fields to enter data + */ Optional showInputDialogAndWait(String title, String content); /** @@ -64,6 +85,13 @@ default void showErrorDialogAndWait(Exception exception) { showErrorDialogAndWait(Localization.lang("Unhandled exception occurred."), exception); } + /** + * Create and display error dialog displaying the given exception. + * + * @param exception the exception causing the error + */ + void showErrorDialogAndWait(String title, String content, Throwable exception); + /** * Create and display error dialog displaying the given message. * @@ -85,7 +113,7 @@ default void showErrorDialogAndWait(Exception exception) { * Create and display a new confirmation dialog. * It will include a blue question icon on the left and * a OK (with given label) and Cancel button. To create a confirmation dialog with custom - * buttons see also {@link #showCustomButtonDialogAndWait(Alert.AlertType, String, String, ButtonType...)} + * buttons see also {@link #showCustomButtonDialogAndWait(Alert.AlertType, String, String, ButtonType...)}. * * @return true if the use clicked "OK" otherwise false */ @@ -95,12 +123,37 @@ default void showErrorDialogAndWait(Exception exception) { * Create and display a new confirmation dialog. * It will include a blue question icon on the left and * a OK (with given label) and Cancel (also with given label) button. To create a confirmation dialog with custom - * buttons see also {@link #showCustomButtonDialogAndWait(Alert.AlertType, String, String, ButtonType...)} + * buttons see also {@link #showCustomButtonDialogAndWait(Alert.AlertType, String, String, ButtonType...)}. * * @return true if the use clicked "OK" otherwise false */ boolean showConfirmationDialogAndWait(String title, String content, String okButtonLabel, String cancelButtonLabel); + /** + * Create and display a new confirmation dialog. + * It will include a blue question icon on the left and + * a YES (with given label) and Cancel (also with given label) button. To create a confirmation dialog with custom + * buttons see also {@link #showCustomButtonDialogAndWait(Alert.AlertType, String, String, ButtonType...)}. + * Moreover, the dialog contains a opt-out checkbox with the given text to support "Do not ask again"-behaviour. + * + * @return true if the use clicked "YES" otherwise false + */ + boolean showConfirmationDialogWithOptOutAndWait(String title, String content, + String optOutMessage, Consumer optOutAction); + + /** + * Create and display a new confirmation dialog. + * It will include a blue question icon on the left and + * a YES (with given label) and Cancel (also with given label) button. To create a confirmation dialog with custom + * buttons see also {@link #showCustomButtonDialogAndWait(Alert.AlertType, String, String, ButtonType...)}. + * Moreover, the dialog contains a opt-out checkbox with the given text to support "Do not ask again"-behaviour. + * + * @return true if the use clicked "YES" otherwise false + */ + boolean showConfirmationDialogWithOptOutAndWait(String title, String content, + String okButtonLabel, String cancelButtonLabel, + String optOutMessage, Consumer optOutAction); + /** * This will create and display a new dialog of the specified * {@link Alert.AlertType} but with user defined buttons as optional @@ -109,7 +162,7 @@ default void showErrorDialogAndWait(Exception exception) { * @return Optional with the pressed Button as ButtonType */ Optional showCustomButtonDialogAndWait(Alert.AlertType type, String title, String content, - ButtonType... buttonTypes); + ButtonType... buttonTypes); /** * This will create and display a new dialog showing a custom {@link DialogPane} @@ -191,4 +244,5 @@ Optional showCustomButtonDialogAndWait(Alert.AlertType type, String * @return false if the user opts to cancel printing */ boolean showPrintDialog(PrinterJob job); + } diff --git a/src/main/java/org/jabref/gui/DragAndDropDataFormats.java b/src/main/java/org/jabref/gui/DragAndDropDataFormats.java index 9ffe3125c10..bee99cbd86a 100644 --- a/src/main/java/org/jabref/gui/DragAndDropDataFormats.java +++ b/src/main/java/org/jabref/gui/DragAndDropDataFormats.java @@ -9,5 +9,5 @@ public class DragAndDropDataFormats { public static final DataFormat GROUP = new DataFormat("dnd/org.jabref.model.groups.GroupTreeNode"); public static final DataFormat LINKED_FILE = new DataFormat("dnd/org.jabref.model.entry.LinkedFile"); - public static final DataFormat ENTRIES = new DataFormat("application/x-java-jvm-local-objectref"); + public static final DataFormat ENTRIES = new DataFormat("dnd/org.jabref.model.entry.BibEntries"); } diff --git a/src/main/java/org/jabref/gui/DragDropPane.java b/src/main/java/org/jabref/gui/DragDropPane.java index 4382b1cfea5..99890bce454 100644 --- a/src/main/java/org/jabref/gui/DragDropPane.java +++ b/src/main/java/org/jabref/gui/DragDropPane.java @@ -15,10 +15,11 @@ import javax.swing.JTabbedPane; import javax.swing.SwingUtilities; +import org.jabref.gui.icon.IconTheme; +import org.jabref.gui.icon.JabRefIcon; + /** * Extends the JTabbedPane class to support Drag&Drop of Tabs. - * - * @author kleinms, strassfn */ class DragDropPane extends JTabbedPane { @@ -124,14 +125,14 @@ public void mouseReleased(MouseEvent e) { static class MarkerPane extends JPanel { private Point locationP; - private final IconTheme.JabRefIcon moveTabArrow; + private final JabRefIcon moveTabArrow; public MarkerPane() { setOpaque(false); // Sets the marker fontIcon - moveTabArrow = IconTheme.JabRefIcon.MOVE_TAB_ARROW; + moveTabArrow = IconTheme.JabRefIcons.MOVE_TAB_ARROW; } @Override @@ -141,7 +142,7 @@ public void paintComponent(Graphics g) { g2.setComposite(AlphaComposite.getInstance( AlphaComposite.SRC_OVER, 0.9f)); // Set transparency g.setFont(IconTheme.FONT.deriveFont(Font.BOLD, 24f)); - g.drawString(moveTabArrow.getCode(), locationP.x - (moveTabArrow.getIcon().getIconWidth() / 2), + moveTabArrow.getSmallIcon().paintIcon(this, g, locationP.x - (moveTabArrow.getIcon().getIconWidth() / 2), locationP.y + (moveTabArrow.getIcon().getIconHeight() / 2)); } diff --git a/src/main/java/org/jabref/gui/DuplicateResolverDialog.java b/src/main/java/org/jabref/gui/DuplicateResolverDialog.java index baae8dac19a..2151be6eaa3 100644 --- a/src/main/java/org/jabref/gui/DuplicateResolverDialog.java +++ b/src/main/java/org/jabref/gui/DuplicateResolverDialog.java @@ -6,6 +6,7 @@ import javax.swing.Box; import javax.swing.JButton; +import javax.swing.JFrame; import javax.swing.JPanel; import org.jabref.gui.help.HelpAction; @@ -45,7 +46,7 @@ public enum DuplicateResolverResult { private MergeEntries me; public DuplicateResolverDialog(JabRefFrame frame, BibEntry one, BibEntry two, DuplicateResolverType type) { - super(frame, Localization.lang("Possible duplicate entries"), true, DuplicateResolverDialog.class); + super((JFrame) null, Localization.lang("Possible duplicate entries"), true, DuplicateResolverDialog.class); this.frame = frame; init(one, two, type); } diff --git a/src/main/java/org/jabref/gui/DuplicateSearch.java b/src/main/java/org/jabref/gui/DuplicateSearch.java index fd6537ea3c5..f1a1a8266e6 100644 --- a/src/main/java/org/jabref/gui/DuplicateSearch.java +++ b/src/main/java/org/jabref/gui/DuplicateSearch.java @@ -10,6 +10,7 @@ import org.jabref.JabRefGUI; import org.jabref.gui.DuplicateResolverDialog.DuplicateResolverResult; import org.jabref.gui.DuplicateResolverDialog.DuplicateResolverType; +import org.jabref.gui.actions.SimpleCommand; import org.jabref.gui.undo.NamedCompound; import org.jabref.gui.undo.UndoableInsertEntry; import org.jabref.gui.undo.UndoableRemoveEntry; @@ -20,19 +21,24 @@ import spin.Spin; -public class DuplicateSearch implements Runnable { +public class DuplicateSearch extends SimpleCommand { - private final BasePanel panel; + private final JabRefFrame frame; private List bes; private final List> duplicates = new ArrayList<>(); - - public DuplicateSearch(BasePanel bp) { - panel = bp; + public DuplicateSearch(JabRefFrame frame) { + this.frame = frame; } @Override + public void execute() { + JabRefExecutorService.INSTANCE.execute(() -> run()); + + } + public void run() { + BasePanel panel = frame.getCurrentBasePanel(); panel.output(Localization.lang("Searching for duplicates...")); @@ -125,7 +131,7 @@ public void run() { if (!toAdd.isEmpty()) { for (BibEntry entry : toAdd) { panel.getDatabase().insertEntry(entry); - ce.addEdit(new UndoableInsertEntry(panel.getDatabase(), entry, panel)); + ce.addEdit(new UndoableInsertEntry(panel.getDatabase(), entry)); } panel.markBaseChanged(); } @@ -149,6 +155,7 @@ class SearcherRunnable implements Runnable { @Override public void run() { + BasePanel panel = frame.getCurrentBasePanel(); for (int i = 0; (i < (bes.size() - 1)) && !finished; i++) { for (int j = i + 1; (j < bes.size()) && !finished; j++) { BibEntry first = bes.get(i); @@ -191,7 +198,6 @@ static class DuplicateCallBack implements CallBack { private final DuplicateResolverType dialogType; private BibEntry merged; - public DuplicateCallBack(JabRefFrame frame, BibEntry one, BibEntry two, DuplicateResolverType dialogType) { this.frame = frame; this.one = one; diff --git a/src/main/java/org/jabref/gui/EntryMarker.java b/src/main/java/org/jabref/gui/EntryMarker.java deleted file mode 100644 index 8237304aced..00000000000 --- a/src/main/java/org/jabref/gui/EntryMarker.java +++ /dev/null @@ -1,199 +0,0 @@ -package org.jabref.gui; - -import java.util.Set; -import java.util.TreeSet; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.jabref.Globals; -import org.jabref.gui.undo.NamedCompound; -import org.jabref.gui.undo.UndoableFieldChange; -import org.jabref.model.database.BibDatabase; -import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.FieldName; -import org.jabref.preferences.JabRefPreferences; - -public class EntryMarker { - - public static final int MARK_COLOR_LEVELS = 6; - public static final int MAX_MARKING_LEVEL = MARK_COLOR_LEVELS - 1; - public static final int IMPORT_MARK_LEVEL = MARK_COLOR_LEVELS; - - private static final Pattern MARK_NUMBER_PATTERN = Pattern.compile(JabRefPreferences.getInstance().MARKING_WITH_NUMBER_PATTERN); - - private EntryMarker() { - } - - /** - * @param increment whether the given increment should be added to the current one. Currently never used in JabRef. Could be used to increase marking color ("Mark in specific color"). - */ - public static void markEntry(BibEntry be, int markIncrement, boolean increment, NamedCompound ce) { - int prevMarkLevel; - String newValue = null; - if (be.hasField(FieldName.MARKED_INTERNAL)) { - String markerString = be.getField(FieldName.MARKED_INTERNAL).get(); - int index = markerString.indexOf(Globals.prefs.getWrappedUsername()); - if (index >= 0) { - // Already marked 1 for this user. - prevMarkLevel = 1; - newValue = markerString.substring(0, index) - + markerString.substring(index + Globals.prefs.getWrappedUsername().length()) - + Globals.prefs.getWrappedUsername().substring(0, - Globals.prefs.getWrappedUsername().length() - 1) - + ":" + (increment ? Math.min(MAX_MARKING_LEVEL, prevMarkLevel + markIncrement) : markIncrement) - + "]"; - } else { - Matcher m = MARK_NUMBER_PATTERN.matcher(markerString); - if (m.find()) { - try { - prevMarkLevel = Integer.parseInt(m.group(1)); - newValue = markerString.substring(0, m.start(1)) + (increment ? Math.min(MAX_MARKING_LEVEL, prevMarkLevel + markIncrement) : markIncrement) + markerString.substring(m.end(1)); - } catch (NumberFormatException ex) { - // Do nothing. - } - } - } - } - if (newValue == null) { - newValue = Globals.prefs.getWrappedUsername().substring(0, Globals.prefs.getWrappedUsername().length() - 1) + ":" + markIncrement + "]"; - } - - ce.addEdit(new UndoableFieldChange(be, FieldName.MARKED_INTERNAL, - be.getField(FieldName.MARKED_INTERNAL).orElse(null), newValue)); - be.setField(FieldName.MARKED_INTERNAL, newValue); - } - - /** - * SIDE EFFECT: Unselects given entry - */ - public static void unmarkEntry(BibEntry be, boolean onlyMaxLevel, BibDatabase database, NamedCompound ce) { - if (be.hasField(FieldName.MARKED_INTERNAL)) { - String markerString = be.getField(FieldName.MARKED_INTERNAL).get(); - if ("0".equals(markerString)) { - if (!onlyMaxLevel) { - unmarkOldStyle(be, database, ce); - } - return; - } - String newValue = null; - int index = markerString.indexOf(Globals.prefs.getWrappedUsername()); - if (index >= 0) { - // Marked 1 for this user. - if (onlyMaxLevel) { - return; - } else { - newValue = markerString.substring(0, index) - + markerString.substring(index + Globals.prefs.getWrappedUsername().length()); - } - } else { - Matcher m = MARK_NUMBER_PATTERN.matcher(markerString); - if (m.find()) { - try { - int prevMarkLevel = Integer.parseInt(m.group(1)); - if (!onlyMaxLevel || (prevMarkLevel == MARK_COLOR_LEVELS)) { - if (prevMarkLevel > 1) { - newValue = markerString.substring(0, m.start(1)) + markerString.substring(m.end(1)); - } else { - String toRemove = Globals.prefs.getWrappedUsername().substring(0, - Globals.prefs.getWrappedUsername().length() - 1) + ":1]"; - index = markerString.indexOf(toRemove); - if (index >= 0) { - newValue = markerString.substring(0, index) + markerString.substring(index + toRemove.length()); - } - } - } else { - return; - } - } catch (NumberFormatException ex) { - // Do nothing. - } - } - } - - /*int piv = 0, hit; - StringBuffer sb = new StringBuffer(); - while ((hit = s.indexOf(G047749118118 - 1110lobals.prefs.WRAPPED_USERNAME, piv)) >= 0) { - if (hit > 0) - sb.append(s.substring(piv, hit)); - piv = hit + Globals.prefs.WRAPPED_USERNAME.length(); - } - if (piv < s.length() - 1) { - sb.append(s.substring(piv)); - } - String newVal = sb.length() > 0 ? sb.toString() : null;*/ - ce.addEdit(new UndoableFieldChange(be, FieldName.MARKED_INTERNAL, - be.getField(FieldName.MARKED_INTERNAL).get(), newValue)); - if (newValue == null) { - be.clearField(FieldName.MARKED_INTERNAL); - } else { - be.setField(FieldName.MARKED_INTERNAL, newValue); - } - } - } - - /** - * An entry is marked with a "0", not in the new style with user names. We - * want to unmark it as transparently as possible. Since this shouldn't - * happen too often, we do it by scanning the "owner" fields of the entire - * database, collecting all user names. We then mark the entry for all users - * except the current one. Thus only the user who unmarks will see that it - * is unmarked, and we get rid of the old-style marking. - * - * @param be - * @param ce - */ - private static void unmarkOldStyle(BibEntry be, BibDatabase database, NamedCompound ce) { - Set owners = new TreeSet<>(); - for (BibEntry entry : database.getEntries()) { - entry.getField(FieldName.OWNER).ifPresent(owners::add); - } - owners.remove(Globals.prefs.get(JabRefPreferences.DEFAULT_OWNER)); - StringBuilder sb = new StringBuilder(); - for (Object owner : owners) { - sb.append('['); - sb.append(owner); - sb.append(']'); - } - String newVal = sb.toString(); - if (newVal.isEmpty()) { - ce.addEdit(new UndoableFieldChange(be, FieldName.MARKED_INTERNAL, - be.getField(FieldName.MARKED_INTERNAL).orElse(null), null)); - be.clearField(FieldName.MARKED_INTERNAL); - } else { - ce.addEdit(new UndoableFieldChange(be, FieldName.MARKED_INTERNAL, - be.getField(FieldName.MARKED_INTERNAL).orElse(null), newVal)); - be.setField(FieldName.MARKED_INTERNAL, newVal); - } - } - - public static int isMarked(BibEntry be) { - if (!be.hasField(FieldName.MARKED_INTERNAL)) { - return 0; - } - String s = be.getField(FieldName.MARKED_INTERNAL).get(); - if ("0".equals(s)) { - return 1; - } - int index = s.indexOf(Globals.prefs.getWrappedUsername()); - if (index >= 0) { - return 1; - } - - Matcher m = MARK_NUMBER_PATTERN.matcher(s); - if (m.find()) { - try { - return Integer.parseInt(m.group(1)); - } catch (NumberFormatException ex) { - return 1; - } - } else { - return 0; - } - - } - - public static boolean shouldMarkEntries() { - return Globals.prefs.getBoolean(JabRefPreferences.MARK_IMPORTED_ENTRIES); - } -} diff --git a/src/main/java/org/jabref/gui/EntryTypeDialog.java b/src/main/java/org/jabref/gui/EntryTypeDialog.java index 40b19ab5c94..d37d398420a 100644 --- a/src/main/java/org/jabref/gui/EntryTypeDialog.java +++ b/src/main/java/org/jabref/gui/EntryTypeDialog.java @@ -20,7 +20,6 @@ import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JLabel; -import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.SwingUtilities; @@ -66,7 +65,7 @@ public class EntryTypeDialog extends JabRefDialog implements ActionListener { public EntryTypeDialog(JabRefFrame frame) { // modal dialog - super(frame, true, EntryTypeDialog.class); + super(null, true, EntryTypeDialog.class); this.frame = frame; @@ -118,7 +117,7 @@ private JPanel createCancelButtonBarPanel() { cancel.addActionListener(this); // Make ESC close dialog, equivalent to clicking Cancel. - cancel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE_DIALOG), "close"); + cancel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE), "close"); cancel.getActionMap().put("close", cancelAction); JPanel buttons = new JPanel(); @@ -313,12 +312,11 @@ protected void done() { final BibEntry bibEntry = result.get(); if ((DuplicateCheck.containsDuplicate(frame.getCurrentBasePanel().getDatabase(), bibEntry, frame.getCurrentBasePanel().getBibDatabaseContext().getMode()).isPresent())) { //If there are duplicates starts ImportInspectionDialog - final BasePanel panel = (BasePanel) frame.getTabbedPane().getSelectedComponent(); + final BasePanel panel = frame.getCurrentBasePanel(); ImportInspectionDialog diag = new ImportInspectionDialog(frame, panel, Localization.lang("Import"), false); diag.addEntry(bibEntry); diag.entryListComplete(); - diag.setLocationRelativeTo(frame); diag.setVisible(true); diag.toFront(); } else { @@ -333,13 +331,13 @@ protected void done() { dispose(); } else if (searchID.trim().isEmpty()) { - JOptionPane.showMessageDialog(frame, Localization.lang("The given search ID was empty."), Localization.lang("Empty search ID"), JOptionPane.WARNING_MESSAGE); + frame.getDialogService().showWarningDialogAndWait(Localization.lang("Empty search ID"), + Localization.lang("The given search ID was empty.")); } else if (!fetcherException) { - JOptionPane.showMessageDialog(frame, Localization.lang("Fetcher '%0' did not find an entry for id '%1'.", fetcher.getName(), searchID) + "\n" + fetcherExceptionMessage, Localization.lang("No files found."), JOptionPane.WARNING_MESSAGE); + frame.getDialogService().showErrorDialogAndWait(Localization.lang("No files found.", + Localization.lang("Fetcher '%0' did not find an entry for id '%1'.", fetcher.getName(), searchID) + "\n" + fetcherExceptionMessage)); } else { - JOptionPane.showMessageDialog(frame, - Localization.lang("Error while fetching from %0", fetcher.getName()) + "." + "\n" + fetcherExceptionMessage, - Localization.lang("Error"), JOptionPane.ERROR_MESSAGE); + frame.getDialogService().showErrorDialogAndWait(Localization.lang("Error"), Localization.lang("Error while fetching from %0", fetcher.getName()) + "." + "\n" + fetcherExceptionMessage); } fetcherWorker = new FetcherWorker(); SwingUtilities.invokeLater(() -> { diff --git a/src/main/java/org/jabref/gui/FXDialog.java b/src/main/java/org/jabref/gui/FXDialog.java index d59ccaecda4..e577568267a 100644 --- a/src/main/java/org/jabref/gui/FXDialog.java +++ b/src/main/java/org/jabref/gui/FXDialog.java @@ -1,10 +1,5 @@ package org.jabref.gui; -import java.awt.Window; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; - -import javafx.application.Platform; import javafx.fxml.FXMLLoader; import javafx.scene.control.Alert; import javafx.scene.control.Dialog; @@ -14,17 +9,13 @@ import javafx.stage.Stage; import org.jabref.Globals; -import org.jabref.JabRefGUI; +import org.jabref.gui.icon.IconTheme; import org.jabref.gui.keyboard.KeyBinding; import org.jabref.gui.keyboard.KeyBindingRepository; /** * This class provides a super class for all dialogs implemented in JavaFX. - * It mimics the behavior of a Swing JDialog which means once a object of this class - * is shown all Swing windows will be blocked and stay in the background. Since this - * class extends from a JavaFX {@link Alert} it behaves as a normal dialog towards all - * windows in the JavaFX thread. - *

+ * * To create a custom JavaFX dialog one should create an instance of this class and set a dialog * pane through the inherited {@link Dialog#setDialogPane(DialogPane)} method. * The dialog can be shown via {@link Dialog#show()} or {@link Dialog#showAndWait()}. @@ -34,33 +25,6 @@ */ public class FXDialog extends Alert { - /** - * The WindowAdapter will be added to all Swing windows once an instance - * of this class is shown and redirects the focus towards this instance. - * The WindowAdapter will be removed once the instance of this class gets hidden. - * - */ - private final WindowAdapter fxOverSwingHelper = new WindowAdapter() { - - @Override - public void windowActivated(WindowEvent e) { - Platform.runLater(() -> { - Stage fxDialogWindow = getDialogWindow(); - fxDialogWindow.toFront(); - fxDialogWindow.requestFocus(); - }); - } - - @Override - public void windowGainedFocus(WindowEvent e) { - Platform.runLater(() -> { - Stage fxDialogWindow = getDialogWindow(); - fxDialogWindow.toFront(); - fxDialogWindow.requestFocus(); - }); - } - }; - public FXDialog(AlertType type, String title, Image image, boolean isModal) { this(type, title, isModal); setDialogIcon(image); @@ -93,17 +57,10 @@ public FXDialog(AlertType type, boolean isModal) { } else { initModality(Modality.NONE); } - dialogWindow.setOnShown(evt -> { - setSwingWindowsEnabledAndFocusable(!isModal); - setLocationRelativeToMainWindow(); - }); - dialogWindow.setOnHiding(evt -> setSwingWindowsEnabledAndFocusable(true)); - - dialogWindow.setOnCloseRequest(evt -> this.close()); dialogWindow.getScene().setOnKeyPressed(event -> { KeyBindingRepository keyBindingRepository = Globals.getKeyPrefs(); - if (keyBindingRepository.checkKeyCombinationEquality(KeyBinding.CLOSE_DIALOG, event)) { + if (keyBindingRepository.checkKeyCombinationEquality(KeyBinding.CLOSE, event)) { dialogWindow.close(); } }); @@ -113,7 +70,7 @@ public FXDialog(AlertType type) { this(type, true); } - public void setDialogIcon(Image image) { + private void setDialogIcon(Image image) { Stage fxDialogWindow = getDialogWindow(); fxDialogWindow.getIcons().add(image); } @@ -122,25 +79,4 @@ private Stage getDialogWindow() { return (Stage) getDialogPane().getScene().getWindow(); } - private void setSwingWindowsEnabledAndFocusable(boolean enabled) { - for (Window swingWindow : Window.getWindows()) { - swingWindow.setEnabled(enabled); - if (!enabled) { - swingWindow.addWindowListener(fxOverSwingHelper); - } else { - swingWindow.removeWindowListener(fxOverSwingHelper); - } - } - } - - private void setLocationRelativeToMainWindow() { - double mainWindowX = JabRefGUI.getMainFrame().getLocationOnScreen().getX(); - double mainWindowY = JabRefGUI.getMainFrame().getLocationOnScreen().getY(); - double mainWindowWidth = JabRefGUI.getMainFrame().getSize().getWidth(); - double mainWindowHeight = JabRefGUI.getMainFrame().getSize().getHeight(); - - setX((mainWindowX + (mainWindowWidth / 2)) - (getWidth() / 2)); - setY((mainWindowY + (mainWindowHeight / 2)) - (getHeight() / 2)); - } - } diff --git a/src/main/java/org/jabref/gui/FXDialogService.java b/src/main/java/org/jabref/gui/FXDialogService.java index a42523f17bf..0b25b524cd6 100644 --- a/src/main/java/org/jabref/gui/FXDialogService.java +++ b/src/main/java/org/jabref/gui/FXDialogService.java @@ -2,22 +2,29 @@ import java.io.File; import java.nio.file.Path; +import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Optional; +import java.util.function.Consumer; import java.util.stream.Collectors; import javafx.concurrent.Task; import javafx.print.PrinterJob; +import javafx.scene.Group; +import javafx.scene.Node; import javafx.scene.control.Alert.AlertType; import javafx.scene.control.Button; import javafx.scene.control.ButtonBar; import javafx.scene.control.ButtonType; +import javafx.scene.control.CheckBox; +import javafx.scene.control.ChoiceDialog; import javafx.scene.control.DialogPane; import javafx.scene.control.TextInputDialog; import javafx.scene.layout.Region; import javafx.stage.DirectoryChooser; import javafx.stage.FileChooser; +import javafx.stage.Window; import org.jabref.JabRefGUI; import org.jabref.gui.util.DirectoryDialogConfiguration; @@ -38,6 +45,20 @@ */ public class FXDialogService implements DialogService { + private final Window mainWindow; + + /** + * @deprecated try not to initialize a new dialog service but reuse the one constructed in {@link org.jabref.gui.JabRefFrame}. + */ + @Deprecated + public FXDialogService() { + this(null); + } + + public FXDialogService(Window mainWindow) { + this.mainWindow = mainWindow; + } + private static FXDialog createDialog(AlertType type, String title, String content) { FXDialog alert = new FXDialog(type, title, true); alert.setHeaderText(null); @@ -46,6 +67,50 @@ private static FXDialog createDialog(AlertType type, String title, String conten return alert; } + private static FXDialog createDialogWithOptOut(AlertType type, String title, String content, + String optOutMessage, Consumer optOutAction) { + FXDialog alert = new FXDialog(type, title, true); + // Need to force the alert to layout in order to grab the graphic as we are replacing the dialog pane with a custom pane + alert.getDialogPane().applyCss(); + Node graphic = alert.getDialogPane().getGraphic(); + + // Create a new dialog pane that has a checkbox instead of the hide/show details button + // Use the supplied callback for the action of the checkbox + alert.setDialogPane(new DialogPane() { + + @Override + protected Node createDetailsButton() { + CheckBox optOut = new CheckBox(); + optOut.setText(optOutMessage); + optOut.setOnAction(e -> optOutAction.accept(optOut.isSelected())); + return optOut; + } + }); + + // Fool the dialog into thinking there is some expandable content; a group won't take up any space if it has no children + alert.getDialogPane().setExpandableContent(new Group()); + alert.getDialogPane().setExpanded(true); + + // Reset the dialog graphic using the default style + alert.getDialogPane().setGraphic(graphic); + + alert.setHeaderText(null); + alert.setContentText(content); + alert.getDialogPane().setMinHeight(Region.USE_PREF_SIZE); + return alert; + } + + @Override + public Optional showChoiceDialogAndWait(String title, String content, String okButtonLabel, T defaultChoice, Collection choices) { + ChoiceDialog choiceDialog = new ChoiceDialog<>(defaultChoice, choices); + ButtonType okButtonType = new ButtonType(okButtonLabel, ButtonBar.ButtonData.OK_DONE); + choiceDialog.getDialogPane().getButtonTypes().setAll(ButtonType.CANCEL, okButtonType); + choiceDialog.setHeaderText(title); + choiceDialog.setContentText(content); + return choiceDialog.showAndWait(); + + } + @Override public Optional showInputDialogAndWait(String title, String content) { TextInputDialog inputDialog = new TextInputDialog(); @@ -79,6 +144,14 @@ public void showErrorDialogAndWait(String message, Throwable exception) { exceptionDialog.showAndWait(); } + @Override + public void showErrorDialogAndWait(String title, String content, Throwable exception) { + ExceptionDialog exceptionDialog = new ExceptionDialog(exception); + exceptionDialog.setHeaderText(title); + exceptionDialog.setContentText(content); + exceptionDialog.showAndWait(); + } + @Override public void showErrorDialogAndWait(String message) { FXDialog alert = createDialog(AlertType.ERROR, Localization.lang("Error Occurred"), message); @@ -100,8 +173,8 @@ public boolean showConfirmationDialogAndWait(String title, String content, Strin } @Override - public boolean showConfirmationDialogAndWait(String title, String content, String okButtonLabel, - String cancelButtonLabel) { + public boolean showConfirmationDialogAndWait(String title, String content, + String okButtonLabel, String cancelButtonLabel) { FXDialog alert = createDialog(AlertType.CONFIRMATION, title, content); ButtonType okButtonType = new ButtonType(okButtonLabel, ButtonBar.ButtonData.OK_DONE); ButtonType cancelButtonType = new ButtonType(cancelButtonLabel, ButtonBar.ButtonData.NO); @@ -109,6 +182,25 @@ public boolean showConfirmationDialogAndWait(String title, String content, Strin return alert.showAndWait().filter(buttonType -> buttonType == okButtonType).isPresent(); } + @Override + public boolean showConfirmationDialogWithOptOutAndWait(String title, String content, + String optOutMessage, Consumer optOutAction) { + FXDialog alert = createDialogWithOptOut(AlertType.CONFIRMATION, title, content, optOutMessage, optOutAction); + alert.getButtonTypes().setAll(ButtonType.YES, ButtonType.NO); + return alert.showAndWait().filter(buttonType -> buttonType == ButtonType.YES).isPresent(); + } + + @Override + public boolean showConfirmationDialogWithOptOutAndWait(String title, String content, + String okButtonLabel, String cancelButtonLabel, + String optOutMessage, Consumer optOutAction) { + FXDialog alert = createDialogWithOptOut(AlertType.CONFIRMATION, title, content, optOutMessage, optOutAction); + ButtonType okButtonType = new ButtonType(okButtonLabel, ButtonBar.ButtonData.YES); + ButtonType cancelButtonType = new ButtonType(cancelButtonLabel, ButtonBar.ButtonData.NO); + alert.getButtonTypes().setAll(okButtonType, cancelButtonType); + return alert.showAndWait().filter(buttonType -> buttonType == okButtonType).isPresent(); + } + @Override public Optional showCustomButtonDialogAndWait(AlertType type, String title, String content, ButtonType... buttonTypes) { @@ -123,6 +215,8 @@ public Optional showCustomDialogAndWait(String title, DialogPane con FXDialog alert = new FXDialog(AlertType.NONE, title); alert.setDialogPane(contentPane); alert.getButtonTypes().setAll(buttonTypes); + alert.getDialogPane().setMinHeight(Region.USE_PREF_SIZE); + alert.setResizable(true); return alert.showAndWait(); } @@ -153,7 +247,7 @@ public void notify(String message) { @Override public Optional showFileSaveDialog(FileDialogConfiguration fileDialogConfiguration) { FileChooser chooser = getConfiguredFileChooser(fileDialogConfiguration); - File file = chooser.showSaveDialog(null); + File file = chooser.showSaveDialog(mainWindow); Optional.ofNullable(chooser.getSelectedExtensionFilter()).ifPresent(fileDialogConfiguration::setSelectedExtensionFilter); return Optional.ofNullable(file).map(File::toPath); } @@ -161,7 +255,7 @@ public Optional showFileSaveDialog(FileDialogConfiguration fileDialogConfi @Override public Optional showFileOpenDialog(FileDialogConfiguration fileDialogConfiguration) { FileChooser chooser = getConfiguredFileChooser(fileDialogConfiguration); - File file = chooser.showOpenDialog(null); + File file = chooser.showOpenDialog(mainWindow); Optional.ofNullable(chooser.getSelectedExtensionFilter()).ifPresent(fileDialogConfiguration::setSelectedExtensionFilter); return Optional.ofNullable(file).map(File::toPath); } @@ -169,14 +263,14 @@ public Optional showFileOpenDialog(FileDialogConfiguration fileDialogConfi @Override public Optional showDirectorySelectionDialog(DirectoryDialogConfiguration directoryDialogConfiguration) { DirectoryChooser chooser = getConfiguredDirectoryChooser(directoryDialogConfiguration); - File file = chooser.showDialog(null); + File file = chooser.showDialog(mainWindow); return Optional.ofNullable(file).map(File::toPath); } @Override public List showFileOpenDialogAndGetMultipleFiles(FileDialogConfiguration fileDialogConfiguration) { FileChooser chooser = getConfiguredFileChooser(fileDialogConfiguration); - List files = chooser.showOpenMultipleDialog(null); + List files = chooser.showOpenMultipleDialog(mainWindow); return files != null ? files.stream().map(File::toPath).collect(Collectors.toList()) : Collections.emptyList(); } @@ -197,6 +291,6 @@ private FileChooser getConfiguredFileChooser(FileDialogConfiguration fileDialogC @Override public boolean showPrintDialog(PrinterJob job) { - return job.showPrintDialog(null); + return job.showPrintDialog(mainWindow); } } diff --git a/src/main/java/org/jabref/gui/FindUnlinkedFilesDialog.java b/src/main/java/org/jabref/gui/FindUnlinkedFilesDialog.java index aea7055cf98..7d2a77b38bf 100644 --- a/src/main/java/org/jabref/gui/FindUnlinkedFilesDialog.java +++ b/src/main/java/org/jabref/gui/FindUnlinkedFilesDialog.java @@ -95,15 +95,6 @@ */ public class FindUnlinkedFilesDialog extends JabRefDialog { - /** - * Keys to be used for referencing this Action. - */ - public static final String ACTION_COMMAND = "findUnlinkedFiles"; - public static final String ACTION_MENU_TITLE = Localization.menuTitle("Find unlinked files..."); - - public static final String ACTION_SHORT_DESCRIPTION = Localization - .lang("Searches for unlinked PDF files on the file system"); - private static final Logger LOGGER = LoggerFactory.getLogger(FindUnlinkedFilesDialog.class); private static final String GLOBAL_PREFS_WORKING_DIRECTORY_KEY = "findUnlinkedFilesWD"; @@ -167,14 +158,15 @@ public class FindUnlinkedFilesDialog extends JabRefDialog { private boolean checkBoxWhyIsThereNoGetSelectedStupidSwing; - public FindUnlinkedFilesDialog(Frame owner, JabRefFrame frame, BasePanel panel) { + public FindUnlinkedFilesDialog(Frame owner, JabRefFrame frame) { super(owner, Localization.lang("Find unlinked files"), true, FindUnlinkedFilesDialog.class); this.frame = frame; restoreSizeOfDialog(); - databaseContext = panel.getBibDatabaseContext(); + databaseContext = frame.getCurrentBasePanel().getBibDatabaseContext(); creatorManager = new EntryFromFileCreatorManager(ExternalFileTypes.getInstance()); + crawler = new UnlinkedFilesCrawler(databaseContext); lastSelectedDirectory = loadLastSelectedDirectory(); @@ -663,7 +655,7 @@ private void setupActions() { DirectoryDialogConfiguration directoryDialogConfiguration = new DirectoryDialogConfiguration.Builder() .withInitialDirectory(Globals.prefs.get(JabRefPreferences.WORKING_DIRECTORY)).build(); - DialogService ds = new FXDialogService(); + DialogService ds = frame.getDialogService(); /** * Stores the selected directory. */ @@ -1073,7 +1065,7 @@ public Component getListCellRendererComponent(JList list, Object value, int i if (value instanceof EntryFromFileCreator) { EntryFromFileCreator creator = (EntryFromFileCreator) value; if (creator.getExternalFileType() != null) { - label.setIcon(creator.getExternalFileType().getIcon()); + label.setIcon(creator.getExternalFileType().getIcon().getSmallIcon()); } } return label; @@ -1101,10 +1093,6 @@ private void createEntryTypesCombobox() { /** * Wrapper for displaying the Type {@link BibtexEntryType} in a Combobox. - * - * @author Nosh&Dan - * @version 12.11.2008 | 01:02:30 - * */ private static class BibtexEntryTypeWrapper { diff --git a/src/main/java/org/jabref/gui/GUIGlobals.java b/src/main/java/org/jabref/gui/GUIGlobals.java index 2b3ba25b364..cbfeb8dc34d 100644 --- a/src/main/java/org/jabref/gui/GUIGlobals.java +++ b/src/main/java/org/jabref/gui/GUIGlobals.java @@ -2,21 +2,10 @@ import java.awt.Color; import java.awt.Font; -import java.awt.Toolkit; -import java.util.HashMap; -import java.util.Map; - -import javax.swing.JLabel; import org.jabref.Globals; -import org.jabref.gui.externalfiletype.ExternalFileType; -import org.jabref.gui.externalfiletype.ExternalFileTypes; import org.jabref.gui.keyboard.EmacsKeyBindings; -import org.jabref.gui.specialfields.SpecialFieldViewModel; import org.jabref.logic.l10n.Localization; -import org.jabref.logic.util.OS; -import org.jabref.model.entry.FieldName; -import org.jabref.model.entry.specialfields.SpecialField; import org.jabref.preferences.JabRefPreferences; import org.slf4j.Logger; @@ -39,29 +28,15 @@ public class GUIGlobals { public static final int WIDTH_ICON_COL_RANKING = 5 * JabRefPreferences.getInstance().getInt(JabRefPreferences.ICON_SIZE_SMALL); // Width of Ranking Icon Column public static final String UNTITLED_TITLE = Localization.lang("untitled"); - public static final int MAX_BACK_HISTORY_SIZE = 10; // The maximum number of "Back" operations stored. // Colors. public static final Color ENTRY_EDITOR_LABEL_COLOR = new Color(100, 100, 150); // Empty field, blue. - static final Color INACTIVE_TABBED_COLOR = Color.black; // inactive Database private static final Logger LOGGER = LoggerFactory.getLogger(GUIGlobals.class); - private static final Map TABLE_ICONS = new HashMap<>(); // Contains table icon mappings. Set up - static final Color ACTIVE_TABBED_COLOR = ENTRY_EDITOR_LABEL_COLOR.darker(); // active Database (JTabbedPane) private GUIGlobals() { } - public static JLabel getTableIcon(String fieldType) { - JLabel label = GUIGlobals.TABLE_ICONS.get(fieldType); - if (label == null) { - LOGGER.info("Error: no table icon defined for type '" + fieldType + "'."); - return null; - } else { - return label; - } - } - public static void updateEntryEditorColors() { GUIGlobals.activeBackgroundColor = JabRefPreferences.getInstance().getColor(JabRefPreferences.ACTIVE_FIELD_EDITOR_BACKGROUND_COLOR); GUIGlobals.validFieldBackgroundColor = JabRefPreferences.getInstance().getColor(JabRefPreferences.VALID_FIELD_BACKGROUND_COLOR); @@ -75,79 +50,6 @@ public static void updateEntryEditorColors() { * on Un*x is unavailable. */ public static void init() { - JLabel label; - label = new JLabel(IconTheme.JabRefIcon.PDF_FILE.getSmallIcon()); - label.setToolTipText(Localization.lang("Open") + " PDF"); - GUIGlobals.TABLE_ICONS.put(FieldName.PDF, label); - - label = new JLabel(IconTheme.JabRefIcon.WWW.getSmallIcon()); - label.setToolTipText(Localization.lang("Open") + " URL"); - GUIGlobals.TABLE_ICONS.put(FieldName.URL, label); - - label = new JLabel(IconTheme.JabRefIcon.WWW.getSmallIcon()); - label.setToolTipText(Localization.lang("Open") + " CiteSeer URL"); - GUIGlobals.TABLE_ICONS.put("citeseerurl", label); - - label = new JLabel(IconTheme.JabRefIcon.WWW.getSmallIcon()); - label.setToolTipText(Localization.lang("Open") + " ArXiv URL"); - GUIGlobals.TABLE_ICONS.put(FieldName.EPRINT, label); - - label = new JLabel(IconTheme.JabRefIcon.DOI.getSmallIcon()); - label.setToolTipText(Localization.lang("Open") + " DOI " + Localization.lang("web link")); - GUIGlobals.TABLE_ICONS.put(FieldName.DOI, label); - - label = new JLabel(IconTheme.JabRefIcon.FILE.getSmallIcon()); - label.setToolTipText(Localization.lang("Open") + " PS"); - GUIGlobals.TABLE_ICONS.put(FieldName.PS, label); - - label = new JLabel(IconTheme.JabRefIcon.FOLDER.getSmallIcon()); - label.setToolTipText(Localization.lang("Open folder")); - GUIGlobals.TABLE_ICONS.put(FieldName.FOLDER, label); - - label = new JLabel(IconTheme.JabRefIcon.FILE.getSmallIcon()); - label.setToolTipText(Localization.lang("Open file")); - GUIGlobals.TABLE_ICONS.put(FieldName.FILE, label); - - for (ExternalFileType fileType : ExternalFileTypes.getInstance().getExternalFileTypeSelection()) { - label = new JLabel(fileType.getIcon()); - label.setToolTipText(Localization.lang("Open %0 file", fileType.getName())); - GUIGlobals.TABLE_ICONS.put(fileType.getName(), label); - } - - SpecialFieldViewModel relevanceViewModel = new SpecialFieldViewModel(SpecialField.RELEVANCE); - label = new JLabel(relevanceViewModel.getRepresentingIcon()); - label.setToolTipText(relevanceViewModel.getLocalization()); - GUIGlobals.TABLE_ICONS.put(SpecialField.RELEVANCE.getFieldName(), label); - - SpecialFieldViewModel qualityViewModel = new SpecialFieldViewModel(SpecialField.QUALITY); - label = new JLabel(qualityViewModel.getRepresentingIcon()); - label.setToolTipText(qualityViewModel.getLocalization()); - GUIGlobals.TABLE_ICONS.put(SpecialField.QUALITY.getFieldName(), label); - - // Ranking item in the menu uses one star - SpecialFieldViewModel rankViewModel = new SpecialFieldViewModel(SpecialField.RANKING); - label = new JLabel(rankViewModel.getRepresentingIcon()); - label.setToolTipText(rankViewModel.getLocalization()); - GUIGlobals.TABLE_ICONS.put(SpecialField.RANKING.getFieldName(), label); - - // Priority icon used for the menu - SpecialFieldViewModel priorityViewModel = new SpecialFieldViewModel(SpecialField.PRIORITY); - label = new JLabel(priorityViewModel.getRepresentingIcon()); - label.setToolTipText(priorityViewModel.getLocalization()); - GUIGlobals.TABLE_ICONS.put(SpecialField.PRIORITY.getFieldName(), label); - - // Read icon used for menu - SpecialFieldViewModel readViewModel = new SpecialFieldViewModel(SpecialField.READ_STATUS); - label = new JLabel(readViewModel.getRepresentingIcon()); - label.setToolTipText(readViewModel.getLocalization()); - GUIGlobals.TABLE_ICONS.put(SpecialField.READ_STATUS.getFieldName(), label); - - // Print icon used for menu - SpecialFieldViewModel printedViewModel = new SpecialFieldViewModel(SpecialField.PRINTED); - label = new JLabel(printedViewModel.getRepresentingIcon()); - label.setToolTipText(printedViewModel.getLocalization()); - GUIGlobals.TABLE_ICONS.put(SpecialField.PRINTED.getFieldName(), label); - if (Globals.prefs.getBoolean(JabRefPreferences.EDITOR_EMACS_KEYBINDINGS)) { EmacsKeyBindings.load(); } @@ -157,19 +59,6 @@ public static void init() { GUIGlobals.currentFont = new Font(Globals.prefs.get(JabRefPreferences.FONT_FAMILY), Globals.prefs.getInt(JabRefPreferences.FONT_STYLE), Globals.prefs.getInt(JabRefPreferences.FONT_SIZE)); - - // Set WM_CLASS using reflection for certain Un*x window managers - if (!OS.WINDOWS && !OS.OS_X) { - try { - Toolkit xToolkit = Toolkit.getDefaultToolkit(); - java.lang.reflect.Field awtAppClassNameField = xToolkit.getClass().getDeclaredField("awtAppClassName"); - awtAppClassNameField.setAccessible(true); - awtAppClassNameField.set(xToolkit, "org-jabref-JabRefMain"); - } catch (Exception e) { - // ignore any error since this code only works for certain toolkits - } - } - } public static void setFont(int size) { diff --git a/src/main/java/org/jabref/gui/GenFieldsCustomizer.java b/src/main/java/org/jabref/gui/GenFieldsCustomizer.java index b8b3a800b76..6bff3e65d56 100644 --- a/src/main/java/org/jabref/gui/GenFieldsCustomizer.java +++ b/src/main/java/org/jabref/gui/GenFieldsCustomizer.java @@ -6,7 +6,9 @@ import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; +import java.util.List; import java.util.Locale; +import java.util.Map; import javax.swing.AbstractAction; import javax.swing.ActionMap; @@ -14,6 +16,7 @@ import javax.swing.InputMap; import javax.swing.JButton; import javax.swing.JComponent; +import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; @@ -21,7 +24,6 @@ import javax.swing.JTextArea; import org.jabref.Globals; -import org.jabref.gui.entryeditor.EntryEditorTabList; import org.jabref.gui.help.HelpAction; import org.jabref.gui.keyboard.KeyBinding; import org.jabref.logic.bibtexkeypattern.BibtexKeyGenerator; @@ -49,7 +51,7 @@ public class GenFieldsCustomizer extends JabRefDialog { private final JButton revert = new JButton(); public GenFieldsCustomizer(JabRefFrame frame) { - super(frame, Localization.lang("Set general fields"), false, GenFieldsCustomizer.class); + super((JFrame) null, Localization.lang("Set general fields"), false, GenFieldsCustomizer.class); helpBut = new HelpAction(HelpFile.GENERAL_FIELDS).getHelpButton(); jbInit(); setSize(new Dimension(650, 300)); @@ -95,7 +97,7 @@ private void jbInit() { // Key bindings: ActionMap am = buttons.getActionMap(); InputMap im = buttons.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); - im.put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE_DIALOG), "close"); + im.put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE), "close"); am.put("close", new AbstractAction() { @Override @@ -143,11 +145,10 @@ private void okActionPerformed() { private void setFieldsText() { StringBuilder sb = new StringBuilder(); - EntryEditorTabList tabList = Globals.prefs.getEntryEditorTabList(); - for (int i = 0; i < tabList.getTabCount(); i++) { - sb.append(tabList.getTabName(i)); + for (Map.Entry> tab : Globals.prefs.getEntryEditorTabList().entrySet()) { + sb.append(tab.getKey()); sb.append(':'); - sb.append(String.join(";", tabList.getTabFields(i))); + sb.append(String.join(";", tab.getValue())); sb.append('\n'); } diff --git a/src/main/java/org/jabref/gui/JabRefFrame.java b/src/main/java/org/jabref/gui/JabRefFrame.java index 0efa554e479..fe47af976ce 100644 --- a/src/main/java/org/jabref/gui/JabRefFrame.java +++ b/src/main/java/org/jabref/gui/JabRefFrame.java @@ -1,29 +1,16 @@ package org.jabref.gui; -import java.awt.BorderLayout; import java.awt.Component; -import java.awt.Container; -import java.awt.Cursor; -import java.awt.FlowLayout; -import java.awt.Frame; -import java.awt.GraphicsEnvironment; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.Window; import java.awt.event.ActionEvent; -import java.awt.event.KeyAdapter; -import java.awt.event.MouseAdapter; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; import java.io.File; import java.io.IOException; -import java.lang.reflect.InvocationTargetException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; @@ -32,93 +19,95 @@ import java.util.Optional; import java.util.TimerTask; -import javax.swing.AbstractAction; import javax.swing.Action; -import javax.swing.Icon; -import javax.swing.JButton; -import javax.swing.JCheckBoxMenuItem; import javax.swing.JComponent; -import javax.swing.JDialog; -import javax.swing.JFrame; import javax.swing.JLabel; -import javax.swing.JMenu; -import javax.swing.JMenuBar; -import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; -import javax.swing.JPopupMenu; import javax.swing.JProgressBar; -import javax.swing.JSplitPane; -import javax.swing.JTabbedPane; -import javax.swing.JToggleButton; -import javax.swing.KeyStroke; -import javax.swing.MenuElement; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; -import javax.swing.TransferHandler; import javax.swing.UIManager; -import javax.swing.WindowConstants; import javafx.application.Platform; +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; +import javafx.collections.ListChangeListener; +import javafx.scene.Node; +import javafx.scene.control.Alert; +import javafx.scene.control.Button; +import javafx.scene.control.ButtonBar; +import javafx.scene.control.ButtonType; +import javafx.scene.control.Menu; +import javafx.scene.control.MenuBar; +import javafx.scene.control.SeparatorMenuItem; +import javafx.scene.control.SplitPane; +import javafx.scene.control.Tab; +import javafx.scene.control.TabPane; +import javafx.scene.control.ToolBar; +import javafx.scene.control.Tooltip; +import javafx.scene.input.KeyEvent; +import javafx.scene.layout.BorderPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Pane; +import javafx.scene.layout.Priority; +import javafx.stage.Stage; import org.jabref.Globals; import org.jabref.JabRefExecutorService; +import org.jabref.gui.actions.ActionFactory; import org.jabref.gui.actions.Actions; import org.jabref.gui.actions.AutoLinkFilesAction; -import org.jabref.gui.actions.ConnectToSharedDatabaseAction; +import org.jabref.gui.actions.BibtexKeyPatternAction; +import org.jabref.gui.actions.ConnectToSharedDatabaseCommand; +import org.jabref.gui.actions.CopyFilesAction; +import org.jabref.gui.actions.CustomizeEntryAction; +import org.jabref.gui.actions.CustomizeKeyBindingAction; +import org.jabref.gui.actions.DatabasePropertiesAction; +import org.jabref.gui.actions.EditExternalFileTypesAction; import org.jabref.gui.actions.ErrorConsoleAction; +import org.jabref.gui.actions.FindUnlinkedFilesAction; import org.jabref.gui.actions.IntegrityCheckAction; import org.jabref.gui.actions.LookupIdentifierAction; +import org.jabref.gui.actions.ManageCustomExportsAction; +import org.jabref.gui.actions.ManageCustomImportsAction; +import org.jabref.gui.actions.ManageJournalsAction; import org.jabref.gui.actions.ManageKeywordsAction; +import org.jabref.gui.actions.ManageProtectedTermsAction; import org.jabref.gui.actions.MassSetFieldAction; -import org.jabref.gui.actions.MnemonicAwareAction; +import org.jabref.gui.actions.MergeEntriesAction; import org.jabref.gui.actions.NewDatabaseAction; import org.jabref.gui.actions.NewEntryAction; -import org.jabref.gui.actions.NewSubDatabaseAction; +import org.jabref.gui.actions.NewEntryFromPlainTextAction; +import org.jabref.gui.actions.NewSubLibraryAction; +import org.jabref.gui.actions.OldDatabaseCommandWrapper; import org.jabref.gui.actions.OpenBrowserAction; import org.jabref.gui.actions.SearchForUpdateAction; -import org.jabref.gui.actions.SortTabsAction; -import org.jabref.gui.bibtexkeypattern.BibtexKeyPatternDialog; -import org.jabref.gui.copyfiles.CopyFilesAction; -import org.jabref.gui.customentrytypes.EntryCustomizationDialog; -import org.jabref.gui.dbproperties.DatabasePropertiesDialog; +import org.jabref.gui.actions.SetupGeneralFieldsAction; +import org.jabref.gui.actions.ShowDocumentViewerAction; +import org.jabref.gui.actions.ShowPreferencesAction; +import org.jabref.gui.actions.SimpleCommand; +import org.jabref.gui.actions.StandardActions; import org.jabref.gui.dialogs.AutosaveUIManager; -import org.jabref.gui.documentviewer.ShowDocumentViewerAction; -import org.jabref.gui.exporter.ExportAction; -import org.jabref.gui.exporter.ExportCustomizationDialog; +import org.jabref.gui.exporter.ExportCommand; import org.jabref.gui.exporter.SaveAllAction; import org.jabref.gui.exporter.SaveDatabaseAction; -import org.jabref.gui.externalfiletype.ExternalFileTypeEditor; -import org.jabref.gui.groups.EntryTableTransferHandler; -import org.jabref.gui.groups.GroupSidePane; +import org.jabref.gui.externalfiletype.ExternalFileTypes; import org.jabref.gui.help.AboutAction; import org.jabref.gui.help.HelpAction; -import org.jabref.gui.importer.ImportCustomizationDialog; -import org.jabref.gui.importer.ImportFormats; +import org.jabref.gui.importer.ImportCommand; import org.jabref.gui.importer.ImportInspectionDialog; import org.jabref.gui.importer.actions.OpenDatabaseAction; -import org.jabref.gui.importer.fetcher.GeneralFetcher; -import org.jabref.gui.journals.ManageJournalsAction; import org.jabref.gui.keyboard.KeyBinding; -import org.jabref.gui.keyboard.KeyBindingAction; -import org.jabref.gui.menus.ChangeEntryTypeMenu; import org.jabref.gui.menus.FileHistoryMenu; -import org.jabref.gui.menus.RightClickMenu; -import org.jabref.gui.openoffice.OpenOfficePanel; -import org.jabref.gui.openoffice.OpenOfficeSidePanel; -import org.jabref.gui.preftabs.PreferencesDialog; -import org.jabref.gui.protectedterms.ProtectedTermsDialog; import org.jabref.gui.push.PushToApplicationButton; import org.jabref.gui.push.PushToApplications; import org.jabref.gui.search.GlobalSearchBar; -import org.jabref.gui.specialfields.SpecialFieldDropDown; -import org.jabref.gui.specialfields.SpecialFieldValueViewModel; +import org.jabref.gui.specialfields.SpecialFieldMenuItemFactory; +import org.jabref.gui.undo.CountingUndoManager; import org.jabref.gui.util.DefaultTaskExecutor; -import org.jabref.gui.util.WindowLocation; -import org.jabref.gui.worker.MarkEntriesAction; import org.jabref.logic.autosaveandbackup.AutosaveManager; import org.jabref.logic.autosaveandbackup.BackupManager; -import org.jabref.logic.help.HelpFile; import org.jabref.logic.importer.IdFetcher; import org.jabref.logic.importer.OutputPrinter; import org.jabref.logic.importer.ParserResult; @@ -134,8 +123,8 @@ import org.jabref.model.database.BibDatabaseMode; import org.jabref.model.database.shared.DatabaseLocation; import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.BiblatexEntryTypes; import org.jabref.model.entry.BibtexEntryTypes; -import org.jabref.model.entry.EntryType; import org.jabref.model.entry.FieldName; import org.jabref.model.entry.specialfields.SpecialField; import org.jabref.preferences.JabRefPreferences; @@ -143,6 +132,9 @@ import org.jabref.preferences.SearchPreferences; import com.google.common.eventbus.Subscribe; +import org.eclipse.fx.ui.controls.tabpane.DndTabPane; +import org.eclipse.fx.ui.controls.tabpane.DndTabPaneFactory; +import org.fxmisc.easybind.EasyBind; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import osx.macadapter.MacAdapter; @@ -150,290 +142,24 @@ /** * The main window of the application. */ -public class JabRefFrame extends JFrame implements OutputPrinter { - private static final Logger LOGGER = LoggerFactory.getLogger(JabRefFrame.class); +public class JabRefFrame extends BorderPane implements OutputPrinter { // Frame titles. - private static final String FRAME_TITLE = "JabRef"; - private static final String ELLIPSES = "..."; - public final AbstractAction nextTab = new ChangeTabAction(true); - public final AbstractAction prevTab = new ChangeTabAction(false); - private final JSplitPane splitPane = new JSplitPane(); + public static final String FRAME_TITLE = "JabRef"; + + private static final Logger LOGGER = LoggerFactory.getLogger(JabRefFrame.class); + + private final SplitPane splitPane = new SplitPane(); private final JabRefPreferences prefs = Globals.prefs; - private final Insets marg = new Insets(1, 0, 2, 0); - private final IntegrityCheckAction checkIntegrity = new IntegrityCheckAction(this); - private final ToolBar tlb = new ToolBar(); private final GlobalSearchBar globalSearchBar = new GlobalSearchBar(this); - private final JMenuBar mb = new JMenuBar(); private final JLabel statusLine = new JLabel("", SwingConstants.LEFT); private final JLabel statusLabel = new JLabel( Localization.lang("Status") - + ':', SwingConstants.LEFT); + + ':', + SwingConstants.LEFT); private final JProgressBar progressBar = new JProgressBar(); private final FileHistoryMenu fileHistory = new FileHistoryMenu(prefs, this); - private final OpenDatabaseAction open = new OpenDatabaseAction(this, true); - private final EditModeAction editModeAction = new EditModeAction(); - - // Here we instantiate menu/toolbar actions. Actions regarding - // the currently open database are defined as a GeneralAction - // with a unique command string. This causes the appropriate - // BasePanel's runCommand() method to be called with that command. - // Note: GeneralAction's constructor automatically gets translations - // for the name and message strings. - private final AbstractAction quit = new CloseAction(); - private final AbstractAction keyBindingAction = new KeyBindingAction(); - private final AbstractAction newBibtexDatabaseAction = new NewDatabaseAction(this, BibDatabaseMode.BIBTEX); - private final AbstractAction newBiblatexDatabaseAction = new NewDatabaseAction(this, BibDatabaseMode.BIBLATEX); - private final AbstractAction connectToSharedDatabaseAction = new ConnectToSharedDatabaseAction(this); - private final AbstractAction newSubDatabaseAction = new NewSubDatabaseAction(this); - private final AbstractAction jabrefWebPageAction = new OpenBrowserAction("https://jabref.org", - Localization.menuTitle("Website"), Localization.lang("Opens JabRef's website"), - IconTheme.getImage("about"), IconTheme.getImage("about")); - private final AbstractAction jabrefFacebookAction = new OpenBrowserAction("https://www.facebook.com/JabRef/", - "Facebook", Localization.lang("Opens JabRef's Facebook page"), - IconTheme.JabRefIcon.FACEBOOK.getSmallIcon(), IconTheme.JabRefIcon.FACEBOOK.getIcon()); - private final AbstractAction jabrefTwitterAction = new OpenBrowserAction("https://twitter.com/jabref_org", - "Twitter", Localization.lang("Opens JabRef's Twitter page"), - IconTheme.JabRefIcon.TWITTER.getSmallIcon(), IconTheme.JabRefIcon.TWITTER.getIcon()); - private final AbstractAction jabrefBlogAction = new OpenBrowserAction("https://blog.jabref.org/", - Localization.menuTitle("Blog"), Localization.lang("Opens JabRef's blog"), - IconTheme.JabRefIcon.BLOG.getSmallIcon(), IconTheme.JabRefIcon.BLOG.getIcon()); - private final AbstractAction developmentVersionAction = new OpenBrowserAction("https://builds.jabref.org/master/", - Localization.menuTitle("Development version"), - Localization.lang("Opens a link where the current development version can be downloaded")); - private final AbstractAction changeLogAction = new OpenBrowserAction( - "https://github.com/JabRef/jabref/blob/master/CHANGELOG.md", Localization.menuTitle("View change log"), - Localization.lang("See what has been changed in the JabRef versions")); - private final AbstractAction forkMeOnGitHubAction = new OpenBrowserAction("https://github.com/JabRef/jabref", - Localization.menuTitle("Fork me on GitHub"), Localization.lang("Opens JabRef's GitHub page"), IconTheme.JabRefIcon.GITHUB.getSmallIcon(), IconTheme.JabRefIcon.GITHUB.getIcon()); - private final AbstractAction donationAction = new OpenBrowserAction("https://donations.jabref.org", - Localization.menuTitle("Donate to JabRef"), Localization.lang("Donate to JabRef"), IconTheme.JabRefIcon.DONATE.getSmallIcon(), IconTheme.JabRefIcon.DONATE.getIcon()); - private final AbstractAction openForumAction = new OpenBrowserAction("http://discourse.jabref.org/", - Localization.menuTitle("Online help forum"), Localization.lang("Online help forum"), IconTheme.JabRefIcon.FORUM.getSmallIcon(), IconTheme.JabRefIcon.FORUM.getIcon()); - private final AbstractAction help = new HelpAction(Localization.menuTitle("Online help"), Localization.lang("Online help"), - HelpFile.CONTENTS, Globals.getKeyPrefs().getKey(KeyBinding.HELP)); - private final AbstractAction about = new AboutAction(Localization.menuTitle("About JabRef"), Localization.lang("About JabRef"), - IconTheme.getImage("about")); - private final AbstractAction editEntry = new GeneralAction(Actions.EDIT, Localization.menuTitle("Edit entry"), - Localization.lang("Edit entry"), Globals.getKeyPrefs().getKey(KeyBinding.EDIT_ENTRY), IconTheme.JabRefIcon.EDIT_ENTRY.getIcon()); - private final AbstractAction focusTable = new GeneralAction(Actions.FOCUS_TABLE, - Localization.menuTitle("Focus entry table"), - Localization.lang("Move the keyboard focus to the entry table"), Globals.getKeyPrefs().getKey(KeyBinding.FOCUS_ENTRY_TABLE)); - private final AbstractAction save = new GeneralAction(Actions.SAVE, Localization.menuTitle("Save library"), - Localization.lang("Save library"), Globals.getKeyPrefs().getKey(KeyBinding.SAVE_DATABASE), IconTheme.JabRefIcon.SAVE.getIcon()); - private final AbstractAction saveAs = new GeneralAction(Actions.SAVE_AS, - Localization.menuTitle("Save library as..."), Localization.lang("Save library as..."), - Globals.getKeyPrefs().getKey(KeyBinding.SAVE_DATABASE_AS)); - private final AbstractAction saveAll = new SaveAllAction(JabRefFrame.this); - private final AbstractAction saveSelectedAs = new GeneralAction(Actions.SAVE_SELECTED_AS, - Localization.menuTitle("Save selected as..."), Localization.lang("Save selected as...")); - private final AbstractAction saveSelectedAsPlain = new GeneralAction(Actions.SAVE_SELECTED_AS_PLAIN, - Localization.menuTitle("Save selected as plain BibTeX..."), - Localization.lang("Save selected as plain BibTeX...")); - private final AbstractAction importCurrent = ImportFormats.getImportAction(this, false); - private final AbstractAction importNew = ImportFormats.getImportAction(this, true); - private final AbstractAction sortTabs = new SortTabsAction(this); - private final AbstractAction undo = new GeneralAction(Actions.UNDO, Localization.menuTitle("Undo"), - Localization.lang("Undo"), Globals.getKeyPrefs().getKey(KeyBinding.UNDO), IconTheme.JabRefIcon.UNDO.getIcon()); - private final AbstractAction redo = new GeneralAction(Actions.REDO, Localization.menuTitle("Redo"), - Localization.lang("Redo"), Globals.getKeyPrefs().getKey(KeyBinding.REDO), IconTheme.JabRefIcon.REDO.getIcon()); - private final AbstractAction forward = new GeneralAction(Actions.FORWARD, Localization.menuTitle("Forward"), - Localization.lang("Forward"), Globals.getKeyPrefs().getKey(KeyBinding.FORWARD), IconTheme.JabRefIcon.RIGHT.getIcon()); - private final AbstractAction back = new GeneralAction(Actions.BACK, Localization.menuTitle("Back"), - Localization.lang("Back"), Globals.getKeyPrefs().getKey(KeyBinding.BACK), IconTheme.JabRefIcon.LEFT.getIcon()); - private final AbstractAction deleteEntry = new GeneralAction(Actions.DELETE, Localization.menuTitle("Delete entry"), - Localization.lang("Delete entry"), Globals.getKeyPrefs().getKey(KeyBinding.DELETE_ENTRY), IconTheme.JabRefIcon.DELETE_ENTRY.getIcon()); - private final AbstractAction copy = new EditAction(Actions.COPY, Localization.menuTitle("Copy"), - Localization.lang("Copy"), Globals.getKeyPrefs().getKey(KeyBinding.COPY), IconTheme.JabRefIcon.COPY.getIcon()); - private final AbstractAction paste = new EditAction(Actions.PASTE, Localization.menuTitle("Paste"), - Localization.lang("Paste"), Globals.getKeyPrefs().getKey(KeyBinding.PASTE), IconTheme.JabRefIcon.PASTE.getIcon()); - private final AbstractAction cut = new EditAction(Actions.CUT, Localization.menuTitle("Cut"), - Localization.lang("Cut"), Globals.getKeyPrefs().getKey(KeyBinding.CUT), IconTheme.JabRefIcon.CUT.getIcon()); - private final AbstractAction openConsole = new GeneralAction(Actions.OPEN_CONSOLE, - Localization.menuTitle("Open terminal here"), - Localization.lang("Open terminal here"), - Globals.getKeyPrefs().getKey(KeyBinding.OPEN_CONSOLE), - IconTheme.JabRefIcon.CONSOLE.getIcon()); - private final AbstractAction pullChangesFromSharedDatabase = new GeneralAction(Actions.PULL_CHANGES_FROM_SHARED_DATABASE, - Localization.menuTitle("Pull changes from shared database"), - Localization.lang("Pull changes from shared database"), - Globals.getKeyPrefs().getKey(KeyBinding.PULL_CHANGES_FROM_SHARED_DATABASE), - IconTheme.JabRefIcon.PULL.getIcon()); - private final AbstractAction mark = new GeneralAction(Actions.MARK_ENTRIES, Localization.menuTitle("Mark entries"), - Localization.lang("Mark entries"), Globals.getKeyPrefs().getKey(KeyBinding.MARK_ENTRIES), IconTheme.JabRefIcon.MARK_ENTRIES.getIcon()); - private final JMenu markSpecific = JabRefFrame.subMenu(Localization.menuTitle("Mark specific color")); - private final AbstractAction unmark = new GeneralAction(Actions.UNMARK_ENTRIES, - Localization.menuTitle("Unmark entries"), Localization.lang("Unmark entries"), - Globals.getKeyPrefs().getKey(KeyBinding.UNMARK_ENTRIES), IconTheme.JabRefIcon.UNMARK_ENTRIES.getIcon()); - private final AbstractAction unmarkAll = new GeneralAction(Actions.UNMARK_ALL, Localization.menuTitle("Unmark all")); - private final AbstractAction toggleRelevance = new GeneralAction( - new SpecialFieldValueViewModel(SpecialField.RELEVANCE.getValues().get(0)).getActionName(), - new SpecialFieldValueViewModel(SpecialField.RELEVANCE.getValues().get(0)).getMenuString(), - new SpecialFieldValueViewModel(SpecialField.RELEVANCE.getValues().get(0)).getToolTipText(), - IconTheme.JabRefIcon.RELEVANCE.getIcon()); - private final AbstractAction toggleQualityAssured = new GeneralAction( - new SpecialFieldValueViewModel(SpecialField.QUALITY.getValues().get(0)).getActionName(), - new SpecialFieldValueViewModel(SpecialField.QUALITY.getValues().get(0)).getMenuString(), - new SpecialFieldValueViewModel(SpecialField.QUALITY.getValues().get(0)).getToolTipText(), - IconTheme.JabRefIcon.QUALITY_ASSURED.getIcon()); - private final AbstractAction togglePrinted = new GeneralAction( - new SpecialFieldValueViewModel(SpecialField.PRINTED.getValues().get(0)).getActionName(), - new SpecialFieldValueViewModel(SpecialField.PRINTED.getValues().get(0)).getMenuString(), - new SpecialFieldValueViewModel(SpecialField.PRINTED.getValues().get(0)).getToolTipText(), - IconTheme.JabRefIcon.PRINTED.getIcon()); - private final AbstractAction normalSearch = new GeneralAction(Actions.SEARCH, Localization.menuTitle("Search"), - Localization.lang("Search"), Globals.getKeyPrefs().getKey(KeyBinding.SEARCH), IconTheme.JabRefIcon.SEARCH.getIcon()); - private final AbstractAction manageSelectors = new GeneralAction(Actions.MANAGE_SELECTORS, - Localization.menuTitle("Manage content selectors")); - private final AbstractAction copyPreview = new GeneralAction(Actions.COPY_CITATION_HTML, Localization.lang("Copy preview"), - Globals.getKeyPrefs().getKey(KeyBinding.COPY_PREVIEW)); - private final AbstractAction copyTitle = new GeneralAction(Actions.COPY_TITLE, Localization.menuTitle("Copy title"), - Globals.getKeyPrefs().getKey(KeyBinding.COPY_TITLE)); - private final AbstractAction copyKey = new GeneralAction(Actions.COPY_KEY, Localization.menuTitle("Copy BibTeX key"), - Globals.getKeyPrefs().getKey(KeyBinding.COPY_BIBTEX_KEY)); - private final AbstractAction copyCiteKey = new GeneralAction(Actions.COPY_CITE_KEY, Localization.menuTitle( - "Copy \\cite{BibTeX key}"), - Globals.getKeyPrefs().getKey(KeyBinding.COPY_CITE_BIBTEX_KEY)); - private final AbstractAction copyKeyAndTitle = new GeneralAction(Actions.COPY_KEY_AND_TITLE, - Localization.menuTitle("Copy BibTeX key and title"), - Globals.getKeyPrefs().getKey(KeyBinding.COPY_BIBTEX_KEY_AND_TITLE)); - private final AbstractAction copyKeyAndLink = new GeneralAction(Actions.COPY_KEY_AND_LINK, - Localization.menuTitle("Copy BibTeX key and link"), - Globals.getKeyPrefs().getKey(KeyBinding.COPY_BIBTEX_KEY_AND_LINK)); - private final AbstractAction mergeDatabaseAction = new GeneralAction(Actions.MERGE_DATABASE, - Localization.menuTitle("Append library"), - Localization.lang("Append contents from a BibTeX library into the currently viewed library")); - private final AbstractAction selectAll = new GeneralAction(Actions.SELECT_ALL, Localization.menuTitle("Select all"), - Globals.getKeyPrefs().getKey(KeyBinding.SELECT_ALL)); - private final AbstractAction replaceAll = new GeneralAction(Actions.REPLACE_ALL, - Localization.menuTitle("Replace string") + ELLIPSES, Globals.getKeyPrefs().getKey(KeyBinding.REPLACE_STRING)); - private final AbstractAction editPreamble = new GeneralAction(Actions.EDIT_PREAMBLE, - Localization.menuTitle("Edit preamble"), - Localization.lang("Edit preamble")); - private final AbstractAction editStrings = new GeneralAction(Actions.EDIT_STRINGS, - Localization.menuTitle("Edit strings"), - Localization.lang("Edit strings"), - Globals.getKeyPrefs().getKey(KeyBinding.EDIT_STRINGS), - IconTheme.JabRefIcon.EDIT_STRINGS.getIcon()); - private final AbstractAction customizeAction = new CustomizeEntryTypeAction(); - private final Action toggleToolbar = enableToggle(new AbstractAction(Localization.menuTitle("Hide/show toolbar")) { - - { - putValue(Action.SHORT_DESCRIPTION, Localization.lang("Hide/show toolbar")); - } - @Override - public void actionPerformed(ActionEvent e) { - tlb.setVisible(!tlb.isVisible()); - } - }); - private final AbstractAction showPdvViewer = new ShowDocumentViewerAction(); - private final AbstractAction addToGroup = new GeneralAction(Actions.ADD_TO_GROUP, Localization.lang("Add to group") + ELLIPSES); - private final AbstractAction removeFromGroup = new GeneralAction(Actions.REMOVE_FROM_GROUP, - Localization.lang("Remove from group") + ELLIPSES); - private final AbstractAction moveToGroup = new GeneralAction(Actions.MOVE_TO_GROUP, Localization.lang("Move to group") + ELLIPSES); - private final Action togglePreview = enableToggle(new GeneralAction(Actions.TOGGLE_PREVIEW, - Localization.menuTitle("Toggle entry preview"), - Localization.lang("Toggle entry preview"), - Globals.getKeyPrefs().getKey(KeyBinding.TOGGLE_ENTRY_PREVIEW), - IconTheme.JabRefIcon.TOGGLE_ENTRY_PREVIEW.getIcon())); - private final AbstractAction nextPreviewStyle = new GeneralAction(Actions.NEXT_PREVIEW_STYLE, - Localization.menuTitle("Next preview layout"), - Globals.getKeyPrefs().getKey(KeyBinding.NEXT_PREVIEW_LAYOUT)); - private final AbstractAction previousPreviewStyle = new GeneralAction(Actions.PREVIOUS_PREVIEW_STYLE, - Localization.menuTitle("Previous preview layout"), - Globals.getKeyPrefs().getKey(KeyBinding.PREVIOUS_PREVIEW_LAYOUT)); - private final AbstractAction makeKeyAction = new GeneralAction(Actions.MAKE_KEY, - Localization.menuTitle("Autogenerate BibTeX keys"), - Localization.lang("Autogenerate BibTeX keys"), - Globals.getKeyPrefs().getKey(KeyBinding.AUTOGENERATE_BIBTEX_KEYS), - IconTheme.JabRefIcon.MAKE_KEY.getIcon()); - private final AbstractAction writeXmpAction = new GeneralAction(Actions.WRITE_XMP, - Localization.menuTitle("Write XMP-metadata to PDFs"), - Localization.lang("Will write XMP-metadata to the PDFs linked from selected entries."), - Globals.getKeyPrefs().getKey(KeyBinding.WRITE_XMP)); - private final AbstractAction openFolder = new GeneralAction(Actions.OPEN_FOLDER, - Localization.menuTitle("Open folder"), Localization.lang("Open folder"), - Globals.getKeyPrefs().getKey(KeyBinding.OPEN_FOLDER)); - private final AbstractAction openFile = new GeneralAction(Actions.OPEN_EXTERNAL_FILE, - Localization.menuTitle("Open file"), - Localization.lang("Open file"), - Globals.getKeyPrefs().getKey(KeyBinding.OPEN_FILE), - IconTheme.JabRefIcon.FILE.getIcon()); - private final AbstractAction openUrl = new GeneralAction(Actions.OPEN_URL, - Localization.menuTitle("Open URL or DOI"), - Localization.lang("Open URL or DOI"), - Globals.getKeyPrefs().getKey(KeyBinding.OPEN_URL_OR_DOI), - IconTheme.JabRefIcon.WWW.getIcon()); - private final AbstractAction dupliCheck = new GeneralAction(Actions.DUPLI_CHECK, - Localization.menuTitle("Find duplicates"), IconTheme.JabRefIcon.FIND_DUPLICATES.getIcon()); - private final AbstractAction plainTextImport = new GeneralAction(Actions.PLAIN_TEXT_IMPORT, - Localization.menuTitle("New entry from plain text") + ELLIPSES, - Globals.getKeyPrefs().getKey(KeyBinding.NEW_FROM_PLAIN_TEXT)); - private final AbstractAction customExpAction = new CustomizeExportsAction(); - private final AbstractAction customImpAction = new CustomizeImportsAction(); - private final AbstractAction customFileTypesAction = ExternalFileTypeEditor.getAction(this); - private final AbstractAction exportToClipboard = new GeneralAction(Actions.EXPORT_TO_CLIPBOARD, - Localization.menuTitle("Export selected entries to clipboard"), - IconTheme.JabRefIcon.EXPORT_TO_CLIPBOARD.getIcon()); - private final AbstractAction autoSetFile = new GeneralAction(Actions.AUTO_SET_FILE, - Localization.lang("Synchronize file links") + ELLIPSES, - Globals.getKeyPrefs().getKey(KeyBinding.SYNCHRONIZE_FILES)); - private final AbstractAction abbreviateMedline = new GeneralAction(Actions.ABBREVIATE_MEDLINE, - Localization.menuTitle("Abbreviate journal names (MEDLINE)"), - Localization.lang("Abbreviate journal names of the selected entries (MEDLINE abbreviation)")); - private final AbstractAction abbreviateIso = new GeneralAction(Actions.ABBREVIATE_ISO, - Localization.menuTitle("Abbreviate journal names (ISO)"), - Localization.lang("Abbreviate journal names of the selected entries (ISO abbreviation)"), - Globals.getKeyPrefs().getKey(KeyBinding.ABBREVIATE)); - private final AbstractAction unabbreviate = new GeneralAction(Actions.UNABBREVIATE, - Localization.menuTitle("Unabbreviate journal names"), - Localization.lang("Unabbreviate journal names of the selected entries"), - Globals.getKeyPrefs().getKey(KeyBinding.UNABBREVIATE)); - private final AbstractAction exportLinkedFiles = new CopyFilesAction(); - private final AbstractAction manageJournals = new ManageJournalsAction(); - private final AbstractAction databaseProperties = new DatabasePropertiesAction(); - private final AbstractAction bibtexKeyPattern = new BibtexKeyPatternAction(); - private final AbstractAction errorConsole = new ErrorConsoleAction(); - private final AbstractAction cleanupEntries = new GeneralAction(Actions.CLEANUP, - Localization.menuTitle("Cleanup entries") + ELLIPSES, - Localization.lang("Cleanup entries"), - Globals.getKeyPrefs().getKey(KeyBinding.CLEANUP), - IconTheme.JabRefIcon.CLEANUP_ENTRIES.getIcon()); - private final AbstractAction mergeEntries = new GeneralAction(Actions.MERGE_ENTRIES, - Localization.menuTitle("Merge entries") + ELLIPSES, - Localization.lang("Merge entries"), - IconTheme.JabRefIcon.MERGE_ENTRIES.getIcon()); - private final AbstractAction downloadFullText = new GeneralAction(Actions.DOWNLOAD_FULL_TEXT, - Localization.menuTitle("Look up full text documents"), - Globals.getKeyPrefs().getKey(KeyBinding.DOWNLOAD_FULL_TEXT)); - private final AbstractAction increaseFontSize = new IncreaseTableFontSizeAction(); - private final AbstractAction defaultFontSize = new DefaultTableFontSizeAction(); - private final AbstractAction decreseFontSize = new DecreaseTableFontSizeAction(); - private final AbstractAction resolveDuplicateKeys = new GeneralAction(Actions.RESOLVE_DUPLICATE_KEYS, - Localization.menuTitle("Resolve duplicate BibTeX keys"), - Localization.lang("Find and remove duplicate BibTeX keys"), - Globals.getKeyPrefs().getKey(KeyBinding.RESOLVE_DUPLICATE_BIBTEX_KEYS)); - private final AbstractAction sendAsEmail = new GeneralAction(Actions.SEND_AS_EMAIL, - Localization.lang("Send as email"), IconTheme.JabRefIcon.EMAIL.getIcon()); - private final MassSetFieldAction massSetField = new MassSetFieldAction(this); - private final ManageKeywordsAction manageKeywords = new ManageKeywordsAction(this); - private final JMenu lookupIdentifiers = JabRefFrame.subMenu(Localization.menuTitle("Look up document identifier...")); - private final GeneralAction findUnlinkedFiles = new GeneralAction( - FindUnlinkedFilesDialog.ACTION_COMMAND, - FindUnlinkedFilesDialog.ACTION_MENU_TITLE, FindUnlinkedFilesDialog.ACTION_SHORT_DESCRIPTION, - Globals.getKeyPrefs().getKey(KeyBinding.FIND_UNLINKED_FILES) - ); - private final AutoLinkFilesAction autoLinkFile = new AutoLinkFilesAction(); - // The action for adding a new entry of unspecified type. - private final NewEntryAction newEntryAction = new NewEntryAction(this, Globals.getKeyPrefs().getKey(KeyBinding.NEW_ENTRY)); - private final List newSpecificEntryAction = getNewEntryActions(); - // The action for closing the current database and leaving the window open. - private final CloseDatabaseAction closeDatabaseAction = new CloseDatabaseAction(); - private final CloseAllDatabasesAction closeAllDatabasesAction = new CloseAllDatabasesAction(); - private final CloseOtherDatabasesAction closeOtherDatabasesAction = new CloseOtherDatabasesAction(); - // The action for opening the preferences dialog. - private final AbstractAction showPrefs = new ShowPrefsAction(); // Lists containing different subsets of actions for different purposes private final List specialFieldButtons = new LinkedList<>(); private final List openDatabaseOnlyActions = new LinkedList<>(); @@ -446,52 +172,19 @@ public void actionPerformed(ActionEvent e) { private final List oneEntryWithURLorDOIOnlyActions = new LinkedList<>(); private final List twoEntriesOnlyActions = new LinkedList<>(); private final List atLeastOneEntryActions = new LinkedList<>(); - private PreferencesDialog prefsDialog; - private int lastTabbedPanelSelectionIndex = -1; + private final Stage mainStage; // The sidepane manager takes care of populating the sidepane. private SidePaneManager sidePaneManager; - private JTabbedPane tabbedPane; // initialized at constructor - private final AbstractAction exportAll = ExportAction.getExportAction(this, false); - private final AbstractAction exportSelected = ExportAction.getExportAction(this, true); - /* References to the toggle buttons in the toolbar */ - private JToggleButton previewToggle; - private JMenu rankSubMenu; - private PushToApplicationButton pushExternalButton; + private TabPane tabbedPane; private PushToApplications pushApplications; - private GeneralFetcher generalFetcher; - private OpenOfficePanel openOfficePanel; - private GroupSidePane groupSidePane; - private int previousTabCount = -1; - private JMenu newSpec; + private final CountingUndoManager undoManager = new CountingUndoManager(); + private final DialogService dialogService; + private SidePane sidePane; - public JabRefFrame() { + public JabRefFrame(Stage mainStage) { + this.mainStage = mainStage; + this.dialogService = new FXDialogService(mainStage); init(); - updateEnabledState(); - } - - private static Action enableToggle(Action a, boolean initialValue) { - // toggle only works correctly when the SELECTED_KEY is set to false or true explicitly upon start - a.putValue(Action.SELECTED_KEY, String.valueOf(initialValue)); - - return a; - } - - private static Action enableToggle(Action a) { - return enableToggle(a, false); - } - - public static JMenu subMenu(String name) { - int i = name.indexOf('&'); - JMenu res; - if (i >= 0) { - res = new JMenu(name.substring(0, i) + name.substring(i + 1)); - char mnemonic = Character.toUpperCase(name.charAt(i + 1)); - res.setMnemonic((int) mnemonic); - } else { - res = new JMenu(name); - } - - return res; } /** @@ -517,95 +210,34 @@ private static void setEnabled(List list, boolean enabled) { } } - private List getNewEntryActions() { - // only Bibtex - List actions = new ArrayList<>(); - for (EntryType type : BibtexEntryTypes.ALL) { - KeyStroke keyStroke = new ChangeEntryTypeMenu().entryShortCuts.get(type.getName()); - if (keyStroke == null) { - actions.add(new NewEntryAction(this, type.getName())); - } else { - actions.add(new NewEntryAction(this, type.getName(), keyStroke)); - } - } - return actions; - } - - private JPopupMenu tabPopupMenu() { - JPopupMenu popupMenu = new JPopupMenu(); - - // Close actions - JMenuItem close = new JMenuItem(Localization.lang("Close")); - JMenuItem closeOthers = new JMenuItem(Localization.lang("Close others")); - JMenuItem closeAll = new JMenuItem(Localization.lang("Close all")); - close.addActionListener(closeDatabaseAction); - closeOthers.addActionListener(closeOtherDatabasesAction); - closeAll.addActionListener(closeAllDatabasesAction); - popupMenu.add(close); - popupMenu.add(closeOthers); - popupMenu.add(closeAll); - - popupMenu.addSeparator(); - - JMenuItem databasePropertiesMenu = new JMenuItem(Localization.lang("Library properties")); - databasePropertiesMenu.addActionListener(this.databaseProperties); - popupMenu.add(databasePropertiesMenu); - - JMenuItem bibtexKeyPatternBtn = new JMenuItem(Localization.lang("BibTeX key patterns")); - bibtexKeyPatternBtn.addActionListener(bibtexKeyPattern); - popupMenu.add(bibtexKeyPatternBtn); - - return popupMenu; - } - private void init() { + sidePaneManager = new SidePaneManager(Globals.prefs, this); + sidePane = sidePaneManager.getPane(); - tabbedPane = new DragDropPopupPane(tabPopupMenu()); - - MyGlassPane glassPane = new MyGlassPane(); - setGlassPane(glassPane); - - setTitle(FRAME_TITLE); - setIconImages(IconTheme.getLogoSet()); - setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); - addWindowListener(new WindowAdapter() { - - @Override - public void windowClosing(WindowEvent e) { - - if (OS.OS_X) { - JabRefFrame.this.setVisible(false); - } else { - new CloseAction().actionPerformed(null); - } - } - }); - - initSidePane(); + Pane containerPane = DndTabPaneFactory.createDefaultDnDPane(DndTabPaneFactory.FeedbackType.MARKER, null); + tabbedPane = (DndTabPane) containerPane.getChildren().get(0); initLayout(); initActions(); - // Show the toolbar if it was visible at last shutdown: - tlb.setVisible(Globals.prefs.getBoolean(JabRefPreferences.TOOLBAR_VISIBLE)); - - setBounds(GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds()); - WindowLocation pw = new WindowLocation(this, JabRefPreferences.POS_X, JabRefPreferences.POS_Y, JabRefPreferences.SIZE_X, - JabRefPreferences.SIZE_Y); - pw.displayWindowAtStoredLocation(); + initKeyBindings(); - tabbedPane.setBorder(null); - tabbedPane.setForeground(GUIGlobals.INACTIVE_TABBED_COLOR); + //setBounds(GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds()); + //WindowLocation pw = new WindowLocation(this, JabRefPreferences.POS_X, JabRefPreferences.POS_Y, JabRefPreferences.SIZE_X, + // JabRefPreferences.SIZE_Y); + //pw.displayWindowAtStoredLocation(); /* * The following state listener makes sure focus is registered with the * correct database when the user switches tabs. Without this, * cut/paste/copy operations would some times occur in the wrong tab. */ - tabbedPane.addChangeListener(e -> { - - markActiveBasePanel(); + EasyBind.subscribe(tabbedPane.getSelectionModel().selectedItemProperty(), e -> { + if (e == null) { + Globals.stateManager.activeDatabaseProperty().setValue(Optional.empty()); + return; + } BasePanel currentBasePanel = getCurrentBasePanel(); if (currentBasePanel == null) { @@ -614,9 +246,7 @@ public void windowClosing(WindowEvent e) { // Poor-mans binding to global state // We need to invoke this in the JavaFX thread as all the listeners sit there - Platform.runLater(() -> - Globals.stateManager.activeDatabaseProperty().setValue(Optional.of(currentBasePanel.getBibDatabaseContext())) - ); + Platform.runLater(() -> Globals.stateManager.activeDatabaseProperty().setValue(Optional.of(currentBasePanel.getBibDatabaseContext()))); if (new SearchPreferences(Globals.prefs).isGlobalSearch()) { globalSearchBar.performSearch(); } else { @@ -628,19 +258,18 @@ public void windowClosing(WindowEvent e) { globalSearchBar.setSearchTerm(content); } - currentBasePanel.getPreviewPanel().updateLayout(); + currentBasePanel.getPreviewPanel().updateLayout(Globals.prefs.getPreviewPreferences()); - groupSidePane.getToggleAction().setSelected(sidePaneManager.isComponentVisible(GroupSidePane.class)); - previewToggle.setSelected(Globals.prefs.getPreviewPreferences().isPreviewPanelEnabled()); - generalFetcher.getToggleAction().setSelected(sidePaneManager.isComponentVisible(GeneralFetcher.class)); - openOfficePanel.getToggleAction().setSelected(sidePaneManager.isComponentVisible(OpenOfficeSidePanel.class)); - Globals.getFocusListener().setFocused(currentBasePanel.getMainTable()); + // groupSidePane.getToggleCommand().setSelected(sidePaneManager.isComponentVisible(GroupSidePane.class)); + //previewToggle.setSelected(Globals.prefs.getPreviewPreferences().isPreviewPanelEnabled()); + //generalFetcher.getToggleCommand().setSelected(sidePaneManager.isComponentVisible(GeneralFetcher.class)); + //openOfficePanel.getToggleCommand().setSelected(sidePaneManager.isComponentVisible(OpenOfficeSidePanel.class)); + // TODO: Can't notify focus listener since it is expecting a swing component + //Globals.getFocusListener().setFocused(currentBasePanel.getMainTable()); setWindowTitle(); - editModeAction.initName(); // Update search autocompleter with information for the correct database: currentBasePanel.updateSearchManager(); - // Set correct enabled state for Back and Forward actions: - currentBasePanel.setBackAndForwardEnabledState(); + currentBasePanel.getUndoManager().postUndoRedoEvent(); currentBasePanel.getMainTable().requestFocus(); }); @@ -657,6 +286,42 @@ public void windowClosing(WindowEvent e) { } initShowTrackingNotification(); + + } + + private void initKeyBindings() { + addEventFilter(KeyEvent.KEY_PRESSED, event -> { + Optional keyBinding = Globals.getKeyPrefs().mapToKeyBinding(event); + if (keyBinding.isPresent()) { + switch (keyBinding.get()) { + case FOCUS_ENTRY_TABLE: + getCurrentBasePanel().getMainTable().requestFocus(); + event.consume(); + break; + case NEXT_LIBRARY: + tabbedPane.getSelectionModel().selectNext(); + event.consume(); + break; + case PREVIOUS_LIBRARY: + tabbedPane.getSelectionModel().selectPrevious(); + event.consume(); + break; + case INCREASE_TABLE_FONT_SIZE: + increaseTableFontSize(); + event.consume(); + break; + case DECREASE_TABLE_FONT_SIZE: + decreaseTableFontSize(); + event.consume(); + break; + case DEFAULT_TABLE_FONT_SIZE: + setDefaultTableFontSize(); + event.consume(); + break; + default: + } + } + }); } private void initShowTrackingNotification() { @@ -675,7 +340,6 @@ public void run() { private Void showTrackingNotification() { if (!Globals.prefs.shouldCollectTelemetry()) { - DialogService dialogService = new FXDialogService(); boolean shouldCollect = dialogService.showConfirmationDialogAndWait( Localization.lang("Telemetry: Help make JabRef better"), Localization.lang("To improve the user experience, we would like to collect anonymous statistics on the features you use. We will only record what features you access and how often you do it. We will neither collect any personal data nor the content of bibliographic items. If you choose to allow data collection, you can later disable it via Options -> Preferences -> General."), @@ -690,8 +354,11 @@ private Void showTrackingNotification() { } public void refreshTitleAndTabs() { - setWindowTitle(); - updateAllTabTitles(); + DefaultTaskExecutor.runInJavaFXThread(() -> { + + setWindowTitle(); + updateAllTabTitles(); + }); } /** @@ -702,7 +369,7 @@ public void setWindowTitle() { // no database open if (panel == null) { - setTitle(FRAME_TITLE); + //setTitle(FRAME_TITLE); return; } @@ -712,25 +379,17 @@ public void setWindowTitle() { if (panel.getBibDatabaseContext().getLocation() == DatabaseLocation.LOCAL) { String changeFlag = panel.isModified() && !isAutosaveEnabled ? "*" : ""; - String databaseFile = panel.getBibDatabaseContext().getDatabaseFile().map(File::getPath) + String databaseFile = panel.getBibDatabaseContext() + .getDatabaseFile() + .map(File::getPath) .orElse(GUIGlobals.UNTITLED_TITLE); - setTitle(FRAME_TITLE + " - " + databaseFile + changeFlag + modeInfo); + //setTitle(FRAME_TITLE + " - " + databaseFile + changeFlag + modeInfo); } else if (panel.getBibDatabaseContext().getLocation() == DatabaseLocation.SHARED) { - setTitle(FRAME_TITLE + " - " + panel.getBibDatabaseContext().getDBMSSynchronizer().getDBName() + " [" - + Localization.lang("shared") + "]" + modeInfo); + //setTitle(FRAME_TITLE + " - " + panel.getBibDatabaseContext().getDBMSSynchronizer().getDBName() + " [" + // + Localization.lang("shared") + "]" + modeInfo); } } - private void initSidePane() { - sidePaneManager = new SidePaneManager(this); - - groupSidePane = new GroupSidePane(this, sidePaneManager); - openOfficePanel = new OpenOfficePanel(this, sidePaneManager); - generalFetcher = new GeneralFetcher(this, sidePaneManager); - - sidePaneManager.register(groupSidePane); - } - /** * The MacAdapter calls this method when a "BIB" file has been double-clicked from the Finder. */ @@ -740,27 +399,11 @@ public void openAction(String filePath) { getOpenDatabaseAction().openFile(file, true); } - // General info dialog. The MacAdapter calls this method when "About" - // is selected from the application menu. + /** + * The MacAdapter calls this method when "About" is selected from the application menu. + */ public void about() { - // reuse the normal about action - // null as parameter is OK as the code of actionPerformed does not rely on the data sent in the event. - about.actionPerformed(null); - } - - // General preferences dialog. The MacAdapter calls this method when "Preferences..." - // is selected from the application menu. - public void showPreferencesDialog() { - output(Localization.lang("Opening preferences...")); - if (prefsDialog == null) { - prefsDialog = new PreferencesDialog(JabRefFrame.this); - prefsDialog.setLocationRelativeTo(JabRefFrame.this); - } else { - prefsDialog.setValues(); - } - - prefsDialog.setVisible(true); - output(""); + HelpAction.getCommand().execute(); } public JabRefPreferences prefs() { @@ -778,16 +421,10 @@ private void tearDownJabRef(List filenames) { Globals.stopBackgroundTasks(); Globals.shutdownThreadPools(); - dispose(); + //dispose(); - prefs.putBoolean(JabRefPreferences.WINDOW_MAXIMISED, getExtendedState() == Frame.MAXIMIZED_BOTH); + //prefs.putBoolean(JabRefPreferences.WINDOW_MAXIMISED, getExtendedState() == Frame.MAXIMIZED_BOTH); - prefs.putBoolean(JabRefPreferences.TOOLBAR_VISIBLE, tlb.isVisible()); - // Store divider location for side pane: - int width = splitPane.getDividerLocation(); - if (width > 0) { - prefs.putInt(JabRefPreferences.SIDE_PANE_WIDTH, width); - } if (prefs.getBoolean(JabRefPreferences.OPEN_LAST_EDITED)) { // Here we store the names of all current files. If // there is no current file, we remove any @@ -799,6 +436,7 @@ private void tearDownJabRef(List filenames) { File focusedDatabase = getCurrentBasePanel().getBibDatabaseContext().getDatabaseFile().orElse(null); new LastFocusedTabPreferences(prefs).setLastFocusedTab(focusedDatabase); } + } fileHistory.storeHistory(); @@ -825,97 +463,86 @@ private void tearDownJabRef(List filenames) { * @return true if the user chose to quit; false otherwise */ public boolean quit() { - // Ask here if the user really wants to close, if the base - // has not been saved since last save. - boolean close = true; - + // First ask if the user really wants to close, if the library has not been saved since last save. List filenames = new ArrayList<>(); - if (tabbedPane.getTabCount() > 0) { - for (int i = 0; i < tabbedPane.getTabCount(); i++) { - BibDatabaseContext context = getBasePanelAt(i).getBibDatabaseContext(); - - if (getBasePanelAt(i).isModified() && (context.getLocation() == DatabaseLocation.LOCAL)) { - tabbedPane.setSelectedIndex(i); - String filename = context.getDatabaseFile().map(File::getAbsolutePath).orElse(GUIGlobals.UNTITLED_TITLE); - int answer = showSaveDialog(filename); - - if ((answer == JOptionPane.CANCEL_OPTION) || - (answer == JOptionPane.CLOSED_OPTION)) { - return false; - } - if (answer == JOptionPane.YES_OPTION) { - // The user wants to save. - try { - //getCurrentBasePanel().runCommand("save"); - SaveDatabaseAction saveAction = new SaveDatabaseAction(getCurrentBasePanel()); - saveAction.runCommand(); - if (saveAction.isCanceled() || !saveAction.isSuccess()) { - // The action was either canceled or unsuccessful. - // Break! - output(Localization.lang("Unable to save library")); - close = false; - } - } catch (Throwable ex) { - // Something prevented the file - // from being saved. Break!!! - close = false; - break; - } - } - } else if (context.getLocation() == DatabaseLocation.SHARED) { - context.convertToLocalDatabase(); - context.getDBMSSynchronizer().closeSharedDatabase(); - context.clearDBMSSynchronizer(); + for (int i = 0; i < tabbedPane.getTabs().size(); i++) { + BasePanel panel = getBasePanelAt(i); + BibDatabaseContext context = panel.getBibDatabaseContext(); + + if (panel.isModified() && (context.getLocation() == DatabaseLocation.LOCAL)) { + tabbedPane.getSelectionModel().select(i); + if (!confirmClose(panel)) { + return false; } - AutosaveManager.shutdown(context); - BackupManager.shutdown(context); - context.getDatabaseFile().map(File::getAbsolutePath).ifPresent(filenames::add); + } else if (context.getLocation() == DatabaseLocation.SHARED) { + context.convertToLocalDatabase(); + context.getDBMSSynchronizer().closeSharedDatabase(); + context.clearDBMSSynchronizer(); } - } - - if (close) { - for (int i = 0; i < tabbedPane.getTabCount(); i++) { - if (getBasePanelAt(i).isSaving()) { - // There is a database still being saved, so we need to wait. - WaitForSaveOperation w = new WaitForSaveOperation(this); - w.show(); // This method won't return until canceled or the save operation is done. - if (w.canceled()) { - return false; // The user clicked cancel. - } + AutosaveManager.shutdown(context); + BackupManager.shutdown(context); + context.getDatabaseFile().map(File::getAbsolutePath).ifPresent(filenames::add); + } + + // Wait for save operations to finish + for (int i = 0; i < tabbedPane.getTabs().size(); i++) { + if (getBasePanelAt(i).isSaving()) { + // There is a database still being saved, so we need to wait. + WaitForSaveOperation w = new WaitForSaveOperation(this); + w.show(); // This method won't return until canceled or the save operation is done. + if (w.canceled()) { + return false; // The user clicked cancel. } } - - tearDownJabRef(filenames); - return true; } - return false; + // Good bye! + tearDownJabRef(filenames); + Platform.exit(); + return true; } private void initLayout() { - setProgressBarVisible(false); - pushApplications = new PushToApplications(); - pushExternalButton = new PushToApplicationButton(this, pushApplications.getApplications()); - fillMenu(); - createToolBar(); - setJMenuBar(mb); - getContentPane().setLayout(new BorderLayout()); + pushApplications = new PushToApplications(this.getDialogService()); + + BorderPane head = new BorderPane(); + head.setTop(createMenu()); + head.setCenter(createToolbar()); + setTop(head); + + SplitPane.setResizableWithParent(sidePane, Boolean.FALSE); + splitPane.getItems().addAll(sidePane, tabbedPane); + + // We need to wait with setting the divider since it gets reset a few times during the initial set-up + mainStage.showingProperty().addListener(new ChangeListener() { + + @Override + public void changed(ObservableValue observable, Boolean oldValue, Boolean showing) { + if (showing) { + setDividerPosition(); + + EasyBind.subscribe(sidePane.visibleProperty(), visible -> { + if (visible) { + if (!splitPane.getItems().contains(sidePane)) { + splitPane.getItems().add(0, sidePane); + setDividerPosition(); + } + } else { + splitPane.getItems().remove(sidePane); + } + }); - JPanel toolbarPanel = new JPanel(new WrapLayout(FlowLayout.LEFT)); - toolbarPanel.add(tlb); - toolbarPanel.add(globalSearchBar); - getContentPane().add(toolbarPanel, BorderLayout.PAGE_START); + mainStage.showingProperty().removeListener(this); + observable.removeListener(this); + } + } + }); - splitPane.setDividerSize(2); - splitPane.setBorder(null); - splitPane.setRightComponent(tabbedPane); - splitPane.setLeftComponent(sidePaneManager.getPanel()); - getContentPane().add(splitPane, BorderLayout.CENTER); + setCenter(splitPane); UIManager.put("TabbedPane.contentBorderInsets", new Insets(0, 0, 0, 0)); - sidePaneManager.updateView(); GridBagLayout gbl = new GridBagLayout(); GridBagConstraints con = new GridBagConstraints(); @@ -940,14 +567,72 @@ private void initLayout() { gbl.setConstraints(progressBar, con); status.add(progressBar); statusLabel.setForeground(GUIGlobals.ENTRY_EDITOR_LABEL_COLOR.darker()); - getContentPane().add(status, BorderLayout.PAGE_END); + } - // Drag and drop for tabbedPane: - TransferHandler xfer = new EntryTableTransferHandler(null, this, null); - tabbedPane.setTransferHandler(xfer); - tlb.setTransferHandler(xfer); - mb.setTransferHandler(xfer); - sidePaneManager.getPanel().setTransferHandler(xfer); + private void setDividerPosition() { + splitPane.setDividerPositions(prefs.getDouble(JabRefPreferences.SIDE_PANE_WIDTH)); + if (!splitPane.getDividers().isEmpty()) { + EasyBind.subscribe(splitPane.getDividers().get(0).positionProperty(), + position -> prefs.putDouble(JabRefPreferences.SIDE_PANE_WIDTH, position.doubleValue())); + } + } + + private Node createToolbar() { + Pane leftSpacer = new Pane(); + HBox.setHgrow(leftSpacer, Priority.SOMETIMES); + Pane rightSpacer = new Pane(); + HBox.setHgrow(rightSpacer, Priority.SOMETIMES); + + ActionFactory factory = new ActionFactory(Globals.getKeyPrefs()); + + Button newLibrary; + if (Globals.prefs.getBoolean(JabRefPreferences.BIBLATEX_DEFAULT_MODE)) { + newLibrary = factory.createIconButton(StandardActions.NEW_LIBRARY_BIBLATEX, new NewDatabaseAction(this, BibDatabaseMode.BIBLATEX)); + } else { + newLibrary = factory.createIconButton(StandardActions.NEW_LIBRARY_BIBTEX, new NewDatabaseAction(this, BibDatabaseMode.BIBTEX)); + } + + HBox leftSide = new HBox( + newLibrary, + factory.createIconButton(StandardActions.OPEN_LIBRARY, new OpenDatabaseAction(this)), + factory.createIconButton(StandardActions.SAVE_LIBRARY, new OldDatabaseCommandWrapper(Actions.SAVE, this, Globals.stateManager)), + leftSpacer); + leftSide.setMinWidth(100); + leftSide.prefWidthProperty().bind(sidePane.widthProperty()); + leftSide.maxWidthProperty().bind(sidePane.widthProperty()); + + PushToApplicationButton pushToExternal = new PushToApplicationButton(this, pushApplications.getApplications()); + HBox rightSide = new HBox ( + factory.createIconButton(StandardActions.NEW_ENTRY, new NewEntryAction(this, BiblatexEntryTypes.ARTICLE)), + factory.createIconButton(StandardActions.DELETE_ENTRY, new OldDatabaseCommandWrapper(Actions.DELETE, this, Globals.stateManager)), + + factory.createIconButton(StandardActions.UNDO, new OldDatabaseCommandWrapper(Actions.UNDO, this, Globals.stateManager)), + factory.createIconButton(StandardActions.REDO, new OldDatabaseCommandWrapper(Actions.REDO, this, Globals.stateManager)), + factory.createIconButton(StandardActions.CUT, new OldDatabaseCommandWrapper(Actions.CUT, this, Globals.stateManager)), + factory.createIconButton(StandardActions.COPY, new OldDatabaseCommandWrapper(Actions.COPY, this, Globals.stateManager)), + factory.createIconButton(StandardActions.PASTE, new OldDatabaseCommandWrapper(Actions.PASTE, this, Globals.stateManager)), + + factory.createIconButton(StandardActions.CLEANUP_ENTRIES, new OldDatabaseCommandWrapper(Actions.CLEANUP, this, Globals.stateManager)), + factory.createIconButton(pushToExternal.getMenuAction(), pushToExternal), + + factory.createIconButton(StandardActions.FORK_ME, new OpenBrowserAction("https://github.com/JabRef/jabref")), + factory.createIconButton(StandardActions.OPEN_FACEBOOK, new OpenBrowserAction("https://www.facebook.com/JabRef/")), + factory.createIconButton(StandardActions.OPEN_TWITTER, new OpenBrowserAction("https://twitter.com/jabref_org")) + ); + + HBox.setHgrow(globalSearchBar, Priority.ALWAYS); + + ToolBar toolBar = new ToolBar( + leftSide, + + globalSearchBar, + + rightSpacer, + rightSide + ); + toolBar.getStyleClass().add("mainToolbar"); + + return toolBar; } /** @@ -956,448 +641,371 @@ private void initLayout() { * @param i Index of base */ public BasePanel getBasePanelAt(int i) { - return (BasePanel) tabbedPane.getComponentAt(i); + return (BasePanel) tabbedPane.getTabs().get(i).getContent(); } /** * Returns a list of BasePanel. + * */ public List getBasePanelList() { List returnList = new ArrayList<>(); for (int i = 0; i < getBasePanelCount(); i++) { - returnList.add((BasePanel) tabbedPane.getComponentAt(i)); + returnList.add(getBasePanelAt(i)); } return returnList; } public void showBasePanelAt(int i) { - tabbedPane.setSelectedIndex(i); + tabbedPane.getSelectionModel().select(i); } public void showBasePanel(BasePanel bp) { - tabbedPane.setSelectedComponent(bp); + tabbedPane.getSelectionModel().select(getTab(bp)); } /** * Returns the currently viewed BasePanel. */ public BasePanel getCurrentBasePanel() { - if (tabbedPane == null) { + if ((tabbedPane == null) || (tabbedPane.getSelectionModel().getSelectedItem() == null)) { return null; } - return (BasePanel) tabbedPane.getSelectedComponent(); + return (BasePanel) tabbedPane.getSelectionModel().getSelectedItem().getContent(); } /** * @return the BasePanel count. */ public int getBasePanelCount() { - return tabbedPane.getComponentCount(); - } - - /** - * handle the color of active and inactive JTabbedPane tabs - */ - private void markActiveBasePanel() { - int now = tabbedPane.getSelectedIndex(); - int len = tabbedPane.getTabCount(); - if ((lastTabbedPanelSelectionIndex > -1) && (lastTabbedPanelSelectionIndex < len)) { - tabbedPane.setForegroundAt(lastTabbedPanelSelectionIndex, GUIGlobals.INACTIVE_TABBED_COLOR); - } - if ((now > -1) && (now < len)) { - tabbedPane.setForegroundAt(now, GUIGlobals.ACTIVE_TABBED_COLOR); - } - lastTabbedPanelSelectionIndex = now; + return tabbedPane.getTabs().size(); } - private int getTabIndex(JComponent comp) { - for (int i = 0; i < tabbedPane.getTabCount(); i++) { - if (tabbedPane.getComponentAt(i) == comp) { - return i; + private Tab getTab(BasePanel comp) { + for (Tab tab : tabbedPane.getTabs()) { + if (tab.getContent() == comp) { + return tab; } } - return -1; + return null; } - public JTabbedPane getTabbedPane() { + /** + * @deprecated do not operate on tabs but on BibDatabaseContexts + */ + @Deprecated + public TabPane getTabbedPane() { return tabbedPane; } - public void setTabTitle(JComponent comp, String title, String toolTip) { - int index = getTabIndex(comp); - tabbedPane.setTitleAt(index, title); - tabbedPane.setToolTipTextAt(index, toolTip); - } - - private void fillMenu() { - mb.setBorder(null); - JMenu file = JabRefFrame.subMenu(Localization.menuTitle("File")); - JMenu edit = JabRefFrame.subMenu(Localization.menuTitle("Edit")); - JMenu search = JabRefFrame.subMenu(Localization.menuTitle("Search")); - JMenu groups = JabRefFrame.subMenu(Localization.menuTitle("Groups")); - JMenu bibtex = JabRefFrame.subMenu("&BibTeX"); - JMenu quality = JabRefFrame.subMenu(Localization.menuTitle("Quality")); - JMenu view = JabRefFrame.subMenu(Localization.menuTitle("View")); - JMenu tools = JabRefFrame.subMenu(Localization.menuTitle("Tools")); - JMenu options = JabRefFrame.subMenu(Localization.menuTitle("Options")); - newSpec = JabRefFrame.subMenu(Localization.menuTitle("New entry by type...")); - JMenu helpMenu = JabRefFrame.subMenu(Localization.menuTitle("Help")); - - file.add(newBibtexDatabaseAction); - file.add(newBiblatexDatabaseAction); - file.add(getOpenDatabaseAction()); - file.add(mergeDatabaseAction); - file.add(save); - file.add(saveAs); - file.add(saveAll); - file.add(saveSelectedAs); - file.add(saveSelectedAsPlain); - file.addSeparator(); - file.add(importNew); - file.add(importCurrent); - file.add(exportAll); - file.add(exportSelected); - file.add(exportLinkedFiles); - file.addSeparator(); - file.add(connectToSharedDatabaseAction); - file.add(pullChangesFromSharedDatabase); - - file.addSeparator(); - file.add(databaseProperties); - file.add(editModeAction); - file.addSeparator(); - - file.add(fileHistory); - file.addSeparator(); - file.add(closeDatabaseAction); - file.add(quit); - mb.add(file); - - edit.add(undo); - edit.add(redo); - - edit.addSeparator(); - - edit.add(cut); - edit.add(copy); - edit.add(paste); - - edit.addSeparator(); - - edit.add(copyTitle); - edit.add(copyKey); - edit.add(copyCiteKey); - edit.add(copyKeyAndTitle); - edit.add(copyKeyAndLink); - edit.add(copyPreview); - edit.add(exportToClipboard); - edit.add(sendAsEmail); - - edit.addSeparator(); - edit.add(mark); - for (int i = 0; i < EntryMarker.MAX_MARKING_LEVEL; i++) { - markSpecific.add(new MarkEntriesAction(this, i).getMenuItem()); - } - edit.add(markSpecific); - edit.add(unmark); - edit.add(unmarkAll); - edit.addSeparator(); + public void setTabTitle(BasePanel comp, String title, String toolTip) { + DefaultTaskExecutor.runInJavaFXThread(() -> { + Tab tab = getTab(comp); + tab.setText(title); + tab.setTooltip(new Tooltip(toolTip)); + }); + } + + private MenuBar createMenu() { + ActionFactory factory = new ActionFactory(Globals.getKeyPrefs()); + Menu file = new Menu(Localization.lang("File")); + Menu edit = new Menu(Localization.lang("Edit")); + Menu library = new Menu(Localization.lang("Library")); + Menu quality = new Menu(Localization.lang("Quality")); + Menu view = new Menu(Localization.lang("View")); + Menu tools = new Menu(Localization.lang("Tools")); + Menu options = new Menu(Localization.lang("Options")); + Menu help = new Menu(Localization.lang("Help")); + + file.getItems().addAll( + factory.createMenuItem(StandardActions.NEW_LIBRARY_BIBTEX, new NewDatabaseAction(this, BibDatabaseMode.BIBTEX)), + factory.createMenuItem(StandardActions.NEW_LIBRARY_BIBLATEX, new NewDatabaseAction(this, BibDatabaseMode.BIBLATEX)), + factory.createMenuItem(StandardActions.OPEN_LIBRARY, getOpenDatabaseAction()), + factory.createMenuItem(StandardActions.SAVE_LIBRARY, new OldDatabaseCommandWrapper(Actions.SAVE, this, Globals.stateManager)), + factory.createMenuItem(StandardActions.SAVE_LIBRARY_AS, new OldDatabaseCommandWrapper(Actions.SAVE_AS, this, Globals.stateManager)), + factory.createMenuItem(StandardActions.SAVE_ALL, new SaveAllAction(this)), + + factory.createSubMenu(StandardActions.IMPORT_EXPORT, + factory.createMenuItem(StandardActions.MERGE_DATABASE, new OldDatabaseCommandWrapper(Actions.MERGE_DATABASE, this, Globals.stateManager)), // TODO: merge with import + factory.createMenuItem(StandardActions.IMPORT_INTO_CURRENT_LIBRARY, new ImportCommand(this, false)), + factory.createMenuItem(StandardActions.IMPORT_INTO_NEW_LIBRARY, new ImportCommand(this, true)), + factory.createMenuItem(StandardActions.EXPORT_ALL, new ExportCommand(this, false, Globals.prefs)), + factory.createMenuItem(StandardActions.EXPORT_SELECTED, new ExportCommand(this, true, Globals.prefs)), + factory.createMenuItem(StandardActions.SAVE_SELECTED_AS_PLAIN_BIBTEX, new OldDatabaseCommandWrapper(Actions.SAVE_SELECTED_AS_PLAIN, this, Globals.stateManager)) + ), + + new SeparatorMenuItem(), + + factory.createMenuItem(StandardActions.CONNECT_TO_SHARED_DB, new ConnectToSharedDatabaseCommand(this)), + factory.createMenuItem(StandardActions.PULL_CHANGES_FROM_SHARED_DB, new OldDatabaseCommandWrapper(Actions.PULL_CHANGES_FROM_SHARED_DATABASE, this, Globals.stateManager)), + + new SeparatorMenuItem(), + + fileHistory, + + new SeparatorMenuItem(), + + factory.createMenuItem(StandardActions.CLOSE_LIBRARY, new CloseDatabaseAction()), + factory.createMenuItem(StandardActions.QUIT, new CloseAction()) + + ); + + edit.getItems().addAll( + factory.createMenuItem(StandardActions.UNDO, new OldDatabaseCommandWrapper(Actions.UNDO, this, Globals.stateManager)), + factory.createMenuItem(StandardActions.REDO, new OldDatabaseCommandWrapper(Actions.REDO, this, Globals.stateManager)), + + new SeparatorMenuItem(), + + factory.createMenuItem(StandardActions.CUT, new EditAction(Actions.CUT)), + + factory.createMenuItem(StandardActions.COPY, new EditAction(Actions.COPY)), + factory.createSubMenu(StandardActions.COPY_MORE, + factory.createMenuItem(StandardActions.COPY_TITLE, new OldDatabaseCommandWrapper(Actions.COPY_TITLE, this, Globals.stateManager)), + factory.createMenuItem(StandardActions.COPY_KEY, new OldDatabaseCommandWrapper(Actions.COPY_KEY, this, Globals.stateManager)), + factory.createMenuItem(StandardActions.COPY_CITE_KEY, new OldDatabaseCommandWrapper(Actions.COPY_CITE_KEY, this, Globals.stateManager)), + factory.createMenuItem(StandardActions.COPY_KEY_AND_TITLE, new OldDatabaseCommandWrapper(Actions.COPY_KEY_AND_TITLE, this, Globals.stateManager)), + factory.createMenuItem(StandardActions.COPY_KEY_AND_LINK, new OldDatabaseCommandWrapper(Actions.COPY_KEY_AND_LINK, this, Globals.stateManager)), + factory.createMenuItem(StandardActions.COPY_CITATION_PREVIEW, new OldDatabaseCommandWrapper(Actions.COPY_CITATION_HTML, this, Globals.stateManager)), + factory.createMenuItem(StandardActions.EXPORT_SELECTED_TO_CLIPBOARD, new OldDatabaseCommandWrapper(Actions.EXPORT_TO_CLIPBOARD, this, Globals.stateManager))), + + factory.createMenuItem(StandardActions.PASTE, new EditAction(Actions.PASTE)), + + new SeparatorMenuItem(), + + factory.createMenuItem(StandardActions.SEND_AS_EMAIL, new OldDatabaseCommandWrapper(Actions.SEND_AS_EMAIL, this, Globals.stateManager)), + + new SeparatorMenuItem() + + ); + if (Globals.prefs.getBoolean(JabRefPreferences.SPECIALFIELDSENABLED)) { - boolean menuitem = false; + boolean menuItemAdded = false; if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_RANKING)) { - rankSubMenu = new JMenu(); - RightClickMenu.populateSpecialFieldMenu(rankSubMenu, SpecialField.RANKING, this); - edit.add(rankSubMenu); - menuitem = true; + edit.getItems().add(SpecialFieldMenuItemFactory.createSpecialFieldMenuForActiveDatabase(SpecialField.RANKING, factory, undoManager)); + menuItemAdded = true; } + if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_RELEVANCE)) { - edit.add(toggleRelevance); - menuitem = true; + edit.getItems().add(SpecialFieldMenuItemFactory.getSpecialFieldSingleItemForActiveDatabase(SpecialField.RELEVANCE, factory)); + menuItemAdded = true; } + if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_QUALITY)) { - edit.add(toggleQualityAssured); - menuitem = true; - } - if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_PRIORITY)) { - rankSubMenu = new JMenu(); - RightClickMenu.populateSpecialFieldMenu(rankSubMenu, SpecialField.PRIORITY, this); - edit.add(rankSubMenu); - menuitem = true; + edit.getItems().add(SpecialFieldMenuItemFactory.getSpecialFieldSingleItemForActiveDatabase(SpecialField.QUALITY, factory)); + menuItemAdded = true; } + if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_PRINTED)) { - edit.add(togglePrinted); - menuitem = true; + edit.getItems().add(SpecialFieldMenuItemFactory.getSpecialFieldSingleItemForActiveDatabase(SpecialField.PRINTED, factory)); + menuItemAdded = true; } + + if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_PRIORITY)) { + edit.getItems().add(SpecialFieldMenuItemFactory.createSpecialFieldMenuForActiveDatabase(SpecialField.PRIORITY, factory, undoManager)); + menuItemAdded = true; + } + if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_READ)) { - rankSubMenu = new JMenu(); - RightClickMenu.populateSpecialFieldMenu(rankSubMenu, SpecialField.READ_STATUS, this); - edit.add(rankSubMenu); - menuitem = true; + edit.getItems().add(SpecialFieldMenuItemFactory.createSpecialFieldMenuForActiveDatabase(SpecialField.READ_STATUS, factory, undoManager)); + menuItemAdded = true; } - if (menuitem) { - edit.addSeparator(); + + if (menuItemAdded) { + edit.getItems().add(new SeparatorMenuItem()); } } - edit.add(getManageKeywords()); - edit.add(getMassSetField()); - edit.addSeparator(); - edit.add(selectAll); - mb.add(edit); - - search.add(normalSearch); - search.add(replaceAll); - search.addSeparator(); - search.add(new JCheckBoxMenuItem(generalFetcher.getToggleAction())); - if (prefs.getBoolean(JabRefPreferences.WEB_SEARCH_VISIBLE)) { - sidePaneManager.register(generalFetcher); - sidePaneManager.show(GeneralFetcher.class); - } - mb.add(search); + edit.getItems().addAll( + factory.createMenuItem(StandardActions.MANAGE_KEYWORDS, new ManageKeywordsAction(this)), + factory.createMenuItem(StandardActions.REPLACE_ALL, new OldDatabaseCommandWrapper(Actions.REPLACE_ALL, this, Globals.stateManager)), + factory.createMenuItem(StandardActions.MASS_SET_FIELDS, new MassSetFieldAction(this)) - groups.add(new JCheckBoxMenuItem(groupSidePane.getToggleAction())); - if (prefs.getBoolean(JabRefPreferences.GROUP_SIDEPANE_VISIBLE)) { - sidePaneManager.register(groupSidePane); - sidePaneManager.show(GroupSidePane.class); - } + ); - groups.addSeparator(); - groups.add(addToGroup); - groups.add(removeFromGroup); - groups.add(moveToGroup); - mb.add(groups); - - view.add(getBackAction()); - view.add(getForwardAction()); - view.add(focusTable); - view.add(nextTab); - view.add(prevTab); - view.add(sortTabs); - view.addSeparator(); - view.add(increaseFontSize); - view.add(decreseFontSize); - view.add(defaultFontSize); - view.addSeparator(); - view.add(new JCheckBoxMenuItem(toggleToolbar)); - view.add(new JCheckBoxMenuItem(enableToggle(generalFetcher.getToggleAction()))); - view.add(new JCheckBoxMenuItem(groupSidePane.getToggleAction())); - view.add(new JCheckBoxMenuItem(togglePreview)); - view.add(showPdvViewer); - view.add(getNextPreviewStyleAction()); - view.add(getPreviousPreviewStyleAction()); - - mb.add(view); - - bibtex.add(newEntryAction); - - for (NewEntryAction a : newSpecificEntryAction) { - newSpec.add(a); - } - bibtex.add(newSpec); - - bibtex.add(plainTextImport); - bibtex.addSeparator(); - bibtex.add(editEntry); - bibtex.add(editPreamble); - bibtex.add(editStrings); - bibtex.addSeparator(); - bibtex.add(customizeAction); - bibtex.addSeparator(); - bibtex.add(deleteEntry); - mb.add(bibtex); - - quality.add(dupliCheck); - quality.add(mergeEntries); - quality.addSeparator(); - quality.add(resolveDuplicateKeys); - quality.add(checkIntegrity); - quality.add(cleanupEntries); - quality.add(massSetField); - quality.add(makeKeyAction); - quality.addSeparator(); - quality.add(autoSetFile); - quality.add(findUnlinkedFiles); - quality.add(autoLinkFile); - - for (IdFetcher fetcher : WebFetchers.getIdFetchers(Globals.prefs.getImportFormatPreferences())) { - lookupIdentifiers.add(new LookupIdentifierAction(this, fetcher)); + library.getItems().addAll( + factory.createMenuItem(StandardActions.NEW_ARTICLE, new NewEntryAction(this, BibtexEntryTypes.ARTICLE)), + factory.createMenuItem(StandardActions.NEW_ENTRY, new NewEntryAction(this)), + factory.createMenuItem(StandardActions.NEW_ENTRY_FROM_PLAINTEX, new NewEntryFromPlainTextAction(this, Globals.prefs.getUpdateFieldPreferences())), + + new SeparatorMenuItem(), + + factory.createMenuItem(StandardActions.DELETE_ENTRY, new OldDatabaseCommandWrapper(Actions.DELETE, this, Globals.stateManager)), + + new SeparatorMenuItem(), + + factory.createMenuItem(StandardActions.LIBRARY_PROPERTIES, new DatabasePropertiesAction(this)), + factory.createMenuItem(StandardActions.EDIT_PREAMBLE, new PreambleEditor(this)), + factory.createMenuItem(StandardActions.EDIT_STRINGS, new OldDatabaseCommandWrapper(Actions.EDIT_STRINGS, this, Globals.stateManager)) + + ); + + Menu lookupIdentifiers = factory.createSubMenu(StandardActions.LOOKUP_DOC_IDENTIFIER); + for (IdFetcher fetcher : WebFetchers.getIdFetchers(Globals.prefs.getImportFormatPreferences())) { + LookupIdentifierAction identifierAction = new LookupIdentifierAction<>(this, fetcher); + lookupIdentifiers.getItems().add(factory.createMenuItem(identifierAction.getAction(), identifierAction)); } - quality.add(lookupIdentifiers); - quality.add(downloadFullText); - mb.add(quality); - - tools.add(newSubDatabaseAction); - tools.add(writeXmpAction); - tools.add(new JCheckBoxMenuItem(openOfficePanel.getToggleAction())); - tools.add(pushExternalButton.getMenuAction()); - tools.addSeparator(); - tools.add(openFolder); - tools.add(openFile); - tools.add(openUrl); - tools.add(openConsole); - tools.addSeparator(); - tools.add(abbreviateIso); - tools.add(abbreviateMedline); - tools.add(unabbreviate); - mb.add(tools); - - options.add(showPrefs); - - AbstractAction genFieldsCustomization = new GenFieldsCustomizationAction(); - AbstractAction protectTerms = new ProtectedTermsAction(); - options.add(genFieldsCustomization); - options.add(customImpAction); - options.add(customExpAction); - options.add(customFileTypesAction); - options.add(manageJournals); - options.add(keyBindingAction); - options.add(protectTerms); - options.add(manageSelectors); - mb.add(options); - - helpMenu.add(help); - helpMenu.add(openForumAction); - helpMenu.addSeparator(); - helpMenu.add(errorConsole); - helpMenu.addSeparator(); - helpMenu.add(new SearchForUpdateAction()); - JMenu webMenu = JabRefFrame.subMenu(Localization.menuTitle("JabRef resources")); - webMenu.add(jabrefWebPageAction); - webMenu.add(jabrefBlogAction); - webMenu.add(jabrefFacebookAction); - webMenu.add(jabrefTwitterAction); - webMenu.addSeparator(); - webMenu.add(forkMeOnGitHubAction); - webMenu.add(developmentVersionAction); - webMenu.add(changeLogAction); - webMenu.addSeparator(); - webMenu.add(donationAction); - helpMenu.add(webMenu); - helpMenu.add(about); - mb.add(helpMenu); - - createDisabledIconsForMenuEntries(mb); - } - - public void addParserResult(ParserResult parserResult, boolean focusPanel) { - if (parserResult.toOpenTab()) { + + quality.getItems().addAll( + factory.createMenuItem(StandardActions.FIND_DUPLICATES, new DuplicateSearch(this)), + factory.createMenuItem(StandardActions.MERGE_ENTRIES, new MergeEntriesAction(this)), + + new SeparatorMenuItem(), + + factory.createMenuItem(StandardActions.RESOLVE_DUPLICATE_KEYS, new OldDatabaseCommandWrapper(Actions.RESOLVE_DUPLICATE_KEYS, this, Globals.stateManager)), + factory.createMenuItem(StandardActions.CHECK_INTEGRITY, new IntegrityCheckAction(this)), + factory.createMenuItem(StandardActions.CLEANUP_ENTRIES, new OldDatabaseCommandWrapper(Actions.CLEANUP, this, Globals.stateManager)), + factory.createMenuItem(StandardActions.GENERATE_CITE_KEY, new OldDatabaseCommandWrapper(Actions.MAKE_KEY, this, Globals.stateManager)), + + new SeparatorMenuItem(), + + factory.createMenuItem(StandardActions.SET_FILE_LINKS, new AutoLinkFilesAction()), + factory.createMenuItem(StandardActions.FIND_UNLINKED_FILES, new FindUnlinkedFilesAction(this)), + lookupIdentifiers, + factory.createMenuItem(StandardActions.DOWNLOAD_FULL_TEXT, new OldDatabaseCommandWrapper(Actions.DOWNLOAD_FULL_TEXT, this, Globals.stateManager)) + + ); + + SidePaneComponent webSearch = sidePaneManager.getComponent(SidePaneType.WEB_SEARCH); + SidePaneComponent groups = sidePaneManager.getComponent(SidePaneType.GROUPS); + SidePaneComponent openOffice = sidePaneManager.getComponent(SidePaneType.OPEN_OFFICE); + + view.getItems().addAll( + factory.createMenuItem(webSearch.getToggleAction(), webSearch.getToggleCommand()), + factory.createMenuItem(groups.getToggleAction(), groups.getToggleCommand()), + factory.createMenuItem(StandardActions.TOGGLE_PREVIEW, new OldDatabaseCommandWrapper(Actions.TOGGLE_PREVIEW, this, Globals.stateManager)), + factory.createMenuItem(StandardActions.EDIT_ENTRY, new OldDatabaseCommandWrapper(Actions.EDIT, this, Globals.stateManager)), + factory.createMenuItem(StandardActions.SHOW_PDV_VIEWER, new ShowDocumentViewerAction()), + + new SeparatorMenuItem(), + + factory.createMenuItem(StandardActions.SELECT_ALL, new OldDatabaseCommandWrapper(Actions.SELECT_ALL, this, Globals.stateManager)), + + new SeparatorMenuItem(), + + factory.createMenuItem(StandardActions.NEXT_PREVIEW_STYLE, new OldDatabaseCommandWrapper(Actions.NEXT_PREVIEW_STYLE, this, Globals.stateManager)), + factory.createMenuItem(StandardActions.PREVIOUS_PREVIEW_STYLE, new OldDatabaseCommandWrapper(Actions.PREVIOUS_PREVIEW_STYLE, this, Globals.stateManager)) + + ); + + PushToApplicationButton pushToExternal = new PushToApplicationButton(this, pushApplications.getApplications()); + tools.getItems().addAll( + factory.createMenuItem(StandardActions.NEW_SUB_LIBRARY_FROM_AUX, new NewSubLibraryAction(this)), + factory.createMenuItem(StandardActions.WRITE_XMP, new OldDatabaseCommandWrapper(Actions.WRITE_XMP, this, Globals.stateManager)), + + new SeparatorMenuItem(), + + factory.createMenuItem(openOffice.getToggleAction(), openOffice.getToggleCommand()), + factory.createMenuItem(pushToExternal.getMenuAction(), pushToExternal), + + new SeparatorMenuItem(), + + factory.createMenuItem(StandardActions.OPEN_FOLDER, new OldDatabaseCommandWrapper(Actions.OPEN_FOLDER, this, Globals.stateManager)), + factory.createMenuItem(StandardActions.OPEN_FILE, new OldDatabaseCommandWrapper(Actions.OPEN_EXTERNAL_FILE, this, Globals.stateManager)), + factory.createMenuItem(StandardActions.OPEN_URL, new OldDatabaseCommandWrapper(Actions.OPEN_URL, this, Globals.stateManager)), + factory.createMenuItem(StandardActions.OPEN_CONSOLE, new OldDatabaseCommandWrapper(Actions.OPEN_CONSOLE, this, Globals.stateManager)), + factory.createMenuItem(StandardActions.COPY_LINKED_FILES, new CopyFilesAction(this)), + + new SeparatorMenuItem(), + + factory.createMenuItem(StandardActions.ABBREVIATE_ISO, new OldDatabaseCommandWrapper(Actions.ABBREVIATE_ISO, this, Globals.stateManager)), + factory.createMenuItem(StandardActions.ABBREVIATE_MEDLINE, new OldDatabaseCommandWrapper(Actions.ABBREVIATE_MEDLINE, this, Globals.stateManager)), + factory.createMenuItem(StandardActions.UNABBREVIATE, new OldDatabaseCommandWrapper(Actions.UNABBREVIATE, this, Globals.stateManager)) + + ); + + options.getItems().addAll( + factory.createMenuItem(StandardActions.SHOW_PREFS, new ShowPreferencesAction(this)), + + new SeparatorMenuItem(), + + factory.createMenuItem(StandardActions.SETUP_GENERAL_FIELDS, new SetupGeneralFieldsAction(this)), + factory.createMenuItem(StandardActions.MANAGE_CUSTOM_IMPORTS, new ManageCustomImportsAction(this)), + factory.createMenuItem(StandardActions.MANAGE_CUSTOM_EXPORTS, new ManageCustomExportsAction(this)), + factory.createMenuItem(StandardActions.MANAGE_EXTERNAL_FILETYPES, new EditExternalFileTypesAction()), + factory.createMenuItem(StandardActions.MANAGE_JOURNALS, new ManageJournalsAction()), + factory.createMenuItem(StandardActions.CUSTOMIZE_KEYBINDING, new CustomizeKeyBindingAction()), + factory.createMenuItem(StandardActions.MANAGE_PROTECTED_TERMS, new ManageProtectedTermsAction(this, Globals.protectedTermsLoader)), + + new SeparatorMenuItem(), + + factory.createMenuItem(StandardActions.MANAGE_CONTENT_SELECTORS, new OldDatabaseCommandWrapper(Actions.MANAGE_SELECTORS, this, Globals.stateManager)), + factory.createMenuItem(StandardActions.CUSTOMIZE_ENTRY_TYPES, new CustomizeEntryAction(this)), + factory.createMenuItem(StandardActions.MANAGE_CITE_KEY_PATTERNS, new BibtexKeyPatternAction(this)) + + ); + + help.getItems().addAll( + factory.createMenuItem(StandardActions.HELP, HelpAction.getCommand()), + factory.createMenuItem(StandardActions.OPEN_FORUM, new OpenBrowserAction("http://discourse.jabref.org/")), + + new SeparatorMenuItem(), + + factory.createMenuItem(StandardActions.ERROR_CONSOLE, new ErrorConsoleAction()), + + new SeparatorMenuItem(), + + factory.createMenuItem(StandardActions.SEARCH_FOR_UPDATES, new SearchForUpdateAction()), + factory.createSubMenu(StandardActions.WEB_MENU, + factory.createMenuItem(StandardActions.OPEN_WEBPAGE, new OpenBrowserAction("https://jabref.org/")), + factory.createMenuItem(StandardActions.OPEN_BLOG, new OpenBrowserAction("https://blog.jabref.org/")), + factory.createMenuItem(StandardActions.OPEN_FACEBOOK, new OpenBrowserAction("https://www.facebook.com/JabRef/")), + factory.createMenuItem(StandardActions.OPEN_TWITTER, new OpenBrowserAction("https://twitter.com/jabref_org")), + + new SeparatorMenuItem(), + + factory.createMenuItem(StandardActions.FORK_ME, new OpenBrowserAction("https://github.com/JabRef/jabref")), + factory.createMenuItem(StandardActions.OPEN_DEV_VERSION_LINK, new OpenBrowserAction("https://builds.jabref.org/master/")), + factory.createMenuItem(StandardActions.OPEN_CHANGELOG, new OpenBrowserAction("https://github.com/JabRef/jabref/blob/master/CHANGELOG.md")), + + new SeparatorMenuItem(), + + factory.createMenuItem(StandardActions.DONATE, new OpenBrowserAction("https://donations.jabref.org")) + + ), + factory.createMenuItem(StandardActions.ABOUT, new AboutAction()) + + ); + + MenuBar menu = new MenuBar(); + menu.getStyleClass().add("mainMenu"); + menu.getMenus().addAll( + file, + edit, + library, + quality, + tools, + view, + options, + help); + menu.setUseSystemMenuBar(true); + return menu; + } + + public void addParserResult(ParserResult pr, boolean focusPanel) { + if (pr.toOpenTab()) { // Add the entries to the open tab. BasePanel panel = getCurrentBasePanel(); if (panel == null) { // There is no open tab to add to, so we create a new tab: - panel = addTab(parserResult.getDatabaseContext(), focusPanel); - if (parserResult.wasChangedOnMigration()) { - panel.markBaseChanged(); - } + addTab(pr.getDatabaseContext(), focusPanel); } else { - List entries = new ArrayList<>(parserResult.getDatabase().getEntries()); - addImportedEntries(panel, entries, false); + List entries = new ArrayList<>(pr.getDatabase().getEntries()); + addImportedEntries(panel, entries); } } else { // only add tab if DB is not already open Optional panel = getBasePanelList().stream() - .filter(p -> p.getBibDatabaseContext().getDatabaseFile().equals(parserResult.getFile())).findFirst(); + .filter(p -> p.getBibDatabaseContext().getDatabaseFile().equals(pr.getFile())) + .findFirst(); if (panel.isPresent()) { - tabbedPane.setSelectedComponent(panel.get()); + tabbedPane.getSelectionModel().select(getTab(panel.get())); } else { - BasePanel basePanel = addTab(parserResult.getDatabaseContext(), focusPanel); - if (parserResult.wasChangedOnMigration()) { - basePanel.markBaseChanged(); - } + addTab(pr.getDatabaseContext(), focusPanel); } } } - private void createToolBar() { - tlb.setBorder(null); - tlb.setRollover(true); - - tlb.setFloatable(false); - if (Globals.prefs.getBoolean(JabRefPreferences.BIBLATEX_DEFAULT_MODE)) { - tlb.addAction(newBiblatexDatabaseAction); - } else { - tlb.addAction(newBibtexDatabaseAction); - } - tlb.addAction(getOpenDatabaseAction()); - tlb.addAction(save); - tlb.addAction(saveAll); - - tlb.addSeparator(); - tlb.addAction(cut); - tlb.addAction(copy); - tlb.addAction(paste); - tlb.addAction(undo); - tlb.addAction(redo); - - tlb.addSeparator(); - tlb.addAction(getBackAction()); - tlb.addAction(getForwardAction()); - tlb.addSeparator(); - tlb.addAction(newEntryAction); - tlb.addAction(editEntry); - tlb.addAction(editStrings); - tlb.addAction(deleteEntry); - tlb.addSeparator(); - tlb.addAction(makeKeyAction); - tlb.addAction(cleanupEntries); - tlb.addAction(mergeEntries); - tlb.addAction(pullChangesFromSharedDatabase); - tlb.addAction(openConsole); - - tlb.addSeparator(); - tlb.addAction(mark); - tlb.addAction(unmark); - if (Globals.prefs.getBoolean(JabRefPreferences.SPECIALFIELDSENABLED)) { - if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_RANKING)) { - JButton button = SpecialFieldDropDown - .generateSpecialFieldButtonWithDropDown(SpecialField.RANKING, this); - tlb.add(button); - specialFieldButtons.add(button); - } - if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_RELEVANCE)) { - tlb.addAction(toggleRelevance); - } - if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_QUALITY)) { - tlb.addAction(toggleQualityAssured); - } - if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_PRIORITY)) { - JButton button = SpecialFieldDropDown - .generateSpecialFieldButtonWithDropDown(SpecialField.PRIORITY, this); - tlb.add(button); - specialFieldButtons.add(button); - } - if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_PRINTED)) { - tlb.addAction(togglePrinted); - } - if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_READ)) { - JButton button = SpecialFieldDropDown - .generateSpecialFieldButtonWithDropDown(SpecialField.READ_STATUS, this); - tlb.add(button); - specialFieldButtons.add(button); - } - } - tlb.addSeparator(); - - tlb.addJToggleButton(new JToggleButton(generalFetcher.getToggleAction())); - - previewToggle = new JToggleButton(togglePreview); - tlb.addJToggleButton(previewToggle); - - tlb.addJToggleButton(new JToggleButton(groupSidePane.getToggleAction())); - - tlb.addSeparator(); - - tlb.add(pushExternalButton.getComponent()); - tlb.addSeparator(); - tlb.add(donationAction); - tlb.add(forkMeOnGitHubAction); - tlb.add(jabrefFacebookAction); - tlb.add(jabrefTwitterAction); - - createDisabledIconsForButtons(tlb); - } - /** * displays the String on the Status Line visible on the bottom of the JabRef mainframe */ @@ -1409,47 +1017,39 @@ public void output(final String s) { } private void initActions() { + /* openDatabaseOnlyActions.clear(); openDatabaseOnlyActions.addAll(Arrays.asList(manageSelectors, mergeDatabaseAction, newSubDatabaseAction, save, copyPreview, - saveAs, saveSelectedAs, saveSelectedAsPlain, editModeAction, undo, redo, cut, deleteEntry, copy, paste, mark, markSpecific, unmark, + saveAs, saveSelectedAs, saveSelectedAsPlain, undo, redo, cut, deleteEntry, copy, paste, mark, markSpecific, unmark, unmarkAll, rankSubMenu, editEntry, selectAll, copyKey, copyCiteKey, copyKeyAndTitle, copyKeyAndLink, editPreamble, editStrings, - groupSidePane.getToggleAction(), makeKeyAction, normalSearch, generalFetcher.getToggleAction(), mergeEntries, cleanupEntries, exportToClipboard, replaceAll, - sendAsEmail, downloadFullText, lookupIdentifiers, writeXmpAction, openOfficePanel.getToggleAction(), findUnlinkedFiles, addToGroup, removeFromGroup, + groupSidePane.getToggleCommand(), makeKeyAction, normalSearch, generalFetcher.getToggleCommand(), mergeEntries, cleanupEntries, exportToClipboard, replaceAll, + sendAsEmail, downloadFullText, lookupIdentifiers, writeXmpAction, openOfficePanel.getToggleCommand(), findUnlinkedFiles, addToGroup, removeFromGroup, moveToGroup, autoLinkFile, resolveDuplicateKeys, openUrl, openFolder, openFile, togglePreview, dupliCheck, autoSetFile, newEntryAction, newSpec, customizeAction, plainTextImport, getMassSetField(), getManageKeywords(), pushExternalButton.getMenuAction(), closeDatabaseAction, getNextPreviewStyleAction(), getPreviousPreviewStyleAction(), checkIntegrity, databaseProperties, abbreviateIso, abbreviateMedline, unabbreviate, exportAll, exportSelected, importCurrent, saveAll, focusTable, increaseFontSize, decreseFontSize, defaultFontSize, toggleRelevance, toggleQualityAssured, togglePrinted, pushExternalButton.getComponent())); - openDatabaseOnlyActions.addAll(newSpecificEntryAction); - openDatabaseOnlyActions.addAll(specialFieldButtons); - severalDatabasesOnlyActions.clear(); severalDatabasesOnlyActions.addAll(Arrays .asList(nextTab, prevTab, sortTabs)); - openAndSavedDatabasesOnlyActions.addAll(Collections.singletonList(openConsole)); sharedDatabaseOnlyActions.addAll(Collections.singletonList(pullChangesFromSharedDatabase)); noSharedDatabaseActions.addAll(Arrays.asList(save, saveAll)); - oneEntryOnlyActions.clear(); oneEntryOnlyActions.addAll(Arrays.asList(editEntry)); - oneEntryWithFileOnlyActions.clear(); oneEntryWithFileOnlyActions.addAll(Arrays.asList(openFolder, openFile)); - oneEntryWithURLorDOIOnlyActions.clear(); oneEntryWithURLorDOIOnlyActions.addAll(Arrays.asList(openUrl)); - twoEntriesOnlyActions.clear(); twoEntriesOnlyActions.addAll(Arrays.asList(mergeEntries)); - atLeastOneEntryActions.clear(); atLeastOneEntryActions.addAll(Arrays.asList(downloadFullText, lookupIdentifiers, exportLinkedFiles)); - - tabbedPane.addChangeListener(event -> updateEnabledState()); + tabbedPane.getTabs().addListener(this::updateEnabledState); + */ } /** @@ -1457,16 +1057,16 @@ dupliCheck, autoSetFile, newEntryAction, newSpec, customizeAction, plainTextImpo *

* The action that are affected are set in initActions. */ - public void updateEnabledState() { - int tabCount = tabbedPane.getTabCount(); - if (tabCount != previousTabCount) { - previousTabCount = tabCount; + public void updateEnabledState(ListChangeListener.Change change) { + int tabCount = tabbedPane.getTabs().size(); + if (!change.next()) { + return; + } + if (change.wasAdded() || change.wasRemoved()) { setEnabled(openDatabaseOnlyActions, tabCount > 0); setEnabled(severalDatabasesOnlyActions, tabCount > 1); } if (tabCount == 0) { - getBackAction().setEnabled(false); - getForwardAction().setEnabled(false); setEnabled(openAndSavedDatabasesOnlyActions, false); setEnabled(sharedDatabaseOnlyActions, false); setEnabled(oneEntryOnlyActions, false); @@ -1506,12 +1106,12 @@ public void setupAllTables() { // We want to notify all tabs about the changes to // avoid problems when changing the column set. - for (int i = 0; i < tabbedPane.getTabCount(); i++) { + for (int i = 0; i < tabbedPane.getTabs().size(); i++) { BasePanel bf = getBasePanelAt(i); // Update tables: if (bf.getDatabase() != null) { - bf.setupMainPanel(); + DefaultTaskExecutor.runInJavaFXThread(bf::setupMainPanel); } } } @@ -1550,48 +1150,49 @@ public void updateAllTabTitles() { if (!uniqPath.equals(file.get().getName()) && uniqPath.contains(File.separator)) { // remove filename uniqPath = uniqPath.substring(0, uniqPath.lastIndexOf(File.separator)); - tabbedPane.setTitleAt(i, getBasePanelAt(i).getTabTitle() + " \u2014 " + uniqPath); + tabbedPane.getTabs().get(i).setText(getBasePanelAt(i).getTabTitle() + " \u2014 " + uniqPath); } else { // set original filename (again) - tabbedPane.setTitleAt(i, getBasePanelAt(i).getTabTitle()); + tabbedPane.getTabs().get(i).setText(getBasePanelAt(i).getTabTitle()); } } else { - tabbedPane.setTitleAt(i, getBasePanelAt(i).getTabTitle()); + tabbedPane.getTabs().get(i).setText(getBasePanelAt(i).getTabTitle()); } - tabbedPane.setToolTipTextAt(i, file.map(File::getAbsolutePath).orElse(null)); + tabbedPane.getTabs().get(i).setTooltip(new Tooltip(file.map(File::getAbsolutePath).orElse(null))); } } - public BasePanel addTab(BasePanel basePanel, boolean raisePanel) { - // add tab - tabbedPane.add(basePanel.getTabTitle(), basePanel); + public void addTab(BasePanel basePanel, boolean raisePanel) { + DefaultTaskExecutor.runInJavaFXThread(() -> { + // add tab + Tab newTab = new Tab(basePanel.getTabTitle(), basePanel); + tabbedPane.getTabs().add(newTab); - // update all tab titles - updateAllTabTitles(); + // update all tab titles + updateAllTabTitles(); - if (raisePanel) { - tabbedPane.setSelectedComponent(basePanel); - } + if (raisePanel) { + tabbedPane.getSelectionModel().select(newTab); + } - // Register undo/redo listener - basePanel.getUndoManager().registerListener(new UndoRedoEventManager()); + // Register undo/redo listener + basePanel.getUndoManager().registerListener(new UndoRedoEventManager()); - BibDatabaseContext context = basePanel.getBibDatabaseContext(); + BibDatabaseContext context = basePanel.getBibDatabaseContext(); - if (readyForAutosave(context)) { - AutosaveManager autosaver = AutosaveManager.start(context); - autosaver.registerListener(new AutosaveUIManager(basePanel)); - } + if (readyForAutosave(context)) { + AutosaveManager autosaver = AutosaveManager.start(context); + autosaver.registerListener(new AutosaveUIManager(basePanel)); + } - BackupManager.start(context); + BackupManager.start(context); - // Track opening - trackOpenNewDatabase(basePanel); - return basePanel; + // Track opening + trackOpenNewDatabase(basePanel); + }); } private void trackOpenNewDatabase(BasePanel basePanel) { - Map properties = new HashMap<>(); Map measurements = new HashMap<>(); measurements.put("NumberOfEntries", (double) basePanel.getBibDatabaseContext().getDatabase().getEntryCount()); @@ -1601,9 +1202,10 @@ private void trackOpenNewDatabase(BasePanel basePanel) { public BasePanel addTab(BibDatabaseContext databaseContext, boolean raisePanel) { Objects.requireNonNull(databaseContext); - BasePanel basePanel = new BasePanel(JabRefFrame.this, databaseContext); - addTab(basePanel, raisePanel); - return basePanel; + + BasePanel bp = new BasePanel(this, BasePanelPreferences.from(Globals.prefs), databaseContext, ExternalFileTypes.getInstance()); + addTab(bp, raisePanel); + return bp; } private boolean readyForAutosave(BibDatabaseContext context) { @@ -1612,55 +1214,19 @@ private boolean readyForAutosave(BibDatabaseContext context) { context.getDatabaseFile().isPresent(); } - /** - * Creates icons for the disabled state for all JMenuItems with FontBasedIcons in the given menuElement. - * This is necessary as Swing is not able to generate default disabled icons for font based icons. - * - * @param menuElement the menuElement for which disabled icons should be generated - */ - public void createDisabledIconsForMenuEntries(MenuElement menuElement) { - for (MenuElement subElement : menuElement.getSubElements()) { - if ((subElement instanceof JMenu) || (subElement instanceof JPopupMenu)) { - createDisabledIconsForMenuEntries(subElement); - } else if (subElement instanceof JMenuItem) { - JMenuItem item = (JMenuItem) subElement; - if (item.getIcon() instanceof IconTheme.FontBasedIcon) { - item.setDisabledIcon(((IconTheme.FontBasedIcon) item.getIcon()).createDisabledIcon()); - } - } - } - } - - public void createDisabledIconsForButtons(Container container) { - for (int index = 0; index < container.getComponentCount(); index++) { - Component component = container.getComponent(index); - if (component instanceof JButton) { - JButton button = (JButton) component; - if (button.getIcon() instanceof IconTheme.FontBasedIcon) { - button.setDisabledIcon(((IconTheme.FontBasedIcon) button.getIcon()).createDisabledIcon()); - } - } else if (component instanceof JPanel) { - createDisabledIconsForButtons((JPanel) component); - } - } - } - /** * This method does the job of adding imported entries into the active * database, or into a new one. It shows the ImportInspectionDialog if * preferences indicate it should be used. Otherwise it imports directly. - * - * @param panel The BasePanel to add to. + * @param panel The BasePanel to add to. * @param entries The entries to add. - * @param openInNew Should the entries be imported into a new database? */ - private void addImportedEntries(final BasePanel panel, final List entries, final boolean openInNew) { + private void addImportedEntries(final BasePanel panel, final List entries) { SwingUtilities.invokeLater(() -> { ImportInspectionDialog diag = new ImportInspectionDialog(JabRefFrame.this, panel, - Localization.lang("Import"), openInNew); + Localization.lang("Import"), false); diag.addEntries(entries); diag.entryListComplete(); - diag.setLocationRelativeTo(JabRefFrame.this); diag.setVisible(true); diag.toFront(); }); @@ -1670,38 +1236,6 @@ public FileHistoryMenu getFileHistory() { return fileHistory; } - /** - * This method shows a wait cursor and blocks all input to the JFrame's contents. - */ - public void block() { - changeBlocking(true); - } - - /** - * This method reverts the cursor to normal, and stops blocking input to the JFrame's contents. - * There are no adverse effects of calling this method redundantly. - */ - public void unblock() { - changeBlocking(false); - } - - /** - * Do the actual blocking/unblocking - * - * @param blocked true if input should be blocked - */ - private void changeBlocking(boolean blocked) { - if (SwingUtilities.isEventDispatchThread()) { - getGlassPane().setVisible(blocked); - } else { - try { - SwingUtilities.invokeAndWait(() -> getGlassPane().setVisible(blocked)); - } catch (InvocationTargetException | InterruptedException e) { - LOGGER.error("Problem " + (blocked ? "" : "un") + "blocking UI", e); - } - } - } - /** * Set the visibility of the progress bar in the right end of the * status line at the bottom of the frame. @@ -1729,6 +1263,7 @@ public void setProgressBarValue(final int value) { } else { SwingUtilities.invokeLater(() -> progressBar.setValue(value)); } + } /** @@ -1743,6 +1278,7 @@ public void setProgressBarIndeterminate(final boolean value) { } else { SwingUtilities.invokeLater(() -> progressBar.setIndeterminate(value)); } + } /** @@ -1759,11 +1295,11 @@ public void setProgressBarMaximum(final int value) { } else { SwingUtilities.invokeLater(() -> progressBar.setMaximum(value)); } + } /** * Return a boolean, if the selected entry have file - * * @param selectEntryList A selected entries list of the current base pane * @return true, if the selected entry contains file. * false, if multiple entries are selected or the selected entry doesn't contains file @@ -1778,7 +1314,6 @@ private boolean isExistFile(List selectEntryList) { /** * Return a boolean, if the selected entry have url or doi - * * @param selectEntryList A selected entries list of the current base pane * @return true, if the selected entry contains url or doi. * false, if multiple entries are selected or the selected entry doesn't contains url or doi @@ -1793,7 +1328,7 @@ private boolean isExistURLorDOI(List selectEntryList) { @Override public void showMessage(String message, String title, int msgType) { - JOptionPane.showMessageDialog(this, message, title, msgType); + JOptionPane.showMessageDialog(null, message, title, msgType); } @Override @@ -1803,18 +1338,45 @@ public void setStatus(String s) { @Override public void showMessage(String message) { - JOptionPane.showMessageDialog(this, message); + JOptionPane.showMessageDialog(null, message); } - private int showSaveDialog(String filename) { - Object[] options = {Localization.lang("Save changes"), - Localization.lang("Discard changes"), - Localization.lang("Return to JabRef")}; - - return JOptionPane.showOptionDialog(JabRefFrame.this, + /** + * Ask if the user really wants to close the given database + * + * @return true if the user choose to close the database + */ + private boolean confirmClose(BasePanel panel) { + String filename = panel.getBibDatabaseContext() + .getDatabasePath() + .map(Path::toAbsolutePath) + .map(Path::toString) + .orElse(GUIGlobals.UNTITLED_TITLE); + + ButtonType saveChanges = new ButtonType(Localization.lang("Save changes"), ButtonBar.ButtonData.YES); + ButtonType discardChanges = new ButtonType(Localization.lang("Discard changes"), ButtonBar.ButtonData.NO); + ButtonType cancel = new ButtonType(Localization.lang("Return to JabRef"), ButtonBar.ButtonData.CANCEL_CLOSE); + + Optional response = dialogService.showCustomButtonDialogAndWait(Alert.AlertType.CONFIRMATION, + Localization.lang("Save before closing"), Localization.lang("Library '%0' has changed.", filename), - Localization.lang("Save before closing"), JOptionPane.YES_NO_CANCEL_OPTION, - JOptionPane.WARNING_MESSAGE, null, options, options[2]); + saveChanges, discardChanges, cancel); + + if (response.isPresent() && response.get().equals(saveChanges)) { + // The user wants to save. + try { + SaveDatabaseAction saveAction = new SaveDatabaseAction(panel); + saveAction.runCommand(); + if (saveAction.isCanceled() || !saveAction.isSuccess()) { + // The action was either canceled or unsuccessful. + output(Localization.lang("Unable to save library")); + return false; + } + } catch (Throwable ex) { + return false; + } + } else return !response.isPresent() || !response.get().equals(cancel); + return false; } private void closeTab(BasePanel panel) { @@ -1841,94 +1403,33 @@ private void closeTab(BasePanel panel) { BackupManager.shutdown(context); } - // Ask if the user really wants to close, if the base has not been saved - private boolean confirmClose(BasePanel panel) { - boolean close = false; - String filename; - - filename = panel.getBibDatabaseContext().getDatabaseFile().map(File::getAbsolutePath) - .orElse(GUIGlobals.UNTITLED_TITLE); - - int answer = showSaveDialog(filename); - if (answer == JOptionPane.YES_OPTION) { - // The user wants to save. - try { - SaveDatabaseAction saveAction = new SaveDatabaseAction(panel); - saveAction.runCommand(); - if (saveAction.isSuccess()) { - close = true; - } - } catch (Throwable ex) { - // do not close - } - } else if (answer == JOptionPane.NO_OPTION) { - // discard changes - close = true; - } - return close; - } - private void removeTab(BasePanel panel) { - panel.cleanUp(); - tabbedPane.remove(panel); - if (tabbedPane.getTabCount() > 0) { - markActiveBasePanel(); - } - setWindowTitle(); - updateEnabledState(); - output(Localization.lang("Closed library") + '.'); - // update tab titles - updateAllTabTitles(); + DefaultTaskExecutor.runInJavaFXThread(() -> { + panel.cleanUp(); + tabbedPane.getTabs().remove(getTab(panel)); + setWindowTitle(); + output(Localization.lang("Closed library") + '.'); + // update tab titles + updateAllTabTitles(); + }); } public void closeCurrentTab() { removeTab(getCurrentBasePanel()); } - public ManageKeywordsAction getManageKeywords() { - return manageKeywords; - } - - public MassSetFieldAction getMassSetField() { - return massSetField; - } - public OpenDatabaseAction getOpenDatabaseAction() { - return open; + return new OpenDatabaseAction(this); } public String getStatusLineText() { return statusLine.getText(); } - public AbstractAction getForwardAction() { - return forward; - } - - public AbstractAction getBackAction() { - return back; - } - - public AbstractAction getNextPreviewStyleAction() { - return nextPreviewStyle; - } - - public AbstractAction getPreviousPreviewStyleAction() { - return previousPreviewStyle; - } - - public JSplitPane getSplitPane() { - return splitPane; - } - public SidePaneManager getSidePaneManager() { return sidePaneManager; } - public void setPreviewToggle(boolean enabled) { - previewToggle.setSelected(enabled); - } - public PushToApplications getPushApplications() { return pushApplications; } @@ -1937,185 +1438,22 @@ public GlobalSearchBar getGlobalSearchBar() { return globalSearchBar; } - private static class MyGlassPane extends JPanel { - public MyGlassPane() { - addKeyListener(new KeyAdapter() { - // Nothing - }); - addMouseListener(new MouseAdapter() { - // Nothing - }); - /* infoLabel.setForeground(new Color(255, 100, 100, 124)); - - setLayout(new BorderLayout()); - add(infoLabel, BorderLayout.CENTER);*/ - super.setCursor( - Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - } - - // Override isOpaque() to prevent the glasspane from hiding the window contents: - @Override - public boolean isOpaque() { - return false; - } + public CountingUndoManager getUndoManager() { + return undoManager; } - private class EditModeAction extends AbstractAction { - - public EditModeAction() { - initName(); - } - - public void initName() { - if (JabRefFrame.this.getCurrentBasePanel() == null) { - putValue(Action.NAME, Localization.menuTitle("Switch to %0 mode", "BibTeX/biblatex")); - } else { - BibDatabaseMode mode = JabRefFrame.this.getCurrentBasePanel().getBibDatabaseContext().getMode(); - String modeName = mode.getOppositeMode().getFormattedName(); - putValue(Action.NAME, Localization.menuTitle("Switch to %0 mode", modeName)); - } - } - - @Override - public void actionPerformed(ActionEvent evt) { - if (JabRefFrame.this.getCurrentBasePanel() == null) { - return; - } - - BibDatabaseMode newMode = JabRefFrame.this.getCurrentBasePanel().getBibDatabaseContext().getMode() - .getOppositeMode(); - JabRefFrame.this.getCurrentBasePanel().getBibDatabaseContext().setMode(newMode); - JabRefFrame.this.refreshTitleAndTabs(); - - initName(); - - // update all elements in current base panel - JabRefFrame.this.getCurrentBasePanel().hideBottomComponent(); - JabRefFrame.this.getCurrentBasePanel().updateEntryEditorIfShowing(); - } - } - - private class GeneralAction extends MnemonicAwareAction { - - private final String command; - - public GeneralAction(String command, String text) { - this.command = command; - putValue(Action.NAME, text); - } - - public GeneralAction(String command, String text, String description) { - this.command = command; - putValue(Action.NAME, text); - putValue(Action.SHORT_DESCRIPTION, description); - } - - public GeneralAction(String command, String text, Icon icon) { - super(icon); - - this.command = command; - putValue(Action.NAME, text); - } - - public GeneralAction(String command, String text, String description, Icon icon) { - super(icon); - - this.command = command; - putValue(Action.NAME, text); - putValue(Action.SHORT_DESCRIPTION, description); - } - - public GeneralAction(String command, String text, KeyStroke key) { - this.command = command; - putValue(Action.NAME, text); - putValue(Action.ACCELERATOR_KEY, key); - } - - public GeneralAction(String command, String text, String description, KeyStroke key) { - this.command = command; - putValue(Action.NAME, text); - putValue(Action.SHORT_DESCRIPTION, description); - putValue(Action.ACCELERATOR_KEY, key); - } - - public GeneralAction(String command, String text, String description, KeyStroke key, Icon icon) { - super(icon); - - this.command = command; - putValue(Action.NAME, text); - putValue(Action.SHORT_DESCRIPTION, description); - putValue(Action.ACCELERATOR_KEY, key); - } - - @Override - public void actionPerformed(ActionEvent e) { - if (tabbedPane.getTabCount() > 0) { - try { - ((BasePanel) tabbedPane.getSelectedComponent()).runCommand(command); - } catch (Throwable ex) { - LOGGER.error("Problem with executing command: " + command, ex); - } - } else { - LOGGER.info("Action '" + command + "' must be disabled when no database is open."); - } - } + public DialogService getDialogService() { + return dialogService; } /** * The action concerned with closing the window. */ - private class CloseAction extends MnemonicAwareAction { - - public CloseAction() { - putValue(Action.NAME, Localization.menuTitle("Quit")); - putValue(Action.SHORT_DESCRIPTION, Localization.lang("Quit JabRef")); - putValue(Action.ACCELERATOR_KEY, Globals.getKeyPrefs().getKey(KeyBinding.QUIT_JABREF)); - } + private class CloseAction extends SimpleCommand { @Override - public void actionPerformed(ActionEvent e) { + public void execute() { quit(); - Platform.exit(); - } - } - - private class ShowPrefsAction extends MnemonicAwareAction { - - public ShowPrefsAction() { - super(IconTheme.JabRefIcon.PREFERENCES.getIcon()); - putValue(Action.NAME, Localization.menuTitle("Preferences")); - putValue(Action.SHORT_DESCRIPTION, Localization.lang("Preferences")); - } - - @Override - public void actionPerformed(ActionEvent e) { - showPreferencesDialog(); - } - } - - private class ChangeTabAction extends MnemonicAwareAction { - - private final boolean next; - - public ChangeTabAction(boolean next) { - putValue(Action.NAME, next ? Localization.menuTitle("Next tab") : - Localization.menuTitle("Previous tab")); - this.next = next; - putValue(Action.ACCELERATOR_KEY, - next ? Globals.getKeyPrefs().getKey(KeyBinding.NEXT_TAB) : Globals.getKeyPrefs().getKey(KeyBinding.PREVIOUS_TAB)); - } - - @Override - public void actionPerformed(ActionEvent e) { - int i = tabbedPane.getSelectedIndex(); - int newI = next ? i + 1 : i - 1; - if (newI < 0) { - newI = tabbedPane.getTabCount() - 1; - } - if (newI == tabbedPane.getTabCount()) { - newI = 0; - } - tabbedPane.setSelectedIndex(newI); } } @@ -2124,266 +1462,61 @@ public void actionPerformed(ActionEvent e) { * kept track of by Globals.focusListener, and we call the action stored under the * relevant name in its action map. */ - private class EditAction extends MnemonicAwareAction { + private class EditAction extends SimpleCommand { - private final String command; + private final Actions command; - public EditAction(String command, String menuTitle, String description, KeyStroke key, Icon icon) { - super(icon); + public EditAction(Actions command) { this.command = command; - putValue(Action.NAME, menuTitle); - putValue(Action.ACCELERATOR_KEY, key); - putValue(Action.SHORT_DESCRIPTION, description); } @Override - public void actionPerformed(ActionEvent e) { - + public void execute() { LOGGER.debug(Globals.getFocusListener().getFocused().toString()); JComponent source = Globals.getFocusListener().getFocused(); Action action = source.getActionMap().get(command); if (action != null) { - action.actionPerformed(new ActionEvent(source, 0, command)); - } - } - } - - private class CustomizeExportsAction extends MnemonicAwareAction { - - public CustomizeExportsAction() { - putValue(Action.NAME, Localization.menuTitle("Manage custom exports")); - } - - @Override - public void actionPerformed(ActionEvent e) { - ExportCustomizationDialog ecd = new ExportCustomizationDialog(JabRefFrame.this); - ecd.setVisible(true); - } - } - - private class CustomizeImportsAction extends MnemonicAwareAction { - - public CustomizeImportsAction() { - putValue(Action.NAME, Localization.menuTitle("Manage custom imports")); - } - - @Override - public void actionPerformed(ActionEvent e) { - ImportCustomizationDialog ecd = new ImportCustomizationDialog(JabRefFrame.this); - ecd.setVisible(true); - } - } - - private class CustomizeEntryTypeAction extends MnemonicAwareAction { - - public CustomizeEntryTypeAction() { - putValue(Action.NAME, Localization.menuTitle("Customize entry types")); - } - - @Override - public void actionPerformed(ActionEvent e) { - JDialog dl = new EntryCustomizationDialog(JabRefFrame.this); - dl.setLocationRelativeTo(JabRefFrame.this); - dl.setVisible(true); - } - } - - private class GenFieldsCustomizationAction extends MnemonicAwareAction { - - public GenFieldsCustomizationAction() { - putValue(Action.NAME, Localization.menuTitle("Set up general fields")); - } - - @Override - public void actionPerformed(ActionEvent e) { - GenFieldsCustomizer gf = new GenFieldsCustomizer(JabRefFrame.this); - gf.setLocationRelativeTo(JabRefFrame.this); - gf.setVisible(true); - } - } - - private class ProtectedTermsAction extends MnemonicAwareAction { - - public ProtectedTermsAction() { - putValue(Action.NAME, Localization.menuTitle("Manage protected terms")); - } - - @Override - public void actionPerformed(ActionEvent e) { - ProtectedTermsDialog protectTermsDialog = new ProtectedTermsDialog(JabRefFrame.this); - protectTermsDialog.setVisible(true); - } - } - - private class DatabasePropertiesAction extends MnemonicAwareAction { - - private DatabasePropertiesDialog propertiesDialog; - - public DatabasePropertiesAction() { - putValue(Action.NAME, Localization.menuTitle("Library properties")); - } - - @Override - public void actionPerformed(ActionEvent e) { - if (propertiesDialog == null) { - propertiesDialog = new DatabasePropertiesDialog(JabRefFrame.this); - } - propertiesDialog.setPanel(getCurrentBasePanel()); - propertiesDialog.updateEnableStatus(); - propertiesDialog.setLocationRelativeTo(JabRefFrame.this); - propertiesDialog.setVisible(true); - } - } - - private class BibtexKeyPatternAction extends MnemonicAwareAction { - - private BibtexKeyPatternDialog bibtexKeyPatternDialog; - - public BibtexKeyPatternAction() { - putValue(Action.NAME, Localization.lang("BibTeX key patterns")); - } - - @Override - public void actionPerformed(ActionEvent e) { - JabRefPreferences.getInstance(); - if (bibtexKeyPatternDialog == null) { - // if no instance of BibtexKeyPatternDialog exists, create new one - bibtexKeyPatternDialog = new BibtexKeyPatternDialog(JabRefFrame.this, getCurrentBasePanel()); - } else { - // BibtexKeyPatternDialog allows for updating content based on currently selected panel - bibtexKeyPatternDialog.setPanel(getCurrentBasePanel()); + action.actionPerformed(new ActionEvent(source, 0, command.name())); } - bibtexKeyPatternDialog.setLocationRelativeTo(JabRefFrame.this); - bibtexKeyPatternDialog.setVisible(true); } } - private class DefaultTableFontSizeAction extends MnemonicAwareAction { - - public DefaultTableFontSizeAction() { - putValue(Action.NAME, Localization.menuTitle("Default table font size")); - putValue(Action.ACCELERATOR_KEY, Globals.getKeyPrefs().getKey(KeyBinding.DEFAULT_TABLE_FONT_SIZE)); - } - - @Override - public void actionPerformed(ActionEvent event) { - GUIGlobals.setFont(Globals.prefs.getIntDefault(JabRefPreferences.FONT_SIZE)); - for (BasePanel basePanel : getBasePanelList()) { - basePanel.updateTableFont(); - } - setStatus(Localization.lang("Table font size is %0", String.valueOf(GUIGlobals.currentFont.getSize()))); + private void setDefaultTableFontSize() { + GUIGlobals.setFont(Globals.prefs.getIntDefault(JabRefPreferences.FONT_SIZE)); + for (BasePanel basePanel : getBasePanelList()) { + basePanel.updateTableFont(); } + setStatus(Localization.lang("Table font size is %0", String.valueOf(GUIGlobals.currentFont.getSize()))); } - private class IncreaseTableFontSizeAction extends MnemonicAwareAction { - - public IncreaseTableFontSizeAction() { - putValue(Action.NAME, Localization.menuTitle("Increase table font size")); - putValue(Action.ACCELERATOR_KEY, Globals.getKeyPrefs().getKey(KeyBinding.INCREASE_TABLE_FONT_SIZE)); - } - - @Override - public void actionPerformed(ActionEvent event) { - GUIGlobals.setFont(GUIGlobals.currentFont.getSize() + 1); - for (BasePanel basePanel : getBasePanelList()) { - basePanel.updateTableFont(); - } - setStatus(Localization.lang("Table font size is %0", String.valueOf(GUIGlobals.currentFont.getSize()))); + private void increaseTableFontSize() { + GUIGlobals.setFont(GUIGlobals.currentFont.getSize() + 1); + for (BasePanel basePanel : getBasePanelList()) { + basePanel.updateTableFont(); } + setStatus(Localization.lang("Table font size is %0", String.valueOf(GUIGlobals.currentFont.getSize()))); } - private class DecreaseTableFontSizeAction extends MnemonicAwareAction { - - public DecreaseTableFontSizeAction() { - putValue(Action.NAME, Localization.menuTitle("Decrease table font size")); - putValue(Action.ACCELERATOR_KEY, Globals.getKeyPrefs().getKey(KeyBinding.DECREASE_TABLE_FONT_SIZE)); + private void decreaseTableFontSize() { + int currentSize = GUIGlobals.currentFont.getSize(); + if (currentSize < 2) { + return; } - - @Override - public void actionPerformed(ActionEvent event) { - int currentSize = GUIGlobals.currentFont.getSize(); - if (currentSize < 2) { - return; - } - GUIGlobals.setFont(currentSize - 1); - for (BasePanel basePanel : getBasePanelList()) { - basePanel.updateTableFont(); - } - setStatus(Localization.lang("Table font size is %0", String.valueOf(GUIGlobals.currentFont.getSize()))); + GUIGlobals.setFont(currentSize - 1); + for (BasePanel basePanel : getBasePanelList()) { + basePanel.updateTableFont(); } + setStatus(Localization.lang("Table font size is %0", String.valueOf(GUIGlobals.currentFont.getSize()))); } - private class CloseDatabaseAction extends MnemonicAwareAction { - - public CloseDatabaseAction() { - super(IconTheme.JabRefIcon.CLOSE.getSmallIcon()); - putValue(Action.NAME, Localization.menuTitle("Close library")); - putValue(Action.SHORT_DESCRIPTION, Localization.lang("Close the current library")); - putValue(Action.ACCELERATOR_KEY, Globals.getKeyPrefs().getKey(KeyBinding.CLOSE_DATABASE)); - } + private class CloseDatabaseAction extends SimpleCommand { @Override - public void actionPerformed(ActionEvent e) { + public void execute() { closeTab(getCurrentBasePanel()); } } - private class CloseAllDatabasesAction extends MnemonicAwareAction { - - @Override - public void actionPerformed(ActionEvent e) { - final Component[] panels = tabbedPane.getComponents(); - - for (Component p : panels) { - closeTab((BasePanel) p); - } - } - } - - private class CloseOtherDatabasesAction extends MnemonicAwareAction { - - @Override - public void actionPerformed(ActionEvent e) { - final BasePanel active = getCurrentBasePanel(); - final Component[] panels = tabbedPane.getComponents(); - - for (Component p : panels) { - if (!Objects.equals(p, active)) { - closeTab((BasePanel) p); - } - } - } - } - - private class ToolBar extends OSXCompatibleToolbar { - - public void addAction(Action a) { - JButton b = new JButton(a); - b.setText(null); - if (!OS.OS_X) { - b.setMargin(marg); - } - // create a disabled Icon for FontBasedIcons as Swing does not automatically create one - Object obj = a.getValue(Action.LARGE_ICON_KEY); - if (obj instanceof IconTheme.FontBasedIcon) { - b.setDisabledIcon(((IconTheme.FontBasedIcon) obj).createDisabledIcon()); - } - add(b); - } - - public void addJToggleButton(JToggleButton button) { - button.setText(null); - if (!OS.OS_X) { - button.setMargin(marg); - } - Object obj = button.getAction().getValue(Action.LARGE_ICON_KEY); - if (obj instanceof IconTheme.FontBasedIcon) { - button.setDisabledIcon(((IconTheme.FontBasedIcon) obj).createDisabledIcon()); - } - add(button); - } - } - private class UndoRedoEventManager { @Subscribe @@ -2398,12 +1531,14 @@ public void listen(AddUndoableActionEvent event) { } private void updateTexts(UndoChangeEvent event) { + /* TODO SwingUtilities.invokeLater(() -> { undo.putValue(Action.SHORT_DESCRIPTION, event.getUndoDescription()); undo.setEnabled(event.isCanUndo()); redo.putValue(Action.SHORT_DESCRIPTION, event.getRedoDescription()); redo.setEnabled(event.isCanRedo()); }); + */ } } } diff --git a/src/main/java/org/jabref/gui/Main.css b/src/main/java/org/jabref/gui/Main.css deleted file mode 100644 index 5f01e7afd41..00000000000 --- a/src/main/java/org/jabref/gui/Main.css +++ /dev/null @@ -1,118 +0,0 @@ -/* - * The base css file defining the style that is valid for every pane and dialog. - */ - -.root { - /* - * A strong blue to indicate something neutral. - */ - -fx-neutral: #2980b9; - - /* - * A strong green to indicate something positive. - */ - -fx-positive: #27ae60; - - /* - * A strong red to indicate something negative. - */ - -fx-negative: #c0392b; - - /* - * A dark grayish blue to display information (but kind of highlighted). - */ - -fx-info: #2c3e50; - - /* - * A light gray for accented background - */ - -fx-accented-background: #dadad8; - - /* - * A dark gray as background - */ - -fx-dark-background: #757575; - - /* - * A strong white as background - */ - -fx-light-background: #ffffff; - - /* - * A strong blue for backgrounds of active items (toggle button, selected list item) - */ - -fx-active-background: #6A9FCD; - -} - -.hyperlink { - -fx-padding: 0; - -fx-underline: false; - -fx-border-style: null; - -fx-border-color: null; -} - -.hyperlink:visited { - -fx-text-fill: -fx-accent; -} - - .icon { - -fx-font-family: 'Material Design Icons'; - -fx-font-size: 16.0; - } - -.glyph-icon { - -fx-font-size: 20.0; - -glyph-size: 20.0; -} - -.tooltip { - -fx-background-color: #616161; - -fx-opacity: 95%; - -fx-text-fill: rgba(255, 255, 255, 0.9); - -fx-font-size: 1em; -} - -.tooltip > TextFlow > Text { - -fx-fill: rgba(255, 255, 255, 0.9); - -fx-font-size: 1em; -} - -.tooltip > TextFlow > .tooltip-text-bold { - -fx-font-weight: bold; -} - -.tooltip > TextFlow > .tooltip-text-italic { - -fx-font-style: italic; -} - -.tooltip > TextFlow > .tooltip-text-monospaced { - -fx-font-family: monospace; -} - -.flatButtonNoSpaceBottom, -.flatButtonNoSpaceTop, -.flatButton { - -fx-shadow-highlight-color: transparent; - -fx-outer-border: transparent; - -fx-inner-border: transparent; - -fx-focus-color: #6A9FCD; - -fx-faint-focus-color: transparent; - -fx-background-color: transparent; - -fx-text-background-color: dimgray; - -fx-padding: 0.5em; -} - -.flatButton:selected { - -fx-background-color: -fx-active-background; - -fx-text-fill: white; - -fx-fill: white; -} - -.flatButtonNoSpaceBottom { - -fx-padding: 0.5em 0.5em -0.1em 0.5em; -} - -.flatButtonNoSpaceTop { - -fx-padding: -0.1em 0.5em 0.5em 0.5em; -} diff --git a/src/main/java/org/jabref/gui/MergeDialog.java b/src/main/java/org/jabref/gui/MergeDialog.java index 805e19010a2..8129da56e1b 100644 --- a/src/main/java/org/jabref/gui/MergeDialog.java +++ b/src/main/java/org/jabref/gui/MergeDialog.java @@ -13,6 +13,7 @@ import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComponent; +import javax.swing.JFrame; import javax.swing.JPanel; import org.jabref.Globals; @@ -20,12 +21,8 @@ import org.jabref.logic.l10n.Localization; /** - *

Title: MergeDialog

- *

Description: Asks for details about merge database operation.

- *

Copyright: Copyright (c) 2003

- * @author Morten O. Alver + * Asks for details about merge database operation. */ - public class MergeDialog extends JabRefDialog { private final JPanel panel1 = new JPanel(); @@ -44,7 +41,7 @@ public class MergeDialog extends JabRefDialog { private boolean okPressed; public MergeDialog(JabRefFrame frame, String title, boolean modal) { - super(frame, title, modal, MergeDialog.class); + super((JFrame) null, title, modal, MergeDialog.class); jbInit(); pack(); } @@ -90,7 +87,7 @@ private void jbInit() { // Key bindings: ActionMap am = jPanel1.getActionMap(); InputMap im = jPanel1.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); - im.put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE_DIALOG), "close"); + im.put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE), "close"); am.put("close", new AbstractAction() { @Override diff --git a/src/main/java/org/jabref/gui/PreambleEditor.java b/src/main/java/org/jabref/gui/PreambleEditor.java index ffcfb095c7a..d28cb2c69c7 100644 --- a/src/main/java/org/jabref/gui/PreambleEditor.java +++ b/src/main/java/org/jabref/gui/PreambleEditor.java @@ -1,214 +1,56 @@ package org.jabref.gui; -import java.awt.BorderLayout; -import java.awt.Component; -import java.awt.Container; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.awt.Insets; -import java.awt.event.ActionEvent; -import java.awt.event.FocusAdapter; -import java.awt.event.FocusEvent; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; - -import javax.swing.AbstractAction; -import javax.swing.Action; -import javax.swing.JPanel; -import javax.swing.LayoutFocusTraversalPolicy; -import javax.swing.text.JTextComponent; - -import org.jabref.Globals; -import org.jabref.gui.actions.Actions; -import org.jabref.gui.fieldeditors.FieldEditor; -import org.jabref.gui.fieldeditors.TextArea; -import org.jabref.gui.keyboard.KeyBinding; +import java.util.Optional; + +import javafx.scene.control.ButtonType; +import javafx.scene.control.DialogPane; +import javafx.scene.control.TextArea; + +import org.jabref.gui.actions.SimpleCommand; import org.jabref.gui.undo.UndoablePreambleChange; -import org.jabref.gui.util.WindowLocation; import org.jabref.logic.l10n.Localization; import org.jabref.model.database.BibDatabase; -import org.jabref.preferences.JabRefPreferences; - -class PreambleEditor extends JabRefDialog { - // A reference to the entry this object works on. - private final BibDatabase database; - private final BasePanel panel; - - private final FieldEditor editor; - - private final UndoAction undoAction = new UndoAction(); - private final StoreFieldAction storeFieldAction = new StoreFieldAction(); - private final RedoAction redoAction = new RedoAction(); - // The action concerned with closing the window. - private final CloseAction closeAction = new CloseAction(); - - public PreambleEditor(JabRefFrame baseFrame, BasePanel panel, BibDatabase database) { - super(baseFrame, PreambleEditor.class); - this.panel = panel; - this.database = database; - - addWindowListener(new WindowAdapter() { - - @Override - public void windowClosing(WindowEvent e) { - closeAction.actionPerformed(null); - } - - @Override - public void windowOpened(WindowEvent e) { - editor.requestFocus(); - } - }); - setFocusTraversalPolicy(new LayoutFocusTraversalPolicy() { - - @Override - protected boolean accept(Component c) { - return super.accept(c) && (c instanceof FieldEditor); - } - }); - JPanel pan = new JPanel(); - GridBagLayout gbl = new GridBagLayout(); - pan.setLayout(gbl); - GridBagConstraints con = new GridBagConstraints(); - con.fill = GridBagConstraints.BOTH; - con.weighty = 1; - con.insets = new Insets(10, 5, 10, 5); +class PreambleEditor extends SimpleCommand { - editor = new TextArea(Localization.lang("Preamble"), database.getPreamble().orElse("")); - - // TODO: Reenable this - //setupJTextComponent((TextArea) editor); - - //gbl.setConstraints(editor.getLabel(), con); - //pan.add(editor.getLabel()); - - con.weightx = 1; - - gbl.setConstraints(editor.getPane(), con); - pan.add(editor.getPane()); - - Container conPane = getContentPane(); - conPane.add(pan, BorderLayout.CENTER); - setTitle(Localization.lang("Edit preamble")); - - WindowLocation pw = new WindowLocation(this, JabRefPreferences.PREAMBLE_POS_X, JabRefPreferences.PREAMBLE_POS_Y, - JabRefPreferences.PREAMBLE_SIZE_X, JabRefPreferences.PREAMBLE_SIZE_Y); - pw.displayWindowAtStoredLocation(); - } - - private void setupJTextComponent(JTextComponent ta) { - // Set up key bindings and focus listener for the FieldEditor. - ta.getInputMap().put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE_DIALOG), "close"); - ta.getActionMap().put("close", closeAction); - ta.getInputMap().put(Globals.getKeyPrefs().getKey(KeyBinding.PREAMBLE_EDITOR_STORE_CHANGES), "store"); - ta.getActionMap().put("store", storeFieldAction); - - ta.getInputMap().put(Globals.getKeyPrefs().getKey(KeyBinding.UNDO), "undo"); - ta.getActionMap().put(Actions.UNDO, undoAction); - ta.getInputMap().put(Globals.getKeyPrefs().getKey(KeyBinding.REDO), "redo"); - ta.getActionMap().put(Actions.REDO, redoAction); - - ta.addFocusListener(new FieldListener()); - } - - public void updatePreamble() { - editor.setText(database.getPreamble().orElse("")); - } + private final TextArea editor = new TextArea(); - public FieldEditor getFieldEditor() { - return editor; - } + private final JabRefFrame frame; - public void storeCurrentEdit() { - storeFieldAction.actionPerformed(null); + public PreambleEditor(JabRefFrame frame) { + this.frame = frame; } - private class FieldListener extends FocusAdapter { + @Override + public void execute() { + BasePanel panel = frame.getCurrentBasePanel(); + BibDatabase database = frame.getCurrentBasePanel().getDatabase(); - /* - * Focus listener that fires the storeFieldAction when a TextArea - * loses focus. - */ - @Override - public void focusLost(FocusEvent e) { - if (!e.isTemporary()) { - storeFieldAction.actionPerformed(new ActionEvent(e.getSource(), 0, "")); - } - } + DialogPane pane = new DialogPane(); - } + editor.setText(frame.getCurrentBasePanel() + .getDatabase() + .getPreamble() + .orElse("")); + pane.setContent(editor); - class StoreFieldAction extends AbstractAction { + Optional pressedButton = frame.getDialogService().showCustomDialogAndWait(Localization.lang("Edit Preamble"), pane, ButtonType.APPLY, ButtonType.CANCEL); - public StoreFieldAction() { - super("Store field value"); - putValue(Action.SHORT_DESCRIPTION, "Store field value"); - } - - @Override - public void actionPerformed(ActionEvent e) { - String toSet = editor.getText(); + if (pressedButton.isPresent() && pressedButton.get().equals(ButtonType.APPLY)) { + String newPreamble = editor.getText(); // We check if the field has changed, since we don't want to mark the // base as changed unless we have a real change. - if (!database.getPreamble().orElse("").equals(toSet)) { + if (!database.getPreamble().orElse("").equals(newPreamble)) { + panel.getUndoManager().addEdit( - new UndoablePreambleChange(database, panel, database.getPreamble().orElse(null), toSet)); - database.setPreamble(toSet); - //if ((toSet == null) || toSet.isEmpty()) { - // editor.setLabelColor(GUIGlobals.NULL_FIELD_COLOR); - //} else { - // editor.setLabelColor(GUIGlobals.ENTRY_EDITOR_LABEL_COLOR); - //} - editor.setValidBackgroundColor(); - if (editor.hasFocus()) { - editor.setActiveBackgroundColor(); - } + new UndoablePreambleChange(database, database.getPreamble().orElse(null), newPreamble)); + database.setPreamble(newPreamble); + panel.markBaseChanged(); } - - } - } - - class UndoAction extends AbstractAction { - - public UndoAction() { - super("Undo", IconTheme.JabRefIcon.UNDO.getIcon()); - putValue(Action.SHORT_DESCRIPTION, "Undo"); } - @Override - public void actionPerformed(ActionEvent e) { - panel.runCommand(Actions.UNDO); - } - } - - class RedoAction extends AbstractAction { - - public RedoAction() { - super("Redo", IconTheme.JabRefIcon.REDO.getIcon()); - putValue(Action.SHORT_DESCRIPTION, "Redo"); - } - - @Override - public void actionPerformed(ActionEvent e) { - panel.runCommand(Actions.REDO); - } - } - - class CloseAction extends AbstractAction { - - public CloseAction() { - super(Localization.lang("Close window")); - } - - @Override - public void actionPerformed(ActionEvent e) { - storeFieldAction.actionPerformed(null); - panel.preambleEditorClosing(); - dispose(); - } } } diff --git a/src/main/java/org/jabref/gui/PreviewPanel.java b/src/main/java/org/jabref/gui/PreviewPanel.java index fedb268ae15..b2e39f825e6 100644 --- a/src/main/java/org/jabref/gui/PreviewPanel.java +++ b/src/main/java/org/jabref/gui/PreviewPanel.java @@ -18,6 +18,7 @@ import javafx.scene.web.WebView; import org.jabref.Globals; +import org.jabref.gui.icon.IconTheme; import org.jabref.gui.keyboard.KeyBinding; import org.jabref.gui.keyboard.KeyBindingRepository; import org.jabref.gui.util.BackgroundTask; @@ -26,6 +27,7 @@ import org.jabref.logic.exporter.ExporterFactory; import org.jabref.logic.l10n.Localization; import org.jabref.logic.layout.Layout; +import org.jabref.logic.layout.LayoutFormatterPreferences; import org.jabref.logic.layout.LayoutHelper; import org.jabref.logic.search.SearchQueryHighlightListener; import org.jabref.model.database.BibDatabaseContext; @@ -68,50 +70,48 @@ public class PreviewPanel extends ScrollPane implements SearchQueryHighlightList * @param panel (may be null) Only set this if the preview is associated to the main window. * @param databaseContext (may be null) Used for resolving pdf directories for links. */ - public PreviewPanel(BasePanel panel, BibDatabaseContext databaseContext) { + public PreviewPanel(BasePanel panel, BibDatabaseContext databaseContext, KeyBindingRepository keyBindingRepository, PreviewPreferences preferences, DialogService dialogService) { this.databaseContext = Optional.ofNullable(databaseContext); this.basePanel = Optional.ofNullable(panel); + this.dialogService = dialogService; this.clipBoardManager = new ClipBoardManager(); - this.dialogService = new FXDialogService(); - this.keyBindingRepository = Globals.getKeyPrefs(); + this.keyBindingRepository = keyBindingRepository; + + // Set up scroll pane for preview pane + setFitToHeight(true); + setFitToWidth(true); + previewView = new WebView(); + setContent(previewView); + previewView.setContextMenuEnabled(false); + setContextMenu(createPopupMenu()); + + if (this.basePanel.isPresent()) { + // Handler for drag content of preview to different window + // only created for main window (not for windows like the search results dialog) + setOnDragDetected(event -> { + Dragboard dragboard = startDragAndDrop(TransferMode.COPY); + ClipboardContent content = new ClipboardContent(); + content.putHtml((String) previewView.getEngine().executeScript("window.getSelection().toString()")); + dragboard.setContent(content); - DefaultTaskExecutor.runInJavaFXThread(() -> { - // Set up scroll pane for preview pane - setFitToHeight(true); - setFitToWidth(true); - previewView = new WebView(); - setContent(previewView); - previewView.setContextMenuEnabled(false); - setContextMenu(createPopupMenu()); - - if (this.basePanel.isPresent()) { - // Handler for drag content of preview to different window - // only created for main window (not for windows like the search results dialog) - setOnDragDetected(event -> { - Dragboard dragboard = startDragAndDrop(TransferMode.COPY); - ClipboardContent content = new ClipboardContent(); - content.putHtml((String) previewView.getEngine().executeScript("window.getSelection().toString()")); - dragboard.setContent(content); - - event.consume(); - } - ); - } - createKeyBindings(); - updateLayout(); - }); + event.consume(); + } + ); + } + createKeyBindings(); + updateLayout(preferences); } private void createKeyBindings() { addEventFilter(KeyEvent.KEY_PRESSED, event -> { - Optional keyBinding = Globals.getKeyPrefs().mapToKeyBinding(event); + Optional keyBinding = keyBindingRepository.mapToKeyBinding(event); if (keyBinding.isPresent()) { switch (keyBinding.get()) { case COPY_PREVIEW: copyPreviewToClipBoard(); event.consume(); break; - case CLOSE_DIALOG: + case CLOSE: close(); event.consume(); break; @@ -122,15 +122,15 @@ private void createKeyBindings() { } private ContextMenu createPopupMenu() { - MenuItem copyPreview = new MenuItem(Localization.lang("Copy preview"), IconTheme.JabRefIcon.COPY.getGraphicNode()); + MenuItem copyPreview = new MenuItem(Localization.lang("Copy preview"), IconTheme.JabRefIcons.COPY.getGraphicNode()); copyPreview.setAccelerator(keyBindingRepository.getKeyCombination(KeyBinding.COPY_PREVIEW)); copyPreview.setOnAction(event -> copyPreviewToClipBoard()); - MenuItem printEntryPreview = new MenuItem(Localization.lang("Print entry preview"), IconTheme.JabRefIcon.PRINTED.getGraphicNode()); + MenuItem printEntryPreview = new MenuItem(Localization.lang("Print entry preview"), IconTheme.JabRefIcons.PRINTED.getGraphicNode()); printEntryPreview.setOnAction(event -> print()); - MenuItem previousPreviewLayout = new MenuItem(Localization.menuTitleFX("Previous preview layout")); + MenuItem previousPreviewLayout = new MenuItem(Localization.lang("Previous preview layout")); previousPreviewLayout.setAccelerator(keyBindingRepository.getKeyCombination(KeyBinding.PREVIOUS_PREVIEW_LAYOUT)); previousPreviewLayout.setOnAction(event -> basePanel.ifPresent(BasePanel::previousPreviewStyle)); - MenuItem nextPreviewLayout = new MenuItem(Localization.menuTitleFX("Next preview layout")); + MenuItem nextPreviewLayout = new MenuItem(Localization.lang("Next preview layout")); nextPreviewLayout.setAccelerator(keyBindingRepository.getKeyCombination(KeyBinding.NEXT_PREVIEW_LAYOUT)); nextPreviewLayout.setOnAction(event -> basePanel.ifPresent(BasePanel::nextPreviewStyle)); @@ -161,35 +161,28 @@ public void updateLayout(PreviewPreferences previewPreferences) { return; } - String style = previewPreferences.getPreviewCycle().get(previewPreferences.getPreviewCyclePosition()); - + String style = previewPreferences.getCurrentPreviewStyle(); if (CitationStyle.isCitationStyleFile(style)) { if (basePanel.isPresent()) { layout = Optional.empty(); CitationStyle.createCitationStyleFromFile(style) - .ifPresent(citationStyle -> { - basePanel.get().getCitationStyleCache().setCitationStyle(citationStyle); - basePanel.get().output(Localization.lang("Preview style changed to: %0", citationStyle.getTitle())); - }); + .ifPresent(citationStyle -> { + basePanel.get().getCitationStyleCache().setCitationStyle(citationStyle); + basePanel.get().output(Localization.lang("Preview style changed to: %0", citationStyle.getTitle())); + }); } } else { - updatePreviewLayout(previewPreferences.getPreviewStyle()); + updatePreviewLayout(previewPreferences.getPreviewStyle(), previewPreferences.getLayoutFormatterPreferences()); basePanel.ifPresent(panel -> panel.output(Localization.lang("Preview style changed to: %0", Localization.lang("Preview")))); } update(); } - public void updateLayout() { - updateLayout(Globals.prefs.getPreviewPreferences()); - } - - private void updatePreviewLayout(String layoutFile) { + private void updatePreviewLayout(String layoutFile, LayoutFormatterPreferences layoutFormatterPreferences) { StringReader sr = new StringReader(layoutFile.replace("__NEWLINE__", "\n")); try { - layout = Optional.of( - new LayoutHelper(sr, Globals.prefs.getLayoutFormatterPreferences(Globals.journalAbbreviationLoader)) - .getLayoutFromText()); + layout = Optional.of(new LayoutHelper(sr, layoutFormatterPreferences).getLayoutFromText()); } catch (IOException e) { layout = Optional.empty(); LOGGER.debug("no layout could be set", e); @@ -274,7 +267,7 @@ public void highlightPattern(Optional newPattern) { */ public void setFixedLayout(String layout) { this.fixedLayout = true; - updatePreviewLayout(layout); + updatePreviewLayout(layout, Globals.prefs.getLayoutFormatterPreferences(Globals.journalAbbreviationLoader)); } public void print() { @@ -295,7 +288,7 @@ public void print() { } public void close() { - basePanel.ifPresent(BasePanel::hideBottomComponent); + basePanel.ifPresent(BasePanel::closeBottomPane); } private void copyPreviewToClipBoard() { diff --git a/src/main/java/org/jabref/gui/ReplaceStringDialog.java b/src/main/java/org/jabref/gui/ReplaceStringDialog.java index 6d5175bd9be..10fd5ccc1cf 100644 --- a/src/main/java/org/jabref/gui/ReplaceStringDialog.java +++ b/src/main/java/org/jabref/gui/ReplaceStringDialog.java @@ -16,6 +16,7 @@ import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComponent; +import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JRadioButton; @@ -47,7 +48,7 @@ class ReplaceStringDialog extends JabRefDialog { public ReplaceStringDialog(JabRefFrame parent) { - super(parent, Localization.lang("Replace string"), true, ReplaceStringDialog.class); + super((JFrame) null, Localization.lang("Replace string"), true, ReplaceStringDialog.class); ButtonGroup bg = new ButtonGroup(); bg.add(allFi); @@ -80,7 +81,7 @@ public void actionPerformed(ActionEvent e) { JPanel settings = new JPanel(); ActionMap am = settings.getActionMap(); InputMap im = settings.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); - im.put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE_DIALOG), "close"); + im.put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE), "close"); am.put("close", cancelAction); // Layout starts here. @@ -162,8 +163,6 @@ public void actionPerformed(ActionEvent e) { getContentPane().add(opt, BorderLayout.SOUTH); pack(); - - this.setLocationRelativeTo(parent); } public boolean okPressed() { diff --git a/src/main/java/org/jabref/gui/SidePane.java b/src/main/java/org/jabref/gui/SidePane.java index 353b74bfc6f..b4f22230346 100644 --- a/src/main/java/org/jabref/gui/SidePane.java +++ b/src/main/java/org/jabref/gui/SidePane.java @@ -1,94 +1,30 @@ package org.jabref.gui; -import java.awt.BorderLayout; -import java.awt.Component; -import java.awt.Dimension; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.awt.Insets; import java.util.Collection; -import javax.swing.Box; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.ScrollPaneConstants; +import javafx.scene.layout.BorderPane; +import javafx.scene.layout.VBox; /** - * The side pane is displayed at the left side of JabRef and shows instances of - * SidePaneComponents, for instance the GroupSelector, or the SearchManager. + * The side pane is displayed at the left side of JabRef and shows instances of {@link SidePaneComponent}. */ -public class SidePane extends JPanel { - - private final Dimension PREFERRED_SIZE = new Dimension(220, 100); - - private final GridBagLayout gridBagLayout = new GridBagLayout(); - - private final GridBagConstraints constraint = new GridBagConstraints(); - - private final JPanel mainPanel = new JPanel(); +public class SidePane extends BorderPane { + private final VBox mainPanel = new VBox(); public SidePane() { - // For debugging the border: - // setBorder(BorderFactory.createLineBorder(Color.BLUE)); - - setLayout(new BorderLayout()); - mainPanel.setLayout(gridBagLayout); - - // Initialize constraint - constraint.anchor = GridBagConstraints.NORTH; - constraint.fill = GridBagConstraints.BOTH; - constraint.gridwidth = GridBagConstraints.REMAINDER; - constraint.insets = new Insets(1, 1, 1, 1); - constraint.gridheight = 1; - constraint.weightx = 1; - - /* - * Added Scrollpane to fix: - */ - JScrollPane sp = new JScrollPane(mainPanel, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, - ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); - sp.setBorder(null); - - // To remove the scroll panel just change sp to mainPanel and comment - // the JScrollPane declaration - super.add(sp); + setCenter(mainPanel); } - public void setComponents(Collection comps) { - mainPanel.removeAll(); + public void setComponents(Collection components) { + mainPanel.getChildren().clear(); - int totalWeights = 0; - for (SidePaneComponent c : comps) { - constraint.weighty = c.getRescalingWeight(); - totalWeights += c.getRescalingWeight(); - gridBagLayout.setConstraints(c, constraint); - mainPanel.add(c); + for (SidePaneComponent component : components) { + BorderPane node = new BorderPane(); + node.setTop(component.getHeader()); + node.setCenter(component.getContentPane()); + mainPanel.getChildren().add(node); + VBox.setVgrow(node, component.getResizePolicy()); } - if (totalWeights <= 0) { - // Fill vertical space so that components start at top - constraint.weighty = 1; - Component bx = Box.createVerticalGlue(); - gridBagLayout.setConstraints(bx, constraint); - mainPanel.add(bx); - } - - revalidate(); - repaint(); - } - - @Override - public void remove(Component c) { - mainPanel.remove(c); - } - - @Override - public Dimension getMaximumSize() { - return getPreferredSize(); - } - - @Override - public Dimension getPreferredSize() { - return PREFERRED_SIZE; } } diff --git a/src/main/java/org/jabref/gui/SidePaneComponent.java b/src/main/java/org/jabref/gui/SidePaneComponent.java index d6d54678b57..603a1bb1407 100644 --- a/src/main/java/org/jabref/gui/SidePaneComponent.java +++ b/src/main/java/org/jabref/gui/SidePaneComponent.java @@ -1,165 +1,158 @@ package org.jabref.gui; -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Insets; -import java.awt.event.ActionEvent; -import java.awt.event.InputEvent; - -import javax.swing.Action; -import javax.swing.BorderFactory; -import javax.swing.Icon; -import javax.swing.JButton; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.JToolBar; -import javax.swing.KeyStroke; - -import org.jabref.gui.actions.MnemonicAwareAction; - -public abstract class SidePaneComponent extends JPanel { - - protected final JButton close = new JButton(IconTheme.JabRefIcon.CLOSE.getSmallIcon()); - - protected final SidePaneManager manager; - - protected BasePanel panel; - - - public SidePaneComponent(SidePaneManager manager, Icon icon, String title) { - super(new BorderLayout()); +import java.util.Collections; +import java.util.List; + +import javafx.scene.Node; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.Tooltip; +import javafx.scene.layout.BorderPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; + +import org.jabref.gui.actions.Action; +import org.jabref.gui.actions.SimpleCommand; +import org.jabref.gui.icon.IconTheme; +import org.jabref.gui.icon.JabRefIcon; +import org.jabref.logic.l10n.Localization; + +public abstract class SidePaneComponent { + + private final SidePaneManager manager; + private final ToggleCommand toggleCommand; + private final JabRefIcon icon; + private final String title; + private Node contentNode; + + public SidePaneComponent(SidePaneManager manager, JabRefIcon icon, String title) { this.manager = manager; + this.icon = icon; + this.title = title; + this.toggleCommand = new ToggleCommand(this); - setBorder(BorderFactory.createEmptyBorder()); - - close.setMargin(new Insets(0, 0, 0, 0)); - close.setBorder(null); - close.addActionListener(e -> hideAway()); - - JButton up = new JButton(IconTheme.JabRefIcon.UP.getSmallIcon()); - up.setMargin(new Insets(0, 0, 0, 0)); - up.setBorder(null); - up.addActionListener(e -> moveUp()); - - JButton down = new JButton(IconTheme.JabRefIcon.DOWN.getSmallIcon()); - down.setMargin(new Insets(0, 0, 0, 0)); - down.setBorder(null); - down.addActionListener(e -> moveDown()); - - JPanel titlePanel = new JPanel(new BorderLayout()); - titlePanel.add(new JLabel(icon), BorderLayout.WEST); - JLabel titleLabel = new JLabel(title); - titleLabel.setOpaque(true); - titleLabel.setForeground(new Color(79, 95, 143)); - titlePanel.add(titleLabel, BorderLayout.CENTER); - - JToolBar toolbar = new OSXCompatibleToolbar(); - toolbar.add(up); - toolbar.add(down); - toolbar.add(close); - toolbar.setOpaque(false); - toolbar.setFloatable(false); - - titlePanel.add(toolbar, BorderLayout.EAST); - - - this.add(titlePanel, BorderLayout.NORTH); } - public void setContentContainer(JPanel panel) { - this.add(panel, BorderLayout.CENTER); + protected void hide() { + manager.hide(this.getType()); } - private void hideAway() { - manager.hideComponent(this); + protected void show() { + manager.show(this.getType()); } - private void moveUp() { + protected void moveUp() { manager.moveUp(this); } - private void moveDown() { + protected void moveDown() { manager.moveDown(this); } - public void setActiveBasePanel(BasePanel panel) { - this.panel = panel; + /** + * Override this method if the component needs to make any changes before it can close. + */ + public void beforeClosing() { + // Nothing to do by default } - public BasePanel getActiveBasePanel() { - return panel; + /** + * Override this method if the component needs to do any actions after it is shown. + */ + public void afterOpening() { + // Nothing to do by default } /** - * Override this method if the component needs to make any changes before it can close. + * Specifies how to this side pane component behaves if there is additional vertical space. + */ + public abstract Priority getResizePolicy(); + + /** + * @return the command which toggles this {@link SidePaneComponent} + */ + public ToggleCommand getToggleCommand() { + return toggleCommand; + } + + /** + * @return the action to toggle this {@link SidePaneComponent} + */ + public abstract Action getToggleAction(); + + /** + * @return the content of this component */ - public void componentClosing() { - // Nothing right now + public final Node getContentPane() { + if (contentNode == null) { + contentNode = createContentPane(); + } + + return contentNode; } /** - * Override this method if the component needs to do any actions when opening. + * @return the header pane for this component */ - public void componentOpening() { - // Nothing right now + public final Node getHeader() { + Button close = IconTheme.JabRefIcons.CLOSE.asButton(); + close.setTooltip(new Tooltip(Localization.lang("Hide panel"))); + close.setOnAction(event -> hide()); + + Button up = IconTheme.JabRefIcons.UP.asButton(); + up.setTooltip(new Tooltip(Localization.lang("Move panel up"))); + up.setOnAction(event -> moveUp()); + + Button down = IconTheme.JabRefIcons.DOWN.asButton(); + down.setTooltip(new Tooltip(Localization.lang("Move panel down"))); + down.setOnAction(event -> moveDown()); + + final HBox buttonContainer = new HBox(); + buttonContainer.getChildren().addAll(up, down); + buttonContainer.getChildren().addAll(getAdditionalHeaderButtons()); + buttonContainer.getChildren().add(close); + + BorderPane graphic = new BorderPane(); + graphic.setCenter(icon.getGraphicNode()); + + final Label label = new Label(title); + BorderPane container = new BorderPane(); + container.setCenter(label); + container.setRight(buttonContainer); + container.getStyleClass().add("sidePaneComponentHeader"); + + return container; } - @Override - public Dimension getMinimumSize() { - return getPreferredSize(); + protected List getAdditionalHeaderButtons() { + return Collections.emptyList(); } /** - * Specifies how to distribute extra vertical space between side pane components. - * 0: fixed height, 1: fill the remaining space + * Create the content of this component + * + * @implNote The {@link SidePaneManager} always creates an instance of every side component (e.g., to get the toggle action) + * but we only want to create the content view if the component is shown to save resources. + * This is the reason for the lazy loading. */ - public abstract int getRescalingWeight(); + protected abstract Node createContentPane(); /** - * @return the action which toggles this {@link SidePaneComponent} + * @return the type of this component */ - public abstract ToggleAction getToggleAction(); + public abstract SidePaneType getType(); - public class ToggleAction extends MnemonicAwareAction { + public class ToggleCommand extends SimpleCommand { - public ToggleAction(String text, String description, KeyStroke key, IconTheme.JabRefIcon icon) { - super(icon.getIcon()); - putValue(Action.NAME, text); - putValue(Action.ACCELERATOR_KEY, key); - putValue(Action.SHORT_DESCRIPTION, description); - } + private final SidePaneComponent component; - public ToggleAction(String text, String description, KeyStroke key, Icon icon) { - super(icon); - putValue(Action.NAME, text); - putValue(Action.ACCELERATOR_KEY, key); - putValue(Action.SHORT_DESCRIPTION, description); + public ToggleCommand(SidePaneComponent component) { + this.component = component; } @Override - public void actionPerformed(ActionEvent e) { - if (!manager.hasComponent(SidePaneComponent.this.getClass())) { - manager.register(SidePaneComponent.this); - } - - // if clicked by mouse just toggle - if ((e.getModifiers() & InputEvent.BUTTON1_MASK) != 0) { - manager.toggle(SidePaneComponent.this.getClass()); - } else { - manager.toggleThreeWay(SidePaneComponent.this.getClass()); - } - putValue(Action.SELECTED_KEY, manager.isComponentVisible(SidePaneComponent.this.getClass())); - } - - public void setSelected(boolean selected) { - putValue(Action.SELECTED_KEY, selected); - } - - public boolean isSelected() { - return Boolean.TRUE.equals(getValue(Action.SELECTED_KEY)); + public void execute() { + manager.toggle(component.getType()); } - } - } diff --git a/src/main/java/org/jabref/gui/SidePaneManager.java b/src/main/java/org/jabref/gui/SidePaneManager.java index d9af9434c18..f878614b4ec 100644 --- a/src/main/java/org/jabref/gui/SidePaneManager.java +++ b/src/main/java/org/jabref/gui/SidePaneManager.java @@ -1,233 +1,137 @@ package org.jabref.gui; -import java.util.Collections; import java.util.Comparator; -import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; - -import javax.swing.SwingUtilities; +import java.util.stream.Stream; import org.jabref.Globals; -import org.jabref.gui.maintable.MainTable; +import org.jabref.gui.collab.FileUpdatePanel; +import org.jabref.gui.groups.GroupSidePane; +import org.jabref.gui.importer.fetcher.GeneralFetcher; +import org.jabref.gui.openoffice.OpenOfficeSidePanel; +import org.jabref.logic.openoffice.OpenOfficePreferences; import org.jabref.preferences.JabRefPreferences; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - /** - * Manages visibility of SideShowComponents in a given newly constructed - * sidePane. + * Manages which {@link SidePaneComponent}s are shown. */ public class SidePaneManager { - private static final Logger LOGGER = LoggerFactory.getLogger(SidePaneManager.class); - private final JabRefFrame frame; + private final SidePane sidePane; + private final Map components = new LinkedHashMap<>(); + private final List visibleComponents = new LinkedList<>(); + private final JabRefPreferences preferences; - private final SidePane sidep; + public SidePaneManager(JabRefPreferences preferences, JabRefFrame frame) { + this.preferences = preferences; + this.sidePane = new SidePane(); - private final Map, SidePaneComponent> components = new LinkedHashMap<>(); + OpenOfficePreferences openOfficePreferences = preferences.getOpenOfficePreferences(); + Stream.of( + new FileUpdatePanel(this), + new GroupSidePane(this, preferences, frame.getDialogService()), + new GeneralFetcher(this, preferences, frame), + new OpenOfficeSidePanel(this, openOfficePreferences, frame)) + .forEach(pane -> components.put(pane.getType(), pane)); - private final List visible = new LinkedList<>(); + if (preferences.getBoolean(JabRefPreferences.GROUP_SIDEPANE_VISIBLE)) { + show(SidePaneType.GROUPS); + } - public SidePaneManager(JabRefFrame frame) { - this.frame = frame; - /* - * Change by Morten Alver 2005.12.04: By postponing the updating of the - * side pane components, we get rid of the annoying latency when - * switching tabs: - */ - frame.getTabbedPane().addChangeListener(event -> SwingUtilities.invokeLater( - () -> setActiveBasePanel(SidePaneManager.this.frame.getCurrentBasePanel()))); - sidep = new SidePane(); - sidep.setVisible(false); + if (openOfficePreferences.getShowPanel()) { + show(SidePaneType.OPEN_OFFICE); + } } - public SidePane getPanel() { - return sidep; + public SidePane getPane() { + return sidePane; } - public synchronized boolean hasComponent(Class sidePaneComponent) { - return components.containsKey(sidePaneComponent); + public boolean isComponentVisible(SidePaneType type) { + return visibleComponents.contains(getComponent(type)); } - public synchronized boolean isComponentVisible(Class sidePaneComponent) { - SidePaneComponent component = components.get(sidePaneComponent); + public SidePaneComponent getComponent(SidePaneType type) { + SidePaneComponent component = components.get(type); if (component == null) { - return false; + throw new IllegalStateException("Side component " + type + " not registered."); } else { - return visible.contains(component); + return component; } } /** - * If panel is visible it will be hidden and the other way around + * If the given component is visible it will be hidden and the other way around. */ - public synchronized void toggle(Class sidePaneComponent) { - if (isComponentVisible(sidePaneComponent)) { - hide(sidePaneComponent); + public void toggle(SidePaneType type) { + if (isComponentVisible(type)) { + hide(type); } else { - show(sidePaneComponent); + show(type); } } /** - * If panel is hidden it will be shown and focused - * If panel is visible but not focused it will be focused - * If panel is visible and focused it will be hidden + * Makes sure that the given component is visible. */ - public synchronized void toggleThreeWay(Class sidePaneComponent) { - boolean isPanelFocused = Globals.getFocusListener().getFocused() == components.get(sidePaneComponent); - if (isComponentVisible(sidePaneComponent) && isPanelFocused) { - hide(sidePaneComponent); - } else { - show(sidePaneComponent); - } - } - - public synchronized void show(Class sidePaneComponent) { - SidePaneComponent component = components.get(sidePaneComponent); - if (component == null) { - LOGGER.warn("Side pane component '" + sidePaneComponent + "' unknown."); - } else { - show(component); - } - } - - public synchronized void hide(Class sidePaneComponent) { - SidePaneComponent component = components.get(sidePaneComponent); - if (component == null) { - LOGGER.warn("Side pane component '" + sidePaneComponent + "' unknown."); - } else { - hideComponent(component); - if (frame.getCurrentBasePanel() != null) { - MainTable mainTable = frame.getCurrentBasePanel().getMainTable(); - mainTable.setSelected(mainTable.getSelectedRow()); - mainTable.requestFocus(); - } - } - } - - public synchronized void register(SidePaneComponent comp) { - components.put(comp.getClass(), comp); - } - - private synchronized void show(SidePaneComponent component) { - if (!visible.contains(component)) { - // Put the new component at the top of the group - visible.add(0, component); + public void show(SidePaneType type) { + SidePaneComponent component = getComponent(type); + if (!visibleComponents.contains(component)) { + // Add the new component + visibleComponents.add(component); // Sort the visible components by their preferred position - Collections.sort(visible, new PreferredIndexSort()); - - updateView(); - component.componentOpening(); - } - Globals.getFocusListener().setFocused(component); - component.grabFocus(); - } - - public synchronized SidePaneComponent getComponent(Class sidePaneComponent) { - return components.get(sidePaneComponent); - } + visibleComponents.sort(new PreferredIndexSort()); - public synchronized void hideComponent(SidePaneComponent comp) { - if (visible.contains(comp)) { - comp.componentClosing(); - visible.remove(comp); updateView(); - } - } - public synchronized void hideComponent(Class sidePaneComponent) { - SidePaneComponent component = components.get(sidePaneComponent); - if (component == null) { - return; - } - if (visible.contains(component)) { - component.componentClosing(); - visible.remove(component); - updateView(); + component.afterOpening(); } } - private static Map, Integer> getPreferredPositions() { - Map, Integer> preferredPositions = new HashMap<>(); + /** + * Makes sure that the given component is not visible. + */ + public void hide(SidePaneType type) { + SidePaneComponent component = getComponent(type); + if (visibleComponents.contains(component)) { + component.beforeClosing(); - List componentNames = Globals.prefs.getStringList(JabRefPreferences.SIDE_PANE_COMPONENT_NAMES); - List componentPositions = Globals.prefs - .getStringList(JabRefPreferences.SIDE_PANE_COMPONENT_PREFERRED_POSITIONS); + visibleComponents.remove(component); - for (int i = 0; i < componentNames.size(); ++i) { - String componentName = componentNames.get(i); - try { - Class componentClass = (Class) Class.forName(componentName); - preferredPositions.put(componentClass, Integer.parseInt(componentPositions.get(i))); - } catch (ClassNotFoundException e) { - LOGGER.debug("Following side pane could not be found: " + componentName, e); - } catch (ClassCastException e) { - LOGGER.debug("Following Class is no side pane: '" + componentName, e); - } catch (NumberFormatException e) { - LOGGER.debug("Invalid number format for side pane component '" + componentName + "'.", e); - } + updateView(); } - - return preferredPositions; } + /** + * Stores the current configuration of visible components in the preferences, + * so that we show components at the preferred position next time. + */ private void updatePreferredPositions() { - Map, Integer> preferredPositions = getPreferredPositions(); + Map preferredPositions = preferences.getSidePanePreferredPositions(); - // Update the preferred positions of all visible components + // Use the currently shown positions of all visible components int index = 0; - for (SidePaneComponent comp : visible) { - preferredPositions.put(comp.getClass(), index); + for (SidePaneComponent comp : visibleComponents) { + preferredPositions.put(comp.getType(), index); index++; } - - // Split the map into a pair of parallel String lists suitable for storage - List tmpComponentNames = preferredPositions.keySet().parallelStream() - .map(Class::getName) - .collect(Collectors.toList()); - - List componentPositions = preferredPositions.values().stream().map(Object::toString) - .collect(Collectors.toList()); - - Globals.prefs.putStringList(JabRefPreferences.SIDE_PANE_COMPONENT_NAMES, tmpComponentNames); - Globals.prefs.putStringList(JabRefPreferences.SIDE_PANE_COMPONENT_PREFERRED_POSITIONS, componentPositions); + preferences.storeSidePanePreferredPositions(preferredPositions); } - /** - * Helper class for sorting visible components based on their preferred position + * Moves the given component up. */ - private class PreferredIndexSort implements Comparator { - - private final Map, Integer> preferredPositions; - - - public PreferredIndexSort() { - preferredPositions = getPreferredPositions(); - } - - @Override - public int compare(SidePaneComponent comp1, SidePaneComponent comp2) { - int pos1 = preferredPositions.getOrDefault(comp1.getClass(), 0); - int pos2 = preferredPositions.getOrDefault(comp2.getClass(), 0); - return Integer.valueOf(pos1).compareTo(pos2); - } - } - - public synchronized void moveUp(SidePaneComponent comp) { - if (visible.contains(comp)) { - int currIndex = visible.indexOf(comp); - if (currIndex > 0) { - int newIndex = currIndex - 1; - visible.remove(currIndex); - visible.add(newIndex, comp); + public void moveUp(SidePaneComponent component) { + if (visibleComponents.contains(component)) { + int currentPosition = visibleComponents.indexOf(component); + if (currentPosition > 0) { + int newPosition = currentPosition - 1; + visibleComponents.remove(currentPosition); + visibleComponents.add(newPosition, component); updatePreferredPositions(); updateView(); @@ -235,13 +139,16 @@ public synchronized void moveUp(SidePaneComponent comp) { } } - public synchronized void moveDown(SidePaneComponent comp) { - if (visible.contains(comp)) { - int currIndex = visible.indexOf(comp); - if (currIndex < (visible.size() - 1)) { - int newIndex = currIndex + 1; - visible.remove(currIndex); - visible.add(newIndex, comp); + /** + * Moves the given component down. + */ + public void moveDown(SidePaneComponent comp) { + if (visibleComponents.contains(comp)) { + int currentPosition = visibleComponents.indexOf(comp); + if (currentPosition < (visibleComponents.size() - 1)) { + int newPosition = currentPosition + 1; + visibleComponents.remove(currentPosition); + visibleComponents.add(newPosition, comp); updatePreferredPositions(); updateView(); @@ -249,40 +156,35 @@ public synchronized void moveDown(SidePaneComponent comp) { } } - public synchronized void unregisterComponent(Class sidePaneComponent) { - components.remove(sidePaneComponent); + /** + * Updates the view to reflect changes to visible components. + */ + private void updateView() { + sidePane.setComponents(visibleComponents); + + if (visibleComponents.isEmpty()) { + sidePane.setVisible(false); + } else { + sidePane.setVisible(true); + } } /** - * Update all side pane components to show information from the given - * BasePanel. - * - * @param panel + * Helper class for sorting visible components based on their preferred position. */ - private synchronized void setActiveBasePanel(BasePanel panel) { - for (SidePaneComponent component : components.values()) { - component.setActiveBasePanel(panel); + private class PreferredIndexSort implements Comparator { + + private final Map preferredPositions; + + public PreferredIndexSort() { + preferredPositions = Globals.prefs.getSidePanePreferredPositions(); } - } - public synchronized void updateView() { - sidep.setComponents(visible); - if (visible.isEmpty()) { - if (sidep.isVisible()) { - Globals.prefs.putInt(JabRefPreferences.SIDE_PANE_WIDTH, frame.getSplitPane().getDividerLocation()); - } - sidep.setVisible(false); - } else { - boolean wasVisible = sidep.isVisible(); - sidep.setVisible(true); - if (!wasVisible) { - int width = Globals.prefs.getInt(JabRefPreferences.SIDE_PANE_WIDTH); - if (width > 0) { - frame.getSplitPane().setDividerLocation(width); - } else { - frame.getSplitPane().setDividerLocation(getPanel().getPreferredSize().width); - } - } + @Override + public int compare(SidePaneComponent comp1, SidePaneComponent comp2) { + int pos1 = preferredPositions.getOrDefault(comp1.getType(), 0); + int pos2 = preferredPositions.getOrDefault(comp2.getType(), 0); + return Integer.compare(pos1, pos2); } } } diff --git a/src/main/java/org/jabref/gui/SidePaneType.java b/src/main/java/org/jabref/gui/SidePaneType.java new file mode 100644 index 00000000000..cd60411cf61 --- /dev/null +++ b/src/main/java/org/jabref/gui/SidePaneType.java @@ -0,0 +1,8 @@ +package org.jabref.gui; + +/** + * Definition of all possible components in the side pane. + */ +public enum SidePaneType { + OPEN_OFFICE, WEB_SEARCH, FILE_UPDATE_NOTIFICATION, GROUPS +} diff --git a/src/main/java/org/jabref/gui/StateManager.java b/src/main/java/org/jabref/gui/StateManager.java index c09a7024372..2acc073ae7b 100644 --- a/src/main/java/org/jabref/gui/StateManager.java +++ b/src/main/java/org/jabref/gui/StateManager.java @@ -14,6 +14,7 @@ import javafx.collections.ObservableList; import javafx.collections.ObservableMap; +import org.jabref.logic.search.SearchQuery; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; import org.jabref.model.groups.GroupTreeNode; @@ -36,6 +37,7 @@ public class StateManager { private final ReadOnlyListWrapper activeGroups = new ReadOnlyListWrapper<>(FXCollections.observableArrayList()); private final ObservableList selectedEntries = FXCollections.observableArrayList(); private final ObservableMap> selectedGroups = FXCollections.observableHashMap(); + private final ObjectProperty> activeSearchQuery = new SimpleObjectProperty<>(Optional.empty()); public StateManager() { MonadicBinding currentDatabase = EasyBind.map(activeDatabase, database -> database.orElse(null)); @@ -46,6 +48,10 @@ public ObjectProperty> activeDatabaseProperty() { return activeDatabase; } + public ObjectProperty> activeSearchQueryProperty() { + return activeSearchQuery; + } + public ReadOnlyListProperty activeGroupProperty() { return activeGroups.getReadOnlyProperty(); } @@ -80,4 +86,12 @@ public List getEntriesInCurrentDatabase() { return OptionalUtil.flatMap(activeDatabase.get(), BibDatabaseContext::getEntries) .collect(Collectors.toList()); } + + public void clearSearchQuery() { + activeSearchQuery.setValue(Optional.empty()); + } + + public void setSearchQuery(SearchQuery searchQuery) { + activeSearchQuery.setValue(Optional.of(searchQuery)); + } } diff --git a/src/main/java/org/jabref/gui/StringDialog.java b/src/main/java/org/jabref/gui/StringDialog.java index d79dbb67383..796a557dbec 100644 --- a/src/main/java/org/jabref/gui/StringDialog.java +++ b/src/main/java/org/jabref/gui/StringDialog.java @@ -33,6 +33,7 @@ import org.jabref.Globals; import org.jabref.gui.actions.Actions; import org.jabref.gui.help.HelpAction; +import org.jabref.gui.icon.IconTheme; import org.jabref.gui.keyboard.KeyBinding; import org.jabref.gui.undo.UndoableInsertString; import org.jabref.gui.undo.UndoableRemoveString; @@ -65,7 +66,7 @@ class StringDialog extends JabRefDialog { public StringDialog(JabRefFrame frame, BasePanel panel, BibDatabase base) { - super(frame, StringDialog.class); + super(null, StringDialog.class); this.panel = panel; this.base = base; @@ -119,7 +120,7 @@ protected boolean accept(Component c) { am.put("remove", removeStringAction); im.put(Globals.getKeyPrefs().getKey(KeyBinding.SAVE_DATABASE), "save"); am.put("save", saveAction); - im.put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE_DIALOG), "close"); + im.put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE), "close"); am.put("close", closeAction); im.put(Globals.getKeyPrefs().getKey(KeyBinding.HELP), "help"); am.put("help", helpAction); @@ -190,7 +191,7 @@ static class SaveDatabaseAction extends AbstractAction { public SaveDatabaseAction(StringDialog parent) { - super("Save library", IconTheme.JabRefIcon.SAVE.getIcon()); + super("Save library", IconTheme.JabRefIcons.SAVE.getIcon()); putValue(Action.SHORT_DESCRIPTION, Localization.lang("Save library")); this.parent = parent; } @@ -217,8 +218,7 @@ public StringTable(StringTableModel stm) { TableColumnModel cm = getColumnModel(); cm.getColumn(0).setPreferredWidth(800); cm.getColumn(1).setPreferredWidth(2000); - sp.getViewport().setBackground(Globals.prefs.getColor(JabRefPreferences.TABLE_BACKGROUND)); - getInputMap().put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE_DIALOG), "close"); + getInputMap().put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE), "close"); getActionMap().put("close", closeAction); getInputMap().put(Globals.getKeyPrefs().getKey(KeyBinding.HELP), "help"); getActionMap().put("help", helpAction); @@ -336,7 +336,7 @@ class NewStringAction extends AbstractAction { public NewStringAction(StringDialog parent) { - super("New string", IconTheme.JabRefIcon.ADD.getIcon()); + super("New string", IconTheme.JabRefIcons.ADD.getIcon()); putValue(Action.SHORT_DESCRIPTION, Localization.lang("New string")); this.parent = parent; } @@ -385,7 +385,7 @@ class RemoveStringAction extends AbstractAction { public RemoveStringAction(StringDialog parent) { - super("Remove selected strings", IconTheme.JabRefIcon.REMOVE.getIcon()); + super("Remove selected strings", IconTheme.JabRefIcons.REMOVE.getIcon()); putValue(Action.SHORT_DESCRIPTION, Localization.lang("Remove selected strings")); this.parent = parent; } @@ -430,7 +430,7 @@ public void actionPerformed(ActionEvent e) { class UndoAction extends AbstractAction { public UndoAction() { - super("Undo", IconTheme.JabRefIcon.UNDO.getIcon()); + super("Undo", IconTheme.JabRefIcons.UNDO.getIcon()); putValue(Action.SHORT_DESCRIPTION, Localization.lang("Undo")); } @@ -443,7 +443,7 @@ public void actionPerformed(ActionEvent e) { class RedoAction extends AbstractAction { public RedoAction() { - super("Redo", IconTheme.JabRefIcon.REDO.getIcon()); + super("Redo", IconTheme.JabRefIcons.REDO.getIcon()); putValue(Action.SHORT_DESCRIPTION, Localization.lang("Redo")); } diff --git a/src/main/java/org/jabref/gui/WaitForSaveOperation.java b/src/main/java/org/jabref/gui/WaitForSaveOperation.java index 8d10d066884..86b2e0a2f8b 100644 --- a/src/main/java/org/jabref/gui/WaitForSaveOperation.java +++ b/src/main/java/org/jabref/gui/WaitForSaveOperation.java @@ -7,6 +7,7 @@ import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JDialog; +import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JProgressBar; import javax.swing.Timer; @@ -33,7 +34,7 @@ public WaitForSaveOperation(JabRefFrame frame) { JProgressBar prog = new JProgressBar(0); prog.setIndeterminate(true); prog.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); - diag = new JDialog(frame, Localization.lang("Please wait..."), true); + diag = new JDialog((JFrame) null, Localization.lang("Please wait..."), true); ButtonBarBuilder bb = new ButtonBarBuilder(); bb.addGlue(); @@ -55,7 +56,6 @@ public WaitForSaveOperation(JabRefFrame frame) { } public void show() { - diag.setLocationRelativeTo(frame); t.start(); diag.setVisible(true); diff --git a/src/main/java/org/jabref/gui/actions/Action.java b/src/main/java/org/jabref/gui/actions/Action.java new file mode 100644 index 00000000000..5d940ffba55 --- /dev/null +++ b/src/main/java/org/jabref/gui/actions/Action.java @@ -0,0 +1,16 @@ +package org.jabref.gui.actions; + +import java.util.Optional; + +import org.jabref.gui.icon.JabRefIcon; +import org.jabref.gui.keyboard.KeyBinding; + +public interface Action { + Optional getIcon(); + + Optional getKeyBinding(); + + String getText(); + + String getDescription(); +} diff --git a/src/main/java/org/jabref/gui/actions/ActionFactory.java b/src/main/java/org/jabref/gui/actions/ActionFactory.java new file mode 100644 index 00000000000..5183ca1cc80 --- /dev/null +++ b/src/main/java/org/jabref/gui/actions/ActionFactory.java @@ -0,0 +1,68 @@ +package org.jabref.gui.actions; + +import java.util.Objects; + +import javafx.scene.control.Button; +import javafx.scene.control.Menu; +import javafx.scene.control.MenuItem; + +import org.jabref.gui.keyboard.KeyBindingRepository; + +import de.saxsys.mvvmfx.utils.commands.Command; +import org.controlsfx.control.action.ActionUtils; + +/** + * Helper class to create and style controls according to an {@link Action}. + */ +public class ActionFactory { + + private final KeyBindingRepository keyBindingRepository; + + public ActionFactory(KeyBindingRepository keyBindingRepository) { + this.keyBindingRepository = Objects.requireNonNull(keyBindingRepository); + } + + /** + * For some reason the graphic is not set correctly by the {@link ActionUtils} class, so we have to fix this by hand + */ + private static void setGraphic(MenuItem node, Action action) { + node.graphicProperty().unbind(); + action.getIcon().ifPresent(icon -> node.setGraphic(icon.getGraphicNode())); + } + + public MenuItem configureMenuItem(Action action, Command command, MenuItem menuItem) { + return ActionUtils.configureMenuItem(new JabRefAction(action, command, keyBindingRepository), menuItem); + } + + public MenuItem createMenuItem(Action action, Command command) { + MenuItem menuItem = ActionUtils.createMenuItem(new JabRefAction(action, command, keyBindingRepository)); + setGraphic(menuItem, action); + + return menuItem; + } + + public Menu createMenu(Action action) { + Menu menu = ActionUtils.createMenu(new JabRefAction(action, keyBindingRepository)); + + // For some reason the graphic is not set correctly, so let's fix this + setGraphic(menu, action); + return menu; + } + + public Menu createSubMenu(Action action, MenuItem... children) { + Menu menu = createMenu(action); + menu.getItems().addAll(children); + return menu; + } + + public Button createIconButton(Action action, Command command) { + Button button = ActionUtils.createButton(new JabRefAction(action, command, keyBindingRepository), ActionUtils.ActionTextBehavior.HIDE); + button.getStyleClass().setAll("flatButton"); + + // For some reason the graphic is not set correctly, so let's fix this + button.graphicProperty().unbind(); + action.getIcon().ifPresent(icon -> button.setGraphic(icon.getGraphicNode())); + + return button; + } +} diff --git a/src/main/java/org/jabref/gui/actions/Actions.java b/src/main/java/org/jabref/gui/actions/Actions.java index 8f93cd76970..3f5522e095e 100644 --- a/src/main/java/org/jabref/gui/actions/Actions.java +++ b/src/main/java/org/jabref/gui/actions/Actions.java @@ -3,73 +3,76 @@ /** * Global String constants for GUI actions */ -public class Actions { +public enum Actions { - public static final String ABBREVIATE_ISO = "abbreviateIso"; - public static final String ABBREVIATE_MEDLINE = "abbreviateMedline"; - public static final String ADD_FILE_LINK = "addFileLink"; - public static final String ADD_TO_GROUP = "addToGroup"; - public static final String AUTO_SET_FILE = "autoSetFile"; - public static final String BACK = "back"; - public static final String CLEANUP = "Cleanup"; - public static final String COPY = "copy"; - public static final String COPY_CITATION_ASCII_DOC = "copyCitaitonAsciidoc"; - public static final String COPY_CITATION_XSLFO = "copyCitaitonFo"; - public static final String COPY_CITATION_HTML = "copyCitaitonHtml"; - public static final String COPY_CITATION_RTF = "copyCitaitonRtf"; - public static final String COPY_CITATION_TEXT = "copyCitaitonText"; - public static final String COPY_KEY = "copyKey"; - public static final String COPY_CITE_KEY = "copyCiteKey"; - public static final String COPY_KEY_AND_TITLE = "copyKeyAndTitle"; - public static final String COPY_KEY_AND_LINK = "copyKeyAndLink"; - public static final String COPY_TITLE = "copyTitle"; - public static final String CUT = "cut"; - public static final String DELETE = "delete"; - public static final String DOWNLOAD_FULL_TEXT = "downloadFullText"; - public static final String DUPLI_CHECK = "dupliCheck"; - public static final String EDIT = "edit"; - public static final String EDIT_PREAMBLE = "editPreamble"; - public static final String EDIT_STRINGS = "editStrings"; - public static final String EXPORT_TO_CLIPBOARD = "exportToClipboard"; - public static final String FOCUS_TABLE = "focusTable"; - public static final String FORWARD = "forward"; - public static final String MAKE_KEY = "makeKey"; - public static final String MANAGE_SELECTORS = "manageSelectors"; - public static final String MARK_ENTRIES = "markEntries"; - public static final String MERGE_DATABASE = "mergeDatabase"; - public static final String MERGE_ENTRIES = "mergeEntries"; - public static final String MERGE_WITH_FETCHED_ENTRY = "mergeWithFetchedEntry"; - public static final String NEXT_PREVIEW_STYLE = "nextPreviewStyle"; - public static final String MOVE_TO_GROUP = "moveToGroup"; - public static final String OPEN_CONSOLE = "openConsole"; - public static final String OPEN_EXTERNAL_FILE = "openExternalFile"; - public static final String OPEN_FOLDER = "openFolder"; - public static final String OPEN_URL = "openUrl"; - public static final String PASTE = "paste"; - public static final String PLAIN_TEXT_IMPORT = "plainTextImport"; - public static final String PREVIOUS_PREVIEW_STYLE = "previousPreviewStyle"; - public static final String PULL_CHANGES_FROM_SHARED_DATABASE = "pullChangesFromSharedDatabase"; - public static final String REDO = "redo"; - public static final String REMOVE_FROM_GROUP = "removeFromGroup"; - public static final String REPLACE_ALL = "replaceAll"; - public static final String RESOLVE_DUPLICATE_KEYS = "resolveDuplicateKeys"; - public static final String SAVE = "save"; - public static final String SAVE_AS = "saveAs"; - public static final String SAVE_SELECTED_AS = "saveSelectedAs"; - public static final String SAVE_SELECTED_AS_PLAIN = "saveSelectedAsPlain"; - public static final String SEARCH = "search"; - public static final String GLOBAL_SEARCH = "globalSearch"; - public static final String SELECT_ALL = "selectAll"; - public static final String SEND_AS_EMAIL = "sendAsEmail"; - public static final String TOGGLE_GROUPS = "toggleGroups"; - public static final String TOGGLE_PREVIEW = "togglePreview"; - public static final String UNABBREVIATE = "unabbreviate"; - public static final String UNDO = "undo"; - public static final String UNMARK_ALL = "unmarkAll"; - public static final String UNMARK_ENTRIES = "unmarkEntries"; - public static final String WRITE_XMP = "writeXMP"; - public static final String PRINT_PREVIEW = "printPreview"; - - private Actions() { - } + ABBREVIATE_ISO, + ABBREVIATE_MEDLINE, + ADD_FILE_LINK, + ADD_TO_GROUP, + CLEANUP, + COPY, + COPY_CITATION_ASCII_DOC, + COPY_CITATION_XSLFO, + COPY_CITATION_HTML, + COPY_CITATION_RTF, + COPY_CITATION_TEXT, + COPY_KEY, + COPY_CITE_KEY, + COPY_KEY_AND_TITLE, + COPY_KEY_AND_LINK, + COPY_TITLE, + CUT, + DELETE, + DOWNLOAD_FULL_TEXT, + EDIT, + EDIT_PREAMBLE, + EDIT_STRINGS, + EXPORT_TO_CLIPBOARD, + MAKE_KEY, + MANAGE_SELECTORS, + MERGE_DATABASE, + MERGE_ENTRIES, + MERGE_WITH_FETCHED_ENTRY, + NEXT_PREVIEW_STYLE, + MOVE_TO_GROUP, + OPEN_CONSOLE, + OPEN_EXTERNAL_FILE, + OPEN_FOLDER, + OPEN_URL, + PASTE, + PREVIOUS_PREVIEW_STYLE, + PULL_CHANGES_FROM_SHARED_DATABASE, + REDO, + REMOVE_FROM_GROUP, + REPLACE_ALL, + RESOLVE_DUPLICATE_KEYS, + SAVE, + SAVE_AS, + SAVE_SELECTED_AS_PLAIN, + SEARCH, + GLOBAL_SEARCH, + SELECT_ALL, + SEND_AS_EMAIL, + TOGGLE_GROUPS, + TOGGLE_PREVIEW, + UNABBREVIATE, + UNDO, + WRITE_XMP, + PRINT_PREVIEW, + TOGGLE_PRINTED, + CLEAR_PRIORITY, + SET_PRIORITY_1, + SET_PRIORITY_2, + SET_PRIORITY_3, + TOGGLE_QUALITY_ASSURED, + CLEAR_RANK, + SET_RANK_1, + SET_RANK_2, + SET_RANK_3, + SET_RANK_4, + SET_RANK_5, + CLEAR_READ_STATUS, + SET_READ_STATUS_TO_READ, + SET_READ_STATUS_TO_SKIMMED, + TOGGLE_RELEVANCE } diff --git a/src/main/java/org/jabref/gui/actions/AutoLinkFilesAction.java b/src/main/java/org/jabref/gui/actions/AutoLinkFilesAction.java index db9931a8f00..7b77c9f59b4 100644 --- a/src/main/java/org/jabref/gui/actions/AutoLinkFilesAction.java +++ b/src/main/java/org/jabref/gui/actions/AutoLinkFilesAction.java @@ -1,18 +1,13 @@ package org.jabref.gui.actions; -import java.awt.event.ActionEvent; import java.util.List; -import javax.swing.AbstractAction; -import javax.swing.Action; import javax.swing.JDialog; +import javax.swing.JFrame; -import org.jabref.Globals; import org.jabref.JabRefExecutorService; import org.jabref.JabRefGUI; -import org.jabref.gui.IconTheme; import org.jabref.gui.externalfiles.AutoSetLinks; -import org.jabref.gui.keyboard.KeyBinding; import org.jabref.gui.undo.NamedCompound; import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.BibEntry; @@ -21,24 +16,21 @@ * This Action may only be used in a menu or button. * Never in the entry editor. FileListEditor and EntryEditor have other ways to update the file links */ -public class AutoLinkFilesAction extends AbstractAction { +public class AutoLinkFilesAction extends SimpleCommand { public AutoLinkFilesAction() { - putValue(Action.SMALL_ICON, IconTheme.JabRefIcon.AUTO_FILE_LINK.getSmallIcon()); - putValue(Action.LARGE_ICON_KEY, IconTheme.JabRefIcon.AUTO_FILE_LINK.getIcon()); - putValue(Action.NAME, Localization.lang("Automatically set file links")); - putValue(Action.ACCELERATOR_KEY, Globals.getKeyPrefs().getKey(KeyBinding.AUTOMATICALLY_LINK_FILES)); + } @Override - public void actionPerformed(ActionEvent event) { + public void execute() { List entries = JabRefGUI.getMainFrame().getCurrentBasePanel().getSelectedEntries(); if (entries.isEmpty()) { JabRefGUI.getMainFrame().getCurrentBasePanel() .output(Localization.lang("This operation requires one or more entries to be selected.")); return; } - JDialog diag = new JDialog(JabRefGUI.getMainFrame(), true); + JDialog diag = new JDialog((JFrame) null, true); final NamedCompound nc = new NamedCompound(Localization.lang("Automatically set file links")); Runnable runnable = AutoSetLinks.autoSetLinks(entries, nc, null, JabRefGUI.getMainFrame().getCurrentBasePanel().getBibDatabaseContext(), e -> { diff --git a/src/main/java/org/jabref/gui/actions/BibtexKeyPatternAction.java b/src/main/java/org/jabref/gui/actions/BibtexKeyPatternAction.java new file mode 100644 index 00000000000..71c125f9659 --- /dev/null +++ b/src/main/java/org/jabref/gui/actions/BibtexKeyPatternAction.java @@ -0,0 +1,20 @@ +package org.jabref.gui.actions; + +import org.jabref.gui.JabRefFrame; +import org.jabref.gui.bibtexkeypattern.BibtexKeyPatternDialog; + +public class BibtexKeyPatternAction extends SimpleCommand { + + private JabRefFrame frame; + + public BibtexKeyPatternAction(JabRefFrame frame) { + this.frame = frame; + } + + @Override + public void execute() { + BibtexKeyPatternDialog bibtexKeyPatternDialog = new BibtexKeyPatternDialog(frame.getCurrentBasePanel()); + bibtexKeyPatternDialog.setLocationRelativeTo(null); + bibtexKeyPatternDialog.setVisible(true); + } +} diff --git a/src/main/java/org/jabref/gui/actions/CleanupAction.java b/src/main/java/org/jabref/gui/actions/CleanupAction.java index b2d4ac7c995..71d8f6e24c7 100644 --- a/src/main/java/org/jabref/gui/actions/CleanupAction.java +++ b/src/main/java/org/jabref/gui/actions/CleanupAction.java @@ -1,18 +1,15 @@ package org.jabref.gui.actions; import java.util.List; -import java.util.Objects; - -import javax.swing.JOptionPane; +import java.util.Optional; import org.jabref.Globals; import org.jabref.gui.BasePanel; -import org.jabref.gui.JabRefFrame; -import org.jabref.gui.cleanup.CleanupPresetPanel; +import org.jabref.gui.DialogService; +import org.jabref.gui.cleanup.CleanupDialog; import org.jabref.gui.undo.NamedCompound; import org.jabref.gui.undo.UndoableFieldChange; import org.jabref.gui.util.DefaultTaskExecutor; -import org.jabref.gui.util.component.CheckBoxMessage; import org.jabref.gui.worker.AbstractWorker; import org.jabref.logic.cleanup.CleanupPreset; import org.jabref.logic.cleanup.CleanupWorker; @@ -24,7 +21,7 @@ public class CleanupAction extends AbstractWorker { private final BasePanel panel; - private final JabRefFrame frame; + private final DialogService dialogService; /** * Global variable to count unsuccessful renames @@ -37,8 +34,8 @@ public class CleanupAction extends AbstractWorker { public CleanupAction(BasePanel panel, JabRefPreferences preferences) { this.panel = panel; - this.frame = panel.frame(); - this.preferences = Objects.requireNonNull(preferences); + this.preferences = preferences; + this.dialogService = panel.frame().getDialogService(); } @Override @@ -46,41 +43,40 @@ public void init() { canceled = false; modifiedEntriesCount = 0; if (panel.getSelectedEntries().isEmpty()) { // None selected. Inform the user to select entries first. - JOptionPane.showMessageDialog(frame, Localization.lang("First select entries to clean up."), - Localization.lang("Cleanup entry"), JOptionPane.INFORMATION_MESSAGE); + dialogService.showInformationDialogAndWait(Localization.lang("Cleanup entry"), Localization.lang("First select entries to clean up.")); canceled = true; return; } - frame.block(); panel.output(Localization.lang("Doing a cleanup for %0 entries...", Integer.toString(panel.getSelectedEntries().size()))); } @Override public void run() { + if (canceled) { return; } - CleanupPresetPanel presetPanel = new CleanupPresetPanel(panel.getBibDatabaseContext(), - preferences.getCleanupPreset()); - int choice = showDialog(presetPanel); - if (choice != JOptionPane.OK_OPTION) { + CleanupDialog cleanupDialog = new CleanupDialog(panel.getBibDatabaseContext(), preferences.getCleanupPreset()); + + Optional chosenPreset = cleanupDialog.showAndWait(); + if (!chosenPreset.isPresent()) { canceled = true; return; } - CleanupPreset cleanupPreset = presetPanel.getCleanupPreset(); + CleanupPreset cleanupPreset = chosenPreset.get(); preferences.setCleanupPreset(cleanupPreset); - if (cleanupPreset.isRenamePDF() && Globals.prefs.getBoolean(JabRefPreferences.ASK_AUTO_NAMING_PDFS_AGAIN)) { - CheckBoxMessage cbm = new CheckBoxMessage( + if (cleanupPreset.isRenamePDF() && preferences.getBoolean(JabRefPreferences.ASK_AUTO_NAMING_PDFS_AGAIN)) { + + boolean confirmed = DefaultTaskExecutor.runInJavaFXThread(() -> dialogService.showConfirmationDialogWithOptOutAndWait(Localization.lang("Autogenerate PDF Names"), Localization.lang("Auto-generating PDF-Names does not support undo. Continue?"), - Localization.lang("Disable this confirmation dialog"), false); - int answer = JOptionPane.showConfirmDialog(frame, cbm, Localization.lang("Autogenerate PDF Names"), - JOptionPane.YES_NO_OPTION); - if (cbm.isSelected()) { - Globals.prefs.putBoolean(JabRefPreferences.ASK_AUTO_NAMING_PDFS_AGAIN, false); - } - if (answer == JOptionPane.NO_OPTION) { + Localization.lang("Autogenerate PDF Names"), + Localization.lang("Cancel"), + Localization.lang("Disable this confirmation dialog"), + optOut -> Globals.prefs.putBoolean(JabRefPreferences.ASK_AUTO_NAMING_PDFS_AGAIN, !optOut))); + + if (!confirmed) { canceled = true; return; } @@ -98,18 +94,18 @@ public void run() { panel.getUndoManager().addEdit(ce); } } + } @Override public void update() { if (canceled) { - frame.unblock(); return; } if (unsuccessfulRenames > 0) { //Rename failed for at least one entry - JOptionPane.showMessageDialog(frame, - Localization.lang("File rename failed for %0 entries.", Integer.toString(unsuccessfulRenames)), - Localization.lang("Autogenerate PDF Names"), JOptionPane.INFORMATION_MESSAGE); + dialogService.showErrorDialogAndWait( + Localization.lang("Autogenerate PDF Names"), + Localization.lang("File rename failed for %0 entries.", Integer.toString(unsuccessfulRenames))); } if (modifiedEntriesCount > 0) { panel.updateEntryEditorIfShowing(); @@ -117,25 +113,17 @@ public void update() { } String message; switch (modifiedEntriesCount) { - case 0: - message = Localization.lang("No entry needed a clean up"); - break; - case 1: - message = Localization.lang("One entry needed a clean up"); - break; - default: - message = Localization.lang("%0 entries needed a clean up", Integer.toString(modifiedEntriesCount)); - break; + case 0: + message = Localization.lang("No entry needed a clean up"); + break; + case 1: + message = Localization.lang("One entry needed a clean up"); + break; + default: + message = Localization.lang("%0 entries needed a clean up", Integer.toString(modifiedEntriesCount)); + break; } panel.output(message); - frame.unblock(); - } - - private int showDialog(CleanupPresetPanel presetPanel) { - String dialogTitle = Localization.lang("Cleanup entries"); - Object[] messages = {Localization.lang("What would you like to clean up?"), presetPanel.getScrollPane()}; - return JOptionPane.showConfirmDialog(frame, messages, dialogTitle, JOptionPane.OK_CANCEL_OPTION, - JOptionPane.QUESTION_MESSAGE); } /** @@ -145,7 +133,7 @@ private void doCleanup(CleanupPreset preset, BibEntry entry, NamedCompound ce) { // Create and run cleaner CleanupWorker cleaner = new CleanupWorker(panel.getBibDatabaseContext(), preferences.getCleanupPreferences( Globals.journalAbbreviationLoader)); - List changes = DefaultTaskExecutor.runInJavaFXThread(() -> cleaner.cleanup(preset, entry)); + List changes = cleaner.cleanup(preset, entry); unsuccessfulRenames = cleaner.getUnsuccessfulRenames(); diff --git a/src/main/java/org/jabref/gui/actions/ConnectToSharedDatabaseAction.java b/src/main/java/org/jabref/gui/actions/ConnectToSharedDatabaseAction.java deleted file mode 100644 index 1e3f46ec437..00000000000 --- a/src/main/java/org/jabref/gui/actions/ConnectToSharedDatabaseAction.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.jabref.gui.actions; - -import java.awt.event.ActionEvent; - -import javax.swing.Action; - -import org.jabref.gui.JabRefFrame; -import org.jabref.gui.shared.ConnectToSharedDatabaseDialog; -import org.jabref.logic.l10n.Localization; - -/** - * The action concerned with opening a shared database. - */ -public class ConnectToSharedDatabaseAction extends MnemonicAwareAction { - - private final JabRefFrame jabRefFrame; - - - public ConnectToSharedDatabaseAction(JabRefFrame jabRefFrame) { - super(); - this.jabRefFrame = jabRefFrame; - putValue(Action.NAME, Localization.menuTitle("Connect to shared database")); - putValue(Action.SHORT_DESCRIPTION, Localization.lang("Connect to shared database")); - } - - @Override - public void actionPerformed(ActionEvent e) { - ConnectToSharedDatabaseDialog connectToSharedDatabaseDialog = new ConnectToSharedDatabaseDialog(jabRefFrame); - connectToSharedDatabaseDialog.setVisible(true); - } -} diff --git a/src/main/java/org/jabref/gui/actions/ConnectToSharedDatabaseCommand.java b/src/main/java/org/jabref/gui/actions/ConnectToSharedDatabaseCommand.java new file mode 100644 index 00000000000..d31b3382c95 --- /dev/null +++ b/src/main/java/org/jabref/gui/actions/ConnectToSharedDatabaseCommand.java @@ -0,0 +1,22 @@ +package org.jabref.gui.actions; + +import org.jabref.gui.JabRefFrame; +import org.jabref.gui.shared.ConnectToSharedDatabaseDialog; + +/** + * Opens a shared database. + */ +public class ConnectToSharedDatabaseCommand extends SimpleCommand { + + private final JabRefFrame jabRefFrame; + + public ConnectToSharedDatabaseCommand(JabRefFrame jabRefFrame) { + this.jabRefFrame = jabRefFrame; + } + + @Override + public void execute() { + ConnectToSharedDatabaseDialog connectToSharedDatabaseDialog = new ConnectToSharedDatabaseDialog(jabRefFrame); + connectToSharedDatabaseDialog.setVisible(true); + } +} diff --git a/src/main/java/org/jabref/gui/actions/CopyBibTeXKeyAndLinkAction.java b/src/main/java/org/jabref/gui/actions/CopyBibTeXKeyAndLinkAction.java index d5b1652b6c4..831ac29ec93 100644 --- a/src/main/java/org/jabref/gui/actions/CopyBibTeXKeyAndLinkAction.java +++ b/src/main/java/org/jabref/gui/actions/CopyBibTeXKeyAndLinkAction.java @@ -3,10 +3,8 @@ import java.util.List; import java.util.stream.Collectors; -import javafx.scene.input.Clipboard; -import javafx.scene.input.ClipboardContent; - import org.jabref.JabRefGUI; +import org.jabref.gui.ClipBoardManager; import org.jabref.gui.maintable.MainTable; import org.jabref.gui.util.DefaultTaskExecutor; import org.jabref.logic.l10n.Localization; @@ -22,9 +20,11 @@ public class CopyBibTeXKeyAndLinkAction implements BaseAction { private final MainTable mainTable; + private final ClipBoardManager clipboardManager; - public CopyBibTeXKeyAndLinkAction(MainTable mainTable) { + public CopyBibTeXKeyAndLinkAction(MainTable mainTable, ClipBoardManager clipboardManager) { this.mainTable = mainTable; + this.clipboardManager = clipboardManager; } @Override @@ -47,13 +47,7 @@ public void action() throws Exception { sb.append(OS.NEWLINE); } - // This works on Mac and Windows 10, but not on Ubuntu 16.04 - DefaultTaskExecutor.runInJavaFXThread(() -> { - final Clipboard clipboard = Clipboard.getSystemClipboard(); - final ClipboardContent content = new ClipboardContent(); - content.putHtml(sb.toString()); - clipboard.setContent(content); - }); + DefaultTaskExecutor.runInJavaFXThread(() -> clipboardManager.setClipboardHtmlContent(sb.toString())); int copied = entriesWithKey.size(); int toCopy = entries.size(); diff --git a/src/main/java/org/jabref/gui/actions/CopyDoiUrlAction.java b/src/main/java/org/jabref/gui/actions/CopyDoiUrlAction.java index d511de57caf..fd8bfb7ec86 100644 --- a/src/main/java/org/jabref/gui/actions/CopyDoiUrlAction.java +++ b/src/main/java/org/jabref/gui/actions/CopyDoiUrlAction.java @@ -21,7 +21,7 @@ public class CopyDoiUrlAction extends AbstractAction { private String identifier; public CopyDoiUrlAction(String identifier) { - super(Localization.menuTitle("Copy DOI url")); + super(Localization.lang("Copy DOI url")); this.identifier = identifier; } diff --git a/src/main/java/org/jabref/gui/copyfiles/CopyFilesAction.java b/src/main/java/org/jabref/gui/actions/CopyFilesAction.java similarity index 56% rename from src/main/java/org/jabref/gui/copyfiles/CopyFilesAction.java rename to src/main/java/org/jabref/gui/actions/CopyFilesAction.java index 19020f2f35c..5efa6415506 100644 --- a/src/main/java/org/jabref/gui/copyfiles/CopyFilesAction.java +++ b/src/main/java/org/jabref/gui/actions/CopyFilesAction.java @@ -1,63 +1,43 @@ -package org.jabref.gui.copyfiles; +package org.jabref.gui.actions; -import java.awt.event.ActionEvent; import java.nio.file.Path; import java.nio.file.Paths; import java.util.List; import java.util.Optional; -import javax.swing.AbstractAction; - import javafx.concurrent.Task; import org.jabref.Globals; -import org.jabref.JabRefGUI; import org.jabref.gui.DialogService; -import org.jabref.gui.FXDialogService; -import org.jabref.gui.util.DefaultTaskExecutor; +import org.jabref.gui.JabRefFrame; +import org.jabref.gui.copyfiles.CopyFilesDialogView; +import org.jabref.gui.copyfiles.CopyFilesResultItemViewModel; +import org.jabref.gui.copyfiles.CopyFilesResultListDependency; +import org.jabref.gui.copyfiles.CopyFilesTask; import org.jabref.gui.util.DirectoryDialogConfiguration; import org.jabref.logic.l10n.Localization; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; import org.jabref.preferences.JabRefPreferences; -public class CopyFilesAction extends AbstractAction { +public class CopyFilesAction extends SimpleCommand { - private final DialogService dialogService = new FXDialogService(); + private final DialogService dialogService; private BibDatabaseContext databaseContext; private List entries; + private final JabRefFrame frame; - public CopyFilesAction() { - super(Localization.lang("Copy linked files to folder...")); - } - - @Override - public void actionPerformed(ActionEvent e) { - - DirectoryDialogConfiguration dirDialogConfiguration = new DirectoryDialogConfiguration.Builder() - .withInitialDirectory(Paths.get(Globals.prefs.get(JabRefPreferences.EXPORT_WORKING_DIRECTORY))) - .build(); - entries = JabRefGUI.getMainFrame().getCurrentBasePanel().getSelectedEntries(); - - Optional exportPath = DefaultTaskExecutor - .runInJavaFXThread(() -> dialogService.showDirectorySelectionDialog(dirDialogConfiguration)); - - exportPath.ifPresent(path -> { - databaseContext = JabRefGUI.getMainFrame().getCurrentBasePanel().getBibDatabaseContext(); - - Task> exportTask = new CopyFilesTask(databaseContext, entries, path); - startServiceAndshowProgessDialog(exportTask); - }); + public CopyFilesAction(JabRefFrame frame) { + this.frame = frame; + this.dialogService = frame.getDialogService(); } private void startServiceAndshowProgessDialog(Task> exportService) { - DefaultTaskExecutor.runInJavaFXThread(() -> { - dialogService.showCanceableProgressDialogAndWait(exportService); - }); + dialogService.showCanceableProgressDialogAndWait(exportService); exportService.run(); - DefaultTaskExecutor.runInJavaFXThread(() -> { + exportService.setOnSucceeded((e) -> { showDialog(exportService.getValue()); }); } @@ -67,7 +47,25 @@ private void showDialog(List data) { dialogService.showInformationDialogAndWait(Localization.lang("Copy linked files to folder..."), Localization.lang("No linked files found for export.")); return; } - CopyFilesDialogView dlg = new CopyFilesDialogView(databaseContext, new CopyFilesResultListDependency(data)); - dlg.show(); + CopyFilesDialogView dialog = new CopyFilesDialogView(databaseContext, new CopyFilesResultListDependency(data)); + dialog.showAndWait(); + } + + @Override + public void execute() { + DirectoryDialogConfiguration dirDialogConfiguration = new DirectoryDialogConfiguration.Builder() + .withInitialDirectory(Paths.get(Globals.prefs.get(JabRefPreferences.EXPORT_WORKING_DIRECTORY))) + .build(); + entries = frame.getCurrentBasePanel().getSelectedEntries(); + + Optional exportPath = dialogService.showDirectorySelectionDialog(dirDialogConfiguration); + + exportPath.ifPresent(path -> { + databaseContext = frame.getCurrentBasePanel().getBibDatabaseContext(); + + Task> exportTask = new CopyFilesTask(databaseContext, entries, path); + startServiceAndshowProgessDialog(exportTask); + }); + } } diff --git a/src/main/java/org/jabref/gui/actions/CustomizeEntryAction.java b/src/main/java/org/jabref/gui/actions/CustomizeEntryAction.java new file mode 100644 index 00000000000..aaee283cde1 --- /dev/null +++ b/src/main/java/org/jabref/gui/actions/CustomizeEntryAction.java @@ -0,0 +1,21 @@ +package org.jabref.gui.actions; + +import javax.swing.JDialog; + +import org.jabref.gui.JabRefFrame; +import org.jabref.gui.customentrytypes.EntryCustomizationDialog; + +public class CustomizeEntryAction extends SimpleCommand { + + private final JabRefFrame frame; + + public CustomizeEntryAction(JabRefFrame frame) { + this.frame = frame; + } + + @Override + public void execute() { + JDialog dialog = new EntryCustomizationDialog(frame); + dialog.setVisible(true); + } +} diff --git a/src/main/java/org/jabref/gui/actions/CustomizeKeyBindingAction.java b/src/main/java/org/jabref/gui/actions/CustomizeKeyBindingAction.java new file mode 100644 index 00000000000..fdaa5538ff4 --- /dev/null +++ b/src/main/java/org/jabref/gui/actions/CustomizeKeyBindingAction.java @@ -0,0 +1,12 @@ +package org.jabref.gui.actions; + +import org.jabref.gui.keyboard.KeyBindingsDialogView; + +public class CustomizeKeyBindingAction extends SimpleCommand { + + @Override + public void execute() { + new KeyBindingsDialogView().show(); + } + +} diff --git a/src/main/java/org/jabref/gui/actions/DatabasePropertiesAction.java b/src/main/java/org/jabref/gui/actions/DatabasePropertiesAction.java new file mode 100644 index 00000000000..d7b3ffe35bf --- /dev/null +++ b/src/main/java/org/jabref/gui/actions/DatabasePropertiesAction.java @@ -0,0 +1,21 @@ +package org.jabref.gui.actions; + +import org.jabref.gui.JabRefFrame; +import org.jabref.gui.dbproperties.DatabasePropertiesDialog; + +public class DatabasePropertiesAction extends SimpleCommand { + + private final JabRefFrame frame; + + public DatabasePropertiesAction(JabRefFrame frame) { + this.frame = frame; + } + + @Override + public void execute() { + DatabasePropertiesDialog propertiesDialog = new DatabasePropertiesDialog(null, frame.getCurrentBasePanel()); + propertiesDialog.updateEnableStatus(); + propertiesDialog.setVisible(true); + } + +} diff --git a/src/main/java/org/jabref/gui/actions/EditExternalFileTypesAction.java b/src/main/java/org/jabref/gui/actions/EditExternalFileTypesAction.java new file mode 100644 index 00000000000..82bbc9123ce --- /dev/null +++ b/src/main/java/org/jabref/gui/actions/EditExternalFileTypesAction.java @@ -0,0 +1,12 @@ +package org.jabref.gui.actions; + +import org.jabref.gui.externalfiletype.ExternalFileTypeEditor; + +public class EditExternalFileTypesAction extends SimpleCommand { + + @Override + public void execute() { + ExternalFileTypeEditor editor = new ExternalFileTypeEditor(); + editor.show(); + } +} diff --git a/src/main/java/org/jabref/gui/actions/ErrorConsoleAction.java b/src/main/java/org/jabref/gui/actions/ErrorConsoleAction.java index f81b8ce5bae..2ac2dbf6623 100644 --- a/src/main/java/org/jabref/gui/actions/ErrorConsoleAction.java +++ b/src/main/java/org/jabref/gui/actions/ErrorConsoleAction.java @@ -1,14 +1,6 @@ package org.jabref.gui.actions; -import java.awt.event.ActionEvent; - -import javax.swing.AbstractAction; -import javax.swing.Action; - -import javafx.application.Platform; - import org.jabref.gui.errorconsole.ErrorConsoleView; -import org.jabref.logic.l10n.Localization; /** * Such an error console can be @@ -17,16 +9,11 @@ *

* It offers a separate tab for the log output. */ -public class ErrorConsoleAction extends AbstractAction { - - public ErrorConsoleAction() { - super(Localization.menuTitle("View event log")); - putValue(Action.SHORT_DESCRIPTION, Localization.lang("Display all error messages")); - } +public class ErrorConsoleAction extends SimpleCommand { @Override - public void actionPerformed(ActionEvent e) { - Platform.runLater(() -> new ErrorConsoleView().show()); + public void execute() { + new ErrorConsoleView().show(); } } diff --git a/src/main/java/org/jabref/gui/actions/FindUnlinkedFilesAction.java b/src/main/java/org/jabref/gui/actions/FindUnlinkedFilesAction.java new file mode 100644 index 00000000000..9e3f32dc8f2 --- /dev/null +++ b/src/main/java/org/jabref/gui/actions/FindUnlinkedFilesAction.java @@ -0,0 +1,20 @@ +package org.jabref.gui.actions; + +import org.jabref.gui.FindUnlinkedFilesDialog; +import org.jabref.gui.JabRefFrame; + +public class FindUnlinkedFilesAction extends SimpleCommand { + + private final JabRefFrame jabRefFrame; + + public FindUnlinkedFilesAction(JabRefFrame jabRefFrame) { + this.jabRefFrame = jabRefFrame; + } + + @Override + public void execute() { + FindUnlinkedFilesDialog dlg = new FindUnlinkedFilesDialog(null, jabRefFrame); + dlg.setVisible(true); + } + +} diff --git a/src/main/java/org/jabref/gui/actions/IntegrityCheckAction.java b/src/main/java/org/jabref/gui/actions/IntegrityCheckAction.java index 25a186f33e7..d5702800f5f 100644 --- a/src/main/java/org/jabref/gui/actions/IntegrityCheckAction.java +++ b/src/main/java/org/jabref/gui/actions/IntegrityCheckAction.java @@ -1,15 +1,14 @@ package org.jabref.gui.actions; import java.awt.Component; -import java.awt.event.ActionEvent; import java.util.HashMap; import java.util.List; import java.util.Map; -import javax.swing.Action; import javax.swing.JButton; import javax.swing.JCheckBoxMenuItem; import javax.swing.JDialog; +import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.JPopupMenu; import javax.swing.JProgressBar; @@ -25,7 +24,6 @@ import org.jabref.Globals; import org.jabref.gui.JabRefFrame; -import org.jabref.gui.keyboard.KeyBinding; import org.jabref.logic.integrity.IntegrityCheck; import org.jabref.logic.integrity.IntegrityMessage; import org.jabref.logic.l10n.Localization; @@ -36,7 +34,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class IntegrityCheckAction extends MnemonicAwareAction { +public class IntegrityCheckAction extends SimpleCommand { private static final Logger LOGGER = LoggerFactory.getLogger(IntegrityCheckAction.class); private static final String ELLIPSES = "..."; @@ -45,21 +43,18 @@ public class IntegrityCheckAction extends MnemonicAwareAction { public IntegrityCheckAction(JabRefFrame frame) { this.frame = frame; - putValue(Action.NAME, Localization.menuTitle("Check integrity") + ELLIPSES); - putValue(Action.ACCELERATOR_KEY, Globals.getKeyPrefs().getKey(KeyBinding.CHECK_INTEGRITY)); } @Override - public void actionPerformed(ActionEvent e) { + public void execute() { IntegrityCheck check = new IntegrityCheck(frame.getCurrentBasePanel().getBibDatabaseContext(), Globals.prefs.getFileDirectoryPreferences(), Globals.prefs.getBibtexKeyPatternPreferences(), Globals.journalAbbreviationLoader.getRepository(Globals.prefs.getJournalAbbreviationPreferences()), Globals.prefs.getBoolean(JabRefPreferences.ENFORCE_LEGAL_BIBTEX_KEY)); - final JDialog integrityDialog = new JDialog(frame, true); + final JDialog integrityDialog = new JDialog((JFrame) null, true); integrityDialog.setUndecorated(true); - integrityDialog.setLocationRelativeTo(frame); JProgressBar integrityProgressBar = new JProgressBar(); integrityProgressBar.setIndeterminate(true); integrityProgressBar.setStringPainted(true); @@ -88,7 +83,7 @@ protected void done() { } if (messages.isEmpty()) { - JOptionPane.showMessageDialog(frame.getCurrentBasePanel(), Localization.lang("No problems found.")); + JOptionPane.showMessageDialog(null, Localization.lang("No problems found.")); } else { Map showMessage = new HashMap<>(); // prepare data model @@ -148,7 +143,7 @@ public boolean include(Entry entry) { table.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN); JScrollPane scrollPane = new JScrollPane(table); String title = Localization.lang("%0 problem(s) found", String.valueOf(messages.size())); - JDialog dialog = new JDialog(frame, title, false); + JDialog dialog = new JDialog((JFrame) null, title, false); JPopupMenu menu = new JPopupMenu(); for (String messageString : showMessage.keySet()) { diff --git a/src/main/java/org/jabref/gui/actions/JabRefAction.java b/src/main/java/org/jabref/gui/actions/JabRefAction.java new file mode 100644 index 00000000000..d000f716040 --- /dev/null +++ b/src/main/java/org/jabref/gui/actions/JabRefAction.java @@ -0,0 +1,37 @@ +package org.jabref.gui.actions; + +import org.jabref.Globals; +import org.jabref.gui.keyboard.KeyBindingRepository; + +import de.saxsys.mvvmfx.utils.commands.Command; + +/** + * Wrapper around one of our actions from {@link Action} to convert them to controlsfx {@link org.controlsfx.control.action.Action}. + */ +class JabRefAction extends org.controlsfx.control.action.Action { + + + public JabRefAction(Action action, KeyBindingRepository keyBindingRepository) { + super(action.getText()); + action.getIcon() + .ifPresent(icon -> setGraphic(icon.getGraphicNode())); + action.getKeyBinding() + .ifPresent(keyBinding -> setAccelerator(keyBindingRepository.getKeyCombination(keyBinding))); + + setLongText(action.getDescription()); + + } + + public JabRefAction(Action action, Command command, KeyBindingRepository keyBindingRepository) { + this(action, keyBindingRepository); + setEventHandler(event -> { + command.execute(); + trackExecute(); + }); + } + + private void trackExecute() { + Globals.getTelemetryClient() + .ifPresent(telemetryClient -> telemetryClient.trackEvent(getText())); + } +} diff --git a/src/main/java/org/jabref/gui/actions/LookupIdentifierAction.java b/src/main/java/org/jabref/gui/actions/LookupIdentifierAction.java index 2f488fdb45b..895f9854dca 100644 --- a/src/main/java/org/jabref/gui/actions/LookupIdentifierAction.java +++ b/src/main/java/org/jabref/gui/actions/LookupIdentifierAction.java @@ -1,38 +1,62 @@ package org.jabref.gui.actions; -import java.awt.event.ActionEvent; - -import javax.swing.Action; +import java.util.Optional; import org.jabref.gui.BasePanel; import org.jabref.gui.JabRefFrame; +import org.jabref.gui.icon.JabRefIcon; +import org.jabref.gui.keyboard.KeyBinding; import org.jabref.gui.worker.LookupIdentifiersWorker; import org.jabref.logic.importer.IdFetcher; +import org.jabref.model.entry.identifier.Identifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class LookupIdentifierAction extends MnemonicAwareAction { +public class LookupIdentifierAction extends SimpleCommand { private static final Logger LOGGER = LoggerFactory.getLogger(LookupIdentifierAction.class); private final JabRefFrame frame; - private final IdFetcher fetcher; - public LookupIdentifierAction(JabRefFrame frame, IdFetcher fetcher) { - super(); + private final IdFetcher fetcher; + + public LookupIdentifierAction(JabRefFrame frame, IdFetcher fetcher) { this.frame = frame; this.fetcher = fetcher; - - putValue(Action.NAME, fetcher.getIdentifierName()); } @Override - public void actionPerformed(ActionEvent actionEvent) { + public void execute() { try { - BasePanel.runWorker(new LookupIdentifiersWorker(frame, fetcher)); + BasePanel.runWorker(new LookupIdentifiersWorker<>(frame, fetcher)); } catch (Exception e) { LOGGER.error("Problem running ID Worker", e); } } + + public Action getAction() { + return new Action() { + + @Override + public Optional getIcon() { + return Optional.empty(); + } + + @Override + public Optional getKeyBinding() { + return Optional.empty(); + } + + @Override + public String getText() { + return fetcher.getIdentifierName(); + } + + @Override + public String getDescription() { + return ""; + } + }; + } } diff --git a/src/main/java/org/jabref/gui/actions/ManageCustomExportsAction.java b/src/main/java/org/jabref/gui/actions/ManageCustomExportsAction.java new file mode 100644 index 00000000000..90567f5f820 --- /dev/null +++ b/src/main/java/org/jabref/gui/actions/ManageCustomExportsAction.java @@ -0,0 +1,20 @@ +package org.jabref.gui.actions; + +import org.jabref.gui.JabRefFrame; +import org.jabref.gui.exporter.ExportCustomizationDialog; + +public class ManageCustomExportsAction extends SimpleCommand { + + private final JabRefFrame jabRefFrame; + + public ManageCustomExportsAction(JabRefFrame jabRefFrame) { + this.jabRefFrame = jabRefFrame; + } + + @Override + public void execute() { + ExportCustomizationDialog ecd = new ExportCustomizationDialog(jabRefFrame); + ecd.setVisible(true); + } + +} diff --git a/src/main/java/org/jabref/gui/actions/ManageCustomImportsAction.java b/src/main/java/org/jabref/gui/actions/ManageCustomImportsAction.java new file mode 100644 index 00000000000..5359168805c --- /dev/null +++ b/src/main/java/org/jabref/gui/actions/ManageCustomImportsAction.java @@ -0,0 +1,21 @@ +package org.jabref.gui.actions; + +import org.jabref.gui.JabRefFrame; +import org.jabref.gui.importer.ImportCustomizationDialog; + +public class ManageCustomImportsAction extends SimpleCommand { + + private final JabRefFrame jabRefFrame; + + public ManageCustomImportsAction(JabRefFrame jabRefFrame) { + this.jabRefFrame = jabRefFrame; + } + + @Override + public void execute() { + ImportCustomizationDialog ecd = new ImportCustomizationDialog(jabRefFrame); + ecd.setVisible(true); + + } + +} diff --git a/src/main/java/org/jabref/gui/actions/ManageJournalsAction.java b/src/main/java/org/jabref/gui/actions/ManageJournalsAction.java new file mode 100644 index 00000000000..b089a505a9e --- /dev/null +++ b/src/main/java/org/jabref/gui/actions/ManageJournalsAction.java @@ -0,0 +1,12 @@ +package org.jabref.gui.actions; + +import org.jabref.gui.journals.ManageJournalAbbreviationsView; + +public class ManageJournalsAction extends SimpleCommand { + + @Override + public void execute() { + new ManageJournalAbbreviationsView().show(); + } + +} diff --git a/src/main/java/org/jabref/gui/actions/ManageKeywordsAction.java b/src/main/java/org/jabref/gui/actions/ManageKeywordsAction.java index 1e3304323c1..0af7a02f91c 100644 --- a/src/main/java/org/jabref/gui/actions/ManageKeywordsAction.java +++ b/src/main/java/org/jabref/gui/actions/ManageKeywordsAction.java @@ -21,6 +21,7 @@ import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JDialog; +import javax.swing.JFrame; import javax.swing.JList; import javax.swing.JRadioButton; import javax.swing.JScrollPane; @@ -48,7 +49,7 @@ * An Action for launching keyword managing dialog * */ -public class ManageKeywordsAction extends MnemonicAwareAction { +public class ManageKeywordsAction extends SimpleCommand { private final JabRefFrame frame; private final KeywordList sortedKeywordsOfAllEntriesBeforeUpdateByUser = new KeywordList(); @@ -60,7 +61,6 @@ public class ManageKeywordsAction extends MnemonicAwareAction { public ManageKeywordsAction(JabRefFrame frame) { - putValue(Action.NAME, Localization.menuTitle("Manage keywords")); this.frame = frame; } @@ -76,7 +76,7 @@ private void createDialog() { keywordList.setVisibleRowCount(8); JScrollPane kPane = new JScrollPane(keywordList); - diag = new JDialog(frame, Localization.lang("Manage keywords"), true); + diag = new JDialog((JFrame) null, Localization.lang("Manage keywords"), true); JButton ok = new JButton(Localization.lang("OK")); JButton cancel = new JButton(Localization.lang("Cancel")); @@ -197,7 +197,7 @@ public void keyPressed(KeyEvent e) { // Key bindings: ActionMap am = builder.getPanel().getActionMap(); InputMap im = builder.getPanel().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); - im.put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE_DIALOG), "close"); + im.put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE), "close"); am.put("close", cancelAction); diag.getContentPane().add(builder.getPanel(), BorderLayout.CENTER); @@ -240,7 +240,7 @@ private void addKeywordToKeywordListModel(String keyword) { } @Override - public void actionPerformed(ActionEvent e) { + public void execute() { BasePanel bp = frame.getCurrentBasePanel(); if (bp == null) { return; @@ -258,7 +258,6 @@ public void actionPerformed(ActionEvent e) { fillKeyWordList(); diag.pack(); - diag.setLocationRelativeTo(frame); diag.setVisible(true); if (canceled) { return; diff --git a/src/main/java/org/jabref/gui/actions/ManageProtectedTermsAction.java b/src/main/java/org/jabref/gui/actions/ManageProtectedTermsAction.java new file mode 100644 index 00000000000..c4f05f955cf --- /dev/null +++ b/src/main/java/org/jabref/gui/actions/ManageProtectedTermsAction.java @@ -0,0 +1,23 @@ +package org.jabref.gui.actions; + +import org.jabref.gui.JabRefFrame; +import org.jabref.gui.protectedterms.ProtectedTermsDialog; +import org.jabref.logic.protectedterms.ProtectedTermsLoader; + +public class ManageProtectedTermsAction extends SimpleCommand { + + private final JabRefFrame jabRefFrame; + private final ProtectedTermsLoader termsLoader; + + public ManageProtectedTermsAction(JabRefFrame jabRefFrame, ProtectedTermsLoader termsLoader) { + this.jabRefFrame = jabRefFrame; + this.termsLoader = termsLoader; + } + @Override + public void execute() { + ProtectedTermsDialog protectTermsDialog = new ProtectedTermsDialog(jabRefFrame); + protectTermsDialog.setVisible(true); + + } + +} diff --git a/src/main/java/org/jabref/gui/actions/MassSetFieldAction.java b/src/main/java/org/jabref/gui/actions/MassSetFieldAction.java index 6743657960a..a93aaebe2b8 100644 --- a/src/main/java/org/jabref/gui/actions/MassSetFieldAction.java +++ b/src/main/java/org/jabref/gui/actions/MassSetFieldAction.java @@ -19,7 +19,7 @@ import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JDialog; -import javax.swing.JOptionPane; +import javax.swing.JFrame; import javax.swing.JRadioButton; import javax.swing.JTextField; import javax.swing.undo.UndoableEdit; @@ -45,7 +45,7 @@ * * Input field name * * Either set field, or clear field. */ -public class MassSetFieldAction extends MnemonicAwareAction { +public class MassSetFieldAction extends SimpleCommand { private final JabRefFrame frame; private JDialog diag; @@ -62,135 +62,41 @@ public class MassSetFieldAction extends MnemonicAwareAction { private boolean canceled = true; private JCheckBox overwrite; - public MassSetFieldAction(JabRefFrame frame) { - putValue(Action.NAME, Localization.menuTitle("Set/clear/append/rename fields") + "..."); this.frame = frame; } - private void createDialog() { - diag = new JDialog(frame, Localization.lang("Set/clear/append/rename fields"), true); - - field = new JComboBox<>(); - field.setEditable(true); - textFieldSet = new JTextField(); - textFieldSet.setEnabled(false); - textFieldAppend = new JTextField(); - textFieldAppend.setEnabled(false); - textFieldRename = new JTextField(); - textFieldRename.setEnabled(false); - - JButton ok = new JButton(Localization.lang("OK")); - JButton cancel = new JButton(Localization.lang("Cancel")); - - all = new JRadioButton(Localization.lang("All entries")); - selected = new JRadioButton(Localization.lang("Selected entries")); - clear = new JRadioButton(Localization.lang("Clear fields")); - set = new JRadioButton(Localization.lang("Set fields")); - append = new JRadioButton(Localization.lang("Append to fields")); - rename = new JRadioButton(Localization.lang("Rename field to") + ":"); - rename.setToolTipText(Localization.lang("Move contents of a field into a field with a different name")); - - Set allFields = frame.getCurrentBasePanel().getDatabase().getAllVisibleFields(); - - for (String f : allFields) { - field.addItem(f); - } - - set.addChangeListener(e -> - // Entering a setText is only relevant if we are setting, not clearing: - textFieldSet.setEnabled(set.isSelected())); - - append.addChangeListener(e -> { - // Text to append is only required if we are appending: - textFieldAppend.setEnabled(append.isSelected()); - // Overwrite protection makes no sense if we are appending to a field: - overwrite.setEnabled(!clear.isSelected() && !append.isSelected()); - }); - - clear.addChangeListener(e -> - // Overwrite protection makes no sense if we are clearing the field: - overwrite.setEnabled(!clear.isSelected() && !append.isSelected())); - - rename.addChangeListener(e -> - // Entering a setText is only relevant if we are renaming - textFieldRename.setEnabled(rename.isSelected())); - - overwrite = new JCheckBox(Localization.lang("Overwrite existing field values"), true); - ButtonGroup bg = new ButtonGroup(); - bg.add(all); - bg.add(selected); - bg = new ButtonGroup(); - bg.add(clear); - bg.add(set); - bg.add(append); - bg.add(rename); - FormBuilder builder = FormBuilder.create().layout(new FormLayout( - "left:pref, 4dlu, fill:100dlu:grow", "pref, 2dlu, pref, 2dlu, pref, 2dlu, pref, 2dlu, pref, 2dlu, pref, 2dlu, pref, 2dlu, pref, 2dlu, pref, 2dlu, pref, 2dlu, pref")); - builder.addSeparator(Localization.lang("Field name")).xyw(1, 1, 3); - builder.add(Localization.lang("Field name")).xy(1, 3); - builder.add(field).xy(3, 3); - builder.addSeparator(Localization.lang("Include entries")).xyw(1, 5, 3); - builder.add(all).xyw(1, 7, 3); - builder.add(selected).xyw(1, 9, 3); - builder.addSeparator(Localization.lang("New field value")).xyw(1, 11, 3); - builder.add(set).xy(1, 13); - builder.add(textFieldSet).xy(3, 13); - builder.add(clear).xyw(1, 15, 3); - builder.add(append).xy(1, 17); - builder.add(textFieldAppend).xy(3, 17); - builder.add(rename).xy(1, 19); - builder.add(textFieldRename).xy(3, 19); - builder.add(overwrite).xyw(1, 21, 3); - - ButtonBarBuilder bb = new ButtonBarBuilder(); - bb.addGlue(); - bb.addButton(ok); - bb.addButton(cancel); - bb.addGlue(); - builder.getPanel().setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); - bb.getPanel().setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); - diag.getContentPane().add(builder.getPanel(), BorderLayout.CENTER); - diag.getContentPane().add(bb.getPanel(), BorderLayout.SOUTH); - diag.pack(); - - ok.addActionListener(e -> { - // Check that any field name is set - String fieldText = (String) field.getSelectedItem(); - if ((fieldText == null) || fieldText.trim().isEmpty()) { - JOptionPane.showMessageDialog(diag, Localization.lang("You must enter at least one field name"), "", - JOptionPane.ERROR_MESSAGE); - return; // Do not close the dialog. - } + /** + * Set a given field to a given value for all entries in a Collection. This method DOES NOT update any UndoManager, + * but returns a relevant CompoundEdit that should be registered by the caller. + * + * @param entries The entries to set the field for. + * @param field The name of the field to set. + * @param textToSet The value to set. This value can be null, indicating that the field should be cleared. + * @param overwriteValues Indicate whether the value should be set even if an entry already has the field set. + * @return A CompoundEdit for the entire operation. + */ + private static UndoableEdit massSetField(Collection entries, String field, String textToSet, + boolean overwriteValues) { - // Check if the user tries to rename multiple fields: - if (rename.isSelected()) { - String[] fields = getFieldNames(fieldText); - if (fields.length > 1) { - JOptionPane.showMessageDialog(diag, Localization.lang("You can only rename one field at a time"), - "", JOptionPane.ERROR_MESSAGE); - return; // Do not close the dialog. - } + NamedCompound compoundEdit = new NamedCompound(Localization.lang("Set field")); + for (BibEntry entry : entries) { + Optional oldValue = entry.getField(field); + // If we are not allowed to overwrite values, check if there is a + // nonempty + // value already for this entry: + if (!overwriteValues && (oldValue.isPresent()) && !oldValue.get().isEmpty()) { + continue; } - canceled = false; - diag.dispose(); - }); - - Action cancelAction = new AbstractAction() { - - @Override - public void actionPerformed(ActionEvent e) { - canceled = true; - diag.dispose(); + if (textToSet == null) { + entry.clearField(field); + } else { + entry.setField(field, textToSet); } - }; - cancel.addActionListener(cancelAction); - - // Key bindings: - ActionMap am = builder.getPanel().getActionMap(); - InputMap im = builder.getPanel().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); - im.put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE_DIALOG), "close"); - am.put("close", cancelAction); + compoundEdit.addEdit(new UndoableFieldChange(entry, field, oldValue.orElse(null), textToSet)); + } + compoundEdit.end(); + return compoundEdit; } private void prepareDialog(boolean selection) { @@ -207,7 +113,7 @@ private void prepareDialog(boolean selection) { } @Override - public void actionPerformed(ActionEvent e) { + public void execute() { BasePanel bp = frame.getCurrentBasePanel(); if (bp == null) { return; @@ -220,7 +126,6 @@ public void actionPerformed(ActionEvent e) { canceled = true; prepareDialog(!entries.isEmpty()); if (diag != null) { - diag.setLocationRelativeTo(frame); diag.setVisible(true); } if (canceled) { @@ -244,8 +149,7 @@ public void actionPerformed(ActionEvent e) { NamedCompound compoundEdit = new NamedCompound(Localization.lang("Set field")); if (rename.isSelected()) { if (fields.length > 1) { - JOptionPane.showMessageDialog(diag, Localization.lang("You can only rename one field at a time"), "", - JOptionPane.ERROR_MESSAGE); + frame.getDialogService().showErrorDialogAndWait(Localization.lang("You can only rename one field at a time")); return; // Do not close the dialog. } else { compoundEdit.addEdit(MassSetFieldAction.massRenameField(entryList, fields[0], textFieldRename.getText(), @@ -259,7 +163,7 @@ public void actionPerformed(ActionEvent e) { for (String field : fields) { compoundEdit.addEdit(MassSetFieldAction.massSetField(entryList, field, set.isSelected() ? toSet : null, - overwrite.isSelected())); + overwrite.isSelected())); } } compoundEdit.end(); @@ -267,46 +171,13 @@ public void actionPerformed(ActionEvent e) { bp.markBaseChanged(); } - /** - * Set a given field to a given value for all entries in a Collection. This method DOES NOT update any UndoManager, - * but returns a relevant CompoundEdit that should be registered by the caller. - * - * @param entries The entries to set the field for. - * @param field The name of the field to set. - * @param textToSet The value to set. This value can be null, indicating that the field should be cleared. - * @param overwriteValues Indicate whether the value should be set even if an entry already has the field set. - * @return A CompoundEdit for the entire operation. - */ - private static UndoableEdit massSetField(Collection entries, String field, String textToSet, - boolean overwriteValues) { - - NamedCompound compoundEdit = new NamedCompound(Localization.lang("Set field")); - for (BibEntry entry : entries) { - Optional oldValue = entry.getField(field); - // If we are not allowed to overwrite values, check if there is a - // nonempty - // value already for this entry: - if (!overwriteValues && (oldValue.isPresent()) && !oldValue.get().isEmpty()) { - continue; - } - if (textToSet == null) { - entry.clearField(field); - } else { - entry.setField(field, textToSet); - } - compoundEdit.addEdit(new UndoableFieldChange(entry, field, oldValue.orElse(null), textToSet)); - } - compoundEdit.end(); - return compoundEdit; - } - /** * Append a given value to a given field for all entries in a Collection. This method DOES NOT update any UndoManager, * but returns a relevant CompoundEdit that should be registered by the caller. * - * @param entries The entries to process the operation for. - * @param field The name of the field to append to. - * @param textToAppend The value to set. A null in this case will simply preserve the current field state. + * @param entries The entries to process the operation for. + * @param field The name of the field to append to. + * @param textToAppend The value to set. A null in this case will simply preserve the current field state. * @return A CompoundEdit for the entire operation. */ private static UndoableEdit massAppendField(Collection entries, String field, String textToAppend) { @@ -338,7 +209,7 @@ private static UndoableEdit massAppendField(Collection entries, String * @return A CompoundEdit for the entire operation. */ private static UndoableEdit massRenameField(Collection entries, String field, String newField, - boolean overwriteValues) { + boolean overwriteValues) { NamedCompound compoundEdit = new NamedCompound(Localization.lang("Rename field")); for (BibEntry entry : entries) { Optional valToMove = entry.getField(field); @@ -362,6 +233,133 @@ private static UndoableEdit massRenameField(Collection entries, String return compoundEdit; } + private void createDialog() { + diag = new JDialog((JFrame) null, Localization.lang("Set/clear/append/rename fields"), true); + + field = new JComboBox<>(); + field.setEditable(true); + textFieldSet = new JTextField(); + textFieldSet.setEnabled(false); + textFieldAppend = new JTextField(); + textFieldAppend.setEnabled(false); + textFieldRename = new JTextField(); + textFieldRename.setEnabled(false); + + JButton ok = new JButton(Localization.lang("OK")); + JButton cancel = new JButton(Localization.lang("Cancel")); + + all = new JRadioButton(Localization.lang("All entries")); + selected = new JRadioButton(Localization.lang("Selected entries")); + clear = new JRadioButton(Localization.lang("Clear fields")); + set = new JRadioButton(Localization.lang("Set fields")); + append = new JRadioButton(Localization.lang("Append to fields")); + rename = new JRadioButton(Localization.lang("Rename field to") + ":"); + rename.setToolTipText(Localization.lang("Move contents of a field into a field with a different name")); + + Set allFields = frame.getCurrentBasePanel().getDatabase().getAllVisibleFields(); + + for (String f : allFields) { + field.addItem(f); + } + + set.addChangeListener(e -> + // Entering a setText is only relevant if we are setting, not clearing: + textFieldSet.setEnabled(set.isSelected())); + + append.addChangeListener(e -> { + // Text to append is only required if we are appending: + textFieldAppend.setEnabled(append.isSelected()); + // Overwrite protection makes no sense if we are appending to a field: + overwrite.setEnabled(!clear.isSelected() && !append.isSelected()); + }); + + clear.addChangeListener(e -> + // Overwrite protection makes no sense if we are clearing the field: + overwrite.setEnabled(!clear.isSelected() && !append.isSelected())); + + rename.addChangeListener(e -> + // Entering a setText is only relevant if we are renaming + textFieldRename.setEnabled(rename.isSelected())); + + overwrite = new JCheckBox(Localization.lang("Overwrite existing field values"), true); + ButtonGroup bg = new ButtonGroup(); + bg.add(all); + bg.add(selected); + bg = new ButtonGroup(); + bg.add(clear); + bg.add(set); + bg.add(append); + bg.add(rename); + FormBuilder builder = FormBuilder.create().layout(new FormLayout( + "left:pref, 4dlu, fill:100dlu:grow", "pref, 2dlu, pref, 2dlu, pref, 2dlu, pref, 2dlu, pref, 2dlu, pref, 2dlu, pref, 2dlu, pref, 2dlu, pref, 2dlu, pref, 2dlu, pref")); + builder.addSeparator(Localization.lang("Field name")).xyw(1, 1, 3); + builder.add(Localization.lang("Field name")).xy(1, 3); + builder.add(field).xy(3, 3); + builder.addSeparator(Localization.lang("Include entries")).xyw(1, 5, 3); + builder.add(all).xyw(1, 7, 3); + builder.add(selected).xyw(1, 9, 3); + builder.addSeparator(Localization.lang("New field value")).xyw(1, 11, 3); + builder.add(set).xy(1, 13); + builder.add(textFieldSet).xy(3, 13); + builder.add(clear).xyw(1, 15, 3); + builder.add(append).xy(1, 17); + builder.add(textFieldAppend).xy(3, 17); + builder.add(rename).xy(1, 19); + builder.add(textFieldRename).xy(3, 19); + builder.add(overwrite).xyw(1, 21, 3); + + ButtonBarBuilder bb = new ButtonBarBuilder(); + bb.addGlue(); + bb.addButton(ok); + bb.addButton(cancel); + bb.addGlue(); + builder.getPanel().setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); + bb.getPanel().setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); + diag.getContentPane().add(builder.getPanel(), BorderLayout.CENTER); + diag.getContentPane().add(bb.getPanel(), BorderLayout.SOUTH); + diag.pack(); + + ok.addActionListener(e -> { + // Check that any field name is set + String fieldText = (String) field.getSelectedItem(); + if ((fieldText == null) || fieldText.trim().isEmpty()) { + + frame.getDialogService().showErrorDialogAndWait(Localization.lang("You must enter at least one field name")); + + return; // Do not close the dialog. + } + + // Check if the user tries to rename multiple fields: + if (rename.isSelected()) { + String[] fields = getFieldNames(fieldText); + if (fields.length > 1) { + + frame.getDialogService().showErrorDialogAndWait(Localization.lang("You can only rename one field at a time")); + + return; // Do not close the dialog. + } + } + canceled = false; + diag.dispose(); + }); + + Action cancelAction = new AbstractAction() { + + @Override + public void actionPerformed(ActionEvent e) { + canceled = true; + diag.dispose(); + } + }; + cancel.addActionListener(cancelAction); + + // Key bindings: + ActionMap am = builder.getPanel().getActionMap(); + InputMap im = builder.getPanel().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); + im.put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE), "close"); + am.put("close", cancelAction); + } + private static String[] getFieldNames(String s) { return s.split("[\\s;,]"); } diff --git a/src/main/java/org/jabref/gui/actions/MergeEntriesAction.java b/src/main/java/org/jabref/gui/actions/MergeEntriesAction.java new file mode 100644 index 00000000000..257c8b04a18 --- /dev/null +++ b/src/main/java/org/jabref/gui/actions/MergeEntriesAction.java @@ -0,0 +1,20 @@ +package org.jabref.gui.actions; + +import org.jabref.gui.JabRefFrame; +import org.jabref.gui.mergeentries.MergeEntriesDialog; + +public class MergeEntriesAction extends SimpleCommand { + + private final JabRefFrame jabRefFrame; + + public MergeEntriesAction(JabRefFrame jabRefFrame) { + this.jabRefFrame = jabRefFrame; + } + + @Override + public void execute() { + MergeEntriesDialog dlg = new MergeEntriesDialog(jabRefFrame.getCurrentBasePanel(), jabRefFrame.getDialogService()); + dlg.setVisible(true); + } + +} diff --git a/src/main/java/org/jabref/gui/actions/MnemonicAwareAction.java b/src/main/java/org/jabref/gui/actions/MnemonicAwareAction.java index 13ba654cc38..b1bfa9f87d5 100644 --- a/src/main/java/org/jabref/gui/actions/MnemonicAwareAction.java +++ b/src/main/java/org/jabref/gui/actions/MnemonicAwareAction.java @@ -4,7 +4,7 @@ import javax.swing.Action; import javax.swing.Icon; -import org.jabref.gui.IconTheme; +import org.jabref.gui.icon.IconTheme; /** * This class extends {@link AbstractAction} with the ability to set diff --git a/src/main/java/org/jabref/gui/actions/NewDatabaseAction.java b/src/main/java/org/jabref/gui/actions/NewDatabaseAction.java index 5aa52aa62b0..90b2f8ced30 100644 --- a/src/main/java/org/jabref/gui/actions/NewDatabaseAction.java +++ b/src/main/java/org/jabref/gui/actions/NewDatabaseAction.java @@ -1,10 +1,5 @@ package org.jabref.gui.actions; -import java.awt.event.ActionEvent; - -import javax.swing.Action; - -import org.jabref.gui.IconTheme; import org.jabref.gui.JabRefFrame; import org.jabref.logic.l10n.Localization; import org.jabref.model.Defaults; @@ -12,24 +7,20 @@ import org.jabref.model.database.BibDatabaseMode; /** - * The action concerned with opening a new database. + * Create a new, empty, database. */ -public class NewDatabaseAction extends MnemonicAwareAction { +public class NewDatabaseAction extends SimpleCommand { private final JabRefFrame jabRefFrame; private final BibDatabaseMode mode; public NewDatabaseAction(JabRefFrame jabRefFrame, BibDatabaseMode mode) { - super(IconTheme.JabRefIcon.NEW.getIcon()); this.jabRefFrame = jabRefFrame; this.mode = mode; - putValue(Action.NAME, Localization.menuTitle("New %0 library", mode.getFormattedName())); - putValue(Action.SHORT_DESCRIPTION, Localization.lang("New %0 library", mode.getFormattedName())); } @Override - public void actionPerformed(ActionEvent e) { - // Create a new, empty, database. + public void execute() { BibDatabaseContext bibDatabaseContext = new BibDatabaseContext(new Defaults(BibDatabaseMode.BIBTEX)); bibDatabaseContext.setMode(mode); jabRefFrame.addTab(bibDatabaseContext, true); diff --git a/src/main/java/org/jabref/gui/actions/NewEntryAction.java b/src/main/java/org/jabref/gui/actions/NewEntryAction.java index c8f4a198591..72e657e2fb8 100644 --- a/src/main/java/org/jabref/gui/actions/NewEntryAction.java +++ b/src/main/java/org/jabref/gui/actions/NewEntryAction.java @@ -1,76 +1,56 @@ package org.jabref.gui.actions; -import java.awt.event.ActionEvent; import java.util.HashMap; import java.util.Map; - -import javax.swing.Action; -import javax.swing.KeyStroke; +import java.util.Optional; import org.jabref.Globals; import org.jabref.gui.EntryTypeDialog; -import org.jabref.gui.IconTheme; import org.jabref.gui.JabRefFrame; -import org.jabref.logic.l10n.Localization; -import org.jabref.model.EntryTypes; import org.jabref.model.entry.EntryType; -import org.jabref.model.strings.StringUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class NewEntryAction extends MnemonicAwareAction { +public class NewEntryAction extends SimpleCommand { private static final Logger LOGGER = LoggerFactory.getLogger(NewEntryAction.class); private final JabRefFrame jabRefFrame; - private String type; // The type of item to create. + /** + * The type of the entry to create. + */ + private final Optional type; - public NewEntryAction(JabRefFrame jabRefFrame, KeyStroke key) { - // This action leads to a dialog asking for entry type. - super(IconTheme.JabRefIcon.ADD_ENTRY.getIcon()); - this.jabRefFrame = jabRefFrame; - putValue(Action.NAME, Localization.menuTitle("New entry") + "..."); - putValue(Action.ACCELERATOR_KEY, key); - putValue(Action.SHORT_DESCRIPTION, Localization.lang("New BibTeX entry")); - } - public NewEntryAction(JabRefFrame jabRefFrame, String type) { + public NewEntryAction(JabRefFrame jabRefFrame) { this.jabRefFrame = jabRefFrame; - // This action leads to the creation of a specific entry. - putValue(Action.NAME, StringUtil.capitalizeFirst(type)); - this.type = type; + this.type = Optional.empty(); } - public NewEntryAction(JabRefFrame jabRefFrame, String type, KeyStroke key) { + public NewEntryAction(JabRefFrame jabRefFrame, EntryType type) { this.jabRefFrame = jabRefFrame; - // This action leads to the creation of a specific entry. - putValue(Action.NAME, StringUtil.capitalizeFirst(type)); - putValue(Action.ACCELERATOR_KEY, key); - this.type = type; + this.type = Optional.of(type); } @Override - public void actionPerformed(ActionEvent e) { - String thisType = type; - if (thisType == null) { - EntryTypeDialog etd = new EntryTypeDialog(jabRefFrame); - etd.setLocationRelativeTo(jabRefFrame); - etd.setVisible(true); - EntryType tp = etd.getChoice(); - if (tp == null) { - return; - } - thisType = tp.getName(); - - trackNewEntry(tp); + public void execute() { + if (jabRefFrame.getBasePanelCount() <= 0) { + LOGGER.error("Action 'New entry' must be disabled when no database is open."); + return; } - if (jabRefFrame.getBasePanelCount() > 0) { - jabRefFrame.getCurrentBasePanel().newEntry( - EntryTypes.getType(thisType, jabRefFrame.getCurrentBasePanel().getBibDatabaseContext().getMode()) - .get()); + if (type.isPresent()) { + jabRefFrame.getCurrentBasePanel().newEntry(type.get()); } else { - LOGGER.info("Action 'New entry' must be disabled when no database is open."); + EntryTypeDialog typeChoiceDialog = new EntryTypeDialog(jabRefFrame); + typeChoiceDialog.setVisible(true); + EntryType selectedType = typeChoiceDialog.getChoice(); + if (selectedType == null) { + return; + } + + trackNewEntry(selectedType); + jabRefFrame.getCurrentBasePanel().newEntry(selectedType); } } diff --git a/src/main/java/org/jabref/gui/actions/NewEntryFromPlainTextAction.java b/src/main/java/org/jabref/gui/actions/NewEntryFromPlainTextAction.java new file mode 100644 index 00000000000..0c048ea7ed8 --- /dev/null +++ b/src/main/java/org/jabref/gui/actions/NewEntryFromPlainTextAction.java @@ -0,0 +1,49 @@ +package org.jabref.gui.actions; + +import org.jabref.gui.EntryTypeDialog; +import org.jabref.gui.JabRefFrame; +import org.jabref.gui.plaintextimport.TextInputDialog; +import org.jabref.logic.util.UpdateField; +import org.jabref.logic.util.UpdateFieldPreferences; +import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.EntryType; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class NewEntryFromPlainTextAction extends SimpleCommand { + + private static final Logger LOGGER = LoggerFactory.getLogger(NewEntryFromPlainTextAction.class); + + private final UpdateFieldPreferences prefs; + private final JabRefFrame jabRefFrame; + + public NewEntryFromPlainTextAction(JabRefFrame jabRefFrame, UpdateFieldPreferences prefs) { + this.jabRefFrame = jabRefFrame; + this.prefs = prefs; + + } + + @Override + public void execute() { + if (jabRefFrame.getBasePanelCount() <= 0) { + LOGGER.error("Action 'New entry' must be disabled when no database is open."); + return; + } + + EntryTypeDialog typeChoiceDialog = new EntryTypeDialog(jabRefFrame); + typeChoiceDialog.setVisible(true); + EntryType selectedType = typeChoiceDialog.getChoice(); + if (selectedType == null) { + return; + } + BibEntry bibEntry = new BibEntry(selectedType.getName()); + + TextInputDialog tidialog = new TextInputDialog(jabRefFrame, bibEntry); + tidialog.setVisible(true); + if (tidialog.okPressed()) { + UpdateField.setAutomaticFields(bibEntry, false, false, prefs); + jabRefFrame.getCurrentBasePanel().insertEntry(bibEntry); + } + } +} diff --git a/src/main/java/org/jabref/gui/actions/NewSubDatabaseAction.java b/src/main/java/org/jabref/gui/actions/NewSubLibraryAction.java similarity index 55% rename from src/main/java/org/jabref/gui/actions/NewSubDatabaseAction.java rename to src/main/java/org/jabref/gui/actions/NewSubLibraryAction.java index 199f0400e4d..368fe9975ff 100644 --- a/src/main/java/org/jabref/gui/actions/NewSubDatabaseAction.java +++ b/src/main/java/org/jabref/gui/actions/NewSubLibraryAction.java @@ -1,14 +1,11 @@ package org.jabref.gui.actions; -import java.awt.event.ActionEvent; - -import javax.swing.Action; - import org.jabref.Globals; import org.jabref.gui.BasePanel; -import org.jabref.gui.IconTheme; +import org.jabref.gui.BasePanelPreferences; import org.jabref.gui.JabRefFrame; import org.jabref.gui.auximport.FromAuxDialog; +import org.jabref.gui.externalfiletype.ExternalFileTypes; import org.jabref.logic.l10n.Localization; import org.jabref.model.Defaults; import org.jabref.model.database.BibDatabaseContext; @@ -16,31 +13,26 @@ /** * The action concerned with generate a new (sub-)database from latex AUX file. */ -public class NewSubDatabaseAction extends MnemonicAwareAction { +public class NewSubLibraryAction extends SimpleCommand { private final JabRefFrame jabRefFrame; - public NewSubDatabaseAction(JabRefFrame jabRefFrame) { - super(IconTheme.JabRefIcon.NEW.getIcon()); + public NewSubLibraryAction(JabRefFrame jabRefFrame) { this.jabRefFrame = jabRefFrame; - putValue(Action.NAME, Localization.menuTitle("New sublibrary based on AUX file") + "..."); - putValue(Action.SHORT_DESCRIPTION, Localization.lang("New BibTeX sublibrary")); } @Override - public void actionPerformed(ActionEvent e) { - // Create a new, empty, database. - + public void execute() { FromAuxDialog dialog = new FromAuxDialog(jabRefFrame, "", true, jabRefFrame.getTabbedPane()); - dialog.setLocationRelativeTo(jabRefFrame); dialog.setVisible(true); if (dialog.generatePressed()) { Defaults defaults = new Defaults(Globals.prefs.getDefaultBibDatabaseMode()); - BasePanel bp = new BasePanel(jabRefFrame, new BibDatabaseContext(dialog.getGenerateDB(), defaults)); + BasePanel bp = new BasePanel(jabRefFrame, BasePanelPreferences.from(Globals.prefs), new BibDatabaseContext(dialog.getGenerateDB(), defaults), ExternalFileTypes.getInstance()); jabRefFrame.addTab(bp, true); jabRefFrame.output(Localization.lang("New library created.")); } } + } diff --git a/src/main/java/org/jabref/gui/actions/OldCommandWrapper.java b/src/main/java/org/jabref/gui/actions/OldCommandWrapper.java new file mode 100644 index 00000000000..c187b412684 --- /dev/null +++ b/src/main/java/org/jabref/gui/actions/OldCommandWrapper.java @@ -0,0 +1,50 @@ +package org.jabref.gui.actions; + +import javafx.beans.property.ReadOnlyDoubleProperty; + +import org.jabref.gui.BasePanel; +import org.jabref.gui.util.BindingsHelper; + +import de.saxsys.mvvmfx.utils.commands.CommandBase; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This wraps the old Swing commands so that they fit into the new infrastructure. + * In the long term, this class should be removed. + */ +public class OldCommandWrapper extends CommandBase { + + private static final Logger LOGGER = LoggerFactory.getLogger(OldCommandWrapper.class); + + private final Actions command; + private final BasePanel panel; + + public OldCommandWrapper(Actions command, BasePanel panel) { + this.command = command; + this.panel = panel; + } + + @Override + public void execute() { + try { + panel.runCommand(command); + } catch (Throwable ex) { + LOGGER.debug("Cannot execute command " + command + ".", ex); + } + } + + @Override + public double getProgress() { + return 0; + } + + @Override + public ReadOnlyDoubleProperty progressProperty() { + return null; + } + + public void setExecutable(boolean executable) { + this.executable.bind(BindingsHelper.constantOf(executable)); + } +} diff --git a/src/main/java/org/jabref/gui/actions/OldCommandWrapperForActiveDatabase.java b/src/main/java/org/jabref/gui/actions/OldCommandWrapperForActiveDatabase.java new file mode 100644 index 00000000000..d0807faee27 --- /dev/null +++ b/src/main/java/org/jabref/gui/actions/OldCommandWrapperForActiveDatabase.java @@ -0,0 +1,48 @@ +package org.jabref.gui.actions; + +import javafx.beans.property.ReadOnlyDoubleProperty; + +import org.jabref.JabRefGUI; +import org.jabref.gui.util.BindingsHelper; + +import de.saxsys.mvvmfx.utils.commands.CommandBase; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This wraps the old Swing commands so that they fit into the new infrastructure. + * In the long term, this class should be removed. + */ +public class OldCommandWrapperForActiveDatabase extends CommandBase { + + private static final Logger LOGGER = LoggerFactory.getLogger(OldCommandWrapperForActiveDatabase.class); + + private final Actions command; + + public OldCommandWrapperForActiveDatabase(Actions command) { + this.command = command; + } + + @Override + public void execute() { + try { + JabRefGUI.getMainFrame().getCurrentBasePanel().runCommand(command); + } catch (Throwable ex) { + LOGGER.debug("Cannot execute command " + command + ".", ex); + } + } + + @Override + public double getProgress() { + return 0; + } + + @Override + public ReadOnlyDoubleProperty progressProperty() { + return null; + } + + public void setExecutable(boolean executable) { + this.executable.bind(BindingsHelper.constantOf(executable)); + } +} diff --git a/src/main/java/org/jabref/gui/actions/OldDatabaseCommandWrapper.java b/src/main/java/org/jabref/gui/actions/OldDatabaseCommandWrapper.java new file mode 100644 index 00000000000..a752da3ce9c --- /dev/null +++ b/src/main/java/org/jabref/gui/actions/OldDatabaseCommandWrapper.java @@ -0,0 +1,55 @@ +package org.jabref.gui.actions; + +import java.util.Optional; + +import javafx.beans.property.ReadOnlyDoubleProperty; + +import org.jabref.gui.JabRefFrame; +import org.jabref.gui.StateManager; + +import de.saxsys.mvvmfx.utils.commands.CommandBase; +import org.fxmisc.easybind.EasyBind; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A command that is only executable if a database is open. + */ +public class OldDatabaseCommandWrapper extends CommandBase { + + private static final Logger LOGGER = LoggerFactory.getLogger(OldDatabaseCommandWrapper.class); + + private final Actions command; + private final JabRefFrame frame; + + public OldDatabaseCommandWrapper(Actions command, JabRefFrame frame, StateManager stateManager) { + this.command = command; + this.frame = frame; + + this.executable.bind( + EasyBind.map(stateManager.activeDatabaseProperty(), Optional::isPresent)); + } + + @Override + public void execute() { + if (frame.getTabbedPane().getTabs().size() > 0) { + try { + frame.getCurrentBasePanel().runCommand(command); + } catch (Throwable ex) { + LOGGER.error("Problem with executing command: " + command, ex); + } + } else { + LOGGER.info("Action '" + command + "' must be disabled when no database is open."); + } + } + + @Override + public double getProgress() { + return 0; + } + + @Override + public ReadOnlyDoubleProperty progressProperty() { + return null; + } +} diff --git a/src/main/java/org/jabref/gui/actions/OpenBrowserAction.java b/src/main/java/org/jabref/gui/actions/OpenBrowserAction.java index 56457b4c3d5..9cd0b92524e 100644 --- a/src/main/java/org/jabref/gui/actions/OpenBrowserAction.java +++ b/src/main/java/org/jabref/gui/actions/OpenBrowserAction.java @@ -1,49 +1,19 @@ package org.jabref.gui.actions; -import java.awt.event.ActionEvent; - -import javax.swing.AbstractAction; -import javax.swing.Action; -import javax.swing.Icon; - import org.jabref.gui.desktop.JabRefDesktop; -public class OpenBrowserAction extends AbstractAction { +public class OpenBrowserAction extends SimpleCommand { private final String urlToOpen; - /** - * OpenBrowserAction without icons - only to be used for menus - * - * @param urlToOpen URL string of an URL to be shown in the default web browser - * @param menuTitle title of the menu entry; should already be localized - * @param description description shown in a tooltip hovering over the menu/icon bar entry; should already be localized - */ - public OpenBrowserAction(String urlToOpen, String menuTitle, String description) { - super(menuTitle); - this.urlToOpen = urlToOpen; - putValue(Action.SHORT_DESCRIPTION, description); - } - - /** - * OpenBrowserAction with icons - * - * @param urlToOpen URL string of an URL to be shown in the default web browser - * @param menuTitle title of the menu entry; should already be localized - * @param description description shown in a tooltip hovering over the menu/icon bar entry; should already be localized - * @param smallIcon smallIcon to be shown in the menus - * @param largeIcon larger icon to be shown in the icon bar - */ - public OpenBrowserAction(String urlToOpen, String menuTitle, String description, Icon smallIcon, Icon largeIcon) { - super(menuTitle, smallIcon); + public OpenBrowserAction(String urlToOpen) { this.urlToOpen = urlToOpen; - putValue(Action.SHORT_DESCRIPTION, description); - putValue(Action.LARGE_ICON_KEY, largeIcon); } @Override - public void actionPerformed(ActionEvent e) { + public void execute() { JabRefDesktop.openBrowserShowPopup(urlToOpen); + } } diff --git a/src/main/java/org/jabref/gui/actions/SearchForUpdateAction.java b/src/main/java/org/jabref/gui/actions/SearchForUpdateAction.java index acf9807c849..5a8dc415b74 100644 --- a/src/main/java/org/jabref/gui/actions/SearchForUpdateAction.java +++ b/src/main/java/org/jabref/gui/actions/SearchForUpdateAction.java @@ -1,20 +1,11 @@ package org.jabref.gui.actions; -import java.awt.event.ActionEvent; - -import javax.swing.AbstractAction; - import org.jabref.JabRefGUI; -import org.jabref.logic.l10n.Localization; -public class SearchForUpdateAction extends AbstractAction { - - public SearchForUpdateAction() { - super(Localization.lang("Check for updates")); - } +public class SearchForUpdateAction extends SimpleCommand { @Override - public void actionPerformed(ActionEvent e) { + public void execute() { JabRefGUI.checkForNewVersion(true); } } diff --git a/src/main/java/org/jabref/gui/actions/SetupGeneralFieldsAction.java b/src/main/java/org/jabref/gui/actions/SetupGeneralFieldsAction.java new file mode 100644 index 00000000000..3f75fc14c20 --- /dev/null +++ b/src/main/java/org/jabref/gui/actions/SetupGeneralFieldsAction.java @@ -0,0 +1,21 @@ +package org.jabref.gui.actions; + +import org.jabref.gui.GenFieldsCustomizer; +import org.jabref.gui.JabRefFrame; + +public class SetupGeneralFieldsAction extends SimpleCommand { + + private final JabRefFrame jabRefFrame; + + public SetupGeneralFieldsAction(JabRefFrame jabRefFrame) { + this.jabRefFrame = jabRefFrame; + } + + @Override + public void execute() { + GenFieldsCustomizer gf = new GenFieldsCustomizer(jabRefFrame); + gf.setVisible(true); + + } + +} diff --git a/src/main/java/org/jabref/gui/actions/ShowDocumentViewerAction.java b/src/main/java/org/jabref/gui/actions/ShowDocumentViewerAction.java new file mode 100644 index 00000000000..7c15ae6d119 --- /dev/null +++ b/src/main/java/org/jabref/gui/actions/ShowDocumentViewerAction.java @@ -0,0 +1,12 @@ +package org.jabref.gui.actions; + +import org.jabref.gui.documentviewer.DocumentViewerView; + +public class ShowDocumentViewerAction extends SimpleCommand { + + @Override + public void execute() { + new DocumentViewerView().show(); + } + +} diff --git a/src/main/java/org/jabref/gui/actions/ShowPreferencesAction.java b/src/main/java/org/jabref/gui/actions/ShowPreferencesAction.java new file mode 100644 index 00000000000..7e80756495f --- /dev/null +++ b/src/main/java/org/jabref/gui/actions/ShowPreferencesAction.java @@ -0,0 +1,25 @@ +package org.jabref.gui.actions; + +import org.jabref.gui.JabRefFrame; +import org.jabref.gui.preftabs.PreferencesDialog; + +public class ShowPreferencesAction extends SimpleCommand { + + private PreferencesDialog prefsDialog; + private final JabRefFrame jabRefFrame; + + public ShowPreferencesAction(JabRefFrame jabRefFrame) { + this.jabRefFrame = jabRefFrame; + } + + @Override + public void execute() { + if (prefsDialog == null) { + prefsDialog = new PreferencesDialog(jabRefFrame); + } else { + prefsDialog.setValues(); + } + + prefsDialog.showAndWait(); + } +} diff --git a/src/main/java/org/jabref/gui/actions/SimpleCommand.java b/src/main/java/org/jabref/gui/actions/SimpleCommand.java new file mode 100644 index 00000000000..78b52e7f206 --- /dev/null +++ b/src/main/java/org/jabref/gui/actions/SimpleCommand.java @@ -0,0 +1,26 @@ +package org.jabref.gui.actions; + +import javafx.beans.property.ReadOnlyDoubleProperty; + +import org.jabref.gui.util.BindingsHelper; + +import de.saxsys.mvvmfx.utils.commands.CommandBase; + +/** + * A simple command that does not track progress of the action. + */ +public abstract class SimpleCommand extends CommandBase { + @Override + public double getProgress() { + return 0; + } + + @Override + public ReadOnlyDoubleProperty progressProperty() { + return null; + } + + public void setExecutable(boolean executable) { + this.executable.bind(BindingsHelper.constantOf(executable)); + } +} diff --git a/src/main/java/org/jabref/gui/actions/SortTabsAction.java b/src/main/java/org/jabref/gui/actions/SortTabsAction.java deleted file mode 100644 index 55f2432b0ce..00000000000 --- a/src/main/java/org/jabref/gui/actions/SortTabsAction.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.jabref.gui.actions; - -import java.awt.event.ActionEvent; -import java.util.Comparator; -import java.util.Locale; -import java.util.Map; -import java.util.TreeMap; - -import javax.swing.Action; - -import org.jabref.gui.BasePanel; -import org.jabref.gui.JabRefFrame; -import org.jabref.logic.l10n.Localization; - -/** - * This action rearranges all tabs in the main tabbed pane of the given JabRefFrame - * in alphabetical order. - */ -public class SortTabsAction extends MnemonicAwareAction implements Comparator { - private final JabRefFrame frame; - - public SortTabsAction(JabRefFrame frame) { - putValue(Action.NAME, Localization.menuTitle("Sort tabs")); - putValue(Action.SHORT_DESCRIPTION, Localization.lang("Rearrange tabs alphabetically by title")); - this.frame = frame; - } - - @Override - public void actionPerformed(ActionEvent e) { - // Make a sorted Map that compares case-insensitively: - Map map = new TreeMap<>(this); - - for (BasePanel panel : frame.getBasePanelList()) { - map.put(panel.getTabTitle(), panel); - } - - frame.getTabbedPane().removeAll(); - for (Map.Entry entry : map.entrySet()) { - frame.addTab(entry.getValue(), false); - } - } - - @Override - public int compare(String o1, String o2) { - return o1.toLowerCase(Locale.ROOT).compareTo(o2.toLowerCase(Locale.ROOT)); - } -} diff --git a/src/main/java/org/jabref/gui/actions/StandardActions.java b/src/main/java/org/jabref/gui/actions/StandardActions.java new file mode 100644 index 00000000000..d6bf600aed5 --- /dev/null +++ b/src/main/java/org/jabref/gui/actions/StandardActions.java @@ -0,0 +1,234 @@ +package org.jabref.gui.actions; + +import java.util.Optional; + +import org.jabref.gui.icon.IconTheme; +import org.jabref.gui.icon.JabRefIcon; +import org.jabref.gui.keyboard.KeyBinding; +import org.jabref.logic.l10n.Localization; +import org.jabref.model.database.BibDatabaseMode; + +public enum StandardActions implements Action { + + COPY_MORE(Localization.lang("Copy") + "..."), + COPY_TITLE(Localization.lang("Copy title"), KeyBinding.COPY_TITLE), + COPY_KEY(Localization.lang("Copy BibTeX key"), KeyBinding.COPY_BIBTEX_KEY), + COPY_CITE_KEY(Localization.lang("Copy \\cite{BibTeX key}"), KeyBinding.COPY_CITE_BIBTEX_KEY), + COPY_KEY_AND_TITLE(Localization.lang("Copy BibTeX key and title"), KeyBinding.COPY_BIBTEX_KEY_AND_TITLE), + COPY_KEY_AND_LINK(Localization.lang("Copy BibTeX key and link"), KeyBinding.COPY_BIBTEX_KEY_AND_LINK), + COPY_CITATION_HTML(Localization.lang("Copy citation") + " (HTML)", KeyBinding.COPY_PREVIEW), + COPY_CITATION_MORE(Localization.lang("Copy citation") + "..."), + COPY_CITATION_TEXT("Text"), + COPY_CITATION_RTF("RTF"), + COPY_CITATION_ASCII_DOC("AsciiDoc"), + COPY_CITATION_XSLFO("XSL-FO"), + COPY_CITATION_PREVIEW(Localization.lang("Copy preview"), KeyBinding.COPY_PREVIEW), + EXPORT_TO_CLIPBOARD(Localization.lang("Export to clipboard"), IconTheme.JabRefIcons.EXPORT_TO_CLIPBOARD), + EXPORT_SELECTED_TO_CLIPBOARD(Localization.lang("Export selected entries to clipboard"), IconTheme.JabRefIcons.EXPORT_TO_CLIPBOARD), + COPY(Localization.lang("Copy"), IconTheme.JabRefIcons.COPY, KeyBinding.COPY), + PASTE(Localization.lang("Paste"), IconTheme.JabRefIcons.PASTE, KeyBinding.PASTE), + CUT(Localization.lang("Cut"), IconTheme.JabRefIcons.CUT, KeyBinding.CUT), + DELETE(Localization.lang("Delete"), IconTheme.JabRefIcons.DELETE_ENTRY), + DELETE_ENTRY(Localization.lang("Delete Entry"), IconTheme.JabRefIcons.DELETE_ENTRY, KeyBinding.DELETE_ENTRY), + SEND_AS_EMAIL(Localization.lang("Send as email"), IconTheme.JabRefIcons.EMAIL), + OPEN_EXTERNAL_FILE(Localization.lang("Open file"), IconTheme.JabRefIcons.FILE, KeyBinding.OPEN_FILE), + OPEN_URL(Localization.lang("Open URL or DOI"), IconTheme.JabRefIcons.WWW, KeyBinding.OPEN_URL_OR_DOI), + MERGE_WITH_FETCHED_ENTRY(Localization.lang("Get BibTeX data from %0", "DOI/ISBN/...")), + ATTACH_FILE(Localization.lang("Attach file"), IconTheme.JabRefIcons.ATTACH_FILE), + ADD_TO_GROUP(Localization.lang("Add to group")), + REMOVE_FROM_GROUP(Localization.lang("Remove from group")), + MOVE_TO_GROUP(Localization.lang("Move to group")), + PRIORITY(Localization.lang("Priority"), IconTheme.JabRefIcons.PRIORITY), + CLEAR_PRIORITY(Localization.lang("Clear priority")), + PRIORITY_HIGH(Localization.lang("Set priority to high"), IconTheme.JabRefIcons.PRIORITY_HIGH), + PRIORITY_MEDIUM(Localization.lang("Set priority to medium"), IconTheme.JabRefIcons.PRIORITY_MEDIUM), + PRIORITY_LOW(Localization.lang("Set priority to low"), IconTheme.JabRefIcons.PRIORITY_LOW), + QUALITY(Localization.lang("Quality"), IconTheme.JabRefIcons.QUALITY), + QUALITY_ASSURED(Localization.lang("Toggle quality assured"), IconTheme.JabRefIcons.QUALITY_ASSURED), + RANKING(Localization.lang("Rank"), IconTheme.JabRefIcons.RANKING), + CLEAR_RANK(Localization.lang("Clear rank")), + RANK_1("", IconTheme.JabRefIcons.RANK1), + RANK_2("", IconTheme.JabRefIcons.RANK2), + RANK_3("", IconTheme.JabRefIcons.RANK3), + RANK_4("", IconTheme.JabRefIcons.RANK4), + RANK_5("", IconTheme.JabRefIcons.RANK5), + PRINTED(Localization.lang("Printed"), IconTheme.JabRefIcons.PRINTED), + TOGGLE_PRINTED(Localization.lang("Toggle print status"), IconTheme.JabRefIcons.PRINTED), + READ_STATUS(Localization.lang("Read status"), IconTheme.JabRefIcons.READ_STATUS), + CLEAR_READ_STATUS(Localization.lang("Clear read status")), + READ(Localization.lang("Set read status to read"), IconTheme.JabRefIcons.READ_STATUS_READ), + SKIMMED(Localization.lang("Set read status to skimmed"), IconTheme.JabRefIcons.READ_STATUS_SKIMMED), + RELEVANCE(Localization.lang("Relevance"), IconTheme.JabRefIcons.RELEVANCE), + RELEVANT(Localization.lang("Toggle relevance"), IconTheme.JabRefIcons.RELEVANCE), + NEW_LIBRARY_BIBTEX(Localization.lang("New %0 library", BibDatabaseMode.BIBTEX.getFormattedName()), IconTheme.JabRefIcons.NEW), + NEW_LIBRARY_BIBLATEX(Localization.lang("New %0 library", BibDatabaseMode.BIBLATEX.getFormattedName()), IconTheme.JabRefIcons.NEW), + OPEN_LIBRARY(Localization.lang("Open library"), IconTheme.JabRefIcons.OPEN, KeyBinding.OPEN_DATABASE), + IMPORT_EXPORT(Localization.lang("Import & Export"), IconTheme.JabRefIcons.IMPORT_EXPORT), + MERGE_DATABASE(Localization.lang("Append library"), Localization.lang("Append contents from a BibTeX library into the currently viewed library")), + SAVE_LIBRARY(Localization.lang("Save library"), IconTheme.JabRefIcons.SAVE, KeyBinding.SAVE_DATABASE), + SAVE_LIBRARY_AS(Localization.lang("Save library as..."), KeyBinding.SAVE_DATABASE_AS), + SAVE_SELECTED_AS_PLAIN_BIBTEX(Localization.lang("Save selected as plain BibTeX...")), + SAVE_ALL(Localization.lang("Save all"), Localization.lang("Save all open libraries"), IconTheme.JabRefIcons.SAVE_ALL, KeyBinding.SAVE_ALL), + IMPORT_INTO_NEW_LIBRARY(Localization.lang("Import into new library"), KeyBinding.IMPORT_INTO_NEW_DATABASE), + IMPORT_INTO_CURRENT_LIBRARY(Localization.lang("Import into current library"), KeyBinding.IMPORT_INTO_CURRENT_DATABASE), + EXPORT_ALL(Localization.lang("Export")), + EXPORT_SELECTED(Localization.lang("Export selected entries")), + CONNECT_TO_SHARED_DB(Localization.lang("Connect to shared database")), + PULL_CHANGES_FROM_SHARED_DB(Localization.lang("Pull changes from shared database"), IconTheme.JabRefIcons.PULL, KeyBinding.PULL_CHANGES_FROM_SHARED_DATABASE), + CLOSE_LIBRARY(Localization.lang("Close library"), Localization.lang("Close the current library"), IconTheme.JabRefIcons.CLOSE, KeyBinding.CLOSE_DATABASE), + QUIT(Localization.lang("Quit"), Localization.lang("Quit JabRef"), IconTheme.JabRefIcons.CLOSE_JABREF, KeyBinding.QUIT_JABREF), + UNDO(Localization.lang("Undo"), IconTheme.JabRefIcons.UNDO, KeyBinding.UNDO), + REDO(Localization.lang("Redo"), IconTheme.JabRefIcons.REDO, KeyBinding.REDO), + REPLACE_ALL(Localization.lang("Replace string"), KeyBinding.REPLACE_STRING), + MANAGE_KEYWORDS(Localization.lang("Manage keywords")), + MASS_SET_FIELDS(Localization.lang("Set/clear/append/rename fields")), + TOGGLE_GROUPS(Localization.lang("Toggle groups interface"), IconTheme.JabRefIcons.TOGGLE_GROUPS, KeyBinding.TOGGLE_GROUPS_INTERFACE), + TOOGLE_OO(Localization.lang("OpenOffice/LibreOffice connection"), IconTheme.JabRefIcons.FILE_OPENOFFICE, KeyBinding.OPEN_OPEN_OFFICE_LIBRE_OFFICE_CONNECTION), + TOGGLE_WEB_SEARCH(Localization.lang("Web search"), Localization.lang("Toggle web search interface"), IconTheme.JabRefIcons.WWW, KeyBinding.WEB_SEARCH), + + NEW_SUB_LIBRARY_FROM_AUX(Localization.lang("New sublibrary based on AUX file") + "...", Localization.lang("New BibTeX sublibrary"), IconTheme.JabRefIcons.NEW), + WRITE_XMP(Localization.lang("Write XMP-metadata to PDFs"), Localization.lang("Will write XMP-metadata to the PDFs linked from selected entries."), KeyBinding.WRITE_XMP), + OPEN_FOLDER(Localization.lang("Open folder"), Localization.lang("Open folder"), KeyBinding.OPEN_FOLDER), + OPEN_FILE(Localization.lang("Open file"), Localization.lang("Open file"), IconTheme.JabRefIcons.FILE, KeyBinding.OPEN_FILE), + OPEN_CONSOLE(Localization.lang("Open terminal here"), Localization.lang("Open terminal here"), IconTheme.JabRefIcons.CONSOLE, KeyBinding.OPEN_CONSOLE), + COPY_LINKED_FILES(Localization.lang("Copy linked files to folder...")), + ABBREVIATE_ISO(Localization.lang("Abbreviate journal names (ISO)"), Localization.lang("Abbreviate journal names of the selected entries (ISO abbreviation)"), KeyBinding.ABBREVIATE), + ABBREVIATE_MEDLINE(Localization.lang("Abbreviate journal names (MEDLINE)"), Localization.lang("Abbreviate journal names of the selected entries (MEDLINE abbreviation)")), + UNABBREVIATE(Localization.lang("Unabbreviate journal names"), Localization.lang("Unabbreviate journal names of the selected entries"), KeyBinding.UNABBREVIATE), + + MANAGE_CUSTOM_EXPORTS(Localization.lang("Manage custom exports")), + MANAGE_CUSTOM_IMPORTS(Localization.lang("Manage custom imports")), + CUSTOMIZE_ENTRY_TYPES(Localization.lang("Customize entry types")), + SETUP_GENERAL_FIELDS(Localization.lang("Set up general fields")), + MANAGE_EXTERNAL_FILETYPES(Localization.lang("Manage external file types")), + MANAGE_PROTECTED_TERMS(Localization.lang("Manage protected terms")), + BIBTEX_KEY_PATTERN(Localization.lang("BibTeX key patterns")), + SHOW_PREFS(Localization.lang("Preferences")), + MANAGE_JOURNALS(Localization.lang("Manage journal abbreviations")), + CUSTOMIZE_KEYBINDING(Localization.lang("Customize key bindings"), IconTheme.JabRefIcons.KEY_BINDINGS), + MANAGE_CONTENT_SELECTORS(Localization.lang("Manage content selectors"), IconTheme.JabRefIcons.PREFERENCES), + MANAGE_CITE_KEY_PATTERNS(Localization.lang("BibTeX key patterns")), + + TOGGLE_PREVIEW(Localization.lang("Toggle entry preview"), IconTheme.JabRefIcons.TOGGLE_ENTRY_PREVIEW, KeyBinding.TOGGLE_ENTRY_PREVIEW), + EDIT_ENTRY(Localization.lang("Edit entry"), IconTheme.JabRefIcons.EDIT_ENTRY, KeyBinding.EDIT_ENTRY), + SHOW_PDV_VIEWER(Localization.lang("Show document viewer"), IconTheme.JabRefIcons.PDF_FILE), + NEXT_PREVIEW_STYLE(Localization.lang("Next preview layout"), KeyBinding.NEXT_PREVIEW_LAYOUT), + PREVIOUS_PREVIEW_STYLE(Localization.lang("Previous preview layout"), KeyBinding.PREVIOUS_PREVIEW_LAYOUT), + SELECT_ALL(Localization.lang("Select all"), KeyBinding.SELECT_ALL), + + NEW_ENTRY(Localization.lang("New entry"), IconTheme.JabRefIcons.ADD_ENTRY, KeyBinding.NEW_ENTRY), + NEW_ARTICLE(Localization.lang("New article"), IconTheme.JabRefIcons.ADD_ENTRY), + NEW_ENTRY_FROM_PLAINTEX(Localization.lang("New entry from plain text"), KeyBinding.NEW_FROM_PLAIN_TEXT), + LIBRARY_PROPERTIES(Localization.lang("Library properties")), + EDIT_PREAMBLE(Localization.lang("Edit preamble")), + EDIT_STRINGS(Localization.lang("Edit strings"), IconTheme.JabRefIcons.EDIT_STRINGS, KeyBinding.EDIT_STRINGS), + + FIND_DUPLICATES(Localization.lang("Find duplicates"), IconTheme.JabRefIcons.FIND_DUPLICATES), + MERGE_ENTRIES(Localization.lang("Merge entries"), IconTheme.JabRefIcons.MERGE_ENTRIES), + RESOLVE_DUPLICATE_KEYS(Localization.lang("Resolve duplicate BibTeX keys"), Localization.lang("Find and remove duplicate BibTeX keys"), KeyBinding.RESOLVE_DUPLICATE_BIBTEX_KEYS), + CHECK_INTEGRITY(Localization.lang("Check integrity"), KeyBinding.CHECK_INTEGRITY), + AUTOGENERATE_KEYS(Localization.lang("Autogenerate BibTeX keys"), IconTheme.JabRefIcons.MAKE_KEY, KeyBinding.AUTOGENERATE_BIBTEX_KEYS), + FIND_UNLINKED_FILES(Localization.lang("Find unlinked files"), Localization.lang("Searches for unlinked PDF files on the file system"), KeyBinding.FIND_UNLINKED_FILES), + AUTO_LINK_FILES(Localization.lang("Automatically set file links"), IconTheme.JabRefIcons.AUTO_FILE_LINK, KeyBinding.AUTOMATICALLY_LINK_FILES), + LOOKUP_DOC_IDENTIFIER(Localization.lang("Look up document identifier")), + LOOKUP_FULLTEXT(Localization.lang("Look up full text documents"), KeyBinding.DOWNLOAD_FULL_TEXT), + + GENERATE_CITE_KEY(Localization.lang("Autogenerate BibTeX keys"), IconTheme.JabRefIcons.MAKE_KEY, KeyBinding.AUTOGENERATE_BIBTEX_KEYS), + DOWNLOAD_FULL_TEXT(Localization.lang("Look up full text documents"), KeyBinding.DOWNLOAD_FULL_TEXT), + CLEANUP_ENTRIES(Localization.lang("Cleanup entries"), IconTheme.JabRefIcons.CLEANUP_ENTRIES, KeyBinding.CLEANUP), + SET_FILE_LINKS(Localization.lang("Automatically set file links"), IconTheme.JabRefIcons.AUTO_FILE_LINK, KeyBinding.AUTOMATICALLY_LINK_FILES), + + HELP(Localization.lang("Online help"), IconTheme.JabRefIcons.HELP, KeyBinding.HELP), + WEB_MENU(Localization.lang("JabRef resources")), + OPEN_WEBPAGE(Localization.lang("Website"), Localization.lang("Opens JabRef's website")), + OPEN_FACEBOOK("Facebook", Localization.lang("Opens JabRef's Facebook page"), IconTheme.JabRefIcons.FACEBOOK), + OPEN_TWITTER("Twitter", Localization.lang("Opens JabRef's Twitter page"), IconTheme.JabRefIcons.TWITTER), + OPEN_BLOG(Localization.lang("Blog"), Localization.lang("Opens JabRef's blog"), IconTheme.JabRefIcons.BLOG), + OPEN_DEV_VERSION_LINK(Localization.lang("Development version"), Localization.lang("Opens a link where the current development version can be downloaded")), + OPEN_CHANGELOG(Localization.lang("View change log"), Localization.lang("See what has been changed in the JabRef versions")), + FORK_ME(Localization.lang("Fork me on GitHub"), Localization.lang("Opens JabRef's GitHub page"), IconTheme.JabRefIcons.GITHUB), + DONATE(Localization.lang("Donate to JabRef"), Localization.lang("Donate to JabRef"), IconTheme.JabRefIcons.DONATE), + OPEN_FORUM(Localization.lang("Online help forum"), Localization.lang("Online help forum"), IconTheme.JabRefIcons.FORUM), + ERROR_CONSOLE(Localization.lang("View event log"), Localization.lang("Display all error messages")), + SEARCH_FOR_UPDATES(Localization.lang("Check for updates")), + ABOUT(Localization.lang("About JabRef"), Localization.lang("About JabRef")); + + + private final String text; + private final String description; + private final Optional icon; + private final Optional keyBinding; + + StandardActions(String text) { + this(text, ""); + } + + StandardActions(String text, IconTheme.JabRefIcons icon) { + this.text = text; + this.description = ""; + this.icon = Optional.of(icon); + this.keyBinding = Optional.empty(); + } + + StandardActions(String text, IconTheme.JabRefIcons icon, KeyBinding keyBinding) { + this.text = text; + this.description = ""; + this.icon = Optional.of(icon); + this.keyBinding = Optional.of(keyBinding); + } + + StandardActions(String text, String description, IconTheme.JabRefIcons icon) { + this.text = text; + this.description = description; + this.icon = Optional.of(icon); + this.keyBinding = Optional.empty(); + } + + StandardActions(String text, String description, IconTheme.JabRefIcons icon, KeyBinding keyBinding) { + this.text = text; + this.description = description; + this.icon = Optional.of(icon); + this.keyBinding = Optional.of(keyBinding); + } + + StandardActions(String text, KeyBinding keyBinding) { + this.text = text; + this.description = ""; + this.keyBinding = Optional.of(keyBinding); + this.icon = Optional.empty(); + } + + StandardActions(String text, String description) { + this.text = text; + this.description = description; + this.icon = Optional.empty(); + this.keyBinding = Optional.empty(); + } + + StandardActions(String text, String description, KeyBinding keyBinding) { + this.text = text; + this.description = description; + this.icon = Optional.empty(); + this.keyBinding = Optional.of(keyBinding); + } + + @Override + public Optional getIcon() { + return icon; + } + + @Override + public Optional getKeyBinding() { + return keyBinding; + } + + @Override + public String getText() { + return text; + } + + @Override + public String getDescription() { + return description; + } +} diff --git a/src/main/java/org/jabref/gui/actions/WriteXMPAction.java b/src/main/java/org/jabref/gui/actions/WriteXMPAction.java new file mode 100644 index 00000000000..8873ea254a7 --- /dev/null +++ b/src/main/java/org/jabref/gui/actions/WriteXMPAction.java @@ -0,0 +1,20 @@ +package org.jabref.gui.actions; + +import org.jabref.gui.BasePanel; +import org.jabref.gui.externalfiles.WriteXMPActionWorker; + +public class WriteXMPAction extends SimpleCommand { + + private final BasePanel basePanel; + + public WriteXMPAction(BasePanel basePanel) { + this.basePanel = basePanel; + + } + + @Override + public void execute() { + new WriteXMPActionWorker(basePanel).run(); + } + +} diff --git a/src/main/java/org/jabref/gui/auximport/FromAuxDialog.java b/src/main/java/org/jabref/gui/auximport/FromAuxDialog.java index 76892c71620..22a65babf34 100644 --- a/src/main/java/org/jabref/gui/auximport/FromAuxDialog.java +++ b/src/main/java/org/jabref/gui/auximport/FromAuxDialog.java @@ -13,18 +13,18 @@ import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JComponent; +import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JScrollPane; -import javax.swing.JTabbedPane; import javax.swing.JTextArea; import javax.swing.JTextField; +import javafx.scene.control.TabPane; + import org.jabref.Globals; import org.jabref.gui.BasePanel; -import org.jabref.gui.DialogService; -import org.jabref.gui.FXDialogService; import org.jabref.gui.JabRefDialog; import org.jabref.gui.JabRefFrame; import org.jabref.gui.keyboard.KeyBinding; @@ -60,7 +60,7 @@ public class FromAuxDialog extends JabRefDialog { private JTextArea statusInfos; // all open databases from JabRefFrame - private final JTabbedPane parentTabbedPane; + private final TabPane parentTabbedPane; private boolean generatePressed; @@ -68,8 +68,8 @@ public class FromAuxDialog extends JabRefDialog { private final JabRefFrame parentFrame; - public FromAuxDialog(JabRefFrame frame, String title, boolean modal, JTabbedPane viewedDBs) { - super(frame, title, modal, FromAuxDialog.class); + public FromAuxDialog(JabRefFrame frame, String title, boolean modal, TabPane viewedDBs) { + super((JFrame) null, title, modal, FromAuxDialog.class); parentTabbedPane = viewedDBs; parentFrame = frame; @@ -132,7 +132,7 @@ private void jbInit() { // Key bindings: ActionMap am = statusPanel.getActionMap(); InputMap im = statusPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); - im.put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE_DIALOG), "close"); + im.put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE), "close"); am.put("close", new AbstractAction() { @Override @@ -145,10 +145,10 @@ public void actionPerformed(ActionEvent e) { private void initPanels() { // collect the names of all open databases - int len = parentTabbedPane.getTabCount(); + int len = parentTabbedPane.getTabs().size(); int toSelect = -1; for (int i = 0; i < len; i++) { - dbChooser.addItem(parentTabbedPane.getTitleAt(i)); + dbChooser.addItem(parentTabbedPane.getTabs().get(i).getText()); if (parentFrame.getBasePanelAt(i) == parentFrame.getCurrentBasePanel()) { toSelect = i; } @@ -164,11 +164,10 @@ private void initPanels() { .addExtensionFilter(FileType.AUX) .withDefaultExtension(FileType.AUX) .withInitialDirectory(Globals.prefs.get(JabRefPreferences.WORKING_DIRECTORY)).build(); - DialogService ds = new FXDialogService(); browseAuxFileButton.addActionListener(e -> { Optional file = DefaultTaskExecutor - .runInJavaFXThread(() -> ds.showFileOpenDialog(fileDialogConfiguration)); + .runInJavaFXThread(() -> parentFrame.getDialogService().showFileOpenDialog(fileDialogConfiguration)); file.ifPresent(f -> auxFileField.setText(f.toAbsolutePath().toString())); }); @@ -202,7 +201,7 @@ private void initPanels() { private void parseActionPerformed() { parseButton.setEnabled(false); - BasePanel bp = (BasePanel) parentTabbedPane.getComponentAt(dbChooser.getSelectedIndex()); + BasePanel bp = (BasePanel) parentTabbedPane.getTabs().get(dbChooser.getSelectedIndex()).getContent(); notFoundList.removeAll(); statusInfos.setText(null); BibDatabase refBase = bp.getDatabase(); diff --git a/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternDialog.java b/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternDialog.java index 503f2368107..3897f74042b 100644 --- a/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternDialog.java +++ b/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternDialog.java @@ -10,13 +10,13 @@ import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JDialog; +import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.WindowConstants; import org.jabref.Globals; import org.jabref.gui.BasePanel; import org.jabref.gui.JabRefDialog; -import org.jabref.gui.JabRefFrame; import org.jabref.gui.keyboard.KeyBinder; import org.jabref.logic.l10n.Localization; import org.jabref.model.bibtexkeypattern.AbstractBibtexKeyPattern; @@ -26,28 +26,18 @@ public class BibtexKeyPatternDialog extends JabRefDialog { - private MetaData metaData; - private BasePanel panel; + private final MetaData metaData; + private final BasePanel panel; private final BibtexKeyPatternPanel bibtexKeyPatternPanel; - - public BibtexKeyPatternDialog(JabRefFrame parent, BasePanel panel) { - super(parent, Localization.lang("BibTeX key patterns"), true, BibtexKeyPatternDialog.class); + public BibtexKeyPatternDialog(BasePanel panel) { + super((JFrame) null, Localization.lang("BibTeX key patterns"), true, BibtexKeyPatternDialog.class); this.bibtexKeyPatternPanel = new BibtexKeyPatternPanel(panel); - setPanel(panel); - init(); - } - - /** - * Used for updating an existing Dialog - * - * @param panel the panel to read the data from - */ - public void setPanel(BasePanel panel) { this.panel = panel; this.metaData = panel.getBibDatabaseContext().getMetaData(); - AbstractBibtexKeyPattern keypatterns = metaData.getCiteKeyPattern(Globals.prefs.getKeyPattern()); - bibtexKeyPatternPanel.setValues(keypatterns); + AbstractBibtexKeyPattern keyPattern = metaData.getCiteKeyPattern(Globals.prefs.getKeyPattern()); + bibtexKeyPatternPanel.setValues(keyPattern); + init(); } private void init() { diff --git a/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternPanel.java b/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternPanel.java index f14b7ab073f..5d92dce5e62 100644 --- a/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternPanel.java +++ b/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternPanel.java @@ -19,8 +19,8 @@ import org.jabref.Globals; import org.jabref.gui.BasePanel; -import org.jabref.gui.IconTheme; import org.jabref.gui.help.HelpAction; +import org.jabref.gui.icon.IconTheme; import org.jabref.logic.help.HelpFile; import org.jabref.logic.l10n.Localization; import org.jabref.model.EntryTypes; @@ -135,7 +135,7 @@ private void buildGUI() { con.weighty = 0; con.anchor = GridBagConstraints.SOUTHEAST; con.insets = new Insets(0, 5, 0, 5); - JButton hlb = new JButton(IconTheme.JabRefIcon.HELP.getSmallIcon()); + JButton hlb = new JButton(IconTheme.JabRefIcons.HELP.getSmallIcon()); hlb.setToolTipText(Localization.lang("Help on key patterns")); gbl.setConstraints(hlb, con); add(hlb); diff --git a/src/main/java/org/jabref/gui/bibtexkeypattern/ResolveDuplicateLabelDialog.java b/src/main/java/org/jabref/gui/bibtexkeypattern/ResolveDuplicateLabelDialog.java index 88b21423bdb..e4ecee93456 100644 --- a/src/main/java/org/jabref/gui/bibtexkeypattern/ResolveDuplicateLabelDialog.java +++ b/src/main/java/org/jabref/gui/bibtexkeypattern/ResolveDuplicateLabelDialog.java @@ -14,6 +14,7 @@ import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JDialog; +import javax.swing.JFrame; import javax.swing.JLabel; import javafx.embed.swing.JFXPanel; @@ -21,6 +22,7 @@ import org.jabref.Globals; import org.jabref.gui.BasePanel; +import org.jabref.gui.FXDialogService; import org.jabref.gui.PreviewPanel; import org.jabref.gui.customjfx.CustomJFXPanel; import org.jabref.gui.keyboard.KeyBinding; @@ -43,7 +45,7 @@ class ResolveDuplicateLabelDialog { public ResolveDuplicateLabelDialog(BasePanel panel, String key, List entries) { - diag = new JDialog(panel.frame(), Localization.lang("Duplicate BibTeX key"), true); + diag = new JDialog((JFrame) null, Localization.lang("Duplicate BibTeX key"), true); FormBuilder b = FormBuilder.create().layout(new FormLayout( "left:pref, 4dlu, fill:pref", "p")); @@ -56,7 +58,7 @@ public ResolveDuplicateLabelDialog(BasePanel panel, String key, List e JCheckBox cb = new JCheckBox(Localization.lang("Generate BibTeX key"), !first); b.appendRows("1dlu, p"); b.add(cb).xy(1, row); - PreviewPanel previewPanel = new PreviewPanel(null, null); + PreviewPanel previewPanel = new PreviewPanel(null, null, Globals.getKeyPrefs(), Globals.prefs.getPreviewPreferences(), new FXDialogService()); previewPanel.setEntry(entry); JFXPanel container = CustomJFXPanel.wrap(new Scene(previewPanel)); container.setPreferredSize(new Dimension(800, 90)); @@ -102,7 +104,7 @@ public void actionPerformed(ActionEvent e) { ActionMap am = b.getPanel().getActionMap(); InputMap im = b.getPanel().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); - im.put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE_DIALOG), "close"); + im.put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE), "close"); am.put("close", closeAction); } diff --git a/src/main/java/org/jabref/gui/cleanup/CleanupDialog.java b/src/main/java/org/jabref/gui/cleanup/CleanupDialog.java new file mode 100644 index 00000000000..4ac358e8434 --- /dev/null +++ b/src/main/java/org/jabref/gui/cleanup/CleanupDialog.java @@ -0,0 +1,34 @@ +package org.jabref.gui.cleanup; + +import javax.swing.JScrollPane; + +import javafx.scene.control.ButtonType; + +import org.jabref.gui.util.BaseDialog; +import org.jabref.gui.util.ControlHelper; +import org.jabref.logic.cleanup.CleanupPreset; +import org.jabref.logic.l10n.Localization; +import org.jabref.model.database.BibDatabaseContext; + +public class CleanupDialog extends BaseDialog { + + public CleanupDialog(BibDatabaseContext databaseContext, CleanupPreset initialPreset) { + setTitle(Localization.lang("Cleanup entries")); + getDialogPane().setPrefSize(600, 600); + getDialogPane().getButtonTypes().setAll(ButtonType.OK, ButtonType.CANCEL); + + CleanupPresetPanel presetPanel = new CleanupPresetPanel(databaseContext, initialPreset); + presetPanel.getScrollPane().setVisible(true); + JScrollPane scrollPane = presetPanel.getScrollPane(); + + setResultConverter(button -> { + if (button == ButtonType.OK) { + return presetPanel.getCleanupPreset(); + } else { + return null; + } + }); + + ControlHelper.setSwingContent(getDialogPane(), scrollPane); + } +} diff --git a/src/main/java/org/jabref/gui/collab/ChangeScanner.java b/src/main/java/org/jabref/gui/collab/ChangeScanner.java index f91c7e8c2b2..b7f6ab06d70 100644 --- a/src/main/java/org/jabref/gui/collab/ChangeScanner.java +++ b/src/main/java/org/jabref/gui/collab/ChangeScanner.java @@ -7,7 +7,6 @@ import java.util.List; import java.util.Optional; -import javax.swing.JOptionPane; import javax.swing.SwingUtilities; import javax.swing.tree.DefaultMutableTreeNode; @@ -32,18 +31,17 @@ import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.BibtexString; -import org.jabref.model.metadata.MetaData; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ChangeScanner implements Runnable { + private static final Logger LOGGER = LoggerFactory.getLogger(ChangeScanner.class); private final File file; private final Path tempFile; private final BibDatabaseContext databaseInMemory; - private final MetaData metadataInMemory; private final BasePanel panel; private final JabRefFrame frame; @@ -62,7 +60,6 @@ public ChangeScanner(JabRefFrame frame, BasePanel bp, File file, Path tempFile) this.panel = bp; this.frame = frame; this.databaseInMemory = bp.getBibDatabaseContext(); - this.metadataInMemory = bp.getBibDatabaseContext().getMetaData(); this.file = file; this.tempFile = tempFile; } @@ -84,8 +81,7 @@ private static BibEntry bestFit(BibEntry targetEntry, List entries) { public void displayResult(final DisplayResultCallback fup) { if (changes.getChildCount() > 0) { SwingUtilities.invokeLater(() -> { - ChangeDisplayDialog changeDialog = new ChangeDisplayDialog(frame, panel, databaseInTemp.getDatabase(), changes); - changeDialog.setLocationRelativeTo(frame); + ChangeDisplayDialog changeDialog = new ChangeDisplayDialog(null, panel, databaseInTemp.getDatabase(), changes); changeDialog.setVisible(true); fup.scanResultsResolved(changeDialog.isOkPressed()); if (changeDialog.isOkPressed()) { @@ -94,8 +90,9 @@ public void displayResult(final DisplayResultCallback fup) { } }); } else { - JOptionPane.showMessageDialog(frame, Localization.lang("No actual changes found."), - Localization.lang("External changes"), JOptionPane.INFORMATION_MESSAGE); + frame.getDialogService().showInformationDialogAndWait(Localization.lang("External changes"), + Localization.lang("No actual changes found.")); + fup.scanResultsResolved(true); } } @@ -103,8 +100,11 @@ public void displayResult(final DisplayResultCallback fup) { private void storeTempDatabase() { JabRefExecutorService.INSTANCE.execute(() -> { try { - SavePreferences prefs = Globals.prefs.loadForSaveFromPreferences().withMakeBackup(false) - .withEncoding(panel.getBibDatabaseContext().getMetaData().getEncoding() + SavePreferences prefs = Globals.prefs.loadForSaveFromPreferences() + .withMakeBackup(false) + .withEncoding(panel.getBibDatabaseContext() + .getMetaData() + .getEncoding() .orElse(Globals.prefs.getDefaultEncoding())); BibDatabaseWriter databaseWriter = new BibtexDatabaseWriter<>(FileSaveSession::new); @@ -132,7 +132,7 @@ public void run() { // Start looking at changes. BibDatabaseDiff differences = BibDatabaseDiff.compare(databaseInTemp, databaseOnDisk); differences.getMetaDataDifferences().ifPresent(diff -> { - changes.add(new MetaDataChangeViewModel(metadataInMemory, diff)); + changes.add(new MetaDataChangeViewModel(diff)); diff.getGroupDifferences().ifPresent(groupDiff -> changes.add(new GroupChangeViewModel(groupDiff))); }); differences.getPreambleDifferences().ifPresent(diff -> changes.add(new PreambleChangeViewModel(databaseInMemory.getDatabase().getPreamble().orElse(""), diff))); @@ -176,6 +176,7 @@ private ChangeViewModel createBibEntryDiff(BibEntryDiff diff) { @FunctionalInterface public interface DisplayResultCallback { + void scanResultsResolved(boolean resolved); } } diff --git a/src/main/java/org/jabref/gui/collab/DatabaseChangeMonitor.java b/src/main/java/org/jabref/gui/collab/DatabaseChangeMonitor.java index bf73e9b098d..8b4424e870b 100644 --- a/src/main/java/org/jabref/gui/collab/DatabaseChangeMonitor.java +++ b/src/main/java/org/jabref/gui/collab/DatabaseChangeMonitor.java @@ -10,6 +10,7 @@ import org.jabref.JabRefExecutorService; import org.jabref.gui.BasePanel; import org.jabref.gui.SidePaneManager; +import org.jabref.gui.SidePaneType; import org.jabref.logic.util.io.FileBasedLock; import org.jabref.logic.util.io.FileUtil; import org.jabref.model.database.BibDatabaseContext; @@ -82,18 +83,15 @@ public void fileUpdated() { // thread: Runnable t = () -> { - // Check if there is already a notification about external - // changes: + // Check if there is already a notification about external changes: SidePaneManager sidePaneManager = panel.getSidePaneManager(); - boolean hasAlready = sidePaneManager.hasComponent(FileUpdatePanel.class); + boolean hasAlready = sidePaneManager.isComponentVisible(SidePaneType.FILE_UPDATE_NOTIFICATION); if (hasAlready) { - sidePaneManager.hideComponent(FileUpdatePanel.class); - sidePaneManager.unregisterComponent(FileUpdatePanel.class); + sidePaneManager.hide(SidePaneType.FILE_UPDATE_NOTIFICATION); } - FileUpdatePanel pan = new FileUpdatePanel(panel, sidePaneManager, - database.getDatabaseFile().orElse(null), scanner); - sidePaneManager.register(pan); - sidePaneManager.show(FileUpdatePanel.class); + + FileUpdatePanel component = (FileUpdatePanel) sidePaneManager.getComponent(SidePaneType.FILE_UPDATE_NOTIFICATION); + component.showForFile(panel, database.getDatabaseFile().orElse(null), scanner); }; if (scanner.changesFound()) { diff --git a/src/main/java/org/jabref/gui/collab/EntryAddChangeViewModel.java b/src/main/java/org/jabref/gui/collab/EntryAddChangeViewModel.java index 5905d1a67ff..e4334d5598b 100644 --- a/src/main/java/org/jabref/gui/collab/EntryAddChangeViewModel.java +++ b/src/main/java/org/jabref/gui/collab/EntryAddChangeViewModel.java @@ -5,7 +5,9 @@ import javafx.embed.swing.JFXPanel; import javafx.scene.Scene; +import org.jabref.Globals; import org.jabref.gui.BasePanel; +import org.jabref.gui.FXDialogService; import org.jabref.gui.PreviewPanel; import org.jabref.gui.customjfx.CustomJFXPanel; import org.jabref.gui.undo.NamedCompound; @@ -25,7 +27,7 @@ public EntryAddChangeViewModel(BibEntry diskEntry) { super(Localization.lang("Added entry")); this.diskEntry = diskEntry; - PreviewPanel previewPanel = new PreviewPanel(null, null); + PreviewPanel previewPanel = new PreviewPanel(null, null, Globals.getKeyPrefs(), Globals.prefs.getPreviewPreferences(), new FXDialogService()); previewPanel.setEntry(diskEntry); container = CustomJFXPanel.wrap(new Scene(previewPanel)); } @@ -35,7 +37,7 @@ public boolean makeChange(BasePanel panel, BibDatabase secondary, NamedCompound diskEntry.setId(IdGenerator.next()); panel.getDatabase().insertEntry(diskEntry); secondary.insertEntry(diskEntry); - undoEdit.addEdit(new UndoableInsertEntry(panel.getDatabase(), diskEntry, panel)); + undoEdit.addEdit(new UndoableInsertEntry(panel.getDatabase(), diskEntry)); return true; } diff --git a/src/main/java/org/jabref/gui/collab/EntryDeleteChangeViewModel.java b/src/main/java/org/jabref/gui/collab/EntryDeleteChangeViewModel.java index 0f7d0a11779..a36990be7eb 100644 --- a/src/main/java/org/jabref/gui/collab/EntryDeleteChangeViewModel.java +++ b/src/main/java/org/jabref/gui/collab/EntryDeleteChangeViewModel.java @@ -5,7 +5,9 @@ import javafx.embed.swing.JFXPanel; import javafx.scene.Scene; +import org.jabref.Globals; import org.jabref.gui.BasePanel; +import org.jabref.gui.FXDialogService; import org.jabref.gui.PreviewPanel; import org.jabref.gui.customjfx.CustomJFXPanel; import org.jabref.gui.undo.NamedCompound; @@ -42,7 +44,7 @@ public EntryDeleteChangeViewModel(BibEntry memEntry, BibEntry tmpEntry) { LOGGER.debug("Modified entry: " + memEntry.getCiteKeyOptional().orElse("") + "\n Modified locally: " + isModifiedLocally); - PreviewPanel previewPanel = new PreviewPanel(null, null); + PreviewPanel previewPanel = new PreviewPanel(null, null, Globals.getKeyPrefs(), Globals.prefs.getPreviewPreferences(), new FXDialogService()); previewPanel.setEntry(memEntry); container = CustomJFXPanel.wrap(new Scene(previewPanel)); } diff --git a/src/main/java/org/jabref/gui/collab/FileUpdatePanel.java b/src/main/java/org/jabref/gui/collab/FileUpdatePanel.java index b2e72606dec..ea270674a02 100644 --- a/src/main/java/org/jabref/gui/collab/FileUpdatePanel.java +++ b/src/main/java/org/jabref/gui/collab/FileUpdatePanel.java @@ -10,41 +10,39 @@ import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; + +import javafx.embed.swing.SwingNode; +import javafx.scene.Node; +import javafx.scene.layout.Priority; import org.jabref.gui.BasePanel; -import org.jabref.gui.IconTheme; import org.jabref.gui.SidePaneComponent; import org.jabref.gui.SidePaneManager; +import org.jabref.gui.SidePaneType; +import org.jabref.gui.actions.Action; +import org.jabref.gui.icon.IconTheme; import org.jabref.logic.l10n.Localization; public class FileUpdatePanel extends SidePaneComponent implements ActionListener, ChangeScanner.DisplayResultCallback { private final SidePaneManager manager; + private ChangeScanner scanner; + private File file; + private BasePanel panel; - private final ChangeScanner scanner; + public FileUpdatePanel(SidePaneManager manager) { + super(manager, IconTheme.JabRefIcons.SAVE, Localization.lang("File changed")); + this.manager = manager; + } - public FileUpdatePanel(BasePanel panel, SidePaneManager manager, File file, ChangeScanner scanner) { - super(manager, IconTheme.JabRefIcon.SAVE.getIcon(), Localization.lang("File changed")); - close.setEnabled(false); + public void showForFile(BasePanel panel, File file, ChangeScanner scanner) { + this.file = file; this.panel = panel; - this.manager = manager; this.scanner = scanner; - JPanel main = new JPanel(); - main.setLayout(new BorderLayout()); - - JLabel message = new JLabel("

" - + Localization.lang("The file
'%0'
has been modified
externally!", file.getName()) - + "
", SwingConstants.CENTER); - - main.add(message, BorderLayout.CENTER); - JButton test = new JButton(Localization.lang("Review changes")); - main.add(test, BorderLayout.SOUTH); - main.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1)); - - add(main, BorderLayout.CENTER); - test.addActionListener(this); + this.show(); } /** @@ -56,25 +54,46 @@ public BasePanel getPanel() { return panel; } - /** - * Unregister when this component closes. We need that to avoid showing - * two such external change warnings at the same time, only the latest one. - */ @Override - public void componentClosing() { - manager.unregisterComponent(FileUpdatePanel.class); + public Priority getResizePolicy() { + return Priority.NEVER; } @Override - public int getRescalingWeight() { - return 0; + public ToggleCommand getToggleCommand() { + throw new UnsupportedOperationException(); } @Override - public ToggleAction getToggleAction() { + public Action getToggleAction() { throw new UnsupportedOperationException(); } + @Override + protected Node createContentPane() { + JPanel main = new JPanel(); + main.setLayout(new BorderLayout()); + + JLabel message = new JLabel("
" + + Localization.lang("The file
'%0'
has been modified
externally!", file.getName()) + + "
", SwingConstants.CENTER); + + main.add(message, BorderLayout.CENTER); + JButton reviewChanges = new JButton(Localization.lang("Review changes")); + reviewChanges.addActionListener(this); + main.add(reviewChanges, BorderLayout.SOUTH); + main.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1)); + + SwingNode swingNode = new SwingNode(); + SwingUtilities.invokeLater(() -> swingNode.setContent(main)); + return swingNode; + } + + @Override + public SidePaneType getType() { + return SidePaneType.FILE_UPDATE_NOTIFICATION; + } + /** * actionPerformed * @@ -103,7 +122,7 @@ public void actionPerformed(ActionEvent e) { @Override public void scanResultsResolved(boolean resolved) { if (resolved) { - manager.hideComponent(this); + manager.hide(this.getType()); panel.markExternalChangesAsResolved(); } } diff --git a/src/main/java/org/jabref/gui/collab/MetaDataChangeViewModel.java b/src/main/java/org/jabref/gui/collab/MetaDataChangeViewModel.java index 307fba9f4a0..7418ff1695f 100644 --- a/src/main/java/org/jabref/gui/collab/MetaDataChangeViewModel.java +++ b/src/main/java/org/jabref/gui/collab/MetaDataChangeViewModel.java @@ -10,19 +10,14 @@ import org.jabref.model.database.BibDatabase; import org.jabref.model.metadata.MetaData; -/** - * - */ class MetaDataChangeViewModel extends ChangeViewModel { private final InfoPane infoPane = new InfoPane(); private final JScrollPane sp = new JScrollPane(infoPane); - private final MetaData originalMetaData; private final MetaData newMetaData; - public MetaDataChangeViewModel(MetaData originalMetaData, MetaDataDiff metaDataDiff) { + public MetaDataChangeViewModel(MetaDataDiff metaDataDiff) { super(Localization.lang("Metadata change")); - this.originalMetaData = originalMetaData; this.newMetaData = metaDataDiff.getNewMetaData(); infoPane.setText("" + Localization.lang("Metadata change") + ""); diff --git a/src/main/java/org/jabref/gui/collab/PreambleChangeViewModel.java b/src/main/java/org/jabref/gui/collab/PreambleChangeViewModel.java index 47946d0196e..a3f707b5cd5 100644 --- a/src/main/java/org/jabref/gui/collab/PreambleChangeViewModel.java +++ b/src/main/java/org/jabref/gui/collab/PreambleChangeViewModel.java @@ -18,7 +18,6 @@ class PreambleChangeViewModel extends ChangeViewModel { private final InfoPane tp = new InfoPane(); private final JScrollPane sp = new JScrollPane(tp); - public PreambleChangeViewModel(String mem, PreambleDiff diff) { super(Localization.lang("Changed preamble")); this.disk = diff.getNewPreamble(); @@ -43,7 +42,7 @@ public PreambleChangeViewModel(String mem, PreambleDiff diff) { @Override public boolean makeChange(BasePanel panel, BibDatabase secondary, NamedCompound undoEdit) { panel.getDatabase().setPreamble(disk); - undoEdit.addEdit(new UndoablePreambleChange(panel.getDatabase(), panel, mem, disk)); + undoEdit.addEdit(new UndoablePreambleChange(panel.getDatabase(), mem, disk)); secondary.setPreamble(disk); return true; } diff --git a/src/main/java/org/jabref/gui/contentselector/ContentSelectorDialog.java b/src/main/java/org/jabref/gui/contentselector/ContentSelectorDialog.java index 8801779f71e..1a180891503 100644 --- a/src/main/java/org/jabref/gui/contentselector/ContentSelectorDialog.java +++ b/src/main/java/org/jabref/gui/contentselector/ContentSelectorDialog.java @@ -197,7 +197,7 @@ private void setupActions() { dispose(); } catch (Exception ex) { LOGGER.info("Could not apply changes in \"Manage content selectors\"", ex); - JOptionPane.showMessageDialog(frame, Localization.lang("Could not apply changes.")); + JOptionPane.showMessageDialog(null, Localization.lang("Could not apply changes.")); } }); @@ -210,7 +210,7 @@ private void setupActions() { applyChanges(); } catch (Exception ex) { LOGGER.info("Could not apply changes in \"Manage content selectors\"", ex); - JOptionPane.showMessageDialog(frame, Localization.lang("Could not apply changes.")); + JOptionPane.showMessageDialog(null, Localization.lang("Could not apply changes.")); } }); diff --git a/src/main/resources/org/jabref/gui/copyfiles/CopyFilesDialog.fxml b/src/main/java/org/jabref/gui/copyfiles/CopyFilesDialog.fxml similarity index 56% rename from src/main/resources/org/jabref/gui/copyfiles/CopyFilesDialog.fxml rename to src/main/java/org/jabref/gui/copyfiles/CopyFilesDialog.fxml index 88aa1b0a03b..177eb45d930 100644 --- a/src/main/resources/org/jabref/gui/copyfiles/CopyFilesDialog.fxml +++ b/src/main/java/org/jabref/gui/copyfiles/CopyFilesDialog.fxml @@ -1,13 +1,12 @@ - - - - +
@@ -22,13 +21,6 @@
- - - -