From ea5d56e4a7a8bcb25c2bb00dc3651c807bc9739e Mon Sep 17 00:00:00 2001 From: Stefan Date: Sun, 18 Feb 2018 04:48:56 +0100 Subject: [PATCH 01/40] Fixed unicode string --- scripts/syncLang.py | 55 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/scripts/syncLang.py b/scripts/syncLang.py index 150d1bbc662..a0359f18bc8 100644 --- a/scripts/syncLang.py +++ b/scripts/syncLang.py @@ -14,7 +14,47 @@ URL_BASE = "https://github.com/JabRef/jabref/tree/master/src/main/resources/l10n/" +try: + # Just to make sure not to break anything, in case py3.x is not supported. + import pathlib + + class PathFinder: + """ + This class is designed to automatically locate this script's path within the repository. + Once it found it's location it can easily provide paths to other important directories and files. + + requires Python 3.4 or higher + """ + + + @staticmethod + def getScriptLocation(): + """ + :return the path this script is currently located as pathlib.Path object. + """ + return pathlib.Path(__file__) + + @staticmethod + def getJabRefMainDirectory(): + """ + Searches the script's path backwards until it finds the matching base directory. + :return the path to JabRef's base directory as pathlib.Path object. + """ + scriptLocation = PathFinder.getScriptLocation() + for parent in scriptLocation.parents: + if parent.name == 'jabref': + return parent + + # Important paths of the JabRef repository + JABREF_BASE_DIRECTORY = PathFinder.getJabRefMainDirectory() + JABREF_SOURCE_DIRECTORY = JABREF_BASE_DIRECTORY / 'src' + JABREF_SCRIPTS_DIRECTORY = JABREF_BASE_DIRECTORY / 'scripts' + JABREF_LOCALIZATION_DIRECTORY = JABREF_SOURCE_DIRECTORY / 'main/resources/l10n' +except: + logging.info("Unable to use PathFinder class.") + class Git: + def get_current_branch(self): """ :return: the current git branch @@ -36,6 +76,7 @@ def __call_command(self, command): class Keys: + def __init__(self, lines): self.lines = lines @@ -50,7 +91,7 @@ def duplicates(self): if key: if key in keys_checked: duplicates.append(u"{key}={value}".format(key=key, value=value)) - translation_in_list = "u{key}={value}".format(key=key, value=keys_checked[key]) + translation_in_list = u"{key}={value}".format(key=key, value=keys_checked[key]) if translation_in_list not in duplicates: duplicates.append(translation_in_list) else: @@ -152,6 +193,7 @@ def __extract_key_and_value(line): class SyncLang: + def __init__(self, extended, out_file='status.md'): """ :param extended: boolean: if the keys with problems should be printed @@ -258,7 +300,7 @@ def __all_jabref_properties(self): :return: list of strings: all the JabRef_*.preferences files with the english at the beginning """ jabref_property_files = sorted(self.__other_jabref_properties()) - jabref_property_files.insert(0, os.path.join(RES_DIR, "JabRef_en.properties")) + jabref_property_files.insert(0, self.main_jabref_preferences) return jabref_property_files def __other_jabref_properties(self): @@ -315,7 +357,7 @@ def __update_properties(self, main_property_file, other_property_files): key = main_keys.key_from_line(line) if key is not None: # Do not write empty keys - if keys[key] != "": + if keys[key] != "": other_lines_to_write.append(u"{key}={value}\n".format(key=key, value=keys[key])) else: other_lines_to_write.append(line) @@ -433,8 +475,7 @@ def _percentage(whole, part): logging.info('Current status written to ' + self.markdown_output) -if '__main__' == __name__: - +def main(): if len(sys.argv) == 2 and sys.argv[1] == "markdown": SyncLang(extended=False, out_file='status.md').status_create_markdown() @@ -464,3 +505,7 @@ def _percentage(whole, part): [-e | --extended]: if the translations keys which create problems should be printed """) + + +if '__main__' == __name__: + main() From ba7d87d2415c54992952b89cdc4673194a5ee929 Mon Sep 17 00:00:00 2001 From: Stefan Date: Sun, 18 Feb 2018 05:55:53 +0100 Subject: [PATCH 02/40] Fixed logical issue within merging process --- scripts/syncLang.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/scripts/syncLang.py b/scripts/syncLang.py index a0359f18bc8..33305f9c01b 100644 --- a/scripts/syncLang.py +++ b/scripts/syncLang.py @@ -111,15 +111,15 @@ def fix_duplicates(self): if key: if key in keys: if not keys[key]: - fixed.append("{key}={value}".format(key=key, value=keys[key])) + fixed.append(u"{key}={value}".format(key=key, value=keys[key])) keys[key] = value elif not value: - fixed.append("{key}={value}".format(key=key, value=value)) + fixed.append(u"{key}={value}".format(key=key, value=value)) elif keys[key] == value: - fixed.append("{key}={value}".format(key=key, value=value)) + fixed.append(u"{key}={value}".format(key=key, value=value)) elif keys[key] != value: - not_fixed.append("{key}={value}".format(key=key, value=value)) - not_fixed.append("{key}={value}".format(key=key, value=keys[key])) + not_fixed.append(u"{key}={value}".format(key=key, value=value)) + not_fixed.append(u"{key}={value}".format(key=key, value=keys[key])) else: keys[key] = value @@ -347,9 +347,11 @@ def __update_properties(self, main_property_file, other_property_files): num_keys_obsolete = len(keys_obsolete) for missing_key in keys_missing: + logging.debug("Adding missing Key: " + missing_key) keys[missing_key] = "" for obsolete_key in keys_obsolete: + logging.debug("Deleting obsolete Key: " + obsolete_key) del keys[obsolete_key] other_lines_to_write = [] @@ -357,8 +359,8 @@ def __update_properties(self, main_property_file, other_property_files): key = main_keys.key_from_line(line) if key is not None: # Do not write empty keys - if keys[key] != "": - other_lines_to_write.append(u"{key}={value}\n".format(key=key, value=keys[key])) + #if keys[key] != "": + other_lines_to_write.append(u"{key}={value}\n".format(key=key, value=keys[key])) else: other_lines_to_write.append(line) From 254449fea3e712ece044322c7a73adc547014cba Mon Sep 17 00:00:00 2001 From: Stefan Date: Sun, 18 Feb 2018 13:22:44 +0100 Subject: [PATCH 03/40] Added format_key_and_value method --- scripts/syncLang.py | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/scripts/syncLang.py b/scripts/syncLang.py index 33305f9c01b..11c870460e8 100644 --- a/scripts/syncLang.py +++ b/scripts/syncLang.py @@ -13,7 +13,6 @@ RES_DIR = "src/main/resources/l10n" URL_BASE = "https://github.com/JabRef/jabref/tree/master/src/main/resources/l10n/" - try: # Just to make sure not to break anything, in case py3.x is not supported. import pathlib @@ -26,7 +25,6 @@ class PathFinder: requires Python 3.4 or higher """ - @staticmethod def getScriptLocation(): """ @@ -52,6 +50,7 @@ def getJabRefMainDirectory(): JABREF_LOCALIZATION_DIRECTORY = JABREF_SOURCE_DIRECTORY / 'main/resources/l10n' except: logging.info("Unable to use PathFinder class.") + class Git: @@ -90,8 +89,8 @@ def duplicates(self): key, value = self.__extract_key_and_value(line=line) if key: if key in keys_checked: - duplicates.append(u"{key}={value}".format(key=key, value=value)) - translation_in_list = u"{key}={value}".format(key=key, value=keys_checked[key]) + duplicates.append(self.format_key_and_value(key=key, value=value)) + translation_in_list = self.format_key_and_value(key=key, value=keys_checked[key]) if translation_in_list not in duplicates: duplicates.append(translation_in_list) else: @@ -111,15 +110,15 @@ def fix_duplicates(self): if key: if key in keys: if not keys[key]: - fixed.append(u"{key}={value}".format(key=key, value=keys[key])) + fixed.append(self.format_key_and_value(key=key, value=keys[key])) keys[key] = value elif not value: - fixed.append(u"{key}={value}".format(key=key, value=value)) + fixed.append(self.format_key_and_value(key=key, value=value)) elif keys[key] == value: - fixed.append(u"{key}={value}".format(key=key, value=value)) + fixed.append(self.format_key_and_value(key=key, value=value)) elif keys[key] != value: - not_fixed.append(u"{key}={value}".format(key=key, value=value)) - not_fixed.append(u"{key}={value}".format(key=key, value=keys[key])) + not_fixed.append(self.format_key_and_value(key=key, value=value)) + not_fixed.append(self.format_key_and_value(key=key, value=keys[key])) else: keys[key] = value @@ -190,6 +189,10 @@ def __extract_key_and_value(line): if index_key_end > 0: return line[0:index_key_end].strip(), line[index_key_end + 1:].strip() return None, None + + @staticmethod + def format_key_and_value(key, value): + return u"{key}={value}".format(key=key, value=value) class SyncLang: @@ -359,8 +362,8 @@ def __update_properties(self, main_property_file, other_property_files): key = main_keys.key_from_line(line) if key is not None: # Do not write empty keys - #if keys[key] != "": - other_lines_to_write.append(u"{key}={value}\n".format(key=key, value=keys[key])) + # if keys[key] != "": + other_lines_to_write.append(Keys.format_key_and_value(key=key, value=keys[key])) else: other_lines_to_write.append(line) From b00bfdd6ce8b3373fa58f6757edee04f79426fe0 Mon Sep 17 00:00:00 2001 From: Stefan Date: Sun, 18 Feb 2018 13:40:13 +0100 Subject: [PATCH 04/40] Added new line for new properties --- scripts/syncLang.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/syncLang.py b/scripts/syncLang.py index 11c870460e8..c9fa5dc70d6 100644 --- a/scripts/syncLang.py +++ b/scripts/syncLang.py @@ -363,7 +363,7 @@ def __update_properties(self, main_property_file, other_property_files): if key is not None: # Do not write empty keys # if keys[key] != "": - other_lines_to_write.append(Keys.format_key_and_value(key=key, value=keys[key])) + other_lines_to_write.append(Keys.format_key_and_value(key=key, value=keys[key]) + "\n") else: other_lines_to_write.append(line) From 7a7f33f27a6e38737869b5756df1dfa4d8f26ee3 Mon Sep 17 00:00:00 2001 From: Stefan Date: Sun, 18 Feb 2018 15:40:47 +0100 Subject: [PATCH 05/40] Renamed method and moved Path variables into PathFinder class --- scripts/syncLang.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/syncLang.py b/scripts/syncLang.py index c9fa5dc70d6..52a5fdf062f 100644 --- a/scripts/syncLang.py +++ b/scripts/syncLang.py @@ -33,7 +33,7 @@ def getScriptLocation(): return pathlib.Path(__file__) @staticmethod - def getJabRefMainDirectory(): + def getJabRefBaseDirectory(): """ Searches the script's path backwards until it finds the matching base directory. :return the path to JabRef's base directory as pathlib.Path object. @@ -43,11 +43,11 @@ def getJabRefMainDirectory(): if parent.name == 'jabref': return parent - # Important paths of the JabRef repository - JABREF_BASE_DIRECTORY = PathFinder.getJabRefMainDirectory() - JABREF_SOURCE_DIRECTORY = JABREF_BASE_DIRECTORY / 'src' - JABREF_SCRIPTS_DIRECTORY = JABREF_BASE_DIRECTORY / 'scripts' - JABREF_LOCALIZATION_DIRECTORY = JABREF_SOURCE_DIRECTORY / 'main/resources/l10n' + # Important paths of the JabRef repository + JABREF_BASE_DIRECTORY = self.getJabRefBaseDirectory() + JABREF_SOURCE_DIRECTORY = JABREF_BASE_DIRECTORY / 'src' + JABREF_SCRIPTS_DIRECTORY = JABREF_BASE_DIRECTORY / 'scripts' + JABREF_LOCALIZATION_DIRECTORY = JABREF_SOURCE_DIRECTORY / 'main/resources/l10n' except: logging.info("Unable to use PathFinder class.") From 759ea5d4436ac3fb3321453a2aaca97630dc5cf0 Mon Sep 17 00:00:00 2001 From: Stefan Date: Mon, 19 Feb 2018 12:44:27 +0100 Subject: [PATCH 06/40] Removed empty line, except statement is now catching ImportErrors --- scripts/syncLang.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/syncLang.py b/scripts/syncLang.py index 52a5fdf062f..817dcfbed08 100644 --- a/scripts/syncLang.py +++ b/scripts/syncLang.py @@ -16,7 +16,6 @@ try: # Just to make sure not to break anything, in case py3.x is not supported. import pathlib - class PathFinder: """ This class is designed to automatically locate this script's path within the repository. @@ -48,7 +47,7 @@ def getJabRefBaseDirectory(): JABREF_SOURCE_DIRECTORY = JABREF_BASE_DIRECTORY / 'src' JABREF_SCRIPTS_DIRECTORY = JABREF_BASE_DIRECTORY / 'scripts' JABREF_LOCALIZATION_DIRECTORY = JABREF_SOURCE_DIRECTORY / 'main/resources/l10n' -except: +except ImportError: logging.info("Unable to use PathFinder class.") From f5752453b825c1fe4763130c736c469fcb33fa31 Mon Sep 17 00:00:00 2001 From: Stefan Date: Mon, 19 Feb 2018 22:15:55 +0100 Subject: [PATCH 07/40] Ignoring empty keys again, new keys are added in english by default. --- scripts/syncLang.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/scripts/syncLang.py b/scripts/syncLang.py index 817dcfbed08..fb612e494a9 100644 --- a/scripts/syncLang.py +++ b/scripts/syncLang.py @@ -315,6 +315,7 @@ def __other_jabref_properties(self): def __update_properties(self, main_property_file, other_property_files): main_lines = self.__read_file_as_lines(filename=main_property_file) main_keys = Keys(main_lines) + main_keys_dict = main_keys.translations_as_dict() main_duplicates = main_keys.duplicates() num_main_duplicates = len(main_duplicates) @@ -350,7 +351,8 @@ def __update_properties(self, main_property_file, other_property_files): for missing_key in keys_missing: logging.debug("Adding missing Key: " + missing_key) - keys[missing_key] = "" + # Missing keys are added with english translation by default. + keys[missing_key] = main_keys_dict[missing_key] for obsolete_key in keys_obsolete: logging.debug("Deleting obsolete Key: " + obsolete_key) @@ -361,8 +363,8 @@ def __update_properties(self, main_property_file, other_property_files): key = main_keys.key_from_line(line) if key is not None: # Do not write empty keys - # if keys[key] != "": - other_lines_to_write.append(Keys.format_key_and_value(key=key, value=keys[key]) + "\n") + if keys[key] != "": + other_lines_to_write.append(Keys.format_key_and_value(key=key, value=keys[key]) + "\n") else: other_lines_to_write.append(line) From 19edb0fb0bf68745f4d37a7d546e61ee54645fc7 Mon Sep 17 00:00:00 2001 From: Stefan Date: Mon, 19 Feb 2018 22:19:46 +0100 Subject: [PATCH 08/40] Removed debug messages --- scripts/syncLang.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/scripts/syncLang.py b/scripts/syncLang.py index fb612e494a9..a4903490d5d 100644 --- a/scripts/syncLang.py +++ b/scripts/syncLang.py @@ -350,12 +350,10 @@ def __update_properties(self, main_property_file, other_property_files): num_keys_obsolete = len(keys_obsolete) for missing_key in keys_missing: - logging.debug("Adding missing Key: " + missing_key) # Missing keys are added with english translation by default. keys[missing_key] = main_keys_dict[missing_key] for obsolete_key in keys_obsolete: - logging.debug("Deleting obsolete Key: " + obsolete_key) del keys[obsolete_key] other_lines_to_write = [] From 011501dde1559b92cc82262612719741b56ddc00 Mon Sep 17 00:00:00 2001 From: Stefan Date: Mon, 19 Feb 2018 22:35:36 +0100 Subject: [PATCH 09/40] Had to kick out the Path variables of the class again. :/ --- scripts/syncLang.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/syncLang.py b/scripts/syncLang.py index a4903490d5d..3f303c4ca34 100644 --- a/scripts/syncLang.py +++ b/scripts/syncLang.py @@ -42,11 +42,11 @@ def getJabRefBaseDirectory(): if parent.name == 'jabref': return parent - # Important paths of the JabRef repository - JABREF_BASE_DIRECTORY = self.getJabRefBaseDirectory() - JABREF_SOURCE_DIRECTORY = JABREF_BASE_DIRECTORY / 'src' - JABREF_SCRIPTS_DIRECTORY = JABREF_BASE_DIRECTORY / 'scripts' - JABREF_LOCALIZATION_DIRECTORY = JABREF_SOURCE_DIRECTORY / 'main/resources/l10n' + # Important paths, files and directories of the JabRef repository + JABREF_BASE_DIRECTORY = PathFinder.getJabRefBaseDirectory() + JABREF_SOURCE_DIRECTORY = JABREF_BASE_DIRECTORY / 'src' + JABREF_SCRIPTS_DIRECTORY = JABREF_BASE_DIRECTORY / 'scripts' + JABREF_LOCALIZATION_DIRECTORY = JABREF_SOURCE_DIRECTORY / 'main/resources/l10n' except ImportError: logging.info("Unable to use PathFinder class.") From e864d2cdca6e8fe867ee695d3ccb427d4fd5c691 Mon Sep 17 00:00:00 2001 From: Stefan Date: Tue, 20 Feb 2018 01:59:38 +0100 Subject: [PATCH 10/40] Improved method names --- scripts/syncLang.py | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/scripts/syncLang.py b/scripts/syncLang.py index 3f303c4ca34..adbc7f7f616 100644 --- a/scripts/syncLang.py +++ b/scripts/syncLang.py @@ -78,7 +78,7 @@ class Keys: def __init__(self, lines): self.lines = lines - def duplicates(self): + def find_duplicates(self): """ return: list of unicode strings """ @@ -220,7 +220,7 @@ def __print_status_menu_properties(self): def __print_status_jabref_properties(self): self.__check_properties(main_property_file=self.main_jabref_preferences, property_files=self.__all_jabref_properties()) - def update(self): + def update_properties(self): """ updates all the localization files fixing unambiguous duplicates, removing obsolete keys, adding missing keys, and sorting them @@ -236,19 +236,19 @@ def __update_jabref_properties(self): self.__update_properties(main_property_file=self.main_jabref_preferences, other_property_files=self.__other_jabref_properties()) def __check_properties(self, main_property_file, property_files): - main_lines = self.__read_file_as_lines(filename=main_property_file) + main_lines = self.__read_lines_from_file(filename=main_property_file) main_keys = Keys(main_lines) # the main property file gets compared to itself, but that is OK for file in property_files: filename = self.__format_filename(filepath=file) - lines = self.__read_file_as_lines(file) + lines = self.__read_lines_from_file(file) keys1 = Keys(main_lines) keys = keys1.keys_from_lines() keys_missing = self.__missing_keys(main_keys.keys_from_lines(), keys) keys_obsolete = self.__missing_keys(keys, main_keys.keys_from_lines()) - keys_duplicate = Keys(lines).duplicates() + keys_duplicate = Keys(lines).find_duplicates() keys_not_translated = Keys(lines=lines).empty_keys() num_keys = len(keys) @@ -313,11 +313,11 @@ def __other_jabref_properties(self): return [os.path.join(RES_DIR, file) for file in jabref_property_files] def __update_properties(self, main_property_file, other_property_files): - main_lines = self.__read_file_as_lines(filename=main_property_file) + main_lines = self.__read_lines_from_file(filename=main_property_file) main_keys = Keys(main_lines) main_keys_dict = main_keys.translations_as_dict() - main_duplicates = main_keys.duplicates() + main_duplicates = main_keys.find_duplicates() num_main_duplicates = len(main_duplicates) if num_main_duplicates != 0: logging.error("There are {num_duplicates} duplicates in {file}, please fix them manually".format(num_duplicates=num_main_duplicates, @@ -329,7 +329,7 @@ def __update_properties(self, main_property_file, other_property_files): for other_property_file in other_property_files: filename = self.__format_filename(filepath=other_property_file) - lines = self.__read_file_as_lines(filename=other_property_file) + lines = self.__read_lines_from_file(filename=other_property_file) keys, not_fixed, fixed = Keys(lines).fix_duplicates() num_keys = len(keys) @@ -408,13 +408,13 @@ def __write_file(filename, content): """ writes the lines to the file in `UTF-8` :param filename: string - :param content: list of unicode unicode: the lines to write + :param content: list of unicode strings: the lines to write """ with codecs.open(filename, 'w', encoding="UTF-8") as f: f.writelines(content) @staticmethod - def __read_file_as_lines(filename): + def __read_lines_from_file(filename): """ :param filename: string :param encoding: string: the encoding of the file to read (standard: `UTF-8`) @@ -423,7 +423,8 @@ def __read_file_as_lines(filename): with codecs.open(filename, 'r', encoding="UTF-8") as file: return [u"{}\n".format(line.strip()) for line in file.readlines()] - def __missing_keys(self, first_list, second_list): + @staticmethod + def __missing_keys(first_list, second_list): """ Finds all keys in the first list that are not present in the second list @@ -431,11 +432,7 @@ def __missing_keys(self, first_list, second_list): :param second_list: list of unicode strings :return: list of unicode strings """ - missing = [] - for key in first_list: - if key not in second_list: - missing.append(key) - return missing + return list(set(first_list).difference(second_list)) def status_create_markdown(self): """ @@ -447,7 +444,7 @@ def _write_properties(output_file, property_files): output_file.write("| ------------- | ---- | --------------- | ------------------- | ------------ |\n") for file in property_files: - lines = self.__read_file_as_lines(file) + lines = self.__read_lines_from_file(file) keys = Keys(lines) num_keys = len(keys.translations_as_dict()) num_keys_missing_value = len(keys.empty_keys()) @@ -484,7 +481,7 @@ def main(): SyncLang(extended=False, out_file='status.md').status_create_markdown() elif (len(sys.argv) == 2 or len(sys.argv) == 3) and sys.argv[1] == "update": - SyncLang(extended=len(sys.argv) == 3 and (sys.argv[2] == "-e" or sys.argv[2] == "--extended")).update() + SyncLang(extended=len(sys.argv) == 3 and (sys.argv[2] == "-e" or sys.argv[2] == "--extended")).update_properties() elif (len(sys.argv) == 2 or len(sys.argv) == 3) and sys.argv[1] == "status": SyncLang(extended=len(sys.argv) == 3 and (sys.argv[2] == "-e" or sys.argv[2] == "--extended")).status() From d940de0fcb1f4bf96a21e1bf166d56a7432a8e52 Mon Sep 17 00:00:00 2001 From: Stefan Date: Tue, 20 Feb 2018 21:03:36 +0100 Subject: [PATCH 11/40] Reworked command-line interface --- scripts/syncLang.py | 72 +++++++++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 32 deletions(-) diff --git a/scripts/syncLang.py b/scripts/syncLang.py index adbc7f7f616..65e75e6a7d5 100644 --- a/scripts/syncLang.py +++ b/scripts/syncLang.py @@ -1,6 +1,7 @@ # coding=utf-8 from __future__ import division +import argparse # Requires Python 2.7, should be safe to use with jython. import codecs import datetime import logging @@ -42,11 +43,15 @@ def getJabRefBaseDirectory(): if parent.name == 'jabref': return parent - # Important paths, files and directories of the JabRef repository + # Important directories of the JabRef repository JABREF_BASE_DIRECTORY = PathFinder.getJabRefBaseDirectory() JABREF_SOURCE_DIRECTORY = JABREF_BASE_DIRECTORY / 'src' JABREF_SCRIPTS_DIRECTORY = JABREF_BASE_DIRECTORY / 'scripts' JABREF_LOCALIZATION_DIRECTORY = JABREF_SOURCE_DIRECTORY / 'main/resources/l10n' + + # Important files + JABREF_MAIN_LOCALIZATION_FILE = JABREF_LOCALIZATION_DIRECTORY / 'JabRef_en.properties' + JABREF_MAIN_MENU_LOCALIZATION_FILE = JABREF_LOCALIZATION_DIRECTORY / 'Menu_en.properties' except ImportError: logging.info("Unable to use PathFinder class.") @@ -196,7 +201,7 @@ def format_key_and_value(key, value): class SyncLang: - def __init__(self, extended, out_file='status.md'): + def __init__(self, extended): """ :param extended: boolean: if the keys with problems should be printed @@ -204,7 +209,6 @@ def __init__(self, extended, out_file='status.md'): self.extended = extended self.main_jabref_preferences = os.path.join(RES_DIR, "JabRef_en.properties") self.main_menu_preferences = os.path.join(RES_DIR, "Menu_en.properties") - self.markdown_output = out_file def status(self): """ @@ -350,7 +354,7 @@ def __update_properties(self, main_property_file, other_property_files): num_keys_obsolete = len(keys_obsolete) for missing_key in keys_missing: - # Missing keys are added with english translation by default. + # Missing keys are added with main translation by default. keys[missing_key] = main_keys_dict[missing_key] for obsolete_key in keys_obsolete: @@ -434,7 +438,7 @@ def __missing_keys(first_list, second_list): """ return list(set(first_list).difference(second_list)) - def status_create_markdown(self): + def status_create_markdown(self, markdown_file='status.md'): """ Creates a markdown file of the current status. """ @@ -465,7 +469,7 @@ def _percentage(whole, part): return 0 return int(part / whole * 100.0) - with codecs.open(self.markdown_output, "w", encoding="UTF-8") as status_file: + with codecs.open(markdown_file, "w", encoding="UTF-8") as status_file: status_file.write('### Localization files status (' + datetime.datetime.now().strftime( "%Y-%m-%d %H:%M") + ' - Branch `' + Git().get_current_branch() + '` `' + Git().get_current_hash_short() + '`)\n\n') status_file.write('Note: To get the current status from your local repository, run `python ./scripts/syncLang.py markdown`\n') @@ -473,39 +477,43 @@ def _percentage(whole, part): _write_properties(status_file, self.__all_menu_properties()) _write_properties(status_file, self.__all_jabref_properties()) - logging.info('Current status written to ' + self.markdown_output) + logging.info('Current status written to ' + markdown_file) def main(): - if len(sys.argv) == 2 and sys.argv[1] == "markdown": - SyncLang(extended=False, out_file='status.md').status_create_markdown() - - elif (len(sys.argv) == 2 or len(sys.argv) == 3) and sys.argv[1] == "update": - SyncLang(extended=len(sys.argv) == 3 and (sys.argv[2] == "-e" or sys.argv[2] == "--extended")).update_properties() - - elif (len(sys.argv) == 2 or len(sys.argv) == 3) and sys.argv[1] == "status": - SyncLang(extended=len(sys.argv) == 3 and (sys.argv[2] == "-e" or sys.argv[2] == "--extended")).status() - - else: - logging.info("""This program must be run from the JabRef base directory. - Usage: syncLang.py {markdown, status [-e | --extended], update [-e | --extended]} - Option can be one of the following: + def markdown(args): + SyncLang(extended=False).status_create_markdown() + def status(args): + SyncLang(extended=args.extended).status() + def update(args): + SyncLang(extended=args.extended).update_properties() + + + parser = argparse.ArgumentParser(add_help=True) + parser.description = "This script is used to synchronize the keys of different *.properties files." + + + shared_arguments = argparse.ArgumentParser(add_help=False) + extended_argument = shared_arguments.add_argument("-e", "--extended", help="Prints extended information about the process to the terminal", required=False, action='store_true', default=False) + + subcommands = parser.add_subparsers(title="Subcommands", description="Provide different options for the user") + + # markdown parser + markdown_parser = subcommands.add_parser("markdown", description="Creates a markdown file of the current status") + markdown_parser.set_defaults(func=markdown) + # TODO add argument to pass a file name for the markdown file - status [-e | --extended]: - prints the current status to the terminal - [-e | --extended]: - if the translations keys which create problems should be printed + # status parser + status_parser = subcommands.add_parser("status", description="Prints the current status to the terminal", parents=[shared_arguments]) + status_parser.set_defaults(func=status) - markdown: - Creates a markdown file of the current status and opens it + # update parser + update_parser = subcommands.add_parser("update", description="Compares all the localization files against the English one and fixes unambiguous duplicates, removes obsolete keys, adds missing keys, and sorts them", parents=[shared_arguments]) + update_parser.set_defaults(func=update) - update [-e | --extended]: - compares all the localization files against the English one and fixes unambiguous duplicates, - removes obsolete keys, adds missing keys, and sorts them - [-e | --extended]: - if the translations keys which create problems should be printed - """) + parsed_args = parser.parse_args() + parsed_args.func(parsed_args) if '__main__' == __name__: From c5eecef7ed48f5e04ab5d41b3a62f966656b14ef Mon Sep 17 00:00:00 2001 From: Stefan Date: Wed, 21 Feb 2018 03:18:27 +0100 Subject: [PATCH 12/40] Reworked logging functionality, added new command-line options --- scripts/syncLang.py | 189 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 148 insertions(+), 41 deletions(-) diff --git a/scripts/syncLang.py b/scripts/syncLang.py index 65e75e6a7d5..733c6a340ba 100644 --- a/scripts/syncLang.py +++ b/scripts/syncLang.py @@ -1,7 +1,7 @@ # coding=utf-8 from __future__ import division -import argparse # Requires Python 2.7, should be safe to use with jython. +import argparse # Requires Python 2.7, should be safe to use with jython. import codecs import datetime import logging @@ -17,6 +17,7 @@ try: # Just to make sure not to break anything, in case py3.x is not supported. import pathlib + class PathFinder: """ This class is designed to automatically locate this script's path within the repository. @@ -201,14 +202,52 @@ def format_key_and_value(key, value): class SyncLang: - def __init__(self, extended): + def __init__(self, extended_logging=False): """ :param extended: boolean: if the keys with problems should be printed """ - self.extended = extended + self.extended_logging = extended_logging self.main_jabref_preferences = os.path.join(RES_DIR, "JabRef_en.properties") self.main_menu_preferences = os.path.join(RES_DIR, "Menu_en.properties") + + def set_extended_logging_enabled(self, value): + self.extended_logging = bool(value) + + def print_missing_keys_for_file(self, file_name): + file_status = self.__get_status_for_file(file_name) + if file_status: + keys_missing, _, _, _ = file_status + + if len(keys_missing) > 0: + logging.info("Printing missing keys for file: " + file_name) + self.__print_keys(keys_missing) + else: + logging.info("No missing keys found for file:" + file_name) + + def print_obsolete_keys_for_file(self, file_name): + file_status = self.__get_status_for_file(file_name) + if file_status: + _, keys_obsolete, _, _ = file_status + + if len(keys_obsolete) > 0: + + logging.info("Printing obsolete keys for file: " + file_name) + self.__print_keys(keys_obsolete) + else: + logging.info("No obsolete keys found for file: " + file_name) + + def print_duplicate_keys_for_file(self, file_name): + file_status = self.__get_status_for_file(file_name) + if file_status: + _, _, keys_duplicate, _ = file_status + + if len(keys_duplicate) > 0: + + logging.info("Printing duplicate keys for file: " + file_name) + self.__print_keys(keys_duplicate) + else: + logging.info("No duplicate keys found for file: " + file_name) def status(self): """ @@ -219,10 +258,10 @@ def status(self): self.__print_status_menu_properties() def __print_status_menu_properties(self): - self.__check_properties(main_property_file=self.main_menu_preferences, property_files=self.__all_menu_properties()) + self.__compare_properties(main_property_file=self.main_menu_preferences, property_files=self.__all_menu_properties()) def __print_status_jabref_properties(self): - self.__check_properties(main_property_file=self.main_jabref_preferences, property_files=self.__all_jabref_properties()) + self.__compare_properties(main_property_file=self.main_jabref_preferences, property_files=self.__all_jabref_properties()) def update_properties(self): """ @@ -238,8 +277,37 @@ def __update_menu_properties(self): def __update_jabref_properties(self): self.__update_properties(main_property_file=self.main_jabref_preferences, other_property_files=self.__other_jabref_properties()) + + def __get_main_file(self, file_name): + + file = os.path.join(RES_DIR, file_name) + + if file in self.__all_jabref_properties(): + return self.main_jabref_preferences + elif file in self.__all_menu_properties(): + return self.main_menu_preferences + + def __get_status_for_file(self, file_name): + main_file = self.__get_main_file(file_name) + if main_file: + main_lines = self.__read_lines_from_file(filename=main_file) + main_keys = Keys(main_lines) + + file = os.path.join(RES_DIR, file_name) + lines = self.__read_lines_from_file(file) + keys1 = Keys(lines) + keys = keys1.keys_from_lines() - def __check_properties(self, main_property_file, property_files): + keys_missing = self.__missing_keys(main_keys.keys_from_lines(), keys) + keys_obsolete = self.__missing_keys(keys, main_keys.keys_from_lines()) + keys_duplicates = keys1.find_duplicates() + keys_not_translated = keys1.empty_keys() + + return (keys_missing, keys_obsolete, keys_duplicates, keys_not_translated) + else: + logging.debug("Unable to find main file for: " + file_name) + + def __compare_properties(self, main_property_file, property_files): main_lines = self.__read_lines_from_file(filename=main_property_file) main_keys = Keys(main_lines) @@ -247,19 +315,19 @@ def __check_properties(self, main_property_file, property_files): for file in property_files: filename = self.__format_filename(filepath=file) lines = self.__read_lines_from_file(file) - keys1 = Keys(main_lines) + keys1 = Keys(lines) keys = keys1.keys_from_lines() keys_missing = self.__missing_keys(main_keys.keys_from_lines(), keys) keys_obsolete = self.__missing_keys(keys, main_keys.keys_from_lines()) - keys_duplicate = Keys(lines).find_duplicates() - keys_not_translated = Keys(lines=lines).empty_keys() + keys_duplicates = keys1.find_duplicates() + keys_not_translated = keys1.empty_keys() num_keys = len(keys) num_keys_missing = len(keys_missing) num_keys_not_translated = len(keys_not_translated) num_keys_obsolete = len(keys_obsolete) - num_keys_duplicate = len(keys_duplicate) + num_keys_duplicate = len(keys_duplicates) num_keys_translated = num_keys - num_keys_not_translated log = logging.error if num_keys_missing != 0 or num_keys_not_translated != 0 or num_keys_obsolete != 0 or num_keys_duplicate != 0 else logging.info @@ -268,23 +336,23 @@ def __check_properties(self, main_property_file, property_files): log = logging.error if num_keys_not_translated != 0 else logging.info log("\t{} not translated keys".format(num_keys_not_translated)) - if self.extended and num_keys_not_translated != 0: - logging.info("\t\t{}".format(", ".join(keys_not_translated))) + if self.extended_logging and num_keys_not_translated != 0: + self.__print_keys(keys_not_translated) log = logging.error if num_keys_missing != 0 else logging.info log("\t{} missing keys".format(num_keys_missing)) - if self.extended and num_keys_missing != 0: - logging.info("\t\t{}".format(", ".join(keys_missing))) + if self.extended_logging and num_keys_missing != 0: + self.__print_keys(keys_missing) log = logging.error if num_keys_obsolete != 0 else logging.info log("\t{} obsolete keys".format(num_keys_obsolete)) - if self.extended and num_keys_obsolete != 0: - logging.info("\t\t{}".format(", ".join(keys_obsolete))) + if self.extended_logging and num_keys_obsolete != 0: + self.__print_keys(keysobsolete) log = logging.error if num_keys_duplicate != 0 else logging.info log("\t{} duplicates".format(num_keys_duplicate)) - if self.extended and num_keys_duplicate != 0: - logging.info("\t\t{}".format(", ".join(keys_duplicate))) + if self.extended_logging and num_keys_duplicate != 0: + self.__print_keys(keys_duplicates) def __all_menu_properties(self): """ @@ -303,7 +371,7 @@ def __other_menu_properties(self): def __all_jabref_properties(self): """ - :return: list of strings: all the JabRef_*.preferences files with the english at the beginning + :return: list of strings: all the JabRef_*.preferences file paths with the english at the beginning """ jabref_property_files = sorted(self.__other_jabref_properties()) jabref_property_files.insert(0, self.main_jabref_preferences) @@ -311,7 +379,7 @@ def __all_jabref_properties(self): def __other_jabref_properties(self): """ - :return: list of strings: all the JabRef_*.preferences files without the english one + :return: list of strings: all the JabRef_*.preferences file paths without the english one """ jabref_property_files = [s for s in os.listdir(RES_DIR) if (s.startswith('JabRef_') and not (s.startswith('JabRef_en')))] return [os.path.join(RES_DIR, file) for file in jabref_property_files] @@ -327,8 +395,8 @@ def __update_properties(self, main_property_file, other_property_files): logging.error("There are {num_duplicates} duplicates in {file}, please fix them manually".format(num_duplicates=num_main_duplicates, file=self.__format_filename( filepath=main_property_file))) - if self.extended: - logging.info("\t{}".format(", ".join(main_duplicates))) + if self.extended_logging: + self.__print_keys(main_duplicates) return for other_property_file in other_property_files: @@ -343,8 +411,8 @@ def __update_properties(self, main_property_file, other_property_files): if num_not_fixed != 0: logging.error("There are {num_not_fixed_duplicates} ambiguous duplicates in {file}, please fix them manually".format( num_not_fixed_duplicates=num_not_fixed, file=filename)) - if self.extended: - logging.error("\t{}".format(", ".join(not_fixed))) + if self.extended_logging: + self.__print_keys(not_fixed) continue keys_missing = self.__missing_keys(main_keys.keys_from_lines(), keys) @@ -381,18 +449,18 @@ def __update_properties(self, main_property_file, other_property_files): logging.info("Processing file '{file}' with {num_keys} Keys".format(file=filename, num_keys=num_keys)) if num_fixed != 0: logging.info("\tfixed {} unambiguous duplicates".format(num_fixed)) - if self.extended: - logging.info("\t\t{}".format(", ".join(fixed))) + if self.extended_logging: + self.__print_keys(fixed) if num_keys_missing != 0: logging.info("\tadded {} missing keys".format(num_keys_missing)) - if self.extended: - logging.info("\t\t{}".format(", ".join(keys_missing))) + if self.extended_logging: + self.__print_keys(keys_missing) if num_keys_obsolete != 0: logging.info("\tdeleted {} obsolete keys".format(num_keys_obsolete)) - if self.extended: - logging.info("\t\t{}".format(", ".join(keys_obsolete))) + if self.extended_logging: + self.__print_keys(keys_obsolete) if sorted_lines: logging.info("\thas been sorted successfully") @@ -403,7 +471,7 @@ def __format_filename(filepath): removes the res_dir path :param filepath: string - :return: string + :return: pure file name of this file path (including file extension e.g. *.txt) """ return filepath.replace("{}\\".format(RES_DIR), "") @@ -437,6 +505,11 @@ def __missing_keys(first_list, second_list): :return: list of unicode strings """ return list(set(first_list).difference(second_list)) + + @staticmethod + def __print_keys(keys, logger=logging.info): + for key in keys: + logger("\t{}\n".format(key)) def status_create_markdown(self, markdown_file='status.md'): """ @@ -482,18 +555,35 @@ def _percentage(whole, part): def main(): - def markdown(args): - SyncLang(extended=False).status_create_markdown() - def status(args): - SyncLang(extended=args.extended).status() - def update(args): - SyncLang(extended=args.extended).update_properties() + syncer = SyncLang() + def markdown_command(args): + syncer.set_extended_logging_enabled(False) + syncer.status_create_markdown() + + def status_command(args): + syncer.set_extended_logging_enabled(args.extended) + syncer.status() + + def update_command(args): + syncer.set_extended_logging_enabled(args.extended) + syncer.update_properties() + + def print_missing(args): + file_name = args.f + syncer.print_missing_keys_for_file(file_name) + + def print_obsolete(args): + file_name = args.f + syncer.print_obsolete_keys_for_file(file_name) + + def print_duplicates(args): + file_name = args.f + syncer.print_duplicate_keys_for_file(file_name) parser = argparse.ArgumentParser(add_help=True) parser.description = "This script is used to synchronize the keys of different *.properties files." - shared_arguments = argparse.ArgumentParser(add_help=False) extended_argument = shared_arguments.add_argument("-e", "--extended", help="Prints extended information about the process to the terminal", required=False, action='store_true', default=False) @@ -501,16 +591,33 @@ def update(args): # markdown parser markdown_parser = subcommands.add_parser("markdown", description="Creates a markdown file of the current status") - markdown_parser.set_defaults(func=markdown) + markdown_parser.set_defaults(func=markdown_command) # TODO add argument to pass a file name for the markdown file # status parser status_parser = subcommands.add_parser("status", description="Prints the current status to the terminal", parents=[shared_arguments]) - status_parser.set_defaults(func=status) + status_parser.set_defaults(func=status_command) # update parser update_parser = subcommands.add_parser("update", description="Compares all the localization files against the English one and fixes unambiguous duplicates, removes obsolete keys, adds missing keys, and sorts them", parents=[shared_arguments]) - update_parser.set_defaults(func=update) + update_parser.set_defaults(func=update_command) + + # print parser + print_parser = subcommands.add_parser("print", description="Prints specific status info to the console") + + shared_print_arguments = argparse.ArgumentParser(add_help=False) + file_argument = shared_print_arguments.add_argument("-f", "-file", help="Specifies a file for the command to run with", required=True, action='store') + + print_options = print_parser.add_subparsers(title="Print Options", description="Different options for printing") + + missing_parser = print_options.add_parser("missing", description="Prints all missing keys", parents=[shared_print_arguments]) + missing_parser.set_defaults(func=print_missing) + + obsolete_parser = print_options.add_parser("obsolete", description="Prints all obsolete keys", parents=[shared_print_arguments]) + obsolete_parser.set_defaults(func=print_obsolete) + + duplicates_parser = print_options.add_parser("duplicates", description="Prints all duplicate keys", parents=[shared_print_arguments]) + duplicates_parser.set_defaults(func=print_duplicates) parsed_args = parser.parse_args() parsed_args.func(parsed_args) From 35b7f8330fb2694afbfc7f5e2be056276d415b3a Mon Sep 17 00:00:00 2001 From: Stefan Date: Wed, 21 Feb 2018 03:33:51 +0100 Subject: [PATCH 13/40] =?UTF-8?q?small=20fix=20on=20=C2=B4getJabRefBaseDir?= =?UTF-8?q?ectory=C2=B4=20method?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/syncLang.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/syncLang.py b/scripts/syncLang.py index 733c6a340ba..09d6403ca39 100644 --- a/scripts/syncLang.py +++ b/scripts/syncLang.py @@ -39,6 +39,9 @@ def getJabRefBaseDirectory(): Searches the script's path backwards until it finds the matching base directory. :return the path to JabRef's base directory as pathlib.Path object. """ + if pathlib.Path.cwd().name == 'jabref': + return pathlib.Path.cwd + scriptLocation = PathFinder.getScriptLocation() for parent in scriptLocation.parents: if parent.name == 'jabref': From ded149b0b1da11a6c92ae9e9212206da8436b82b Mon Sep 17 00:00:00 2001 From: Stefan Date: Wed, 21 Feb 2018 03:34:32 +0100 Subject: [PATCH 14/40] forgot brackets... --- scripts/syncLang.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/syncLang.py b/scripts/syncLang.py index 09d6403ca39..338a504ed74 100644 --- a/scripts/syncLang.py +++ b/scripts/syncLang.py @@ -40,7 +40,7 @@ def getJabRefBaseDirectory(): :return the path to JabRef's base directory as pathlib.Path object. """ if pathlib.Path.cwd().name == 'jabref': - return pathlib.Path.cwd + return pathlib.Path.cwd() scriptLocation = PathFinder.getScriptLocation() for parent in scriptLocation.parents: From 1379dad815880963bfaf1149498cda43ecd9412e Mon Sep 17 00:00:00 2001 From: Stefan Date: Wed, 21 Feb 2018 03:47:58 +0100 Subject: [PATCH 15/40] =?UTF-8?q?Removed=20=C2=B4getScriptLocation=C2=B4?= =?UTF-8?q?=20method?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/syncLang.py | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/scripts/syncLang.py b/scripts/syncLang.py index 338a504ed74..0a679231f1a 100644 --- a/scripts/syncLang.py +++ b/scripts/syncLang.py @@ -26,26 +26,20 @@ class PathFinder: requires Python 3.4 or higher """ - @staticmethod - def getScriptLocation(): - """ - :return the path this script is currently located as pathlib.Path object. - """ - return pathlib.Path(__file__) - @staticmethod def getJabRefBaseDirectory(): """ Searches the script's path backwards until it finds the matching base directory. :return the path to JabRef's base directory as pathlib.Path object. """ - if pathlib.Path.cwd().name == 'jabref': - return pathlib.Path.cwd() + cwd = pathlib.Path.cwd() + if cwd.name == 'jabref': + return cwd - scriptLocation = PathFinder.getScriptLocation() - for parent in scriptLocation.parents: + for parent in cwd.parents: if parent.name == 'jabref': return parent + # TODO What to do if base directory could not be found? # Important directories of the JabRef repository JABREF_BASE_DIRECTORY = PathFinder.getJabRefBaseDirectory() From e7be7ef3eaa55691eaee32b5db804719880295e1 Mon Sep 17 00:00:00 2001 From: Stefan Date: Wed, 21 Feb 2018 03:50:45 +0100 Subject: [PATCH 16/40] =?UTF-8?q?Added=20=C2=B4BASE=5FDIRECTORY=5FNAME?= =?UTF-8?q?=C2=B4=20variable=20to=20PathFinder=20class?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/syncLang.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/syncLang.py b/scripts/syncLang.py index 0a679231f1a..3046eb42b75 100644 --- a/scripts/syncLang.py +++ b/scripts/syncLang.py @@ -26,6 +26,8 @@ class PathFinder: requires Python 3.4 or higher """ + BASE_DIRECTORY_NAME = 'jabref' + @staticmethod def getJabRefBaseDirectory(): """ @@ -33,11 +35,11 @@ def getJabRefBaseDirectory(): :return the path to JabRef's base directory as pathlib.Path object. """ cwd = pathlib.Path.cwd() - if cwd.name == 'jabref': + if cwd.name == PathFinder.BASE_DIRECTORY_NAME: return cwd for parent in cwd.parents: - if parent.name == 'jabref': + if parent.name == PathFinder.BASE_DIRECTORY_NAME: return parent # TODO What to do if base directory could not be found? From cb21464b6173d9a52d5b2abeb6c20825d5099746 Mon Sep 17 00:00:00 2001 From: Stefan Date: Thu, 22 Feb 2018 12:53:58 +0100 Subject: [PATCH 17/40] Print commands will now use localization directory by default --- scripts/syncLang.py | 52 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 9 deletions(-) diff --git a/scripts/syncLang.py b/scripts/syncLang.py index 3046eb42b75..8dfb267edab 100644 --- a/scripts/syncLang.py +++ b/scripts/syncLang.py @@ -213,6 +213,14 @@ def __init__(self, extended_logging=False): def set_extended_logging_enabled(self, value): self.extended_logging = bool(value) + def print_missing_keys(self): + for file in self.__other_jabref_properties(): + file_name = self.__format_filename(file) + self.print_missing_keys_for_file(file_name) + for file in self.__other_menu_properties(): + file_name = self.__format_filename(file) + self.print_missing_keys_for_file(file_name) + def print_missing_keys_for_file(self, file_name): file_status = self.__get_status_for_file(file_name) if file_status: @@ -223,6 +231,15 @@ def print_missing_keys_for_file(self, file_name): self.__print_keys(keys_missing) else: logging.info("No missing keys found for file:" + file_name) + + def print_obsolete_keys(self): + for file in self.__other_jabref_properties(): + file_name = self.__format_filename(file) + self.print_obsolete_keys_for_file(file_name) + for file in self.__other_menu_properties(): + file_name = self.__format_filename(file) + self.print_obsolete_keys_for_file(file_name) + def print_obsolete_keys_for_file(self, file_name): file_status = self.__get_status_for_file(file_name) @@ -235,6 +252,14 @@ def print_obsolete_keys_for_file(self, file_name): self.__print_keys(keys_obsolete) else: logging.info("No obsolete keys found for file: " + file_name) + + def print_duplicate_keys(self): + for file in self.__other_jabref_properties(): + file_name = self.__format_filename(file) + self.print_duplicate_keys_for_file(file_name) + for file in self.__other_menu_properties(): + file_name = self.__format_filename(file) + self.print_duplicate_keys_for_file(file_name) def print_duplicate_keys_for_file(self, file_name): file_status = self.__get_status_for_file(file_name) @@ -569,16 +594,25 @@ def update_command(args): syncer.update_properties() def print_missing(args): - file_name = args.f - syncer.print_missing_keys_for_file(file_name) + file_name = args.file + if file_name: + syncer.print_missing_keys_for_file(file_name) + else: + syncer.print_missing_keys() def print_obsolete(args): - file_name = args.f - syncer.print_obsolete_keys_for_file(file_name) + file_name = args.file + if file_name: + syncer.print_obsolete_keys_for_file(file_name) + else: + syncer.print_obsolete_keys() def print_duplicates(args): - file_name = args.f - syncer.print_duplicate_keys_for_file(file_name) + file_name = args.file + if file_name: + syncer.print_duplicate_keys_for_file(file_name) + else: + syncer.print_duplicate_keys() parser = argparse.ArgumentParser(add_help=True) parser.description = "This script is used to synchronize the keys of different *.properties files." @@ -586,7 +620,7 @@ def print_duplicates(args): shared_arguments = argparse.ArgumentParser(add_help=False) extended_argument = shared_arguments.add_argument("-e", "--extended", help="Prints extended information about the process to the terminal", required=False, action='store_true', default=False) - subcommands = parser.add_subparsers(title="Subcommands", description="Provide different options for the user") + subcommands = parser.add_subparsers(title="Subcommands", description="Provide different options for the user", dest="subcommand") # markdown parser markdown_parser = subcommands.add_parser("markdown", description="Creates a markdown file of the current status") @@ -605,9 +639,9 @@ def print_duplicates(args): print_parser = subcommands.add_parser("print", description="Prints specific status info to the console") shared_print_arguments = argparse.ArgumentParser(add_help=False) - file_argument = shared_print_arguments.add_argument("-f", "-file", help="Specifies a file for the command to run with", required=True, action='store') + file_argument = shared_print_arguments.add_argument("-f", "--file", help="Specifies a file for the command to run with", required=False, action='store') - print_options = print_parser.add_subparsers(title="Print Options", description="Different options for printing") + print_options = print_parser.add_subparsers(title="Print Options", description="Different options for printing", dest="print_option_name") missing_parser = print_options.add_parser("missing", description="Prints all missing keys", parents=[shared_print_arguments]) missing_parser.set_defaults(func=print_missing) From fb3bba0b751cf29253f548d51319b2ddd3de07db Mon Sep 17 00:00:00 2001 From: Stefan Date: Wed, 28 Feb 2018 20:45:33 +0100 Subject: [PATCH 18/40] Missing keys will no longer be written to the properties files --- scripts/syncLang.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/syncLang.py b/scripts/syncLang.py index 8dfb267edab..0dbe32d86b6 100644 --- a/scripts/syncLang.py +++ b/scripts/syncLang.py @@ -445,9 +445,9 @@ def __update_properties(self, main_property_file, other_property_files): num_keys_missing = len(keys_missing) num_keys_obsolete = len(keys_obsolete) - for missing_key in keys_missing: + # for missing_key in keys_missing: # Missing keys are added with main translation by default. - keys[missing_key] = main_keys_dict[missing_key] + # keys[missing_key] = main_keys_dict[missing_key] for obsolete_key in keys_obsolete: del keys[obsolete_key] From 432a92bb31d9737e6466cf7d64e89020ecbefdf6 Mon Sep 17 00:00:00 2001 From: Stefan Date: Fri, 2 Mar 2018 15:44:05 +0100 Subject: [PATCH 19/40] Fixed missing key issue --- scripts/syncLang.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts/syncLang.py b/scripts/syncLang.py index 0dbe32d86b6..0b2386b3617 100644 --- a/scripts/syncLang.py +++ b/scripts/syncLang.py @@ -456,9 +456,10 @@ def __update_properties(self, main_property_file, other_property_files): for line in main_lines: key = main_keys.key_from_line(line) if key is not None: - # Do not write empty keys - if keys[key] != "": - other_lines_to_write.append(Keys.format_key_and_value(key=key, value=keys[key]) + "\n") + if keys.has_key(key): + # Do not write empty keys + if keys[key] != "": + other_lines_to_write.append(Keys.format_key_and_value(key=key, value=keys[key]) + "\n") else: other_lines_to_write.append(line) From 262ebc5fed183298550de7b6691eb52e56da40b5 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Fri, 4 Oct 2019 21:55:47 +0200 Subject: [PATCH 20/40] Add UUID for upgrading In my understanding generating two installers with different versions and same --win-upgrade-uuid should uninstall another version during installation, i.e. this is needed to have a proper upgrade instead of a parallel installation of two JabRef versions. --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index 2a95dc4d428..10b9632072a 100644 --- a/build.gradle +++ b/build.gradle @@ -582,6 +582,7 @@ jlink { installerOptions = [ '--vendor', 'JabRef', '--app-version', "${project.version}", + '--win-upgrade-uuid', 'd636b4ee-6f10-451e-bf57-c89656780e36' '--win-dir-chooser', '--win-shortcut' ] From a53b137dd1111d4fa4c2df75af6a7c6fcb1c8812 Mon Sep 17 00:00:00 2001 From: matthiasgeiger Date: Sat, 5 Oct 2019 10:29:22 +0200 Subject: [PATCH 21/40] add missing ',' --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 10b9632072a..b3d7851f76a 100644 --- a/build.gradle +++ b/build.gradle @@ -582,7 +582,7 @@ jlink { installerOptions = [ '--vendor', 'JabRef', '--app-version', "${project.version}", - '--win-upgrade-uuid', 'd636b4ee-6f10-451e-bf57-c89656780e36' + '--win-upgrade-uuid', 'd636b4ee-6f10-451e-bf57-c89656780e36', '--win-dir-chooser', '--win-shortcut' ] From baa47ff95f13764f6ecb9f9ab38762f56752c342 Mon Sep 17 00:00:00 2001 From: matthiasgeiger Date: Sat, 5 Oct 2019 11:22:39 +0200 Subject: [PATCH 22/40] use submodules to fetch CSL styles properly --- .github/workflows/deployment.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/deployment.yml b/.github/workflows/deployment.yml index 2e3f869b953..7181f896579 100644 --- a/.github/workflows/deployment.yml +++ b/.github/workflows/deployment.yml @@ -33,6 +33,7 @@ jobs: uses: actions/checkout@v1 with: fetch-depth: 1 + submodules: true - name: Set up JDK uses: actions/setup-java@v1 with: From bbab95021364be54ed21e678fcf89ee9d1529766 Mon Sep 17 00:00:00 2001 From: matthiasgeiger Date: Sat, 5 Oct 2019 11:36:19 +0200 Subject: [PATCH 23/40] revert 3fbe0a2b57340f03d7d1271eeeb30a061d724134 --- .github/workflows/deployment.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/deployment.yml b/.github/workflows/deployment.yml index 7181f896579..2889d2e2cac 100644 --- a/.github/workflows/deployment.yml +++ b/.github/workflows/deployment.yml @@ -32,7 +32,6 @@ jobs: - name: Checkout source uses: actions/checkout@v1 with: - fetch-depth: 1 submodules: true - name: Set up JDK uses: actions/setup-java@v1 From d3fd6f930db846c04339c12eaa77907c8d1f082b Mon Sep 17 00:00:00 2001 From: Christoph Date: Sat, 5 Oct 2019 18:09:51 +0200 Subject: [PATCH 24/40] Update deployment.yml Readd depth --- .github/workflows/deployment.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/deployment.yml b/.github/workflows/deployment.yml index 2889d2e2cac..bec5380f3d1 100644 --- a/.github/workflows/deployment.yml +++ b/.github/workflows/deployment.yml @@ -32,6 +32,7 @@ jobs: - name: Checkout source uses: actions/checkout@v1 with: + depth: 1 submodules: true - name: Set up JDK uses: actions/setup-java@v1 From 875b48e8456c2861296f5be29a53c045dea840e2 Mon Sep 17 00:00:00 2001 From: Matthias Geiger Date: Sun, 6 Oct 2019 07:47:23 +0200 Subject: [PATCH 25/40] Reenable prevcycle (#5385) * fixes 5369 - fallback to 0 in case stored preview cycle pos does no longer exist * reenable preview cycling * remove ref to BasePanel * unused imports * update changelog * incorporated suggestions * add next/previousPreviewStyle() to EntryEditorTab * checkstyle... --- CHANGELOG.md | 5 ++ src/main/java/org/jabref/gui/BasePanel.java | 25 +++------- .../jabref/gui/entryeditor/EntryEditor.java | 13 +++-- .../gui/entryeditor/EntryEditorTab.java | 14 ++++++ .../gui/entryeditor/FieldsEditorTab.java | 14 +++++- .../org/jabref/gui/preview/PreviewPanel.java | 50 +++++++++++-------- 6 files changed, 73 insertions(+), 48 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b71f0091dcd..c2285cad78e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,11 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `# - We fixed an exception which occured when trying to open a non existing file from the "Recent files"-menu [#5334](https://github.com/JabRef/jabref/issues/5334) - The context menu for fields in the entry editor is back. [#5254](https://github.com/JabRef/jabref/issues/5254) - We fixed an exception which occurred when trying to open a non existing file from the "Recent files"-menu [#5334](https://github.com/JabRef/jabref/issues/5334) +- We re-introduced the feature to switch between different preview styles. [#5221](https://github.com/JabRef/jabref/issues/5221) + + + + ### Removed diff --git a/src/main/java/org/jabref/gui/BasePanel.java b/src/main/java/org/jabref/gui/BasePanel.java index b35a6bdce4d..30cc6f4aecb 100644 --- a/src/main/java/org/jabref/gui/BasePanel.java +++ b/src/main/java/org/jabref/gui/BasePanel.java @@ -95,7 +95,6 @@ import org.jabref.model.entry.field.SpecialFieldValue; import org.jabref.model.entry.field.StandardField; import org.jabref.preferences.JabRefPreferences; -import org.jabref.preferences.PreviewPreferences; import com.google.common.eventbus.Subscribe; import org.fxmisc.easybind.EasyBind; @@ -352,6 +351,13 @@ private void setupActions() { new SpecialFieldViewModel(SpecialField.READ_STATUS, undoManager).getSpecialFieldAction(status, this.frame)); } + actions.put(Actions.NEXT_PREVIEW_STYLE, () -> { + entryEditor.nextPreviewStyle(); + }); + actions.put(Actions.PREVIOUS_PREVIEW_STYLE, () -> { + entryEditor.previousPreviewStyle(); + }); + actions.put(Actions.SEND_AS_EMAIL, new SendAsEMailAction(frame)); actions.put(Actions.WRITE_XMP, new WriteXMPAction(this)::execute); @@ -844,23 +850,6 @@ private void showAndEdit() { } } - public void nextPreviewStyle() { - cyclePreview(Globals.prefs.getPreviewPreferences().getPreviewCyclePosition() + 1); - } - - public void previousPreviewStyle() { - cyclePreview(Globals.prefs.getPreviewPreferences().getPreviewCyclePosition() - 1); - } - - private void cyclePreview(int newPosition) { - PreviewPreferences previewPreferences = Globals.prefs.getPreviewPreferences() - .getBuilder() - .withPreviewCyclePosition(newPosition) - .build(); - Globals.prefs.storePreviewPreferences(previewPreferences); - entryEditor.updatePreviewInTabs(previewPreferences); - } - /** * Removes the bottom component. */ diff --git a/src/main/java/org/jabref/gui/entryeditor/EntryEditor.java b/src/main/java/org/jabref/gui/entryeditor/EntryEditor.java index dadcad8be9c..9bd2a2a9c4c 100644 --- a/src/main/java/org/jabref/gui/entryeditor/EntryEditor.java +++ b/src/main/java/org/jabref/gui/entryeditor/EntryEditor.java @@ -50,7 +50,6 @@ import org.jabref.model.entry.field.Field; import org.jabref.model.util.FileUpdateMonitor; import org.jabref.preferences.PreferencesService; -import org.jabref.preferences.PreviewPreferences; import com.airhacks.afterburner.views.ViewLoader; import org.fxmisc.easybind.EasyBind; @@ -404,11 +403,11 @@ public void setFocusToField(Field field) { }); } - public void updatePreviewInTabs(PreviewPreferences previewPreferences) { - for (Tab tab : this.entryEditorTabs) { - if (tab instanceof FieldsEditorTab) { - ((FieldsEditorTab) tab).previewPanel.updateLayout(previewPreferences); - } - } + public void nextPreviewStyle() { + this.entryEditorTabs.forEach(EntryEditorTab::nextPreviewStyle); + } + + public void previousPreviewStyle() { + this.entryEditorTabs.forEach(EntryEditorTab::previousPreviewStyle); } } diff --git a/src/main/java/org/jabref/gui/entryeditor/EntryEditorTab.java b/src/main/java/org/jabref/gui/entryeditor/EntryEditorTab.java index a0b91a914f7..6c5da5ec0f6 100644 --- a/src/main/java/org/jabref/gui/entryeditor/EntryEditorTab.java +++ b/src/main/java/org/jabref/gui/entryeditor/EntryEditorTab.java @@ -44,4 +44,18 @@ public void notifyAboutFocus(BibEntry entry) { handleFocus(); } + /** + * Switch to next Preview style - should be overriden if a EntryEditorTab is actually showing a preview + */ + protected void nextPreviewStyle() { + // do nothing by default + } + + /** + * Switch to previous Preview style - should be overriden if a EntryEditorTab is actually showing a preview + */ + protected void previousPreviewStyle() { + // do nothing by default + } + } diff --git a/src/main/java/org/jabref/gui/entryeditor/FieldsEditorTab.java b/src/main/java/org/jabref/gui/entryeditor/FieldsEditorTab.java index ce226b512f8..eba5b206523 100644 --- a/src/main/java/org/jabref/gui/entryeditor/FieldsEditorTab.java +++ b/src/main/java/org/jabref/gui/entryeditor/FieldsEditorTab.java @@ -40,12 +40,12 @@ * A single tab displayed in the EntryEditor holding several FieldEditors. */ abstract class FieldsEditorTab extends EntryEditorTab { - public PreviewPanel previewPanel; protected final BibDatabaseContext databaseContext; private final Map editors = new LinkedHashMap<>(); private final boolean isCompressed; private final SuggestionProviders suggestionProviders; private final DialogService dialogService; + private PreviewPanel previewPanel; private FieldEditorFX activeField; private UndoManager undoManager; private Collection fields = new ArrayList<>(); @@ -197,6 +197,16 @@ protected void bindToEntry(BibEntry entry) { }); } + @Override + protected void nextPreviewStyle() { + previewPanel.nextPreviewStyle(); + } + + @Override + protected void previousPreviewStyle() { + previewPanel.previousPreviewStyle(); + } + protected abstract SortedSet determineFieldsToShow(BibEntry entry); public Collection getShownFields() { @@ -208,7 +218,7 @@ private void initPanel() { gridPane = new GridPane(); gridPane.getStyleClass().add("editorPane"); - previewPanel = new PreviewPanel(databaseContext, null, dialogService, ExternalFileTypes.getInstance(), Globals.getKeyPrefs(), Globals.prefs.getPreviewPreferences()); + previewPanel = new PreviewPanel(databaseContext, dialogService, ExternalFileTypes.getInstance(), Globals.getKeyPrefs(), Globals.prefs); // Warp everything in a scroll-pane ScrollPane scrollPane = new ScrollPane(); diff --git a/src/main/java/org/jabref/gui/preview/PreviewPanel.java b/src/main/java/org/jabref/gui/preview/PreviewPanel.java index c4fbde25a1e..3f25375cf5b 100644 --- a/src/main/java/org/jabref/gui/preview/PreviewPanel.java +++ b/src/main/java/org/jabref/gui/preview/PreviewPanel.java @@ -17,7 +17,6 @@ import javafx.scene.layout.VBox; import org.jabref.Globals; -import org.jabref.gui.BasePanel; import org.jabref.gui.DialogService; import org.jabref.gui.externalfiles.ExternalFilesEntryLinker; import org.jabref.gui.externalfiletype.ExternalFileTypes; @@ -28,6 +27,7 @@ import org.jabref.logic.l10n.Localization; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; +import org.jabref.preferences.JabRefPreferences; import org.jabref.preferences.PreviewPreferences; import org.slf4j.Logger; @@ -40,18 +40,19 @@ public class PreviewPanel extends VBox { private final ExternalFilesEntryLinker fileLinker; private final KeyBindingRepository keyBindingRepository; private final PreviewViewer previewView; + private final JabRefPreferences preferences; private BibEntry entry; - private BasePanel basePanel; private DialogService dialogService; - public PreviewPanel(BibDatabaseContext database, BasePanel basePanel, DialogService dialogService, ExternalFileTypes externalFileTypes, KeyBindingRepository keyBindingRepository, PreviewPreferences preferences) { - this.basePanel = basePanel; + public PreviewPanel(BibDatabaseContext database, DialogService dialogService, ExternalFileTypes externalFileTypes, KeyBindingRepository keyBindingRepository, JabRefPreferences preferences) { this.keyBindingRepository = keyBindingRepository; this.dialogService = dialogService; - fileLinker = new ExternalFilesEntryLinker(externalFileTypes, Globals.prefs.getFilePreferences(), database); + this.preferences = preferences; + fileLinker = new ExternalFilesEntryLinker(externalFileTypes, preferences.getFilePreferences(), database); + PreviewPreferences previewPreferences = preferences.getPreviewPreferences(); previewView = new PreviewViewer(database, dialogService, Globals.stateManager); - previewView.setLayout(preferences.getCurrentPreviewStyle()); + previewView.setLayout(previewPreferences.getCurrentPreviewStyle()); previewView.setContextMenu(createPopupMenu()); previewView.setOnDragDetected(event -> { previewView.startFullDrag(); @@ -97,11 +98,7 @@ public PreviewPanel(BibDatabaseContext database, BasePanel basePanel, DialogServ this.getChildren().add(previewView); createKeyBindings(); - updateLayout(preferences, true); - } - - public void close() { - basePanel.closeBottomPane(); + updateLayout(previewPreferences, true); } public void updateLayout(PreviewPreferences previewPreferences) { @@ -111,6 +108,7 @@ public void updateLayout(PreviewPreferences previewPreferences) { private void updateLayout(PreviewPreferences previewPreferences, boolean init) { PreviewLayout currentPreviewStyle = previewPreferences.getCurrentPreviewStyle(); previewView.setLayout(currentPreviewStyle); + preferences.storePreviewPreferences(previewPreferences); if (!init) { dialogService.notify(Localization.lang("Preview style changed to: %0", currentPreviewStyle.getName())); } @@ -125,10 +123,6 @@ private void createKeyBindings() { previewView.copyPreviewToClipBoard(); event.consume(); break; - case CLOSE: - close(); - event.consume(); - break; default: } } @@ -141,21 +135,19 @@ private ContextMenu createPopupMenu() { copyPreview.setOnAction(event -> previewView.copyPreviewToClipBoard()); MenuItem printEntryPreview = new MenuItem(Localization.lang("Print entry preview"), IconTheme.JabRefIcons.PRINTED.getGraphicNode()); printEntryPreview.setOnAction(event -> previewView.print()); - /* Deleted since it does not work anymore. Needs refactoring. MenuItem previousPreviewLayout = new MenuItem(Localization.lang("Previous preview layout")); previousPreviewLayout.setAccelerator(keyBindingRepository.getKeyCombination(KeyBinding.PREVIOUS_PREVIEW_LAYOUT)); - previousPreviewLayout.setOnAction(event -> basePanel.previousPreviewStyle()); + previousPreviewLayout.setOnAction(event -> this.previousPreviewStyle()); MenuItem nextPreviewLayout = new MenuItem(Localization.lang("Next preview layout")); nextPreviewLayout.setAccelerator(keyBindingRepository.getKeyCombination(KeyBinding.NEXT_PREVIEW_LAYOUT)); - nextPreviewLayout.setOnAction(event -> basePanel.nextPreviewStyle()); - */ + nextPreviewLayout.setOnAction(event -> this.nextPreviewStyle()); ContextMenu menu = new ContextMenu(); menu.getItems().add(copyPreview); menu.getItems().add(printEntryPreview); menu.getItems().add(new SeparatorMenuItem()); - // menu.getItems().add(nextPreviewLayout); - // menu.getItems().add(previousPreviewLayout); + menu.getItems().add(nextPreviewLayout); + menu.getItems().add(previousPreviewLayout); return menu; } @@ -167,4 +159,20 @@ public void setEntry(BibEntry entry) { public void print() { previewView.print(); } + + public void nextPreviewStyle() { + cyclePreview(preferences.getPreviewPreferences().getPreviewCyclePosition() + 1); + } + + public void previousPreviewStyle() { + cyclePreview(preferences.getPreviewPreferences().getPreviewCyclePosition() - 1); + } + + private void cyclePreview(int newPosition) { + PreviewPreferences previewPreferences = preferences.getPreviewPreferences() + .getBuilder() + .withPreviewCyclePosition(newPosition) + .build(); + updateLayout(previewPreferences); + } } From bebea3cfa179150aaa53d57384d4f0ab18944d49 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Sun, 6 Oct 2019 09:55:25 +0200 Subject: [PATCH 26/40] Fix exception when merging entries The problem was that `sourceChanged` was invoked asynchronous and thus the information in the change event could be obsolete if another thread changed the underlying list in the meantime. Solution: run `sourceChanged` on the JavaFX thread but synchronously. Fixes #5169. --- CHANGELOG.md | 1 + .../org/jabref/gui/util/UiThreadList.java | 22 ++++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b71f0091dcd..815537f3f2f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `# - The "All entries group" is no longer shown when no library is open. - We fixed an exception which occurred when closing JabRef. [#5348](https://github.com/JabRef/jabref/issues/5348) - We fixed an error where the groups containing an entry loose their highlight color when scrolling. [#5022](https://github.com/JabRef/jabref/issues/5022) +- We fixed an error where an exception was thrown when merging entries. [#5169](https://github.com/JabRef/jabref/issues/5169) - After assigning an entry to a group, the item count is now properly colored to reflect the new membership of the entry. [#3112](https://github.com/JabRef/jabref/issues/3112) - The group panel is now properly updated when switching between libraries (or when closing/opening one). [#3142](https://github.com/JabRef/jabref/issues/3142) - We fixed an error where the number of matched entries shown in the group pane was not updated correctly. [#4441](https://github.com/JabRef/jabref/issues/4441) diff --git a/src/main/java/org/jabref/gui/util/UiThreadList.java b/src/main/java/org/jabref/gui/util/UiThreadList.java index a09efa8957c..b9f8b8853c7 100644 --- a/src/main/java/org/jabref/gui/util/UiThreadList.java +++ b/src/main/java/org/jabref/gui/util/UiThreadList.java @@ -1,18 +1,38 @@ package org.jabref.gui.util; +import java.util.concurrent.CountDownLatch; + import javafx.application.Platform; import javafx.collections.ListChangeListener; import javafx.collections.ObservableList; import javafx.collections.transformation.TransformationList; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + class UiThreadList extends TransformationList { + private static final Logger LOGGER = LoggerFactory.getLogger(UiThreadList.class); public UiThreadList(ObservableList source) { super(source); } @Override protected void sourceChanged(ListChangeListener.Change change) { - Platform.runLater(() -> fireChange(change)); + if (Platform.isFxApplicationThread()) { + fireChange(change); + } else { + CountDownLatch latch = new CountDownLatch(1); + Platform.runLater(() -> { + fireChange(change); + latch.countDown(); + }); + + try { + latch.await(); + } catch (InterruptedException e) { + LOGGER.error("Error while running on JavaFX thread", e); + } + } } @Override From 9c7f7f61c40443b3688af16c0d95c54a78900f87 Mon Sep 17 00:00:00 2001 From: Matthias Geiger Date: Sun, 6 Oct 2019 10:19:14 +0200 Subject: [PATCH 27/40] Fix 5359: Writing of Editor field is duplicated (#5392) * add (failing) test for #5359 * fixes #5359 - correction writing of OrFields in BibEntryWriter * add changelog entry --- CHANGELOG.md | 5 +- .../jabref/logic/bibtex/BibEntryWriter.java | 2 +- .../logic/bibtex/BibEntryWriterTest.java | 58 +++++++++++++++++++ 3 files changed, 60 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c2285cad78e..9a4e50fdea6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,12 +33,9 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `# - We fixed an exception which occured when trying to open a non existing file from the "Recent files"-menu [#5334](https://github.com/JabRef/jabref/issues/5334) - The context menu for fields in the entry editor is back. [#5254](https://github.com/JabRef/jabref/issues/5254) - We fixed an exception which occurred when trying to open a non existing file from the "Recent files"-menu [#5334](https://github.com/JabRef/jabref/issues/5334) +- We fixed a problem where the "editor" information has been duplicated during saving a .bib-Database. [#5359](https://github.com/JabRef/jabref/issues/5359) - We re-introduced the feature to switch between different preview styles. [#5221](https://github.com/JabRef/jabref/issues/5221) - - - - ### Removed diff --git a/src/main/java/org/jabref/logic/bibtex/BibEntryWriter.java b/src/main/java/org/jabref/logic/bibtex/BibEntryWriter.java index 4169df2da8f..2f1bce49674 100644 --- a/src/main/java/org/jabref/logic/bibtex/BibEntryWriter.java +++ b/src/main/java/org/jabref/logic/bibtex/BibEntryWriter.java @@ -111,7 +111,7 @@ private void writeRequiredFieldsFirstRemainingFieldsSecond(BibEntry entry, Write for (OrFields value : type.get().getRequiredFields()) { for (Field field : value) { writeField(entry, out, field, indentation); - written.add(value.getPrimary()); + written.add(field); } } // Then optional fields. diff --git a/src/test/java/org/jabref/logic/bibtex/BibEntryWriterTest.java b/src/test/java/org/jabref/logic/bibtex/BibEntryWriterTest.java index 3c158a64d53..5b2d91b77c3 100644 --- a/src/test/java/org/jabref/logic/bibtex/BibEntryWriterTest.java +++ b/src/test/java/org/jabref/logic/bibtex/BibEntryWriterTest.java @@ -106,6 +106,64 @@ void writeEntryWithFile() throws Exception { + "}" + OS.NEWLINE, stringWriter.toString()); } + @Test + void writeEntryWithOrField() throws Exception { + StringWriter stringWriter = new StringWriter(); + + BibEntry entry = new BibEntry(StandardEntryType.InBook); + //set an required OR field (author/editor) + entry.setField(StandardField.EDITOR, "Foo Bar"); + entry.setField(StandardField.JOURNAL, "International Journal of Something"); + //set an optional field + entry.setField(StandardField.NUMBER, "1"); + entry.setField(StandardField.NOTE, "some note"); + + writer.write(entry, stringWriter, BibDatabaseMode.BIBTEX); + + String actual = stringWriter.toString(); + + // @formatter:off + String expected = OS.NEWLINE + "@InBook{," + OS.NEWLINE + + " editor = {Foo Bar}," + OS.NEWLINE + + " note = {some note}," + OS.NEWLINE + + " number = {1}," + OS.NEWLINE + + " journal = {International Journal of Something}," + OS.NEWLINE + + "}" + OS.NEWLINE; + // @formatter:on + + assertEquals(expected, actual); + } + + @Test + void writeEntryWithOrFieldBothFieldsPresent() throws Exception { + StringWriter stringWriter = new StringWriter(); + + BibEntry entry = new BibEntry(StandardEntryType.InBook); + //set an required OR field with both fields(author/editor) + entry.setField(StandardField.AUTHOR, "Foo Thor"); + entry.setField(StandardField.EDITOR, "Edi Bar"); + entry.setField(StandardField.JOURNAL, "International Journal of Something"); + //set an optional field + entry.setField(StandardField.NUMBER, "1"); + entry.setField(StandardField.NOTE, "some note"); + + writer.write(entry, stringWriter, BibDatabaseMode.BIBTEX); + + String actual = stringWriter.toString(); + + // @formatter:off + String expected = OS.NEWLINE + "@InBook{," + OS.NEWLINE + + " author = {Foo Thor}," + OS.NEWLINE + + " editor = {Edi Bar}," + OS.NEWLINE + + " note = {some note}," + OS.NEWLINE + + " number = {1}," + OS.NEWLINE + + " journal = {International Journal of Something}," + OS.NEWLINE + + "}" + OS.NEWLINE; + // @formatter:on + + assertEquals(expected, actual); + } + @Test public void writeReallyUnknownTypeTest() throws Exception { String expected = OS.NEWLINE + "@Reallyunknowntype{test," + OS.NEWLINE + From 9117fff18e771f2b1cb23e0dfcc83b0550f63fac Mon Sep 17 00:00:00 2001 From: Matthias Geiger Date: Sun, 6 Oct 2019 11:25:14 +0200 Subject: [PATCH 28/40] Fix various copy to clipboard issues (#5340) * fix plain text copy in preview viewer * put textual representation also to clipboard * fix tests * improve "Export to Clipboard" function * fix checkstyle * fix plain text copy in preview viewer (a bit more intelligent ;-)) * filter exporter list to supported exporters only * update CHANGELOG.md * fix checkstyle * improve exception handling * checkstyle --- CHANGELOG.md | 4 ++ .../gui/exporter/ExportToClipboardAction.java | 40 +++++++++++++++---- .../CitationStyleToClipboardWorker.java | 12 ++++-- .../org/jabref/gui/preview/PreviewViewer.java | 12 +----- .../CitationStyleToClipboardWorkerTest.java | 7 ++-- 5 files changed, 50 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a4e50fdea6..2f9f21900f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,10 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `# - We fixed an exception which occurred when trying to open a non existing file from the "Recent files"-menu [#5334](https://github.com/JabRef/jabref/issues/5334) - We fixed a problem where the "editor" information has been duplicated during saving a .bib-Database. [#5359](https://github.com/JabRef/jabref/issues/5359) - We re-introduced the feature to switch between different preview styles. [#5221](https://github.com/JabRef/jabref/issues/5221) +- We fixed various issues (including [#5263](https://github.com/JabRef/jabref/issues/5263)) related to copying entries to the clipboard + + + ### Removed diff --git a/src/main/java/org/jabref/gui/exporter/ExportToClipboardAction.java b/src/main/java/org/jabref/gui/exporter/ExportToClipboardAction.java index 122b5baf610..94b63150d15 100644 --- a/src/main/java/org/jabref/gui/exporter/ExportToClipboardAction.java +++ b/src/main/java/org/jabref/gui/exporter/ExportToClipboardAction.java @@ -5,6 +5,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; +import java.util.Arrays; import java.util.Comparator; import java.util.List; import java.util.Optional; @@ -20,6 +21,7 @@ import org.jabref.gui.util.BackgroundTask; import org.jabref.logic.exporter.Exporter; import org.jabref.logic.l10n.Localization; +import org.jabref.logic.util.FileType; import org.jabref.logic.util.OS; import org.jabref.model.entry.BibEntry; import org.jabref.preferences.JabRefPreferences; @@ -31,6 +33,9 @@ public class ExportToClipboardAction extends SimpleCommand { private static final Logger LOGGER = LoggerFactory.getLogger(ExportToClipboardAction.class); + // Only text based exporters can be used + private static final List SUPPORTED_FILETYPES = Arrays.asList("txt", "rtf", "rdf", "xml", "html", "htm", "csv", "ris"); + private JabRefFrame frame; private final DialogService dialogService; private BasePanel panel; @@ -59,6 +64,7 @@ public void execute() { List exporters = Globals.exportFactory.getExporters().stream() .sorted(Comparator.comparing(Exporter::getName)) + .filter(exporter -> SUPPORTED_FILETYPES.containsAll(exporter.getFileType().getExtensions())) .collect(Collectors.toList()); //Find default choice, if any @@ -71,12 +77,12 @@ public void execute() { Localization.lang("Export"), defaultChoice, exporters); selectedExporter.ifPresent(exporter -> BackgroundTask.wrap(() -> exportToClipboard(exporter)) - .onSuccess(this::setContentToClipboard) - .executeWith(Globals.TASK_EXECUTOR)); - + .onSuccess(this::setContentToClipboard) + .onFailure(ex -> { /* swallow as already logged */ }) + .executeWith(Globals.TASK_EXECUTOR)); } - private String exportToClipboard(Exporter exporter) { + private ExportResult exportToClipboard(Exporter exporter) throws Exception { // Set the global variable for this database's file directory before exporting, // so formatters can resolve linked files correctly. // (This is an ugly hack!) @@ -102,9 +108,10 @@ private String exportToClipboard(Exporter exporter) { entries); // Read the file and put the contents on the clipboard: - return readFileToString(tmp); + return new ExportResult(readFileToString(tmp), exporter.getFileType()); } catch (Exception e) { LOGGER.error("Error exporting to clipboard", e); + throw new Exception("Rethrow ", e); } finally { // Clean up: if ((tmp != null) && Files.exists(tmp)) { @@ -115,12 +122,19 @@ private String exportToClipboard(Exporter exporter) { } } } - return ""; } - private void setContentToClipboard(String content) { + private void setContentToClipboard(ExportResult result) { ClipboardContent clipboardContent = new ClipboardContent(); - clipboardContent.putRtf(content); + List extensions = result.fileType.getExtensions(); + if (extensions.contains("html")) { + clipboardContent.putHtml(result.content); + } else if (extensions.contains("rtf")) { + clipboardContent.putRtf(result.content); + } else if (extensions.contains("rdf")) { + clipboardContent.putRtf(result.content); + } + clipboardContent.putString(result.content); Globals.clipboardManager.setContent(clipboardContent); dialogService.notify(Localization.lang("Entries exported to clipboard") + ": " + entries.size()); @@ -135,4 +149,14 @@ private String readFileToString(Path tmp) throws IOException { return reader.lines().collect(Collectors.joining(OS.NEWLINE)); } } + + private class ExportResult { + final String content; + final FileType fileType; + + ExportResult(String content, FileType fileType) { + this.content = content; + this.fileType = fileType; + } + } } diff --git a/src/main/java/org/jabref/gui/preview/CitationStyleToClipboardWorker.java b/src/main/java/org/jabref/gui/preview/CitationStyleToClipboardWorker.java index 80299068046..23a4f056d36 100644 --- a/src/main/java/org/jabref/gui/preview/CitationStyleToClipboardWorker.java +++ b/src/main/java/org/jabref/gui/preview/CitationStyleToClipboardWorker.java @@ -87,8 +87,11 @@ private List generateCitations() throws IOException { * Generates a plain text string out of the preview and copies it additionally to the html to the clipboard * (WYSIWYG Editors use the HTML, plain text editors the text) */ - protected static String processPreview(List citations) { - return String.join(CitationStyleOutputFormat.HTML.getLineSeparator(), citations); + protected static ClipboardContent processPreview(List citations) { + ClipboardContent content = new ClipboardContent(); + content.putHtml(String.join(CitationStyleOutputFormat.HTML.getLineSeparator(), citations)); + content.putString(String.join(CitationStyleOutputFormat.HTML.getLineSeparator(), citations)); + return content; } /** @@ -108,6 +111,7 @@ protected static ClipboardContent processRtf(List citations) { String.join(CitationStyleOutputFormat.RTF.getLineSeparator(), citations) + "}"; ClipboardContent content = new ClipboardContent(); + content.putString(result); content.putRtf(result); return content; } @@ -134,6 +138,7 @@ protected static ClipboardContent processXslFo(List citations) { "" + OS.NEWLINE; ClipboardContent content = new ClipboardContent(); + content.putString(result); content.put(ClipBoardManager.XML, result); return content; } @@ -155,6 +160,7 @@ protected static ClipboardContent processHtml(List citations) { "" + OS.NEWLINE; ClipboardContent content = new ClipboardContent(); + content.putString(result); content.putHtml(result); return content; } @@ -162,7 +168,7 @@ protected static ClipboardContent processHtml(List citations) { private void setClipBoardContent(List citations) { // if it's not a citation style take care of the preview if (!(style instanceof CitationStylePreviewLayout)) { - clipBoardManager.setHtmlContent(processPreview(citations)); + clipBoardManager.setContent(processPreview(citations)); } else { // if it's generated by a citation style take care of each output format ClipboardContent content; diff --git a/src/main/java/org/jabref/gui/preview/PreviewViewer.java b/src/main/java/org/jabref/gui/preview/PreviewViewer.java index 8811d398b88..c3d0ec4b405 100644 --- a/src/main/java/org/jabref/gui/preview/PreviewViewer.java +++ b/src/main/java/org/jabref/gui/preview/PreviewViewer.java @@ -29,8 +29,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; /** * Displays an BibEntry using the given layout format. @@ -175,16 +173,8 @@ public void copyPreviewToClipBoard() { StringBuilder previewStringContent = new StringBuilder(); Document document = previewView.getEngine().getDocument(); - NodeList nodeList = document.getElementsByTagName("html"); - - //Nodelist does not implement iterable - for (int i = 0; i < nodeList.getLength(); i++) { - Element element = (Element) nodeList.item(i); - previewStringContent.append(element.getTextContent()); - } - ClipboardContent content = new ClipboardContent(); - content.putString(previewStringContent.toString()); + content.putString(document.getElementById("content").getTextContent()); content.putHtml((String) previewView.getEngine().executeScript("document.documentElement.outerHTML")); clipBoardManager.setContent(content); diff --git a/src/test/java/org/jabref/gui/preview/CitationStyleToClipboardWorkerTest.java b/src/test/java/org/jabref/gui/preview/CitationStyleToClipboardWorkerTest.java index 0ac88a6d323..82501d0e182 100644 --- a/src/test/java/org/jabref/gui/preview/CitationStyleToClipboardWorkerTest.java +++ b/src/test/java/org/jabref/gui/preview/CitationStyleToClipboardWorkerTest.java @@ -39,7 +39,8 @@ void processPreviewText() throws Exception { OS.NEWLINE + "Abstract: This entry describes a test scenario which may be useful in JabRef. By providing a test entry it is possible to see how certain things will look in this graphical BIB-file mananger. "; - String actual = CitationStyleToClipboardWorker.processPreview(Arrays.asList(citation, citation)); + ClipboardContent clipboardContent = CitationStyleToClipboardWorker.processPreview(Arrays.asList(citation, citation)); + String actual = clipboardContent.getString(); assertEquals(expected, actual); } @@ -91,8 +92,8 @@ void processPreviewHtml() throws Exception { "" + OS.NEWLINE + "

"; - String actual = CitationStyleToClipboardWorker.processPreview(Arrays.asList(citation, citation)); - + ClipboardContent clipboardContent = CitationStyleToClipboardWorker.processPreview(Arrays.asList(citation, citation)); + String actual = clipboardContent.getString(); assertEquals(expected, actual); } From b7b93a4d17c48b5b750cd2acc90f9fbc0f621650 Mon Sep 17 00:00:00 2001 From: Steffin Stanly <32876873+steffinstanly@users.noreply.github.com> Date: Sun, 6 Oct 2019 17:01:11 +0530 Subject: [PATCH 29/40] Update CHANGELOG.md --- CHANGELOG.md | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f9f21900f8..d4e0815b371 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `# ### Changed -- We added a short DOI field formatter which shortens DOI to more human readable form. [koppor#343](https://github.com/koppor/jabref/issues/343) +- We added a short DOI field formatter which shortens DOI to more human-readable form. [koppor#343](https://github.com/koppor/jabref/issues/343) - We improved the display of group memberships by adding multiple colored bars if the entry belongs to more than one group. [#4574](https://github.com/JabRef/jabref/issues/4574) ### Fixed @@ -30,9 +30,9 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `# - We fixed an error where the default color of a new group was white instead of dark gray. [#4868](https://github.com/JabRef/jabref/issues/4868) - We fixed an error mentioning "javafx.controls/com.sun.javafx.scene.control" that was thrown when interacting with the toolbar. - We fixed an error where a cleared search was restored after switching libraries. [#4846](https://github.com/JabRef/jabref/issues/4846) -- We fixed an exception which occured when trying to open a non existing file from the "Recent files"-menu [#5334](https://github.com/JabRef/jabref/issues/5334) +- We fixed an exception which occurred when trying to open a non-existing file from the "Recent files"-menu [#5334](https://github.com/JabRef/jabref/issues/5334) - The context menu for fields in the entry editor is back. [#5254](https://github.com/JabRef/jabref/issues/5254) -- We fixed an exception which occurred when trying to open a non existing file from the "Recent files"-menu [#5334](https://github.com/JabRef/jabref/issues/5334) +- We fixed an exception which occurred when trying to open a non-existing file from the "Recent files"-menu [#5334](https://github.com/JabRef/jabref/issues/5334) - We fixed a problem where the "editor" information has been duplicated during saving a .bib-Database. [#5359](https://github.com/JabRef/jabref/issues/5359) - We re-introduced the feature to switch between different preview styles. [#5221](https://github.com/JabRef/jabref/issues/5221) - We fixed various issues (including [#5263](https://github.com/JabRef/jabref/issues/5263)) related to copying entries to the clipboard @@ -107,11 +107,11 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `# - Moreover, empty deprecated fields are no longer shown - Added server timezone parameter when connecting to a shared database. - We updated the dialog for setting up general fields. -- URL field formatting is updated. All whitespace chars, located at the beginning/ending of the url, are trimmed automatically +- URL field formatting is updated. All whitespace chars, located at the beginning/ending of the URL, are trimmed automatically - We changed the behavior of the field formatting dialog such that the `bibtexkey` is not changed when formatting all fields or all text fields. - We added a "Move file to file directory and rename file" option for simultaneously moving and renaming of document file. [#4166](https://github.com/JabRef/jabref/issues/4166) - Use integrated graphics card instead of discrete on macOS [#4070](https://github.com/JabRef/jabref/issues/4070) -- We added a cleanup operation that detects an arXiv identifier in the note, journal or url field and moves it to the `eprint` field. +- We added a cleanup operation that detects an arXiv identifier in the note, journal or URL field and moves it to the `eprint` field. Because of this change, the last-used cleanup operations were reset. - We changed the minimum required version of Java to 1.8.0_171, as this is the latest release for which the automatic Java update works. [#4093](https://github.com/JabRef/jabref/issues/4093) - The special fields like `Printed` and `Read status` now show gray icons when the row is hovered. @@ -130,18 +130,18 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `# - Files without a defined external file type are now directly opened with the default application of the operating system - We streamlined the process to rename and move files by removing the confirmation dialogs. - We removed the redundant new lines of markings and wrapped the summary in the File annotation tab. [#3823](https://github.com/JabRef/jabref/issues/3823) -- We add auto url formatting when user paste link to URL field in entry editor. [koppor#254](https://github.com/koppor/jabref/issues/254) -- We added a minimal height for the entry editor so that it can no longer be hidden by accident. [#4279](https://github.com/JabRef/jabref/issues/4279) +- We add auto URL formatting when user paste link to URL field in entry editor. [koppor#254](https://github.com/koppor/jabref/issues/254) +- We added a minimum height for the entry editor so that it can no longer be hidden by accident. [#4279](https://github.com/JabRef/jabref/issues/4279) - We added a new keyboard shortcut so that the entry editor could be closed by Ctrl + E. [#4222] (https://github.com/JabRef/jabref/issues/4222) - We added an option in the preference dialog box, that allows user to pick the dark or light theme option. [#4130] (https://github.com/JabRef/jabref/issues/4130) -- We updated updated the Related Articles tab to accept JSON from the new version of the Mr. DLib service +- We updated the Related Articles tab to accept JSON from the new version of the Mr. DLib service - We added an option in the preference dialog box that allows user to choose behavior after dragging and dropping files in Entry Editor. [#4356](https://github.com/JabRef/jabref/issues/4356) - We added the ability to have an export preference where previously "File"-->"Export"/"Export selected entries" would not save the user's preference[#4495](https://github.com/JabRef/jabref/issues/4495) - We optimized the code responsible for connecting to an external database, which should lead to huge improvements in performance. - For automatically created groups, added ability to filter groups by entry type. [#4539](https://github.com/JabRef/jabref/issues/4539) - We added the ability to add field names from the Preferences Dialog [#4546](https://github.com/JabRef/jabref/issues/4546) -- We added the ability change the column widths directly in the main table. [#4546](https://github.com/JabRef/jabref/issues/4546) -- We added description of how recommendations where chosen and better error handling to Related Articles tab +- We added the ability to change the column widths directly in the main table. [#4546](https://github.com/JabRef/jabref/issues/4546) +- We added a description of how recommendations were chosen and better error handling to Related Articles tab - We added the ability to execute default action in dialog by using with Ctrl + Enter combination [#4496](https://github.com/JabRef/jabref/issues/4496) - We grouped and reordered the Main Menu (File, Edit, Library, Quality, Tools, and View tabs & icons). [#4666](https://github.com/JabRef/jabref/issues/4666) [#4667](https://github.com/JabRef/jabref/issues/4667) [#4668](https://github.com/JabRef/jabref/issues/4668) [#4669](https://github.com/JabRef/jabref/issues/4669) [#4670](https://github.com/JabRef/jabref/issues/4670) [#4671](https://github.com/JabRef/jabref/issues/4671) [#4672](https://github.com/JabRef/jabref/issues/4672) [#4673](https://github.com/JabRef/jabref/issues/4673) - We added additional modifiers (capitalize, titlecase and sentencecase) to the Bibtex key generator. [#1506](https://github.com/JabRef/jabref/issues/1506) @@ -150,7 +150,7 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `# - We added a browse button next to the path text field for aux-based groups. [#4586](https://github.com/JabRef/jabref/issues/4586) - We changed the title of Group Dialog to "Add subgroup" from "Edit group" when we select Add subgroup option. - We enable import button only if entries are selected. [#4755](https://github.com/JabRef/jabref/issues/4755) -- We made modifications to improve contrast of UI elements. [#4583](https://github.com/JabRef/jabref/issues/4583) +- We made modifications to improve the contrast of UI elements. [#4583](https://github.com/JabRef/jabref/issues/4583) - We added a warning for empty BibTeX keys in the entry editor. [#4440](https://github.com/JabRef/jabref/issues/4440) - We added an option in the settings to set the default action in JabRef when right clicking on any entry in any database and selecting "Open folder". [#4763](https://github.com/JabRef/jabref/issues/4763) - The Medline fetcher now normalizes the author names according to the BibTeX-Standard [#4345](https://github.com/JabRef/jabref/issues/4345) @@ -177,7 +177,7 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `# - We fixed an issue where the group tree was not updated correctly after an entry was changed. https://github.com/JabRef/jabref/issues/3618 - We fixed an issue where a right-click in the main table selected a wrong entry. https://github.com/JabRef/jabref/issues/3267 - We fixed an issue where in rare cases entries where overlayed in the main table. https://github.com/JabRef/jabref/issues/3281 -- We fixed an issue where selecting a group messed up the focus of the main table / entry editor. https://github.com/JabRef/jabref/issues/3367 +- We fixed an issue where selecting a group messed up the focus of the main table/entry editor. https://github.com/JabRef/jabref/issues/3367 - We fixed an issue where composite author names were sorted incorrectly. https://github.com/JabRef/jabref/issues/2828 - We fixed an issue where commands followed by `-` didn't work. [#3805](https://github.com/JabRef/jabref/issues/3805) - We fixed an issue where a non-existing aux file in a group made it impossible to open the library. [#4735](https://github.com/JabRef/jabref/issues/4735) @@ -210,9 +210,9 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `# - We fixed an issue where "Move to group" would always move the first entry in the library and not the selected [#4414](https://github.com/JabRef/jabref/issues/4414) - We fixed an issue where an older dialog appears when downloading full texts from the quality menu. [#4489](https://github.com/JabRef/jabref/issues/4489) - We fixed an issue where right clicking on any entry in any database and selecting "Open folder" results in the NullPointer exception. [#4763](https://github.com/JabRef/jabref/issues/4763) -- We fixed an issue where option 'open terminal here' with custom command was passing wrong argument. [#4802](https://github.com/JabRef/jabref/issues/4802) +- We fixed an issue where option 'open terminal here' with custom command was passing the wrong argument. [#4802](https://github.com/JabRef/jabref/issues/4802) - We fixed an issue where ranking an entry would generate an IllegalArgumentException. [#4754](https://github.com/JabRef/jabref/issues/4754) -- We fixed an issue where special characters where removed from non label key generation pattern parts [#4767](https://github.com/JabRef/jabref/issues/4767) +- We fixed an issue where special characters where removed from non-label key generation pattern parts [#4767](https://github.com/JabRef/jabref/issues/4767) - We fixed an issue where the RIS import would overwite the article date with the value of the acessed date [#4816](https://github.com/JabRef/jabref/issues/4816) - We fixed an issue where an NullPointer exception was thrown when a referenced entry in an Open/Libre Office document was no longer present in the library. Now an error message with the reference marker of the missing entry is shown. [#4932](https://github.com/JabRef/jabref/issues/4932) - We fixed an issue where a database exception related to a missing timezone was too big. [#4827](https://github.com/JabRef/jabref/issues/4827) @@ -228,13 +228,13 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `# - The feature to "mark entries" was removed and merged with the groups functionality. For migration, a group is created for every value of the `__markedentry` field and the entry is added to this group. - The number column was removed. - We removed the global search feature. -- We removed the coloring of cells in the maintable according to whether the field is optional/required. +- We removed the coloring of cells in the main table according to whether the field is optional/required. - We removed the feature to find and resolve duplicate BibTeX keys (as this use case is already covered by the integrity check). - We removed a few commands from the right-click menu that are not needed often and thus don't need to be placed that prominently: - Print entry preview: available through entry preview - All commands related to marking: marking is not yet reimplemented - Set/clear/append/rename fields: available through Edit menu - - Manage keywords: available through Edit menu + - Manage keywords: available through the Edit menu - Copy linked files to folder: available through File menu - Add/move/remove from group: removed completely (functionality still available through group interface) - We removed the option to change the column widths in the preferences dialog. [#4546](https://github.com/JabRef/jabref/issues/4546) From 551ff4c8dd258d7c230d4bc9018b1b8b191c9cef Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sun, 6 Oct 2019 13:34:37 +0200 Subject: [PATCH 30/40] Add hacktoberfest shields.io badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 40910c6466a..880a8eaa086 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# JabRef Bibliography Management +# JabRef Bibliography Management [![Hacktoberfest](https://img.shields.io/github/hacktoberfest/2019/JabRef/jabref?suggestion_label=hacktoberfest)](https://www.jabref.org/hacktoberfest/2019.html) [![Build Status](https://travis-ci.org/JabRef/jabref.svg?branch=master)](https://travis-ci.org/JabRef/jabref) [![codecov.io](https://codecov.io/github/JabRef/jabref/coverage.svg?branch=master)](https://codecov.io/github/JabRef/jabref?branch=master) From 29026c383a6ed68a7541f0230160a0ac8dcc2654 Mon Sep 17 00:00:00 2001 From: Steffin Stanly <32876873+steffinstanly@users.noreply.github.com> Date: Sun, 6 Oct 2019 19:49:24 +0530 Subject: [PATCH 31/40] Update CHANGELOG.md --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d4e0815b371..aae419279ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -140,7 +140,8 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `# - We optimized the code responsible for connecting to an external database, which should lead to huge improvements in performance. - For automatically created groups, added ability to filter groups by entry type. [#4539](https://github.com/JabRef/jabref/issues/4539) - We added the ability to add field names from the Preferences Dialog [#4546](https://github.com/JabRef/jabref/issues/4546) -- We added the ability to change the column widths directly in the main table. [#4546](https://github.com/JabRef/jabref/issues/4546) +- We added the ability to change the column widths directly in the main +. [#4546](https://github.com/JabRef/jabref/issues/4546) - We added a description of how recommendations were chosen and better error handling to Related Articles tab - We added the ability to execute default action in dialog by using with Ctrl + Enter combination [#4496](https://github.com/JabRef/jabref/issues/4496) - We grouped and reordered the Main Menu (File, Edit, Library, Quality, Tools, and View tabs & icons). [#4666](https://github.com/JabRef/jabref/issues/4666) [#4667](https://github.com/JabRef/jabref/issues/4667) [#4668](https://github.com/JabRef/jabref/issues/4668) [#4669](https://github.com/JabRef/jabref/issues/4669) [#4670](https://github.com/JabRef/jabref/issues/4670) [#4671](https://github.com/JabRef/jabref/issues/4671) [#4672](https://github.com/JabRef/jabref/issues/4672) [#4673](https://github.com/JabRef/jabref/issues/4673) @@ -177,7 +178,7 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `# - We fixed an issue where the group tree was not updated correctly after an entry was changed. https://github.com/JabRef/jabref/issues/3618 - We fixed an issue where a right-click in the main table selected a wrong entry. https://github.com/JabRef/jabref/issues/3267 - We fixed an issue where in rare cases entries where overlayed in the main table. https://github.com/JabRef/jabref/issues/3281 -- We fixed an issue where selecting a group messed up the focus of the main table/entry editor. https://github.com/JabRef/jabref/issues/3367 +- We fixed an issue where selecting a group messed up the focus of the main table and the entry editor. https://github.com/JabRef/jabref/issues/3367 - We fixed an issue where composite author names were sorted incorrectly. https://github.com/JabRef/jabref/issues/2828 - We fixed an issue where commands followed by `-` didn't work. [#3805](https://github.com/JabRef/jabref/issues/3805) - We fixed an issue where a non-existing aux file in a group made it impossible to open the library. [#4735](https://github.com/JabRef/jabref/issues/4735) From 8ba046c048509e1d8047c3edb3a0287bc3f5c0cc Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Sun, 6 Oct 2019 22:28:35 +0200 Subject: [PATCH 32/40] Fix JabFox integration With the new jpackage build JabFox stopped working because the registry values were not specified correctly. This fixes #4303 and fixes #4737. Moreover, the correct icon is now displayed in the installer. --- CHANGELOG.md | 1 + build.gradle | 17 +++++++++++- buildres/JabRef-post-image.wsf | 35 ++++++++++++++++++++++++ buildres/{JabRef.bat => JabRefHost.bat} | 2 +- buildres/{JabRef.ps1 => JabRefHost.ps1} | 15 +++++----- buildres/JabRefTopBanner.bmp | Bin 0 -> 85894 bytes buildres/jabref.json | 2 +- 7 files changed, 61 insertions(+), 11 deletions(-) create mode 100644 buildres/JabRef-post-image.wsf rename buildres/{JabRef.bat => JabRefHost.bat} (60%) rename buildres/{JabRef.ps1 => JabRefHost.ps1} (72%) create mode 100644 buildres/JabRefTopBanner.bmp diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a4e50fdea6..5da79394ebc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `# - We fixed an issue where it was no longer possible to connect to LibreOffice. [#5261](https://github.com/JabRef/jabref/issues/5261) - The "All entries group" is no longer shown when no library is open. - We fixed an exception which occurred when closing JabRef. [#5348](https://github.com/JabRef/jabref/issues/5348) +- We fixed a few problems that prevented JabFox to communicate with JabRef. [#4737](https://github.com/JabRef/jabref/issues/4737) [#4303](https://github.com/JabRef/jabref/issues/4303) - We fixed an error where the groups containing an entry loose their highlight color when scrolling. [#5022](https://github.com/JabRef/jabref/issues/5022) - After assigning an entry to a group, the item count is now properly colored to reflect the new membership of the entry. [#3112](https://github.com/JabRef/jabref/issues/3112) - The group panel is now properly updated when switching between libraries (or when closing/opening one). [#3142](https://github.com/JabRef/jabref/issues/3142) diff --git a/build.gradle b/build.gradle index b3d7851f76a..6ee658af349 100644 --- a/build.gradle +++ b/build.gradle @@ -514,6 +514,11 @@ task generateFinalJabRefPS1File(type: Copy) { filter(org.apache.tools.ant.filters.ReplaceTokens, tokens: [jabRefJarFileName: jar.archiveName]) } +task deleteInstallerTemp(type: Delete) { + delete "$buildDir/installer" +} + +jpackage.dependsOn deleteInstallerTemp jlink { options = ['--strip-debug', '--compress', '2', '--no-header-files', '--no-man-pages'] launcher { @@ -584,7 +589,9 @@ jlink { '--app-version', "${project.version}", '--win-upgrade-uuid', 'd636b4ee-6f10-451e-bf57-c89656780e36', '--win-dir-chooser', - '--win-shortcut' + '--win-shortcut', + '--temp', "$buildDir/installer", + '--resource-dir', "${projectDir}/buildres" ] } @@ -609,6 +616,14 @@ jlink { } } } +tasks.jpackageImage.doLast { + copy { + from("/buildres/") { + include "jabref.json", "JabRefHost.bat", "JabRefHost.ps1" + } + into "$buildDir/distribution/JabRef" + } +} jmh { warmupIterations = 5 diff --git a/buildres/JabRef-post-image.wsf b/buildres/JabRef-post-image.wsf new file mode 100644 index 00000000000..56ddd9097f4 --- /dev/null +++ b/buildres/JabRef-post-image.wsf @@ -0,0 +1,35 @@ + + + + + + diff --git a/buildres/JabRef.bat b/buildres/JabRefHost.bat similarity index 60% rename from buildres/JabRef.bat rename to buildres/JabRefHost.bat index 7a2cee363b0..d44d94f282c 100644 --- a/buildres/JabRef.bat +++ b/buildres/JabRefHost.bat @@ -1,3 +1,3 @@ @echo off pushd %~dp0 -@powershell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -NoProfile -WindowStyle Hidden -File ".\JabRef.ps1" +@powershell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -NoProfile -WindowStyle Hidden -File ".\JabRefHost.ps1" diff --git a/buildres/JabRef.ps1 b/buildres/JabRefHost.ps1 similarity index 72% rename from buildres/JabRef.ps1 rename to buildres/JabRefHost.ps1 index fe814e6013e..f31df86f74e 100644 --- a/buildres/JabRef.ps1 +++ b/buildres/JabRefHost.ps1 @@ -11,8 +11,7 @@ function Respond($response) { } } -$jabRefJarFileName = "@jabRefJarFileName@" -$jabRefJar = [System.IO.Path]::Combine($PSScriptRoot, $jabRefJarFileName) +$jabRefExe = [System.IO.Path]::Combine($PSScriptRoot, "JabRef.exe") try { $reader = New-Object System.IO.BinaryReader([System.Console]::OpenStandardInput()) @@ -21,16 +20,16 @@ try { $message = $messageRaw | ConvertFrom-Json if ($message.Status -eq "validate") { - if (-not (Test-Path $jabRefJar)) { - return Respond @{message="jarNotFound";path=$jabRefJar} + if (-not (Test-Path $jabRefExe)) { + return Respond @{message="jarNotFound";path=$jabRefExe} } else { return Respond @{message="jarFound"} } } - - if (-not (Test-Path $jabRefJar)) { + + if (-not (Test-Path $jabRefExe)) { $wshell = New-Object -ComObject Wscript.Shell - $popup = "Unable to locate '$jabRefJarFileName' in '$([System.IO.Path]::GetDirectoryName($jabRefJar))'." + $popup = "Unable to locate '$jabRefExe'." $wshell.Popup($popup,0,"JabRef", 0x0 + 0x30) return } @@ -39,7 +38,7 @@ try { #$wshell.Popup($message.Text,0,"JabRef", 0x0 + 0x30) $messageText = $message.Text - $output = & java -jar $jabRefJar -importBibtex "$messageText" 2>&1 + $output = & $jabRefExe -importBibtex "$messageText" 2>&1 #$output = & echoargs -importBibtex $messageText 2>&1 #$wshell.Popup($output,0,"JabRef", 0x0 + 0x30) return Respond @{message="ok";output="$output"} diff --git a/buildres/JabRefTopBanner.bmp b/buildres/JabRefTopBanner.bmp new file mode 100644 index 0000000000000000000000000000000000000000..7e95c3b8fd763ce3cdc4b35620daf7902dcd8df4 GIT binary patch literal 85894 zcmeI5S65V77RT)`FwgT5<`c}rJkI;9wu5$38w{W#X2hIR8;OGCjDmm)hy+1`0-}KA zoHGaMA7p{nFiYh9dO3-EgDo^$X0QR{y<`|R-V|6Kk0s||+NKl%O#-#Y&L zFaG^%!{7O7d=>m{!v@3mAFq${5&}X%2nd1oOkl%$zIeHIAs_^VfDrg7IxZgqAs_^V z!1^X2I=;Ste{%IgKnPeM@L_SWy{i1-l@mdScV+~6*B9jvcC=29kFo!wUTJqU zy%y)^#&v^jm8Ch6fuYBChq^geyi8X-o#?nCKp8Fsgn)Jld{|uQtf`2*dgAV{U-RX= z`=|J8rwWr|o6Ft|_jb)rPc1GieEev4LI1#Y%*{>=4|Ud7zDr9=x_!~lWy@WMja*WQ zn^RR@rXoSnaYcYKTnGpO?GivgyXvaqub(pNxbdgw_HToaI3;^sdz1VKyLfbzD)3)EA985ZW}knjH1rt16`xiP^B zH_iqea4?s~SH)rNIx=_r|YuXMwzPG-(VAZEH z4ip_%1SrFWfDq6w0dyQ)e&TV(q?;>kcsPE8d5)?gzWH(CjU}&jT^)<_^ETcae)h4! z{+9BR;-_&bKEFkr+VAhO)pPrwTqw()I^v{jo%{Q z-}6*hcJfbmMxNT=Tw1IMT6A0ypbQrRLO{C&^dCM9w6~=C-uP5NE$_kK;O=pifeW0cMts+6uaYcYK zTnGpO?Giw3(cd(`+a}%otPRwhFV7v{`S05rdHTT1s6b|8&T-w)+h<7+E*=Xw;OM<; z6UThkwB`p#ojufERi;Q#bX*aj3>N}IK)VFc+@Y?H=K&t((z(iQhmGMU_BE9jEiTOW zwKhKWys9GKrfa|z(@|ZaNKkZK5ugkg0zyE$1PB2f?&&6z)1;d!8=>xd8s5G}$9r2? zJH4zjm1%73g`-{d)rtf~#}xs}a3LTBv`YXTAL;MO3cY92O_dFM=s3=qp2j*wf}-P! z0A;uk5CYmIfR2w1^ks+ptH`%$tX*{cl6zlEqas1kaYcYKTnGpOEfdg>4-Mu-1)8*2 zWy2mi{_yf~(moXlijFG+l;J`^2xypqUQczZ+}IEm`8JKUhmKRXix?P1f}-P!0A;uk z5CR$|pw~~14Cg%zGikBPhFx_0`e|KHry@boaYcYKTnGpO?GnI0J~cM_Ix(6oO+%87 zLZCMffHl`~E{QS#)aOzpC_1hPP=*TuA)sjjlpgG;sdy3Q7kkm|zU!|(PMfJ)yE;K% z6CF1s7H$95chApc48)Fz-QF z!i{s(!=fsdLC}}_OW62RQO8N#r!5f+o7oZftMXn@z-vM`NPh|bXiy|5I<5#%h6@29 zuucdd=nD(fmBo+I^8PJdfgazvM7cq#V%b<1Wi>kPu+iJ;hfufO^p+#7pL({#ecdyY z-h^d-As_^_O8{>*-F#xsAGPWqr_Olly_;keaWgEI zmZT)GKx$d~dH4SQUz=$6qa2Z9nV{&nWj^w*5D)@iGJ%D;x!S^9!U3%+vcK!LqQ?*C zrl-I`uwY$b9!)r{j^go9lA1v8H@iX<9k(l9nOq160ZkLob$6!Sze{MKWktrRLc@oy zx=I3FxF3GfE-uag4o14=fxP?h%5j!biI1@#2+?u-v6Y#HfDq6$0o>eglH-?*aVw44 z2p`M}^(A)DbU&o~m!>}rb#u0=^F^F^9|AQHAgBF3IQRYbpph3kM#GJ zWh6(Oa<#f#iEo6%aHQabG2Iy9=k)P;eD{*o1yY3G-(^dFT=+ZIAZ%HkZ92Ii562&+S&i4e_X;!nrZQ=ss@l`Pms3EfI7a<>R`+ch4V( zA9u03Mv9bE27s2H^~L#v9W66clWU7fbbM`j%4|YF2xyFeUQc)ly&77|ORDp-sC}61 zbv?{|57kc4Xscck@15T#-8xT9%jB>Q^&jc$!8txXF^(}#EcsAZ`^)H{fc*}(Ooinh z;^s_&Lt+-ovz|4+E$ptZ!B<0WsUkAbaYcYKTnGpOO%tG|N@s0Vitml^lluY>Zb!Z; zc4&+2BJrM%-$b5tZ7g{`J2_Ebluyw_V~yFFiLr|8wBo06G>z+Ns7>{~<>UOL)kgvc za9+OfnBRBZMv73v&2yExnZ_6x6^NqaD)eNm5D)@dCon%d+fZB(ablk>I%|Fm-jeX+ zd#my?Sq^QlDtqd6EhjQyYIKAfo}ZaU$Fb8ZveStur+iAnjk8q5H6L!vHimrBlZUgD zs%{q1ajky}<@$tx5Ktk2FB^lJV&Aq1tLYd|$8SjvqCDZ;)D-2*N%+JiQd5w8 zkwUobRppdRqzG+QZYIta{+r@+dZltMqA#%m*Ttor^mN1;QmHoTgpljZ=LtqwV74Q;odIOtx{rz5EO(s`s|^y z%oO}B1c_60CFsx&{NNrA-&j72@m>5pC8>$xS20nQ4Iv-|gupTcs21B?R!kO;Rbj=E zLYtlkmyQ+0MG)>i+|%_oEeS)Oz{JSY`|*z(gH?>@Ant`ihEF`M;BXH;wi`|FX{^OC zN7Iw;Ttv;icWt)ng-6GUc$u9RzsfSdIN2oxgn$tEod7ycq)P0CqZV|W=tByj;3Pqg zJ8CO&g11$aKJ&Znzi%sk64oS%Fd_OIqkCa~o_PsbnHn1*Sfwm8HS+WUgdUH|Q;#b+ zUTB)!-B5!%Kk>L4h??)*WWm!y3Q~DyirC}wVHE;GKnPeOK*CPz`*&E`%jh`GdUkC_ zZR4+Uj2SzL^sgU`X=QOy6@p===z4aO|lPV$2)5)@y`&#$jR{4AlA*L#a(q( zhPcCnjyO^<=Ltc1856{jL=*Nl)!{QC$`EUvbkJpO^WY=9-e;$&S6>nTxTQ~kye9;N zz^TPiBVrkX}#W6l`r>cSl`e?lb?}fd?Ip2Yc<@M6FtO zVxD7?*A?X%HJ4|Dp^;F0L`^{s4~g_Z5C47Jj6QKcmtPWZUBJ82*V;HfG|m37LXJ8Sjc$G!AxE7nUuMippXK%bA(QJD0z$y91ZdwwzzLGg^5gye4lH=mXE`(2 zr!?a!`;l(~2kGxqo&O>u$SeGWizz<{t&h8Mf>;+yVv)~D$O>sY#+;oG)XC~-%?k5- z9^lbdS;kr@P8d8hMkzPs`y6$8=6B2Rgs873?UOFgbXBf=nNH;5le?EO_JfZ)864~G zdpIwVk%|Pw9#;e?!-aql&@=%G4H9QUx(%wzS|!et!S)t})tF@8+gwjNPvXsUxT;MG zj>(M6JO1j)&e{qVJaMyxpV*fj?r$tUZoFISWRa7JLx$uayer)ewe;cibJ_BT{{)ZC zCYCW1emj#J9fDhi&=;0T@x0Tvf@z6ptjK;|{^D7GTQh$#C=wJMR|F`-g@6#yGyytA z;08fMacZOKEK%}>jyIJSQDOzt*xzNVp~}jibM#rITyl)`7beDpxH&z%?A}^YYF_1v zNifN=$MJEe2YRC8r2c0|1R&)m&k34th=Fnbku0P%|JyaMaz^^P^|V^Xo;UP)p5s}< zPxUSnqT`zW2+G9?0U@wf1W?bh!GY?6Y&;&+S3z)>DU#)|k%CsNPm;rlcRM}ElYkSv zF{SCr^K*aoei*w+M4vs3Qe)9~*1X3^Zzz5hMFh*z8mURp*)Rq*1|Qz}==vF=S@7hT zKNS@3QFL4ppbQrRLSTImKxE%Ne?s)gUrcYK+8SdApWMBKBOA%?Z)=LXdIE#`-kzT_ zLcEu)9*(6?Hc)YLJYIF=o)GoAqWlTnAPGcR`nbrcqwAH52ZEK2;Y?t7PE;TnnEma|)E4iquP#iAi9UCPs6o8j z5hq>A48pRu@t!fjiHCV`+1S3beRuRboLO=+72?S=RrkYBNbD{!X#sm}dXAB-kf4l0c@wYs_bJ5>*>s`lh z$ifZeW%5bwV_)KFhOG z@z;OW{1y%t9k&2S-Vy>r;L9PP|FDR3j`a7Sss#Ma&CF2fih?SSemfg@XgfwU?v&UI zZUym?#Dg13VtxLLAVQ)Ki8rUDZNLFX)ZE{7+k=bl&}`A_Rs{5XhPK+ zHe?0#u7F%}Az96`m0KZLVQf zju9Kr1LmBWm>BG6Yb<$%Q=V>cb|NY|ZYQuZtq>3bnkKNMvkM0KRyV*c-zb7^NW)(X nOMitEiH@%TMs^DUAs__S2?5dZb@Gdn%M=1aKnScrV8ed_Z^w(k literal 0 HcmV?d00001 diff --git a/buildres/jabref.json b/buildres/jabref.json index dee50f008fe..9024c5b17f4 100644 --- a/buildres/jabref.json +++ b/buildres/jabref.json @@ -1,7 +1,7 @@ { "name": "org.jabref.jabref", "description": "JabRef", - "path": "JabRef.bat", + "path": "JabRefHost.bat", "type": "stdio", "allowed_extensions": [ "@jabfox" From a6948ea0de5c8f13da452a5f029129952cc99ca3 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Sun, 6 Oct 2019 22:32:47 +0200 Subject: [PATCH 33/40] Remove unnecessary code --- build.gradle | 8 -------- 1 file changed, 8 deletions(-) diff --git a/build.gradle b/build.gradle index 6ee658af349..7192e613482 100644 --- a/build.gradle +++ b/build.gradle @@ -506,14 +506,6 @@ modernizer { } // Release tasks -task generateFinalJabRefPS1File(type: Copy) { - from('buildres') { - include 'JabRef.ps1' - } - into 'build' - filter(org.apache.tools.ant.filters.ReplaceTokens, tokens: [jabRefJarFileName: jar.archiveName]) -} - task deleteInstallerTemp(type: Delete) { delete "$buildDir/installer" } From ef445c55300bde42fb81667f3048b011f645479d Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2019 12:26:57 +0200 Subject: [PATCH 34/40] Bump slf4j-api from 2.0.0-alpha0 to 2.0.0-alpha1 (#5403) * Bump slf4j-api from 2.0.0-alpha0 to 2.0.0-alpha1 Bumps [slf4j-api](https://github.com/qos-ch/slf4j) from 2.0.0-alpha0 to 2.0.0-alpha1. - [Release notes](https://github.com/qos-ch/slf4j/releases) - [Commits](https://github.com/qos-ch/slf4j/commits/v_2.0.0-alpha1) Signed-off-by: dependabot-preview[bot] * Pin log4j.plugins --- build.gradle | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index b3d7851f76a..f96d0451254 100644 --- a/build.gradle +++ b/build.gradle @@ -164,9 +164,10 @@ dependencies { compile 'org.jsoup:jsoup:1.12.1' compile 'com.mashape.unirest:unirest-java:1.4.9' - compile 'org.slf4j:slf4j-api:2.0.0-alpha0' + compile 'org.slf4j:slf4j-api:2.0.0-alpha1' compile group: 'org.apache.logging.log4j', name: 'log4j-jcl', version: '3.0.0-20190915.182410-364' compile group: 'org.apache.logging.log4j', name: 'log4j-slf4j18-impl', version: '3.0.0-20190915.182922-250' + compile group: 'org.apache.logging.log4j', name: 'log4j-plugins', version: '3.0.0-20190915.182837-57' implementation group: 'org.apache.logging.log4j', name: 'log4j-api', version: '3.0.0-20190915.182113-372' compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '3.0.0-20190915.182215-368' annotationProcessor group: 'org.apache.logging.log4j', name: 'log4j-core', version: '3.0.0-20190915.182215-368' From 845481a05638d722d8756f7ae20a619790836340 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2019 10:28:58 +0000 Subject: [PATCH 35/40] Bump mockito-core from 3.0.0 to 3.1.0 Bumps [mockito-core](https://github.com/mockito/mockito) from 3.0.0 to 3.1.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v3.0.0...v3.1.0) Signed-off-by: dependabot-preview[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index f96d0451254..d7cc1395d17 100644 --- a/build.gradle +++ b/build.gradle @@ -206,7 +206,7 @@ dependencies { testCompile 'net.bytebuddy:byte-buddy-parent:1.10.1' testRuntime group: 'org.apache.logging.log4j', name: 'log4j-core', version: '3.0.0-20190915.182215-368' testRuntime group: 'org.apache.logging.log4j', name: 'log4j-jul', version: '3.0.0-20190915.182552-364' - testCompile 'org.mockito:mockito-core:3.0.0' + testCompile 'org.mockito:mockito-core:3.1.0' //testCompile 'com.github.tomakehurst:wiremock:2.24.1' testCompile ('org.reflections:reflections:0.9.11') { exclude module: "jsr305" From 33755c23c579d7bab34db2e4d18730e5eacbff0b Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2019 10:29:13 +0000 Subject: [PATCH 36/40] Bump mariadb-java-client from 2.4.4 to 2.5.0 Bumps [mariadb-java-client](https://github.com/MariaDB/mariadb-connector-j) from 2.4.4 to 2.5.0. - [Release notes](https://github.com/MariaDB/mariadb-connector-j/releases) - [Commits](https://github.com/MariaDB/mariadb-connector-j/compare/2.4.4...2.5.0) Signed-off-by: dependabot-preview[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index f96d0451254..ab774f3b820 100644 --- a/build.gradle +++ b/build.gradle @@ -138,7 +138,7 @@ dependencies { antlr4 'org.antlr:antlr4:4.7.2' compile 'org.antlr:antlr4-runtime:4.7.2' - compile group: 'org.mariadb.jdbc', name: 'mariadb-java-client', version: '2.4.4' + compile group: 'org.mariadb.jdbc', name: 'mariadb-java-client', version: '2.5.0' compile 'org.postgresql:postgresql:42.2.8' From 7c5597caebef018efbbd188b8c8e33d76dde2381 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2019 10:51:24 +0000 Subject: [PATCH 37/40] Bump src/main/resources/csl-styles from `36ac1f6` to `6169061` Bumps [src/main/resources/csl-styles](https://github.com/citation-style-language/styles) from `36ac1f6` to `6169061`. - [Release notes](https://github.com/citation-style-language/styles/releases) - [Commits](https://github.com/citation-style-language/styles/compare/36ac1f63004b1b85c8aed51f7111a8bed3fb7208...6169061a140068e897337de95f917008037fcd3b) Signed-off-by: dependabot-preview[bot] --- src/main/resources/csl-styles | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/csl-styles b/src/main/resources/csl-styles index 36ac1f63004..6169061a140 160000 --- a/src/main/resources/csl-styles +++ b/src/main/resources/csl-styles @@ -1 +1 @@ -Subproject commit 36ac1f63004b1b85c8aed51f7111a8bed3fb7208 +Subproject commit 6169061a140068e897337de95f917008037fcd3b From 9af26e9645799dda3c4922ea653ad0d921f3fec5 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2019 10:51:40 +0000 Subject: [PATCH 38/40] Bump src/main/resources/csl-locales from `e89e6b0` to `9785a6e` Bumps [src/main/resources/csl-locales](https://github.com/citation-style-language/locales) from `e89e6b0` to `9785a6e`. - [Release notes](https://github.com/citation-style-language/locales/releases) - [Commits](https://github.com/citation-style-language/locales/compare/e89e6b08b5c621a414fc7114f2129efac5f8c7d5...9785a6e3584e8c903df3d5a53f0e800dcabd282b) Signed-off-by: dependabot-preview[bot] --- src/main/resources/csl-locales | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/csl-locales b/src/main/resources/csl-locales index e89e6b08b5c..9785a6e3584 160000 --- a/src/main/resources/csl-locales +++ b/src/main/resources/csl-locales @@ -1 +1 @@ -Subproject commit e89e6b08b5c621a414fc7114f2129efac5f8c7d5 +Subproject commit 9785a6e3584e8c903df3d5a53f0e800dcabd282b From 1c3802edd9c8d84905f5374810013f1305dc44f3 Mon Sep 17 00:00:00 2001 From: Galileo Sartor Date: Mon, 7 Oct 2019 16:19:27 +0200 Subject: [PATCH 39/40] Snap GitHub ci (#5379) * Build snap from java package * add snap to github ci * Use docker snapcraft * Add container to ubuntu matrix item * move snap workflow to matrix * add matrix to snapbuild * add transfer.sh link * Use tar from build/distribution * Add stable snapcraft * Remove explicit container * Attempt at a github actions integration * Try to make it work... * Try to fix ? * Build without docker * Build with latest docker * Add docker image based on bionic * Temporarily revert to version-script * Uncomment upload to builds.jabref * Make sure to move only jabref snap to build folder * Update and rename deployment.yml to snap-deployment.yml Modify to push again * Update and rename snap-deployment.yml to deployment.yml * Reenable checks for PRs * Temporarily disable master branch check to test * I'm tired... * Fix branch name detection for PRs * Try to fix branch name detection * Update deployment.yml * Update deployment.yml * Remove on PR --- .github/workflows/deployment.yml | 18 +- snap/plugins/x_gradle.py | 301 ------------------------------- snap/snapcraft.yaml | 51 ++---- 3 files changed, 26 insertions(+), 344 deletions(-) delete mode 100644 snap/plugins/x_gradle.py diff --git a/.github/workflows/deployment.yml b/.github/workflows/deployment.yml index bec5380f3d1..49eae5fb82f 100644 --- a/.github/workflows/deployment.yml +++ b/.github/workflows/deployment.yml @@ -34,6 +34,14 @@ jobs: with: depth: 1 submodules: true + - name: Extract branch name + shell: bash + run: | + ref=${GITHUB_REF#refs/heads/} + ref=${ref#refs/pull/} + ref=${ref%/merge} + echo "##[set-output name=branch;]${ref}" + id: extract_branch - name: Set up JDK uses: actions/setup-java@v1 with: @@ -75,10 +83,14 @@ jobs: - name: Package application image run: ${{ matrix.archivePortable }} shell: bash - - name: Extract branch name + - name: Build and publish snap + if: matrix.os == 'ubuntu-latest' && steps.extract_branch.outputs.branch == 'master' + env: + SNAPCRAFT_LOGIN_FILE: ${{ secrets.SNAPCRAFT_LOGIN_FILE }} + run: | + docker run -v $(pwd):$(pwd) -t lyzardking/snapcraft-bionic sh -c "apt update -qq && cd $(pwd) && snapcraft && mv jabref*.snap build/distribution/" + # cd build/distribution/ && mdkir .snapcraft && echo ${SNAPCRAFT_LOGIN_FILE} | base64 --decode --ignore-garbage > .snapcraft/snapcraft.cfg && snapcraft push --release=beta *.snap shell: bash - run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})" - id: extract_branch - name: Upload to builds.jabref.org uses: garygrossgarten/github-action-scp@release with: diff --git a/snap/plugins/x_gradle.py b/snap/plugins/x_gradle.py deleted file mode 100644 index 899d6567712..00000000000 --- a/snap/plugins/x_gradle.py +++ /dev/null @@ -1,301 +0,0 @@ -# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*- -# -# Copyright (C) 2016, 2018 Canonical Ltd -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 3 as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -"""This plugin is useful for building parts that use gradle. - -The gradle build system is commonly used to build Java projects. -The plugin requires a pom.xml in the root of the source tree. - -This plugin uses the common plugin keywords as well as those for "sources". -For more information check the 'plugins' topic for the former and the -'sources' topic for the latter. - -Additionally, this plugin uses the following plugin-specific keywords: - - - gradle-options: - (list of strings) - Flags to pass to the build using the gradle semantics for parameters. - The 'jar' option is always passed in as the last parameter. - - - gradle-output-dir: - (string; default: 'build/libs') - The output directory where the resulting jar or war files from gradle[w] - are generated. - - - gradle-version: - (string) - The version of gradle you want to use to build the source artifacts. - Defaults to the current release downloadable from - https://services.gradle.org/distributions/ - The entry is ignored if gradlew is found. - - - gradle-version-checksum: - (string) - The checksum for gradle-version in the form of /. - As an example "sha512/2a803f578f341e164f6753e410413d16ab60fab...". - - - gradle-openjdk-version: - (string) - openjdk version available to the base to use. If not set the latest - version available to the base will be used. -""" - -import logging -import os -import urllib.parse -from glob import glob -from typing import Sequence - -import snapcraft -from snapcraft import file_utils, formatting_utils -from snapcraft.internal import errors, sources - -logger = logging.getLogger(__name__) - - -_DEFAULT_GRADLE_VERSION = "4.10.2" -_DEFAULT_GRADLE_CHECKSUM = ( - "sha256/b49c6da1b2cb67a0caf6c7480630b51c70a11ca2016ff2f555eaeda863143a29" -) -_GRADLE_URL = "https://services.gradle.org/distributions/gradle-{version}-bin.zip" - - -class UnsupportedJDKVersionError(errors.SnapcraftError): - - fmt = ( - "The gradle-openjdk-version plugin property was set to {version!r}.\n" - "Valid values for the {base!r} base are: {valid_versions}." - ) - - def __init__( - self, *, base: str, version: str, valid_versions: Sequence[str] - ) -> None: - super().__init__( - base=base, - version=version, - valid_versions=formatting_utils.humanize_list( - valid_versions, conjunction="or" - ), - ) - - -class GradlePlugin(snapcraft.BasePlugin): - @classmethod - def schema(cls): - schema = super().schema() - schema["properties"]["gradle-options"] = { - "type": "array", - "minitems": 1, - "uniqueItems": True, - "items": {"type": "string"}, - "default": [], - } - schema["properties"]["gradle-output-dir"] = { - "type": "string", - "default": "build/libs", - } - - schema["properties"]["gradle-version"] = {"type": "string"} - - schema["properties"]["gradle-version-checksum"] = {"type": "string"} - - schema["properties"]["gradle-openjdk-version"] = { - "type": "string", - "default": "", - } - - schema["required"] = ["source"] - - return schema - - @classmethod - def get_pull_properties(cls): - # Inform Snapcraft of the properties associated with pulling. If these - # change in the YAML Snapcraft will consider the pull step dirty. - return ["gradle-version", "gradle-version-checksum", "gradle-openjdk-version"] - - @classmethod - def get_build_properties(cls): - # Inform Snapcraft of the properties associated with building. If these - # change in the YAML Snapcraft will consider the build step dirty. - return super().get_build_properties() + ["gradle-options", "gradle-output-dir"] - - @property - def _gradle_tar(self): - if self._gradle_tar_handle is None: - gradle_uri = _GRADLE_URL.format(version=self._gradle_version) - self._gradle_tar_handle = sources.Zip( - gradle_uri, self._gradle_dir, source_checksum=self._gradle_checksum - ) - return self._gradle_tar_handle - - def __init__(self, name, options, project): - super().__init__(name, options, project) - - self._setup_gradle() - self._setup_base_tools(project.info.get_build_base()) - - def _setup_base_tools(self, base): - if base not in ("core", "core16", "core18"): - raise errors.PluginBaseError( - part_name=self.name, base=self.project.info.get_build_base() - ) - - if base in ("core", "core16"): - valid_versions = ["8", "9"] - elif base == "core18": - valid_versions = ["8", "11"] - - version = self.options.gradle_openjdk_version - if not version: - version = valid_versions[-1] - elif version not in valid_versions: - raise UnsupportedJDKVersionError( - version=version, base=base, valid_versions=valid_versions - ) - - self.stage_packages.append("openjdk-{}-jre-headless".format(version)) - self.build_packages.append("openjdk-{}-jdk-headless".format(version)) - self.build_packages.append("ca-certificates-java") - self._java_version = version - - def _using_gradlew(self) -> bool: - return os.path.isfile(os.path.join(self.sourcedir, "gradlew")) - - def _setup_gradle(self): - self._gradle_tar_handle = None - self._gradle_dir = os.path.join(self.partdir, "gradle") - if self.options.gradle_version: - self._gradle_version = self.options.gradle_version - self._gradle_checksum = self.options.gradle_version_checksum - else: - self._gradle_version = _DEFAULT_GRADLE_VERSION - self._gradle_checksum = _DEFAULT_GRADLE_CHECKSUM - - def pull(self): - super().pull() - - if self._using_gradlew(): - logger.info("Found gradlew, skipping gradle setup.") - return - - os.makedirs(self._gradle_dir, exist_ok=True) - self._gradle_tar.download() - - def build(self): - super().build() - - if self._using_gradlew(): - gradle_cmd = ["./gradlew"] - else: - self._gradle_tar.provision(self._gradle_dir, keep_zip=True) - gradle_cmd = ["gradle"] - self.run( - gradle_cmd - + self._get_proxy_options() - + self.options.gradle_options, - rootdir=self.builddir, - ) - - src = os.path.join(self.builddir, self.options.gradle_output_dir) - basedir = "jabref" - # jarfiles = glob(os.path.join(src, "*.jar")) - # warfiles = glob(os.path.join(src, "*.war")) - - # if len(jarfiles) > 0: - # basedir = "jar" - # elif len(warfiles) > 0: - # basedir = "war" - # jarfiles = warfiles - # else: - # raise RuntimeError("Could not find any built jar files for part") - - file_utils.link_or_copy_tree( - src, - os.path.join(self.installdir, basedir), - copy_function=lambda src, dst: file_utils.link_or_copy( - src, dst, self.installdir - ), - ) - - self._create_symlinks() - - def _create_symlinks(self): - if self.project.info.get_build_base() not in ("core18", "core16", "core"): - raise errors.PluginBaseError( - part_name=self.name, base=self.project.info.get_build_base() - ) - - os.makedirs(os.path.join(self.installdir, "bin"), exist_ok=True) - java_bin = glob( - os.path.join( - self.installdir, - "usr", - "lib", - "jvm", - "java-{}-openjdk-*".format(self._java_version), - "bin", - "java", - ) - )[0] - os.symlink( - os.path.relpath(java_bin, os.path.join(self.installdir, "bin")), - os.path.join(self.installdir, "bin", "java"), - ) - - def run(self, cmd, rootdir): - super().run(cmd, cwd=rootdir, env=self._build_environment()) - - def _build_environment(self): - if self._using_gradlew(): - return - - env = os.environ.copy() - gradle_bin = os.path.join( - self._gradle_dir, "gradle-{}".format(self._gradle_version), "bin" - ) - print(gradle_bin) - - if env.get("PATH"): - new_path = "{}:{}".format(gradle_bin, env.get("PATH")) - else: - new_path = gradle_bin - - env["PATH"] = new_path - return env - - def _get_proxy_options(self): - proxy_options = [] - for var in ("http", "https"): - proxy = os.environ.get("{}_proxy".format(var), False) - if proxy: - parsed_url = urllib.parse.urlparse(proxy) - proxy_options.append( - "-D{}.proxyHost={}".format(var, parsed_url.hostname) - ) - if parsed_url.port: - proxy_options.append( - "-D{}.proxyPort={}".format(var, parsed_url.port) - ) - if parsed_url.username: - proxy_options.append( - "-D{}.proxyUser={}".format(var, parsed_url.username) - ) - if parsed_url.password: - proxy_options.append( - "-D{}.proxyPassword={}".format(var, parsed_url.password) - ) - return proxy_options diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index b62d2d571e3..a60eadd2d4d 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -1,7 +1,9 @@ name: jabref -version: "git" +# adopt-info: jabref +version: 'master' version-script: cat build.gradle | grep "^version =" | cut -d'"' -f2 -#icon: snap/gui/jabref.png +icon: snap/gui/jabref.png +license: MIT summary: Bibliography manager description: JabRef is an open source bibliography reference manager. The native file format used by JabRef is BibTeX, the standard LaTeX bibliography format. @@ -14,11 +16,10 @@ architectures: apps: jabref: - command: desktop-launch $SNAP/jabref/bin/JabRefMain + command: bin/JabRef + extensions: [gnome-3-28] environment: _JAVA_OPTIONS: "-Duser.home=$SNAP_USER_DATA" - XDG_DATA_DIRS: $SNAP/share:$XDG_DATA_DIRS - GSETTINGS_SCHEMA_DIR: $SNAP/share/glib-2.0/schemas plugs: - desktop - desktop-legacy @@ -28,43 +29,13 @@ apps: - opengl - network-bind - removable-media - - gnome-3-28-1804 - -plugs: - gnome-3-28-1804: - interface: content - target: gnome-platform - default-provider: gnome-3-28-1804:gnome-3-28-1804 - content: gnome-3-28-1804 - gtk-3-themes: - interface: content - target: $SNAP/data-dir/themes - default-provider: gtk-common-themes:gtk-3-themes - icon-themes: - interface: content - target: $SNAP/data-dir/icons - default-provider: gtk-common-themes:icon-themes - parts: jabref: - plugin: x_gradle - source: . - source-type: git + plugin: dump + source: build/distribution/JabRef-portable_linux.tar.gz + # override-pull: | + # snapcraftctl pull + # snapcraftctl set-version "$(cat app/JabRef.cfg | grep "app.version=" | cut -d'=' -f2)" stage-packages: - - openjdk-11-jre - - openjfx - x11-utils - gradle-options: [jlink, -xtest] - gradle-output-dir: 'build/image' - desktop-gnome-platform: - source: https://github.com/ubuntu/snapcraft-desktop-helpers.git - source-subdir: gtk - plugin: make - make-parameters: ["FLAVOR=gtk3"] - build-packages: - - build-essential - - libgtk-3-dev - override-build: | - snapcraftctl build - mkdir -pv $SNAPCRAFT_PART_INSTALL/gnome-platform From facda00c148954b0ba32d859976fb0d72ce9cac6 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 7 Oct 2019 20:46:22 +0200 Subject: [PATCH 40/40] Add test for regular expression pattern --- .../logic/util/BracketedPatternTest.java | 73 ++++++++++--------- 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/src/test/java/org/jabref/logic/util/BracketedPatternTest.java b/src/test/java/org/jabref/logic/util/BracketedPatternTest.java index 5e2cd0511e9..41bfbad9622 100644 --- a/src/test/java/org/jabref/logic/util/BracketedPatternTest.java +++ b/src/test/java/org/jabref/logic/util/BracketedPatternTest.java @@ -14,14 +14,14 @@ import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertThrows; -public class BracketedPatternTest { +class BracketedPatternTest { private BibEntry bibentry; private BibDatabase database; private BibEntry dbentry; @BeforeEach - public void setUp() throws Exception { + void setUp() throws Exception { bibentry = new BibEntry(); bibentry.setField(StandardField.AUTHOR, "O. Kitsune"); bibentry.setField(StandardField.YEAR, "2017"); @@ -47,27 +47,27 @@ public void setUp() throws Exception { } @Test - public void bibentryExpansionTest() { + void bibentryExpansionTest() { BracketedPattern pattern = new BracketedPattern("[year]_[auth]_[firstpage]"); assertEquals("2017_Kitsune_213", pattern.expand(bibentry)); } @Test - public void nullDatabaseExpansionTest() { + void nullDatabaseExpansionTest() { BibDatabase another_database = null; BracketedPattern pattern = new BracketedPattern("[year]_[auth]_[firstpage]"); assertEquals("2017_Kitsune_213", pattern.expand(bibentry, another_database)); } @Test - public void pureauthReturnsAuthorIfEditorIsAbsent() { + void pureauthReturnsAuthorIfEditorIsAbsent() { BibDatabase emptyDatabase = new BibDatabase(); BracketedPattern pattern = new BracketedPattern("[pureauth]"); assertEquals("Kitsune", pattern.expand(bibentry, emptyDatabase)); } @Test - public void pureauthReturnsAuthorIfEditorIsPresent() { + void pureauthReturnsAuthorIfEditorIsPresent() { BibDatabase emptyDatabase = new BibDatabase(); BracketedPattern pattern = new BracketedPattern("[pureauth]"); bibentry.setField(StandardField.EDITOR, "Editorlastname, Editorfirstname"); @@ -75,7 +75,7 @@ public void pureauthReturnsAuthorIfEditorIsPresent() { } @Test - public void pureauthReturnsEmptyStringIfAuthorIsAbsent() { + void pureauthReturnsEmptyStringIfAuthorIsAbsent() { BibDatabase emptyDatabase = new BibDatabase(); BracketedPattern pattern = new BracketedPattern("[pureauth]"); bibentry.clearField(StandardField.AUTHOR); @@ -83,7 +83,7 @@ public void pureauthReturnsEmptyStringIfAuthorIsAbsent() { } @Test - public void pureauthReturnsEmptyStringIfAuthorIsAbsentAndEditorIsPresent() { + void pureauthReturnsEmptyStringIfAuthorIsAbsentAndEditorIsPresent() { BibDatabase emptyDatabase = new BibDatabase(); BracketedPattern pattern = new BracketedPattern("[pureauth]"); bibentry.clearField(StandardField.AUTHOR); @@ -92,14 +92,14 @@ public void pureauthReturnsEmptyStringIfAuthorIsAbsentAndEditorIsPresent() { } @Test - public void emptyDatabaseExpansionTest() { + void emptyDatabaseExpansionTest() { BibDatabase another_database = new BibDatabase(); BracketedPattern pattern = new BracketedPattern("[year]_[auth]_[firstpage]"); assertEquals("2017_Kitsune_213", pattern.expand(bibentry, another_database)); } @Test - public void databaseWithStringsExpansionTest() { + void databaseWithStringsExpansionTest() { BibDatabase another_database = new BibDatabase(); BibtexString string = new BibtexString("sgr", "Saulius Gražulis"); another_database.addString(string); @@ -113,31 +113,31 @@ public void databaseWithStringsExpansionTest() { } @Test - public void unbalancedBracketsExpandToSomething() { + void unbalancedBracketsExpandToSomething() { BracketedPattern pattern = new BracketedPattern("[year]_[auth_[firstpage]"); assertNotEquals("", pattern.expand(bibentry)); } @Test - public void unbalancedLastBracketExpandsToSomething() { + void unbalancedLastBracketExpandsToSomething() { BracketedPattern pattern = new BracketedPattern("[year]_[auth]_[firstpage"); assertNotEquals("", pattern.expand(bibentry)); } @Test - public void entryTypeExpansionTest() { + void entryTypeExpansionTest() { BracketedPattern pattern = new BracketedPattern("[entrytype]:[year]_[auth]_[pages]"); assertEquals("Misc:2017_Kitsune_213--216", pattern.expand(bibentry)); } @Test - public void entryTypeExpansionLowercaseTest() { + void entryTypeExpansionLowercaseTest() { BracketedPattern pattern = new BracketedPattern("[entrytype:lower]:[year]_[auth]_[firstpage]"); assertEquals("misc:2017_Kitsune_213", pattern.expand(bibentry)); } @Test - public void suppliedBibentryBracketExpansionTest() { + void suppliedBibentryBracketExpansionTest() { BibDatabase another_database = null; BracketedPattern pattern = new BracketedPattern("[year]_[auth]_[firstpage]"); BibEntry another_bibentry = new BibEntry(); @@ -148,7 +148,7 @@ public void suppliedBibentryBracketExpansionTest() { } @Test - public void nullBibentryBracketExpansionTest() { + void nullBibentryBracketExpansionTest() { BibDatabase another_database = null; BibEntry another_bibentry = null; BracketedPattern pattern = new BracketedPattern("[year]_[auth]_[firstpage]"); @@ -156,58 +156,53 @@ public void nullBibentryBracketExpansionTest() { } @Test - public void bracketedExpressionDefaultConstructorTest() { + void bracketedExpressionDefaultConstructorTest() { BibDatabase another_database = null; BracketedPattern pattern = new BracketedPattern(); assertThrows(NullPointerException.class, () -> pattern.expand(bibentry, ';', another_database)); } @Test - public void unknownKeyExpandsToEmptyString() { - Character separator = ';'; - assertEquals("", BracketedPattern.expandBrackets("[unknownkey]", separator, dbentry, database)); + void unknownKeyExpandsToEmptyString() { + assertEquals("", BracketedPattern.expandBrackets("[unknownkey]", ';', dbentry, database)); } @Test - public void emptyPatternAndEmptyModifierExpandsToEmptyString() { - Character separator = ';'; - assertEquals("", BracketedPattern.expandBrackets("[:]", separator, dbentry, database)); + void emptyPatternAndEmptyModifierExpandsToEmptyString() { + assertEquals("", BracketedPattern.expandBrackets("[:]", ';', dbentry, database)); } @Test - public void emptyPatternAndValidModifierExpandsToEmptyString() { + void emptyPatternAndValidModifierExpandsToEmptyString() { Character separator = ';'; assertEquals("", BracketedPattern.expandBrackets("[:lower]", separator, dbentry, database)); } @Test - public void bibtexkeyPatternExpandsToBibTeXKey() { + void bibtexkeyPatternExpandsToBibTeXKey() { Character separator = ';'; assertEquals("HipKro03", BracketedPattern.expandBrackets("[bibtexkey]", separator, dbentry, database)); } @Test - public void bibtexkeyPatternWithEmptyModifierExpandsToBibTeXKey() { - Character separator = ';'; - assertEquals("HipKro03", BracketedPattern.expandBrackets("[bibtexkey:]", separator, dbentry, database)); + void bibtexkeyPatternWithEmptyModifierExpandsToBibTeXKey() { + assertEquals("HipKro03", BracketedPattern.expandBrackets("[bibtexkey:]", ';', dbentry, database)); } @Test - public void authorPatternTreatsVonNamePrefixCorrectly() { - Character separator = ';'; + void authorPatternTreatsVonNamePrefixCorrectly() { assertEquals("Eric von Hippel and Georg von Krogh", - BracketedPattern.expandBrackets("[author]", separator, dbentry, database)); + BracketedPattern.expandBrackets("[author]", ';', dbentry, database)); } @Test - public void lowerFormatterWorksOnVonNamePrefixes() { - Character separator = ';'; + void lowerFormatterWorksOnVonNamePrefixes() { assertEquals("eric von hippel and georg von krogh", - BracketedPattern.expandBrackets("[author:lower]", separator, dbentry, database)); + BracketedPattern.expandBrackets("[author:lower]", ';', dbentry, database)); } @Test - public void testResolvedFieldAndFormat() { + void testResolvedFieldAndFormat() { BibEntry child = new BibEntry(); child.setField(StandardField.CROSSREF, "HipKro03"); database.insertEntry(child); @@ -232,7 +227,7 @@ public void testResolvedFieldAndFormat() { } @Test - public void testResolvedParentNotInDatabase() { + void testResolvedParentNotInDatabase() { BibEntry child = new BibEntry(); child.setField(StandardField.CROSSREF, "HipKro03"); database.removeEntry(dbentry); @@ -240,4 +235,10 @@ public void testResolvedParentNotInDatabase() { assertEquals("", BracketedPattern.expandBrackets("[author]", ';', child, database)); } + + @Test + void regularExpressionReplace() { + assertEquals("2003-JabRef Science", + BracketedPattern.expandBrackets("[year]-[journal:regex(\"Organization\",\"JabRef\")]", ';', dbentry, database)); + } }