[jabref] 01/11: New upstream version 3.8~pre1+ds
Tony Mancill
tmancill at moszumanska.debian.org
Sun Dec 11 06:39:02 UTC 2016
This is an automated email from the git hooks/post-receive script.
tmancill pushed a commit to branch dev
in repository jabref.
commit b3fd4e62aada2c7c722362c90c8fd27e5711850d
Author: tony mancill <tmancill at debian.org>
Date: Fri Dec 9 20:51:19 2016 -0800
New upstream version 3.8~pre1+ds
---
.editorconfig | 6 +
.gitattributes | 6 +-
.github/PULL_REQUEST_TEMPLATE.md | 1 +
.gitignore | 6 +
.mailmap | 19 +-
.travis.yml | 42 +-
AUTHORS | 7 +-
CHANGELOG.md | 240 +-
CONTRIBUTING.md | 18 +-
DEVELOPERS | 6 +-
README.md | 10 +-
build.gradle | 132 +-
buildres/jabref-cert-2016.p12.enc | Bin 0 -> 5504 bytes
circle.yml | 7 +-
config/checkstyle/checkstyle.xml | 4 +
eclipse.gradle | 8 +-
external-libraries.txt | 44 +-
gradlew | 23 +-
gradlew.bat | 6 -
jabref.install4j | 16 +-
licenses/de.undercouch.citeproc-java.txt | 202 ++
licenses/org.citationstyles.locales.txt | 359 +++
licenses/org.citationstyles.styles.txt | 359 +++
localization.gradle | 36 +-
scripts/.gitignore | 4 +
scripts/README.md | 23 +
scripts/after-failure.sh | 27 +
scripts/junit-xml-format-errors.xsl | 61 +
scripts/logger.py | 29 +
scripts/prepare-install4j.sh | 12 +-
scripts/syncLang.py | 582 ++--
scripts/upload-to-builds.jabref.org.sh | 2 +-
.../net/sf/jabref/shared/DBMSConnectorTest.java | 34 -
.../net/sf/jabref/shared/DBMSProcessorTest.java | 326 ---
.../net/sf/jabref/shared/DBMSSynchronizerTest.java | 233 --
.../java/net/sf/jabref/shared/DBMSTypeTest.java | 44 -
.../shared/SynchronizationTestEventListener.java | 31 -
.../shared/SynchronizationTestSimulator.java | 182 --
.../java/net/sf/jabref/shared/TestConnector.java | 35 -
src/graphics/ranks/ranks.xcf | Bin 2057 -> 0 bytes
.../net/sf/jabref/gui/AWTExceptionHandler.java | 25 -
.../java/net/sf/jabref/gui/AbstractUITest.java | 108 -
.../java/net/sf/jabref/gui/DialogTest.java | 77 -
.../java/net/sf/jabref/gui/EntryTableTest.java | 64 -
.../java/net/sf/jabref/gui/GUITest.java | 118 -
.../gui/ParameterizedDialogNewEntryTest.java | 199 --
.../net/sf/jabref/gui/ParameterizedDialogTest.java | 150 -
.../jabref/gui/ParameterizedMenuNewEntryTest.java | 77 -
.../java/net/sf/jabref/gui/UndoTest.java | 64 -
.../java/net/sf/jabref/benchmarks/Benchmarks.java | 33 +-
src/main/antlr4/net/sf/jabref/search/Search.g4 | 6 +-
.../java/net/sf/jabref/BibDatabaseContext.java | 222 --
src/main/java/net/sf/jabref/Defaults.java | 17 -
.../net/sf/jabref/FallbackExceptionHandler.java | 24 +
src/main/java/net/sf/jabref/Globals.java | 29 +-
src/main/java/net/sf/jabref/JabRefException.java | 4 +
.../java/net/sf/jabref/JabRefExecutorService.java | 115 +-
src/main/java/net/sf/jabref/JabRefGUI.java | 91 +-
src/main/java/net/sf/jabref/JabRefMain.java | 27 +-
src/main/java/net/sf/jabref/MetaData.java | 480 ----
.../java/net/sf/jabref/cli/ArgumentProcessor.java | 158 +-
.../java/net/sf/jabref/cli/AuxCommandLine.java | 2 +-
.../sf/jabref/cli/CrossrefFetcherEvaluator.java | 14 +-
.../net/sf/jabref/cli/GenerateCharacterTable.java | 2 +-
src/main/java/net/sf/jabref/cli/XMPUtilMain.java | 17 +-
.../net/sf/jabref/collab/ChangeDisplayDialog.java | 2 -
.../java/net/sf/jabref/collab/ChangeScanner.java | 247 +-
.../java/net/sf/jabref/collab/EntryAddChange.java | 4 +-
.../java/net/sf/jabref/collab/EntryChange.java | 18 +-
.../net/sf/jabref/collab/EntryDeleteChange.java | 4 +-
.../net/sf/jabref/collab/FileUpdateMonitor.java | 41 +-
.../java/net/sf/jabref/collab/FileUpdatePanel.java | 12 +-
.../java/net/sf/jabref/collab/GroupChange.java | 10 +-
.../java/net/sf/jabref/collab/MetaDataChange.java | 101 +-
.../net/sf/jabref/event/GroupUpdatedEvent.java | 19 -
.../net/sf/jabref/event/MetaDataChangedEvent.java | 22 -
.../sf/jabref/event/source/EntryEventSource.java | 11 -
.../net/sf/jabref/external/AttachFileAction.java | 54 -
.../java/net/sf/jabref/external/AutoSetLinks.java | 222 --
.../external/ConfirmCloseFileListEntryEditor.java | 14 -
.../sf/jabref/external/DownloadExternalFile.java | 349 ---
.../net/sf/jabref/external/DroppedFileHandler.java | 542 ----
.../sf/jabref/external/ExternalFileMenuItem.java | 112 -
.../net/sf/jabref/external/ExternalFileType.java | 222 --
.../sf/jabref/external/ExternalFileTypeEditor.java | 386 ---
.../external/ExternalFileTypeEntryEditor.java | 249 --
.../net/sf/jabref/external/ExternalFileTypes.java | 325 ---
.../net/sf/jabref/external/FindFullTextAction.java | 90 -
.../net/sf/jabref/external/MoveFileAction.java | 196 --
.../net/sf/jabref/external/RegExpFileSearch.java | 335 ---
.../sf/jabref/external/SynchronizeFileField.java | 397 ---
.../external/TransferableFileLinkSelection.java | 105 -
.../jabref/external/UnknownExternalFileType.java | 16 -
.../net/sf/jabref/external/WriteXMPAction.java | 293 --
.../jabref/external/WriteXMPEntryEditorAction.java | 143 -
src/main/java/net/sf/jabref/gui/BasePanel.java | 670 +++--
.../net/sf/jabref/gui/BibtexKeyPatternDialog.java | 100 -
.../java/net/sf/jabref/gui/ClipBoardManager.java | 24 +-
.../net/sf/jabref/gui/ContentSelectorDialog2.java | 517 ----
.../net/sf/jabref/gui/DuplicateResolverDialog.java | 6 +-
.../java/net/sf/jabref/gui/DuplicateSearch.java | 2 +-
.../sf/jabref/gui/EntryCustomizationDialog.java | 36 +-
src/main/java/net/sf/jabref/gui/EntryMarker.java | 16 +-
.../java/net/sf/jabref/gui/EntryTypeDialog.java | 163 +-
.../net/sf/jabref/gui/FieldContentSelector.java | 228 --
.../java/net/sf/jabref/gui/FieldSetComponent.java | 4 +-
src/main/java/net/sf/jabref/gui/FileDialog.java | 10 +-
src/main/java/net/sf/jabref/gui/FileListEntry.java | 45 -
.../net/sf/jabref/gui/FileListEntryEditor.java | 362 ---
.../java/net/sf/jabref/gui/FileListTableModel.java | 222 --
.../net/sf/jabref/gui/FindUnlinkedFilesDialog.java | 15 +-
src/main/java/net/sf/jabref/gui/GUIGlobals.java | 55 +-
.../net/sf/jabref/gui/GenFieldsCustomizer.java | 3 -
src/main/java/net/sf/jabref/gui/IconTheme.java | 1 +
.../sf/jabref/gui/JEditorPaneWithHighlighting.java | 58 +
src/main/java/net/sf/jabref/gui/JabRefFrame.java | 577 ++--
src/main/java/net/sf/jabref/gui/MergeDialog.java | 8 -
.../java/net/sf/jabref/gui/PreambleEditor.java | 66 +-
src/main/java/net/sf/jabref/gui/PreviewPanel.java | 161 +-
.../net/sf/jabref/gui/ReplaceStringDialog.java | 2 +-
.../net/sf/jabref/gui/SaveOrderConfigDisplay.java | 2 +-
src/main/java/net/sf/jabref/gui/SidePane.java | 7 +-
.../java/net/sf/jabref/gui/SidePaneComponent.java | 56 +-
.../java/net/sf/jabref/gui/SidePaneManager.java | 132 +-
src/main/java/net/sf/jabref/gui/StringDialog.java | 20 +-
.../net/sf/jabref/gui/TransferableBibtexEntry.java | 3 +-
.../java/net/sf/jabref/gui/actions/Actions.java | 8 +-
.../sf/jabref/gui/actions/AutoLinkFilesAction.java | 2 +-
.../java/net/sf/jabref/gui/actions/BaseAction.java | 2 +-
.../net/sf/jabref/gui/actions/CleanupAction.java | 9 +-
.../gui/actions/ConnectToSharedDatabaseAction.java | 31 +
.../gui/actions/CopyBibTeXKeyAndLinkAction.java | 61 +
.../sf/jabref/gui/actions/CopyDoiUrlAction.java | 45 +
.../jabref/gui/actions/IntegrityCheckAction.java | 10 +-
.../jabref/gui/actions/ManageKeywordsAction.java | 163 +-
.../sf/jabref/gui/actions/MassSetFieldAction.java | 6 +-
.../sf/jabref/gui/actions/NewDatabaseAction.java | 4 +-
.../net/sf/jabref/gui/actions/NewEntryAction.java | 6 +-
.../jabref/gui/actions/NewSubDatabaseAction.java | 4 +-
.../gui/actions/OpenSharedDatabaseAction.java | 32 -
.../gui/autocompleter/AutoCompleteSupport.java | 11 +-
.../autocompleter/ListAutoCompleteRenderer.java | 5 +-
.../gui/autosaveandbackup/AutosaveUIManager.java | 33 +
.../gui/autosaveandbackup/BackupUIManager.java | 30 +
.../bibtexkeypattern/BibtexKeyPatternDialog.java | 101 +
.../bibtexkeypattern/BibtexKeyPatternPanel.java | 7 +-
.../ResolveDuplicateLabelDialog.java | 15 +-
.../bibtexkeypattern/SearchFixDuplicateLabels.java | 11 +-
.../gui/cleanup/CleanupActionsListModel.java | 4 +-
.../sf/jabref/gui/cleanup/CleanupPresetPanel.java | 5 +-
.../gui/cleanup/FieldFormatterCleanupsPanel.java | 40 +-
.../net/sf/jabref/gui/date/DatePickerButton.java | 8 +-
.../gui/dbproperties/DatabasePropertiesDialog.java | 8 +-
.../net/sf/jabref/gui/desktop/JabRefDesktop.java | 23 +-
.../java/net/sf/jabref/gui/desktop/os/Linux.java | 4 +-
.../java/net/sf/jabref/gui/desktop/os/OSX.java | 4 +-
.../java/net/sf/jabref/gui/desktop/os/Windows.java | 4 +-
.../net/sf/jabref/gui/entryeditor/EntryEditor.java | 518 ++--
.../sf/jabref/gui/entryeditor/EntryEditorTab.java | 85 +-
.../entryeditor/EntryEditorTabFocusListener.java | 38 +-
.../gui/entryeditor/FieldExtraComponents.java | 87 +-
.../sf/jabref/gui/exporter/AutoSaveManager.java | 119 -
.../sf/jabref/gui/exporter/CustomExportDialog.java | 1 -
.../net/sf/jabref/gui/exporter/ExportAction.java | 5 +-
.../gui/exporter/ExportCustomizationDialog.java | 11 +-
.../gui/exporter/ExportToClipboardAction.java | 8 +-
.../net/sf/jabref/gui/exporter/SaveAllAction.java | 2 +-
.../sf/jabref/gui/exporter/SaveDatabaseAction.java | 137 +-
.../sf/jabref/gui/externalfiles/AutoSetLinks.java | 228 ++
.../gui/externalfiles/DownloadExternalFile.java | 350 +++
.../gui/externalfiles/DroppedFileHandler.java | 570 ++++
.../gui/externalfiles/FindFullTextAction.java | 122 +
.../jabref/gui/externalfiles/MoveFileAction.java | 195 ++
.../gui/externalfiles/SynchronizeFileField.java | 401 +++
.../TransferableFileLinkSelection.java | 107 +
.../jabref/gui/externalfiles/WriteXMPAction.java | 297 ++
.../externalfiles/WriteXMPEntryEditorAction.java | 143 +
.../gui/externalfiletype/ExternalFileMenuItem.java | 112 +
.../gui/externalfiletype/ExternalFileType.java | 222 ++
.../externalfiletype/ExternalFileTypeEditor.java | 382 +++
.../ExternalFileTypeEntryEditor.java | 249 ++
.../gui/externalfiletype/ExternalFileTypes.java | 322 +++
.../externalfiletype/UnknownExternalFileType.java | 16 +
.../gui/fieldeditors/EntryLinkListEditor.java | 563 ++++
.../gui/fieldeditors/FieldEditorFocusListener.java | 4 +-
.../sf/jabref/gui/fieldeditors/FileListEditor.java | 31 +-
.../FileListEditorTransferHandler.java | 15 +-
.../fieldeditors/JTextAreaWithHighlighting.java | 23 +-
.../net/sf/jabref/gui/fieldeditors/TextArea.java | 6 +-
.../net/sf/jabref/gui/fieldeditors/TextField.java | 10 +-
.../fieldeditors/contextmenu/CaseChangeMenu.java | 2 +-
.../fieldeditors/contextmenu/ConversionMenu.java | 2 +-
.../fieldeditors/contextmenu/FieldTextMenu.java | 17 +-
.../contextmenu/ProtectedTermsMenu.java | 5 +-
.../sf/jabref/gui/filelist/AttachFileAction.java | 51 +
.../filelist/ConfirmCloseFileListEntryEditor.java | 12 +
.../net/sf/jabref/gui/filelist/FileListEntry.java | 45 +
.../jabref/gui/filelist/FileListEntryEditor.java | 364 +++
.../sf/jabref/gui/filelist/FileListTableModel.java | 222 ++
.../net/sf/jabref/gui/groups/AddToGroupAction.java | 6 +-
.../net/sf/jabref/gui/groups/AutoGroupDialog.java | 110 +-
.../gui/groups/EntryTableTransferHandler.java | 9 +-
.../sf/jabref/gui/groups/GroupAddRemoveDialog.java | 11 +-
.../java/net/sf/jabref/gui/groups/GroupDialog.java | 38 +-
.../net/sf/jabref/gui/groups/GroupSelector.java | 90 +-
.../jabref/gui/groups/GroupTreeCellRenderer.java | 4 +-
.../jabref/gui/groups/GroupTreeNodeViewModel.java | 39 +-
.../java/net/sf/jabref/gui/groups/GroupsTree.java | 13 +-
.../jabref/gui/groups/RemoveFromGroupAction.java | 2 +-
.../gui/groups/TransferableEntrySelection.java | 2 +-
.../gui/groups/UndoableAddOrRemoveGroup.java | 2 +-
.../gui/groups/UndoableChangeAssignment.java | 2 +-
.../gui/groups/UndoableChangeEntriesOfGroup.java | 2 +-
.../sf/jabref/gui/groups/UndoableModifyGroup.java | 4 +-
.../jabref/gui/groups/UndoableModifySubtree.java | 2 +-
.../sf/jabref/gui/groups/UndoableMoveGroup.java | 4 +-
.../gui/groups/WarnAssignmentSideEffects.java | 4 +-
.../java/net/sf/jabref/gui/help/AboutAction.java | 8 +-
.../java/net/sf/jabref/gui/help/AboutDialog.java | 12 +-
.../java/net/sf/jabref/gui/help/HelpAction.java | 24 +-
.../net/sf/jabref/gui/help/NewVersionDialog.java | 4 +-
.../gui/importer/EntryFromExternalFileCreator.java | 2 +-
.../jabref/gui/importer/EntryFromFileCreator.java | 16 +-
.../gui/importer/EntryFromFileCreatorManager.java | 4 +-
.../jabref/gui/importer/EntryFromPDFCreator.java | 10 +-
.../jabref/gui/importer/FetcherPreviewDialog.java | 10 +
.../gui/importer/ImportCustomizationDialog.java | 57 +-
.../sf/jabref/gui/importer/ImportFileFilter.java | 6 +-
.../net/sf/jabref/gui/importer/ImportFormats.java | 6 +-
.../gui/importer/ImportInspectionDialog.java | 118 +-
.../net/sf/jabref/gui/importer/ImportMenuItem.java | 19 +-
.../jabref/gui/importer/UnlinkedFilesCrawler.java | 2 +-
.../jabref/gui/importer/UnlinkedPDFFileFilter.java | 6 +-
.../net/sf/jabref/gui/importer/ZipFileChooser.java | 30 +-
.../gui/importer/actions/AppendDatabaseAction.java | 41 +-
.../actions/CheckForNewEntryTypesAction.java | 4 +-
.../actions/ConvertLegacyExplicitGroups.java | 14 +-
.../gui/importer/actions/OpenDatabaseAction.java | 178 +-
.../gui/importer/fetcher/ACMPortalFetcher.java | 28 +-
.../sf/jabref/gui/importer/fetcher/ADSFetcher.java | 166 --
.../gui/importer/fetcher/CiteSeerXFetcher.java | 4 +-
.../jabref/gui/importer/fetcher/DBLPFetcher.java | 164 --
.../jabref/gui/importer/fetcher/DOAJFetcher.java | 35 +-
.../gui/importer/fetcher/DOItoBibTeXFetcher.java | 53 -
.../gui/importer/fetcher/DiVAtoBibTeXFetcher.java | 129 -
.../jabref/gui/importer/fetcher/EntryFetcher.java | 6 +-
.../jabref/gui/importer/fetcher/EntryFetchers.java | 49 +-
.../gui/importer/fetcher/GeneralFetcher.java | 62 +-
.../gui/importer/fetcher/GoogleScholarFetcher.java | 309 ---
.../gui/importer/fetcher/IEEEXploreFetcher.java | 52 +-
.../gui/importer/fetcher/INSPIREFetcher.java | 49 +-
.../gui/importer/fetcher/ISBNtoBibTeXFetcher.java | 154 --
.../gui/importer/fetcher/IdBasedEntryFetcher.java | 65 +
.../gui/importer/fetcher/MedlineFetcher.java | 257 --
.../jabref/gui/importer/fetcher/OAI2Fetcher.java | 95 +-
.../gui/importer/fetcher/PreviewEntryFetcher.java | 2 +-
.../gui/importer/fetcher/ScienceDirectFetcher.java | 7 +-
.../importer/fetcher/SearchBasedEntryFetcher.java | 5 +-
.../gui/importer/fetcher/SpringerFetcher.java | 56 +-
.../importer/worker/AutosaveStartupPrompter.java | 101 -
.../sf/jabref/gui/journals/AbbreviateAction.java | 3 +-
.../jabref/gui/journals/ManageJournalsPanel.java | 11 +-
.../sf/jabref/gui/journals/UnabbreviateAction.java | 3 +-
.../jabref/gui/journals/UndoableAbbreviator.java | 2 +-
.../jabref/gui/journals/UndoableUnabbreviator.java | 2 +-
.../net/sf/jabref/gui/keyboard/KeyBinding.java | 28 +-
.../sf/jabref/gui/keyboard/KeyBindingsDialog.java | 2 -
.../jabref/gui/keyboard/KeyBindingsListener.java | 89 +-
.../sf/jabref/gui/maintable/ListSynchronizer.java | 18 +-
.../net/sf/jabref/gui/maintable/MainTable.java | 155 +-
.../sf/jabref/gui/maintable/MainTableColumn.java | 16 +-
.../jabref/gui/maintable/MainTableDataModel.java | 2 +-
.../sf/jabref/gui/maintable/MainTableFormat.java | 25 +-
.../gui/maintable/MainTableSelectionListener.java | 122 +-
.../gui/maintable/SpecialMainTableColumns.java | 190 --
.../maintable/SpecialMainTableColumnsBuilder.java | 204 ++
.../net/sf/jabref/gui/menus/FileHistoryMenu.java | 15 +-
.../net/sf/jabref/gui/menus/RightClickMenu.java | 168 +-
.../gui/mergeentries/EntryFetchAndMergeWorker.java | 64 +
.../gui/mergeentries/FetchAndMergeEntry.java | 46 +-
.../gui/mergeentries/FetchAndMergeWorker.java | 77 +
.../sf/jabref/gui/mergeentries/MergeEntries.java | 54 +-
.../gui/mergeentries/MergeEntriesDialog.java | 6 +-
.../gui/mergeentries/MergeFetchedEntryDialog.java | 59 +-
.../mergeentries/MergeWithFetchedEntryAction.java | 34 +
.../sf/jabref/gui/openoffice/CitationManager.java | 2 -
.../net/sf/jabref/gui/openoffice/OOBibBase.java | 22 +-
.../sf/jabref/gui/openoffice/OpenOfficePanel.java | 119 +-
.../jabref/gui/openoffice/OpenOfficeSidePanel.java | 52 +
.../jabref/gui/openoffice/StyleSelectDialog.java | 18 +-
.../gui/plaintextimport/TextInputDialog.java | 42 +-
.../net/sf/jabref/gui/preftabs/AdvancedTab.java | 6 +-
.../sf/jabref/gui/preftabs/AppearancePrefsTab.java | 7 +-
.../jabref/gui/preftabs/EntryEditorPrefsTab.java | 31 +-
.../net/sf/jabref/gui/preftabs/ExternalTab.java | 2 +-
.../net/sf/jabref/gui/preftabs/FileSortTab.java | 5 +-
.../java/net/sf/jabref/gui/preftabs/FileTab.java | 63 +-
.../sf/jabref/gui/preftabs/ImportSettingsTab.java | 32 +-
.../sf/jabref/gui/preftabs/NameFormatterTab.java | 10 +-
.../net/sf/jabref/gui/preftabs/NetworkTab.java | 4 +-
.../sf/jabref/gui/preftabs/PreferencesDialog.java | 103 +-
.../gui/preftabs/PreferencesFilterDialog.java | 5 +-
.../sf/jabref/gui/preftabs/PreviewPrefsTab.java | 312 ++-
.../sf/jabref/gui/preftabs/TableColumnsTab.java | 6 +-
.../net/sf/jabref/gui/preftabs/XmpPrefsTab.java | 2 -
.../NewProtectedTermsFileDialog.java | 1 -
.../gui/protectedterms/ProtectedTermsDialog.java | 23 +-
.../jabref/gui/push/AbstractPushToApplication.java | 2 +-
.../net/sf/jabref/gui/push/PushToApplication.java | 2 +-
.../java/net/sf/jabref/gui/push/PushToEmacs.java | 21 +-
.../java/net/sf/jabref/gui/push/PushToLyx.java | 2 +-
.../java/net/sf/jabref/gui/push/PushToVim.java | 2 +-
.../net/sf/jabref/gui/search/GlobalSearchBar.java | 425 +++
.../sf/jabref/gui/search/GlobalSearchWorker.java | 60 +-
.../gui/search/JTextFieldChangeListenerUtil.java | 1 +
.../java/net/sf/jabref/gui/search/SearchBar.java | 367 ---
.../sf/jabref/gui/search/SearchDisplayMode.java | 29 +
.../java/net/sf/jabref/gui/search/SearchMode.java | 31 -
.../sf/jabref/gui/search/SearchResultFrame.java | 641 +++++
.../sf/jabref/gui/search/SearchResultsDialog.java | 501 ----
.../net/sf/jabref/gui/search/SearchWorker.java | 66 +-
.../gui/shared/ConnectToSharedDatabaseDialog.java | 475 ++++
.../jabref/gui/shared/MergeSharedEntryDialog.java | 3 +-
.../sf/jabref/gui/shared/MigrationHelpDialog.java | 2 +-
.../gui/shared/OpenSharedDatabaseDialog.java | 350 ---
.../jabref/gui/shared/SharedDatabaseUIManager.java | 100 +-
.../gui/specialfields/SpecialFieldAction.java | 105 +
.../SpecialFieldDatabaseChangeListener.java | 44 +
.../gui/specialfields/SpecialFieldDropDown.java | 102 +
.../gui/specialfields/SpecialFieldMenuAction.java | 27 +
.../specialfields/SpecialFieldUpdateListener.java | 54 +
.../specialfields/SpecialFieldValueViewModel.java | 187 ++
.../gui/specialfields/SpecialFieldViewModel.java | 69 +
.../net/sf/jabref/gui/undo/UndoableChangeType.java | 2 +-
.../sf/jabref/gui/undo/UndoableFieldChange.java | 2 +-
.../sf/jabref/gui/undo/UndoableInsertEntry.java | 2 +-
.../sf/jabref/gui/undo/UndoableInsertString.java | 2 +-
.../net/sf/jabref/gui/undo/UndoableKeyChange.java | 21 +-
.../sf/jabref/gui/undo/UndoableRemoveEntry.java | 4 +-
.../sf/jabref/gui/undo/UndoableRemoveString.java | 2 +-
.../sf/jabref/gui/undo/UndoableStringChange.java | 2 +-
.../net/sf/jabref/gui/util/FocusRequester.java | 29 -
src/main/java/net/sf/jabref/gui/util/GUIUtil.java | 39 -
.../net/sf/jabref/gui/util/PositionWindow.java | 111 -
.../net/sf/jabref/gui/util/WindowLocation.java | 163 ++
.../gui/util/comparator/FirstColumnComparator.java | 2 +-
.../jabref/gui/util/comparator/IconComparator.java | 4 +-
.../util/comparator/RankingFieldComparator.java | 6 +-
.../util/component/JTextAreaWithPlaceholder.java | 90 +
.../util/component/JTextFieldWithPlaceholder.java | 91 +
.../component/JTextFieldWithUnfocusedText.java | 62 -
.../sf/jabref/gui/util/component/OverlayPanel.java | 3 +-
.../jabref/gui/util/component/VerticalLabelUI.java | 13 +-
.../net/sf/jabref/gui/worker/AbstractWorker.java | 2 +-
.../sf/jabref/gui/worker/SendAsEMailAction.java | 7 +-
.../net/sf/jabref/gui/worker/VersionWorker.java | 84 +-
.../java/net/sf/jabref/logic/TypedBibEntry.java | 10 +-
.../logic/autocompleter/AbstractAutoCompleter.java | 4 +
.../autocompleter/AutoCompletePreferences.java | 4 +-
.../logic/autocompleter/AutoCompleterFactory.java | 8 +-
.../logic/autocompleter/ContentAutoCompleters.java | 17 +-
.../logic/autocompleter/DefaultAutoCompleter.java | 2 +-
.../autocompleter/EntireFieldAutoCompleter.java | 2 +-
.../autocompleter/NameFieldAutoCompleter.java | 2 +-
.../logic/autosaveandbackup/AutosaveManager.java | 94 +
.../logic/autosaveandbackup/BackupManager.java | 163 ++
.../net/sf/jabref/logic/auxparser/AuxParser.java | 86 +-
.../net/sf/jabref/logic/bibtex/BibEntryWriter.java | 5 +-
.../sf/jabref/logic/bibtex/FieldContentParser.java | 8 +-
.../bibtex/FieldContentParserPreferences.java | 6 -
.../jabref/logic/bibtex/LatexFieldFormatter.java | 4 +-
.../bibtex/LatexFieldFormatterPreferences.java | 8 -
.../bibtex/comparator/CrossRefEntryComparator.java | 15 +-
.../logic/bibtex/comparator/EntryComparator.java | 35 +-
.../logic/bibtex/comparator/FieldComparator.java | 12 +-
.../BibtexKeyPatternPreferences.java | 27 +-
.../bibtexkeypattern/BibtexKeyPatternUtil.java | 302 +-
src/main/java/net/sf/jabref/logic/bst/VM.java | 14 +-
.../sf/jabref/logic/cleanup/BiblatexCleanup.java | 40 +-
.../net/sf/jabref/logic/cleanup/CleanupJob.java | 16 -
.../jabref/logic/cleanup/CleanupPreferences.java | 37 +
.../net/sf/jabref/logic/cleanup/CleanupPreset.java | 7 +-
.../net/sf/jabref/logic/cleanup/CleanupWorker.java | 25 +-
.../java/net/sf/jabref/logic/cleanup/Cleanups.java | 140 +
.../net/sf/jabref/logic/cleanup/DoiCleanup.java | 10 +-
.../logic/cleanup/FieldFormatterCleanup.java | 106 -
.../sf/jabref/logic/cleanup/FileLinksCleanup.java | 3 +-
.../net/sf/jabref/logic/cleanup/ISSNCleanup.java | 3 +-
.../sf/jabref/logic/cleanup/MoveFieldCleanup.java | 32 +
.../sf/jabref/logic/cleanup/MoveFilesCleanup.java | 11 +-
.../jabref/logic/cleanup/RelativePathsCleanup.java | 12 +-
.../sf/jabref/logic/cleanup/RenamePdfCleanup.java | 116 +-
.../logic/cleanup/UpgradePdfPsToFileCleanup.java | 29 +-
.../sf/jabref/logic/config/SaveOrderConfig.java | 219 --
.../jabref/logic/exporter/BibDatabaseWriter.java | 37 +-
.../logic/exporter/BibTeXMLExportFormat.java | 246 ++
.../logic/exporter/BibtexDatabaseWriter.java | 23 +-
.../sf/jabref/logic/exporter/CustomExportList.java | 2 +-
.../net/sf/jabref/logic/exporter/ExportFormat.java | 15 +-
.../sf/jabref/logic/exporter/ExportFormats.java | 5 +-
.../logic/exporter/FieldFormatterCleanups.java | 228 --
.../sf/jabref/logic/exporter/FileSaveSession.java | 53 +-
.../sf/jabref/logic/exporter/IExportFormat.java | 10 +-
.../jabref/logic/exporter/MSBibExportFormat.java | 4 +-
.../jabref/logic/exporter/MetaDataSerializer.java | 107 +
.../sf/jabref/logic/exporter/ModsExportFormat.java | 437 ++-
.../sf/jabref/logic/exporter/OOCalcDatabase.java | 16 +-
.../logic/exporter/OpenDocumentRepresentation.java | 16 +-
.../exporter/OpenDocumentSpreadsheetCreator.java | 2 +-
.../logic/exporter/OpenOfficeDocumentCreator.java | 2 +-
.../sf/jabref/logic/exporter/SavePreferences.java | 46 +-
.../net/sf/jabref/logic/formatter/Formatter.java | 74 -
.../net/sf/jabref/logic/formatter/Formatters.java | 19 +
.../jabref/logic/formatter/IdentityFormatter.java | 1 +
.../formatter/bibtexfields/ClearFormatter.java | 2 +-
.../bibtexfields/HtmlToLatexFormatter.java | 4 +-
.../bibtexfields/HtmlToUnicodeFormatter.java | 2 +-
.../bibtexfields/LatexCleanupFormatter.java | 2 +-
.../bibtexfields/NormalizeDateFormatter.java | 2 +-
.../bibtexfields/NormalizeMonthFormatter.java | 2 +-
.../bibtexfields/NormalizeNamesFormatter.java | 9 +-
.../bibtexfields/NormalizePagesFormatter.java | 2 +-
.../OrdinalsToSuperscriptFormatter.java | 2 +-
.../bibtexfields/RemoveBracesFormatter.java | 2 +-
.../bibtexfields/UnicodeToLatexFormatter.java | 4 +-
.../bibtexfields/UnitsToLatexFormatter.java | 2 +-
.../formatter/casechanger/CapitalizeFormatter.java | 2 +-
.../formatter/casechanger/LowerCaseFormatter.java | 2 +-
.../casechanger/ProtectTermsFormatter.java | 2 +-
.../casechanger/SentenceCaseFormatter.java | 2 +-
.../jabref/logic/formatter/casechanger/Title.java | 3 +-
.../formatter/casechanger/TitleCaseFormatter.java | 2 +-
.../formatter/casechanger/UpperCaseFormatter.java | 2 +-
.../minifier/MinifyNameListFormatter.java | 2 +-
.../net/sf/jabref/logic/groups/AbstractGroup.java | 216 --
.../sf/jabref/logic/groups/AllEntriesGroup.java | 95 -
.../sf/jabref/logic/groups/EntriesGroupChange.java | 43 -
.../net/sf/jabref/logic/groups/ExplicitGroup.java | 171 --
.../sf/jabref/logic/groups/GroupDescriptions.java | 120 +
.../sf/jabref/logic/groups/GroupHierarchyType.java | 28 -
.../net/sf/jabref/logic/groups/GroupTreeNode.java | 257 --
.../net/sf/jabref/logic/groups/GroupsParser.java | 183 +-
.../net/sf/jabref/logic/groups/GroupsUtil.java | 80 -
.../net/sf/jabref/logic/groups/KeywordGroup.java | 395 ---
.../sf/jabref/logic/groups/MoveGroupChange.java | 39 -
.../net/sf/jabref/logic/groups/SearchGroup.java | 192 --
.../java/net/sf/jabref/logic/groups/TreeNode.java | 606 ----
.../logic/groups/UnsupportedVersionException.java | 10 -
.../java/net/sf/jabref/logic/help/HelpFile.java | 48 +-
.../jabref/logic/importer/EntryBasedFetcher.java | 21 +
.../logic/importer/EntryBasedParserFetcher.java | 71 +
.../sf/jabref/logic/importer/FetcherException.java | 10 +-
.../sf/jabref/logic/importer/FulltextFetcher.java | 2 +-
.../sf/jabref/logic/importer/FulltextFetchers.java | 10 +-
.../sf/jabref/logic/importer/IdBasedFetcher.java | 1 +
.../logic/importer/IdBasedParserFetcher.java | 94 +
.../sf/jabref/logic/importer/ImportException.java | 19 +
.../logic/importer/ImportFormatPreferences.java | 51 +-
.../jabref/logic/importer/ImportFormatReader.java | 67 +-
.../net/sf/jabref/logic/importer/Importer.java | 169 ++
.../net/sf/jabref/logic/importer/OpenDatabase.java | 40 +-
.../sf/jabref/logic/importer/ParseException.java | 16 +
.../java/net/sf/jabref/logic/importer/Parser.java | 14 +
.../net/sf/jabref/logic/importer/ParserResult.java | 32 +-
.../logic/importer/SearchBasedParserFetcher.java | 75 +
.../net/sf/jabref/logic/importer/WebFetcher.java | 4 +-
.../net/sf/jabref/logic/importer/WebFetchers.java | 29 +
.../net/sf/jabref/logic/importer/fetcher/ACS.java | 2 +-
.../sf/jabref/logic/importer/fetcher/ArXiv.java | 32 +-
.../importer/fetcher/AstrophysicsDataSystem.java | 160 ++
.../logic/importer/fetcher/BibsonomyScraper.java | 11 +-
.../sf/jabref/logic/importer/fetcher/CrossRef.java | 21 +-
.../jabref/logic/importer/fetcher/DBLPFetcher.java | 78 +
.../jabref/logic/importer/fetcher/DOItoBibTeX.java | 99 -
.../net/sf/jabref/logic/importer/fetcher/DiVA.java | 36 +-
.../jabref/logic/importer/fetcher/DoiFetcher.java | 63 +
.../logic/importer/fetcher/DoiResolution.java | 2 +-
.../jabref/logic/importer/fetcher/GVKParser.java | 486 ----
.../logic/importer/fetcher/GoogleScholar.java | 169 +-
.../jabref/logic/importer/fetcher/GvkFetcher.java | 39 +-
.../net/sf/jabref/logic/importer/fetcher/IEEE.java | 4 +-
.../jabref/logic/importer/fetcher/IsbnFetcher.java | 70 +
.../jabref/logic/importer/fetcher/MathSciNet.java | 101 +
.../logic/importer/fetcher/MedlineFetcher.java | 219 ++
.../logic/importer/fetcher/ScienceDirect.java | 2 +-
.../logic/importer/fetcher/SpringerLink.java | 2 +-
.../sf/jabref/logic/importer/fetcher/zbMATH.java | 131 +
.../importer/fileformat/BibTeXMLImporter.java | 15 +-
.../importer/fileformat/BiblioscapeImporter.java | 5 +-
.../logic/importer/fileformat/BibtexImporter.java | 5 +-
.../logic/importer/fileformat/BibtexParser.java | 126 +-
.../logic/importer/fileformat/CopacImporter.java | 7 +-
.../logic/importer/fileformat/CustomImporter.java | 135 +-
.../logic/importer/fileformat/EndnoteImporter.java | 5 +-
.../importer/fileformat/FreeCiteImporter.java | 12 +-
.../logic/importer/fileformat/GvkParser.java | 492 ++++
.../logic/importer/fileformat/ImportFormat.java | 170 --
.../logic/importer/fileformat/InspecImporter.java | 5 +-
.../logic/importer/fileformat/IsiImporter.java | 5 +-
.../logic/importer/fileformat/MedlineImporter.java | 55 +-
.../importer/fileformat/MedlinePlainImporter.java | 19 +-
.../logic/importer/fileformat/ModsImporter.java | 480 ++++
.../logic/importer/fileformat/MsBibImporter.java | 7 +-
.../logic/importer/fileformat/OvidImporter.java | 15 +-
.../importer/fileformat/PdfContentImporter.java | 17 +-
.../logic/importer/fileformat/PdfXmpImporter.java | 11 +-
.../importer/fileformat/RepecNepImporter.java | 10 +-
.../logic/importer/fileformat/RisImporter.java | 228 +-
.../importer/fileformat/SilverPlatterImporter.java | 5 +-
.../importer/fileformat/mods/package-info.java | 14 +
.../sf/jabref/logic/importer/util/DBLPHelper.java | 93 -
.../logic/importer/util/JSONEntryParser.java | 9 +-
.../jabref/logic/importer/util/MetaDataParser.java | 156 ++
.../sf/jabref/logic/importer/util/OAI2Handler.java | 2 +-
.../jabref/logic/importer/util/ParseException.java | 12 -
.../logic/integrity/ASCIICharacterChecker.java | 30 +
.../logic/integrity/AbbreviationChecker.java | 34 +
.../jabref/logic/integrity/AuthorNameChecker.java | 36 +
.../jabref/logic/integrity/BibStringChecker.java | 45 +
.../logic/integrity/BiblatexPagesChecker.java | 50 +
.../jabref/logic/integrity/BibtexkeyChecker.java | 34 +
.../logic/integrity/BibtexkeyDeviationChecker.java | 45 +
.../jabref/logic/integrity/BooktitleChecker.java | 30 +
.../sf/jabref/logic/integrity/BracketChecker.java | 50 +
.../jabref/logic/integrity/DOIValidityChecker.java | 22 +
.../sf/jabref/logic/integrity/EditionChecker.java | 60 +
.../jabref/logic/integrity/EntryLinkChecker.java | 51 +
.../net/sf/jabref/logic/integrity/FileChecker.java | 51 +
.../logic/integrity/HTMLCharacterChecker.java | 39 +
.../logic/integrity/HowpublishedChecker.java | 48 +
.../net/sf/jabref/logic/integrity/ISBNChecker.java | 2 +-
.../net/sf/jabref/logic/integrity/ISSNChecker.java | 3 +-
.../sf/jabref/logic/integrity/IntegrityCheck.java | 423 +--
.../sf/jabref/logic/integrity/MonthChecker.java | 61 +
.../logic/integrity/NoBibtexFieldChecker.java | 31 +
.../net/sf/jabref/logic/integrity/NoteChecker.java | 48 +
.../sf/jabref/logic/integrity/PagesChecker.java | 54 +
.../sf/jabref/logic/integrity/TitleChecker.java | 57 +
.../net/sf/jabref/logic/integrity/TypeChecker.java | 28 +
.../net/sf/jabref/logic/integrity/UrlChecker.java | 29 +
.../net/sf/jabref/logic/integrity/YearChecker.java | 49 +
.../journals/JournalAbbreviationPreferences.java | 9 -
.../java/net/sf/jabref/logic/l10n/Languages.java | 26 +-
.../net/sf/jabref/logic/l10n/Localization.java | 26 +-
.../java/net/sf/jabref/logic/layout/Layout.java | 12 +-
.../net/sf/jabref/logic/layout/LayoutEntry.java | 77 +-
.../logic/layout/LayoutFormatterPreferences.java | 12 -
.../net/sf/jabref/logic/layout/format/Authors.java | 2 +-
.../logic/layout/format/FileLinkPreferences.java | 12 -
.../sf/jabref/logic/layout/format/HTMLChars.java | 4 +-
.../layout/format/LatexToUnicodeFormatter.java | 193 +-
.../jabref/logic/layout/format/NameFormatter.java | 6 +-
.../layout/format/NameFormatterPreferences.java | 7 -
.../sf/jabref/logic/layout/format/RTFChars.java | 151 +-
.../logic/layout/format/RemoveLatexCommands.java | 67 -
.../format/RemoveLatexCommandsFormatter.java | 65 +
.../sf/jabref/logic/layout/format/RisKeywords.java | 10 +-
.../jabref/logic/layout/format/WrapFileLinks.java | 2 +-
.../net/sf/jabref/logic/logging/JabRefLogger.java | 1 -
.../net/sf/jabref/logic/mods/MODSDatabase.java | 73 -
.../java/net/sf/jabref/logic/mods/MODSEntry.java | 319 ---
.../java/net/sf/jabref/logic/mods/PageNumbers.java | 60 -
.../java/net/sf/jabref/logic/mods/PersonName.java | 128 -
.../net/sf/jabref/logic/msbib/BibTeXConverter.java | 12 +-
.../net/sf/jabref/logic/msbib/MSBibConverter.java | 54 +-
.../net/sf/jabref/logic/msbib/MSBibDatabase.java | 31 +-
.../java/net/sf/jabref/logic/msbib/MSBibEntry.java | 62 +-
.../net/sf/jabref/logic/msbib/MSBibMapping.java | 9 +-
.../net/sf/jabref/logic/msbib/PageNumbers.java | 60 +
.../java/net/sf/jabref/logic/msbib/PersonName.java | 128 +
.../net/sf/jabref/logic/net/ProxyPreferences.java | 21 -
.../java/net/sf/jabref/logic/net/URLDownload.java | 107 +-
.../net/sf/jabref/logic/openoffice/OOBibStyle.java | 4 +-
.../sf/jabref/logic/openoffice/OOPreFormatter.java | 4 +-
.../net/sf/jabref/logic/openoffice/OOUtil.java | 2 +-
.../protectedterms/ProtectedTermsPreferences.java | 40 -
.../sf/jabref/logic/remote/RemotePreferences.java | 18 +-
.../server/RemoteListenerServerLifecycle.java | 3 +-
.../sf/jabref/logic/search/MatchesHighlighter.java | 54 -
.../net/sf/jabref/logic/search/SearchMatcher.java | 10 -
.../net/sf/jabref/logic/search/SearchQuery.java | 47 +-
.../logic/search/SearchQueryHighlightListener.java | 3 +
.../search/SearchQueryHighlightObservable.java | 61 +-
.../jabref/logic/search/matchers/AndMatcher.java | 26 -
.../jabref/logic/search/matchers/MatcherSet.java | 45 -
.../jabref/logic/search/matchers/MatcherSets.java | 19 -
.../jabref/logic/search/matchers/NotMatcher.java | 27 -
.../sf/jabref/logic/search/matchers/OrMatcher.java | 26 -
.../logic/search/rules/ContainBasedSearchRule.java | 63 -
.../logic/search/rules/GrammarBasedSearchRule.java | 243 --
.../logic/search/rules/RegexBasedSearchRule.java | 67 -
.../sf/jabref/logic/search/rules/SearchRule.java | 10 -
.../sf/jabref/logic/search/rules/SearchRules.java | 27 -
.../logic/search/rules/SentenceAnalyzer.java | 57 -
.../ContainsAndRegexBasedSearchRuleDescriber.java | 4 +-
.../describer/GrammarBasedSearchRuleDescriber.java | 12 +-
.../search/rules/describer/SearchDescribers.java | 8 +-
.../logic/specialfields/SpecialFieldsUtils.java | 125 +
.../java/net/sf/jabref/logic/util/BuildInfo.java | 13 +-
src/main/java/net/sf/jabref/logic/util/DOI.java | 10 +
.../net/sf/jabref/logic/util/FileExtensions.java | 2 +
src/main/java/net/sf/jabref/logic/util/ISBN.java | 3 +
.../net/sf/jabref/logic/util/OptionalUtil.java | 23 +
.../java/net/sf/jabref/logic/util/UpdateField.java | 2 +-
.../java/net/sf/jabref/logic/util/Version.java | 216 +-
.../net/sf/jabref/logic/util/io/AutoSaveUtil.java | 27 -
.../jabref/logic/util/io/DatabaseFileLookup.java | 10 +-
.../java/net/sf/jabref/logic/util/io/FileUtil.java | 148 +-
.../sf/jabref/logic/util/io/RegExpFileSearch.java | 343 +++
.../logic/util/strings/DiffHighlighting.java | 101 -
.../util/strings/HTMLUnicodeConversionMaps.java | 904 ------
.../sf/jabref/logic/util/strings/RtfCharMap.java | 131 +-
.../sf/jabref/logic/util/strings/StringUtil.java | 676 -----
.../util/strings/UnicodeToReadableCharMap.java | 241 --
.../net/sf/jabref/logic/xmp/XMPPreferences.java | 14 +-
.../net/sf/jabref/logic/xmp/XMPSchemaBibtex.java | 20 +-
src/main/java/net/sf/jabref/logic/xmp/XMPUtil.java | 10 +-
.../jabref/migrations/FileLinksUpgradeWarning.java | 25 +-
.../jabref/migrations/PreferencesMigrations.java | 6 +-
src/main/java/net/sf/jabref/model/ChainNode.java | 154 ++
src/main/java/net/sf/jabref/model/Defaults.java | 17 +
.../java/net/sf/jabref/model/DuplicateCheck.java | 12 +-
src/main/java/net/sf/jabref/model/EntryTypes.java | 12 +-
.../bibtexkeypattern/AbstractBibtexKeyPattern.java | 11 +-
.../bibtexkeypattern/GlobalBibtexKeyPattern.java | 4 +
.../net/sf/jabref/model/cleanup/CleanupJob.java | 16 +
.../model/cleanup/FieldFormatterCleanup.java | 120 +
.../model/cleanup/FieldFormatterCleanups.java | 122 +
.../net/sf/jabref/model/cleanup/Formatter.java | 74 +
.../net/sf/jabref/model/database/BibDatabase.java | 178 +-
.../jabref/model/database/BibDatabaseContext.java | 262 ++
.../sf/jabref/model/database/BibDatabaseMode.java | 38 +-
.../model/database/BibDatabaseModeDetection.java | 10 +-
.../net/sf/jabref/model/database/BibDatabases.java | 7 +
.../sf/jabref/model/database/DatabaseLocation.java | 2 -
.../jabref/model/database/DuplicationChecker.java | 154 +-
.../net/sf/jabref/model/database/EntrySorter.java | 1 -
.../jabref/model/database/KeyChangeListener.java | 14 +-
.../jabref/model/database/event/AutosaveEvent.java | 8 +
.../event/BibDatabaseContextChangedEvent.java | 10 +
.../model/database/event/ChangePropagation.java | 6 +
.../model/database/event/EntryAddedEvent.java | 27 +
.../model/database/event/EntryRemovedEvent.java | 29 +
.../java/net/sf/jabref/model/entry/Author.java | 41 +-
.../java/net/sf/jabref/model/entry/AuthorList.java | 77 +
.../java/net/sf/jabref/model/entry/BibEntry.java | 269 +-
.../sf/jabref/model/entry/BibLatexEntryTypes.java | 476 ++--
.../sf/jabref/model/entry/BibtexSingleField.java | 26 +-
.../net/sf/jabref/model/entry/BibtexString.java | 3 +
.../net/sf/jabref/model/entry/CustomEntryType.java | 6 +-
.../net/sf/jabref/model/entry/EntryLinkList.java | 29 +
.../java/net/sf/jabref/model/entry/EntryUtil.java | 67 -
.../java/net/sf/jabref/model/entry/FieldName.java | 68 +-
.../net/sf/jabref/model/entry/FieldProperties.java | 35 -
.../net/sf/jabref/model/entry/FieldProperty.java | 35 +
.../sf/jabref/model/entry/IEEETranEntryTypes.java | 28 +-
.../jabref/model/entry/InternalBibtexFields.java | 193 +-
.../java/net/sf/jabref/model/entry/Keyword.java | 45 +
.../net/sf/jabref/model/entry/KeywordList.java | 181 ++
.../net/sf/jabref/model/entry/ParsedEntryLink.java | 59 +
.../net/sf/jabref/model/entry/SpecialFields.java | 31 -
.../model/entry/event/EntryChangedEvent.java | 26 +
.../sf/jabref/model/entry/event/EntryEvent.java | 41 +
.../jabref/model/entry/event/EntryEventSource.java | 11 +
.../model/entry/event/FieldChangedEvent.java | 72 +
.../model/entry/specialfields/SpecialField.java | 111 +
.../entry/specialfields/SpecialFieldValue.java | 45 +
.../net/sf/jabref/model/event/EntryAddedEvent.java | 26 -
.../sf/jabref/model/event/EntryChangedEvent.java | 27 -
.../java/net/sf/jabref/model/event/EntryEvent.java | 39 -
.../sf/jabref/model/event/EntryRemovedEvent.java | 28 -
.../sf/jabref/model/event/FieldChangedEvent.java | 73 -
.../net/sf/jabref/model/groups/AbstractGroup.java | 180 ++
.../sf/jabref/model/groups/AllEntriesGroup.java | 78 +
.../sf/jabref/model/groups/EntriesGroupChange.java | 43 +
.../net/sf/jabref/model/groups/ExplicitGroup.java | 103 +
.../sf/jabref/model/groups/GroupHierarchyType.java | 28 +
.../net/sf/jabref/model/groups/GroupTreeNode.java | 250 ++
.../net/sf/jabref/model/groups/GroupsUtil.java | 80 +
.../net/sf/jabref/model/groups/KeywordGroup.java | 298 ++
.../sf/jabref/model/groups/MoveGroupChange.java | 39 +
.../net/sf/jabref/model/groups/SearchGroup.java | 145 +
.../java/net/sf/jabref/model/groups/TreeNode.java | 606 ++++
.../model/groups/event/GroupUpdatedEvent.java | 20 +
.../model/metadata/FileDirectoryPreferences.java | 49 +
.../net/sf/jabref/model/metadata/MetaData.java | 268 ++
.../sf/jabref/model/metadata/SaveOrderConfig.java | 186 ++
.../model/metadata/event/MetaDataChangedEvent.java | 23 +
.../sf/jabref/model/search/GroupSearchQuery.java | 57 +
.../net/sf/jabref/model/search/SearchMatcher.java | 10 +
.../jabref/model/search/matchers/AndMatcher.java | 26 +
.../jabref/model/search/matchers/MatcherSet.java | 45 +
.../jabref/model/search/matchers/MatcherSets.java | 19 +
.../jabref/model/search/matchers/NotMatcher.java | 27 +
.../sf/jabref/model/search/matchers/OrMatcher.java | 26 +
.../model/search/rules/ContainBasedSearchRule.java | 60 +
.../model/search/rules/GrammarBasedSearchRule.java | 257 ++
.../model/search/rules/RegexBasedSearchRule.java | 64 +
.../sf/jabref/model/search/rules/SearchRule.java | 10 +
.../sf/jabref/model/search/rules/SearchRules.java | 33 +
.../model/search/rules/SentenceAnalyzer.java | 57 +
.../model/strings/HTMLUnicodeConversionMaps.java | 904 ++++++
.../sf/jabref/model/strings/LatexToUnicode.java | 209 ++
.../net/sf/jabref/model/strings/StringUtil.java | 708 +++++
.../model/strings/UnicodeToReadableCharMap.java | 241 ++
.../java/net/sf/jabref/pdfimport/ImportDialog.java | 32 +-
.../net/sf/jabref/pdfimport/PdfFileFilter.java | 4 +-
.../java/net/sf/jabref/pdfimport/PdfImporter.java | 29 +-
.../sf/jabref/preferences/CustomImportList.java | 12 +-
.../sf/jabref/preferences/JabRefPreferences.java | 485 ++--
.../sf/jabref/preferences/PreviewPreferences.java | 106 +
.../sf/jabref/preferences/SearchPreferences.java | 117 +
.../sf/jabref/preferences/VersionPreferences.java | 13 +-
.../java/net/sf/jabref/shared/DBMSConnection.java | 73 +
.../sf/jabref/shared/DBMSConnectionProperties.java | 70 +-
.../java/net/sf/jabref/shared/DBMSConnector.java | 69 -
.../java/net/sf/jabref/shared/DBMSProcessor.java | 182 +-
.../net/sf/jabref/shared/DBMSSynchronizer.java | 85 +-
.../java/net/sf/jabref/shared/MySQLProcessor.java | 9 +-
.../java/net/sf/jabref/shared/OracleProcessor.java | 71 +-
.../net/sf/jabref/shared/PostgreSQLProcessor.java | 43 +-
.../jabref/shared/event/ConnectionLostEvent.java | 2 +-
.../sf/jabref/shared/event/UpdateRefusedEvent.java | 2 +-
.../InvalidDBMSConnectionPropertiesException.java | 11 +
.../exception/NotASharedDatabaseException.java | 12 +
.../listener/OracleNotificationListener.java | 24 +
.../shared/prefs/SharedDatabasePreferences.java | 134 +
.../net/sf/jabref/shared/security/Password.java | 65 +
.../java/net/sf/jabref/specialfields/Printed.java | 52 -
.../java/net/sf/jabref/specialfields/Priority.java | 57 -
.../java/net/sf/jabref/specialfields/Quality.java | 53 -
.../java/net/sf/jabref/specialfields/Rank.java | 50 -
.../net/sf/jabref/specialfields/ReadStatus.java | 57 -
.../net/sf/jabref/specialfields/Relevance.java | 52 -
.../net/sf/jabref/specialfields/SpecialField.java | 88 -
.../jabref/specialfields/SpecialFieldAction.java | 74 -
.../SpecialFieldDatabaseChangeListener.java | 34 -
.../jabref/specialfields/SpecialFieldDropDown.java | 97 -
.../specialfields/SpecialFieldMenuAction.java | 27 -
.../specialfields/SpecialFieldUpdateListener.java | 51 -
.../sf/jabref/specialfields/SpecialFieldValue.java | 107 -
.../jabref/specialfields/SpecialFieldsUtils.java | 174 --
src/main/java/oracle/jdbc/OracleConnection.java | 368 +++
src/main/java/oracle/jdbc/OracleStatement.java | 13 +
.../java/oracle/jdbc/dcn/DatabaseChangeEvent.java | 8 +
.../oracle/jdbc/dcn/DatabaseChangeListener.java | 9 +
.../jdbc/dcn/DatabaseChangeRegistration.java | 11 +
src/main/java/oracle/jdbc/driver/OracleDriver.java | 8 +
src/main/java/oracle/jdbc/package-info.java | 4 +
src/main/java/osx/macadapter/MacAdapter.java | 16 +-
.../resources/images/icons/JabRef-icon-mac.svg | 11 +-
src/main/resources/images/icons/JabRef-icon.svg | 29 +-
src/main/resources/l10n/JabRef_da.properties | 1029 +++++--
src/main/resources/l10n/JabRef_de.properties | 672 ++---
src/main/resources/l10n/JabRef_en.properties | 155 +-
src/main/resources/l10n/JabRef_es.properties | 1372 ++++++---
src/main/resources/l10n/JabRef_fa.properties | 542 ++--
src/main/resources/l10n/JabRef_fr.properties | 1060 +++++--
src/main/resources/l10n/JabRef_in.properties | 1048 +++++--
src/main/resources/l10n/JabRef_it.properties | 1949 ++++++++-----
src/main/resources/l10n/JabRef_ja.properties | 779 +++---
src/main/resources/l10n/JabRef_nl.properties | 571 ++--
src/main/resources/l10n/JabRef_no.properties | 927 ++-----
src/main/resources/l10n/JabRef_pt_BR.properties | 1047 +++++--
src/main/resources/l10n/JabRef_ru.properties | 1156 ++++----
src/main/resources/l10n/JabRef_sv.properties | 2166 ++++++++++-----
src/main/resources/l10n/JabRef_tr.properties | 1051 +++++--
src/main/resources/l10n/JabRef_vi.properties | 870 +++---
src/main/resources/l10n/JabRef_zh.properties | 1425 +++++++---
src/main/resources/l10n/Menu_da.properties | 53 +-
src/main/resources/l10n/Menu_de.properties | 195 +-
src/main/resources/l10n/Menu_en.properties | 21 +-
src/main/resources/l10n/Menu_es.properties | 74 +-
src/main/resources/l10n/Menu_fa.properties | 38 +-
src/main/resources/l10n/Menu_fr.properties | 144 +-
src/main/resources/l10n/Menu_in.properties | 83 +-
src/main/resources/l10n/Menu_it.properties | 46 +-
src/main/resources/l10n/Menu_ja.properties | 67 +-
src/main/resources/l10n/Menu_nl.properties | 122 +-
src/main/resources/l10n/Menu_no.properties | 40 +-
src/main/resources/l10n/Menu_pt_BR.properties | 57 +-
src/main/resources/l10n/Menu_ru.properties | 54 +-
src/main/resources/l10n/Menu_sv.properties | 46 +-
src/main/resources/l10n/Menu_tr.properties | 63 +-
src/main/resources/l10n/Menu_vi.properties | 216 +-
src/main/resources/l10n/Menu_zh.properties | 57 +-
.../resource/layout/bibtexml.begin.layout | 5 -
.../resources/resource/layout/bibtexml.end.layout | 1 -
src/main/resources/resource/layout/bibtexml.layout | 36 -
src/main/resources/resource/ods/meta.xml | 5 +-
src/main/resources/resource/ods/settings.xml | 4 +-
.../resource/openoffice/default_authoryear.jstyle | 3 +-
.../resource/openoffice/default_numerical.jstyle | 3 +-
src/main/resources/resource/openoffice/meta.xml | 5 +-
src/main/resources/xjc/mods/mods-3-6.xsd | 1513 ++++++++++
src/main/resources/xjc/mods/mods-binding.xjb | 96 +
src/test/java/net/sf/jabref/ArchitectureTests.java | 26 +-
.../java/net/sf/jabref/BibDatabaseContextTest.java | 37 -
src/test/java/net/sf/jabref/BibtexTestData.java | 9 +-
src/test/java/net/sf/jabref/CodeStyleTests.java | 24 +
src/test/java/net/sf/jabref/MetaDataTest.java | 21 +-
.../cleanup/CleanupActionsListModelTest.java | 9 +-
.../java/net/sf/jabref/cli/AuxCommandLineTest.java | 3 +-
.../sf/jabref/external/ExternalFileTypeTest.java | 30 -
.../sf/jabref/external/RegExpFileSearchTests.java | 157 --
.../net/sf/jabref/gui/AWTExceptionHandler.java | 25 +
.../java/net/sf/jabref/gui/AbstractUITest.java | 111 +
src/test/java/net/sf/jabref/gui/DialogTest.java | 52 +
src/test/java/net/sf/jabref/gui/DialogTest2.java | 46 +
.../java/net/sf/jabref/gui/EntryTableTest.java | 68 +
src/test/java/net/sf/jabref/gui/GUITest.java | 119 +
.../net/sf/jabref/gui/IdFetcherDialogTest.java | 136 +
.../gui/ParameterizedDialogNewEntryTest.java | 203 ++
.../net/sf/jabref/gui/ParameterizedDialogTest.java | 154 ++
.../jabref/gui/ParameterizedMenuNewEntryTest.java | 78 +
src/test/java/net/sf/jabref/gui/UndoTest.java | 68 +
.../sf/jabref/gui/entryeditor/EntryEditorTest.java | 3 +
.../gui/externalfiletype/ExternalFileTypeTest.java | 34 +
.../importer/EntryFromFileCreatorManagerTest.java | 11 +-
.../gui/importer/EntryFromPDFCreatorTest.java | 11 +-
.../actions/ConvertLegacyExplicitGroupsTest.java | 35 +-
.../gui/importer/fetcher/GeneralFetcherTest.java | 75 -
.../importer/fetcher/OAI2HandlerFetcherTest.java | 49 +-
.../sf/jabref/gui/search/SearchResultsTest.java | 97 +
.../logic/autosaveandbackup/BackupManagerTest.java | 18 +
.../sf/jabref/logic/auxparser/AuxParserTest.java | 58 +-
.../net/sf/jabref/logic/bibtex/BibEntryAssert.java | 31 +-
.../sf/jabref/logic/bibtex/BibEntryWriterTest.java | 46 +-
.../logic/bibtex/EntryTypesTestBibLatex.java | 2 +
.../logic/bibtex/LatexFieldFormatterTests.java | 3 +-
.../comparator/CrossRefEntryComparatorTest.java | 56 +
.../bibtex/comparator/EntryComparatorTest.java | 16 +
.../bibtexkeypattern/BibtexKeyPatternUtilTest.java | 113 +-
.../MakeLabelWithDatabaseTest.java | 323 +++
src/test/java/net/sf/jabref/logic/bst/TestVM.java | 3 +-
.../jabref/logic/cleanup/BiblatexCleanupTest.java | 45 +
.../sf/jabref/logic/cleanup/CleanupWorkerTest.java | 76 +-
.../logic/cleanup/FieldFormatterCleanupTest.java | 66 +
.../sf/jabref/logic/cleanup/ISSNCleanupTest.java | 13 +-
.../jabref/logic/cleanup/MoveFilesCleanupTest.java | 13 +-
.../jabref/logic/cleanup/RenamePdfCleanupTest.java | 147 +-
.../logic/exporter/BibTeXMLExporterTestFiles.java | 89 +
.../logic/exporter/BibtexDatabaseWriterTest.java | 85 +-
.../sf/jabref/logic/exporter/ExportFormatTest.java | 13 +-
.../logic/exporter/FieldFormatterCleanupsTest.java | 40 +-
.../logic/exporter/HtmlExportFormatTest.java | 12 +-
.../logic/exporter/MSBibExportFormatTestFiles.java | 24 +-
.../logic/exporter/ModsExportFormatTest.java | 61 +
.../logic/exporter/ModsExportFormatTestFiles.java | 116 +
.../logic/exporter/MsBibExportFormatTest.java | 2 +-
.../sf/jabref/logic/formatter/FormatterTest.java | 5 +-
.../bibtexfields/NormalizeNamesFormatterTest.java | 120 +-
.../casechanger/TitleCaseFormatterTest.java | 52 +-
.../sf/jabref/logic/groups/AbstractGroupTest.java | 25 -
.../jabref/logic/groups/AllEntriesGroupTest.java | 14 -
.../sf/jabref/logic/groups/ExplicitGroupTest.java | 40 -
.../sf/jabref/logic/groups/GroupTreeNodeTest.java | 337 ---
.../net/sf/jabref/logic/groups/GroupsUtilTest.java | 4 +-
.../sf/jabref/logic/groups/KeywordGroupTest.java | 90 -
.../sf/jabref/logic/groups/SearchGroupTest.java | 41 -
.../net/sf/jabref/logic/groups/TreeNodeTest.java | 709 -----
.../logic/importer/BibDatabaseTestsWithFiles.java | 2 +-
.../logic/importer/DatabaseFileLookupTest.java | 2 +-
.../logic/importer/FulltextFetchersTest.java | 3 -
.../ImportFormatReaderIntegrationTest.java | 12 +-
.../ImportFormatReaderTestParameterless.java | 26 +-
.../net/sf/jabref/logic/importer/ImporterTest.java | 118 +
.../sf/jabref/logic/importer/OpenDatabaseTest.java | 18 +-
.../jabref/logic/importer/ParsedBibEntryTests.java | 2 +-
.../sf/jabref/logic/importer/fetcher/ACSTest.java | 3 +
.../jabref/logic/importer/fetcher/ArXivTest.java | 12 +-
.../fetcher/AstrophysicsDataSystemTest.java | 203 ++
.../logic/importer/fetcher/CrossRefTest.java | 5 +-
.../logic/importer/fetcher/DBLPFetcherTest.java | 68 +
.../sf/jabref/logic/importer/fetcher/DiVATest.java | 8 +-
.../logic/importer/fetcher/DoiFetcherTest.java | 85 +
.../logic/importer/fetcher/DoiResolutionTest.java | 8 +-
.../logic/importer/fetcher/GVKParserTest.java | 75 -
.../logic/importer/fetcher/GoogleScholarTest.java | 58 +-
.../logic/importer/fetcher/GvkFetcherTest.java | 9 +-
.../logic/importer/fetcher/GvkParserTest.java | 71 +
.../sf/jabref/logic/importer/fetcher/IEEETest.java | 20 +-
.../logic/importer/fetcher/IsbnFetcherTest.java | 93 +
.../logic/importer/fetcher/MathSciNetTest.java | 72 +
.../logic/importer/fetcher/MedlineFetcherTest.java | 192 ++
.../logic/importer/fetcher/ScienceDirectTest.java | 3 +
.../logic/importer/fetcher/SpringerLinkTest.java | 5 +-
.../jabref/logic/importer/fetcher/zbMATHTest.java | 58 +
.../importer/fileformat/BibTeXMLImporterTest.java | 20 +-
.../fileformat/BibTeXMLImporterTestFiles.java | 22 +-
.../fileformat/BiblioscapeImporterTest.java | 6 +-
.../fileformat/BiblioscapeImporterTestFiles.java | 22 +-
.../importer/fileformat/BibtexImporterTest.java | 93 +-
.../importer/fileformat/BibtexParserTest.java | 613 ++--
.../importer/fileformat/CopacImporterTest.java | 25 +-
.../fileformat/CopacImporterTestFiles.java | 28 +-
.../importer/fileformat/CustomImporterTest.java | 95 +-
.../importer/fileformat/EndnoteImporterTest.java | 90 +-
.../importer/fileformat/FreeCiteImporterTest.java | 5 +-
.../importer/fileformat/ImportFormatTest.java | 101 -
.../importer/fileformat/InspecImportTest.java | 8 +-
.../logic/importer/fileformat/IsiImporterTest.java | 150 +-
.../importer/fileformat/MedlineImporterTest.java | 16 +-
.../fileformat/MedlineImporterTestFiles.java | 35 +-
.../fileformat/MedlinePlainImporterTest.java | 32 +-
.../importer/fileformat/ModsImporterTestFiles.java | 63 +
.../importer/fileformat/MsBibImporterTest.java | 2 +-
.../importer/fileformat/OvidImporterTest.java | 79 +-
.../fileformat/PdfContentImporterTest.java | 11 +-
.../fileformat/PdfContentImporterTestFiles.java | 3 +-
.../importer/fileformat/PdfXmpImporterTest.java | 25 +-
.../logic/importer/fileformat/RISImporterTest.java | 6 +-
.../importer/fileformat/RISImporterTestFiles.java | 11 +-
.../importer/fileformat/RepecNepImporterTest.java | 23 +-
.../fileformat/SilverPlatterImporterTest.java | 7 +-
.../SilverPlatterImporterTestNotRecognized.java | 4 +-
.../logic/importer/util/JSONEntryParserTest.java | 26 +-
.../logic/integrity/EntryLinkCheckerTest.java | 103 +
.../jabref/logic/integrity/IntegrityCheckTest.java | 127 +-
.../jabref/logic/journals/AbbreviationsTest.java | 18 +-
.../net/sf/jabref/logic/l10n/EncodingsTest.java | 28 +
.../net/sf/jabref/logic/l10n/LanguagesTest.java | 33 +-
.../logic/l10n/LocalizationConsistencyTest.java | 86 +-
.../net/sf/jabref/logic/l10n/LocalizationTest.java | 16 +-
.../sf/jabref/logic/layout/LayoutEntryTest.java | 107 +-
.../net/sf/jabref/logic/layout/LayoutTest.java | 25 +-
.../sf/jabref/logic/layout/format/AuthorsTest.java | 17 +
.../jabref/logic/layout/format/FileLinkTest.java | 2 +-
.../jabref/logic/layout/format/RTFCharsTest.java | 159 +-
.../logic/layout/format/WrapFileLinksTest.java | 135 +
.../net/sf/jabref/logic/net/URLDownloadTest.java | 18 +-
.../java/net/sf/jabref/logic/net/URLUtilTest.java | 2 +
.../sf/jabref/logic/openoffice/OOBibStyleTest.java | 15 +-
.../jabref/logic/openoffice/StyleLoaderTest.java | 6 +-
.../jabref/logic/remote/RemotePreferencesTest.java | 53 +
.../jabref/logic/search/DatabaseSearcherTest.java | 84 +-
.../GrammarBasedSearchRuleDescriberTest.java | 2 +-
.../logic/search/MatchesHighlighterTest.java | 55 -
.../search/SearchQueryHighlightObservableTest.java | 55 +-
.../sf/jabref/logic/search/SearchQueryTest.java | 128 +-
.../logic/search/matchers/MatcherSetsTest.java | 50 -
.../search/rules/ContainBasedSearchRuleTest.java | 54 -
.../logic/search/rules/MockSearchMatcher.java | 21 -
.../logic/search/rules/SentenceAnalyzerTest.java | 20 -
.../specialfields/SpecialFieldsUtilsTest.java | 72 +
.../sf/jabref/logic/util/DevelopmentStageTest.java | 37 +
.../net/sf/jabref/logic/util/UpdateFieldTest.java | 6 +-
.../java/net/sf/jabref/logic/util/VersionTest.java | 280 ++
.../sf/jabref/logic/util/io/FileHistoryTest.java | 6 +-
.../net/sf/jabref/logic/util/io/FileUtilTest.java | 215 +-
.../logic/util/io/RegExpFileSearchTests.java | 119 +
.../logic/util/strings/DiffHighlightingTest.java | 81 -
.../jabref/logic/util/strings/StringUtilTest.java | 347 ---
.../sf/jabref/logic/util/version/VersionTest.java | 216 --
.../sf/jabref/logic/xmp/XMPSchemaBibtexTest.java | 2 +-
.../java/net/sf/jabref/logic/xmp/XMPUtilTest.java | 62 +-
.../sf/jabref/model/BibDatabaseContextTest.java | 51 +
.../sf/jabref/model/database/BibDatabaseTest.java | 62 +-
.../model/database/DuplicationCheckerTest.java | 111 +
.../model/database/KeyChangeListenerTest.java | 20 +-
.../net/sf/jabref/model/entry/AuthorListTest.java | 19 +-
.../jabref/model/entry/BibEntryEqualityTest.java | 38 +
.../net/sf/jabref/model/entry/BibEntryTest.java | 2 +-
.../net/sf/jabref/model/entry/BibEntryTests.java | 175 +-
.../sf/jabref/model/entry/BibtexStringTest.java | 6 +
.../net/sf/jabref/model/entry/EntryUtilTest.java | 35 -
.../jabref/model/entry/IEEETranEntryTypesTest.java | 2 +-
.../net/sf/jabref/model/entry/KeywordListTest.java | 70 +
.../entry/specialfields/SpecialFieldTest.java | 34 +
.../sf/jabref/model/event/TestEventListener.java | 3 +
.../sf/jabref/model/groups/AbstractGroupTest.java | 25 +
.../jabref/model/groups/AllEntriesGroupTest.java | 14 +
.../sf/jabref/model/groups/ExplicitGroupTest.java | 62 +
.../sf/jabref/model/groups/GroupTreeNodeTest.java | 313 +++
.../sf/jabref/model/groups/KeywordGroupTest.java | 110 +
.../sf/jabref/model/groups/SearchGroupTest.java | 41 +
.../net/sf/jabref/model/groups/TreeNodeTest.java | 710 +++++
.../model/search/matchers/MatcherSetsTest.java | 50 +
.../search/rules/ContainBasedSearchRuleTest.java | 54 +
.../model/search/rules/MockSearchMatcher.java | 21 +
.../model/search/rules/SentenceAnalyzerTest.java | 20 +
.../sf/jabref/model/strings/StringUtilTest.java | 352 +++
.../net/sf/jabref/shared/DBMSConnectionTest.java | 40 +
.../net/sf/jabref/shared/DBMSProcessorTest.java | 302 ++
.../net/sf/jabref/shared/DBMSSynchronizerTest.java | 220 ++
.../java/net/sf/jabref/shared/DBMSTypeTest.java | 48 +
.../shared/SynchronizationTestEventListener.java | 34 +
.../shared/SynchronizationTestSimulator.java | 161 ++
.../java/net/sf/jabref/shared/TestConnector.java | 40 +
.../java/net/sf/jabref/shared/TestManager.java | 50 +
.../specialfields/SpecialFieldsUtilsTest.java | 122 -
.../java/net/sf/jabref/support/DevEnvironment.java | 13 +
.../java/net/sf/jabref/testutils/AssertUtil.java | 15 -
.../java/net/sf/jabref/testutils/GuiTestUtils.java | 38 -
.../jabref/testutils/category/DatabaseTests.java | 4 +
.../sf/jabref/testutils/category/FetcherTests.java | 4 +
.../net/sf/jabref/testutils/category/GUITests.java | 4 +
.../resources/net/sf/jabref/customPreferences.xml | 2 -
.../net/sf/jabref/logic/auxparser/crossref.aux | 9 +
.../net/sf/jabref/logic/auxparser/nested.aux | 1 +
.../net/sf/jabref/logic/auxparser/origin.bib | 15 +
.../logic/exporter/BibTeXMLExporterTestArticle.bib | 11 +
.../logic/exporter/BibTeXMLExporterTestArticle.xml | 14 +
.../BibTeXMLExporterTestArticleWithoutID.bib | 11 +
.../BibTeXMLExporterTestArticleWithoutID.xml | 14 +
.../logic/exporter/BibTeXMLExporterTestAuthor.bib | 5 +
.../logic/exporter/BibTeXMLExporterTestAuthor.xml | 8 +
.../logic/exporter/BibTeXMLExporterTestBook.bib | 11 +
.../logic/exporter/BibTeXMLExporterTestBook.xml | 14 +
.../logic/exporter/BibTeXMLExporterTestBooklet.bib | 10 +
.../logic/exporter/BibTeXMLExporterTestBooklet.xml | 13 +
.../exporter/BibTeXMLExporterTestConference.bib | 18 +
.../exporter/BibTeXMLExporterTestConference.xml | 21 +
.../logic/exporter/BibTeXMLExporterTestInBook.bib | 13 +
.../logic/exporter/BibTeXMLExporterTestInBook.xml | 17 +
.../exporter/BibTeXMLExporterTestInCollection.bib | 16 +
.../exporter/BibTeXMLExporterTestInCollection.xml | 18 +
.../exporter/BibTeXMLExporterTestInProceedings.bib | 12 +
.../exporter/BibTeXMLExporterTestInProceedings.xml | 15 +
.../BibTeXMLExporterTestInbookLessFields.bib | 15 +
.../BibTeXMLExporterTestInbookLessFields.xml | 21 +
.../exporter/BibTeXMLExporterTestInvalidInbook.bib | 3 +
.../exporter/BibTeXMLExporterTestInvalidInbook.xml | 8 +
.../logic/exporter/BibTeXMLExporterTestManual.bib | 11 +
.../logic/exporter/BibTeXMLExporterTestManual.xml | 14 +
.../exporter/BibTeXMLExporterTestMasterThesis.bib | 12 +
.../exporter/BibTeXMLExporterTestMasterThesis.xml | 15 +
.../logic/exporter/BibTeXMLExporterTestMisc.bib | 10 +
.../logic/exporter/BibTeXMLExporterTestMisc.xml | 13 +
.../exporter/BibTeXMLExporterTestPhdThesis.bib | 12 +
.../exporter/BibTeXMLExporterTestPhdThesis.xml | 15 +
.../exporter/BibTeXMLExporterTestProceedings.bib | 11 +
.../exporter/BibTeXMLExporterTestProceedings.xml | 14 +
.../exporter/BibTeXMLExporterTestTechReport.bib | 11 +
.../exporter/BibTeXMLExporterTestTechReport.xml | 16 +
.../exporter/BibTeXMLExporterTestUnpublished.bib | 9 +
.../exporter/BibTeXMLExporterTestUnpublished.xml | 12 +
.../exporter/ModsExportFormatTestAllFields.bib | 29 +
.../exporter/ModsExportFormatTestAllFields.xml | 81 +
.../logic/exporter/ModsExportFormatTestBook.bib | 9 +
.../logic/exporter/ModsExportFormatTestBook.xml | 24 +
.../ModsExportFormatTestMultipleEntries.bib | 20 +
.../ModsExportFormatTestMultipleEntries.xml | 85 +
.../ModsExportFormatTestOnlyRequiredFields.bib | 9 +
.../ModsExportFormatTestOnlyRequiredFields.xml | 32 +
.../exporter/ModsExportFormatTestTotalPages.bib | 8 +
.../exporter/ModsExportFormatTestTotalPages.xml | 22 +
.../logic/exporter/MsBibExportFormatTest2.xml | 3 +
.../logic/exporter/MsBibExportFormatTest3.xml | 19 +-
.../logic/exporter/MsBibExportFormatTest6.xml | 17 +-
.../net/sf/jabref/logic/exporter/MsBibKeyTest.bib | 12 +
.../net/sf/jabref/logic/exporter/MsBibKeyTest.xml | 19 +
.../sf/jabref/logic/exporter/MsBibLocationTest.bib | 10 +
.../sf/jabref/logic/exporter/MsBibLocationTest.xml | 20 +
.../logic/exporter/MsBibMultiAddressTest.bib | 11 +
.../logic/exporter/MsBibMultiAddressTest.xml | 20 +
...l => gvk_empty_result_because_of_bad_query.xml} | 0
.../fileformat/AutosavedSharedDatabase.bib | 6 +
.../fileformat/MODSImporterTestAllFields.bib | 17 +
.../fileformat/MODSImporterTestAllFields.xml | 61 +
.../fileformat/MODSImporterTestMinimal.bib | 0
.../fileformat/MODSImporterTestMinimal.xml | 6 +
.../importer/fileformat/MODSImporterTestMods.bib | 13 +
.../importer/fileformat/MODSImporterTestMods.xml | 57 +
.../fileformat/MODSImporterTestModsCollection.bib | 33 +
.../fileformat/MODSImporterTestModsCollection.xml | 240 ++
.../MedlineImporterTestArticleNoISSN.bib | 25 +
.../MedlineImporterTestArticleNoISSN.xml | 106 +
.../importer/fileformat/MedlineImporterTestDOI.bib | 26 +
.../importer/fileformat/MedlineImporterTestDOI.xml | 112 +
.../importer/fileformat/MsBibLocationTest.bib | 8 +
.../importer/fileformat/MsBibLocationTest.xml | 20 +
.../fileformat/MsBibMultiLocationAddressTest.bib | 8 +
.../fileformat/MsBibMultiLocationAddressTest.xml | 20 +
.../logic/importer/fileformat/RisImporterTest3.bib | 4 +-
.../logic/importer/fileformat/RisImporterTest3.ris | 1 -
.../logic/importer/fileformat/RisImporterTest6.bib | 2 +-
.../logic/importer/fileformat/RisImporterTest6.ris | 1 -
.../RisImporterTestDoiAndJournalTitle.bib | 12 +
.../RisImporterTestDoiAndJournalTitle.ris | 12 +
.../importer/fileformat/RisImporterTestScopus.bib | 17 +
.../importer/fileformat/RisImporterTestScopus.ris | 26 +
src/test/resources/testbib/complex.bib | 6 +-
src/test/resources/testbib/crossref.bib | 45 +
src/test/resources/testbib/jabref-authors.bib | 2920 ++++++++++++++++++++
xjc.gradle | 7 +
1086 files changed, 58776 insertions(+), 39167 deletions(-)
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..4a1e0be
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,6 @@
+root = true
+
+[*]
+charset = utf-8
+indent_style = space
+insert_final_newline = true
diff --git a/.gitattributes b/.gitattributes
index 9b3ebff..b17095b 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -6,5 +6,7 @@ gradlew eol=lf
*.properties text
*.java text
-CHANGELOG.md merge=union
-src/main/resources/l10n/*.properties merge=union
\ No newline at end of file
+# disalbe after a release
+# CHANGELOG.md merge=union
+
+src/main/resources/l10n/*.properties merge=union
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 4b8ffaa..9b20c4e 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -5,3 +5,4 @@
- [ ] Screenshots added (for bigger UI changes)
- [ ] Manually tested changed features in running JabRef
- [ ] Check documentation status (Issue created for outdated help page at [help.jabref.org](https://github.com/JabRef/help.jabref.org/issues)?)
+- [ ] If you changed the localization: Did you run `gradle localizationUpdate`?
diff --git a/.gitignore b/.gitignore
index b36c596..9cf0806 100644
--- a/.gitignore
+++ b/.gitignore
@@ -49,3 +49,9 @@ bin/
jabref.xml
install4j6/
*.sonargraph
+
+# ignore the generated markdown file if the user forgets to delete it
+status.md
+
+# private data
+/buildres/jabref-cert-2016.p12
diff --git a/.mailmap b/.mailmap
index 00050a1..6f30df5 100644
--- a/.mailmap
+++ b/.mailmap
@@ -11,10 +11,11 @@ Stefan Kolb <stefan-kolb at web.de>
<stefan-kolb at web.de> <stefan-kolb at users.noreply.github.com>
Nicolas Pavillon <pavillon.nicolas at gmail.com>
<pavillon.nicolas at gmail.com> <userid-1711535 at users.sf.net>
-Koji Yokota <yokota33 at gmail.com> kojiyokota <yokota33 at gmail.com>
+Koji Yokota <yokota33 at gmail.com> <yokota33 at gmail.com>
Koji Yokota <yokota33 at gmail.com> <kojiyokota at users.sourceforge.net>
Koji Yokota <yokota33 at gmail.com> <yokota6 at gmail.com>
-Koji Yokota <kojiyokota at users.noreply.github.com>
+Koji Yokota <yokota33 at gmail.com> <kojiyokota at users.noreply.github.com>
+Koji Yokota <yokota33 at gmail.com> <koji33 at users.noreply.github.com>
Dominik Waßenhoven <domwass at users.sourceforge.net> <domwass at users.sourceforge.net>
<domwass at users.sourceforge.net> <domwass at Dominik-Waenhovens-MacBook-Air.local>
Thomas Arildsen <tha at es.aau.dk> ThomasArildsen <tha at es.aau.dk>
@@ -32,7 +33,8 @@ Tobias Diez <tobiasdiez at gmx.de>
Waluyo Adi Siswanto <was.uthm at gmail.com> <was123 at users.sourceforge.net>
Michael Falkenthal <michael.falkenthal at googlemail.com>
Michael Falkenthal <michael.falkenthal at googlemail.com> <michael.falkenthal at iaas.uni-stuttgart.de>
-<ambro2 at users.noreply.github.com> <ambro2 at users.sourceforge.net>
+Ambrogio Oliva <ambro2 at users.noreply.github.com>
+Ambrogio Oliva <ambro2 at users.noreply.github.com> <ambro2 at users.sourceforge.net>
Eduardo Greco <eduardogreco93 at gmail.com>
Daniel Bruehl <bruehl.dev at gmail.com>
Egon Willighagen <egon.willighagen at gmail.com> <egonw at users.sourceforge.net>
@@ -83,11 +85,10 @@ Robert Jäschke <rjoberon at users.sf.net>
Ulrik Stervbo <ulriks at users.sourceforge.net>
Stefano Gariazzo <steog88 at gmail.com>
Lee Patton <lpatton at users.sourceforge.net>
-Jörg Lenhard <joerg.lenhard at uni-bamberg.de>
Jörg Lenhard <joerg.lenhard at kau.se>
-<joerg.lenhard at uni-bamberg.de> <joerg at lenhard.info>
-<joerg.lenhard at uni-bamberg.de> <lenhard at users.noreply.github.com>
-<joerg.lenhard at uni-bamberg.de> <joerg.lenhard at kau.se>
+<joerg.lenhard at kau.se> <joerg at lenhard.info>
+<joerg.lenhard at kau.se> <lenhard at users.noreply.github.com>
+Jörg Lenhard <joerg.lenhard at kau.se> <joerg.lenhard at uni-bamberg.de>
Matthias Geiger <matthias.geiger at uni-bamberg.de>
Christoph Braun <braunch.dev at gmail.com>
Felix Wilke <horstilaemmer at yahoo.com>
@@ -99,4 +100,8 @@ Vincent W. Yang <solrex at gmail.com>
Jorge Tornero <portpel at portpel.cd.ieo.es>
Mélanie Tremblay <mel_4_7 at yahoo.ca>
Christoph Schwentker <cschwentker at gmail.com>
+Christoph Schwentker <cschwentker at gmail.com> <siedlerkiller at gmail.com>
Jens Döcke <jens.doecke at gmail.com>
+Jürgen Lange <juergen.lange at unitybox.de>
+Sascha Zeller <zeller.dev at gmail.com>
+Ali Ayan <ali.ayan at hotmail.de>
diff --git a/.travis.yml b/.travis.yml
index dab832f..ad88841 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,25 +2,17 @@ language: java
# we test at Ubuntu Trusty (Ubuntu 14.04 LTS)
# see https://docs.travis-ci.com/user/trusty-ci-environment/
-sudo: required
+# This environment is continuously updated as described in https://docs.travis-ci.com/user/build-environment-updates/
dist: trusty
-
-# update to latest Java8 as described at https://github.com/travis-ci/travis-ci/issues/4042#issuecomment-109756980
-addons:
- apt:
- packages:
- # most recent Java8 - this makes the DK switcher obsolete - see https://github.com/travis-ci/travis-ci/issues/5897#issuecomment-218354129
- - oracle-java8-installer
- # MySQL 5.6 as desccribed at https://docs.travis-ci.com/user/database-setup/#MySQL-5.6
- - mysql-server-5.6
- - mysql-client-core-5.6
- - mysql-client-5.6
+sudo: required
services:
- postgresql
- mysql
-# skip installation as this is also done during the script step
+env:
+ - GRADLE_OPTS=-Dorg.gradle.daemon=false
+
install: true
before_script:
@@ -28,18 +20,18 @@ before_script:
- mysql -u root -e 'create database jabref'
script:
- - ./gradlew check
- - ./gradlew databaseTest
- # Integration tests currently often fail with "Process 'Gradle Test Executor 1' finished with non-zero exit value 137"
- # They should run, but the result is ignored
+ - ./gradlew check -Dscan
+ - ./gradlew fetcherTest -Dscan
+ - ./gradlew databaseTest -Dscan
+ # Prepare integration tests
- "export DISPLAY=:99.0"
- "sh -e /etc/init.d/xvfb start"
- sleep 3 # give xvfb some time to start
# no need for databases for the integrationTest -> save memory
- - sudo service mysql stop
+ # currently does not work: "stop: Unknown instance:" - sudo service mysql stop
- sudo service postgresql stop
# following services identified by "sudo service --status-all" do not need to run, too
- # excluded: rsyslog (feels wrong), udev (feels wrong), friendly-recovery ("Unkonwn instance" error)
+ # excluded: rsyslog (feels wrong), udev (feels wrong), friendly-recovery ("Unknown instance" error)
- sudo service acpid stop
- sudo service atd stop
- sudo service cron stop
@@ -49,13 +41,18 @@ script:
- sudo service resolvconf stop
- sudo service sshguard stop
- sudo service ssh stop
- - ./gradlew integrationTest --info || true
+ # Integration tests run in a timeout. Just start them and kill them after 60s.
+ - timeout 60 ./gradlew guiTest -Dscan --info || true
after_script:
# enable codecov report
- ./gradlew jacocoTestReport
- bash <(curl -s https://codecov.io/bash)
+after_failure:
+ # show test results if build fails
+ - $TRAVIS_BUILD_DIR/scripts/after-failure.sh
+
# cache gradle dependencies
# https://docs.travis-ci.com/user/languages/java#Caching
before_cache:
@@ -64,8 +61,3 @@ cache:
directories:
- $HOME/.gradle/caches/
- $HOME/.gradle/wrapper/
-
-# enable slack notifications
-notifications:
- slack:
- secure: B5LGefXS1Jt+d7tUzzmakoz+/ZnFUzmmmYuBXaikTUPDuxXacIrVTv4Vx+tcagxDrPQ3A20oi3+0t6p8xagytjLI9u3abACyWwO3+CbywuJDLBzxADVhg/+mKssfTmemRlZoBUrBlHZVk69LIJvqXFR5l5zAiBtDL1dWPeMEEvI=
diff --git a/AUTHORS b/AUTHORS
index e3b803f..069d344 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -8,11 +8,12 @@ Alessio Pollero
Alex Montgomery
Alexis Gallagher
Alexsandro Lauber
-ambro2
+Ali Ayan
Ambrogio Oliva
Andreas Amann
Andreas Rudert
Anh Nghia Tran
+Antonio Ribeiro
Behrouz Javanmardi
Bernd Kalbfuss
Bernhard Tempel
@@ -48,6 +49,7 @@ Fedor Bezrukov
Felix Berger
Felix Langner
Felix Wilke
+Fernando Santagata
Florian Straßer
Francois Charette
Frank Steimle
@@ -78,6 +80,7 @@ Jörg Lenhard
Jörg Wegner
Jörg Zieren
Jørgen Kvalsvik
+Jürgen Lange
Kai Mindermann
Koji Yokota
Kolja Brix
@@ -139,7 +142,7 @@ Sascha Zeller
Saverio Mori
Scott Townsend
Seb Wills
-Siedlerchr
+Shitikanth
Simon Harrer
Simon Rutishauser
speed9
diff --git a/CHANGELOG.md b/CHANGELOG.md
index dec115f..ebdf3e4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,11 +4,247 @@ This project **does not** adhere to [Semantic Versioning](http://semver.org/).
This file tries to follow the conventions proposed by [keepachangelog.com](http://keepachangelog.com/).
Here, the categories "Changed" for added and changed functionality,
"Fixed" for fixed functionality, and
-"Removed" for removed functionality is used.
+"Removed" for removed functionality are used.
We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `#NUM`.
+## [Unreleased]
+
+### Changed
+- Bibliographic information from web resources can now be used to complete existing entries.
+ This functionality can be accessed via a new button in the entry editor.
+- URLs can now be passed as arguments to the `-import` and `-importToOpen` command line options.
+ The referenced file is downloaded and then imported as usual.
+- Windows and OSX binaries are now signed with a certificate.
+- The default emacs executable name on linux changed from `gnuclient` to `emacsclient`.
+ [feature-request 433](https://sourceforge.net/p/jabref/feature-requests/433/)
+- Adds integrity check to detect all bibtex keys which deviate from their generation pattern [#2206](https://github.com/JabRef/jabref/issues/2206)
+- Adds an integrity check that detects invalid DOIs [#1445](https://github.com/JabRef/jabref/issues/1445)
+- Replaces manual thread management with cached thread pool
+- Files can now be moved to subfolders named by a custom format pattern, e.g., based on `entrytype`.
+ The pattern can be specified in the settings like the filename pattern. [#1092](https://github.com/JabRef/jabref/issues/1092)
+
+### Fixed
+- We fixed an issue which prevented JabRef from closing using the "Quit" menu command. [#2336](https://github.com/JabRef/jabref/issues/2336)
+- We fixed an issue where the file permissions of the .bib-file were changed upon saving [#2279](https://github.com/JabRef/jabref/issues/2279).
+- We fixed an issue which prevented that a database was saved successfully if JabRef failed to generate new BibTeX-keys [#2285](https://github.com/JabRef/jabref/issues/2285).
+- We fixed an issue which prevented the preference dialog to open on systems with Java 9.
+- Update check now correctly notifies about new release if development version is used. [#2298](https://github.com/JabRef/jabref/issues/2298)
+- Fixed [#2311](https://github.com/JabRef/jabref/issues/2311): The DBLP fetcher has been rewritten and is working again.
+- Fixed [#2273](https://github.com/JabRef/jabref/issues/2273): Export via commandline in no-gui mode is now working again.
+- We fixed an issue when JabRef restores its session and a shared database was used: The error message "No suitable driver found" will not appear.
+- We fixed an issue which caused a metadata loss on reconnection to shared database. [#2219](https://github.com/JabRef/jabref/issues/2219)
+- We fixed an issue which caused an internal error when leaving the file path field empty and connecting to a shared database.
+- We fixed an issue where the BibLaTeX Cleanup did not move the contents of the fields `year` and `month` to the field `date`. [#2335](https://github.com/JabRef/jabref/issues/2335)
+
+### Removed
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+## [3.7] - 2016-11-14
+
+### Changed
+- Implementation of eventbased autosave and backup functionality and file synchronization for shared DBs. Related to [#344](https://github.com/JabRef/jabref/issues/344)
+- Source tab in the entry editor displays "BibLaTeX Source" when using biblatex mode
+- [koppor#171](https://github.com/koppor/jabref/issues/171): Add Shortcuts to context menu
+- Add session restoring functionality for shared database. Related to [#1703](https://github.com/JabRef/jabref/issues/1703)
+- Implementation of LiveUpdate for PostgreSQL & Oracle systems. Related to [#970](https://github.com/JabRef/jabref/issues/970).
+- [koppor#31](https://github.com/koppor/jabref/issues/31): Number column in the main table is always Left aligned
+- Added support for [1.0.1 CitationStyles](http://citationstyles.org/)
+- You can set and cycle between different preview styles (including CitationStyles)
+- Added fetcher for [MathSciNet](http://www.ams.org/mathscinet), [zbMATH](https://www.zbmath.org/) and [Astrophysics Data System](http://www.adsabs.harvard.edu/)
+- Improved search:
+ - Search queries consisting of a normal query and a field-based query are now supported (for example, `JabRef AND author == you`)
+ - Implemented [#825](https://github.com/JabRef/jabref/issues/825): Search Bar across all bib files instead each having its own
+ - Implemented [#573](https://github.com/JabRef/jabref/issues/573): Add key shortcut for global search (<kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>F</kbd>, if the searchfield is empty it will be focused instead)
+ - The search result Window will now show which entry belongs to which bib file
+ - The search result Window will now remember its location
+ - The search result Window won't stay on top anymore if the main Window is focused and will be present in the taskbar
+ - The user can jump from the searchbar to the maintable with <kbd>Ctrl</kbd> + <kbd>Enter</kbd>
+ - Implemented [#573 (comment)](https://github.com/JabRef/jabref/issues/573#issuecomment-232284156): Added shortcut: closing the search result window with <kbd>Ctrl</kbd> + <kbd>W</kbd>
+- Added integrity check for fields with BibTeX keys, e.g., `crossref` and `related`, to check that the key exists
+- Fields linking to other entries (e.g., `crossref` and `related`) have now specialized editors in the entry editor. Check the tabs "Other fields" and "General".
+- [#1496](https://github.com/JabRef/jabref/issues/1496) Keep track of which entry a downloaded file belongs to
+- Made it possible to download multiple entries in one action
+- [#1506](https://github.com/JabRef/jabref/issues/1506) It is possible to apply two new key modifier `title_case` for Title Case, `capitalize` for Capitalized first character of each word (difference is that title case will leave prepositions etc in lower case), and `sentence_case` for normal sentence case (first word capitalized). In addition `lower_case` and `upper_case` can be used instead of `lower` and `upper`.
+- Added two new pseudo-fields for search: `anykeyword` to search for a specific keyword and `anyfield` to search in all fields (useful in combination with search in specific fields)
+- [#1813](https://github.com/JabRef/jabref/issues/1813) Import/Export preferences dialog default directory set to working directory
+- [#1897](https://github.com/JabRef/jabref/issues/1897) Implemented integrity check for `year` field: Last four nonpunctuation characters should be numerals
+- Address in MS-Office 2007 xml format is now imported as `location`
+- [#1912](https://github.com/JabRef/jabref/issues/1912) Implemented integrity check for `edition` field: Should have the first letter capitalized (BibTeX), Should contain an integer or a literal (BibLaTeX)
+- The dialog for choosing new entries additionally supports ID-based entry generation. For instance, when searching for a DOI or ISBN, you have to press <kbd>Ctrl</kbd> + <kbd>N</kbd> instead of using the web search (<kbd>Alt</kbd> + <kbd>4</kbd>).
+- `number` field is now exported as `number` field in MS-Office 2007 xml format, if no `issue` field is present and the entry type is not `patent`
+- `note` field is now exported as `comments` field in MS-Office 2007 xml format
+- `comments` field in MS-Office 2007 xml format is now imported as `note` field
+- [#463](https://github.com/JabRef/jabref/issues/463): Disable menu-item and toolbar-buttons while no database is open
+- Implemented integrity check for `note` and `howpublished` field: Should have the first letter capitalized (BibTeX)
+- <kbd>Pos1</kbd> / <kbd>Home</kbd> now select the first/last entry in the main table and the search result frame.
+- <kbd>Up</kbd> / <kbd>Down</kbd> / <kbd>Tab</kbd> / <kbd>Shift</kbd> + <kbd>Tab</kbd> in the search result frame have now the same functionality as in the main table.
+- Importer for MODS format added
+- [#2012](https://github.com/JabRef/jabref/issues/2012) Implemented integrity check for `month` field: Should be an integer or normalized (BibLaTeX), Should be normalized (BibTeX)
+- [#1779](https://github.com/JabRef/jabref/issues/1779) Implemented integrity check for `bibtexkey` field: Empty BibTeX key
+- Prohibit more than one connections to the same shared database.
+- Implemented integrity check for `journaltitle` field: BibLaTeX field only (BibTeX)
+- [#463](https://github.com/JabRef/jabref/issues/463): Disable certain menu items, toolbar buttons and context menu items while multiple entries are selected
+- [#490](https://github.com/JabRef/jabref/issues/490) Added right click menu to main table and entry editor to allow copying doi url
+- [#549](https://github.com/JabRef/jabref/issues/549) Added new shortcut to copy the BibTeX key as a hyperlink to its url to the clipboard
+- Complete vietnam language translation in menu
+- Generalize German translation of database into "Datenbank"
+- Improve language quality of the German translation of shared database
+- Change "Recent files" to "Recent databases" to keep the file menu consistent
+- Customized importer files need to be slightly changed since the class `ImportFormat` was renamed to `Importer`
+- [koppor/#97] (https://github.com/koppor/jabref/issues/97): When importing preferences, the explorer will start where the preferences are last exported
+- [koppor#5](https://github.com/koppor/jabref/issues/5) When entries are found while dropping a pdf with xmp meta data the found entries will be displayed in the import dialog
+- [koppor#61](https://github.com/koppor/jabref/issues/61) Display gray background text in "Author" and "Editor" field to assist newcomers
+- Updated Vietnamese translation
+- Added greyed-out suggestion for `year`/`date`/`url` fields
+- [#1908](https://github.com/JabRef/jabref/issues/1908) Add a shortcut for check integrity <kbd>Ctrl</kbd> + <kbd>F8</kbd>
+- When creatig an entry based on an ISBN, but the ISBN is not available on ebook.de, the error message is now more clear.
+
+### Fixed
+- Fixed problem where closing brackets could not be used as texts in layout arguments
+- Fixed NullPointerException when opening search result window for an untitled database
+- Fixed selecting an entry out of multiple duplicates
+- Entries in the SearchResultPanel will be shown correctly (Latex to Unicode)
+- Suggestions in the autocomplete will be shown correctly (Latex to Unicode)
+- Selecting an entry in the search result Window will now select the correct entry in the bib file
+- Suggestions in the autocomplete (search) are now in Unicode
+- Entries in the SearchResultDialog are now converted to Unicode
+- Fixed NullPointerException when opening search result window for an untitled database
+- Fixed entry table traversal with Tab (no column traversal thus no double jump)
+- Fixed: When searching the first match will be selected if the current selection is no match
+- Fixed [koppor#160](https://github.com/koppor/jabref/issues/160): Tooltips now working in the main table
+- Fixed [koppor/#128](https://github.com/koppor/jabref/issues/128): Sensible default settings for "Enable save actions" and "Cleanup"
+- Fixed loop when pulling changes (shared database) when current selected field has changed
+- Fixed field `key` field is not exported to MS-Office 2008 xml format
+- Fixed field `location` containing only city is not exported correctly to MS-Office 2007 xml format
+- Fixed close action of entry editor not working after parsing error corrected
+- Fixed RTFChars would only use "?" for characters with unicode over the value of 127, now it uses the base character (é -> e instead of ?)
+- Fixed download files failed silently when an invalid directory is selected
+- Fixed InvalidBackgroundColor flickering with <kbd>Ctrl</kbd> + <kbd>S</kbd> and File > Save database
+- Fixed file menu displays wrong hotkey in the German translation
+- Fixed [#617](https://github.com/JabRef/jabref/issues/617): `Enter` in global search opens the selected entry & `Enter` in search dialog window opens the selected entry
+- Fixed [#1181](https://github.com/JabRef/jabref/issues/1181) and [#1504](https://github.com/JabRef/jabref/issues/1504): Improved "Normalize to BibTeX name format": Support separated names with commas and colons. Considered name affixes such as "Jr".
+- Fixed [#1235](https://github.com/JabRef/jabref/issues/1235): Modified Key bindings do not work correctly
+- Fixed [#1542](https://github.com/JabRef/jabref/issues/1542): Improved error messages when using fetcher
+- Fixed [#1663](https://github.com/JabRef/jabref/issues/1663): Better multi-monitor support
+- Fixed [#1757](https://github.com/JabRef/jabref/issues/1757): Crash after saving illegal argument in entry editor
+- Fixed [#1808](https://github.com/JabRef/jabref/issues/1808): Font preference dialog now keeps changes
+- Fixed [#1882](https://github.com/JabRef/jabref/issues/1882): Crash after saving illegal bibtexkey in entry editor
+- Fixed [#1937](https://github.com/JabRef/jabref/issues/1937): If no help page for the current chosen language exists, the english help page will be shown
+- Fixed [#1949](https://github.com/JabRef/jabref/issues/1949): Error message directs to the wrong preference tab
+- Fixed [#1958](https://github.com/JabRef/jabref/issues/1958): Verbatim fields are no longer checked for HTML encoded characters by integrity checks
+- Fixed [#1993](https://github.com/JabRef/jabref/issues/1993): Various optimizations regarding search performance
+- Fixed [#2021](https://github.com/JabRef/jabref/issues/2021): All filetypes can be selected on MacOS again
+- Fixed [#2054](https://github.com/JabRef/jabref/issues/2054): Ignoring a new version now works as expected
+- Fixed [#2060](https://github.com/JabRef/jabref/issues/2060): Medline fetcher now imports data in UTF-8 encoding
+- Fixed [#2064](https://github.com/JabRef/jabref/issues/2064): Not all `other fields` are shown on entry change of same type
+- Fixed [#2089](https://github.com/JabRef/jabref/issues/2089): Fixed faulty cite key generation
+- Fixed [#2090](https://github.com/JabRef/jabref/issues/#2090): If special fields were not selected, two menu item separator were shown
+- Fixed [#2092](https://github.com/JabRef/jabref/issues/2092): "None"-button in date picker clears the date field
+- Fixed [#2104](https://github.com/JabRef/jabref/issues/#2104): Crash after saving BibTeX source with parsing error
+- Fixed [#2109](https://github.com/JabRef/jabref/issues/#2109): <kbd>Ctrl</kbd> + <kbd>S</kbd> doesn't trigger parsing error message
+- Fixed [#2200](https://github.com/JabRef/jabref/issues/#2200): Sorting now uses the same unicode representation that is also used for showing the content in the maintable
+- Fixed [#2201](https://github.com/JabRef/jabref/issues/#2201) and [#1825](https://github.com/JabRef/jabref/issues/#1825): Status of the Group panel is saved and reused for next startup of JabRef
+- Fixed [#2228](https://github.com/JabRef/jabref/issues/2228): Fixed Medline fetcher no longer working. The fetcher now uses `https` for fetching
+
+### Removed
+- Removed 2nd preview style
+- The non-supported feature of being able to define file directories for any extension is removed. Still, it should work for older databases using the legacy `ps` and `pdf` fields, although we strongly encourage using the `file` field.
+- Automatic migration for the `evastar_pdf` field is removed.
+- We removed the customizable "content selectors" since they are replaced by the auto-completion feature
+- Removed optional fields from `other fields` (BibTeX), Removed deprecated fields from `other fields` (BibLaTeX)
+
+
## [3.6] - 2016-08-26
### Changed
@@ -490,6 +726,8 @@ Since much functionality has changed during development, a release of this versi
The changelog of 2.11 and versions before is maintained as [text file](https://github.com/JabRef/jabref/blob/v2.11.1/CHANGELOG) in the [v2.11.1 tag](https://github.com/JabRef/jabref/tree/v2.11.1).
+[Unreleased]: https://github.com/JabRef/jabref/compare/v3.7...HEAD
+[3.7]: https://github.com/JabRef/jabref/compare/v3.6...v3.7
[3.6]: https://github.com/JabRef/jabref/compare/v3.5...v3.6
[3.5]: https://github.com/JabRef/jabref/compare/v3.4...v3.5
[3.4]: https://github.com/JabRef/jabref/compare/v3.3...v3.4
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index a60646e..47345a8 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -29,6 +29,17 @@ Add a line with your changes in the appropriate section.
If you did internal refactorings or improvements not visible to the user (e.g., UI, .bib file), then you don't need to put an entry there.
+#### Key format
+Example: `<kbd>Ctrl</kbd> + <kbd>Enter</kbd>`
+
+In case you add keys to the changelog, please follow these rules:
+
+- `<kbd>` tag for each key
+- First letter of key capitalized
+- Combined keys separated by `+`
+- Spaces before and after separator `+`
+
+
### Author credits
You will be given credit in the `AUTHORS` file in the root of the repository and the 'About' pages inside the main application.
We will periodically update the contributors list inside `AUTHORS`.
@@ -42,8 +53,7 @@ More information on this can be found via `man git-shortlog`.
Please, **do not add yourself at `@authors`**.
The contribution information is tracked via the version control system.
-We are currently in transition from [GPL](https://tldrlegal.com/license/gnu-general-public-license-v2) to the [MIT license](https://tldrlegal.com/license/mit-license).
-Thus, all your contributions are considered being made under MIT license.
+Your contribution is considered being made under [MIT license](https://tldrlegal.com/license/mit-license).
### Write a good commit message
@@ -85,7 +95,7 @@ because <additional rationale>.
Add new Localization.lang("KEY") to Java file.
Tests fail. In the test output a snippet is generated which must be added to the English translation file. There is also a snippet generated for the non-English files, but this is irrelevant.
Add snippet to English translation file located at `src/main/resources/l10n/JabRef_en.properties`
-With `gradlew generateMissingTranslationKeys` the "KEY" is added to the other translation files as well.
+With `gradlew localizationUpdate` the "KEY" is added to the other translation files as well.
Tests are green again.
You can also directly run the specific test in your IDE. The test "LocalizationConsistencyTest" is placed under `src/test/java/net.sf.jabref.logic.l10n/LocalizationConsistencyTest.java`
@@ -101,4 +111,4 @@ You can add the prefix `[WIP]` to indicate that the pull request is not yet comp
[commit guidelines section of Pro Git]: http://git-scm.com/book/en/Distributed-Git-Contributing-to-a-Project#Commit-Guidelines
[good commit message]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
-[help documentation]: https://help.github.com/articles/using-pull-requests/
+[help documentation]: https://help.github.com/articles/about-pull-requests/
diff --git a/DEVELOPERS b/DEVELOPERS
index e33a294..ce33c7f 100644
--- a/DEVELOPERS
+++ b/DEVELOPERS
@@ -1,8 +1,8 @@
Oliver Kopp (since 2011)
Simon Harrer (since 2014)
-Joerg Lenhard (since 2015)
-Stefan Kolb (since 2015)
+Jörg Lenhard (since 2015)
+Stefan Kolb (since 2015)
Matthias Geiger (since 2015)
Oscar Gustafsson (since 2015)
-Tobias Diez (since 2015)
+Tobias Diez (since 2015)
Christoph Schwentker (since 2016)
diff --git a/README.md b/README.md
index f9808eb..f277b22 100644
--- a/README.md
+++ b/README.md
@@ -1,12 +1,14 @@
-# JabRef Version 3.6
+# JabRef Development Version
[![Build Status](https://travis-ci.org/JabRef/jabref.svg?branch=master)](https://travis-ci.org/JabRef/jabref)
[![Dependency Status](https://www.versioneye.com/user/projects/557f2723386664002000009c/badge.svg?style=flat)](https://www.versioneye.com/user/projects/557f2723386664002000009c)
[![codecov.io](https://codecov.io/github/JabRef/jabref/coverage.svg?branch=master)](https://codecov.io/github/JabRef/jabref?branch=master)
-[![Donation](https://img.shields.io/badge/donate-paypal-orange.svg)](https://www.paypal.com/cgi-bin/webscr?item_name=JabRef+Bibliography+Manager&cmd=_donations&lc=US¤cy_code=EUR&business=donations%40jabref.org)
+[![Donation](https://img.shields.io/badge/donate-something-orange.svg)](https://donations.jabref.org)
[![Issue Stats](http://www.issuestats.com/github/jabref/jabref/badge/pr)](http://www.issuestats.com/github/jabref/jabref)
[![Issue Stats](http://www.issuestats.com/github/jabref/jabref/badge/issue)](http://www.issuestats.com/github/jabref/jabref)
+This version is a development version. Features may not work as expected.
+
Branches of JabRef development are listed at https://github.com/JabRef/jabref/wiki/Branches.
Development builds are available at [builds.jabref.org](http://builds.jabref.org/master/), the [latest release is available via GitHub](https://github.com/JabRef/jabref/releases/latest).
@@ -102,9 +104,7 @@ Releasing is done using [CircleCI](https://circleci.com/gh/JabRef/jabref). A ful
## License
-We are currently in transition from [GPL](https://tldrlegal.com/license/gnu-general-public-license-v2) to the [MIT license](https://tldrlegal.com/license/mit-license).
-Thus, all new contributions are considered being made under MIT license.
-
+Since version 3.6, JabRef is licensed under the [MIT license](https://tldrlegal.com/license/mit-license).
See the [LICENSE.md](LICENSE.md) for the full MIT license.
JabRef also uses libraries distributed by other parties.
diff --git a/build.gradle b/build.gradle
index 06580ec..91a803b 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,5 +1,7 @@
import org.gradle.internal.os.OperatingSystem
+// to update the gradle wrapper, execute ./gradlew wrapper --gradle-version 3.0
+
buildscript {
repositories {
maven {
@@ -12,13 +14,18 @@ buildscript {
}
plugins {
- id "com.install4j.gradle" version "6.1.2"
- id 'com.github.johnrengelman.shadow' version '1.2.3'
- // TODO replaced by spotless plugin, needs to be updated
- id "com.github.youribonnaffe.gradle.format" version "1.5"
+ id 'com.gradle.build-scan' version '1.3'
+ id "com.install4j.gradle" version "6.1.3"
+ id 'com.github.johnrengelman.shadow' version '1.2.4'
// If this is updated to 0.0.9, check configurations.errorprone
id "net.ltgt.errorprone" version "0.0.8"
- id 'me.champeau.gradle.jmh' version '0.3.0'
+ id 'me.champeau.gradle.jmh' version '0.3.1'
+}
+
+// use the gradle build scan feature: https://scans.gradle.com/get-started
+buildScan {
+ licenseAgreementUrl = 'https://gradle.com/terms-of-service'
+ licenseAgree = 'yes'
}
apply plugin: "java"
@@ -35,8 +42,8 @@ apply from: 'localization.gradle'
apply from: 'xjc.gradle'
group = "net.sf.jabref"
-version = "3.6"
-project.ext.threeDotVersion = "3.6.0.0"
+version = "3.8-dev"
+project.ext.threeDotVersion = "3.7.0.1"
project.ext.install4jDir = hasProperty("install4jDir") ? getProperty("install4jDir") : (OperatingSystem.current().isWindows() ? 'C:/Program Files/install4j6' : 'install4j6')
sourceCompatibility = 1.8
targetCompatibility = 1.8
@@ -46,24 +53,17 @@ install4j {
installDir = file(project.ext.install4jDir)
}
-task wrapper(type: Wrapper) {
- gradleVersion = '2.14.1'
-}
-
repositories {
jcenter()
+ maven {
+ url 'https://oss.sonatype.org/content/groups/public'
+ }
}
configurations {
antlr3
antlr4
-
- databaseTestCompile.extendsFrom testCompile
- databaseTestRuntime.extendsFrom testRuntime
-
- integrationTestCompile.extendsFrom testCompile
- integrationTestRuntime.extendsFrom testRuntime
}
dependencies {
@@ -71,7 +71,9 @@ dependencies {
compile 'com.jgoodies:jgoodies-forms:1.9.0'
compile 'com.jgoodies:jgoodies-looks:2.7.0'
- compile 'org.swinglabs:swingx:1.6.1' // do not update, 1.6.5.1 is broken
+ // Later versions cannot be used. Tested until 1.6.5-1.
+ // See https://github.com/JabRef/jabref/issues/271 for details
+ compile 'org.swinglabs.swingx:swingx-core:1.6.4'
// update to 2.0.x is not possible - see https://github.com/JabRef/jabref/pull/1096#issuecomment-208857517
compile 'org.apache.pdfbox:pdfbox:1.8.12'
@@ -88,39 +90,39 @@ dependencies {
compile 'org.openoffice:ridl:4.1.2'
compile 'org.openoffice:unoil:4.1.2'
- compile 'com.googlecode.java-diff-utils:diffutils:1.3.0'
-
antlr3 'org.antlr:antlr:3.5.2'
compile 'org.antlr:antlr-runtime:3.5.2'
antlr4 'org.antlr:antlr4:4.5.3'
compile 'org.antlr:antlr4-runtime:4.5.3'
- // VersionEye states that 6.0.3 is the most recent version, but http://dev.mysql.com/downloads/connector/j/ shows that as "Development Release"
- compile 'mysql:mysql-connector-java:5.1.39'
+ // VersionEye states that 6.0.5 is the most recent version, but http://dev.mysql.com/downloads/connector/j/ shows that as "Development Release"
+ compile 'mysql:mysql-connector-java:5.1.40'
- compile 'org.postgresql:postgresql:9.4.1209'
+ compile 'org.postgresql:postgresql:9.4.1210'
compile 'net.java.dev.glazedlists:glazedlists_java15:1.9.1'
compile fileTree(dir: 'lib', includes: ['*.jar'])
- compile 'com.google.guava:guava:19.0'
+ compile 'com.google.guava:guava:20.0'
compile 'commons-logging:commons-logging:1.2'
- compile 'org.apache.commons:commons-lang3:3.4'
+ compile 'org.apache.commons:commons-lang3:3.5'
- compile 'org.jsoup:jsoup:1.9.2'
+ compile 'org.jsoup:jsoup:1.10.1'
compile 'com.mashape.unirest:unirest-java:1.4.9'
- compile 'info.debatty:java-string-similarity:0.16'
+ compile 'info.debatty:java-string-similarity:0.19'
- compile 'org.apache.logging.log4j:log4j-jcl:2.6.2'
- compile 'org.apache.logging.log4j:log4j-api:2.6.2'
- compile 'org.apache.logging.log4j:log4j-core:2.6.2'
+ compile 'org.apache.logging.log4j:log4j-jcl:2.7'
+ compile 'org.apache.logging.log4j:log4j-api:2.7'
+ compile 'org.apache.logging.log4j:log4j-core:2.7'
+ compile 'org.xmlunit:xmlunit-core:2.3.0'
+ compile 'org.xmlunit:xmlunit-matchers:2.3.0'
testCompile 'junit:junit:4.12'
- testCompile 'org.mockito:mockito-core:1.10.19'
- testCompile 'com.github.tomakehurst:wiremock:2.1.11'
+ testCompile 'org.mockito:mockito-core:2.2.28'
+ testCompile 'com.github.tomakehurst:wiremock:2.4.1'
testCompile 'org.assertj:assertj-swing-junit:3.4.0'
}
@@ -130,20 +132,6 @@ sourceSets {
srcDirs = ["src/main/java", "src/main/gen"]
}
}
- databaseTest {
- java {
- compileClasspath += main.output + test.output
- runtimeClasspath += main.output + test.output
- }
- }
- integrationTest {
- java {
- compileClasspath += main.output + test.output
- runtimeClasspath += main.output + test.output
- srcDir file('src/integrationTest/java')
- }
- resources.srcDir file('src/integrationTest/resources')
- }
}
processResources {
@@ -152,7 +140,9 @@ processResources {
"year": String.valueOf(Calendar.getInstance().get(Calendar.YEAR)),
"authors": new File('AUTHORS').readLines().findAll { !it.startsWith("#") }.join(", "),
"developers": new File('DEVELOPERS').readLines().findAll { !it.startsWith("#") }.join(", "))
+ filteringCharset = 'UTF-8'
}
+ filteringCharset = 'UTF-8'
filesMatching("resource/**/meta.xml") {
expand version: project.version
@@ -228,22 +218,40 @@ javadoc {
}
test {
+ useJUnit {
+ excludeCategories 'net.sf.jabref.testutils.category.DatabaseTests'
+ excludeCategories 'net.sf.jabref.testutils.category.FetcherTests'
+ excludeCategories 'net.sf.jabref.testutils.category.GUITests'
+ }
testLogging {
events "failed"
exceptionFormat "full"
}
}
-
task databaseTest(type: Test) {
- testClassesDir = sourceSets.databaseTest.output.classesDir
- classpath = sourceSets.databaseTest.runtimeClasspath
+ useJUnit {
+ includeCategories 'net.sf.jabref.testutils.category.DatabaseTests'
+ }
+}
+
+task fetcherTest(type: Test) {
+ useJUnit {
+ includeCategories 'net.sf.jabref.testutils.category.FetcherTests'
+ }
+}
+
+task guiTest(type: Test) {
+ useJUnit {
+ includeCategories 'net.sf.jabref.testutils.category.GUITests'
+ }
}
-task integrationTest(type: Test) {
- testClassesDir = sourceSets.integrationTest.output.classesDir
- classpath = sourceSets.integrationTest.runtimeClasspath
+task copyTestResources(type: Copy) {
+ from "${projectDir}/src/test/resources"
+ into "${buildDir}/classes/test"
}
+processTestResources.dependsOn copyTestResources
tasks.withType(Test) {
reports.html.destination = file("${reporting.baseDir}/${name}")
@@ -259,13 +267,6 @@ jacocoTestReport {
}
}
-// enables `gradlew format`. Currently `LabelPatternUtil.java` is destroyed. Use with care!
-format {
- configurationFile = file('ide-settings/formatter_settings.xml')
- // default: reformat main and test
- //files = sourceSets.main.java
-}
-
shadowJar {
classifier 'fat'
@@ -334,6 +335,8 @@ if (hasProperty('dev')) {
task media(type: com.install4j.gradle.Install4jTask, dependsOn: "releaseJar") {
projectFile = file('jabref.install4j')
release = project.version
+ winKeystorePassword = System.getenv('CERTIFICATE_PW')
+ macKeystorePassword = System.getenv('CERTIFICATE_PW')
variables = [
versionFourDots: project.ext.threeDotVersion,
buildFileName : jar.archiveName,
@@ -375,17 +378,6 @@ task releaseJar(dependsOn: "shadowJar") {
}
}
-// fetch all dependencies to speedup CircleCI build
-// this is necessary until https://discuss.circleci.com/t/effective-caching-for-gradle/540 is resolved
-// see http://stackoverflow.com/a/27455099/873282 for an inspiration of this task
-// better solution: https://discuss.gradle.org/t/how-to-download-maven-dependencies-into-project-local-directory-and-set-eclipse-classpath/9851
-task getdeps(type: Copy) {
- from(configurations.compile + configurations.antlr3 + configurations.antlr4 + configurations.testCompile) {
- include "*.jar"
- }
- into 'build/tmp/alldeps/'
-}
-
jmh {
warmupIterations = 5
iterations = 10
diff --git a/buildres/jabref-cert-2016.p12.enc b/buildres/jabref-cert-2016.p12.enc
new file mode 100644
index 0000000..6277bb8
Binary files /dev/null and b/buildres/jabref-cert-2016.p12.enc differ
diff --git a/circle.yml b/circle.yml
index 994b47d..148d880 100644
--- a/circle.yml
+++ b/circle.yml
@@ -6,11 +6,14 @@ machine:
dependencies:
pre:
+ # update locally with:
+ # openssl aes-256-cbc -e -in ./buildres/jabref-cert-2016.p12 -out jabref-cert-2016.p12.enc -k {PASSWORD}
+ - openssl aes-256-cbc -d -in ./buildres/jabref-cert-2016.p12.enc -out ./buildres/jabref-cert-2016.p12 -k $CERTIFICATE
- scripts/prepare-install4j.sh
- - install4j6/bin/install4jc --verbose --license=$INSTALL4J_KEY
+ - install4j6/bin/install4jc --verbose --license=$INSTALL4J_KEY --win-keystore-password $CERTIFICATE_PW --mac-keystore-password $CERTIFICATE_PW
override:
# We do this to decrease build time by using CircleCI's cache. See https://discuss.circleci.com/t/effective-caching-for-gradle/540 for a longer motivation.
- - ./gradlew getdeps
+ - ./gradlew compileJava
cache_directories:
- "~/.install4j6"
- "~/downloads"
diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml
index f415a26..80e03e1 100644
--- a/config/checkstyle/checkstyle.xml
+++ b/config/checkstyle/checkstyle.xml
@@ -26,6 +26,10 @@
http://checkstyle.sourceforge.net/5.x/config.html#Checker
<property name="basedir" value="${basedir}"/>
-->
+
+ <module name="Header">
+ <property name="header" value=""/>
+ </module>
<module name="TreeWalker">
diff --git a/eclipse.gradle b/eclipse.gradle
index c17c1c2..d3efd8f 100644
--- a/eclipse.gradle
+++ b/eclipse.gradle
@@ -3,8 +3,8 @@ apply plugin: "eclipse"
// ensure that source code is generated, otherwise class `BstLexer` cannot be found
tasks.eclipseClasspath.dependsOn "generateSource"
-// workaround until https://issues.gradle.org/browse/GRADLE-2274 is resolved
-eclipseJdt << {
+// workaround until https://github.com/gradle/gradle/issues/898 is resolved
+eclipseJdt.doLast {
File f = file('.settings/org.eclipse.core.resources.prefs')
f.write('eclipse.preferences.version=1\n')
f.append('encoding/<project>=UTF-8')
@@ -158,7 +158,7 @@ tasks.eclipse.doFirst {
org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
org.eclipse.jdt.core.formatter.blank_lines_before_method=1
- org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=2
+ org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
org.eclipse.jdt.core.formatter.blank_lines_before_package=0
org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
@@ -392,7 +392,7 @@ tasks.eclipse.doFirst {
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.join_lines_in_comments=false
- org.eclipse.jdt.core.formatter.join_wrapped_lines=true
+ org.eclipse.jdt.core.formatter.join_wrapped_lines=false
org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
diff --git a/external-libraries.txt b/external-libraries.txt
index e2a892c..52518a7 100644
--- a/external-libraries.txt
+++ b/external-libraries.txt
@@ -5,11 +5,9 @@ This file is manually kept in sync with build.gradle and the binary jars contain
## License
- * GPLv2+ means "GPLv2 or later"
- * GPLv2! means "exactly version 2.0 of GPL"
- * GPLv2 means, we haven't checked whether later options are allowed
- * similar for LGPL and other version of GPL
-
+We follow the [SPDX license identifiers](https://spdx.org/licenses/).
+In case you add a library, please use these identifiers.
+For instance, "BSD" is not exactg enough, there are numerous variants out there: BSD-2-Clouse, BSD-3-Clause-No-Nuclear-Warranty, ...
# Fonts and Icons
@@ -40,17 +38,12 @@ License: BSD
Id: commons-cli:commons-cli
Project: Apache Commons CLI
URL: http://commons.apache.org/cli/
-License: Apache 2.0
+License: Apache-2.0
Id: commons-logging:commons-logging
Project: Apache Commons Logging
URL: http://commons.apache.org/logging/
-License: Apache 2.0
-
-Id: com.googlecode.java-diff-utils
-Project: java-diff-utils
-URL: http://code.google.com/p/java-diff-utils/
-License: Apache 2.0
+License: Apache-2.0
Id: com.jgoodies:jgoodies-common
Project: JGoodies Common
@@ -80,32 +73,32 @@ License: MIT
Id: mysql:mysql-connector-java
Project: MySQL Connector/J
URL: http://www.mysql.de/downloads/connector/j/
-License: GPLv2! and Oracle's FOSS License Exception (http://www.mysql.com/about/legal/licensing/foss-exception/) allowing GPLv3
+License: GPL-2.0 and Oracle's FOSS License Exception (http://www.mysql.com/about/legal/licensing/foss-exception/) allowing GPLv3
Id: net.java.dev.glazedlists:glazedlists_java15
Project: Glazed Lists
URL: http://www.glazedlists.com/
-License: LPGL 2.1! (not explicitly, but no comments in the source header) and MPL
+License: LGPL-2.1 (not explicitly, but no comments in the source header) and MPL-2.0
Id: org.apache.logging.log4j
Project: Apache Log2j 2
URL: http://logging.apache.org/log4j/2.x/
-License: Apache 2.0
+License: Apache-2.0
Id: org.apache.pdfbox:fontbox
Project: Apache PDFBox
URL: http://pdfbox.apache.org
-License: Apache 2.0
+License: Apache-2.0
Id: org.apache.pdfbox:jempbox
Project: Apache PDFBox
URL: http://pdfbox.apache.org
-License: Apache 2.0
+License: Apache-2.0
Id: org.apache.pdfbox:pdfbox
Project: Apache PDFBox
URL: http://pdfbox.apache.org
-License: Apache 2.0
+License: Apache-2.0
Id: org.bouncycastle:bcprov-jdk15on
Project: The Legion of the Bouncy Castle
@@ -125,27 +118,22 @@ License: LGPL 3.0
Id: org.openoffice:jurt
Project: OpenOffice.org
URL: http://www.openoffice.org/api/SDK
-License: LGPL 3.0
+License: Apache-2.0
Id: org.openoffice:ridl
Project: OpenOffice.org
URL: http://www.openoffice.org/api/SDK
-License: LGPL 3.0
+License: Apache-2.0
Id: org.openoffice:unoil
Project: OpenOffice.org
URL: http://www.openoffice.org/api/SDK
-License: LGPL 3.0
+License: Apache-2.0
Id: org.swinglabs.swingx:swingx-core
Project: SwingX
URL: https://swingx.java.net/
-License: LGPL 3.0
-
-Id: org.postgresql:postgresql
-Project: PostgreSQL JDBC Driver
-URL: http://jdbc.postgresql.org/download.html
-License: BSD
+License: LGPL-3.0
Id: microba
Path: lib/microba.jar
@@ -157,6 +145,6 @@ Id: spin
Path: lib/spin.jar
Project: Spin
URL: http://spin.sourceforge.net/
-License: LGPL 2.1+
+License: LGPL-2.1+
The last entry has to end with an empty line. Otherwise the entry is not present in About.html.
diff --git a/gradlew b/gradlew
index 27309d9..4ef3a87 100755
--- a/gradlew
+++ b/gradlew
@@ -1,4 +1,4 @@
-#!/usr/bin/env bash
+#!/usr/bin/env sh
##############################################################################
##
@@ -154,11 +154,18 @@ if $cygwin ; then
esac
fi
-# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
-function splitJvmOpts() {
- JVM_OPTS=("$@")
-}
-eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
-JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+# Escape application args
+for s in "${@}" ; do
+ s=\"$s\"
+ APP_ARGS=$APP_ARGS" "$s
+done
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- "$DEFAULT_JVM_OPTS" "$JAVA_OPTS" "$GRADLE_OPTS" "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
-exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
index 832fdb6..f955316 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -49,7 +49,6 @@ goto fail
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
-if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
@@ -60,11 +59,6 @@ set _SKIP=2
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
-goto execute
-
-:4NT_args
- at rem Get arguments from the 4NT Shell from JP Software
-set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
diff --git a/jabref.install4j b/jabref.install4j
index 0433156..210e855 100644
--- a/jabref.install4j
+++ b/jabref.install4j
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
-<install4j version="6.1.2" transformSequenceNumber="5">
- <directoryPresets config="./buildres/JabRef.VisualElementsManifest.xml" />
+<install4j version="6.1.3" transformSequenceNumber="5">
+ <directoryPresets config="build/releases/${compiler:buildFileName}" />
<application name="JabRef" distributionSourceDir="" applicationId="0034-7691-1464-4754" mediaDir="build/install4j" mediaFilePattern="${compiler:sys.shortName}_${compiler:sys.platform}_${compiler:sys.version}" compression="6" lzmaCompression="false" pack200Compression="false" excludeSignedFromPacking="true" commonExternalFiles="false" createMd5Sums="true" shrinkRuntime="true" shortName="JabRef" publisher="JabRef Community" publisherWeb="http://www.jabref.org/" version="DEV" allPathsRela [...]
<languages skipLanguageSelection="true" languageSelectionInPrincipalLanguage="false">
<principalLanguage id="en" customLocalizationFile="" />
@@ -41,7 +41,7 @@
<variable name="version" value="3.1dev" description="" category="" />
</variables>
<mergedProjects />
- <codeSigning macEnabled="false" macPkcs12File="" windowsEnabled="false" windowsKeySource="pkcs12" windowsPvkFile="" windowsSpcFile="" windowsPkcs12File="" />
+ <codeSigning macEnabled="true" macPkcs12File="./buildres/jabref-cert-2016.p12" windowsEnabled="true" windowsKeySource="pkcs12" windowsPvkFile="" windowsSpcFile="" windowsPkcs12File="./buildres/jabref-cert-2016.p12" />
</application>
<files keepModificationTimes="false" missingFilesStrategy="warn" globalExcludeSuffixes="" defaultOverwriteMode="4" defaultUninstallMode="0" launcherOverwriteMode="3" defaultFileMode="644" defaultDirMode="755">
<filesets />
@@ -51,14 +51,14 @@
</mountPoints>
<entries>
<fileEntry mountPoint="22" file="build/releases/${compiler:buildFileName}" overwriteMode="4" shared="false" fileMode="644" uninstallMode="0" overrideFileMode="false" overrideOverwriteMode="false" overrideUninstallMode="false" />
- <fileEntry mountPoint="22" file="./LICENSE" overwriteMode="4" shared="false" fileMode="644" uninstallMode="0" overrideFileMode="false" overrideOverwriteMode="false" overrideUninstallMode="false" />
+ <fileEntry mountPoint="22" file="./LICENSE.md" overwriteMode="4" shared="false" fileMode="644" uninstallMode="0" overrideFileMode="false" overrideOverwriteMode="false" overrideUninstallMode="false" />
<fileEntry mountPoint="22" file="./AUTHORS" overwriteMode="4" shared="false" fileMode="644" uninstallMode="0" overrideFileMode="false" overrideOverwriteMode="false" overrideUninstallMode="false" />
<fileEntry mountPoint="22" file="./buildres/JabRef.VisualElementsManifest.xml" overwriteMode="4" shared="false" fileMode="644" uninstallMode="0" overrideFileMode="false" overrideOverwriteMode="false" overrideUninstallMode="false" />
</entries>
<components />
</files>
<launchers>
- <launcher name="JabRef" id="23" customizedId="" external="false" excludeFromMenu="false" unixMode="755" menuName="" icnsFile="./src/main/resources/icons/jabref.icns" customMacBundleIdentifier="false" macBundleIdentifier="" swtApp="false" fileset="" macBundleBinary="JavaApplicationStub" addMacEntitlements="false" macEntitlementsFile="" useCustomMacosExecutableName="false" customMacosExecutableName="" useJavaMinVersionOverride="false" javaMinVersionOverride="" useJavaMaxVersionOverride [...]
+ <launcher name="JabRef" id="23" customizedId="" external="false" excludeFromMenu="false" unixMode="755" unixAutoStart="true" menuName="" icnsFile="./src/main/resources/icons/jabref.icns" customMacBundleIdentifier="false" macBundleIdentifier="" swtApp="false" fileset="" macBundleBinary="JavaApplicationStub" addMacEntitlements="false" macEntitlementsFile="" useCustomMacosExecutableName="false" customMacosExecutableName="" useJavaMinVersionOverride="false" javaMinVersionOverride="" useJ [...]
<executable name="JabRef" type="1" iconSet="true" iconFile="./src/main/resources/icons/jabref.ico" executableDir="" redirectStderr="true" stderrFile="error.log" stderrMode="overwrite" redirectStdout="false" stdoutFile="output.log" stdoutMode="overwrite" failOnStderrOutput="true" executableMode="1" changeWorkingDirectory="true" workingDirectory="." singleInstance="false" serviceStartType="2" serviceDependencies="" serviceDescription="" jreLocation="" executionLevel="asInvoker" check [...]
<versionInfo include="true" fileVersion="${compiler:versionFourDots}" fileDescription="${compiler:sys.fullName}" legalCopyright="${compiler:sys.fullName}" internalName="${compiler:sys.fullName}" productName="" />
</executable>
@@ -708,7 +708,7 @@ return true;</string>
</applications>
</installerGui>
<mediaSets>
- <windows name="Windows 32bit JRE" id="73" customizedId="" mediaFileName="${compiler:sys.shortName}_${compiler:sys.platform}_${compiler:version}" installDir="${compiler:sys.shortName}" overridePrincipalLanguage="false" jreBitType="32" runPostProcessor="false" postProcessor="" failOnPostProcessorError="false" useLegacyMediaFileIds="false" legacyMediaFileIds="" downloadURL="" includeAllDownloadableComponents="false" includedJRE="windows-x86-1.8.0_102" manualJREEntry="false" bundleType=" [...]
+ <windows name="Windows 32bit JRE" id="73" customizedId="" mediaFileName="${compiler:sys.shortName}_${compiler:sys.platform}_${compiler:version}" installDir="${compiler:sys.shortName}" overridePrincipalLanguage="false" jreBitType="32" runPostProcessor="false" postProcessor="" failOnPostProcessorError="false" useLegacyMediaFileIds="false" legacyMediaFileIds="" downloadURL="" includeAllDownloadableComponents="false" includedJRE="windows-x86-1.8.0_112" manualJREEntry="false" bundleType=" [...]
<excludedComponents />
<includedDownloadableComponents />
<excludedLaunchers />
@@ -721,7 +721,7 @@ return true;</string>
<customAttributes />
</autoUpdate>
</windows>
- <windows name="Windows 64bit JRE" id="74" customizedId="" mediaFileName="${compiler:sys.shortName}_${compiler:sys.platform}_${compiler:version}" installDir="${compiler:sys.shortName}" overridePrincipalLanguage="false" jreBitType="64" runPostProcessor="false" postProcessor="" failOnPostProcessorError="false" useLegacyMediaFileIds="false" legacyMediaFileIds="" downloadURL="" includeAllDownloadableComponents="false" includedJRE="windows-amd64-1.8.0_102" manualJREEntry="false" bundleType [...]
+ <windows name="Windows 64bit JRE" id="74" customizedId="" mediaFileName="${compiler:sys.shortName}_${compiler:sys.platform}_${compiler:version}" installDir="${compiler:sys.shortName}" overridePrincipalLanguage="false" jreBitType="64" runPostProcessor="false" postProcessor="" failOnPostProcessorError="false" useLegacyMediaFileIds="false" legacyMediaFileIds="" downloadURL="" includeAllDownloadableComponents="false" includedJRE="windows-amd64-1.8.0_112" manualJREEntry="false" bundleType [...]
<excludedComponents />
<includedDownloadableComponents />
<excludedLaunchers />
@@ -734,7 +734,7 @@ return true;</string>
<customAttributes />
</autoUpdate>
</windows>
- <macos name="Mac OS X Single Bundle JRE" id="77" customizedId="" mediaFileName="${compiler:sys.shortName}_${compiler:sys.platform}_${compiler:version}" installDir="${compiler:sys.fullName}" overridePrincipalLanguage="false" jreBitType="all" runPostProcessor="false" postProcessor="" failOnPostProcessorError="false" useLegacyMediaFileIds="false" legacyMediaFileIds="" downloadURL="" includeAllDownloadableComponents="false" includedJRE="macosx-amd64-1.8.0_102_unpacked" manualJREEntry="fa [...]
+ <macos name="Mac OS X Single Bundle JRE" id="77" customizedId="" mediaFileName="${compiler:sys.shortName}_${compiler:sys.platform}_${compiler:version}" installDir="${compiler:sys.fullName}" overridePrincipalLanguage="false" jreBitType="all" runPostProcessor="false" postProcessor="" failOnPostProcessorError="false" useLegacyMediaFileIds="false" legacyMediaFileIds="" downloadURL="" includeAllDownloadableComponents="false" includedJRE="macosx-amd64-1.8.0_112_unpacked" manualJREEntry="fa [...]
<excludedComponents />
<includedDownloadableComponents />
<excludedBeans />
diff --git a/licenses/de.undercouch.citeproc-java.txt b/licenses/de.undercouch.citeproc-java.txt
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/licenses/de.undercouch.citeproc-java.txt
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/licenses/org.citationstyles.locales.txt b/licenses/org.citationstyles.locales.txt
new file mode 100644
index 0000000..604209a
--- /dev/null
+++ b/licenses/org.citationstyles.locales.txt
@@ -0,0 +1,359 @@
+Creative Commons Legal Code
+
+Attribution-ShareAlike 3.0 Unported
+
+ CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
+ LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN
+ ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
+ INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
+ REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR
+ DAMAGES RESULTING FROM ITS USE.
+
+License
+
+THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE
+COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY
+COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS
+AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
+
+BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE
+TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY
+BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS
+CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND
+CONDITIONS.
+
+1. Definitions
+
+ a. "Adaptation" means a work based upon the Work, or upon the Work and
+ other pre-existing works, such as a translation, adaptation,
+ derivative work, arrangement of music or other alterations of a
+ literary or artistic work, or phonogram or performance and includes
+ cinematographic adaptations or any other form in which the Work may be
+ recast, transformed, or adapted including in any form recognizably
+ derived from the original, except that a work that constitutes a
+ Collection will not be considered an Adaptation for the purpose of
+ this License. For the avoidance of doubt, where the Work is a musical
+ work, performance or phonogram, the synchronization of the Work in
+ timed-relation with a moving image ("synching") will be considered an
+ Adaptation for the purpose of this License.
+ b. "Collection" means a collection of literary or artistic works, such as
+ encyclopedias and anthologies, or performances, phonograms or
+ broadcasts, or other works or subject matter other than works listed
+ in Section 1(f) below, which, by reason of the selection and
+ arrangement of their contents, constitute intellectual creations, in
+ which the Work is included in its entirety in unmodified form along
+ with one or more other contributions, each constituting separate and
+ independent works in themselves, which together are assembled into a
+ collective whole. A work that constitutes a Collection will not be
+ considered an Adaptation (as defined below) for the purposes of this
+ License.
+ c. "Creative Commons Compatible License" means a license that is listed
+ at https://creativecommons.org/compatiblelicenses that has been
+ approved by Creative Commons as being essentially equivalent to this
+ License, including, at a minimum, because that license: (i) contains
+ terms that have the same purpose, meaning and effect as the License
+ Elements of this License; and, (ii) explicitly permits the relicensing
+ of adaptations of works made available under that license under this
+ License or a Creative Commons jurisdiction license with the same
+ License Elements as this License.
+ d. "Distribute" means to make available to the public the original and
+ copies of the Work or Adaptation, as appropriate, through sale or
+ other transfer of ownership.
+ e. "License Elements" means the following high-level license attributes
+ as selected by Licensor and indicated in the title of this License:
+ Attribution, ShareAlike.
+ f. "Licensor" means the individual, individuals, entity or entities that
+ offer(s) the Work under the terms of this License.
+ g. "Original Author" means, in the case of a literary or artistic work,
+ the individual, individuals, entity or entities who created the Work
+ or if no individual or entity can be identified, the publisher; and in
+ addition (i) in the case of a performance the actors, singers,
+ musicians, dancers, and other persons who act, sing, deliver, declaim,
+ play in, interpret or otherwise perform literary or artistic works or
+ expressions of folklore; (ii) in the case of a phonogram the producer
+ being the person or legal entity who first fixes the sounds of a
+ performance or other sounds; and, (iii) in the case of broadcasts, the
+ organization that transmits the broadcast.
+ h. "Work" means the literary and/or artistic work offered under the terms
+ of this License including without limitation any production in the
+ literary, scientific and artistic domain, whatever may be the mode or
+ form of its expression including digital form, such as a book,
+ pamphlet and other writing; a lecture, address, sermon or other work
+ of the same nature; a dramatic or dramatico-musical work; a
+ choreographic work or entertainment in dumb show; a musical
+ composition with or without words; a cinematographic work to which are
+ assimilated works expressed by a process analogous to cinematography;
+ a work of drawing, painting, architecture, sculpture, engraving or
+ lithography; a photographic work to which are assimilated works
+ expressed by a process analogous to photography; a work of applied
+ art; an illustration, map, plan, sketch or three-dimensional work
+ relative to geography, topography, architecture or science; a
+ performance; a broadcast; a phonogram; a compilation of data to the
+ extent it is protected as a copyrightable work; or a work performed by
+ a variety or circus performer to the extent it is not otherwise
+ considered a literary or artistic work.
+ i. "You" means an individual or entity exercising rights under this
+ License who has not previously violated the terms of this License with
+ respect to the Work, or who has received express permission from the
+ Licensor to exercise rights under this License despite a previous
+ violation.
+ j. "Publicly Perform" means to perform public recitations of the Work and
+ to communicate to the public those public recitations, by any means or
+ process, including by wire or wireless means or public digital
+ performances; to make available to the public Works in such a way that
+ members of the public may access these Works from a place and at a
+ place individually chosen by them; to perform the Work to the public
+ by any means or process and the communication to the public of the
+ performances of the Work, including by public digital performance; to
+ broadcast and rebroadcast the Work by any means including signs,
+ sounds or images.
+ k. "Reproduce" means to make copies of the Work by any means including
+ without limitation by sound or visual recordings and the right of
+ fixation and reproducing fixations of the Work, including storage of a
+ protected performance or phonogram in digital form or other electronic
+ medium.
+
+2. Fair Dealing Rights. Nothing in this License is intended to reduce,
+limit, or restrict any uses free from copyright or rights arising from
+limitations or exceptions that are provided for in connection with the
+copyright protection under copyright law or other applicable laws.
+
+3. License Grant. Subject to the terms and conditions of this License,
+Licensor hereby grants You a worldwide, royalty-free, non-exclusive,
+perpetual (for the duration of the applicable copyright) license to
+exercise the rights in the Work as stated below:
+
+ a. to Reproduce the Work, to incorporate the Work into one or more
+ Collections, and to Reproduce the Work as incorporated in the
+ Collections;
+ b. to create and Reproduce Adaptations provided that any such Adaptation,
+ including any translation in any medium, takes reasonable steps to
+ clearly label, demarcate or otherwise identify that changes were made
+ to the original Work. For example, a translation could be marked "The
+ original work was translated from English to Spanish," or a
+ modification could indicate "The original work has been modified.";
+ c. to Distribute and Publicly Perform the Work including as incorporated
+ in Collections; and,
+ d. to Distribute and Publicly Perform Adaptations.
+ e. For the avoidance of doubt:
+
+ i. Non-waivable Compulsory License Schemes. In those jurisdictions in
+ which the right to collect royalties through any statutory or
+ compulsory licensing scheme cannot be waived, the Licensor
+ reserves the exclusive right to collect such royalties for any
+ exercise by You of the rights granted under this License;
+ ii. Waivable Compulsory License Schemes. In those jurisdictions in
+ which the right to collect royalties through any statutory or
+ compulsory licensing scheme can be waived, the Licensor waives the
+ exclusive right to collect such royalties for any exercise by You
+ of the rights granted under this License; and,
+ iii. Voluntary License Schemes. The Licensor waives the right to
+ collect royalties, whether individually or, in the event that the
+ Licensor is a member of a collecting society that administers
+ voluntary licensing schemes, via that society, from any exercise
+ by You of the rights granted under this License.
+
+The above rights may be exercised in all media and formats whether now
+known or hereafter devised. The above rights include the right to make
+such modifications as are technically necessary to exercise the rights in
+other media and formats. Subject to Section 8(f), all rights not expressly
+granted by Licensor are hereby reserved.
+
+4. Restrictions. The license granted in Section 3 above is expressly made
+subject to and limited by the following restrictions:
+
+ a. You may Distribute or Publicly Perform the Work only under the terms
+ of this License. You must include a copy of, or the Uniform Resource
+ Identifier (URI) for, this License with every copy of the Work You
+ Distribute or Publicly Perform. You may not offer or impose any terms
+ on the Work that restrict the terms of this License or the ability of
+ the recipient of the Work to exercise the rights granted to that
+ recipient under the terms of the License. You may not sublicense the
+ Work. You must keep intact all notices that refer to this License and
+ to the disclaimer of warranties with every copy of the Work You
+ Distribute or Publicly Perform. When You Distribute or Publicly
+ Perform the Work, You may not impose any effective technological
+ measures on the Work that restrict the ability of a recipient of the
+ Work from You to exercise the rights granted to that recipient under
+ the terms of the License. This Section 4(a) applies to the Work as
+ incorporated in a Collection, but this does not require the Collection
+ apart from the Work itself to be made subject to the terms of this
+ License. If You create a Collection, upon notice from any Licensor You
+ must, to the extent practicable, remove from the Collection any credit
+ as required by Section 4(c), as requested. If You create an
+ Adaptation, upon notice from any Licensor You must, to the extent
+ practicable, remove from the Adaptation any credit as required by
+ Section 4(c), as requested.
+ b. You may Distribute or Publicly Perform an Adaptation only under the
+ terms of: (i) this License; (ii) a later version of this License with
+ the same License Elements as this License; (iii) a Creative Commons
+ jurisdiction license (either this or a later license version) that
+ contains the same License Elements as this License (e.g.,
+ Attribution-ShareAlike 3.0 US)); (iv) a Creative Commons Compatible
+ License. If you license the Adaptation under one of the licenses
+ mentioned in (iv), you must comply with the terms of that license. If
+ you license the Adaptation under the terms of any of the licenses
+ mentioned in (i), (ii) or (iii) (the "Applicable License"), you must
+ comply with the terms of the Applicable License generally and the
+ following provisions: (I) You must include a copy of, or the URI for,
+ the Applicable License with every copy of each Adaptation You
+ Distribute or Publicly Perform; (II) You may not offer or impose any
+ terms on the Adaptation that restrict the terms of the Applicable
+ License or the ability of the recipient of the Adaptation to exercise
+ the rights granted to that recipient under the terms of the Applicable
+ License; (III) You must keep intact all notices that refer to the
+ Applicable License and to the disclaimer of warranties with every copy
+ of the Work as included in the Adaptation You Distribute or Publicly
+ Perform; (IV) when You Distribute or Publicly Perform the Adaptation,
+ You may not impose any effective technological measures on the
+ Adaptation that restrict the ability of a recipient of the Adaptation
+ from You to exercise the rights granted to that recipient under the
+ terms of the Applicable License. This Section 4(b) applies to the
+ Adaptation as incorporated in a Collection, but this does not require
+ the Collection apart from the Adaptation itself to be made subject to
+ the terms of the Applicable License.
+ c. If You Distribute, or Publicly Perform the Work or any Adaptations or
+ Collections, You must, unless a request has been made pursuant to
+ Section 4(a), keep intact all copyright notices for the Work and
+ provide, reasonable to the medium or means You are utilizing: (i) the
+ name of the Original Author (or pseudonym, if applicable) if supplied,
+ and/or if the Original Author and/or Licensor designate another party
+ or parties (e.g., a sponsor institute, publishing entity, journal) for
+ attribution ("Attribution Parties") in Licensor's copyright notice,
+ terms of service or by other reasonable means, the name of such party
+ or parties; (ii) the title of the Work if supplied; (iii) to the
+ extent reasonably practicable, the URI, if any, that Licensor
+ specifies to be associated with the Work, unless such URI does not
+ refer to the copyright notice or licensing information for the Work;
+ and (iv) , consistent with Ssection 3(b), in the case of an
+ Adaptation, a credit identifying the use of the Work in the Adaptation
+ (e.g., "French translation of the Work by Original Author," or
+ "Screenplay based on original Work by Original Author"). The credit
+ required by this Section 4(c) may be implemented in any reasonable
+ manner; provided, however, that in the case of a Adaptation or
+ Collection, at a minimum such credit will appear, if a credit for all
+ contributing authors of the Adaptation or Collection appears, then as
+ part of these credits and in a manner at least as prominent as the
+ credits for the other contributing authors. For the avoidance of
+ doubt, You may only use the credit required by this Section for the
+ purpose of attribution in the manner set out above and, by exercising
+ Your rights under this License, You may not implicitly or explicitly
+ assert or imply any connection with, sponsorship or endorsement by the
+ Original Author, Licensor and/or Attribution Parties, as appropriate,
+ of You or Your use of the Work, without the separate, express prior
+ written permission of the Original Author, Licensor and/or Attribution
+ Parties.
+ d. Except as otherwise agreed in writing by the Licensor or as may be
+ otherwise permitted by applicable law, if You Reproduce, Distribute or
+ Publicly Perform the Work either by itself or as part of any
+ Adaptations or Collections, You must not distort, mutilate, modify or
+ take other derogatory action in relation to the Work which would be
+ prejudicial to the Original Author's honor or reputation. Licensor
+ agrees that in those jurisdictions (e.g. Japan), in which any exercise
+ of the right granted in Section 3(b) of this License (the right to
+ make Adaptations) would be deemed to be a distortion, mutilation,
+ modification or other derogatory action prejudicial to the Original
+ Author's honor and reputation, the Licensor will waive or not assert,
+ as appropriate, this Section, to the fullest extent permitted by the
+ applicable national law, to enable You to reasonably exercise Your
+ right under Section 3(b) of this License (right to make Adaptations)
+ but not otherwise.
+
+5. Representations, Warranties and Disclaimer
+
+UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR
+OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY
+KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE,
+INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY,
+FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF
+LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS,
+WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION
+OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.
+
+6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE
+LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR
+ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES
+ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS
+BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+7. Termination
+
+ a. This License and the rights granted hereunder will terminate
+ automatically upon any breach by You of the terms of this License.
+ Individuals or entities who have received Adaptations or Collections
+ from You under this License, however, will not have their licenses
+ terminated provided such individuals or entities remain in full
+ compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will
+ survive any termination of this License.
+ b. Subject to the above terms and conditions, the license granted here is
+ perpetual (for the duration of the applicable copyright in the Work).
+ Notwithstanding the above, Licensor reserves the right to release the
+ Work under different license terms or to stop distributing the Work at
+ any time; provided, however that any such election will not serve to
+ withdraw this License (or any other license that has been, or is
+ required to be, granted under the terms of this License), and this
+ License will continue in full force and effect unless terminated as
+ stated above.
+
+8. Miscellaneous
+
+ a. Each time You Distribute or Publicly Perform the Work or a Collection,
+ the Licensor offers to the recipient a license to the Work on the same
+ terms and conditions as the license granted to You under this License.
+ b. Each time You Distribute or Publicly Perform an Adaptation, Licensor
+ offers to the recipient a license to the original Work on the same
+ terms and conditions as the license granted to You under this License.
+ c. If any provision of this License is invalid or unenforceable under
+ applicable law, it shall not affect the validity or enforceability of
+ the remainder of the terms of this License, and without further action
+ by the parties to this agreement, such provision shall be reformed to
+ the minimum extent necessary to make such provision valid and
+ enforceable.
+ d. No term or provision of this License shall be deemed waived and no
+ breach consented to unless such waiver or consent shall be in writing
+ and signed by the party to be charged with such waiver or consent.
+ e. This License constitutes the entire agreement between the parties with
+ respect to the Work licensed here. There are no understandings,
+ agreements or representations with respect to the Work not specified
+ here. Licensor shall not be bound by any additional provisions that
+ may appear in any communication from You. This License may not be
+ modified without the mutual written agreement of the Licensor and You.
+ f. The rights granted under, and the subject matter referenced, in this
+ License were drafted utilizing the terminology of the Berne Convention
+ for the Protection of Literary and Artistic Works (as amended on
+ September 28, 1979), the Rome Convention of 1961, the WIPO Copyright
+ Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996
+ and the Universal Copyright Convention (as revised on July 24, 1971).
+ These rights and subject matter take effect in the relevant
+ jurisdiction in which the License terms are sought to be enforced
+ according to the corresponding provisions of the implementation of
+ those treaty provisions in the applicable national law. If the
+ standard suite of rights granted under applicable copyright law
+ includes additional rights not granted under this License, such
+ additional rights are deemed to be included in the License; this
+ License is not intended to restrict the license of any rights under
+ applicable law.
+
+
+Creative Commons Notice
+
+ Creative Commons is not a party to this License, and makes no warranty
+ whatsoever in connection with the Work. Creative Commons will not be
+ liable to You or any party on any legal theory for any damages
+ whatsoever, including without limitation any general, special,
+ incidental or consequential damages arising in connection to this
+ license. Notwithstanding the foregoing two (2) sentences, if Creative
+ Commons has expressly identified itself as the Licensor hereunder, it
+ shall have all rights and obligations of Licensor.
+
+ Except for the limited purpose of indicating to the public that the
+ Work is licensed under the CCPL, Creative Commons does not authorize
+ the use by either party of the trademark "Creative Commons" or any
+ related trademark or logo of Creative Commons without the prior
+ written consent of Creative Commons. Any permitted use will be in
+ compliance with Creative Commons' then-current trademark usage
+ guidelines, as may be published on its website or otherwise made
+ available upon request from time to time. For the avoidance of doubt,
+ this trademark restriction does not form part of the License.
+
+ Creative Commons may be contacted at https://creativecommons.org/.
diff --git a/licenses/org.citationstyles.styles.txt b/licenses/org.citationstyles.styles.txt
new file mode 100644
index 0000000..604209a
--- /dev/null
+++ b/licenses/org.citationstyles.styles.txt
@@ -0,0 +1,359 @@
+Creative Commons Legal Code
+
+Attribution-ShareAlike 3.0 Unported
+
+ CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
+ LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN
+ ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
+ INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
+ REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR
+ DAMAGES RESULTING FROM ITS USE.
+
+License
+
+THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE
+COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY
+COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS
+AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
+
+BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE
+TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY
+BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS
+CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND
+CONDITIONS.
+
+1. Definitions
+
+ a. "Adaptation" means a work based upon the Work, or upon the Work and
+ other pre-existing works, such as a translation, adaptation,
+ derivative work, arrangement of music or other alterations of a
+ literary or artistic work, or phonogram or performance and includes
+ cinematographic adaptations or any other form in which the Work may be
+ recast, transformed, or adapted including in any form recognizably
+ derived from the original, except that a work that constitutes a
+ Collection will not be considered an Adaptation for the purpose of
+ this License. For the avoidance of doubt, where the Work is a musical
+ work, performance or phonogram, the synchronization of the Work in
+ timed-relation with a moving image ("synching") will be considered an
+ Adaptation for the purpose of this License.
+ b. "Collection" means a collection of literary or artistic works, such as
+ encyclopedias and anthologies, or performances, phonograms or
+ broadcasts, or other works or subject matter other than works listed
+ in Section 1(f) below, which, by reason of the selection and
+ arrangement of their contents, constitute intellectual creations, in
+ which the Work is included in its entirety in unmodified form along
+ with one or more other contributions, each constituting separate and
+ independent works in themselves, which together are assembled into a
+ collective whole. A work that constitutes a Collection will not be
+ considered an Adaptation (as defined below) for the purposes of this
+ License.
+ c. "Creative Commons Compatible License" means a license that is listed
+ at https://creativecommons.org/compatiblelicenses that has been
+ approved by Creative Commons as being essentially equivalent to this
+ License, including, at a minimum, because that license: (i) contains
+ terms that have the same purpose, meaning and effect as the License
+ Elements of this License; and, (ii) explicitly permits the relicensing
+ of adaptations of works made available under that license under this
+ License or a Creative Commons jurisdiction license with the same
+ License Elements as this License.
+ d. "Distribute" means to make available to the public the original and
+ copies of the Work or Adaptation, as appropriate, through sale or
+ other transfer of ownership.
+ e. "License Elements" means the following high-level license attributes
+ as selected by Licensor and indicated in the title of this License:
+ Attribution, ShareAlike.
+ f. "Licensor" means the individual, individuals, entity or entities that
+ offer(s) the Work under the terms of this License.
+ g. "Original Author" means, in the case of a literary or artistic work,
+ the individual, individuals, entity or entities who created the Work
+ or if no individual or entity can be identified, the publisher; and in
+ addition (i) in the case of a performance the actors, singers,
+ musicians, dancers, and other persons who act, sing, deliver, declaim,
+ play in, interpret or otherwise perform literary or artistic works or
+ expressions of folklore; (ii) in the case of a phonogram the producer
+ being the person or legal entity who first fixes the sounds of a
+ performance or other sounds; and, (iii) in the case of broadcasts, the
+ organization that transmits the broadcast.
+ h. "Work" means the literary and/or artistic work offered under the terms
+ of this License including without limitation any production in the
+ literary, scientific and artistic domain, whatever may be the mode or
+ form of its expression including digital form, such as a book,
+ pamphlet and other writing; a lecture, address, sermon or other work
+ of the same nature; a dramatic or dramatico-musical work; a
+ choreographic work or entertainment in dumb show; a musical
+ composition with or without words; a cinematographic work to which are
+ assimilated works expressed by a process analogous to cinematography;
+ a work of drawing, painting, architecture, sculpture, engraving or
+ lithography; a photographic work to which are assimilated works
+ expressed by a process analogous to photography; a work of applied
+ art; an illustration, map, plan, sketch or three-dimensional work
+ relative to geography, topography, architecture or science; a
+ performance; a broadcast; a phonogram; a compilation of data to the
+ extent it is protected as a copyrightable work; or a work performed by
+ a variety or circus performer to the extent it is not otherwise
+ considered a literary or artistic work.
+ i. "You" means an individual or entity exercising rights under this
+ License who has not previously violated the terms of this License with
+ respect to the Work, or who has received express permission from the
+ Licensor to exercise rights under this License despite a previous
+ violation.
+ j. "Publicly Perform" means to perform public recitations of the Work and
+ to communicate to the public those public recitations, by any means or
+ process, including by wire or wireless means or public digital
+ performances; to make available to the public Works in such a way that
+ members of the public may access these Works from a place and at a
+ place individually chosen by them; to perform the Work to the public
+ by any means or process and the communication to the public of the
+ performances of the Work, including by public digital performance; to
+ broadcast and rebroadcast the Work by any means including signs,
+ sounds or images.
+ k. "Reproduce" means to make copies of the Work by any means including
+ without limitation by sound or visual recordings and the right of
+ fixation and reproducing fixations of the Work, including storage of a
+ protected performance or phonogram in digital form or other electronic
+ medium.
+
+2. Fair Dealing Rights. Nothing in this License is intended to reduce,
+limit, or restrict any uses free from copyright or rights arising from
+limitations or exceptions that are provided for in connection with the
+copyright protection under copyright law or other applicable laws.
+
+3. License Grant. Subject to the terms and conditions of this License,
+Licensor hereby grants You a worldwide, royalty-free, non-exclusive,
+perpetual (for the duration of the applicable copyright) license to
+exercise the rights in the Work as stated below:
+
+ a. to Reproduce the Work, to incorporate the Work into one or more
+ Collections, and to Reproduce the Work as incorporated in the
+ Collections;
+ b. to create and Reproduce Adaptations provided that any such Adaptation,
+ including any translation in any medium, takes reasonable steps to
+ clearly label, demarcate or otherwise identify that changes were made
+ to the original Work. For example, a translation could be marked "The
+ original work was translated from English to Spanish," or a
+ modification could indicate "The original work has been modified.";
+ c. to Distribute and Publicly Perform the Work including as incorporated
+ in Collections; and,
+ d. to Distribute and Publicly Perform Adaptations.
+ e. For the avoidance of doubt:
+
+ i. Non-waivable Compulsory License Schemes. In those jurisdictions in
+ which the right to collect royalties through any statutory or
+ compulsory licensing scheme cannot be waived, the Licensor
+ reserves the exclusive right to collect such royalties for any
+ exercise by You of the rights granted under this License;
+ ii. Waivable Compulsory License Schemes. In those jurisdictions in
+ which the right to collect royalties through any statutory or
+ compulsory licensing scheme can be waived, the Licensor waives the
+ exclusive right to collect such royalties for any exercise by You
+ of the rights granted under this License; and,
+ iii. Voluntary License Schemes. The Licensor waives the right to
+ collect royalties, whether individually or, in the event that the
+ Licensor is a member of a collecting society that administers
+ voluntary licensing schemes, via that society, from any exercise
+ by You of the rights granted under this License.
+
+The above rights may be exercised in all media and formats whether now
+known or hereafter devised. The above rights include the right to make
+such modifications as are technically necessary to exercise the rights in
+other media and formats. Subject to Section 8(f), all rights not expressly
+granted by Licensor are hereby reserved.
+
+4. Restrictions. The license granted in Section 3 above is expressly made
+subject to and limited by the following restrictions:
+
+ a. You may Distribute or Publicly Perform the Work only under the terms
+ of this License. You must include a copy of, or the Uniform Resource
+ Identifier (URI) for, this License with every copy of the Work You
+ Distribute or Publicly Perform. You may not offer or impose any terms
+ on the Work that restrict the terms of this License or the ability of
+ the recipient of the Work to exercise the rights granted to that
+ recipient under the terms of the License. You may not sublicense the
+ Work. You must keep intact all notices that refer to this License and
+ to the disclaimer of warranties with every copy of the Work You
+ Distribute or Publicly Perform. When You Distribute or Publicly
+ Perform the Work, You may not impose any effective technological
+ measures on the Work that restrict the ability of a recipient of the
+ Work from You to exercise the rights granted to that recipient under
+ the terms of the License. This Section 4(a) applies to the Work as
+ incorporated in a Collection, but this does not require the Collection
+ apart from the Work itself to be made subject to the terms of this
+ License. If You create a Collection, upon notice from any Licensor You
+ must, to the extent practicable, remove from the Collection any credit
+ as required by Section 4(c), as requested. If You create an
+ Adaptation, upon notice from any Licensor You must, to the extent
+ practicable, remove from the Adaptation any credit as required by
+ Section 4(c), as requested.
+ b. You may Distribute or Publicly Perform an Adaptation only under the
+ terms of: (i) this License; (ii) a later version of this License with
+ the same License Elements as this License; (iii) a Creative Commons
+ jurisdiction license (either this or a later license version) that
+ contains the same License Elements as this License (e.g.,
+ Attribution-ShareAlike 3.0 US)); (iv) a Creative Commons Compatible
+ License. If you license the Adaptation under one of the licenses
+ mentioned in (iv), you must comply with the terms of that license. If
+ you license the Adaptation under the terms of any of the licenses
+ mentioned in (i), (ii) or (iii) (the "Applicable License"), you must
+ comply with the terms of the Applicable License generally and the
+ following provisions: (I) You must include a copy of, or the URI for,
+ the Applicable License with every copy of each Adaptation You
+ Distribute or Publicly Perform; (II) You may not offer or impose any
+ terms on the Adaptation that restrict the terms of the Applicable
+ License or the ability of the recipient of the Adaptation to exercise
+ the rights granted to that recipient under the terms of the Applicable
+ License; (III) You must keep intact all notices that refer to the
+ Applicable License and to the disclaimer of warranties with every copy
+ of the Work as included in the Adaptation You Distribute or Publicly
+ Perform; (IV) when You Distribute or Publicly Perform the Adaptation,
+ You may not impose any effective technological measures on the
+ Adaptation that restrict the ability of a recipient of the Adaptation
+ from You to exercise the rights granted to that recipient under the
+ terms of the Applicable License. This Section 4(b) applies to the
+ Adaptation as incorporated in a Collection, but this does not require
+ the Collection apart from the Adaptation itself to be made subject to
+ the terms of the Applicable License.
+ c. If You Distribute, or Publicly Perform the Work or any Adaptations or
+ Collections, You must, unless a request has been made pursuant to
+ Section 4(a), keep intact all copyright notices for the Work and
+ provide, reasonable to the medium or means You are utilizing: (i) the
+ name of the Original Author (or pseudonym, if applicable) if supplied,
+ and/or if the Original Author and/or Licensor designate another party
+ or parties (e.g., a sponsor institute, publishing entity, journal) for
+ attribution ("Attribution Parties") in Licensor's copyright notice,
+ terms of service or by other reasonable means, the name of such party
+ or parties; (ii) the title of the Work if supplied; (iii) to the
+ extent reasonably practicable, the URI, if any, that Licensor
+ specifies to be associated with the Work, unless such URI does not
+ refer to the copyright notice or licensing information for the Work;
+ and (iv) , consistent with Ssection 3(b), in the case of an
+ Adaptation, a credit identifying the use of the Work in the Adaptation
+ (e.g., "French translation of the Work by Original Author," or
+ "Screenplay based on original Work by Original Author"). The credit
+ required by this Section 4(c) may be implemented in any reasonable
+ manner; provided, however, that in the case of a Adaptation or
+ Collection, at a minimum such credit will appear, if a credit for all
+ contributing authors of the Adaptation or Collection appears, then as
+ part of these credits and in a manner at least as prominent as the
+ credits for the other contributing authors. For the avoidance of
+ doubt, You may only use the credit required by this Section for the
+ purpose of attribution in the manner set out above and, by exercising
+ Your rights under this License, You may not implicitly or explicitly
+ assert or imply any connection with, sponsorship or endorsement by the
+ Original Author, Licensor and/or Attribution Parties, as appropriate,
+ of You or Your use of the Work, without the separate, express prior
+ written permission of the Original Author, Licensor and/or Attribution
+ Parties.
+ d. Except as otherwise agreed in writing by the Licensor or as may be
+ otherwise permitted by applicable law, if You Reproduce, Distribute or
+ Publicly Perform the Work either by itself or as part of any
+ Adaptations or Collections, You must not distort, mutilate, modify or
+ take other derogatory action in relation to the Work which would be
+ prejudicial to the Original Author's honor or reputation. Licensor
+ agrees that in those jurisdictions (e.g. Japan), in which any exercise
+ of the right granted in Section 3(b) of this License (the right to
+ make Adaptations) would be deemed to be a distortion, mutilation,
+ modification or other derogatory action prejudicial to the Original
+ Author's honor and reputation, the Licensor will waive or not assert,
+ as appropriate, this Section, to the fullest extent permitted by the
+ applicable national law, to enable You to reasonably exercise Your
+ right under Section 3(b) of this License (right to make Adaptations)
+ but not otherwise.
+
+5. Representations, Warranties and Disclaimer
+
+UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR
+OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY
+KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE,
+INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY,
+FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF
+LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS,
+WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION
+OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.
+
+6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE
+LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR
+ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES
+ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS
+BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+7. Termination
+
+ a. This License and the rights granted hereunder will terminate
+ automatically upon any breach by You of the terms of this License.
+ Individuals or entities who have received Adaptations or Collections
+ from You under this License, however, will not have their licenses
+ terminated provided such individuals or entities remain in full
+ compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will
+ survive any termination of this License.
+ b. Subject to the above terms and conditions, the license granted here is
+ perpetual (for the duration of the applicable copyright in the Work).
+ Notwithstanding the above, Licensor reserves the right to release the
+ Work under different license terms or to stop distributing the Work at
+ any time; provided, however that any such election will not serve to
+ withdraw this License (or any other license that has been, or is
+ required to be, granted under the terms of this License), and this
+ License will continue in full force and effect unless terminated as
+ stated above.
+
+8. Miscellaneous
+
+ a. Each time You Distribute or Publicly Perform the Work or a Collection,
+ the Licensor offers to the recipient a license to the Work on the same
+ terms and conditions as the license granted to You under this License.
+ b. Each time You Distribute or Publicly Perform an Adaptation, Licensor
+ offers to the recipient a license to the original Work on the same
+ terms and conditions as the license granted to You under this License.
+ c. If any provision of this License is invalid or unenforceable under
+ applicable law, it shall not affect the validity or enforceability of
+ the remainder of the terms of this License, and without further action
+ by the parties to this agreement, such provision shall be reformed to
+ the minimum extent necessary to make such provision valid and
+ enforceable.
+ d. No term or provision of this License shall be deemed waived and no
+ breach consented to unless such waiver or consent shall be in writing
+ and signed by the party to be charged with such waiver or consent.
+ e. This License constitutes the entire agreement between the parties with
+ respect to the Work licensed here. There are no understandings,
+ agreements or representations with respect to the Work not specified
+ here. Licensor shall not be bound by any additional provisions that
+ may appear in any communication from You. This License may not be
+ modified without the mutual written agreement of the Licensor and You.
+ f. The rights granted under, and the subject matter referenced, in this
+ License were drafted utilizing the terminology of the Berne Convention
+ for the Protection of Literary and Artistic Works (as amended on
+ September 28, 1979), the Rome Convention of 1961, the WIPO Copyright
+ Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996
+ and the Universal Copyright Convention (as revised on July 24, 1971).
+ These rights and subject matter take effect in the relevant
+ jurisdiction in which the License terms are sought to be enforced
+ according to the corresponding provisions of the implementation of
+ those treaty provisions in the applicable national law. If the
+ standard suite of rights granted under applicable copyright law
+ includes additional rights not granted under this License, such
+ additional rights are deemed to be included in the License; this
+ License is not intended to restrict the license of any rights under
+ applicable law.
+
+
+Creative Commons Notice
+
+ Creative Commons is not a party to this License, and makes no warranty
+ whatsoever in connection with the Work. Creative Commons will not be
+ liable to You or any party on any legal theory for any damages
+ whatsoever, including without limitation any general, special,
+ incidental or consequential damages arising in connection to this
+ license. Notwithstanding the foregoing two (2) sentences, if Creative
+ Commons has expressly identified itself as the Licensor hereunder, it
+ shall have all rights and obligations of Licensor.
+
+ Except for the limited purpose of indicating to the public that the
+ Work is licensed under the CCPL, Creative Commons does not authorize
+ the use by either party of the trademark "Creative Commons" or any
+ related trademark or logo of Creative Commons without the prior
+ written consent of Creative Commons. Any permitted use will be in
+ compliance with Creative Commons' then-current trademark usage
+ guidelines, as may be published on its website or otherwise made
+ available upon request from time to time. For the avoidance of doubt,
+ this trademark restriction does not form part of the License.
+
+ Creative Commons may be contacted at https://creativecommons.org/.
diff --git a/localization.gradle b/localization.gradle
index 22d5415..7929053 100644
--- a/localization.gradle
+++ b/localization.gradle
@@ -10,39 +10,49 @@ dependencies {
jython 'org.python:jython-standalone:2.7.0'
}
-task checkTranslations(type: JavaExec) {
- description "Print empty and duplicate translations."
+task localizationStatusWithMarkdown(type: JavaExec) {
+ description "Creates an update file in Markdown"
group = 'Localization'
main 'org.python.util.jython'
classpath project.configurations.jython.asPath
args file("scripts/syncLang.py")
- args "-d"
+ args "markdown"
}
-task checkTranslationsSummary(type: JavaExec) {
- description "Print summary of empty and duplicate translations."
+task localizationStatus(type: JavaExec) {
+ description "Prints the current status"
group = 'Localization'
main 'org.python.util.jython'
classpath project.configurations.jython.asPath
args file("scripts/syncLang.py")
- args "-c"
+ args "status"
}
-task showMissingTranslationKeys(type: JavaExec) {
- description "Prints differences between the English translation and translations in other languages."
+task localizationStatusExtended(type: JavaExec) {
+ description "Prints the current status (extended output)"
group = 'Localization'
main 'org.python.util.jython'
classpath project.configurations.jython.asPath
args file("scripts/syncLang.py")
- args "-t"
+ args "status"
+ args "--extended"
}
-task generateMissingTranslationKeys(type: JavaExec) {
- description "Prints differences between the English translation and translations in other languages, and updates translations if possible."
+task localizationUpdate(type: JavaExec) {
+ description "Updates the localization files (fixes duplicates, adds missing keys, and sort them"
group = 'Localization'
main 'org.python.util.jython'
classpath project.configurations.jython.asPath
args file("scripts/syncLang.py")
- args "-t"
- args "-u"
+ args "update"
+}
+
+task localizationUpdateExtended(type: JavaExec) {
+ description "Updates the localization files (fixes duplicates, adds missing keys, and sort them (extended output)"
+ group = 'Localization'
+ main 'org.python.util.jython'
+ classpath project.configurations.jython.asPath
+ args file("scripts/syncLang.py")
+ args "update"
+ args "--extended"
}
diff --git a/scripts/.gitignore b/scripts/.gitignore
index 66b5675..e2c8e94 100644
--- a/scripts/.gitignore
+++ b/scripts/.gitignore
@@ -1,2 +1,6 @@
jq
jq.exe
+
+# python
+*.pyc
+*$py.class
diff --git a/scripts/README.md b/scripts/README.md
new file mode 100644
index 0000000..e5425d5
--- /dev/null
+++ b/scripts/README.md
@@ -0,0 +1,23 @@
+# Script usage
+
+The Script has following commands available
+- `$ python scripts/syncLang.py status [--extended]`
+ - prints the current status to the terminal
+ - `[--extended]` if the translations keys which create problems should be printed
+ - usable with Gradle tasks
+ - `$ gradle localizationStatus`
+ - `$ gradle localizationStatusExtended`
+
+
+- `$ python scripts/syncLang.py markdown`
+ - Creates a markdown file of the current status and opens it
+ - usable with Gradle tasks
+ - `$ gradle localizationStatusWithMarkdown`
+
+
+- `$ python scripts/syncLang.py update [--extended]`
+ - compares all the localization files against the English one and fixes unambiguous duplicates, removes obsolete keys, adds missing keys, and sorts them
+ - `[--extended]` if the translations keys which create problems should be printed
+ - usable with Gradle tasks
+ - `$ gradle localizationUpdate`
+ - `$ gradle localizationUpdateExtended`
diff --git a/scripts/after-failure.sh b/scripts/after-failure.sh
new file mode 100755
index 0000000..fa029d3
--- /dev/null
+++ b/scripts/after-failure.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+# taken from https://github.com/lhotari/travis-gradle-test-failures-to-console/blob/master/travis/junit-errors-to-stdout.sh
+IFS='
+'
+DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
+if [ "$TRAVIS" = "true" ]; then
+ #echo 'Installing xml-twig-tools and xsltproc....'
+ sudo apt-get install -qq -y --force-yes xml-twig-tools xsltproc > /dev/null
+fi
+ROOTDIR="$1"
+if [ -z "$ROOTDIR" ]; then
+ ROOTDIR="."
+fi
+echo 'Formatting results...'
+FILES=$(find "$ROOTDIR" -path '*/build/test-results/*.xml' | xargs --no-run-if-empty xml_grep --files --cond 'testsuite[@failures > 0 or @errors > 0]')
+if [ -n "$FILES" ]; then
+ for file in $FILES; do
+ echo "Formatting $file"
+ if [ -f "$file" ]; then
+ echo '====================================================='
+ xsltproc "$DIR/junit-xml-format-errors.xsl" "$file"
+ fi
+ done
+ echo '====================================================='
+else
+ echo 'No */build/test-results/*.xml files found with failing tests.'
+fi
diff --git a/scripts/junit-xml-format-errors.xsl b/scripts/junit-xml-format-errors.xsl
new file mode 100644
index 0000000..614c774
--- /dev/null
+++ b/scripts/junit-xml-format-errors.xsl
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- based on SO answer http://stackoverflow.com/a/9471505/166062 by dvdvorle http://stackoverflow.com/users/481635/dvdvorle -->
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+ <xsl:output method="text" indent="no"/>
+ <xsl:template match="/testsuite">
+ <xsl:text>Testsuite: </xsl:text><xsl:value-of select="@name" />
+ <xsl:text>
+Tests run: </xsl:text>
+ <xsl:value-of select="@tests" />
+ <xsl:text>, Failures: </xsl:text>
+ <xsl:value-of select="@failures" />
+ <xsl:text>, Errors: </xsl:text>
+ <xsl:value-of select="@errors" />
+ <xsl:text>, Time elapsed: </xsl:text>
+ <xsl:value-of select="@time" />
+ <xsl:text> sec</xsl:text>
+ <xsl:text>
+--------- ----------- ---------</xsl:text>
+ <xsl:apply-templates select="testcase" />
+ <xsl:apply-templates select="system-out" />
+ <xsl:apply-templates select="system-err" />
+ </xsl:template>
+
+ <xsl:template match="testcase">
+ <xsl:text>
+Testcase: </xsl:text>
+ <xsl:value-of select="@name" />
+ <xsl:text> took </xsl:text>
+ <xsl:value-of select="@time" />
+ <xsl:choose>
+ <xsl:when test="failure"><xsl:text> FAILURE </xsl:text><xsl:apply-templates select="failure"/></xsl:when>
+ <xsl:when test="error"><xsl:text> ERROR </xsl:text><xsl:apply-templates select="error"/></xsl:when>
+ <xsl:otherwise><xsl:text> SUCCESS</xsl:text></xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template match="error | failure">
+ <xsl:value-of select="@message" />
+ <xsl:if test="@type != @message">
+ <xsl:text> </xsl:text><xsl:value-of select="@type" />
+ </xsl:if>
+ <xsl:text>
+</xsl:text>
+ <xsl:value-of select="." />
+ </xsl:template>
+
+ <xsl:template match="system-out">
+ <xsl:text>
+------ Standard output ------
+</xsl:text>
+ <xsl:value-of select="." />
+ </xsl:template>
+
+ <xsl:template match="system-err">
+ <xsl:text>
+------ Error output ------
+</xsl:text>
+ <xsl:value-of select="." />
+ </xsl:template>
+
+</xsl:stylesheet>
diff --git a/scripts/logger.py b/scripts/logger.py
new file mode 100644
index 0000000..6226645
--- /dev/null
+++ b/scripts/logger.py
@@ -0,0 +1,29 @@
+def enum(**enums):
+ return type('Enum', (), enums)
+
+
+OUTPUT_COLORS = enum(
+ OK='\033[0;32m',
+ WARN='\033[0;33m',
+ ERROR='\033[0;31m',
+ ENDC='\033[0;38m'
+)
+
+
+def error(content):
+ print u"{color_error}{content}{color_end}".encode('utf8') \
+ .format(color_error=OUTPUT_COLORS.ERROR, content=str(content.encode('utf8')), color_end=OUTPUT_COLORS.ENDC)
+
+
+def warn(content):
+ print u"{color_error}{content}{color_end}".encode('utf8') \
+ .format(color_error=OUTPUT_COLORS.WARN, content=str(content.encode('utf8')), color_end=OUTPUT_COLORS.ENDC).encode('utf8')
+
+
+def ok(content):
+ print u"{color_error}{content}{color_end}".encode('utf8') \
+ .format(color_error=OUTPUT_COLORS.OK, content=str(content.encode('utf8')), color_end=OUTPUT_COLORS.ENDC).encode('utf8')
+
+
+def neutral(content):
+ print content.encode('utf8')
diff --git a/scripts/prepare-install4j.sh b/scripts/prepare-install4j.sh
index 51652f2..86284db 100755
--- a/scripts/prepare-install4j.sh
+++ b/scripts/prepare-install4j.sh
@@ -7,19 +7,17 @@ fi
# ensure that tar archive of install4j exists
cd ~/downloads
-if [ ! -f install4j_unix_6_1_1.tar.gz ]; then
- wget --quiet http://download-aws.ej-technologies.com/install4j/install4j_unix_6_1_1.tar.gz
-fi;
+wget --quiet -nc http://download-keycdn.ej-technologies.com/install4j/install4j_unix_6_1_3.tar.gz
# extract tar archive of install4j into the source directory of JabRef
cd ~/jabref
-tar -xzf ~/downloads/install4j_unix_6_1_1.tar.gz
+tar -xzf ~/downloads/install4j_unix_6_1_3.tar.gz
# fetch JREs
if [ ! -d ~/.install4j6/jres/ ]; then
mkdir -p ~/.install4j6/jres/
fi
cd ~/.install4j6/jres/
-wget --quiet -nc http://files.jabref.org/jres/windows-x86-1.8.0_102.tar.gz
-wget --quiet -nc http://files.jabref.org/jres/windows-amd64-1.8.0_102.tar.gz
-wget --quiet -nc http://files.jabref.org/jres/macosx-amd64-1.8.0_102_unpacked.tar.gz
+wget --quiet -nc https://files.jabref.org/jres/windows-x86-1.8.0_112.tar.gz
+wget --quiet -nc https://files.jabref.org/jres/windows-amd64-1.8.0_112.tar.gz
+wget --quiet -nc https://files.jabref.org/jres/macosx-amd64-1.8.0_112_unpacked.tar.gz
diff --git a/scripts/syncLang.py b/scripts/syncLang.py
index 0263016..d15081d 100644
--- a/scripts/syncLang.py
+++ b/scripts/syncLang.py
@@ -1,38 +1,226 @@
# coding=utf-8
+from __future__ import print_function
+import codecs
+import datetime
import os
+import subprocess
import sys
+import webbrowser
-res_dir = "src/main/resources/l10n"
+import logger
-keyFiles = {}
+RES_DIR = "src/main/resources/l10n"
+STATUS_FILE = "status.md"
+
+
+def get_current_branch():
+ """
+ :return: string: the current git branch
+ """
+ return subprocess.check_output(['git', 'rev-parse', '--abbrev-ref', 'HEAD']).rstrip()
+
+
+def get_current_hash_short():
+ """
+ :return: string: the current git hash (short)
+ """
+ return subprocess.check_output(['git', 'rev-parse', '--short', 'HEAD']).rstrip()
+
+
+def open_file(filename):
+ """
+ :param filename: string: opens the file with its associated application
+ """
+ webbrowser.open(filename)
+
+
+def get_filename(filepath):
+ """
+ removes the res_dir path
+
+ :param filepath: string
+ :return: string
+ """
+ return filepath.replace("{}\\".format(RES_DIR), "")
+
+
+def read_file(filename, encoding="UTF-8"):
+ """
+ :param filename: string
+ :param encoding: string: the encoding of the file to read (standard: `UTF-8`)
+ :return: list of unicode strings: the lines of the file
+ """
+ with codecs.open(filename, encoding=encoding) as file:
+ return [u"{}\r\n".format(line.strip()) for line in file.readlines()]
+
+
+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
+ """
+ codecs.open(filename, "w", encoding='utf-8').writelines(content)
+
+
+def get_main_jabref_preferences():
+ """
+ :return: string: path to JabRef_en.preference
+ """
+ return os.path.join(RES_DIR, "JabRef_en.properties")
+
+
+def get_other_jabref_properties():
+ """
+ :return: list of strings: all the JabRef_*.preferences files without the english one
+ """
+ jabref_property_files = filter(lambda s: (s.startswith('JabRef_') and not (s.startswith('JabRef_en'))), os.listdir(RES_DIR))
+ return [os.path.join(RES_DIR, file) for file in jabref_property_files]
+
+
+def get_all_jabref_properties():
+ """
+ :return: list of strings: all the JabRef_*.preferences files with the english at the beginning
+ """
+ jabref_property_files = get_other_jabref_properties()
+ jabref_property_files.insert(0, os.path.join(RES_DIR, "JabRef_en.properties"))
+ return jabref_property_files
+
+
+def get_main_menu_properties():
+ """
+ :return: string: path to Menu_en.preference
+ """
+ return os.path.join(RES_DIR, "Menu_en.properties")
+
+
+def get_other_menu_properties():
+ """
+ :return: list of strings: all the Menu_*.preferences files without the english one
+ """
+ menu_property_files = filter(lambda s: (s.startswith('Menu_') and not (s.startswith('Menu_en'))), os.listdir(RES_DIR))
+ return [os.path.join(RES_DIR, file) for file in menu_property_files]
+
+
+def get_all_menu_properties():
+ """
+ :return: list of strings: all the Menu_*.preferences files with the english at the beginning
+ """
+ menu_property_files = get_other_menu_properties()
+ menu_property_files.insert(0, os.path.join(RES_DIR, "Menu_en.properties"))
+ return menu_property_files
+
+
+def get_key_from_line(line):
+ """
+ Tries to extract the key from the line
+
+ :param line: unicode string
+ :return: unicode string: the key or None
+ """
+ if line.find("#") != 0 or line.find("!") != 0:
+ index_key_end = line.find("=")
+ while (index_key_end > 0) and (line[index_key_end - 1] == "\\"):
+ index_key_end = line.find("=", index_key_end + 1)
+ if index_key_end > 0:
+ return line[0:index_key_end].strip()
+ return None
+
+
+def get_key_and_value_from_line(line):
+ """
+ Tries to extract the key and value from the line
+
+ :param line: unicode string
+ :return: (unicode string, unicode string) or (None, None): (key, value)
+ """
+ if line.find("#") != 0 or line.find("!") != 0:
+ index_key_end = line.find("=")
+ while (index_key_end > 0) and (line[index_key_end - 1] == "\\"):
+ index_key_end = line.find("=", index_key_end + 1)
+ if index_key_end > 0:
+ return line[0:index_key_end].strip(), line[index_key_end + 1:].strip()
+ return None, None
+
+
+def get_translations_as_dict(lines):
+ """
+ :param lines: list of unicode strings
+ :return: dict of unicode strings:
+ """
+ translations = {}
+ for line in lines:
+ key, value = get_key_and_value_from_line(line=line)
+ if key:
+ translations[key] = value
+ return translations
+
+
+def get_empty_keys(lines):
+ """
+ :param lines: list of unicode strings
+ :return: list of unicode strings: the keys with empty values
+ """
+ not_translated = []
+ keys = get_translations_as_dict(lines=lines)
+ for key, value in keys.iteritems():
+ if not value:
+ not_translated.append(key)
+ return not_translated
+
+
+def fix_duplicates(lines):
+ """
+ Fixes all unambiguous duplicates
+
+ :param lines: list of unicode strings
+ :return: (list of unicode strings, list of unicode strings): not fixed ambiguous duplicates, fixed unambiguous duplicates
+ """
+ keys = {}
+ fixed = []
+ not_fixed = []
+ for line in lines:
+ key, value = get_key_and_value_from_line(line=line)
+ if key:
+ if key in keys:
+ if not keys[key]:
+ fixed.append(u"{key}={value}".format(key=key, value=keys[key]))
+ keys[key] = value
+ elif not value:
+ fixed.append(u"{key}={value}".format(key=key, value=value))
+ elif keys[key] == value:
+ fixed.append(u"{key}={value}".format(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]))
+ else:
+ keys[key] = value
+
+ return keys, not_fixed, fixed
def get_keys_from_lines(lines):
"""
Builds a list of all translation keys in the list of lines.
- :param lines: a list of strings
- :return: the sorted keys within the list of strings
+ :param lines: a list of unicode strings
+ :return: list of unicode strings: the sorted keys within the lines
"""
keys = []
for line in lines:
- comment = line.find("#")
- if comment != 0:
- index = line.find("=")
- while (index > 0) and (line[index - 1] == "\\"):
- index = line.find("=", index + 1)
- if index > 0:
- keys.append(line[0:index])
+ key = get_key_from_line(line)
+ if key:
+ keys.append(key)
return keys
-def find_missing_keys(first_list, second_list):
+def get_missing_keys(first_list, second_list):
"""
Finds all keys in the first list that are not present in the second list
- :param first_list: a list
- :param second_list: a list
- :return: a list
+ :param first_list: list of unicode strings
+ :param second_list: list of unicode strings
+ :return: list of unicode strings
"""
missing = []
for key in first_list:
@@ -41,152 +229,230 @@ def find_missing_keys(first_list, second_list):
return missing
-def read_all_lines(filename):
- f1 = open(filename)
- lines = f1.readlines()
- f1.close()
- return lines
+def get_duplicates(lines):
+ """
+ finds all the duplicates and returns them
+ :param lines: list of unicode strings
+ :return: list of unicode strings
+ """
+ duplicates = []
+ keys_checked = {}
+ for line in lines:
+ key, value = get_key_and_value_from_line(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])
+ if translation_in_list not in duplicates:
+ duplicates.append(translation_in_list)
+ else:
+ keys_checked[key] = value
+ return duplicates
-def append_keys_to_file(filename, keys):
+
+def status(extended):
"""
- Appends all the given keys to the file terminating with an equals sign
+ prints the current status to the terminal
+
+ :param extended: boolean: if the keys with problems should be printed
"""
- f = open(filename, "a")
- f.write("\n")
- for key in keys:
- f.write(key + "=\n")
- f.close()
+ def check_properties(main_property_file, property_files):
+ main_lines = read_file(filename=main_property_file)
+ main_keys = get_keys_from_lines(lines=main_lines)
+
+ # the main property file gets compared to itself, but that is OK
+ for file in property_files:
+ filename = get_filename(filepath=file)
+ lines = read_file(file)
+ keys = get_keys_from_lines(lines=lines)
+
+ keys_missing = get_missing_keys(main_keys, keys)
+ keys_obsolete = get_missing_keys(keys, main_keys)
+ keys_duplicate = get_duplicates(lines=lines)
+ keys_not_translated = get_empty_keys(lines=lines)
+
+ 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_translated = num_keys - num_keys_not_translated
+
+ log = logger.error if num_keys_missing != 0 or num_keys_not_translated != 0 or num_keys_obsolete != 0 or num_keys_duplicate != 0 else logger.ok
+ log("Status of file '{file}' with {num_keys} Keys".format(file=filename, num_keys=num_keys))
+ logger.ok("\t{} translated keys".format(num_keys_translated))
+
+ log = logger.error if num_keys_not_translated != 0 else logger.ok
+ log("\t{} not translated keys".format(num_keys_not_translated))
+ if extended and num_keys_not_translated != 0:
+ logger.neutral(u"\t\t{}".format(", ".join(keys_not_translated)))
+
+ log = logger.error if num_keys_missing != 0 else logger.ok
+ log("\t{} missing keys".format(num_keys_missing))
+ if extended and num_keys_missing != 0:
+ logger.neutral(u"\t\t{}".format(", ".join(keys_missing)))
+
+ log = logger.error if num_keys_obsolete != 0 else logger.ok
+ log("\t{} obsolete keys".format(num_keys_obsolete))
+ if extended and num_keys_obsolete != 0:
+ logger.neutral(u"\t\t{}".format(", ".join(keys_obsolete)))
+
+ log = logger.error if num_keys_duplicate != 0 else logger.ok
+ log("\t{} duplicates".format(num_keys_duplicate))
+ if extended and num_keys_duplicate != 0:
+ logger.neutral(u"\t\t{}".format(", ".join(keys_duplicate)))
+
+ check_properties(main_property_file=get_main_jabref_preferences(), property_files=get_all_jabref_properties())
+ check_properties(main_property_file=get_main_menu_properties(), property_files=get_all_menu_properties())
+
+
+def update(extended):
+ """
+ updates all the localization files
+ fixing unambiguous duplicates, removing obsolete keys, adding missing keys, and sorting them
-def remove_keys_from_file(filename, keys):
- lines = open(filename).readlines()
- lines_to_write = []
- for line in lines:
- add = True
- for key in keys:
- if(line.startswith(key+"=")):
- add = False
- if add:
- lines_to_write.append(line)
- open(filename, 'w').writelines(lines_to_write)
-
-
-def compare_property_files_to_main_property_file(main_properties_file, other_properties_files, append_missing_keys_to_other_properties_files):
- keys_in_properties_file = get_keys_from_lines(read_all_lines(main_properties_file))
-
- for other_properties_file in other_properties_files:
- keys_in_other_properties_file = get_keys_from_lines(read_all_lines(other_properties_file))
- keys_missing = find_missing_keys(keys_in_properties_file, keys_in_other_properties_file)
- keys_obsolete = find_missing_keys(keys_in_other_properties_file, keys_in_properties_file)
-
- print "\n\nFile '" + other_properties_file + "'\n"
- if not keys_missing:
- print "----> No missing keys."
- else:
- print "----> Missing keys:"
- for key in keys_missing:
- print key
-
- if append_missing_keys_to_other_properties_files:
- append_keys_to_file(other_properties_file, keys_missing)
- print ""
-
- if not keys_obsolete:
- print "----> No possible obsolete keys (not in English language file)."
- else:
- print "----> Possible obsolete keys (not in English language file):"
- for key in keys_obsolete:
- print key
-
- if append_missing_keys_to_other_properties_files:
- remove_keys_from_file(other_properties_file, keys_obsolete)
-
- print ""
-
-
-def append_property(properties_file, key, value):
- f = open(properties_file, "a")
- f.write(key + "=" + value + "\n")
- f.close()
-
-
-def find_duplicate_keys_and_keys_with_no_value(current_file, display_keys):
- lines = read_all_lines(current_file)
- mappings = {}
- duplication_count = 0
- empty_values_count = 0
- for line in lines:
- is_no_comment = line.find("#") != 0
- index = line.find("=")
- contains_property = index > 0
- if is_no_comment and contains_property:
- key = line[0:index]
- value = line[index + 1:].strip()
- if key in mappings:
- mappings[key].append(value)
- duplication_count += 1
- if display_keys:
- print "Duplicate: " + current_file + ": " + key + " =",
- print mappings[key]
- else:
- mappings[key] = [value]
- if value == "":
- empty_values_count += 1
- if display_keys:
- print "Empty value: " + current_file + ": " + key
-
- issues_count = duplication_count + empty_values_count
-
- message = ""
- if issues_count == 0:
- message = "ok"
- elif duplication_count > 0:
- message += str(duplication_count) + " duplicates. "
- elif empty_values_count > 0:
- message += str(empty_values_count) + " empty values. "
- print current_file + ": " + message
-
-
-if len(sys.argv) == 1:
- print """This program must be run from the jabref base directory.
-
-Usage: syncLang.py option
+ :param extended: boolean: if the keys with problems should be printed
+ """
+ def update_properties(main_property_file, other_property_files):
+ main_lines = read_file(filename=main_property_file)
+ # saved the stripped lines
+ write_file(main_property_file, main_lines)
+ main_keys = get_keys_from_lines(lines=main_lines)
+
+ main_duplicates = get_duplicates(lines=main_lines)
+ num_main_duplicates = len(main_duplicates)
+ if num_main_duplicates != 0:
+ logger.error("There are {num_duplicates} duplicates in {file}, please fix them manually".format(num_duplicates=num_main_duplicates, file=get_filename(filepath=main_property_file)))
+ if extended:
+ logger.neutral(u"\t{}".format(", ".join(main_duplicates)))
+ return
+
+
+ for other_property_file in other_property_files:
+ filename = get_filename(filepath=other_property_file)
+ lines = read_file(filename=other_property_file)
+ keys, not_fixed, fixed = fix_duplicates(lines=lines)
+
+ num_keys = len(keys)
+ num_not_fixed = len(not_fixed)
+ num_fixed = len(fixed)
+
+ if num_not_fixed != 0:
+ logger.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 extended:
+ logger.error(u"\t{}".format(u", ".join(not_fixed)))
+ continue
+
+ keys_missing = get_missing_keys(main_keys, keys)
+ keys_obsolete = get_missing_keys(keys, main_keys)
+
+ num_keys_missing = len(keys_missing)
+ num_keys_obsolete = len(keys_obsolete)
+
+ for missing_key in keys_missing:
+ keys[missing_key] = ""
+
+ for obsolete_key in keys_obsolete:
+ del keys[obsolete_key]
+
+ other_lines_to_write = []
+ for line in main_lines:
+ key = get_key_from_line(line)
+ if key is not None:
+ other_lines_to_write.append(u"{key}={value}\r\n".format(key=key, value=keys[key]))
+ else:
+ other_lines_to_write.append(line)
+
+ sorted = len(lines) != len(other_lines_to_write)
+ if not sorted:
+ for old_line, new_lines in zip(lines, other_lines_to_write):
+ if old_line != new_lines:
+ sorted = True
+
+ write_file(filename=other_property_file, content=other_lines_to_write)
+
+ logger.ok("Processing file '{file}' with {num_keys} Keys".format(file=filename, num_keys=num_keys))
+ if num_fixed != 0:
+ logger.ok("\tfixed {} unambiguous duplicates".format(num_fixed))
+ if extended:
+ logger.neutral(u"\t\t{}".format(", ".join(fixed)))
+
+ if num_keys_missing != 0:
+ logger.ok("\tadded {} missing keys".format(num_keys_missing))
+ if extended:
+ logger.neutral(u"\t\t{}".format(", ".join(keys_missing)))
+
+ if num_keys_obsolete != 0:
+ logger.ok("\tdeleted {} obsolete keys".format(num_keys_obsolete))
+ if extended:
+ logger.neutral(u"\t\t{}".format(", ".join(keys_obsolete)))
+
+ if sorted:
+ logger.ok("\thas been sorted successfully")
+
+ update_properties(main_property_file=get_main_jabref_preferences(), other_property_files=get_other_jabref_properties())
+ update_properties(main_property_file=get_main_menu_properties(), other_property_files=get_other_menu_properties())
+
+
+def status_create_markdown():
+ """
+ creates a markdown file of the current status and opens it
+ """
+ def write_properties(property_files):
+ markdown.append("\n| Property file | Keys | Keys translated | Keys not translated | % translated |\n")
+ markdown.append("| ------------- | ---- | --------------- | ------------------- | ------------ |\n")
+
+ for file in property_files:
+ lines = read_file(file)
+ keys = get_translations_as_dict(lines=lines)
+ keys_missing_value = get_empty_keys(lines=lines)
+
+ num_keys = len(keys)
+ num_keys_missing_value = len(keys_missing_value)
+ num_keys_translated = num_keys - num_keys_missing_value
+ percent_translated = int((num_keys_translated / float(num_keys)) * 100) if num_keys != 0 else 0
+
+ markdown.append("| {file} | {num_keys} | {num_keys_translated} | {num_keys_missing} | {percent_translated} |\n"
+ .format(file=get_filename(filepath=file), num_keys=num_keys, num_keys_translated=num_keys_translated, num_keys_missing=num_keys_missing_value, percent_translated=percent_translated))
+
+ markdown = []
+ date = datetime.datetime.now().strftime("%Y-%m-%d %H:%M")
+ markdown.append("### Localization files status ({date} - Branch `{branch}` `{hash}`)\n".format(date=date, branch=get_current_branch(), hash=get_current_hash_short()))
+
+ write_properties(property_files=get_all_jabref_properties())
+ write_properties(property_files=get_all_menu_properties())
+ write_file(STATUS_FILE, markdown)
+ logger.ok("Current status written to {}".format(STATUS_FILE))
+ open_file(STATUS_FILE)
+
+
+if len(sys.argv) == 2 and sys.argv[1] == "markdown":
+ status_create_markdown()
+
+elif (len(sys.argv) == 2 or len(sys.argv) == 3) and sys.argv[1] == "update":
+ update(extended=len(sys.argv) == 3 and (sys.argv[2] == "-e" or sys.argv[2] == "--extended"))
+
+elif (len(sys.argv) == 2 or len(sys.argv) == 3) and sys.argv[1] == "status":
+ status(extended=len(sys.argv) == 3 and (sys.argv[2] == "-e" or sys.argv[2] == "--extended"))
+
+else:
+ logger.neutral("""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:
-
- -c: Search the language files for empty and duplicate translations. Display only
- counts for duplicated and empty values in each language file.
-
- -d: Search the language files for empty and duplicate translations.
- For each duplicate set found, a list will be printed showing the various
- translations for the same key. There is currently no option to remove duplicates
- automatically.
-
- -t [-u]: Compare the contents of "JabRef_en.properties" and "Menu_en.properties" against the other
- language files. The program will list for all the other files which keys from the English
- file are missing. Additionally, the program will list keys in the other files which are
- not present in the English file - possible obsolete keys.
-
- If the -u option is specified, all missing keys will automatically be added to the files
- and all obsolete keys will be automatically removed.
-"""
-
-elif (len(sys.argv) >= 2) and (sys.argv[1] == "-t"):
- if (len(sys.argv) >= 3) and (sys.argv[2] == "-u"):
- change_files = True
- else:
- change_files = False
-
- filesJabRef = filter(lambda s: (s.startswith('JabRef_') and not (s.startswith('JabRef_en'))), os.listdir(res_dir))
- filesJabRef = [os.path.join(res_dir, i) for i in filesJabRef]
- filesMenu = filter(lambda s: (s.startswith('Menu_') and not (s.startswith('Menu_en'))), os.listdir(res_dir))
- filesMenu = [os.path.join(res_dir, i) for i in filesMenu]
-
- compare_property_files_to_main_property_file(os.path.join(res_dir, "JabRef_en.properties"), filesJabRef, change_files)
- compare_property_files_to_main_property_file(os.path.join(res_dir, "Menu_en.properties"), filesMenu, change_files)
-
-elif (len(sys.argv) >= 2) and ((sys.argv[1] == "-d") or (sys.argv[1] == "-c")):
- files = filter(lambda s: (s.startswith('JabRef_') and not (s.startswith('JabRef_en'))), os.listdir(res_dir))
- files.extend(filter(lambda s: (s.startswith('Menu_') and not (s.startswith('Menu_en'))), os.listdir(res_dir)))
- files = [os.path.join(res_dir, i) for i in files]
- for f in files:
- find_duplicate_keys_and_keys_with_no_value(f, sys.argv[1] == "-d")
+
+ status [-e | --extended]:
+ prints the current status to the terminal
+ [-e | --extended]:
+ if the translations keys which create problems should be printed
+
+ markdown:
+ Creates a markdown file of the current status and opens it
+
+ 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
+""")
diff --git a/scripts/upload-to-builds.jabref.org.sh b/scripts/upload-to-builds.jabref.org.sh
index de74122..b2415f4 100755
--- a/scripts/upload-to-builds.jabref.org.sh
+++ b/scripts/upload-to-builds.jabref.org.sh
@@ -23,7 +23,7 @@ command="cd www/\n"
# then, "snapshot" is extracted
if [ "snapshot" != "$branch" ] ; then
# change into dir and delete old snapshots
- command="${command}mkdir $branch\ncd $branch\nrm *\n"
+ command="${command}mkdir $branch\ncd $branch\nrm *.dmg\nrm *.jar\nrm *.exe\n"
fi
#only upload [Jr]ab[Rr]ef*, not md5sums, updates.xml, etc.
diff --git a/src/databaseTest/java/net/sf/jabref/shared/DBMSConnectorTest.java b/src/databaseTest/java/net/sf/jabref/shared/DBMSConnectorTest.java
deleted file mode 100644
index ca0d9b9..0000000
--- a/src/databaseTest/java/net/sf/jabref/shared/DBMSConnectorTest.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package net.sf.jabref.shared;
-
-import java.sql.SQLException;
-import java.util.Collection;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameter;
-import org.junit.runners.Parameterized.Parameters;
-
- at RunWith(Parameterized.class)
-public class DBMSConnectorTest {
-
- @Parameter
- public DBMSType dbmsType;
-
-
- @Parameters(name = "Test with {0} database system")
- public static Collection<DBMSType> getTestingDatabaseSystems() {
- return DBMSConnector.getAvailableDBMSTypes();
- }
-
- @Test
- public void testGetNewConnection() throws ClassNotFoundException, SQLException {
- DBMSConnectionProperties properties = TestConnector.getConnectionProperties(dbmsType);
- DBMSConnector.getNewConnection(properties);
- }
-
- @Test(expected = SQLException.class)
- public void testGetNewConnectionFail() throws SQLException, ClassNotFoundException {
- DBMSConnector.getNewConnection(new DBMSConnectionProperties(dbmsType, "XXXX", 0, "XXXX", "XXXX", "XXXX"));
- }
-}
diff --git a/src/databaseTest/java/net/sf/jabref/shared/DBMSProcessorTest.java b/src/databaseTest/java/net/sf/jabref/shared/DBMSProcessorTest.java
deleted file mode 100644
index d5dcc98..0000000
--- a/src/databaseTest/java/net/sf/jabref/shared/DBMSProcessorTest.java
+++ /dev/null
@@ -1,326 +0,0 @@
-package net.sf.jabref.shared;
-
-import java.sql.Connection;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-
-import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.shared.exception.OfflineLockException;
-import net.sf.jabref.shared.exception.SharedEntryNotPresentException;
-
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameter;
-import org.junit.runners.Parameterized.Parameters;
-
- at RunWith(Parameterized.class)
-public class DBMSProcessorTest {
-
- private static Connection connection;
- private DBMSProcessor dbmsProcessor;
-
- @Parameter
- public DBMSType dbmsType;
-
-
- @Before
- public void setUp() throws ClassNotFoundException, SQLException {
- // Get only one connection for each parameter
- if (TestConnector.currentConnectionType != dbmsType) {
- connection = TestConnector.getTestConnection(dbmsType);
- }
- dbmsProcessor = DBMSProcessor.getProcessorInstance(connection, dbmsType);
- dbmsProcessor.setupSharedDatabase();
- }
-
- @Parameters(name = "Test with {0} database system")
- public static Collection<DBMSType> getTestingDatabaseSystems() {
- return DBMSConnector.getAvailableDBMSTypes();
- }
-
- @Test
- public void testCheckBaseIntegrity() throws SQLException {
- Assert.assertTrue(dbmsProcessor.checkBaseIntegrity());
- clear();
- Assert.assertFalse(dbmsProcessor.checkBaseIntegrity());
- }
-
- @Test
- public void testSetUpSharedDatabase() throws SQLException {
- clear();
- dbmsProcessor.setupSharedDatabase();
- Assert.assertTrue(dbmsProcessor.checkBaseIntegrity());
- }
-
- @Test
- public void testInsertEntry() throws SQLException {
- BibEntry expectedEntry = getBibEntryExample();
-
- dbmsProcessor.insertEntry(expectedEntry);
-
- BibEntry emptyEntry = new BibEntry();
- emptyEntry.getSharedBibEntryData().setSharedID(1);
- dbmsProcessor.insertEntry(emptyEntry); // does not insert, due to same sharedID.
-
- Map<String, String> actualFieldMap = new HashMap<>();
-
- try (ResultSet entryResultSet = selectFrom("ENTRY")) {
- Assert.assertTrue(entryResultSet.next());
- Assert.assertEquals(1, entryResultSet.getInt("SHARED_ID"));
- Assert.assertEquals("inproceedings", entryResultSet.getString("TYPE"));
- Assert.assertEquals(1, entryResultSet.getInt("VERSION"));
- Assert.assertFalse(entryResultSet.next());
-
- try (ResultSet fieldResultSet = selectFrom("FIELD")) {
- while (fieldResultSet.next()) {
- actualFieldMap.put(fieldResultSet.getString("NAME"), fieldResultSet.getString("VALUE"));
- }
- }
- }
-
- Map<String, String> expectedFieldMap = expectedEntry.getFieldMap();
-
- Assert.assertEquals(expectedFieldMap, actualFieldMap);
- }
-
- @Test
- public void testUpdateEntry() throws OfflineLockException, SharedEntryNotPresentException, SQLException {
- BibEntry expectedEntry = getBibEntryExample();
-
- dbmsProcessor.insertEntry(expectedEntry);
-
- expectedEntry.setType("book");
- expectedEntry.setField("author", "Michael J and Hutchings");
- expectedEntry.setField("customField", "custom value");
- expectedEntry.clearField("booktitle");
-
- dbmsProcessor.updateEntry(expectedEntry);
-
- Optional<BibEntry> actualEntryOptional = dbmsProcessor
- .getSharedEntry(expectedEntry.getSharedBibEntryData().getSharedID());
-
- if (actualEntryOptional.isPresent()) {
- Assert.assertEquals(expectedEntry, actualEntryOptional.get());
- } else {
- Assert.fail();
- }
- }
-
- @Test(expected = SharedEntryNotPresentException.class)
- public void testUpdateNotExistingEntry() throws SharedEntryNotPresentException, OfflineLockException, SQLException {
- BibEntry expectedEntry = getBibEntryExample();
- dbmsProcessor.updateEntry(expectedEntry);
- }
-
- @Test(expected = OfflineLockException.class)
- public void testUpdateNewerEntry() throws OfflineLockException, SharedEntryNotPresentException, SQLException {
- BibEntry bibEntry = getBibEntryExample();
-
- dbmsProcessor.insertEntry(bibEntry);
-
- bibEntry.getSharedBibEntryData().setVersion(0); // simulate older version
- bibEntry.setField("year", "1993");
-
- dbmsProcessor.updateEntry(bibEntry);
- }
-
- @Test
- public void testUpdateEqualEntry() throws OfflineLockException, SharedEntryNotPresentException, SQLException {
- BibEntry expectedBibEntry = getBibEntryExample();
-
- dbmsProcessor.insertEntry(expectedBibEntry);
-
- expectedBibEntry.getSharedBibEntryData().setVersion(0); // simulate older version
-
- dbmsProcessor.updateEntry(expectedBibEntry);
-
- Optional<BibEntry> actualBibEntryOptional = dbmsProcessor
- .getSharedEntry(expectedBibEntry.getSharedBibEntryData().getSharedID());
-
- if (actualBibEntryOptional.isPresent()) {
- Assert.assertEquals(expectedBibEntry, actualBibEntryOptional.get());
- } else {
- Assert.fail();
- }
- }
-
- @Test
- public void testRemoveEntry() throws SQLException {
- BibEntry bibEntry = getBibEntryExample();
- dbmsProcessor.insertEntry(bibEntry);
- dbmsProcessor.removeEntry(bibEntry);
-
- try (ResultSet resultSet = selectFrom("ENTRY")) {
- Assert.assertFalse(resultSet.next());
- }
- }
-
- @Test
- public void testGetSharedEntries() {
- BibEntry bibEntry = getBibEntryExampleWithEmptyFields();
-
- dbmsProcessor.insertEntry(bibEntry);
-
- List<BibEntry> expectedEntries = Arrays.asList(bibEntry);
- List<BibEntry> actualEntries = dbmsProcessor.getSharedEntries();
-
- Assert.assertEquals(expectedEntries, actualEntries);
- }
-
- @Test
- public void testGetSharedEntry() {
- BibEntry expectedBibEntry = getBibEntryExampleWithEmptyFields();
-
- dbmsProcessor.insertEntry(expectedBibEntry);
-
- Optional<BibEntry> actualBibEntryOptional = dbmsProcessor
- .getSharedEntry(expectedBibEntry.getSharedBibEntryData().getSharedID());
-
- if (actualBibEntryOptional.isPresent()) {
- Assert.assertEquals(expectedBibEntry, actualBibEntryOptional.get());
- } else {
- Assert.fail();
- }
- }
-
- @Test
- public void testGetNotExistingSharedEntry() {
- Optional<BibEntry> actualBibEntryOptional = dbmsProcessor.getSharedEntry(1);
- Assert.assertFalse(actualBibEntryOptional.isPresent());
- }
-
- @Test
- public void testGetSharedIDVersionMapping() throws OfflineLockException, SharedEntryNotPresentException, SQLException {
- BibEntry firstEntry = getBibEntryExample();
- BibEntry secondEntry = getBibEntryExample();
-
- dbmsProcessor.insertEntry(firstEntry);
- dbmsProcessor.insertEntry(secondEntry);
- dbmsProcessor.updateEntry(secondEntry);
-
- Map<Integer, Integer> expectedIDVersionMap = new HashMap<>();
- expectedIDVersionMap.put(firstEntry.getSharedBibEntryData().getSharedID(), 1);
- expectedIDVersionMap.put(secondEntry.getSharedBibEntryData().getSharedID(), 2);
-
- Map<Integer, Integer> actualIDVersionMap = dbmsProcessor.getSharedIDVersionMapping();
-
- Assert.assertEquals(expectedIDVersionMap, actualIDVersionMap);
-
- }
-
- @Test
- public void testGetSharedMetaData() {
- insertMetaData("databaseType", "bibtex;");
- insertMetaData("protectedFlag", "true;");
- insertMetaData("saveActions", "enabled;\nauthor[capitalize,html_to_latex]\ntitle[title_case]\n;");
- insertMetaData("saveOrderConfig", "specified;author;false;title;false;year;true;");
-
- Map<String, String> expectedMetaData = getMetaDataExample();
- Map<String, String> actualMetaData = dbmsProcessor.getSharedMetaData();
-
- Assert.assertEquals(expectedMetaData, actualMetaData);
-
- }
-
- @Test
- public void testSetSharedMetaData() throws SQLException {
- Map<String, String> expectedMetaData = getMetaDataExample();
- dbmsProcessor.setSharedMetaData(expectedMetaData);
-
- Map<String, String> actualMetaData = dbmsProcessor.getSharedMetaData();
-
- Assert.assertEquals(expectedMetaData, actualMetaData);
- }
-
- private Map<String, String> getMetaDataExample() {
- Map<String, String> expectedMetaData = new HashMap<>();
-
- expectedMetaData.put("databaseType", "bibtex;");
- expectedMetaData.put("protectedFlag", "true;");
- expectedMetaData.put("saveActions", "enabled;\nauthor[capitalize,html_to_latex]\ntitle[title_case]\n;");
- expectedMetaData.put("saveOrderConfig", "specified;author;false;title;false;year;true;");
-
- return expectedMetaData;
- }
-
- private BibEntry getBibEntryExampleWithEmptyFields() {
- BibEntry bibEntry = new BibEntry();
- bibEntry.setField("author", "Author");
- bibEntry.setField("title", "");
- bibEntry.setField("year", "");
- bibEntry.getSharedBibEntryData().setSharedID(1);
- return bibEntry;
- }
-
- private BibEntry getBibEntryExample() {
- BibEntry bibEntry = new BibEntry();
- bibEntry.setType("inproceedings");
- bibEntry.setField("author", "Wirthlin, Michael J and Hutchings, Brad L and Gilson, Kent L");
- bibEntry.setField("title", "The nano processor: a low resource reconfigurable processor");
- bibEntry.setField("booktitle", "FPGAs for Custom Computing Machines, 1994. Proceedings. IEEE Workshop on");
- bibEntry.setField("year", "1994");
- bibEntry.setCiteKey("nanoproc1994");
- return bibEntry;
- }
-
- private ResultSet selectFrom(String table) {
- try {
- return connection.createStatement().executeQuery("SELECT * FROM " + escape(table));
- } catch (SQLException e) {
- Assert.fail(e.getMessage());
- return null;
- }
- }
-
- // Oracle does not support multiple tuple insertion in one INSERT INTO command.
- // Therefore this function was defined to improve the readability and to keep the code short.
- private void insertMetaData(String key, String value) {
- try {
- connection.createStatement().executeUpdate("INSERT INTO " + escape("METADATA") + "("
- + escape("KEY") + ", " + escape("VALUE") + ") VALUES("
- + escapeValue(key) + ", " + escapeValue(value) + ")");
- } catch (SQLException e) {
- Assert.fail(e.getMessage());
- }
- }
-
- private String escape(String expression) {
- return dbmsProcessor.escape(expression);
- }
-
- private String escapeValue(String value) {
- return "'" + value + "'";
- }
-
- @After
- public void clear() throws SQLException {
- if ((dbmsType == DBMSType.MYSQL) || (dbmsType == DBMSType.POSTGRESQL)) {
- connection.createStatement().executeUpdate("DROP TABLE IF EXISTS " + escape("FIELD"));
- connection.createStatement().executeUpdate("DROP TABLE IF EXISTS " + escape("ENTRY"));
- connection.createStatement().executeUpdate("DROP TABLE IF EXISTS " + escape("METADATA"));
- } else if (dbmsType == DBMSType.ORACLE) {
- connection.createStatement().executeUpdate(
- "BEGIN\n" +
- "EXECUTE IMMEDIATE 'DROP TABLE " + escape("FIELD") + "';\n" +
- "EXECUTE IMMEDIATE 'DROP TABLE " + escape("ENTRY") + "';\n" +
- "EXECUTE IMMEDIATE 'DROP TABLE " + escape("METADATA") + "';\n" +
- "EXECUTE IMMEDIATE 'DROP SEQUENCE " + escape("ENTRY_SEQ") + "';\n" +
- "EXCEPTION\n" +
- "WHEN OTHERS THEN\n" +
- "IF SQLCODE != -942 THEN\n" +
- "RAISE;\n" +
- "END IF;\n" +
- "END;");
- }
- }
-}
diff --git a/src/databaseTest/java/net/sf/jabref/shared/DBMSSynchronizerTest.java b/src/databaseTest/java/net/sf/jabref/shared/DBMSSynchronizerTest.java
deleted file mode 100644
index 6e8f8d4..0000000
--- a/src/databaseTest/java/net/sf/jabref/shared/DBMSSynchronizerTest.java
+++ /dev/null
@@ -1,233 +0,0 @@
-package net.sf.jabref.shared;
-
-import java.sql.Connection;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-
-import net.sf.jabref.BibDatabaseContext;
-import net.sf.jabref.Globals;
-import net.sf.jabref.MetaData;
-import net.sf.jabref.event.source.EntryEventSource;
-import net.sf.jabref.model.database.BibDatabase;
-import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.preferences.JabRefPreferences;
-import net.sf.jabref.shared.exception.DatabaseNotSupportedException;
-import net.sf.jabref.shared.exception.OfflineLockException;
-import net.sf.jabref.shared.exception.SharedEntryNotPresentException;
-
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameter;
-import org.junit.runners.Parameterized.Parameters;
-
- at RunWith(Parameterized.class)
-public class DBMSSynchronizerTest {
-
- private DBMSSynchronizer dbmsSynchronizer;
- private Connection connection;
- private DBMSProcessor dbmsProcessor;
- private BibDatabase bibDatabase;
-
- @Parameter
- public DBMSType dbmsType;
-
-
- @Before
- public void setUp() throws ClassNotFoundException, SQLException, DatabaseNotSupportedException {
-
- Globals.prefs = JabRefPreferences.getInstance();
-
- connection = TestConnector.getTestConnection(dbmsType);
-
- bibDatabase = new BibDatabase();
- BibDatabaseContext context = new BibDatabaseContext(bibDatabase);
-
-
- dbmsSynchronizer = new DBMSSynchronizer(context);
- dbmsProcessor = DBMSProcessor.getProcessorInstance(connection, dbmsType);
-
- bibDatabase.registerListener(dbmsSynchronizer);
-
- dbmsSynchronizer.openSharedDatabase(connection, dbmsType, "TEST");
- }
-
- @Parameters(name = "Test with {0} database system")
- public static Collection<DBMSType> getTestingDatabaseSystems() {
- return DBMSConnector.getAvailableDBMSTypes();
- }
-
- @Test
- public void testEntryAddedEventListener() {
- BibEntry expectedEntry = getBibEntryExample(1);
- BibEntry furtherEntry = getBibEntryExample(1);
-
- bibDatabase.insertEntry(expectedEntry);
- // should not add into shared database.
- bibDatabase.insertEntry(furtherEntry, EntryEventSource.SHARED);
-
- List<BibEntry> actualEntries = dbmsProcessor.getSharedEntries();
-
- Assert.assertEquals(1, actualEntries.size());
- Assert.assertEquals(expectedEntry, actualEntries.get(0));
- }
-
- @Test
- public void testFieldChangedEventListener() {
- BibEntry expectedEntry = getBibEntryExample(1);
- expectedEntry.registerListener(dbmsSynchronizer);
-
- bibDatabase.insertEntry(expectedEntry);
- expectedEntry.setField("author", "Brad L and Gilson");
- expectedEntry.setField("title", "The micro multiplexer", EntryEventSource.SHARED);
-
- List<BibEntry> actualEntries = dbmsProcessor.getSharedEntries();
- Assert.assertEquals(1, actualEntries.size());
- Assert.assertEquals(expectedEntry.getFieldOptional("author"), actualEntries.get(0).getFieldOptional("author"));
- Assert.assertEquals("The nano processor1", actualEntries.get(0).getFieldOptional("title").get());
-
- }
-
- @Test
- public void testEntryRemovedEventListener() {
- BibEntry bibEntry = getBibEntryExample(1);
- bibDatabase.insertEntry(bibEntry);
-
- List<BibEntry> actualEntries = dbmsProcessor.getSharedEntries();
- Assert.assertEquals(1, actualEntries.size());
- Assert.assertEquals(bibEntry, actualEntries.get(0));
-
- bibDatabase.removeEntry(bibEntry);
- actualEntries = dbmsProcessor.getSharedEntries();
-
- Assert.assertEquals(0, actualEntries.size());
-
- bibDatabase.insertEntry(bibEntry);
- bibDatabase.removeEntry(bibEntry, EntryEventSource.SHARED);
-
- actualEntries = dbmsProcessor.getSharedEntries();
- Assert.assertEquals(1, actualEntries.size());
- Assert.assertEquals(bibEntry, actualEntries.get(0));
- }
-
- @Test
- public void testMetaDataChangedEventListener() {
- MetaData testMetaData = new MetaData();
- testMetaData.registerListener(dbmsSynchronizer);
- dbmsSynchronizer.setMetaData(testMetaData);
- testMetaData.putData("databaseType", Arrays.asList("bibtex"));
-
- Map<String, String> expectedMap = testMetaData.getAsStringMap();
- Map<String, String> actualMap = dbmsProcessor.getSharedMetaData();
-
- Assert.assertEquals(expectedMap, actualMap);
- }
-
- @Test
- public void testInitializeDatabases() throws SQLException, DatabaseNotSupportedException {
- clear();
- dbmsSynchronizer.initializeDatabases();
- Assert.assertTrue(dbmsProcessor.checkBaseIntegrity());
- dbmsSynchronizer.initializeDatabases();
- Assert.assertTrue(dbmsProcessor.checkBaseIntegrity());
- }
-
- @Test
- public void testSynchronizeLocalDatabaseWithEntryRemoval() {
- List<BibEntry> expectedBibEntries = Arrays.asList(getBibEntryExample(1), getBibEntryExample(2));
-
- dbmsProcessor.insertEntry(expectedBibEntries.get(0));
- dbmsProcessor.insertEntry(expectedBibEntries.get(1));
-
- Assert.assertTrue(bibDatabase.getEntries().isEmpty());
-
- dbmsSynchronizer.synchronizeLocalDatabase();
-
- Assert.assertEquals(expectedBibEntries, bibDatabase.getEntries());
-
- dbmsProcessor.removeEntry(expectedBibEntries.get(0));
- dbmsProcessor.removeEntry(expectedBibEntries.get(1));
-
- expectedBibEntries = new ArrayList<>();
-
- dbmsSynchronizer.synchronizeLocalDatabase();
-
- Assert.assertEquals(expectedBibEntries, bibDatabase.getEntries());
- }
-
- @Test
- public void testSynchronizeLocalDatabaseWithEntryUpdate() throws OfflineLockException, SharedEntryNotPresentException, SQLException {
- BibEntry bibEntry = getBibEntryExample(1);
- bibDatabase.insertEntry(bibEntry);
- Assert.assertEquals(1, bibDatabase.getEntries().size());
-
- BibEntry modifiedBibEntry = getBibEntryExample(1);
- modifiedBibEntry.setField("custom", "custom value");
- modifiedBibEntry.clearField("title");
- modifiedBibEntry.setType("article");
-
- dbmsProcessor.updateEntry(modifiedBibEntry);
-
- dbmsSynchronizer.synchronizeLocalDatabase(); // testing point
-
- Assert.assertEquals(bibDatabase.getEntries(), dbmsProcessor.getSharedEntries());
- }
-
- @Test
- public void testApplyMetaData() {
- BibEntry bibEntry = getBibEntryExample(1);
- bibDatabase.insertEntry(bibEntry);
-
- MetaData testMetaData = new MetaData();
- testMetaData.putData("saveActions", Arrays.asList("enabled", "author[lower_case]"));
- dbmsSynchronizer.setMetaData(testMetaData);
-
- dbmsSynchronizer.applyMetaData();
-
- Assert.assertEquals("wirthlin, michael j1", bibEntry.getFieldOptional("author").get());
-
- }
-
- private BibEntry getBibEntryExample(int index) {
- BibEntry bibEntry = new BibEntry();
- bibEntry.setType("book");
- bibEntry.setField("author", "Wirthlin, Michael J" + index);
- bibEntry.setField("title", "The nano processor" + index);
- bibEntry.getSharedBibEntryData().setSharedID(index);
- return bibEntry;
- }
-
- private String escape(String expression) {
- return dbmsProcessor.escape(expression);
- }
-
- @After
- public void clear() throws SQLException {
- if ((dbmsType == DBMSType.MYSQL) || (dbmsType == DBMSType.POSTGRESQL)) {
- connection.createStatement().executeUpdate("DROP TABLE IF EXISTS " + escape("FIELD"));
- connection.createStatement().executeUpdate("DROP TABLE IF EXISTS " + escape("ENTRY"));
- connection.createStatement().executeUpdate("DROP TABLE IF EXISTS " + escape("METADATA"));
- } else if (dbmsType == DBMSType.ORACLE) {
- connection.createStatement().executeUpdate(
- "BEGIN\n" +
- "EXECUTE IMMEDIATE 'DROP TABLE " + escape("FIELD") + "';\n" +
- "EXECUTE IMMEDIATE 'DROP TABLE " + escape("ENTRY") + "';\n" +
- "EXECUTE IMMEDIATE 'DROP TABLE " + escape("METADATA") + "';\n" +
- "EXECUTE IMMEDIATE 'DROP SEQUENCE " + escape("ENTRY_SEQ") + "';\n" +
- "EXCEPTION\n" +
- "WHEN OTHERS THEN\n" +
- "IF SQLCODE != -942 THEN\n" +
- "RAISE;\n" +
- "END IF;\n" +
- "END;");
- }
- }
-
-}
diff --git a/src/databaseTest/java/net/sf/jabref/shared/DBMSTypeTest.java b/src/databaseTest/java/net/sf/jabref/shared/DBMSTypeTest.java
deleted file mode 100644
index 435ada0..0000000
--- a/src/databaseTest/java/net/sf/jabref/shared/DBMSTypeTest.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package net.sf.jabref.shared;
-
-import org.junit.Assert;
-import org.junit.Test;
-
-public class DBMSTypeTest {
-
- @Test
- public void testToString() {
- Assert.assertEquals("MySQL", DBMSType.MYSQL.toString());
- Assert.assertEquals("Oracle", DBMSType.ORACLE.toString());
- Assert.assertEquals("PostgreSQL", DBMSType.POSTGRESQL.toString());
- }
-
- @Test
- public void testGetDriverClassPath() {
- Assert.assertEquals("com.mysql.jdbc.Driver", DBMSType.MYSQL.getDriverClassPath());
- Assert.assertEquals("oracle.jdbc.driver.OracleDriver", DBMSType.ORACLE.getDriverClassPath());
- Assert.assertEquals("org.postgresql.Driver", DBMSType.POSTGRESQL.getDriverClassPath());
- }
-
- @Test
- public void testFromString() {
- Assert.assertEquals(DBMSType.MYSQL, DBMSType.fromString("MySQL").get());
- Assert.assertEquals(DBMSType.ORACLE, DBMSType.fromString("Oracle").get());
- Assert.assertEquals(DBMSType.POSTGRESQL, DBMSType.fromString("PostgreSQL").get());
- Assert.assertFalse(DBMSType.fromString("XXX").isPresent());
- }
-
- @Test
- public void testGetUrl() {
- Assert.assertEquals("jdbc:mysql://localhost:3306/xe", DBMSType.MYSQL.getUrl("localhost", 3306, "xe"));
- Assert.assertEquals("jdbc:oracle:thin:@localhost:1521:xe", DBMSType.ORACLE.getUrl("localhost", 1521, "xe"));
- Assert.assertEquals("jdbc:postgresql://localhost:5432/xe", DBMSType.POSTGRESQL.getUrl("localhost", 5432, "xe"));
- }
-
- @Test
- public void testGetDefaultPort() {
- Assert.assertEquals(3306, DBMSType.MYSQL.getDefaultPort());
- Assert.assertEquals(5432, DBMSType.POSTGRESQL.getDefaultPort());
- Assert.assertEquals(1521, DBMSType.ORACLE.getDefaultPort());
- }
-
-}
diff --git a/src/databaseTest/java/net/sf/jabref/shared/SynchronizationTestEventListener.java b/src/databaseTest/java/net/sf/jabref/shared/SynchronizationTestEventListener.java
deleted file mode 100644
index d4158f5..0000000
--- a/src/databaseTest/java/net/sf/jabref/shared/SynchronizationTestEventListener.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package net.sf.jabref.shared;
-
-import net.sf.jabref.shared.event.SharedEntryNotPresentEvent;
-import net.sf.jabref.shared.event.UpdateRefusedEvent;
-
-import com.google.common.eventbus.Subscribe;
-
-public class SynchronizationTestEventListener {
-
- private SharedEntryNotPresentEvent sharedEntryNotPresentEvent;
- private UpdateRefusedEvent updateRefusedEvent;
-
-
- @Subscribe
- public void listen(SharedEntryNotPresentEvent event) {
- this.sharedEntryNotPresentEvent = event;
- }
-
- @Subscribe
- public void listen(UpdateRefusedEvent event) {
- this.updateRefusedEvent = event;
- }
-
- public SharedEntryNotPresentEvent getSharedEntryNotPresentEvent() {
- return sharedEntryNotPresentEvent;
- }
-
- public UpdateRefusedEvent getUpdateRefusedEvent() {
- return updateRefusedEvent;
- }
-}
diff --git a/src/databaseTest/java/net/sf/jabref/shared/SynchronizationTestSimulator.java b/src/databaseTest/java/net/sf/jabref/shared/SynchronizationTestSimulator.java
deleted file mode 100644
index f11d6f6..0000000
--- a/src/databaseTest/java/net/sf/jabref/shared/SynchronizationTestSimulator.java
+++ /dev/null
@@ -1,182 +0,0 @@
-package net.sf.jabref.shared;
-
-import java.sql.Connection;
-import java.sql.SQLException;
-import java.util.Collection;
-
-import net.sf.jabref.BibDatabaseContext;
-import net.sf.jabref.Defaults;
-import net.sf.jabref.Globals;
-import net.sf.jabref.model.database.BibDatabaseMode;
-import net.sf.jabref.model.database.DatabaseLocation;
-import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.preferences.JabRefPreferences;
-import net.sf.jabref.shared.exception.DatabaseNotSupportedException;
-
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameter;
-import org.junit.runners.Parameterized.Parameters;
-
- at RunWith(Parameterized.class)
-public class SynchronizationTestSimulator {
-
- private static Connection connection;
-
- private BibDatabaseContext clientContextA;
- private BibDatabaseContext clientContextB;
-
- private SynchronizationTestEventListener eventListenerB; // used to monitor occurring events
-
- @Parameter
- public DBMSType dbmsType;
-
-
- @Before
- public void setUp() throws ClassNotFoundException, SQLException, DatabaseNotSupportedException {
- // Get only one connection for each parameter
- if (TestConnector.currentConnectionType != dbmsType) {
- connection = TestConnector.getTestConnection(dbmsType);
- }
-
- Globals.prefs = JabRefPreferences.getInstance();
-
- clientContextA = new BibDatabaseContext(new Defaults(BibDatabaseMode.BIBTEX), DatabaseLocation.SHARED);
- clientContextA.getDBSynchronizer().openSharedDatabase(connection, dbmsType, "A");
-
- clientContextB = new BibDatabaseContext(new Defaults(BibDatabaseMode.BIBTEX), DatabaseLocation.SHARED);
- clientContextB.getDBSynchronizer().openSharedDatabase(connection, dbmsType, "B");
- eventListenerB = new SynchronizationTestEventListener();
- clientContextB.getDBSynchronizer().registerListener(eventListenerB);
- }
-
- @Parameters(name = "Test with {0} database system")
- public static Collection<DBMSType> getTestingDatabaseSystems() {
- return DBMSConnector.getAvailableDBMSTypes();
- }
-
- @Test
- public void simulateEntryInsertionAndManualPull() {
- clientContextA.getDatabase().insertEntry(getBibEntryExample(1)); // client A inserts an entry
- clientContextA.getDatabase().insertEntry(getBibEntryExample(2)); // client A inserts another entry
- clientContextB.getDBSynchronizer().pullChanges(); // client B pulls the changes
-
- Assert.assertEquals(clientContextA.getDatabase().getEntries(), clientContextB.getDatabase().getEntries());
- }
-
- @Test
- public void simulateEntryUpdateAndManualPull() {
- BibEntry bibEntry = getBibEntryExample(1);
- clientContextA.getDatabase().insertEntry(bibEntry); // client A inserts an entry
- bibEntry.setField("custom", "custom value"); // client A changes the entry
- bibEntry.clearField("author");
-
- clientContextB.getDBSynchronizer().pullChanges(); // client B pulls the changes
-
- Assert.assertEquals(clientContextA.getDatabase().getEntries(), clientContextB.getDatabase().getEntries());
- }
-
- @Test
- public void simulateEntryDelitionAndManualPull() {
- BibEntry bibEntry = getBibEntryExample(1);
- clientContextA.getDatabase().insertEntry(bibEntry); // client A inserts an entry
- clientContextB.getDBSynchronizer().pullChanges(); // client B pulls the entry
-
- Assert.assertFalse(clientContextA.getDatabase().getEntries().isEmpty());
- Assert.assertFalse(clientContextB.getDatabase().getEntries().isEmpty());
- Assert.assertEquals(clientContextA.getDatabase().getEntries(), clientContextB.getDatabase().getEntries());
-
- clientContextA.getDatabase().removeEntry(bibEntry); // client A removes the entry
- clientContextB.getDBSynchronizer().pullChanges(); // client B pulls the change
-
- Assert.assertTrue(clientContextA.getDatabase().getEntries().isEmpty());
- Assert.assertTrue(clientContextB.getDatabase().getEntries().isEmpty());
- }
-
- @Test
- public void simulateUpdateOnNoLongerExistingEntry() {
- BibEntry bibEntryOfClientA = getBibEntryExample(1);
- clientContextA.getDatabase().insertEntry(bibEntryOfClientA); // client A inserts an entry
- clientContextB.getDBSynchronizer().pullChanges(); // client B pulls the entry
-
- Assert.assertFalse(clientContextA.getDatabase().getEntries().isEmpty());
- Assert.assertFalse(clientContextB.getDatabase().getEntries().isEmpty());
- Assert.assertEquals(clientContextA.getDatabase().getEntries(), clientContextB.getDatabase().getEntries());
-
- clientContextA.getDatabase().removeEntry(bibEntryOfClientA); // client A removes the entry
-
- Assert.assertFalse(clientContextB.getDatabase().getEntries().isEmpty());
- Assert.assertNull(eventListenerB.getSharedEntryNotPresentEvent());
-
- BibEntry bibEntryOfClientB = clientContextB.getDatabase().getEntries().get(0); // client B tries to update the entry
- bibEntryOfClientB.setField("year", "2009");
-
- // here a new SharedEntryNotPresentEvent has been thrown. In this case the user B would get an pop-up window.
- Assert.assertNotNull(eventListenerB.getSharedEntryNotPresentEvent());
- Assert.assertEquals(bibEntryOfClientB, eventListenerB.getSharedEntryNotPresentEvent().getBibEntry());
- }
-
- @Test
- public void simulateEntryChangeConflicts() {
- BibEntry bibEntryOfClientA = getBibEntryExample(1);
- clientContextA.getDatabase().insertEntry(bibEntryOfClientA); // client A inserts an entry
- clientContextB.getDBSynchronizer().pullChanges(); // client B pulls the entry
-
- bibEntryOfClientA.setField("year", "2001"); // A now increases the version number
-
- // B does nothing here, so there is no event occurrence
-
- // B now tries to update the entry
- Assert.assertFalse(clientContextB.getDatabase().getEntries().isEmpty());
-
- Assert.assertNull(eventListenerB.getUpdateRefusedEvent());
-
- BibEntry bibEntryOfClientB = clientContextB.getDatabase().getEntries().get(0);
- bibEntryOfClientB.setField("year", "2016"); // B also tries to change something
-
- // B now can not update the shared entry, due to optimistic offline lock.
- // In this case an BibEntry merge dialog pops up.
- Assert.assertNotNull(eventListenerB.getUpdateRefusedEvent());
- }
-
- private BibEntry getBibEntryExample(int index) {
- BibEntry bibEntry = new BibEntry();
- bibEntry.setType("inproceedings");
- bibEntry.setField("author", "Wirthlin, Michael J and Hutchings, Brad L and Gilson, Kent L " + index);
- bibEntry.setField("title", "The nano processor: a low resource reconfigurable processor " + index);
- bibEntry.setField("booktitle", "FPGAs for Custom Computing Machines, 1994. Proceedings. IEEE Workshop on " + index);
- bibEntry.setField("year", "199" + index);
- bibEntry.setCiteKey("nanoproc199" + index);
- return bibEntry;
- }
-
- private String escape(String expression) {
- return DBMSProcessor.getProcessorInstance(connection, dbmsType).escape(expression);
- }
-
- @After
- public void clear() throws SQLException {
- if ((dbmsType == DBMSType.MYSQL) || (dbmsType == DBMSType.POSTGRESQL)) {
- connection.createStatement().executeUpdate("DROP TABLE IF EXISTS " + escape("FIELD"));
- connection.createStatement().executeUpdate("DROP TABLE IF EXISTS " + escape("ENTRY"));
- connection.createStatement().executeUpdate("DROP TABLE IF EXISTS " + escape("METADATA"));
- } else if (dbmsType == DBMSType.ORACLE) {
- connection.createStatement().executeUpdate(
- "BEGIN\n" +
- "EXECUTE IMMEDIATE 'DROP TABLE " + escape("FIELD") + "';\n" +
- "EXECUTE IMMEDIATE 'DROP TABLE " + escape("ENTRY") + "';\n" +
- "EXECUTE IMMEDIATE 'DROP TABLE " + escape("METADATA") + "';\n" +
- "EXECUTE IMMEDIATE 'DROP SEQUENCE " + escape("ENTRY_SEQ") + "';\n" +
- "EXCEPTION\n" +
- "WHEN OTHERS THEN\n" +
- "IF SQLCODE != -942 THEN\n" +
- "RAISE;\n" +
- "END IF;\n" +
- "END;");
- }
- }
-}
diff --git a/src/databaseTest/java/net/sf/jabref/shared/TestConnector.java b/src/databaseTest/java/net/sf/jabref/shared/TestConnector.java
deleted file mode 100644
index 949e35f..0000000
--- a/src/databaseTest/java/net/sf/jabref/shared/TestConnector.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package net.sf.jabref.shared;
-
-import java.sql.Connection;
-import java.sql.SQLException;
-
-public class TestConnector {
-
- public static DBMSType currentConnectionType;
-
-
- public static Connection getTestConnection(DBMSType dbmsType) throws ClassNotFoundException, SQLException {
- currentConnectionType = dbmsType;
-
- DBMSConnectionProperties properties = getConnectionProperties(dbmsType);
-
- return DBMSConnector.getNewConnection(properties);
- }
-
- public static DBMSConnectionProperties getConnectionProperties(DBMSType dbmsType) {
-
- if (dbmsType == DBMSType.MYSQL) {
- return new DBMSConnectionProperties(dbmsType, "localhost", dbmsType.getDefaultPort(), "jabref", "root", "");
- }
-
- if (dbmsType == DBMSType.POSTGRESQL) {
- return new DBMSConnectionProperties(dbmsType, "localhost", dbmsType.getDefaultPort(), "jabref", "postgres", "");
- }
-
- if (dbmsType == DBMSType.ORACLE) {
- return new DBMSConnectionProperties(dbmsType, "localhost", dbmsType.getDefaultPort(), "xe", "travis", "travis");
- }
-
- return new DBMSConnectionProperties();
- }
-}
diff --git a/src/graphics/ranks/ranks.xcf b/src/graphics/ranks/ranks.xcf
deleted file mode 100644
index fc5b358..0000000
Binary files a/src/graphics/ranks/ranks.xcf and /dev/null differ
diff --git a/src/integrationTest/java/net/sf/jabref/gui/AWTExceptionHandler.java b/src/integrationTest/java/net/sf/jabref/gui/AWTExceptionHandler.java
deleted file mode 100644
index 4b46c53..0000000
--- a/src/integrationTest/java/net/sf/jabref/gui/AWTExceptionHandler.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package net.sf.jabref.gui;
-
-import java.util.List;
-import java.util.concurrent.CopyOnWriteArrayList;
-
-import javax.swing.SwingUtilities;
-
-/**
- * Can catch any exceptions occuring on the EDT thread for assertion.
- */
-public class AWTExceptionHandler {
-
- private final List<Throwable> list = new CopyOnWriteArrayList<>();
-
- public void installExceptionDetectionInEDT() {
- SwingUtilities.invokeLater(() -> Thread.currentThread().setUncaughtExceptionHandler((t, e) -> list.add(e)));
- }
-
- public void assertNoExceptions() {
- if (!list.isEmpty()) {
- throw new AssertionError("Uncaught exception in EDT", list.get(0));
- }
- }
-
-}
diff --git a/src/integrationTest/java/net/sf/jabref/gui/AbstractUITest.java b/src/integrationTest/java/net/sf/jabref/gui/AbstractUITest.java
deleted file mode 100644
index 087b49f..0000000
--- a/src/integrationTest/java/net/sf/jabref/gui/AbstractUITest.java
+++ /dev/null
@@ -1,108 +0,0 @@
-package net.sf.jabref.gui;
-
-import java.io.IOException;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-
-import net.sf.jabref.JabRefMain;
-
-import org.assertj.swing.fixture.AbstractWindowFixture;
-import org.assertj.swing.fixture.FrameFixture;
-import org.assertj.swing.fixture.JFileChooserFixture;
-import org.assertj.swing.fixture.JTableFixture;
-import org.assertj.swing.image.ScreenshotTaker;
-import org.assertj.swing.junit.testcase.AssertJSwingJUnitTestCase;
-import org.assertj.swing.timing.Pause;
-import org.junit.Assert;
-
-import static org.assertj.swing.finder.WindowFinder.findFrame;
-import static org.assertj.swing.launcher.ApplicationLauncher.application;
-
-public abstract class AbstractUITest extends AssertJSwingJUnitTestCase {
-
- protected final static int SPEED_NORMAL = 50;
-
- protected AWTExceptionHandler awtExceptionHandler;
- protected FrameFixture mainFrame;
-
- @Override
- protected void onSetUp() {
- awtExceptionHandler = new AWTExceptionHandler();
- awtExceptionHandler.installExceptionDetectionInEDT();
- application(JabRefMain.class).start();
-
- robot().waitForIdle();
-
- robot().settings().timeoutToFindSubMenu(1_000);
- robot().settings().delayBetweenEvents(SPEED_NORMAL);
-
- mainFrame = findFrame(JabRefFrame.class).withTimeout(10_000).using(robot());
- robot().waitForIdle();
- }
-
- /**
- * Returns the absolute Path of the given relative Path
- * The backlashes are replaced with forwardslashes b/c assertJ can't type the former one on windows
- * @param relativePath the relative path to the resource database
- */
- protected String getAbsolutePath(String relativePath) {
- final URL resource = this.getClass().getClassLoader().getResource(relativePath);
- try {
- return Paths.get(resource.toURI()).toAbsolutePath().toString().replace("\\", "/");
- } catch (URISyntaxException e) {
- e.printStackTrace();
- }
- return null;
- }
-
- /**
- * opens a database and gives JabRef a second to open it before proceeding
- */
- protected void importBibIntoNewDatabase(String path) {
- mainFrame.menuItemWithPath("File", "Import into new database").click();
- JFileChooserFixture openFileDialog = mainFrame.fileChooser();
- robot().settings().delayBetweenEvents(1);
- openFileDialog.fileNameTextBox().enterText(path);
- openFileDialog.approve();
- Pause.pause(1_000);
- }
-
- protected void exitJabRef() {
- mainFrame.menuItemWithPath("File", "Quit").click();
- awtExceptionHandler.assertNoExceptions();
- }
-
- protected void newDatabase() {
- mainFrame.menuItemWithPath("File", "New BibTeX database").click();
- }
-
- protected void closeDatabase() {
- mainFrame.menuItemWithPath("File", "Close database").click();
- }
-
- protected void takeScreenshot(AbstractWindowFixture<?, ?, ?> dialog, String filename) throws IOException {
- ScreenshotTaker screenshotTaker = new ScreenshotTaker();
- Path folder = Paths.get("build", "screenshots");
- // Create build/srceenshots folder if not present
- if (!Files.exists(folder)) {
- Files.createDirectory(folder);
- }
- Path file = folder.resolve(filename + ".png").toAbsolutePath();
- // Delete already present file
- if (Files.exists(file)) {
- Files.delete(file);
- }
- screenshotTaker.saveComponentAsPng(dialog.target(), file.toString());
- }
-
- protected void assertColumnValue(JTableFixture table, int rowIndex, int columnIndex, String selectionValue){
- String[][] tableContent;
- tableContent = table.contents();
-
- String value = tableContent[rowIndex][columnIndex];
- Assert.assertEquals(value, selectionValue);
- }
-}
diff --git a/src/integrationTest/java/net/sf/jabref/gui/DialogTest.java b/src/integrationTest/java/net/sf/jabref/gui/DialogTest.java
deleted file mode 100644
index b0c204f..0000000
--- a/src/integrationTest/java/net/sf/jabref/gui/DialogTest.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package net.sf.jabref.gui;
-
-import javax.swing.JButton;
-import javax.swing.JDialog;
-
-import org.assertj.swing.core.GenericTypeMatcher;
-import org.assertj.swing.dependency.jsr305.Nonnull;
-import org.junit.Ignore;
-import org.junit.Test;
-
-import static org.assertj.swing.finder.WindowFinder.findDialog;
-
-public class DialogTest extends AbstractUITest {
-
- // Not working on Travis - time out
- @Ignore
- @Test
- public void testCancelStyleSelectDialog() {
- mainFrame.menuItemWithPath("Tools", "OpenOffice/LibreOffice connection").click();
-
- GenericTypeMatcher<JButton> buttonMatcher = new GenericTypeMatcher<JButton>(JButton.class) {
-
- @Override
- protected boolean isMatching(@Nonnull JButton jButton) {
- return "Select style".equals(jButton.getText());
- }
- };
-
- mainFrame.button(buttonMatcher).click();
-
- GenericTypeMatcher<JDialog> styleDialogMatcher = new GenericTypeMatcher<JDialog>(JDialog.class) {
-
- @Override
- protected boolean isMatching(JDialog dialog) {
- return "Select style".equals(dialog.getTitle()); // Only a single SidePane
- }
- };
-
- GenericTypeMatcher<JButton> buttonMatcher2 = new GenericTypeMatcher<JButton>(JButton.class) {
-
- @Override
- protected boolean isMatching(@Nonnull JButton jButton) {
- return "Cancel".equals(jButton.getText());
- }
- };
- findDialog(styleDialogMatcher).withTimeout(10_000).using(robot()).button(buttonMatcher2).click();
- exitJabRef();
- }
-
- // Tests work separately, but not when running both...
- @Test
- @Ignore
- public void testCloseStyleSelectDialog() {
- mainFrame.menuItemWithPath("Tools", "OpenOffice/LibreOffice connection").click();
-
- GenericTypeMatcher<JButton> buttonMatcher = new GenericTypeMatcher<JButton>(JButton.class) {
-
- @Override
- protected boolean isMatching(@Nonnull JButton jButton) {
- return "Select style".equals(jButton.getText());
- }
- };
-
- mainFrame.button(buttonMatcher).click();
-
- GenericTypeMatcher<JDialog> styleDialogMatcher = new GenericTypeMatcher<JDialog>(JDialog.class) {
-
- @Override
- protected boolean isMatching(JDialog dialog) {
- return "Select style".equals(dialog.getTitle()); // Only a single SidePane
- }
- };
-
- findDialog(styleDialogMatcher).withTimeout(10_000).using(robot()).close();
- exitJabRef();
- }
-}
diff --git a/src/integrationTest/java/net/sf/jabref/gui/EntryTableTest.java b/src/integrationTest/java/net/sf/jabref/gui/EntryTableTest.java
deleted file mode 100644
index 3b7b6c7..0000000
--- a/src/integrationTest/java/net/sf/jabref/gui/EntryTableTest.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package net.sf.jabref.gui;
-
-import java.awt.event.KeyEvent;
-import java.util.regex.Pattern;
-
-import org.assertj.swing.fixture.JTableCellFixture;
-import org.assertj.swing.fixture.JTableFixture;
-import org.junit.Assert;
-import org.junit.Test;
-
-/**
- * Specific Use-Case:
- * I import a database. Then I doubleclick on the first entry in the table to open the entry editor.
- * Then I click on the first entry again, and scroll through all of the lists entries, without having to click
- * on the table again.
- */
-public class EntryTableTest extends AbstractUITest{
-
- private final static int SCROLL_ACTION_EXECUTION = 5;
- private final static String TEST_FILE_NAME = "testbib/testjabref.bib";
- private final static int DOWN = KeyEvent.VK_DOWN;
- private final static int UP = KeyEvent.VK_UP;
- private final static int TITLE_COLUMN_INDEX = 5;
-
- @Test
- public void scrollThroughEntryList() {
- String path = getAbsolutePath(TEST_FILE_NAME);
-
- importBibIntoNewDatabase(path);
-
- JTableFixture entryTable = mainFrame.table();
-
- //use a pattern from the first row to select it since it seems to be the best way to get the cell object
- Pattern pattern = Pattern.compile("256.*");
- JTableCellFixture firstCell = entryTable.cell(pattern);
-
- entryTable.selectRows(0).doubleClick();
- //delay has to be shortened so that double click is recognized
- robot().settings().delayBetweenEvents(0);
- firstCell.doubleClick();
- robot().settings().delayBetweenEvents(SPEED_NORMAL);
-
- firstCell.click();
- //is the first table entry selected?
- assertColumnValue(entryTable, 0, TITLE_COLUMN_INDEX, entryTable.selectionValue());
-
- //go throught the table and check if the entry with the correct index is selected
- for (int i=0; i < SCROLL_ACTION_EXECUTION; i++) {
- robot().pressAndReleaseKey(DOWN);
- Assert.assertTrue(entryTable.selectionValue() != null);
- assertColumnValue(entryTable, i+1, TITLE_COLUMN_INDEX, entryTable.selectionValue());
- }
- //do the same going up again
- for (int i = SCROLL_ACTION_EXECUTION; i > 0; i--) {
- robot().pressAndReleaseKey(UP);
- Assert.assertTrue(entryTable.selectionValue() != null);
- assertColumnValue(entryTable, i-1, TITLE_COLUMN_INDEX, entryTable.selectionValue());
- }
-
- closeDatabase();
- exitJabRef();
- }
-
-}
diff --git a/src/integrationTest/java/net/sf/jabref/gui/GUITest.java b/src/integrationTest/java/net/sf/jabref/gui/GUITest.java
deleted file mode 100644
index 0416a9a..0000000
--- a/src/integrationTest/java/net/sf/jabref/gui/GUITest.java
+++ /dev/null
@@ -1,118 +0,0 @@
-package net.sf.jabref.gui;
-
-import java.io.IOException;
-
-import javax.swing.JButton;
-
-import net.sf.jabref.gui.dbproperties.DatabasePropertiesDialog;
-import net.sf.jabref.gui.preftabs.PreferencesDialog;
-
-import org.assertj.swing.core.GenericTypeMatcher;
-import org.assertj.swing.dependency.jsr305.Nonnull;
-import org.assertj.swing.fixture.DialogFixture;
-import org.junit.Ignore;
-import org.junit.Test;
-
-import static org.assertj.swing.finder.WindowFinder.findDialog;
-
-public class GUITest extends AbstractUITest {
-
- @Test
- public void testExit() {
- exitJabRef();
- }
-
- @Test
- public void testNewFile() {
- newDatabase();
- closeDatabase();
- exitJabRef();
- }
-
- @Test
- public void testCreateBibtexEntry() throws IOException {
- newDatabase();
-
- mainFrame.menuItemWithPath("BibTeX", "New entry...").click();
- findDialog(EntryTypeDialog.class).withTimeout(10_000).using(robot())
- .button(new GenericTypeMatcher<JButton>(JButton.class) {
- @Override
- protected boolean isMatching(@Nonnull JButton jButton) {
- return "Book".equals(jButton.getText());
- }
- }).click();
- takeScreenshot(mainFrame, "MainWindowWithOneDatabase");
- }
-
- @Ignore
- @Test
- public void testOpenAndSavePreferences() throws IOException {
- mainFrame.menuItemWithPath("Options", "Preferences").click();
-
- robot().waitForIdle();
-
- DialogFixture preferencesDialog = findDialog(PreferencesDialog.class).withTimeout(10_000).using(robot());
- takeScreenshot(preferencesDialog, "PreferencesDialog");
- preferencesDialog.button(new GenericTypeMatcher<JButton>(JButton.class) {
- @Override
- protected boolean isMatching(@Nonnull JButton jButton) {
- return "OK".equals(jButton.getText());
- }
- }).click();
-
- exitJabRef();
- }
-
- /**
- * tests different buttons
- * sometimes this test clicks some buttons twice to reverse their effect and leaves JabRef as it was before
- */
- @Test
- public void testViewChanges() {
- newDatabase();
-
- mainFrame.menuItemWithPath("View", "Increase table font size").click();
- mainFrame.menuItemWithPath("View", "Decrease table font size").click();
-
- mainFrame.menuItemWithPath("View", "Web search").click();
- mainFrame.menuItemWithPath("View", "Web search").click();
-
- mainFrame.menuItemWithPath("View", "Toggle groups interface").click();
- mainFrame.menuItemWithPath("View", "Toggle groups interface").click();
-
- mainFrame.menuItemWithPath("View", "Toggle entry preview").click();
- mainFrame.menuItemWithPath("View", "Toggle entry preview").click();
-
- mainFrame.menuItemWithPath("View", "Switch preview layout").click();
- mainFrame.menuItemWithPath("View", "Switch preview layout").click();
-
- mainFrame.menuItemWithPath("View", "Hide/show toolbar").click();
- mainFrame.menuItemWithPath("View", "Hide/show toolbar").click();
-
- mainFrame.menuItemWithPath("View", "Focus entry table").click();
-
- closeDatabase();
- exitJabRef();
- }
-
- @Test
- public void testDatabasePropertiesDialog() throws IOException {
- newDatabase();
-
- mainFrame.menuItemWithPath("File", "Database properties").click();
-
- robot().waitForIdle();
-
- DialogFixture databasePropertiesDialog = findDialog(DatabasePropertiesDialog.class).withTimeout(10_000).using(robot());
- takeScreenshot(databasePropertiesDialog, "DatabasePropertiesDialog");
- databasePropertiesDialog.button(new GenericTypeMatcher<JButton>(JButton.class) {
- @Override
- protected boolean isMatching(@Nonnull JButton jButton) {
- return "OK".equals(jButton.getText());
- }
- }).click();
-
- closeDatabase();
- exitJabRef();
- }
-}
diff --git a/src/integrationTest/java/net/sf/jabref/gui/ParameterizedDialogNewEntryTest.java b/src/integrationTest/java/net/sf/jabref/gui/ParameterizedDialogNewEntryTest.java
deleted file mode 100644
index e9d5620..0000000
--- a/src/integrationTest/java/net/sf/jabref/gui/ParameterizedDialogNewEntryTest.java
+++ /dev/null
@@ -1,199 +0,0 @@
-package net.sf.jabref.gui;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Locale;
-
-import javax.swing.JButton;
-import javax.swing.JDialog;
-
-import org.assertj.swing.core.GenericTypeMatcher;
-import org.assertj.swing.dependency.jsr305.Nonnull;
-import org.assertj.swing.fixture.JTableFixture;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-import static org.assertj.swing.finder.WindowFinder.findDialog;
-
- at RunWith(Parameterized.class)
-public class ParameterizedDialogNewEntryTest extends AbstractUITest {
-
- private final String databaseMode;
- private final String entryType;
-
-
- public ParameterizedDialogNewEntryTest(String databaseMode, String entryType) {
- this.databaseMode = databaseMode;
- this.entryType = entryType;
- }
-
- @Test
- public void addEntryOfGivenType() {
- mainFrame.menuItemWithPath("File", "New " + databaseMode + " database").click();
- JTableFixture entryTable = mainFrame.table();
-
- entryTable.requireRowCount(0);
- mainFrame.menuItemWithPath("BibTeX", "New entry...").click();
-
- selectEntryType();
-
- entryTable.requireRowCount(1);
- }
-
- private void selectEntryType() {
- GenericTypeMatcher<JDialog> matcher = new GenericTypeMatcher<JDialog>(JDialog.class) {
-
- @Override
- protected boolean isMatching(JDialog dialog) {
- return "Select entry type".equals(dialog.getTitle());
- }
- };
-
- findDialog(matcher).withTimeout(10_000).using(robot()).button(new GenericTypeMatcher<JButton>(JButton.class) {
-
- @Override
- protected boolean isMatching(@Nonnull JButton jButton) {
- return entryType.equals(jButton.getText());
- }
- }).click();
- }
-
- @Test
- public void addEntryPlainTextOfGivenType() {
- mainFrame.menuItemWithPath("File", "New " + databaseMode + " database").click();
- JTableFixture entryTable = mainFrame.table();
-
- entryTable.requireRowCount(0);
- mainFrame.menuItemWithPath("BibTeX", "New entry from plain text...").click();
-
- selectEntryType();
-
- GenericTypeMatcher<JDialog> matcher2 = plainTextMatcher();
-
- findDialog(matcher2).withTimeout(10_000).using(robot()).button(new GenericTypeMatcher<JButton>(JButton.class) {
-
- @Override
- protected boolean isMatching(@Nonnull JButton jButton) {
- return "Accept".equals(jButton.getText());
- }
- }).click();
-
- entryTable.requireRowCount(1);
- }
-
- @Test
- public void closeAddingEntryPlainTextOfGivenType() {
- mainFrame.menuItemWithPath("File", "New " + databaseMode + " database").click();
- JTableFixture entryTable = mainFrame.table();
-
- entryTable.requireRowCount(0);
- mainFrame.menuItemWithPath("BibTeX", "New entry from plain text...").click();
-
- selectEntryType();
-
- GenericTypeMatcher<JDialog> matcher2 = plainTextMatcher();
-
- findDialog(matcher2).withTimeout(10_000).using(robot()).close();
- entryTable.requireRowCount(0);
- }
-
- @Test
- public void cancelAddingEntryPlainTextOfGivenType() {
- mainFrame.menuItemWithPath("File", "New " + databaseMode + " database").click();
- JTableFixture entryTable = mainFrame.table();
-
- entryTable.requireRowCount(0);
- mainFrame.menuItemWithPath("BibTeX", "New entry from plain text...").click();
-
- selectEntryType();
-
- GenericTypeMatcher<JDialog> matcher2 = plainTextMatcher();
-
- findDialog(matcher2).withTimeout(10_000).using(robot()).button(new GenericTypeMatcher<JButton>(JButton.class) {
-
- @Override
- protected boolean isMatching(@Nonnull JButton jButton) {
- return "Cancel".equals(jButton.getText());
- }
- }).click();
-
- entryTable.requireRowCount(0);
- }
-
- private GenericTypeMatcher<JDialog> plainTextMatcher() {
- GenericTypeMatcher<JDialog> matcher2 = new GenericTypeMatcher<JDialog>(JDialog.class) {
-
- @Override
- protected boolean isMatching(JDialog dialog) {
- return ("Plain text import for " + entryType.toLowerCase(Locale.ENGLISH)).equals(dialog.getTitle());
- }
- };
- return matcher2;
- }
-
- @Parameterized.Parameters(name = "{index}: {0} : {1}")
- public static Collection<Object[]> instancesToTest() {
- // Create entry from menu
- // Structure:
- // {"BibTeX"/"BibLaTeX", "type"}
- // @formatter:off
- return Arrays.asList(
- new Object[]{"BibTeX", "Article"},
-/* new Object[]{"BibTeX", "InBook"},
- new Object[]{"BibTeX", "Book"},
- new Object[]{"BibTeX", "Booklet"},
- new Object[]{"BibTeX", "InCollection"},
- new Object[]{"BibTeX", "Conference"},
- new Object[]{"BibTeX", "InProceedings"},
- new Object[]{"BibTeX", "Proceedings"},
- new Object[]{"BibTeX", "Manual"},
- new Object[]{"BibTeX", "MastersThesis"},
- new Object[]{"BibTeX", "PhdThesis"},
- new Object[]{"BibTeX", "TechReport"},
- new Object[]{"BibTeX", "Unpublished"},
- new Object[]{"BibTeX", "Misc"},
- new Object[]{"BibTeX", "Electronic"},
- new Object[]{"BibTeX", "IEEEtranBSTCTL"},
- new Object[]{"BibTeX", "Periodical"},
- new Object[]{"BibTeX", "Patent"},
- new Object[]{"BibTeX", "Standard"},
- new Object[]{"BibLaTeX", "Article"},
- new Object[]{"BibLaTeX", "Book"},
- new Object[]{"BibLaTeX", "BookInBook"},
- new Object[]{"BibLaTeX", "Booklet"},
- new Object[]{"BibLaTeX", "Collection"},
- new Object[]{"BibLaTeX", "Conference"},
- new Object[]{"BibLaTeX", "Electronic"},
- new Object[]{"BibLaTeX", "IEEEtranBSTCTL"},
- new Object[]{"BibLaTeX", "InBook"},
- new Object[]{"BibLaTeX", "InCollection"},
- new Object[]{"BibLaTeX", "InProceedings"},
- new Object[]{"BibLaTeX", "InReference"},
- new Object[]{"BibLaTeX", "Manual"},
- new Object[]{"BibLaTeX", "MastersThesis"},
- new Object[]{"BibLaTeX", "Misc"},
- new Object[]{"BibLaTeX", "MvBook"},
- new Object[]{"BibLaTeX", "MvCollection"},
- new Object[]{"BibLaTeX", "MvProceedings"},
- new Object[]{"BibLaTeX", "MvReference"},
- new Object[]{"BibLaTeX", "Online"},
- new Object[]{"BibLaTeX", "Patent"},
- new Object[]{"BibLaTeX", "Periodical"},
- new Object[]{"BibLaTeX", "PhdThesis"},
- new Object[]{"BibLaTeX", "Proceedings"},
- new Object[]{"BibLaTeX", "Reference"},
- new Object[]{"BibLaTeX", "Report"},
- new Object[]{"BibLaTeX", "Set"},
- new Object[]{"BibLaTeX", "SuppBook"},
- new Object[]{"BibLaTeX", "SuppCollection"},
- new Object[]{"BibLaTeX", "SuppPeriodical"},
- new Object[]{"BibLaTeX", "TechReport"},
- new Object[]{"BibLaTeX", "Thesis"},
- new Object[]{"BibLaTeX", "Unpublished"},*/
- new Object[]{"BibLaTeX", "WWW"}
- );
- // @formatter:on
- }
-
-}
diff --git a/src/integrationTest/java/net/sf/jabref/gui/ParameterizedDialogTest.java b/src/integrationTest/java/net/sf/jabref/gui/ParameterizedDialogTest.java
deleted file mode 100644
index 7b2f634..0000000
--- a/src/integrationTest/java/net/sf/jabref/gui/ParameterizedDialogTest.java
+++ /dev/null
@@ -1,150 +0,0 @@
-package net.sf.jabref.gui;
-
-import java.util.Arrays;
-import java.util.Collection;
-
-import javax.swing.JButton;
-import javax.swing.JDialog;
-
-import org.assertj.swing.core.GenericTypeMatcher;
-import org.assertj.swing.dependency.jsr305.Nonnull;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-import static org.assertj.swing.finder.WindowFinder.findDialog;
-
- at RunWith(Parameterized.class)
-public class ParameterizedDialogTest extends AbstractUITest {
-
- private final boolean createDatabase;
- private final String[] menuPath;
- private final String dialogTitle;
- private final String buttonName;
- private final boolean closeButton;
-
-
- public ParameterizedDialogTest(boolean createDatabase, String[] menuPath, String dialogTitle, String buttonName,
- boolean closeButton) {
- this.createDatabase = createDatabase;
- this.menuPath = menuPath;
- this.dialogTitle = dialogTitle;
- this.buttonName = buttonName;
- this.closeButton = closeButton;
- }
-
- @Test
- public void openAndExitDialog() {
- if (createDatabase) {
- newDatabase();
- }
- mainFrame.menuItemWithPath(menuPath).click();
- GenericTypeMatcher<JDialog> matcher = new GenericTypeMatcher<JDialog>(JDialog.class) {
-
- @Override
- protected boolean isMatching(JDialog dialog) {
- return dialogTitle.equals(dialog.getTitle());
- }
- };
-
- if (closeButton) {
- findDialog(matcher).withTimeout(10_000).using(robot()).close();
- } else {
- findDialog(matcher).withTimeout(10_000).using(robot())
- .button(new GenericTypeMatcher<JButton>(JButton.class) {
-
- @Override
- protected boolean isMatching(@Nonnull JButton jButton) {
- return buttonName.equals(jButton.getText());
- }
- }).click();
- }
- if (createDatabase) {
- closeDatabase();
- }
- exitJabRef();
- }
-
- @Parameterized.Parameters(name = "{index}: {1} -> {2} : {3}")
- public static Collection<Object[]> instancesToTest() {
- // Opening and closing (in different ways) the dialogs accessible from the menus without doing anything else
- // Structure:
- // {create new database, {"Menu", "Submenu", "Sub-sub-menu"}, "Dialog title", "Button name", use close button}
- // @formatter:off
- return Arrays.asList(
- new Object[]{false, new String[]{"File", "Open database"}, "Open", "Cancel", false},
- new Object[]{false, new String[]{"File", "Open database"}, "Open", "Close button", true},
- new Object[]{true, new String[]{"File", "Append database"}, "Append database", "Cancel", false},
- new Object[]{true, new String[]{"File", "Append database"}, "Append database", "Close button", true},
- new Object[]{true, new String[]{"File", "Save database"}, "Save", "Cancel", false},
- new Object[]{true, new String[]{"File", "Save database"}, "Save", "Close button", true},
- new Object[]{true, new String[]{"File", "Save database as..."}, "Save", "Cancel", false},
- new Object[]{true, new String[]{"File", "Save database as..."}, "Save", "Close button", true},
- new Object[]{true, new String[]{"File", "Save all"}, "Save", "Cancel", false},
- new Object[]{true, new String[]{"File", "Save all"}, "Save", "Close button", true},
- new Object[]{false, new String[]{"File", "Import into new database"}, "Open", "Cancel", false},
- new Object[]{false, new String[]{"File", "Import into new database"}, "Open", "Close button", true},
- new Object[]{true, new String[]{"File", "Import into current database"}, "Open", "Cancel", false},
- new Object[]{true, new String[]{"File", "Import into current database"}, "Open", "Close button", true},
- new Object[]{true, new String[]{"File", "Export"}, "Save", "Cancel", false},
- new Object[]{true, new String[]{"File", "Export"}, "Save", "Close button", true},
- new Object[]{true, new String[]{"File", "Open shared database"}, "Open shared database", "Cancel", false},
- new Object[]{true, new String[]{"File", "Database properties"}, "Database properties", "Cancel", false},
- new Object[]{true, new String[]{"File", "Database properties"}, "Database properties", "OK", false},
- new Object[]{true, new String[]{"File", "Database properties"}, "Database properties", "Close button", true},
- new Object[]{true, new String[]{"Edit", "Set/clear/rename fields..."}, "Set/clear/rename fields", "Cancel", false},
- //new Object[]{true, new String[]{"Edit", "Set/clear/rename fields..."}, "Set/clear/rename fields", "OK", false},
- new Object[]{true, new String[]{"Edit", "Set/clear/rename fields..."}, "Set/clear/rename fields", "Close button", true},
- new Object[]{true, new String[]{"Search", "Replace string..."}, "Replace string", "Cancel", false},
- new Object[]{true, new String[]{"Search", "Replace string..."}, "Replace string", "Close button", true},
- new Object[]{true, new String[]{"Groups", "Add to group..."}, "Add to group", "Cancel", false},
- new Object[]{true, new String[]{"Groups", "Add to group..."}, "Add to group", "Close button", true},
- new Object[]{true, new String[]{"Groups", "Remove from group..."}, "Remove from group", "Cancel", false},
- new Object[]{true, new String[]{"Groups", "Remove from group..."}, "Remove from group", "Close button", true},
- new Object[]{true, new String[]{"Groups", "Move to group..."}, "Move to group", "Cancel", false},
- new Object[]{true, new String[]{"Groups", "Move to group..."}, "Move to group", "Close button", true},
- new Object[]{true, new String[]{"BibTeX", "New entry..."}, "Select entry type", "Cancel", false},
- new Object[]{true, new String[]{"BibTeX", "New entry..."}, "Select entry type", "Close button", true},
- new Object[]{true, new String[]{"BibTeX", "Edit preamble"}, "Edit preamble", "Close button", true},
- new Object[]{true, new String[]{"BibTeX", "Edit strings"}, "Strings for database: untitled", "Close button", true},
- new Object[]{true, new String[]{"BibTeX", "Customize entry types"}, "Customize entry types", "Cancel", false},
- new Object[]{true, new String[]{"BibTeX", "Customize entry types"}, "Customize entry types", "OK", false},
- new Object[]{true, new String[]{"BibTeX", "Customize entry types"}, "Customize entry types", "Close button", true},
- new Object[]{true, new String[]{"Quality", "Synchronize file links..."}, "Synchronize file links", "Cancel", false},
- new Object[]{true, new String[]{"Quality", "Synchronize file links..."}, "Synchronize file links", "Close button", true},
- new Object[]{true, new String[]{"Quality", "Find unlinked files..."}, "Find unlinked files", "Close", false},
- new Object[]{true, new String[]{"Quality", "Find unlinked files..."}, "Find unlinked files", "Close button", true},
- new Object[]{true, new String[]{"Tools", "New subdatabase based on AUX file..."}, "AUX file import", "Cancel", false},
- new Object[]{true, new String[]{"Tools", "New subdatabase based on AUX file..."}, "AUX file import", "Close button", true},
- new Object[]{false, new String[]{"Options", "Preferences"}, "JabRef preferences", "Cancel", false},
- new Object[]{false, new String[]{"Options", "Preferences"}, "JabRef preferences", "OK", false},
- new Object[]{false, new String[]{"Options", "Preferences"}, "JabRef preferences", "Close button", true},
- new Object[]{false, new String[]{"Options", "Set up general fields"}, "Set general fields", "Cancel", false},
- new Object[]{false, new String[]{"Options", "Set up general fields"}, "Set general fields", "OK", false},
- new Object[]{false, new String[]{"Options", "Set up general fields"}, "Set general fields", "Close button", true},
- new Object[]{false, new String[]{"Options", "Manage custom exports"}, "Manage custom exports", "Close", false},
- new Object[]{false, new String[]{"Options", "Manage custom exports"}, "Manage custom exports", "Close button", true},
- new Object[]{false, new String[]{"Options", "Manage custom imports"}, "Manage custom imports", "Close", false},
- new Object[]{false, new String[]{"Options", "Manage custom imports"}, "Manage custom imports", "Close button", true},
- new Object[]{false, new String[]{"Options", "Manage external file types"}, "Manage external file types", "Cancel", false},
- new Object[]{false, new String[]{"Options", "Manage external file types"}, "Manage external file types", "OK", false},
- new Object[]{false, new String[]{"Options", "Manage external file types"}, "Manage external file types", "Close button", true},
- new Object[]{false, new String[]{"Options", "Manage journal abbreviations"}, "Journal abbreviations", "Cancel", false},
- new Object[]{false, new String[]{"Options", "Manage journal abbreviations"}, "Journal abbreviations", "OK", false},
- new Object[]{false, new String[]{"Options", "Manage journal abbreviations"}, "Journal abbreviations", "Close button", true},
- new Object[]{true, new String[]{"Options", "Manage content selectors"}, "Manage content selectors", "Cancel", false},
- // new Object[]{true, new String[]{"Options", "Manage content selectors"}, "Manage content selectors", "OK", false},
- new Object[]{true, new String[]{"Options", "Manage content selectors"}, "Manage content selectors", "Close button", true},
- new Object[]{false, new String[]{"Options", "Manage protected terms"}, "Manage protected terms files", "Cancel", false},
- new Object[]{false, new String[]{"Options", "Manage protected terms"}, "Manage protected terms files", "OK", false},
- new Object[]{false, new String[]{"Options", "Manage protected terms"}, "Manage protected terms files", "Close button", true},
- new Object[]{false, new String[]{"Options", "Customize key bindings"}, "Key bindings", "Cancel", false},
- new Object[]{false, new String[]{"Options", "Customize key bindings"}, "Key bindings", "Close button", true},
- new Object[]{false, new String[]{"Help", "Show error console"}, "Program output", "OK", false},
- new Object[]{false, new String[]{"Help", "Show error console"}, "Program output", "Close button", true},
- new Object[]{false, new String[]{"Help", "About JabRef"}, "About JabRef", "Close button", true}
- );
- // @formatter:on
- }
-
-}
diff --git a/src/integrationTest/java/net/sf/jabref/gui/ParameterizedMenuNewEntryTest.java b/src/integrationTest/java/net/sf/jabref/gui/ParameterizedMenuNewEntryTest.java
deleted file mode 100644
index ab191b8..0000000
--- a/src/integrationTest/java/net/sf/jabref/gui/ParameterizedMenuNewEntryTest.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package net.sf.jabref.gui;
-
-import java.util.Arrays;
-import java.util.Collection;
-
-import net.sf.jabref.model.entry.EntryUtil;
-
-import org.assertj.swing.fixture.JTableFixture;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
- at RunWith(Parameterized.class)
-public class ParameterizedMenuNewEntryTest extends AbstractUITest {
-
- private final String databaseMode;
- private final String entryType;
-
-
- public ParameterizedMenuNewEntryTest(String databaseMode, String entryType) {
- this.databaseMode = databaseMode;
- this.entryType = entryType;
- }
-
- // Not working on Travis
- @Ignore
- @Test
- public void addEntryOfGivenType() {
- mainFrame.menuItemWithPath("File", "New " + databaseMode + " database").click();
- JTableFixture entryTable = mainFrame.table();
-
- entryTable.requireRowCount(0);
- mainFrame.menuItemWithPath("BibTeX", "New entry by type...", EntryUtil.capitalizeFirst(entryType)).click();
- entryTable.requireRowCount(1);
- }
-
- @Parameterized.Parameters(name = "{index}: {0} : {1}")
- public static Collection<Object[]> instancesToTest() {
- // Create entry from menu
- // Structure:
- // {"BibTeX"/"BibLaTeX", "type"}
- // @formatter:off
- return Arrays.asList(
- new Object[]{"BibTeX", "article"},
-/* new Object[]{"BibTeX", "inbook"},
- new Object[]{"BibTeX", "book"},
- new Object[]{"BibTeX", "booklet"},
- new Object[]{"BibTeX", "incollection"},
- new Object[]{"BibTeX", "conference"},
- new Object[]{"BibTeX", "inproceedings"},
- new Object[]{"BibTeX", "proceedings"},
- new Object[]{"BibTeX", "manual"},
- new Object[]{"BibTeX", "mastersthesis"},
- new Object[]{"BibTeX", "phdthesis"},
- new Object[]{"BibTeX", "techreport"},
- new Object[]{"BibTeX", "unpublished"},
- new Object[]{"BibTeX", "misc"},
- new Object[]{"BibLaTeX", "article"},
- new Object[]{"BibLaTeX", "inbook"},
- new Object[]{"BibLaTeX", "book"},
- new Object[]{"BibLaTeX", "booklet"},
- new Object[]{"BibLaTeX", "incollection"},
- new Object[]{"BibLaTeX", "conference"},
- new Object[]{"BibLaTeX", "inproceedings"},
- new Object[]{"BibLaTeX", "proceedings"},
- new Object[]{"BibLaTeX", "manual"},
- new Object[]{"BibLaTeX", "mastersthesis"},
- new Object[]{"BibLaTeX", "phdthesis"},
- new Object[]{"BibLaTeX", "techreport"},
- new Object[]{"BibLaTeX", "unpublished"}, */
- new Object[]{"BibLaTeX", "misc"}
- );
- // @formatter:on
- }
-
-}
diff --git a/src/integrationTest/java/net/sf/jabref/gui/UndoTest.java b/src/integrationTest/java/net/sf/jabref/gui/UndoTest.java
deleted file mode 100644
index 09cd6c6..0000000
--- a/src/integrationTest/java/net/sf/jabref/gui/UndoTest.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package net.sf.jabref.gui;
-
-import javax.swing.JButton;
-
-import org.assertj.swing.core.GenericTypeMatcher;
-import org.assertj.swing.dependency.jsr305.Nonnull;
-import org.assertj.swing.fixture.JTableFixture;
-import org.junit.Test;
-
-import static org.assertj.swing.finder.WindowFinder.findDialog;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-public class UndoTest extends AbstractUITest {
-
- @Test
- public void undoCutOfMultipleEntries() {
- importBibIntoNewDatabase(getAbsolutePath("testbib/testjabref.bib"));
-
- JTableFixture entryTable = mainFrame.table();
-
- assertTrue("The database must have at least 2 entries for the test to begin!", entryTable.rowCount() >= 2);
- entryTable.selectRows(0, 1);
- entryTable.requireSelectedRows(0, 1);
-
- int oldRowCount = entryTable.rowCount();
- mainFrame.menuItemWithPath("Edit", "Cut").click();
- mainFrame.menuItemWithPath("Edit", "Undo").click();
- entryTable.requireRowCount(oldRowCount);
-
- closeDatabase();
- exitJabRef();
- }
-
- @Test
- public void undoRedoUpdatedCorrectly() {
- newDatabase();
- assertFalse(mainFrame.menuItemWithPath("Edit", "Undo").isEnabled());
- assertFalse(mainFrame.menuItemWithPath("Edit", "Redo").isEnabled());
- JTableFixture entryTable = mainFrame.table();
- mainFrame.menuItemWithPath("BibTeX", "New entry...").click();
- findDialog(EntryTypeDialog.class).withTimeout(10_000).using(robot())
- .button(new GenericTypeMatcher<JButton>(JButton.class) {
-
- @Override
- protected boolean isMatching(@Nonnull JButton jButton) {
- return "Book".equals(jButton.getText());
- }
- }).click();
-
- assertTrue(mainFrame.menuItemWithPath("Edit", "Undo").isEnabled());
- assertFalse(mainFrame.menuItemWithPath("Edit", "Redo").isEnabled());
- entryTable.requireRowCount(1);
-
- mainFrame.menuItemWithPath("Edit", "Undo").click();
- assertFalse(mainFrame.menuItemWithPath("Edit", "Undo").isEnabled());
- assertTrue(mainFrame.menuItemWithPath("Edit", "Redo").isEnabled());
- entryTable.requireRowCount(0);
-
- closeDatabase();
- exitJabRef();
- }
-
-}
diff --git a/src/jmh/java/net/sf/jabref/benchmarks/Benchmarks.java b/src/jmh/java/net/sf/jabref/benchmarks/Benchmarks.java
index 1a0f6a8..d6d2945 100644
--- a/src/jmh/java/net/sf/jabref/benchmarks/Benchmarks.java
+++ b/src/jmh/java/net/sf/jabref/benchmarks/Benchmarks.java
@@ -2,32 +2,30 @@ package net.sf.jabref.benchmarks;
import java.io.IOException;
import java.io.StringReader;
-import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
-import net.sf.jabref.BibDatabaseContext;
-import net.sf.jabref.Defaults;
import net.sf.jabref.Globals;
-import net.sf.jabref.MetaData;
import net.sf.jabref.logic.exporter.BibtexDatabaseWriter;
import net.sf.jabref.logic.exporter.SavePreferences;
import net.sf.jabref.logic.exporter.StringSaveSession;
import net.sf.jabref.logic.formatter.bibtexfields.HtmlToLatexFormatter;
-import net.sf.jabref.logic.groups.GroupHierarchyType;
-import net.sf.jabref.logic.groups.KeywordGroup;
-import net.sf.jabref.logic.importer.ImportFormatPreferences;
+import net.sf.jabref.logic.importer.ParseException;
import net.sf.jabref.logic.importer.ParserResult;
import net.sf.jabref.logic.importer.fileformat.BibtexParser;
-import net.sf.jabref.logic.importer.util.ParseException;
import net.sf.jabref.logic.layout.format.HTMLChars;
import net.sf.jabref.logic.layout.format.LatexToUnicodeFormatter;
import net.sf.jabref.logic.search.SearchQuery;
+import net.sf.jabref.model.Defaults;
import net.sf.jabref.model.database.BibDatabase;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.database.BibDatabaseMode;
import net.sf.jabref.model.database.BibDatabaseModeDetection;
import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.groups.GroupHierarchyType;
+import net.sf.jabref.model.groups.KeywordGroup;
+import net.sf.jabref.model.metadata.MetaData;
import net.sf.jabref.preferences.JabRefPreferences;
import org.openjdk.jmh.Main;
@@ -74,10 +72,8 @@ public class Benchmarks {
@Benchmark
public ParserResult parse() throws IOException {
- StringReader bibtexStringReader = new StringReader(bibtexString);
- BibtexParser parser = new BibtexParser(bibtexStringReader,
- ImportFormatPreferences.fromPreferences(Globals.prefs));
- return parser.parse();
+ BibtexParser parser = new BibtexParser(Globals.prefs.getImportFormatPreferences());
+ return parser.parse(new StringReader(bibtexString));
}
@Benchmark
@@ -93,9 +89,14 @@ public class Benchmarks {
public List<BibEntry> search() {
// FIXME: Reuse SearchWorker here
SearchQuery searchQuery = new SearchQuery("Journal Title 500", false, false);
- List<BibEntry> matchedEntries = new ArrayList<>();
- matchedEntries.addAll(database.getEntries().stream().filter(searchQuery::isMatch).collect(Collectors.toList()));
- return matchedEntries;
+ return database.getEntries().stream().filter(searchQuery::isMatch).collect(Collectors.toList());
+ }
+
+ @Benchmark
+ public List<BibEntry> parallelSearch() {
+ // FIXME: Reuse SearchWorker here
+ SearchQuery searchQuery = new SearchQuery("Journal Title 500", false, false);
+ return database.getEntries().parallelStream().filter(searchQuery::isMatch).collect(Collectors.toList());
}
@Benchmark
@@ -124,7 +125,7 @@ public class Benchmarks {
@Benchmark
public boolean keywordGroupContains() throws ParseException {
KeywordGroup group = new KeywordGroup("testGroup", "keyword", "testkeyword", false, false,
- GroupHierarchyType.INDEPENDENT, Globals.prefs);
+ GroupHierarchyType.INDEPENDENT, ',');
return group.containsAll(database.getEntries());
}
diff --git a/src/main/antlr4/net/sf/jabref/search/Search.g4 b/src/main/antlr4/net/sf/jabref/search/Search.g4
index 955e615..097083e 100644
--- a/src/main/antlr4/net/sf/jabref/search/Search.g4
+++ b/src/main/antlr4/net/sf/jabref/search/Search.g4
@@ -41,9 +41,11 @@ expression:
;
comparison:
- left=name operator=(CONTAINS | MATCHES | EQUAL | EEQUAL | NEQUAL) right=name; // example: author != miller
+ left=name operator=(CONTAINS | MATCHES | EQUAL | EEQUAL | NEQUAL) right=name // example: author != miller
+ | right=name // example: miller (search all fields)
+ ;
name:
STRING // example: "miller"
| FIELDTYPE // example: author
- ;
\ No newline at end of file
+ ;
diff --git a/src/main/java/net/sf/jabref/BibDatabaseContext.java b/src/main/java/net/sf/jabref/BibDatabaseContext.java
deleted file mode 100644
index dd0d805..0000000
--- a/src/main/java/net/sf/jabref/BibDatabaseContext.java
+++ /dev/null
@@ -1,222 +0,0 @@
-package net.sf.jabref;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-import java.util.Optional;
-
-import net.sf.jabref.logic.layout.format.FileLinkPreferences;
-import net.sf.jabref.model.database.BibDatabase;
-import net.sf.jabref.model.database.BibDatabaseMode;
-import net.sf.jabref.model.database.BibDatabaseModeDetection;
-import net.sf.jabref.model.database.DatabaseLocation;
-import net.sf.jabref.model.entry.FieldName;
-import net.sf.jabref.preferences.JabRefPreferences;
-import net.sf.jabref.shared.DBMSSynchronizer;
-
-/**
- * Represents everything related to a BIB file.
- * <p>
- * The entries are stored in BibDatabase, the other data in MetaData and the options relevant for this file in Defaults.
- */
-public class BibDatabaseContext {
-
- private final BibDatabase database;
- private final MetaData metaData;
- private final Defaults defaults;
- /** The file where this database was last saved to. */
- private File file;
- private DBMSSynchronizer dbmsSynchronizer;
- private DatabaseLocation location;
-
- public BibDatabaseContext() {
- this(new Defaults());
- }
-
- public BibDatabaseContext(Defaults defaults) {
- this(new BibDatabase(), defaults);
- }
-
- public BibDatabaseContext(BibDatabase database) {
- this(database, new Defaults());
- }
-
- public BibDatabaseContext(BibDatabase database, Defaults defaults) {
- this(database, new MetaData(), defaults);
- }
-
- public BibDatabaseContext(BibDatabase database, MetaData metaData, Defaults defaults) {
- this(database, metaData, defaults, DatabaseLocation.LOCAL);
- }
-
- public BibDatabaseContext(BibDatabase database, MetaData metaData, Defaults defaults, DatabaseLocation location) {
- this.defaults = Objects.requireNonNull(defaults);
- this.database = Objects.requireNonNull(database);
- this.metaData = Objects.requireNonNull(metaData);
-
- updateDatabaseLocation(location);
- }
-
- public BibDatabaseContext(BibDatabase database, MetaData metaData) {
- this(database, metaData, new Defaults());
- }
-
- public BibDatabaseContext(BibDatabase database, MetaData metaData, File file, Defaults defaults) {
- this(database, metaData, defaults);
-
- this.setDatabaseFile(file);
- }
-
- public BibDatabaseContext(BibDatabase database, MetaData metaData, File file) {
- this(database, metaData, file, new Defaults());
- }
-
- public BibDatabaseContext(Defaults defaults, DatabaseLocation location) {
- this(new BibDatabase(), new MetaData(), defaults, location);
- }
-
- public BibDatabaseMode getMode() {
- Optional<BibDatabaseMode> mode = metaData.getMode();
-
- if (!mode.isPresent()) {
- BibDatabaseMode inferredMode = BibDatabaseModeDetection.inferMode(database);
- BibDatabaseMode newMode = BibDatabaseMode.BIBTEX;
- if ((defaults.mode == BibDatabaseMode.BIBLATEX) || (inferredMode == BibDatabaseMode.BIBLATEX)) {
- newMode = BibDatabaseMode.BIBLATEX;
- }
- this.setMode(newMode);
- return newMode;
- }
- return mode.get();
- }
-
- public void setMode(BibDatabaseMode bibDatabaseMode) {
- metaData.setMode(bibDatabaseMode);
- }
-
- /**
- * Get the file where this database was last saved to or loaded from, if any.
- *
- * @return The relevant File, or null if none is defined.
- */
- public File getDatabaseFile() {
- return file;
- }
-
- public void setDatabaseFile(File file) {
- this.file = file;
- }
-
- public BibDatabase getDatabase() {
- return database;
- }
-
- public MetaData getMetaData() {
- return metaData;
- }
-
- public boolean isBiblatexMode() {
- return getMode() == BibDatabaseMode.BIBLATEX;
- }
-
- /**
- * Look up the directory set up for the given field type for this database.
- * If no directory is set up, return that defined in global preferences.
- * There can be up to three directory definitions for these files:
- * the database's metadata can specify a general directory and/or a user-specific directory
- * or the preferences can specify one.
- * <p>
- * The settings are prioritized in the following order and the first defined setting is used:
- * 1. metadata user-specific directory
- * 2. metadata general directory
- * 3. preferences directory
- * 4. BIB file directory
- *
- * @param fieldName The field type
- * @return The default directory for this field type.
- */
- public List<String> getFileDirectory(String fieldName) {
- List<String> fileDirs = new ArrayList<>();
-
- // 1. metadata user-specific directory
- Optional<String> userFileDirectory = metaData.getUserFileDirectory(Globals.prefs.getUser());
- if(userFileDirectory.isPresent()) {
- fileDirs.add(getFileDirectoryPath(userFileDirectory.get()));
- }
-
- // 2. metadata general directory
- Optional<String> metaDataDirectory = metaData.getDefaultFileDirectory();
- if(metaDataDirectory.isPresent()) {
- fileDirs.add(getFileDirectoryPath(metaDataDirectory.get()));
- }
-
- // 3. preferences directory
- String dir = Globals.prefs.get(fieldName + FileLinkPreferences.DIR_SUFFIX); // FILE_DIR
- if (dir != null) {
- fileDirs.add(dir);
- }
-
- // 4. BIB file directory
- if (getDatabaseFile() != null) {
- String parentDir = getDatabaseFile().getParent();
- // Check if we should add it as primary file dir (first in the list) or not:
- if (Globals.prefs.getBoolean(JabRefPreferences.BIB_LOC_AS_PRIMARY_DIR)) {
- fileDirs.add(0, parentDir);
- } else {
- fileDirs.add(parentDir);
- }
- }
-
- return fileDirs;
- }
-
- private String getFileDirectoryPath(String directoryName) {
- String dir = directoryName;
- // If this directory is relative, we try to interpret it as relative to
- // the file path of this BIB file:
- if (!new File(dir).isAbsolute() && (getDatabaseFile() != null)) {
- String relDir;
- if (".".equals(dir)) {
- // if dir is only "current" directory, just use its parent (== real current directory) as path
- relDir = getDatabaseFile().getParent();
- } else {
- relDir = getDatabaseFile().getParent() + File.separator + dir;
- }
- // If this directory actually exists, it is very likely that the
- // user wants us to use it:
- if (new File(relDir).exists()) {
- dir = relDir;
- }
- }
- return dir;
- }
-
- public List<String> getFileDirectory() {
- return getFileDirectory(FieldName.FILE);
- }
-
- public DBMSSynchronizer getDBSynchronizer() {
- return this.dbmsSynchronizer;
- }
-
- public DatabaseLocation getLocation() {
- return this.location;
- }
-
- public void updateDatabaseLocation(DatabaseLocation newLocation) {
-
- if ((this.location == DatabaseLocation.SHARED) && (newLocation == DatabaseLocation.LOCAL)) {
- this.database.unregisterListener(dbmsSynchronizer);
- this.metaData.unregisterListener(dbmsSynchronizer);
- }
-
- if (newLocation == DatabaseLocation.SHARED) {
- this.dbmsSynchronizer = new DBMSSynchronizer(this);
- this.database.registerListener(dbmsSynchronizer);
- this.metaData.registerListener(dbmsSynchronizer);
- }
-
- this.location = newLocation;
- }
-}
diff --git a/src/main/java/net/sf/jabref/Defaults.java b/src/main/java/net/sf/jabref/Defaults.java
deleted file mode 100644
index 0f2a23b..0000000
--- a/src/main/java/net/sf/jabref/Defaults.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package net.sf.jabref;
-
-import net.sf.jabref.model.database.BibDatabaseMode;
-
-public class Defaults {
-
- public final BibDatabaseMode mode;
-
- public Defaults() {
- this.mode = BibDatabaseMode.BIBTEX;
- }
-
- public Defaults(BibDatabaseMode mode) {
- this.mode = mode;
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/FallbackExceptionHandler.java b/src/main/java/net/sf/jabref/FallbackExceptionHandler.java
new file mode 100644
index 0000000..53d0bd7
--- /dev/null
+++ b/src/main/java/net/sf/jabref/FallbackExceptionHandler.java
@@ -0,0 +1,24 @@
+package net.sf.jabref;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.Marker;
+import org.apache.logging.log4j.MarkerManager;
+
+/**
+ * Catch and log any unhandled exceptions.
+ */
+public class FallbackExceptionHandler implements Thread.UncaughtExceptionHandler {
+
+ private static final Marker UncaughtException_MARKER = MarkerManager.getMarker("UncaughtException");
+
+ public static void installExceptionHandler() {
+ Thread.setDefaultUncaughtExceptionHandler(new FallbackExceptionHandler());
+ }
+
+ @Override
+ public void uncaughtException(Thread thread, Throwable exception) {
+ Logger logger = LogManager.getLogger(FallbackExceptionHandler.class);
+ logger.error(UncaughtException_MARKER, "Uncaught exception Occurred in " + thread, exception);
+ }
+}
diff --git a/src/main/java/net/sf/jabref/Globals.java b/src/main/java/net/sf/jabref/Globals.java
index 3f0380e..682b980 100644
--- a/src/main/java/net/sf/jabref/Globals.java
+++ b/src/main/java/net/sf/jabref/Globals.java
@@ -1,11 +1,7 @@
package net.sf.jabref;
-import java.util.Optional;
-
import net.sf.jabref.collab.FileUpdateMonitor;
import net.sf.jabref.gui.GlobalFocusListener;
-import net.sf.jabref.gui.JabRefFrame;
-import net.sf.jabref.gui.exporter.AutoSaveManager;
import net.sf.jabref.gui.keyboard.KeyBindingPreferences;
import net.sf.jabref.logic.error.StreamEavesdropper;
import net.sf.jabref.logic.importer.ImportFormatReader;
@@ -49,9 +45,6 @@ public class Globals {
private static FileUpdateMonitor fileUpdateMonitor;
private static StreamEavesdropper streamEavesdropper;
- // Autosave manager
- private static AutoSaveManager autoSaveManager;
-
// Key binding preferences
public static KeyBindingPreferences getKeyPrefs() {
if (keyPrefs == null) {
@@ -68,8 +61,7 @@ public class Globals {
Globals.streamEavesdropper = StreamEavesdropper.eavesdropOnSystem();
Globals.fileUpdateMonitor = new FileUpdateMonitor();
- JabRefExecutorService.INSTANCE.executeWithLowPriorityInOwnThread(Globals.fileUpdateMonitor,
- "FileUpdateMonitor");
+ JabRefExecutorService.INSTANCE.executeInterruptableTask(Globals.fileUpdateMonitor, "FileUpdateMonitor");
}
public static GlobalFocusListener getFocusListener() {
@@ -83,23 +75,4 @@ public class Globals {
public static StreamEavesdropper getStreamEavesdropper() {
return streamEavesdropper;
}
-
- // Autosave manager
- public static void startAutoSaveManager(JabRefFrame frame) {
- Globals.autoSaveManager = new AutoSaveManager(frame);
- Globals.autoSaveManager.startAutoSaveTimer();
- }
-
- // Stop the autosave manager if it has been started
- public static void stopAutoSaveManager() {
- if (Globals.autoSaveManager != null) {
- Globals.autoSaveManager.stopAutoSaveTimer();
- Globals.autoSaveManager.clearAutoSaves();
- Globals.autoSaveManager = null;
- }
- }
-
- public static Optional<AutoSaveManager> getAutoSaveManager() {
- return Optional.ofNullable(Globals.autoSaveManager);
- }
}
diff --git a/src/main/java/net/sf/jabref/JabRefException.java b/src/main/java/net/sf/jabref/JabRefException.java
index b69c610..a43ff82 100644
--- a/src/main/java/net/sf/jabref/JabRefException.java
+++ b/src/main/java/net/sf/jabref/JabRefException.java
@@ -27,6 +27,10 @@ public class JabRefException extends Exception {
this.localizedMessage = localizedMessage;
}
+ public JabRefException(Throwable cause) {
+ super(cause);
+ }
+
@Override
public String getLocalizedMessage() {
if (localizedMessage == null) {
diff --git a/src/main/java/net/sf/jabref/JabRefExecutorService.java b/src/main/java/net/sf/jabref/JabRefExecutorService.java
index 7fb967f..017c964 100644
--- a/src/main/java/net/sf/jabref/JabRefExecutorService.java
+++ b/src/main/java/net/sf/jabref/JabRefExecutorService.java
@@ -2,7 +2,6 @@ package net.sf.jabref;
import java.util.Timer;
import java.util.TimerTask;
-import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
@@ -23,12 +22,21 @@ public class JabRefExecutorService implements Executor {
public static final JabRefExecutorService INSTANCE = new JabRefExecutorService();
+ private Thread remoteThread;
+
private final ExecutorService executorService = Executors.newCachedThreadPool(r -> {
Thread thread = new Thread(r);
thread.setName("JabRef CachedThreadPool");
+ thread.setUncaughtExceptionHandler(new FallbackExceptionHandler());
+ return thread;
+ });
+
+ private final ExecutorService lowPriorityExecutorService = Executors.newCachedThreadPool(r -> {
+ Thread thread = new Thread(r);
+ thread.setName("JabRef LowPriorityCachedThreadPool");
+ thread.setUncaughtExceptionHandler(new FallbackExceptionHandler());
return thread;
});
- private final ConcurrentLinkedQueue<Thread> startedThreads = new ConcurrentLinkedQueue<>();
private final Timer timer = new Timer("timer", true);
@@ -36,8 +44,8 @@ public class JabRefExecutorService implements Executor {
@Override
public void execute(Runnable command) {
- if(command == null) {
- //TODO logger
+ if (command == null) {
+ LOGGER.debug("Received null as command for execution");
return;
}
@@ -45,13 +53,13 @@ public class JabRefExecutorService implements Executor {
}
public void executeAndWait(Runnable command) {
- if(command == null) {
- //TODO logger
+ if (command == null) {
+ LOGGER.debug("Received null as command for execution");
return;
}
Future<?> future = executorService.submit(command);
- while(true) {
+ while (true) {
try {
future.get();
return;
@@ -63,78 +71,83 @@ public class JabRefExecutorService implements Executor {
}
}
- private static class AutoCleanupRunnable implements Runnable {
+ public void executeInterruptableTask(final Runnable runnable) {
+ this.lowPriorityExecutorService.execute(runnable);
+ }
+
+ public void executeInterruptableTask(final Runnable runnable, String taskName) {
+ this.lowPriorityExecutorService.execute(new NamedRunnable(taskName, runnable));
+ }
+
+ class NamedRunnable implements Runnable {
- private final Runnable runnable;
- private final ConcurrentLinkedQueue<Thread> startedThreads;
+ private final String name;
- public Thread thread;
+ private final Runnable task;
- private AutoCleanupRunnable(Runnable runnable, ConcurrentLinkedQueue<Thread> startedThreads) {
- this.runnable = runnable;
- this.startedThreads = startedThreads;
+ public NamedRunnable(String name, Runnable runnable){
+ this.name = name;
+ this.task = runnable;
}
@Override
public void run() {
+ final String orgName = Thread.currentThread().getName();
+ Thread.currentThread().setName(name);
try {
- runnable.run();
+ task.run();
} finally {
- startedThreads.remove(thread);
+ Thread.currentThread().setName(orgName);
}
}
}
- public void executeWithLowPriorityInOwnThread(final Runnable runnable, String name) {
- AutoCleanupRunnable target = new AutoCleanupRunnable(runnable, startedThreads);
- final Thread thread = new Thread(target);
- target.thread = thread;
- thread.setName("JabRef - " + name + " - low prio");
- startedThreads.add(thread);
- thread.setPriority(Thread.MIN_PRIORITY);
- thread.start();
- }
-
- public void executeInOwnThread(Thread thread) {
- // this is a special case method for Threads that cannot be interrupted so easily
- // this method should normally not be used
- startedThreads.add(thread);
- // TODO memory leak when thread is finished
- thread.start();
- }
-
- public void executeWithLowPriorityInOwnThreadAndWait(Runnable runnable) {
- Thread thread = new Thread(runnable);
- thread.setName("JabRef low prio");
- startedThreads.add(thread);
- thread.setPriority(Thread.MIN_PRIORITY);
- thread.start();
-
- waitForThreadToFinish(thread);
- }
+ public void executeInterruptableTaskAndWait(Runnable runnable) {
+ if(runnable == null) {
+ LOGGER.debug("Received null as command for execution");
+ return;
+ }
- private void waitForThreadToFinish(Thread thread) {
- while(true) {
+ Future<?> future = lowPriorityExecutorService.submit(runnable);
+ while (true) {
try {
- thread.join();
- startedThreads.remove(thread);
+ future.get();
return;
} catch (InterruptedException ignored) {
// Ignored
+ } catch (ExecutionException e) {
+ LOGGER.error("Problem executing command", e);
}
}
}
+ public void manageRemoteThread(Thread thread) {
+ if (this.remoteThread != null){
+ throw new IllegalStateException("Remote thread is already attached");
+ } else {
+ this.remoteThread = thread;
+ remoteThread.start();
+ }
+ }
+
+ public void stopRemoteThread() {
+ if (remoteThread != null) {
+ remoteThread.interrupt();
+ remoteThread = null;
+ }
+ }
+
public void submit(TimerTask timerTask, long millisecondsDelay) {
timer.schedule(timerTask, millisecondsDelay);
}
public void shutdownEverything() {
+ // those threads will be allowed to finish
this.executorService.shutdown();
- for(Thread thread : startedThreads) {
- thread.interrupt();
- }
- startedThreads.clear();
+ //those threads will be interrupted in their current task
+ this.lowPriorityExecutorService.shutdownNow();
+ // kill the remote thread
+ stopRemoteThread();
// timer doesn't need to be canceled as it is run in daemon mode, which ensures that it is stopped if the application is shut down
}
diff --git a/src/main/java/net/sf/jabref/JabRefGUI.java b/src/main/java/net/sf/jabref/JabRefGUI.java
index efec40a..e5b29d5 100644
--- a/src/main/java/net/sf/jabref/JabRefGUI.java
+++ b/src/main/java/net/sf/jabref/JabRefGUI.java
@@ -1,37 +1,39 @@
package net.sf.jabref;
+import java.awt.Frame;
import java.io.File;
+import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
-import javax.swing.JFrame;
import javax.swing.JOptionPane;
-import javax.swing.SwingUtilities;
import javax.swing.UIDefaults;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.plaf.FontUIResource;
+import javax.swing.plaf.metal.MetalLookAndFeel;
import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.gui.GUIGlobals;
import net.sf.jabref.gui.JabRefFrame;
+import net.sf.jabref.gui.autosaveandbackup.BackupUIManager;
import net.sf.jabref.gui.importer.ParserResultWarningDialog;
import net.sf.jabref.gui.importer.actions.OpenDatabaseAction;
-import net.sf.jabref.gui.importer.worker.AutosaveStartupPrompter;
-import net.sf.jabref.gui.util.FocusRequester;
+import net.sf.jabref.gui.shared.SharedDatabaseUIManager;
import net.sf.jabref.gui.worker.VersionWorker;
-import net.sf.jabref.logic.importer.ImportFormatPreferences;
+import net.sf.jabref.logic.autosaveandbackup.BackupManager;
import net.sf.jabref.logic.importer.OpenDatabase;
import net.sf.jabref.logic.importer.ParserResult;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.util.OS;
import net.sf.jabref.logic.util.Version;
-import net.sf.jabref.migrations.PreferencesMigrations;
import net.sf.jabref.preferences.JabRefPreferences;
-import net.sf.jabref.preferences.VersionPreferences;
+import net.sf.jabref.shared.exception.DatabaseNotSupportedException;
+import net.sf.jabref.shared.exception.InvalidDBMSConnectionPropertiesException;
+import net.sf.jabref.shared.exception.NotASharedDatabaseException;
import com.jgoodies.looks.plastic.Plastic3DLookAndFeel;
import com.jgoodies.looks.plastic.theme.SkyBluer;
@@ -45,7 +47,6 @@ public class JabRefGUI {
private final List<ParserResult> bibDatabases;
private final boolean isBlank;
- private final List<File> postponed = new ArrayList<>();
private final List<ParserResult> failed = new ArrayList<>();
private final List<ParserResult> toOpenTab = new ArrayList<>();
@@ -56,27 +57,20 @@ public class JabRefGUI {
this.isBlank = isBlank;
// passed file (we take the first one) should be focused
- if (!argsDatabases.isEmpty()) {
- focusedFile = argsDatabases.get(0).getFile().get().getAbsolutePath();
- } else {
- focusedFile = Globals.prefs.get(JabRefPreferences.LAST_FOCUSED);
- }
+ focusedFile = argsDatabases.stream().findFirst().flatMap(ParserResult::getFile).map(File::getAbsolutePath)
+ .orElse(Globals.prefs.get(JabRefPreferences.LAST_FOCUSED));
openWindow();
JabRefGUI.checkForNewVersion(false);
}
public static void checkForNewVersion(boolean manualExecution) {
- Version toBeIgnored = new VersionPreferences(Globals.prefs).getIgnoredVersion();
+ Version toBeIgnored = Globals.prefs.getVersionPreferences().getIgnoredVersion();
Version currentVersion = Globals.BUILD_INFO.getVersion();
new VersionWorker(JabRefGUI.getMainFrame(), manualExecution, currentVersion, toBeIgnored).execute();
}
private void openWindow() {
- // Perform checks and changes for users with a preference set from an older JabRef version.
- PreferencesMigrations.upgradeSortOrder();
- PreferencesMigrations.upgradeFaultyEncodingStrings();
- PreferencesMigrations.upgradeLabelPatternToBibtexKeyPattern();
// This property is set to make the Mac OSX Java VM move the menu bar to the top of the screen
if (OS.OS_X) {
@@ -110,7 +104,6 @@ public class JabRefGUI {
if (!bibDatabases.isEmpty()) {
for (Iterator<ParserResult> parserResultIterator = bibDatabases.iterator(); parserResultIterator.hasNext();) {
ParserResult pr = parserResultIterator.next();
-
// Define focused tab
if (pr.getFile().get().getAbsolutePath().equals(focusedFile)) {
first = true;
@@ -119,18 +112,27 @@ public class JabRefGUI {
if (pr.isInvalid()) {
failed.add(pr);
parserResultIterator.remove();
- } else if (!pr.isPostponedAutosaveFound()) {
- if (pr.toOpenTab()) {
- // things to be appended to an opened tab should be done after opening all tabs
- // add them to the list
- toOpenTab.add(pr);
- } else {
- JabRefGUI.getMainFrame().addParserResult(pr, first);
- first = false;
+ } else if (pr.getDatabase().isShared()) {
+ try {
+ new SharedDatabaseUIManager(mainFrame).openSharedDatabaseFromParserResult(pr);
+ } catch (SQLException | DatabaseNotSupportedException | InvalidDBMSConnectionPropertiesException |
+ NotASharedDatabaseException e) {
+ pr.getDatabaseContext().clearDatabaseFile(); // do not open the original file
+ pr.getDatabase().clearSharedDatabaseID();
+
+ LOGGER.error("Connection error", e);
+ JOptionPane.showMessageDialog(mainFrame,
+ e.getMessage() + "\n\n" + Localization.lang("A local copy will be opened."),
+ Localization.lang("Connection error"), JOptionPane.WARNING_MESSAGE);
}
+ toOpenTab.add(pr);
+ } else if (pr.toOpenTab()) {
+ // things to be appended to an opened tab should be done after opening all tabs
+ // add them to the list
+ toOpenTab.add(pr);
} else {
- parserResultIterator.remove();
- postponed.add(pr.getFile().get());
+ JabRefGUI.getMainFrame().addParserResult(pr, first);
+ first = false;
}
}
}
@@ -141,24 +143,15 @@ public class JabRefGUI {
first = false;
}
- // Start auto save timer:
- if (Globals.prefs.getBoolean(JabRefPreferences.AUTO_SAVE)) {
- Globals.startAutoSaveManager(JabRefGUI.getMainFrame());
- }
-
// If we are set to remember the window location, we also remember the maximised
// state. This needs to be set after the window has been made visible, so we
// do it here:
if (Globals.prefs.getBoolean(JabRefPreferences.WINDOW_MAXIMISED)) {
- JabRefGUI.getMainFrame().setExtendedState(JFrame.MAXIMIZED_BOTH);
+ JabRefGUI.getMainFrame().setExtendedState(Frame.MAXIMIZED_BOTH);
}
JabRefGUI.getMainFrame().setVisible(true);
- if (Globals.prefs.getBoolean(JabRefPreferences.WINDOW_MAXIMISED)) {
- JabRefGUI.getMainFrame().setExtendedState(JFrame.MAXIMIZED_BOTH);
- }
-
for (ParserResult pr : failed) {
String message = "<html>" + Localization.lang("Error opening file '%0'.", pr.getFile().get().getName())
+ "<p>"
@@ -191,15 +184,8 @@ public class JabRefGUI {
LOGGER.debug("Finished adding panels");
- // If any database loading was postponed due to an autosave, schedule them
- // for handing now:
- if (!postponed.isEmpty()) {
- AutosaveStartupPrompter asp = new AutosaveStartupPrompter(JabRefGUI.getMainFrame(), postponed);
- SwingUtilities.invokeLater(asp);
- }
-
if (!bibDatabases.isEmpty()) {
- new FocusRequester(JabRefGUI.getMainFrame().getCurrentBasePanel().getMainTable());
+ JabRefGUI.getMainFrame().getCurrentBasePanel().getMainTable().requestFocus();
}
}
@@ -207,7 +193,6 @@ public class JabRefGUI {
if (Globals.prefs.get(JabRefPreferences.LAST_EDITED) == null) {
return;
}
-
List<String> lastFiles = Globals.prefs.getStringList(JabRefPreferences.LAST_EDITED);
for (String fileName : lastFiles) {
@@ -218,8 +203,12 @@ public class JabRefGUI {
continue;
}
- ParserResult parsedDatabase = OpenDatabase.loadDatabaseOrAutoSave(fileName, false,
- ImportFormatPreferences.fromPreferences(Globals.prefs));
+ if (BackupManager.checkForBackupFile(dbFile.toPath())) {
+ BackupUIManager.showRestoreBackupDialog(mainFrame, dbFile.toPath());
+ }
+
+ ParserResult parsedDatabase = OpenDatabase.loadDatabase(fileName,
+ Globals.prefs.getImportFormatPreferences());
if (parsedDatabase.isNullResult()) {
LOGGER.error(Localization.lang("Error opening file") + " '" + dbFile.getPath() + "'");
@@ -263,7 +252,7 @@ public class JabRefGUI {
&& !System.getProperty("java.runtime.name").contains("OpenJDK")) {
// try to avoid ending up with the ugly Metal L&F
Plastic3DLookAndFeel lnf = new Plastic3DLookAndFeel();
- Plastic3DLookAndFeel.setCurrentTheme(new SkyBluer());
+ MetalLookAndFeel.setCurrentTheme(new SkyBluer());
com.jgoodies.looks.Options.setPopupDropShadowEnabled(true);
UIManager.setLookAndFeel(lnf);
} else {
diff --git a/src/main/java/net/sf/jabref/JabRefMain.java b/src/main/java/net/sf/jabref/JabRefMain.java
index b4665ca..468a0d9 100644
--- a/src/main/java/net/sf/jabref/JabRefMain.java
+++ b/src/main/java/net/sf/jabref/JabRefMain.java
@@ -12,7 +12,6 @@ import net.sf.jabref.logic.exporter.ExportFormat;
import net.sf.jabref.logic.exporter.ExportFormats;
import net.sf.jabref.logic.exporter.SavePreferences;
import net.sf.jabref.logic.formatter.casechanger.ProtectTermsFormatter;
-import net.sf.jabref.logic.importer.ImportFormatPreferences;
import net.sf.jabref.logic.journals.JournalAbbreviationLoader;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.layout.LayoutFormatterPreferences;
@@ -20,11 +19,10 @@ import net.sf.jabref.logic.net.ProxyAuthenticator;
import net.sf.jabref.logic.net.ProxyPreferences;
import net.sf.jabref.logic.net.ProxyRegisterer;
import net.sf.jabref.logic.protectedterms.ProtectedTermsLoader;
-import net.sf.jabref.logic.protectedterms.ProtectedTermsPreferences;
import net.sf.jabref.logic.remote.RemotePreferences;
import net.sf.jabref.logic.remote.client.RemoteListenerClient;
import net.sf.jabref.logic.util.OS;
-import net.sf.jabref.logic.xmp.XMPPreferences;
+import net.sf.jabref.migrations.PreferencesMigrations;
import net.sf.jabref.model.entry.InternalBibtexFields;
import net.sf.jabref.preferences.JabRefPreferences;
@@ -42,9 +40,11 @@ public class JabRefMain {
}
private static void start(String[] args) {
+ FallbackExceptionHandler.installExceptionHandler();
+
JabRefPreferences preferences = JabRefPreferences.getInstance();
- ProxyPreferences proxyPreferences = ProxyPreferences.loadFromPreferences(preferences);
+ ProxyPreferences proxyPreferences = preferences.getProxyPreferences();
ProxyRegisterer.register(proxyPreferences);
if (proxyPreferences.isUseProxy() && proxyPreferences.isUseAuthentication()) {
Authenticator.setDefault(new ProxyAuthenticator());
@@ -55,6 +55,12 @@ public class JabRefMain {
Localization.setLanguage(preferences.get(JabRefPreferences.LANGUAGE));
Globals.prefs.setLanguageDependentDefaultValues();
+ // Perform Migrations
+ // Perform checks and changes for users with a preference set from an older JabRef version.
+ PreferencesMigrations.upgradeSortOrder();
+ PreferencesMigrations.upgradeFaultyEncodingStrings();
+ PreferencesMigrations.upgradeLabelPatternToBibtexKeyPattern();
+
// Update handling of special fields based on preferences
InternalBibtexFields
.updateSpecialFields(Globals.prefs.getBoolean(JabRefPreferences.SERIALIZESPECIALFIELDS));
@@ -67,23 +73,22 @@ public class JabRefMain {
Globals.journalAbbreviationLoader = new JournalAbbreviationLoader();
/* Build list of Import and Export formats */
- Globals.IMPORT_FORMAT_READER.resetImportFormats(ImportFormatPreferences.fromPreferences(Globals.prefs),
- XMPPreferences.fromPreferences(Globals.prefs));
+ Globals.IMPORT_FORMAT_READER.resetImportFormats(Globals.prefs.getImportFormatPreferences(),
+ Globals.prefs.getXMPPreferences());
CustomEntryTypesManager.loadCustomEntryTypes(preferences);
Map<String, ExportFormat> customFormats = Globals.prefs.customExports.getCustomExportFormats(Globals.prefs,
Globals.journalAbbreviationLoader);
- LayoutFormatterPreferences layoutPreferences = LayoutFormatterPreferences.fromPreferences(Globals.prefs,
- Globals.journalAbbreviationLoader);
+ LayoutFormatterPreferences layoutPreferences = Globals.prefs
+ .getLayoutFormatterPreferences(Globals.journalAbbreviationLoader);
SavePreferences savePreferences = SavePreferences.loadForExportFromPreferences(Globals.prefs);
ExportFormats.initAllExports(customFormats, layoutPreferences, savePreferences);
// Initialize protected terms loader
- Globals.protectedTermsLoader = new ProtectedTermsLoader(
- ProtectedTermsPreferences.fromPreferences(Globals.prefs));
+ Globals.protectedTermsLoader = new ProtectedTermsLoader(Globals.prefs.getProtectedTermsPreferences());
ProtectTermsFormatter.setProtectedTermsLoader(Globals.protectedTermsLoader);
// Check for running JabRef
- RemotePreferences remotePreferences = new RemotePreferences(Globals.prefs);
+ RemotePreferences remotePreferences = Globals.prefs.getRemotePreferences();
if (remotePreferences.useRemoteServer()) {
Globals.REMOTE_LISTENER.open(new JabRefMessageHandler(), remotePreferences.getPort());
diff --git a/src/main/java/net/sf/jabref/MetaData.java b/src/main/java/net/sf/jabref/MetaData.java
deleted file mode 100644
index 49db365..0000000
--- a/src/main/java/net/sf/jabref/MetaData.java
+++ /dev/null
@@ -1,480 +0,0 @@
-package net.sf.jabref;
-
-import java.io.IOException;
-import java.io.Reader;
-import java.io.StringReader;
-import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.Vector;
-
-import net.sf.jabref.event.GroupUpdatedEvent;
-import net.sf.jabref.event.MetaDataChangedEvent;
-import net.sf.jabref.logic.config.SaveOrderConfig;
-import net.sf.jabref.logic.exporter.FieldFormatterCleanups;
-import net.sf.jabref.logic.groups.GroupTreeNode;
-import net.sf.jabref.logic.importer.util.ParseException;
-import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.logic.layout.format.FileLinkPreferences;
-import net.sf.jabref.logic.util.OS;
-import net.sf.jabref.logic.util.strings.StringUtil;
-import net.sf.jabref.model.bibtexkeypattern.AbstractBibtexKeyPattern;
-import net.sf.jabref.model.bibtexkeypattern.DatabaseBibtexKeyPattern;
-import net.sf.jabref.model.bibtexkeypattern.GlobalBibtexKeyPattern;
-import net.sf.jabref.model.database.BibDatabaseMode;
-import net.sf.jabref.model.entry.FieldName;
-
-import com.google.common.eventbus.EventBus;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-public class MetaData implements Iterable<String> {
- private static final Log LOGGER = LogFactory.getLog(MetaData.class);
-
- public static final String META_FLAG = "jabref-meta: ";
- private static final String SAVE_ORDER_CONFIG = "saveOrderConfig";
-
- private static final String SAVE_ACTIONS = "saveActions";
- private static final String PREFIX_KEYPATTERN = "keypattern_";
- private static final String KEYPATTERNDEFAULT = "keypatterndefault";
- private static final String DATABASE_TYPE = "databaseType";
-
- private static final String GROUPSTREE = "groupstree";
- private static final String FILE_DIRECTORY = FieldName.FILE + FileLinkPreferences.DIR_SUFFIX;
- public static final String SELECTOR_META_PREFIX = "selector_";
- private static final String PROTECTED_FLAG_META = "protectedFlag";
-
- private final Map<String, List<String>> metaData = new HashMap<>();
- private GroupTreeNode groupsRoot;
- private final EventBus eventBus = new EventBus();
-
- private AbstractBibtexKeyPattern bibtexKeyPattern;
-
- private Charset encoding;
-
- /**
- * The MetaData object stores all meta data sets in Vectors. To ensure that
- * the data is written correctly to string, the user of a meta data Vector
- * must simply make sure the appropriate changes are reflected in the Vector
- * it has been passed.
- */
- private MetaData(Map<String, String> inData) throws ParseException {
- Objects.requireNonNull(inData);
- setData(inData);
- }
- private MetaData(Map<String, String> inData, Charset encoding) throws ParseException {
- this(inData);
- this.encoding = Objects.requireNonNull(encoding);
- }
-
- /**
- * The MetaData object can be constructed with no data in it.
- */
- public MetaData() {
- // Do nothing
- }
-
- public MetaData(Charset encoding) {
- this.encoding = encoding;
- }
-
- public static MetaData parse(Map<String, String> data) throws ParseException {
- return new MetaData(data);
- }
-
- public static MetaData parse(Map<String, String> data, Charset encoding) throws ParseException {
- return new MetaData(data, encoding);
- }
-
- public void setData(Map<String, String> inData) throws ParseException {
- clearMetaData();
- for (Map.Entry<String, String> entry : inData.entrySet()) {
- StringReader data = new StringReader(entry.getValue());
- List<String> orderedData = new ArrayList<>();
- // We must allow for ; and \ in escape sequences.
- try {
- Optional<String> unit;
- while ((unit = getNextUnit(data)).isPresent()) {
- orderedData.add(unit.get());
- }
- } catch (IOException ex) {
- LOGGER.error("Weird error while parsing meta data.", ex);
- }
- if (GROUPSTREE.equals(entry.getKey())) {
- putGroups(orderedData);
- // the keys "groupsversion" and "groups" were used in JabRef versions around 1.3, we will not support them anymore
- eventBus.post(new GroupUpdatedEvent(this));
- } else if (SAVE_ACTIONS.equals(entry.getKey())) {
- metaData.put(SAVE_ACTIONS, FieldFormatterCleanups.parse(orderedData).getAsStringList()); // Without MetaDataChangedEvent
- } else {
- metaData.put(entry.getKey(), orderedData);
- }
- }
- }
-
- public Optional<SaveOrderConfig> getSaveOrderConfig() {
- List<String> storedSaveOrderConfig = getData(SAVE_ORDER_CONFIG);
- if (storedSaveOrderConfig != null) {
- return Optional.of(SaveOrderConfig.parse(storedSaveOrderConfig));
- }
- return Optional.empty();
- }
-
- /**
- * Add default metadata for new database:
- */
- public void initializeNewDatabase() {
- metaData.put(SELECTOR_META_PREFIX + FieldName.KEYWORDS, new Vector<>());
- metaData.put(SELECTOR_META_PREFIX + FieldName.AUTHOR, new Vector<>());
- metaData.put(SELECTOR_META_PREFIX + FieldName.JOURNAL, new Vector<>());
- metaData.put(SELECTOR_META_PREFIX + FieldName.PUBLISHER, new Vector<>());
- metaData.put(SELECTOR_META_PREFIX + FieldName.REVIEW, new Vector<>());
- }
-
- /**
- * @return Iterator on all keys stored in the metadata
- */
- @Override
- public Iterator<String> iterator() {
- return metaData.keySet().iterator();
- }
-
- /**
- * Retrieves the stored meta data.
- *
- * @param key the key to look up
- * @return null if no data is found
- */
- public List<String> getData(String key) {
- return metaData.get(key);
- }
-
- /**
- * Removes the given key from metadata.
- * Nothing is done if key is not found.
- *
- * @param key the key to remove
- */
- public void remove(String key) {
- if (metaData.containsKey(key)) { //otherwise redundant and disturbing events are going to be posted
- metaData.remove(key);
- postChange();
- }
- }
-
- /**
- * Stores the specified data in this object, using the specified key. For
- * certain keys (e.g. "groupstree"), the objects in orderedData are
- * reconstructed from their textual (String) representation if they are of
- * type String, and stored as an actual instance.
- */
- public void putData(String key, List<String> orderedData) {
- metaData.put(key, orderedData);
- postChange();
- }
-
- /**
- * Parse the groups metadata string
- *
- * @param orderedData The vector of metadata strings
- */
- private void putGroups(List<String> orderedData) throws ParseException {
- try {
- groupsRoot = GroupTreeNode.parse(orderedData, Globals.prefs);
- eventBus.post(new GroupUpdatedEvent(this));
- } catch (ParseException e) {
- throw new ParseException(Localization.lang(
- "Group tree could not be parsed. If you save the BibTeX database, all groups will be lost."), e);
- }
- }
-
- public GroupTreeNode getGroups() {
- return groupsRoot;
- }
-
- /**
- * Sets a new group root node. <b>WARNING </b>: This invalidates everything
- * returned by getGroups() so far!!!
- */
- public void setGroups(GroupTreeNode root) {
- groupsRoot = root;
- eventBus.post(new GroupUpdatedEvent(this));
- }
-
- /**
- * Reads the next unit. Units are delimited by ';'.
- */
- private static Optional<String> getNextUnit(Reader reader) throws IOException {
- int c;
- boolean escape = false;
- StringBuilder res = new StringBuilder();
- while ((c = reader.read()) != -1) {
- if (escape) {
- res.append((char) c);
- escape = false;
- } else if (c == '\\') {
- escape = true;
- } else if (c == ';') {
- break;
- } else {
- res.append((char) c);
- }
- }
- if (res.length() > 0) {
- return Optional.of(res.toString());
- }
- return Optional.empty();
- }
-
- /**
- * @return the stored label patterns
- */
- public AbstractBibtexKeyPattern getBibtexKeyPattern(GlobalBibtexKeyPattern globalPattern) {
- if (bibtexKeyPattern != null) {
- return bibtexKeyPattern;
- }
-
- bibtexKeyPattern = new DatabaseBibtexKeyPattern(globalPattern);
-
- // read the data from the metadata and store it into the bibtexKeyPattern
- for (String key : this) {
- if (key.startsWith(PREFIX_KEYPATTERN)) {
- List<String> value = getData(key);
- String type = key.substring(PREFIX_KEYPATTERN.length());
- bibtexKeyPattern.addBibtexKeyPattern(type, value.get(0));
- }
- }
- List<String> defaultPattern = getData(KEYPATTERNDEFAULT);
- if (defaultPattern != null) {
- bibtexKeyPattern.setDefaultValue(defaultPattern.get(0));
- }
-
- return bibtexKeyPattern;
- }
-
- /**
- * Updates the stored key patterns to the given key patterns.
- *
- * @param bibtexKeyPattern the key patterns to update to. <br />
- * A reference to this object is stored internally and is returned at getBibtexKeyPattern();
- */
- public void setBibtexKeyPattern(AbstractBibtexKeyPattern bibtexKeyPattern) {
- // remove all keypatterns from metadata
- Iterator<String> iterator = this.iterator();
- while (iterator.hasNext()) {
- String key = iterator.next();
- if (key.startsWith(PREFIX_KEYPATTERN)) {
- iterator.remove();
- }
- }
-
- // set new value if it is not a default value
- Set<String> allKeys = bibtexKeyPattern.getAllKeys();
- for (String key : allKeys) {
- String metaDataKey = PREFIX_KEYPATTERN + key;
- if (!bibtexKeyPattern.isDefaultValue(key)) {
- List<String> data = new ArrayList<>();
- data.add(bibtexKeyPattern.getValue(key).get(0));
- this.putData(metaDataKey, data);
- }
- }
-
- // store default pattern
- if (bibtexKeyPattern.getDefaultValue() == null) {
- this.remove(KEYPATTERNDEFAULT);
- } else {
- List<String> data = new ArrayList<>();
- data.add(bibtexKeyPattern.getDefaultValue().get(0));
- this.putData(KEYPATTERNDEFAULT, data);
- }
-
- this.bibtexKeyPattern = bibtexKeyPattern;
- }
-
- public Optional<FieldFormatterCleanups> getSaveActions() {
- if (this.getData(SAVE_ACTIONS) == null) {
- return Optional.empty();
- } else {
- return Optional.of(FieldFormatterCleanups.parse(getData(SAVE_ACTIONS)));
- }
- }
-
- public Optional<BibDatabaseMode> getMode() {
- List<String> data = getData(DATABASE_TYPE);
- if ((data == null) || data.isEmpty()) {
- return Optional.empty();
- }
- return Optional.of(BibDatabaseMode.parse(data.get(0)));
- }
-
- public boolean isProtected() {
- List<String> data = getData(PROTECTED_FLAG_META);
- if ((data == null) || data.isEmpty()) {
- return false;
- } else {
- return Boolean.parseBoolean(data.get(0));
- }
- }
-
- public List<String> getContentSelectors(String fieldName) {
- List<String> contentSelectors = getData(SELECTOR_META_PREFIX + fieldName);
- if (contentSelectors == null) {
- return Collections.emptyList();
- } else {
- return contentSelectors;
- }
- }
-
- public Optional<String> getDefaultFileDirectory() {
- List<String> fileDirectory = getData(FILE_DIRECTORY);
- if ((fileDirectory == null) || fileDirectory.isEmpty()) {
- return Optional.empty();
- } else {
- return Optional.of(fileDirectory.get(0).trim());
- }
- }
-
- public Optional<String> getUserFileDirectory(String user) {
- List<String> fileDirectory = getData(FILE_DIRECTORY + '-' + user);
- if ((fileDirectory == null) || fileDirectory.isEmpty()) {
- return Optional.empty();
- } else {
- return Optional.of(fileDirectory.get(0).trim());
- }
- }
-
- /**
- * Writes all data in the format <key, serialized data>.
- */
- public Map<String, String> getAsStringMap() {
-
- Map<String, String> serializedMetaData = new TreeMap<>();
-
- // first write all meta data except groups
- for (Map.Entry<String, List<String>> metaItem : metaData.entrySet()) {
-
- StringBuilder stringBuilder = new StringBuilder();
- for (String dataItem : metaItem.getValue()) {
- stringBuilder.append(StringUtil.quote(dataItem, ";", '\\')).append(";");
-
- //in case of save actions, add an additional newline after the enabled flag
- if (metaItem.getKey().equals(SAVE_ACTIONS) && ("enabled".equals(dataItem) || "disabled".equals(dataItem))) {
- stringBuilder.append(OS.NEWLINE);
- }
- }
-
- String serializedItem = stringBuilder.toString();
- // Only add non-empty values
- if (!serializedItem.isEmpty() && !";".equals(serializedItem)) {
- serializedMetaData.put(metaItem.getKey(), serializedItem);
- }
- }
-
- // write groups if present. skip this if only the root node exists
- // (which is always the AllEntriesGroup).
- if ((groupsRoot != null) && (groupsRoot.getNumberOfChildren() > 0)) {
- StringBuilder stringBuilder = new StringBuilder();
- stringBuilder.append(OS.NEWLINE);
-
- for (String groupNode : groupsRoot.getTreeAsString()) {
- stringBuilder.append(StringUtil.quote(groupNode, ";", '\\'));
- stringBuilder.append(";");
- stringBuilder.append(OS.NEWLINE);
- }
- serializedMetaData.put(GROUPSTREE, stringBuilder.toString());
- }
- return serializedMetaData;
- }
-
- public void setSaveActions(FieldFormatterCleanups saveActions) {
- List<String> actionsSerialized = saveActions.getAsStringList();
- putData(SAVE_ACTIONS, actionsSerialized);
- }
-
- public void setSaveOrderConfig(SaveOrderConfig saveOrderConfig) {
- List<String> serialized = saveOrderConfig.getAsStringList();
- putData(SAVE_ORDER_CONFIG, serialized);
- }
-
- public void setMode(BibDatabaseMode mode) {
- putData(DATABASE_TYPE, Collections.singletonList(mode.getAsString()));
- }
-
- public void markAsProtected() {
- putData(PROTECTED_FLAG_META, Collections.singletonList("true"));
- }
-
- public void setContentSelectors(String fieldName, List<String> contentSelectors) {
- putData(SELECTOR_META_PREFIX + fieldName, contentSelectors);
- }
-
- public void setDefaultFileDirectory(String path) {
- putData(FILE_DIRECTORY, Collections.singletonList(path));
- }
-
- public void clearDefaultFileDirectory() {
- remove(FILE_DIRECTORY);
- }
-
- public void setUserFileDirectory(String user, String path) {
- putData(FILE_DIRECTORY + '-' + user, Collections.singletonList(path.trim()));
- }
-
- public void clearUserFileDirectory(String user) {
- remove(FILE_DIRECTORY + '-' + user);
- }
-
- public void clearContentSelectors(String fieldName) {
- remove(SELECTOR_META_PREFIX + fieldName);
- }
-
- public void markAsNotProtected() {
- remove(PROTECTED_FLAG_META);
- }
-
- public void clearSaveActions() {
- remove(SAVE_ACTIONS);
- }
-
- public void clearSaveOrderConfig() {
- remove(SAVE_ORDER_CONFIG);
- }
-
- /**
- * Posts a new {@link MetaDataChangedEvent} on the {@link EventBus}.
- */
- public void postChange() {
- eventBus.post(new MetaDataChangedEvent(this));
- }
-
- /**
- * Returns the encoding used during parsing.
- */
- public Optional<Charset> getEncoding() {
- return Optional.ofNullable(encoding);
- }
-
- public void setEncoding(Charset encoding) {
- this.encoding = Objects.requireNonNull(encoding);
- }
-
- public void clearMetaData() {
- metaData.clear();
- }
-
- public void registerListener(Object listener) {
- this.eventBus.register(listener);
- }
-
- public void unregisterListener(Object listener) {
- this.eventBus.unregister(listener);
- }
-}
diff --git a/src/main/java/net/sf/jabref/cli/ArgumentProcessor.java b/src/main/java/net/sf/jabref/cli/ArgumentProcessor.java
index bdc772b..4b3588a 100644
--- a/src/main/java/net/sf/jabref/cli/ArgumentProcessor.java
+++ b/src/main/java/net/sf/jabref/cli/ArgumentProcessor.java
@@ -13,16 +13,12 @@ import java.util.Map;
import java.util.Optional;
import java.util.prefs.BackingStoreException;
-import net.sf.jabref.BibDatabaseContext;
-import net.sf.jabref.Defaults;
import net.sf.jabref.Globals;
import net.sf.jabref.JabRefException;
-import net.sf.jabref.MetaData;
-import net.sf.jabref.external.AutoSetLinks;
+import net.sf.jabref.gui.externalfiles.AutoSetLinks;
import net.sf.jabref.gui.importer.fetcher.EntryFetcher;
import net.sf.jabref.gui.importer.fetcher.EntryFetchers;
import net.sf.jabref.logic.CustomEntryTypesManager;
-import net.sf.jabref.logic.bibtexkeypattern.BibtexKeyPatternPreferences;
import net.sf.jabref.logic.bibtexkeypattern.BibtexKeyPatternUtil;
import net.sf.jabref.logic.exporter.BibDatabaseWriter;
import net.sf.jabref.logic.exporter.BibtexDatabaseWriter;
@@ -33,7 +29,7 @@ import net.sf.jabref.logic.exporter.IExportFormat;
import net.sf.jabref.logic.exporter.SaveException;
import net.sf.jabref.logic.exporter.SavePreferences;
import net.sf.jabref.logic.exporter.SaveSession;
-import net.sf.jabref.logic.importer.ImportFormatPreferences;
+import net.sf.jabref.logic.importer.ImportException;
import net.sf.jabref.logic.importer.ImportFormatReader;
import net.sf.jabref.logic.importer.OpenDatabase;
import net.sf.jabref.logic.importer.OutputPrinter;
@@ -41,26 +37,35 @@ import net.sf.jabref.logic.importer.ParserResult;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.layout.LayoutFormatterPreferences;
import net.sf.jabref.logic.logging.JabRefLogger;
+import net.sf.jabref.logic.net.URLDownload;
import net.sf.jabref.logic.search.DatabaseSearcher;
import net.sf.jabref.logic.search.SearchQuery;
import net.sf.jabref.logic.util.OS;
-import net.sf.jabref.logic.util.strings.StringUtil;
+import net.sf.jabref.model.Defaults;
import net.sf.jabref.model.database.BibDatabase;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.database.BibDatabaseMode;
import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.metadata.MetaData;
+import net.sf.jabref.model.strings.StringUtil;
import net.sf.jabref.preferences.JabRefPreferences;
+import net.sf.jabref.preferences.SearchPreferences;
+import net.sf.jabref.shared.prefs.SharedDatabasePreferences;
+import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class ArgumentProcessor {
+
private static final Log LOGGER = LogFactory.getLog(ArgumentProcessor.class);
+
public enum Mode {
- INITIAL_START,
- REMOTE_START
+ INITIAL_START, REMOTE_START
}
+
private final JabRefCLI cli;
private final List<ParserResult> parserResults;
@@ -69,6 +74,7 @@ public class ArgumentProcessor {
private boolean noGUINeeded;
+
public ArgumentProcessor(String[] args, Mode startupMode) {
cli = new JabRefCLI(args);
this.startupMode = startupMode;
@@ -167,9 +173,9 @@ public class ArgumentProcessor {
BibDatabaseContext databaseContext = pr.getDatabaseContext();
BibDatabase dataBase = pr.getDatabase();
- SearchQuery query = new SearchQuery(searchTerm,
- Globals.prefs.getBoolean(JabRefPreferences.SEARCH_CASE_SENSITIVE),
- Globals.prefs.getBoolean(JabRefPreferences.SEARCH_REG_EXP));
+ SearchPreferences searchPreferences = new SearchPreferences(Globals.prefs);
+ SearchQuery query = new SearchQuery(searchTerm, searchPreferences.isCaseSensitive(),
+ searchPreferences.isRegularExpression());
List<BibEntry> matches = new DatabaseSearcher(query, dataBase).getMatches();
//export matches
@@ -205,7 +211,7 @@ public class ArgumentProcessor {
matches);
} catch (Exception ex) {
System.err.println(Localization.lang("Could not export file") + " '" + data[1] + "': "
- + ex.getMessage());
+ + ExceptionUtils.getStackTrace(ex));
}
}
} else {
@@ -239,10 +245,9 @@ public class ArgumentProcessor {
// BIB files to open. Other files, and files that could not be opened
// as bib, we try to import instead.
boolean bibExtension = aLeftOver.toLowerCase(Locale.ENGLISH).endsWith("bib");
- ParserResult pr = null;
+ ParserResult pr = ParserResult.getNullResult();
if (bibExtension) {
- pr = OpenDatabase.loadDatabaseOrAutoSave(aLeftOver, false,
- ImportFormatPreferences.fromPreferences(Globals.prefs));
+ pr = OpenDatabase.loadDatabase(aLeftOver, Globals.prefs.getImportFormatPreferences());
}
if (!bibExtension || (pr.isNullResult())) {
@@ -293,11 +298,10 @@ public class ArgumentProcessor {
try {
System.out.println(Localization.lang("Saving") + ": " + subName);
SavePreferences prefs = SavePreferences.loadForSaveFromPreferences(Globals.prefs);
- BibDatabaseWriter databaseWriter = new BibtexDatabaseWriter(FileSaveSession::new);
+ BibDatabaseWriter<SaveSession> databaseWriter = new BibtexDatabaseWriter<>(FileSaveSession::new);
Defaults defaults = new Defaults(BibDatabaseMode
.fromPreference(Globals.prefs.getBoolean(JabRefPreferences.BIBLATEX_DEFAULT_MODE)));
- SaveSession session = databaseWriter.saveDatabase(new BibDatabaseContext(newBase, defaults),
- prefs);
+ SaveSession session = databaseWriter.saveDatabase(new BibDatabaseContext(newBase, defaults), prefs);
// Show just a warning message if encoding did not work for all characters:
if (!session.getWriter().couldEncodeAll()) {
@@ -309,8 +313,7 @@ public class ArgumentProcessor {
}
session.commit(subName);
} catch (SaveException ex) {
- System.err.println(
- Localization.lang("Could not save file.") + "\n" + ex.getLocalizedMessage());
+ System.err.println(Localization.lang("Could not save file.") + "\n" + ex.getLocalizedMessage());
}
notSavedMsg = true;
@@ -335,9 +338,10 @@ public class ArgumentProcessor {
try {
System.out.println(Localization.lang("Saving") + ": " + data[0]);
SavePreferences prefs = SavePreferences.loadForSaveFromPreferences(Globals.prefs);
- Defaults defaults = new Defaults(BibDatabaseMode.fromPreference(
- Globals.prefs.getBoolean(JabRefPreferences.BIBLATEX_DEFAULT_MODE)));
- BibDatabaseWriter databaseWriter = new BibtexDatabaseWriter(FileSaveSession::new);
+ Defaults defaults = new Defaults(BibDatabaseMode
+ .fromPreference(Globals.prefs.getBoolean(JabRefPreferences.BIBLATEX_DEFAULT_MODE)));
+ BibDatabaseWriter<SaveSession> databaseWriter = new BibtexDatabaseWriter<>(
+ FileSaveSession::new);
SaveSession session = databaseWriter.saveDatabase(
new BibDatabaseContext(pr.getDatabase(), pr.getMetaData(), defaults), prefs);
@@ -351,8 +355,7 @@ public class ArgumentProcessor {
}
session.commit(data[0]);
} catch (SaveException ex) {
- System.err.println(
- Localization.lang("Could not save file.") + "\n" + ex.getLocalizedMessage());
+ System.err.println(Localization.lang("Could not save file.") + "\n" + ex.getLocalizedMessage());
}
}
} else {
@@ -372,7 +375,8 @@ public class ArgumentProcessor {
}
BibDatabaseContext databaseContext = pr.getDatabaseContext();
databaseContext.setDatabaseFile(theFile);
- Globals.prefs.fileDirForDatabase = databaseContext.getFileDirectory();
+ Globals.prefs.fileDirForDatabase = databaseContext
+ .getFileDirectories(Globals.prefs.getFileDirectoryPreferences());
System.out.println(Localization.lang("Exporting") + ": " + data[0]);
IExportFormat format = ExportFormats.getExportFormat(data[1]);
if (format == null) {
@@ -383,10 +387,11 @@ public class ArgumentProcessor {
format.performExport(pr.getDatabaseContext(), data[0],
pr.getDatabaseContext().getMetaData().getEncoding()
.orElse(Globals.prefs.getDefaultEncoding()),
- null);
+ pr.getDatabaseContext().getDatabase().getEntries());
} catch (Exception ex) {
+
System.err.println(Localization.lang("Could not export file") + " '" + data[0] + "': "
- + ex.getMessage());
+ + ExceptionUtils.getStackTrace(ex));
}
}
@@ -399,8 +404,8 @@ public class ArgumentProcessor {
CustomEntryTypesManager.loadCustomEntryTypes(Globals.prefs);
Map<String, ExportFormat> customFormats = Globals.prefs.customExports.getCustomExportFormats(Globals.prefs,
Globals.journalAbbreviationLoader);
- LayoutFormatterPreferences layoutPreferences = LayoutFormatterPreferences.fromPreferences(Globals.prefs,
- Globals.journalAbbreviationLoader);
+ LayoutFormatterPreferences layoutPreferences = Globals.prefs
+ .getLayoutFormatterPreferences(Globals.journalAbbreviationLoader);
SavePreferences savePreferences = SavePreferences.loadForExportFromPreferences(Globals.prefs);
ExportFormats.initAllExports(customFormats, layoutPreferences, savePreferences);
} catch (JabRefException ex) {
@@ -413,6 +418,7 @@ public class ArgumentProcessor {
try {
System.out.println(Localization.lang("Setting all preferences to default values."));
Globals.prefs.clear();
+ new SharedDatabasePreferences().clear();
} catch (BackingStoreException e) {
System.err.println(Localization.lang("Unable to clear preferences."));
LOGGER.error("Unable to clear preferences", e);
@@ -447,8 +453,9 @@ public class ArgumentProcessor {
LOGGER.info(Localization.lang("Regenerating BibTeX keys according to metadata"));
for (BibEntry entry : database.getEntries()) {
// try to make a new label
- BibtexKeyPatternUtil.makeLabel(metaData, database, entry,
- BibtexKeyPatternPreferences.fromPreferences(Globals.prefs));
+ BibtexKeyPatternUtil.makeAndSetLabel(
+ metaData.getCiteKeyPattern(Globals.prefs.getBibtexKeyPatternPreferences().getKeyPattern()),
+ database, entry, Globals.prefs.getBibtexKeyPatternPreferences());
}
} else {
LOGGER.info(Localization.lang("No meta data present in BIB_file. Cannot regenerate BibTeX keys"));
@@ -529,54 +536,63 @@ public class ArgumentProcessor {
private static Optional<ParserResult> importFile(String argument) {
String[] data = argument.split(",");
- OutputPrinter printer = new SystemOutputPrinter();
- try {
- if ((data.length > 1) && !"*".equals(data[1])) {
- System.out.println(Localization.lang("Importing") + ": " + data[0]);
- try {
- Path file;
- if (OS.WINDOWS) {
- file = Paths.get(data[0]);
- } else {
- file = Paths.get(data[0].replace("~", System.getProperty("user.home")));
- }
- ParserResult result = Globals.IMPORT_FORMAT_READER.importFromFile(data[1], file);
+ String address = data[0];
+ Path file;
+ if (address.startsWith("http://") || address.startsWith("https://") || address.startsWith("ftp://")) {
+ // Download web resource to temporary file
+ try {
+ file = new URLDownload(address).downloadToTemporaryFile();
+ } catch (IOException e) {
+ System.err.println(Localization.lang("Problem downloading from %1", address) + e.getLocalizedMessage());
+ return Optional.empty();
+ }
+ } else {
+ if (OS.WINDOWS) {
+ file = Paths.get(address);
+ } else {
+ file = Paths.get(address.replace("~", System.getProperty("user.home")));
+ }
+ }
- if(result.hasWarnings()) {
- printer.showMessage(result.getErrorMessage());
- }
+ String importFormat;
+ if (data.length > 1) {
+ importFormat = data[1];
+ } else {
+ importFormat = "*";
+ }
- return Optional.of(result);
- } catch (IllegalArgumentException ex) {
- System.err.println(Localization.lang("Unknown import format") + ": " + data[1]);
- return Optional.empty();
- }
+ Optional<ParserResult> importResult = importFile(file, importFormat);
+ importResult.ifPresent(result -> {
+ OutputPrinter printer = new SystemOutputPrinter();
+ if (result.hasWarnings()) {
+ printer.showMessage(result.getErrorMessage());
+ }
+ });
+ return importResult;
+ }
+
+ private static Optional<ParserResult> importFile(Path file, String importFormat) {
+ try {
+ if (!"*".equals(importFormat)) {
+ System.out.println(Localization.lang("Importing") + ": " + file);
+ ParserResult result = Globals.IMPORT_FORMAT_READER.importFromFile(importFormat, file);
+ return Optional.of(result);
} else {
// * means "guess the format":
- System.out.println(Localization.lang("Importing in unknown format") + ": " + data[0]);
+ System.out.println(Localization.lang("Importing in unknown format") + ": " + file);
ImportFormatReader.UnknownFormatImport importResult;
- if (OS.WINDOWS) {
- importResult = Globals.IMPORT_FORMAT_READER.importUnknownFormat(data[0]);
- } else {
- importResult = Globals.IMPORT_FORMAT_READER
- .importUnknownFormat(data[0].replace("~", System.getProperty("user.home")));
- }
+ importResult = Globals.IMPORT_FORMAT_READER.importUnknownFormat(file);
- if (importResult == null) {
- System.out.println(Localization.lang("Could not find a suitable import format."));
- } else {
- System.out.println(Localization.lang("Format used") + ": " + importResult.format);
-
- return Optional.of(importResult.parserResult);
- }
+ System.out.println(Localization.lang("Format used") + ": " + importResult.format);
+ return Optional.of(importResult.parserResult);
}
- } catch (IOException ex) {
- System.err.println(
- Localization.lang("Error opening file") + " '" + data[0] + "': " + ex.getLocalizedMessage());
+ } catch (ImportException ex) {
+ System.err
+ .println(Localization.lang("Error opening file") + " '" + file + "': " + ex.getLocalizedMessage());
+ return Optional.empty();
}
- return Optional.empty();
}
public boolean shouldShutDown() {
diff --git a/src/main/java/net/sf/jabref/cli/AuxCommandLine.java b/src/main/java/net/sf/jabref/cli/AuxCommandLine.java
index 11a6c25..d86e954 100644
--- a/src/main/java/net/sf/jabref/cli/AuxCommandLine.java
+++ b/src/main/java/net/sf/jabref/cli/AuxCommandLine.java
@@ -2,8 +2,8 @@ package net.sf.jabref.cli;
import net.sf.jabref.logic.auxparser.AuxParser;
import net.sf.jabref.logic.auxparser.AuxParserResult;
-import net.sf.jabref.logic.util.strings.StringUtil;
import net.sf.jabref.model.database.BibDatabase;
+import net.sf.jabref.model.strings.StringUtil;
public class AuxCommandLine {
private final String auxFile;
diff --git a/src/main/java/net/sf/jabref/cli/CrossrefFetcherEvaluator.java b/src/main/java/net/sf/jabref/cli/CrossrefFetcherEvaluator.java
index 63e91f3..b88eedf 100644
--- a/src/main/java/net/sf/jabref/cli/CrossrefFetcherEvaluator.java
+++ b/src/main/java/net/sf/jabref/cli/CrossrefFetcherEvaluator.java
@@ -10,7 +10,6 @@ import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import net.sf.jabref.Globals;
-import net.sf.jabref.logic.importer.ImportFormatPreferences;
import net.sf.jabref.logic.importer.ParserResult;
import net.sf.jabref.logic.importer.fetcher.CrossRef;
import net.sf.jabref.logic.importer.fileformat.BibtexParser;
@@ -28,19 +27,20 @@ public class CrossrefFetcherEvaluator {
public static void main(String[] args) throws IOException, InterruptedException {
Globals.prefs = JabRefPreferences.getInstance();
try (FileReader reader = new FileReader(args[0])) {
- BibtexParser parser = new BibtexParser(reader, ImportFormatPreferences.fromPreferences(Globals.prefs));
- ParserResult result = parser.parse();
+ BibtexParser parser = new BibtexParser(Globals.prefs.getImportFormatPreferences());
+ ParserResult result = parser.parse(reader);
BibDatabase db = result.getDatabase();
- int total = result.getDatabase().getEntryCount();
+ List<BibEntry> entries = db.getEntries();
AtomicInteger dois = new AtomicInteger();
AtomicInteger doiFound = new AtomicInteger();
AtomicInteger doiNew = new AtomicInteger();
AtomicInteger doiIdentical = new AtomicInteger();
- List<BibEntry> entries = db.getEntries();
- CountDownLatch countDownLatch = new CountDownLatch(entries.size());
+ int total = entries.size();
+
+ CountDownLatch countDownLatch = new CountDownLatch(total);
ExecutorService executorService = Executors.newFixedThreadPool(5);
@@ -49,7 +49,7 @@ public class CrossrefFetcherEvaluator {
@Override
public void run() {
- Optional<DOI> origDOI = entry.getFieldOptional(FieldName.DOI).flatMap(DOI::build);
+ Optional<DOI> origDOI = entry.getField(FieldName.DOI).flatMap(DOI::build);
if (origDOI.isPresent()) {
dois.incrementAndGet();
Optional<DOI> crossrefDOI = CrossRef.findDOI(entry);
diff --git a/src/main/java/net/sf/jabref/cli/GenerateCharacterTable.java b/src/main/java/net/sf/jabref/cli/GenerateCharacterTable.java
index 6af3726..b49093b 100644
--- a/src/main/java/net/sf/jabref/cli/GenerateCharacterTable.java
+++ b/src/main/java/net/sf/jabref/cli/GenerateCharacterTable.java
@@ -3,7 +3,7 @@ package net.sf.jabref.cli;
import java.util.Map;
import java.util.TreeMap;
-import net.sf.jabref.logic.util.strings.HTMLUnicodeConversionMaps;
+import net.sf.jabref.model.strings.HTMLUnicodeConversionMaps;
public class GenerateCharacterTable {
diff --git a/src/main/java/net/sf/jabref/cli/XMPUtilMain.java b/src/main/java/net/sf/jabref/cli/XMPUtilMain.java
index bb9c891..816fbd8 100644
--- a/src/main/java/net/sf/jabref/cli/XMPUtilMain.java
+++ b/src/main/java/net/sf/jabref/cli/XMPUtilMain.java
@@ -1,8 +1,11 @@
package net.sf.jabref.cli;
+import java.io.BufferedReader;
import java.io.File;
+import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
+import java.io.InputStreamReader;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
@@ -14,7 +17,6 @@ import javax.xml.transform.TransformerException;
import net.sf.jabref.Globals;
import net.sf.jabref.logic.bibtex.BibEntryWriter;
import net.sf.jabref.logic.bibtex.LatexFieldFormatter;
-import net.sf.jabref.logic.bibtex.LatexFieldFormatterPreferences;
import net.sf.jabref.logic.importer.ImportFormatPreferences;
import net.sf.jabref.logic.importer.ParserResult;
import net.sf.jabref.logic.importer.fileformat.BibtexParser;
@@ -60,8 +62,8 @@ public class XMPUtilMain {
Globals.prefs = JabRefPreferences.getInstance();
}
- XMPPreferences xmpPreferences = XMPPreferences.fromPreferences(Globals.prefs);
- ImportFormatPreferences importFormatPreferences = ImportFormatPreferences.fromPreferences(Globals.prefs);
+ XMPPreferences xmpPreferences = Globals.prefs.getXMPPreferences();
+ ImportFormatPreferences importFormatPreferences = Globals.prefs.getImportFormatPreferences();
switch (args.length) {
case 0:
@@ -74,7 +76,7 @@ public class XMPUtilMain {
List<BibEntry> l = XMPUtil.readXMP(new File(args[0]), xmpPreferences);
BibEntryWriter bibtexEntryWriter = new BibEntryWriter(
- new LatexFieldFormatter(LatexFieldFormatterPreferences.fromPreferences(Globals.prefs)), false);
+ new LatexFieldFormatter(Globals.prefs.getLatexFieldFormatterPreferences()), false);
for (BibEntry entry : l) {
StringWriter sw = new StringWriter();
@@ -112,7 +114,10 @@ public class XMPUtilMain {
}
if (args[0].endsWith(".bib") && args[1].endsWith(".pdf")) {
- ParserResult result = BibtexParser.parse(new FileReader(args[0]), importFormatPreferences);
+
+ BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(args[0]), StandardCharsets.UTF_8));
+ // we need ParserResult as we access result.getDatabase() later
+ ParserResult result = new BibtexParser(importFormatPreferences).parse(reader);
Collection<BibEntry> entries = result.getDatabase().getEntries();
@@ -154,7 +159,7 @@ public class XMPUtilMain {
/**
* Print usage information for the command line tool xmpUtil.
*
- * @see XMPUtil#main(String[])
+ * @see XMPUtilMain#main(String[])
*/
private static void usage() {
System.out.println("Read or write XMP-metadata from or to pdf file.");
diff --git a/src/main/java/net/sf/jabref/collab/ChangeDisplayDialog.java b/src/main/java/net/sf/jabref/collab/ChangeDisplayDialog.java
index a3670e4..cae1a54 100644
--- a/src/main/java/net/sf/jabref/collab/ChangeDisplayDialog.java
+++ b/src/main/java/net/sf/jabref/collab/ChangeDisplayDialog.java
@@ -22,7 +22,6 @@ import javax.swing.tree.DefaultMutableTreeNode;
import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.gui.undo.NamedCompound;
-import net.sf.jabref.gui.util.GUIUtil;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.model.database.BibDatabase;
@@ -50,7 +49,6 @@ class ChangeDisplayDialog extends JDialog implements TreeSelectionListener {
}
tree = new JTree(root);
tree.addTreeSelectionListener(this);
- GUIUtil.correctRowHeight(tree);
JSplitPane pane = new JSplitPane();
pane.setLeftComponent(new JScrollPane(tree));
diff --git a/src/main/java/net/sf/jabref/collab/ChangeScanner.java b/src/main/java/net/sf/jabref/collab/ChangeScanner.java
index 3642e60..e2aeb32 100644
--- a/src/main/java/net/sf/jabref/collab/ChangeScanner.java
+++ b/src/main/java/net/sf/jabref/collab/ChangeScanner.java
@@ -3,10 +3,9 @@ package net.sf.jabref.collab;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
-import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
-import java.util.List;
+import java.util.Objects;
import java.util.Optional;
import java.util.Set;
@@ -14,11 +13,8 @@ import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.tree.DefaultMutableTreeNode;
-import net.sf.jabref.BibDatabaseContext;
-import net.sf.jabref.Defaults;
import net.sf.jabref.Globals;
import net.sf.jabref.JabRefExecutorService;
-import net.sf.jabref.MetaData;
import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.gui.JabRefFrame;
import net.sf.jabref.logic.bibtex.comparator.EntryComparator;
@@ -28,38 +24,39 @@ import net.sf.jabref.logic.exporter.FileSaveSession;
import net.sf.jabref.logic.exporter.SaveException;
import net.sf.jabref.logic.exporter.SavePreferences;
import net.sf.jabref.logic.exporter.SaveSession;
-import net.sf.jabref.logic.groups.GroupTreeNode;
import net.sf.jabref.logic.importer.ImportFormatPreferences;
import net.sf.jabref.logic.importer.OpenDatabase;
import net.sf.jabref.logic.importer.ParserResult;
import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.Defaults;
import net.sf.jabref.model.DuplicateCheck;
import net.sf.jabref.model.database.BibDatabase;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.database.BibDatabaseMode;
import net.sf.jabref.model.database.EntrySorter;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.BibtexString;
import net.sf.jabref.model.entry.FieldName;
+import net.sf.jabref.model.groups.GroupTreeNode;
+import net.sf.jabref.model.metadata.MetaData;
import net.sf.jabref.preferences.JabRefPreferences;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class ChangeScanner implements Runnable {
+ private static final Log LOGGER = LogFactory.getLog(ChangeScanner.class);
private static final String[] SORT_BY = new String[] {FieldName.YEAR, FieldName.AUTHOR, FieldName.TITLE};
- private final File f;
-
- private final BibDatabase inMem;
- private final MetaData mdInMem;
+ private final File file;
+ private final BibDatabase databaseInMemory;
+ private final MetaData metadataInMemory;
private final BasePanel panel;
- private final JabRefFrame frame;
-
- private BibDatabase inTemp;
- private MetaData mdInTemp;
- private static final Log LOGGER = LogFactory.getLog(ChangeScanner.class);
+ private final JabRefFrame frame;
+ private BibDatabase databaseInTemp;
+ private MetaData metadataInTemp;
private static final double MATCH_THRESHOLD = 0.4;
@@ -75,9 +72,9 @@ public class ChangeScanner implements Runnable {
public ChangeScanner(JabRefFrame frame, BasePanel bp, File file) {
this.panel = bp;
this.frame = frame;
- this.inMem = bp.getDatabase();
- this.mdInMem = bp.getBibDatabaseContext().getMetaData();
- this.f = file;
+ this.databaseInMemory = bp.getDatabase();
+ this.metadataInMemory = bp.getBibDatabaseContext().getMetaData();
+ this.file = file;
}
@Override
@@ -86,37 +83,38 @@ public class ChangeScanner implements Runnable {
// Parse the temporary file.
Path tempFile = Globals.getFileUpdateMonitor().getTempFile(panel.fileMonitorHandle());
- ImportFormatPreferences importFormatPreferences = ImportFormatPreferences.fromPreferences(Globals.prefs);
- ParserResult pr = OpenDatabase.loadDatabase(tempFile.toFile(), importFormatPreferences);
- inTemp = pr.getDatabase();
- mdInTemp = pr.getMetaData();
+ ImportFormatPreferences importFormatPreferences = Globals.prefs.getImportFormatPreferences();
+ ParserResult result = OpenDatabase.loadDatabase(tempFile.toFile(), importFormatPreferences);
+ databaseInTemp = result.getDatabase();
+ metadataInTemp = result.getMetaData();
+
// Parse the modified file.
- pr = OpenDatabase.loadDatabase(f, importFormatPreferences);
- BibDatabase onDisk = pr.getDatabase();
- MetaData mdOnDisk = pr.getMetaData();
+ result = OpenDatabase.loadDatabase(file, importFormatPreferences);
+ BibDatabase databaseOnDisk = result.getDatabase();
+ MetaData metadataOnDisk = result.getMetaData();
// Sort both databases according to a common sort key.
- EntryComparator comp = new EntryComparator(false, true, SORT_BY[2]);
- comp = new EntryComparator(false, true, SORT_BY[1], comp);
- comp = new EntryComparator(false, true, SORT_BY[0], comp);
- EntrySorter sInTemp = inTemp.getSorter(comp);
- comp = new EntryComparator(false, true, SORT_BY[2]);
- comp = new EntryComparator(false, true, SORT_BY[1], comp);
- comp = new EntryComparator(false, true, SORT_BY[0], comp);
- EntrySorter sOnDisk = onDisk.getSorter(comp);
- comp = new EntryComparator(false, true, SORT_BY[2]);
- comp = new EntryComparator(false, true, SORT_BY[1], comp);
- comp = new EntryComparator(false, true, SORT_BY[0], comp);
- EntrySorter sInMem = inMem.getSorter(comp);
+ EntryComparator comparator = new EntryComparator(false, true, SORT_BY[2]);
+ comparator = new EntryComparator(false, true, SORT_BY[1], comparator);
+ comparator = new EntryComparator(false, true, SORT_BY[0], comparator);
+ EntrySorter sorterInTemp = databaseInTemp.getSorter(comparator);
+ comparator = new EntryComparator(false, true, SORT_BY[2]);
+ comparator = new EntryComparator(false, true, SORT_BY[1], comparator);
+ comparator = new EntryComparator(false, true, SORT_BY[0], comparator);
+ EntrySorter sorterOnDisk = databaseOnDisk.getSorter(comparator);
+ comparator = new EntryComparator(false, true, SORT_BY[2]);
+ comparator = new EntryComparator(false, true, SORT_BY[1], comparator);
+ comparator = new EntryComparator(false, true, SORT_BY[0], comparator);
+ EntrySorter sorterInMem = databaseInMemory.getSorter(comparator);
// Start looking at changes.
- scanMetaData(mdInMem, mdInTemp, mdOnDisk);
- scanPreamble(inMem, inTemp, onDisk);
- scanStrings(inMem, inTemp, onDisk);
+ scanMetaData(metadataInMemory, metadataInTemp, metadataOnDisk);
+ scanPreamble(databaseInMemory, databaseInTemp, databaseOnDisk);
+ scanStrings(databaseInMemory, databaseInTemp, databaseOnDisk);
- scanEntries(sInMem, sInTemp, sOnDisk);
+ scanEntries(sorterInMem, sorterInTemp, sorterOnDisk);
- scanGroups(mdInTemp, mdOnDisk);
+ scanGroups(metadataInTemp, metadataOnDisk);
} catch (IOException ex) {
LOGGER.warn("Problem running", ex);
@@ -130,11 +128,11 @@ public class ChangeScanner implements Runnable {
public void displayResult(final DisplayResultCallback fup) {
if (changes.getChildCount() > 0) {
SwingUtilities.invokeLater(() -> {
- ChangeDisplayDialog dial = new ChangeDisplayDialog(frame, panel, inTemp, changes);
- dial.setLocationRelativeTo(frame);
- dial.setVisible(true);
- fup.scanResultsResolved(dial.isOkPressed());
- if (dial.isOkPressed()) {
+ ChangeDisplayDialog changeDialog = new ChangeDisplayDialog(frame, panel, databaseInTemp, changes);
+ changeDialog.setLocationRelativeTo(frame);
+ changeDialog.setVisible(true);
+ fup.scanResultsResolved(changeDialog.isOkPressed());
+ if (changeDialog.isOkPressed()) {
// Overwrite the temp database:
storeTempDatabase();
}
@@ -156,8 +154,8 @@ public class ChangeScanner implements Runnable {
Defaults defaults = new Defaults(BibDatabaseMode
.fromPreference(Globals.prefs.getBoolean(JabRefPreferences.BIBLATEX_DEFAULT_MODE)));
- BibDatabaseWriter databaseWriter = new BibtexDatabaseWriter(FileSaveSession::new);
- SaveSession ss = databaseWriter.saveDatabase(new BibDatabaseContext(inTemp, mdInTemp, defaults), prefs);
+ BibDatabaseWriter<SaveSession> databaseWriter = new BibtexDatabaseWriter<>(FileSaveSession::new);
+ SaveSession ss = databaseWriter.saveDatabase(new BibDatabaseContext(databaseInTemp, metadataInTemp, defaults), prefs);
ss.commit(Globals.getFileUpdateMonitor().getTempFile(panel.fileMonitorHandle()));
} catch (SaveException ex) {
LOGGER.warn("Problem updating tmp file after accepting external changes", ex);
@@ -165,40 +163,19 @@ public class ChangeScanner implements Runnable {
});
}
- private void scanMetaData(MetaData inMem1, MetaData inTemp1, MetaData onDisk) {
- MetaDataChange mdc = new MetaDataChange(inMem1, inTemp1);
- List<String> handledOnDisk = new ArrayList<>();
- // Loop through the metadata entries of the "tmp" database, looking for
- // matches
- for (String key : inTemp1) {
- // See if the key is missing in the disk database:
- List<String> vod = onDisk.getData(key);
- if (vod == null) {
- mdc.insertMetaDataRemoval(key);
- } else {
- // Both exist. Check if they are different:
- List<String> vit = inTemp1.getData(key);
- if (!vod.equals(vit)) {
- mdc.insertMetaDataChange(key, vod);
- }
- // Remember that we've handled this one:
- handledOnDisk.add(key);
+ private void scanMetaData(MetaData inMemory, MetaData onTmp, MetaData onDisk) {
+ if (!onTmp.isEmpty()) {
+ if (!inMemory.equals(onDisk)) {
+ changes.add(new MetaDataChange(inMemory, onDisk));
}
- }
-
- // See if there are unhandled keys in the disk database:
- for (String key : onDisk) {
- if (!handledOnDisk.contains(key)) {
- mdc.insertMetaDataAddition(key, onDisk.getData(key));
+ } else {
+ if (!onDisk.isEmpty() || !onTmp.equals(onDisk)) {
+ changes.add(new MetaDataChange(inMemory, onDisk));
}
}
-
- if (mdc.getChangeCount() > 0) {
- changes.add(mdc);
- }
}
- private void scanEntries(EntrySorter mem, EntrySorter tmp, EntrySorter disk) {
+ private void scanEntries(EntrySorter memorySorter, EntrySorter tmpSorter, EntrySorter diskSorter) {
// Create pointers that are incremented as the entries of each base are used in
// successive order from the beginning. Entries "further down" in the "disk" base
@@ -208,21 +185,21 @@ public class ChangeScanner implements Runnable {
// Create a HashSet where we can put references to entry numbers in the "disk"
// database that we have matched. This is to avoid matching them twice.
- Set<String> used = new HashSet<>(disk.getEntryCount());
- Set<Integer> notMatched = new HashSet<>(tmp.getEntryCount());
+ Set<String> used = new HashSet<>(diskSorter.getEntryCount());
+ Set<Integer> notMatched = new HashSet<>(tmpSorter.getEntryCount());
// Loop through the entries of the "tmp" database, looking for exact matches in the "disk" one.
// We must finish scanning for exact matches before looking for near matches, to avoid an exact
// match being "stolen" from another entry.
mainLoop:
- for (piv1 = 0; piv1 < tmp.getEntryCount(); piv1++) {
+ for (piv1 = 0; piv1 < tmpSorter.getEntryCount(); piv1++) {
// First check if the similarly placed entry in the other base matches exactly.
double comp = -1;
// (if there are not any entries left in the "disk" database, comp will stay at -1,
// and this entry will be marked as nonmatched).
- if (!used.contains(String.valueOf(piv2)) && (piv2 < disk.getEntryCount())) {
- comp = DuplicateCheck.compareEntriesStrictly(tmp.getEntryAt(piv1), disk.getEntryAt(piv2));
+ if (!used.contains(String.valueOf(piv2)) && (piv2 < diskSorter.getEntryCount())) {
+ comp = DuplicateCheck.compareEntriesStrictly(tmpSorter.getEntryAt(piv1), diskSorter.getEntryAt(piv2));
}
if (comp > 1) {
used.add(String.valueOf(piv2));
@@ -231,12 +208,12 @@ public class ChangeScanner implements Runnable {
}
// No? Then check if another entry matches exactly.
- if (piv2 < (disk.getEntryCount() - 1)) {
- for (int i = piv2 + 1; i < disk.getEntryCount(); i++) {
+ if (piv2 < (diskSorter.getEntryCount() - 1)) {
+ for (int i = piv2 + 1; i < diskSorter.getEntryCount(); i++) {
if (used.contains(String.valueOf(i))) {
comp = -1;
} else {
- comp = DuplicateCheck.compareEntriesStrictly(tmp.getEntryAt(piv1), disk.getEntryAt(i));
+ comp = DuplicateCheck.compareEntriesStrictly(tmpSorter.getEntryAt(piv1), diskSorter.getEntryAt(i));
}
if (comp > 1) {
@@ -264,12 +241,12 @@ public class ChangeScanner implements Runnable {
double bestMatch = 0;
double comp;
- if (piv2 < (disk.getEntryCount() - 1)) {
- for (int i = piv2; i < disk.getEntryCount(); i++) {
+ if (piv2 < (diskSorter.getEntryCount() - 1)) {
+ for (int i = piv2; i < diskSorter.getEntryCount(); i++) {
if (used.contains(String.valueOf(i))) {
comp = -1;
} else {
- comp = DuplicateCheck.compareEntriesStrictly(tmp.getEntryAt(piv1), disk.getEntryAt(i));
+ comp = DuplicateCheck.compareEntriesStrictly(tmpSorter.getEntryAt(piv1), diskSorter.getEntryAt(i));
}
if (comp > bestMatch) {
@@ -283,12 +260,11 @@ public class ChangeScanner implements Runnable {
used.add(String.valueOf(bestMatchI));
it.remove();
- EntryChange ec = new EntryChange(bestFit(tmp, mem, piv1), tmp.getEntryAt(piv1),
- disk.getEntryAt(bestMatchI));
- changes.add(ec);
+ changes.add(new EntryChange(bestFit(tmpSorter, memorySorter, piv1), tmpSorter.getEntryAt(piv1),
+ diskSorter.getEntryAt(bestMatchI)));
} else {
- EntryDeleteChange ec = new EntryDeleteChange(bestFit(tmp, mem, piv1), tmp.getEntryAt(piv1));
- changes.add(ec);
+ changes.add(
+ new EntryDeleteChange(bestFit(tmpSorter, memorySorter, piv1), tmpSorter.getEntryAt(piv1)));
}
}
@@ -297,21 +273,20 @@ public class ChangeScanner implements Runnable {
// Finally, look if there are still untouched entries in the disk database. These
// may have been added.
- if (used.size() < disk.getEntryCount()) {
- for (int i = 0; i < disk.getEntryCount(); i++) {
+ if (used.size() < diskSorter.getEntryCount()) {
+ for (int i = 0; i < diskSorter.getEntryCount(); i++) {
if (!used.contains(String.valueOf(i))) {
// See if there is an identical dupe in the mem database:
boolean hasAlready = false;
- for (int j = 0; j < mem.getEntryCount(); j++) {
- if (DuplicateCheck.compareEntriesStrictly(mem.getEntryAt(j), disk.getEntryAt(i)) >= 1) {
+ for (int j = 0; j < memorySorter.getEntryCount(); j++) {
+ if (DuplicateCheck.compareEntriesStrictly(memorySorter.getEntryAt(j), diskSorter.getEntryAt(i)) >= 1) {
hasAlready = true;
break;
}
}
if (!hasAlready) {
- EntryAddChange ec = new EntryAddChange(disk.getEntryAt(i));
- changes.add(ec);
+ changes.add(new EntryAddChange(diskSorter.getEntryAt(i)));
}
}
}
@@ -322,16 +297,16 @@ public class ChangeScanner implements Runnable {
* Finds the entry in neu best fitting the specified entry in old. If no entries get a score
* above zero, an entry is still returned.
*
- * @param old EntrySorter
- * @param neu EntrySorter
+ * @param oldSorter EntrySorter
+ * @param newSorter EntrySorter
* @param index int
* @return BibEntry
*/
- private static BibEntry bestFit(EntrySorter old, EntrySorter neu, int index) {
+ private static BibEntry bestFit(EntrySorter oldSorter, EntrySorter newSorter, int index) {
double comp = -1;
int found = 0;
- for (int i = 0; i < neu.getEntryCount(); i++) {
- double res = DuplicateCheck.compareEntriesStrictly(old.getEntryAt(index), neu.getEntryAt(i));
+ for (int i = 0; i < newSorter.getEntryCount(); i++) {
+ double res = DuplicateCheck.compareEntriesStrictly(oldSorter.getEntryAt(index), newSorter.getEntryAt(i));
if (res > comp) {
comp = res;
found = i;
@@ -340,44 +315,42 @@ public class ChangeScanner implements Runnable {
break;
}
}
- return neu.getEntryAt(found);
+ return newSorter.getEntryAt(found);
}
- private void scanPreamble(BibDatabase inMem1, BibDatabase onTmp, BibDatabase onDisk) {
- String mem = inMem1.getPreamble();
- String tmp = onTmp.getPreamble();
- String disk = onDisk.getPreamble();
- if (tmp == null) {
- if ((disk != null) && !disk.isEmpty()) {
- changes.add(new PreambleChange(mem, disk));
- }
+ private void scanPreamble(BibDatabase inMemory, BibDatabase onTmp, BibDatabase onDisk) {
+ String mem = inMemory.getPreamble().orElse(null);
+ Optional<String> tmp = onTmp.getPreamble();
+ Optional<String> disk = onDisk.getPreamble();
+ if (!tmp.isPresent()) {
+ disk.ifPresent(diskContent -> changes.add(new PreambleChange(mem, diskContent)));
} else {
- if ((disk == null) || !tmp.equals(disk)) {
- changes.add(new PreambleChange(mem, disk));
+ if (!disk.isPresent() || !tmp.equals(disk)) {
+ changes.add(new PreambleChange(mem, disk.orElse(null)));
}
}
}
- private void scanStrings(BibDatabase inMem1, BibDatabase onTmp, BibDatabase onDisk) {
- if (onTmp.hasNoStrings() && onDisk.hasNoStrings()) {
+ private void scanStrings(BibDatabase inMem1, BibDatabase inTmp, BibDatabase onDisk) {
+ if (inTmp.hasNoStrings() && onDisk.hasNoStrings()) {
return;
}
Set<Object> used = new HashSet<>();
Set<Object> usedInMem = new HashSet<>();
- Set<String> notMatched = new HashSet<>(onTmp.getStringCount());
+ Set<String> notMatched = new HashSet<>(inTmp.getStringCount());
// First try to match by string names.
mainLoop:
- for (String key : onTmp.getStringKeySet()) {
- BibtexString tmp = onTmp.getString(key);
+ for (String key : inTmp.getStringKeySet()) {
+ BibtexString tmp = inTmp.getString(key);
for (String diskId : onDisk.getStringKeySet()) {
if (!used.contains(diskId)) {
BibtexString disk = onDisk.getString(diskId);
if (disk.getName().equals(tmp.getName())) {
// We have found a string with a matching name.
- if ((tmp.getContent() != null) && !tmp.getContent().equals(disk.getContent())) {
+ if (!Objects.equals(tmp.getContent(), disk.getContent())) {
// But they have nonmatching contents, so we've found a change.
Optional<BibtexString> mem = findString(inMem1, tmp.getName(), usedInMem);
if (mem.isPresent()) {
@@ -400,7 +373,7 @@ public class ChangeScanner implements Runnable {
// See if we can detect a name change for those entries that we couldn't match.
if (!notMatched.isEmpty()) {
for (Iterator<String> i = notMatched.iterator(); i.hasNext(); ) {
- BibtexString tmp = onTmp.getString(i.next());
+ BibtexString tmp = inTmp.getString(i.next());
// If we get to this point, we found no string with matching name. See if we
// can find one with matching content.
@@ -418,8 +391,8 @@ public class ChangeScanner implements Runnable {
for (String memId : inMem1.getStringKeySet()) {
BibtexString bsMemCandidate = inMem1.getString(memId);
- if (bsMemCandidate.getContent().equals(disk.getContent()) && !usedInMem.contains(
- memId)) {
+ if (bsMemCandidate.getContent().equals(disk.getContent())
+ && !usedInMem.contains(memId)) {
usedInMem.add(memId);
bsMem = bsMemCandidate;
break;
@@ -427,9 +400,8 @@ public class ChangeScanner implements Runnable {
}
if (bsMem != null) {
- changes.add(
- new StringNameChange(bsMem, tmp, bsMem.getName(), tmp.getName(), disk.getName(),
- tmp.getContent()));
+ changes.add(new StringNameChange(bsMem, tmp, bsMem.getName(), tmp.getName(),
+ disk.getName(), tmp.getContent()));
i.remove();
used.add(diskId);
}
@@ -442,8 +414,8 @@ public class ChangeScanner implements Runnable {
if (!notMatched.isEmpty()) {
// Still one or more non-matched strings. So they must have been removed.
- for (String nmId : notMatched) {
- BibtexString tmp = onTmp.getString(nmId);
+ for (String notMatchedId : notMatched) {
+ BibtexString tmp = inTmp.getString(notMatchedId);
// The removed string is not removed from the mem version.
findString(inMem1, tmp.getName(), usedInMem).ifPresent(
x -> changes.add(new StringRemoveChange(tmp, tmp, x)));
@@ -479,18 +451,19 @@ public class ChangeScanner implements Runnable {
* This method only detects whether a change took place or not. It does not determine the type of change. This would
* be possible, but difficult to do properly, so I rather only report the change.
*/
- private void scanGroups(MetaData onTmp, MetaData onDisk) {
- final GroupTreeNode groupsTmp = onTmp.getGroups();
- final GroupTreeNode groupsDisk = onDisk.getGroups();
- if ((groupsTmp == null) && (groupsDisk == null)) {
+ private void scanGroups(MetaData inTemp, MetaData onDisk) {
+ final Optional<GroupTreeNode> groupsTmp = inTemp.getGroups();
+ final Optional<GroupTreeNode> groupsDisk = onDisk.getGroups();
+ if (!groupsTmp.isPresent() && !groupsDisk.isPresent()) {
return;
}
- if (((groupsTmp != null) && (groupsDisk == null)) || (groupsTmp == null)) {
- changes.add(new GroupChange(groupsDisk, groupsTmp));
+ if ((groupsTmp.isPresent() && !groupsDisk.isPresent()) || !groupsTmp.isPresent()) {
+ changes.add(new GroupChange(groupsDisk.orElse(null), groupsTmp.orElse(null)));
return;
}
+ // Both present here
if (!groupsTmp.equals(groupsDisk)) {
- changes.add(new GroupChange(groupsDisk, groupsTmp));
+ changes.add(new GroupChange(groupsDisk.get(), groupsTmp.get()));
}
}
diff --git a/src/main/java/net/sf/jabref/collab/EntryAddChange.java b/src/main/java/net/sf/jabref/collab/EntryAddChange.java
index f4dddb6..a0a79a1 100644
--- a/src/main/java/net/sf/jabref/collab/EntryAddChange.java
+++ b/src/main/java/net/sf/jabref/collab/EntryAddChange.java
@@ -3,7 +3,6 @@ package net.sf.jabref.collab;
import javax.swing.JComponent;
import javax.swing.JScrollPane;
-import net.sf.jabref.Globals;
import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.gui.PreviewPanel;
import net.sf.jabref.gui.undo.NamedCompound;
@@ -12,7 +11,6 @@ import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.model.database.BibDatabase;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.IdGenerator;
-import net.sf.jabref.preferences.JabRefPreferences;
class EntryAddChange extends Change {
@@ -24,7 +22,7 @@ class EntryAddChange extends Change {
super(Localization.lang("Added entry"));
this.diskEntry = diskEntry;
- PreviewPanel pp = new PreviewPanel(null, diskEntry, null, Globals.prefs.get(JabRefPreferences.PREVIEW_0));
+ PreviewPanel pp = new PreviewPanel(null, diskEntry, null);
sp = new JScrollPane(pp);
}
diff --git a/src/main/java/net/sf/jabref/collab/EntryChange.java b/src/main/java/net/sf/jabref/collab/EntryChange.java
index 0bddca7..17e2998 100644
--- a/src/main/java/net/sf/jabref/collab/EntryChange.java
+++ b/src/main/java/net/sf/jabref/collab/EntryChange.java
@@ -51,19 +51,21 @@ class EntryChange extends Change {
allFields.addAll(diskEntry.getFieldNames());
for (String field : allFields) {
- String mem = memEntry.getField(field);
- String tmp = tmpEntry.getField(field);
- String disk = diskEntry.getField(field);
+ Optional<String> mem = memEntry.getField(field);
+ Optional<String> tmp = tmpEntry.getField(field);
+ Optional<String> disk = diskEntry.getField(field);
- if ((tmp != null) && (disk != null)) {
+ if ((tmp.isPresent()) && (disk.isPresent())) {
if (!tmp.equals(disk)) {
// Modified externally.
- add(new FieldChange(field, memEntry, tmpEntry, mem, tmp, disk));
+ add(new FieldChange(field, memEntry, tmpEntry, mem.orElse(null), tmp.get(), disk.get()));
}
- } else if (((tmp == null) && (disk != null) && !disk.isEmpty()) || ((disk == null) && (tmp != null) && !tmp.isEmpty()
- && (mem != null) && !mem.isEmpty())) {
+ } else if (((!tmp.isPresent()) && (disk.isPresent()) && !disk.get().isEmpty())
+ || ((!disk.isPresent()) && (tmp.isPresent()) && !tmp.get().isEmpty()
+ && (mem.isPresent()) && !mem.get().isEmpty())) {
// Added externally.
- add(new FieldChange(field, memEntry, tmpEntry, mem, tmp, disk));
+ add(new FieldChange(field, memEntry, tmpEntry, mem.orElse(null), tmp.orElse(null),
+ disk.orElse(null)));
}
}
}
diff --git a/src/main/java/net/sf/jabref/collab/EntryDeleteChange.java b/src/main/java/net/sf/jabref/collab/EntryDeleteChange.java
index 5b925c3..7d8a422 100644
--- a/src/main/java/net/sf/jabref/collab/EntryDeleteChange.java
+++ b/src/main/java/net/sf/jabref/collab/EntryDeleteChange.java
@@ -3,7 +3,6 @@ package net.sf.jabref.collab;
import javax.swing.JComponent;
import javax.swing.JScrollPane;
-import net.sf.jabref.Globals;
import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.gui.PreviewPanel;
import net.sf.jabref.gui.undo.NamedCompound;
@@ -12,7 +11,6 @@ import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.model.DuplicateCheck;
import net.sf.jabref.model.database.BibDatabase;
import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.preferences.JabRefPreferences;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -41,7 +39,7 @@ class EntryDeleteChange extends Change {
LOGGER.debug("Modified entry: " + memEntry.getCiteKeyOptional().orElse("<no BibTeX key set>")
+ "\n Modified locally: " + isModifiedLocally);
- PreviewPanel pp = new PreviewPanel(null, memEntry, null, Globals.prefs.get(JabRefPreferences.PREVIEW_0));
+ PreviewPanel pp = new PreviewPanel(null, memEntry, null);
sp = new JScrollPane(pp);
}
diff --git a/src/main/java/net/sf/jabref/collab/FileUpdateMonitor.java b/src/main/java/net/sf/jabref/collab/FileUpdateMonitor.java
index baf273d..47d2242 100644
--- a/src/main/java/net/sf/jabref/collab/FileUpdateMonitor.java
+++ b/src/main/java/net/sf/jabref/collab/FileUpdateMonitor.java
@@ -60,7 +60,7 @@ public class FileUpdateMonitor implements Runnable {
}
numberOfUpdateListener++;
String key = String.valueOf(numberOfUpdateListener);
- entries.put(key, new Entry(ul, file));
+ entries.put(key, new Entry(ul, file.toPath()));
return key;
}
@@ -106,7 +106,11 @@ public class FileUpdateMonitor implements Runnable {
public void updateTimeStamp(String key) {
Entry entry = entries.get(key);
if (entry != null) {
- entry.updateTimeStamp();
+ try {
+ entry.updateTimeStamp();
+ } catch (IOException e) {
+ LOGGER.error("Couldn't update timestamp", e);
+ }
}
}
@@ -132,17 +136,17 @@ public class FileUpdateMonitor implements Runnable {
static class Entry {
private final FileUpdateListener listener;
- private final File file;
+ private final Path file;
private final Path tmpFile;
private long timeStamp;
private long fileSize;
- public Entry(FileUpdateListener ul, File f) {
+ public Entry(FileUpdateListener ul, Path f) throws IOException {
listener = ul;
file = f;
- timeStamp = file.lastModified();
- fileSize = file.length();
+ timeStamp = Files.getLastModifiedTime(file).toMillis();
+ fileSize = Files.size(file);
tmpFile = FileUpdateMonitor.getTempFile();
if (tmpFile != null) {
tmpFile.toFile().deleteOnExit();
@@ -156,42 +160,37 @@ public class FileUpdateMonitor implements Runnable {
* @return boolean true if the file has changed.
*/
public boolean hasBeenUpdated() throws IOException {
- long modified = file.lastModified();
+ long modified = Files.getLastModifiedTime(file).toMillis();
if (modified == 0L) {
throw new IOException("File deleted");
}
- long fileSizeNow = file.length();
+ long fileSizeNow = Files.size(file);
return (timeStamp != modified) || (fileSize != fileSizeNow);
}
- public void updateTimeStamp() {
- timeStamp = file.lastModified();
+ public void updateTimeStamp() throws IOException {
+ timeStamp = Files.getLastModifiedTime(file).toMillis();
if (timeStamp == 0L) {
notifyFileRemoved();
}
- fileSize = file.length();
+ fileSize = Files.size(file);
copy();
}
public boolean copy() {
- boolean res = false;
- try {
- res = FileUtil.copyFile(file, tmpFile.toFile(), true);
- } catch (IOException ex) {
- LOGGER.info("Cannot copy to temporary file '" + tmpFile + '\'', ex);
- }
- return res;
+ return FileUtil.copyFile(file, tmpFile, true);
+
}
/**
* Call the listener method to signal that the file has changed.
*/
- public void notifyListener() {
+ public void notifyListener() throws IOException {
// Update time stamp.
- timeStamp = file.lastModified();
- fileSize = file.length();
+ timeStamp = Files.getLastModifiedTime(file).toMillis();
+ fileSize = Files.size(file);
listener.fileUpdated();
}
diff --git a/src/main/java/net/sf/jabref/collab/FileUpdatePanel.java b/src/main/java/net/sf/jabref/collab/FileUpdatePanel.java
index 2d2ce42..2694d32 100644
--- a/src/main/java/net/sf/jabref/collab/FileUpdatePanel.java
+++ b/src/main/java/net/sf/jabref/collab/FileUpdatePanel.java
@@ -17,10 +17,7 @@ import net.sf.jabref.gui.SidePaneComponent;
import net.sf.jabref.gui.SidePaneManager;
import net.sf.jabref.logic.l10n.Localization;
-public class FileUpdatePanel extends SidePaneComponent implements ActionListener,
- ChangeScanner.DisplayResultCallback {
-
- public static final String NAME = "fileUpdate";
+public class FileUpdatePanel extends SidePaneComponent implements ActionListener, ChangeScanner.DisplayResultCallback {
private final SidePaneManager manager;
@@ -65,7 +62,7 @@ public class FileUpdatePanel extends SidePaneComponent implements ActionListener
*/
@Override
public void componentClosing() {
- manager.unregisterComponent(FileUpdatePanel.NAME);
+ manager.unregisterComponent(FileUpdatePanel.class);
}
@Override
@@ -73,6 +70,11 @@ public class FileUpdatePanel extends SidePaneComponent implements ActionListener
return 0;
}
+ @Override
+ public ToggleAction getToggleAction() {
+ throw new UnsupportedOperationException();
+ }
+
/**
* actionPerformed
*
diff --git a/src/main/java/net/sf/jabref/collab/GroupChange.java b/src/main/java/net/sf/jabref/collab/GroupChange.java
index 31d11c0..e15c722 100644
--- a/src/main/java/net/sf/jabref/collab/GroupChange.java
+++ b/src/main/java/net/sf/jabref/collab/GroupChange.java
@@ -7,10 +7,10 @@ import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.gui.groups.GroupTreeNodeViewModel;
import net.sf.jabref.gui.groups.UndoableModifySubtree;
import net.sf.jabref.gui.undo.NamedCompound;
-import net.sf.jabref.logic.groups.AllEntriesGroup;
-import net.sf.jabref.logic.groups.GroupTreeNode;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.model.database.BibDatabase;
+import net.sf.jabref.model.groups.AllEntriesGroup;
+import net.sf.jabref.model.groups.GroupTreeNode;
class GroupChange extends Change {
@@ -27,14 +27,14 @@ class GroupChange extends Change {
@Override
public boolean makeChange(BasePanel panel, BibDatabase secondary, NamedCompound undoEdit) {
- final GroupTreeNode root = panel.getBibDatabaseContext().getMetaData().getGroups();
+ final GroupTreeNode root = panel.getBibDatabaseContext().getMetaData().getGroups().orElse(null);
final UndoableModifySubtree undo = new UndoableModifySubtree(
- new GroupTreeNodeViewModel(panel.getBibDatabaseContext().getMetaData().getGroups()),
+ new GroupTreeNodeViewModel(panel.getBibDatabaseContext().getMetaData().getGroups().orElse(null)),
new GroupTreeNodeViewModel(root), Localization.lang("Modified groups"));
root.removeAllChildren();
if (changedGroups == null) {
// I think setting root to null is not possible
- root.setGroup(new AllEntriesGroup());
+ root.setGroup(new AllEntriesGroup(Localization.lang("All entries")));
} else {
// change root group, even though it'll be AllEntries anyway
root.setGroup(changedGroups.getGroup());
diff --git a/src/main/java/net/sf/jabref/collab/MetaDataChange.java b/src/main/java/net/sf/jabref/collab/MetaDataChange.java
index 1d4ba55..563a578 100644
--- a/src/main/java/net/sf/jabref/collab/MetaDataChange.java
+++ b/src/main/java/net/sf/jabref/collab/MetaDataChange.java
@@ -1,122 +1,49 @@
package net.sf.jabref.collab;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.stream.Collectors;
-
import javax.swing.JComponent;
import javax.swing.JScrollPane;
-import net.sf.jabref.MetaData;
import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.gui.undo.NamedCompound;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.model.database.BibDatabase;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
+import net.sf.jabref.model.metadata.MetaData;
/**
*
*/
class MetaDataChange extends Change {
- private static final int ADD = 1;
- private static final int REMOVE = 2;
- private static final int MODIFY = 3;
-
- private final InfoPane tp = new InfoPane();
- private final JScrollPane sp = new JScrollPane(tp);
- private final MetaData md;
- private final MetaData mdSecondary;
- private final List<MetaDataChangeUnit> changes = new ArrayList<>();
+ private final InfoPane infoPane = new InfoPane();
+ private final JScrollPane sp = new JScrollPane(infoPane);
+ private final MetaData originalMetaData;
+ private final MetaData newMetaData;
- private static final Log LOGGER = LogFactory.getLog(MetaDataChange.class);
-
-
- public MetaDataChange(MetaData md, MetaData mdSecondary) {
+ public MetaDataChange(MetaData originalMetaData, MetaData newMetaData) {
super(Localization.lang("Metadata change"));
- this.md = md;
- this.mdSecondary = mdSecondary;
-
- tp.setText("<html>" + Localization.lang("Metadata change") + "</html>");
- }
-
- public int getChangeCount() {
- return changes.size();
- }
-
- public void insertMetaDataAddition(String key, List<String> value) {
- changes.add(new MetaDataChangeUnit(MetaDataChange.ADD, key, value));
- }
+ this.originalMetaData = originalMetaData;
+ this.newMetaData = newMetaData;
- public void insertMetaDataRemoval(String key) {
- changes.add(new MetaDataChangeUnit(MetaDataChange.REMOVE, key, null));
- }
-
- public void insertMetaDataChange(String key, List<String> value) {
- changes.add(new MetaDataChangeUnit(MetaDataChange.MODIFY, key, value));
+ infoPane.setText("<html>" + Localization.lang("Metadata change") + "</html>");
}
@Override
public JComponent description() {
+ /*
+ // TODO: Show detailed description of the changes
StringBuilder sb = new StringBuilder(
"<html>" + Localization.lang("Changes have been made to the following metadata elements")
+ ":<p><br> ");
sb.append(changes.stream().map(unit -> unit.key).collect(Collectors.joining("<br> ")));
sb.append("</html>");
- tp.setText(sb.toString());
+ infoPane.setText(sb.toString());
+ */
return sp;
}
@Override
public boolean makeChange(BasePanel panel, BibDatabase secondary, NamedCompound undoEdit) {
- for (MetaDataChangeUnit unit : changes) {
- switch (unit.getType()) {
- case ADD:
- md.putData(unit.getKey(), unit.getValue());
- mdSecondary.putData(unit.getKey(), unit.getValue());
- break;
- case REMOVE:
- md.remove(unit.getKey());
- mdSecondary.remove(unit.getKey());
- break;
- case MODIFY:
- md.putData(unit.getKey(), unit.getValue());
- mdSecondary.putData(unit.getKey(), unit.getValue());
- break;
- default:
- LOGGER.error("Undefined meta data change unit type");
- break;
- }
- }
+ panel.getBibDatabaseContext().setMetaData(newMetaData);
return true;
}
-
-
- static class MetaDataChangeUnit {
-
- private final int type;
- private final String key;
- private final List<String> value;
-
-
- public MetaDataChangeUnit(int type, String key, List<String> value) {
- this.type = type;
- this.key = key;
- this.value = value;
- }
-
- public int getType() {
- return type;
- }
-
- public String getKey() {
- return key;
- }
-
- public List<String> getValue() {
- return value;
- }
- }
}
diff --git a/src/main/java/net/sf/jabref/event/GroupUpdatedEvent.java b/src/main/java/net/sf/jabref/event/GroupUpdatedEvent.java
deleted file mode 100644
index 8b44b78..0000000
--- a/src/main/java/net/sf/jabref/event/GroupUpdatedEvent.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package net.sf.jabref.event;
-
-import net.sf.jabref.MetaData;
-
-public class GroupUpdatedEvent {
-
- private final MetaData metaData;
-
- /**
- * @param metaData Affected instance
- */
- public GroupUpdatedEvent(MetaData metaData) {
- this.metaData = metaData;
- }
-
- public MetaData getMetaData() {
- return this.metaData;
- }
-}
diff --git a/src/main/java/net/sf/jabref/event/MetaDataChangedEvent.java b/src/main/java/net/sf/jabref/event/MetaDataChangedEvent.java
deleted file mode 100644
index 7a3c249..0000000
--- a/src/main/java/net/sf/jabref/event/MetaDataChangedEvent.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package net.sf.jabref.event;
-
-import net.sf.jabref.MetaData;
-
-/**
- * {@link MetaDataChangedEvent} is fired when a tuple of meta data has been put or removed.
- */
-public class MetaDataChangedEvent {
-
- private final MetaData metaData;
-
- /**
- * @param metaData Affected instance
- */
- public MetaDataChangedEvent(MetaData metaData) {
- this.metaData = metaData;
- }
-
- public MetaData getMetaData() {
- return this.metaData;
- }
-}
diff --git a/src/main/java/net/sf/jabref/event/source/EntryEventSource.java b/src/main/java/net/sf/jabref/event/source/EntryEventSource.java
deleted file mode 100644
index ceb2ba4..0000000
--- a/src/main/java/net/sf/jabref/event/source/EntryEventSource.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package net.sf.jabref.event.source;
-
-/**
- * This enum represents the context EntryEvents were sent from.
- */
-public enum EntryEventSource {
- LOCAL,
- SHARED,
- UNDO,
- SAVE_ACTION
-}
diff --git a/src/main/java/net/sf/jabref/external/AttachFileAction.java b/src/main/java/net/sf/jabref/external/AttachFileAction.java
deleted file mode 100644
index 8429df5..0000000
--- a/src/main/java/net/sf/jabref/external/AttachFileAction.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package net.sf.jabref.external;
-
-import net.sf.jabref.gui.BasePanel;
-import net.sf.jabref.gui.FileListEntry;
-import net.sf.jabref.gui.FileListEntryEditor;
-import net.sf.jabref.gui.FileListTableModel;
-import net.sf.jabref.gui.actions.BaseAction;
-import net.sf.jabref.gui.undo.UndoableFieldChange;
-import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.model.entry.FieldName;
-
-/**
- * Created by IntelliJ IDEA.
- * User: alver
- * Date: 5/24/12
- * Time: 8:48 PM
- * To change this template use File | Settings | File Templates.
- */
-public class AttachFileAction implements BaseAction {
-
- private final BasePanel panel;
-
-
- public AttachFileAction(BasePanel panel) {
- this.panel = panel;
- }
-
- @Override
- public void action() {
- if (panel.getSelectedEntries().size() != 1) {
- panel.output(Localization.lang("This operation requires exactly one item to be selected."));
- return;
- }
- BibEntry entry = panel.getSelectedEntries().get(0);
- FileListEntry flEntry = new FileListEntry("", "");
- FileListEntryEditor editor = new FileListEntryEditor(panel.frame(), flEntry, false, true,
- panel.getBibDatabaseContext());
- editor.setVisible(true, true);
- if (editor.okPressed()) {
- FileListTableModel model = new FileListTableModel();
- entry.getFieldOptional(FieldName.FILE).ifPresent(model::setContent);
- model.addEntry(model.getRowCount(), flEntry);
- String newVal = model.getStringRepresentation();
-
- UndoableFieldChange ce = new UndoableFieldChange(entry, FieldName.FILE,
- entry.getFieldOptional(FieldName.FILE).orElse(null), newVal);
- entry.setField(FieldName.FILE, newVal);
- panel.getUndoManager().addEdit(ce);
- panel.markBaseChanged();
- }
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/external/AutoSetLinks.java b/src/main/java/net/sf/jabref/external/AutoSetLinks.java
deleted file mode 100644
index 57fd67e..0000000
--- a/src/main/java/net/sf/jabref/external/AutoSetLinks.java
+++ /dev/null
@@ -1,222 +0,0 @@
-package net.sf.jabref.external;
-
-import java.awt.BorderLayout;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Optional;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-import javax.swing.BorderFactory;
-import javax.swing.JDialog;
-import javax.swing.JLabel;
-import javax.swing.JProgressBar;
-import javax.swing.SwingUtilities;
-
-import net.sf.jabref.BibDatabaseContext;
-import net.sf.jabref.Globals;
-import net.sf.jabref.gui.FileListEntry;
-import net.sf.jabref.gui.FileListTableModel;
-import net.sf.jabref.gui.undo.NamedCompound;
-import net.sf.jabref.gui.undo.UndoableFieldChange;
-import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.logic.util.io.FileUtil;
-import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.model.entry.FieldName;
-import net.sf.jabref.preferences.JabRefPreferences;
-
-public class AutoSetLinks {
-
- /**
- * Shortcut method if links are set without using the GUI
- *
- * @param entries the entries for which links should be set
- * @param databaseContext the database for which links are set
- */
- public static void autoSetLinks(List<BibEntry> entries, BibDatabaseContext databaseContext) {
- autoSetLinks(entries, null, null, null, databaseContext, null, null);
- }
-
- /**
- * Automatically add links for this set of entries, based on the globally stored list of external file types. The
- * entries are modified, and corresponding UndoEdit elements added to the NamedCompound given as argument.
- * Furthermore, all entries which are modified are added to the Set of entries given as an argument.
- * <p>
- * The entries' bibtex keys must have been set - entries lacking key are ignored. The operation is done in a new
- * thread, which is returned for the caller to wait for if needed.
- *
- * @param entries A collection of BibEntry objects to find links for.
- * @param ce A NamedCompound to add UndoEdit elements to.
- * @param changedEntries MODIFIED, optional. A Set of BibEntry objects to which all modified entries is added.
- * This is used for status output and debugging
- * @param singleTableModel UGLY HACK. The table model to insert links into. Already existing links are not
- * duplicated or removed. This parameter has to be null if entries.count() != 1. The hack has been
- * introduced as a bibtexentry does not (yet) support the function getListTableModel() and the
- * FileListEntryEditor editor holds an instance of that table model and does not reconstruct it after the
- * search has succeeded.
- * @param databaseContext The database providing the relevant file directory, if any.
- * @param callback An ActionListener that is notified (on the event dispatch thread) when the search is finished.
- * The ActionEvent has id=0 if no new links were added, and id=1 if one or more links were added. This
- * parameter can be null, which means that no callback will be notified.
- * @param diag An instantiated modal JDialog which will be used to display the progress of the automatically setting. This
- * parameter can be null, which means that no progress update will be shown.
- * @return the thread performing the automatically setting
- */
- public static Runnable autoSetLinks(final List<BibEntry> entries, final NamedCompound ce,
- final Set<BibEntry> changedEntries, final FileListTableModel singleTableModel,
- final BibDatabaseContext databaseContext, final ActionListener callback, final JDialog diag) {
- final Collection<ExternalFileType> types = ExternalFileTypes.getInstance().getExternalFileTypeSelection();
- if (diag != null) {
- final JProgressBar prog = new JProgressBar(JProgressBar.HORIZONTAL, 0, types.size() - 1);
- final JLabel label = new JLabel(Localization.lang("Searching for files"));
- prog.setIndeterminate(true);
- prog.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
- diag.setTitle(Localization.lang("Automatically setting file links"));
- diag.getContentPane().add(prog, BorderLayout.CENTER);
- diag.getContentPane().add(label, BorderLayout.SOUTH);
-
- diag.pack();
- diag.setLocationRelativeTo(diag.getParent());
- }
-
- Runnable r = new Runnable() {
-
- @Override
- public void run() {
- // determine directories to search in
- List<File> dirs = new ArrayList<>();
- List<String> dirsS = databaseContext.getFileDirectory();
- dirs.addAll(dirsS.stream().map(File::new).collect(Collectors.toList()));
-
- // determine extensions
- List<String> extensions = new ArrayList<>();
- for (final ExternalFileType type : types) {
- extensions.add(type.getExtension());
- }
-
- // Run the search operation:
- Map<BibEntry, List<File>> result;
- if (Globals.prefs.getBoolean(JabRefPreferences.AUTOLINK_USE_REG_EXP_SEARCH_KEY)) {
- String regExp = Globals.prefs.get(JabRefPreferences.REG_EXP_SEARCH_EXPRESSION_KEY);
- result = RegExpFileSearch.findFilesForSet(entries, extensions, dirs, regExp);
- } else {
- boolean autoLinkExactKeyOnly = Globals.prefs.getBoolean(JabRefPreferences.AUTOLINK_EXACT_KEY_ONLY);
- result = FileUtil.findAssociatedFiles(entries, extensions, dirs, autoLinkExactKeyOnly);
- }
-
- boolean foundAny = false;
- // Iterate over the entries:
- for (Entry<BibEntry, List<File>> entryFilePair : result.entrySet()) {
- FileListTableModel tableModel;
- Optional<String> oldVal = entryFilePair.getKey().getFieldOptional(FieldName.FILE);
- if (singleTableModel == null) {
- tableModel = new FileListTableModel();
- oldVal.ifPresent(tableModel::setContent);
- } else {
- assert entries.size() == 1;
- tableModel = singleTableModel;
- }
- List<File> files = entryFilePair.getValue();
- for (File f : files) {
- f = FileUtil.shortenFileName(f, dirsS);
- boolean alreadyHas = false;
- //System.out.println("File: "+f.getPath());
- for (int j = 0; j < tableModel.getRowCount(); j++) {
- FileListEntry existingEntry = tableModel.getEntry(j);
- //System.out.println("Comp: "+existingEntry.getLink());
- if (new File(existingEntry.link).equals(f)) {
- alreadyHas = true;
- foundAny = true;
- break;
- }
- }
- if (!alreadyHas) {
- foundAny = true;
- Optional<ExternalFileType> type;
- Optional<String> extension = FileUtil.getFileExtension(f);
- if (extension.isPresent()) {
- type = ExternalFileTypes.getInstance().getExternalFileTypeByExt(extension.get());
- } else {
- type = Optional.of(new UnknownExternalFileType(""));
- }
- FileListEntry flEntry = new FileListEntry(f.getName(), f.getPath(), type);
- tableModel.addEntry(tableModel.getRowCount(), flEntry);
-
- String newVal = tableModel.getStringRepresentation();
- if (newVal.isEmpty()) {
- newVal = null;
- }
- if (ce != null) {
- // store undo information
- UndoableFieldChange change = new UndoableFieldChange(entryFilePair.getKey(),
- FieldName.FILE, oldVal.orElse(null), newVal);
- ce.addEdit(change);
- }
- // hack: if table model is given, do NOT modify entry
- if (singleTableModel == null) {
- entryFilePair.getKey().setField(FieldName.FILE, newVal);
- }
- if (changedEntries != null) {
- changedEntries.add(entryFilePair.getKey());
- }
- }
- }
- }
-
- // handle callbacks and dialog
- // FIXME: The ID signals if action was successful :/
- final int id = foundAny ? 1 : 0;
- SwingUtilities.invokeLater(new Runnable() {
-
- @Override
- public void run() {
- if (diag != null) {
- diag.dispose();
- }
- if (callback != null) {
- callback.actionPerformed(new ActionEvent(this, id, ""));
- }
- }
- });
- }
- };
- SwingUtilities.invokeLater(() -> {
- // show dialog which will be hidden when the task is done
- if (diag != null) {
- diag.setVisible(true);
- }
- });
- return r;
- }
-
- /**
- * Automatically add links for this entry to the table model given as an argument, based on the globally stored list
- * of external file types. The entry itself is not modified. The entry's bibtex key must have been set.
- *
- * @param entry The BibEntry to find links for.
- * @param singleTableModel The table model to insert links into. Already existing links are not duplicated or
- * removed.
- * @param databaseContext The database providing the relevant file directory, if any.
- * @param callback An ActionListener that is notified (on the event dispatch thread) when the search is finished.
- * The ActionEvent has id=0 if no new links were added, and id=1 if one or more links were added. This
- * parameter can be null, which means that no callback will be notified. The passed ActionEvent is
- * constructed with (this, id, ""), where id is 1 if something has been done and 0 if nothing has been
- * done.
- * @param diag An instantiated modal JDialog which will be used to display the progress of the automatically setting. This
- * parameter can be null, which means that no progress update will be shown.
- * @return the runnable able to perform the automatically setting
- */
- public static Runnable autoSetLinks(final BibEntry entry, final FileListTableModel singleTableModel,
- final BibDatabaseContext databaseContext, final ActionListener callback, final JDialog diag) {
- return autoSetLinks(Collections.singletonList(entry), null, null, singleTableModel, databaseContext, callback,
- diag);
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/external/ConfirmCloseFileListEntryEditor.java b/src/main/java/net/sf/jabref/external/ConfirmCloseFileListEntryEditor.java
deleted file mode 100644
index 6b208ed..0000000
--- a/src/main/java/net/sf/jabref/external/ConfirmCloseFileListEntryEditor.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package net.sf.jabref.external;
-
-import net.sf.jabref.gui.FileListEntry;
-
-/**
- * An implementation of this interface is called to confirm whether a FileListEntryEditor
- * is ready to close when Ok is pressed, or whether there is a problem that needs to be
- * resolved first.
- */
- at FunctionalInterface
-public interface ConfirmCloseFileListEntryEditor {
-
- boolean confirmClose(FileListEntry entry);
-}
diff --git a/src/main/java/net/sf/jabref/external/DownloadExternalFile.java b/src/main/java/net/sf/jabref/external/DownloadExternalFile.java
deleted file mode 100644
index 812a6c2..0000000
--- a/src/main/java/net/sf/jabref/external/DownloadExternalFile.java
+++ /dev/null
@@ -1,349 +0,0 @@
-package net.sf.jabref.external;
-
-import java.io.File;
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.List;
-import java.util.Optional;
-
-import javax.swing.JOptionPane;
-import javax.swing.SwingUtilities;
-
-import net.sf.jabref.BibDatabaseContext;
-import net.sf.jabref.Globals;
-import net.sf.jabref.JabRefExecutorService;
-import net.sf.jabref.gui.FileListEntry;
-import net.sf.jabref.gui.FileListEntryEditor;
-import net.sf.jabref.gui.JabRefFrame;
-import net.sf.jabref.gui.net.MonitoredURLDownload;
-import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.logic.layout.LayoutFormatterPreferences;
-import net.sf.jabref.logic.net.URLDownload;
-import net.sf.jabref.logic.util.OS;
-import net.sf.jabref.logic.util.io.FileUtil;
-import net.sf.jabref.preferences.JabRefPreferences;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * This class handles the download of an external file. Typically called when the user clicks
- * the "Download" button in a FileListEditor shown in an EntryEditor.
- * <p/>
- * The FileListEditor constructs the DownloadExternalFile instance, then calls the download()
- * method passing a reference to itself as a callback. The download() method asks for the URL,
- * then starts the download. When the download is completed, it calls the downloadCompleted()
- * method on the callback FileListEditor, which then needs to take care of linking to the file.
- * The local filename is passed as an argument to the downloadCompleted() method.
- * <p/>
- * If the download is canceled, or failed, the user is informed. The callback is never called.
- */
-public class DownloadExternalFile {
- private static final Log LOGGER = LogFactory.getLog(DownloadExternalFile.class);
-
- private final JabRefFrame frame;
- private final BibDatabaseContext databaseContext;
- private final String bibtexKey;
- private FileListEntryEditor editor;
- private boolean downloadFinished;
- private boolean dontShowDialog;
-
- public DownloadExternalFile(JabRefFrame frame, BibDatabaseContext databaseContext, String bibtexKey) {
- this.frame = frame;
- this.databaseContext = databaseContext;
- this.bibtexKey = bibtexKey;
- }
-
- /**
- * Start a download.
- *
- * @param callback The object to which the filename should be reported when download
- * is complete.
- */
- public void download(final DownloadCallback callback) throws IOException {
- dontShowDialog = false;
- final String res = JOptionPane.showInputDialog(frame, Localization.lang("Enter URL to download"));
-
- if ((res == null) || res.trim().isEmpty()) {
- return;
- }
-
- URL url;
- try {
- url = new URL(res);
- } catch (MalformedURLException ex1) {
- JOptionPane.showMessageDialog(frame, Localization.lang("Invalid URL"),
- Localization.lang("Download file"), JOptionPane.ERROR_MESSAGE);
- return;
- }
-
- download(url, callback);
- }
-
- /**
- * Start a download.
- *
- * @param callback The object to which the filename should be reported when download
- * is complete.
- */
- public void download(URL url, final DownloadCallback callback) throws IOException {
- String res = url.toString();
- String mimeType;
-
- // First of all, start the download itself in the background to a temporary file:
- final File tmp = File.createTempFile("jabref_download", "tmp");
- tmp.deleteOnExit();
-
- URLDownload udl = MonitoredURLDownload.buildMonitoredDownload(frame, url);
-
- try {
- // TODO: what if this takes long time?
- // TODO: stop editor dialog if this results in an error:
- mimeType = udl.determineMimeType(); // Read MIME type
- } catch (IOException ex) {
- JOptionPane.showMessageDialog(frame, Localization.lang("Invalid URL") + ": "
- + ex.getMessage(), Localization.lang("Download file"),
- JOptionPane.ERROR_MESSAGE);
- LOGGER.info("Error while downloading " + "'" + res + "'", ex);
- return;
- }
- final URL urlF = url;
- final URLDownload udlF = udl;
-
- JabRefExecutorService.INSTANCE.execute(() -> {
- try {
- udlF.downloadToFile(tmp);
- } catch (IOException e2) {
- dontShowDialog = true;
- if ((editor != null) && editor.isVisible()) {
- editor.setVisible(false, false);
- }
- JOptionPane.showMessageDialog(frame, Localization.lang("Invalid URL") + ": " + e2.getMessage(),
- Localization.lang("Download file"), JOptionPane.ERROR_MESSAGE);
- LOGGER.info("Error while downloading " + "'" + urlF + "'", e2);
- return;
- }
- // Download finished: call the method that stops the progress bar etc.:
- SwingUtilities.invokeLater(DownloadExternalFile.this::downloadFinished);
- });
-
- Optional<ExternalFileType> suggestedType = Optional.empty();
- if (mimeType != null) {
- LOGGER.debug("MIME Type suggested: " + mimeType);
- suggestedType = ExternalFileTypes.getInstance().getExternalFileTypeByMimeType(mimeType);
- }
- // Then, while the download is proceeding, let the user choose the details of the file:
- String suffix;
- if (suggestedType.isPresent()) {
- suffix = suggestedType.get().getExtension();
- } else {
- // If we did not find a file type from the MIME type, try based on extension:
- suffix = getSuffix(res);
- if (suffix == null) {
- suffix = "";
- }
- suggestedType = ExternalFileTypes.getInstance().getExternalFileTypeByExt(suffix);
- }
-
- String suggestedName = getSuggestedFileName(suffix);
- List<String> fDirectory = databaseContext.getFileDirectory();
- String directory;
- if (fDirectory.isEmpty()) {
- directory = null;
- } else {
- directory = fDirectory.get(0);
- }
- final String suggestDir = directory == null ? System.getProperty("user.home") : directory;
- File file = new File(new File(suggestDir), suggestedName);
- FileListEntry entry = new FileListEntry("", file.getCanonicalPath(), suggestedType);
- editor = new FileListEntryEditor(frame, entry, true, false, databaseContext);
- editor.getProgressBar().setIndeterminate(true);
- editor.setOkEnabled(false);
- editor.setExternalConfirm(closeEntry -> {
- File f = directory == null ? new File(closeEntry.link) : expandFilename(directory, closeEntry.link);
- if (f.isDirectory()) {
- JOptionPane.showMessageDialog(frame, Localization.lang("Target file cannot be a directory."),
- Localization.lang("Download file"), JOptionPane.ERROR_MESSAGE);
- return false;
- }
- if (f.exists()) {
- return JOptionPane.showConfirmDialog(frame,
- Localization.lang("'%0' exists. Overwrite file?", f.getName()),
- Localization.lang("Download file"), JOptionPane.OK_CANCEL_OPTION) == JOptionPane.OK_OPTION;
- } else {
- return true;
- }
- });
- if (dontShowDialog) {
- return;
- } else {
- editor.setVisible(true, false);
- }
- // Editor closed. Go on:
- if (editor.okPressed()) {
- File toFile = directory == null ? new File(entry.link) : expandFilename(directory, entry.link);
- String dirPrefix;
- if (directory == null) {
- dirPrefix = null;
- } else {
- if (directory.endsWith(OS.FILE_SEPARATOR)) {
- dirPrefix = directory;
- } else {
- dirPrefix = directory + OS.FILE_SEPARATOR;
- }
- }
-
- try {
- boolean success = FileUtil.copyFile(tmp, toFile, true);
- if (!success) {
- // OOps, the file exists!
- LOGGER.error("File already exists! DownloadExternalFile.download()");
- }
-
- // If the local file is in or below the main file directory, change the
- // path to relative:
- if ((directory != null) && entry.link.startsWith(directory) &&
- (entry.link.length() > dirPrefix.length())) {
- entry = new FileListEntry(entry.description, entry.link.substring(dirPrefix.length()), entry.type);
- }
-
- callback.downloadComplete(entry);
- } catch (IOException ex) {
- LOGGER.warn("Problem downloading file", ex);
- }
-
- if (!tmp.delete()) {
- LOGGER.info("Cannot delete temporary file");
- }
- } else {
- // Canceled. Just delete the temp file:
- if (downloadFinished && !tmp.delete()) {
- LOGGER.info("Cannot delete temporary file");
- }
- }
-
- }
-
- /**
- * Construct a File object pointing to the file linked, whether the link is
- * absolute or relative to the main directory.
- *
- * @param directory The main directory.
- * @param link The absolute or relative link.
- * @return The expanded File.
- */
- private File expandFilename(String directory, String link) {
- File toFile = new File(link);
- // If this is a relative link, we should perhaps append the directory:
- String dirPrefix = directory + OS.FILE_SEPARATOR;
- if (!toFile.isAbsolute()) {
- toFile = new File(dirPrefix + link);
- }
- return toFile;
- }
-
- /**
- * This is called by the download thread when download is completed.
- */
- private void downloadFinished() {
- downloadFinished = true;
- editor.getProgressBar().setVisible(false);
- editor.getProgressBarLabel().setVisible(false);
- editor.setOkEnabled(true);
- editor.getProgressBar().setValue(editor.getProgressBar().getMaximum());
- }
-
- // FIXME: will break download if no bibtexkey is present!
- private String getSuggestedFileName(String suffix) {
- String plannedName = FileUtil.createFileNameFromPattern(databaseContext.getDatabase(),
- frame.getCurrentBasePanel().getSelectedEntries().get(0),
- Globals.prefs.get(JabRefPreferences.IMPORT_FILENAMEPATTERN),
- LayoutFormatterPreferences.fromPreferences(Globals.prefs, Globals.journalAbbreviationLoader));
-
- if (!suffix.isEmpty()) {
- plannedName += "." + suffix;
- }
-
- /*
- * [ 1548875 ] download pdf produces unsupported filename
- *
- * http://sourceforge.net/tracker/index.php?func=detail&aid=1548875&group_id=92314&atid=600306
- * FIXME: rework this! just allow alphanumeric stuff or so?
- * https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#naming_conventions
- * http://superuser.com/questions/358855/what-characters-are-safe-in-cross-platform-file-names-for-linux-windows-and-os
- * https://support.apple.com/en-us/HT202808
- */
- if (OS.WINDOWS) {
- plannedName = plannedName.replaceAll("\\?|\\*|\\<|\\>|\\||\\\"|\\:|\\.$|\\[|\\]", "");
- } else if (OS.OS_X) {
- plannedName = plannedName.replace(":", "");
- }
-
- return plannedName;
- }
-
- /**
- * Look for the last '.' in the link, and return the following characters.
- * This gives the extension for most reasonably named links.
- *
- * @param link The link
- * @return The suffix, excluding the dot (e.g. "pdf")
- */
- private String getSuffix(final String link) {
- String strippedLink = link;
- try {
- // Try to strip the query string, if any, to get the correct suffix:
- URL url = new URL(link);
- if ((url.getQuery() != null) && (url.getQuery().length() < (link.length() - 1))) {
- strippedLink = link.substring(0, link.length() - url.getQuery().length() - 1);
- }
- } catch (MalformedURLException e) {
- // Don't report this error, since this getting the suffix is a non-critical
- // operation, and this error will be triggered and reported elsewhere.
- }
- // First see if the stripped link gives a reasonable suffix:
- String suffix;
- int strippedLinkIndex = strippedLink.lastIndexOf('.');
- if ((strippedLinkIndex <= 0) || (strippedLinkIndex == (strippedLink.length() - 1))) {
- suffix = null;
- } else {
- suffix = strippedLink.substring(strippedLinkIndex + 1);
- }
- if (!ExternalFileTypes.getInstance().isExternalFileTypeByExt(suffix)) {
- // If the suffix doesn't seem to give any reasonable file type, try
- // with the non-stripped link:
- int index = link.lastIndexOf('.');
- if ((index <= 0) || (index == (link.length() - 1))) {
- // No occurrence, or at the end
- // Check if there are path separators in the suffix - if so, it is definitely
- // not a proper suffix, so we should give up:
- if (strippedLink.substring(strippedLinkIndex + 1).indexOf('/') >= 1) {
- return "";
- } else {
- return suffix; // return the first one we found, anyway.
- }
- } else {
- // Check if there are path separators in the suffix - if so, it is definitely
- // not a proper suffix, so we should give up:
- if (link.substring(index + 1).indexOf('/') >= 1) {
- return "";
- } else {
- return link.substring(index + 1);
- }
- }
- } else {
- return suffix;
- }
-
- }
-
- /**
- * Callback interface that users of this class must implement in order to receive
- * notification when download is complete.
- */
- @FunctionalInterface
- public interface DownloadCallback {
- void downloadComplete(FileListEntry file);
- }
-}
diff --git a/src/main/java/net/sf/jabref/external/DroppedFileHandler.java b/src/main/java/net/sf/jabref/external/DroppedFileHandler.java
deleted file mode 100644
index 0a18dbe..0000000
--- a/src/main/java/net/sf/jabref/external/DroppedFileHandler.java
+++ /dev/null
@@ -1,542 +0,0 @@
-package net.sf.jabref.external;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.List;
-import java.util.Optional;
-
-import javax.swing.ButtonGroup;
-import javax.swing.JCheckBox;
-import javax.swing.JLabel;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JRadioButton;
-import javax.swing.JTextField;
-import javax.swing.event.ChangeEvent;
-import javax.swing.event.ChangeListener;
-
-import net.sf.jabref.Globals;
-import net.sf.jabref.gui.BasePanel;
-import net.sf.jabref.gui.FileListEntry;
-import net.sf.jabref.gui.FileListTableModel;
-import net.sf.jabref.gui.JabRefFrame;
-import net.sf.jabref.gui.maintable.MainTable;
-import net.sf.jabref.gui.undo.NamedCompound;
-import net.sf.jabref.gui.undo.UndoableFieldChange;
-import net.sf.jabref.gui.undo.UndoableInsertEntry;
-import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.logic.layout.LayoutFormatterPreferences;
-import net.sf.jabref.logic.util.OS;
-import net.sf.jabref.logic.util.io.FileUtil;
-import net.sf.jabref.logic.xmp.XMPPreferences;
-import net.sf.jabref.logic.xmp.XMPUtil;
-import net.sf.jabref.model.database.BibDatabase;
-import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.model.entry.FieldName;
-import net.sf.jabref.model.entry.IdGenerator;
-import net.sf.jabref.preferences.JabRefPreferences;
-
-import com.jgoodies.forms.builder.FormBuilder;
-import com.jgoodies.forms.layout.FormLayout;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * This class holds the functionality of autolinking to a file that's dropped
- * onto an entry.
- * <p>
- * Options for handling the files are:
- * <p>
- * 1) Link to the file in its current position (disabled if the file is remote)
- * <p>
- * 2) Copy the file to ??? directory, rename after bibtex key, and extension
- * <p>
- * 3) Move the file to ??? directory, rename after bibtex key, and extension
- */
-public class DroppedFileHandler {
-
- private static final Log LOGGER = LogFactory.getLog(DroppedFileHandler.class);
-
- private final JabRefFrame frame;
-
- private final BasePanel panel;
-
- private final JRadioButton linkInPlace = new JRadioButton();
- private final JRadioButton copyRadioButton = new JRadioButton();
- private final JRadioButton moveRadioButton = new JRadioButton();
-
- private final JLabel destDirLabel = new JLabel();
-
- private final JCheckBox renameCheckBox = new JCheckBox();
-
- private final JTextField renameToTextBox = new JTextField(50);
-
- private final JPanel optionsPanel = new JPanel();
-
-
- public DroppedFileHandler(JabRefFrame frame, BasePanel panel) {
-
- this.frame = frame;
- this.panel = panel;
-
- ButtonGroup grp = new ButtonGroup();
- grp.add(linkInPlace);
- grp.add(copyRadioButton);
- grp.add(moveRadioButton);
-
- FormLayout layout = new FormLayout("left:15dlu,pref,pref,pref", "bottom:14pt,pref,pref,pref,pref");
- layout.setRowGroups(new int[][]{{1, 2, 3, 4, 5}});
- FormBuilder builder = FormBuilder.create().layout(layout);
-
- builder.add(linkInPlace).xyw(1, 1, 4);
- builder.add(destDirLabel).xyw(1, 2, 4);
- builder.add(copyRadioButton).xyw(2, 3, 3);
- builder.add(moveRadioButton).xyw(2, 4, 3);
- builder.add(renameCheckBox).xyw(2, 5, 1);
- builder.add(renameToTextBox).xyw(4, 5, 1);
- optionsPanel.add(builder.getPanel());
- }
-
- /**
- * Offer copy/move/linking options for a dragged external file. Perform the
- * chosen operation, if any.
- *
- * @param fileName The name of the dragged file.
- * @param fileType The FileType associated with the file.
- * @param mainTable The MainTable the file was dragged to.
- * @param dropRow The row where the file was dropped.
- */
- public void handleDroppedfile(String fileName, ExternalFileType fileType, MainTable mainTable, int dropRow) {
-
- BibEntry entry = mainTable.getEntryAt(dropRow);
- handleDroppedfile(fileName, fileType, entry);
- }
-
- /**
- * @param fileName The name of the dragged file.
- * @param fileType The FileType associated with the file.
- * @param entry The target entry for the drop.
- */
- public void handleDroppedfile(String fileName, ExternalFileType fileType, BibEntry entry) {
- NamedCompound edits = new NamedCompound(Localization.lang("Drop %0", fileType.getExtension()));
-
- if (tryXmpImport(fileName, fileType, edits)) {
- edits.end();
- panel.getUndoManager().addEdit(edits);
- return;
- }
-
- // Show dialog
- if (!showLinkMoveCopyRenameDialog(fileName, fileType, entry, panel.getDatabase())) {
- return;
- }
-
- /*
- * Ok, we're ready to go. See first if we need to do a file copy before
- * linking:
- */
-
- boolean success = true;
- String destFilename;
-
- if (linkInPlace.isSelected()) {
- destFilename = FileUtil.shortenFileName(new File(fileName), panel.getBibDatabaseContext().getFileDirectory()).toString();
- } else {
- destFilename = renameCheckBox.isSelected() ? renameToTextBox.getText() : new File(fileName).getName();
- if (copyRadioButton.isSelected()) {
- success = doCopy(fileName, destFilename, edits);
- } else if (moveRadioButton.isSelected()) {
- success = doMove(fileName, destFilename, edits);
- }
- }
-
- if (success) {
- doLink(entry, fileType, destFilename, false, edits);
- panel.markBaseChanged();
- panel.updateEntryEditorIfShowing();
- }
- edits.end();
- panel.getUndoManager().addEdit(edits);
-
- }
-
- // Done by MrDlib
- public void linkPdfToEntry(String fileName, MainTable entryTable, int dropRow) {
- BibEntry entry = entryTable.getEntryAt(dropRow);
- linkPdfToEntry(fileName, entry);
- }
-
- public void linkPdfToEntry(String fileName, BibEntry entry) {
- Optional<ExternalFileType> optFileType = ExternalFileTypes.getInstance().getExternalFileTypeByExt("pdf");
-
- if (!optFileType.isPresent()) {
- LOGGER.warn("No file type with extension 'pdf' registered.");
- return;
- }
-
- ExternalFileType fileType = optFileType.get();
- // Show dialog
- if (!showLinkMoveCopyRenameDialog(fileName, fileType, entry, panel.getDatabase())) {
- return;
- }
-
- /*
- * Ok, we're ready to go. See first if we need to do a file copy before
- * linking:
- */
-
- boolean success = true;
- String destFilename;
- NamedCompound edits = new NamedCompound(Localization.lang("Drop %0", fileType.getExtension()));
-
- if (linkInPlace.isSelected()) {
- destFilename = FileUtil.shortenFileName(new File(fileName), panel.getBibDatabaseContext().getFileDirectory()).toString();
- } else {
- destFilename = renameCheckBox.isSelected() ? renameToTextBox.getText() : new File(fileName).getName();
- if (copyRadioButton.isSelected()) {
- success = doCopy(fileName, destFilename, edits);
- } else if (moveRadioButton.isSelected()) {
- success = doMove(fileName, destFilename, edits);
- }
- }
-
- if (success) {
- doLink(entry, fileType, destFilename, false, edits);
- panel.markBaseChanged();
- }
- edits.end();
- panel.getUndoManager().addEdit(edits);
- }
-
- // Done by MrDlib
-
- private boolean tryXmpImport(String fileName, ExternalFileType fileType, NamedCompound edits) {
-
- if (!"pdf".equals(fileType.getExtension())) {
- return false;
- }
-
- List<BibEntry> xmpEntriesInFile;
- try {
- xmpEntriesInFile = XMPUtil.readXMP(fileName, XMPPreferences.fromPreferences(Globals.prefs));
- } catch (IOException e) {
- LOGGER.warn("Problem reading XMP", e);
- return false;
- }
-
- if ((xmpEntriesInFile == null) || xmpEntriesInFile.isEmpty()) {
- return false;
- }
-
- JLabel confirmationMessage = new JLabel(
- Localization.lang("The PDF contains one or several BibTeX-records.")
- + "\n"
- + Localization.lang("Do you want to import these as new entries into the current database?"));
-
- int reply = JOptionPane.showConfirmDialog(frame, confirmationMessage,
- Localization.lang("XMP-metadata found in PDF: %0", fileName), JOptionPane.YES_NO_CANCEL_OPTION,
- JOptionPane.QUESTION_MESSAGE);
-
- if (reply == JOptionPane.CANCEL_OPTION) {
- return true; // The user canceled thus that we are done.
- }
- if (reply == JOptionPane.NO_OPTION) {
- return false;
- }
-
- // reply == JOptionPane.YES_OPTION)
-
- /*
- * TODO Extract Import functionality from ImportMenuItem then we could
- * do:
- *
- * ImportMenuItem importer = new ImportMenuItem(frame, (mainTable ==
- * null), new PdfXmpImporter());
- *
- * importer.automatedImport(new String[] { fileName });
- */
-
- boolean isSingle = xmpEntriesInFile.size() == 1;
- BibEntry single = isSingle ? xmpEntriesInFile.get(0) : null;
-
- boolean success = true;
-
- String destFilename;
-
- if (linkInPlace.isSelected()) {
- destFilename = FileUtil.shortenFileName(new File(fileName), panel.getBibDatabaseContext().getFileDirectory()).toString();
- } else {
- if (renameCheckBox.isSelected()) {
- destFilename = fileName;
- } else {
- destFilename = single.getCiteKey() + "." + fileType.getExtension();
- }
-
- if (copyRadioButton.isSelected()) {
- success = doCopy(fileName, destFilename, edits);
- } else if (moveRadioButton.isSelected()) {
- success = doMove(fileName, destFilename, edits);
- }
- }
- if (success) {
-
- for (BibEntry aXmpEntriesInFile : xmpEntriesInFile) {
-
- aXmpEntriesInFile.setId(IdGenerator.next());
- edits.addEdit(new UndoableInsertEntry(panel.getDatabase(), aXmpEntriesInFile, panel));
- panel.getDatabase().insertEntry(aXmpEntriesInFile);
- doLink(aXmpEntriesInFile, fileType, destFilename, true, edits);
-
- }
- panel.markBaseChanged();
- panel.updateEntryEditorIfShowing();
- }
- return true;
- }
-
- //
- // @return true if user pushed "OK", false otherwise
- //
- private boolean showLinkMoveCopyRenameDialog(String linkFileName, ExternalFileType fileType, BibEntry entry,
- BibDatabase database) {
-
- String dialogTitle = Localization.lang("Link to file %0", linkFileName);
- List<String> dirs = panel.getBibDatabaseContext().getFileDirectory();
- int found = -1;
- for (int i = 0; i < dirs.size(); i++) {
- if (new File(dirs.get(i)).exists()) {
- found = i;
- break;
- }
- }
- if (found < 0) {
- destDirLabel.setText(Localization.lang("File directory is not set or does not exist!"));
- copyRadioButton.setEnabled(false);
- moveRadioButton.setEnabled(false);
- renameToTextBox.setEnabled(false);
- renameCheckBox.setEnabled(false);
- linkInPlace.setSelected(true);
- } else {
- destDirLabel.setText(Localization.lang("File directory is '%0':", dirs.get(found)));
- copyRadioButton.setEnabled(true);
- moveRadioButton.setEnabled(true);
- renameToTextBox.setEnabled(true);
- renameCheckBox.setEnabled(true);
- }
-
- ChangeListener cl = arg0 -> {
- renameCheckBox.setEnabled(!linkInPlace.isSelected());
- renameToTextBox.setEnabled(!linkInPlace.isSelected());
- };
-
- linkInPlace.setText(Localization.lang("Leave file in its current directory"));
- copyRadioButton.setText(Localization.lang("Copy file to file directory"));
- moveRadioButton.setText(Localization.lang("Move file to file directory"));
- renameCheckBox.setText(Localization.lang("Rename file to").concat(": "));
-
- // Determine which name to suggest:
- String targetName = FileUtil.createFileNameFromPattern(database, entry,
- Globals.prefs.get(JabRefPreferences.IMPORT_FILENAMEPATTERN),
- LayoutFormatterPreferences.fromPreferences(Globals.prefs, Globals.journalAbbreviationLoader));
-
- renameToTextBox.setText(targetName.concat(".").concat(fileType.getExtension()));
-
- linkInPlace.setSelected(frame.prefs().getBoolean(JabRefPreferences.DROPPEDFILEHANDLER_LEAVE));
- copyRadioButton.setSelected(frame.prefs().getBoolean(JabRefPreferences.DROPPEDFILEHANDLER_COPY));
- moveRadioButton.setSelected(frame.prefs().getBoolean(JabRefPreferences.DROPPEDFILEHANDLER_MOVE));
- renameCheckBox.setSelected(frame.prefs().getBoolean(JabRefPreferences.DROPPEDFILEHANDLER_RENAME));
-
- linkInPlace.addChangeListener(cl);
- cl.stateChanged(new ChangeEvent(linkInPlace));
-
- try {
- Object[] messages = {Localization.lang("How would you like to link to '%0'?", linkFileName),
- optionsPanel};
- int reply = JOptionPane.showConfirmDialog(frame, messages, dialogTitle,
- JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);
- if (reply == JOptionPane.OK_OPTION) {
- // store user's choice
- frame.prefs().putBoolean(JabRefPreferences.DROPPEDFILEHANDLER_LEAVE, linkInPlace.isSelected());
- frame.prefs().putBoolean(JabRefPreferences.DROPPEDFILEHANDLER_COPY, copyRadioButton.isSelected());
- frame.prefs().putBoolean(JabRefPreferences.DROPPEDFILEHANDLER_MOVE, moveRadioButton.isSelected());
- frame.prefs().putBoolean(JabRefPreferences.DROPPEDFILEHANDLER_RENAME, renameCheckBox.isSelected());
- return true;
- } else {
- return false;
- }
- } finally {
- linkInPlace.removeChangeListener(cl);
- }
- }
-
- /**
- * Make a extension to the file.
- *
- * @param entry The entry to extension from.
- * @param fileType The FileType associated with the file.
- * @param filename The path to the file.
- * @param edits An NamedCompound action this action is to be added to. If none
- * is given, the edit is added to the panel's undoManager.
- */
- private void doLink(BibEntry entry, ExternalFileType fileType, String filename,
- boolean avoidDuplicate, NamedCompound edits) {
-
- Optional<String> oldValue = entry.getFieldOptional(FieldName.FILE);
- FileListTableModel tm = new FileListTableModel();
- oldValue.ifPresent(tm::setContent);
-
- // If avoidDuplicate==true, we should check if this file is already linked:
- if (avoidDuplicate) {
- // For comparison, find the absolute filename:
- List<String> dirs = panel.getBibDatabaseContext().getFileDirectory();
- String absFilename;
- if (new File(filename).isAbsolute() || dirs.isEmpty()) {
- absFilename = filename;
- } else {
- Optional<File> file = FileUtil.expandFilename(filename, dirs);
- if (file.isPresent()) {
- absFilename = file.get().getAbsolutePath();
- } else {
- absFilename = ""; // This shouldn't happen based on the old code, so maybe one should set it something else?
- }
- }
-
- LOGGER.debug("absFilename: " + absFilename);
-
- for (int i = 0; i < tm.getRowCount(); i++) {
- FileListEntry flEntry = tm.getEntry(i);
- // Find the absolute filename for this existing link:
- String absName;
- if (new File(flEntry.link).isAbsolute() || dirs.isEmpty()) {
- absName = flEntry.link;
- } else {
- Optional<File> file = FileUtil.expandFilename(flEntry.link, dirs);
- if (file.isPresent()) {
- absName = file.get().getAbsolutePath();
- } else {
- absName = null;
- }
- }
- LOGGER.debug("absName: " + absName);
- // If the filenames are equal, we don't need to link, so we simply return:
- if (absFilename.equals(absName)) {
- return;
- }
- }
- }
-
- tm.addEntry(tm.getRowCount(), new FileListEntry("", filename, fileType));
- String newValue = tm.getStringRepresentation();
- UndoableFieldChange edit = new UndoableFieldChange(entry, FieldName.FILE, oldValue.orElse(null), newValue);
- entry.setField(FieldName.FILE, newValue);
-
- if (edits == null) {
- panel.getUndoManager().addEdit(edit);
- } else {
- edits.addEdit(edit);
- }
- }
-
- /**
- * Move the given file to the base directory for its file type, and rename
- * it to the given filename.
- *
- * @param fileName The name of the source file.
- * @param destFilename The destination filename.
- * @param edits TODO we should be able to undo this action
- * @return true if the operation succeeded.
- */
- private boolean doMove(String fileName, String destFilename,
- NamedCompound edits) {
- List<String> dirs = panel.getBibDatabaseContext().getFileDirectory();
- int found = -1;
- for (int i = 0; i < dirs.size(); i++) {
- if (new File(dirs.get(i)).exists()) {
- found = i;
- break;
- }
- }
- if (found < 0) {
- // OOps, we don't know which directory to put it in, or the given
- // dir doesn't exist....
- // This should not happen!!
- LOGGER.warn("Cannot determine destination directory or destination directory does not exist");
- return false;
- }
- File toFile = new File(dirs.get(found) + OS.FILE_SEPARATOR + destFilename);
- if (toFile.exists()) {
- int answer = JOptionPane.showConfirmDialog(frame,
- Localization.lang("'%0' exists. Overwrite file?", toFile.getAbsolutePath()),
- Localization.lang("Overwrite file?"),
- JOptionPane.YES_NO_OPTION);
- if (answer == JOptionPane.NO_OPTION) {
- return false;
- }
- }
-
- File fromFile = new File(fileName);
- if (fromFile.renameTo(toFile)) {
- return true;
- } else {
- JOptionPane.showMessageDialog(frame,
- Localization.lang("Could not move file '%0'.", toFile.getAbsolutePath()) +
- Localization.lang("Please move the file manually and link in place."),
- Localization.lang("Move file failed"), JOptionPane.ERROR_MESSAGE);
- return false;
- }
-
- }
-
- /**
- * Copy the given file to the base directory for its file type, and give it
- * the given name.
- *
- * @param fileName The name of the source file.
- * @param toFile The destination filename. An existing path-component will be removed.
- * @param edits TODO we should be able to undo this!
- * @return
- */
- private boolean doCopy(String fileName, String toFile, NamedCompound edits) {
-
- List<String> dirs = panel.getBibDatabaseContext().getFileDirectory();
- int found = -1;
- for (int i = 0; i < dirs.size(); i++) {
- if (new File(dirs.get(i)).exists()) {
- found = i;
- break;
- }
- }
- if (found < 0) {
- // OOps, we don't know which directory to put it in, or the given
- // dir doesn't exist....
- // This should not happen!!
- LOGGER.warn("Cannot determine destination directory or destination directory does not exist");
- return false;
- }
- String destinationFileName = new File(toFile).getName();
-
- File destFile = new File(dirs.get(found) + OS.FILE_SEPARATOR + destinationFileName);
- if (destFile.equals(new File(fileName))) {
- // File is already in the correct position. Don't override!
- return true;
- }
-
- if (destFile.exists()) {
- int answer = JOptionPane.showConfirmDialog(frame,
- Localization.lang("'%0' exists. Overwrite file?", destFile.getPath()),
- Localization.lang("File exists"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
- if (answer == JOptionPane.NO_OPTION) {
- return false;
- }
- }
- try {
- FileUtil.copyFile(new File(fileName), destFile, true);
- } catch (IOException e) {
- LOGGER.error("Problem copying file", e);
- return false;
- }
-
- return true;
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/external/ExternalFileMenuItem.java b/src/main/java/net/sf/jabref/external/ExternalFileMenuItem.java
deleted file mode 100644
index 306744c..0000000
--- a/src/main/java/net/sf/jabref/external/ExternalFileMenuItem.java
+++ /dev/null
@@ -1,112 +0,0 @@
-package net.sf.jabref.external;
-
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.io.File;
-import java.io.IOException;
-import java.util.Optional;
-
-import javax.swing.Icon;
-import javax.swing.JMenuItem;
-import javax.swing.JOptionPane;
-
-import net.sf.jabref.BibDatabaseContext;
-import net.sf.jabref.gui.JabRefFrame;
-import net.sf.jabref.gui.desktop.JabRefDesktop;
-import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.model.entry.BibEntry;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * The menu item used in the popup menu for opening external resources associated
- * with an entry. Shows the resource name and icon given, and adds an action listener
- * to process the request if the user clicks this menu item.
- */
-public class ExternalFileMenuItem extends JMenuItem implements ActionListener {
-
- private static final Log LOGGER = LogFactory.getLog(ExternalFileMenuItem.class);
-
- private final BibEntry entry;
- private final String link;
- private final BibDatabaseContext databaseContext;
- private Optional<ExternalFileType> fileType;
- private final JabRefFrame frame;
- private String fieldName;
-
-
- public ExternalFileMenuItem(JabRefFrame frame, BibEntry entry, String name, String link, Icon icon,
- BibDatabaseContext databaseContext, Optional<ExternalFileType> fileType) {
- super(name, icon);
- this.frame = frame;
- this.entry = entry;
- this.link = link;
- this.databaseContext = databaseContext;
- this.fileType = fileType;
- addActionListener(this);
- }
-
- public ExternalFileMenuItem(JabRefFrame frame, BibEntry entry, String name, String link, Icon icon,
- BibDatabaseContext databaseContext, String fieldName) {
- this(frame, entry, name, link, icon, databaseContext, Optional.empty());
- this.fieldName = fieldName;
- }
-
- @Override
- public void actionPerformed(ActionEvent e) {
- boolean success = openLink();
- if (!success) {
- frame.output(Localization.lang("Unable to open link."));
- }
- }
-
- public boolean openLink() {
- frame.output(Localization.lang("External viewer called") + ".");
- try {
- Optional<ExternalFileType> type = fileType;
- if (!this.fileType.isPresent()) {
- if (this.fieldName == null) {
- // We don't already know the file type, so we try to deduce it from the extension:
- File file = new File(link);
- // We try to check the extension for the file:
- String name = file.getName();
- int pos = name.indexOf('.');
- String extension = (pos >= 0) && (pos < (name.length() - 1)) ? name.substring(pos + 1)
- .trim().toLowerCase() : null;
- // Now we know the extension, check if it is one we know about:
- type = ExternalFileTypes.getInstance().getExternalFileTypeByExt(extension);
- fileType = type;
- } else {
- JabRefDesktop.openExternalViewer(databaseContext, link, fieldName);
- return true;
- }
- }
-
- if (type.isPresent() && (type.get() instanceof UnknownExternalFileType)) {
- return JabRefDesktop.openExternalFileUnknown(frame, entry, databaseContext, link,
- (UnknownExternalFileType) type.get());
- } else {
- return JabRefDesktop.openExternalFileAnyFormat(databaseContext, link, type);
- }
-
- } catch (IOException e1) {
- // See if we should show an error message concerning the application to open the
- // link with. We check if the file type is set, and if the file type has a non-empty
- // application link. If that link is referred by the error message, we can assume
- // that the problem is in the open-with-application setting:
- if ((fileType.isPresent()) && (!fileType.get().getOpenWithApplication().isEmpty())
- && e1.getMessage().contains(fileType.get().getOpenWithApplication())) {
-
- JOptionPane.showMessageDialog(frame, Localization.lang("Unable to open link. "
- + "The application '%0' associated with the file type '%1' could not be called.",
- fileType.get().getOpenWithApplication(), fileType.get().getName()),
- Localization.lang("Could not open link"), JOptionPane.ERROR_MESSAGE);
- return false;
- }
-
- LOGGER.warn("Unable to open link", e1);
- }
- return false;
- }
-}
diff --git a/src/main/java/net/sf/jabref/external/ExternalFileType.java b/src/main/java/net/sf/jabref/external/ExternalFileType.java
deleted file mode 100644
index 0d29ee2..0000000
--- a/src/main/java/net/sf/jabref/external/ExternalFileType.java
+++ /dev/null
@@ -1,222 +0,0 @@
-package net.sf.jabref.external;
-
-import java.util.Objects;
-
-import javax.swing.Icon;
-import javax.swing.JLabel;
-
-import net.sf.jabref.gui.IconTheme;
-
-/**
- * This class defines a type of external files that can be linked to from JabRef.
- * The class contains enough information to provide an icon, a standard extension
- * and a link to which application handles files of this type.
- */
-public class ExternalFileType implements Comparable<ExternalFileType> {
-
- private String name;
- private String extension;
- private String openWith;
- private String iconName;
- private String mimeType;
- private Icon icon;
- private final JLabel label = new JLabel();
-
- public ExternalFileType(String name, String extension, String mimeType,
- String openWith, String iconName, Icon icon) {
- label.setText(null);
- this.name = name;
- label.setToolTipText(this.name);
- this.extension = extension;
- this.mimeType = mimeType;
- this.openWith = openWith;
-
- setIconName(iconName);
- setIcon(icon);
- }
-
- /**
- * Construct an ExternalFileType from a String array. This is used when
- * reading file type definitions from Preferences, where the available data types are
- * limited. We assume that the array contains the same values as the main constructor,
- * in the same order.
- *
- * @param val arguments.
- */
- public static ExternalFileType buildFromArgs(String[] val) {
- if ((val == null) || (val.length < 4) || (val.length > 5)) {
- throw new IllegalArgumentException("Cannot construct ExternalFileType without four elements in String[] argument.");
- }
- String name = val[0];
- String extension = val[1];
- String openWith;
- String mimeType;
- String iconName;
- Icon icon;
-
- if (val.length == 4) {
- // Up to version 2.4b the mime type is not included:
- mimeType = "";
- openWith = val[2];
- iconName = val[3];
- } else {
- // When mime type is included, the array length should be 5:
- mimeType = val[2];
- openWith = val[3];
- iconName = val[4];
- }
-
- // set icon to default first
- icon = IconTheme.JabRefIcon.FILE.getSmallIcon();
-
- // check whether there is another icon defined for this file type
- for(ExternalFileType fileType : ExternalFileTypes.getDefaultExternalFileTypes()) {
- if(fileType.getName().equals(name)) {
- icon = fileType.icon;
- break;
- }
- }
-
- return new ExternalFileType(name, extension, mimeType, openWith, iconName, icon);
- }
-
- /**
- * Return a String array representing this file type. This is used for storage into
- * Preferences, and the same array can be used to construct the file type later,
- * using the String[] constructor.
- *
- * @return A String[] containing all information about this file type.
- */
- public String[] getStringArrayRepresentation() {
- return new String[]{name, extension, mimeType, openWith, iconName};
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- label.setToolTipText(this.name);
- }
-
- public String getExtension() {
- if (extension == null) {
- return "";
- }
- return extension;
- }
-
- public void setExtension(String extension) {
- this.extension = extension;
- }
-
- public String getMimeType() {
- if (mimeType == null) {
- return "";
- }
- return mimeType;
- }
-
- public void setMimeType(String mimeType) {
- this.mimeType = mimeType;
- }
-
- /**
- * Get the bibtex field name used to extension to this file type.
- * Currently we assume that field name equals filename extension.
- *
- * @return The field name.
- */
- public String getFieldName() {
- return extension;
- }
-
- public String getOpenWithApplication() {
- if (openWith == null) {
- return "";
- }
- return openWith;
- }
-
- public void setOpenWith(String openWith) {
- this.openWith = openWith;
- }
-
- /**
- * Set the string associated with this file type's icon.
- *
- * @param name The icon name to use.
- */
- public void setIconName(String name) {
- this.iconName = name;
- }
-
- /**
- * Obtain a JLabel instance set with this file type's icon. The same JLabel
- * is returned from each call of this method.
- *
- * @return the label.
- */
- public JLabel getIconLabel() {
- return label;
- }
-
- /**
- * Get the string associated with this file type's icon.
- *
- * @return The icon name.
- */
- public String getIconName() {
- return iconName;
- }
-
- public Icon getIcon() {
- return icon;
- }
-
- public void setIcon(Icon icon) {
- this.icon = icon;
- label.setIcon(this.icon);
- }
-
- @Override
- public String toString() {
- return getName();
- }
-
- @Override
- public int compareTo(ExternalFileType o) {
- return getName().compareTo(o.getName());
- }
-
- public ExternalFileType copy() {
- return new ExternalFileType(name, extension, mimeType, openWith, iconName, icon);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(name, extension, mimeType, openWith, iconName);
- }
-
- /**
- * We define two file type objects as equal if their name, extension, openWith and
- * iconName are equal.
- *
- * @param object The file type to compare with.
- * @return true if the file types are equal.
- */
- @Override
- public boolean equals(Object object) {
- if (this == object) {
- return true;
- }
-
- if (object instanceof ExternalFileType) {
- ExternalFileType other = (ExternalFileType) object;
- return Objects.equals(name, other.name) && Objects.equals(extension, other.extension) &&
- Objects.equals(mimeType, other.mimeType) && Objects.equals(openWith, other.openWith) && Objects.equals(iconName, other.iconName);
- }
- return false;
- }
-}
diff --git a/src/main/java/net/sf/jabref/external/ExternalFileTypeEditor.java b/src/main/java/net/sf/jabref/external/ExternalFileTypeEditor.java
deleted file mode 100644
index 226d6d7..0000000
--- a/src/main/java/net/sf/jabref/external/ExternalFileTypeEditor.java
+++ /dev/null
@@ -1,386 +0,0 @@
-package net.sf.jabref.external;
-
-import java.awt.BorderLayout;
-import java.awt.Component;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-
-import javax.swing.AbstractAction;
-import javax.swing.Action;
-import javax.swing.ActionMap;
-import javax.swing.BorderFactory;
-import javax.swing.Icon;
-import javax.swing.ImageIcon;
-import javax.swing.InputMap;
-import javax.swing.JButton;
-import javax.swing.JComponent;
-import javax.swing.JDialog;
-import javax.swing.JFrame;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.JTable;
-import javax.swing.table.AbstractTableModel;
-import javax.swing.table.TableCellRenderer;
-
-import net.sf.jabref.Globals;
-import net.sf.jabref.gui.IconTheme;
-import net.sf.jabref.gui.JabRefFrame;
-import net.sf.jabref.gui.actions.MnemonicAwareAction;
-import net.sf.jabref.gui.keyboard.KeyBinding;
-import net.sf.jabref.gui.util.GUIUtil;
-import net.sf.jabref.logic.l10n.Localization;
-
-import com.jgoodies.forms.builder.ButtonBarBuilder;
-import com.jgoodies.forms.builder.ButtonStackBuilder;
-
-/**
- * Editor for external file types.
- */
-public class ExternalFileTypeEditor extends JDialog {
-
- private JFrame frame;
- private JDialog dialog;
- private List<ExternalFileType> fileTypes;
- private JTable table;
- private ExternalFileTypeEntryEditor entryEditor;
- private FileTypeTableModel tableModel;
- private final JButton ok = new JButton(Localization.lang("OK"));
- private final JButton cancel = new JButton(Localization.lang("Cancel"));
- private final JButton add = new JButton(IconTheme.JabRefIcon.ADD_NOBOX.getIcon());
- private final JButton remove = new JButton(IconTheme.JabRefIcon.REMOVE_NOBOX.getIcon());
- private final JButton edit = new JButton(IconTheme.JabRefIcon.EDIT.getIcon());
- private final JButton toDefaults = new JButton(Localization.lang("Default"));
- private final EditListener editListener = new EditListener();
-
-
- private ExternalFileTypeEditor(JFrame frame) {
- super(frame, Localization.lang("Manage external file types"), true);
- this.frame = frame;
- init();
- }
-
- private ExternalFileTypeEditor(JDialog dialog) {
- super(dialog, Localization.lang("Manage external file types"), true);
- this.dialog = dialog;
- init();
- }
-
- /**
- * Update the editor to show the current settings in Preferences.
- */
- private void setValues() {
- fileTypes.clear();
- Collection<ExternalFileType> types = ExternalFileTypes.getInstance().getExternalFileTypeSelection();
- for (ExternalFileType type : types) {
- fileTypes.add(type.copy());
- }
- Collections.sort(fileTypes);
- }
-
- /**
- * Store the list of external entry types to Preferences.
- */
- private void storeSettings() {
- ExternalFileTypes.getInstance().setExternalFileTypes(fileTypes);
- }
-
- private void init() {
-
- ok.addActionListener(e -> {
- storeSettings();
- dispose();
- });
- Action cancelAction = new AbstractAction() {
-
- @Override
- public void actionPerformed(ActionEvent e) {
- dispose();
- }
- };
- cancel.addActionListener(cancelAction);
- // The toDefaults resets the entire list to its default values.
- toDefaults.addActionListener(e -> {
- /*int reply = JOptionPane.showConfirmDialog(ExternalFileTypeEditor.this,
- Globals.lang("All custom file types will be lost. Proceed?"),
- Globals.lang("Reset file type definitions"), JOptionPane.YES_NO_OPTION,
- JOptionPane.QUESTION_MESSAGE);*/
- //if (reply == JOptionPane.YES_OPTION) {
- List<ExternalFileType> list = ExternalFileTypes.getDefaultExternalFileTypes();
- fileTypes.clear();
- fileTypes.addAll(list);
- Collections.sort(fileTypes);
- //Globals.prefs.resetExternalFileTypesToDefault();
- //setValues();
- tableModel.fireTableDataChanged();
- //}
- });
-
- add.addActionListener(e -> {
- // Generate a new file type:
- ExternalFileType type = new ExternalFileType("", "", "", "", "new",
- IconTheme.JabRefIcon.FILE.getSmallIcon());
- // Show the file type editor:
- getEditor(type).setVisible(true);
- if (entryEditor.okPressed()) {
- // Ok was pressed. Add the new file type and update the table:
- fileTypes.add(type);
- tableModel.fireTableDataChanged();
- }
- });
-
- remove.addActionListener(e -> {
- int[] rows = table.getSelectedRows();
- if (rows.length == 0) {
- return;
- }
- for (int i = rows.length - 1; i >= 0; i--) {
- fileTypes.remove(rows[i]);
- }
- tableModel.fireTableDataChanged();
- if (!fileTypes.isEmpty()) {
- int row = Math.min(rows[0], fileTypes.size() - 1);
- table.setRowSelectionInterval(row, row);
- }
- });
-
- edit.addActionListener(editListener);
- fileTypes = new ArrayList<>();
- setValues();
-
- tableModel = new FileTypeTableModel();
- table = new JTable(tableModel);
- table.setDefaultRenderer(ImageIcon.class, new IconRenderer());
- table.addMouseListener(new TableClickListener());
-
- table.getColumnModel().getColumn(0).setMaxWidth(24);
- table.getColumnModel().getColumn(0).setMinWidth(24);
- table.getColumnModel().getColumn(1).setMinWidth(170);
- table.getColumnModel().getColumn(2).setMinWidth(60);
- table.getColumnModel().getColumn(3).setMinWidth(100);
- table.getColumnModel().getColumn(0).setResizable(false);
-
- GUIUtil.correctRowHeight(table);
-
- JScrollPane sp = new JScrollPane(table);
-
- JPanel upper = new JPanel();
- upper.setLayout(new BorderLayout());
- upper.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
- upper.add(sp, BorderLayout.CENTER);
- getContentPane().add(upper, BorderLayout.CENTER);
-
- ButtonStackBuilder bs = new ButtonStackBuilder();
- bs.addButton(add);
- bs.addButton(remove);
- bs.addButton(edit);
- bs.addRelatedGap();
- bs.addButton(toDefaults);
- upper.add(bs.getPanel(), BorderLayout.EAST);
-
- ButtonBarBuilder bb = new ButtonBarBuilder();
- bb.addGlue();
- bb.addButton(ok);
- bb.addButton(cancel);
- bb.addGlue();
- bb.getPanel().setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
- getContentPane().add(bb.getPanel(), BorderLayout.SOUTH);
- pack();
-
- // Key bindings:
- ActionMap am = upper.getActionMap();
- InputMap im = upper.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
- im.put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE_DIALOG), "close");
- am.put("close", cancelAction);
- am = bb.getPanel().getActionMap();
- im = bb.getPanel().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
- im.put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE_DIALOG), "close");
- am.put("close", cancelAction);
-
- if (frame == null) {
- setLocationRelativeTo(dialog);
- } else {
- setLocationRelativeTo(frame);
- }
- }
-
- private ExternalFileTypeEntryEditor getEditor(ExternalFileType type) {
- if (entryEditor == null) {
- entryEditor = new ExternalFileTypeEntryEditor(ExternalFileTypeEditor.this, type);
- } else {
- entryEditor.setEntry(type);
- }
- return entryEditor;
- }
-
- /**
- * Get an AbstractAction for opening the external file types editor.
- * @param frame The JFrame used as parent window for the dialog.
- * @return An Action for opening the editor.
- */
- public static AbstractAction getAction(JabRefFrame frame) {
- return new EditExternalFileTypesAction(frame);
- }
-
- /**
- * Get an AbstractAction for opening the external file types editor.
- * @param dialog The JDialog used as parent window for the dialog.
- * @return An Action for opening the editor.
- */
- public static AbstractAction getAction(JDialog dialog) {
- return new EditExternalFileTypesAction(dialog);
- }
-
-
- class EditListener implements ActionListener {
-
- @Override
- public void actionPerformed(ActionEvent e) {
- int[] rows = table.getSelectedRows();
- if (rows.length != 1) {
- return;
- }
- getEditor(fileTypes.get(rows[0])).setVisible(true);
- if (entryEditor.okPressed()) {
- tableModel.fireTableDataChanged();
- }
- }
- }
-
- static class IconRenderer implements TableCellRenderer {
-
- private final JLabel lab = new JLabel();
-
-
- @Override
- public Component getTableCellRendererComponent(JTable tab, Object value, boolean isSelected, boolean hasFocus,
- int row, int column) {
- lab.setText(null);
- lab.setIcon((Icon) value);
- return lab;
- }
- }
-
- private class FileTypeTableModel extends AbstractTableModel {
-
- @Override
- public int getColumnCount() {
- return 5;
- }
-
- @Override
- public int getRowCount() {
- return fileTypes.size();
- }
-
- @Override
- public String getColumnName(int column) {
- switch (column) {
- case 0:
- return " ";
- case 1:
- return Localization.lang("Name");
- case 2:
- return Localization.lang("Extension");
- case 3:
- return Localization.lang("MIME type");
- default: // Five columns
- return Localization.lang("Application");
- }
- }
-
- @Override
- public Class<?> getColumnClass(int columnIndex) {
- if (columnIndex == 0) {
- return ImageIcon.class;
- } else {
- return String.class;
- }
- }
-
- @Override
- public Object getValueAt(int rowIndex, int columnIndex) {
- ExternalFileType type = fileTypes.get(rowIndex);
- switch (columnIndex) {
- case 0:
- return type.getIcon();
- case 1:
- return type.getName();
- case 2:
- return type.getExtension();
- case 3:
- return type.getMimeType();
- default:
- return type.getOpenWithApplication();
- }
- }
- }
-
- class TableClickListener extends MouseAdapter {
-
- private void handleClick(MouseEvent e) {
- if (e.getClickCount() == 2) {
- editListener.actionPerformed(null);
- }
- }
-
- @Override
- public void mouseClicked(MouseEvent e) {
- handleClick(e);
- }
-
- @Override
- public void mousePressed(MouseEvent e) {
- handleClick(e);
- }
-
- @Override
- public void mouseReleased(MouseEvent e) {
- handleClick(e);
- }
- }
-
- public static class EditExternalFileTypesAction extends MnemonicAwareAction {
-
- private JabRefFrame frame;
- private JDialog dialog;
- private ExternalFileTypeEditor editor;
-
-
- public EditExternalFileTypesAction(JabRefFrame frame) {
- super();
- putValue(Action.NAME, Localization.menuTitle("Manage external file types"));
- this.frame = frame;
- }
-
- public EditExternalFileTypesAction(JDialog dialog) {
- super();
- putValue(Action.NAME, Localization.menuTitle("Manage external file types"));
- this.dialog = dialog;
- }
-
- @Override
- public void actionPerformed(ActionEvent e) {
- if (editor == null) {
- if (frame == null) {
- editor = new ExternalFileTypeEditor(dialog);
- } else {
- editor = new ExternalFileTypeEditor(frame);
- }
- }
- editor.setValues();
- editor.setVisible(true);
- if ((frame != null) && (frame.getCurrentBasePanel() != null)) {
- frame.getCurrentBasePanel().getMainTable().repaint();
- }
- }
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/external/ExternalFileTypeEntryEditor.java b/src/main/java/net/sf/jabref/external/ExternalFileTypeEntryEditor.java
deleted file mode 100644
index 069831f..0000000
--- a/src/main/java/net/sf/jabref/external/ExternalFileTypeEntryEditor.java
+++ /dev/null
@@ -1,249 +0,0 @@
-package net.sf.jabref.external;
-
-import java.awt.BorderLayout;
-import java.awt.Dimension;
-import java.awt.event.ActionListener;
-import java.nio.file.Path;
-import java.util.Optional;
-
-import javax.swing.BorderFactory;
-import javax.swing.ButtonGroup;
-import javax.swing.JButton;
-import javax.swing.JDialog;
-import javax.swing.JFrame;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.JRadioButton;
-import javax.swing.JTextField;
-import javax.swing.event.DocumentEvent;
-import javax.swing.event.DocumentListener;
-
-import net.sf.jabref.Globals;
-import net.sf.jabref.gui.FileDialog;
-import net.sf.jabref.gui.IconTheme;
-import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.logic.util.OS;
-import net.sf.jabref.preferences.JabRefPreferences;
-
-import com.jgoodies.forms.builder.ButtonBarBuilder;
-import com.jgoodies.forms.builder.FormBuilder;
-import com.jgoodies.forms.layout.FormLayout;
-
-/**
- * This class produces a dialog box for editing an external file type.
- */
-public class ExternalFileTypeEntryEditor {
-
- private JFrame fParent;
- private JDialog dParent;
- private JDialog diag;
- private final JTextField extension = new JTextField();
- private final JTextField name = new JTextField();
- private final JTextField mimeType = new JTextField();
- private final JTextField application = new JTextField();
- private final JLabel icon = new JLabel(IconTheme.JabRefIcon.FILE.getSmallIcon());
- private final JButton ok = new JButton(Localization.lang("OK"));
- private final JButton cancel = new JButton(Localization.lang("Cancel"));
- private final JRadioButton useDefault = new JRadioButton(Localization.lang("Default"));
- private final JRadioButton other = new JRadioButton("");
- private final String editFileTitle = Localization.lang("Edit file type");
- private final String newFileTitle = Localization.lang("Add new file type");
-
- private ExternalFileType entry;
- private boolean okPressed;
-
- private final ActionListener browsePressed = e -> {
- String appDir = application.getText().trim();
- if (appDir.isEmpty()) {
- appDir = Globals.prefs.get(JabRefPreferences.FILE_WORKING_DIRECTORY);
- }
-
- Optional<Path> path = new FileDialog(fParent, appDir).showDialogAndGetSelectedFile();
- path.ifPresent(applicationDir -> {
- if (applicationDir.getParent() != null) {
- Globals.prefs.put(JabRefPreferences.FILE_WORKING_DIRECTORY, applicationDir.getParent().toString());
- }
- application.setText(applicationDir.toString());
- });
- };
-
- public ExternalFileTypeEntryEditor(JFrame parent, ExternalFileType entry) {
- fParent = parent;
- init(entry);
- }
-
- public ExternalFileTypeEntryEditor(JDialog parent, ExternalFileType entry) {
- dParent = parent;
- init(entry);
- }
-
- private void init(ExternalFileType inEntry) {
- entry = inEntry;
- icon.setText(null);
-
- ButtonGroup bg = new ButtonGroup();
- bg.add(useDefault);
- bg.add(other);
-
- FormBuilder builder = FormBuilder.create();
- builder.layout(new FormLayout("left:pref, 4dlu, fill:150dlu, 4dlu, fill:pref",
- "p, 2dlu, p, 2dlu, p, 2dlu, p, 2dlu, p, 2dlu, p"));
- builder.add(Localization.lang("Icon")).xy(1, 1);
- builder.add(icon).xy(3, 1);
- builder.add(Localization.lang("Name")).xy(1, 3);
- builder.add(name).xy(3, 3);
- builder.add(Localization.lang("Extension")).xy(1, 5);
- builder.add(extension).xy(3, 5);
- builder.add(Localization.lang("MIME type")).xy(1, 7);
- builder.add(mimeType).xy(3, 7);
- builder.getPanel().setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
- builder.add(Localization.lang("Application")).xy(1, 9);
- JButton browseBut = new JButton(Localization.lang("Browse"));
- if (OS.WINDOWS) {
- builder.add(useDefault).xy(3, 9);
- builder.appendRows("2dlu, p");
- JPanel p1 = new JPanel();
- builder.add(p1).xy(1, 11);
- JPanel p2 = new JPanel();
- application.setPreferredSize(new Dimension(300, application.getPreferredSize().height));
- BorderLayout bl = new BorderLayout();
- bl.setHgap(4);
- p2.setLayout(bl);
- p2.add(other, BorderLayout.WEST);
- p2.add(application, BorderLayout.CENTER);
- builder.add(p2).xy(3, 11);
- builder.add(browseBut).xy(5, 11);
- } else {
- builder.add(application).xy(3, 9);
- builder.add(browseBut).xy(5, 9);
- }
- ButtonBarBuilder bb = new ButtonBarBuilder();
- bb.addGlue();
- bb.addButton(ok);
- bb.addButton(cancel);
- bb.addGlue();
-
- ok.addActionListener(e -> {
- okPressed = true;
-
- storeSettings(ExternalFileTypeEntryEditor.this.entry);
- diag.dispose();
-
- });
- cancel.addActionListener(e -> diag.dispose());
-
- if (OS.WINDOWS) {
- application.getDocument().addDocumentListener(new DocumentListener() {
-
- private void handle() {
- if (application.getText().isEmpty()) {
- useDefault.setSelected(true);
- } else {
- other.setSelected(true);
- }
- }
-
- @Override
- public void insertUpdate(DocumentEvent documentEvent) {
- handle();
- }
-
- @Override
- public void removeUpdate(DocumentEvent documentEvent) {
- handle();
- }
-
- @Override
- public void changedUpdate(DocumentEvent documentEvent) {
- handle();
- }
- });
- }
-
- String title = editFileTitle;
-
- if (entry.getName().isEmpty()) {
- title = newFileTitle;
- }
-
- if (dParent == null) {
- diag = new JDialog(fParent, title, true);
- } else {
- diag = new JDialog(dParent, title, true);
- }
- diag.getContentPane().add(builder.getPanel(), BorderLayout.CENTER);
- diag.getContentPane().add(bb.getPanel(), BorderLayout.SOUTH);
- diag.pack();
-
- browseBut.addActionListener(browsePressed);
-
- if (dParent == null) {
- diag.setLocationRelativeTo(fParent);
- } else {
- diag.setLocationRelativeTo(dParent);
- }
-
- setValues(entry);
- }
-
- public void setEntry(ExternalFileType entry) {
- this.entry = entry;
- if (entry.getName().isEmpty()) {
- diag.setTitle(newFileTitle);
- } else {
- diag.setTitle(editFileTitle);
- }
- setValues(entry);
- }
-
- public void setVisible(boolean visible) {
- if (visible) {
- okPressed = false;
- }
- diag.setVisible(visible);
- }
-
- private void setValues(ExternalFileType entry) {
- name.setText(entry.getName());
- extension.setText(entry.getExtension());
- mimeType.setText(entry.getMimeType());
- application.setText(entry.getOpenWithApplication());
- icon.setIcon(entry.getIcon());
- if (application.getText().isEmpty()) {
- useDefault.setSelected(true);
- } else {
- other.setSelected(true);
- }
- }
-
- private void storeSettings(ExternalFileType fileTypeEntry) {
- fileTypeEntry.setName(name.getText().trim());
- fileTypeEntry.setMimeType(mimeType.getText().trim());
- // Set extension, but remove initial dot if user has added that:
- String ext = extension.getText().trim();
- if (!ext.isEmpty() && (ext.charAt(0) == '.')) {
- fileTypeEntry.setExtension(ext.substring(1));
- } else {
- fileTypeEntry.setExtension(ext);
- }
-
- if (OS.WINDOWS) {
- // On Windows, store application as empty if the "Default" option is selected,
- // or if the application name is empty:
- if (useDefault.isSelected() || application.getText().trim().isEmpty()) {
- fileTypeEntry.setOpenWith("");
- } else {
- fileTypeEntry.setOpenWith(application.getText().trim());
- }
- } else {
- fileTypeEntry.setOpenWith(application.getText().trim());
- }
- }
-
- public boolean okPressed() {
- return okPressed;
- }
-
-
-
-}
diff --git a/src/main/java/net/sf/jabref/external/ExternalFileTypes.java b/src/main/java/net/sf/jabref/external/ExternalFileTypes.java
deleted file mode 100644
index 76ec7f5..0000000
--- a/src/main/java/net/sf/jabref/external/ExternalFileTypes.java
+++ /dev/null
@@ -1,325 +0,0 @@
-package net.sf.jabref.external;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Optional;
-import java.util.Set;
-import java.util.TreeSet;
-
-import net.sf.jabref.Globals;
-import net.sf.jabref.gui.IconTheme;
-import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.logic.util.strings.StringUtil;
-import net.sf.jabref.model.entry.FileField;
-import net.sf.jabref.preferences.JabRefPreferences;
-
-public final class ExternalFileTypes {
-
- // This String is used in the encoded list in prefs of external file type
- // modifications, in order to indicate a removed default file type:
- private static final String FILE_TYPE_REMOVED_FLAG = "REMOVED";
-
- // Map containing all registered external file types:
- private final Set<ExternalFileType> externalFileTypes = new TreeSet<>();
-
- private final ExternalFileType HTML_FALLBACK_TYPE = new ExternalFileType("URL", "html", "text/html", "", "www",
- IconTheme.JabRefIcon.WWW.getSmallIcon());
-
- // The only instance of this class:
- private static ExternalFileTypes singleton;
-
-
- public static ExternalFileTypes getInstance() {
- if (ExternalFileTypes.singleton == null) {
- ExternalFileTypes.singleton = new ExternalFileTypes();
- }
- return ExternalFileTypes.singleton;
- }
-
- private ExternalFileTypes() {
- updateExternalFileTypes();
- }
-
- public static List<ExternalFileType> getDefaultExternalFileTypes() {
- List<ExternalFileType> list = new ArrayList<>();
- list.add(new ExternalFileType("PDF", "pdf", "application/pdf", "evince", "pdfSmall",
- IconTheme.JabRefIcon.PDF_FILE.getSmallIcon()));
- list.add(new ExternalFileType("PostScript", "ps", "application/postscript", "evince", "psSmall",
- IconTheme.JabRefIcon.FILE.getSmallIcon()));
- list.add(new ExternalFileType("Word", "doc", "application/msword", "oowriter", "openoffice",
- IconTheme.JabRefIcon.FILE_WORD.getSmallIcon()));
- list.add(new ExternalFileType("Word 2007+", "docx",
- "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "oowriter", "openoffice",
- IconTheme.JabRefIcon.FILE_WORD.getSmallIcon()));
- list.add(new ExternalFileType(Localization.lang("OpenDocument text"), "odt",
- "application/vnd.oasis.opendocument.text", "oowriter", "openoffice", IconTheme.getImage("openoffice")));
- list.add(new ExternalFileType("Excel", "xls", "application/excel", "oocalc", "openoffice",
- IconTheme.JabRefIcon.FILE_EXCEL.getSmallIcon()));
- list.add(new ExternalFileType("Excel 2007+", "xlsx",
- "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "oocalc", "openoffice",
- IconTheme.JabRefIcon.FILE_EXCEL.getSmallIcon()));
- list.add(new ExternalFileType(Localization.lang("OpenDocument spreadsheet"), "ods",
- "application/vnd.oasis.opendocument.spreadsheet", "oocalc", "openoffice",
- IconTheme.getImage("openoffice")));
- list.add(new ExternalFileType("PowerPoint", "ppt", "application/vnd.ms-powerpoint", "ooimpress", "openoffice",
- IconTheme.JabRefIcon.FILE_POWERPOINT.getSmallIcon()));
- list.add(new ExternalFileType("PowerPoint 2007+", "pptx",
- "application/vnd.openxmlformats-officedocument.presentationml.presentation", "ooimpress", "openoffice",
- IconTheme.JabRefIcon.FILE_POWERPOINT.getSmallIcon()));
- list.add(new ExternalFileType(Localization.lang("OpenDocument presentation"), "odp",
- "application/vnd.oasis.opendocument.presentation", "ooimpress", "openoffice",
- IconTheme.getImage("openoffice")));
- list.add(new ExternalFileType("Rich Text Format", "rtf", "application/rtf", "oowriter", "openoffice",
- IconTheme.JabRefIcon.FILE_TEXT.getSmallIcon()));
- list.add(new ExternalFileType(Localization.lang("%0 image", "PNG"), "png", "image/png", "gimp", "picture",
- IconTheme.JabRefIcon.PICTURE.getSmallIcon()));
- list.add(new ExternalFileType(Localization.lang("%0 image", "GIF"), "gif", "image/gif", "gimp", "picture",
- IconTheme.JabRefIcon.PICTURE.getSmallIcon()));
- list.add(new ExternalFileType(Localization.lang("%0 image", "JPG"), "jpg", "image/jpeg", "gimp", "picture",
- IconTheme.JabRefIcon.PICTURE.getSmallIcon()));
- list.add(new ExternalFileType("Djvu", "djvu", "image/vnd.djvu", "evince", "psSmall",
- IconTheme.JabRefIcon.FILE.getSmallIcon()));
- list.add(new ExternalFileType("Text", "txt", "text/plain", "emacs", "emacs",
- IconTheme.JabRefIcon.FILE_TEXT.getSmallIcon()));
- list.add(new ExternalFileType("LaTeX", "tex", "application/x-latex", "emacs", "emacs",
- IconTheme.JabRefIcon.FILE_TEXT.getSmallIcon()));
- list.add(new ExternalFileType("CHM", "chm", "application/mshelp", "gnochm", "www",
- IconTheme.JabRefIcon.WWW.getSmallIcon()));
- list.add(new ExternalFileType(Localization.lang("%0 image", "TIFF"), "tiff", "image/tiff", "gimp", "picture",
- IconTheme.JabRefIcon.PICTURE.getSmallIcon()));
- list.add(new ExternalFileType("URL", "html", "text/html", "firefox", "www",
- IconTheme.JabRefIcon.WWW.getSmallIcon()));
- list.add(new ExternalFileType("MHT", "mht", "multipart/related", "firefox", "www",
- IconTheme.JabRefIcon.WWW.getSmallIcon()));
- list.add(new ExternalFileType("ePUB", "epub", "application/epub+zip", "firefox", "www",
- IconTheme.JabRefIcon.WWW.getSmallIcon()));
-
- // On all OSes there is a generic application available to handle file opening,
- // so we don't need the default application settings anymore:
- for (ExternalFileType type : list) {
- type.setOpenWith("");
- }
-
- return list;
- }
-
- public Set<ExternalFileType> getExternalFileTypeSelection() {
- return externalFileTypes;
- }
-
- /**
- * Look up the external file type registered with this name, if any.
- *
- * @param name The file type name.
- * @return The ExternalFileType registered, or null if none.
- */
- public Optional<ExternalFileType> getExternalFileTypeByName(String name) {
- for (ExternalFileType type : externalFileTypes) {
- if (type.getName().equals(name)) {
- return Optional.of(type);
- }
- }
- // Return an instance that signifies an unknown file type:
- return Optional.of(new UnknownExternalFileType(name));
- }
-
- /**
- * Look up the external file type registered for this extension, if any.
- *
- * @param extension The file extension.
- * @return The ExternalFileType registered, or null if none.
- */
- public Optional<ExternalFileType> getExternalFileTypeByExt(String extension) {
- for (ExternalFileType type : externalFileTypes) {
- if (type.getExtension().equalsIgnoreCase(extension)) {
- return Optional.of(type);
- }
- }
- return Optional.empty();
- }
-
- /**
- * Returns true if there is an external file type registered for this extension.
- *
- * @param extension The file extension.
- * @return true if an ExternalFileType with the extension exists, false otherwise
- */
- public boolean isExternalFileTypeByExt(String extension) {
- for (ExternalFileType type : externalFileTypes) {
- if (type.getExtension().equalsIgnoreCase(extension)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Look up the external file type name registered for this extension, if any.
- *
- * @param extension The file extension.
- * @return The name of the ExternalFileType registered, or null if none.
- */
- public String getExternalFileTypeNameByExt(String extension) {
- for (ExternalFileType type : externalFileTypes) {
- if (type.getExtension().equalsIgnoreCase(extension)) {
- return type.getName();
- }
- }
- return "";
- }
-
- /**
- * Look up the external file type registered for this filename, if any.
- *
- * @param filename The name of the file whose type to look up.
- * @return The ExternalFileType registered, or null if none.
- */
- public Optional<ExternalFileType> getExternalFileTypeForName(String filename) {
- int longestFound = -1;
- ExternalFileType foundType = null;
- for (ExternalFileType type : externalFileTypes) {
- if (!type.getExtension().isEmpty() && filename.toLowerCase().endsWith(type.getExtension().toLowerCase())
- && (type.getExtension().length() > longestFound)) {
- longestFound = type.getExtension().length();
- foundType = type;
- }
- }
- return Optional.ofNullable(foundType);
- }
-
- /**
- * Look up the external file type registered for this MIME type, if any.
- *
- * @param mimeType The MIME type.
- * @return The ExternalFileType registered, or null if none. For the mime type "text/html", a valid file type is
- * guaranteed to be returned.
- */
- public Optional<ExternalFileType> getExternalFileTypeByMimeType(String mimeType) {
- for (ExternalFileType type : externalFileTypes) {
- if (type.getMimeType().equalsIgnoreCase(mimeType)) {
- return Optional.of(type);
- }
- }
- if ("text/html".equalsIgnoreCase(mimeType)) {
- return Optional.of(HTML_FALLBACK_TYPE);
- } else {
- return Optional.empty();
- }
- }
-
- /**
- * Reset the List of external file types after user customization.
- *
- * @param types The new List of external file types. This is the complete list, not just new entries.
- */
- public void setExternalFileTypes(List<ExternalFileType> types) {
-
- // First find a list of the default types:
- List<ExternalFileType> defTypes = getDefaultExternalFileTypes();
- // Make a list of types that are unchanged:
- List<ExternalFileType> unchanged = new ArrayList<>();
-
- externalFileTypes.clear();
- for (ExternalFileType type : types) {
- externalFileTypes.add(type);
-
- // See if we can find a type with matching name in the default type list:
- ExternalFileType found = null;
- for (ExternalFileType defType : defTypes) {
- if (defType.getName().equals(type.getName())) {
- found = defType;
- break;
- }
- }
- if (found != null) {
- // Found it! Check if it is an exact match, or if it has been customized:
- if (found.equals(type)) {
- unchanged.add(type);
- } else {
- // It was modified. Remove its entry from the defaults list, since
- // the type hasn't been removed:
- defTypes.remove(found);
- }
- }
- }
-
- // Go through unchanged types. Remove them from the ones that should be stored,
- // and from the list of defaults, since we don't need to mention these in prefs:
- for (ExternalFileType type : unchanged) {
- defTypes.remove(type);
- types.remove(type);
- }
-
- // Now set up the array to write to prefs, containing all new types, all modified
- // types, and a flag denoting each default type that has been removed:
- String[][] array = new String[types.size() + defTypes.size()][];
- int i = 0;
- for (ExternalFileType type : types) {
- array[i] = type.getStringArrayRepresentation();
- i++;
- }
- for (ExternalFileType type : defTypes) {
- array[i] = new String[] {type.getName(), FILE_TYPE_REMOVED_FLAG};
- i++;
- }
- Globals.prefs.put(JabRefPreferences.EXTERNAL_FILE_TYPES, FileField.encodeStringArray(array));
- }
-
- /**
- * Set up the list of external file types, either from default values, or from values recorded in Preferences.
- */
- private void updateExternalFileTypes() {
- // First get a list of the default file types as a starting point:
- List<ExternalFileType> types = getDefaultExternalFileTypes();
- // If no changes have been stored, simply use the defaults:
- if (Globals.prefs.get(JabRefPreferences.EXTERNAL_FILE_TYPES, null) == null) {
- externalFileTypes.clear();
- externalFileTypes.addAll(types);
- return;
- }
- // Read the prefs information for file types:
- String[][] vals = StringUtil
- .decodeStringDoubleArray(Globals.prefs.get(JabRefPreferences.EXTERNAL_FILE_TYPES, ""));
- for (String[] val : vals) {
- if ((val.length == 2) && val[1].equals(FILE_TYPE_REMOVED_FLAG)) {
- // This entry indicates that a default entry type should be removed:
- ExternalFileType toRemove = null;
- for (ExternalFileType type : types) {
- if (type.getName().equals(val[0])) {
- toRemove = type;
- break;
- }
- }
- // If we found it, remove it from the type list:
- if (toRemove != null) {
- types.remove(toRemove);
- }
- } else {
- // A new or modified entry type. Construct it from the string array:
- ExternalFileType type = ExternalFileType.buildFromArgs(val);
- // Check if there is a default type with the same name. If so, this is a
- // modification of that type, so remove the default one:
- ExternalFileType toRemove = null;
- for (ExternalFileType defType : types) {
- if (type.getName().equals(defType.getName())) {
- toRemove = defType;
- break;
- }
- }
- // If we found it, remove it from the type list:
- if (toRemove != null) {
- types.remove(toRemove);
- }
-
- // Then add the new one:
- types.add(type);
- }
- }
-
- // Finally, build the list of types based on the modified defaults list:
- for (ExternalFileType type : types) {
- externalFileTypes.add(type);
- }
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/external/FindFullTextAction.java b/src/main/java/net/sf/jabref/external/FindFullTextAction.java
deleted file mode 100644
index 50ae73b..0000000
--- a/src/main/java/net/sf/jabref/external/FindFullTextAction.java
+++ /dev/null
@@ -1,90 +0,0 @@
-package net.sf.jabref.external;
-
-import java.io.IOException;
-import java.net.URL;
-import java.util.List;
-import java.util.Optional;
-
-import javax.swing.JOptionPane;
-
-import net.sf.jabref.gui.BasePanel;
-import net.sf.jabref.gui.FileListTableModel;
-import net.sf.jabref.gui.undo.UndoableFieldChange;
-import net.sf.jabref.gui.worker.AbstractWorker;
-import net.sf.jabref.logic.importer.FulltextFetchers;
-import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.model.entry.FieldName;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * Try to download fulltext PDF for selected entry(ies) by following URL or DOI link.
- */
-public class FindFullTextAction extends AbstractWorker {
- private static final Log LOGGER = LogFactory.getLog(FindFullTextAction.class);
-
- private final BasePanel basePanel;
- private BibEntry entry;
- private Optional<URL> result;
-
- public FindFullTextAction(BasePanel basePanel) {
- this.basePanel = basePanel;
- }
-
- @Override
- public void init() throws Throwable {
- basePanel.output(Localization.lang("Looking for full text document..."));
- }
-
- @Override
- public void run() {
- if (basePanel.getSelectedEntries().size() != 1) {
- basePanel.output(Localization.lang("This operation requires exactly one item to be selected."));
- result = Optional.empty();
- } else {
- entry = basePanel.getSelectedEntries().get(0);
- FulltextFetchers fft = new FulltextFetchers();
- result = fft.findFullTextPDF(entry);
- }
- }
-
- @Override
- public void update() {
- if (result.isPresent()) {
- List<String> dirs = basePanel.getBibDatabaseContext().getFileDirectory();
- if (dirs.isEmpty()) {
- JOptionPane.showMessageDialog(basePanel.frame(),
- Localization.lang("Main file directory not set!") + " " + Localization.lang("Preferences")
- + " -> " + Localization.lang("External programs"),
- Localization.lang("Directory not found"), JOptionPane.ERROR_MESSAGE);
- return;
- }
- String bibtexKey = entry.getCiteKey();
- // TODO: this needs its own thread as it blocks the UI!
- DownloadExternalFile def = new DownloadExternalFile(basePanel.frame(), basePanel.getBibDatabaseContext(), bibtexKey);
- try {
- def.download(result.get(), file -> {
- FileListTableModel tm = new FileListTableModel();
- entry.getFieldOptional(FieldName.FILE).ifPresent(tm::setContent);
- tm.addEntry(tm.getRowCount(), file);
- String newValue = tm.getStringRepresentation();
- UndoableFieldChange edit = new UndoableFieldChange(entry, FieldName.FILE,
- entry.getFieldOptional(FieldName.FILE).orElse(null), newValue);
- entry.setField(FieldName.FILE, newValue);
- basePanel.getUndoManager().addEdit(edit);
- basePanel.markBaseChanged();
- });
- } catch (IOException e) {
- LOGGER.warn("Problem downloading file", e);
- }
- basePanel.output(Localization.lang("Finished downloading full text document"));
- }
- else {
- String message = Localization.lang("Full text document download failed");
- basePanel.output(message);
- JOptionPane.showMessageDialog(basePanel.frame(), message, message, JOptionPane.ERROR_MESSAGE);
- }
- }
-}
diff --git a/src/main/java/net/sf/jabref/external/MoveFileAction.java b/src/main/java/net/sf/jabref/external/MoveFileAction.java
deleted file mode 100644
index 59f4f24..0000000
--- a/src/main/java/net/sf/jabref/external/MoveFileAction.java
+++ /dev/null
@@ -1,196 +0,0 @@
-package net.sf.jabref.external;
-
-import java.awt.event.ActionEvent;
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.List;
-import java.util.Locale;
-import java.util.Optional;
-
-import javax.swing.AbstractAction;
-import javax.swing.JOptionPane;
-
-import net.sf.jabref.Globals;
-import net.sf.jabref.gui.FileDialog;
-import net.sf.jabref.gui.FileListEntry;
-import net.sf.jabref.gui.JabRefFrame;
-import net.sf.jabref.gui.entryeditor.EntryEditor;
-import net.sf.jabref.gui.fieldeditors.FileListEditor;
-import net.sf.jabref.gui.util.component.CheckBoxMessage;
-import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.logic.layout.LayoutFormatterPreferences;
-import net.sf.jabref.logic.util.io.FileUtil;
-import net.sf.jabref.preferences.JabRefPreferences;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * Action for moving or renaming a file that is linked to from an entry in JabRef.
- */
-public class MoveFileAction extends AbstractAction {
-
- private static final Log LOGGER = LogFactory.getLog(MoveFileAction.class);
-
- private final JabRefFrame frame;
- private final EntryEditor eEditor;
- private final FileListEditor editor;
-
- private final boolean toFileDir;
-
- private static final String MOVE_RENAME = Localization.lang("Move/Rename file");
-
-
- public MoveFileAction(JabRefFrame frame, EntryEditor eEditor, FileListEditor editor, boolean toFileDir) {
- this.frame = frame;
- this.eEditor = eEditor;
- this.editor = editor;
- this.toFileDir = toFileDir;
- }
-
- @Override
- public void actionPerformed(ActionEvent event) {
- int selected = editor.getSelectedRow();
-
- if (selected == -1) {
- return;
- }
-
- FileListEntry entry = editor.getTableModel().getEntry(selected);
-
- // Check if the current file exists:
- String ln = entry.link;
- boolean httpLink = ln.toLowerCase(Locale.ENGLISH).startsWith("http");
- if (httpLink) {
- // TODO: notify that this operation cannot be done on remote links
- return;
- }
-
- // Get an absolute path representation:
- List<String> dirs = frame.getCurrentBasePanel().getBibDatabaseContext().getFileDirectory();
- int found = -1;
- for (int i = 0; i < dirs.size(); i++) {
- if (new File(dirs.get(i)).exists()) {
- found = i;
- break;
- }
- }
- if (found < 0) {
- JOptionPane.showMessageDialog(frame, Localization.lang("File_directory_is_not_set_or_does_not_exist!"),
- MOVE_RENAME, JOptionPane.ERROR_MESSAGE);
- return;
- }
- File file = new File(ln);
- if (!file.isAbsolute()) {
- file = FileUtil.expandFilename(ln, dirs).orElse(null);
- }
- if ((file != null) && file.exists()) {
- // Ok, we found the file. Now get a new name:
-
- File newFile = null;
- boolean repeat = true;
- while (repeat) {
- repeat = false;
- String chosenFile;
- if (toFileDir) {
- // Determine which name to suggest:
- String suggName = FileUtil
- .createFileNameFromPattern(eEditor.getDatabase(), eEditor.getEntry(),
- Globals.prefs.get(JabRefPreferences.IMPORT_FILENAMEPATTERN),
- LayoutFormatterPreferences.fromPreferences(Globals.prefs,
- Globals.journalAbbreviationLoader))
- .concat(entry.type.isPresent() ? "." + entry.type.get().getExtension() : "");
- CheckBoxMessage cbm = new CheckBoxMessage(Localization.lang("Move file to file directory?"),
- Localization.lang("Rename to '%0'", suggName),
- Globals.prefs.getBoolean(JabRefPreferences.RENAME_ON_MOVE_FILE_TO_FILE_DIR));
- int answer;
- // Only ask about renaming file if the file doesn't have the proper name already:
- if (suggName.equals(file.getName())) {
- answer = JOptionPane.showConfirmDialog(frame, Localization.lang("Move file to file directory?"),
- MOVE_RENAME, JOptionPane.YES_NO_OPTION);
- } else {
- answer = JOptionPane.showConfirmDialog(frame, cbm, MOVE_RENAME, JOptionPane.YES_NO_OPTION);
- }
- if (answer != JOptionPane.YES_OPTION) {
- return;
- }
- Globals.prefs.putBoolean(JabRefPreferences.RENAME_ON_MOVE_FILE_TO_FILE_DIR, cbm.isSelected());
- StringBuilder sb = new StringBuilder(dirs.get(found));
- if (!dirs.get(found).endsWith(File.separator)) {
- sb.append(File.separator);
- }
- if (cbm.isSelected()) {
- // Rename:
- sb.append(suggName);
- } else {
- // Do not rename:
- sb.append(file.getName());
- }
- chosenFile = sb.toString();
- } else {
- Optional<Path> path = new FileDialog(frame, file.getPath()).saveNewFile();
- if (path.isPresent()) {
- chosenFile = path.get().toString();
- } else {
- return;
- }
- }
- newFile = new File(chosenFile);
-
- }
-
- if (!newFile.equals(file)) {
- try {
- boolean success = file.renameTo(newFile);
- if (!success) {
- success = FileUtil.copyFile(file, newFile, true);
- }
- if (success) {
- // Remove the original file:
- Files.deleteIfExists(file.toPath());
-
- // Relativise path, if possible.
- String canPath = new File(dirs.get(found)).getCanonicalPath();
- if (newFile.getCanonicalPath().startsWith(canPath)) {
- if ((newFile.getCanonicalPath().length() > canPath.length())
- && (newFile.getCanonicalPath().charAt(canPath.length()) == File.separatorChar)) {
-
- String newLink = newFile.getCanonicalPath().substring(1 + canPath.length());
- editor.getTableModel().setEntry(selected,
- new FileListEntry(entry.description, newLink, entry.type));
- } else {
- String newLink = newFile.getCanonicalPath().substring(canPath.length());
- editor.getTableModel().setEntry(selected,
- new FileListEntry(entry.description, newLink, entry.type));
- }
-
- } else {
- String newLink = newFile.getCanonicalPath();
- editor.getTableModel().setEntry(selected,
- new FileListEntry(entry.description, newLink, entry.type));
- }
- eEditor.updateField(editor);
- frame.output(Localization.lang("File moved"));
- } else {
- JOptionPane.showMessageDialog(frame, Localization.lang("Move file failed"), MOVE_RENAME,
- JOptionPane.ERROR_MESSAGE);
- }
-
- } catch (SecurityException | IOException ex) {
- LOGGER.warn("Could not move file", ex);
- JOptionPane.showMessageDialog(frame,
- Localization.lang("Could not move file '%0'.", file.getAbsolutePath()) + ex.getMessage(),
- MOVE_RENAME, JOptionPane.ERROR_MESSAGE);
- }
-
- }
- } else {
- // File doesn't exist, so we can't move it.
- JOptionPane.showMessageDialog(frame, Localization.lang("Could not find file '%0'.", entry.link),
- Localization.lang("File not found"), JOptionPane.ERROR_MESSAGE);
- }
-
- }
-}
diff --git a/src/main/java/net/sf/jabref/external/RegExpFileSearch.java b/src/main/java/net/sf/jabref/external/RegExpFileSearch.java
deleted file mode 100644
index d8f218e..0000000
--- a/src/main/java/net/sf/jabref/external/RegExpFileSearch.java
+++ /dev/null
@@ -1,335 +0,0 @@
-package net.sf.jabref.external;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import net.sf.jabref.logic.bibtexkeypattern.BibtexKeyPatternUtil;
-import net.sf.jabref.logic.util.strings.StringUtil;
-import net.sf.jabref.model.database.BibDatabase;
-import net.sf.jabref.model.entry.BibEntry;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * Created by IntelliJ IDEA.
- * User: alver
- * Date: Apr 12, 2008
- * Time: 1:46:44 PM
- * To change this template use File | Settings | File Templates.
- */
-public class RegExpFileSearch {
-
- private static final Log LOGGER = LogFactory.getLog(RegExpFileSearch.class);
-
- private static final String EXT_MARKER = "__EXTENSION__";
-
- private static final Pattern ESCAPE_PATTERN = Pattern.compile("([^\\\\])\\\\([^\\\\])");
-
- private static final Pattern SQUARE_BRACKETS_PATTERN = Pattern.compile("\\[.*?\\]");
-
-
- /**
- * Search for file links for a set of entries using regexp. Lists of extensions and directories
- * are given.
- * @param entries The entries to search for.
- * @param extensions The extensions that are acceptable.
- * @param directories The root directories to search.
- * @param regExp The expression deciding which names are acceptable.
- * @return A map linking each given entry to a list of files matching the given criteria.
- */
- public static Map<BibEntry, List<File>> findFilesForSet(List<BibEntry> entries, List<String> extensions,
- List<File> directories, String regExp) {
-
- Map<BibEntry, List<File>> res = new HashMap<>();
- for (BibEntry entry : entries) {
- res.put(entry, findFiles(entry, extensions, directories, regExp));
- }
- return res;
- }
-
- /**
- * Method for searching for files using regexp. A list of extensions and directories can be
- * given.
- * @param entry The entry to search for.
- * @param extensions The extensions that are acceptable.
- * @param directories The root directories to search.
- * @param regularExpression The expression deciding which names are acceptable.
- * @return A list of files paths matching the given criteria.
- */
- private static List<File> findFiles(BibEntry entry, List<String> extensions, List<File> directories,
- String regularExpression) {
-
- String extensionRegExp = '(' + String.join("|", extensions) + ')';
-
- return findFile(entry, directories, regularExpression, extensionRegExp);
- }
-
- /**
- * Searches the given directory and filename pattern for a file for the
- * BibTeX entry.
- *
- * Used to fix:
- *
- * http://sourceforge.net/tracker/index.php?func=detail&aid=1503410&group_id=92314&atid=600309
- *
- * Requirements:
- * - Be able to find the associated PDF in a set of given directories.
- * - Be able to return a relative path or absolute path.
- * - Be fast.
- * - Allow for flexible naming schemes in the PDFs.
- *
- * Syntax scheme for file:
- * <ul>
- * <li>* Any subDir</li>
- * <li>** Any subDir (recursive)</li>
- * <li>[key] Key from BibTeX file and database</li>
- * <li>.* Anything else is taken to be a Regular expression.</li>
- * </ul>
- *
- * @param entry
- * non-null
- * @param dirs
- * A set of root directories to start the search from. Paths are
- * returned relative to these directories if relative is set to
- * true. These directories will not be expanded or anything. Use
- * the file attribute for this.
- * @param file
- * non-null
- *
- * @param relative
- * whether to return relative file paths or absolute ones
- *
- * @return Will return the first file found to match the given criteria or
- * null if none was found.
- */
- private static List<File> findFile(BibEntry entry, List<File> dirs, String file, String extensionRegExp) {
- List<File> res = new ArrayList<>();
- for (File directory : dirs) {
- res.addAll(findFile(entry, directory.getPath(), file, extensionRegExp));
- }
- return res;
- }
-
- /**
- * Internal Version of findFile, which also accepts a current directory to
- * base the search on.
- *
- */
- private static List<File> findFile(BibEntry entry, String directory, String file, String extensionRegExp) {
-
- File root;
- if (directory == null) {
- root = new File(".");
- } else {
- root = new File(directory);
- }
- if (!root.exists()) {
- return Collections.emptyList();
- }
- List<File> fileList = RegExpFileSearch.findFile(entry, root, file, extensionRegExp);
-
- List<File> result = new ArrayList<>();
- for (File tmpFile : fileList) {
- try {
- /**
- * [ 1601651 ] PDF subdirectory - missing first character
- *
- * http://sourceforge.net/tracker/index.php?func=detail&aid=1601651&group_id=92314&atid=600306
- */
- // Changed by M. Alver 2007.01.04:
- // Remove first character if it is a directory separator character:
- String tmp = tmpFile.getCanonicalPath().substring(root.getCanonicalPath().length());
- if ((tmp.length() > 1) && (tmp.charAt(0) == File.separatorChar)) {
- tmp = tmp.substring(1);
- }
- result.add(new File(tmp));
-
- } catch (IOException e) {
- LOGGER.warn("Problem searching", e);
- }
- }
- return result;
- }
-
- /**
- * The actual work-horse. Will find absolute filepaths starting from the
- * given directory using the given regular expression string for search.
- */
- private static List<File> findFile(BibEntry entry, File directory, String file, String extensionRegExp) {
-
- List<File> res = new ArrayList<>();
-
- File actualDirectory;
- if (file.startsWith("/")) {
- actualDirectory = new File(".");
- file = file.substring(1);
- } else {
- actualDirectory = directory;
- }
-
- // Escape handling...
- Matcher m = ESCAPE_PATTERN.matcher(file);
- StringBuffer s = new StringBuffer();
- while (m.find()) {
- m.appendReplacement(s, m.group(1) + '/' + m.group(2));
- }
- m.appendTail(s);
- file = s.toString();
- String[] fileParts = file.split("/");
-
- if (fileParts.length == 0) {
- return res;
- }
-
- for (int i = 0; i < (fileParts.length - 1); i++) {
-
- String dirToProcess = fileParts[i];
- dirToProcess = expandBrackets(dirToProcess, entry, null);
-
- if (dirToProcess.matches("^.:$")) { // Windows Drive Letter
- actualDirectory = new File(dirToProcess + '/');
- continue;
- }
- if (".".equals(dirToProcess)) { // Stay in current directory
- continue;
- }
- if ("..".equals(dirToProcess)) {
- actualDirectory = new File(actualDirectory.getParent());
- continue;
- }
- if ("*".equals(dirToProcess)) { // Do for all direct subdirs
-
- File[] subDirs = actualDirectory.listFiles();
- if (subDirs != null) {
- String restOfFileString = StringUtil.join(fileParts, "/", i + 1, fileParts.length);
- for (File subDir : subDirs) {
- if (subDir.isDirectory()) {
- res.addAll(findFile(entry, subDir, restOfFileString, extensionRegExp));
- }
- }
- }
- }
- // Do for all direct and indirect subdirs
- if ("**".equals(dirToProcess)) {
- List<File> toDo = new LinkedList<>();
- toDo.add(actualDirectory);
-
- String restOfFileString = StringUtil.join(fileParts, "/", i + 1, fileParts.length);
-
- while (!toDo.isEmpty()) {
-
- // Get all subdirs of each of the elements found in toDo
- File[] subDirs = toDo.remove(0).listFiles();
- if (subDirs == null) {
- continue;
- }
-
- toDo.addAll(Arrays.asList(subDirs));
-
- for (File subDir : subDirs) {
- if (!subDir.isDirectory()) {
- continue;
- }
- res.addAll(findFile(entry, subDir, restOfFileString, extensionRegExp));
- }
- }
-
- } // End process directory information
- }
-
- // Last step: check if the given file can be found in this directory
- String filePart = fileParts[fileParts.length - 1].replace("[extension]", EXT_MARKER);
- String filenameToLookFor = expandBrackets(filePart, entry, null).replaceAll(EXT_MARKER, extensionRegExp);
- final Pattern toMatch = Pattern.compile('^' + filenameToLookFor.replaceAll("\\\\\\\\", "\\\\") + '$',
- Pattern.CASE_INSENSITIVE);
-
- File[] matches = actualDirectory.listFiles((arg0, arg1) -> {
- return toMatch.matcher(arg1).matches();
- });
- if ((matches != null) && (matches.length > 0)) {
- Collections.addAll(res, matches);
- }
- return res;
- }
-
- /**
- * Takes a string that contains bracketed expression and expands each of these using getFieldAndFormat.
- * <p>
- * Unknown Bracket expressions are silently dropped.
- *
- * @param bracketString
- * @param entry
- * @param database
- * @return
- */
- public static String expandBrackets(String bracketString, BibEntry entry, BibDatabase database) {
- Matcher m = SQUARE_BRACKETS_PATTERN.matcher(bracketString);
- StringBuffer s = new StringBuffer();
- while (m.find()) {
- String replacement = getFieldAndFormat(m.group(), entry, database);
- m.appendReplacement(s, replacement);
- }
- m.appendTail(s);
-
- return s.toString();
- }
-
- /**
- * Accepts a string like [author:lower] or [title:abbr] or [auth], whereas the first part signifies the bibtex-field
- * to get, or the key generator field marker to use, while the others are the modifiers that will be applied.
- *
- * @param fieldAndFormat
- * @param entry
- * @param database
- * @return
- */
- public static String getFieldAndFormat(String fieldAndFormat, BibEntry entry, BibDatabase database) {
-
- String strippedFieldAndFormat = StringUtil.stripBrackets(fieldAndFormat);
-
- int colon = strippedFieldAndFormat.indexOf(':');
-
- String beforeColon;
- String afterColon;
- if (colon == -1) {
- beforeColon = strippedFieldAndFormat;
- afterColon = null;
- } else {
- beforeColon = strippedFieldAndFormat.substring(0, colon);
- afterColon = strippedFieldAndFormat.substring(colon + 1);
- }
- beforeColon = beforeColon.trim();
-
- if (beforeColon.isEmpty()) {
- return "";
- }
-
- // If no field value was found, try to interpret it as a key generator field marker:
- String fieldValue = BibDatabase.getResolvedField(beforeColon, entry, database)
- .orElse(BibtexKeyPatternUtil.makeLabel(entry, beforeColon));
-
- if (fieldValue == null) {
- return "";
- }
-
- if ((afterColon == null) || afterColon.isEmpty()) {
- return fieldValue;
- }
-
- String[] parts = afterColon.split(":");
- fieldValue = BibtexKeyPatternUtil.applyModifiers(fieldValue, parts, 0);
-
- return fieldValue;
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/external/SynchronizeFileField.java b/src/main/java/net/sf/jabref/external/SynchronizeFileField.java
deleted file mode 100644
index 6931b46..0000000
--- a/src/main/java/net/sf/jabref/external/SynchronizeFileField.java
+++ /dev/null
@@ -1,397 +0,0 @@
-package net.sf.jabref.external;
-
-import java.awt.BorderLayout;
-import java.awt.event.ActionEvent;
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Locale;
-import java.util.Optional;
-import java.util.Set;
-
-import javax.swing.AbstractAction;
-import javax.swing.Action;
-import javax.swing.ActionMap;
-import javax.swing.BorderFactory;
-import javax.swing.ButtonGroup;
-import javax.swing.InputMap;
-import javax.swing.JButton;
-import javax.swing.JCheckBox;
-import javax.swing.JComponent;
-import javax.swing.JDialog;
-import javax.swing.JFrame;
-import javax.swing.JLabel;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JRadioButton;
-
-import net.sf.jabref.BibDatabaseContext;
-import net.sf.jabref.Globals;
-import net.sf.jabref.JabRefExecutorService;
-import net.sf.jabref.gui.BasePanel;
-import net.sf.jabref.gui.FileListEntry;
-import net.sf.jabref.gui.FileListEntryEditor;
-import net.sf.jabref.gui.FileListTableModel;
-import net.sf.jabref.gui.IconTheme;
-import net.sf.jabref.gui.keyboard.KeyBinding;
-import net.sf.jabref.gui.undo.NamedCompound;
-import net.sf.jabref.gui.undo.UndoableFieldChange;
-import net.sf.jabref.gui.util.FocusRequester;
-import net.sf.jabref.gui.worker.AbstractWorker;
-import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.logic.util.io.FileUtil;
-import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.model.entry.FieldName;
-
-import com.jgoodies.forms.builder.ButtonBarBuilder;
-import com.jgoodies.forms.builder.FormBuilder;
-import com.jgoodies.forms.layout.FormLayout;
-
-/**
- * This action goes through all selected entries in the BasePanel, and attempts to autoset the
- * given external file (pdf, ps, ...) based on the same algorithm used for the "Auto" button in
- * EntryEditor.
- */
-public class SynchronizeFileField extends AbstractWorker {
-
- private final BasePanel panel;
- private List<BibEntry> sel;
- private SynchronizeFileField.OptionsDialog optDiag;
-
- private int entriesChangedCount;
-
- private final Object[] brokenLinkOptions = {Localization.lang("Ignore"), Localization.lang("Assign new file"),
- Localization.lang("Remove link"), Localization.lang("Remove all broken links"),
- Localization.lang("Quit synchronization")};
-
- private boolean goOn = true;
- private boolean autoSet = true;
- private boolean checkExisting = true;
-
-
- public SynchronizeFileField(BasePanel panel) {
- this.panel = panel;
- }
-
- @Override
- public void init() {
- Collection<BibEntry> col = panel.getDatabase().getEntries();
- goOn = true;
- sel = new ArrayList<>(col);
-
- // Ask about rules for the operation:
- if (optDiag == null) {
- optDiag = new SynchronizeFileField.OptionsDialog(panel.frame(), panel.getBibDatabaseContext());
- }
- optDiag.setLocationRelativeTo(panel.frame());
- optDiag.setVisible(true);
- if (optDiag.canceled()) {
- goOn = false;
- return;
- }
- autoSet = !optDiag.isAutoSetNone();
- checkExisting = optDiag.isCheckLinks();
-
- panel.output(Localization.lang("Synchronizing file links..."));
- }
-
- @Override
- public void run() {
- if (!goOn) {
- panel.output(Localization.lang("This operation requires one or more entries to be selected."));
- return;
- }
- entriesChangedCount = 0;
- panel.frame().setProgressBarValue(0);
- panel.frame().setProgressBarVisible(true);
- int weightAutoSet = 10; // autoSet takes 10 (?) times longer than checkExisting
- int progressBarMax = (autoSet ? weightAutoSet * sel.size() : 0) + (checkExisting ? sel.size() : 0);
- panel.frame().setProgressBarMaximum(progressBarMax);
- int progress = 0;
- final NamedCompound ce = new NamedCompound(Localization.lang("Automatically set file links"));
-
- Set<BibEntry> changedEntries = new HashSet<>();
-
- // First we try to autoset fields
- if (autoSet) {
- List<BibEntry> entries = new ArrayList<>(sel);
-
- // Start the automatically setting process:
- Runnable r = AutoSetLinks.autoSetLinks(entries, ce, changedEntries, null, panel.getBibDatabaseContext(), null, null);
- JabRefExecutorService.INSTANCE.executeAndWait(r);
- }
- progress += sel.size() * weightAutoSet;
- panel.frame().setProgressBarValue(progress);
- // The following loop checks all external links that are already set.
- if (checkExisting) {
- boolean removeAllBroken = false;
- mainLoop: for (BibEntry aSel : sel) {
- panel.frame().setProgressBarValue(progress++);
- final Optional<String> old = aSel.getFieldOptional(FieldName.FILE);
- // Check if a extension is set:
- if (old.isPresent() && !(old.get().isEmpty())) {
- FileListTableModel tableModel = new FileListTableModel();
- tableModel.setContentDontGuessTypes(old.get());
-
- // We need to specify which directories to search in for Util.expandFilename:
- List<String> dirsS = panel.getBibDatabaseContext().getFileDirectory();
- List<File> dirs = new ArrayList<>();
- for (String dirs1 : dirsS) {
- dirs.add(new File(dirs1));
- }
-
- for (int j = 0; j < tableModel.getRowCount(); j++) {
- FileListEntry flEntry = tableModel.getEntry(j);
- // See if the link looks like an URL:
- boolean httpLink = flEntry.link.toLowerCase(Locale.ENGLISH).startsWith("http");
- if (httpLink) {
- continue; // Don't check the remote file.
- // TODO: should there be an option to check remote links?
- }
-
- // A variable to keep track of whether this link gets deleted:
- boolean deleted = false;
-
- // Get an absolute path representation:
- Optional<File> file = FileUtil.expandFilename(flEntry.link, dirsS);
- if ((!file.isPresent()) || !file.get().exists()) {
- int answer;
- if (removeAllBroken) {
- answer = 2; // We should delete this link.
- } else {
- answer = JOptionPane.showOptionDialog(panel.frame(),
- Localization.lang("<HTML>Could not find file '%0'<BR>linked from entry '%1'</HTML>",
- flEntry.link,
- aSel.getCiteKeyOptional().orElse(Localization.lang("undefined"))),
- Localization.lang("Broken link"),
- JOptionPane.YES_NO_CANCEL_OPTION,
- JOptionPane.QUESTION_MESSAGE, null, brokenLinkOptions, brokenLinkOptions[0]
- );
- }
- switch (answer) {
- case 1:
- // Assign new file.
- FileListEntryEditor flEditor = new FileListEntryEditor
- (panel.frame(), flEntry, false, true, panel.getBibDatabaseContext());
- flEditor.setVisible(true, true);
- break;
- case 2:
- // Clear field:
- tableModel.removeEntry(j);
- deleted = true; // Make sure we don't investigate this link further.
- j--; // Step back in the iteration, because we removed an entry.
- break;
- case 3:
- // Clear field:
- tableModel.removeEntry(j);
- deleted = true; // Make sure we don't investigate this link further.
- j--; // Step back in the iteration, because we removed an entry.
- removeAllBroken = true; // Notify for further cases.
- break;
- default:
- // Cancel
- break mainLoop;
- }
- }
-
- // Unless we deleted this link, see if its file type is recognized:
- if (!deleted && flEntry.type.isPresent()
- && (flEntry.type.get() instanceof UnknownExternalFileType)) {
- String[] options = new String[] {
- Localization.lang("Define '%0'", flEntry.type.get().getName()),
- Localization.lang("Change file type"),
- Localization.lang("Cancel")};
- String defOption = options[0];
- int answer = JOptionPane.showOptionDialog(panel.frame(), Localization.lang("One or more file links are of the type '%0', which is undefined. What do you want to do?",
- flEntry.type.get().getName()),
- Localization.lang("Undefined file type"), JOptionPane.YES_NO_CANCEL_OPTION,
- JOptionPane.QUESTION_MESSAGE, null, options, defOption
- );
- if (answer == JOptionPane.CANCEL_OPTION) {
- // User doesn't want to handle this unknown link type.
- } else if (answer == JOptionPane.YES_OPTION) {
- // User wants to define the new file type. Show the dialog:
- ExternalFileType newType = new ExternalFileType(flEntry.type.get().getName(), "", "",
- "", "new", IconTheme.JabRefIcon.FILE.getSmallIcon());
- ExternalFileTypeEntryEditor editor = new ExternalFileTypeEntryEditor(panel.frame(), newType);
- editor.setVisible(true);
- if (editor.okPressed()) {
- // Get the old list of types, add this one, and update the list in prefs:
- List<ExternalFileType> fileTypes = new ArrayList<>(
- ExternalFileTypes.getInstance().getExternalFileTypeSelection());
- fileTypes.add(newType);
- Collections.sort(fileTypes);
- ExternalFileTypes.getInstance().setExternalFileTypes(fileTypes);
- panel.getMainTable().repaint();
- }
- } else {
- // User wants to change the type of this link.
- // First get a model of all file links for this entry:
- FileListEntryEditor editor = new FileListEntryEditor
- (panel.frame(), flEntry, false, true, panel.getBibDatabaseContext());
- editor.setVisible(true, false);
- }
- }
- }
-
- if (!tableModel.getStringRepresentation().equals(old.orElse(null))) {
- // The table has been modified. Store the change:
- String toSet = tableModel.getStringRepresentation();
- if (toSet.isEmpty()) {
- ce.addEdit(new UndoableFieldChange(aSel, FieldName.FILE, old.orElse(null), null));
- aSel.clearField(FieldName.FILE);
- } else {
- ce.addEdit(new UndoableFieldChange(aSel, FieldName.FILE, old.orElse(null), toSet));
- aSel.setField(FieldName.FILE, toSet);
- }
- changedEntries.add(aSel);
- }
-
- }
- }
- }
-
- if (!changedEntries.isEmpty()) {
- // Add the undo edit:
- ce.end();
- panel.getUndoManager().addEdit(ce);
- panel.markBaseChanged();
- entriesChangedCount = changedEntries.size();
- }
- }
-
- @Override
- public void update() {
- if (!goOn) {
- return;
- }
-
- panel.output(Localization.lang("Finished synchronizing file links. Entries changed: %0.",
- String.valueOf(entriesChangedCount)));
- panel.frame().setProgressBarVisible(false);
- if (entriesChangedCount > 0) {
- panel.markBaseChanged();
- }
- }
-
-
- static class OptionsDialog extends JDialog {
-
-
- private final JButton ok = new JButton(Localization.lang("OK"));
- private final JButton cancel = new JButton(Localization.lang("Cancel"));
- private boolean canceled = true;
- private final BibDatabaseContext databaseContext;
- private final JRadioButton autoSetUnset = new JRadioButton(Localization.lang("Automatically set file links")
- + ". " + Localization.lang("Do not overwrite existing links."), true);
- private final JRadioButton autoSetAll = new JRadioButton(Localization.lang("Automatically set file links")
- + ". " + Localization.lang("Allow overwriting existing links."), false);
- private final JRadioButton autoSetNone = new JRadioButton(Localization.lang("Do not automatically set"), false);
- private final JCheckBox checkLinks = new JCheckBox(Localization.lang("Check existing file links"), true);
-
-
- public OptionsDialog(JFrame parent, BibDatabaseContext databaseContext) {
- super(parent, Localization.lang("Synchronize file links"), true);
- this.databaseContext = databaseContext;
- ok.addActionListener(e -> {
- canceled = false;
- dispose();
- });
-
- Action closeAction = new AbstractAction() {
-
- @Override
- public void actionPerformed(ActionEvent e) {
- dispose();
- }
- };
-
- cancel.addActionListener(closeAction);
-
- InputMap im = cancel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
- ActionMap am = cancel.getActionMap();
- im.put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE_DIALOG), "close");
- am.put("close", closeAction);
-
- ButtonGroup bg = new ButtonGroup();
- bg.add(autoSetUnset);
- bg.add(autoSetNone);
- bg.add(autoSetAll);
-
- FormLayout layout = new FormLayout("fill:pref",
- "pref, 2dlu, pref, 2dlu, pref, pref, pref, 2dlu, pref, 2dlu, pref, 2dlu, pref, 2dlu, pref");
- FormBuilder builder = FormBuilder.create().layout(layout);
- JLabel description = new JLabel("<HTML>"
- + Localization
- .lang("Attempt to automatically set file links for your entries. Automatically setting works if "
- + "a file in your file directory<BR>or a subdirectory is named identically to an entry's BibTeX key, plus extension.")
- + "</HTML>");
-
- builder.addSeparator(Localization.lang("Automatically set file links")).xy(1, 1);
- builder.add(description).xy(1, 3);
- builder.add(autoSetUnset).xy(1, 5);
- builder.add(autoSetAll).xy(1, 6);
- builder.add(autoSetNone).xy(1, 7);
- builder.addSeparator(Localization.lang("Check links")).xy(1, 9);
-
- description = new JLabel("<HTML>"
- + Localization
- .lang("This makes JabRef look up each file link and check if the file exists. If not, you will be given options<BR>to resolve the problem.")
- + "</HTML>");
- builder.add(description).xy(1, 11);
- builder.add(checkLinks).xy(1, 13);
- builder.addSeparator("").xy(1, 15);
-
- JPanel main = builder.getPanel();
- main.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
-
- ButtonBarBuilder bb = new ButtonBarBuilder();
- bb.addGlue();
- bb.addButton(ok);
- bb.addButton(cancel);
- bb.addGlue();
- getContentPane().add(main, BorderLayout.CENTER);
- getContentPane().add(bb.getPanel(), BorderLayout.SOUTH);
-
- pack();
- }
-
- @Override
- public void setVisible(boolean visible) {
- if (visible) {
- canceled = true;
- }
-
- List<String> dirs = databaseContext.getFileDirectory();
- if (dirs.isEmpty()) {
- autoSetNone.setSelected(true);
- autoSetNone.setEnabled(false);
- autoSetAll.setEnabled(false);
- autoSetUnset.setEnabled(false);
- } else {
- autoSetNone.setEnabled(true);
- autoSetAll.setEnabled(true);
- autoSetUnset.setEnabled(true);
- }
-
- new FocusRequester(ok);
- super.setVisible(visible);
-
- }
-
- public boolean isAutoSetNone() {
- return autoSetNone.isSelected();
- }
-
- public boolean isCheckLinks() {
- return checkLinks.isSelected();
- }
-
- public boolean canceled() {
- return canceled;
- }
- }
-}
diff --git a/src/main/java/net/sf/jabref/external/TransferableFileLinkSelection.java b/src/main/java/net/sf/jabref/external/TransferableFileLinkSelection.java
deleted file mode 100644
index a80706b..0000000
--- a/src/main/java/net/sf/jabref/external/TransferableFileLinkSelection.java
+++ /dev/null
@@ -1,105 +0,0 @@
-package net.sf.jabref.external;
-
-import java.awt.datatransfer.DataFlavor;
-import java.awt.datatransfer.Transferable;
-import java.awt.datatransfer.UnsupportedFlavorException;
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-import net.sf.jabref.gui.BasePanel;
-import net.sf.jabref.gui.FileListTableModel;
-import net.sf.jabref.logic.util.io.FileUtil;
-import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.model.entry.FieldName;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- *
- */
-public class TransferableFileLinkSelection implements Transferable {
-
- private final List<File> fileList = new ArrayList<>();
-
- private static final Log LOGGER = LogFactory.getLog(TransferableFileLinkSelection.class);
-
-
- public TransferableFileLinkSelection(BasePanel panel, List<BibEntry> selection) {
- FileListTableModel tm = new FileListTableModel();
- selection.get(0).getFieldOptional(FieldName.FILE).ifPresent(tm::setContent);
- if (tm.getRowCount() > 0) {
- // Find the default directory for this field type, if any:
- List<String> dirs = panel.getBibDatabaseContext().getFileDirectory();
- FileUtil.expandFilename(tm.getEntry(0).link, dirs).ifPresent(fileList::add);
- }
-
- }
-
- @Override
- public DataFlavor[] getTransferDataFlavors() {
- return new DataFlavor[] {DataFlavor.javaFileListFlavor};//, DataFlavor.stringFlavor};
- }
-
- @Override
- public boolean isDataFlavorSupported(DataFlavor dataFlavor) {
- LOGGER.debug("Query: " + dataFlavor.getHumanPresentableName() + " , "
- +
- dataFlavor.getDefaultRepresentationClass() + " , " + dataFlavor.getMimeType());
- return dataFlavor.equals(DataFlavor.javaFileListFlavor)
- || dataFlavor.equals(DataFlavor.stringFlavor);
- }
-
- @Override
- public Object getTransferData(DataFlavor dataFlavor) throws UnsupportedFlavorException, IOException {
- //if (dataFlavor.equals(DataFlavor.javaFileListFlavor))
- return fileList;
- //else
- // return "test";
- }
- /*
- private StringSelection ss;
-
- public TransferableFileLinkSelection(BasePanel panel, BibEntry[] selection) {
- String s = selection[0].getField(GUIGlobals.FILE_FIELD);
- FileListTableModel tm = new FileListTableModel();
- if (s != null)
- tm.setContent(s);
- if (tm.getRowCount() > 0) {
- // Find the default directory for this field type, if any:
- String dir = panel.metaData().getFileDirectory(GUIGlobals.FILE_FIELD);
- // Include the standard "file" directory:
- String fileDir = panel.metaData().getFileDirectory(GUIGlobals.FILE_FIELD);
- // Include the directory of the BIB file:
- String[] dirs;
- if (panel.metaData().getDatabaseFile() != null) {
- String databaseDir = panel.metaData().getDatabaseFile().getParent();
- dirs = new String[] { dir, fileDir, databaseDir };
- }
- else
- dirs = new String[] { dir, fileDir };
- System.out.println(tm.getEntry(0).getLink());
- for (int i = 0; i < dirs.length; i++) {
- String dir1 = dirs[i];
- System.out.println("dir:"+dir1);
- }
- File expLink = Util.expandFilename(tm.getEntry(0).getLink(), dirs);
- try {
- System.out.println(expLink.toURI().toURL().toString());
- ss = new StringSelection(expLink.toURI().toURL().toString());
-
- } catch (MalformedURLException ex) {
- ss = new StringSelection("");
- }
- }
- else
- ss = new StringSelection("");
-
- }
-
- public Transferable getTransferable() {
- return ss;
- } */
-}
diff --git a/src/main/java/net/sf/jabref/external/UnknownExternalFileType.java b/src/main/java/net/sf/jabref/external/UnknownExternalFileType.java
deleted file mode 100644
index 46a811a..0000000
--- a/src/main/java/net/sf/jabref/external/UnknownExternalFileType.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package net.sf.jabref.external;
-
-import net.sf.jabref.gui.IconTheme;
-
-/**
- * This subclass of ExternalFileType is used to mark types that are unknown.
- * This can be the case when a database is loaded which contains links to files
- * of a type that has not been defined on this JabRef instance.
- */
-public class UnknownExternalFileType extends ExternalFileType {
-
- public UnknownExternalFileType(String name) {
- super(name, "", "", "", "unknown", IconTheme.JabRefIcon.FILE.getSmallIcon());
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/external/WriteXMPAction.java b/src/main/java/net/sf/jabref/external/WriteXMPAction.java
deleted file mode 100644
index f23bf88..0000000
--- a/src/main/java/net/sf/jabref/external/WriteXMPAction.java
+++ /dev/null
@@ -1,293 +0,0 @@
-package net.sf.jabref.external;
-
-import java.awt.BorderLayout;
-import java.awt.Color;
-import java.awt.Dimension;
-import java.awt.event.ActionEvent;
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-import javax.swing.AbstractAction;
-import javax.swing.ActionMap;
-import javax.swing.BorderFactory;
-import javax.swing.InputMap;
-import javax.swing.JButton;
-import javax.swing.JComponent;
-import javax.swing.JDialog;
-import javax.swing.JFrame;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.JTextArea;
-import javax.swing.SwingUtilities;
-
-import net.sf.jabref.Globals;
-import net.sf.jabref.gui.BasePanel;
-import net.sf.jabref.gui.FileListEntry;
-import net.sf.jabref.gui.FileListTableModel;
-import net.sf.jabref.gui.keyboard.KeyBinding;
-import net.sf.jabref.gui.util.FocusRequester;
-import net.sf.jabref.gui.worker.AbstractWorker;
-import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.logic.util.io.FileUtil;
-import net.sf.jabref.logic.xmp.XMPPreferences;
-import net.sf.jabref.logic.xmp.XMPUtil;
-import net.sf.jabref.model.database.BibDatabase;
-import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.model.entry.FieldName;
-
-import com.jgoodies.forms.builder.ButtonBarBuilder;
-
-/**
- *
- * This action goes through all selected entries in the BasePanel, and attempts
- * to write the XMP data to the external pdf.
- */
-public class WriteXMPAction extends AbstractWorker {
-
- private final BasePanel panel;
-
- private Collection<BibEntry> entries;
-
- private BibDatabase database;
-
- private OptionsDialog optDiag;
-
- private boolean goOn = true;
-
- private int skipped;
- private int entriesChanged;
- private int errors;
-
-
- public WriteXMPAction(BasePanel panel) {
- this.panel = panel;
- }
-
- @Override
- public void init() {
-
- database = panel.getDatabase();
- // Get entries and check if it makes sense to perform this operation
- entries = panel.getSelectedEntries();
-
- if (entries.isEmpty()) {
-
- entries = database.getEntries();
-
- if (entries.isEmpty()) {
-
- JOptionPane.showMessageDialog(panel,
- Localization.lang("This operation requires one or more entries to be selected."),
- Localization.lang("Write XMP-metadata"), JOptionPane.ERROR_MESSAGE);
- goOn = false;
- return;
-
- } else {
-
- int response = JOptionPane.showConfirmDialog(panel, Localization.lang("Write XMP-metadata for all PDFs in current database?"),
- Localization.lang("Write XMP-metadata"), JOptionPane.YES_NO_CANCEL_OPTION,
- JOptionPane.QUESTION_MESSAGE);
-
- if (response != JOptionPane.YES_OPTION) {
- goOn = false;
- return;
- }
- }
- }
-
- errors = entriesChanged = skipped = 0;
-
- if (optDiag == null) {
- optDiag = new OptionsDialog(panel.frame());
- }
- optDiag.open();
-
- panel.output(Localization.lang("Writing XMP-metadata..."));
- }
-
- @Override
- public void run() {
-
- if (!goOn) {
- return;
- }
-
- for (BibEntry entry : entries) {
-
- // Make a list of all PDFs linked from this entry:
- List<File> files = new ArrayList<>();
-
- // First check the (legacy) "pdf" field:
- entry.getFieldOptional(FieldName.PDF).ifPresent(pdf ->
- FileUtil.expandFilename(pdf, panel.getBibDatabaseContext().getFileDirectory("pdf"))
- .ifPresent(files::add));
- // Then check the "file" field:
- List<String> dirs = panel.getBibDatabaseContext().getFileDirectory();
- if (entry.hasField(FieldName.FILE)) {
- FileListTableModel tm = new FileListTableModel();
- entry.getFieldOptional(FieldName.FILE).ifPresent(tm::setContent);
- for (int j = 0; j < tm.getRowCount(); j++) {
- FileListEntry flEntry = tm.getEntry(j);
- if ((flEntry.type.isPresent()) && "pdf".equalsIgnoreCase(flEntry.type.get().getName())) {
- FileUtil.expandFilename(flEntry.link, dirs).ifPresent(files::add);
- }
- }
- }
-
- SwingUtilities.invokeLater(() -> optDiag.getProgressArea()
- .append(entry.getCiteKeyOptional().orElse(Localization.lang("undefined")) + "\n"));
-
- if (files.isEmpty()) {
- skipped++;
- SwingUtilities.invokeLater(() -> optDiag.getProgressArea()
- .append(" " + Localization.lang("Skipped - No PDF linked") + ".\n"));
- } else {
- for (File file : files) {
- if (file.exists()) {
- try {
- XMPUtil.writeXMP(file, entry, database, XMPPreferences.fromPreferences(Globals.prefs));
- SwingUtilities.invokeLater(
- () -> optDiag.getProgressArea().append(" " + Localization.lang("OK") + ".\n"));
- entriesChanged++;
- } catch (Exception e) {
- SwingUtilities.invokeLater(() -> {
- optDiag.getProgressArea().append(" " + Localization.lang("Error while writing") + " '"
- + file.getPath() + "':\n");
- optDiag.getProgressArea().append(" " + e.getLocalizedMessage() + "\n");
- });
- errors++;
- }
- } else {
- skipped++;
- SwingUtilities.invokeLater(() -> {
- optDiag.getProgressArea()
- .append(" " + Localization.lang("Skipped - PDF does not exist") + ":\n");
- optDiag.getProgressArea().append(" " + file.getPath() + "\n");
- });
- }
- }
- }
-
- if (optDiag.isCanceled()) {
- SwingUtilities.invokeLater(
- () -> optDiag.getProgressArea().append("\n" + Localization.lang("Operation canceled.") + "\n"));
- break;
- }
- }
- SwingUtilities.invokeLater(() -> {
- optDiag.getProgressArea()
- .append("\n"
- + Localization.lang("Finished writing XMP for %0 file (%1 skipped, %2 errors).", String
- .valueOf(entriesChanged), String.valueOf(skipped), String.valueOf(errors)));
- optDiag.done();
- });
- }
-
- @Override
- public void update() {
- if (!goOn) {
- return;
- }
-
- panel.output(Localization.lang("Finished writing XMP for %0 file (%1 skipped, %2 errors).",
- String.valueOf(entriesChanged), String.valueOf(skipped), String.valueOf(errors)));
- }
-
-
- class OptionsDialog extends JDialog {
-
- private final JButton okButton = new JButton(Localization.lang("OK"));
- private final JButton cancelButton = new JButton(Localization.lang("Cancel"));
-
- private boolean canceled;
-
- private final JTextArea progressArea;
-
-
- public OptionsDialog(JFrame parent) {
- super(parent, Localization.lang("Writing XMP-metadata for selected entries..."), false);
- okButton.setEnabled(false);
-
- okButton.addActionListener(e -> dispose());
-
- AbstractAction cancel = new AbstractAction() {
- @Override
- public void actionPerformed(ActionEvent e) {
- canceled = true;
- }
- };
- cancelButton.addActionListener(cancel);
-
- InputMap im = cancelButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
- ActionMap am = cancelButton.getActionMap();
- im.put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE_DIALOG), "close");
- am.put("close", cancel);
-
- progressArea = new JTextArea(15, 60);
-
- JScrollPane scrollPane = new JScrollPane(progressArea,
- JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
- Dimension d = progressArea.getPreferredSize();
- d.height += scrollPane.getHorizontalScrollBar().getHeight() + 15;
- d.width += scrollPane.getVerticalScrollBar().getWidth() + 15;
-
- panel.setSize(d);
-
- progressArea.setBackground(Color.WHITE);
- progressArea.setEditable(false);
- progressArea.setBorder(BorderFactory.createEmptyBorder(3, 3, 3,
- 3));
- progressArea.setText("");
-
- JPanel tmpPanel = new JPanel();
- tmpPanel.setBorder(BorderFactory.createEmptyBorder(3, 2, 3, 2));
- tmpPanel.add(scrollPane);
-
- // progressArea.setPreferredSize(new Dimension(300, 300));
-
- ButtonBarBuilder bb = new ButtonBarBuilder();
- bb.addGlue();
- bb.addButton(okButton);
- bb.addRelatedGap();
- bb.addButton(cancelButton);
- bb.addGlue();
- JPanel bbPanel = bb.getPanel();
- bbPanel.setBorder(BorderFactory.createEmptyBorder(0, 3, 3, 3));
- getContentPane().add(tmpPanel, BorderLayout.CENTER);
- getContentPane().add(bbPanel, BorderLayout.SOUTH);
-
- pack();
- this.setResizable(false);
-
- }
-
- public void done() {
- okButton.setEnabled(true);
- cancelButton.setEnabled(false);
- }
-
- public void open() {
- progressArea.setText("");
- canceled = false;
- optDiag.setLocationRelativeTo(panel.frame());
-
- okButton.setEnabled(false);
- cancelButton.setEnabled(true);
-
- new FocusRequester(okButton);
-
- optDiag.setVisible(true);
- }
-
- public boolean isCanceled() {
- return canceled;
- }
-
- public JTextArea getProgressArea() {
- return progressArea;
- }
- }
-}
diff --git a/src/main/java/net/sf/jabref/external/WriteXMPEntryEditorAction.java b/src/main/java/net/sf/jabref/external/WriteXMPEntryEditorAction.java
deleted file mode 100644
index 90bc368..0000000
--- a/src/main/java/net/sf/jabref/external/WriteXMPEntryEditorAction.java
+++ /dev/null
@@ -1,143 +0,0 @@
-package net.sf.jabref.external;
-
-import java.awt.event.ActionEvent;
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.swing.AbstractAction;
-import javax.swing.Action;
-import javax.xml.transform.TransformerException;
-
-import net.sf.jabref.Globals;
-import net.sf.jabref.gui.BasePanel;
-import net.sf.jabref.gui.FileListEntry;
-import net.sf.jabref.gui.FileListTableModel;
-import net.sf.jabref.gui.IconTheme;
-import net.sf.jabref.gui.entryeditor.EntryEditor;
-import net.sf.jabref.gui.worker.AbstractWorker;
-import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.logic.util.io.FileUtil;
-import net.sf.jabref.logic.xmp.XMPPreferences;
-import net.sf.jabref.logic.xmp.XMPUtil;
-import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.model.entry.FieldName;
-
-/**
- * Write XMP action for EntryEditor toolbar.
- */
-public class WriteXMPEntryEditorAction extends AbstractAction {
-
- private final BasePanel panel;
- private final EntryEditor editor;
- private String message;
-
-
- public WriteXMPEntryEditorAction(BasePanel panel, EntryEditor editor) {
- this.panel = panel;
- this.editor = editor;
- // normally, the next call should be without "Localization.lang". However, the string "Write XMP" is also used in non-menu places and therefore, the translation must be also available at Localization.lang
- putValue(Action.NAME, Localization.lang("Write XMP"));
- putValue(Action.SMALL_ICON, IconTheme.JabRefIcon.WRITE_XMP.getIcon());
- putValue(Action.SHORT_DESCRIPTION, Localization.lang("Write BibTeXEntry as XMP-metadata to PDF."));
- }
-
- @Override
- public void actionPerformed(ActionEvent actionEvent) {
- setEnabled(false);
- panel.output(Localization.lang("Writing XMP-metadata..."));
- panel.frame().setProgressBarIndeterminate(true);
- panel.frame().setProgressBarVisible(true);
- BibEntry entry = editor.getEntry();
-
- // Make a list of all PDFs linked from this entry:
- List<File> files = new ArrayList<>();
-
- // First check the (legacy) "pdf" field:
- entry.getFieldOptional(FieldName.PDF).ifPresent(pdf -> FileUtil
- .expandFilename(pdf, panel.getBibDatabaseContext().getFileDirectory("pdf")).ifPresent(files::add));
-
- // Then check the "file" field:
- List<String> dirs = panel.getBibDatabaseContext().getFileDirectory();
- if (entry.hasField(FieldName.FILE)) {
- FileListTableModel tm = new FileListTableModel();
- entry.getFieldOptional(FieldName.FILE).ifPresent(tm::setContent);
- for (int j = 0; j < tm.getRowCount(); j++) {
- FileListEntry flEntry = tm.getEntry(j);
- if ((flEntry.type.isPresent()) && "pdf".equalsIgnoreCase(flEntry.type.get().getName())) {
- FileUtil.expandFilename(flEntry.link, dirs).ifPresent(files::add);
- }
- }
- }
-
- // We want to offload the actual work to a background thread, so we have a worker
- // thread:
- AbstractWorker worker = new WriteXMPWorker(files, entry);
- // Using Spin, we get a thread that gets synchronously offloaded to a new thread,
- // blocking the execution of this method:
- worker.getWorker().run();
- // After the worker thread finishes, we are unblocked and ready to print the
- // status message:
- panel.output(message);
- panel.frame().setProgressBarVisible(false);
- setEnabled(true);
- }
-
-
- class WriteXMPWorker extends AbstractWorker {
-
- private final List<File> files;
- private final BibEntry entry;
-
-
- public WriteXMPWorker(List<File> files, BibEntry entry) {
-
- this.files = files;
- this.entry = entry;
- }
-
- @Override
- public void run() {
- if (files.isEmpty()) {
- message = Localization.lang("No PDF linked") + ".\n";
- } else {
- int written = 0;
- int error = 0;
- for (File file : files) {
- if (!file.exists()) {
- if (files.size() == 1) {
- message = Localization.lang("PDF does not exist");
- }
- error++;
-
- } else {
- try {
- XMPUtil.writeXMP(file, entry, panel.getDatabase(),
- XMPPreferences.fromPreferences(Globals.prefs));
- if (files.size() == 1) {
- message = Localization.lang("Wrote XMP-metadata");
- }
- written++;
- } catch (IOException | TransformerException e) {
- if (files.size() == 1) {
- message = Localization.lang("Error while writing") + " '" + file.getPath() + "'";
- }
- error++;
-
- }
- }
- }
- if (files.size() > 1) {
- StringBuilder sb = new StringBuilder();
- sb.append(Localization.lang("Finished writing XMP-metadata. Wrote to %0 file(s).",
- String.valueOf(written)));
- if (error > 0) {
- sb.append(' ').append(Localization.lang("Error writing to %0 file(s).", String.valueOf(error)));
- }
- message = sb.toString();
- }
- }
- }
- }
-}
diff --git a/src/main/java/net/sf/jabref/gui/BasePanel.java b/src/main/java/net/sf/jabref/gui/BasePanel.java
index dffaa87..eba7d75 100644
--- a/src/main/java/net/sf/jabref/gui/BasePanel.java
+++ b/src/main/java/net/sf/jabref/gui/BasePanel.java
@@ -20,7 +20,6 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -40,44 +39,47 @@ import javax.swing.tree.TreePath;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
-import net.sf.jabref.BibDatabaseContext;
import net.sf.jabref.Globals;
import net.sf.jabref.JabRefExecutorService;
import net.sf.jabref.collab.ChangeScanner;
import net.sf.jabref.collab.FileUpdateListener;
import net.sf.jabref.collab.FileUpdatePanel;
-import net.sf.jabref.event.source.EntryEventSource;
-import net.sf.jabref.external.AttachFileAction;
-import net.sf.jabref.external.ExternalFileMenuItem;
-import net.sf.jabref.external.ExternalFileType;
-import net.sf.jabref.external.ExternalFileTypes;
-import net.sf.jabref.external.FindFullTextAction;
-import net.sf.jabref.external.RegExpFileSearch;
-import net.sf.jabref.external.SynchronizeFileField;
-import net.sf.jabref.external.WriteXMPAction;
import net.sf.jabref.gui.actions.Actions;
import net.sf.jabref.gui.actions.BaseAction;
import net.sf.jabref.gui.actions.CleanupAction;
+import net.sf.jabref.gui.actions.CopyBibTeXKeyAndLinkAction;
import net.sf.jabref.gui.bibtexkeypattern.SearchFixDuplicateLabels;
import net.sf.jabref.gui.desktop.JabRefDesktop;
import net.sf.jabref.gui.entryeditor.EntryEditor;
import net.sf.jabref.gui.exporter.ExportToClipboardAction;
import net.sf.jabref.gui.exporter.SaveDatabaseAction;
+import net.sf.jabref.gui.externalfiles.FindFullTextAction;
+import net.sf.jabref.gui.externalfiles.SynchronizeFileField;
+import net.sf.jabref.gui.externalfiles.WriteXMPAction;
+import net.sf.jabref.gui.externalfiletype.ExternalFileMenuItem;
+import net.sf.jabref.gui.externalfiletype.ExternalFileType;
+import net.sf.jabref.gui.externalfiletype.ExternalFileTypes;
import net.sf.jabref.gui.fieldeditors.FieldEditor;
+import net.sf.jabref.gui.filelist.AttachFileAction;
+import net.sf.jabref.gui.filelist.FileListEntry;
+import net.sf.jabref.gui.filelist.FileListTableModel;
import net.sf.jabref.gui.groups.GroupAddRemoveDialog;
import net.sf.jabref.gui.groups.GroupSelector;
import net.sf.jabref.gui.groups.GroupTreeNodeViewModel;
import net.sf.jabref.gui.importer.actions.AppendDatabaseAction;
import net.sf.jabref.gui.journals.AbbreviateAction;
import net.sf.jabref.gui.journals.UnabbreviateAction;
+import net.sf.jabref.gui.keyboard.KeyBinding;
import net.sf.jabref.gui.maintable.MainTable;
import net.sf.jabref.gui.maintable.MainTableDataModel;
import net.sf.jabref.gui.maintable.MainTableFormat;
import net.sf.jabref.gui.maintable.MainTableSelectionListener;
-import net.sf.jabref.gui.mergeentries.FetchAndMergeEntry;
import net.sf.jabref.gui.mergeentries.MergeEntriesDialog;
+import net.sf.jabref.gui.mergeentries.MergeWithFetchedEntryAction;
import net.sf.jabref.gui.plaintextimport.TextInputDialog;
-import net.sf.jabref.gui.search.SearchBar;
+import net.sf.jabref.gui.specialfields.SpecialFieldDatabaseChangeListener;
+import net.sf.jabref.gui.specialfields.SpecialFieldValueViewModel;
+import net.sf.jabref.gui.specialfields.SpecialFieldViewModel;
import net.sf.jabref.gui.undo.CountingUndoManager;
import net.sf.jabref.gui.undo.NamedCompound;
import net.sf.jabref.gui.undo.UndoableChangeType;
@@ -85,7 +87,6 @@ import net.sf.jabref.gui.undo.UndoableFieldChange;
import net.sf.jabref.gui.undo.UndoableInsertEntry;
import net.sf.jabref.gui.undo.UndoableKeyChange;
import net.sf.jabref.gui.undo.UndoableRemoveEntry;
-import net.sf.jabref.gui.util.FocusRequester;
import net.sf.jabref.gui.util.component.CheckBoxMessage;
import net.sf.jabref.gui.worker.AbstractWorker;
import net.sf.jabref.gui.worker.CallBack;
@@ -96,7 +97,6 @@ import net.sf.jabref.logic.autocompleter.AutoCompletePreferences;
import net.sf.jabref.logic.autocompleter.AutoCompleter;
import net.sf.jabref.logic.autocompleter.AutoCompleterFactory;
import net.sf.jabref.logic.autocompleter.ContentAutoCompleters;
-import net.sf.jabref.logic.bibtexkeypattern.BibtexKeyPatternPreferences;
import net.sf.jabref.logic.bibtexkeypattern.BibtexKeyPatternUtil;
import net.sf.jabref.logic.exporter.BibtexDatabaseWriter;
import net.sf.jabref.logic.exporter.FileSaveSession;
@@ -106,34 +106,33 @@ import net.sf.jabref.logic.exporter.SaveSession;
import net.sf.jabref.logic.l10n.Encodings;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.layout.Layout;
-import net.sf.jabref.logic.layout.LayoutFormatterPreferences;
import net.sf.jabref.logic.layout.LayoutHelper;
+import net.sf.jabref.logic.search.SearchQuery;
import net.sf.jabref.logic.util.FileExtensions;
import net.sf.jabref.logic.util.UpdateField;
import net.sf.jabref.logic.util.io.FileBasedLock;
import net.sf.jabref.logic.util.io.FileUtil;
+import net.sf.jabref.logic.util.io.RegExpFileSearch;
import net.sf.jabref.model.FieldChange;
+import net.sf.jabref.model.bibtexkeypattern.AbstractBibtexKeyPattern;
import net.sf.jabref.model.database.BibDatabase;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.database.DatabaseLocation;
import net.sf.jabref.model.database.KeyCollisionException;
+import net.sf.jabref.model.database.event.EntryAddedEvent;
+import net.sf.jabref.model.database.event.EntryRemovedEvent;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.EntryType;
import net.sf.jabref.model.entry.FieldName;
import net.sf.jabref.model.entry.IdGenerator;
-import net.sf.jabref.model.event.EntryAddedEvent;
-import net.sf.jabref.model.event.EntryChangedEvent;
+import net.sf.jabref.model.entry.event.EntryChangedEvent;
+import net.sf.jabref.model.entry.event.EntryEventSource;
+import net.sf.jabref.model.entry.specialfields.SpecialField;
+import net.sf.jabref.model.entry.specialfields.SpecialFieldValue;
import net.sf.jabref.preferences.HighlightMatchingGroupPreferences;
import net.sf.jabref.preferences.JabRefPreferences;
+import net.sf.jabref.preferences.PreviewPreferences;
import net.sf.jabref.shared.DBMSSynchronizer;
-import net.sf.jabref.specialfields.Printed;
-import net.sf.jabref.specialfields.Priority;
-import net.sf.jabref.specialfields.Quality;
-import net.sf.jabref.specialfields.Rank;
-import net.sf.jabref.specialfields.ReadStatus;
-import net.sf.jabref.specialfields.Relevance;
-import net.sf.jabref.specialfields.SpecialFieldAction;
-import net.sf.jabref.specialfields.SpecialFieldDatabaseChangeListener;
-import net.sf.jabref.specialfields.SpecialFieldValue;
import ca.odell.glazedlists.event.ListEventListener;
import com.google.common.eventbus.Subscribe;
@@ -143,7 +142,6 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListener {
-
private static final Log LOGGER = LogFactory.getLog(BasePanel.class);
// Divider size for BaseFrame split pane. 0 means non-resizable.
@@ -157,7 +155,6 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
private BasePanelMode mode = BasePanelMode.SHOWING_NOTHING;
private EntryEditor currentEditor;
- private PreviewPanel currentPreview;
private MainTableSelectionListener selectionListener;
private ListEventListener<BibEntry> groupsHighlightListener;
@@ -192,8 +189,6 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
// Variable to prevent erroneous update of back/forward histories at the time
// when a Back or Forward operation is being processed:
private boolean backOrForwardInProgress;
- // To indicate which entry is currently shown.
- private final Map<String, EntryEditor> entryEditors = new HashMap<>();
// in switching between entries.
private PreambleEditor preambleEditor;
@@ -206,9 +201,10 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
private final SidePaneManager sidePaneManager;
- private final SearchBar searchBar;
private ContentAutoCompleters autoCompleters;
+ private SearchQuery currentSearchQuery;
+
public BasePanel(JabRefFrame frame, BibDatabaseContext bibDatabaseContext) {
Objects.requireNonNull(frame);
@@ -220,31 +216,30 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
this.frame = frame;
this.tableModel = new MainTableDataModel(getBibDatabaseContext());
- searchBar = new SearchBar(this);
-
setupMainPanel();
setupActions();
- File file = bibDatabaseContext.getDatabaseFile();
+ this.getDatabase().registerListener(new SearchListener());
// ensure that at each addition of a new entry, the entry is added to the groups interface
this.bibDatabaseContext.getDatabase().registerListener(new GroupTreeListener());
- if (file == null) {
+ Optional<File> file = bibDatabaseContext.getDatabaseFile();
+ if (file.isPresent()) {
+ // Register so we get notifications about outside changes to the file.
+ try {
+ fileMonitorHandle = Globals.getFileUpdateMonitor().addUpdateListener(this, file.get());
+ } catch (IOException ex) {
+ LOGGER.warn("Could not register FileUpdateMonitor", ex);
+ }
+ } else {
if (bibDatabaseContext.getDatabase().hasEntries()) {
// if the database is not empty and no file is assigned,
// the database came from an import and has to be treated somehow
// -> mark as changed
this.baseChanged = true;
}
- } else {
- // Register so we get notifications about outside changes to the file.
- try {
- fileMonitorHandle = Globals.getFileUpdateMonitor().addUpdateListener(this, file);
- } catch (IOException ex) {
- LOGGER.warn("Could not register FileUpdateMonitor", ex);
- }
}
}
@@ -256,9 +251,14 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
public String getTabTitle() {
StringBuilder title = new StringBuilder();
DatabaseLocation databaseLocation = this.bibDatabaseContext.getLocation();
+ boolean isAutosaveEnabled = Globals.prefs.getBoolean(JabRefPreferences.LOCAL_AUTO_SAVE);
if (databaseLocation == DatabaseLocation.LOCAL) {
- if (this.bibDatabaseContext.getDatabaseFile() == null) {
+ if (this.bibDatabaseContext.getDatabaseFile().isPresent()) {
+ // check if file is modified
+ String changeFlag = isModified() && !isAutosaveEnabled ? "*" : "";
+ title.append(this.bibDatabaseContext.getDatabaseFile().get().getName()).append(changeFlag);
+ } else {
title.append(GUIGlobals.UNTITLED_TITLE);
if (getDatabase().hasEntries()) {
@@ -268,13 +268,10 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
// This also happens internally at basepanel to ensure consistency line 224
title.append('*');
}
- } else {
- // check if file is modified
- String changeFlag = isModified() ? "*" : "";
- title.append(this.bibDatabaseContext.getDatabaseFile().getName()).append(changeFlag);
}
} else if (databaseLocation == DatabaseLocation.SHARED) {
- title.append(this.bibDatabaseContext.getDBSynchronizer().getDBName() + " [shared]");
+ title.append(
+ this.bibDatabaseContext.getDBMSSynchronizer().getDBName() + " [" + Localization.lang("shared") + "]");
}
return title.toString();
@@ -307,7 +304,9 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
actions.put(Actions.UNDO, undoAction);
actions.put(Actions.REDO, redoAction);
- actions.put(Actions.FOCUS_TABLE, (BaseAction) () -> new FocusRequester(mainTable));
+ actions.put(Actions.FOCUS_TABLE, (BaseAction) () -> {
+ mainTable.requestFocus();
+ });
// The action for opening an entry editor.
actions.put(Actions.EDIT, (BaseAction) selectionListener::editSignalled);
@@ -327,32 +326,11 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
actions.put(Actions.PRINT_PREVIEW, new PrintPreviewAction());
- //when you modify this action be sure to adjust Actions.DELETE
- //they are the same except of the Localization, delete confirmation and Actions.COPY call
- actions.put(Actions.CUT, (BaseAction) () -> {
- runCommand(Actions.COPY);
- List<BibEntry> entries = mainTable.getSelectedEntries();
- if (entries.isEmpty()) {
- return;
- }
-
- NamedCompound compound = new NamedCompound(
- (entries.size() > 1 ? Localization.lang("cut entries") : Localization.lang("cut entry")));
- for (BibEntry entry : entries) {
- compound.addEdit(new UndoableRemoveEntry(bibDatabaseContext.getDatabase(), entry, BasePanel.this));
- bibDatabaseContext.getDatabase().removeEntry(entry);
- ensureNotShowingBottomPanel(entry);
- }
- compound.end();
- getUndoManager().addEdit(compound);
-
- frame.output(formatOutputMessage(Localization.lang("Cut"), entries.size()));
- markBaseChanged();
- });
+ actions.put(Actions.CUT, (BaseAction) this::cut);
//when you modify this action be sure to adjust Actions.CUT,
//they are the same except of the Localization, delete confirmation and Actions.COPY call
- actions.put(Actions.DELETE, (BaseAction) () -> delete());
+ actions.put(Actions.DELETE, (BaseAction) () -> delete(false));
// The action for pasting entries or cell contents.
// - more robust detection of available content flavors (doesn't only look at first one offered)
@@ -389,12 +367,6 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
});
- // The action for toggling the groups interface
- actions.put(Actions.TOGGLE_GROUPS, (BaseAction) () -> {
- sidePaneManager.toggle("groups");
- frame.groupToggle.setSelected(sidePaneManager.isComponentVisible("groups"));
- });
-
actions.put(FindUnlinkedFilesDialog.ACTION_COMMAND, (BaseAction) () -> {
final FindUnlinkedFilesDialog dialog = new FindUnlinkedFilesDialog(frame, frame, BasePanel.this);
dialog.setLocationRelativeTo(frame);
@@ -428,63 +400,47 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
// Run second, on a different thread:
@Override
public void run() {
- BibEntry bes;
-
- // First check if any entries have keys set already. If so, possibly remove
- // them from consideration, or warn about overwriting keys.
- // This is a partial clone of net.sf.jabref.gui.entryeditor.EntryEditor.GenerateKeyAction.actionPerformed(ActionEvent)
- for (final Iterator<BibEntry> i = entries.iterator(); i.hasNext();) {
- bes = i.next();
- if (bes.hasCiteKey()) {
- if (Globals.prefs.getBoolean(JabRefPreferences.AVOID_OVERWRITING_KEY)) {
- // Remove the entry, because its key is already set:
- i.remove();
- } else if (Globals.prefs.getBoolean(JabRefPreferences.WARN_BEFORE_OVERWRITING_KEY)) {
- // Ask if the user wants to cancel the operation:
- CheckBoxMessage cbm = new CheckBoxMessage(
- Localization.lang("One or more keys will be overwritten. Continue?"),
- Localization.lang("Disable this confirmation dialog"), false);
- final int answer = JOptionPane.showConfirmDialog(frame, cbm,
- Localization.lang("Overwrite keys"), JOptionPane.YES_NO_OPTION);
- if (cbm.isSelected()) {
- Globals.prefs.putBoolean(JabRefPreferences.WARN_BEFORE_OVERWRITING_KEY, false);
- }
- if (answer == JOptionPane.NO_OPTION) {
- // Ok, break off the operation.
- canceled = true;
- return;
- }
- // No need to check more entries, because the user has already confirmed
- // that it's ok to overwrite keys:
- break;
+ // We don't want to generate keys for entries which already have one thus remove the entries
+ if (Globals.prefs.getBoolean(JabRefPreferences.AVOID_OVERWRITING_KEY)) {
+ entries.removeIf(BibEntry::hasCiteKey);
+
+ // if we're going to override some cite keys warn the user about it
+ } else if (Globals.prefs.getBoolean(JabRefPreferences.WARN_BEFORE_OVERWRITING_KEY)) {
+ if (entries.parallelStream().anyMatch(BibEntry::hasCiteKey)) {
+ CheckBoxMessage cbm = new CheckBoxMessage(
+ Localization.lang("One or more keys will be overwritten. Continue?"),
+ Localization.lang("Disable this confirmation dialog"), false);
+ final int answer = JOptionPane.showConfirmDialog(frame, cbm,
+ Localization.lang("Overwrite keys"), JOptionPane.YES_NO_OPTION);
+ Globals.prefs.putBoolean(JabRefPreferences.WARN_BEFORE_OVERWRITING_KEY, !cbm.isSelected());
+
+ // The user doesn't want to overide cite keys
+ if (answer == JOptionPane.NO_OPTION) {
+ canceled = true;
+ return;
}
}
}
- Map<BibEntry, Object> oldvals = new HashMap<>();
- // Iterate again, removing already set keys. This is skipped if overwriting
- // is disabled, since all entries with keys set will have been removed.
- if (!Globals.prefs.getBoolean(JabRefPreferences.AVOID_OVERWRITING_KEY)) {
- for (BibEntry entry : entries) {
- bes = entry;
- // Store the old value:
- oldvals.put(bes, bes.getCiteKeyOptional().orElse(null));
- bibDatabaseContext.getDatabase().setCiteKeyForEntry(bes, null);
- }
- }
-
+ // generate the new cite keys for each entry
final NamedCompound ce = new NamedCompound(Localization.lang("Autogenerate BibTeX keys"));
-
- // Finally, set the new keys:
+ AbstractBibtexKeyPattern citeKeyPattern = bibDatabaseContext.getMetaData()
+ .getCiteKeyPattern(Globals.prefs.getBibtexKeyPatternPreferences().getKeyPattern());
for (BibEntry entry : entries) {
- bes = entry;
- BibtexKeyPatternUtil.makeLabel(bibDatabaseContext.getMetaData(), bibDatabaseContext.getDatabase(),
- bes, BibtexKeyPatternPreferences.fromPreferences(Globals.prefs));
- ce.addEdit(new UndoableKeyChange(bibDatabaseContext.getDatabase(), bes, (String) oldvals.get(bes),
- bes.getCiteKeyOptional().orElse(null)));
+ String oldCiteKey = entry.getCiteKeyOptional().orElse("");
+ BibtexKeyPatternUtil.makeAndSetLabel(citeKeyPattern, bibDatabaseContext.getDatabase(),
+ entry, Globals.prefs.getBibtexKeyPatternPreferences());
+ String newCiteKey = entry.getCiteKeyOptional().orElse("");
+ if (!oldCiteKey.equals(newCiteKey)) {
+ ce.addEdit(new UndoableKeyChange(entry, oldCiteKey, newCiteKey));
+ }
}
ce.end();
- getUndoManager().addEdit(ce);
+
+ // register the undo event only if new cite keys were generated
+ if (ce.hasEdits()) {
+ getUndoManager().addEdit(ce);
+ }
}
// Run third, on EDT:
@@ -519,7 +475,8 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
actions.put(Actions.MERGE_ENTRIES, (BaseAction) () -> new MergeEntriesDialog(BasePanel.this));
- actions.put(Actions.SEARCH, (BaseAction) searchBar::focus);
+ actions.put(Actions.SEARCH, (BaseAction) frame.getGlobalSearchBar()::focus);
+ actions.put(Actions.GLOBAL_SEARCH, (BaseAction) frame.getGlobalSearchBar()::performGlobalSearch);
// The action for copying the selected entry's key.
actions.put(Actions.COPY_KEY, (BaseAction) () -> copyKey());
@@ -530,6 +487,9 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
// The action for copying the BibTeX key and the title for the first selected entry
actions.put(Actions.COPY_KEY_AND_TITLE, (BaseAction) () -> copyKeyAndTitle());
+ // The action for copying the BibTeX keys as hyperlinks to the urls of the selected entries
+ actions.put(Actions.COPY_KEY_AND_LINK, new CopyBibTeXKeyAndLinkAction(mainTable));
+
actions.put(Actions.MERGE_DATABASE, new AppendDatabaseAction(frame, this));
actions.put(Actions.ADD_FILE_LINK, new AttachFileAction(this));
@@ -538,7 +498,7 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
actions.put(Actions.OPEN_FOLDER, (BaseAction) () -> JabRefExecutorService.INSTANCE.execute(() -> {
final List<File> files = FileUtil.getListOfLinkedFiles(mainTable.getSelectedEntries(),
- bibDatabaseContext.getFileDirectory());
+ bibDatabaseContext.getFileDirectories(Globals.prefs.getFileDirectoryPreferences()));
for (final File f : files) {
try {
JabRefDesktop.openFolderAndSelectFile(f.getAbsolutePath());
@@ -549,29 +509,16 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
}));
actions.put(Actions.OPEN_CONSOLE, (BaseAction) () -> JabRefDesktop
- .openConsole(frame.getCurrentBasePanel().getBibDatabaseContext().getDatabaseFile()));
+ .openConsole(frame.getCurrentBasePanel().getBibDatabaseContext().getDatabaseFile().orElse(null)));
actions.put(Actions.PULL_CHANGES_FROM_SHARED_DATABASE, (BaseAction) () -> {
- DBMSSynchronizer dbmsSynchronizer = frame.getCurrentBasePanel().getBibDatabaseContext().getDBSynchronizer();
+ DBMSSynchronizer dbmsSynchronizer = frame.getCurrentBasePanel().getBibDatabaseContext().getDBMSSynchronizer();
dbmsSynchronizer.pullChanges();
});
actions.put(Actions.OPEN_URL, new OpenURLAction());
- actions.put(Actions.MERGE_WITH_FETCHED_ENTRY, (BaseAction) () -> {
- if (mainTable.getSelectedEntries().size() == 1) {
- BibEntry originalEntry = mainTable.getSelectedEntries().get(0);
- new FetchAndMergeEntry(originalEntry, this, FetchAndMergeEntry.SUPPORTED_FIELDS);
- } else {
- JOptionPane.showMessageDialog(frame(),
- Localization.lang("This operation requires exactly one item to be selected."),
- Localization.lang("Merge entry with %0 information",
- FieldName.orFields(FieldName.getDisplayName(FieldName.DOI),
- FieldName.getDisplayName(FieldName.ISBN),
- FieldName.getDisplayName(FieldName.EPRINT))),
- JOptionPane.INFORMATION_MESSAGE);
- }
- });
+ actions.put(Actions.MERGE_WITH_FETCHED_ENTRY, new MergeWithFetchedEntryAction(this));
actions.put(Actions.REPLACE_ALL, (BaseAction) () -> {
final ReplaceStringDialog rsd = new ReplaceStringDialog(frame);
@@ -667,32 +614,33 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
});
// Note that we can't put the number of entries that have been reverted into the undoText as the concrete number cannot be injected
- actions.put(Relevance.getInstance().getValues().get(0).getActionName(),
- new SpecialFieldAction(frame, Relevance.getInstance(),
- Relevance.getInstance().getValues().get(0).getFieldValue().get(), true,
- Localization.lang("Toggle relevance")));
- actions.put(Quality.getInstance().getValues().get(0).getActionName(),
- new SpecialFieldAction(frame, Quality.getInstance(),
- Quality.getInstance().getValues().get(0).getFieldValue().get(), true,
- Localization.lang("Toggle quality assured")));
- actions.put(Printed.getInstance().getValues().get(0).getActionName(),
- new SpecialFieldAction(frame, Printed.getInstance(),
- Printed.getInstance().getValues().get(0).getFieldValue().get(), true,
- Localization.lang("Toggle print status")));
+ actions.put(new SpecialFieldValueViewModel(SpecialField.RELEVANCE.getValues().get(0)).getActionName(),
+ new SpecialFieldViewModel(SpecialField.RELEVANCE).getSpecialFieldAction(
+ SpecialField.RELEVANCE.getValues().get(0), frame));
+ actions.put(new SpecialFieldValueViewModel(SpecialField.QUALITY.getValues().get(0)).getActionName(),
+ new SpecialFieldViewModel(SpecialField.QUALITY).getSpecialFieldAction(SpecialField.QUALITY.getValues().get(0), frame));
+ actions.put(new SpecialFieldValueViewModel(SpecialField.PRINTED.getValues().get(0)).getActionName(),
+ new SpecialFieldViewModel(SpecialField.PRINTED).getSpecialFieldAction(
+ SpecialField.PRINTED.getValues().get(0), frame));
- for (SpecialFieldValue prio : Priority.getInstance().getValues()) {
- actions.put(prio.getActionName(), prio.getAction(this.frame));
+ for (SpecialFieldValue prio : SpecialField.PRIORITY.getValues()) {
+ actions.put(new SpecialFieldValueViewModel(prio).getActionName(), new SpecialFieldViewModel(SpecialField.PRIORITY).getSpecialFieldAction(prio, this.frame));
}
- for (SpecialFieldValue rank : Rank.getInstance().getValues()) {
- actions.put(rank.getActionName(), rank.getAction(this.frame));
+ for (SpecialFieldValue rank : SpecialField.RANKING.getValues()) {
+ actions.put(new SpecialFieldValueViewModel(rank).getActionName(), new SpecialFieldViewModel(SpecialField.RANKING).getSpecialFieldAction(rank, this.frame));
}
- for (SpecialFieldValue status : ReadStatus.getInstance().getValues()) {
- actions.put(status.getActionName(), status.getAction(this.frame));
+ for (SpecialFieldValue status : SpecialField.READ_STATUS.getValues()) {
+ actions.put(new SpecialFieldValueViewModel(status).getActionName(), new SpecialFieldViewModel(SpecialField.READ_STATUS).getSpecialFieldAction(status, this.frame));
}
actions.put(Actions.TOGGLE_PREVIEW, (BaseAction) () -> {
- boolean enabled = !Globals.prefs.getBoolean(JabRefPreferences.PREVIEW_ENABLED);
- Globals.prefs.putBoolean(JabRefPreferences.PREVIEW_ENABLED, enabled);
+ PreviewPreferences previewPreferences = Globals.prefs.getPreviewPreferences();
+ boolean enabled = !previewPreferences.isPreviewPanelEnabled();
+ PreviewPreferences newPreviewPreferences = previewPreferences
+ .getBuilder()
+ .withPreviewPanelEnabled(enabled)
+ .build();
+ Globals.prefs.storePreviewPreferences(newPreviewPreferences);
setPreviewActiveBasePanels(enabled);
frame.setPreviewToggle(enabled);
});
@@ -715,13 +663,8 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
groupsHighlightListener.listChanged(null);
});
- actions.put(Actions.SWITCH_PREVIEW, (BaseAction) selectionListener::switchPreview);
-
- actions.put(Actions.MANAGE_SELECTORS, (BaseAction) () -> {
- ContentSelectorDialog2 csd = new ContentSelectorDialog2(frame, frame, BasePanel.this, false, null);
- csd.setLocationRelativeTo(frame);
- csd.setVisible(true);
- });
+ actions.put(Actions.NEXT_PREVIEW_STYLE, (BaseAction) selectionListener::nextPreviewStyle);
+ actions.put(Actions.PREVIOUS_PREVIEW_STYLE, (BaseAction) selectionListener::previousPreviewStyle);
actions.put(Actions.EXPORT_TO_CLIPBOARD, new ExportToClipboardAction(frame));
actions.put(Actions.SEND_AS_EMAIL, new SendAsEMailAction(frame));
@@ -771,19 +714,42 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
}
}
- //when you modify this action be sure to adjust Actions.CUT,
- //they are the same except of the Localization, delete confirmation and Actions.COPY call
- private void delete() {
+ private void cut() {
+ runCommand(Actions.COPY);
+ // cannot call runCommand(Actions.DELETE), b/c it will call delete(false) with the wrong parameter
+ delete(true);
+ }
+
+ /**
+ * Removes the selected entries from the database
+ * @param cut If false the user will get asked if he really wants to delete the entries, and it will be localized
+ * as "deleted".
+ * If true the action will be localized as "cut"
+ */
+ private void delete(boolean cut) {
List<BibEntry> entries = mainTable.getSelectedEntries();
if (entries.isEmpty()) {
return;
}
- if (!showDeleteConfirmationDialog(entries.size())) {
+ if (!cut && !showDeleteConfirmationDialog(entries.size())) {
return;
}
- NamedCompound compound = new NamedCompound(
- (entries.size() > 1 ? Localization.lang("delete entries") : Localization.lang("delete entry")));
+ // select the next entry to stay at the same place as before (or the previous if we're already at the end)
+ if (mainTable.getSelectedRow() != mainTable.getRowCount() -1){
+ selectNextEntry();
+ } else {
+ selectPreviousEntry();
+ }
+
+ NamedCompound compound;
+ if (cut) {
+ compound = new NamedCompound(
+ (entries.size() > 1 ? Localization.lang("cut entries") : Localization.lang("cut entry")));
+ } else {
+ compound = new NamedCompound(
+ (entries.size() > 1 ? Localization.lang("delete entries") : Localization.lang("delete entry")));
+ }
for (BibEntry entry : entries) {
compound.addEdit(new UndoableRemoveEntry(bibDatabaseContext.getDatabase(), entry, BasePanel.this));
bibDatabaseContext.getDatabase().removeEntry(entry);
@@ -793,7 +759,10 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
getUndoManager().addEdit(compound);
markBaseChanged();
- frame.output(formatOutputMessage(Localization.lang("Deleted"), entries.size()));
+ frame.output(formatOutputMessage(cut ? Localization.lang("Cut") : Localization.lang("Deleted"), entries.size()));
+
+ // prevent the main table from loosing focus
+ mainTable.requestFocus();
}
private void paste() {
@@ -837,12 +806,12 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
output(formatOutputMessage(Localization.lang("Pasted"), bes.size()));
markBaseChanged();
+ highlightEntry(firstBE);
+ mainTable.requestFocus();
+
if (Globals.prefs.getBoolean(JabRefPreferences.AUTO_OPEN_FORM)) {
selectionListener.editSignalled(firstBE);
}
-
- // If we inserted a duplicate we want to select the duplicate (thus we have to search from the back)
- highlightLastEntry(firstBE);
}
}
@@ -912,7 +881,7 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
Layout layout;
try {
layout = new LayoutHelper(sr,
- LayoutFormatterPreferences.fromPreferences(Globals.prefs, Globals.journalAbbreviationLoader))
+ Globals.prefs.getLayoutFormatterPreferences(Globals.journalAbbreviationLoader))
.getLayoutFromText();
} catch (IOException e) {
LOGGER.info("Could not get layout", e);
@@ -962,14 +931,14 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
new SearchAndOpenFile(entry, BasePanel.this).searchAndOpen();
return;
}
- FileListTableModel tableModel = new FileListTableModel();
- entry.getFieldOptional(FieldName.FILE).ifPresent(tableModel::setContent);
- if (tableModel.getRowCount() == 0) {
- // content in bibtex field is not readable
+ FileListTableModel fileListTableModel = new FileListTableModel();
+ entry.getField(FieldName.FILE).ifPresent(fileListTableModel::setContent);
+ if (fileListTableModel.getRowCount() == 0) {
+ // content in BibTeX field is not readable
new SearchAndOpenFile(entry, BasePanel.this).searchAndOpen();
return;
}
- FileListEntry flEntry = tableModel.getEntry(0);
+ FileListEntry flEntry = fileListTableModel.getEntry(0);
ExternalFileMenuItem item = new ExternalFileMenuItem(frame(), entry, "", flEntry.link,
flEntry.type.get().getIcon(), bibDatabaseContext, flEntry.type);
item.openLink();
@@ -1048,10 +1017,7 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
} catch (SaveException ex) {
if (ex.specificEntry()) {
// Error occurred during processing of the entry. Highlight it:
- final int row = mainTable.findEntry(ex.getEntry());
- final int topShow = Math.max(0, row - 3);
- mainTable.setRowSelectionInterval(row, row);
- mainTable.scrollTo(topShow);
+ highlightEntry(ex.getEntry());
showEntry(ex.getEntry());
} else {
LOGGER.warn("Could not save", ex);
@@ -1157,17 +1123,14 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
mode = BasePanelMode.WILL_SHOW_EDITOR;
}
- int row = mainTable.findEntry(be);
- if (row >= 0) {
- highlightEntry(be); // Selects the entry. The selection listener will open the editor.
- } else {
- // The entry is not visible in the table, perhaps due to a filtering search
- // or group selection. Show the entry editor anyway:
- showEntry(be);
- }
+ highlightEntry(be);
- markBaseChanged(); // The database just changed.
- new FocusRequester(getEntryEditor(be));
+ // The database just changed.
+ markBaseChanged();
+
+ final EntryEditor entryEditor = getEntryEditor(be);
+ this.showEntryEditor(entryEditor);
+ entryEditor.requestFocus();
return be;
} catch (KeyCollisionException ex) {
@@ -1177,11 +1140,6 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
return null;
}
- public SearchBar getSearchBar() {
- return searchBar;
- }
-
-
private class GroupTreeListener {
private final Runnable task = new Runnable() {
@@ -1217,7 +1175,7 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
}
// Automatically add new entry to the selected group (or set of groups)
- if (Globals.prefs.getBoolean(JabRefPreferences.AUTO_ASSIGN_GROUP) && frame.groupToggle.isSelected()) {
+ if (Globals.prefs.getBoolean(JabRefPreferences.AUTO_ASSIGN_GROUP) && frame.getGroupSelector().getToggleAction().isSelected()) {
final List<BibEntry> entries = Collections.singletonList(addedEntryEvent.getBibEntry());
final TreePath[] selection = frame.getGroupSelector().getGroupsTree().getSelectionPaths();
if (selection != null) {
@@ -1284,6 +1242,28 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
}
}
+ /**
+ * Ensures that the results of the current search are updated when a new entry is inserted into the database
+ */
+ private class SearchListener {
+ @Subscribe
+ public void listen(EntryAddedEvent addedEntryEvent) {
+ frame.getGlobalSearchBar().performSearch();
+ }
+
+ @Subscribe
+ public void listen(EntryChangedEvent entryChangedEvent) {
+ frame.getGlobalSearchBar().setDontSelectSearchBar(true);
+ frame.getGlobalSearchBar().performSearch();
+ }
+
+ @Subscribe
+ public void listen(EntryRemovedEvent removedEntryEvent) {
+ // IMO only used to update the status (found X entries)
+ frame.getGlobalSearchBar().performSearch();
+ }
+ }
+
/**
* This method is called from JabRefFrame when the user wants to create a new entry.
@@ -1321,7 +1301,8 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
selectionListener.editSignalled();
final EntryEditor editor = getEntryEditor(entries.get(0));
editor.setFocusToField(fieldName);
- new FocusRequester(editor);
+ this.showEntryEditor(editor);
+ editor.requestFocus();
}
}
@@ -1359,6 +1340,30 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
};
mainTable.addSelectionListener(groupsHighlightListener);
+ String clearSearch = "clearSearch";
+ mainTable.getInputMap().put(Globals.getKeyPrefs().getKey(KeyBinding.CLEAR_SEARCH), clearSearch);
+ mainTable.getActionMap().put(clearSearch, new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ // need to close these here, b/c this action overshadows the responsible actions when the main table is selected
+ switch (mode) {
+ case SHOWING_NOTHING:
+ frame.getGlobalSearchBar().endSearch();
+ break;
+ case SHOWING_PREVIEW:
+ getPreviewPanel().close();
+ break;
+ case SHOWING_EDITOR:
+ case WILL_SHOW_EDITOR:
+ getCurrentEditor().close();
+ break;
+ default:
+ LOGGER.warn("unknown BasePanelMode: '" + mode + "', doing nothing");
+ break;
+ }
+ }
+ });
+
mainTable.getActionMap().put(Actions.CUT, new AbstractAction() {
@Override
@@ -1465,10 +1470,6 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
createMainTable();
- for (EntryEditor ee : entryEditors.values()) {
- ee.validateAllFields();
- }
-
splitPane.setTopComponent(mainTable.getPane());
// Remove borders
@@ -1479,11 +1480,7 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
// otherwise set the bottom component to null.
if (mode == BasePanelMode.SHOWING_PREVIEW) {
mode = BasePanelMode.SHOWING_NOTHING;
- int row = mainTable.findEntry(currentPreview.getEntry());
- if (row >= 0) {
- mainTable.setRowSelectionInterval(row, row);
- }
-
+ highlightEntry(selectionListener.getPreview().getEntry());
} else if (mode == BasePanelMode.SHOWING_EDITOR) {
mode = BasePanelMode.SHOWING_NOTHING;
} else {
@@ -1492,7 +1489,6 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
setLayout(new BorderLayout());
removeAll();
- add(searchBar, BorderLayout.NORTH);
add(splitPane, BorderLayout.CENTER);
// Set up name autocompleter for search:
@@ -1502,8 +1498,7 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
AutoCompletePreferences autoCompletePreferences = new AutoCompletePreferences(Globals.prefs);
// Set up AutoCompleters for this panel:
if (Globals.prefs.getBoolean(JabRefPreferences.AUTO_COMPLETE)) {
- autoCompleters = new ContentAutoCompleters(getDatabase(), bibDatabaseContext.getMetaData(),
- autoCompletePreferences, Globals.journalAbbreviationLoader);
+ autoCompleters = new ContentAutoCompleters(getDatabase(), autoCompletePreferences, Globals.journalAbbreviationLoader);
// ensure that the autocompleters are in sync with entries
this.getDatabase().registerListener(new AutoCompleteListener());
} else {
@@ -1526,7 +1521,7 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
}
public void updateSearchManager() {
- searchBar.setAutoCompleter(searchAutoCompleter);
+ frame.getGlobalSearchBar().setAutoCompleter(searchAutoCompleter);
}
private void instantiateSearchAutoCompleter() {
@@ -1560,7 +1555,7 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
public void adjustSplitter() {
if (mode == BasePanelMode.SHOWING_PREVIEW) {
splitPane.setDividerLocation(
- splitPane.getHeight() - Globals.prefs.getInt(JabRefPreferences.PREVIEW_PANEL_HEIGHT));
+ splitPane.getHeight() - Globals.prefs.getPreviewPreferences().getPreviewPanelHeight());
} else {
splitPane.setDividerLocation(
splitPane.getHeight() - Globals.prefs.getInt(JabRefPreferences.ENTRY_EDITOR_HEIGHT));
@@ -1593,41 +1588,17 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
}
- EntryEditor form;
- int divLoc = -1;
String visName = null;
if ((getShowing() != null) && isShowingEditor()) {
visName = ((EntryEditor) splitPane.getBottomComponent()).getVisiblePanelName();
}
- if (getShowing() != null) {
- divLoc = splitPane.getDividerLocation();
- }
-
- if (entryEditors.containsKey(be.getType())) {
- // We already have an editor for this entry type.
- form = entryEditors.get(be.getType());
- form.switchTo(be);
- if (visName != null) {
- form.setVisiblePanel(visName);
- }
- splitPane.setBottomComponent(form);
- } else {
- // We must instantiate a new editor for this type.
- form = new EntryEditor(frame, BasePanel.this, be);
- if (visName != null) {
- form.setVisiblePanel(visName);
- }
- splitPane.setBottomComponent(form);
-
- entryEditors.put(be.getType(), form);
+ // We must instantiate a new editor.
+ EntryEditor entryEditor = new EntryEditor(frame, BasePanel.this, be);
+ if (visName != null) {
+ entryEditor.setVisiblePanel(visName);
}
- if (divLoc > 0) {
- splitPane.setDividerLocation(divLoc);
- } else {
- splitPane.setDividerLocation(
- splitPane.getHeight() - Globals.prefs.getInt(JabRefPreferences.ENTRY_EDITOR_HEIGHT));
- }
+ showEntryEditor(entryEditor);
newEntryShowing(be);
setEntryEditorEnabled(true); // Make sure it is enabled.
@@ -1641,30 +1612,10 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
* @return A suitable entry editor.
*/
public EntryEditor getEntryEditor(BibEntry entry) {
- EntryEditor form;
- if (entryEditors.containsKey(entry.getType())) {
- EntryEditor visibleNow = currentEditor;
-
- // We already have an editor for this entry type.
- form = entryEditors.get(entry.getType());
-
- // If the cached editor is not the same as the currently shown one,
- // make sure the current one stores its current edit:
- if ((visibleNow != null) && (!(form.equals(visibleNow)))) {
- visibleNow.storeCurrentEdit();
- }
-
- form.switchTo(entry);
- } else {
- // We must instantiate a new editor for this type. First make sure the old one
- // stores its last edit:
- storeCurrentEdit();
- // Then start the new one:
- form = new EntryEditor(frame, BasePanel.this, entry);
-
- entryEditors.put(entry.getType(), form);
- }
- return form;
+ // We must instantiate a new editor. First make sure the old one stores its last edit:
+ storeCurrentEdit();
+ // Then start the new one:
+ return new EntryEditor(frame, BasePanel.this, entry);
}
public EntryEditor getCurrentEditor() {
@@ -1681,18 +1632,17 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
if (mode == BasePanelMode.SHOWING_EDITOR) {
Globals.prefs.putInt(JabRefPreferences.ENTRY_EDITOR_HEIGHT,
splitPane.getHeight() - splitPane.getDividerLocation());
- } else if (mode == BasePanelMode.SHOWING_PREVIEW) {
- Globals.prefs.putInt(JabRefPreferences.PREVIEW_PANEL_HEIGHT,
- splitPane.getHeight() - splitPane.getDividerLocation());
}
mode = BasePanelMode.SHOWING_EDITOR;
+ if (currentEditor != null) {
+ currentEditor.setMovingToDifferentEntry();
+ }
currentEditor = editor;
splitPane.setBottomComponent(editor);
if (editor.getEntry() != getShowing()) {
newEntryShowing(editor.getEntry());
}
adjustSplitter();
-
}
/**
@@ -1702,8 +1652,8 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
*/
public void showPreview(PreviewPanel preview) {
mode = BasePanelMode.SHOWING_PREVIEW;
- currentPreview = preview;
splitPane.setBottomComponent(preview);
+ adjustSplitter();
}
/**
@@ -1723,25 +1673,32 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
}
/**
- * This method selects the given entry (searches from the back), and scrolls it into view in the table.
- * If an entryEditor is shown, it is given focus afterwards.
- */
- public void highlightLastEntry(final BibEntry bibEntry) {
- highlightEntry(mainTable.findLastEntry(bibEntry));
- }
-
- /**
* This method selects the entry on the given position, and scrolls it into view in the table.
* If an entryEditor is shown, it is given focus afterwards.
*/
public void highlightEntry(int pos) {
- if (pos >= 0) {
- mainTable.clearSelection();
- mainTable.addRowSelectionInterval(pos, pos);
+ if ((pos >= 0) && (pos < mainTable.getRowCount())) {
+ mainTable.setRowSelectionInterval(pos, pos);
mainTable.ensureVisible(pos);
}
}
+ public void selectPreviousEntry() {
+ highlightEntry(((mainTable.getSelectedRow() - 1) + mainTable.getRowCount()) % mainTable.getRowCount());
+ }
+
+ public void selectNextEntry() {
+ highlightEntry((mainTable.getSelectedRow() + 1) % mainTable.getRowCount());
+ }
+
+ public void selectFirstEntry() {
+ highlightEntry(0);
+ }
+
+ public void selectLastEntry() {
+ highlightEntry(mainTable.getRowCount() - 1);
+ }
+
/**
* This method is called from an EntryEditor when it should be closed. We relay to the selection listener, which
* takes care of the rest.
@@ -1760,7 +1717,7 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
*/
public void ensureNotShowingBottomPanel(BibEntry entry) {
if (((mode == BasePanelMode.SHOWING_EDITOR) && (currentEditor.getEntry() == entry))
- || ((mode == BasePanelMode.SHOWING_PREVIEW) && (currentPreview.getEntry() == entry))) {
+ || ((mode == BasePanelMode.SHOWING_PREVIEW) && (selectionListener.getPreview().getEntry() == entry))) {
hideBottomComponent();
}
}
@@ -1789,25 +1746,6 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
}
}
- /**
- * This method iterates through all existing entry editors in this BasePanel, telling each to update all its
- * instances of FieldContentSelector. This is done to ensure that the list of words in each selector is up-to-date
- * after the user has made changes in the Manage dialog.
- */
- public void updateAllContentSelectors() {
- for (Map.Entry<String, EntryEditor> stringEntryEditorEntry : entryEditors.entrySet()) {
- EntryEditor ed = stringEntryEditorEntry.getValue();
- ed.updateAllContentSelectors();
- }
- }
-
- public void rebuildAllEntryEditors() {
- for (Map.Entry<String, EntryEditor> stringEntryEditorEntry : entryEditors.entrySet()) {
- EntryEditor ed = stringEntryEditorEntry.getValue();
- ed.rebuildPanels();
- }
- }
-
public void markBaseChanged() {
baseChanged = true;
@@ -1847,10 +1785,11 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
}
} else if (baseChanged && !nonUndoableChange) {
baseChanged = false;
- if (getBibDatabaseContext().getDatabaseFile() == null) {
- frame.setTabTitle(this, GUIGlobals.UNTITLED_TITLE, null);
+ if (getBibDatabaseContext().getDatabaseFile().isPresent()) {
+ frame.setTabTitle(this, getTabTitle(),
+ getBibDatabaseContext().getDatabaseFile().get().getAbsolutePath());
} else {
- frame.setTabTitle(this, getTabTitle(), getBibDatabaseContext().getDatabaseFile().getAbsolutePath());
+ frame.setTabTitle(this, GUIGlobals.UNTITLED_TITLE, null);
}
}
frame.setWindowTitle();
@@ -1932,20 +1871,21 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
public void autoGenerateKeysBeforeSaving() {
if (Globals.prefs.getBoolean(JabRefPreferences.GENERATE_KEYS_BEFORE_SAVING)) {
NamedCompound ce = new NamedCompound(Localization.lang("Autogenerate BibTeX keys"));
- boolean any = false;
for (BibEntry bes : bibDatabaseContext.getDatabase().getEntries()) {
Optional<String> oldKey = bes.getCiteKeyOptional();
if (!(oldKey.isPresent()) || oldKey.get().isEmpty()) {
- BibtexKeyPatternUtil.makeLabel(bibDatabaseContext.getMetaData(), bibDatabaseContext.getDatabase(),
- bes, BibtexKeyPatternPreferences.fromPreferences(Globals.prefs));
- ce.addEdit(new UndoableKeyChange(bibDatabaseContext.getDatabase(), bes, null,
- bes.getCiteKeyOptional().get())); // Cite key is set here
- any = true;
+ BibtexKeyPatternUtil.makeAndSetLabel(bibDatabaseContext.getMetaData()
+ .getCiteKeyPattern(Globals.prefs.getBibtexKeyPatternPreferences().getKeyPattern()),
+ bibDatabaseContext.getDatabase(),
+ bes, Globals.prefs.getBibtexKeyPatternPreferences());
+ bes.getCiteKeyOptional().ifPresent(
+ newKey -> ce.addEdit(new UndoableKeyChange(bes, oldKey.orElse(""), newKey)));
}
}
+
// Store undo information, if any:
- if (any) {
+ if (ce.hasEdits()) {
ce.end();
getUndoManager().addEdit(ce);
}
@@ -1968,8 +1908,12 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
*/
public void saveDividerLocation() {
if (mode == BasePanelMode.SHOWING_PREVIEW) {
- Globals.prefs.putInt(JabRefPreferences.PREVIEW_PANEL_HEIGHT,
- splitPane.getHeight() - splitPane.getDividerLocation());
+ int previewPanelHeight = splitPane.getHeight() - splitPane.getDividerLocation();
+ PreviewPreferences previewPreferences = Globals.prefs.getPreviewPreferences()
+ .getBuilder()
+ .withPreviewPanelHeight(previewPanelHeight)
+ .build();
+ Globals.prefs.storePreviewPreferences(previewPreferences);
} else if (mode == BasePanelMode.SHOWING_EDITOR) {
Globals.prefs.putInt(JabRefPreferences.ENTRY_EDITOR_HEIGHT,
splitPane.getHeight() - splitPane.getDividerLocation());
@@ -2011,9 +1955,9 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
final List<BibEntry> bes = mainTable.getSelectedEntries();
if (bes.size() == 1) {
String field = FieldName.DOI;
- Optional<String> link = bes.get(0).getFieldOptional(FieldName.DOI);
+ Optional<String> link = bes.get(0).getField(FieldName.DOI);
if (bes.get(0).hasField(FieldName.URL)) {
- link = bes.get(0).getFieldOptional(FieldName.URL);
+ link = bes.get(0).getField(FieldName.URL);
field = FieldName.URL;
}
if (link.isPresent()) {
@@ -2028,7 +1972,7 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
// Look for web links in the "file" field as a fallback:
FileListEntry entry = null;
FileListTableModel tm = new FileListTableModel();
- bes.get(0).getFieldOptional(FieldName.FILE).ifPresent(tm::setContent);
+ bes.get(0).getField(FieldName.FILE).ifPresent(tm::setContent);
for (int i = 0; i < tm.getRowCount(); i++) {
FileListEntry flEntry = tm.getEntry(i);
if (FieldName.URL.equalsIgnoreCase(flEntry.type.get().getName())
@@ -2084,11 +2028,9 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
@Override
public void action() throws Exception {
- if (currentPreview == null) {
- selectionListener.setPreviewActive(true);
- showPreview(selectionListener.getPreview());
- }
- currentPreview.getPrintAction().actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, null));
+ selectionListener.setPreviewActive(true);
+ showPreview(selectionListener.getPreview());
+ selectionListener.getPreview().getPrintAction().actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, null));
}
}
@@ -2122,11 +2064,11 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
updatedExternally = true;
final ChangeScanner scanner = new ChangeScanner(frame, BasePanel.this,
- getBibDatabaseContext().getDatabaseFile());
+ getBibDatabaseContext().getDatabaseFile().orElse(null));
// Test: running scan automatically in background
- if ((getBibDatabaseContext().getDatabaseFile() != null)
- && !FileBasedLock.waitForFileLock(getBibDatabaseContext().getDatabaseFile().toPath())) {
+ if ((getBibDatabaseContext().getDatabaseFile().isPresent())
+ && !FileBasedLock.waitForFileLock(getBibDatabaseContext().getDatabaseFile().get().toPath())) {
// The file is locked even after the maximum wait. Do nothing.
LOGGER.error("File updated externally, but change scan failed because the file is locked.");
// Perturb the stored timestamp so successive checks are made:
@@ -2134,7 +2076,7 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
return;
}
- JabRefExecutorService.INSTANCE.executeWithLowPriorityInOwnThreadAndWait(scanner);
+ JabRefExecutorService.INSTANCE.executeInterruptableTaskAndWait(scanner);
// Adding the sidepane component is Swing work, so we must do this in the Swing
// thread:
@@ -2142,15 +2084,15 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
// Check if there is already a notification about external
// changes:
- boolean hasAlready = sidePaneManager.hasComponent(FileUpdatePanel.NAME);
+ boolean hasAlready = sidePaneManager.hasComponent(FileUpdatePanel.class);
if (hasAlready) {
- sidePaneManager.hideComponent(FileUpdatePanel.NAME);
- sidePaneManager.unregisterComponent(FileUpdatePanel.NAME);
+ sidePaneManager.hideComponent(FileUpdatePanel.class);
+ sidePaneManager.unregisterComponent(FileUpdatePanel.class);
}
FileUpdatePanel pan = new FileUpdatePanel(BasePanel.this, sidePaneManager,
- getBibDatabaseContext().getDatabaseFile(), scanner);
- sidePaneManager.register(FileUpdatePanel.NAME, pan);
- sidePaneManager.show(FileUpdatePanel.NAME);
+ getBibDatabaseContext().getDatabaseFile().orElse(null), scanner);
+ sidePaneManager.register(pan);
+ sidePaneManager.show(FileUpdatePanel.class);
};
if (scanner.changesFound()) {
@@ -2162,7 +2104,7 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
@Override
public void fileRemoved() {
- LOGGER.info("File '" + getBibDatabaseContext().getDatabaseFile().getPath() + "' has been deleted.");
+ LOGGER.info("File '" + getBibDatabaseContext().getDatabaseFile().get().getPath() + "' has been deleted.");
}
/**
@@ -2174,10 +2116,10 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
}
// Check if there is a FileUpdatePanel for this BasePanel being shown. If so,
// remove it:
- if (sidePaneManager.hasComponent("fileUpdate")) {
- FileUpdatePanel fup = (FileUpdatePanel) sidePaneManager.getComponent("fileUpdate");
+ if (sidePaneManager.hasComponent(FileUpdatePanel.class)) {
+ FileUpdatePanel fup = (FileUpdatePanel) sidePaneManager.getComponent(FileUpdatePanel.class);
if (fup.getPanel() == this) {
- sidePaneManager.hideComponent("fileUpdate");
+ sidePaneManager.hideComponent(FileUpdatePanel.class);
}
}
}
@@ -2358,12 +2300,10 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
final Set<ExternalFileType> types = ExternalFileTypes.getInstance().getExternalFileTypeSelection();
final List<File> dirs = new ArrayList<>();
- if (!basePanel.getBibDatabaseContext().getFileDirectory().isEmpty()) {
- final List<String> mdDirs = basePanel.getBibDatabaseContext().getFileDirectory();
- for (final String mdDir : mdDirs) {
- dirs.add(new File(mdDir));
-
- }
+ final List<String> mdDirs = basePanel.getBibDatabaseContext()
+ .getFileDirectories(Globals.prefs.getFileDirectoryPreferences());
+ for (final String mdDir : mdDirs) {
+ dirs.add(new File(mdDir));
}
final List<String> extensions = new ArrayList<>();
for (final ExternalFileType type : types) {
@@ -2373,7 +2313,8 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
Map<BibEntry, List<File>> result;
if (Globals.prefs.getBoolean(JabRefPreferences.AUTOLINK_USE_REG_EXP_SEARCH_KEY)) {
String regExp = Globals.prefs.get(JabRefPreferences.REG_EXP_SEARCH_EXPRESSION_KEY);
- result = RegExpFileSearch.findFilesForSet(entries, extensions, dirs, regExp);
+ result = RegExpFileSearch.findFilesForSet(entries, extensions, dirs, regExp,
+ Globals.prefs.getKeywordDelimiter());
} else {
boolean autoLinkExactKeyOnly = Globals.prefs.getBoolean(JabRefPreferences.AUTOLINK_EXACT_KEY_ONLY);
result = FileUtil.findAssociatedFiles(entries, extensions, dirs, autoLinkExactKeyOnly);
@@ -2424,11 +2365,24 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
return mainTable;
}
- public Map<String, EntryEditor> getEntryEditors() {
- return entryEditors;
- }
-
public BibDatabaseContext getDatabaseContext() {
return bibDatabaseContext;
}
+
+ public SearchQuery getCurrentSearchQuery() {
+ return currentSearchQuery;
+ }
+
+ public void setCurrentSearchQuery(SearchQuery currentSearchQuery) {
+ this.currentSearchQuery = currentSearchQuery;
+ }
+
+ public PreviewPanel getPreviewPanel() {
+ if (selectionListener == null) {
+ // only occurs if this is called while instantiating this BasePanel
+ return null;
+ }
+ return selectionListener.getPreview();
+ }
+
}
diff --git a/src/main/java/net/sf/jabref/gui/BibtexKeyPatternDialog.java b/src/main/java/net/sf/jabref/gui/BibtexKeyPatternDialog.java
deleted file mode 100644
index affb600..0000000
--- a/src/main/java/net/sf/jabref/gui/BibtexKeyPatternDialog.java
+++ /dev/null
@@ -1,100 +0,0 @@
-package net.sf.jabref.gui;
-
-import java.awt.BorderLayout;
-import java.awt.Dimension;
-import java.awt.event.ActionEvent;
-import java.awt.event.WindowEvent;
-
-import javax.swing.AbstractAction;
-import javax.swing.Action;
-import javax.swing.BorderFactory;
-import javax.swing.JButton;
-import javax.swing.JDialog;
-import javax.swing.JPanel;
-import javax.swing.WindowConstants;
-
-import net.sf.jabref.Globals;
-import net.sf.jabref.MetaData;
-import net.sf.jabref.gui.bibtexkeypattern.BibtexKeyPatternPanel;
-import net.sf.jabref.gui.keyboard.KeyBinder;
-import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.model.bibtexkeypattern.AbstractBibtexKeyPattern;
-
-import com.jgoodies.forms.builder.ButtonBarBuilder;
-
-public class BibtexKeyPatternDialog extends JDialog {
-
- private MetaData metaData;
- private BasePanel panel;
- private final BibtexKeyPatternPanel bibtexKeyPatternPanel;
-
-
- public BibtexKeyPatternDialog(JabRefFrame parent, BasePanel panel) {
- super(parent, Localization.lang("BibTeX key patterns"), true);
- this.bibtexKeyPatternPanel = new BibtexKeyPatternPanel(panel);
- setPanel(panel);
- init();
- }
-
- /**
- * Used for updating an existing Dialog
- *
- * @param panel the panel to read the data from
- */
- public void setPanel(BasePanel panel) {
- this.panel = panel;
- this.metaData = panel.getBibDatabaseContext().getMetaData();
- AbstractBibtexKeyPattern keypatterns = metaData.getBibtexKeyPattern(Globals.prefs.getKeyPattern());
- bibtexKeyPatternPanel.setValues(keypatterns);
- }
-
- private void init() {
- getContentPane().setLayout(new BorderLayout());
- getContentPane().add(bibtexKeyPatternPanel, BorderLayout.CENTER);
-
- JButton ok = new JButton(Localization.lang("OK"));
- JButton cancel = new JButton(); // label of "cancel" is set later as the label is overwritten by assigning an action to the button
-
- JPanel lower = new JPanel();
- lower.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
- ButtonBarBuilder bb = new ButtonBarBuilder(lower);
- bb.addGlue();
- bb.addButton(ok);
- bb.addButton(cancel);
- bb.addGlue();
-
- getContentPane().add(lower, BorderLayout.SOUTH);
-
- this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
- getContentPane().setPreferredSize(new Dimension(500, 600));
- pack();
-
- ok.addActionListener(e -> {
- metaData.setBibtexKeyPattern(bibtexKeyPatternPanel.getKeyPatternAsDatabaseBibtexKeyPattern());
- panel.markNonUndoableBaseChanged();
- dispose();
- });
-
- final JDialog dialog = this;
-
- Action cancelAction = new AbstractAction() {
-
- @Override
- public void actionPerformed(ActionEvent e) {
- dialog.dispatchEvent(new WindowEvent(dialog, WindowEvent.WINDOW_CLOSING));
- }
- };
- cancel.setAction(cancelAction);
- cancel.setText(Localization.lang("Cancel"));
-
- KeyBinder.bindCloseDialogKeyToCancelAction(this.getRootPane(), cancelAction);
- }
-
- @Override
- public void setVisible(boolean visible) {
- if (visible) {
- super.setVisible(visible);
- }
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/gui/ClipBoardManager.java b/src/main/java/net/sf/jabref/gui/ClipBoardManager.java
index 79712d0..fc1caf1 100644
--- a/src/main/java/net/sf/jabref/gui/ClipBoardManager.java
+++ b/src/main/java/net/sf/jabref/gui/ClipBoardManager.java
@@ -14,8 +14,8 @@ import java.util.List;
import java.util.Optional;
import net.sf.jabref.Globals;
-import net.sf.jabref.logic.importer.ImportFormatPreferences;
-import net.sf.jabref.logic.importer.fetcher.DOItoBibTeX;
+import net.sf.jabref.logic.importer.FetcherException;
+import net.sf.jabref.logic.importer.fetcher.DoiFetcher;
import net.sf.jabref.logic.importer.fileformat.BibtexParser;
import net.sf.jabref.logic.util.DOI;
import net.sf.jabref.model.database.BibDatabase;
@@ -67,15 +67,19 @@ public class ClipBoardManager implements ClipboardOwner {
return result;
}
+
public List<BibEntry> extractBibEntriesFromClipboard() {
// Get clipboard contents, and see if TransferableBibtexEntry is among the content flavors offered
Transferable content = CLIPBOARD.getContents(null);
-
List<BibEntry> result = new ArrayList<>();
+
+
if (content.isDataFlavorSupported(TransferableBibtexEntry.entryFlavor)) {
// We have determined that the clipboard data is a set of entries.
- try {
- result = (List<BibEntry>) content.getTransferData(TransferableBibtexEntry.entryFlavor);
+ try {
+ @SuppressWarnings("unchecked")
+ List<BibEntry> contents = (List<BibEntry>) content.getTransferData(TransferableBibtexEntry.entryFlavor);
+ result = contents;
} catch (UnsupportedFlavorException | ClassCastException ex) {
LOGGER.warn("Could not paste this type", ex);
} catch (IOException ex) {
@@ -87,14 +91,12 @@ public class ClipBoardManager implements ClipboardOwner {
// fetch from doi
if (DOI.build(data).isPresent()) {
LOGGER.info("Found DOI in clipboard");
- Optional<BibEntry> entry = DOItoBibTeX.getEntryFromDOI(new DOI(data).getDOI(),
- ImportFormatPreferences.fromPreferences(Globals.prefs));
+ Optional<BibEntry> entry = new DoiFetcher(Globals.prefs.getImportFormatPreferences()).performSearchById(new DOI(data).getDOI());
entry.ifPresent(result::add);
} else {
// parse bibtex string
- BibtexParser bp = new BibtexParser(new StringReader(data),
- ImportFormatPreferences.fromPreferences(Globals.prefs));
- BibDatabase db = bp.parse().getDatabase();
+ BibtexParser bp = new BibtexParser(Globals.prefs.getImportFormatPreferences());
+ BibDatabase db = bp.parse(new StringReader(data)).getDatabase();
LOGGER.info("Parsed " + db.getEntryCount() + " entries from clipboard text");
if (db.hasEntries()) {
result = db.getEntries();
@@ -104,6 +106,8 @@ public class ClipBoardManager implements ClipboardOwner {
LOGGER.warn("Could not parse this type", ex);
} catch (IOException ex) {
LOGGER.warn("Data is no longer available in the requested flavor", ex);
+ } catch (FetcherException ex) {
+ LOGGER.error("Error while fetching", ex);
}
}
diff --git a/src/main/java/net/sf/jabref/gui/ContentSelectorDialog2.java b/src/main/java/net/sf/jabref/gui/ContentSelectorDialog2.java
deleted file mode 100644
index 7c35341..0000000
--- a/src/main/java/net/sf/jabref/gui/ContentSelectorDialog2.java
+++ /dev/null
@@ -1,517 +0,0 @@
-package net.sf.jabref.gui;
-
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.Insets;
-import java.awt.Window;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.FocusAdapter;
-import java.awt.event.FocusEvent;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.SortedSet;
-import java.util.TreeSet;
-
-import javax.swing.AbstractAction;
-import javax.swing.Action;
-import javax.swing.BorderFactory;
-import javax.swing.DefaultListModel;
-import javax.swing.JButton;
-import javax.swing.JDialog;
-import javax.swing.JList;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.JTextField;
-
-import net.sf.jabref.MetaData;
-import net.sf.jabref.gui.help.HelpAction;
-import net.sf.jabref.gui.keyboard.KeyBinder;
-import net.sf.jabref.gui.util.FocusRequester;
-import net.sf.jabref.logic.help.HelpFile;
-import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.model.entry.FieldName;
-
-import com.jgoodies.forms.builder.ButtonBarBuilder;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-class ContentSelectorDialog2 extends JDialog {
-
- private final GridBagLayout gbl = new GridBagLayout();
- private final GridBagConstraints con = new GridBagConstraints();
- private final JPanel fieldPan = new JPanel();
- private final JPanel wordPan = new JPanel();
- private final JPanel buttonPan = new JPanel();
- private final JPanel fieldNamePan = new JPanel();
- private final JPanel wordEditPan = new JPanel();
-
- private static final String WORD_FIRSTLINE_TEXT = Localization.lang("<select word>");
- private static final String FIELD_FIRST_LINE = Localization.lang("<field name>");
- private final MetaData metaData;
- private String currentField;
- private final JabRefFrame frame;
- private final BasePanel panel;
- private final JButton newField = new JButton(Localization.lang("New"));
- private final JButton removeField = new JButton(Localization.lang("Remove"));
- private final JButton newWord = new JButton(Localization.lang("New"));
- private final JButton removeWord = new JButton(Localization.lang("Remove"));
- private final JButton ok = new JButton(Localization.lang("OK"));
- private final JButton cancel = new JButton();
- private final JButton apply = new JButton(Localization.lang("Apply"));
- private final DefaultListModel<String> fieldListModel = new DefaultListModel<>();
- private DefaultListModel<String> wordListModel = new DefaultListModel<>();
- private final JList<String> fieldList = new JList<>(fieldListModel);
- private final JList<String> wordList = new JList<>(wordListModel);
- private final JTextField fieldNameField = new JTextField("", 20);
- private final JTextField wordEditField = new JTextField("", 20);
- private final JScrollPane fPane = new JScrollPane(fieldList);
- private final JScrollPane wPane = new JScrollPane(wordList);
-
- private final Map<String, DefaultListModel<String>> wordListModels = new HashMap<>();
- private final List<String> removedFields = new ArrayList<>();
-
- private static final Log LOGGER = LogFactory.getLog(ContentSelectorDialog2.class);
-
- /**
- *
- * @param owner the parent Window (Dialog or Frame)
- * @param frame the JabRef Frame
- * @param panel the currently selected BasePanel
- * @param modal should this dialog be modal?
- * @param fieldName the field this selector is initialized for. May be null.
- */
- public ContentSelectorDialog2(Window owner, JabRefFrame frame, BasePanel panel, boolean modal,
- String fieldName) {
- super(owner, Localization.lang("Manage content selectors"));
- this.setModal(modal);
- this.metaData = panel.getBibDatabaseContext().getMetaData();
- this.frame = frame;
- this.panel = panel;
- this.currentField = fieldName;
-
- initLayout();
-
- setupFieldSelector();
- if (currentField != null) {
- int fieldInd = fieldListModel.indexOf(currentField);
- if (fieldInd >= 0) {
- fieldList.setSelectedIndex(fieldInd);
- }
- } else {
- if (!fieldListModel.isEmpty()) {
- fieldList.setSelectedIndex(0);
- currentField = fieldList.getSelectedValue();
- }
- }
-
- setupWordSelector();
- setupActions();
- KeyBinder.bindCloseDialogKeyToCancelAction(this.rootPane, cancel.getAction());
-
- pack();
- }
-
- private void setupActions() {
-
- wordList.addListSelectionListener(e -> {
- wordEditField.setText(wordList.getSelectedValue());
- wordEditField.selectAll();
- new FocusRequester(wordEditField);
- });
-
- newWord.addActionListener(e -> newWordAction());
-
- ActionListener wordEditFieldListener = e -> actOnWordEdit();
- wordEditField.addActionListener(wordEditFieldListener);
-
- removeWord.addActionListener(e -> {
- int index = wordList.getSelectedIndex();
- if (index == -1) {
- return;
- }
- wordListModel.remove(index);
- wordEditField.setText("");
- if (!wordListModel.isEmpty()) {
- wordList.setSelectedIndex(Math.min(index, wordListModel.size() - 1));
- }
- });
-
- fieldList.addListSelectionListener(e -> {
- currentField = fieldList.getSelectedValue();
- fieldNameField.setText("");
- setupWordSelector();
- });
-
- newField.addActionListener(e -> {
- if (!fieldListModel.get(0).equals(FIELD_FIRST_LINE)) {
- // only add <field name> once
- fieldListModel.add(0, FIELD_FIRST_LINE);
- }
- fieldList.setSelectedIndex(0);
- fPane.getVerticalScrollBar().setValue(0);
- fieldNameField.setEnabled(true);
- fieldNameField.setText(currentField);
- fieldNameField.selectAll();
-
- new FocusRequester(fieldNameField);
- });
-
- fieldNameField.addActionListener(e -> fieldNameField.transferFocus());
-
- fieldNameField.addFocusListener(new FieldNameFocusAdapter());
-
- removeField.addActionListener(e -> {
- int index = fieldList.getSelectedIndex();
- if (index == -1) {
- return;
- }
- String fieldName = fieldListModel.get(index);
- removedFields.add(fieldName);
- fieldListModel.remove(index);
- wordListModels.remove(fieldName);
- fieldNameField.setText("");
- if (!fieldListModel.isEmpty()) {
- fieldList.setSelectedIndex(Math.min(index, wordListModel.size() - 1));
- }
- });
-
- ok.addActionListener(e -> {
- try {
- applyChanges();
- dispose();
- } catch (Exception ex) {
- LOGGER.info("Could not apply changes in \"Manage content selectors\"", ex);
- JOptionPane.showMessageDialog(frame, Localization.lang("Could not apply changes."));
- }
- });
-
- apply.addActionListener(e -> {
- // Store if an entry is currently being edited:
- if (!"".equals(wordEditField.getText())) {
- wordEditFieldListener.actionPerformed(null);
- }
- try {
- applyChanges();
- } catch (Exception ex) {
- LOGGER.info("Could not apply changes in \"Manage content selectors\"", ex);
- JOptionPane.showMessageDialog(frame, Localization.lang("Could not apply changes."));
- }
- });
-
- Action cancelAction = new AbstractAction() {
-
- @Override
- public void actionPerformed(ActionEvent e) {
- dispose();
- }
- };
- cancelAction.putValue(Action.NAME, Localization.lang("Cancel"));
- cancel.setAction(cancelAction);
- }
-
- private void actOnWordEdit() {
- String old = wordList.getSelectedValue();
- String newVal = wordEditField.getText();
- if ("".equals(newVal) || newVal.equals(old)) {
- return; // Empty string or no change.
- }
- int index = wordList.getSelectedIndex();
- if (wordListModel.contains(newVal)) {
- // ensure that word already in list is visible
- index = wordListModel.indexOf(newVal);
- wordList.ensureIndexIsVisible(index);
- return;
- }
-
- int newIndex = findPos(wordListModel, newVal);
- if (index >= 0) {
- // initiate replacement of selected word
- wordListModel.remove(index);
- if (newIndex > index) {
- // newIndex has to be adjusted after removal of previous entry
- newIndex--;
- }
- }
- wordListModel.add(newIndex, newVal);
- wordList.ensureIndexIsVisible(newIndex);
- wordEditField.selectAll();
- }
-
- private void newWordAction() {
- if (wordListModel.isEmpty() ||
- !wordListModel.get(0).equals(WORD_FIRSTLINE_TEXT)) {
- wordListModel.add(0, WORD_FIRSTLINE_TEXT);
- }
- wordList.setSelectedIndex(0);
- wPane.getVerticalScrollBar().setValue(0);
- }
-
- private void applyChanges() {
- boolean changedFieldSet = false; // Watch if we need to rebuild entry editors
- boolean anythingChanged = false; // Watch if we should mark as there is data changed
-
- // First remove the mappings for fields that have been deleted.
- // If these were re-added, they will be added below, so it doesn't
- // cause any harm to remove them here.
- for (String fieldName : removedFields) {
- metaData.clearContentSelectors(fieldName);
- changedFieldSet = true;
- anythingChanged = true;
- }
-
- // Cycle through all fields that we have created listmodels for:
- for (Map.Entry<String, DefaultListModel<String>> entry : wordListModels.entrySet()) {
- // For each field name, store the values:
- if ((entry.getKey() == null) || FIELD_FIRST_LINE.equals(entry.getKey())) {
- continue;
- }
- DefaultListModel<String> lm = entry.getValue();
- int start = 0;
- // Avoid storing the <new word> marker if it is there:
- if (!lm.isEmpty()) {
- while ((start < lm.size()) && lm.get(start).equals(WORD_FIRSTLINE_TEXT)) {
- start++;
- }
- }
-
- Set<String> data = new HashSet<>();
- for (int wrd = start; wrd < lm.size(); wrd++) {
- String word = lm.get(wrd);
- data.add(word);
- }
-
- // Check if any words have been added
- if (!data.equals(new HashSet<>(metaData.getContentSelectors(entry.getKey())))) {
- anythingChanged = true;
- }
-
- // Check if there are words to be added and previously there were no content selector for the field
- if (!data.isEmpty() && metaData.getContentSelectors(entry.getKey()).isEmpty()) {
- changedFieldSet = true;
- }
-
- metaData.setContentSelectors(entry.getKey(), new ArrayList<>(data));
- }
-
- // Update all selectors in the current BasePanel.
- if (changedFieldSet) {
- // We have added or removed content selectors, update the entry editor
- panel.rebuildAllEntryEditors();
- } else if (anythingChanged) {
- // Enough to update the content selectors, if anything changed
- panel.updateAllContentSelectors();
- }
-
- if (anythingChanged) {
- // Mark the database updated so changes are not lost
- panel.markNonUndoableBaseChanged();
- }
-
- panel.getAutoCompleters().addContentSelectorValuesToAutoCompleters(panel.getBibDatabaseContext().getMetaData());
-
- }
-
- /**
- * Set the contents of the field selector list.
- *
- */
- private void setupFieldSelector() {
- fieldListModel.clear();
- SortedSet<String> contents = new TreeSet<>();
- for (String s : metaData) {
- if (s.startsWith(MetaData.SELECTOR_META_PREFIX)) {
- contents.add(s.substring(MetaData.SELECTOR_META_PREFIX.length()));
- }
- }
- if (contents.isEmpty()) {
- // if nothing was added, put the default fields (as described in the help)
- fieldListModel.addElement(FieldName.AUTHOR);
- fieldListModel.addElement(FieldName.JOURNAL);
- fieldListModel.addElement(FieldName.KEYWORDS);
- fieldListModel.addElement(FieldName.PUBLISHER);
- } else {
- for (String s : contents) {
- fieldListModel.addElement(s);
- }
- }
-
- if (currentField == null) {
- // if dialog is created for the whole database,
- // select the first field to avoid confusions in GUI usage
- fieldList.setSelectedIndex(0);
- } else {
- // a specific field has been chosen at the constructor
- // select this field
- int i = fieldListModel.indexOf(currentField);
- if (i != -1) {
- // field has been found in list, select it
- fieldList.setSelectedIndex(i);
- }
- }
- }
-
- private void setupWordSelector() {
-
- // Have we already created a listmodel for this field?
- wordListModel = wordListModels.get(currentField);
- if (wordListModel == null) {
- wordListModel = new DefaultListModel<>();
- wordList.setModel(wordListModel);
- wordListModels.put(currentField, wordListModel);
-
- int index = 0;
- for (String s : metaData.getContentSelectors(currentField)) {
- wordListModel.add(index, s);
- index++;
- }
- } else {
- wordList.setModel(wordListModel);
- }
- }
-
- private static int findPos(DefaultListModel<String> lm, String item) {
- for (int i = 0; i < lm.size(); i++) {
- String s = lm.get(i);
- if (item.compareToIgnoreCase(s) < 0) { // item precedes s
- return i;
- }
- }
- return lm.size();
- }
-
- private void initLayout() {
- fieldNameField.setEnabled(false);
- fieldList.setVisibleRowCount(4);
- wordList.setVisibleRowCount(10);
- final String VAL = "Uren luren himmelturen, ja Besseggen.";
- fieldList.setPrototypeCellValue(VAL);
- wordList.setPrototypeCellValue(VAL);
-
- fieldPan.setBorder(BorderFactory.createTitledBorder
- (BorderFactory.createEtchedBorder(),
- Localization.lang("Field name")));
- wordPan.setBorder(BorderFactory.createTitledBorder
- (BorderFactory.createEtchedBorder(),
- Localization.lang("Keyword")));
- fieldPan.setLayout(gbl);
- wordPan.setLayout(gbl);
- con.insets = new Insets(2, 2, 2, 2);
- con.fill = GridBagConstraints.BOTH;
- con.gridwidth = 2;
- con.weightx = 1;
- con.weighty = 1;
- con.gridx = 0;
- con.gridy = 0;
- gbl.setConstraints(fPane, con);
- fieldPan.add(fPane);
- gbl.setConstraints(wPane, con);
- wordPan.add(wPane);
- con.gridwidth = 1;
- con.gridx = 2;
- //con.weightx = 0.7;
- con.gridheight = 2;
- gbl.setConstraints(fieldNamePan, con);
- fieldPan.add(fieldNamePan);
- gbl.setConstraints(wordEditPan, con);
- wordPan.add(wordEditPan);
- con.gridx = 0;
- con.gridy = 1;
- con.weightx = 0;
- con.weighty = 0;
- con.gridwidth = 1;
- con.gridheight = 1;
- con.fill = GridBagConstraints.NONE;
- con.anchor = GridBagConstraints.WEST;
- gbl.setConstraints(newField, con);
- fieldPan.add(newField);
- gbl.setConstraints(newWord, con);
- wordPan.add(newWord);
- con.gridx = 1;
- //con.anchor = GridBagConstraints.EAST;
- gbl.setConstraints(removeField, con);
- fieldPan.add(removeField);
- gbl.setConstraints(removeWord, con);
- wordPan.add(removeWord);
- con.anchor = GridBagConstraints.WEST;
- con.gridx = 0;
- con.gridy = 0;
- gbl.setConstraints(fieldNameField, con);
- fieldNamePan.add(fieldNameField);
- gbl.setConstraints(wordEditField, con);
- wordEditPan.add(wordEditField);
-
- // Add buttons:
- ButtonBarBuilder bsb = new ButtonBarBuilder(buttonPan);
- bsb.addGlue();
- bsb.addButton(ok);
- bsb.addButton(apply);
- bsb.addButton(cancel);
- bsb.addRelatedGap();
- bsb.addButton(new HelpAction(HelpFile.CONTENT_SELECTOR).getHelpButton());
- bsb.addGlue();
-
- // Add panels to dialog:
- con.fill = GridBagConstraints.BOTH;
- getContentPane().setLayout(gbl);
- con.weightx = 1;
- con.weighty = 0.5;
- con.gridwidth = 1;
- con.gridheight = 1;
- con.gridx = 0;
- con.gridy = 0;
- gbl.setConstraints(fieldPan, con);
- getContentPane().add(fieldPan);
- con.gridy = 1;
- gbl.setConstraints(wordPan, con);
- getContentPane().add(wordPan);
- con.weighty = 0;
- con.gridy = 2;
- con.insets = new Insets(12, 2, 2, 2);
- gbl.setConstraints(buttonPan, con);
- getContentPane().add(buttonPan);
-
- }
-
-
- private class FieldNameFocusAdapter extends FocusAdapter {
-
- /**
- * Adds the text value to the list
- */
- @Override
- public void focusLost(FocusEvent e) {
- String s = fieldNameField.getText();
- fieldNameField.setText("");
- fieldNameField.setEnabled(false);
- if (!FIELD_FIRST_LINE.equals(s) && !"".equals(s)) {
- // user has typed something
-
- // remove "<first name>" from list
- fieldListModel.remove(0);
-
- int pos;
- if (fieldListModel.contains(s)) {
- // field already exists, scroll to that field (below)
- pos = fieldListModel.indexOf(s);
- } else {
- // Add new field.
- pos = findPos(fieldListModel, s);
- fieldListModel.add(Math.max(0, pos), s);
- }
- fieldList.setSelectedIndex(pos);
- fieldList.ensureIndexIsVisible(pos);
- currentField = s;
- setupWordSelector();
- newWordAction();
- }
- }
-
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/gui/DuplicateResolverDialog.java b/src/main/java/net/sf/jabref/gui/DuplicateResolverDialog.java
index fb9f556..f881291 100644
--- a/src/main/java/net/sf/jabref/gui/DuplicateResolverDialog.java
+++ b/src/main/java/net/sf/jabref/gui/DuplicateResolverDialog.java
@@ -12,7 +12,7 @@ import javax.swing.JPanel;
import net.sf.jabref.gui.help.HelpAction;
import net.sf.jabref.gui.importer.ImportInspectionDialog;
import net.sf.jabref.gui.mergeentries.MergeEntries;
-import net.sf.jabref.gui.util.PositionWindow;
+import net.sf.jabref.gui.util.WindowLocation;
import net.sf.jabref.logic.help.HelpFile;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.model.entry.BibEntry;
@@ -124,10 +124,10 @@ public class DuplicateResolverDialog extends JDialog {
getContentPane().add(options, BorderLayout.SOUTH);
pack();
- PositionWindow pw = new PositionWindow(this, JabRefPreferences.DUPLICATES_POS_X,
+ WindowLocation pw = new WindowLocation(this, JabRefPreferences.DUPLICATES_POS_X,
JabRefPreferences.DUPLICATES_POS_Y, JabRefPreferences.DUPLICATES_SIZE_X,
JabRefPreferences.DUPLICATES_SIZE_Y);
- pw.setWindowPosition();
+ pw.displayWindowAtStoredLocation();
both.requestFocus();
}
diff --git a/src/main/java/net/sf/jabref/gui/DuplicateSearch.java b/src/main/java/net/sf/jabref/gui/DuplicateSearch.java
index dfef3e5..fbfc1cb 100644
--- a/src/main/java/net/sf/jabref/gui/DuplicateSearch.java
+++ b/src/main/java/net/sf/jabref/gui/DuplicateSearch.java
@@ -42,7 +42,7 @@ public class DuplicateSearch implements Runnable {
}
SearcherRunnable st = new SearcherRunnable();
- JabRefExecutorService.INSTANCE.executeWithLowPriorityInOwnThread(st, "Searcher");
+ JabRefExecutorService.INSTANCE.executeInterruptableTask(st, "DuplicateSearcher");
int current = 0;
final List<BibEntry> toRemove = new ArrayList<>();
diff --git a/src/main/java/net/sf/jabref/gui/EntryCustomizationDialog.java b/src/main/java/net/sf/jabref/gui/EntryCustomizationDialog.java
index 94b8f23..04a4bbe 100644
--- a/src/main/java/net/sf/jabref/gui/EntryCustomizationDialog.java
+++ b/src/main/java/net/sf/jabref/gui/EntryCustomizationDialog.java
@@ -26,21 +26,22 @@ import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.ListSelectionModel;
+import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
+import javax.swing.table.AbstractTableModel;
import net.sf.jabref.Globals;
import net.sf.jabref.gui.keyboard.KeyBinding;
-import net.sf.jabref.gui.util.FocusRequester;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.model.EntryTypes;
import net.sf.jabref.model.database.BibDatabaseMode;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.CustomEntryType;
import net.sf.jabref.model.entry.EntryType;
-import net.sf.jabref.model.entry.EntryUtil;
import net.sf.jabref.model.entry.InternalBibtexFields;
+import net.sf.jabref.model.strings.StringUtil;
import com.jgoodies.forms.builder.ButtonBarBuilder;
@@ -222,7 +223,7 @@ public class EntryCustomizationDialog extends JDialog implements ListSelectionLi
optComp2.setFields(new ArrayList<>());
optComp2.setEnabled(true);
}
- new FocusRequester(reqComp);
+ reqComp.requestFocus();
}
} else {
reqComp.setFields(rl);
@@ -260,10 +261,10 @@ public class EntryCustomizationDialog extends JDialog implements ListSelectionLi
if (defaulted.contains(stringListEntry.getKey())) {
// This type should be reverted to its default setup.
- String nm = EntryUtil.capitalizeFirst(stringListEntry.getKey());
+ String nm = StringUtil.capitalizeFirst(stringListEntry.getKey());
EntryTypes.removeType(nm, bibDatabaseMode);
- updateTypesForEntries(nm);
+ updateTypesForEntries();
continue;
}
@@ -285,11 +286,11 @@ public class EntryCustomizationDialog extends JDialog implements ListSelectionLi
if (changesMade) {
CustomEntryType typ = biblatexMode ?
- new CustomEntryType(EntryUtil.capitalizeFirst(stringListEntry.getKey()), reqStr, optStr, opt2Str) :
- new CustomEntryType(EntryUtil.capitalizeFirst(stringListEntry.getKey()), reqStr, optStr);
+ new CustomEntryType(StringUtil.capitalizeFirst(stringListEntry.getKey()), reqStr, optStr, opt2Str) :
+ new CustomEntryType(StringUtil.capitalizeFirst(stringListEntry.getKey()), reqStr, optStr);
EntryTypes.addOrModifyCustomEntryType(typ);
- updateTypesForEntries(typ.getName());
+ updateTypesForEntries();
}
}
@@ -320,14 +321,14 @@ public class EntryCustomizationDialog extends JDialog implements ListSelectionLi
+ "type will be declared "
+ "typeless. Continue?"),
Localization.lang("Delete custom format") +
- " '" + EntryUtil.capitalizeFirst(name) + '\'', JOptionPane.YES_NO_OPTION,
+ " '" + StringUtil.capitalizeFirst(name) + '\'', JOptionPane.YES_NO_OPTION,
JOptionPane.WARNING_MESSAGE);
if (reply != JOptionPane.YES_OPTION) {
return;
}
}
EntryTypes.removeType(name, bibDatabaseMode);
- updateTypesForEntries(EntryUtil.capitalizeFirst(name));
+ updateTypesForEntries();
changed.remove(name);
reqLists.remove(name);
optLists.remove(name);
@@ -377,22 +378,17 @@ public class EntryCustomizationDialog extends JDialog implements ListSelectionLi
* a valid type, that no obsolete entry editors are around, and that
* the right-click menus' change type menu is up-to-date.
*/
- private void updateTypesForEntries(String typeName) {
+ private void updateTypesForEntries() {
for (BasePanel bp : frame.getBasePanelList()) {
-
- // Invalidate associated cached entry editor
- bp.getEntryEditors().remove(typeName);
-
for (BibEntry entry : bp.getDatabase().getEntries()) {
EntryTypes.getType(entry.getType(), bibDatabaseMode).ifPresent(entry::setType);
}
}
-
}
private void updateTables() {
for (BasePanel basePanel : frame.getBasePanelList()) {
- ((javax.swing.table.AbstractTableModel) basePanel.getMainTable().getModel()).fireTableDataChanged();
+ ((AbstractTableModel) basePanel.getMainTable().getModel()).fireTableDataChanged();
}
}
@@ -437,17 +433,17 @@ public class EntryCustomizationDialog extends JDialog implements ListSelectionLi
class DataListener implements ListDataListener {
@Override
- public void intervalAdded(javax.swing.event.ListDataEvent e) {
+ public void intervalAdded(ListDataEvent e) {
record();
}
@Override
- public void intervalRemoved(javax.swing.event.ListDataEvent e) {
+ public void intervalRemoved(ListDataEvent e) {
record();
}
@Override
- public void contentsChanged(javax.swing.event.ListDataEvent e) {
+ public void contentsChanged(ListDataEvent e) {
record();
}
diff --git a/src/main/java/net/sf/jabref/gui/EntryMarker.java b/src/main/java/net/sf/jabref/gui/EntryMarker.java
index 3c55b5a..b2f28a7 100644
--- a/src/main/java/net/sf/jabref/gui/EntryMarker.java
+++ b/src/main/java/net/sf/jabref/gui/EntryMarker.java
@@ -29,7 +29,7 @@ public class EntryMarker {
int prevMarkLevel;
String newValue = null;
if (be.hasField(FieldName.MARKED_INTERNAL)) {
- String markerString = be.getFieldOptional(FieldName.MARKED_INTERNAL).get();
+ String markerString = be.getField(FieldName.MARKED_INTERNAL).get();
int index = markerString.indexOf(Globals.prefs.getWrappedUsername());
if (index >= 0) {
// Already marked 1 for this user.
@@ -57,7 +57,7 @@ public class EntryMarker {
}
ce.addEdit(new UndoableFieldChange(be, FieldName.MARKED_INTERNAL,
- be.getFieldOptional(FieldName.MARKED_INTERNAL).orElse(null), newValue));
+ be.getField(FieldName.MARKED_INTERNAL).orElse(null), newValue));
be.setField(FieldName.MARKED_INTERNAL, newValue);
}
@@ -66,7 +66,7 @@ public class EntryMarker {
*/
public static void unmarkEntry(BibEntry be, boolean onlyMaxLevel, BibDatabase database, NamedCompound ce) {
if (be.hasField(FieldName.MARKED_INTERNAL)) {
- String markerString = be.getFieldOptional(FieldName.MARKED_INTERNAL).get();
+ String markerString = be.getField(FieldName.MARKED_INTERNAL).get();
if ("0".equals(markerString)) {
if (!onlyMaxLevel) {
unmarkOldStyle(be, database, ce);
@@ -121,7 +121,7 @@ public class EntryMarker {
}
String newVal = sb.length() > 0 ? sb.toString() : null;*/
ce.addEdit(new UndoableFieldChange(be, FieldName.MARKED_INTERNAL,
- be.getFieldOptional(FieldName.MARKED_INTERNAL).get(), newValue));
+ be.getField(FieldName.MARKED_INTERNAL).get(), newValue));
if (newValue == null) {
be.clearField(FieldName.MARKED_INTERNAL);
} else {
@@ -144,7 +144,7 @@ public class EntryMarker {
private static void unmarkOldStyle(BibEntry be, BibDatabase database, NamedCompound ce) {
Set<Object> owners = new TreeSet<>();
for (BibEntry entry : database.getEntries()) {
- entry.getFieldOptional(FieldName.OWNER).ifPresent(owners::add);
+ entry.getField(FieldName.OWNER).ifPresent(owners::add);
}
owners.remove(Globals.prefs.get(JabRefPreferences.DEFAULT_OWNER));
StringBuilder sb = new StringBuilder();
@@ -156,11 +156,11 @@ public class EntryMarker {
String newVal = sb.toString();
if (newVal.isEmpty()) {
ce.addEdit(new UndoableFieldChange(be, FieldName.MARKED_INTERNAL,
- be.getFieldOptional(FieldName.MARKED_INTERNAL).orElse(null), null));
+ be.getField(FieldName.MARKED_INTERNAL).orElse(null), null));
be.clearField(FieldName.MARKED_INTERNAL);
} else {
ce.addEdit(new UndoableFieldChange(be, FieldName.MARKED_INTERNAL,
- be.getFieldOptional(FieldName.MARKED_INTERNAL).orElse(null), newVal));
+ be.getField(FieldName.MARKED_INTERNAL).orElse(null), newVal));
be.setField(FieldName.MARKED_INTERNAL, newVal);
}
}
@@ -169,7 +169,7 @@ public class EntryMarker {
if (!be.hasField(FieldName.MARKED_INTERNAL)) {
return 0;
}
- String s = be.getFieldOptional(FieldName.MARKED_INTERNAL).get();
+ String s = be.getField(FieldName.MARKED_INTERNAL).get();
if ("0".equals(s)) {
return 1;
}
diff --git a/src/main/java/net/sf/jabref/gui/EntryTypeDialog.java b/src/main/java/net/sf/jabref/gui/EntryTypeDialog.java
index 9f60af9..2fb61ef 100644
--- a/src/main/java/net/sf/jabref/gui/EntryTypeDialog.java
+++ b/src/main/java/net/sf/jabref/gui/EntryTypeDialog.java
@@ -9,25 +9,39 @@ import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Collection;
+import java.util.Optional;
+import java.util.concurrent.ExecutionException;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.JButton;
+import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.SwingUtilities;
+import javax.swing.SwingWorker;
-import net.sf.jabref.BibDatabaseContext;
import net.sf.jabref.Globals;
+import net.sf.jabref.gui.importer.fetcher.EntryFetchers;
import net.sf.jabref.gui.keyboard.KeyBinding;
import net.sf.jabref.logic.CustomEntryTypesManager;
+import net.sf.jabref.logic.importer.FetcherException;
+import net.sf.jabref.logic.importer.IdBasedFetcher;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.model.EntryTypes;
+import net.sf.jabref.model.database.BibDatabaseContext;
+import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.BibtexEntryTypes;
import net.sf.jabref.model.entry.EntryType;
import net.sf.jabref.model.entry.IEEETranEntryTypes;
import com.jgoodies.forms.builder.ButtonBarBuilder;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
import org.jdesktop.swingx.VerticalLayout;
/**
@@ -35,7 +49,15 @@ import org.jdesktop.swingx.VerticalLayout;
* Returns null if canceled.
*/
public class EntryTypeDialog extends JDialog implements ActionListener {
+
+ private static final Log LOGGER = LogFactory.getLog(EntryTypeDialog.class);
+
private EntryType type;
+ private SwingWorker<Optional<BibEntry>, Void> fetcherWorker = new FetcherWorker();
+ private JButton generateButton;
+ private JTextField idTextField;
+ private JComboBox<String> comboBox;
+ private final JabRefFrame frame;
private static final int COLUMN = 3;
private final boolean biblatexMode;
@@ -47,7 +69,7 @@ public class EntryTypeDialog extends JDialog implements ActionListener {
private final EntryType type;
- public TypeButton(String label, EntryType type) {
+ TypeButton(String label, EntryType type) {
super(label);
this.type = type;
}
@@ -66,6 +88,8 @@ public class EntryTypeDialog extends JDialog implements ActionListener {
// modal dialog
super(frame, true);
+ this.frame = frame;
+
bibDatabaseContext = frame.getCurrentBasePanel().getBibDatabaseContext();
biblatexMode = bibDatabaseContext.isBiblatexMode();
@@ -91,13 +115,17 @@ public class EntryTypeDialog extends JDialog implements ActionListener {
JPanel panel = new JPanel();
panel.setLayout(new VerticalLayout());
- if(biblatexMode) {
+ if (biblatexMode) {
panel.add(createEntryGroupPanel("BibLateX", EntryTypes.getAllValues(bibDatabaseContext.getMode())));
} else {
panel.add(createEntryGroupPanel("BibTeX", BibtexEntryTypes.ALL));
panel.add(createEntryGroupPanel("IEEETran", IEEETranEntryTypes.ALL));
- panel.add(createEntryGroupPanel(Localization.lang("Custom"), CustomEntryTypesManager.ALL));
+
+ if (!CustomEntryTypesManager.ALL.isEmpty()) {
+ panel.add(createEntryGroupPanel(Localization.lang("Custom"), CustomEntryTypesManager.ALL));
+ }
}
+ panel.add(createIdFetcherPanel());
return panel;
}
@@ -148,11 +176,81 @@ public class EntryTypeDialog extends JDialog implements ActionListener {
return panel;
}
+ private JPanel createIdFetcherPanel() {
+ JLabel fetcherLabel = new JLabel(Localization.lang("ID type"));
+ JLabel idLabel = new JLabel(Localization.lang("ID"));
+ generateButton = new JButton(Localization.lang("Generate"));
+ idTextField = new JTextField("");
+ comboBox = new JComboBox<>();
+
+ EntryFetchers.getIdFetchers().forEach(fetcher -> comboBox.addItem(fetcher.getName()));
+
+ generateButton.addActionListener(action -> {
+ fetcherWorker.execute();
+ });
+
+ comboBox.addActionListener(e -> {
+ idTextField.requestFocus();
+ idTextField.selectAll();
+ });
+
+ idTextField.addActionListener(event -> fetcherWorker.execute());
+
+ JPanel jPanel = new JPanel();
+
+ GridBagConstraints constraints = new GridBagConstraints();
+ constraints.insets = new Insets(4,4,4,4);
+
+ GridBagLayout layout = new GridBagLayout();
+ jPanel.setLayout(layout);
+
+ constraints.fill = GridBagConstraints.HORIZONTAL;
+
+ constraints.gridx = 0;
+ constraints.gridy = 0;
+ constraints.weightx = 1;
+ jPanel.add(fetcherLabel, constraints);
+
+ constraints.gridx = 1;
+ constraints.gridy = 0;
+ constraints.weightx = 2;
+ jPanel.add(comboBox, constraints);
+
+ constraints.gridx = 0;
+ constraints.gridy = 1;
+ constraints.weightx = 1;
+ jPanel.add(idLabel, constraints);
+
+ constraints.gridx = 1;
+ constraints.gridy = 1;
+ constraints.weightx = 2;
+ jPanel.add(idTextField, constraints);
+
+ constraints.gridy = 2;
+ constraints.gridx = 0;
+ constraints.gridwidth = 2;
+ constraints.fill = GridBagConstraints.NONE;
+ jPanel.add(generateButton, constraints);
+
+ jPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), Localization.lang("ID-based_entry_generator")));
+
+ SwingUtilities.invokeLater(() -> idTextField.requestFocus());
+
+ return jPanel;
+ }
+
+ private void stopFetching() {
+ if (fetcherWorker.getState() == SwingWorker.StateValue.STARTED) {
+ fetcherWorker.cancel(true);
+ }
+ }
+
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() instanceof TypeButton) {
type = ((TypeButton) e.getSource()).getType();
}
+ stopFetching();
dispose();
}
@@ -168,8 +266,65 @@ public class EntryTypeDialog extends JDialog implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
+ stopFetching();
dispose();
}
}
+ private class FetcherWorker extends SwingWorker<Optional<BibEntry>, Void> {
+ private boolean fetcherException = false;
+ private String fetcherExceptionMessage = "";
+ private IdBasedFetcher fetcher = null;
+ private String searchID = "";
+
+ @Override
+ protected Optional<BibEntry> doInBackground() throws Exception {
+ Optional<BibEntry> bibEntry = Optional.empty();
+ SwingUtilities.invokeLater(() -> {
+ generateButton.setEnabled(false);
+ generateButton.setText(Localization.lang("Searching..."));
+ });
+ searchID = idTextField.getText().trim();
+ fetcher = EntryFetchers.getIdFetchers().get(comboBox.getSelectedIndex());
+ if (!searchID.isEmpty()) {
+ try {
+ bibEntry = fetcher.performSearchById(searchID);
+ } catch (FetcherException e) {
+ LOGGER.error(e.getMessage(), e);
+ fetcherException = true;
+ fetcherExceptionMessage = e.getMessage();
+ }
+ }
+ return bibEntry;
+ }
+
+ @Override
+ protected void done() {
+ try {
+ Optional<BibEntry> result = get();
+ if (result.isPresent()) {
+ frame.getCurrentBasePanel().insertEntry(result.get());
+ dispose();
+ } else if (searchID.trim().isEmpty()) {
+ JOptionPane.showMessageDialog(frame, Localization.lang("The given search ID was empty."), Localization.lang("Empty search ID"), JOptionPane.WARNING_MESSAGE);
+ } else if (!fetcherException) {
+ JOptionPane.showMessageDialog(frame, Localization.lang("Fetcher_'%0'_did_not_find_an_entry_for_id_'%1'.", fetcher.getName(), searchID)+ "\n" + fetcherExceptionMessage, Localization.lang("No files found."), JOptionPane.WARNING_MESSAGE);
+ } else {
+ JOptionPane.showMessageDialog(frame,
+ Localization.lang("Error while fetching from %0", fetcher.getName()) +"." + "\n" + fetcherExceptionMessage,
+ Localization.lang("Error"), JOptionPane.ERROR_MESSAGE);
+ }
+ fetcherWorker = new FetcherWorker();
+ SwingUtilities.invokeLater(() -> {
+ idTextField.requestFocus();
+ idTextField.selectAll();
+ generateButton.setText(Localization.lang("Generate"));
+ generateButton.setEnabled(true);
+ });
+ } catch (ExecutionException | InterruptedException e) {
+ LOGGER.error(String.format("Exception during fetching when using fetcher '%s' with entry id '%s'.", searchID, fetcher.getName()), e);
+ }
+ }
+ }
+
}
diff --git a/src/main/java/net/sf/jabref/gui/FieldContentSelector.java b/src/main/java/net/sf/jabref/gui/FieldContentSelector.java
deleted file mode 100644
index fe8e88d..0000000
--- a/src/main/java/net/sf/jabref/gui/FieldContentSelector.java
+++ /dev/null
@@ -1,228 +0,0 @@
-package net.sf.jabref.gui;
-
-import java.awt.Dimension;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.Window;
-import java.awt.event.ActionEvent;
-
-import javax.swing.AbstractAction;
-import javax.swing.Box;
-import javax.swing.JButton;
-import javax.swing.JComboBox;
-import javax.swing.JComponent;
-import javax.swing.KeyStroke;
-
-import net.sf.jabref.MetaData;
-import net.sf.jabref.gui.fieldeditors.FieldEditor;
-import net.sf.jabref.logic.l10n.Localization;
-
-import com.jgoodies.forms.layout.Sizes;
-import com.jgoodies.looks.Options;
-
-/**
- * A combo-box and a manage button that will add selected strings to an
- * associated entry editor.
- *
- * Used to manage keywords and authors for instance.
- */
-public class FieldContentSelector extends JComponent {
-
- private static final int MAX_CONTENT_SELECTOR_WIDTH = 240; // The max width of the combobox for content selectors.
- private final JComboBox<String> comboBox;
-
- private final FieldEditor editor;
-
- private final MetaData metaData;
-
- private final AbstractAction action;
- private final String delimiter;
-
-
- /**
- *
- * Create a new FieldContentSelector.
- *
- * @param frame
- * The one JabRef-Frame.
- * @param panel
- * The basepanel the entry-editor is on.
- * @param owner
- * The window/frame/dialog which should be the owner of the
- * content selector dialog.
- * @param editor
- * The entry editor which will be appended by the text selected
- * by the user from the combobox.
- * @param action
- * The action that will be performed to after an item from the
- * combobox has been appended to the text in the entryeditor.
- * @param horizontalLayout
- * Whether to put a 2 pixel horizontal strut between combobox and
- * button.
- */
- public FieldContentSelector(JabRefFrame frame, final BasePanel panel,
- Window owner, final FieldEditor editor,
- final AbstractAction action, boolean horizontalLayout, String delimiter) {
-
-
- this.editor = editor;
- this.metaData = panel.getBibDatabaseContext().getMetaData();
- this.action = action;
- this.delimiter = delimiter;
-
- comboBox = new JComboBox<String>() {
-
- @Override
- public Dimension getPreferredSize() {
- Dimension parents = super.getPreferredSize();
- if (parents.width > MAX_CONTENT_SELECTOR_WIDTH) {
- parents.width = MAX_CONTENT_SELECTOR_WIDTH;
- }
- return parents;
- }
- };
-
- GridBagLayout gbl = new GridBagLayout();
- GridBagConstraints con = new GridBagConstraints();
-
- setLayout(gbl);
-
- // comboBox.setEditable(true);
-
- comboBox.setMaximumRowCount(35);
-
- // Set the width of the popup independent of the size of th box itself:
- comboBox.putClientProperty(Options.COMBO_POPUP_PROTOTYPE_DISPLAY_VALUE_KEY,
- "The longest text in the combo popup menu. And even longer.");
-
- rebuildComboBox();
-
- con.gridwidth = horizontalLayout ? 3 : GridBagConstraints.REMAINDER;
- con.fill = GridBagConstraints.HORIZONTAL;
- con.weightx = 1;
- gbl.setConstraints(comboBox, con);
-
- comboBox.addActionListener(e -> {
- /*
- * These conditions signify arrow key navigation in the dropdown
- * list, so we should not react to it. I'm not sure if this is
- * well defined enough to be guaranteed to work everywhere.
- */
- if ("comboBoxChanged".equals(e.getActionCommand()) && (e.getModifiers() == 0)) {
- return;
- }
-
- selectionMade();
- });
- // Add an action for the Enter key that signals a selection:
- comboBox.getInputMap().put(KeyStroke.getKeyStroke("ENTER"), "enter");
- comboBox.getActionMap().put("enter", new AbstractAction() {
-
- @Override
- public void actionPerformed(ActionEvent actionEvent) {
- selectionMade();
- comboBox.setPopupVisible(false);
- }
- });
-
- add(comboBox);
-
- if (horizontalLayout) {
- add(Box.createHorizontalStrut(Sizes.dialogUnitXAsPixel(2, this)));
- }
-
- JButton manage = new JButton(Localization.lang("Manage"));
- gbl.setConstraints(manage, con);
- add(manage);
-
- manage.addActionListener(e -> {
- ContentSelectorDialog2 csd = new ContentSelectorDialog2(owner, frame, panel, true,
- editor.getFieldName());
- csd.setLocationRelativeTo(frame);
-
- // Calling setVisible(true) will open the modal dialog and block
- // for the dialog to close.
- csd.setVisible(true);
-
- // So we need to rebuild the ComboBox afterwards
- rebuildComboBox();
- });
- }
-
- private void selectionMade() {
- // The first element is only for show.
- // CO: Why?
- if (comboBox.getSelectedIndex() == 0) {
- return;
- }
-
- String chosen = (String) comboBox.getSelectedItem();
- if ((chosen == null) || chosen.isEmpty()) {
- return;
- }
-
- // The following is not possible at the moment since the
- // combobox cannot be edited!
-
- // User edited in a new word. Add it.
- // if (comboBox.getSelectedIndex() == -1)
- // addWord(chosen);
-
- // TODO: could improve checking as not do add the same item twice
- if (!"".equals(editor.getText())) {
- editor.append(FieldContentSelector.this.delimiter);
- }
-
- editor.append(chosen);
-
- comboBox.setSelectedIndex(0);
-
- // Fire event that we changed the editor
- if (action != null) {
- action.actionPerformed(new ActionEvent(editor, 0, ""));
- }
-
- // Transfer focus to the editor.
- editor.requestFocus();
- }
-
- public void rebuildComboBox() {
- comboBox.removeAllItems();
-
- // TODO: CO - What for?
- comboBox.addItem("");
- for (String item : metaData.getContentSelectors(editor.getFieldName())) {
- comboBox.addItem(item);
- }
- }
- // Not used since the comboBox is not editable
-
- // /**
- // * Adds a word to the selector (to the JList and to the MetaData), unless it
- // * is already there
- // *
- // * @param newWord
- // * String Word to add
- // */
- // public void addWord(String newWord) {
- //
- // Vector items = metaData.getData(Globals.SELECTOR_META_PREFIX + editor.getFieldName());
- // boolean exists = false;
- // int pos = -1;
- // for (int i = 0; i < items.size(); i++) {
- // String s = (String) items.elementAt(i);
- // if (s.equals(newWord)) {
- // exists = true;
- // break;
- // }
- // if (s.toLowerCase().compareTo(newWord.toLowerCase()) < 0)
- // pos = i + 1;
- // }
- // if (!exists) {
- // items.add(Math.max(0, pos), newWord);
- // // TODO CO: Why is this non-undoable?
- // panel.markNonUndoableBaseChanged();
- // panel.updateAllContentSelectors();
- // }
- // }
-}
diff --git a/src/main/java/net/sf/jabref/gui/FieldSetComponent.java b/src/main/java/net/sf/jabref/gui/FieldSetComponent.java
index ca8a0f3..b50bc10 100644
--- a/src/main/java/net/sf/jabref/gui/FieldSetComponent.java
+++ b/src/main/java/net/sf/jabref/gui/FieldSetComponent.java
@@ -28,6 +28,7 @@ import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JViewport;
import javax.swing.ListSelectionModel;
+import javax.swing.ScrollPaneConstants;
import javax.swing.event.ListDataListener;
import javax.swing.event.ListSelectionListener;
@@ -107,7 +108,8 @@ class FieldSetComponent extends JPanel implements ActionListener {
}
con.weighty = 1;
- sp = new JScrollPane(list, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
+ sp = new JScrollPane(list, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
+ ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
gbl.setConstraints(sp, con);
add(sp);
con.weighty = 0;
diff --git a/src/main/java/net/sf/jabref/gui/FileDialog.java b/src/main/java/net/sf/jabref/gui/FileDialog.java
index 238d703..45360ca 100644
--- a/src/main/java/net/sf/jabref/gui/FileDialog.java
+++ b/src/main/java/net/sf/jabref/gui/FileDialog.java
@@ -1,5 +1,6 @@
package net.sf.jabref.gui;
+import java.awt.Component;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -13,7 +14,6 @@ import java.util.Optional;
import java.util.stream.Collectors;
import javax.swing.JFileChooser;
-import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.filechooser.FileFilter;
import javax.swing.filechooser.FileNameExtensionFilter;
@@ -55,7 +55,7 @@ public class FileDialog {
}
};
- private final JFrame parent;
+ private final Component parent;
private final String directory;
private Collection<FileExtensions> extensions = EnumSet.noneOf(FileExtensions.class);
@@ -63,7 +63,7 @@ public class FileDialog {
* Creates a new filedialog showing the current working dir {@link JabRefPreferences#WORKING_DIRECTORY}
* @param parent The parent frame associated with this dialog
*/
- public FileDialog(JFrame parent) {
+ public FileDialog(Component parent) {
this(parent, getWorkingDir());
}
@@ -72,7 +72,7 @@ public class FileDialog {
* @param parent The parent frame associated with this dialog
* @param dir The starting directory to show in the dialog
*/
- public FileDialog(JFrame parent, String dir) {
+ public FileDialog(Component parent, String dir) {
Objects.requireNonNull(dir, "Directory must not be null");
this.parent = parent;
@@ -101,6 +101,8 @@ public class FileDialog {
for (FileExtensions ext : fileExtensions) {
FileNameExtensionFilter extFilter = new FileNameExtensionFilter(ext.getDescription(), ext.getExtensions());
fileChooser.addChoosableFileFilter(extFilter);
+ // explictly needed for OSX to enable *.* file filter
+ fileChooser.setAcceptAllFileFilterUsed(true);
}
return this;
diff --git a/src/main/java/net/sf/jabref/gui/FileListEntry.java b/src/main/java/net/sf/jabref/gui/FileListEntry.java
deleted file mode 100644
index 64033b5..0000000
--- a/src/main/java/net/sf/jabref/gui/FileListEntry.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package net.sf.jabref.gui;
-
-import java.util.Objects;
-import java.util.Optional;
-
-import net.sf.jabref.external.ExternalFileType;
-
-/**
- * This class represents a file link for a Bibtex entry.
- */
-public class FileListEntry {
-
- public String description;
- public String link;
- public Optional<ExternalFileType> type;
-
- public FileListEntry(String description, String link) {
- this(description, link, Optional.empty());
- }
-
- public FileListEntry(String description, String link, ExternalFileType type) {
- this.description = Objects.requireNonNull(description);
- this.link = Objects.requireNonNull(link);
- this.type = Optional.of(Objects.requireNonNull(type));
- }
-
- public FileListEntry(String description, String link, Optional<ExternalFileType> type) {
- this.description = Objects.requireNonNull(description);
- this.link = Objects.requireNonNull(link);
- this.type = Objects.requireNonNull(type);
- }
-
- public String[] getStringArrayRepresentation() {
- return new String[] {description, link, getTypeName()};
- }
-
- private String getTypeName() {
- return this.type.isPresent() ? this.type.get().getName() : "";
- }
-
- @Override
- public String toString() {
- return description + " : " + link + " : " + type.orElse(null);
- }
-}
diff --git a/src/main/java/net/sf/jabref/gui/FileListEntryEditor.java b/src/main/java/net/sf/jabref/gui/FileListEntryEditor.java
deleted file mode 100644
index 6e16806..0000000
--- a/src/main/java/net/sf/jabref/gui/FileListEntryEditor.java
+++ /dev/null
@@ -1,362 +0,0 @@
-package net.sf.jabref.gui;
-
-import java.awt.BorderLayout;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Path;
-import java.util.Collection;
-import java.util.List;
-import java.util.Optional;
-import java.util.regex.Pattern;
-
-import javax.swing.AbstractAction;
-import javax.swing.ActionMap;
-import javax.swing.BorderFactory;
-import javax.swing.DefaultComboBoxModel;
-import javax.swing.InputMap;
-import javax.swing.JButton;
-import javax.swing.JComboBox;
-import javax.swing.JComponent;
-import javax.swing.JDialog;
-import javax.swing.JLabel;
-import javax.swing.JProgressBar;
-import javax.swing.JTextField;
-import javax.swing.SwingConstants;
-import javax.swing.SwingUtilities;
-import javax.swing.event.DocumentEvent;
-import javax.swing.event.DocumentListener;
-
-import net.sf.jabref.BibDatabaseContext;
-import net.sf.jabref.Globals;
-import net.sf.jabref.external.ConfirmCloseFileListEntryEditor;
-import net.sf.jabref.external.ExternalFileType;
-import net.sf.jabref.external.ExternalFileTypes;
-import net.sf.jabref.external.UnknownExternalFileType;
-import net.sf.jabref.gui.desktop.JabRefDesktop;
-import net.sf.jabref.gui.keyboard.KeyBinding;
-import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.logic.util.io.FileUtil;
-import net.sf.jabref.preferences.JabRefPreferences;
-
-import com.jgoodies.forms.builder.ButtonBarBuilder;
-import com.jgoodies.forms.builder.FormBuilder;
-import com.jgoodies.forms.layout.FormLayout;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * This class produces a dialog box for editing a single file link from a Bibtex entry.
- *
- * The information to be edited includes the file description, the link itself and the
- * file type. The dialog also includes convenience buttons for quick linking.
- *
- * For use when downloading files, this class also offers a progress bar and a "Downloading..."
- * label that can be hidden when the download is complete.
- */
-public class FileListEntryEditor {
- private static final Log LOGGER = LogFactory.getLog(FileListEntryEditor.class);
-
- private JDialog diag;
- private final JTextField link = new JTextField();
- private final JTextField description = new JTextField();
- private final JButton ok = new JButton(Localization.lang("OK"));
-
- private final JComboBox<ExternalFileType> types;
- private final JProgressBar prog = new JProgressBar(SwingConstants.HORIZONTAL);
- private final JLabel downloadLabel = new JLabel(Localization.lang("Downloading..."));
- private ConfirmCloseFileListEntryEditor externalConfirm;
-
- private FileListEntry entry;
- //Do not make this variable final, as then the lambda action listener will fail on compiöe
- private BibDatabaseContext databaseContext;
- private boolean okPressed;
- private boolean okDisabledExternally;
- private boolean openBrowseWhenShown;
- private boolean dontOpenBrowseUntilDisposed;
-
- //Do not make this variable final, as then the lambda action listener will fail on compile
- private JabRefFrame frame;
-
- private static final Pattern REMOTE_LINK_PATTERN = Pattern.compile("[a-z]+://.*");
-
-
- public FileListEntryEditor(JabRefFrame frame, FileListEntry entry, boolean showProgressBar, boolean showOpenButton,
- BibDatabaseContext databaseContext) {
- this.entry = entry;
- this.databaseContext = databaseContext;
- this.frame = frame;
-
- ActionListener okAction = e -> {
- // If OK button is disabled, ignore this event:
- if (!ok.isEnabled()) {
- return;
- }
- // If necessary, ask the external confirm object whether we are ready to close.
- if (externalConfirm != null) {
- // Construct an updated FileListEntry:
- storeSettings(entry);
- if (!externalConfirm.confirmClose(entry)) {
- return;
- }
- }
- diag.dispose();
- storeSettings(FileListEntryEditor.this.entry);
- okPressed = true;
- };
- types = new JComboBox<>();
- types.addItemListener(itemEvent -> {
- if (!okDisabledExternally) {
- ok.setEnabled(types.getSelectedItem() != null);
- }
- });
-
- FormBuilder builder = FormBuilder.create().layout(new FormLayout(
- "left:pref, 4dlu, fill:150dlu, 4dlu, fill:pref, 4dlu, fill:pref", "p, 2dlu, p, 2dlu, p"));
- builder.add(Localization.lang("Link")).xy(1, 1);
- builder.add(link).xy(3, 1);
- //final BrowseListener browse = new BrowseListener(frame, link); //TODO: Maybe use browse action
-
- final JButton browseBut = new JButton(Localization.lang("Browse"));
- browseBut.addActionListener(browsePressed);
- builder.add(browseBut).xy(5, 1);
- JButton open = new JButton(Localization.lang("Open"));
- if (showOpenButton) {
- builder.add(open).xy(7, 1);
- }
- builder.add(Localization.lang("Description")).xy(1, 3);
- builder.add(description).xyw(3, 3, 3);
- builder.getPanel().setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
- builder.add(Localization.lang("File type")).xy(1, 5);
- builder.add(types).xyw(3, 5, 3);
- if (showProgressBar) {
- builder.appendRows("2dlu, p");
- builder.add(downloadLabel).xy(1, 7);
- builder.add(prog).xyw(3, 7, 3);
- }
-
- ButtonBarBuilder bb = new ButtonBarBuilder();
- bb.addGlue();
- bb.addRelatedGap();
- bb.addButton(ok);
- JButton cancel = new JButton(Localization.lang("Cancel"));
- bb.addButton(cancel);
- bb.addGlue();
- bb.getPanel().setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
-
- ok.addActionListener(okAction);
- // Add OK action to the two text fields to simplify entering:
- link.addActionListener(okAction);
- description.addActionListener(okAction);
-
- open.addActionListener(e -> openFile());
-
- AbstractAction cancelAction = new AbstractAction() {
-
- @Override
- public void actionPerformed(ActionEvent e) {
- diag.dispose();
- }
- };
- cancel.addActionListener(cancelAction);
-
- // Key bindings:
- ActionMap am = builder.getPanel().getActionMap();
- InputMap im = builder.getPanel().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
- im.put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE_DIALOG), "close");
- am.put("close", cancelAction);
-
- link.getDocument().addDocumentListener(new DocumentListener() {
-
- @Override
- public void insertUpdate(DocumentEvent documentEvent) {
- checkExtension();
- }
-
- @Override
- public void removeUpdate(DocumentEvent documentEvent) {
- // Do nothing
- }
-
- @Override
- public void changedUpdate(DocumentEvent documentEvent) {
- checkExtension();
- }
-
- });
-
- diag = new JDialog(frame, Localization.lang("Save file"), true);
- diag.getContentPane().add(builder.getPanel(), BorderLayout.CENTER);
- diag.getContentPane().add(bb.getPanel(), BorderLayout.SOUTH);
- diag.pack();
- diag.setLocationRelativeTo(frame);
- diag.addWindowListener(new WindowAdapter() {
-
- @Override
- public void windowActivated(WindowEvent event) {
- if (openBrowseWhenShown && !dontOpenBrowseUntilDisposed) {
- dontOpenBrowseUntilDisposed = true;
- SwingUtilities.invokeLater(() -> browsePressed.actionPerformed(new ActionEvent(browseBut, 0, "")));
- }
- }
-
- @Override
- public void windowClosed(WindowEvent event) {
- dontOpenBrowseUntilDisposed = false;
- }
- });
- setValues(entry);
- }
-
- private void checkExtension() {
- if ((types.getSelectedIndex() == -1) && (!link.getText().trim().isEmpty())) {
-
- // Check if this looks like a remote link:
- if (FileListEntryEditor.REMOTE_LINK_PATTERN.matcher(link.getText()).matches()) {
- Optional<ExternalFileType> type = ExternalFileTypes.getInstance().getExternalFileTypeByExt("html");
- if (type.isPresent()) {
- types.setSelectedItem(type.get());
- return;
- }
- }
-
- // Try to guess the file type:
- String theLink = link.getText().trim();
- ExternalFileTypes.getInstance().getExternalFileTypeForName(theLink).ifPresent(types::setSelectedItem);
- }
- }
-
- private void openFile() {
- ExternalFileType type = (ExternalFileType) types.getSelectedItem();
- if (type != null) {
- try {
- JabRefDesktop.openExternalFileAnyFormat(databaseContext, link.getText(), Optional.of(type));
- } catch (IOException e) {
- LOGGER.error("File could not be opened", e);
- }
- }
- }
-
- public void setExternalConfirm(ConfirmCloseFileListEntryEditor eC) {
- this.externalConfirm = eC;
- }
-
- public void setOkEnabled(boolean enabled) {
- okDisabledExternally = !enabled;
- ok.setEnabled(enabled);
- }
-
- public JProgressBar getProgressBar() {
- return prog;
- }
-
- public JLabel getProgressBarLabel() {
- return downloadLabel;
- }
-
- public void setEntry(FileListEntry entry) {
- this.entry = entry;
- setValues(entry);
- }
-
- public void setVisible(boolean visible, boolean openBrowse) {
- openBrowseWhenShown = openBrowse && Globals.prefs.getBoolean(JabRefPreferences.ALLOW_FILE_AUTO_OPEN_BROWSE);
- if (visible) {
- okPressed = false;
- }
- diag.setVisible(visible);
- }
-
- public boolean isVisible() {
- return (diag != null) && diag.isVisible();
- }
-
- private void setValues(FileListEntry entry) {
- description.setText(entry.description);
- link.setText(entry.link);
-
- Collection<ExternalFileType> list = ExternalFileTypes.getInstance().getExternalFileTypeSelection();
-
- types.setModel(new DefaultComboBoxModel<>(list.toArray(new ExternalFileType[list.size()])));
- types.setSelectedIndex(-1);
- // See what is a reasonable selection for the type combobox:
- if ((entry.type.isPresent()) && !(entry.type.get() instanceof UnknownExternalFileType)) {
- types.setSelectedItem(entry.type.get());
- } else if ((entry.link != null) && (!entry.link.isEmpty())) {
- checkExtension();
- }
- }
-
- private void storeSettings(FileListEntry entry) {
- String descriptionText = this.description.getText().trim();
- String link = "";
- // See if we should trim the file link to be relative to the file directory:
- try {
- List<String> dirs = databaseContext.getFileDirectory();
- if (dirs.isEmpty()) {
- link = this.link.getText().trim();
- } else {
- boolean found = false;
- for (String dir : dirs) {
- String canPath = (new File(dir)).getCanonicalPath();
- File fl = new File(this.link.getText().trim());
- if (fl.isAbsolute()) {
- String flPath = fl.getCanonicalPath();
- if ((flPath.length() > canPath.length()) && (flPath.startsWith(canPath))) {
- link = fl.getCanonicalPath().substring(canPath.length() + 1);
- found = true;
- break;
- }
- }
- }
- if (!found) {
- link = this.link.getText().trim();
- }
- }
- } catch (IOException ex) {
- // Don't think this should happen, but set the file link directly as a fallback:
- link = this.link.getText().trim();
- }
-
- ExternalFileType type = (ExternalFileType) types.getSelectedItem();
-
- entry.description = descriptionText;
- entry.type = Optional.ofNullable(type);
- entry.link = link;
- }
-
- public boolean okPressed() {
- return okPressed;
-
- }
-
- private final ActionListener browsePressed = e -> {
- String filePath = link.getText().trim();
- Optional<File> file = FileUtil.expandFilename(this.databaseContext, filePath);
- String workingDir;
- // no file set yet or found
- if (file.isPresent()) {
- workingDir = file.get().getPath();
- } else {
- workingDir = Globals.prefs.get(JabRefPreferences.FILE_WORKING_DIRECTORY);
- }
-
- Optional<Path> path = new FileDialog(this.frame, workingDir).showDialogAndGetSelectedFile();
-
- path.ifPresent(selection -> {
- File newFile = selection.toFile();
- // Store the directory for next time:
- Globals.prefs.put(JabRefPreferences.FILE_WORKING_DIRECTORY, newFile.getPath());
-
- // If the file is below the file directory, make the path relative:
- List<String> fileDirs = this.databaseContext.getFileDirectory();
- newFile = FileUtil.shortenFileName(newFile, fileDirs);
-
- link.setText(newFile.getPath());
- link.requestFocus();
- });
- };
-}
diff --git a/src/main/java/net/sf/jabref/gui/FileListTableModel.java b/src/main/java/net/sf/jabref/gui/FileListTableModel.java
deleted file mode 100644
index 418b900..0000000
--- a/src/main/java/net/sf/jabref/gui/FileListTableModel.java
+++ /dev/null
@@ -1,222 +0,0 @@
-package net.sf.jabref.gui;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Optional;
-import java.util.StringJoiner;
-
-import javax.swing.JLabel;
-import javax.swing.SwingUtilities;
-import javax.swing.event.TableModelEvent;
-import javax.swing.table.AbstractTableModel;
-
-import net.sf.jabref.external.ExternalFileType;
-import net.sf.jabref.external.ExternalFileTypes;
-import net.sf.jabref.external.UnknownExternalFileType;
-import net.sf.jabref.logic.util.io.FileUtil;
-import net.sf.jabref.model.entry.FileField;
-import net.sf.jabref.model.entry.ParsedFileField;
-
-/**
- * Data structure to contain a list of file links, parseable from a coded string.
- * Doubles as a table model for the file list editor.
- */
-public class FileListTableModel extends AbstractTableModel {
-
- private final List<FileListEntry> list = new ArrayList<>();
-
- @Override
- public int getRowCount() {
- synchronized (list) {
- return list.size();
- }
- }
-
- @Override
- public int getColumnCount() {
- return 3;
- }
-
- @Override
- public Class<String> getColumnClass(int columnIndex) {
- return String.class;
- }
-
- @Override
- public Object getValueAt(int rowIndex, int columnIndex) {
- synchronized (list) {
- FileListEntry entry = list.get(rowIndex);
- switch (columnIndex) {
- case 0:
- return entry.description;
- case 1:
- return entry.link;
- default:
- return entry.type.isPresent() ? entry.type.get().getName() : "";
- }
- }
- }
-
- public FileListEntry getEntry(int index) {
- synchronized (list) {
- return list.get(index);
- }
- }
-
- public void setEntry(int index, FileListEntry entry) {
- synchronized (list) {
- list.set(index, entry);
- fireTableRowsUpdated(index, index);
- }
- }
-
- public void removeEntry(int index) {
- synchronized (list) {
- list.remove(index);
- fireTableRowsDeleted(index, index);
- }
-
- }
-
- /**
- * Add an entry to the table model, and fire a change event. The change event
- * is fired on the event dispatch thread.
- * @param index The row index to insert the entry at.
- * @param entry The entry to insert.
- */
- public void addEntry(final int index, final FileListEntry entry) {
- synchronized (list) {
- list.add(index, entry);
- if (SwingUtilities.isEventDispatchThread()) {
- fireTableRowsInserted(index, index);
- } else {
- SwingUtilities.invokeLater(() -> fireTableRowsInserted(index, index));
- }
- }
-
- }
-
- @Override
- public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
- // Do nothing
- }
-
- /**
- * Set up the table contents based on the flat string representation of the file list
- * @param value The string representation
- */
- public void setContent(String value) {
- setContent(value, false, true);
- }
-
- public void setContentDontGuessTypes(String value) {
- setContent(value, false, false);
- }
-
- private FileListEntry setContent(String val, boolean firstOnly, boolean deduceUnknownTypes) {
- String value = val;
- if (value == null) {
- value = "";
- }
-
- List<ParsedFileField> fields = FileField.parse(value);
- List<FileListEntry> files = new ArrayList<>();
-
- for(ParsedFileField entry : fields) {
- if (entry.isEmpty()) {
- continue;
- }
-
- if (firstOnly) {
- return decodeEntry(entry, deduceUnknownTypes);
- } else {
- files.add(decodeEntry(entry, deduceUnknownTypes));
- }
- }
-
- synchronized (list) {
- list.clear();
- list.addAll(files);
- }
- fireTableChanged(new TableModelEvent(this));
- return null;
- }
-
- /**
- * Convenience method for finding a label corresponding to the type of the
- * first file link in the given field content. The difference between using
- * this method and using setContent() on an instance of FileListTableModel
- * is a slight optimization: with this method, parsing is discontinued after
- * the first entry has been found.
- * @param content The file field content, as fed to this class' setContent() method.
- * @return A JLabel set up with no text and the icon of the first entry's file type,
- * or null if no entry was found or the entry had no icon.
- */
- public static JLabel getFirstLabel(String content) {
- FileListTableModel tm = new FileListTableModel();
- FileListEntry entry = tm.setContent(content, true, true);
- if ((entry == null) || (!entry.type.isPresent())) {
- return null;
- }
- return entry.type.get().getIconLabel();
- }
-
- private FileListEntry decodeEntry(ParsedFileField entry, boolean deduceUnknownType) {
- Optional<ExternalFileType> type = ExternalFileTypes.getInstance().getExternalFileTypeByName(entry.getFileType());
-
- if (deduceUnknownType && (type.get() instanceof UnknownExternalFileType)) {
- // No file type was recognized. Try to find a usable file type based
- // on mime type:
- type = ExternalFileTypes.getInstance().getExternalFileTypeByMimeType(entry.getFileType());
- if (!type.isPresent()) {
- // No type could be found from mime type on the extension:
- Optional<String> extension = FileUtil.getFileExtension(entry.getLink());
- if (extension.isPresent()) {
- Optional<ExternalFileType> typeGuess = ExternalFileTypes.getInstance()
- .getExternalFileTypeByExt(extension.get());
-
- if (typeGuess.isPresent()) {
- type = typeGuess;
- }
- }
- }
- }
-
- return new FileListEntry(entry.getDescription(), entry.getLink(), type);
- }
-
- /**
- * Transform the file list shown in the table into a flat string representable
- * as a BibTeX field:
- * @return String representation.
- */
- public String getStringRepresentation() {
- synchronized (list) {
- String[][] array = new String[list.size()][];
- int i = 0;
- for (FileListEntry entry : list) {
- array[i] = entry.getStringArrayRepresentation();
- i++;
- }
- return FileField.encodeStringArray(array);
- }
- }
-
- /**
- * Transform the file list shown in the table into a HTML string representation
- * suitable for displaying the contents in a tooltip.
- * @return Tooltip representation.
- */
- public String getToolTipHTMLRepresentation() {
- StringJoiner sb = new StringJoiner("<br>", "<html>", "</html>");
-
- synchronized (list) {
- for (FileListEntry entry : list) {
- sb.add(String.format("%s (%s)", entry.description, entry.link));
- }
- }
-
- return sb.toString();
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/gui/FindUnlinkedFilesDialog.java b/src/main/java/net/sf/jabref/gui/FindUnlinkedFilesDialog.java
index 092473a..70f1711 100644
--- a/src/main/java/net/sf/jabref/gui/FindUnlinkedFilesDialog.java
+++ b/src/main/java/net/sf/jabref/gui/FindUnlinkedFilesDialog.java
@@ -43,7 +43,6 @@ import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JDialog;
-import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
@@ -54,6 +53,7 @@ import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.KeyStroke;
+import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import javax.swing.event.ChangeEvent;
@@ -66,7 +66,6 @@ import javax.swing.tree.TreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
-import net.sf.jabref.BibDatabaseContext;
import net.sf.jabref.Globals;
import net.sf.jabref.JabRefExecutorService;
import net.sf.jabref.JabRefGUI;
@@ -75,9 +74,10 @@ import net.sf.jabref.gui.importer.EntryFromFileCreator;
import net.sf.jabref.gui.importer.EntryFromFileCreatorManager;
import net.sf.jabref.gui.importer.UnlinkedFilesCrawler;
import net.sf.jabref.gui.importer.UnlinkedPDFFileFilter;
-import net.sf.jabref.gui.util.GUIUtil;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.model.EntryTypes;
+import net.sf.jabref.model.database.BibDatabaseContext;
+import net.sf.jabref.model.entry.BibtexEntryType;
import net.sf.jabref.model.entry.EntryType;
import net.sf.jabref.model.entry.FieldName;
import net.sf.jabref.preferences.JabRefPreferences;
@@ -151,7 +151,6 @@ public class FindUnlinkedFilesDialog extends JDialog {
private JComboBox<BibtexEntryTypeWrapper> comboBoxEntryTypeSelection;
private JProgressBar progressBarSearching;
private JProgressBar progressBarImporting;
- private JFileChooser fileChooser;
private MouseListener treeMouseListener;
private Action actionSelectAll;
@@ -742,14 +741,13 @@ public class FindUnlinkedFilesDialog extends JDialog {
labelFilesDescription = new JLabel(Localization.lang("These files are not linked in the active database."));
labelEntryTypeDescription = new JLabel(Localization.lang("Entry type to be created:"));
labelSearchingDirectoryInfo = new JLabel(Localization.lang("Searching file system..."));
- labelSearchingDirectoryInfo.setHorizontalAlignment(JTextField.CENTER);
+ labelSearchingDirectoryInfo.setHorizontalAlignment(SwingConstants.CENTER);
labelSearchingDirectoryInfo.setVisible(false);
labelImportingInfo = new JLabel(Localization.lang("Importing into Database..."));
- labelImportingInfo.setHorizontalAlignment(JTextField.CENTER);
+ labelImportingInfo.setHorizontalAlignment(SwingConstants.CENTER);
labelImportingInfo.setVisible(false);
tree = new JTree();
- GUIUtil.correctRowHeight(tree);
scrollpaneTree = new JScrollPane(tree);
scrollpaneTree.setWheelScrollingEnabled(true);
@@ -1025,7 +1023,8 @@ public class FindUnlinkedFilesDialog extends JDialog {
Iterator<EntryType> iterator = EntryTypes
.getAllValues(frame.getCurrentBasePanel().getBibDatabaseContext().getMode()).iterator();
Vector<BibtexEntryTypeWrapper> list = new Vector<>();
- list.add(new BibtexEntryTypeWrapper(null));
+ list.add(
+ new BibtexEntryTypeWrapper(null));
while (iterator.hasNext()) {
list.add(new BibtexEntryTypeWrapper(iterator.next()));
}
diff --git a/src/main/java/net/sf/jabref/gui/GUIGlobals.java b/src/main/java/net/sf/jabref/gui/GUIGlobals.java
index 0a72d78..193326d 100644
--- a/src/main/java/net/sf/jabref/gui/GUIGlobals.java
+++ b/src/main/java/net/sf/jabref/gui/GUIGlobals.java
@@ -8,19 +8,14 @@ import java.util.Map;
import javax.swing.JLabel;
import net.sf.jabref.Globals;
-import net.sf.jabref.external.ExternalFileType;
-import net.sf.jabref.external.ExternalFileTypes;
+import net.sf.jabref.gui.externalfiletype.ExternalFileType;
+import net.sf.jabref.gui.externalfiletype.ExternalFileTypes;
import net.sf.jabref.gui.keyboard.EmacsKeyBindings;
+import net.sf.jabref.gui.specialfields.SpecialFieldViewModel;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.model.entry.FieldName;
-import net.sf.jabref.model.entry.SpecialFields;
+import net.sf.jabref.model.entry.specialfields.SpecialField;
import net.sf.jabref.preferences.JabRefPreferences;
-import net.sf.jabref.specialfields.Printed;
-import net.sf.jabref.specialfields.Priority;
-import net.sf.jabref.specialfields.Quality;
-import net.sf.jabref.specialfields.Rank;
-import net.sf.jabref.specialfields.ReadStatus;
-import net.sf.jabref.specialfields.Relevance;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -115,33 +110,39 @@ public class GUIGlobals {
GUIGlobals.TABLE_ICONS.put(fileType.getName(), label);
}
- label = new JLabel(Relevance.getInstance().getRepresentingIcon());
- label.setToolTipText(Relevance.getInstance().getToolTip());
- GUIGlobals.TABLE_ICONS.put(SpecialFields.FIELDNAME_RELEVANCE, label);
+ SpecialFieldViewModel relevanceViewModel = new SpecialFieldViewModel(SpecialField.RELEVANCE);
+ label = new JLabel(relevanceViewModel.getRepresentingIcon());
+ label.setToolTipText(relevanceViewModel.getLocalization());
+ GUIGlobals.TABLE_ICONS.put(SpecialField.RELEVANCE.getFieldName(), label);
- label = new JLabel(Quality.getInstance().getRepresentingIcon());
- label.setToolTipText(Quality.getInstance().getToolTip());
- GUIGlobals.TABLE_ICONS.put(SpecialFields.FIELDNAME_QUALITY, label);
+ SpecialFieldViewModel qualityViewModel = new SpecialFieldViewModel(SpecialField.QUALITY);
+ label = new JLabel(qualityViewModel.getRepresentingIcon());
+ label.setToolTipText(qualityViewModel.getLocalization());
+ GUIGlobals.TABLE_ICONS.put(SpecialField.QUALITY.getFieldName(), label);
// Ranking item in the menu uses one star
- label = new JLabel(Rank.getInstance().getRepresentingIcon());
- label.setToolTipText(Rank.getInstance().getToolTip());
- GUIGlobals.TABLE_ICONS.put(SpecialFields.FIELDNAME_RANKING, label);
+ SpecialFieldViewModel rankViewModel = new SpecialFieldViewModel(SpecialField.RANKING);
+ label = new JLabel(rankViewModel.getRepresentingIcon());
+ label.setToolTipText(rankViewModel.getLocalization());
+ GUIGlobals.TABLE_ICONS.put(SpecialField.RANKING.getFieldName(), label);
// Priority icon used for the menu
- label = new JLabel(Priority.getInstance().getRepresentingIcon());
- label.setToolTipText(Priority.getInstance().getToolTip());
- GUIGlobals.TABLE_ICONS.put(SpecialFields.FIELDNAME_PRIORITY, label);
+ SpecialFieldViewModel priorityViewModel = new SpecialFieldViewModel(SpecialField.PRIORITY);
+ label = new JLabel(priorityViewModel.getRepresentingIcon());
+ label.setToolTipText(priorityViewModel.getLocalization());
+ GUIGlobals.TABLE_ICONS.put(SpecialField.PRIORITY.getFieldName(), label);
// Read icon used for menu
- label = new JLabel(ReadStatus.getInstance().getRepresentingIcon());
- label.setToolTipText(ReadStatus.getInstance().getToolTip());
- GUIGlobals.TABLE_ICONS.put(SpecialFields.FIELDNAME_READ, label);
+ SpecialFieldViewModel readViewModel = new SpecialFieldViewModel(SpecialField.READ_STATUS);
+ label = new JLabel(readViewModel.getRepresentingIcon());
+ label.setToolTipText(readViewModel.getLocalization());
+ GUIGlobals.TABLE_ICONS.put(SpecialField.READ_STATUS.getFieldName(), label);
// Print icon used for menu
- label = new JLabel(Printed.getInstance().getRepresentingIcon());
- label.setToolTipText(Printed.getInstance().getToolTip());
- GUIGlobals.TABLE_ICONS.put(SpecialFields.FIELDNAME_PRINTED, label);
+ SpecialFieldViewModel printedViewModel = new SpecialFieldViewModel(SpecialField.PRINTED);
+ label = new JLabel(printedViewModel.getRepresentingIcon());
+ label.setToolTipText(printedViewModel.getLocalization());
+ GUIGlobals.TABLE_ICONS.put(SpecialField.PRINTED.getFieldName(), label);
if (Globals.prefs.getBoolean(JabRefPreferences.EDITOR_EMACS_KEYBINDINGS)) {
EmacsKeyBindings.load();
diff --git a/src/main/java/net/sf/jabref/gui/GenFieldsCustomizer.java b/src/main/java/net/sf/jabref/gui/GenFieldsCustomizer.java
index 38ac080..e1b7122 100644
--- a/src/main/java/net/sf/jabref/gui/GenFieldsCustomizer.java
+++ b/src/main/java/net/sf/jabref/gui/GenFieldsCustomizer.java
@@ -46,12 +46,10 @@ public class GenFieldsCustomizer extends JDialog {
private final JLabel jLabel2 = new JLabel();
private final JTextArea fieldsArea = new JTextArea();
private final GridBagLayout gridBagLayout2 = new GridBagLayout();
- private final JabRefFrame parentFrame;
private final JButton revert = new JButton();
public GenFieldsCustomizer(JabRefFrame frame) {
super(frame, Localization.lang("Set general fields"), false);
- parentFrame = frame;
helpBut = new HelpAction(HelpFile.GENERAL_FIELDS).getHelpButton();
jbInit();
setSize(new Dimension(650, 300));
@@ -139,7 +137,6 @@ public class GenFieldsCustomizer extends JDialog {
Globals.prefs.purgeSeries(JabRefPreferences.CUSTOM_TAB_FIELDS, i);
Globals.prefs.updateEntryEditorTabList();
- parentFrame.removeCachedEntryEditors();
dispose();
}
diff --git a/src/main/java/net/sf/jabref/gui/IconTheme.java b/src/main/java/net/sf/jabref/gui/IconTheme.java
index dbcd2c2..2177138 100644
--- a/src/main/java/net/sf/jabref/gui/IconTheme.java
+++ b/src/main/java/net/sf/jabref/gui/IconTheme.java
@@ -157,6 +157,7 @@ public class IconTheme {
FORUM("\uf28c"), /* css: forum */
FACEBOOK("\uf20c"), /* css: facebook */
BLOG("\uf46b"), /* css: rss */
+ GLOBAL_SEARCH("\uF1E7"), /* css: earth */
// STILL MISSING:
GROUP_REGULAR("\uF4E6", Color.RED);
diff --git a/src/main/java/net/sf/jabref/gui/JEditorPaneWithHighlighting.java b/src/main/java/net/sf/jabref/gui/JEditorPaneWithHighlighting.java
new file mode 100644
index 0000000..bcbce0f
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/JEditorPaneWithHighlighting.java
@@ -0,0 +1,58 @@
+package net.sf.jabref.gui;
+
+import java.util.Optional;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.swing.JEditorPane;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.DefaultHighlighter;
+import javax.swing.text.Document;
+import javax.swing.text.Highlighter;
+import javax.swing.text.LayeredHighlighter.LayerPainter;
+
+import net.sf.jabref.gui.fieldeditors.JTextAreaWithHighlighting;
+import net.sf.jabref.logic.search.SearchQueryHighlightListener;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class JEditorPaneWithHighlighting extends JEditorPane implements SearchQueryHighlightListener {
+
+ private static final Log LOGGER = LogFactory.getLog(JTextAreaWithHighlighting.class);
+
+ public void highlightPattern(Optional<Pattern> highlightPattern) {
+ Highlighter highlighter = getHighlighter();
+ highlighter.removeAllHighlights();
+
+ if ((highlightPattern == null) || !highlightPattern.isPresent()) {
+ return;
+ }
+
+ String text = getDocumentText();
+
+ Matcher matcher = highlightPattern.get().matcher(text);
+ LayerPainter painter = DefaultHighlighter.DefaultPainter;
+ while (matcher.find()) {
+ try {
+ highlighter.addHighlight(matcher.start(), matcher.end(), painter);
+ } catch (BadLocationException ble) {
+ // should not occur if matcher works right
+ LOGGER.warn("Highlighting not possible, bad location", ble);
+ }
+ }
+ }
+
+
+ private String getDocumentText() {
+ Document doc = getDocument();
+ String text;
+ try {
+ text = doc.getText(0, doc.getLength());
+ } catch (Exception e) {
+ LOGGER.error("Error while getting document text");
+ text = "";
+ }
+ return text;
+ }
+}
diff --git a/src/main/java/net/sf/jabref/gui/JabRefFrame.java b/src/main/java/net/sf/jabref/gui/JabRefFrame.java
index 13acede..f0d6965 100644
--- a/src/main/java/net/sf/jabref/gui/JabRefFrame.java
+++ b/src/main/java/net/sf/jabref/gui/JabRefFrame.java
@@ -1,7 +1,10 @@
package net.sf.jabref.gui;
+import java.awt.BorderLayout;
import java.awt.Component;
+import java.awt.Container;
import java.awt.Cursor;
+import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Frame;
import java.awt.GraphicsEnvironment;
@@ -27,7 +30,6 @@ import java.util.Optional;
import javax.swing.AbstractAction;
import javax.swing.Action;
-import javax.swing.Box;
import javax.swing.ButtonGroup;
import javax.swing.Icon;
import javax.swing.ImageIcon;
@@ -56,12 +58,11 @@ import javax.swing.TransferHandler;
import javax.swing.UIManager;
import javax.swing.WindowConstants;
-import net.sf.jabref.BibDatabaseContext;
import net.sf.jabref.Globals;
import net.sf.jabref.JabRefExecutorService;
-import net.sf.jabref.external.ExternalFileTypeEditor;
import net.sf.jabref.gui.actions.Actions;
import net.sf.jabref.gui.actions.AutoLinkFilesAction;
+import net.sf.jabref.gui.actions.ConnectToSharedDatabaseAction;
import net.sf.jabref.gui.actions.ErrorConsoleAction;
import net.sf.jabref.gui.actions.IntegrityCheckAction;
import net.sf.jabref.gui.actions.ManageKeywordsAction;
@@ -71,19 +72,19 @@ import net.sf.jabref.gui.actions.NewDatabaseAction;
import net.sf.jabref.gui.actions.NewEntryAction;
import net.sf.jabref.gui.actions.NewSubDatabaseAction;
import net.sf.jabref.gui.actions.OpenBrowserAction;
-import net.sf.jabref.gui.actions.OpenSharedDatabaseAction;
import net.sf.jabref.gui.actions.SearchForUpdateAction;
import net.sf.jabref.gui.actions.SortTabsAction;
+import net.sf.jabref.gui.autosaveandbackup.AutosaveUIManager;
+import net.sf.jabref.gui.bibtexkeypattern.BibtexKeyPatternDialog;
import net.sf.jabref.gui.dbproperties.DatabasePropertiesDialog;
-import net.sf.jabref.gui.exporter.AutoSaveManager;
import net.sf.jabref.gui.exporter.ExportAction;
import net.sf.jabref.gui.exporter.ExportCustomizationDialog;
import net.sf.jabref.gui.exporter.SaveAllAction;
import net.sf.jabref.gui.exporter.SaveDatabaseAction;
+import net.sf.jabref.gui.externalfiletype.ExternalFileTypeEditor;
import net.sf.jabref.gui.groups.EntryTableTransferHandler;
import net.sf.jabref.gui.groups.GroupSelector;
import net.sf.jabref.gui.help.AboutAction;
-import net.sf.jabref.gui.help.AboutDialog;
import net.sf.jabref.gui.help.HelpAction;
import net.sf.jabref.gui.importer.ImportCustomizationDialog;
import net.sf.jabref.gui.importer.ImportFormats;
@@ -98,38 +99,42 @@ import net.sf.jabref.gui.menus.ChangeEntryTypeMenu;
import net.sf.jabref.gui.menus.FileHistoryMenu;
import net.sf.jabref.gui.menus.RightClickMenu;
import net.sf.jabref.gui.openoffice.OpenOfficePanel;
+import net.sf.jabref.gui.openoffice.OpenOfficeSidePanel;
import net.sf.jabref.gui.preftabs.PreferencesDialog;
import net.sf.jabref.gui.protectedterms.ProtectedTermsDialog;
import net.sf.jabref.gui.push.PushToApplicationButton;
import net.sf.jabref.gui.push.PushToApplications;
-import net.sf.jabref.gui.util.FocusRequester;
-import net.sf.jabref.gui.util.PositionWindow;
+import net.sf.jabref.gui.search.GlobalSearchBar;
+import net.sf.jabref.gui.specialfields.SpecialFieldDropDown;
+import net.sf.jabref.gui.specialfields.SpecialFieldValueViewModel;
+import net.sf.jabref.gui.util.WindowLocation;
import net.sf.jabref.gui.worker.MarkEntriesAction;
import net.sf.jabref.logic.CustomEntryTypesManager;
+import net.sf.jabref.logic.autosaveandbackup.AutosaveManager;
+import net.sf.jabref.logic.autosaveandbackup.BackupManager;
import net.sf.jabref.logic.help.HelpFile;
import net.sf.jabref.logic.importer.OutputPrinter;
import net.sf.jabref.logic.importer.ParserResult;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.logging.GuiAppender;
+import net.sf.jabref.logic.search.SearchQuery;
import net.sf.jabref.logic.undo.AddUndoableActionEvent;
import net.sf.jabref.logic.undo.UndoChangeEvent;
import net.sf.jabref.logic.undo.UndoRedoEvent;
import net.sf.jabref.logic.util.OS;
import net.sf.jabref.logic.util.io.FileUtil;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.database.BibDatabaseMode;
import net.sf.jabref.model.database.DatabaseLocation;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.BibtexEntryTypes;
import net.sf.jabref.model.entry.EntryType;
+import net.sf.jabref.model.entry.FieldName;
+import net.sf.jabref.model.entry.specialfields.SpecialField;
import net.sf.jabref.preferences.HighlightMatchingGroupPreferences;
import net.sf.jabref.preferences.JabRefPreferences;
import net.sf.jabref.preferences.LastFocusedTabPreferences;
-import net.sf.jabref.specialfields.Printed;
-import net.sf.jabref.specialfields.Priority;
-import net.sf.jabref.specialfields.Quality;
-import net.sf.jabref.specialfields.Rank;
-import net.sf.jabref.specialfields.ReadStatus;
-import net.sf.jabref.specialfields.Relevance;
+import net.sf.jabref.preferences.SearchPreferences;
import com.google.common.eventbus.Subscribe;
import com.jgoodies.looks.HeaderStyle;
@@ -162,17 +167,13 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
private final Insets marg = new Insets(1, 0, 2, 0);
- private PositionWindow pw;
-
private final IntegrityCheckAction checkIntegrity = new IntegrityCheckAction(this);
private final ToolBar tlb = new ToolBar();
+ private final GlobalSearchBar globalSearchBar = new GlobalSearchBar(this);
private final JMenuBar mb = new JMenuBar();
- private final GridBagLayout gbl = new GridBagLayout();
- private final GridBagConstraints con = new GridBagConstraints();
-
private final JLabel statusLine = new JLabel("", SwingConstants.LEFT);
private final JLabel statusLabel = new JLabel(
Localization.lang("Status")
@@ -181,9 +182,6 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
private final FileHistoryMenu fileHistory = new FileHistoryMenu(prefs, this);
- // The help window.
- private final AboutDialog aboutDiag = new AboutDialog(this);
-
// Here we instantiate menu/toolbar actions. Actions regarding
// the currently open database are defined as a GeneralAction
// with a unique command string. This causes the appropriate
@@ -192,11 +190,7 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
// for the name and message strings.
/* References to the toggle buttons in the toolbar */
- // the groups interface
- public JToggleButton groupToggle;
private JToggleButton previewToggle;
- private JToggleButton fetcherToggle;
-
private final OpenDatabaseAction open = new OpenDatabaseAction(this, true);
private final EditModeAction editModeAction = new EditModeAction();
@@ -204,7 +198,7 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
private final AbstractAction selectKeys = new SelectKeysAction();
private final AbstractAction newBibtexDatabaseAction = new NewDatabaseAction(this, BibDatabaseMode.BIBTEX);
private final AbstractAction newBiblatexDatabaseAction = new NewDatabaseAction(this, BibDatabaseMode.BIBLATEX);
- private final AbstractAction openSharedDatabaseAction = new OpenSharedDatabaseAction(this);
+ private final AbstractAction connectToSharedDatabaseAction = new ConnectToSharedDatabaseAction(this);
private final AbstractAction newSubDatabaseAction = new NewSubDatabaseAction(this);
private final AbstractAction jabrefWebPageAction = new OpenBrowserAction("https://jabref.org",
Localization.menuTitle("Website"), Localization.lang("Opens JabRef's website"),
@@ -229,7 +223,7 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
Localization.menuTitle("Online help forum"), Localization.lang("Online help forum"), IconTheme.JabRefIcon.FORUM.getSmallIcon(), IconTheme.JabRefIcon.FORUM.getIcon());
private final AbstractAction help = new HelpAction(Localization.menuTitle("Online help"), Localization.lang("Online help"),
HelpFile.CONTENTS, Globals.getKeyPrefs().getKey(KeyBinding.HELP));
- private final AbstractAction about = new AboutAction(Localization.menuTitle("About JabRef"), aboutDiag,
+ private final AbstractAction about = new AboutAction(Localization.menuTitle("About JabRef"), this,
Localization.lang("About JabRef"), IconTheme.getImage("about"));
private final AbstractAction editEntry = new GeneralAction(Actions.EDIT, Localization.menuTitle("Edit entry"),
Localization.lang("Edit entry"), Globals.getKeyPrefs().getKey(KeyBinding.EDIT_ENTRY), IconTheme.JabRefIcon.EDIT_ENTRY.getIcon());
@@ -284,27 +278,27 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
private final AbstractAction mark = new GeneralAction(Actions.MARK_ENTRIES, Localization.menuTitle("Mark entries"),
Localization.lang("Mark entries"), Globals.getKeyPrefs().getKey(KeyBinding.MARK_ENTRIES), IconTheme.JabRefIcon.MARK_ENTRIES.getIcon());
+ private final JMenu markSpecific = JabRefFrame.subMenu(Localization.menuTitle("Mark specific color"));
private final AbstractAction unmark = new GeneralAction(Actions.UNMARK_ENTRIES,
Localization.menuTitle("Unmark entries"), Localization.lang("Unmark entries"),
Globals.getKeyPrefs().getKey(KeyBinding.UNMARK_ENTRIES), IconTheme.JabRefIcon.UNMARK_ENTRIES.getIcon());
private final AbstractAction unmarkAll = new GeneralAction(Actions.UNMARK_ALL, Localization.menuTitle("Unmark all"));
+ private JMenu rankSubMenu;
private final AbstractAction toggleRelevance = new GeneralAction(
- Relevance.getInstance().getValues().get(0).getActionName(),
- Relevance.getInstance().getValues().get(0).getMenuString(),
- Relevance.getInstance().getValues().get(0).getToolTipText(),
+ new SpecialFieldValueViewModel(SpecialField.RELEVANCE.getValues().get(0)).getActionName(),
+ new SpecialFieldValueViewModel(SpecialField.RELEVANCE.getValues().get(0)).getMenuString(),
+ new SpecialFieldValueViewModel(SpecialField.RELEVANCE.getValues().get(0)).getToolTipText(),
IconTheme.JabRefIcon.RELEVANCE.getIcon());
private final AbstractAction toggleQualityAssured = new GeneralAction(
- Quality.getInstance().getValues().get(0).getActionName(),
- Quality.getInstance().getValues().get(0).getMenuString(),
- Quality.getInstance().getValues().get(0).getToolTipText(),
+ new SpecialFieldValueViewModel(SpecialField.QUALITY.getValues().get(0)).getActionName(),
+ new SpecialFieldValueViewModel(SpecialField.QUALITY.getValues().get(0)).getMenuString(),
+ new SpecialFieldValueViewModel(SpecialField.QUALITY.getValues().get(0)).getToolTipText(),
IconTheme.JabRefIcon.QUALITY_ASSURED.getIcon());
private final AbstractAction togglePrinted = new GeneralAction(
- Printed.getInstance().getValues().get(0).getActionName(),
- Printed.getInstance().getValues().get(0).getMenuString(),
- Printed.getInstance().getValues().get(0).getToolTipText(),
+ new SpecialFieldValueViewModel(SpecialField.PRINTED.getValues().get(0)).getActionName(),
+ new SpecialFieldValueViewModel(SpecialField.PRINTED.getValues().get(0)).getMenuString(),
+ new SpecialFieldValueViewModel(SpecialField.PRINTED.getValues().get(0)).getToolTipText(),
IconTheme.JabRefIcon.PRINTED.getIcon());
- private final AbstractAction manageSelectors = new GeneralAction(Actions.MANAGE_SELECTORS,
- Localization.menuTitle("Manage content selectors"));
private final AbstractAction normalSearch = new GeneralAction(Actions.SEARCH, Localization.menuTitle("Search"),
Localization.lang("Search"), Globals.getKeyPrefs().getKey(KeyBinding.SEARCH), IconTheme.JabRefIcon.SEARCH.getIcon());
@@ -316,6 +310,9 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
private final AbstractAction copyKeyAndTitle = new GeneralAction(Actions.COPY_KEY_AND_TITLE,
Localization.menuTitle("Copy BibTeX key and title"),
Globals.getKeyPrefs().getKey(KeyBinding.COPY_BIBTEX_KEY_AND_TITLE));
+ private final AbstractAction copyKeyAndLink = new GeneralAction(Actions.COPY_KEY_AND_LINK,
+ Localization.menuTitle("Copy BibTeX key and link"),
+ Globals.getKeyPrefs().getKey(KeyBinding.COPY_BIBTEX_KEY_AND_LINK));
private final AbstractAction mergeDatabaseAction = new GeneralAction(Actions.MERGE_DATABASE,
Localization.menuTitle("Append database"),
Localization.lang("Append contents from a BibTeX database into the currently viewed database"));
@@ -345,11 +342,6 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
}
});
- private final Action toggleGroups = enableToggle(new GeneralAction(Actions.TOGGLE_GROUPS,
- Localization.menuTitle("Toggle groups interface"),
- Localization.lang("Toggle groups interface"),
- Globals.getKeyPrefs().getKey(KeyBinding.TOGGLE_GROUPS_INTERFACE),
- IconTheme.JabRefIcon.TOGGLE_GROUPS.getIcon()));
private final AbstractAction addToGroup = new GeneralAction(Actions.ADD_TO_GROUP, Localization.lang("Add to group") + ELLIPSES);
private final AbstractAction removeFromGroup = new GeneralAction(Actions.REMOVE_FROM_GROUP,
Localization.lang("Remove from group") + ELLIPSES);
@@ -371,9 +363,12 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
Localization.lang("Disable highlight groups matching entries")));
- private final AbstractAction switchPreview = new GeneralAction(Actions.SWITCH_PREVIEW,
- Localization.menuTitle("Switch preview layout"),
- Globals.getKeyPrefs().getKey(KeyBinding.SWITCH_PREVIEW_LAYOUT));
+ private final AbstractAction nextPreviewStyle = new GeneralAction(Actions.NEXT_PREVIEW_STYLE,
+ Localization.menuTitle("Next preview layout"),
+ Globals.getKeyPrefs().getKey(KeyBinding.NEXT_PREVIEW_LAYOUT));
+ private final AbstractAction previousPreviewStyle = new GeneralAction(Actions.PREVIOUS_PREVIEW_STYLE,
+ Localization.menuTitle("Previous preview layout"),
+ Globals.getKeyPrefs().getKey(KeyBinding.PREVIOUS_PREVIEW_LAYOUT));
private final AbstractAction makeKeyAction = new GeneralAction(Actions.MAKE_KEY,
Localization.menuTitle("Autogenerate BibTeX keys"),
Localization.lang("Autogenerate BibTeX keys"),
@@ -443,8 +438,9 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
IconTheme.JabRefIcon.MERGE_ENTRIES.getIcon());
private final AbstractAction downloadFullText = new GeneralAction(Actions.DOWNLOAD_FULL_TEXT,
- Localization.menuTitle("Look up full text document"),
- Localization.lang("Follow DOI or URL link and try to locate PDF full text document"));
+ Localization.menuTitle("Look up full text documents"),
+ Localization.lang("Look up full text documents"));
+
private final AbstractAction increaseFontSize = new IncreaseTableFontSizeAction();
private final AbstractAction decreseFontSize = new DecreaseTableFontSizeAction();
private final AbstractAction resolveDuplicateKeys = new GeneralAction(Actions.RESOLVE_DUPLICATE_KEYS,
@@ -470,13 +466,14 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
private PushToApplications pushApplications;
private GeneralFetcher generalFetcher;
-
+ private OpenOfficePanel openOfficePanel;
private GroupSelector groupSelector;
private int previousTabCount = -1;
// The action for adding a new entry of unspecified type.
private final NewEntryAction newEntryAction = new NewEntryAction(this, Globals.getKeyPrefs().getKey(KeyBinding.NEW_ENTRY));
+ private JMenu newSpec;
private final List<NewEntryAction> newSpecificEntryAction = getNewEntryActions();
// The action for closing the current database and leaving the window open.
@@ -494,7 +491,11 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
private final List<Object> openAndSavedDatabasesOnlyActions = new LinkedList<>();
private final List<Object> sharedDatabaseOnlyActions = new LinkedList<>();
private final List<Object> noSharedDatabaseActions = new LinkedList<>();
-
+ private final List<Object> oneEntryOnlyActions = new LinkedList<>();
+ private final List<Object> oneEntryWithFileOnlyActions = new LinkedList<>();
+ private final List<Object> oneEntryWithURLorDOIOnlyActions = new LinkedList<>();
+ private final List<Object> twoEntriesOnlyActions = new LinkedList<>();
+ private final List<Object> atLeastOneEntryActions = new LinkedList<>();
private class EditModeAction extends AbstractAction {
@@ -527,7 +528,6 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
// update all elements in current base panel
JabRefFrame.this.getCurrentBasePanel().hideBottomComponent();
- JabRefFrame.this.getCurrentBasePanel().rebuildAllEntryEditors();
JabRefFrame.this.getCurrentBasePanel().updateEntryEditorIfShowing();
}
@@ -537,7 +537,6 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
public JabRefFrame() {
init();
updateEnabledState();
-
}
private List<NewEntryAction> getNewEntryActions() {
@@ -570,18 +569,14 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
popupMenu.addSeparator();
- JMenuItem databaseProperties = new JMenuItem(Localization.lang("Database properties"));
- databaseProperties.addActionListener(this.databaseProperties);
- popupMenu.add(databaseProperties);
+ JMenuItem databasePropertiesMenu = new JMenuItem(Localization.lang("Database properties"));
+ databasePropertiesMenu.addActionListener(this.databaseProperties);
+ popupMenu.add(databasePropertiesMenu);
JMenuItem bibtexKeyPatternBtn = new JMenuItem(Localization.lang("BibTeX key patterns"));
bibtexKeyPatternBtn.addActionListener(bibtexKeyPattern);
popupMenu.add(bibtexKeyPatternBtn);
- JMenuItem manageSelectorsBtn = new JMenuItem(Localization.lang("Manage content selectors"));
- manageSelectorsBtn.addActionListener(manageSelectors);
- popupMenu.add(manageSelectorsBtn);
-
return popupMenu;
}
@@ -617,9 +612,9 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
tlb.setVisible(Globals.prefs.getBoolean(JabRefPreferences.TOOLBAR_VISIBLE));
setBounds(GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds());
- pw = new PositionWindow(this, JabRefPreferences.POS_X, JabRefPreferences.POS_Y, JabRefPreferences.SIZE_X,
+ WindowLocation pw = new WindowLocation(this, JabRefPreferences.POS_X, JabRefPreferences.POS_Y, JabRefPreferences.SIZE_X,
JabRefPreferences.SIZE_Y);
- positionWindowOnScreen();
+ pw.displayWindowAtStoredLocation();
tabbedPane.setBorder(null);
tabbedPane.setForeground(GUIGlobals.INACTIVE_TABBED_COLOR);
@@ -632,23 +627,37 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
tabbedPane.addChangeListener(e -> {
markActiveBasePanel();
- BasePanel bp = getCurrentBasePanel();
- if (bp == null) {
+ BasePanel currentBasePanel = getCurrentBasePanel();
+ if (currentBasePanel == null) {
return;
}
- groupToggle.setSelected(sidePaneManager.isComponentVisible("groups"));
- previewToggle.setSelected(Globals.prefs.getBoolean(JabRefPreferences.PREVIEW_ENABLED));
- fetcherToggle.setSelected(sidePaneManager.isComponentVisible(generalFetcher.getTitle()));
- Globals.getFocusListener().setFocused(bp.getMainTable());
+ if (new SearchPreferences(Globals.prefs).isGlobalSearch()) {
+ globalSearchBar.performSearch();
+ } else {
+ String content = "";
+ SearchQuery currentSearchQuery = currentBasePanel.getCurrentSearchQuery();
+ if ((currentSearchQuery != null) && !currentSearchQuery.getQuery().trim().isEmpty()) {
+ content = currentSearchQuery.getQuery();
+ }
+ globalSearchBar.setSearchTerm(content, true);
+ }
+
+ currentBasePanel.getPreviewPanel().updateLayout();
+
+ groupSelector.getToggleAction().setSelected(sidePaneManager.isComponentVisible(GroupSelector.class));
+ previewToggle.setSelected(Globals.prefs.getPreviewPreferences().isPreviewPanelEnabled());
+ generalFetcher.getToggleAction().setSelected(sidePaneManager.isComponentVisible(GeneralFetcher.class));
+ openOfficePanel.getToggleAction().setSelected(sidePaneManager.isComponentVisible(OpenOfficeSidePanel.class));
+ Globals.getFocusListener().setFocused(currentBasePanel.getMainTable());
setWindowTitle();
editModeAction.initName();
// Update search autocompleter with information for the correct database:
- bp.updateSearchManager();
+ currentBasePanel.updateSearchManager();
// Set correct enabled state for Back and Forward actions:
- bp.setBackAndForwardEnabledState();
- bp.getUndoManager().postUndoRedoEvent();
- new FocusRequester(bp.getMainTable());
+ currentBasePanel.setBackAndForwardEnabledState();
+ currentBasePanel.getUndoManager().postUndoRedoEvent();
+ currentBasePanel.getMainTable().requestFocus();
});
//Note: The registration of Apple event is at the end of initialization, because
@@ -664,12 +673,6 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
}
- private void positionWindowOnScreen() {
- if (!prefs.getBoolean(JabRefPreferences.WINDOW_MAXIMISED)) {
- pw.setWindowPosition();
- }
- }
-
public void refreshTitleAndTabs() {
setWindowTitle();
updateAllTabTitles();
@@ -689,18 +692,16 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
String mode = panel.getBibDatabaseContext().getMode().getFormattedName();
String modeInfo = String.format(" (%s)", Localization.lang("%0 mode", mode));
- String changeFlag = panel.isModified() ? "*" : "";
+ boolean isAutosaveEnabled = Globals.prefs.getBoolean(JabRefPreferences.LOCAL_AUTO_SAVE);
if (panel.getBibDatabaseContext().getLocation() == DatabaseLocation.LOCAL) {
- if (panel.getBibDatabaseContext().getDatabaseFile() == null) {
- setTitle(FRAME_TITLE + " - " + GUIGlobals.UNTITLED_TITLE + changeFlag + modeInfo);
- } else {
- String databaseFile = panel.getBibDatabaseContext().getDatabaseFile().getPath();
+ String changeFlag = panel.isModified() && !isAutosaveEnabled ? "*" : "";
+ String databaseFile = panel.getBibDatabaseContext().getDatabaseFile().map(File::getPath)
+ .orElse(GUIGlobals.UNTITLED_TITLE);
setTitle(FRAME_TITLE + " - " + databaseFile + changeFlag + modeInfo);
- }
} else if (panel.getBibDatabaseContext().getLocation() == DatabaseLocation.SHARED) {
- setTitle(FRAME_TITLE + " - " + panel.getBibDatabaseContext().getDBSynchronizer().getDBName() + " [shared]"
- + modeInfo);
+ setTitle(FRAME_TITLE + " - " + panel.getBibDatabaseContext().getDBMSSynchronizer().getDBName() + " ["
+ + Localization.lang("shared") + "]" + modeInfo);
}
}
@@ -708,10 +709,10 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
sidePaneManager = new SidePaneManager(this);
groupSelector = new GroupSelector(this, sidePaneManager);
+ openOfficePanel = new OpenOfficePanel(this, sidePaneManager);
+ generalFetcher = new GeneralFetcher(this, sidePaneManager);
- generalFetcher = new GeneralFetcher(sidePaneManager, this);
-
- sidePaneManager.register("groups", groupSelector);
+ sidePaneManager.register(groupSelector);
}
/**
@@ -762,7 +763,6 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
dispose();
- //prefs.putBoolean(JabRefPreferences.WINDOW_MAXIMISED, (getExtendedState()&MAXIMIZED_BOTH)>0);
prefs.putBoolean(JabRefPreferences.WINDOW_MAXIMISED, getExtendedState() == Frame.MAXIMIZED_BOTH);
prefs.putBoolean(JabRefPreferences.TOOLBAR_VISIBLE, tlb.isVisible());
@@ -779,7 +779,7 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
prefs.remove(JabRefPreferences.LAST_EDITED);
} else {
prefs.putStringList(JabRefPreferences.LAST_EDITED, filenames);
- File focusedDatabase = getCurrentBasePanel().getBibDatabaseContext().getDatabaseFile();
+ File focusedDatabase = getCurrentBasePanel().getBibDatabaseContext().getDatabaseFile().orElse(null);
new LastFocusedTabPreferences(prefs).setLastFocusedTab(focusedDatabase);
}
@@ -790,19 +790,12 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
prefs.customImports.store();
CustomEntryTypesManager.saveCustomEntryTypes(prefs);
- // Clear autosave files:
- // TODO: Is this really needed since clearAutoSave() is called in stopAutoSaveManager() a few rows below?
- Globals.getAutoSaveManager().ifPresent(manager -> manager.clearAutoSaves());
-
prefs.flush();
// dispose all windows, even if they are not displayed anymore
for (Window window : Window.getWindows()) {
window.dispose();
}
-
- // shutdown any timers that are may be active
- Globals.stopAutoSaveManager();
}
/**
@@ -820,19 +813,15 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
// Ask here if the user really wants to close, if the base
// has not been saved since last save.
boolean close = true;
+
List<String> filenames = new ArrayList<>();
if (tabbedPane.getTabCount() > 0) {
for (int i = 0; i < tabbedPane.getTabCount(); i++) {
- if (getBasePanelAt(i).isModified()
- && (getBasePanelAt(i).getBibDatabaseContext().getLocation() == DatabaseLocation.LOCAL)) {
- tabbedPane.setSelectedIndex(i);
- String filename;
+ BibDatabaseContext context = getBasePanelAt(i).getBibDatabaseContext();
- if (getBasePanelAt(i).getBibDatabaseContext().getDatabaseFile() == null) {
- filename = GUIGlobals.UNTITLED_TITLE;
- } else {
- filename = getBasePanelAt(i).getBibDatabaseContext().getDatabaseFile().getAbsolutePath();
- }
+ if (getBasePanelAt(i).isModified() && (context.getLocation() == DatabaseLocation.LOCAL)) {
+ tabbedPane.setSelectedIndex(i);
+ String filename = context.getDatabaseFile().map(File::getAbsolutePath).orElse(GUIGlobals.UNTITLED_TITLE);
int answer = showSaveDialog(filename);
if ((answer == JOptionPane.CANCEL_OPTION) ||
@@ -858,11 +847,14 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
break;
}
}
+ } else if (context.getLocation() == DatabaseLocation.SHARED) {
+ context.convertToLocalDatabase();
+ context.getDBMSSynchronizer().closeSharedDatabase();
+ context.clearDBMSSynchronizer();
}
-
- if (getBasePanelAt(i).getBibDatabaseContext().getDatabaseFile() != null) {
- filenames.add(getBasePanelAt(i).getBibDatabaseContext().getDatabaseFile().getAbsolutePath());
- }
+ AutosaveManager.shutdown(context);
+ BackupManager.shutdown(context);
+ context.getDatabaseFile().map(File::getAbsolutePath).ifPresent(filenames::add);
}
}
@@ -894,59 +886,27 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
pushExternalButton = new PushToApplicationButton(this, pushApplications.getApplications());
fillMenu();
createToolBar();
- getContentPane().setLayout(gbl);
- splitPane.setDividerSize(2);
- splitPane.setBorder(null);
- //getContentPane().setBackground(GUIGlobals.lightGray);
- con.fill = GridBagConstraints.HORIZONTAL;
- con.anchor = GridBagConstraints.WEST;
- con.weightx = 1;
- con.weighty = 0;
- con.gridwidth = GridBagConstraints.REMAINDER;
-
- //gbl.setConstraints(mb, con);
- //getContentPane().add(mb);
setJMenuBar(mb);
- con.anchor = GridBagConstraints.NORTH;
- //con.gridwidth = 1;//GridBagConstraints.REMAINDER;;
- gbl.setConstraints(tlb, con);
- getContentPane().add(tlb);
-
- Component lim = Box.createGlue();
- gbl.setConstraints(lim, con);
- //getContentPane().add(lim);
- /*
- JPanel empt = new JPanel();
- empt.setBackground(GUIGlobals.lightGray);
- gbl.setConstraints(empt, con);
- getContentPane().add(empt);
-
- con.insets = new Insets(1,0,1,1);
- con.anchor = GridBagConstraints.EAST;
- con.weightx = 0;
- gbl.setConstraints(searchManager, con);
- getContentPane().add(searchManager);*/
- con.gridwidth = GridBagConstraints.REMAINDER;
- con.weightx = 1;
- con.weighty = 0;
- con.fill = GridBagConstraints.BOTH;
- con.anchor = GridBagConstraints.WEST;
- con.insets = new Insets(0, 0, 0, 0);
- lim = Box.createGlue();
- gbl.setConstraints(lim, con);
- getContentPane().add(lim);
- //tabbedPane.setVisible(false);
- //tabbedPane.setForeground(GUIGlobals.lightGray);
- con.weighty = 1;
- gbl.setConstraints(splitPane, con);
- getContentPane().add(splitPane);
+ getContentPane().setLayout(new BorderLayout());
- UIManager.put("TabbedPane.contentBorderInsets", new Insets(0, 0, 0, 0));
+ JPanel toolbarPanel = new JPanel(new WrapLayout(FlowLayout.LEFT));
+ toolbarPanel.add(tlb);
+ toolbarPanel.add(globalSearchBar);
+ getContentPane().add(toolbarPanel, BorderLayout.PAGE_START);
+ splitPane.setDividerSize(2);
+ splitPane.setBorder(null);
splitPane.setRightComponent(tabbedPane);
splitPane.setLeftComponent(sidePaneManager.getPanel());
+ getContentPane().add(splitPane, BorderLayout.CENTER);
+
+ UIManager.put("TabbedPane.contentBorderInsets", new Insets(0, 0, 0, 0));
sidePaneManager.updateView();
+ GridBagLayout gbl = new GridBagLayout();
+ GridBagConstraints con = new GridBagConstraints();
+ con.fill = GridBagConstraints.BOTH;
+ con.anchor = GridBagConstraints.WEST;
JPanel status = new JPanel();
status.setLayout(gbl);
con.weighty = 0;
@@ -965,12 +925,8 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
con.insets = new Insets(2, 4, 2, 2);
gbl.setConstraints(progressBar, con);
status.add(progressBar);
- con.weightx = 1;
- con.gridwidth = GridBagConstraints.REMAINDER;
statusLabel.setForeground(GUIGlobals.ENTRY_EDITOR_LABEL_COLOR.darker());
- con.insets = new Insets(0, 0, 0, 0);
- gbl.setConstraints(status, con);
- getContentPane().add(status);
+ getContentPane().add(status, BorderLayout.PAGE_END);
// Drag and drop for tabbedPane:
TransferHandler xfer = new EntryTableTransferHandler(null, this, null);
@@ -1137,6 +1093,7 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
}
}
+
private void fillMenu() {
mb.setBorder(null);
JMenu file = JabRefFrame.subMenu(Localization.menuTitle("File"));
@@ -1148,7 +1105,7 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
JMenu view = JabRefFrame.subMenu(Localization.menuTitle("View"));
JMenu tools = JabRefFrame.subMenu(Localization.menuTitle("Tools"));
JMenu options = JabRefFrame.subMenu(Localization.menuTitle("Options"));
- JMenu newSpec = JabRefFrame.subMenu(Localization.menuTitle("New entry by type..."));
+ newSpec = JabRefFrame.subMenu(Localization.menuTitle("New entry by type..."));
JMenu helpMenu = JabRefFrame.subMenu(Localization.menuTitle("Help"));
file.add(newBibtexDatabaseAction);
@@ -1166,7 +1123,7 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
file.add(exportAll);
file.add(exportSelected);
file.addSeparator();
- file.add(openSharedDatabaseAction);
+ file.add(connectToSharedDatabaseAction);
file.add(pullChangesFromSharedDatabase);
file.addSeparator();
@@ -1194,12 +1151,12 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
edit.add(copyKey);
edit.add(copyCiteKey);
edit.add(copyKeyAndTitle);
+ edit.add(copyKeyAndLink);
edit.add(exportToClipboard);
edit.add(sendAsEmail);
edit.addSeparator();
edit.add(mark);
- JMenu markSpecific = JabRefFrame.subMenu(Localization.menuTitle("Mark specific color"));
for (int i = 0; i < EntryMarker.MAX_MARKING_LEVEL; i++) {
markSpecific.add(new MarkEntriesAction(this, i).getMenuItem());
}
@@ -1208,32 +1165,40 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
edit.add(unmarkAll);
edit.addSeparator();
if (Globals.prefs.getBoolean(JabRefPreferences.SPECIALFIELDSENABLED)) {
- JMenu m;
+ boolean menuitem = false;
if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_RANKING)) {
- m = new JMenu();
- RightClickMenu.populateSpecialFieldMenu(m, Rank.getInstance(), this);
- edit.add(m);
+ rankSubMenu = new JMenu();
+ RightClickMenu.populateSpecialFieldMenu(rankSubMenu, SpecialField.RANKING, this);
+ edit.add(rankSubMenu);
+ menuitem = true;
}
if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_RELEVANCE)) {
edit.add(toggleRelevance);
+ menuitem = true;
}
if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_QUALITY)) {
edit.add(toggleQualityAssured);
+ menuitem = true;
}
if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_PRIORITY)) {
- m = new JMenu();
- RightClickMenu.populateSpecialFieldMenu(m, Priority.getInstance(), this);
- edit.add(m);
+ rankSubMenu = new JMenu();
+ RightClickMenu.populateSpecialFieldMenu(rankSubMenu, SpecialField.PRIORITY, this);
+ edit.add(rankSubMenu);
+ menuitem = true;
}
if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_PRINTED)) {
edit.add(togglePrinted);
+ menuitem = true;
}
if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_READ)) {
- m = new JMenu();
- RightClickMenu.populateSpecialFieldMenu(m, ReadStatus.getInstance(), this);
- edit.add(m);
+ rankSubMenu = new JMenu();
+ RightClickMenu.populateSpecialFieldMenu(rankSubMenu, SpecialField.READ_STATUS, this);
+ edit.add(rankSubMenu);
+ menuitem = true;
+ }
+ if (menuitem) {
+ edit.addSeparator();
}
- edit.addSeparator();
}
edit.add(getManageKeywords());
@@ -1245,14 +1210,19 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
search.add(normalSearch);
search.add(replaceAll);
search.addSeparator();
- search.add(new JCheckBoxMenuItem(generalFetcher.getAction()));
+ search.add(new JCheckBoxMenuItem(generalFetcher.getToggleAction()));
if (prefs.getBoolean(JabRefPreferences.WEB_SEARCH_VISIBLE)) {
- sidePaneManager.register(generalFetcher.getTitle(), generalFetcher);
- sidePaneManager.show(generalFetcher.getTitle());
+ sidePaneManager.register(generalFetcher);
+ sidePaneManager.show(GeneralFetcher.class);
}
mb.add(search);
- groups.add(new JCheckBoxMenuItem(toggleGroups));
+ groups.add(new JCheckBoxMenuItem(groupSelector.getToggleAction()));
+ if (prefs.getBoolean(JabRefPreferences.GROUP_SIDEPANE_VISIBLE)) {
+ sidePaneManager.register(groupSelector);
+ sidePaneManager.show(GroupSelector.class);
+ }
+
groups.addSeparator();
groups.add(addToGroup);
groups.add(removeFromGroup);
@@ -1269,10 +1239,11 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
highlightButtonGroup.add(toggleHighlightAnyItem);
highlightButtonGroup.add(toggleHighlightAllItem);
- HighlightMatchingGroupPreferences highlightMatchingGroupPreferences = new HighlightMatchingGroupPreferences(Globals.prefs);
- if(highlightMatchingGroupPreferences.isAll()) {
+ HighlightMatchingGroupPreferences highlightMatchingGroupPreferences = new HighlightMatchingGroupPreferences(
+ Globals.prefs);
+ if (highlightMatchingGroupPreferences.isAll()) {
toggleHighlightAllItem.setSelected(true);
- } else if(highlightMatchingGroupPreferences.isAny()) {
+ } else if (highlightMatchingGroupPreferences.isAny()) {
toggleHighlightAnyItem.setSelected(true);
} else {
toggleHighlightDisableItem.setSelected(true);
@@ -1291,10 +1262,11 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
view.add(decreseFontSize);
view.addSeparator();
view.add(new JCheckBoxMenuItem(toggleToolbar));
- view.add(new JCheckBoxMenuItem(enableToggle(generalFetcher.getAction())));
- view.add(new JCheckBoxMenuItem(toggleGroups));
+ view.add(new JCheckBoxMenuItem(enableToggle(generalFetcher.getToggleAction())));
+ view.add(new JCheckBoxMenuItem(groupSelector.getToggleAction()));
view.add(new JCheckBoxMenuItem(togglePreview));
- view.add(getSwitchPreviewAction());
+ view.add(getNextPreviewStyleAction());
+ view.add(getPreviousPreviewStyleAction());
mb.add(view);
@@ -1322,6 +1294,7 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
quality.add(resolveDuplicateKeys);
quality.add(checkIntegrity);
quality.add(cleanupEntries);
+ quality.add(massSetField);
quality.add(makeKeyAction);
quality.addSeparator();
quality.add(autoSetFile);
@@ -1332,9 +1305,7 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
tools.add(newSubDatabaseAction);
tools.add(writeXmpAction);
- OpenOfficePanel otp = OpenOfficePanel.getInstance();
- otp.init(this, sidePaneManager);
- tools.add(otp.getMenuItem());
+ tools.add(new JCheckBoxMenuItem(openOfficePanel.getToggleAction()));
tools.add(pushExternalButton.getMenuAction());
tools.addSeparator();
tools.add(openFolder);
@@ -1356,7 +1327,6 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
options.add(customImpAction);
options.add(customFileTypesAction);
options.add(manageJournals);
- options.add(manageSelectors);
options.add(protectTerms);
options.add(selectKeys);
mb.add(options);
@@ -1412,8 +1382,7 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
} else {
// only add tab if DB is not already open
Optional<BasePanel> panel = getBasePanelList().stream()
- .filter(p -> p.getBibDatabaseContext().getDatabaseFile().equals(pr.getFile().orElse(null)))
- .findFirst();
+ .filter(p -> p.getBibDatabaseContext().getDatabaseFile().equals(pr.getFile())).findFirst();
if (panel.isPresent()) {
tabbedPane.setSelectedComponent(panel.get());
@@ -1465,8 +1434,8 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
tlb.addAction(unmark);
if (Globals.prefs.getBoolean(JabRefPreferences.SPECIALFIELDSENABLED)) {
if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_RANKING)) {
- JButton button = net.sf.jabref.specialfields.SpecialFieldDropDown
- .generateSpecialFieldButtonWithDropDown(Rank.getInstance(), this);
+ JButton button = SpecialFieldDropDown
+ .generateSpecialFieldButtonWithDropDown(SpecialField.RANKING, this);
tlb.add(button);
specialFieldButtons.add(button);
}
@@ -1477,8 +1446,8 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
tlb.addAction(toggleQualityAssured);
}
if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_PRIORITY)) {
- JButton button = net.sf.jabref.specialfields.SpecialFieldDropDown
- .generateSpecialFieldButtonWithDropDown(Priority.getInstance(), this);
+ JButton button = SpecialFieldDropDown
+ .generateSpecialFieldButtonWithDropDown(SpecialField.PRIORITY, this);
tlb.add(button);
specialFieldButtons.add(button);
}
@@ -1486,22 +1455,20 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
tlb.addAction(togglePrinted);
}
if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_READ)) {
- JButton button = net.sf.jabref.specialfields.SpecialFieldDropDown
- .generateSpecialFieldButtonWithDropDown(ReadStatus.getInstance(), this);
+ JButton button = SpecialFieldDropDown
+ .generateSpecialFieldButtonWithDropDown(SpecialField.READ_STATUS, this);
tlb.add(button);
specialFieldButtons.add(button);
}
}
tlb.addSeparator();
- fetcherToggle = new JToggleButton(generalFetcher.getAction());
- tlb.addJToogleButton(fetcherToggle);
+ tlb.addJToggleButton(new JToggleButton(generalFetcher.getToggleAction()));
previewToggle = new JToggleButton(togglePreview);
- tlb.addJToogleButton(previewToggle);
+ tlb.addJToggleButton(previewToggle);
- groupToggle = new JToggleButton(toggleGroups);
- tlb.addJToogleButton(groupToggle);
+ tlb.addJToggleButton(new JToggleButton(groupSelector.getToggleAction()));
tlb.addSeparator();
@@ -1509,6 +1476,8 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
tlb.addSeparator();
tlb.add(donationAction);
tlb.add(forkMeOnGitHubAction);
+
+ createDisabledIconsForButtons(tlb);
}
/**
@@ -1523,16 +1492,16 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
private void initActions() {
openDatabaseOnlyActions.clear();
- openDatabaseOnlyActions.addAll(Arrays.asList(manageSelectors, mergeDatabaseAction, newSubDatabaseAction, save,
- saveAs, saveSelectedAs, saveSelectedAsPlain, undo, redo, cut, deleteEntry, copy, paste, mark, unmark,
- unmarkAll, editEntry, selectAll, copyKey, copyCiteKey, copyKeyAndTitle, editPreamble, editStrings,
- toggleGroups, makeKeyAction, normalSearch, mergeEntries, cleanupEntries, exportToClipboard, replaceAll,
- sendAsEmail, downloadFullText, writeXmpAction, findUnlinkedFiles, addToGroup, removeFromGroup,
+ openDatabaseOnlyActions.addAll(Arrays.asList(mergeDatabaseAction, newSubDatabaseAction, save,
+ saveAs, saveSelectedAs, saveSelectedAsPlain, editModeAction, undo, redo, cut, deleteEntry, copy, paste, mark, markSpecific, unmark,
+ unmarkAll, rankSubMenu, editEntry, selectAll, copyKey, copyCiteKey, copyKeyAndTitle, copyKeyAndLink, editPreamble, editStrings,
+ groupSelector.getToggleAction(), makeKeyAction, normalSearch, generalFetcher.getToggleAction(), mergeEntries, cleanupEntries, exportToClipboard, replaceAll,
+ sendAsEmail, downloadFullText, writeXmpAction, openOfficePanel.getToggleAction(), findUnlinkedFiles, addToGroup, removeFromGroup,
moveToGroup, autoLinkFile, resolveDuplicateKeys, openUrl, openFolder, openFile, togglePreview,
- dupliCheck, autoSetFile, newEntryAction, plainTextImport, getMassSetField(), getManageKeywords(),
- pushExternalButton.getMenuAction(), closeDatabaseAction, getSwitchPreviewAction(), checkIntegrity,
+ dupliCheck, autoSetFile, newEntryAction, newSpec, customizeAction, plainTextImport, getMassSetField(), getManageKeywords(),
+ pushExternalButton.getMenuAction(), closeDatabaseAction, getNextPreviewStyleAction(), getPreviousPreviewStyleAction(), checkIntegrity,
toggleHighlightAny, toggleHighlightAll, toggleHighlightDisable, databaseProperties, abbreviateIso, abbreviateMedline,
- unabbreviate, exportAll, exportSelected, importCurrent, saveAll, focusTable,
+ unabbreviate, exportAll, exportSelected, importCurrent, saveAll, focusTable, increaseFontSize, decreseFontSize,
toggleRelevance, toggleQualityAssured, togglePrinted, pushExternalButton.getComponent()));
openDatabaseOnlyActions.addAll(newSpecificEntryAction);
@@ -1547,6 +1516,21 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
sharedDatabaseOnlyActions.addAll(Collections.singletonList(pullChangesFromSharedDatabase));
noSharedDatabaseActions.addAll(Arrays.asList(save, saveAll));
+ oneEntryOnlyActions.clear();
+ oneEntryOnlyActions.addAll(Arrays.asList(editEntry));
+
+ oneEntryWithFileOnlyActions.clear();
+ oneEntryWithFileOnlyActions.addAll(Arrays.asList(openFolder, openFile));
+
+ oneEntryWithURLorDOIOnlyActions.clear();
+ oneEntryWithURLorDOIOnlyActions.addAll(Arrays.asList(openUrl));
+
+ twoEntriesOnlyActions.clear();
+ twoEntriesOnlyActions.addAll(Arrays.asList(mergeEntries));
+
+ atLeastOneEntryActions.clear();
+ atLeastOneEntryActions.addAll(Arrays.asList(downloadFullText));
+
tabbedPane.addChangeListener(event -> updateEnabledState());
}
@@ -1558,12 +1542,18 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
* @param enabled
*/
private static void setEnabled(List<Object> list, boolean enabled) {
- for (Object o : list) {
- if (o instanceof Action) {
- ((Action) o).setEnabled(enabled);
+ for (Object actionOrComponent : list) {
+ if (actionOrComponent instanceof Action) {
+ ((Action) actionOrComponent).setEnabled(enabled);
}
- if (o instanceof Component) {
- ((Component) o).setEnabled(enabled);
+ if (actionOrComponent instanceof Component) {
+ ((Component) actionOrComponent).setEnabled(enabled);
+ if (actionOrComponent instanceof JPanel) {
+ JPanel root = (JPanel) actionOrComponent;
+ for (int index = 0; index < root.getComponentCount(); index++) {
+ root.getComponent(index).setEnabled(enabled);
+ }
+ }
}
}
}
@@ -1585,16 +1575,28 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
getForwardAction().setEnabled(false);
setEnabled(openAndSavedDatabasesOnlyActions, false);
setEnabled(sharedDatabaseOnlyActions, false);
+ setEnabled(oneEntryOnlyActions, false);
}
-
if (tabCount > 0) {
BasePanel current = getCurrentBasePanel();
- boolean saved = current.getBibDatabaseContext().getDatabaseFile() != null;
+ boolean saved = current.getBibDatabaseContext().getDatabasePath().isPresent();
setEnabled(openAndSavedDatabasesOnlyActions, saved);
+
boolean isShared = current.getBibDatabaseContext().getLocation() == DatabaseLocation.SHARED;
setEnabled(sharedDatabaseOnlyActions, isShared);
setEnabled(noSharedDatabaseActions, !isShared);
+
+ boolean oneEntrySelected = current.getSelectedEntries().size() == 1;
+ setEnabled(oneEntryOnlyActions, oneEntrySelected);
+ setEnabled(oneEntryWithFileOnlyActions, isExistFile(current.getSelectedEntries()));
+ setEnabled(oneEntryWithURLorDOIOnlyActions, isExistURLorDOI(current.getSelectedEntries()));
+
+ boolean twoEntriesSelected = current.getSelectedEntries().size() == 2;
+ setEnabled(twoEntriesOnlyActions, twoEntriesSelected);
+
+ boolean atLeastOneEntrySelected = !current.getSelectedEntries().isEmpty();
+ setEnabled(atLeastOneEntryActions, atLeastOneEntrySelected);
}
}
@@ -1627,10 +1629,10 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
for (BasePanel basePanel : getBasePanelList()) {
try {
// db file exists
- if (basePanel.getBibDatabaseContext().getDatabaseFile() == null) {
- dbPaths.add("");
+ if (basePanel.getBibDatabaseContext().getDatabaseFile().isPresent()) {
+ dbPaths.add(basePanel.getBibDatabaseContext().getDatabaseFile().get().getCanonicalPath());
} else {
- dbPaths.add(basePanel.getBibDatabaseContext().getDatabaseFile().getCanonicalPath());
+ dbPaths.add("");
}
} catch (IOException ex) {
LOGGER.error("Invalid database file path: " + ex.getMessage());
@@ -1649,12 +1651,10 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
List<String> paths = getUniquePathParts();
for (int i = 0; i < getBasePanelCount(); i++) {
String uniqPath = paths.get(i);
- File file = getBasePanelAt(i).getBibDatabaseContext().getDatabaseFile();
+ Optional<File> file = getBasePanelAt(i).getBibDatabaseContext().getDatabaseFile();
- if (file == null) {
- tabbedPane.setTitleAt(i, getBasePanelAt(i).getTabTitle());
- } else {
- if (!uniqPath.equals(file.getName())) {
+ if (file.isPresent()) {
+ if (!uniqPath.equals(file.get().getName())) {
// remove filename
uniqPath = uniqPath.substring(0, uniqPath.lastIndexOf(File.separator));
tabbedPane.setTitleAt(i, getBasePanelAt(i).getTabTitle() + " \u2014 " + uniqPath);
@@ -1662,34 +1662,51 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
// set original filename (again)
tabbedPane.setTitleAt(i, getBasePanelAt(i).getTabTitle());
}
+ } else {
+ tabbedPane.setTitleAt(i, getBasePanelAt(i).getTabTitle());
}
- tabbedPane.setToolTipTextAt(i, file == null ? null : file.getAbsolutePath());
+ tabbedPane.setToolTipTextAt(i, file.map(File::getAbsolutePath).orElse(null));
}
}
- public void addTab(BasePanel bp, boolean raisePanel) {
+ public void addTab(BasePanel basePanel, boolean raisePanel) {
// add tab
- tabbedPane.add(bp.getTabTitle(), bp);
+ tabbedPane.add(basePanel.getTabTitle(), basePanel);
// update all tab titles
updateAllTabTitles();
if (raisePanel) {
- tabbedPane.setSelectedComponent(bp);
+ tabbedPane.setSelectedComponent(basePanel);
}
// Register undo/redo listener
- bp.getUndoManager().registerListener(new UndoRedoEventManager());
+ basePanel.getUndoManager().registerListener(new UndoRedoEventManager());
+
+ BibDatabaseContext context = basePanel.getBibDatabaseContext();
+
+ if (readyForAutosave(context)) {
+ AutosaveManager autosaver = AutosaveManager.start(context);
+ autosaver.registerListener(new AutosaveUIManager(basePanel));
+ }
+
+ BackupManager.start(context);
}
public BasePanel addTab(BibDatabaseContext databaseContext, boolean raisePanel) {
Objects.requireNonNull(databaseContext);
-
BasePanel bp = new BasePanel(JabRefFrame.this, databaseContext);
addTab(bp, raisePanel);
return bp;
}
+ private boolean readyForAutosave(BibDatabaseContext context) {
+ return (context.getLocation() == DatabaseLocation.SHARED ||
+ ((context.getLocation() == DatabaseLocation.LOCAL) && Globals.prefs.getBoolean(JabRefPreferences.LOCAL_AUTO_SAVE))) &&
+ context.getDatabaseFile().isPresent();
+ }
+
+
/**
* Creates icons for the disabled state for all JMenuItems with FontBasedIcons in the given menuElement.
* This is necessary as Swing is not able to generate default disabled icons for font based icons.
@@ -1709,6 +1726,20 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
}
}
+ public void createDisabledIconsForButtons(Container container) {
+ for (int index = 0; index < container.getComponentCount(); index++) {
+ Component component = container.getComponent(index);
+ if (component instanceof JButton) {
+ JButton button = (JButton) component;
+ if (button.getIcon() instanceof IconTheme.FontBasedIcon) {
+ button.setDisabledIcon(((IconTheme.FontBasedIcon) button.getIcon()).createDisabledIcon());
+ }
+ } else if (component instanceof JPanel) {
+ createDisabledIconsForButtons((JPanel) component);
+ }
+ }
+ }
+
private class SelectKeysAction extends AbstractAction {
public SelectKeysAction() {
@@ -1782,13 +1813,6 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
return fileHistory;
}
- public void removeCachedEntryEditors() {
- for (int j = 0; j < tabbedPane.getTabCount(); j++) {
- BasePanel bp = (BasePanel) tabbedPane.getComponentAt(j);
- bp.getEntryEditors().clear();
- }
- }
-
/**
* This method shows a wait cursor and blocks all input to the JFrame's contents.
*/
@@ -1883,6 +1907,34 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
}
+ /**
+ * Return a boolean, if the selected entry have file
+ * @param selectEntryList A selected entries list of the current base pane
+ * @return true, if the selected entry contains file.
+ * false, if multiple entries are selected or the selected entry doesn't contains file
+ */
+ private boolean isExistFile(List<BibEntry> selectEntryList) {
+ if (selectEntryList.size() == 1) {
+ BibEntry selectedEntry = selectEntryList.get(0);
+ return selectedEntry.getField(FieldName.FILE).isPresent();
+ }
+ return false;
+ }
+
+ /**
+ * Return a boolean, if the selected entry have url or doi
+ * @param selectEntryList A selected entries list of the current base pane
+ * @return true, if the selected entry contains url or doi.
+ * false, if multiple entries are selected or the selected entry doesn't contains url or doi
+ */
+ private boolean isExistURLorDOI(List<BibEntry> selectEntryList) {
+ if (selectEntryList.size() == 1) {
+ BibEntry selectedEntry = selectEntryList.get(0);
+ return (selectedEntry.getField(FieldName.URL).isPresent() || selectedEntry.getField(FieldName.DOI).isPresent());
+ }
+ return false;
+ }
+
private class ChangeTabAction extends MnemonicAwareAction {
private final boolean next;
@@ -2148,13 +2200,22 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
return;
}
- if (panel.isModified() && (panel.getBibDatabaseContext().getLocation() == DatabaseLocation.LOCAL)) {
+ BibDatabaseContext context = panel.getBibDatabaseContext();
+
+ if (panel.isModified() && (context.getLocation() == DatabaseLocation.LOCAL)) {
if (confirmClose(panel)) {
removeTab(panel);
}
+ } else if (context.getLocation() == DatabaseLocation.SHARED) {
+ context.convertToLocalDatabase();
+ context.getDBMSSynchronizer().closeSharedDatabase();
+ context.clearDBMSSynchronizer();
+ removeTab(panel);
} else {
removeTab(panel);
}
+ AutosaveManager.shutdown(context);
+ BackupManager.shutdown(context);
}
// Ask if the user really wants to close, if the base has not been saved
@@ -2162,11 +2223,8 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
boolean close = false;
String filename;
- if (panel.getBibDatabaseContext().getDatabaseFile() == null) {
- filename = GUIGlobals.UNTITLED_TITLE;
- } else {
- filename = panel.getBibDatabaseContext().getDatabaseFile().getAbsolutePath();
- }
+ filename = panel.getBibDatabaseContext().getDatabaseFile().map(File::getAbsolutePath)
+ .orElse(GUIGlobals.UNTITLED_TITLE);
int answer = showSaveDialog(filename);
if (answer == JOptionPane.YES_OPTION) {
@@ -2190,7 +2248,6 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
private void removeTab(BasePanel panel) {
panel.cleanUp();
- AutoSaveManager.deleteAutoSaveFile(panel);
tabbedPane.remove(panel);
if (tabbedPane.getTabCount() > 0) {
markActiveBasePanel();
@@ -2276,7 +2333,7 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
add(b);
}
- public void addJToogleButton(JToggleButton button) {
+ public void addJToggleButton(JToggleButton button) {
button.setText(null);
if (!OS.OS_X) {
button.setMargin(marg);
@@ -2302,8 +2359,12 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
return back;
}
- public AbstractAction getSwitchPreviewAction() {
- return switchPreview;
+ public AbstractAction getNextPreviewStyleAction() {
+ return nextPreviewStyle;
+ }
+
+ public AbstractAction getPreviousPreviewStyleAction() {
+ return previousPreviewStyle;
}
public JSplitPane getSplitPane() {
@@ -2318,10 +2379,6 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
return groupSelector;
}
- public void setFetcherToggle(boolean enabled) {
- fetcherToggle.setSelected(enabled);
- }
-
public void setPreviewToggle(boolean enabled) {
previewToggle.setSelected(enabled);
}
@@ -2330,6 +2387,10 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
return pushApplications;
}
+ public GlobalSearchBar getGlobalSearchBar() {
+ return globalSearchBar;
+ }
+
private class UndoRedoEventManager {
@@ -2346,12 +2407,10 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
private void updateTexts(UndoChangeEvent event) {
SwingUtilities.invokeLater(() -> {
- if (JabRefFrame.this != null) {
- undo.putValue(Action.SHORT_DESCRIPTION, event.getUndoDescription());
- undo.setEnabled(event.isCanUndo());
- redo.putValue(Action.SHORT_DESCRIPTION, event.getRedoDescription());
- redo.setEnabled(event.isCanRedo());
- }
+ undo.putValue(Action.SHORT_DESCRIPTION, event.getUndoDescription());
+ undo.setEnabled(event.isCanUndo());
+ redo.putValue(Action.SHORT_DESCRIPTION, event.getRedoDescription());
+ redo.setEnabled(event.isCanRedo());
});
}
}
diff --git a/src/main/java/net/sf/jabref/gui/MergeDialog.java b/src/main/java/net/sf/jabref/gui/MergeDialog.java
index edfb593..b7dd704 100644
--- a/src/main/java/net/sf/jabref/gui/MergeDialog.java
+++ b/src/main/java/net/sf/jabref/gui/MergeDialog.java
@@ -39,7 +39,6 @@ public class MergeDialog extends JDialog {
private final JCheckBox strings = new JCheckBox();
private final GridBagLayout gridBagLayout1 = new GridBagLayout();
private final JCheckBox groups = new JCheckBox();
- private final JCheckBox selector = new JCheckBox();
private boolean okPressed;
@@ -69,7 +68,6 @@ public class MergeDialog extends JDialog {
strings.setSelected(true);
strings.setText(Localization.lang("Import strings"));
groups.setText(Localization.lang("Import group definitions"));
- selector.setText(Localization.lang("Import word selector definitions"));
this.setModal(true);
this.setResizable(false);
getContentPane().add(panel1);
@@ -83,8 +81,6 @@ public class MergeDialog extends JDialog {
, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
jPanel1.add(groups, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0
, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
- jPanel1.add(selector, new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0
- , GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
// Key bindings:
ActionMap am = jPanel1.getActionMap();
@@ -111,9 +107,5 @@ public class MergeDialog extends JDialog {
public boolean importStrings() {
return strings.isSelected();
}
-
- public boolean importSelectorWords() {
- return selector.isSelected();
- }
}
diff --git a/src/main/java/net/sf/jabref/gui/PreambleEditor.java b/src/main/java/net/sf/jabref/gui/PreambleEditor.java
index af0bc09..dc1ce00 100644
--- a/src/main/java/net/sf/jabref/gui/PreambleEditor.java
+++ b/src/main/java/net/sf/jabref/gui/PreambleEditor.java
@@ -25,17 +25,17 @@ import net.sf.jabref.gui.fieldeditors.FieldEditor;
import net.sf.jabref.gui.fieldeditors.TextArea;
import net.sf.jabref.gui.keyboard.KeyBinding;
import net.sf.jabref.gui.undo.UndoablePreambleChange;
-import net.sf.jabref.gui.util.PositionWindow;
+import net.sf.jabref.gui.util.WindowLocation;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.model.database.BibDatabase;
import net.sf.jabref.preferences.JabRefPreferences;
class PreambleEditor extends JDialog {
// A reference to the entry this object works on.
- private final BibDatabase base;
+ private final BibDatabase database;
private final BasePanel panel;
- private final FieldEditor ed;
+ private final FieldEditor editor;
private final UndoAction undoAction = new UndoAction();
private final StoreFieldAction storeFieldAction = new StoreFieldAction();
@@ -43,10 +43,10 @@ class PreambleEditor extends JDialog {
// The action concerned with closing the window.
private final CloseAction closeAction = new CloseAction();
- public PreambleEditor(JabRefFrame baseFrame, BasePanel panel, BibDatabase base) {
+ public PreambleEditor(JabRefFrame baseFrame, BasePanel panel, BibDatabase database) {
super(baseFrame);
this.panel = panel;
- this.base = base;
+ this.database = database;
addWindowListener(new WindowAdapter() {
@@ -57,7 +57,7 @@ class PreambleEditor extends JDialog {
@Override
public void windowOpened(WindowEvent e) {
- ed.requestFocus();
+ editor.requestFocus();
}
});
setFocusTraversalPolicy(new LayoutFocusTraversalPolicy() {
@@ -76,27 +76,25 @@ class PreambleEditor extends JDialog {
con.weighty = 1;
con.insets = new Insets(10, 5, 10, 5);
- String content = base.getPreamble();
+ editor = new TextArea(Localization.lang("Preamble"), database.getPreamble().orElse(""));
- ed = new TextArea(Localization.lang("Preamble"), content == null ? "" : content);
+ setupJTextComponent((TextArea) editor);
- setupJTextComponent((TextArea) ed);
-
- gbl.setConstraints(ed.getLabel(), con);
- pan.add(ed.getLabel());
+ gbl.setConstraints(editor.getLabel(), con);
+ pan.add(editor.getLabel());
con.weightx = 1;
- gbl.setConstraints(ed.getPane(), con);
- pan.add(ed.getPane());
+ gbl.setConstraints(editor.getPane(), con);
+ pan.add(editor.getPane());
Container conPane = getContentPane();
conPane.add(pan, BorderLayout.CENTER);
setTitle(Localization.lang("Edit preamble"));
- PositionWindow pw = new PositionWindow(this, JabRefPreferences.PREAMBLE_POS_X, JabRefPreferences.PREAMBLE_POS_Y,
+ WindowLocation pw = new WindowLocation(this, JabRefPreferences.PREAMBLE_POS_X, JabRefPreferences.PREAMBLE_POS_Y,
JabRefPreferences.PREAMBLE_SIZE_X, JabRefPreferences.PREAMBLE_SIZE_Y);
- pw.setWindowPosition();
+ pw.displayWindowAtStoredLocation();
}
private void setupJTextComponent(JTextComponent ta) {
@@ -115,7 +113,7 @@ class PreambleEditor extends JDialog {
}
public void updatePreamble() {
- ed.setText(base.getPreamble());
+ editor.setText(database.getPreamble().orElse(""));
}
@@ -145,32 +143,22 @@ class PreambleEditor extends JDialog {
@Override
public void actionPerformed(ActionEvent e) {
- String toSet = null;
- boolean set;
- if (!ed.getText().isEmpty()) {
- toSet = ed.getText();
- }
+ String toSet = editor.getText();
+
// We check if the field has changed, since we don't want to mark the
// base as changed unless we have a real change.
- if (toSet == null) {
- set = base.getPreamble() != null;
- } else {
- set = !((base.getPreamble() != null)
- && toSet.equals(base.getPreamble()));
- }
-
- if (set) {
- panel.getUndoManager().addEdit(new UndoablePreambleChange
- (base, panel, base.getPreamble(), toSet));
- base.setPreamble(toSet);
+ if (!database.getPreamble().orElse("").equals(toSet)) {
+ panel.getUndoManager().addEdit(
+ new UndoablePreambleChange(database, panel, database.getPreamble().orElse(null), toSet));
+ database.setPreamble(toSet);
if ((toSet == null) || toSet.isEmpty()) {
- ed.setLabelColor(GUIGlobals.NULL_FIELD_COLOR);
+ editor.setLabelColor(GUIGlobals.NULL_FIELD_COLOR);
} else {
- ed.setLabelColor(GUIGlobals.ENTRY_EDITOR_LABEL_COLOR);
+ editor.setLabelColor(GUIGlobals.ENTRY_EDITOR_LABEL_COLOR);
}
- ed.setValidBackgroundColor();
- if (ed.getTextComponent().hasFocus()) {
- ed.setActiveBackgroundColor();
+ editor.setValidBackgroundColor();
+ if (editor.getTextComponent().hasFocus()) {
+ editor.setActiveBackgroundColor();
}
panel.markBaseChanged();
}
@@ -226,7 +214,7 @@ class PreambleEditor extends JDialog {
public FieldEditor getFieldEditor() {
- return ed;
+ return editor;
}
public void storeCurrentEdit() {
diff --git a/src/main/java/net/sf/jabref/gui/PreviewPanel.java b/src/main/java/net/sf/jabref/gui/PreviewPanel.java
index 0615264..97501e0 100644
--- a/src/main/java/net/sf/jabref/gui/PreviewPanel.java
+++ b/src/main/java/net/sf/jabref/gui/PreviewPanel.java
@@ -7,8 +7,6 @@ import java.awt.event.ActionEvent;
import java.awt.print.PrinterException;
import java.io.IOException;
import java.io.StringReader;
-import java.lang.reflect.InvocationTargetException;
-import java.util.Objects;
import java.util.Optional;
import java.util.regex.Pattern;
@@ -20,7 +18,6 @@ import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
-import javax.swing.JEditorPane;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
@@ -29,7 +26,6 @@ import javax.swing.ScrollPaneConstants;
import javax.swing.SwingUtilities;
import javax.swing.event.HyperlinkEvent;
-import net.sf.jabref.BibDatabaseContext;
import net.sf.jabref.Globals;
import net.sf.jabref.JabRefExecutorService;
import net.sf.jabref.gui.desktop.JabRefDesktop;
@@ -38,12 +34,13 @@ import net.sf.jabref.gui.keyboard.KeyBinding;
import net.sf.jabref.logic.exporter.ExportFormats;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.layout.Layout;
-import net.sf.jabref.logic.layout.LayoutFormatterPreferences;
import net.sf.jabref.logic.layout.LayoutHelper;
import net.sf.jabref.logic.search.SearchQueryHighlightListener;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.FieldName;
-import net.sf.jabref.model.event.FieldChangedEvent;
+import net.sf.jabref.model.entry.event.FieldChangedEvent;
+import net.sf.jabref.preferences.PreviewPreferences;
import com.google.common.eventbus.Subscribe;
import org.apache.commons.logging.Log;
@@ -52,8 +49,7 @@ import org.apache.commons.logging.LogFactory;
/**
* Displays an BibEntry using the given layout format.
*/
-public class PreviewPanel extends JPanel
- implements SearchQueryHighlightListener, EntryContainer {
+public class PreviewPanel extends JPanel implements SearchQueryHighlightListener, EntryContainer {
private static final Log LOGGER = LogFactory.getLog(PreviewPanel.class);
@@ -68,24 +64,17 @@ public class PreviewPanel extends JPanel
*/
private Optional<BibDatabaseContext> databaseContext = Optional.empty();
- private Optional<Layout> layout = Optional.empty();
-
- /**
- * must not be null, must always be set during constructor, but can change over time
- */
- private String layoutFile;
-
- private final Optional<BasePanel> basePanel;
+ private Optional<BasePanel> basePanel = Optional.empty();
- private JEditorPane previewPane;
+ private boolean fixedLayout;
+ private Optional<Layout> layout = Optional.empty();
+ private JEditorPaneWithHighlighting previewPane;
private final JScrollPane scrollPane;
- private final PrintAction printAction;
-
- private final CloseAction closeAction;
-
- private final CopyPreviewAction copyPreviewAction;
+ private final PrintAction printAction = new PrintAction();
+ private final CloseAction closeAction = new CloseAction();
+ private final CopyPreviewAction copyPreviewAction = new CopyPreviewAction();
private Optional<Pattern> highlightPattern = Optional.empty();
@@ -98,12 +87,9 @@ public class PreviewPanel extends JPanel
* @param panel
* (may be null) If not given no toolbar is shown on the right
* hand side.
- * @param layoutFile
- * (must be given) Used for layout
*/
- public PreviewPanel(BibDatabaseContext databaseContext, BibEntry entry,
- BasePanel panel, String layoutFile) {
- this(panel, databaseContext, layoutFile);
+ public PreviewPanel(BibDatabaseContext databaseContext, BibEntry entry, BasePanel panel) {
+ this(panel, databaseContext);
setEntry(entry);
}
@@ -114,25 +100,16 @@ public class PreviewPanel extends JPanel
* hand side.
* @param databaseContext
* (may be null) Used for resolving pdf directories for links.
- * @param layoutFile
- * (must be given) Used for layout
*/
- public PreviewPanel(BasePanel panel, BibDatabaseContext databaseContext, String layoutFile) {
+ public PreviewPanel(BasePanel panel, BibDatabaseContext databaseContext) {
super(new BorderLayout(), true);
this.databaseContext = Optional.ofNullable(databaseContext);
- this.layoutFile = Objects.requireNonNull(layoutFile);
- updateLayout();
-
- this.closeAction = new CloseAction();
- this.printAction = new PrintAction();
- this.copyPreviewAction = new CopyPreviewAction();
-
this.basePanel = Optional.ofNullable(panel);
createPreviewPane();
- if (panel != null) {
+ if (this.basePanel.isPresent()) {
// dropped files handler only created for main window
// not for Windows as like the search results window
this.previewPane.setTransferHandler(new PreviewPanelTransferHandler(panel.frame(), this, this.previewPane.getTransferHandler()));
@@ -144,10 +121,10 @@ public class PreviewPanel extends JPanel
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
scrollPane.setBorder(null);
-
add(scrollPane, BorderLayout.CENTER);
this.createKeyBindings();
+ updateLayout();
}
private void createKeyBindings(){
@@ -167,12 +144,13 @@ public class PreviewPanel extends JPanel
JPopupMenu menu = new JPopupMenu();
menu.add(this.printAction);
menu.add(this.copyPreviewAction);
- this.basePanel.ifPresent(p -> menu.add(p.frame().getSwitchPreviewAction()));
+ this.basePanel.ifPresent(p -> menu.add(p.frame().getNextPreviewStyleAction()));
+ this.basePanel.ifPresent(p -> menu.add(p.frame().getPreviousPreviewStyleAction()));
return menu;
}
private void createPreviewPane() {
- previewPane = new JEditorPane() {
+ previewPane = new JEditorPaneWithHighlighting() {
@Override
public Dimension getPreferredScrollableViewportSize() {
return getPreferredSize();
@@ -204,17 +182,37 @@ public class PreviewPanel extends JPanel
this.databaseContext = Optional.ofNullable(databaseContext);
}
- public void updateLayout(String layoutFormat) {
- layoutFile = layoutFormat;
- updateLayout();
+ public Optional<BasePanel> getBasePanel() {
+ return this.basePanel;
+ }
+
+ public void setBasePanel(BasePanel basePanel) {
+ this.basePanel = Optional.ofNullable(basePanel);
+ }
+
+ public void updateLayout() {
+ if (fixedLayout) {
+ LOGGER.debug("cannot change the layout because the layout is fixed");
+ return;
+ }
+
+ PreviewPreferences previewPreferences = Globals.prefs.getPreviewPreferences();
+ String style = previewPreferences.getPreviewCycle().get(previewPreferences.getPreviewCyclePosition());
+
+ updatePreviewLayout(previewPreferences.getPreviewStyle());
+ if (basePanel.isPresent()) {
+ basePanel.get().output(Localization.lang("Preview style changed to: %0", Localization.lang("Preview")));
+ }
+
+ update();
}
- private void updateLayout() {
+ private void updatePreviewLayout(String layoutFile){
StringReader sr = new StringReader(layoutFile.replace("__NEWLINE__", "\n"));
try {
- layout = Optional
- .of(new LayoutHelper(sr, LayoutFormatterPreferences.fromPreferences(Globals.prefs,
- Globals.journalAbbreviationLoader)).getLayoutFromText());
+ layout = Optional.of(
+ new LayoutHelper(sr, Globals.prefs.getLayoutFormatterPreferences(Globals.journalAbbreviationLoader))
+ .getLayoutFromText());
} catch (IOException e) {
layout = Optional.empty();
LOGGER.debug("no layout could be set", e);
@@ -231,7 +229,6 @@ public class PreviewPanel extends JPanel
bibEntry = Optional.ofNullable(newEntry);
bibEntry.ifPresent(e -> e.registerListener(this));
- updateLayout();
update();
}
@@ -251,30 +248,33 @@ public class PreviewPanel extends JPanel
}
public void update() {
- StringBuilder sb = new StringBuilder();
ExportFormats.entryNumber = 1; // Set entry number in case that is included in the preview layout.
- bibEntry.ifPresent(entry ->
- layout.ifPresent(acutalLayout -> sb.append(acutalLayout
- .doLayout(entry, databaseContext.map(BibDatabaseContext::getDatabase).orElse(null),
- highlightPattern)))
- );
- String newValue = sb.toString();
+ if (layout.isPresent()){
+ StringBuilder sb = new StringBuilder();
+ bibEntry.ifPresent(entry -> sb.append(layout.get()
+ .doLayout(entry, databaseContext.map(BibDatabaseContext::getDatabase).orElse(null))));
+ setPreviewLabel(sb.toString());
+ markHighlights();
+ }
+
+ }
+
+ public void markHighlights() {
+ previewPane.highlightPattern(highlightPattern);
+ }
+
+ public void setPreviewLabel(String text) {
if (SwingUtilities.isEventDispatchThread()) {
- previewPane.setText(newValue);
+ previewPane.setText(text);
previewPane.revalidate();
} else {
- try {
- SwingUtilities.invokeAndWait(() -> {
- previewPane.setText(newValue);
- previewPane.revalidate();
- });
- } catch (InvocationTargetException | InterruptedException e) {
- LOGGER.info("Problem setting preview text", e);
- }
+ SwingUtilities.invokeLater(() -> {
+ previewPane.setText(text);
+ previewPane.revalidate();
+ });
}
- // Scroll to top:
- scrollToTop();
+ this.scrollToTop();
}
private void scrollToTop() {
@@ -287,6 +287,25 @@ public class PreviewPanel extends JPanel
update();
}
+ public Optional<Pattern> getHighlightPattern() {
+ return highlightPattern;
+ }
+
+ /**
+ * this fixes the Layout, the user cannot change it anymore. Useful for testing the styles in the settings
+ */
+ public PreviewPanel setFixedLayout(String parameter) {
+ this.fixedLayout = true;
+
+ if (parameter instanceof String) {
+ updatePreviewLayout((String) parameter);
+ } else {
+ LOGGER.error("unknown style type");
+ }
+ update();
+ return this;
+ }
+
class PrintAction extends AbstractAction {
public PrintAction() {
super(Localization.lang("Print entry preview"), IconTheme.JabRefIcon.PRINTED.getIcon());
@@ -314,7 +333,10 @@ public class PreviewPanel extends JPanel
}
});
}
+ }
+ public void close() {
+ basePanel.ifPresent(BasePanel::hideBottomComponent);
}
class CloseAction extends AbstractAction {
@@ -323,12 +345,11 @@ public class PreviewPanel extends JPanel
super(Localization.lang("Close window"), IconTheme.JabRefIcon.CLOSE.getSmallIcon());
putValue(Action.SHORT_DESCRIPTION, Localization.lang("Close window"));
}
+
@Override
public void actionPerformed(ActionEvent e) {
- basePanel.ifPresent(BasePanel::hideBottomComponent);
+ close();
}
-
-
}
class CopyPreviewAction extends AbstractAction {
diff --git a/src/main/java/net/sf/jabref/gui/ReplaceStringDialog.java b/src/main/java/net/sf/jabref/gui/ReplaceStringDialog.java
index f1a670d..94ca5c0 100644
--- a/src/main/java/net/sf/jabref/gui/ReplaceStringDialog.java
+++ b/src/main/java/net/sf/jabref/gui/ReplaceStringDialog.java
@@ -207,7 +207,7 @@ class ReplaceStringDialog extends JDialog {
if (!be.hasField(fieldname)) {
return 0;
}
- String txt = be.getFieldOptional(fieldname).get();
+ String txt = be.getField(fieldname).get();
StringBuilder sb = new StringBuilder();
int ind;
int piv = 0;
diff --git a/src/main/java/net/sf/jabref/gui/SaveOrderConfigDisplay.java b/src/main/java/net/sf/jabref/gui/SaveOrderConfigDisplay.java
index 09d77c4..d7122fe 100644
--- a/src/main/java/net/sf/jabref/gui/SaveOrderConfigDisplay.java
+++ b/src/main/java/net/sf/jabref/gui/SaveOrderConfigDisplay.java
@@ -9,10 +9,10 @@ import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JPanel;
-import net.sf.jabref.logic.config.SaveOrderConfig;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.InternalBibtexFields;
+import net.sf.jabref.model.metadata.SaveOrderConfig;
import com.jgoodies.forms.builder.FormBuilder;
import com.jgoodies.forms.layout.FormLayout;
diff --git a/src/main/java/net/sf/jabref/gui/SidePane.java b/src/main/java/net/sf/jabref/gui/SidePane.java
index e60c219..69b9d1b 100644
--- a/src/main/java/net/sf/jabref/gui/SidePane.java
+++ b/src/main/java/net/sf/jabref/gui/SidePane.java
@@ -11,6 +11,7 @@ import java.util.Collection;
import javax.swing.Box;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
+import javax.swing.ScrollPaneConstants;
/**
* The side pane is displayed at the left side of JabRef and shows instances of
@@ -43,10 +44,10 @@ public class SidePane extends JPanel {
constraint.weightx = 1;
/*
- * Added Scrollpane to fix:
+ * Added Scrollpane to fix:
*/
- JScrollPane sp = new JScrollPane(mainPanel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
- JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
+ JScrollPane sp = new JScrollPane(mainPanel, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
+ ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
sp.setBorder(null);
// To remove the scroll panel just change sp to mainPanel and comment
diff --git a/src/main/java/net/sf/jabref/gui/SidePaneComponent.java b/src/main/java/net/sf/jabref/gui/SidePaneComponent.java
index 3ed6190..97bebba 100644
--- a/src/main/java/net/sf/jabref/gui/SidePaneComponent.java
+++ b/src/main/java/net/sf/jabref/gui/SidePaneComponent.java
@@ -3,12 +3,18 @@ package net.sf.jabref.gui;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.InputEvent;
+import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JToolBar;
+import javax.swing.KeyStroke;
+
+import net.sf.jabref.gui.actions.MnemonicAwareAction;
import org.jdesktop.swingx.JXTitledPanel;
import org.jdesktop.swingx.painter.MattePainter;
@@ -17,7 +23,7 @@ public abstract class SidePaneComponent extends JXTitledPanel {
protected final JButton close = new JButton(IconTheme.JabRefIcon.CLOSE.getSmallIcon());
- private final SidePaneManager manager;
+ protected final SidePaneManager manager;
protected BasePanel panel;
@@ -100,4 +106,52 @@ public abstract class SidePaneComponent extends JXTitledPanel {
* 0: fixed height, 1: fill the remaining space
*/
public abstract int getRescalingWeight();
+
+ /**
+ * @return the action which toggles this {@link SidePaneComponent}
+ */
+ public abstract ToggleAction getToggleAction();
+
+
+ public class ToggleAction extends MnemonicAwareAction {
+
+ public ToggleAction(String text, String description, KeyStroke key, IconTheme.JabRefIcon icon){
+ super(icon.getIcon());
+ putValue(Action.NAME, text);
+ putValue(Action.ACCELERATOR_KEY, key);
+ putValue(Action.SHORT_DESCRIPTION, description);
+ }
+
+ public ToggleAction(String text, String description, KeyStroke key, Icon icon){
+ super(icon);
+ putValue(Action.NAME, text);
+ putValue(Action.ACCELERATOR_KEY, key);
+ putValue(Action.SHORT_DESCRIPTION, description);
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (!manager.hasComponent(SidePaneComponent.this.getClass())) {
+ manager.register(SidePaneComponent.this);
+ }
+
+ // if clicked by mouse just toggle
+ if ((e.getModifiers() & InputEvent.BUTTON1_MASK) != 0) {
+ manager.toggle(SidePaneComponent.this.getClass());
+ } else {
+ manager.toggleThreeWay(SidePaneComponent.this.getClass());
+ }
+ putValue(Action.SELECTED_KEY, manager.isComponentVisible(SidePaneComponent.this.getClass()));
+ }
+
+ public void setSelected(boolean selected){
+ putValue(Action.SELECTED_KEY, selected);
+ }
+
+ public boolean isSelected() {
+ return Boolean.TRUE.equals(getValue(Action.SELECTED_KEY));
+ }
+
+ }
+
}
diff --git a/src/main/java/net/sf/jabref/gui/SidePaneManager.java b/src/main/java/net/sf/jabref/gui/SidePaneManager.java
index 7e3febe..3070543 100644
--- a/src/main/java/net/sf/jabref/gui/SidePaneManager.java
+++ b/src/main/java/net/sf/jabref/gui/SidePaneManager.java
@@ -1,6 +1,5 @@
package net.sf.jabref.gui;
-import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
@@ -24,19 +23,16 @@ import org.apache.commons.logging.LogFactory;
* sidePane.
*/
public class SidePaneManager {
-
private static final Log LOGGER = LogFactory.getLog(SidePaneManager.class);
private final JabRefFrame frame;
private final SidePane sidep;
- private final Map<String, SidePaneComponent> components = new LinkedHashMap<>();
- private final Map<SidePaneComponent, String> componentNames = new HashMap<>();
+ private final Map<Class<? extends SidePaneComponent>, SidePaneComponent> components = new LinkedHashMap<>();
private final List<SidePaneComponent> visible = new LinkedList<>();
-
public SidePaneManager(JabRefFrame frame) {
this.frame = frame;
/*
@@ -54,42 +50,59 @@ public class SidePaneManager {
return sidep;
}
- public synchronized boolean hasComponent(String name) {
- return components.containsKey(name);
+ public synchronized <T extends SidePaneComponent> boolean hasComponent(Class<T> sidePaneComponent) {
+ return components.containsKey(sidePaneComponent);
}
- public synchronized boolean isComponentVisible(String name) {
- SidePaneComponent sidePaneComponent = components.get(name);
- if (sidePaneComponent == null) {
+ public synchronized <T extends SidePaneComponent> boolean isComponentVisible(Class<T> sidePaneComponent) {
+ SidePaneComponent component = components.get(sidePaneComponent);
+ if (component == null) {
return false;
} else {
- return visible.contains(sidePaneComponent);
+ return visible.contains(component);
}
}
- public synchronized void toggle(String name) {
- if (isComponentVisible(name)) {
- hide(name);
+ /**
+ * If panel is visible it will be hidden and the other way around
+ */
+ public synchronized <T extends SidePaneComponent> void toggle(Class<T> sidePaneComponent) {
+ if (isComponentVisible(sidePaneComponent)) {
+ hide(sidePaneComponent);
} else {
- show(name);
+ show(sidePaneComponent);
}
}
- public synchronized void show(String name) {
- SidePaneComponent sidePaneComponent = components.get(name);
- if (sidePaneComponent == null) {
- LOGGER.warn("Side pane component '" + name + "' unknown.");
+ /**
+ * If panel is hidden it will be shown and focused
+ * If panel is visible but not focused it will be focused
+ * If panel is visible and focused it will be hidden
+ */
+ public synchronized <T extends SidePaneComponent> void toggleThreeWay(Class<T> sidePaneComponent) {
+ boolean isPanelFocused = Globals.getFocusListener().getFocused() == components.get(sidePaneComponent);
+ if (isComponentVisible(sidePaneComponent) && isPanelFocused) {
+ hide(sidePaneComponent);
} else {
show(sidePaneComponent);
}
}
- public synchronized void hide(String name) {
- SidePaneComponent sidePaneComponent = components.get(name);
- if (sidePaneComponent == null) {
- LOGGER.warn("Side pane component '" + name + "' unknown.");
+ public synchronized <T extends SidePaneComponent> void show(Class<T> sidePaneComponent) {
+ SidePaneComponent component = components.get(sidePaneComponent);
+ if (component == null) {
+ LOGGER.warn("Side pane component '" + sidePaneComponent + "' unknown.");
+ } else {
+ show(component);
+ }
+ }
+
+ public synchronized <T extends SidePaneComponent> void hide(Class<T> sidePaneComponent) {
+ SidePaneComponent component = components.get(sidePaneComponent);
+ if (component == null) {
+ LOGGER.warn("Side pane component '" + sidePaneComponent + "' unknown.");
} else {
- hideComponent(sidePaneComponent);
+ hideComponent(component);
if (frame.getCurrentBasePanel() != null) {
MainTable mainTable = frame.getCurrentBasePanel().getMainTable();
mainTable.setSelected(mainTable.getSelectedRow());
@@ -98,9 +111,8 @@ public class SidePaneManager {
}
}
- public synchronized void register(String name, SidePaneComponent comp) {
- components.put(name, comp);
- componentNames.put(comp, name);
+ public synchronized void register(SidePaneComponent comp) {
+ components.put(comp.getClass(), comp);
}
private synchronized void show(SidePaneComponent component) {
@@ -114,14 +126,12 @@ public class SidePaneManager {
updateView();
component.componentOpening();
}
+ Globals.getFocusListener().setFocused(component);
+ component.grabFocus();
}
- public synchronized SidePaneComponent getComponent(String name) {
- return components.get(name);
- }
-
- private synchronized String getComponentName(SidePaneComponent comp) {
- return componentNames.get(comp);
+ public synchronized <T extends SidePaneComponent> SidePaneComponent getComponent(Class<T> sidePaneComponent) {
+ return components.get(sidePaneComponent);
}
public synchronized void hideComponent(SidePaneComponent comp) {
@@ -132,30 +142,36 @@ public class SidePaneManager {
}
}
- public synchronized void hideComponent(String name) {
- SidePaneComponent comp = components.get(name);
- if (comp == null) {
+ public synchronized <T extends SidePaneComponent> void hideComponent(Class<T> sidePaneComponent) {
+ SidePaneComponent component = components.get(sidePaneComponent);
+ if (component == null) {
return;
}
- if (visible.contains(comp)) {
- comp.componentClosing();
- visible.remove(comp);
+ if (visible.contains(component)) {
+ component.componentClosing();
+ visible.remove(component);
updateView();
}
}
- private static Map<String, Integer> getPreferredPositions() {
- Map<String, Integer> preferredPositions = new HashMap<>();
+ private static Map<Class<? extends SidePaneComponent>, Integer> getPreferredPositions() {
+ Map<Class<? extends SidePaneComponent>, Integer> preferredPositions = new HashMap<>();
List<String> componentNames = Globals.prefs.getStringList(JabRefPreferences.SIDE_PANE_COMPONENT_NAMES);
List<String> componentPositions = Globals.prefs
.getStringList(JabRefPreferences.SIDE_PANE_COMPONENT_PREFERRED_POSITIONS);
for (int i = 0; i < componentNames.size(); ++i) {
+ String componentName = componentNames.get(i);
try {
- preferredPositions.put(componentNames.get(i), Integer.parseInt(componentPositions.get(i)));
+ Class<? extends SidePaneComponent> componentClass = (Class<? extends SidePaneComponent>) Class.forName(componentName);
+ preferredPositions.put(componentClass, Integer.parseInt(componentPositions.get(i)));
+ } catch (ClassNotFoundException e) {
+ LOGGER.error("Following side pane could not be found: " + componentName, e);
+ } catch (ClassCastException e) {
+ LOGGER.error("Following Class is no side pane: '" + componentName, e);
} catch (NumberFormatException e) {
- LOGGER.info("Invalid number format for side pane component '" + componentNames.get(i) + "'.", e);
+ LOGGER.info("Invalid number format for side pane component '" + componentName + "'.", e);
}
}
@@ -163,18 +179,20 @@ public class SidePaneManager {
}
private void updatePreferredPositions() {
- Map<String, Integer> preferredPositions = getPreferredPositions();
+ Map<Class<? extends SidePaneComponent>, Integer> preferredPositions = getPreferredPositions();
// Update the preferred positions of all visible components
int index = 0;
for (SidePaneComponent comp : visible) {
- String componentName = getComponentName(comp);
- preferredPositions.put(componentName, index);
+ preferredPositions.put(comp.getClass(), index);
index++;
}
// Split the map into a pair of parallel String lists suitable for storage
- List<String> tmpComponentNames = new ArrayList<>(preferredPositions.keySet());
+ List<String> tmpComponentNames = preferredPositions.keySet().parallelStream()
+ .map(Class::getName)
+ .collect(Collectors.toList());
+
List<String> componentPositions = preferredPositions.values().stream().map(Object::toString)
.collect(Collectors.toList());
@@ -183,10 +201,12 @@ public class SidePaneManager {
}
- // Helper class for sorting visible components based on their preferred position
+ /**
+ * Helper class for sorting visible components based on their preferred position
+ */
private class PreferredIndexSort implements Comparator<SidePaneComponent> {
- private final Map<String, Integer> preferredPositions;
+ private final Map<Class<? extends SidePaneComponent>, Integer> preferredPositions;
public PreferredIndexSort() {
@@ -195,8 +215,8 @@ public class SidePaneManager {
@Override
public int compare(SidePaneComponent comp1, SidePaneComponent comp2) {
- int pos1 = preferredPositions.getOrDefault(getComponentName(comp1), 0);
- int pos2 = preferredPositions.getOrDefault(getComponentName(comp2), 0);
+ int pos1 = preferredPositions.getOrDefault(comp1.getClass(), 0);
+ int pos2 = preferredPositions.getOrDefault(comp2.getClass(), 0);
return Integer.valueOf(pos1).compareTo(pos2);
}
}
@@ -230,9 +250,8 @@ public class SidePaneManager {
}
}
- public synchronized void unregisterComponent(String name) {
- componentNames.remove(components.get(name));
- components.remove(name);
+ public synchronized <T extends SidePaneComponent> void unregisterComponent(Class<T> sidePaneComponent) {
+ components.remove(sidePaneComponent);
}
/**
@@ -241,10 +260,9 @@ public class SidePaneManager {
*
* @param panel
*/
-
private synchronized void setActiveBasePanel(BasePanel panel) {
- for (Map.Entry<String, SidePaneComponent> stringSidePaneComponentEntry : components.entrySet()) {
- stringSidePaneComponentEntry.getValue().setActiveBasePanel(panel);
+ for (SidePaneComponent component : components.values()) {
+ component.setActiveBasePanel(panel);
}
}
diff --git a/src/main/java/net/sf/jabref/gui/StringDialog.java b/src/main/java/net/sf/jabref/gui/StringDialog.java
index 60a17f3..ab3e32b 100644
--- a/src/main/java/net/sf/jabref/gui/StringDialog.java
+++ b/src/main/java/net/sf/jabref/gui/StringDialog.java
@@ -8,6 +8,7 @@ import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
+import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -37,10 +38,8 @@ import net.sf.jabref.gui.keyboard.KeyBinding;
import net.sf.jabref.gui.undo.UndoableInsertString;
import net.sf.jabref.gui.undo.UndoableRemoveString;
import net.sf.jabref.gui.undo.UndoableStringChange;
-import net.sf.jabref.gui.util.GUIUtil;
-import net.sf.jabref.gui.util.PositionWindow;
+import net.sf.jabref.gui.util.WindowLocation;
import net.sf.jabref.logic.bibtex.LatexFieldFormatter;
-import net.sf.jabref.logic.bibtex.LatexFieldFormatterPreferences;
import net.sf.jabref.logic.bibtex.comparator.BibtexStringComparator;
import net.sf.jabref.logic.help.HelpFile;
import net.sf.jabref.logic.l10n.Localization;
@@ -108,7 +107,6 @@ class StringDialog extends JDialog {
if (!base.hasNoStrings()) {
table.setRowSelectionInterval(0, 0);
}
- GUIUtil.correctRowHeight(table);
gbl.setConstraints(table.getPane(), con);
pan.add(table.getPane());
@@ -143,17 +141,13 @@ class StringDialog extends JDialog {
conPane.add(tlb, BorderLayout.NORTH);
conPane.add(pan, BorderLayout.CENTER);
- if (panel.getBibDatabaseContext().getDatabaseFile() == null) {
- setTitle(STRINGS_TITLE + ": " + GUIGlobals.UNTITLED_TITLE);
- } else {
- setTitle(STRINGS_TITLE + ": " + panel.getBibDatabaseContext().getDatabaseFile().getName());
- }
- PositionWindow pw = new PositionWindow(this, JabRefPreferences.STRINGS_POS_X, JabRefPreferences.STRINGS_POS_Y,
+ setTitle(STRINGS_TITLE + ": "
+ + panel.getBibDatabaseContext().getDatabaseFile().map(File::getName).orElse(GUIGlobals.UNTITLED_TITLE));
+ WindowLocation pw = new WindowLocation(this, JabRefPreferences.STRINGS_POS_X, JabRefPreferences.STRINGS_POS_Y,
JabRefPreferences.STRINGS_SIZE_X, JabRefPreferences.STRINGS_SIZE_Y);
- pw.setWindowPosition();
+ pw.displayWindowAtStoredLocation();
}
-
class StringTable extends JTable {
private final JScrollPane sp = new JScrollPane(this);
@@ -254,7 +248,7 @@ class StringDialog extends JDialog {
if (!value.equals(subject.getContent())) {
try {
- new LatexFieldFormatter(LatexFieldFormatterPreferences.fromPreferences(Globals.prefs))
+ new LatexFieldFormatter(Globals.prefs.getLatexFieldFormatterPreferences())
.format((String) value, "__dummy");
} catch (IllegalArgumentException ex) {
return;
diff --git a/src/main/java/net/sf/jabref/gui/TransferableBibtexEntry.java b/src/main/java/net/sf/jabref/gui/TransferableBibtexEntry.java
index 9ac2696..906d5db 100644
--- a/src/main/java/net/sf/jabref/gui/TransferableBibtexEntry.java
+++ b/src/main/java/net/sf/jabref/gui/TransferableBibtexEntry.java
@@ -12,7 +12,6 @@ import javax.swing.JOptionPane;
import net.sf.jabref.Globals;
import net.sf.jabref.logic.bibtex.BibEntryWriter;
import net.sf.jabref.logic.bibtex.LatexFieldFormatter;
-import net.sf.jabref.logic.bibtex.LatexFieldFormatterPreferences;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.model.database.BibDatabaseMode;
import net.sf.jabref.model.entry.BibEntry;
@@ -51,7 +50,7 @@ public class TransferableBibtexEntry implements Transferable {
try {
StringWriter sw = new StringWriter();
BibEntryWriter bibtexEntryWriter = new BibEntryWriter(
- new LatexFieldFormatter(LatexFieldFormatterPreferences.fromPreferences(Globals.prefs)), false);
+ new LatexFieldFormatter(Globals.prefs.getLatexFieldFormatterPreferences()), false);
for (BibEntry entry : data) {
bibtexEntryWriter.write(entry, sw, BibDatabaseMode.BIBTEX);
}
diff --git a/src/main/java/net/sf/jabref/gui/actions/Actions.java b/src/main/java/net/sf/jabref/gui/actions/Actions.java
index 74e8ece..d518a2a 100644
--- a/src/main/java/net/sf/jabref/gui/actions/Actions.java
+++ b/src/main/java/net/sf/jabref/gui/actions/Actions.java
@@ -16,8 +16,8 @@ public class Actions {
public static final String COPY_KEY = "copyKey";
public static final String COPY_CITE_KEY = "copyCiteKey";
public static final String COPY_KEY_AND_TITLE = "copyKeyAndTitle";
+ public static final String COPY_KEY_AND_LINK = "copyKeyAndLink";
public static final String CUT = "cut";
- public static final String DB_CONNECT = "dbConnect";
public static final String DELETE = "delete";
public static final String DOWNLOAD_FULL_TEXT = "downloadFullText";
public static final String DUPLI_CHECK = "dupliCheck";
@@ -28,11 +28,11 @@ public class Actions {
public static final String FOCUS_TABLE = "focusTable";
public static final String FORWARD = "forward";
public static final String MAKE_KEY = "makeKey";
- public static final String MANAGE_SELECTORS = "manageSelectors";
public static final String MARK_ENTRIES = "markEntries";
public static final String MERGE_DATABASE = "mergeDatabase";
public static final String MERGE_ENTRIES = "mergeEntries";
public static final String MERGE_WITH_FETCHED_ENTRY = "mergeWithFetchedEntry";
+ public static final String NEXT_PREVIEW_STYLE = "nextPreviewStyle";
public static final String MOVE_TO_GROUP = "moveToGroup";
public static final String OPEN_CONSOLE = "openConsole";
public static final String OPEN_EXTERNAL_FILE = "openExternalFile";
@@ -40,6 +40,7 @@ public class Actions {
public static final String OPEN_URL = "openUrl";
public static final String PASTE = "paste";
public static final String PLAIN_TEXT_IMPORT = "plainTextImport";
+ public static final String PREVIOUS_PREVIEW_STYLE = "previousPreviewStyle";
public static final String PULL_CHANGES_FROM_SHARED_DATABASE = "pullChangesFromSharedDatabase";
public static final String REDO = "redo";
public static final String REMOVE_FROM_GROUP = "removeFromGroup";
@@ -50,15 +51,14 @@ public class Actions {
public static final String SAVE_SELECTED_AS = "saveSelectedAs";
public static final String SAVE_SELECTED_AS_PLAIN = "saveSelectedAsPlain";
public static final String SEARCH = "search";
+ public static final String GLOBAL_SEARCH = "globalSearch";
public static final String SELECT_ALL = "selectAll";
public static final String SEND_AS_EMAIL = "sendAsEmail";
- public static final String SWITCH_PREVIEW = "switchPreview";
public static final String TOGGLE_HIGHLIGHTS_GROUPS_MATCHING_ALL = "toggleHighlightGroupsMatchingAll";
public static final String TOGGLE_HIGHLIGHTS_GROUPS_MATCHING_ANY = "toggleHighlightGroupsMatchingAny";
public static final String TOGGLE_HIGHLIGHTS_GROUPS_MATCHING_DISABLE = "toggleHighlightGroupsMatchingDisable";
public static final String TOGGLE_GROUPS = "toggleGroups";
public static final String TOGGLE_PREVIEW = "togglePreview";
- public static final String TOGGLE_TOOLBAR = "toggleToolbar";
public static final String UNABBREVIATE = "unabbreviate";
public static final String UNDO = "undo";
public static final String UNMARK_ALL = "unmarkAll";
diff --git a/src/main/java/net/sf/jabref/gui/actions/AutoLinkFilesAction.java b/src/main/java/net/sf/jabref/gui/actions/AutoLinkFilesAction.java
index 8a02031..ee3d7a4 100644
--- a/src/main/java/net/sf/jabref/gui/actions/AutoLinkFilesAction.java
+++ b/src/main/java/net/sf/jabref/gui/actions/AutoLinkFilesAction.java
@@ -10,8 +10,8 @@ import javax.swing.JDialog;
import net.sf.jabref.Globals;
import net.sf.jabref.JabRefExecutorService;
import net.sf.jabref.JabRefGUI;
-import net.sf.jabref.external.AutoSetLinks;
import net.sf.jabref.gui.IconTheme;
+import net.sf.jabref.gui.externalfiles.AutoSetLinks;
import net.sf.jabref.gui.keyboard.KeyBinding;
import net.sf.jabref.gui.undo.NamedCompound;
import net.sf.jabref.logic.l10n.Localization;
diff --git a/src/main/java/net/sf/jabref/gui/actions/BaseAction.java b/src/main/java/net/sf/jabref/gui/actions/BaseAction.java
index d42feda..6887bcd 100644
--- a/src/main/java/net/sf/jabref/gui/actions/BaseAction.java
+++ b/src/main/java/net/sf/jabref/gui/actions/BaseAction.java
@@ -8,5 +8,5 @@ package net.sf.jabref.gui.actions;
@FunctionalInterface
public interface BaseAction {
- void action() throws Throwable;
+ void action() throws Exception;
}
diff --git a/src/main/java/net/sf/jabref/gui/actions/CleanupAction.java b/src/main/java/net/sf/jabref/gui/actions/CleanupAction.java
index 80d2cad..50ba23c 100644
--- a/src/main/java/net/sf/jabref/gui/actions/CleanupAction.java
+++ b/src/main/java/net/sf/jabref/gui/actions/CleanupAction.java
@@ -5,7 +5,6 @@ import java.util.Objects;
import javax.swing.JOptionPane;
-import net.sf.jabref.BibDatabaseContext;
import net.sf.jabref.Globals;
import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.gui.JabRefFrame;
@@ -17,7 +16,6 @@ import net.sf.jabref.gui.worker.AbstractWorker;
import net.sf.jabref.logic.cleanup.CleanupPreset;
import net.sf.jabref.logic.cleanup.CleanupWorker;
import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.logic.layout.LayoutFormatterPreferences;
import net.sf.jabref.model.FieldChange;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.preferences.JabRefPreferences;
@@ -146,10 +144,8 @@ public class CleanupAction extends AbstractWorker {
*/
private void doCleanup(CleanupPreset preset, BibEntry entry, NamedCompound ce) {
// Create and run cleaner
- BibDatabaseContext bibDatabaseContext = panel.getBibDatabaseContext();
- CleanupWorker cleaner = new CleanupWorker(bibDatabaseContext,
- Globals.prefs.get(JabRefPreferences.IMPORT_FILENAMEPATTERN),
- LayoutFormatterPreferences.fromPreferences(Globals.prefs, Globals.journalAbbreviationLoader));
+ CleanupWorker cleaner = new CleanupWorker(panel.getBibDatabaseContext(), preferences.getCleanupPreferences(
+ Globals.journalAbbreviationLoader));
List<FieldChange> changes = cleaner.cleanup(preset, entry);
unsuccessfulRenames = cleaner.getUnsuccessfulRenames();
@@ -163,4 +159,5 @@ public class CleanupAction extends AbstractWorker {
ce.addEdit(new UndoableFieldChange(change));
}
}
+
}
diff --git a/src/main/java/net/sf/jabref/gui/actions/ConnectToSharedDatabaseAction.java b/src/main/java/net/sf/jabref/gui/actions/ConnectToSharedDatabaseAction.java
new file mode 100644
index 0000000..9dce269
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/actions/ConnectToSharedDatabaseAction.java
@@ -0,0 +1,31 @@
+package net.sf.jabref.gui.actions;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.Action;
+
+import net.sf.jabref.gui.JabRefFrame;
+import net.sf.jabref.gui.shared.ConnectToSharedDatabaseDialog;
+import net.sf.jabref.logic.l10n.Localization;
+
+/**
+ * The action concerned with opening a shared database.
+ */
+public class ConnectToSharedDatabaseAction extends MnemonicAwareAction {
+
+ private final JabRefFrame jabRefFrame;
+
+
+ public ConnectToSharedDatabaseAction(JabRefFrame jabRefFrame) {
+ super();
+ this.jabRefFrame = jabRefFrame;
+ putValue(Action.NAME, Localization.menuTitle("Connect to shared database"));
+ putValue(Action.SHORT_DESCRIPTION, Localization.lang("Connect to shared database"));
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ ConnectToSharedDatabaseDialog connectToSharedDatabaseDialog = new ConnectToSharedDatabaseDialog(jabRefFrame);
+ connectToSharedDatabaseDialog.setVisible(true);
+ }
+}
diff --git a/src/main/java/net/sf/jabref/gui/actions/CopyBibTeXKeyAndLinkAction.java b/src/main/java/net/sf/jabref/gui/actions/CopyBibTeXKeyAndLinkAction.java
new file mode 100644
index 0000000..ebd8a37
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/actions/CopyBibTeXKeyAndLinkAction.java
@@ -0,0 +1,61 @@
+package net.sf.jabref.gui.actions;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import net.sf.jabref.JabRefGUI;
+import net.sf.jabref.gui.ClipBoardManager;
+import net.sf.jabref.gui.maintable.MainTable;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.logic.util.OS;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldName;
+
+/**
+ * This class will copy each selected entry's BibTeX key as a hyperlink to its url to the clipboard.
+ * In case an entry doesn't have a BibTeX key it will not be copied.
+ * In case an entry doesn't have an url this will only copy the BibTeX key.
+ */
+public class CopyBibTeXKeyAndLinkAction implements BaseAction {
+
+ private final MainTable mainTable;
+
+ public CopyBibTeXKeyAndLinkAction(MainTable mainTable) {
+ this.mainTable = mainTable;
+ }
+
+ @Override
+ public void action() throws Exception {
+ List<BibEntry> entries = mainTable.getSelectedEntries();
+ if (!entries.isEmpty()) {
+ StringBuilder sb = new StringBuilder();
+
+ List<BibEntry> entriesWithKey = entries.stream().filter(BibEntry::hasCiteKey).collect(Collectors.toList());
+
+ if (entriesWithKey.isEmpty()) {
+ JabRefGUI.getMainFrame().output(Localization.lang("None of the selected entries have BibTeX keys."));
+ return;
+ }
+
+ for (BibEntry entry : entriesWithKey) {
+ String key = entry.getCiteKeyOptional().get();
+ String url = entry.getField(FieldName.URL).orElse("");
+ sb.append(url.isEmpty() ? key : String.format("<a href=\"%s\">%s</a>", url, key));
+ sb.append(OS.NEWLINE);
+ }
+
+ ClipBoardManager clipboard = new ClipBoardManager();
+ clipboard.setClipboardContents(sb.toString());
+
+ int copied = entriesWithKey.size();
+ int toCopy = entries.size();
+ if (copied == toCopy) {
+ // All entries had keys.
+ JabRefGUI.getMainFrame().output((entries.size() > 1 ? Localization.lang("Copied keys") : Localization.lang("Copied key")) + '.');
+ } else {
+ JabRefGUI.getMainFrame().output(Localization.lang("Warning: %0 out of %1 entries have undefined BibTeX key.",
+ Long.toString(toCopy - copied), Integer.toString(toCopy)));
+ }
+ }
+ }
+}
diff --git a/src/main/java/net/sf/jabref/gui/actions/CopyDoiUrlAction.java b/src/main/java/net/sf/jabref/gui/actions/CopyDoiUrlAction.java
new file mode 100644
index 0000000..b314778
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/actions/CopyDoiUrlAction.java
@@ -0,0 +1,45 @@
+package net.sf.jabref.gui.actions;
+
+import java.awt.event.ActionEvent;
+import java.util.Optional;
+
+import javax.swing.AbstractAction;
+import javax.swing.text.JTextComponent;
+
+import net.sf.jabref.JabRefGUI;
+import net.sf.jabref.gui.ClipBoardManager;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.logic.util.DOI;
+
+/**
+ * Copies the doi url to the clipboard
+ */
+public class CopyDoiUrlAction extends AbstractAction {
+
+ private JTextComponent component = null;
+ private String identifier;
+
+ public CopyDoiUrlAction(String identifier) {
+ super(Localization.menuTitle("Copy DOI url"));
+ this.identifier = identifier;
+ }
+
+ public CopyDoiUrlAction(JTextComponent component) {
+ this(component.getText());
+ this.component = component;
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ identifier = component == null ? identifier : component.getText();
+
+ Optional<String> urlOptional = DOI.build(identifier).map(DOI::getURIAsASCIIString);
+ if (urlOptional.isPresent()) {
+ ClipBoardManager clipBoard = new ClipBoardManager();
+ clipBoard.setClipboardContents(urlOptional.get());
+ JabRefGUI.getMainFrame().output(Localization.lang("The link has been copied to the clipboard."));
+ } else {
+ JabRefGUI.getMainFrame().output(Localization.lang("Invalid DOI: '%0'.", identifier));
+ }
+ }
+}
diff --git a/src/main/java/net/sf/jabref/gui/actions/IntegrityCheckAction.java b/src/main/java/net/sf/jabref/gui/actions/IntegrityCheckAction.java
index 2df02dc..c0a7062 100644
--- a/src/main/java/net/sf/jabref/gui/actions/IntegrityCheckAction.java
+++ b/src/main/java/net/sf/jabref/gui/actions/IntegrityCheckAction.java
@@ -19,8 +19,9 @@ import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
+import net.sf.jabref.Globals;
import net.sf.jabref.gui.JabRefFrame;
-import net.sf.jabref.gui.util.GUIUtil;
+import net.sf.jabref.gui.keyboard.KeyBinding;
import net.sf.jabref.logic.integrity.IntegrityCheck;
import net.sf.jabref.logic.integrity.IntegrityMessage;
import net.sf.jabref.logic.l10n.Localization;
@@ -39,11 +40,14 @@ public class IntegrityCheckAction extends MnemonicAwareAction {
public IntegrityCheckAction(JabRefFrame frame) {
this.frame = frame;
putValue(Action.NAME, Localization.menuTitle("Check integrity") + ELLIPSES);
+ putValue(Action.ACCELERATOR_KEY, Globals.getKeyPrefs().getKey(KeyBinding.CHECK_INTEGRITY));
}
@Override
public void actionPerformed(ActionEvent e) {
- IntegrityCheck check = new IntegrityCheck(frame.getCurrentBasePanel().getBibDatabaseContext());
+ IntegrityCheck check = new IntegrityCheck(frame.getCurrentBasePanel().getBibDatabaseContext(),
+ Globals.prefs.getFileDirectoryPreferences(),
+ Globals.prefs.getBibtexKeyPatternPreferences());
List<IntegrityMessage> messages = check.checkBibtexDatabase();
if (messages.isEmpty()) {
@@ -94,8 +98,6 @@ public class IntegrityCheckAction extends MnemonicAwareAction {
}
});
- GUIUtil.correctRowHeight(table);
-
table.getColumnModel().getColumn(0).setPreferredWidth(100);
table.getColumnModel().getColumn(1).setPreferredWidth(60);
table.getColumnModel().getColumn(2).setPreferredWidth(400);
diff --git a/src/main/java/net/sf/jabref/gui/actions/ManageKeywordsAction.java b/src/main/java/net/sf/jabref/gui/actions/ManageKeywordsAction.java
index e8fa5a8..0cbede0 100644
--- a/src/main/java/net/sf/jabref/gui/actions/ManageKeywordsAction.java
+++ b/src/main/java/net/sf/jabref/gui/actions/ManageKeywordsAction.java
@@ -6,11 +6,8 @@ import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Enumeration;
-import java.util.HashSet;
import java.util.List;
import java.util.Optional;
-import java.util.Set;
-import java.util.TreeSet;
import javax.swing.AbstractAction;
import javax.swing.Action;
@@ -37,17 +34,13 @@ import net.sf.jabref.gui.undo.NamedCompound;
import net.sf.jabref.gui.undo.UndoableFieldChange;
import net.sf.jabref.logic.autocompleter.AutoCompleter;
import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.logic.specialfields.SpecialFieldsUtils;
import net.sf.jabref.model.FieldChange;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.FieldName;
-import net.sf.jabref.preferences.JabRefPreferences;
-import net.sf.jabref.specialfields.Printed;
-import net.sf.jabref.specialfields.Priority;
-import net.sf.jabref.specialfields.Quality;
-import net.sf.jabref.specialfields.Rank;
-import net.sf.jabref.specialfields.ReadStatus;
-import net.sf.jabref.specialfields.Relevance;
-import net.sf.jabref.specialfields.SpecialFieldsUtils;
+import net.sf.jabref.model.entry.Keyword;
+import net.sf.jabref.model.entry.KeywordList;
+import net.sf.jabref.model.strings.StringUtil;
import com.jgoodies.forms.builder.ButtonBarBuilder;
import com.jgoodies.forms.builder.FormBuilder;
@@ -64,14 +57,14 @@ public class ManageKeywordsAction extends MnemonicAwareAction {
private JDialog diag;
- private DefaultListModel<String> keywordListModel;
+ private DefaultListModel<Keyword> keywordListModel;
private JRadioButton intersectKeywords;
private JRadioButton mergeKeywords;
private boolean canceled;
- private final Set<String> sortedKeywordsOfAllEntriesBeforeUpdateByUser = new TreeSet<>();
+ private final KeywordList sortedKeywordsOfAllEntriesBeforeUpdateByUser = new KeywordList();
public ManageKeywordsAction(JabRefFrame frame) {
@@ -87,7 +80,7 @@ public class ManageKeywordsAction extends MnemonicAwareAction {
JTextField keyword = new JTextField();
keywordListModel = new DefaultListModel<>();
- JList<String> keywordList = new JList<>(keywordListModel);
+ JList<Keyword> keywordList = new JList<>(keywordListModel);
keywordList.setVisibleRowCount(8);
JScrollPane kPane = new JScrollPane(keywordList);
@@ -149,9 +142,9 @@ public class ManageKeywordsAction extends MnemonicAwareAction {
final ActionListener removeActionListenter = arg0 -> {
// keywordList.getSelectedIndices(); does not work, therefore we operate on the values
- List<String> values = keywordList.getSelectedValuesList();
+ List<Keyword> values = keywordList.getSelectedValuesList();
- for (String val : values) {
+ for (Keyword val : values) {
keywordListModel.removeElement(val);
}
};
@@ -213,29 +206,33 @@ public class ManageKeywordsAction extends MnemonicAwareAction {
diag.getContentPane().add(bb.getPanel(), BorderLayout.SOUTH);
}
- private void addButtonActionListener(JTextField keyword) {
- String text = keyword.getText().trim();
- if (!text.isEmpty()) {
- if (keywordListModel.isEmpty()) {
- keywordListModel.addElement(text);
+ private void addButtonActionListener(JTextField keywordTextField) {
+ if (StringUtil.isBlank(keywordTextField.getText())) {
+ return; // nothing to add
+ }
+
+
+ Keyword newKeyword = new Keyword(keywordTextField.getText().trim());
+ if (keywordListModel.isEmpty()) {
+ keywordListModel.addElement(newKeyword);
+ } else {
+ int idx = 0;
+ Keyword element = keywordListModel.getElementAt(idx);
+ while ((idx < keywordListModel.size()) && (element.compareTo(newKeyword) < 0)) {
+ idx++;
+ }
+ if (idx == keywordListModel.size()) {
+ // list is empty or word is greater than last word in list
+ keywordListModel.addElement(newKeyword);
+ } else if (element.compareTo(newKeyword) == 0) {
+ // nothing to do, word already in table
} else {
- int idx = 0;
- String element = keywordListModel.getElementAt(idx);
- while ((idx < keywordListModel.size()) && (element.compareTo(text) < 0)) {
- idx++;
- }
- if (idx == keywordListModel.size()) {
- // list is empty or word is greater than last word in list
- keywordListModel.addElement(text);
- } else if (element.compareTo(text) == 0) {
- // nothing to do, word already in table
- } else {
- keywordListModel.add(idx, text);
- }
+ keywordListModel.add(idx, newKeyword);
}
- keyword.setText(null);
- keyword.requestFocusInWindow();
}
+ keywordTextField.setText(null);
+ keywordTextField.requestFocusInWindow();
+
}
@Override
@@ -263,19 +260,19 @@ public class ManageKeywordsAction extends MnemonicAwareAction {
return;
}
- Set<String> keywordsToAdd = new HashSet<>();
- Set<String> userSelectedKeywords = new HashSet<>();
+ KeywordList keywordsToAdd = new KeywordList();
+ KeywordList userSelectedKeywords = new KeywordList();
// build keywordsToAdd and userSelectedKeywords in parallel
- for (Enumeration<String> keywords = keywordListModel.elements(); keywords.hasMoreElements();) {
- String keyword = keywords.nextElement();
+ for (Enumeration<Keyword> keywords = keywordListModel.elements(); keywords.hasMoreElements();) {
+ Keyword keyword = keywords.nextElement();
userSelectedKeywords.add(keyword);
if (!sortedKeywordsOfAllEntriesBeforeUpdateByUser.contains(keyword)) {
keywordsToAdd.add(keyword);
}
}
- Set<String> keywordsToRemove = new HashSet<>();
- for (String kword : sortedKeywordsOfAllEntriesBeforeUpdateByUser) {
+ KeywordList keywordsToRemove = new KeywordList();
+ for (Keyword kword : sortedKeywordsOfAllEntriesBeforeUpdateByUser) {
if (!userSelectedKeywords.contains(kword)) {
keywordsToRemove.add(kword);
}
@@ -286,8 +283,8 @@ public class ManageKeywordsAction extends MnemonicAwareAction {
return;
}
- if (SpecialFieldsUtils.keywordSyncEnabled() && !keywordsToAdd.isEmpty()) {
- synchronizeSpecialFields(keywordsToAdd, keywordsToRemove);
+ if (Globals.prefs.isKeywordSyncEnabled() && !keywordsToAdd.isEmpty()) {
+ SpecialFieldsUtils.synchronizeSpecialFields(keywordsToAdd, keywordsToRemove);
}
NamedCompound ce = updateKeywords(bp.getSelectedEntries(), keywordsToAdd, keywordsToRemove);
@@ -295,86 +292,30 @@ public class ManageKeywordsAction extends MnemonicAwareAction {
bp.markBaseChanged();
}
- private NamedCompound updateKeywords(List<BibEntry> entries, Set<String> keywordsToAdd,
- Set<String> keywordsToRemove) {
+ private NamedCompound updateKeywords(List<BibEntry> entries, KeywordList keywordsToAdd,
+ KeywordList keywordsToRemove) {
NamedCompound ce = new NamedCompound(Localization.lang("Update keywords"));
for (BibEntry entry : entries) {
- Set<String> keywords = entry.getKeywords();
+ KeywordList keywords = entry.getKeywords(Globals.prefs.getKeywordDelimiter());
// update keywords
keywords.removeAll(keywordsToRemove);
keywords.addAll(keywordsToAdd);
// put keywords back
- Optional<FieldChange> change = entry.putKeywords(keywords,
- Globals.prefs.get(JabRefPreferences.KEYWORD_SEPARATOR));
+ Optional<FieldChange> change = entry.putKeywords(keywords, Globals.prefs.getKeywordDelimiter());
if (change.isPresent()) {
ce.addEdit(new UndoableFieldChange(change.get()));
}
- if (SpecialFieldsUtils.keywordSyncEnabled()) {
- SpecialFieldsUtils.syncSpecialFieldsFromKeywords(entry, ce);
+ if (Globals.prefs.isKeywordSyncEnabled()) {
+ SpecialFieldsUtils.syncSpecialFieldsFromKeywords(entry, Globals.prefs.getKeywordDelimiter());
}
}
ce.end();
return ce;
}
- private void synchronizeSpecialFields(Set<String> keywordsToAdd, Set<String> keywordsToRemove) {
- // we need to check whether a special field is added
- // for each field:
- // check if something is added
- // if yes, add all keywords of that special fields to the keywords to be removed
-
- Set<String> clone;
-
- // Priority
- clone = createClone(keywordsToAdd);
- clone.retainAll(Priority.getInstance().getKeyWords());
- if (!clone.isEmpty()) {
- keywordsToRemove.addAll(Priority.getInstance().getKeyWords());
- }
-
- // Quality
- clone = createClone(keywordsToAdd);
- clone.retainAll(Quality.getInstance().getKeyWords());
- if (!clone.isEmpty()) {
- keywordsToRemove.addAll(Quality.getInstance().getKeyWords());
- }
-
- // Rank
- clone = createClone(keywordsToAdd);
- clone.retainAll(Rank.getInstance().getKeyWords());
- if (!clone.isEmpty()) {
- keywordsToRemove.addAll(Rank.getInstance().getKeyWords());
- }
-
- // Relevance
- clone = createClone(keywordsToAdd);
- clone.retainAll(Relevance.getInstance().getKeyWords());
- if (!clone.isEmpty()) {
- keywordsToRemove.addAll(Relevance.getInstance().getKeyWords());
- }
-
- // Read status
- clone = createClone(keywordsToAdd);
- clone.retainAll(ReadStatus.getInstance().getKeyWords());
- if (!clone.isEmpty()) {
- keywordsToRemove.addAll(ReadStatus.getInstance().getKeyWords());
- }
-
- // Printed
- clone = createClone(keywordsToAdd);
- clone.retainAll(Printed.getInstance().getKeyWords());
- if (!clone.isEmpty()) {
- keywordsToRemove.addAll(Printed.getInstance().getKeyWords());
- }
- }
-
- private static Set<String> createClone(Set<String> keywordsToAdd) {
- return new HashSet<>(keywordsToAdd);
- }
-
private void fillKeyWordList() {
BasePanel bp = frame.getCurrentBasePanel();
List<BibEntry> entries = bp.getSelectedEntries();
@@ -385,7 +326,7 @@ public class ManageKeywordsAction extends MnemonicAwareAction {
if (mergeKeywords.isSelected()) {
for (BibEntry entry : entries) {
- Set<String> separatedKeywords = entry.getKeywords();
+ KeywordList separatedKeywords = entry.getKeywords(Globals.prefs.getKeywordDelimiter());
sortedKeywordsOfAllEntriesBeforeUpdateByUser.addAll(separatedKeywords);
}
} else {
@@ -393,19 +334,19 @@ public class ManageKeywordsAction extends MnemonicAwareAction {
// all keywords from first entry have to be added
BibEntry firstEntry = entries.get(0);
- Set<String> separatedKeywords = firstEntry.getKeywords();
+ KeywordList separatedKeywords = firstEntry.getKeywords(Globals.prefs.getKeywordDelimiter());
sortedKeywordsOfAllEntriesBeforeUpdateByUser.addAll(separatedKeywords);
// for the remaining entries, intersection has to be used
// this approach ensures that one empty keyword list leads to an empty set of common keywords
for (int i = 1; i < entries.size(); i++) {
BibEntry entry = entries.get(i);
- separatedKeywords = entry.getKeywords();
+ separatedKeywords = entry.getKeywords(Globals.prefs.getKeywordDelimiter());
sortedKeywordsOfAllEntriesBeforeUpdateByUser.retainAll(separatedKeywords);
}
}
- for (String s : sortedKeywordsOfAllEntriesBeforeUpdateByUser) {
- keywordListModel.addElement(s);
+ for (Keyword keyword : sortedKeywordsOfAllEntriesBeforeUpdateByUser) {
+ keywordListModel.addElement(keyword);
}
}
diff --git a/src/main/java/net/sf/jabref/gui/actions/MassSetFieldAction.java b/src/main/java/net/sf/jabref/gui/actions/MassSetFieldAction.java
index 9cf3548..f708d94 100644
--- a/src/main/java/net/sf/jabref/gui/actions/MassSetFieldAction.java
+++ b/src/main/java/net/sf/jabref/gui/actions/MassSetFieldAction.java
@@ -261,7 +261,7 @@ public class MassSetFieldAction extends MnemonicAwareAction {
NamedCompound ce = new NamedCompound(Localization.lang("Set field"));
for (BibEntry entry : entries) {
- Optional<String> oldVal = entry.getFieldOptional(field);
+ Optional<String> oldVal = entry.getField(field);
// If we are not allowed to overwrite values, check if there is a
// nonempty
// value already for this entry:
@@ -293,14 +293,14 @@ public class MassSetFieldAction extends MnemonicAwareAction {
boolean overwriteValues) {
NamedCompound ce = new NamedCompound(Localization.lang("Rename field"));
for (BibEntry entry : entries) {
- Optional<String> valToMove = entry.getFieldOptional(field);
+ Optional<String> valToMove = entry.getField(field);
// If there is no value, do nothing:
if ((!valToMove.isPresent()) || valToMove.get().isEmpty()) {
continue;
}
// If we are not allowed to overwrite values, check if there is a
// non-empty value already for this entry for the new field:
- Optional<String> valInNewField = entry.getFieldOptional(newField);
+ Optional<String> valInNewField = entry.getField(newField);
if (!overwriteValues && (valInNewField.isPresent()) && !valInNewField.get().isEmpty()) {
continue;
}
diff --git a/src/main/java/net/sf/jabref/gui/actions/NewDatabaseAction.java b/src/main/java/net/sf/jabref/gui/actions/NewDatabaseAction.java
index 8b9b8f2..67bf768 100644
--- a/src/main/java/net/sf/jabref/gui/actions/NewDatabaseAction.java
+++ b/src/main/java/net/sf/jabref/gui/actions/NewDatabaseAction.java
@@ -4,11 +4,11 @@ import java.awt.event.ActionEvent;
import javax.swing.Action;
-import net.sf.jabref.BibDatabaseContext;
-import net.sf.jabref.Defaults;
import net.sf.jabref.gui.IconTheme;
import net.sf.jabref.gui.JabRefFrame;
import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.Defaults;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.database.BibDatabaseMode;
/**
diff --git a/src/main/java/net/sf/jabref/gui/actions/NewEntryAction.java b/src/main/java/net/sf/jabref/gui/actions/NewEntryAction.java
index 0130ae2..e0d44b1 100644
--- a/src/main/java/net/sf/jabref/gui/actions/NewEntryAction.java
+++ b/src/main/java/net/sf/jabref/gui/actions/NewEntryAction.java
@@ -11,7 +11,7 @@ import net.sf.jabref.gui.JabRefFrame;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.model.EntryTypes;
import net.sf.jabref.model.entry.EntryType;
-import net.sf.jabref.model.entry.EntryUtil;
+import net.sf.jabref.model.strings.StringUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -34,14 +34,14 @@ public class NewEntryAction extends MnemonicAwareAction {
public NewEntryAction(JabRefFrame jabRefFrame, String type) {
this.jabRefFrame = jabRefFrame;
// This action leads to the creation of a specific entry.
- putValue(Action.NAME, EntryUtil.capitalizeFirst(type));
+ putValue(Action.NAME, StringUtil.capitalizeFirst(type));
this.type = type;
}
public NewEntryAction(JabRefFrame jabRefFrame, String type, KeyStroke key) {
this.jabRefFrame = jabRefFrame;
// This action leads to the creation of a specific entry.
- putValue(Action.NAME, EntryUtil.capitalizeFirst(type));
+ putValue(Action.NAME, StringUtil.capitalizeFirst(type));
putValue(Action.ACCELERATOR_KEY, key);
this.type = type;
}
diff --git a/src/main/java/net/sf/jabref/gui/actions/NewSubDatabaseAction.java b/src/main/java/net/sf/jabref/gui/actions/NewSubDatabaseAction.java
index b455a35..20eca4b 100644
--- a/src/main/java/net/sf/jabref/gui/actions/NewSubDatabaseAction.java
+++ b/src/main/java/net/sf/jabref/gui/actions/NewSubDatabaseAction.java
@@ -4,14 +4,14 @@ import java.awt.event.ActionEvent;
import javax.swing.Action;
-import net.sf.jabref.BibDatabaseContext;
-import net.sf.jabref.Defaults;
import net.sf.jabref.Globals;
import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.gui.IconTheme;
import net.sf.jabref.gui.JabRefFrame;
import net.sf.jabref.gui.auximport.FromAuxDialog;
import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.Defaults;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.database.BibDatabaseMode;
import net.sf.jabref.preferences.JabRefPreferences;
diff --git a/src/main/java/net/sf/jabref/gui/actions/OpenSharedDatabaseAction.java b/src/main/java/net/sf/jabref/gui/actions/OpenSharedDatabaseAction.java
deleted file mode 100644
index f8c99a3..0000000
--- a/src/main/java/net/sf/jabref/gui/actions/OpenSharedDatabaseAction.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package net.sf.jabref.gui.actions;
-
-import java.awt.event.ActionEvent;
-
-import javax.swing.Action;
-
-import net.sf.jabref.gui.JabRefFrame;
-import net.sf.jabref.gui.shared.OpenSharedDatabaseDialog;
-import net.sf.jabref.logic.l10n.Localization;
-
-/**
- * The action concerned with opening a shared database.
- */
-public class OpenSharedDatabaseAction extends MnemonicAwareAction {
-
- private final JabRefFrame jabRefFrame;
-
-
- public OpenSharedDatabaseAction(JabRefFrame jabRefFrame) {
- super();
- this.jabRefFrame = jabRefFrame;
- putValue(Action.NAME, Localization.menuTitle("Open shared database"));
- putValue(Action.SHORT_DESCRIPTION, Localization.lang("Open shared database"));
- }
-
- @Override
- public void actionPerformed(ActionEvent e) {
-
- OpenSharedDatabaseDialog openSharedDatabaseDialog = new OpenSharedDatabaseDialog(jabRefFrame);
- openSharedDatabaseDialog.setVisible(true);
- }
-}
diff --git a/src/main/java/net/sf/jabref/gui/autocompleter/AutoCompleteSupport.java b/src/main/java/net/sf/jabref/gui/autocompleter/AutoCompleteSupport.java
index e7a3e19..59e9415 100644
--- a/src/main/java/net/sf/jabref/gui/autocompleter/AutoCompleteSupport.java
+++ b/src/main/java/net/sf/jabref/gui/autocompleter/AutoCompleteSupport.java
@@ -279,4 +279,13 @@ public class AutoCompleteSupport<E> {
public void setAutoCompleter(AutoCompleter<E> autoCompleter) {
this.autoCompleter = autoCompleter;
}
-}
\ No newline at end of file
+
+ public void setVisible(boolean visible){
+ popup.setVisible(visible);
+ }
+
+ public boolean isVisible() {
+ return popup.isVisible();
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/gui/autocompleter/ListAutoCompleteRenderer.java b/src/main/java/net/sf/jabref/gui/autocompleter/ListAutoCompleteRenderer.java
index b2afa96..5be4089 100644
--- a/src/main/java/net/sf/jabref/gui/autocompleter/ListAutoCompleteRenderer.java
+++ b/src/main/java/net/sf/jabref/gui/autocompleter/ListAutoCompleteRenderer.java
@@ -11,6 +11,7 @@ import javax.swing.DefaultListModel;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.ListSelectionModel;
+import javax.swing.ScrollPaneConstants;
/**
* Renders possible autocomplete items in form of a simple list.
@@ -57,8 +58,8 @@ public class ListAutoCompleteRenderer<E> extends AutoCompleteRenderer<E> {
scrollPane.setFocusable(false);
scrollPane.setRequestFocusEnabled(false);
scrollPane.setBorder(BorderFactory.createEmptyBorder());
- scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
- scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
+ scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
+ scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
return scrollPane;
}
diff --git a/src/main/java/net/sf/jabref/gui/autosaveandbackup/AutosaveUIManager.java b/src/main/java/net/sf/jabref/gui/autosaveandbackup/AutosaveUIManager.java
new file mode 100644
index 0000000..fbc6e6a
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/autosaveandbackup/AutosaveUIManager.java
@@ -0,0 +1,33 @@
+package net.sf.jabref.gui.autosaveandbackup;
+
+import net.sf.jabref.gui.BasePanel;
+import net.sf.jabref.gui.exporter.SaveDatabaseAction;
+import net.sf.jabref.model.database.event.AutosaveEvent;
+
+import com.google.common.eventbus.Subscribe;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * This class has an abstract UI role as it listens for an {@link AutosaveEvent}
+ * and saves the bib file associated with the given {@link BasePanel}.
+ */
+public class AutosaveUIManager {
+
+ private static final Log LOGGER = LogFactory.getLog(AutosaveUIManager.class);
+ private final BasePanel panel;
+
+
+ public AutosaveUIManager(BasePanel panel) {
+ this.panel = panel;
+ }
+
+ @Subscribe
+ public void listen(@SuppressWarnings("unused") AutosaveEvent event) {
+ try {
+ new SaveDatabaseAction(panel).runCommand();
+ } catch (Throwable e) {
+ LOGGER.error("Problem occured while saving.", e);
+ }
+ }
+}
diff --git a/src/main/java/net/sf/jabref/gui/autosaveandbackup/BackupUIManager.java b/src/main/java/net/sf/jabref/gui/autosaveandbackup/BackupUIManager.java
new file mode 100644
index 0000000..e7cf7f3
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/autosaveandbackup/BackupUIManager.java
@@ -0,0 +1,30 @@
+package net.sf.jabref.gui.autosaveandbackup;
+
+import java.nio.file.Path;
+
+import javax.swing.JFrame;
+import javax.swing.JOptionPane;
+
+import net.sf.jabref.logic.autosaveandbackup.BackupManager;
+import net.sf.jabref.logic.l10n.Localization;
+
+/**
+ * Stores all user dialogs related to {@link BackupManager}.
+ */
+public class BackupUIManager {
+
+ public static void showRestoreBackupDialog(JFrame frame, Path originalPath) {
+ int answer = JOptionPane.showConfirmDialog(frame,
+ new StringBuilder()
+ .append(Localization.lang("A backup file for '%0' was found.", originalPath.getFileName().toString()))
+ .append("\n")
+ .append(Localization.lang("This could indicate that JabRef did not shut down cleanly last time the file was used."))
+ .append("\n\n")
+ .append(Localization.lang("Do you want to recover the database from the backup file?")).toString(),
+ Localization.lang("Backup found"), JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
+
+ if (answer == 0) {
+ BackupManager.restoreBackup(originalPath);
+ }
+ }
+}
diff --git a/src/main/java/net/sf/jabref/gui/bibtexkeypattern/BibtexKeyPatternDialog.java b/src/main/java/net/sf/jabref/gui/bibtexkeypattern/BibtexKeyPatternDialog.java
new file mode 100644
index 0000000..86b926c
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/bibtexkeypattern/BibtexKeyPatternDialog.java
@@ -0,0 +1,101 @@
+package net.sf.jabref.gui.bibtexkeypattern;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.event.ActionEvent;
+import java.awt.event.WindowEvent;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.BorderFactory;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JPanel;
+import javax.swing.WindowConstants;
+
+import net.sf.jabref.Globals;
+import net.sf.jabref.gui.BasePanel;
+import net.sf.jabref.gui.JabRefFrame;
+import net.sf.jabref.gui.keyboard.KeyBinder;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.bibtexkeypattern.AbstractBibtexKeyPattern;
+import net.sf.jabref.model.metadata.MetaData;
+
+import com.jgoodies.forms.builder.ButtonBarBuilder;
+
+public class BibtexKeyPatternDialog extends JDialog {
+
+ private MetaData metaData;
+ private BasePanel panel;
+ private final BibtexKeyPatternPanel bibtexKeyPatternPanel;
+
+
+ public BibtexKeyPatternDialog(JabRefFrame parent, BasePanel panel) {
+ super(parent, Localization.lang("BibTeX key patterns"), true);
+ this.bibtexKeyPatternPanel = new BibtexKeyPatternPanel(panel);
+ setPanel(panel);
+ init();
+ }
+
+ /**
+ * Used for updating an existing Dialog
+ *
+ * @param panel the panel to read the data from
+ */
+ public void setPanel(BasePanel panel) {
+ this.panel = panel;
+ this.metaData = panel.getBibDatabaseContext().getMetaData();
+ AbstractBibtexKeyPattern keypatterns = metaData.getCiteKeyPattern(Globals.prefs.getKeyPattern());
+ bibtexKeyPatternPanel.setValues(keypatterns);
+ }
+
+ private void init() {
+ getContentPane().setLayout(new BorderLayout());
+ getContentPane().add(bibtexKeyPatternPanel, BorderLayout.CENTER);
+
+ JButton ok = new JButton(Localization.lang("OK"));
+ JButton cancel = new JButton(); // label of "cancel" is set later as the label is overwritten by assigning an action to the button
+
+ JPanel lower = new JPanel();
+ lower.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
+ ButtonBarBuilder bb = new ButtonBarBuilder(lower);
+ bb.addGlue();
+ bb.addButton(ok);
+ bb.addButton(cancel);
+ bb.addGlue();
+
+ getContentPane().add(lower, BorderLayout.SOUTH);
+
+ this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
+ getContentPane().setPreferredSize(new Dimension(500, 600));
+ pack();
+
+ ok.addActionListener(e -> {
+ metaData.setCiteKeyPattern(bibtexKeyPatternPanel.getKeyPatternAsDatabaseBibtexKeyPattern());
+ panel.markNonUndoableBaseChanged();
+ dispose();
+ });
+
+ final JDialog dialog = this;
+
+ Action cancelAction = new AbstractAction() {
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ dialog.dispatchEvent(new WindowEvent(dialog, WindowEvent.WINDOW_CLOSING));
+ }
+ };
+ cancel.setAction(cancelAction);
+ cancel.setText(Localization.lang("Cancel"));
+
+ KeyBinder.bindCloseDialogKeyToCancelAction(this.getRootPane(), cancelAction);
+ }
+
+ @Override
+ public void setVisible(boolean visible) {
+ if (visible) {
+ super.setVisible(visible);
+ }
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/gui/bibtexkeypattern/BibtexKeyPatternPanel.java b/src/main/java/net/sf/jabref/gui/bibtexkeypattern/BibtexKeyPatternPanel.java
index 8481821..572b6a3 100644
--- a/src/main/java/net/sf/jabref/gui/bibtexkeypattern/BibtexKeyPatternPanel.java
+++ b/src/main/java/net/sf/jabref/gui/bibtexkeypattern/BibtexKeyPatternPanel.java
@@ -224,8 +224,9 @@ public class BibtexKeyPatternPanel extends JPanel {
}
protected GlobalBibtexKeyPattern getKeyPatternAsGlobalBibtexKeyPattern() {
- GlobalBibtexKeyPattern res = new GlobalBibtexKeyPattern(
- AbstractBibtexKeyPattern.split(JabRefPreferences.getInstance().get(JabRefPreferences.DEFAULT_BIBTEX_KEY_PATTERN)));
+ GlobalBibtexKeyPattern res = GlobalBibtexKeyPattern.fromPattern(
+ JabRefPreferences.getInstance().get(JabRefPreferences.DEFAULT_BIBTEX_KEY_PATTERN)
+ );
fillPatternUsingPanelData(res);
return res;
}
@@ -246,7 +247,7 @@ public class BibtexKeyPatternPanel extends JPanel {
setValue(entry.getValue(), entry.getKey(), keyPattern);
}
- if (keyPattern.getDefaultValue() == null) {
+ if (keyPattern.getDefaultValue() == null || keyPattern.getDefaultValue().isEmpty()) {
defaultPat.setText("");
} else {
defaultPat.setText(keyPattern.getDefaultValue().get(0));
diff --git a/src/main/java/net/sf/jabref/gui/bibtexkeypattern/ResolveDuplicateLabelDialog.java b/src/main/java/net/sf/jabref/gui/bibtexkeypattern/ResolveDuplicateLabelDialog.java
index 926438b..d8dcbfd 100644
--- a/src/main/java/net/sf/jabref/gui/bibtexkeypattern/ResolveDuplicateLabelDialog.java
+++ b/src/main/java/net/sf/jabref/gui/bibtexkeypattern/ResolveDuplicateLabelDialog.java
@@ -38,19 +38,6 @@ class ResolveDuplicateLabelDialog {
private boolean okPressed;
private boolean cancelPressed;
- private static final String LAYOUT = "<font face=\"arial\"><b><i>\\entrytype</i><a name=\"\\bibtexkey\">\\begin{bibtexkey} (\\bibtexkey)</a>\\end{bibtexkey}</b><br>\n"
- + "\\begin{author} \\format[HTMLChars,AuthorAbbreviator,AuthorAndsReplacer]{\\author}<BR>\\end{author}\n"
- + "\\begin{editor} \\format[HTMLChars,AuthorAbbreviator,AuthorAndsReplacer]{\\editor} <i>(\\format[IfPlural(Eds.,Ed.)]{\\editor})</i><BR>\\end{editor}\n"
- + "\\begin{title} \\format[HTMLChars]{\\title} \\end{title}<BR>\n"
- + "\\begin{chapter} \\format[HTMLChars]{\\chapter}<BR>\\end{chapter}\n"
- + "\\begin{journal} <em>\\format[HTMLChars]{\\journal}, </em>\\end{journal}\n"
- + "\\begin{booktitle} <em>\\format[HTMLChars]{\\booktitle}, </em>\\end{booktitle}\n"
- + "\\begin{school} <em>\\format[HTMLChars]{\\school}, </em>\\end{school}\n"
- + "\\begin{institution} <em>\\format[HTMLChars]{\\institution}, </em>\\end{institution}\n"
- + "\\begin{publisher} <em>\\format[HTMLChars]{\\publisher}, </em>\\end{publisher}\n"
- + "\\begin{year}<b>\\year</b>\\end{year}\\begin{volume}<i>, \\volume</i>\\end{volume}\\begin{pages}, \\format[FormatPagesForHTML]{\\pages} \\end{pages}\n"
- + "<p></p></font>";
-
public ResolveDuplicateLabelDialog(BasePanel panel, String key, List<BibEntry> entries) {
diag = new JDialog(panel.frame(), Localization.lang("Duplicate BibTeX key"), true);
@@ -66,7 +53,7 @@ class ResolveDuplicateLabelDialog {
JCheckBox cb = new JCheckBox(Localization.lang("Generate BibTeX key"), !first);
b.appendRows("1dlu, p");
b.add(cb).xy(1, row);
- PreviewPanel pp = new PreviewPanel(null, entry, null, ResolveDuplicateLabelDialog.LAYOUT);
+ PreviewPanel pp = new PreviewPanel(null, entry, null);
pp.setPreferredSize(new Dimension(800, 90));
b.add(new JScrollPane(pp)).xy(3, row);
row += 2;
diff --git a/src/main/java/net/sf/jabref/gui/bibtexkeypattern/SearchFixDuplicateLabels.java b/src/main/java/net/sf/jabref/gui/bibtexkeypattern/SearchFixDuplicateLabels.java
index dfce10e..a786dad 100644
--- a/src/main/java/net/sf/jabref/gui/bibtexkeypattern/SearchFixDuplicateLabels.java
+++ b/src/main/java/net/sf/jabref/gui/bibtexkeypattern/SearchFixDuplicateLabels.java
@@ -12,7 +12,6 @@ import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.gui.undo.NamedCompound;
import net.sf.jabref.gui.undo.UndoableKeyChange;
import net.sf.jabref.gui.worker.AbstractWorker;
-import net.sf.jabref.logic.bibtexkeypattern.BibtexKeyPatternPreferences;
import net.sf.jabref.logic.bibtexkeypattern.BibtexKeyPatternUtil;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.model.database.BibDatabase;
@@ -65,7 +64,7 @@ public class SearchFixDuplicateLabels extends AbstractWorker {
}
@Override
- public void init() throws Throwable {
+ public void init() throws Exception {
panel.output(Localization.lang("Resolving duplicate BibTeX keys..."));
}
@@ -94,9 +93,11 @@ public class SearchFixDuplicateLabels extends AbstractWorker {
NamedCompound ce = new NamedCompound(Localization.lang("Resolve duplicate BibTeX keys"));
for (BibEntry entry : toGenerateFor) {
String oldKey = entry.getCiteKeyOptional().orElse(null);
- BibtexKeyPatternUtil.makeLabel(panel.getBibDatabaseContext().getMetaData(), panel.getDatabase(), entry,
- BibtexKeyPatternPreferences.fromPreferences(Globals.prefs));
- ce.addEdit(new UndoableKeyChange(panel.getDatabase(), entry, oldKey, entry.getCiteKeyOptional().get()));
+ BibtexKeyPatternUtil.makeAndSetLabel(panel.getBibDatabaseContext().getMetaData()
+ .getCiteKeyPattern(Globals.prefs.getBibtexKeyPatternPreferences().getKeyPattern()),
+ panel.getDatabase(), entry,
+ Globals.prefs.getBibtexKeyPatternPreferences());
+ ce.addEdit(new UndoableKeyChange(entry, oldKey, entry.getCiteKeyOptional().get()));
}
ce.end();
panel.getUndoManager().addEdit(ce);
diff --git a/src/main/java/net/sf/jabref/gui/cleanup/CleanupActionsListModel.java b/src/main/java/net/sf/jabref/gui/cleanup/CleanupActionsListModel.java
index 280d508..feb4749 100644
--- a/src/main/java/net/sf/jabref/gui/cleanup/CleanupActionsListModel.java
+++ b/src/main/java/net/sf/jabref/gui/cleanup/CleanupActionsListModel.java
@@ -8,8 +8,8 @@ import javax.swing.ListModel;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
-import net.sf.jabref.logic.cleanup.FieldFormatterCleanup;
-import net.sf.jabref.logic.exporter.FieldFormatterCleanups;
+import net.sf.jabref.model.cleanup.FieldFormatterCleanup;
+import net.sf.jabref.model.cleanup.FieldFormatterCleanups;
public class CleanupActionsListModel implements ListModel<FieldFormatterCleanup> {
diff --git a/src/main/java/net/sf/jabref/gui/cleanup/CleanupPresetPanel.java b/src/main/java/net/sf/jabref/gui/cleanup/CleanupPresetPanel.java
index b4096cd..b53fa6e 100644
--- a/src/main/java/net/sf/jabref/gui/cleanup/CleanupPresetPanel.java
+++ b/src/main/java/net/sf/jabref/gui/cleanup/CleanupPresetPanel.java
@@ -8,10 +8,11 @@ import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
-import net.sf.jabref.BibDatabaseContext;
import net.sf.jabref.Globals;
import net.sf.jabref.logic.cleanup.CleanupPreset;
+import net.sf.jabref.logic.cleanup.Cleanups;
import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.entry.FieldName;
import net.sf.jabref.preferences.JabRefPreferences;
@@ -68,7 +69,7 @@ public class CleanupPresetPanel {
"Convert to BibLatex format (for example, move the value of the 'journal' field to 'journaltitle')"));
cleanUpFormatters = new FieldFormatterCleanupsPanel(Localization.lang("Run field formatter:"),
- JabRefPreferences.CLEANUP_DEFAULT_PRESET.getFormatterCleanups());
+ Cleanups.DEFAULT_SAVE_ACTIONS);
updateDisplay(cleanupPreset);
diff --git a/src/main/java/net/sf/jabref/gui/cleanup/FieldFormatterCleanupsPanel.java b/src/main/java/net/sf/jabref/gui/cleanup/FieldFormatterCleanupsPanel.java
index c89166b..7004206 100644
--- a/src/main/java/net/sf/jabref/gui/cleanup/FieldFormatterCleanupsPanel.java
+++ b/src/main/java/net/sf/jabref/gui/cleanup/FieldFormatterCleanupsPanel.java
@@ -25,13 +25,16 @@ import javax.swing.UIManager;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
-import net.sf.jabref.MetaData;
-import net.sf.jabref.logic.cleanup.FieldFormatterCleanup;
-import net.sf.jabref.logic.exporter.FieldFormatterCleanups;
-import net.sf.jabref.logic.formatter.Formatter;
+import net.sf.jabref.JabRefGUI;
+import net.sf.jabref.logic.cleanup.Cleanups;
import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.cleanup.FieldFormatterCleanup;
+import net.sf.jabref.model.cleanup.FieldFormatterCleanups;
+import net.sf.jabref.model.cleanup.Formatter;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.InternalBibtexFields;
+import net.sf.jabref.model.metadata.MetaData;
import com.jgoodies.forms.builder.FormBuilder;
import com.jgoodies.forms.layout.FormLayout;
@@ -48,6 +51,7 @@ public class FieldFormatterCleanupsPanel extends JPanel {
private JTextArea descriptionAreaText;
private JButton removeButton;
private JButton resetButton;
+ private JButton recommendButton;
private final FieldFormatterCleanups defaultFormatters;
@@ -60,7 +64,7 @@ public class FieldFormatterCleanupsPanel extends JPanel {
public void setValues(MetaData metaData) {
Objects.requireNonNull(metaData);
Optional<FieldFormatterCleanups> saveActions = metaData.getSaveActions();
- setValues(saveActions.orElse(FieldFormatterCleanups.DEFAULT_SAVE_ACTIONS));
+ setValues(saveActions.orElse(Cleanups.DEFAULT_SAVE_ACTIONS));
}
public void setValues(FieldFormatterCleanups formatterCleanups) {
@@ -130,12 +134,26 @@ public class FieldFormatterCleanupsPanel extends JPanel {
resetButton = new JButton(Localization.lang("Reset"));
resetButton.addActionListener(e -> ((CleanupActionsListModel) actionsList.getModel()).reset(defaultFormatters));
+ BibDatabaseContext databaseContext = JabRefGUI.getMainFrame().getCurrentBasePanel().getDatabaseContext();
+
+ recommendButton = new JButton(Localization.lang("Recommended for %0", databaseContext.getMode().getFormattedName()));
+ boolean isBibLaTeX = databaseContext.isBiblatexMode();
+
+ recommendButton.addActionListener(e -> {
+ if (isBibLaTeX) {
+ ((CleanupActionsListModel) actionsList.getModel()).reset(Cleanups.RECOMMEND_BIBLATEX_ACTIONS);
+ } else {
+ ((CleanupActionsListModel) actionsList.getModel()).reset(Cleanups.RECOMMEND_BIBTEX_ACTIONS);
+ }
+ });
+
removeButton = new JButton(Localization.lang("Remove selected"));
removeButton.addActionListener(
e -> ((CleanupActionsListModel) actionsList.getModel()).removeAtIndex(actionsList.getSelectedIndex()));
builder.add(removeButton).xy(7, 11);
builder.add(resetButton).xy(3, 11);
+ builder.add(recommendButton).xy(5, 11);
builder.add(getSelectorPanel()).xyw(3, 15, 5);
makeDescriptionTextAreaLikeJLabel();
@@ -191,9 +209,8 @@ public class FieldFormatterCleanupsPanel extends JPanel {
.layout(new FormLayout("left:pref:grow, 4dlu, left:pref:grow, 4dlu, pref:grow, 4dlu, right:pref",
"pref, 2dlu, pref:grow, 2dlu"));
- List<String> fieldNames = InternalBibtexFields.getAllPublicFieldNames();
+ List<String> fieldNames = InternalBibtexFields.getAllPublicAndInteralFieldNames();
fieldNames.add(BibEntry.KEY_FIELD);
- fieldNames.add("all");
Collections.sort(fieldNames);
String[] allPlusKey = fieldNames.toArray(new String[fieldNames.size()]);
@@ -201,9 +218,9 @@ public class FieldFormatterCleanupsPanel extends JPanel {
selectFieldCombobox.setEditable(true);
builder.add(selectFieldCombobox).xy(1, 1);
- List<String> formatterNames = fieldFormatterCleanups.getAvailableFormatters().stream()
+ List<String> formatterNames = Cleanups.getAvailableFormatters().stream()
.map(Formatter::getName).collect(Collectors.toList());
- List<String> formatterDescriptions = fieldFormatterCleanups.getAvailableFormatters().stream()
+ List<String> formatterDescriptions = Cleanups.getAvailableFormatters().stream()
.map(Formatter::getDescription).collect(Collectors.toList());
formattersCombobox = new JComboBox<>(formatterNames.toArray());
formattersCombobox.setRenderer(new DefaultListCellRenderer() {
@@ -260,7 +277,7 @@ public class FieldFormatterCleanupsPanel extends JPanel {
}
public boolean isDefaultSaveActions() {
- return FieldFormatterCleanups.DEFAULT_SAVE_ACTIONS.equals(getFormatterCleanups());
+ return Cleanups.DEFAULT_SAVE_ACTIONS.equals(getFormatterCleanups());
}
private FieldFormatterCleanup getFieldFormatterCleanup() {
@@ -274,7 +291,7 @@ public class FieldFormatterCleanupsPanel extends JPanel {
private Formatter getFieldFormatter() {
Formatter selectedFormatter = null;
String selectedFormatterName = formattersCombobox.getSelectedItem().toString();
- for (Formatter formatter : fieldFormatterCleanups.getAvailableFormatters()) {
+ for (Formatter formatter : Cleanups.getAvailableFormatters()) {
if (formatter.getName().equals(selectedFormatterName)) {
selectedFormatter = formatter;
break;
@@ -304,6 +321,7 @@ public class FieldFormatterCleanupsPanel extends JPanel {
addButton.setEnabled(status);
removeButton.setEnabled(status);
resetButton.setEnabled(status);
+ recommendButton.setEnabled(status);
}
}
diff --git a/src/main/java/net/sf/jabref/gui/date/DatePickerButton.java b/src/main/java/net/sf/jabref/gui/date/DatePickerButton.java
index 1ef0563..a11d771 100644
--- a/src/main/java/net/sf/jabref/gui/date/DatePickerButton.java
+++ b/src/main/java/net/sf/jabref/gui/date/DatePickerButton.java
@@ -10,7 +10,6 @@ import javax.swing.JPanel;
import net.sf.jabref.Globals;
import net.sf.jabref.gui.fieldeditors.FieldEditor;
-import net.sf.jabref.gui.util.FocusRequester;
import net.sf.jabref.logic.util.date.EasyDateFormat;
import net.sf.jabref.preferences.JabRefPreferences;
@@ -48,9 +47,12 @@ public class DatePickerButton implements ActionListener {
.fromTimeStampFormat(Globals.prefs.get(JabRefPreferences.TIME_STAMP_FORMAT))
.getDateAt(date));
}
- // Set focus to editor component after changing its text:
- new FocusRequester(editor.getTextComponent());
+ } else {
+ // in this case the user selected "none" in the date picker, so we just clear the field
+ editor.setText("");
}
+ // Set focus to editor component after changing its text:
+ editor.getTextComponent().requestFocus();
}
public JComponent getDatePicker() {
diff --git a/src/main/java/net/sf/jabref/gui/dbproperties/DatabasePropertiesDialog.java b/src/main/java/net/sf/jabref/gui/dbproperties/DatabasePropertiesDialog.java
index 57c970a..d0e798a 100644
--- a/src/main/java/net/sf/jabref/gui/dbproperties/DatabasePropertiesDialog.java
+++ b/src/main/java/net/sf/jabref/gui/dbproperties/DatabasePropertiesDialog.java
@@ -22,19 +22,19 @@ import javax.swing.JRadioButton;
import javax.swing.JTextField;
import net.sf.jabref.Globals;
-import net.sf.jabref.MetaData;
import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.gui.FileDialog;
import net.sf.jabref.gui.SaveOrderConfigDisplay;
import net.sf.jabref.gui.cleanup.FieldFormatterCleanupsPanel;
import net.sf.jabref.gui.help.HelpAction;
import net.sf.jabref.gui.keyboard.KeyBinding;
-import net.sf.jabref.logic.config.SaveOrderConfig;
-import net.sf.jabref.logic.exporter.FieldFormatterCleanups;
+import net.sf.jabref.logic.cleanup.Cleanups;
import net.sf.jabref.logic.help.HelpFile;
import net.sf.jabref.logic.l10n.Encodings;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.model.database.DatabaseLocation;
+import net.sf.jabref.model.metadata.MetaData;
+import net.sf.jabref.model.metadata.SaveOrderConfig;
import com.jgoodies.forms.builder.ButtonBarBuilder;
import com.jgoodies.forms.builder.FormBuilder;
@@ -132,7 +132,7 @@ public class DatabasePropertiesDialog extends JDialog {
builder.add(protect).xyw(1, 25, 5);
fieldFormatterCleanupsPanel = new FieldFormatterCleanupsPanel(Localization.lang("Enable save actions"),
- FieldFormatterCleanups.DEFAULT_SAVE_ACTIONS);
+ Cleanups.DEFAULT_SAVE_ACTIONS);
builder.addSeparator(Localization.lang("Save actions")).xyw(1, 27, 5);
builder.add(fieldFormatterCleanupsPanel).xyw(1, 29, 5);
diff --git a/src/main/java/net/sf/jabref/gui/desktop/JabRefDesktop.java b/src/main/java/net/sf/jabref/gui/desktop/JabRefDesktop.java
index 45a2012..95fb7da 100644
--- a/src/main/java/net/sf/jabref/gui/desktop/JabRefDesktop.java
+++ b/src/main/java/net/sf/jabref/gui/desktop/JabRefDesktop.java
@@ -10,17 +10,9 @@ import java.util.regex.Pattern;
import javax.swing.JOptionPane;
-import net.sf.jabref.BibDatabaseContext;
import net.sf.jabref.Globals;
import net.sf.jabref.JabRefGUI;
-import net.sf.jabref.external.ExternalFileType;
-import net.sf.jabref.external.ExternalFileTypeEntryEditor;
-import net.sf.jabref.external.ExternalFileTypes;
-import net.sf.jabref.external.UnknownExternalFileType;
import net.sf.jabref.gui.ClipBoardManager;
-import net.sf.jabref.gui.FileListEntry;
-import net.sf.jabref.gui.FileListEntryEditor;
-import net.sf.jabref.gui.FileListTableModel;
import net.sf.jabref.gui.IconTheme;
import net.sf.jabref.gui.JabRefFrame;
import net.sf.jabref.gui.desktop.os.DefaultDesktop;
@@ -28,11 +20,19 @@ import net.sf.jabref.gui.desktop.os.Linux;
import net.sf.jabref.gui.desktop.os.NativeDesktop;
import net.sf.jabref.gui.desktop.os.OSX;
import net.sf.jabref.gui.desktop.os.Windows;
+import net.sf.jabref.gui.externalfiletype.ExternalFileType;
+import net.sf.jabref.gui.externalfiletype.ExternalFileTypeEntryEditor;
+import net.sf.jabref.gui.externalfiletype.ExternalFileTypes;
+import net.sf.jabref.gui.externalfiletype.UnknownExternalFileType;
+import net.sf.jabref.gui.filelist.FileListEntry;
+import net.sf.jabref.gui.filelist.FileListEntryEditor;
+import net.sf.jabref.gui.filelist.FileListTableModel;
import net.sf.jabref.gui.undo.UndoableFieldChange;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.util.DOI;
import net.sf.jabref.logic.util.OS;
import net.sf.jabref.logic.util.io.FileUtil;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.FieldName;
import net.sf.jabref.preferences.JabRefPreferences;
@@ -61,7 +61,7 @@ public class JabRefDesktop {
String fieldName = initialFieldName;
if (FieldName.PS.equals(fieldName) || FieldName.PDF.equals(fieldName)) {
// Find the default directory for this field type:
- List<String> dir = databaseContext.getFileDirectory(fieldName);
+ List<String> dir = databaseContext.getFileDirectories(fieldName, Globals.prefs.getFileDirectoryPreferences());
Optional<File> file = FileUtil.expandFilename(link, dir);
@@ -144,7 +144,8 @@ public class JabRefDesktop {
File file = new File(link);
if (!httpLink) {
- Optional<File> tmp = FileUtil.expandFilename(databaseContext, link);
+ Optional<File> tmp = FileUtil.expandFilename(databaseContext, link,
+ Globals.prefs.getFileDirectoryPreferences());
if (tmp.isPresent()) {
file = tmp.get();
}
@@ -214,7 +215,7 @@ public class JabRefDesktop {
// User wants to change the type of this link.
// First get a model of all file links for this entry:
FileListTableModel tModel = new FileListTableModel();
- Optional<String> oldValue = entry.getFieldOptional(FieldName.FILE);
+ Optional<String> oldValue = entry.getField(FieldName.FILE);
oldValue.ifPresent(tModel::setContent);
FileListEntry flEntry = null;
// Then find which one we are looking at:
diff --git a/src/main/java/net/sf/jabref/gui/desktop/os/Linux.java b/src/main/java/net/sf/jabref/gui/desktop/os/Linux.java
index 386fd6c..1de066e 100644
--- a/src/main/java/net/sf/jabref/gui/desktop/os/Linux.java
+++ b/src/main/java/net/sf/jabref/gui/desktop/os/Linux.java
@@ -7,8 +7,8 @@ import java.io.InputStreamReader;
import java.nio.file.Paths;
import java.util.Optional;
-import net.sf.jabref.external.ExternalFileType;
-import net.sf.jabref.external.ExternalFileTypes;
+import net.sf.jabref.gui.externalfiletype.ExternalFileType;
+import net.sf.jabref.gui.externalfiletype.ExternalFileTypes;
public class Linux implements NativeDesktop {
@Override
diff --git a/src/main/java/net/sf/jabref/gui/desktop/os/OSX.java b/src/main/java/net/sf/jabref/gui/desktop/os/OSX.java
index 9864939..e9088d8 100644
--- a/src/main/java/net/sf/jabref/gui/desktop/os/OSX.java
+++ b/src/main/java/net/sf/jabref/gui/desktop/os/OSX.java
@@ -5,8 +5,8 @@ import java.io.File;
import java.io.IOException;
import java.util.Optional;
-import net.sf.jabref.external.ExternalFileType;
-import net.sf.jabref.external.ExternalFileTypes;
+import net.sf.jabref.gui.externalfiletype.ExternalFileType;
+import net.sf.jabref.gui.externalfiletype.ExternalFileTypes;
public class OSX implements NativeDesktop {
diff --git a/src/main/java/net/sf/jabref/gui/desktop/os/Windows.java b/src/main/java/net/sf/jabref/gui/desktop/os/Windows.java
index 604d201..a7c83ab 100644
--- a/src/main/java/net/sf/jabref/gui/desktop/os/Windows.java
+++ b/src/main/java/net/sf/jabref/gui/desktop/os/Windows.java
@@ -5,8 +5,8 @@ import java.io.IOException;
import java.nio.file.Paths;
import java.util.Optional;
-import net.sf.jabref.external.ExternalFileType;
-import net.sf.jabref.external.ExternalFileTypes;
+import net.sf.jabref.gui.externalfiletype.ExternalFileType;
+import net.sf.jabref.gui.externalfiletype.ExternalFileTypes;
public class Windows implements NativeDesktop {
private static String DEFAULT_EXECUTABLE_EXTENSION = ".exe";
diff --git a/src/main/java/net/sf/jabref/gui/entryeditor/EntryEditor.java b/src/main/java/net/sf/jabref/gui/entryeditor/EntryEditor.java
index 3e38130..1550ecf 100644
--- a/src/main/java/net/sf/jabref/gui/entryeditor/EntryEditor.java
+++ b/src/main/java/net/sf/jabref/gui/entryeditor/EntryEditor.java
@@ -25,7 +25,6 @@ import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
-import java.util.stream.Stream;
import javax.swing.AbstractAction;
import javax.swing.Action;
@@ -34,6 +33,7 @@ import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JLabel;
+import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
@@ -50,40 +50,39 @@ import javax.swing.event.ChangeListener;
import javax.swing.text.JTextComponent;
import net.sf.jabref.Globals;
-import net.sf.jabref.external.WriteXMPEntryEditorAction;
import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.gui.EntryContainer;
-import net.sf.jabref.gui.FieldContentSelector;
import net.sf.jabref.gui.GUIGlobals;
import net.sf.jabref.gui.IconTheme;
import net.sf.jabref.gui.JabRefFrame;
import net.sf.jabref.gui.OSXCompatibleToolbar;
import net.sf.jabref.gui.actions.Actions;
+import net.sf.jabref.gui.externalfiles.WriteXMPEntryEditorAction;
import net.sf.jabref.gui.fieldeditors.FieldEditor;
import net.sf.jabref.gui.fieldeditors.FieldEditorFocusListener;
import net.sf.jabref.gui.fieldeditors.FileListEditor;
import net.sf.jabref.gui.fieldeditors.JTextAreaWithHighlighting;
import net.sf.jabref.gui.fieldeditors.TextField;
import net.sf.jabref.gui.help.HelpAction;
+import net.sf.jabref.gui.importer.fetcher.EntryFetchers;
import net.sf.jabref.gui.keyboard.KeyBinding;
import net.sf.jabref.gui.menus.ChangeEntryTypeMenu;
+import net.sf.jabref.gui.mergeentries.EntryFetchAndMergeWorker;
+import net.sf.jabref.gui.specialfields.SpecialFieldUpdateListener;
import net.sf.jabref.gui.undo.NamedCompound;
import net.sf.jabref.gui.undo.UndoableChangeType;
import net.sf.jabref.gui.undo.UndoableFieldChange;
import net.sf.jabref.gui.undo.UndoableKeyChange;
import net.sf.jabref.gui.undo.UndoableRemoveEntry;
-import net.sf.jabref.gui.util.FocusRequester;
import net.sf.jabref.gui.util.component.CheckBoxMessage;
import net.sf.jabref.gui.util.component.VerticalLabelUI;
import net.sf.jabref.logic.TypedBibEntry;
import net.sf.jabref.logic.autocompleter.AutoCompleter;
import net.sf.jabref.logic.bibtex.BibEntryWriter;
import net.sf.jabref.logic.bibtex.LatexFieldFormatter;
-import net.sf.jabref.logic.bibtex.LatexFieldFormatterPreferences;
-import net.sf.jabref.logic.bibtexkeypattern.BibtexKeyPatternPreferences;
import net.sf.jabref.logic.bibtexkeypattern.BibtexKeyPatternUtil;
import net.sf.jabref.logic.help.HelpFile;
-import net.sf.jabref.logic.importer.ImportFormatPreferences;
+import net.sf.jabref.logic.importer.EntryBasedFetcher;
import net.sf.jabref.logic.importer.ParserResult;
import net.sf.jabref.logic.importer.fileformat.BibtexParser;
import net.sf.jabref.logic.l10n.Localization;
@@ -98,11 +97,10 @@ import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.EntryConverter;
import net.sf.jabref.model.entry.EntryType;
import net.sf.jabref.model.entry.FieldName;
-import net.sf.jabref.model.entry.FieldProperties;
+import net.sf.jabref.model.entry.FieldProperty;
import net.sf.jabref.model.entry.InternalBibtexFields;
-import net.sf.jabref.model.event.FieldChangedEvent;
+import net.sf.jabref.model.entry.event.FieldChangedEvent;
import net.sf.jabref.preferences.JabRefPreferences;
-import net.sf.jabref.specialfields.SpecialFieldUpdateListener;
import com.google.common.eventbus.Subscribe;
import org.apache.commons.logging.Log;
@@ -119,33 +117,33 @@ import org.apache.commons.logging.LogFactory;
* update themselves if the change is made from somewhere else.
*/
public class EntryEditor extends JPanel implements EntryContainer {
-
private static final Log LOGGER = LogFactory.getLog(EntryEditor.class);
- // A reference to the entry this object works on.
+ /** A reference to the entry this object works on. */
private BibEntry entry;
- // The currently displayed type
+ /** The currently displayed type */
private final String displayedBibEntryType;
- // The action concerned with closing the window.
- private final CloseAction closeAction;
-
- // The action that deletes the current entry, and closes the editor.
+ /** The action concerned with closing the window. */
+ private final CloseAction closeAction = new CloseAction();
+ /** The action that deletes the current entry, and closes the editor. */
private final DeleteAction deleteAction = new DeleteAction();
- // Actions for switching to next/previous entry.
+ /** The action for switching to the next entry. */
private final AbstractAction nextEntryAction = new NextEntryAction();
+ /** The action for switching to the previous entry. */
private final AbstractAction prevEntryAction = new PrevEntryAction();
- // The action concerned with storing a field value.
- private final StoreFieldAction storeFieldAction;
+ /** The action concerned with storing a field value. */
+ private final StoreFieldAction storeFieldAction = new StoreFieldAction();
- // The actions concerned with switching the panels.
+ /** The action for switching to the next tab */
private final SwitchLeftAction switchLeftAction = new SwitchLeftAction();
+ /** The action for switching to the previous tab */
private final SwitchRightAction switchRightAction = new SwitchRightAction();
- // The action which generates a bibtexkey for this entry.
- private final GenerateKeyAction generateKeyAction;
+ /** The action which generates a BibTeX key for this entry. */
+ private final GenerateKeyAction generateKeyAction = new GenerateKeyAction();
// UGLY HACK to have a pointer to the fileListEditor to call autoSetLinks()
private FileListEditor fileListEditor;
@@ -165,30 +163,33 @@ public class EntryEditor extends JPanel implements EntryContainer {
private final BasePanel panel;
- private final Set<FieldContentSelector> contentSelectors = new HashSet<>();
-
- private boolean updateSource = true; // This can be set to false to stop the source
- private boolean movingToDifferentEntry; // Indicates that we are about to go to the next or previous entry
+ /**
+ * This can be set to false to stop the source text area from getting updated. This is used in cases where the
+ * source couldn't be parsed, and the user is given the option to edit it.
+ */
+ private boolean updateSource = true;
+ /** Indicates that we are about to go to the next or previous entry */
+ private boolean movingToDifferentEntry;
private boolean validEntry = true;
private final List<Object> tabs = new ArrayList<>();
- // text area from getting updated. This is used in cases where the source
- // couldn't be parsed, and the user is given the option to edit it.
- private boolean lastSourceAccepted = true; // This indicates whether the last
+ private boolean lastFieldAccepted = true;
+
+ /**
+ * This indicates whether the last attempt at parsing the source was successful. It is used to determine whether
+ * the dialog should close; it should stay open if the user received an error message about the source,
+ * whatever he or she chose to do about it.
+ */
+ private boolean lastSourceAccepted = true;
- // attempt
- // at parsing the source was successful. It is used to determine whether the
- // dialog should close; it should stay open if the user received an error
- // message about the source, whatever he or she chose to do about it.
- private String lastSourceStringAccepted; // This is used to prevent double
+ /** This is used to prevent double updates after editing source. */
+ private String lastSourceStringAccepted;
- // fields.
- // These values can be used to calculate the preferred height for the form.
- // reqW starts at 1 because it needs room for the bibtex key field.
- private int sourceIndex = -1; // The index the source panel has in tabbed.
+ /** The index the source panel has in tabbed. */
+ private int sourceIndex = -1;
- private final HelpAction helpAction;
+ private final HelpAction helpAction = new HelpAction(HelpFile.ENTRY_EDITOR, IconTheme.JabRefIcon.HELP.getIcon());
private final UndoAction undoAction = new UndoAction();
@@ -196,6 +197,8 @@ public class EntryEditor extends JPanel implements EntryContainer {
private final TabListener tabListener = new TabListener();
+ private final List<SearchQueryHighlightListener> searchListeners = new ArrayList<>();
+
public EntryEditor(JabRefFrame frame, BasePanel panel, BibEntry entry) {
this.frame = frame;
@@ -207,10 +210,6 @@ public class EntryEditor extends JPanel implements EntryContainer {
displayedBibEntryType = entry.getType();
- helpAction = new HelpAction(HelpFile.ENTRY_EDITOR, IconTheme.JabRefIcon.HELP.getIcon());
- closeAction = new CloseAction();
- generateKeyAction = new GenerateKeyAction();
- storeFieldAction = new StoreFieldAction();
writeXmp = new WriteXMPEntryEditorAction(panel, this);
BorderLayout borderLayout = new BorderLayout();
@@ -234,24 +233,22 @@ public class EntryEditor extends JPanel implements EntryContainer {
tabbed.removeAll();
tabs.clear();
- EntryType type = EntryTypes.getTypeOrDefault(entry.getType(), this.frame.getCurrentBasePanel().getBibDatabaseContext().getMode());
+ EntryType type = EntryTypes.getTypeOrDefault(entry.getType(),
+ this.frame.getCurrentBasePanel().getBibDatabaseContext().getMode());
// required fields
- List<String> requiredFields = addRequiredTab(type);
+ addRequiredTab(type);
// optional fields
- List<String> displayedOptionalFields = new ArrayList<>();
+ Set<String> deprecatedFields = new HashSet<>(EntryConverter.FIELD_ALIASES_TEX_TO_LTX.keySet());
+ Set<String> usedOptionalFieldsDeprecated = new HashSet<>(deprecatedFields);
if ((type.getOptionalFields() != null) && !type.getOptionalFields().isEmpty()) {
if (!frame.getCurrentBasePanel().getBibDatabaseContext().isBiblatexMode()) {
addOptionalTab(type);
} else {
- displayedOptionalFields.addAll(type.getPrimaryOptionalFields());
- displayedOptionalFields.addAll(type.getSecondaryOptionalFields());
-
addOptionalTab(type);
- Set<String> deprecatedFields = new HashSet<>(EntryConverter.FIELD_ALIASES_TEX_TO_LTX.keySet());
deprecatedFields.add(FieldName.YEAR);
deprecatedFields.add(FieldName.MONTH);
List<String> secondaryOptionalFields = type.getSecondaryOptionalFields();
@@ -268,17 +265,19 @@ public class EntryEditor extends JPanel implements EntryContainer {
}
// Get all optional fields which are deprecated
- Set<String> usedOptionalFieldsDeprecated = new HashSet<>(deprecatedFields);
usedOptionalFieldsDeprecated.retainAll(optionalFieldsAndAliases);
+ // Get other deprecated fields
+ usedOptionalFieldsDeprecated.add(FieldName.MONTH);
+
// Add tabs
EntryEditorTab optPan2 = new EntryEditorTab(frame, panel, optionalFieldsNotPrimaryOrDeprecated, this,
false, true, Localization.lang("Optional fields 2"));
if (optPan2.fileListEditor != null) {
fileListEditor = optPan2.fileListEditor;
}
- tabbed.addTab(Localization.lang("Optional fields 2"), IconTheme.JabRefIcon.OPTIONAL.getSmallIcon(), optPan2
- .getPane(), Localization.lang("Show optional fields"));
+ tabbed.addTab(Localization.lang("Optional fields 2"), IconTheme.JabRefIcon.OPTIONAL.getSmallIcon(),
+ optPan2.getPane(), Localization.lang("Show optional fields"));
tabs.add(optPan2);
if (!usedOptionalFieldsDeprecated.isEmpty()) {
@@ -288,16 +287,21 @@ public class EntryEditor extends JPanel implements EntryContainer {
if (optPan3.fileListEditor != null) {
fileListEditor = optPan3.fileListEditor;
}
- tabbed.addTab(Localization.lang("Deprecated fields"), IconTheme.JabRefIcon.OPTIONAL.getSmallIcon(), optPan3
- .getPane(), Localization.lang("Show deprecated BibTeX fields"));
+ tabbed.addTab(Localization.lang("Deprecated fields"), IconTheme.JabRefIcon.OPTIONAL.getSmallIcon(),
+ optPan3.getPane(), Localization.lang("Show deprecated BibTeX fields"));
tabs.add(optPan3);
}
}
}
// other fields
- List<String> displayedFields = Stream.concat(requiredFields.stream(), displayedOptionalFields.stream()).map(String::toLowerCase).collect(Collectors.toList());
- List<String> otherFields = entry.getFieldNames().stream().map(String::toLowerCase).filter(f -> !displayedFields.contains(f)).collect(Collectors.toList());
+ List<String> displayedFields = type.getAllFields().stream().map(String::toLowerCase)
+ .collect(Collectors.toList());
+ List<String> otherFields = entry.getFieldNames().stream().map(String::toLowerCase)
+ .filter(f -> !displayedFields.contains(f)).collect(Collectors.toList());
+ if (!usedOptionalFieldsDeprecated.isEmpty()) {
+ otherFields.removeAll(usedOptionalFieldsDeprecated);
+ }
otherFields.remove(BibEntry.KEY_FIELD);
otherFields.removeAll(Globals.prefs.getCustomTabFieldNames());
@@ -325,11 +329,12 @@ public class EntryEditor extends JPanel implements EntryContainer {
}
private void addSourceTab() {
- srcPanel.setName(Localization.lang("BibTeX source"));
- tabbed.addTab(Localization.lang("BibTeX source"), IconTheme.JabRefIcon.SOURCE.getSmallIcon(), srcPanel,
- Localization.lang("Show/edit BibTeX source"));
+ String panelName = Localization.lang("%0 source", panel.getBibDatabaseContext().getMode().getFormattedName());
+ String toolTip = Localization.lang("Show/edit %0 source", panel.getBibDatabaseContext().getMode().getFormattedName());
+ srcPanel.setName(panelName);
+ tabbed.addTab(panelName, IconTheme.JabRefIcon.SOURCE.getSmallIcon(), srcPanel, toolTip);
tabs.add(srcPanel);
- sourceIndex = tabs.size() - 1; // Set the sourceIndex variable.
+ sourceIndex = tabs.size() - 1;
srcPanel.setFocusCycleRoot(true);
}
@@ -395,8 +400,7 @@ public class EntryEditor extends JPanel implements EntryContainer {
toolBar.setMargin(new Insets(0, 0, 0, 2));
- // The toolbar carries all the key bindings that are valid for the whole
- // window.
+ // The toolbar carries all the key bindings that are valid for the whole window.
ActionMap actionMap = toolBar.getActionMap();
InputMap inputMap = toolBar.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
@@ -439,6 +443,27 @@ public class EntryEditor extends JPanel implements EntryContainer {
toolBar.add(writeXmp);
+ JPopupMenu fetcherPopup = new JPopupMenu();
+ for(EntryBasedFetcher fetcher : EntryFetchers.getEntryBasedFetchers()) {
+ fetcherPopup.add(new JMenuItem(new AbstractAction(fetcher.getName()) {
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ new EntryFetchAndMergeWorker(panel, getEntry(), fetcher).execute();
+ }
+ }));
+ }
+ JButton fetcherButton = new JButton(IconTheme.JabRefIcon.REFRESH.getIcon());
+ fetcherButton.setToolTipText(Localization.lang("Update with bibliographic information from the web"));
+ fetcherButton.addMouseListener(new MouseAdapter() {
+
+ @Override
+ public void mousePressed(MouseEvent e) {
+ fetcherPopup.show(e.getComponent(), e.getX(), e.getY());
+ }
+ });
+ toolBar.add(fetcherButton);
+
toolBar.addSeparator();
toolBar.add(deleteAction);
@@ -460,22 +485,6 @@ public class EntryEditor extends JPanel implements EntryContainer {
}
/**
- * Rebuild the field tabs. This is called e.g. when a new content selector
- * has been added.
- */
- public void rebuildPanels() {
- // Remove change listener, because the rebuilding causes meaningless
- // events and trouble:
- tabbed.removeChangeListener(tabListener);
-
- setupFieldPanels();
- // Add the change listener again:
- tabbed.addChangeListener(tabListener);
- revalidate();
- repaint();
- }
-
- /**
* getExtra checks the field name against InternalBibtexFields.getFieldExtras(name).
* If the name has an entry, the proper component to be shown is created and
* returned. Otherwise, null is returned. In addition, e.g. listeners can be
@@ -487,52 +496,47 @@ public class EntryEditor extends JPanel implements EntryContainer {
public Optional<JComponent> getExtra(final FieldEditor editor) {
final String fieldName = editor.getFieldName();
- final Set<FieldProperties> fieldExtras = InternalBibtexFields.getFieldExtras(fieldName);
+ final Set<FieldProperty> fieldExtras = InternalBibtexFields.getFieldProperties(fieldName);
// timestamp or a other field with datepicker command
if (Globals.prefs.get(JabRefPreferences.TIME_STAMP_FIELD).equals(fieldName)
- || fieldExtras.contains(FieldProperties.DATE)) {
+ || fieldExtras.contains(FieldProperty.DATE)) {
// double click AND datefield => insert the current date (today)
return FieldExtraComponents.getDateTimeExtraComponent(editor,
- fieldExtras.contains(FieldProperties.DATE), fieldExtras.contains(FieldProperties.ISO_DATE));
- } else if (fieldExtras.contains(FieldProperties.EXTERNAL)) {
+ fieldExtras.contains(FieldProperty.DATE), fieldExtras.contains(FieldProperty.ISO_DATE));
+ } else if (fieldExtras.contains(FieldProperty.EXTERNAL)) {
return FieldExtraComponents.getExternalExtraComponent(panel, editor);
- } else if (fieldExtras.contains(FieldProperties.JOURNAL_NAME)) {
+ } else if (fieldExtras.contains(FieldProperty.JOURNAL_NAME)) {
// Add controls for switching between abbreviated and full journal names.
// If this field also has a FieldContentSelector, we need to combine these.
- return FieldExtraComponents.getJournalExtraComponent(frame, panel, editor, entry, contentSelectors,
- getStoreFieldAction());
- } else if (!panel.getBibDatabaseContext().getMetaData().getContentSelectors(fieldName).isEmpty()) {
- return FieldExtraComponents.getSelectorExtraComponent(frame, panel, editor, contentSelectors, getStoreFieldAction());
- } else if (fieldExtras.contains(FieldProperties.DOI)) {
+ return FieldExtraComponents.getJournalExtraComponent(panel, editor, entry, getStoreFieldAction());
+ } else if (fieldExtras.contains(FieldProperty.DOI)) {
return FieldExtraComponents.getDoiExtraComponent(panel, this, editor);
- } else if (fieldExtras.contains(FieldProperties.EPRINT)) {
+ } else if (fieldExtras.contains(FieldProperty.EPRINT)) {
return FieldExtraComponents.getEprintExtraComponent(panel, this, editor);
- } else if (fieldExtras.contains(FieldProperties.ISBN)) {
+ } else if (fieldExtras.contains(FieldProperty.ISBN)) {
return FieldExtraComponents.getIsbnExtraComponent(panel, this, editor);
- } else if (fieldExtras.contains(FieldProperties.OWNER)) {
+ } else if (fieldExtras.contains(FieldProperty.OWNER)) {
return FieldExtraComponents.getSetOwnerExtraComponent(editor, getStoreFieldAction());
- } else if (fieldExtras.contains(FieldProperties.YES_NO)) {
+ } else if (fieldExtras.contains(FieldProperty.YES_NO)) {
return FieldExtraComponents.getYesNoExtraComponent(editor, this);
- } else if (fieldExtras.contains(FieldProperties.MONTH)) {
+ } else if (fieldExtras.contains(FieldProperty.MONTH)) {
return FieldExtraComponents.getMonthExtraComponent(editor, this, frame.getCurrentBasePanel().getBibDatabaseContext().getMode());
- } else if (fieldExtras.contains(FieldProperties.GENDER)) {
+ } else if (fieldExtras.contains(FieldProperty.GENDER)) {
return FieldExtraComponents.getGenderExtraComponent(editor, this);
- } else if (fieldExtras.contains(FieldProperties.EDITOR_TYPE)) {
+ } else if (fieldExtras.contains(FieldProperty.EDITOR_TYPE)) {
return FieldExtraComponents.getEditorTypeExtraComponent(editor, this);
- } else if (fieldExtras.contains(FieldProperties.PAGINATION)) {
+ } else if (fieldExtras.contains(FieldProperty.PAGINATION)) {
return FieldExtraComponents.getPaginationExtraComponent(editor, this);
- } else if (fieldExtras.contains(FieldProperties.TYPE)) {
+ } else if (fieldExtras.contains(FieldProperty.TYPE)) {
return FieldExtraComponents.getTypeExtraComponent(editor, this, "patent".equalsIgnoreCase(entry.getType()));
- } else if (fieldExtras.contains(FieldProperties.CROSSREF)) {
- return FieldExtraComponents.getCrossrefExtraComponent(editor, frame.getCurrentBasePanel());
}
return Optional.empty();
}
private void setupSourcePanel() {
source = new JTextAreaWithHighlighting();
- panel.getSearchBar().getSearchQueryHighlightObservable().addSearchListener((SearchQueryHighlightListener) source);
+ addSearchListener((SearchQueryHighlightListener) source);
source.setEditable(true);
source.setLineWrap(true);
@@ -550,6 +554,17 @@ public class EntryEditor extends JPanel implements EntryContainer {
srcPanel.add(scrollPane, BorderLayout.CENTER);
}
+ void addSearchListener(SearchQueryHighlightListener listener) {
+ searchListeners.add(listener);
+ panel.frame().getGlobalSearchBar().getSearchQueryHighlightObservable().addSearchListener(listener);
+ }
+
+ private void removeSearchListeners() {
+ for (SearchQueryHighlightListener listener : searchListeners) {
+ panel.frame().getGlobalSearchBar().getSearchQueryHighlightObservable().removeSearchListener(listener);
+ }
+ }
+
public void updateSource() {
if (updateSource) {
@@ -558,25 +573,12 @@ public class EntryEditor extends JPanel implements EntryContainer {
source.setText(srcString);
lastSourceStringAccepted = srcString;
- //////////////////////////////////////////////////////////
// Set the current Entry to be selected.
- // Fixes the bug of losing selection after, e.g.
- // an autogeneration of a BibTeX key.
- // - ILC (16/02/2010) -
- //////////////////////////////////////////////////////////
- SwingUtilities.invokeLater(() -> {
- final int row = panel.getMainTable().findEntry(entry);
- if (row >= 0) {
- if (panel.getMainTable().getSelectedRowCount() == 0) {
- panel.getMainTable().setRowSelectionInterval(row, row);
- }
- panel.getMainTable().ensureVisible(row);
- }
- });
+ // Fixes the bug of losing selection after, e.g. an autogeneration of a BibTeX key.
+ panel.highlightEntry(entry);
} catch (IOException ex) {
source.setText(ex.getMessage() + "\n\n" +
- Localization.lang("Correct the entry, and "
- + "reopen editor to display/edit source."));
+ Localization.lang("Correct the entry, and reopen editor to display/edit source."));
source.setEditable(false);
LOGGER.debug("Incorrect entry", ex);
}
@@ -584,10 +586,10 @@ public class EntryEditor extends JPanel implements EntryContainer {
}
}
- public static String getSourceString(BibEntry entry, BibDatabaseMode type) throws IOException {
+ private static String getSourceString(BibEntry entry, BibDatabaseMode type) throws IOException {
StringWriter stringWriter = new StringWriter(200);
LatexFieldFormatter formatter = LatexFieldFormatter
- .buildIgnoreHashes(LatexFieldFormatterPreferences.fromPreferences(Globals.prefs));
+ .buildIgnoreHashes(Globals.prefs.getLatexFieldFormatterPreferences());
new BibEntryWriter(formatter, false).writeWithoutPrependedNewlines(entry, stringWriter, type);
return stringWriter.getBuffer().toString();
@@ -616,8 +618,6 @@ public class EntryEditor extends JPanel implements EntryContainer {
inputMap.put(Globals.getKeyPrefs().getKey(KeyBinding.HELP), "help");
actionMap.put("help", getHelpAction());
- inputMap.put(Globals.getKeyPrefs().getKey(KeyBinding.SAVE_DATABASE), "save");
- actionMap.put("save", getSaveDatabaseAction());
inputMap.put(Globals.getKeyPrefs().getKey(KeyBinding.NEXT_TAB), "nexttab");
actionMap.put("nexttab", frame.nextTab);
@@ -647,9 +647,9 @@ public class EntryEditor extends JPanel implements EntryContainer {
Object activeTab = tabs.get(tabbed.getSelectedIndex());
if (activeTab instanceof EntryEditorTab) {
- ((EntryEditorTab) activeTab).activate();
+ ((EntryEditorTab) activeTab).focus();
} else {
- new FocusRequester(source);
+ source.requestFocus();
}
}
@@ -676,17 +676,6 @@ public class EntryEditor extends JPanel implements EntryContainer {
}
/**
- * Centers the given row, and highlights it.
- *
- * @param row an <code>int</code> value
- */
- private void scrollTo(int row) {
- movingToDifferentEntry = true;
- panel.getMainTable().setRowSelectionInterval(row, row);
- panel.getMainTable().ensureVisible(row);
- }
-
- /**
* Makes sure the current edit is stored.
*/
public void storeCurrentEdit() {
@@ -700,15 +689,6 @@ public class EntryEditor extends JPanel implements EntryContainer {
}
/**
- * Returns the index of the active (visible) panel.
- *
- * @return an <code>int</code> value
- */
- public int getVisiblePanel() {
- return tabbed.getSelectedIndex();
- }
-
- /**
* Returns the name of the currently selected component.
*/
public String getVisiblePanelName() {
@@ -733,41 +713,15 @@ public class EntryEditor extends JPanel implements EntryContainer {
EntryEditorTab entryEditorTab = (EntryEditorTab) tab;
setVisiblePanel(entryEditorTab.getTabTitle());
entryEditorTab.setActive(fieldName);
- entryEditorTab.activate();
+ entryEditorTab.focus();
}
}
}
- /**
- * Updates this editor to show the given entry, regardless of type
- * correspondence.
- *
- * @param switchEntry a <code>BibEntry</code> value
- */
- public synchronized void switchTo(BibEntry switchEntry) {
- storeCurrentEdit();
-
- // Remove this instance as property listener for the entry:
- this.entry.unregisterListener(this);
-
- this.entry = switchEntry;
-
- // Register as property listener for the new entry:
- this.entry.registerListener(this);
-
- updateAllFields();
- validateAllFields();
- updateSource();
- panel.newEntryShowing(switchEntry);
-
- }
-
private boolean storeSource() {
- BibtexParser bibtexParser = new BibtexParser(new StringReader(source.getText()),
- ImportFormatPreferences.fromPreferences(Globals.prefs));
-
+ BibtexParser bibtexParser = new BibtexParser(Globals.prefs.getImportFormatPreferences());
try {
- ParserResult parserResult = bibtexParser.parse();
+ ParserResult parserResult = bibtexParser.parse(new StringReader(source.getText()));
BibDatabase database = parserResult.getDatabase();
if (database.getEntryCount() > 1) {
@@ -787,11 +741,12 @@ public class EntryEditor extends JPanel implements EntryContainer {
BibEntry newEntry = database.getEntries().get(0);
String newKey = newEntry.getCiteKeyOptional().orElse(null);
boolean entryChanged = false;
- boolean duplicateWarning = false;
boolean emptyWarning = (newKey == null) || newKey.isEmpty();
- if (panel.getDatabase().setCiteKeyForEntry(entry, newKey)) {
- duplicateWarning = true;
+ if (newKey != null) {
+ entry.setCiteKey(newKey);
+ } else {
+ entry.clearCiteKey();
}
// First, remove fields that the user has removed.
@@ -810,11 +765,11 @@ public class EntryEditor extends JPanel implements EntryContainer {
// Then set all fields that have been set by the user.
for (Entry<String, String> field : newEntry.getFieldMap().entrySet()) {
String fieldName = field.getKey();
- String oldValue = entry.getFieldOptional(fieldName).orElse(null);
+ String oldValue = entry.getField(fieldName).orElse(null);
String newValue = field.getValue();
if (!Objects.equals(oldValue, newValue)) {
// Test if the field is legally set.
- new LatexFieldFormatter(LatexFieldFormatterPreferences.fromPreferences(Globals.prefs))
+ new LatexFieldFormatter(Globals.prefs.getLatexFieldFormatterPreferences())
.format(newValue, fieldName);
compound.addEdit(new UndoableFieldChange(entry, fieldName, oldValue, newValue));
@@ -837,7 +792,7 @@ public class EntryEditor extends JPanel implements EntryContainer {
panel.getUndoManager().addEdit(compound);
- if (duplicateWarning) {
+ if (panel.getDatabase().getDuplicationChecker().isDuplicateCiteKeyExisting(entry)) {
warnDuplicateBibtexkey();
} else if (emptyWarning) {
warnEmptyBibtexkey();
@@ -854,12 +809,7 @@ public class EntryEditor extends JPanel implements EntryContainer {
// TODO: does updating work properly after source stored?
panel.markBaseChanged();
- SwingUtilities.invokeLater(() -> {
- final int row = panel.getMainTable().findEntry(entry);
- if (row >= 0) {
- panel.getMainTable().ensureVisible(row);
- }
- });
+ panel.highlightEntry(entry);
return true;
} catch (IllegalStateException | IOException ex) {
@@ -872,13 +822,16 @@ public class EntryEditor extends JPanel implements EntryContainer {
Object[] options = {Localization.lang("Edit"), Localization.lang("Revert to original source")};
- int answer = JOptionPane.showOptionDialog(frame, Localization.lang("Error") + ": " + ex.getMessage(),
- Localization.lang("Problem with parsing entry"), JOptionPane.YES_NO_OPTION,
- JOptionPane.ERROR_MESSAGE, null, options, options[0]);
+ if (!SwingUtilities.isEventDispatchThread()) {
+ int answer = JOptionPane.showOptionDialog(frame, Localization.lang("Error") + ": " + ex.getMessage(),
+ Localization.lang("Problem with parsing entry"), JOptionPane.YES_NO_OPTION,
+ JOptionPane.ERROR_MESSAGE, null, options, options[0]);
- if (answer != 0) {
- updateSource = true;
- updateSource();
+ if (answer != 0) {
+ updateSource = true;
+ lastSourceAccepted = true;
+ updateSource();
+ }
}
LOGGER.debug("Incorrect source", ex);
@@ -907,28 +860,10 @@ public class EntryEditor extends JPanel implements EntryContainer {
}
/**
- * Removes the "invalid field" color from all text areas.
- */
- public void validateAllFields() {
- for (Object tab : tabs) {
- if (tab instanceof EntryEditorTab) {
- ((EntryEditorTab) tab).validateAllFields();
- }
- }
- }
-
- public void updateAllContentSelectors() {
- if (!contentSelectors.isEmpty()) {
- for (FieldContentSelector contentSelector : contentSelectors) {
- contentSelector.rebuildComboBox();
- }
- }
- }
-
- /**
* Update the JTextArea when a field has changed.
*/
@Subscribe
+ @SuppressWarnings("unused")
public void listen(FieldChangedEvent fieldChangedEvent) {
String newValue = fieldChangedEvent.getNewValue() == null ? "" : fieldChangedEvent.getNewValue();
if (SwingUtilities.isEventDispatchThread()) {
@@ -944,8 +879,13 @@ public class EntryEditor extends JPanel implements EntryContainer {
public void setMovingToDifferentEntry() {
movingToDifferentEntry = true;
+ unregisterListeners();
}
+ private void unregisterListeners() {
+ entry.unregisterListener(this);
+ removeSearchListeners();
+ }
private class TypeButton extends JButton {
public TypeButton() {
@@ -999,17 +939,10 @@ public class EntryEditor extends JPanel implements EntryContainer {
}
}
+ /**
+ * Focus listener that fires the storeFieldAction when a TextArea loses focus.
+ */
private class FieldListener extends FocusAdapter {
-
- /*
- * Focus listener that fires the storeFieldAction when a TextArea
- * loses focus.
- */
- @Override
- public void focusGained(FocusEvent e) {
- // Do nothing
- }
-
@Override
public void focusLost(FocusEvent event) {
if (!event.isTemporary()) {
@@ -1021,10 +954,8 @@ public class EntryEditor extends JPanel implements EntryContainer {
private class TabListener implements ChangeListener {
@Override
public void stateChanged(ChangeEvent event) {
- // We tell the editor tab to update all its fields.
- // This makes sure they are updated even if the tab we
- // just left contained one
- // or more of the same fields as this one:
+ // We tell the editor tab to update all its fields. This makes sure they are updated even if the tab we
+ // just left contained one or more of the same fields as this one:
SwingUtilities.invokeLater(() -> {
Object activeTab = tabs.get(tabbed.getSelectedIndex());
if (activeTab instanceof EntryEditorTab) {
@@ -1058,6 +989,25 @@ public class EntryEditor extends JPanel implements EntryContainer {
}
}
+ public void close() {
+ if (tabbed.getSelectedComponent() == srcPanel) {
+ updateField(source);
+ if (lastSourceAccepted) {
+ panel.entryEditorClosing(EntryEditor.this);
+ } else {
+ panel.runCommand(Actions.SAVE);
+ lastSourceAccepted = true;
+ }
+ } else {
+ if (lastFieldAccepted) {
+ panel.entryEditorClosing(EntryEditor.this);
+ } else {
+ panel.runCommand(Actions.SAVE);
+ lastFieldAccepted = true;
+ }
+ }
+ }
+
class CloseAction extends AbstractAction {
public CloseAction() {
super(Localization.lang("Close window"), IconTheme.JabRefIcon.CLOSE.getSmallIcon());
@@ -1066,18 +1016,11 @@ public class EntryEditor extends JPanel implements EntryContainer {
@Override
public void actionPerformed(ActionEvent e) {
- if (tabbed.getSelectedComponent() == srcPanel) {
- updateField(source);
- if (lastSourceAccepted) {
- panel.entryEditorClosing(EntryEditor.this);
- }
- } else {
- panel.entryEditorClosing(EntryEditor.this);
- }
+ close();
}
}
- public class StoreFieldAction extends AbstractAction {
+ class StoreFieldAction extends AbstractAction {
public StoreFieldAction() {
super("Store field value");
@@ -1109,17 +1052,22 @@ public class EntryEditor extends JPanel implements EntryContainer {
if ((cleaned == null) || cleaned.equals(newValue)) {
textField.setValidBackgroundColor();
} else {
- JOptionPane.showMessageDialog(frame, Localization.lang("Invalid BibTeX key"),
- Localization.lang("Error setting field"), JOptionPane.ERROR_MESSAGE);
+ lastFieldAccepted = false;
textField.setInvalidBackgroundColor();
+ if (!SwingUtilities.isEventDispatchThread()) {
+ JOptionPane.showMessageDialog(frame, Localization.lang("Invalid BibTeX key"),
+ Localization.lang("Error setting field"), JOptionPane.ERROR_MESSAGE);
+ requestFocus();
+ }
return;
}
- boolean isDuplicate = panel.getDatabase().setCiteKeyForEntry(entry, newValue);
-
if (newValue == null) {
+ entry.clearCiteKey();
warnEmptyBibtexkey();
} else {
+ entry.setCiteKey(newValue);
+ boolean isDuplicate = panel.getDatabase().getDuplicationChecker().isDuplicateCiteKeyExisting(entry);
if (isDuplicate) {
warnDuplicateBibtexkey();
} else {
@@ -1128,7 +1076,7 @@ public class EntryEditor extends JPanel implements EntryContainer {
}
// Add an UndoableKeyChange to the baseframe's undoManager.
- UndoableKeyChange undoableKeyChange = new UndoableKeyChange(panel.getDatabase(), entry, oldValue, newValue);
+ UndoableKeyChange undoableKeyChange = new UndoableKeyChange(entry, oldValue, newValue);
if (updateTimeStampIsSet()) {
NamedCompound ce = new NamedCompound(undoableKeyChange.getPresentationName());
ce.addEdit(undoableKeyChange);
@@ -1162,22 +1110,23 @@ public class EntryEditor extends JPanel implements EntryContainer {
set = entry.hasField(fieldEditor.getFieldName());
} else {
set = !((entry.hasField(fieldEditor.getFieldName()))
- && toSet.equals(entry.getFieldOptional(fieldEditor.getFieldName()).orElse(null)));
+ && toSet.equals(entry.getField(fieldEditor.getFieldName()).orElse(null)));
}
- if (set) {
+ if (!set) {
+ // We set the field and label color.
+ fieldEditor.setValidBackgroundColor();
+ } else {
try {
- // The following statement attempts to write the
- // new contents into a StringWriter, and this will
- // cause an IOException if the field is not
- // properly formatted. If that happens, the field
+ // The following statement attempts to write the new contents into a StringWriter, and this will
+ // cause an IOException if the field is not properly formatted. If that happens, the field
// is not stored and the textarea turns red.
if (toSet != null) {
- new LatexFieldFormatter(LatexFieldFormatterPreferences.fromPreferences(Globals.prefs))
- .format(toSet, fieldEditor.getFieldName());
+ new LatexFieldFormatter(Globals.prefs.getLatexFieldFormatterPreferences()).format(toSet,
+ fieldEditor.getFieldName());
}
- String oldValue = entry.getFieldOptional(fieldEditor.getFieldName()).orElse(null);
+ String oldValue = entry.getField(fieldEditor.getFieldName()).orElse(null);
if (toSet == null) {
entry.clearField(fieldEditor.getFieldName());
@@ -1194,7 +1143,8 @@ public class EntryEditor extends JPanel implements EntryContainer {
}
// Add an UndoableFieldChange to the baseframe's undoManager.
- UndoableFieldChange undoableFieldChange = new UndoableFieldChange(entry, fieldEditor.getFieldName(), oldValue, toSet);
+ UndoableFieldChange undoableFieldChange = new UndoableFieldChange(entry,
+ fieldEditor.getFieldName(), oldValue, toSet);
if (updateTimeStampIsSet()) {
NamedCompound ce = new NamedCompound(undoableFieldChange.getPresentationName());
ce.addEdit(undoableFieldChange);
@@ -1211,33 +1161,27 @@ public class EntryEditor extends JPanel implements EntryContainer {
updateSource();
panel.markBaseChanged();
} catch (IllegalArgumentException ex) {
- JOptionPane.showMessageDialog(frame, Localization.lang("Error") + ": " + ex.getMessage(),
- Localization.lang("Error setting field"), JOptionPane.ERROR_MESSAGE);
+ lastFieldAccepted = false;
fieldEditor.setInvalidBackgroundColor();
- LOGGER.debug("Error setting field", ex);
+ if (!SwingUtilities.isEventDispatchThread()) {
+ JOptionPane.showMessageDialog(frame, Localization.lang("Error") + ": " + ex.getMessage(),
+ Localization.lang("Error setting field"), JOptionPane.ERROR_MESSAGE);
+ LOGGER.debug("Error setting field", ex);
+ requestFocus();
+ }
}
- } else {
- // set == false
- // We set the field and label color.
- fieldEditor.setValidBackgroundColor();
}
if (fieldEditor.getTextComponent().hasFocus()) {
fieldEditor.setBackground(GUIGlobals.ACTIVE_EDITOR_COLOR);
}
- } else if (source.isEditable()
- && !source.getText().equals(lastSourceStringAccepted)) {
+ } else if (source.isEditable() && !source.getText().equals(lastSourceStringAccepted)) {
validEntry = storeSource();
}
// Make sure we scroll to the entry if it moved in the table.
// Should only be done if this editor is currently showing:
if (!movingAway && isShowing()) {
- SwingUtilities.invokeLater(() -> {
- final int row = panel.getMainTable().findEntry(entry);
- if (row >= 0) {
- panel.getMainTable().ensureVisible(row);
- }
- });
+ panel.highlightEntry(entry);
}
}
}
@@ -1279,22 +1223,7 @@ public class EntryEditor extends JPanel implements EntryContainer {
@Override
public void actionPerformed(ActionEvent e) {
-
- int thisRow = panel.getMainTable().findEntry(entry);
- int newRow;
-
- if ((thisRow + 1) < panel.getDatabase().getEntryCount()) {
- newRow = thisRow + 1;
- } else if (thisRow > 0) {
- newRow = 0;
- } else {
- return; // newRow is still -1, so we can assume the database has
- // only one entry.
- }
-
- scrollTo(newRow);
- panel.getMainTable().setRowSelectionInterval(newRow, newRow);
-
+ panel.selectNextEntry();
}
}
@@ -1307,22 +1236,7 @@ public class EntryEditor extends JPanel implements EntryContainer {
@Override
public void actionPerformed(ActionEvent e) {
- int thisRow = panel.getMainTable().findEntry(entry);
- int newRow;
-
- if ((thisRow - 1) >= 0) {
- newRow = thisRow - 1;
- } else if (thisRow != (panel.getDatabase().getEntryCount() - 1)) {
- newRow = panel.getDatabase().getEntryCount() - 1;
- } else {
- return; // newRow is still -1, so we can assume the database has
- // only one entry.
-
- }
-
- scrollTo(newRow);
- panel.getMainTable().setRowSelectionInterval(newRow, newRow);
-
+ panel.selectPreviousEntry();
}
}
@@ -1340,14 +1254,12 @@ public class EntryEditor extends JPanel implements EntryContainer {
// 1. get BibEntry for selected index (already have)
// 2. update label
- // Store the current edit in case this action is called during the
- // editing of a field:
+ // Store the current edit in case this action is called during the editing of a field:
storeCurrentEdit();
// This is a partial clone of net.sf.jabref.gui.BasePanel.setupActions().new AbstractWorker() {...}.run()
- // this updates the table automatically, on close, but not
- // within the tab
+ // this updates the table automatically, on close, but not within the tab
Optional<String> oldValue = entry.getCiteKeyOptional();
if (oldValue.isPresent()) {
@@ -1369,12 +1281,13 @@ public class EntryEditor extends JPanel implements EntryContainer {
}
}
- BibtexKeyPatternUtil.makeLabel(panel.getBibDatabaseContext().getMetaData(), panel.getDatabase(), entry,
- BibtexKeyPatternPreferences.fromPreferences(Globals.prefs));
+ BibtexKeyPatternUtil.makeAndSetLabel(panel.getBibDatabaseContext().getMetaData()
+ .getCiteKeyPattern(Globals.prefs.getBibtexKeyPatternPreferences().getKeyPattern()), panel.getDatabase(), entry,
+ Globals.prefs.getBibtexKeyPatternPreferences());
// Store undo information:
panel.getUndoManager().addEdit(
- new UndoableKeyChange(panel.getDatabase(), entry, oldValue.orElse(null),
+ new UndoableKeyChange(entry, oldValue.orElse(null),
entry.getCiteKeyOptional().get())); // Cite key always set here
// here we update the field
@@ -1382,7 +1295,6 @@ public class EntryEditor extends JPanel implements EntryContainer {
setField(BibEntry.KEY_FIELD, bibtexKeyData);
updateSource();
panel.markBaseChanged();
-
}
}
diff --git a/src/main/java/net/sf/jabref/gui/entryeditor/EntryEditorTab.java b/src/main/java/net/sf/jabref/gui/entryeditor/EntryEditorTab.java
index 1c409b9..8a9c6a8 100644
--- a/src/main/java/net/sf/jabref/gui/entryeditor/EntryEditorTab.java
+++ b/src/main/java/net/sf/jabref/gui/entryeditor/EntryEditorTab.java
@@ -27,16 +27,17 @@ import net.sf.jabref.Globals;
import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.gui.JabRefFrame;
import net.sf.jabref.gui.autocompleter.AutoCompleteListener;
+import net.sf.jabref.gui.fieldeditors.EntryLinkListEditor;
import net.sf.jabref.gui.fieldeditors.FieldEditor;
import net.sf.jabref.gui.fieldeditors.FileListEditor;
import net.sf.jabref.gui.fieldeditors.TextArea;
import net.sf.jabref.gui.fieldeditors.TextField;
import net.sf.jabref.gui.keyboard.KeyBinding;
-import net.sf.jabref.gui.util.FocusRequester;
-import net.sf.jabref.gui.util.GUIUtil;
import net.sf.jabref.logic.autocompleter.AutoCompleter;
+import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.model.entry.FieldProperties;
+import net.sf.jabref.model.entry.FieldName;
+import net.sf.jabref.model.entry.FieldProperty;
import net.sf.jabref.model.entry.InternalBibtexFields;
import com.jgoodies.forms.builder.DefaultFormBuilder;
@@ -91,10 +92,7 @@ class EntryEditorTab {
setupPanel(frame, panel, addKeyField, compressed, tabTitle);
- /*
- * The following line makes sure focus cycles inside tab instead of
- * being lost to other parts of the frame:
- */
+ // The following line makes sure focus cycles inside tab instead of being lost to other parts of the frame:
scrollPane.setFocusCycleRoot(true);
}
@@ -135,16 +133,23 @@ class EntryEditorTab {
FieldEditor fieldEditor;
int defaultHeight;
int wHeight = (int) (50.0 * InternalBibtexFields.getFieldWeight(field));
- if (InternalBibtexFields.getFieldExtras(field).contains(FieldProperties.FILE_EDITOR)) {
+ if (InternalBibtexFields.getFieldProperties(field).contains(FieldProperty.FILE_EDITOR)) {
fieldEditor = new FileListEditor(frame, bPanel.getBibDatabaseContext(), field, null, parent);
fileListEditor = (FileListEditor) fieldEditor;
- GUIUtil.correctRowHeight(fileListEditor);
defaultHeight = 0;
+ } else if (InternalBibtexFields.getFieldProperties(field).contains(FieldProperty.SINGLE_ENTRY_LINK)) {
+ fieldEditor = new EntryLinkListEditor(frame, bPanel.getBibDatabaseContext(), field, null, parent,
+ true);
+ defaultHeight = 0;
+ } else if (InternalBibtexFields.getFieldProperties(field).contains(FieldProperty.MULTIPLE_ENTRY_LINK)) {
+ fieldEditor = new EntryLinkListEditor(frame, bPanel.getBibDatabaseContext(), field, null, parent,
+ false);
+ defaultHeight = 0;
} else {
- fieldEditor = new TextArea(field, null);
- bPanel.getSearchBar().getSearchQueryHighlightObservable().addSearchListener((TextArea) fieldEditor);
+ fieldEditor = new TextArea(field, null, getPrompt(field));
+ parent.addSearchListener((TextArea) fieldEditor);
defaultHeight = fieldEditor.getPane().getPreferredSize().height;
}
@@ -203,6 +208,28 @@ class EntryEditorTab {
}
}
+ private String getPrompt(String field) {
+
+ Set<FieldProperty> fieldProperties = InternalBibtexFields.getFieldProperties(field);
+ if (fieldProperties.contains(FieldProperty.PERSON_NAMES)) {
+ return String.format("%1$s and %1$s and others", Localization.lang("Firstname Lastname"));
+ } else if (fieldProperties.contains(FieldProperty.DOI)) {
+ return "10.ORGANISATION/ID";
+ } else if (fieldProperties.contains(FieldProperty.DATE)) {
+ return "YYYY-MM-DD";
+ }
+
+ switch (field) {
+ case FieldName.YEAR:
+ return "YYYY";
+ case FieldName.MONTH:
+ return "MM or #mmm#";
+ case FieldName.URL:
+ return "https://";
+ }
+
+ return "";
+ }
private BibEntry getEntry() {
return entry;
@@ -214,13 +241,12 @@ class EntryEditorTab {
if (text.isEmpty()) {
return getEntry().hasField(fieldEditor.getFieldName());
} else {
- return !Optional.of(text).equals(getEntry().getFieldOptional(fieldEditor.getFieldName()));
+ return !Optional.of(text).equals(getEntry().getField(fieldEditor.getFieldName()));
}
}
public void markIfModified(FieldEditor fieldEditor) {
- // Only mark as changed if not already is and the field was indeed
- // modified
+ // Only mark as changed if not already is and the field was indeed modified
if (!updating && !basePanel.isModified() && isFieldModified(fieldEditor)) {
markBaseChanged();
}
@@ -233,7 +259,7 @@ class EntryEditorTab {
/**
* Only sets the activeField variable but does not focus it.
* <p>
- * Call activate afterwards.
+ * If you want to focus it call {@link #focus()} afterwards.
*
* @param fieldEditor
*/
@@ -255,12 +281,9 @@ class EntryEditorTab {
return fields;
}
- public void activate() {
+ public void focus() {
if (activeField != null) {
- /**
- * Corrected to fix [ 1594169 ] Entry editor: navigation between panels
- */
- new FocusRequester(activeField.getTextComponent());
+ activeField.getTextComponent().requestFocus();
}
}
@@ -271,13 +294,11 @@ class EntryEditorTab {
setEntry(getEntry());
}
-
-
public void setEntry(BibEntry entry) {
try {
updating = true;
for (FieldEditor editor : editors.values()) {
- String toSet = entry.getFieldOptional(editor.getFieldName()).orElse("");
+ String toSet = entry.getField(editor.getFieldName()).orElse("");
if (!toSet.equals(editor.getText())) {
editor.setText(toSet);
}
@@ -292,7 +313,12 @@ class EntryEditorTab {
if (!editors.containsKey(field)) {
return false;
}
+
FieldEditor fieldEditor = editors.get(field);
+ if (fieldEditor.getText().equals(content)){
+ return true;
+ }
+
// trying to preserve current edit position (fixes SF bug #1285)
if(fieldEditor.getTextComponent() instanceof JTextComponent) {
int initialCaretPosition = ((JTextComponent) fieldEditor).getCaretPosition();
@@ -309,19 +335,6 @@ class EntryEditorTab {
return true;
}
- public void validateAllFields() {
- for (Map.Entry<String, FieldEditor> stringFieldEditorEntry : editors.entrySet()) {
- FieldEditor ed = stringFieldEditorEntry.getValue();
- ed.updateFontColor();
- ed.setEnabled(true);
- if (((Component) ed).hasFocus()) {
- ed.setActiveBackgroundColor();
- } else {
- ed.setValidBackgroundColor();
- }
- }
- }
-
public void setEnabled(boolean enabled) {
for (FieldEditor editor : editors.values()) {
editor.setEnabled(enabled);
diff --git a/src/main/java/net/sf/jabref/gui/entryeditor/EntryEditorTabFocusListener.java b/src/main/java/net/sf/jabref/gui/entryeditor/EntryEditorTabFocusListener.java
index 4344b8b..5e46972 100644
--- a/src/main/java/net/sf/jabref/gui/entryeditor/EntryEditorTabFocusListener.java
+++ b/src/main/java/net/sf/jabref/gui/entryeditor/EntryEditorTabFocusListener.java
@@ -13,16 +13,19 @@ import javax.swing.text.JTextComponent;
import net.sf.jabref.gui.fieldeditors.FieldEditor;
-/*
- * Focus listener that fires the storeFieldAction when a TextArea loses
- * focus.
+
+/**
+ * Focus listener that fires the storeFieldAction when a TextArea loses focus.
*/
class EntryEditorTabFocusListener implements FocusListener {
+ /** The component this DocumentListener is currently tied to */
private JTextComponent textComponent;
+ /** The listener which gets tied to each TextComponent (and removed) */
private DocumentListener documentListener;
+ /** The EntryEditorTab this FocusListener is currently tied to */
private final EntryEditorTab entryEditorTab;
@@ -32,7 +35,6 @@ class EntryEditorTabFocusListener implements FocusListener {
@Override
public void focusGained(FocusEvent event) {
-
synchronized (this) {
if (textComponent != null) {
textComponent.getDocument().removeDocumentListener(documentListener);
@@ -41,15 +43,9 @@ class EntryEditorTabFocusListener implements FocusListener {
}
if (event.getSource() instanceof JTextComponent) {
-
textComponent = (JTextComponent) event.getSource();
- /**
- * [ 1553552 ] Not properly detecting changes to flag as
- * changed
- */
documentListener = new DocumentListener() {
-
- void fire() {
+ private void fire() {
if (textComponent.isFocusOwner()) {
entryEditorTab.markIfModified((FieldEditor) textComponent);
}
@@ -72,16 +68,14 @@ class EntryEditorTabFocusListener implements FocusListener {
};
textComponent.getDocument().addDocumentListener(documentListener);
- /**
- * Makes the vertical scroll panel view follow the focus
- */
- Component scrollPane = textComponent.getParent().getParent();
- if (scrollPane instanceof JScrollPane) {
- JScrollPane componentPane = (JScrollPane) scrollPane;
- Component cPane = componentPane.getParent();
- if (cPane instanceof JPanel) {
- JPanel panel = (JPanel) cPane;
- Rectangle bounds = componentPane.getBounds();
+ // Makes the vertical scroll panel view follow the focus
+ Component component = textComponent.getParent().getParent();
+ if (component instanceof JScrollPane) {
+ JScrollPane scrollPane = (JScrollPane) component;
+ Component scrollPaneParent = scrollPane.getParent();
+ if (scrollPaneParent instanceof JPanel) {
+ JPanel panel = (JPanel) scrollPaneParent;
+ Rectangle bounds = scrollPane.getBounds();
panel.scrollRectToVisible(bounds);
}
}
@@ -90,7 +84,6 @@ class EntryEditorTabFocusListener implements FocusListener {
}
entryEditorTab.setActive((FieldEditor) event.getSource());
-
}
@Override
@@ -106,4 +99,5 @@ class EntryEditorTabFocusListener implements FocusListener {
entryEditorTab.getParent().updateField(event.getSource());
}
}
+
}
diff --git a/src/main/java/net/sf/jabref/gui/entryeditor/FieldExtraComponents.java b/src/main/java/net/sf/jabref/gui/entryeditor/FieldExtraComponents.java
index 9b008ef..e21173a 100644
--- a/src/main/java/net/sf/jabref/gui/entryeditor/FieldExtraComponents.java
+++ b/src/main/java/net/sf/jabref/gui/entryeditor/FieldExtraComponents.java
@@ -6,7 +6,6 @@ import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.util.Optional;
-import java.util.Set;
import javax.swing.JButton;
import javax.swing.JComboBox;
@@ -19,15 +18,12 @@ import javax.swing.text.JTextComponent;
import net.sf.jabref.Globals;
import net.sf.jabref.gui.BasePanel;
-import net.sf.jabref.gui.FieldContentSelector;
-import net.sf.jabref.gui.JabRefFrame;
import net.sf.jabref.gui.date.DatePickerButton;
import net.sf.jabref.gui.desktop.JabRefDesktop;
import net.sf.jabref.gui.entryeditor.EntryEditor.StoreFieldAction;
import net.sf.jabref.gui.fieldeditors.FieldEditor;
import net.sf.jabref.gui.mergeentries.FetchAndMergeEntry;
import net.sf.jabref.gui.undo.UndoableFieldChange;
-import net.sf.jabref.logic.journals.JournalAbbreviationPreferences;
import net.sf.jabref.logic.journals.JournalAbbreviationRepository;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.net.URLUtil;
@@ -37,8 +33,6 @@ import net.sf.jabref.logic.util.date.EasyDateFormat;
import net.sf.jabref.model.database.BibDatabaseMode;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.FieldName;
-import net.sf.jabref.model.entry.FieldProperties;
-import net.sf.jabref.model.entry.InternalBibtexFields;
import net.sf.jabref.model.entry.MonthUtil;
import net.sf.jabref.preferences.JabRefPreferences;
@@ -54,24 +48,16 @@ public class FieldExtraComponents {
* Add controls for switching between abbreviated and full journal names.
* If this field also has a FieldContentSelector, we need to combine these.
*
- * @param frame
* @param panel
* @param editor
* @param entry
- * @param contentSelectors
* @param storeFieldAction
* @return
*/
- public static Optional<JComponent> getJournalExtraComponent(JabRefFrame frame, BasePanel panel, FieldEditor editor,
- BibEntry entry, Set<FieldContentSelector> contentSelectors, StoreFieldAction storeFieldAction) {
+ public static Optional<JComponent> getJournalExtraComponent(BasePanel panel, FieldEditor editor, BibEntry entry,
+ StoreFieldAction storeFieldAction) {
JPanel controls = new JPanel();
controls.setLayout(new BorderLayout());
- if (!panel.getBibDatabaseContext().getMetaData().getContentSelectors(editor.getFieldName()).isEmpty()) {
- FieldContentSelector ws = new FieldContentSelector(frame, panel, frame, editor, storeFieldAction, false,
- ", ");
- contentSelectors.add(ws);
- controls.add(ws, BorderLayout.NORTH);
- }
// Button to toggle abbreviated/full journal names
JButton button = new JButton(Localization.lang("Toggle abbreviation"));
@@ -79,7 +65,7 @@ public class FieldExtraComponents {
button.addActionListener(actionEvent -> {
String text = editor.getText();
JournalAbbreviationRepository abbreviationRepository = Globals.journalAbbreviationLoader
- .getRepository(JournalAbbreviationPreferences.fromPreferences(Globals.prefs));
+ .getRepository(Globals.prefs.getJournalAbbreviationPreferences());
if (abbreviationRepository.isKnownName(text)) {
String s = abbreviationRepository.getNextAbbreviation(text).orElse(text);
@@ -395,26 +381,6 @@ public class FieldExtraComponents {
}
/**
- * Return a button opening a content selector for fields where one exists
- *
- * @param frame
- * @param panel
- * @param editor
- * @param contentSelectors
- * @param storeFieldAction
- * @return
- */
- public static Optional<JComponent> getSelectorExtraComponent(JabRefFrame frame, BasePanel panel, FieldEditor editor,
- Set<FieldContentSelector> contentSelectors, StoreFieldAction storeFieldAction) {
- FieldContentSelector ws = new FieldContentSelector(frame, panel, frame, editor,
- storeFieldAction, false,
- InternalBibtexFields.getFieldExtras(editor.getFieldName())
- .contains(FieldProperties.PERSON_NAMES) ? " and " : ", ");
- contentSelectors.add(ws);
- return Optional.of(ws);
- }
-
- /**
* Set up field such that double click inserts the current date
* If isDataPicker is True, a button with a data picker is returned
*
@@ -550,51 +516,4 @@ public class FieldExtraComponents {
}
- /**
- * Return a button which allows to go to the parent entry of the crossref field
- * @param fieldEditor The FieldEditor component to get the entry key from
- * @param panel The current BasePanel
- * @return
- */
-
- public static Optional<JComponent> getCrossrefExtraComponent(FieldEditor fieldEditor,
- BasePanel panel) {
- JButton button = new JButton(Localization.lang("Select"));
- JTextComponent crossref = (JTextComponent) fieldEditor;
-
- button.addActionListener(
- actionEvent -> panel.getDatabase().getEntryByKey(crossref.getText()).ifPresent(e -> panel.highlightEntry(e))
- );
-
- // enable/disable button
- crossref.getDocument().addDocumentListener(new DocumentListener() {
-
- @Override
- public void changedUpdate(DocumentEvent documentEvent) {
- checkValidKey();
- }
-
- @Override
- public void insertUpdate(DocumentEvent documentEvent) {
- checkValidKey();
- }
-
- @Override
- public void removeUpdate(DocumentEvent documentEvent) {
- checkValidKey();
- }
-
- private void checkValidKey() {
- if (panel.getDatabase().getEntryByKey(crossref.getText()) != null) {
- button.setEnabled(true);
- } else {
- button.setEnabled(false);
- }
- }
- });
-
- return Optional.of(button);
-
- }
-
}
diff --git a/src/main/java/net/sf/jabref/gui/exporter/AutoSaveManager.java b/src/main/java/net/sf/jabref/gui/exporter/AutoSaveManager.java
deleted file mode 100644
index 75e1224..0000000
--- a/src/main/java/net/sf/jabref/gui/exporter/AutoSaveManager.java
+++ /dev/null
@@ -1,119 +0,0 @@
-package net.sf.jabref.gui.exporter;
-
-import java.io.File;
-import java.util.Timer;
-import java.util.TimerTask;
-
-import net.sf.jabref.Globals;
-import net.sf.jabref.gui.BasePanel;
-import net.sf.jabref.gui.JabRefFrame;
-import net.sf.jabref.logic.exporter.BibDatabaseWriter;
-import net.sf.jabref.logic.exporter.BibtexDatabaseWriter;
-import net.sf.jabref.logic.exporter.FileSaveSession;
-import net.sf.jabref.logic.exporter.SaveException;
-import net.sf.jabref.logic.exporter.SavePreferences;
-import net.sf.jabref.logic.exporter.SaveSession;
-import net.sf.jabref.logic.util.io.AutoSaveUtil;
-import net.sf.jabref.preferences.JabRefPreferences;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * Background task and utilities for autosave feature.
- */
-public class AutoSaveManager {
-
- private static final Log LOGGER = LogFactory.getLog(AutoSaveManager.class);
-
- private final JabRefFrame frame;
- private Timer t;
-
- public AutoSaveManager(JabRefFrame frame) {
- this.frame = frame;
- }
-
- public void startAutoSaveTimer() {
- if(t != null) {
- // shut down any previously set timer to not leak any timers
- t.cancel();
- }
-
- TimerTask task = new AutoSaveTask();
- t = new Timer();
- long interval = (long) 60000 * Globals.prefs.getInt(JabRefPreferences.AUTO_SAVE_INTERVAL);
- t.scheduleAtFixedRate(task, interval, interval);
- }
-
- public void stopAutoSaveTimer() {
- t.cancel();
- }
-
-
- private class AutoSaveTask extends TimerTask {
-
- @Override
- public void run() {
- // Since this method is running in the background, we must be prepared that
- // there could be changes done by the user while this method is running.
-
- for (BasePanel panel : frame.getBasePanelList()) {
- if (panel.isModified() && (panel.getBibDatabaseContext().getDatabaseFile() != null)) {
- AutoSaveManager.autoSave(panel);
- }
- }
- }
- }
-
-
- /**
- * Perform an autosave.
- * @param panel The BasePanel to autosave for.
- * @return true if successful, false otherwise.
- */
- private static boolean autoSave(BasePanel panel) {
- File databaseFile = panel.getBibDatabaseContext().getDatabaseFile();
- File backupFile = AutoSaveUtil.getAutoSaveFile(databaseFile);
- try {
- SavePreferences prefs = SavePreferences.loadForSaveFromPreferences(Globals.prefs)
- .withMakeBackup(false)
- .withEncoding(panel.getBibDatabaseContext().getMetaData().getEncoding()
- .orElse(Globals.prefs.getDefaultEncoding()));
-
- BibDatabaseWriter databaseWriter = new BibtexDatabaseWriter(FileSaveSession::new);
- SaveSession ss = databaseWriter.saveDatabase(panel.getBibDatabaseContext(), prefs);
- ss.commit(backupFile.toPath());
- } catch (SaveException e) {
- LOGGER.error("Problem with automatic save", e);
- return false;
- }
- return true;
- }
-
- /**
- * Delete this BasePanel's autosave if it exists.
- * @param panel The BasePanel in question.
- * @return true if there was no autosave or if the autosave was successfully deleted, false otherwise.
- */
- public static boolean deleteAutoSaveFile(BasePanel panel) {
- if (panel.getBibDatabaseContext().getDatabaseFile() == null) {
- return true;
- }
- File backupFile = AutoSaveUtil.getAutoSaveFile(panel.getBibDatabaseContext().getDatabaseFile());
- if (backupFile.exists()) {
- return backupFile.delete();
- } else {
- return true;
- }
- }
-
- /**
- * Clean up by deleting the autosave files corresponding to all open files,
- * if they exist.
- */
- public void clearAutoSaves() {
- for (BasePanel panel : frame.getBasePanelList()) {
- AutoSaveManager.deleteAutoSaveFile(panel);
- }
- }
-}
diff --git a/src/main/java/net/sf/jabref/gui/exporter/CustomExportDialog.java b/src/main/java/net/sf/jabref/gui/exporter/CustomExportDialog.java
index 79151e0..c30446d 100644
--- a/src/main/java/net/sf/jabref/gui/exporter/CustomExportDialog.java
+++ b/src/main/java/net/sf/jabref/gui/exporter/CustomExportDialog.java
@@ -6,7 +6,6 @@ import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
-
import java.nio.file.Path;
import java.nio.file.Paths;
diff --git a/src/main/java/net/sf/jabref/gui/exporter/ExportAction.java b/src/main/java/net/sf/jabref/gui/exporter/ExportAction.java
index 6d3aeb8..bab68d9 100644
--- a/src/main/java/net/sf/jabref/gui/exporter/ExportAction.java
+++ b/src/main/java/net/sf/jabref/gui/exporter/ExportAction.java
@@ -64,7 +64,8 @@ public class ExportAction {
public void actionPerformed(ActionEvent e) {
Map<String, ExportFormat> customFormats = Globals.prefs.customExports.getCustomExportFormats(Globals.prefs,
Globals.journalAbbreviationLoader);
- LayoutFormatterPreferences layoutPreferences = LayoutFormatterPreferences.fromPreferences(Globals.prefs, Globals.journalAbbreviationLoader);
+ LayoutFormatterPreferences layoutPreferences = Globals.prefs
+ .getLayoutFormatterPreferences(Globals.journalAbbreviationLoader);
SavePreferences savePreferences = SavePreferences.loadForExportFromPreferences(Globals.prefs);
ExportFormats.initAllExports(customFormats, layoutPreferences, savePreferences);
JFileChooser fc = ExportAction
@@ -105,7 +106,7 @@ public class ExportAction {
// so formatters can resolve linked files correctly.
// (This is an ugly hack!)
Globals.prefs.fileDirForDatabase = frame.getCurrentBasePanel().getBibDatabaseContext()
- .getFileDirectory();
+ .getFileDirectories(Globals.prefs.getFileDirectoryPreferences());
// Make sure we remember which filter was used, to set
// the default for next time:
diff --git a/src/main/java/net/sf/jabref/gui/exporter/ExportCustomizationDialog.java b/src/main/java/net/sf/jabref/gui/exporter/ExportCustomizationDialog.java
index 7ca4c6c..b4ec7e2 100644
--- a/src/main/java/net/sf/jabref/gui/exporter/ExportCustomizationDialog.java
+++ b/src/main/java/net/sf/jabref/gui/exporter/ExportCustomizationDialog.java
@@ -26,8 +26,6 @@ import net.sf.jabref.Globals;
import net.sf.jabref.gui.JabRefFrame;
import net.sf.jabref.gui.help.HelpAction;
import net.sf.jabref.gui.keyboard.KeyBinding;
-import net.sf.jabref.gui.util.FocusRequester;
-import net.sf.jabref.gui.util.GUIUtil;
import net.sf.jabref.logic.exporter.SavePreferences;
import net.sf.jabref.logic.help.HelpFile;
import net.sf.jabref.logic.l10n.Localization;
@@ -71,8 +69,6 @@ public class ExportCustomizationDialog extends JDialog {
table.setRowSelectionInterval(0, 0);
}
- GUIUtil.correctRowHeight(table);
-
JButton addExport = new JButton(Localization.lang("Add new"));
addExport.addActionListener(e -> {
CustomExportDialog ecd = new CustomExportDialog(frame);
@@ -80,7 +76,7 @@ public class ExportCustomizationDialog extends JDialog {
if (ecd.okPressed()) {
List<String> newFormat = Arrays.asList(ecd.name(), ecd.layoutFile(), ecd.extension());
Globals.prefs.customExports.addFormat(newFormat,
- LayoutFormatterPreferences.fromPreferences(Globals.prefs, Globals.journalAbbreviationLoader),
+ Globals.prefs.getLayoutFormatterPreferences(Globals.journalAbbreviationLoader),
SavePreferences.loadForExportFromPreferences(Globals.prefs));
Globals.prefs.customExports.store(Globals.prefs);
}
@@ -115,7 +111,8 @@ public class ExportCustomizationDialog extends JDialog {
for (int i = 0; i < rows.length; i++) {
entries.add(Globals.prefs.customExports.getSortedList().get(rows[i]));
}
- LayoutFormatterPreferences layoutPreferences = LayoutFormatterPreferences.fromPreferences(Globals.prefs, Globals.journalAbbreviationLoader);
+ LayoutFormatterPreferences layoutPreferences = Globals.prefs
+ .getLayoutFormatterPreferences(Globals.journalAbbreviationLoader);
SavePreferences savePreferences = SavePreferences.loadForExportFromPreferences(Globals.prefs);
for (List<String> list : entries) {
Globals.prefs.customExports.remove(list, layoutPreferences, savePreferences);
@@ -160,7 +157,7 @@ public class ExportCustomizationDialog extends JDialog {
getContentPane().add(buttons, BorderLayout.SOUTH);
pack();
setLocationRelativeTo(frame);
- new FocusRequester(table);
+ table.requestFocus();
}
diff --git a/src/main/java/net/sf/jabref/gui/exporter/ExportToClipboardAction.java b/src/main/java/net/sf/jabref/gui/exporter/ExportToClipboardAction.java
index 5c54cd4..5328ca3 100644
--- a/src/main/java/net/sf/jabref/gui/exporter/ExportToClipboardAction.java
+++ b/src/main/java/net/sf/jabref/gui/exporter/ExportToClipboardAction.java
@@ -77,9 +77,9 @@ public class ExportToClipboardAction extends AbstractWorker {
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
int answer = JOptionPane.showOptionDialog(frame, list, Localization.lang("Select export format"),
JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null,
- new String[] {Localization.lang("Export with selected format"),
- Localization.lang("Return to JabRef")},
- Localization.lang("Export with selected format"));
+ new String[] {Localization.lang("Export"),
+ Localization.lang("Cancel")},
+ Localization.lang("Export"));
if (answer == JOptionPane.NO_OPTION) {
return;
}
@@ -90,7 +90,7 @@ public class ExportToClipboardAction extends AbstractWorker {
// so formatters can resolve linked files correctly.
// (This is an ugly hack!)
Globals.prefs.fileDirForDatabase = frame.getCurrentBasePanel().getBibDatabaseContext()
- .getFileDirectory();
+ .getFileDirectories(Globals.prefs.getFileDirectoryPreferences());
File tmp = null;
try {
diff --git a/src/main/java/net/sf/jabref/gui/exporter/SaveAllAction.java b/src/main/java/net/sf/jabref/gui/exporter/SaveAllAction.java
index 1ec9295..bad33e4 100644
--- a/src/main/java/net/sf/jabref/gui/exporter/SaveAllAction.java
+++ b/src/main/java/net/sf/jabref/gui/exporter/SaveAllAction.java
@@ -49,7 +49,7 @@ public class SaveAllAction extends MnemonicAwareAction implements Worker {
for (int i = 0; i < databases; i++) {
if (i < frame.getBasePanelCount()) {
BasePanel panel = frame.getBasePanelAt(i);
- if (panel.getBibDatabaseContext().getDatabaseFile() == null) {
+ if (!panel.getBibDatabaseContext().getDatabaseFile().isPresent()) {
frame.showBasePanelAt(i);
}
panel.runCommand(Actions.SAVE);
diff --git a/src/main/java/net/sf/jabref/gui/exporter/SaveDatabaseAction.java b/src/main/java/net/sf/jabref/gui/exporter/SaveDatabaseAction.java
index 05bd22b..68376cd 100644
--- a/src/main/java/net/sf/jabref/gui/exporter/SaveDatabaseAction.java
+++ b/src/main/java/net/sf/jabref/gui/exporter/SaveDatabaseAction.java
@@ -14,12 +14,16 @@ import javax.swing.SwingUtilities;
import net.sf.jabref.Globals;
import net.sf.jabref.JabRefExecutorService;
import net.sf.jabref.collab.ChangeScanner;
+import net.sf.jabref.collab.FileUpdatePanel;
import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.gui.FileDialog;
import net.sf.jabref.gui.JabRefFrame;
+import net.sf.jabref.gui.autosaveandbackup.AutosaveUIManager;
import net.sf.jabref.gui.worker.AbstractWorker;
import net.sf.jabref.gui.worker.CallBack;
import net.sf.jabref.gui.worker.Worker;
+import net.sf.jabref.logic.autosaveandbackup.AutosaveManager;
+import net.sf.jabref.logic.autosaveandbackup.BackupManager;
import net.sf.jabref.logic.exporter.BibtexDatabaseWriter;
import net.sf.jabref.logic.exporter.FileSaveSession;
import net.sf.jabref.logic.exporter.SaveException;
@@ -29,8 +33,13 @@ import net.sf.jabref.logic.l10n.Encodings;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.util.FileExtensions;
import net.sf.jabref.logic.util.io.FileBasedLock;
+import net.sf.jabref.model.database.BibDatabaseContext;
+import net.sf.jabref.model.database.DatabaseLocation;
+import net.sf.jabref.model.database.event.ChangePropagation;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.preferences.JabRefPreferences;
+import net.sf.jabref.shared.DBMSConnectionProperties;
+import net.sf.jabref.shared.prefs.SharedDatabasePreferences;
import com.jgoodies.forms.builder.FormBuilder;
import com.jgoodies.forms.layout.FormLayout;
@@ -45,6 +54,7 @@ import org.apache.commons.logging.LogFactory;
* Callers can query whether the operation was canceled, or whether it was successful.
*/
public class SaveDatabaseAction extends AbstractWorker {
+ private static final Log LOGGER = LogFactory.getLog(SaveDatabaseAction.class);
private final BasePanel panel;
private final JabRefFrame frame;
@@ -52,22 +62,30 @@ public class SaveDatabaseAction extends AbstractWorker {
private boolean canceled;
private boolean fileLockedError;
- private static final Log LOGGER = LogFactory.getLog(SaveDatabaseAction.class);
+ private Optional<Path> filePath;
public SaveDatabaseAction(BasePanel panel) {
this.panel = panel;
this.frame = panel.frame();
+ this.filePath = Optional.empty();
+ }
+
+ /**
+ * @param panel BasePanel which contains the database to be saved
+ * @param filePath Path to the file the database should be saved to
+ */
+ public SaveDatabaseAction(BasePanel panel, Path filePath) {
+ this(panel);
+ this.filePath = Optional.ofNullable(filePath);
}
@Override
- public void init() throws Throwable {
+ public void init() throws Exception {
success = false;
canceled = false;
fileLockedError = false;
- if (panel.getBibDatabaseContext().getDatabaseFile() == null) {
- saveAs();
- } else {
+ if (panel.getBibDatabaseContext().getDatabaseFile().isPresent()) {
// Check for external modifications: if true, save not performed so do not tell the user a save is underway but return instead.
if (checkExternalModification()) {
return;
@@ -75,6 +93,11 @@ public class SaveDatabaseAction extends AbstractWorker {
panel.frame().output(Localization.lang("Saving database") + "...");
panel.setSaving(true);
+ } else if (filePath.isPresent()) {
+ // save as directly if the target file location is known
+ saveAs(filePath.get().toFile());
+ } else {
+ saveAs();
}
}
@@ -83,9 +106,9 @@ public class SaveDatabaseAction extends AbstractWorker {
if (success) {
// Reset title of tab
frame.setTabTitle(panel, panel.getTabTitle(),
- panel.getBibDatabaseContext().getDatabaseFile().getAbsolutePath());
+ panel.getBibDatabaseContext().getDatabaseFile().get().getAbsolutePath());
frame.output(Localization.lang("Saved database") + " '"
- + panel.getBibDatabaseContext().getDatabaseFile().getPath() + "'.");
+ + panel.getBibDatabaseContext().getDatabaseFile().get().getPath() + "'.");
frame.setWindowTitle();
frame.updateAllTabTitles();
} else if (!canceled) {
@@ -100,7 +123,7 @@ public class SaveDatabaseAction extends AbstractWorker {
@Override
public void run() {
- if (canceled || (panel.getBibDatabaseContext().getDatabaseFile() == null)) {
+ if (canceled || !panel.getBibDatabaseContext().getDatabaseFile().isPresent()) {
return;
}
@@ -111,7 +134,7 @@ public class SaveDatabaseAction extends AbstractWorker {
// If set in preferences, generate missing BibTeX keys
panel.autoGenerateKeysBeforeSaving();
- if (FileBasedLock.waitForFileLock(panel.getBibDatabaseContext().getDatabaseFile().toPath())) {
+ if (FileBasedLock.waitForFileLock(panel.getBibDatabaseContext().getDatabaseFile().get().toPath())) {
// Check for external modifications to alleviate multiuser concurrency issue when near
// simultaneous saves occur to a shared database file: if true, do not perform the save
// rather return instead.
@@ -120,9 +143,8 @@ public class SaveDatabaseAction extends AbstractWorker {
}
// Save the database
- success = saveDatabase(panel.getBibDatabaseContext().getDatabaseFile(), false,
- panel.getBibDatabaseContext().getMetaData().getEncoding()
- .orElse(Globals.prefs.getDefaultEncoding()));
+ success = saveDatabase(panel.getBibDatabaseContext().getDatabaseFile().get(), false,
+ panel.getBibDatabaseContext().getMetaData().getEncoding().orElse(Globals.prefs.getDefaultEncoding()));
Globals.getFileUpdateMonitor().updateTimeStamp(panel.getFileMonitorHandle());
} else {
@@ -135,7 +157,6 @@ public class SaveDatabaseAction extends AbstractWorker {
if (success) {
panel.getUndoManager().markUnchanged();
- AutoSaveManager.deleteAutoSaveFile(panel);
// (Only) after a successful save the following
// statement marks that the base is unchanged
// since last save:
@@ -233,7 +254,8 @@ public class SaveDatabaseAction extends AbstractWorker {
try {
if (success) {
session.commit(file.toPath());
- panel.getBibDatabaseContext().getMetaData().setEncoding(encoding); // Make sure to remember which encoding we used.
+ // Make sure to remember which encoding we used.
+ panel.getBibDatabaseContext().getMetaData().setEncoding(encoding, ChangePropagation.DO_NOT_POST_EVENT);
} else {
session.cancel();
}
@@ -245,7 +267,7 @@ public class SaveDatabaseAction extends AbstractWorker {
if (ans == JOptionPane.YES_OPTION) {
session.setUseBackup(false);
session.commit(file.toPath());
- panel.getBibDatabaseContext().getMetaData().setEncoding(encoding);
+ panel.getBibDatabaseContext().getMetaData().setEncoding(encoding, ChangePropagation.DO_NOT_POST_EVENT);
} else {
success = false;
}
@@ -258,7 +280,7 @@ public class SaveDatabaseAction extends AbstractWorker {
* Run the "Save" operation. This method offloads the actual save operation to a background thread, but
* still runs synchronously using Spin (the method returns only after completing the operation).
*/
- public void runCommand() throws Throwable {
+ public void runCommand() throws Exception {
// This part uses Spin's features:
Worker worker = getWorker();
// The Worker returned by getWorker() has been wrapped
@@ -278,52 +300,80 @@ public class SaveDatabaseAction extends AbstractWorker {
callback.update(); // Runs the update() method on the EDT.
}
- public void save() throws Throwable {
+ public void save() throws Exception {
runCommand();
frame.updateEnabledState();
}
+ public void saveAs() throws Exception {
+ // configure file dialog
+ FileDialog dialog = new FileDialog(frame);
+ dialog.withExtension(FileExtensions.BIBTEX_DB);
+ dialog.setDefaultExtension(FileExtensions.BIBTEX_DB);
+
+ Optional<Path> path = dialog.saveNewFile();
+ if (path.isPresent()) {
+ saveAs(path.get().toFile());
+ } else {
+ canceled = true;
+ return;
+ }
+ }
+
/**
* Run the "Save as" operation. This method offloads the actual save operation to a background thread, but
* still runs synchronously using Spin (the method returns only after completing the operation).
*/
- public void saveAs() throws Throwable {
- File file = null;
- while (file == null) {
- // configure file dialog
- FileDialog dialog = new FileDialog(frame);
- dialog.withExtension(FileExtensions.BIBTEX_DB);
- dialog.setDefaultExtension(FileExtensions.BIBTEX_DB);
-
- Optional<Path> path = dialog.saveNewFile();
- if (path.isPresent()) {
- file = path.get().toFile();
- } else {
- canceled = true;
- return;
- }
+ public void saveAs(File file) throws Exception {
+ BibDatabaseContext context = panel.getBibDatabaseContext();
+
+ if (context.getLocation() == DatabaseLocation.SHARED) {
+ // Save all properties dependent on the ID. This makes it possible to restore them.
+ DBMSConnectionProperties properties = context.getDBMSSynchronizer().getDBProcessor().getDBMSConnectionProperties();
+ new SharedDatabasePreferences(context.getDatabase().generateSharedDatabaseID()).putAllDBMSConnectionProperties(properties);
}
- File oldFile = panel.getBibDatabaseContext().getDatabaseFile();
- panel.getBibDatabaseContext().setDatabaseFile(file);
- Globals.prefs.put(JabRefPreferences.WORKING_DIRECTORY, file.getParent());
+ context.setDatabaseFile(file);
+ if (file.getParent() != null) {
+ Globals.prefs.put(JabRefPreferences.WORKING_DIRECTORY, file.getParent());
+ }
runCommand();
// If the operation failed, revert the file field and return:
if (!success) {
- panel.getBibDatabaseContext().setDatabaseFile(oldFile);
return;
}
// Register so we get notifications about outside changes to the file.
+
try {
panel.setFileMonitorHandle(Globals.getFileUpdateMonitor().addUpdateListener(panel,
- panel.getBibDatabaseContext().getDatabaseFile()));
+ context.getDatabaseFile().orElse(null)));
} catch (IOException ex) {
LOGGER.error("Problem registering file change notifications", ex);
}
- frame.getFileHistory().newFile(panel.getBibDatabaseContext().getDatabaseFile().getPath());
+
+ if (readyForAutosave(context)) {
+ AutosaveManager autosaver = AutosaveManager.start(context);
+ autosaver.registerListener(new AutosaveUIManager(panel));
+ }
+
+ if (readyForBackup(context)) {
+ BackupManager.start(context);
+ }
+
+ context.getDatabaseFile().ifPresent(presentFile -> frame.getFileHistory().newFile(presentFile.getPath()));
frame.updateEnabledState();
}
+ private boolean readyForAutosave(BibDatabaseContext context) {
+ return (context.getLocation() == DatabaseLocation.SHARED ||
+ ((context.getLocation() == DatabaseLocation.LOCAL) && Globals.prefs.getBoolean(JabRefPreferences.LOCAL_AUTO_SAVE))) &&
+ context.getDatabaseFile().isPresent();
+ }
+
+ private boolean readyForBackup(BibDatabaseContext context) {
+ return context.getLocation() == DatabaseLocation.LOCAL && context.getDatabaseFile().isPresent();
+ }
+
/**
* Query whether the last operation was successful.
*
@@ -369,19 +419,20 @@ public class SaveDatabaseAction extends AbstractWorker {
JabRefExecutorService.INSTANCE.execute(() -> {
- if (!FileBasedLock.waitForFileLock(panel.getBibDatabaseContext().getDatabaseFile().toPath())) {
+ if (!FileBasedLock
+ .waitForFileLock(panel.getBibDatabaseContext().getDatabaseFile().get().toPath())) {
// TODO: GUI handling of the situation when the externally modified file keeps being locked.
LOGGER.error("File locked, this will be trouble.");
}
ChangeScanner scanner = new ChangeScanner(panel.frame(), panel,
- panel.getBibDatabaseContext().getDatabaseFile());
- JabRefExecutorService.INSTANCE.executeWithLowPriorityInOwnThreadAndWait(scanner);
+ panel.getBibDatabaseContext().getDatabaseFile().get());
+ JabRefExecutorService.INSTANCE.executeInterruptableTaskAndWait(scanner);
if (scanner.changesFound()) {
scanner.displayResult(resolved -> {
if (resolved) {
panel.setUpdatedExternally(false);
- SwingUtilities.invokeLater(() -> panel.getSidePaneManager().hide("fileUpdate"));
+ SwingUtilities.invokeLater(() -> panel.getSidePaneManager().hide(FileUpdatePanel.class));
} else {
canceled = true;
}
@@ -399,7 +450,7 @@ public class SaveDatabaseAction extends AbstractWorker {
canceled = true;
} else {
panel.setUpdatedExternally(false);
- panel.getSidePaneManager().hide("fileUpdate");
+ panel.getSidePaneManager().hide(FileUpdatePanel.class);
}
}
}
diff --git a/src/main/java/net/sf/jabref/gui/externalfiles/AutoSetLinks.java b/src/main/java/net/sf/jabref/gui/externalfiles/AutoSetLinks.java
new file mode 100644
index 0000000..68f4489
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/externalfiles/AutoSetLinks.java
@@ -0,0 +1,228 @@
+package net.sf.jabref.gui.externalfiles;
+
+import java.awt.BorderLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import javax.swing.BorderFactory;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JProgressBar;
+import javax.swing.SwingConstants;
+import javax.swing.SwingUtilities;
+
+import net.sf.jabref.Globals;
+import net.sf.jabref.gui.externalfiletype.ExternalFileType;
+import net.sf.jabref.gui.externalfiletype.ExternalFileTypes;
+import net.sf.jabref.gui.externalfiletype.UnknownExternalFileType;
+import net.sf.jabref.gui.filelist.FileListEntry;
+import net.sf.jabref.gui.filelist.FileListTableModel;
+import net.sf.jabref.gui.undo.NamedCompound;
+import net.sf.jabref.gui.undo.UndoableFieldChange;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.logic.util.io.FileUtil;
+import net.sf.jabref.logic.util.io.RegExpFileSearch;
+import net.sf.jabref.model.database.BibDatabaseContext;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldName;
+import net.sf.jabref.preferences.JabRefPreferences;
+
+public class AutoSetLinks {
+
+ /**
+ * Shortcut method if links are set without using the GUI
+ *
+ * @param entries the entries for which links should be set
+ * @param databaseContext the database for which links are set
+ */
+ public static void autoSetLinks(List<BibEntry> entries, BibDatabaseContext databaseContext) {
+ autoSetLinks(entries, null, null, null, databaseContext, null, null);
+ }
+
+ /**
+ * Automatically add links for this set of entries, based on the globally stored list of external file types. The
+ * entries are modified, and corresponding UndoEdit elements added to the NamedCompound given as argument.
+ * Furthermore, all entries which are modified are added to the Set of entries given as an argument.
+ * <p>
+ * The entries' bibtex keys must have been set - entries lacking key are ignored. The operation is done in a new
+ * thread, which is returned for the caller to wait for if needed.
+ *
+ * @param entries A collection of BibEntry objects to find links for.
+ * @param ce A NamedCompound to add UndoEdit elements to.
+ * @param changedEntries MODIFIED, optional. A Set of BibEntry objects to which all modified entries is added.
+ * This is used for status output and debugging
+ * @param singleTableModel UGLY HACK. The table model to insert links into. Already existing links are not
+ * duplicated or removed. This parameter has to be null if entries.count() != 1. The hack has been
+ * introduced as a bibtexentry does not (yet) support the function getListTableModel() and the
+ * FileListEntryEditor editor holds an instance of that table model and does not reconstruct it after the
+ * search has succeeded.
+ * @param databaseContext The database providing the relevant file directory, if any.
+ * @param callback An ActionListener that is notified (on the event dispatch thread) when the search is finished.
+ * The ActionEvent has id=0 if no new links were added, and id=1 if one or more links were added. This
+ * parameter can be null, which means that no callback will be notified.
+ * @param diag An instantiated modal JDialog which will be used to display the progress of the automatically setting. This
+ * parameter can be null, which means that no progress update will be shown.
+ * @return the thread performing the automatically setting
+ */
+ public static Runnable autoSetLinks(final List<BibEntry> entries, final NamedCompound ce,
+ final Set<BibEntry> changedEntries, final FileListTableModel singleTableModel,
+ final BibDatabaseContext databaseContext, final ActionListener callback, final JDialog diag) {
+ final Collection<ExternalFileType> types = ExternalFileTypes.getInstance().getExternalFileTypeSelection();
+ if (diag != null) {
+ final JProgressBar prog = new JProgressBar(SwingConstants.HORIZONTAL, 0, types.size() - 1);
+ final JLabel label = new JLabel(Localization.lang("Searching for files"));
+ prog.setIndeterminate(true);
+ prog.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
+ diag.setTitle(Localization.lang("Automatically setting file links"));
+ diag.getContentPane().add(prog, BorderLayout.CENTER);
+ diag.getContentPane().add(label, BorderLayout.SOUTH);
+
+ diag.pack();
+ diag.setLocationRelativeTo(diag.getParent());
+ }
+
+ Runnable r = new Runnable() {
+
+ @Override
+ public void run() {
+ // determine directories to search in
+ List<File> dirs = new ArrayList<>();
+ List<String> dirsS = databaseContext.getFileDirectories(Globals.prefs.getFileDirectoryPreferences());
+ dirs.addAll(dirsS.stream().map(File::new).collect(Collectors.toList()));
+
+ // determine extensions
+ List<String> extensions = new ArrayList<>();
+ for (final ExternalFileType type : types) {
+ extensions.add(type.getExtension());
+ }
+
+ // Run the search operation:
+ Map<BibEntry, List<File>> result;
+ if (Globals.prefs.getBoolean(JabRefPreferences.AUTOLINK_USE_REG_EXP_SEARCH_KEY)) {
+ String regExp = Globals.prefs.get(JabRefPreferences.REG_EXP_SEARCH_EXPRESSION_KEY);
+ result = RegExpFileSearch.findFilesForSet(entries, extensions, dirs, regExp,
+ Globals.prefs.getKeywordDelimiter());
+ } else {
+ boolean autoLinkExactKeyOnly = Globals.prefs.getBoolean(JabRefPreferences.AUTOLINK_EXACT_KEY_ONLY);
+ result = FileUtil.findAssociatedFiles(entries, extensions, dirs, autoLinkExactKeyOnly);
+ }
+
+ boolean foundAny = false;
+ // Iterate over the entries:
+ for (Entry<BibEntry, List<File>> entryFilePair : result.entrySet()) {
+ FileListTableModel tableModel;
+ Optional<String> oldVal = entryFilePair.getKey().getField(FieldName.FILE);
+ if (singleTableModel == null) {
+ tableModel = new FileListTableModel();
+ oldVal.ifPresent(tableModel::setContent);
+ } else {
+ assert entries.size() == 1;
+ tableModel = singleTableModel;
+ }
+ List<File> files = entryFilePair.getValue();
+ for (File f : files) {
+ f = FileUtil.shortenFileName(f, dirsS);
+ boolean alreadyHas = false;
+ //System.out.println("File: "+f.getPath());
+ for (int j = 0; j < tableModel.getRowCount(); j++) {
+ FileListEntry existingEntry = tableModel.getEntry(j);
+ //System.out.println("Comp: "+existingEntry.getLink());
+ if (new File(existingEntry.link).equals(f)) {
+ alreadyHas = true;
+ foundAny = true;
+ break;
+ }
+ }
+ if (!alreadyHas) {
+ foundAny = true;
+ Optional<ExternalFileType> type;
+ Optional<String> extension = FileUtil.getFileExtension(f);
+ if (extension.isPresent()) {
+ type = ExternalFileTypes.getInstance().getExternalFileTypeByExt(extension.get());
+ } else {
+ type = Optional.of(new UnknownExternalFileType(""));
+ }
+ FileListEntry flEntry = new FileListEntry(f.getName(), f.getPath(), type);
+ tableModel.addEntry(tableModel.getRowCount(), flEntry);
+
+ String newVal = tableModel.getStringRepresentation();
+ if (newVal.isEmpty()) {
+ newVal = null;
+ }
+ if (ce != null) {
+ // store undo information
+ UndoableFieldChange change = new UndoableFieldChange(entryFilePair.getKey(),
+ FieldName.FILE, oldVal.orElse(null), newVal);
+ ce.addEdit(change);
+ }
+ // hack: if table model is given, do NOT modify entry
+ if (singleTableModel == null) {
+ entryFilePair.getKey().setField(FieldName.FILE, newVal);
+ }
+ if (changedEntries != null) {
+ changedEntries.add(entryFilePair.getKey());
+ }
+ }
+ }
+ }
+
+ // handle callbacks and dialog
+ // FIXME: The ID signals if action was successful :/
+ final int id = foundAny ? 1 : 0;
+ SwingUtilities.invokeLater(new Runnable() {
+
+ @Override
+ public void run() {
+ if (diag != null) {
+ diag.dispose();
+ }
+ if (callback != null) {
+ callback.actionPerformed(new ActionEvent(this, id, ""));
+ }
+ }
+ });
+ }
+ };
+ SwingUtilities.invokeLater(() -> {
+ // show dialog which will be hidden when the task is done
+ if (diag != null) {
+ diag.setVisible(true);
+ }
+ });
+ return r;
+ }
+
+ /**
+ * Automatically add links for this entry to the table model given as an argument, based on the globally stored list
+ * of external file types. The entry itself is not modified. The entry's bibtex key must have been set.
+ *
+ * @param entry The BibEntry to find links for.
+ * @param singleTableModel The table model to insert links into. Already existing links are not duplicated or
+ * removed.
+ * @param databaseContext The database providing the relevant file directory, if any.
+ * @param callback An ActionListener that is notified (on the event dispatch thread) when the search is finished.
+ * The ActionEvent has id=0 if no new links were added, and id=1 if one or more links were added. This
+ * parameter can be null, which means that no callback will be notified. The passed ActionEvent is
+ * constructed with (this, id, ""), where id is 1 if something has been done and 0 if nothing has been
+ * done.
+ * @param diag An instantiated modal JDialog which will be used to display the progress of the automatically setting. This
+ * parameter can be null, which means that no progress update will be shown.
+ * @return the runnable able to perform the automatically setting
+ */
+ public static Runnable autoSetLinks(final BibEntry entry, final FileListTableModel singleTableModel,
+ final BibDatabaseContext databaseContext, final ActionListener callback, final JDialog diag) {
+ return autoSetLinks(Collections.singletonList(entry), null, null, singleTableModel, databaseContext, callback,
+ diag);
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/gui/externalfiles/DownloadExternalFile.java b/src/main/java/net/sf/jabref/gui/externalfiles/DownloadExternalFile.java
new file mode 100644
index 0000000..cc0d6ec
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/externalfiles/DownloadExternalFile.java
@@ -0,0 +1,350 @@
+package net.sf.jabref.gui.externalfiles;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.file.Paths;
+import java.util.List;
+import java.util.Optional;
+
+import javax.swing.JOptionPane;
+import javax.swing.SwingUtilities;
+
+import net.sf.jabref.Globals;
+import net.sf.jabref.JabRefExecutorService;
+import net.sf.jabref.gui.JabRefFrame;
+import net.sf.jabref.gui.externalfiletype.ExternalFileType;
+import net.sf.jabref.gui.externalfiletype.ExternalFileTypes;
+import net.sf.jabref.gui.filelist.FileListEntry;
+import net.sf.jabref.gui.filelist.FileListEntryEditor;
+import net.sf.jabref.gui.net.MonitoredURLDownload;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.logic.net.URLDownload;
+import net.sf.jabref.logic.util.OS;
+import net.sf.jabref.logic.util.io.FileUtil;
+import net.sf.jabref.model.database.BibDatabaseContext;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.preferences.JabRefPreferences;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * This class handles the download of an external file. Typically called when the user clicks
+ * the "Download" button in a FileListEditor shown in an EntryEditor.
+ * <p/>
+ * The FileListEditor constructs the DownloadExternalFile instance, then calls the download()
+ * method passing a reference to itself as a callback. The download() method asks for the URL,
+ * then starts the download. When the download is completed, it calls the downloadCompleted()
+ * method on the callback FileListEditor, which then needs to take care of linking to the file.
+ * The local filename is passed as an argument to the downloadCompleted() method.
+ * <p/>
+ * If the download is canceled, or failed, the user is informed. The callback is never called.
+ */
+public class DownloadExternalFile {
+
+ private static final Log LOGGER = LogFactory.getLog(DownloadExternalFile.class);
+
+ private final JabRefFrame frame;
+ private final BibDatabaseContext databaseContext;
+ private final BibEntry entry;
+ private FileListEntryEditor editor;
+ private boolean downloadFinished;
+ private boolean dontShowDialog;
+
+
+ public DownloadExternalFile(JabRefFrame frame, BibDatabaseContext databaseContext, BibEntry entry) {
+ this.frame = frame;
+ this.databaseContext = databaseContext;
+ this.entry = entry;
+ }
+
+ /**
+ * Start a download.
+ *
+ * @param callback The object to which the filename should be reported when download
+ * is complete.
+ */
+ public void download(final DownloadCallback callback) throws IOException {
+ dontShowDialog = false;
+ final String res = JOptionPane.showInputDialog(frame, Localization.lang("Enter URL to download"));
+
+ if ((res == null) || res.trim().isEmpty()) {
+ return;
+ }
+
+ URL url;
+ try {
+ url = new URL(res);
+ } catch (MalformedURLException ex1) {
+ JOptionPane.showMessageDialog(frame, Localization.lang("Invalid URL"), Localization.lang("Download file"),
+ JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+
+ download(url, callback);
+ }
+
+ /**
+ * Start a download.
+ *
+ * @param callback The object to which the filename should be reported when download
+ * is complete.
+ */
+ public void download(URL url, final DownloadCallback callback) throws IOException {
+ String res = url.toString();
+ String mimeType;
+
+ // First of all, start the download itself in the background to a temporary file:
+ final File tmp = File.createTempFile("jabref_download", "tmp");
+ tmp.deleteOnExit();
+
+ URLDownload udl = MonitoredURLDownload.buildMonitoredDownload(frame, url);
+
+ try {
+ // TODO: what if this takes long time?
+ // TODO: stop editor dialog if this results in an error:
+ mimeType = udl.determineMimeType(); // Read MIME type
+ } catch (IOException ex) {
+ JOptionPane.showMessageDialog(frame, Localization.lang("Invalid URL") + ": " + ex.getMessage(),
+ Localization.lang("Download file"), JOptionPane.ERROR_MESSAGE);
+ LOGGER.info("Error while downloading " + "'" + res + "'", ex);
+ return;
+ }
+ final URL urlF = url;
+ final URLDownload udlF = udl;
+
+ JabRefExecutorService.INSTANCE.execute(() -> {
+ try {
+ udlF.downloadToFile(tmp);
+ } catch (IOException e2) {
+ dontShowDialog = true;
+ if ((editor != null) && editor.isVisible()) {
+ editor.setVisible(false, false);
+ }
+ JOptionPane.showMessageDialog(frame, Localization.lang("Invalid URL") + ": " + e2.getMessage(),
+ Localization.lang("Download file"), JOptionPane.ERROR_MESSAGE);
+ LOGGER.info("Error while downloading " + "'" + urlF + "'", e2);
+ return;
+ }
+ // Download finished: call the method that stops the progress bar etc.:
+ SwingUtilities.invokeLater(DownloadExternalFile.this::downloadFinished);
+ });
+
+ Optional<ExternalFileType> suggestedType = Optional.empty();
+ if (mimeType != null) {
+ LOGGER.debug("MIME Type suggested: " + mimeType);
+ suggestedType = ExternalFileTypes.getInstance().getExternalFileTypeByMimeType(mimeType);
+ }
+ // Then, while the download is proceeding, let the user choose the details of the file:
+ String suffix;
+ if (suggestedType.isPresent()) {
+ suffix = suggestedType.get().getExtension();
+ } else {
+ // If we did not find a file type from the MIME type, try based on extension:
+ suffix = getSuffix(res);
+ if (suffix == null) {
+ suffix = "";
+ }
+ suggestedType = ExternalFileTypes.getInstance().getExternalFileTypeByExt(suffix);
+ }
+
+ String suggestedName = getSuggestedFileName(suffix);
+ List<String> fDirectory = databaseContext.getFileDirectories(Globals.prefs.getFileDirectoryPreferences());
+ String directory;
+ if (fDirectory.isEmpty()) {
+ directory = null;
+ } else {
+ directory = fDirectory.get(0);
+ }
+ final String suggestDir = directory == null ? System.getProperty("user.home") : directory;
+ File file = new File(new File(suggestDir), suggestedName);
+ FileListEntry fileListEntry = new FileListEntry("", file.getCanonicalPath(), suggestedType);
+ editor = new FileListEntryEditor(frame, fileListEntry, true, false, databaseContext);
+ editor.getProgressBar().setIndeterminate(true);
+ editor.setOkEnabled(false);
+ editor.setExternalConfirm(closeEntry -> {
+ File f = directory == null ? new File(closeEntry.link) : expandFilename(directory, closeEntry.link);
+ if (f.isDirectory()) {
+ JOptionPane.showMessageDialog(frame, Localization.lang("Target file cannot be a directory."),
+ Localization.lang("Download file"), JOptionPane.ERROR_MESSAGE);
+ return false;
+ }
+ if (f.exists()) {
+ return JOptionPane.showConfirmDialog(frame,
+ Localization.lang("'%0' exists. Overwrite file?", f.getName()),
+ Localization.lang("Download file"), JOptionPane.OK_CANCEL_OPTION) == JOptionPane.OK_OPTION;
+ } else {
+ return true;
+ }
+ });
+ if (dontShowDialog) {
+ return;
+ } else {
+ editor.setVisible(true, false);
+ }
+ // Editor closed. Go on:
+ if (editor.okPressed()) {
+ File toFile = directory == null ? new File(fileListEntry.link) : expandFilename(directory,
+ fileListEntry.link);
+ String dirPrefix;
+ if (directory == null) {
+ dirPrefix = null;
+ } else {
+ if (directory.endsWith(OS.FILE_SEPARATOR)) {
+ dirPrefix = directory;
+ } else {
+ dirPrefix = directory + OS.FILE_SEPARATOR;
+ }
+ }
+
+ boolean success = FileUtil.copyFile(Paths.get(tmp.toURI()), Paths.get(toFile.toURI()), true);
+ if (!success) {
+ // OOps, the file exists!
+ LOGGER.error("File already exists! DownloadExternalFile.download()");
+ }
+
+ // If the local file is in or below the main file directory, change the
+ // path to relative:
+ if ((dirPrefix != null) && fileListEntry.link.startsWith(directory)
+ && (fileListEntry.link.length() > dirPrefix.length())) {
+ fileListEntry = new FileListEntry(fileListEntry.description,
+ fileListEntry.link.substring(dirPrefix.length()), fileListEntry.type);
+ }
+ callback.downloadComplete(fileListEntry);
+
+ if (!tmp.delete()) {
+ LOGGER.info("Cannot delete temporary file");
+ }
+ } else {
+ // Canceled. Just delete the temp file:
+ if (downloadFinished && !tmp.delete()) {
+ LOGGER.info("Cannot delete temporary file");
+ }
+ }
+
+ }
+
+ /**
+ * Construct a File object pointing to the file linked, whether the link is
+ * absolute or relative to the main directory.
+ *
+ * @param directory The main directory.
+ * @param link The absolute or relative link.
+ * @return The expanded File.
+ */
+ private File expandFilename(String directory, String link) {
+ File toFile = new File(link);
+ // If this is a relative link, we should perhaps append the directory:
+ String dirPrefix = directory + OS.FILE_SEPARATOR;
+ if (!toFile.isAbsolute()) {
+ toFile = new File(dirPrefix + link);
+ }
+ return toFile;
+ }
+
+ /**
+ * This is called by the download thread when download is completed.
+ */
+ private void downloadFinished() {
+ downloadFinished = true;
+ editor.getProgressBar().setVisible(false);
+ editor.getProgressBarLabel().setVisible(false);
+ editor.setOkEnabled(true);
+ editor.getProgressBar().setValue(editor.getProgressBar().getMaximum());
+ }
+
+ private String getSuggestedFileName(String suffix) {
+ String plannedName = FileUtil.createFileNameFromPattern(databaseContext.getDatabase(), entry,
+ Globals.prefs.get(JabRefPreferences.IMPORT_FILENAMEPATTERN),
+ Globals.prefs.getLayoutFormatterPreferences(Globals.journalAbbreviationLoader));
+
+ if (!suffix.isEmpty()) {
+ plannedName += "." + suffix;
+ }
+
+ /*
+ * [ 1548875 ] download pdf produces unsupported filename
+ *
+ * http://sourceforge.net/tracker/index.php?func=detail&aid=1548875&group_id=92314&atid=600306
+ * FIXME: rework this! just allow alphanumeric stuff or so?
+ * https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#naming_conventions
+ * http://superuser.com/questions/358855/what-characters-are-safe-in-cross-platform-file-names-for-linux-windows-and-os
+ * https://support.apple.com/en-us/HT202808
+ */
+ if (OS.WINDOWS) {
+ plannedName = plannedName.replaceAll("\\?|\\*|\\<|\\>|\\||\\\"|\\:|\\.$|\\[|\\]", "");
+ } else if (OS.OS_X) {
+ plannedName = plannedName.replace(":", "");
+ }
+
+ return plannedName;
+ }
+
+ /**
+ * Look for the last '.' in the link, and return the following characters.
+ * This gives the extension for most reasonably named links.
+ *
+ * @param link The link
+ * @return The suffix, excluding the dot (e.g. "pdf")
+ */
+ private String getSuffix(final String link) {
+ String strippedLink = link;
+ try {
+ // Try to strip the query string, if any, to get the correct suffix:
+ URL url = new URL(link);
+ if ((url.getQuery() != null) && (url.getQuery().length() < (link.length() - 1))) {
+ strippedLink = link.substring(0, link.length() - url.getQuery().length() - 1);
+ }
+ } catch (MalformedURLException e) {
+ // Don't report this error, since this getting the suffix is a non-critical
+ // operation, and this error will be triggered and reported elsewhere.
+ }
+ // First see if the stripped link gives a reasonable suffix:
+ String suffix;
+ int strippedLinkIndex = strippedLink.lastIndexOf('.');
+ if ((strippedLinkIndex <= 0) || (strippedLinkIndex == (strippedLink.length() - 1))) {
+ suffix = null;
+ } else {
+ suffix = strippedLink.substring(strippedLinkIndex + 1);
+ }
+ if (!ExternalFileTypes.getInstance().isExternalFileTypeByExt(suffix)) {
+ // If the suffix doesn't seem to give any reasonable file type, try
+ // with the non-stripped link:
+ int index = link.lastIndexOf('.');
+ if ((index <= 0) || (index == (link.length() - 1))) {
+ // No occurrence, or at the end
+ // Check if there are path separators in the suffix - if so, it is definitely
+ // not a proper suffix, so we should give up:
+ if (strippedLink.substring(strippedLinkIndex + 1).indexOf('/') >= 1) {
+ return "";
+ } else {
+ return suffix; // return the first one we found, anyway.
+ }
+ } else {
+ // Check if there are path separators in the suffix - if so, it is definitely
+ // not a proper suffix, so we should give up:
+ if (link.substring(index + 1).indexOf('/') >= 1) {
+ return "";
+ } else {
+ return link.substring(index + 1);
+ }
+ }
+ } else {
+ return suffix;
+ }
+
+ }
+
+
+ /**
+ * Callback interface that users of this class must implement in order to receive
+ * notification when download is complete.
+ */
+ @FunctionalInterface
+ public interface DownloadCallback {
+
+ void downloadComplete(FileListEntry file);
+ }
+}
diff --git a/src/main/java/net/sf/jabref/gui/externalfiles/DroppedFileHandler.java b/src/main/java/net/sf/jabref/gui/externalfiles/DroppedFileHandler.java
new file mode 100644
index 0000000..f89b985
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/externalfiles/DroppedFileHandler.java
@@ -0,0 +1,570 @@
+package net.sf.jabref.gui.externalfiles;
+
+import java.awt.BorderLayout;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+import java.util.Optional;
+
+import javax.swing.BoxLayout;
+import javax.swing.ButtonGroup;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.JTextArea;
+import javax.swing.JTextField;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+import net.sf.jabref.Globals;
+import net.sf.jabref.gui.BasePanel;
+import net.sf.jabref.gui.JabRefFrame;
+import net.sf.jabref.gui.externalfiletype.ExternalFileType;
+import net.sf.jabref.gui.externalfiletype.ExternalFileTypes;
+import net.sf.jabref.gui.filelist.FileListEntry;
+import net.sf.jabref.gui.filelist.FileListTableModel;
+import net.sf.jabref.gui.maintable.MainTable;
+import net.sf.jabref.gui.undo.NamedCompound;
+import net.sf.jabref.gui.undo.UndoableFieldChange;
+import net.sf.jabref.gui.undo.UndoableInsertEntry;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.logic.layout.LayoutFormatterPreferences;
+import net.sf.jabref.logic.util.io.FileUtil;
+import net.sf.jabref.logic.xmp.XMPUtil;
+import net.sf.jabref.model.database.BibDatabase;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldName;
+import net.sf.jabref.model.entry.IdGenerator;
+import net.sf.jabref.preferences.JabRefPreferences;
+
+import com.jgoodies.forms.builder.FormBuilder;
+import com.jgoodies.forms.layout.FormLayout;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * This class holds the functionality of autolinking to a file that's dropped
+ * onto an entry.
+ * <p>
+ * Options for handling the files are:
+ * <p>
+ * 1) Link to the file in its current position (disabled if the file is remote)
+ * <p>
+ * 2) Copy the file to ??? directory, rename after bibtex key, and extension
+ * <p>
+ * 3) Move the file to ??? directory, rename after bibtex key, and extension
+ */
+public class DroppedFileHandler {
+
+ private static final Log LOGGER = LogFactory.getLog(DroppedFileHandler.class);
+
+ private final JabRefFrame frame;
+
+ private final BasePanel panel;
+
+ private final JRadioButton linkInPlace = new JRadioButton();
+ private final JRadioButton copyRadioButton = new JRadioButton();
+ private final JRadioButton moveRadioButton = new JRadioButton();
+
+ private final JLabel destDirLabel = new JLabel();
+
+ private final JCheckBox renameCheckBox = new JCheckBox();
+
+ private final JTextField renameToTextBox = new JTextField(50);
+
+ private final JPanel optionsPanel = new JPanel();
+
+ public DroppedFileHandler(JabRefFrame frame, BasePanel panel) {
+
+ this.frame = frame;
+ this.panel = panel;
+
+ ButtonGroup grp = new ButtonGroup();
+ grp.add(linkInPlace);
+ grp.add(copyRadioButton);
+ grp.add(moveRadioButton);
+
+ FormLayout layout = new FormLayout("left:15dlu,pref,pref,pref", "bottom:14pt,pref,pref,pref,pref");
+ layout.setRowGroups(new int[][] {{1, 2, 3, 4, 5}});
+ FormBuilder builder = FormBuilder.create().layout(layout);
+
+ builder.add(linkInPlace).xyw(1, 1, 4);
+ builder.add(destDirLabel).xyw(1, 2, 4);
+ builder.add(copyRadioButton).xyw(2, 3, 3);
+ builder.add(moveRadioButton).xyw(2, 4, 3);
+ builder.add(renameCheckBox).xyw(2, 5, 1);
+ builder.add(renameToTextBox).xyw(4, 5, 1);
+ optionsPanel.add(builder.getPanel());
+ }
+
+ /**
+ * Offer copy/move/linking options for a dragged external file. Perform the
+ * chosen operation, if any.
+ *
+ * @param fileName The name of the dragged file.
+ * @param fileType The FileType associated with the file.
+ * @param mainTable The MainTable the file was dragged to.
+ * @param dropRow The row where the file was dropped.
+ */
+ public void handleDroppedfile(String fileName, ExternalFileType fileType, MainTable mainTable, int dropRow) {
+
+ BibEntry entry = mainTable.getEntryAt(dropRow);
+ handleDroppedfile(fileName, fileType, entry);
+ }
+
+ /**
+ * @param fileName The name of the dragged file.
+ * @param fileType The FileType associated with the file.
+ * @param entry The target entry for the drop.
+ */
+ public void handleDroppedfile(String fileName, ExternalFileType fileType, BibEntry entry) {
+ NamedCompound edits = new NamedCompound(Localization.lang("Drop %0", fileType.getExtension()));
+
+ if (tryXmpImport(fileName, fileType, edits)) {
+ edits.end();
+ panel.getUndoManager().addEdit(edits);
+ return;
+ }
+
+ // Show dialog
+ if (!showLinkMoveCopyRenameDialog(fileName, fileType, entry, panel.getDatabase())) {
+ return;
+ }
+
+ /*
+ * Ok, we're ready to go. See first if we need to do a file copy before
+ * linking:
+ */
+
+ boolean success = true;
+ String destFilename;
+
+ if (linkInPlace.isSelected()) {
+ destFilename = FileUtil.shortenFileName(new File(fileName),
+ panel.getBibDatabaseContext().getFileDirectories(Globals.prefs.getFileDirectoryPreferences()))
+ .toString();
+ } else {
+ destFilename = renameCheckBox.isSelected() ? renameToTextBox.getText() : Paths.get(fileName).toString();
+ if (copyRadioButton.isSelected()) {
+ success = doCopy(fileName, destFilename, edits);
+ } else if (moveRadioButton.isSelected()) {
+ success = doMove(fileName, destFilename, edits);
+ }
+ }
+
+ if (success) {
+ doLink(entry, fileType, destFilename, false, edits);
+ panel.markBaseChanged();
+ panel.updateEntryEditorIfShowing();
+ }
+ edits.end();
+ panel.getUndoManager().addEdit(edits);
+
+ }
+
+ // Done by MrDlib
+ public void linkPdfToEntry(String fileName, MainTable entryTable, int dropRow) {
+ BibEntry entry = entryTable.getEntryAt(dropRow);
+ linkPdfToEntry(fileName, entry);
+ }
+
+ public void linkPdfToEntry(String fileName, BibEntry entry) {
+ Optional<ExternalFileType> optFileType = ExternalFileTypes.getInstance().getExternalFileTypeByExt("pdf");
+
+ if (!optFileType.isPresent()) {
+ LOGGER.warn("No file type with extension 'pdf' registered.");
+ return;
+ }
+
+ ExternalFileType fileType = optFileType.get();
+ // Show dialog
+ if (!showLinkMoveCopyRenameDialog(fileName, fileType, entry, panel.getDatabase())) {
+ return;
+ }
+
+ /*
+ * Ok, we're ready to go. See first if we need to do a file copy before
+ * linking:
+ */
+
+ boolean success = true;
+ String destFilename;
+ NamedCompound edits = new NamedCompound(Localization.lang("Drop %0", fileType.getExtension()));
+
+ if (linkInPlace.isSelected()) {
+ destFilename = FileUtil.shortenFileName(new File(fileName),
+ panel.getBibDatabaseContext().getFileDirectories(Globals.prefs.getFileDirectoryPreferences()))
+ .toString();
+ } else {
+ destFilename = renameCheckBox.isSelected() ? renameToTextBox.getText() : new File(fileName).getName();
+ if (copyRadioButton.isSelected()) {
+ success = doCopy(fileName, destFilename, edits);
+ } else if (moveRadioButton.isSelected()) {
+ success = doMove(fileName, destFilename, edits);
+ }
+ }
+
+ if (success) {
+ doLink(entry, fileType, destFilename, false, edits);
+ panel.markBaseChanged();
+ }
+ edits.end();
+ panel.getUndoManager().addEdit(edits);
+ }
+
+ // Done by MrDlib
+
+ private boolean tryXmpImport(String fileName, ExternalFileType fileType, NamedCompound edits) {
+
+ if (!"pdf".equals(fileType.getExtension())) {
+ return false;
+ }
+
+ List<BibEntry> xmpEntriesInFile;
+ try {
+ xmpEntriesInFile = XMPUtil.readXMP(fileName, Globals.prefs.getXMPPreferences());
+ } catch (IOException e) {
+ LOGGER.warn("Problem reading XMP", e);
+ return false;
+ }
+
+ if ((xmpEntriesInFile == null) || xmpEntriesInFile.isEmpty()) {
+ return false;
+ }
+
+ JLabel confirmationMessage = new JLabel(Localization.lang("The PDF contains one or several BibTeX-records.")
+ + "\n" + Localization.lang("Do you want to import these as new entries into the current database?"));
+ JPanel entriesPanel = new JPanel();
+ entriesPanel.setLayout(new BoxLayout(entriesPanel, BoxLayout.Y_AXIS));
+ xmpEntriesInFile.forEach(entry -> {
+ JTextArea entryArea = new JTextArea(entry.toString());
+ entryArea.setEditable(false);
+ entriesPanel.add(entryArea);
+ });
+
+ JPanel contentPanel = new JPanel(new BorderLayout());
+ contentPanel.add(confirmationMessage, BorderLayout.NORTH);
+ contentPanel.add(entriesPanel, BorderLayout.CENTER);
+
+ int reply = JOptionPane.showConfirmDialog(frame, contentPanel,
+ Localization.lang("XMP-metadata found in PDF: %0", fileName), JOptionPane.YES_NO_CANCEL_OPTION,
+ JOptionPane.QUESTION_MESSAGE);
+
+ if (reply == JOptionPane.CANCEL_OPTION) {
+ return true; // The user canceled thus that we are done.
+ }
+ if (reply == JOptionPane.NO_OPTION) {
+ return false;
+ }
+
+ // reply == JOptionPane.YES_OPTION)
+
+ /*
+ * TODO Extract Import functionality from ImportMenuItem then we could
+ * do:
+ *
+ * ImportMenuItem importer = new ImportMenuItem(frame, (mainTable ==
+ * null), new PdfXmpImporter());
+ *
+ * importer.automatedImport(new String[] { fileName });
+ */
+
+ boolean isSingle = xmpEntriesInFile.size() == 1;
+ BibEntry single = isSingle ? xmpEntriesInFile.get(0) : null;
+
+ boolean success = true;
+
+ String destFilename;
+
+ if (linkInPlace.isSelected()) {
+ destFilename = FileUtil.shortenFileName(new File(fileName),
+ panel.getBibDatabaseContext().getFileDirectories(Globals.prefs.getFileDirectoryPreferences()))
+ .toString();
+ } else {
+ if (renameCheckBox.isSelected() || (single == null)) {
+ destFilename = fileName;
+ } else {
+ destFilename = single.getCiteKey() + "." + fileType.getExtension();
+ }
+
+ if (copyRadioButton.isSelected()) {
+ success = doCopy(fileName, destFilename, edits);
+ } else if (moveRadioButton.isSelected()) {
+ success = doMove(fileName, destFilename, edits);
+ }
+ }
+ if (success) {
+
+ for (BibEntry aXmpEntriesInFile : xmpEntriesInFile) {
+
+ aXmpEntriesInFile.setId(IdGenerator.next());
+ edits.addEdit(new UndoableInsertEntry(panel.getDatabase(), aXmpEntriesInFile, panel));
+ panel.getDatabase().insertEntry(aXmpEntriesInFile);
+ doLink(aXmpEntriesInFile, fileType, destFilename, true, edits);
+
+ }
+ panel.markBaseChanged();
+ panel.updateEntryEditorIfShowing();
+ }
+ return true;
+ }
+
+ //
+ // @return true if user pushed "OK", false otherwise
+ //
+ private boolean showLinkMoveCopyRenameDialog(String linkFileName, ExternalFileType fileType, BibEntry entry,
+ BibDatabase database) {
+
+ String dialogTitle = Localization.lang("Link to file %0", linkFileName);
+
+ Optional<Path> dir = panel.getBibDatabaseContext()
+ .getFirstExistingFileDir(Globals.prefs.getFileDirectoryPreferences());
+
+ if (!dir.isPresent()) {
+ destDirLabel.setText(Localization.lang("File directory is not set or does not exist!"));
+ copyRadioButton.setEnabled(false);
+ moveRadioButton.setEnabled(false);
+ renameToTextBox.setEnabled(false);
+ renameCheckBox.setEnabled(false);
+ linkInPlace.setSelected(true);
+ } else {
+ destDirLabel.setText(Localization.lang("File directory is '%0':", dir.get().toString()));
+ copyRadioButton.setEnabled(true);
+ moveRadioButton.setEnabled(true);
+ renameToTextBox.setEnabled(true);
+ renameCheckBox.setEnabled(true);
+ }
+
+ ChangeListener cl = arg0 -> {
+ renameCheckBox.setEnabled(!linkInPlace.isSelected());
+ renameToTextBox.setEnabled(!linkInPlace.isSelected());
+ };
+
+ linkInPlace.setText(Localization.lang("Leave file in its current directory"));
+ copyRadioButton.setText(Localization.lang("Copy file to file directory"));
+ moveRadioButton.setText(Localization.lang("Move file to file directory"));
+ renameCheckBox.setText(Localization.lang("Rename file to").concat(": "));
+
+ LayoutFormatterPreferences layoutPrefs = Globals.prefs
+ .getLayoutFormatterPreferences(Globals.journalAbbreviationLoader);
+
+ // Determine which name to suggest:
+ String targetName = FileUtil.createFileNameFromPattern(database, entry,
+ Globals.prefs.get(JabRefPreferences.IMPORT_FILENAMEPATTERN), layoutPrefs);
+
+ String fileDirPattern = Globals.prefs.get(JabRefPreferences.IMPORT_FILEDIRPATTERN);
+
+ String targetDirName = "";
+ if (!fileDirPattern.isEmpty()) {
+ targetDirName = FileUtil.createFileNameFromPattern(database, entry, fileDirPattern, layoutPrefs);
+ }
+
+ if (targetDirName.isEmpty()) {
+ renameToTextBox.setText(targetName.concat(".").concat(fileType.getExtension()));
+ } else {
+ renameToTextBox
+ .setText(targetDirName.concat("/").concat(targetName.concat(".").concat(fileType.getExtension())));
+ }
+ linkInPlace.setSelected(frame.prefs().getBoolean(JabRefPreferences.DROPPEDFILEHANDLER_LEAVE));
+ copyRadioButton.setSelected(frame.prefs().getBoolean(JabRefPreferences.DROPPEDFILEHANDLER_COPY));
+ moveRadioButton.setSelected(frame.prefs().getBoolean(JabRefPreferences.DROPPEDFILEHANDLER_MOVE));
+ renameCheckBox.setSelected(frame.prefs().getBoolean(JabRefPreferences.DROPPEDFILEHANDLER_RENAME));
+
+ linkInPlace.addChangeListener(cl);
+ cl.stateChanged(new ChangeEvent(linkInPlace));
+
+ try {
+ Object[] messages = {Localization.lang("How would you like to link to '%0'?", linkFileName), optionsPanel};
+ int reply = JOptionPane.showConfirmDialog(frame, messages, dialogTitle, JOptionPane.OK_CANCEL_OPTION,
+ JOptionPane.QUESTION_MESSAGE);
+ if (reply == JOptionPane.OK_OPTION) {
+ // store user's choice
+ frame.prefs().putBoolean(JabRefPreferences.DROPPEDFILEHANDLER_LEAVE, linkInPlace.isSelected());
+ frame.prefs().putBoolean(JabRefPreferences.DROPPEDFILEHANDLER_COPY, copyRadioButton.isSelected());
+ frame.prefs().putBoolean(JabRefPreferences.DROPPEDFILEHANDLER_MOVE, moveRadioButton.isSelected());
+ frame.prefs().putBoolean(JabRefPreferences.DROPPEDFILEHANDLER_RENAME, renameCheckBox.isSelected());
+ return true;
+ } else {
+ return false;
+ }
+ } finally {
+ linkInPlace.removeChangeListener(cl);
+ }
+ }
+
+ /**
+ * Make a extension to the file.
+ *
+ * @param entry The entry to extension from.
+ * @param fileType The FileType associated with the file.
+ * @param filename The path to the file.
+ * @param edits An NamedCompound action this action is to be added to. If none
+ * is given, the edit is added to the panel's undoManager.
+ */
+ private void doLink(BibEntry entry, ExternalFileType fileType, String filename, boolean avoidDuplicate,
+ NamedCompound edits) {
+
+ Optional<String> oldValue = entry.getField(FieldName.FILE);
+ FileListTableModel tm = new FileListTableModel();
+ oldValue.ifPresent(tm::setContent);
+
+ // If avoidDuplicate==true, we should check if this file is already linked:
+ if (avoidDuplicate) {
+ // For comparison, find the absolute filename:
+ List<String> dirs = panel.getBibDatabaseContext()
+ .getFileDirectories(Globals.prefs.getFileDirectoryPreferences());
+ String absFilename;
+ if (new File(filename).isAbsolute() || dirs.isEmpty()) {
+ absFilename = filename;
+ } else {
+ Optional<File> file = FileUtil.expandFilename(filename, dirs);
+ if (file.isPresent()) {
+ absFilename = file.get().getAbsolutePath();
+ } else {
+ absFilename = ""; // This shouldn't happen based on the old code, so maybe one should set it something else?
+ }
+ }
+
+ LOGGER.debug("absFilename: " + absFilename);
+
+ for (int i = 0; i < tm.getRowCount(); i++) {
+ FileListEntry flEntry = tm.getEntry(i);
+ // Find the absolute filename for this existing link:
+ String absName;
+ if (new File(flEntry.link).isAbsolute() || dirs.isEmpty()) {
+ absName = flEntry.link;
+ } else {
+ Optional<File> file = FileUtil.expandFilename(flEntry.link, dirs);
+ if (file.isPresent()) {
+ absName = file.get().getAbsolutePath();
+ } else {
+ absName = null;
+ }
+ }
+ LOGGER.debug("absName: " + absName);
+ // If the filenames are equal, we don't need to link, so we simply return:
+ if (absFilename.equals(absName)) {
+ return;
+ }
+ }
+ }
+
+ tm.addEntry(tm.getRowCount(), new FileListEntry("", filename, fileType));
+ String newValue = tm.getStringRepresentation();
+ UndoableFieldChange edit = new UndoableFieldChange(entry, FieldName.FILE, oldValue.orElse(null), newValue);
+ entry.setField(FieldName.FILE, newValue);
+
+ if (edits == null) {
+ panel.getUndoManager().addEdit(edit);
+ } else {
+ edits.addEdit(edit);
+ }
+ }
+
+ /**
+ * Move the given file to the base directory for its file type, and rename
+ * it to the given filename.
+ *
+ * @param fileName The name of the source file.
+ * @param destFilename The destination filename.
+ * @param edits TODO we should be able to undo this action
+ * @return true if the operation succeeded.
+ */
+ private boolean doMove(String fileName, String destFilename, NamedCompound edits) {
+ Optional<Path> dir = panel.getBibDatabaseContext()
+ .getFirstExistingFileDir(Globals.prefs.getFileDirectoryPreferences());
+
+ if (dir.isPresent()) {
+ Path destFile = dir.get().resolve(destFilename);
+
+ if (Files.exists(destFile)) {
+ int answer = JOptionPane.showConfirmDialog(frame,
+ Localization.lang("'%0' exists. Overwrite file?", destFile.toString()),
+ Localization.lang("Overwrite file?"), JOptionPane.YES_NO_OPTION);
+ if (answer == JOptionPane.NO_OPTION) {
+ return false;
+ }
+ }
+
+ Path fromFile = Paths.get(fileName);
+ try {
+ if (!Files.exists(destFile)) {
+ Files.createDirectories(destFile);
+ }
+ } catch (IOException e) {
+ LOGGER.error("Problem creating target directories", e);
+ }
+ if (FileUtil.renameFile(fromFile, destFile, true)) {
+ return true;
+ } else {
+ JOptionPane.showMessageDialog(frame,
+ Localization.lang("Could not move file '%0'.", destFile.toString())
+ + Localization.lang("Please move the file manually and link in place."),
+ Localization.lang("Move file failed"), JOptionPane.ERROR_MESSAGE);
+ return false;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Copy the given file to the base directory for its file type, and give it
+ * the given name.
+ *
+ * @param fileName The name of the source file.
+ * @param toFile The destination filename. An existing path-component will be removed.
+ * @param edits TODO we should be able to undo this!
+ * @return true if the operation succeeded.
+ */
+ private boolean doCopy(String fileName, String toFile, NamedCompound edits) {
+
+ List<String> dirs = panel.getBibDatabaseContext()
+ .getFileDirectories(Globals.prefs.getFileDirectoryPreferences());
+ int found = -1;
+ for (int i = 0; i < dirs.size(); i++) {
+ if (new File(dirs.get(i)).exists()) {
+ found = i;
+ break;
+ }
+ }
+ if (found < 0) {
+ // OOps, we don't know which directory to put it in, or the given
+ // dir doesn't exist....
+ // This should not happen!!
+ LOGGER.warn("Cannot determine destination directory or destination directory does not exist");
+ return false;
+ }
+
+ Path destFile = Paths.get(dirs.get(found)).resolve(toFile);
+ if (destFile.toString().equals(fileName)) {
+ // File is already in the correct position. Don't override!
+ return true;
+ }
+
+ if (Files.exists(destFile)) {
+ int answer = JOptionPane.showConfirmDialog(frame,
+ Localization.lang("'%0' exists. Overwrite file?", destFile.toString()),
+ Localization.lang("File exists"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
+ if (answer == JOptionPane.NO_OPTION) {
+ return false;
+ }
+ }
+ try {
+ //copy does not create directories, therefore we have to create them manually
+ if (!Files.exists(destFile)) {
+ Files.createDirectories(destFile);
+ }
+ FileUtil.copyFile(Paths.get(fileName), destFile, true);
+ } catch (IOException e) {
+ LOGGER.error("Problem copying file", e);
+ return false;
+ }
+ return true;
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/gui/externalfiles/FindFullTextAction.java b/src/main/java/net/sf/jabref/gui/externalfiles/FindFullTextAction.java
new file mode 100644
index 0000000..bf967fb
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/externalfiles/FindFullTextAction.java
@@ -0,0 +1,122 @@
+package net.sf.jabref.gui.externalfiles;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.swing.JOptionPane;
+
+import net.sf.jabref.Globals;
+import net.sf.jabref.gui.BasePanel;
+import net.sf.jabref.gui.filelist.FileListTableModel;
+import net.sf.jabref.gui.undo.UndoableFieldChange;
+import net.sf.jabref.gui.worker.AbstractWorker;
+import net.sf.jabref.logic.importer.FulltextFetchers;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldName;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Try to download fulltext PDF for selected entry(ies) by following URL or DOI link.
+ */
+public class FindFullTextAction extends AbstractWorker {
+ private static final Log LOGGER = LogFactory.getLog(FindFullTextAction.class);
+
+ private static final int warningLimit = 10; // The minimum number of selected entries to ask the user for confirmation
+
+ private final BasePanel basePanel;
+ private final Map<Optional<URL>, BibEntry> downloads = new ConcurrentHashMap<>();
+
+ public FindFullTextAction(BasePanel basePanel) {
+ this.basePanel = basePanel;
+ }
+
+ @Override
+ public void init() throws Exception {
+ if (!basePanel.getSelectedEntries().isEmpty()) {
+ basePanel.output(Localization.lang("Looking for full text document..."));
+ } else {
+ LOGGER.debug("No entry selected for fulltext download.");
+ }
+ }
+
+ @Override
+ public void run() {
+ if (basePanel.getSelectedEntries().size() >= warningLimit) {
+ String[] options = new String[]{Localization.lang("Look up full text documents"), Localization.lang("Cancel")};
+ int answer = JOptionPane.showOptionDialog(basePanel.frame(),
+ Localization.lang(
+ "You are about to look up full text documents for %0 entries.",
+ String.valueOf(basePanel.getSelectedEntries().size())) + "\n"
+ + Localization.lang("Do you still want to continue?"),
+ Localization.lang("Look up full text documents"), JOptionPane.OK_CANCEL_OPTION,
+ JOptionPane.QUESTION_MESSAGE, null, options, options[0]);
+ if (answer != JOptionPane.OK_OPTION) {
+ basePanel.output(Localization.lang("Operation canceled."));
+ return;
+ }
+ }
+ for (BibEntry entry : basePanel.getSelectedEntries()) {
+ FulltextFetchers fft = new FulltextFetchers(Globals.prefs.getImportFormatPreferences());
+ downloads.put(fft.findFullTextPDF(entry), entry);
+ }
+ }
+
+ @Override
+ public void update() {
+ List<Optional<URL>> remove = new ArrayList<>();
+ for (Entry<Optional<URL>, BibEntry> download : downloads.entrySet()) {
+ BibEntry entry = download.getValue();
+ Optional<URL> result = download.getKey();
+ if (result.isPresent()) {
+ List<String> dirs = basePanel.getBibDatabaseContext()
+ .getFileDirectories(Globals.prefs.getFileDirectoryPreferences());
+ if (dirs.isEmpty()) {
+ JOptionPane.showMessageDialog(basePanel.frame(),
+ Localization.lang("Main file directory not set!") + " " + Localization.lang("Preferences")
+ + " -> " + Localization.lang("File"),
+ Localization.lang("Directory not found"), JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+ DownloadExternalFile def = new DownloadExternalFile(basePanel.frame(),
+ basePanel.getBibDatabaseContext(), entry);
+ try {
+ def.download(result.get(), file -> {
+ FileListTableModel tm = new FileListTableModel();
+ entry.getField(FieldName.FILE).ifPresent(tm::setContent);
+ tm.addEntry(tm.getRowCount(), file);
+ String newValue = tm.getStringRepresentation();
+ UndoableFieldChange edit = new UndoableFieldChange(entry, FieldName.FILE,
+ entry.getField(FieldName.FILE).orElse(null), newValue);
+ entry.setField(FieldName.FILE, newValue);
+ basePanel.getUndoManager().addEdit(edit);
+ basePanel.markBaseChanged();
+ });
+ } catch (IOException e) {
+ LOGGER.warn("Problem downloading file", e);
+ }
+ basePanel.output(Localization.lang("Finished downloading full text document for entry %0.",
+ entry.getCiteKeyOptional().orElse(Localization.lang("undefined"))));
+ } else {
+ String title = Localization.lang("Full text document download failed");
+ String message = Localization.lang("Full text document download failed for entry %0.",
+ entry.getCiteKeyOptional().orElse(Localization.lang("undefined")));
+
+ basePanel.output(message);
+ JOptionPane.showMessageDialog(basePanel.frame(), message, title, JOptionPane.ERROR_MESSAGE);
+ }
+ remove.add(result);
+ }
+ for (Optional<URL> result : remove) {
+ downloads.remove(result);
+ }
+ }
+}
diff --git a/src/main/java/net/sf/jabref/gui/externalfiles/MoveFileAction.java b/src/main/java/net/sf/jabref/gui/externalfiles/MoveFileAction.java
new file mode 100644
index 0000000..682261d
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/externalfiles/MoveFileAction.java
@@ -0,0 +1,195 @@
+package net.sf.jabref.gui.externalfiles;
+
+import java.awt.event.ActionEvent;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.List;
+import java.util.Locale;
+import java.util.Optional;
+
+import javax.swing.AbstractAction;
+import javax.swing.JOptionPane;
+
+import net.sf.jabref.Globals;
+import net.sf.jabref.gui.FileDialog;
+import net.sf.jabref.gui.JabRefFrame;
+import net.sf.jabref.gui.entryeditor.EntryEditor;
+import net.sf.jabref.gui.fieldeditors.FileListEditor;
+import net.sf.jabref.gui.filelist.FileListEntry;
+import net.sf.jabref.gui.util.component.CheckBoxMessage;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.logic.util.io.FileUtil;
+import net.sf.jabref.preferences.JabRefPreferences;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Action for moving or renaming a file that is linked to from an entry in JabRef.
+ */
+public class MoveFileAction extends AbstractAction {
+
+ private static final Log LOGGER = LogFactory.getLog(MoveFileAction.class);
+
+ private final JabRefFrame frame;
+ private final EntryEditor eEditor;
+ private final FileListEditor editor;
+
+ private final boolean toFileDir;
+
+ private static final String MOVE_RENAME = Localization.lang("Move/Rename file");
+
+
+ public MoveFileAction(JabRefFrame frame, EntryEditor eEditor, FileListEditor editor, boolean toFileDir) {
+ this.frame = frame;
+ this.eEditor = eEditor;
+ this.editor = editor;
+ this.toFileDir = toFileDir;
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ int selected = editor.getSelectedRow();
+
+ if (selected == -1) {
+ return;
+ }
+
+ FileListEntry entry = editor.getTableModel().getEntry(selected);
+
+ // Check if the current file exists:
+ String ln = entry.link;
+ boolean httpLink = ln.toLowerCase(Locale.ENGLISH).startsWith("http");
+ if (httpLink) {
+ // TODO: notify that this operation cannot be done on remote links
+ return;
+ }
+
+ // Get an absolute path representation:
+ List<String> dirs = frame.getCurrentBasePanel().getBibDatabaseContext()
+ .getFileDirectories(Globals.prefs.getFileDirectoryPreferences());
+ int found = -1;
+ for (int i = 0; i < dirs.size(); i++) {
+ if (new File(dirs.get(i)).exists()) {
+ found = i;
+ break;
+ }
+ }
+ if (found < 0) {
+ JOptionPane.showMessageDialog(frame, Localization.lang("File_directory_is_not_set_or_does_not_exist!"),
+ MOVE_RENAME, JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+ File file = new File(ln);
+ if (!file.isAbsolute()) {
+ file = FileUtil.expandFilename(ln, dirs).orElse(null);
+ }
+ if ((file != null) && file.exists()) {
+ // Ok, we found the file. Now get a new name:
+
+ File newFile = null;
+ boolean repeat = true;
+ while (repeat) {
+ repeat = false;
+ String chosenFile;
+ if (toFileDir) {
+ // Determine which name to suggest:
+ String suggName = FileUtil
+ .createFileNameFromPattern(eEditor.getDatabase(), eEditor.getEntry(),
+ Globals.prefs.get(JabRefPreferences.IMPORT_FILENAMEPATTERN),
+ Globals.prefs.getLayoutFormatterPreferences(Globals.journalAbbreviationLoader))
+ .concat(entry.type.isPresent() ? "." + entry.type.get().getExtension() : "");
+ CheckBoxMessage cbm = new CheckBoxMessage(Localization.lang("Move file to file directory?"),
+ Localization.lang("Rename to '%0'", suggName),
+ Globals.prefs.getBoolean(JabRefPreferences.RENAME_ON_MOVE_FILE_TO_FILE_DIR));
+ int answer;
+ // Only ask about renaming file if the file doesn't have the proper name already:
+ if (suggName.equals(file.getName())) {
+ answer = JOptionPane.showConfirmDialog(frame, Localization.lang("Move file to file directory?"),
+ MOVE_RENAME, JOptionPane.YES_NO_OPTION);
+ } else {
+ answer = JOptionPane.showConfirmDialog(frame, cbm, MOVE_RENAME, JOptionPane.YES_NO_OPTION);
+ }
+ if (answer != JOptionPane.YES_OPTION) {
+ return;
+ }
+ Globals.prefs.putBoolean(JabRefPreferences.RENAME_ON_MOVE_FILE_TO_FILE_DIR, cbm.isSelected());
+ StringBuilder sb = new StringBuilder(dirs.get(found));
+ if (!dirs.get(found).endsWith(File.separator)) {
+ sb.append(File.separator);
+ }
+ if (cbm.isSelected()) {
+ // Rename:
+ sb.append(suggName);
+ } else {
+ // Do not rename:
+ sb.append(file.getName());
+ }
+ chosenFile = sb.toString();
+ } else {
+ Optional<Path> path = new FileDialog(frame, file.getPath()).saveNewFile();
+ if (path.isPresent()) {
+ chosenFile = path.get().toString();
+ } else {
+ return;
+ }
+ }
+ newFile = new File(chosenFile);
+
+ }
+
+ if ((newFile != null) && !newFile.equals(file)) {
+ try {
+ boolean success = file.renameTo(newFile);
+ if (!success) {
+ success = FileUtil.copyFile(file.toPath(), newFile.toPath(), true);
+ }
+ if (success) {
+ // Remove the original file:
+ Files.deleteIfExists(file.toPath());
+
+ // Relativise path, if possible.
+ String canPath = new File(dirs.get(found)).getCanonicalPath();
+ if (newFile.getCanonicalPath().startsWith(canPath)) {
+ if ((newFile.getCanonicalPath().length() > canPath.length())
+ && (newFile.getCanonicalPath().charAt(canPath.length()) == File.separatorChar)) {
+
+ String newLink = newFile.getCanonicalPath().substring(1 + canPath.length());
+ editor.getTableModel().setEntry(selected,
+ new FileListEntry(entry.description, newLink, entry.type));
+ } else {
+ String newLink = newFile.getCanonicalPath().substring(canPath.length());
+ editor.getTableModel().setEntry(selected,
+ new FileListEntry(entry.description, newLink, entry.type));
+ }
+
+ } else {
+ String newLink = newFile.getCanonicalPath();
+ editor.getTableModel().setEntry(selected,
+ new FileListEntry(entry.description, newLink, entry.type));
+ }
+ eEditor.updateField(editor);
+ frame.output(Localization.lang("File moved"));
+ } else {
+ JOptionPane.showMessageDialog(frame, Localization.lang("Move file failed"), MOVE_RENAME,
+ JOptionPane.ERROR_MESSAGE);
+ }
+
+ } catch (SecurityException | IOException ex) {
+ LOGGER.warn("Could not move file", ex);
+ JOptionPane.showMessageDialog(frame,
+ Localization.lang("Could not move file '%0'.", file.getAbsolutePath()) + ex.getMessage(),
+ MOVE_RENAME, JOptionPane.ERROR_MESSAGE);
+ }
+
+ }
+ } else {
+ // File doesn't exist, so we can't move it.
+ JOptionPane.showMessageDialog(frame, Localization.lang("Could not find file '%0'.", entry.link),
+ Localization.lang("File not found"), JOptionPane.ERROR_MESSAGE);
+ }
+
+ }
+}
diff --git a/src/main/java/net/sf/jabref/gui/externalfiles/SynchronizeFileField.java b/src/main/java/net/sf/jabref/gui/externalfiles/SynchronizeFileField.java
new file mode 100644
index 0000000..672033f
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/externalfiles/SynchronizeFileField.java
@@ -0,0 +1,401 @@
+package net.sf.jabref.gui.externalfiles;
+
+import java.awt.BorderLayout;
+import java.awt.event.ActionEvent;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Optional;
+import java.util.Set;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.ActionMap;
+import javax.swing.BorderFactory;
+import javax.swing.ButtonGroup;
+import javax.swing.InputMap;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JComponent;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+
+import net.sf.jabref.Globals;
+import net.sf.jabref.JabRefExecutorService;
+import net.sf.jabref.gui.BasePanel;
+import net.sf.jabref.gui.IconTheme;
+import net.sf.jabref.gui.externalfiletype.ExternalFileType;
+import net.sf.jabref.gui.externalfiletype.ExternalFileTypeEntryEditor;
+import net.sf.jabref.gui.externalfiletype.ExternalFileTypes;
+import net.sf.jabref.gui.externalfiletype.UnknownExternalFileType;
+import net.sf.jabref.gui.filelist.FileListEntry;
+import net.sf.jabref.gui.filelist.FileListEntryEditor;
+import net.sf.jabref.gui.filelist.FileListTableModel;
+import net.sf.jabref.gui.keyboard.KeyBinding;
+import net.sf.jabref.gui.undo.NamedCompound;
+import net.sf.jabref.gui.undo.UndoableFieldChange;
+import net.sf.jabref.gui.worker.AbstractWorker;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.logic.util.io.FileUtil;
+import net.sf.jabref.model.database.BibDatabaseContext;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldName;
+
+import com.jgoodies.forms.builder.ButtonBarBuilder;
+import com.jgoodies.forms.builder.FormBuilder;
+import com.jgoodies.forms.layout.FormLayout;
+
+/**
+ * This action goes through all selected entries in the BasePanel, and attempts to autoset the
+ * given external file (pdf, ps, ...) based on the same algorithm used for the "Auto" button in
+ * EntryEditor.
+ */
+public class SynchronizeFileField extends AbstractWorker {
+
+ private final BasePanel panel;
+ private List<BibEntry> sel;
+ private SynchronizeFileField.OptionsDialog optDiag;
+
+ private int entriesChangedCount;
+
+ private final Object[] brokenLinkOptions = {Localization.lang("Ignore"), Localization.lang("Assign new file"),
+ Localization.lang("Remove link"), Localization.lang("Remove all broken links"),
+ Localization.lang("Quit synchronization")};
+
+ private boolean goOn = true;
+ private boolean autoSet = true;
+ private boolean checkExisting = true;
+
+
+ public SynchronizeFileField(BasePanel panel) {
+ this.panel = panel;
+ }
+
+ @Override
+ public void init() {
+ Collection<BibEntry> col = panel.getDatabase().getEntries();
+ goOn = true;
+ sel = new ArrayList<>(col);
+
+ // Ask about rules for the operation:
+ if (optDiag == null) {
+ optDiag = new SynchronizeFileField.OptionsDialog(panel.frame(), panel.getBibDatabaseContext());
+ }
+ optDiag.setLocationRelativeTo(panel.frame());
+ optDiag.setVisible(true);
+ if (optDiag.canceled()) {
+ goOn = false;
+ return;
+ }
+ autoSet = !optDiag.isAutoSetNone();
+ checkExisting = optDiag.isCheckLinks();
+
+ panel.output(Localization.lang("Synchronizing file links..."));
+ }
+
+ @Override
+ public void run() {
+ if (!goOn) {
+ panel.output(Localization.lang("This operation requires one or more entries to be selected."));
+ return;
+ }
+ entriesChangedCount = 0;
+ panel.frame().setProgressBarValue(0);
+ panel.frame().setProgressBarVisible(true);
+ int weightAutoSet = 10; // autoSet takes 10 (?) times longer than checkExisting
+ int progressBarMax = (autoSet ? weightAutoSet * sel.size() : 0) + (checkExisting ? sel.size() : 0);
+ panel.frame().setProgressBarMaximum(progressBarMax);
+ int progress = 0;
+ final NamedCompound ce = new NamedCompound(Localization.lang("Automatically set file links"));
+
+ Set<BibEntry> changedEntries = new HashSet<>();
+
+ // First we try to autoset fields
+ if (autoSet) {
+ List<BibEntry> entries = new ArrayList<>(sel);
+
+ // Start the automatically setting process:
+ Runnable r = AutoSetLinks.autoSetLinks(entries, ce, changedEntries, null, panel.getBibDatabaseContext(), null, null);
+ JabRefExecutorService.INSTANCE.executeAndWait(r);
+ }
+ progress += sel.size() * weightAutoSet;
+ panel.frame().setProgressBarValue(progress);
+ // The following loop checks all external links that are already set.
+ if (checkExisting) {
+ boolean removeAllBroken = false;
+ mainLoop: for (BibEntry aSel : sel) {
+ panel.frame().setProgressBarValue(progress++);
+ final Optional<String> old = aSel.getField(FieldName.FILE);
+ // Check if a extension is set:
+ if (old.isPresent() && !(old.get().isEmpty())) {
+ FileListTableModel tableModel = new FileListTableModel();
+ tableModel.setContentDontGuessTypes(old.get());
+
+ // We need to specify which directories to search in for Util.expandFilename:
+ List<String> dirsS = panel.getBibDatabaseContext()
+ .getFileDirectories(Globals.prefs.getFileDirectoryPreferences());
+ List<File> dirs = new ArrayList<>();
+ for (String dirs1 : dirsS) {
+ dirs.add(new File(dirs1));
+ }
+
+ for (int j = 0; j < tableModel.getRowCount(); j++) {
+ FileListEntry flEntry = tableModel.getEntry(j);
+ // See if the link looks like an URL:
+ boolean httpLink = flEntry.link.toLowerCase(Locale.ENGLISH).startsWith("http");
+ if (httpLink) {
+ continue; // Don't check the remote file.
+ // TODO: should there be an option to check remote links?
+ }
+
+ // A variable to keep track of whether this link gets deleted:
+ boolean deleted = false;
+
+ // Get an absolute path representation:
+ Optional<File> file = FileUtil.expandFilename(flEntry.link, dirsS);
+ if ((!file.isPresent()) || !file.get().exists()) {
+ int answer;
+ if (removeAllBroken) {
+ answer = 2; // We should delete this link.
+ } else {
+ answer = JOptionPane.showOptionDialog(panel.frame(),
+ Localization.lang("<HTML>Could not find file '%0'<BR>linked from entry '%1'</HTML>",
+ flEntry.link,
+ aSel.getCiteKeyOptional().orElse(Localization.lang("undefined"))),
+ Localization.lang("Broken link"),
+ JOptionPane.YES_NO_CANCEL_OPTION,
+ JOptionPane.QUESTION_MESSAGE, null, brokenLinkOptions, brokenLinkOptions[0]
+ );
+ }
+ switch (answer) {
+ case 1:
+ // Assign new file.
+ FileListEntryEditor flEditor = new FileListEntryEditor
+ (panel.frame(), flEntry, false, true, panel.getBibDatabaseContext());
+ flEditor.setVisible(true, true);
+ break;
+ case 2:
+ // Clear field:
+ tableModel.removeEntry(j);
+ deleted = true; // Make sure we don't investigate this link further.
+ j--; // Step back in the iteration, because we removed an entry.
+ break;
+ case 3:
+ // Clear field:
+ tableModel.removeEntry(j);
+ deleted = true; // Make sure we don't investigate this link further.
+ j--; // Step back in the iteration, because we removed an entry.
+ removeAllBroken = true; // Notify for further cases.
+ break;
+ default:
+ // Cancel
+ break mainLoop;
+ }
+ }
+
+ // Unless we deleted this link, see if its file type is recognized:
+ if (!deleted && flEntry.type.isPresent()
+ && (flEntry.type.get() instanceof UnknownExternalFileType)) {
+ String[] options = new String[] {
+ Localization.lang("Define '%0'", flEntry.type.get().getName()),
+ Localization.lang("Change file type"),
+ Localization.lang("Cancel")};
+ String defOption = options[0];
+ int answer = JOptionPane.showOptionDialog(panel.frame(), Localization.lang("One or more file links are of the type '%0', which is undefined. What do you want to do?",
+ flEntry.type.get().getName()),
+ Localization.lang("Undefined file type"), JOptionPane.YES_NO_CANCEL_OPTION,
+ JOptionPane.QUESTION_MESSAGE, null, options, defOption
+ );
+ if (answer == JOptionPane.CANCEL_OPTION) {
+ // User doesn't want to handle this unknown link type.
+ } else if (answer == JOptionPane.YES_OPTION) {
+ // User wants to define the new file type. Show the dialog:
+ ExternalFileType newType = new ExternalFileType(flEntry.type.get().getName(), "", "",
+ "", "new", IconTheme.JabRefIcon.FILE.getSmallIcon());
+ ExternalFileTypeEntryEditor editor = new ExternalFileTypeEntryEditor(panel.frame(), newType);
+ editor.setVisible(true);
+ if (editor.okPressed()) {
+ // Get the old list of types, add this one, and update the list in prefs:
+ List<ExternalFileType> fileTypes = new ArrayList<>(
+ ExternalFileTypes.getInstance().getExternalFileTypeSelection());
+ fileTypes.add(newType);
+ Collections.sort(fileTypes);
+ ExternalFileTypes.getInstance().setExternalFileTypes(fileTypes);
+ panel.getMainTable().repaint();
+ }
+ } else {
+ // User wants to change the type of this link.
+ // First get a model of all file links for this entry:
+ FileListEntryEditor editor = new FileListEntryEditor
+ (panel.frame(), flEntry, false, true, panel.getBibDatabaseContext());
+ editor.setVisible(true, false);
+ }
+ }
+ }
+
+ if (!tableModel.getStringRepresentation().equals(old.orElse(null))) {
+ // The table has been modified. Store the change:
+ String toSet = tableModel.getStringRepresentation();
+ if (toSet.isEmpty()) {
+ ce.addEdit(new UndoableFieldChange(aSel, FieldName.FILE, old.orElse(null), null));
+ aSel.clearField(FieldName.FILE);
+ } else {
+ ce.addEdit(new UndoableFieldChange(aSel, FieldName.FILE, old.orElse(null), toSet));
+ aSel.setField(FieldName.FILE, toSet);
+ }
+ changedEntries.add(aSel);
+ }
+
+ }
+ }
+ }
+
+ if (!changedEntries.isEmpty()) {
+ // Add the undo edit:
+ ce.end();
+ panel.getUndoManager().addEdit(ce);
+ panel.markBaseChanged();
+ entriesChangedCount = changedEntries.size();
+ }
+ }
+
+ @Override
+ public void update() {
+ if (!goOn) {
+ return;
+ }
+
+ panel.output(Localization.lang("Finished synchronizing file links. Entries changed: %0.",
+ String.valueOf(entriesChangedCount)));
+ panel.frame().setProgressBarVisible(false);
+ if (entriesChangedCount > 0) {
+ panel.markBaseChanged();
+ }
+ }
+
+
+ static class OptionsDialog extends JDialog {
+
+
+ private final JButton ok = new JButton(Localization.lang("OK"));
+ private final JButton cancel = new JButton(Localization.lang("Cancel"));
+ private boolean canceled = true;
+ private final BibDatabaseContext databaseContext;
+ private final JRadioButton autoSetUnset = new JRadioButton(Localization.lang("Automatically set file links")
+ + ". " + Localization.lang("Do not overwrite existing links."), true);
+ private final JRadioButton autoSetAll = new JRadioButton(Localization.lang("Automatically set file links")
+ + ". " + Localization.lang("Allow overwriting existing links."), false);
+ private final JRadioButton autoSetNone = new JRadioButton(Localization.lang("Do not automatically set"), false);
+ private final JCheckBox checkLinks = new JCheckBox(Localization.lang("Check existing file links"), true);
+
+
+ public OptionsDialog(JFrame parent, BibDatabaseContext databaseContext) {
+ super(parent, Localization.lang("Synchronize file links"), true);
+ this.databaseContext = databaseContext;
+ ok.addActionListener(e -> {
+ canceled = false;
+ dispose();
+ });
+
+ Action closeAction = new AbstractAction() {
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ dispose();
+ }
+ };
+
+ cancel.addActionListener(closeAction);
+
+ InputMap im = cancel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
+ ActionMap am = cancel.getActionMap();
+ im.put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE_DIALOG), "close");
+ am.put("close", closeAction);
+
+ ButtonGroup bg = new ButtonGroup();
+ bg.add(autoSetUnset);
+ bg.add(autoSetNone);
+ bg.add(autoSetAll);
+
+ FormLayout layout = new FormLayout("fill:pref",
+ "pref, 2dlu, pref, 2dlu, pref, pref, pref, 2dlu, pref, 2dlu, pref, 2dlu, pref, 2dlu, pref");
+ FormBuilder builder = FormBuilder.create().layout(layout);
+ JLabel description = new JLabel("<HTML>"
+ + Localization
+ .lang("Attempt to automatically set file links for your entries. Automatically setting works if "
+ + "a file in your file directory<BR>or a subdirectory is named identically to an entry's BibTeX key, plus extension.")
+ + "</HTML>");
+
+ builder.addSeparator(Localization.lang("Automatically set file links")).xy(1, 1);
+ builder.add(description).xy(1, 3);
+ builder.add(autoSetUnset).xy(1, 5);
+ builder.add(autoSetAll).xy(1, 6);
+ builder.add(autoSetNone).xy(1, 7);
+ builder.addSeparator(Localization.lang("Check links")).xy(1, 9);
+
+ description = new JLabel("<HTML>"
+ + Localization
+ .lang("This makes JabRef look up each file link and check if the file exists. If not, you will be given options<BR>to resolve the problem.")
+ + "</HTML>");
+ builder.add(description).xy(1, 11);
+ builder.add(checkLinks).xy(1, 13);
+ builder.addSeparator("").xy(1, 15);
+
+ JPanel main = builder.getPanel();
+ main.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
+
+ ButtonBarBuilder bb = new ButtonBarBuilder();
+ bb.addGlue();
+ bb.addButton(ok);
+ bb.addButton(cancel);
+ bb.addGlue();
+ getContentPane().add(main, BorderLayout.CENTER);
+ getContentPane().add(bb.getPanel(), BorderLayout.SOUTH);
+
+ pack();
+ }
+
+ @Override
+ public void setVisible(boolean visible) {
+ if (visible) {
+ canceled = true;
+ }
+
+ List<String> dirs = databaseContext.getFileDirectories(Globals.prefs.getFileDirectoryPreferences());
+ if (dirs.isEmpty()) {
+ autoSetNone.setSelected(true);
+ autoSetNone.setEnabled(false);
+ autoSetAll.setEnabled(false);
+ autoSetUnset.setEnabled(false);
+ } else {
+ autoSetNone.setEnabled(true);
+ autoSetAll.setEnabled(true);
+ autoSetUnset.setEnabled(true);
+ }
+
+ ok.requestFocus();
+ super.setVisible(visible);
+
+ }
+
+ public boolean isAutoSetNone() {
+ return autoSetNone.isSelected();
+ }
+
+ public boolean isCheckLinks() {
+ return checkLinks.isSelected();
+ }
+
+ public boolean canceled() {
+ return canceled;
+ }
+ }
+}
diff --git a/src/main/java/net/sf/jabref/gui/externalfiles/TransferableFileLinkSelection.java b/src/main/java/net/sf/jabref/gui/externalfiles/TransferableFileLinkSelection.java
new file mode 100644
index 0000000..bb1edd8
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/externalfiles/TransferableFileLinkSelection.java
@@ -0,0 +1,107 @@
+package net.sf.jabref.gui.externalfiles;
+
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.Transferable;
+import java.awt.datatransfer.UnsupportedFlavorException;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import net.sf.jabref.Globals;
+import net.sf.jabref.gui.BasePanel;
+import net.sf.jabref.gui.filelist.FileListTableModel;
+import net.sf.jabref.logic.util.io.FileUtil;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldName;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ *
+ */
+public class TransferableFileLinkSelection implements Transferable {
+
+ private final List<File> fileList = new ArrayList<>();
+
+ private static final Log LOGGER = LogFactory.getLog(TransferableFileLinkSelection.class);
+
+
+ public TransferableFileLinkSelection(BasePanel panel, List<BibEntry> selection) {
+ FileListTableModel tm = new FileListTableModel();
+ selection.get(0).getField(FieldName.FILE).ifPresent(tm::setContent);
+ if (tm.getRowCount() > 0) {
+ // Find the default directory for this field type, if any:
+ List<String> dirs = panel.getBibDatabaseContext()
+ .getFileDirectories(Globals.prefs.getFileDirectoryPreferences());
+ FileUtil.expandFilename(tm.getEntry(0).link, dirs).ifPresent(fileList::add);
+ }
+
+ }
+
+ @Override
+ public DataFlavor[] getTransferDataFlavors() {
+ return new DataFlavor[] {DataFlavor.javaFileListFlavor};//, DataFlavor.stringFlavor};
+ }
+
+ @Override
+ public boolean isDataFlavorSupported(DataFlavor dataFlavor) {
+ LOGGER.debug("Query: " + dataFlavor.getHumanPresentableName() + " , "
+ +
+ dataFlavor.getDefaultRepresentationClass() + " , " + dataFlavor.getMimeType());
+ return dataFlavor.equals(DataFlavor.javaFileListFlavor)
+ || dataFlavor.equals(DataFlavor.stringFlavor);
+ }
+
+ @Override
+ public Object getTransferData(DataFlavor dataFlavor) throws UnsupportedFlavorException, IOException {
+ //if (dataFlavor.equals(DataFlavor.javaFileListFlavor))
+ return fileList;
+ //else
+ // return "test";
+ }
+ /*
+ private StringSelection ss;
+
+ public TransferableFileLinkSelection(BasePanel panel, BibEntry[] selection) {
+ String s = selection[0].getField(GUIGlobals.FILE_FIELD);
+ FileListTableModel tm = new FileListTableModel();
+ if (s != null)
+ tm.setContent(s);
+ if (tm.getRowCount() > 0) {
+ // Find the default directory for this field type, if any:
+ String dir = panel.metaData().getFileDirectory(GUIGlobals.FILE_FIELD);
+ // Include the standard "file" directory:
+ String fileDir = panel.metaData().getFileDirectory(GUIGlobals.FILE_FIELD);
+ // Include the directory of the BIB file:
+ String[] dirs;
+ if (panel.metaData().getDatabaseFile() != null) {
+ String databaseDir = panel.metaData().getDatabaseFile().getParent();
+ dirs = new String[] { dir, fileDir, databaseDir };
+ }
+ else
+ dirs = new String[] { dir, fileDir };
+ System.out.println(tm.getEntry(0).getLink());
+ for (int i = 0; i < dirs.length; i++) {
+ String dir1 = dirs[i];
+ System.out.println("dir:"+dir1);
+ }
+ File expLink = Util.expandFilename(tm.getEntry(0).getLink(), dirs);
+ try {
+ System.out.println(expLink.toURI().toURL().toString());
+ ss = new StringSelection(expLink.toURI().toURL().toString());
+
+ } catch (MalformedURLException ex) {
+ ss = new StringSelection("");
+ }
+ }
+ else
+ ss = new StringSelection("");
+
+ }
+
+ public Transferable getTransferable() {
+ return ss;
+ } */
+}
diff --git a/src/main/java/net/sf/jabref/gui/externalfiles/WriteXMPAction.java b/src/main/java/net/sf/jabref/gui/externalfiles/WriteXMPAction.java
new file mode 100644
index 0000000..adb541b
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/externalfiles/WriteXMPAction.java
@@ -0,0 +1,297 @@
+package net.sf.jabref.gui.externalfiles;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.event.ActionEvent;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import javax.swing.AbstractAction;
+import javax.swing.ActionMap;
+import javax.swing.BorderFactory;
+import javax.swing.InputMap;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.ScrollPaneConstants;
+import javax.swing.SwingUtilities;
+
+import net.sf.jabref.Globals;
+import net.sf.jabref.gui.BasePanel;
+import net.sf.jabref.gui.filelist.FileListEntry;
+import net.sf.jabref.gui.filelist.FileListTableModel;
+import net.sf.jabref.gui.keyboard.KeyBinding;
+import net.sf.jabref.gui.worker.AbstractWorker;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.logic.util.io.FileUtil;
+import net.sf.jabref.logic.xmp.XMPUtil;
+import net.sf.jabref.model.database.BibDatabase;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldName;
+
+import com.jgoodies.forms.builder.ButtonBarBuilder;
+
+/**
+ *
+ * This action goes through all selected entries in the BasePanel, and attempts
+ * to write the XMP data to the external pdf.
+ */
+public class WriteXMPAction extends AbstractWorker {
+
+ private final BasePanel panel;
+
+ private Collection<BibEntry> entries;
+
+ private BibDatabase database;
+
+ private OptionsDialog optDiag;
+
+ private boolean goOn = true;
+
+ private int skipped;
+ private int entriesChanged;
+ private int errors;
+
+
+ public WriteXMPAction(BasePanel panel) {
+ this.panel = panel;
+ }
+
+ @Override
+ public void init() {
+
+ database = panel.getDatabase();
+ // Get entries and check if it makes sense to perform this operation
+ entries = panel.getSelectedEntries();
+
+ if (entries.isEmpty()) {
+
+ entries = database.getEntries();
+
+ if (entries.isEmpty()) {
+
+ JOptionPane.showMessageDialog(panel,
+ Localization.lang("This operation requires one or more entries to be selected."),
+ Localization.lang("Write XMP-metadata"), JOptionPane.ERROR_MESSAGE);
+ goOn = false;
+ return;
+
+ } else {
+
+ int response = JOptionPane.showConfirmDialog(panel, Localization.lang("Write XMP-metadata for all PDFs in current database?"),
+ Localization.lang("Write XMP-metadata"), JOptionPane.YES_NO_CANCEL_OPTION,
+ JOptionPane.QUESTION_MESSAGE);
+
+ if (response != JOptionPane.YES_OPTION) {
+ goOn = false;
+ return;
+ }
+ }
+ }
+
+ errors = entriesChanged = skipped = 0;
+
+ if (optDiag == null) {
+ optDiag = new OptionsDialog(panel.frame());
+ }
+ optDiag.open();
+
+ panel.output(Localization.lang("Writing XMP-metadata..."));
+ }
+
+ @Override
+ public void run() {
+
+ if (!goOn) {
+ return;
+ }
+
+ for (BibEntry entry : entries) {
+
+ // Make a list of all PDFs linked from this entry:
+ List<File> files = new ArrayList<>();
+
+ // First check the (legacy) "pdf" field:
+ entry.getField(FieldName.PDF)
+ .ifPresent(
+ pdf -> FileUtil
+ .expandFilename(pdf,
+ panel.getBibDatabaseContext().getFileDirectories(FieldName.PDF,
+ Globals.prefs.getFileDirectoryPreferences()))
+ .ifPresent(files::add));
+ // Then check the "file" field:
+ List<String> dirs = panel.getBibDatabaseContext()
+ .getFileDirectories(Globals.prefs.getFileDirectoryPreferences());
+ if (entry.hasField(FieldName.FILE)) {
+ FileListTableModel tm = new FileListTableModel();
+ entry.getField(FieldName.FILE).ifPresent(tm::setContent);
+ for (int j = 0; j < tm.getRowCount(); j++) {
+ FileListEntry flEntry = tm.getEntry(j);
+ if ((flEntry.type.isPresent()) && "pdf".equalsIgnoreCase(flEntry.type.get().getName())) {
+ FileUtil.expandFilename(flEntry.link, dirs).ifPresent(files::add);
+ }
+ }
+ }
+
+ SwingUtilities.invokeLater(() -> optDiag.getProgressArea()
+ .append(entry.getCiteKeyOptional().orElse(Localization.lang("undefined")) + "\n"));
+
+ if (files.isEmpty()) {
+ skipped++;
+ SwingUtilities.invokeLater(() -> optDiag.getProgressArea()
+ .append(" " + Localization.lang("Skipped - No PDF linked") + ".\n"));
+ } else {
+ for (File file : files) {
+ if (file.exists()) {
+ try {
+ XMPUtil.writeXMP(file, entry, database, Globals.prefs.getXMPPreferences());
+ SwingUtilities.invokeLater(
+ () -> optDiag.getProgressArea().append(" " + Localization.lang("OK") + ".\n"));
+ entriesChanged++;
+ } catch (Exception e) {
+ SwingUtilities.invokeLater(() -> {
+ optDiag.getProgressArea().append(" " + Localization.lang("Error while writing") + " '"
+ + file.getPath() + "':\n");
+ optDiag.getProgressArea().append(" " + e.getLocalizedMessage() + "\n");
+ });
+ errors++;
+ }
+ } else {
+ skipped++;
+ SwingUtilities.invokeLater(() -> {
+ optDiag.getProgressArea()
+ .append(" " + Localization.lang("Skipped - PDF does not exist") + ":\n");
+ optDiag.getProgressArea().append(" " + file.getPath() + "\n");
+ });
+ }
+ }
+ }
+
+ if (optDiag.isCanceled()) {
+ SwingUtilities.invokeLater(
+ () -> optDiag.getProgressArea().append("\n" + Localization.lang("Operation canceled.") + "\n"));
+ break;
+ }
+ }
+ SwingUtilities.invokeLater(() -> {
+ optDiag.getProgressArea()
+ .append("\n"
+ + Localization.lang("Finished writing XMP for %0 file (%1 skipped, %2 errors).", String
+ .valueOf(entriesChanged), String.valueOf(skipped), String.valueOf(errors)));
+ optDiag.done();
+ });
+ }
+
+ @Override
+ public void update() {
+ if (!goOn) {
+ return;
+ }
+
+ panel.output(Localization.lang("Finished writing XMP for %0 file (%1 skipped, %2 errors).",
+ String.valueOf(entriesChanged), String.valueOf(skipped), String.valueOf(errors)));
+ }
+
+
+ class OptionsDialog extends JDialog {
+
+ private final JButton okButton = new JButton(Localization.lang("OK"));
+ private final JButton cancelButton = new JButton(Localization.lang("Cancel"));
+
+ private boolean canceled;
+
+ private final JTextArea progressArea;
+
+
+ public OptionsDialog(JFrame parent) {
+ super(parent, Localization.lang("Writing XMP-metadata for selected entries..."), false);
+ okButton.setEnabled(false);
+
+ okButton.addActionListener(e -> dispose());
+
+ AbstractAction cancel = new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ canceled = true;
+ }
+ };
+ cancelButton.addActionListener(cancel);
+
+ InputMap im = cancelButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
+ ActionMap am = cancelButton.getActionMap();
+ im.put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE_DIALOG), "close");
+ am.put("close", cancel);
+
+ progressArea = new JTextArea(15, 60);
+
+ JScrollPane scrollPane = new JScrollPane(progressArea,
+ ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
+ Dimension d = progressArea.getPreferredSize();
+ d.height += scrollPane.getHorizontalScrollBar().getHeight() + 15;
+ d.width += scrollPane.getVerticalScrollBar().getWidth() + 15;
+
+ panel.setSize(d);
+
+ progressArea.setBackground(Color.WHITE);
+ progressArea.setEditable(false);
+ progressArea.setBorder(BorderFactory.createEmptyBorder(3, 3, 3,
+ 3));
+ progressArea.setText("");
+
+ JPanel tmpPanel = new JPanel();
+ tmpPanel.setBorder(BorderFactory.createEmptyBorder(3, 2, 3, 2));
+ tmpPanel.add(scrollPane);
+
+ // progressArea.setPreferredSize(new Dimension(300, 300));
+
+ ButtonBarBuilder bb = new ButtonBarBuilder();
+ bb.addGlue();
+ bb.addButton(okButton);
+ bb.addRelatedGap();
+ bb.addButton(cancelButton);
+ bb.addGlue();
+ JPanel bbPanel = bb.getPanel();
+ bbPanel.setBorder(BorderFactory.createEmptyBorder(0, 3, 3, 3));
+ getContentPane().add(tmpPanel, BorderLayout.CENTER);
+ getContentPane().add(bbPanel, BorderLayout.SOUTH);
+
+ pack();
+ this.setResizable(false);
+
+ }
+
+ public void done() {
+ okButton.setEnabled(true);
+ cancelButton.setEnabled(false);
+ }
+
+ public void open() {
+ progressArea.setText("");
+ canceled = false;
+ optDiag.setLocationRelativeTo(panel.frame());
+
+ okButton.setEnabled(false);
+ cancelButton.setEnabled(true);
+
+ okButton.requestFocus();
+
+ optDiag.setVisible(true);
+ }
+
+ public boolean isCanceled() {
+ return canceled;
+ }
+
+ public JTextArea getProgressArea() {
+ return progressArea;
+ }
+ }
+}
diff --git a/src/main/java/net/sf/jabref/gui/externalfiles/WriteXMPEntryEditorAction.java b/src/main/java/net/sf/jabref/gui/externalfiles/WriteXMPEntryEditorAction.java
new file mode 100644
index 0000000..f9d5037
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/externalfiles/WriteXMPEntryEditorAction.java
@@ -0,0 +1,143 @@
+package net.sf.jabref.gui.externalfiles;
+
+import java.awt.event.ActionEvent;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.xml.transform.TransformerException;
+
+import net.sf.jabref.Globals;
+import net.sf.jabref.gui.BasePanel;
+import net.sf.jabref.gui.IconTheme;
+import net.sf.jabref.gui.entryeditor.EntryEditor;
+import net.sf.jabref.gui.filelist.FileListEntry;
+import net.sf.jabref.gui.filelist.FileListTableModel;
+import net.sf.jabref.gui.worker.AbstractWorker;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.logic.util.io.FileUtil;
+import net.sf.jabref.logic.xmp.XMPUtil;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldName;
+
+/**
+ * Write XMP action for EntryEditor toolbar.
+ */
+public class WriteXMPEntryEditorAction extends AbstractAction {
+
+ private final BasePanel panel;
+ private final EntryEditor editor;
+ private String message;
+
+
+ public WriteXMPEntryEditorAction(BasePanel panel, EntryEditor editor) {
+ this.panel = panel;
+ this.editor = editor;
+ // normally, the next call should be without "Localization.lang". However, the string "Write XMP" is also used in non-menu places and therefore, the translation must be also available at Localization.lang
+ putValue(Action.NAME, Localization.lang("Write XMP"));
+ putValue(Action.SMALL_ICON, IconTheme.JabRefIcon.WRITE_XMP.getIcon());
+ putValue(Action.SHORT_DESCRIPTION, Localization.lang("Write BibTeXEntry as XMP-metadata to PDF."));
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent actionEvent) {
+ setEnabled(false);
+ panel.output(Localization.lang("Writing XMP-metadata..."));
+ panel.frame().setProgressBarIndeterminate(true);
+ panel.frame().setProgressBarVisible(true);
+ BibEntry entry = editor.getEntry();
+
+ // Make a list of all PDFs linked from this entry:
+ List<File> files = new ArrayList<>();
+
+ // First check the (legacy) "pdf" field:
+ entry.getField(FieldName.PDF)
+ .ifPresent(pdf -> FileUtil.expandFilename(pdf, panel.getBibDatabaseContext()
+ .getFileDirectories(FieldName.PDF, Globals.prefs.getFileDirectoryPreferences()))
+ .ifPresent(files::add));
+
+ // Then check the "file" field:
+ List<String> dirs = panel.getBibDatabaseContext().getFileDirectories(Globals.prefs.getFileDirectoryPreferences());
+ if (entry.hasField(FieldName.FILE)) {
+ FileListTableModel tm = new FileListTableModel();
+ entry.getField(FieldName.FILE).ifPresent(tm::setContent);
+ for (int j = 0; j < tm.getRowCount(); j++) {
+ FileListEntry flEntry = tm.getEntry(j);
+ if ((flEntry.type.isPresent()) && "pdf".equalsIgnoreCase(flEntry.type.get().getName())) {
+ FileUtil.expandFilename(flEntry.link, dirs).ifPresent(files::add);
+ }
+ }
+ }
+
+ // We want to offload the actual work to a background thread, so we have a worker
+ // thread:
+ AbstractWorker worker = new WriteXMPWorker(files, entry);
+ // Using Spin, we get a thread that gets synchronously offloaded to a new thread,
+ // blocking the execution of this method:
+ worker.getWorker().run();
+ // After the worker thread finishes, we are unblocked and ready to print the
+ // status message:
+ panel.output(message);
+ panel.frame().setProgressBarVisible(false);
+ setEnabled(true);
+ }
+
+
+ class WriteXMPWorker extends AbstractWorker {
+
+ private final List<File> files;
+ private final BibEntry entry;
+
+
+ public WriteXMPWorker(List<File> files, BibEntry entry) {
+
+ this.files = files;
+ this.entry = entry;
+ }
+
+ @Override
+ public void run() {
+ if (files.isEmpty()) {
+ message = Localization.lang("No PDF linked") + ".\n";
+ } else {
+ int written = 0;
+ int error = 0;
+ for (File file : files) {
+ if (!file.exists()) {
+ if (files.size() == 1) {
+ message = Localization.lang("PDF does not exist");
+ }
+ error++;
+
+ } else {
+ try {
+ XMPUtil.writeXMP(file, entry, panel.getDatabase(), Globals.prefs.getXMPPreferences());
+ if (files.size() == 1) {
+ message = Localization.lang("Wrote XMP-metadata");
+ }
+ written++;
+ } catch (IOException | TransformerException e) {
+ if (files.size() == 1) {
+ message = Localization.lang("Error while writing") + " '" + file.getPath() + "'";
+ }
+ error++;
+
+ }
+ }
+ }
+ if (files.size() > 1) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(Localization.lang("Finished writing XMP-metadata. Wrote to %0 file(s).",
+ String.valueOf(written)));
+ if (error > 0) {
+ sb.append(' ').append(Localization.lang("Error writing to %0 file(s).", String.valueOf(error)));
+ }
+ message = sb.toString();
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/net/sf/jabref/gui/externalfiletype/ExternalFileMenuItem.java b/src/main/java/net/sf/jabref/gui/externalfiletype/ExternalFileMenuItem.java
new file mode 100644
index 0000000..c41c383
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/externalfiletype/ExternalFileMenuItem.java
@@ -0,0 +1,112 @@
+package net.sf.jabref.gui.externalfiletype;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.File;
+import java.io.IOException;
+import java.util.Optional;
+
+import javax.swing.Icon;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+
+import net.sf.jabref.gui.JabRefFrame;
+import net.sf.jabref.gui.desktop.JabRefDesktop;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.database.BibDatabaseContext;
+import net.sf.jabref.model.entry.BibEntry;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * The menu item used in the popup menu for opening external resources associated
+ * with an entry. Shows the resource name and icon given, and adds an action listener
+ * to process the request if the user clicks this menu item.
+ */
+public class ExternalFileMenuItem extends JMenuItem implements ActionListener {
+
+ private static final Log LOGGER = LogFactory.getLog(ExternalFileMenuItem.class);
+
+ private final BibEntry entry;
+ private final String link;
+ private final BibDatabaseContext databaseContext;
+ private Optional<ExternalFileType> fileType;
+ private final JabRefFrame frame;
+ private String fieldName;
+
+
+ public ExternalFileMenuItem(JabRefFrame frame, BibEntry entry, String name, String link, Icon icon,
+ BibDatabaseContext databaseContext, Optional<ExternalFileType> fileType) {
+ super(name, icon);
+ this.frame = frame;
+ this.entry = entry;
+ this.link = link;
+ this.databaseContext = databaseContext;
+ this.fileType = fileType;
+ addActionListener(this);
+ }
+
+ public ExternalFileMenuItem(JabRefFrame frame, BibEntry entry, String name, String link, Icon icon,
+ BibDatabaseContext databaseContext, String fieldName) {
+ this(frame, entry, name, link, icon, databaseContext, Optional.empty());
+ this.fieldName = fieldName;
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ boolean success = openLink();
+ if (!success) {
+ frame.output(Localization.lang("Unable to open link."));
+ }
+ }
+
+ public boolean openLink() {
+ frame.output(Localization.lang("External viewer called") + ".");
+ try {
+ Optional<ExternalFileType> type = fileType;
+ if (!this.fileType.isPresent()) {
+ if (this.fieldName == null) {
+ // We don't already know the file type, so we try to deduce it from the extension:
+ File file = new File(link);
+ // We try to check the extension for the file:
+ String name = file.getName();
+ int pos = name.indexOf('.');
+ String extension = (pos >= 0) && (pos < (name.length() - 1)) ? name.substring(pos + 1)
+ .trim().toLowerCase() : null;
+ // Now we know the extension, check if it is one we know about:
+ type = ExternalFileTypes.getInstance().getExternalFileTypeByExt(extension);
+ fileType = type;
+ } else {
+ JabRefDesktop.openExternalViewer(databaseContext, link, fieldName);
+ return true;
+ }
+ }
+
+ if (type.isPresent() && (type.get() instanceof UnknownExternalFileType)) {
+ return JabRefDesktop.openExternalFileUnknown(frame, entry, databaseContext, link,
+ (UnknownExternalFileType) type.get());
+ } else {
+ return JabRefDesktop.openExternalFileAnyFormat(databaseContext, link, type);
+ }
+
+ } catch (IOException e1) {
+ // See if we should show an error message concerning the application to open the
+ // link with. We check if the file type is set, and if the file type has a non-empty
+ // application link. If that link is referred by the error message, we can assume
+ // that the problem is in the open-with-application setting:
+ if ((fileType.isPresent()) && (!fileType.get().getOpenWithApplication().isEmpty())
+ && e1.getMessage().contains(fileType.get().getOpenWithApplication())) {
+
+ JOptionPane.showMessageDialog(frame, Localization.lang("Unable to open link. "
+ + "The application '%0' associated with the file type '%1' could not be called.",
+ fileType.get().getOpenWithApplication(), fileType.get().getName()),
+ Localization.lang("Could not open link"), JOptionPane.ERROR_MESSAGE);
+ return false;
+ }
+
+ LOGGER.warn("Unable to open link", e1);
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/net/sf/jabref/gui/externalfiletype/ExternalFileType.java b/src/main/java/net/sf/jabref/gui/externalfiletype/ExternalFileType.java
new file mode 100644
index 0000000..f8687bc
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/externalfiletype/ExternalFileType.java
@@ -0,0 +1,222 @@
+package net.sf.jabref.gui.externalfiletype;
+
+import java.util.Objects;
+
+import javax.swing.Icon;
+import javax.swing.JLabel;
+
+import net.sf.jabref.gui.IconTheme;
+
+/**
+ * This class defines a type of external files that can be linked to from JabRef.
+ * The class contains enough information to provide an icon, a standard extension
+ * and a link to which application handles files of this type.
+ */
+public class ExternalFileType implements Comparable<ExternalFileType> {
+
+ private String name;
+ private String extension;
+ private String openWith;
+ private String iconName;
+ private String mimeType;
+ private Icon icon;
+ private final JLabel label = new JLabel();
+
+ public ExternalFileType(String name, String extension, String mimeType,
+ String openWith, String iconName, Icon icon) {
+ label.setText(null);
+ this.name = name;
+ label.setToolTipText(this.name);
+ this.extension = extension;
+ this.mimeType = mimeType;
+ this.openWith = openWith;
+
+ setIconName(iconName);
+ setIcon(icon);
+ }
+
+ /**
+ * Construct an ExternalFileType from a String array. This is used when
+ * reading file type definitions from Preferences, where the available data types are
+ * limited. We assume that the array contains the same values as the main constructor,
+ * in the same order.
+ *
+ * @param val arguments.
+ */
+ public static ExternalFileType buildFromArgs(String[] val) {
+ if ((val == null) || (val.length < 4) || (val.length > 5)) {
+ throw new IllegalArgumentException("Cannot construct ExternalFileType without four elements in String[] argument.");
+ }
+ String name = val[0];
+ String extension = val[1];
+ String openWith;
+ String mimeType;
+ String iconName;
+ Icon icon;
+
+ if (val.length == 4) {
+ // Up to version 2.4b the mime type is not included:
+ mimeType = "";
+ openWith = val[2];
+ iconName = val[3];
+ } else {
+ // When mime type is included, the array length should be 5:
+ mimeType = val[2];
+ openWith = val[3];
+ iconName = val[4];
+ }
+
+ // set icon to default first
+ icon = IconTheme.JabRefIcon.FILE.getSmallIcon();
+
+ // check whether there is another icon defined for this file type
+ for(ExternalFileType fileType : ExternalFileTypes.getDefaultExternalFileTypes()) {
+ if(fileType.getName().equals(name)) {
+ icon = fileType.icon;
+ break;
+ }
+ }
+
+ return new ExternalFileType(name, extension, mimeType, openWith, iconName, icon);
+ }
+
+ /**
+ * Return a String array representing this file type. This is used for storage into
+ * Preferences, and the same array can be used to construct the file type later,
+ * using the String[] constructor.
+ *
+ * @return A String[] containing all information about this file type.
+ */
+ public String[] getStringArrayRepresentation() {
+ return new String[]{name, extension, mimeType, openWith, iconName};
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ label.setToolTipText(this.name);
+ }
+
+ public String getExtension() {
+ if (extension == null) {
+ return "";
+ }
+ return extension;
+ }
+
+ public void setExtension(String extension) {
+ this.extension = extension;
+ }
+
+ public String getMimeType() {
+ if (mimeType == null) {
+ return "";
+ }
+ return mimeType;
+ }
+
+ public void setMimeType(String mimeType) {
+ this.mimeType = mimeType;
+ }
+
+ /**
+ * Get the bibtex field name used to extension to this file type.
+ * Currently we assume that field name equals filename extension.
+ *
+ * @return The field name.
+ */
+ public String getFieldName() {
+ return extension;
+ }
+
+ public String getOpenWithApplication() {
+ if (openWith == null) {
+ return "";
+ }
+ return openWith;
+ }
+
+ public void setOpenWith(String openWith) {
+ this.openWith = openWith;
+ }
+
+ /**
+ * Set the string associated with this file type's icon.
+ *
+ * @param name The icon name to use.
+ */
+ public void setIconName(String name) {
+ this.iconName = name;
+ }
+
+ /**
+ * Obtain a JLabel instance set with this file type's icon. The same JLabel
+ * is returned from each call of this method.
+ *
+ * @return the label.
+ */
+ public JLabel getIconLabel() {
+ return label;
+ }
+
+ /**
+ * Get the string associated with this file type's icon.
+ *
+ * @return The icon name.
+ */
+ public String getIconName() {
+ return iconName;
+ }
+
+ public Icon getIcon() {
+ return icon;
+ }
+
+ public void setIcon(Icon icon) {
+ this.icon = icon;
+ label.setIcon(this.icon);
+ }
+
+ @Override
+ public String toString() {
+ return getName();
+ }
+
+ @Override
+ public int compareTo(ExternalFileType o) {
+ return getName().compareTo(o.getName());
+ }
+
+ public ExternalFileType copy() {
+ return new ExternalFileType(name, extension, mimeType, openWith, iconName, icon);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(name, extension, mimeType, openWith, iconName);
+ }
+
+ /**
+ * We define two file type objects as equal if their name, extension, openWith and
+ * iconName are equal.
+ *
+ * @param object The file type to compare with.
+ * @return true if the file types are equal.
+ */
+ @Override
+ public boolean equals(Object object) {
+ if (this == object) {
+ return true;
+ }
+
+ if (object instanceof ExternalFileType) {
+ ExternalFileType other = (ExternalFileType) object;
+ return Objects.equals(name, other.name) && Objects.equals(extension, other.extension) &&
+ Objects.equals(mimeType, other.mimeType) && Objects.equals(openWith, other.openWith) && Objects.equals(iconName, other.iconName);
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/net/sf/jabref/gui/externalfiletype/ExternalFileTypeEditor.java b/src/main/java/net/sf/jabref/gui/externalfiletype/ExternalFileTypeEditor.java
new file mode 100644
index 0000000..aa14b7a
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/externalfiletype/ExternalFileTypeEditor.java
@@ -0,0 +1,382 @@
+package net.sf.jabref.gui.externalfiletype;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.ActionMap;
+import javax.swing.BorderFactory;
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+import javax.swing.InputMap;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTable;
+import javax.swing.table.AbstractTableModel;
+import javax.swing.table.TableCellRenderer;
+
+import net.sf.jabref.Globals;
+import net.sf.jabref.gui.IconTheme;
+import net.sf.jabref.gui.JabRefFrame;
+import net.sf.jabref.gui.actions.MnemonicAwareAction;
+import net.sf.jabref.gui.keyboard.KeyBinding;
+import net.sf.jabref.logic.l10n.Localization;
+
+import com.jgoodies.forms.builder.ButtonBarBuilder;
+import com.jgoodies.forms.builder.ButtonStackBuilder;
+
+/**
+ * Editor for external file types.
+ */
+public class ExternalFileTypeEditor extends JDialog {
+
+ private JFrame frame;
+ private JDialog dialog;
+ private List<ExternalFileType> fileTypes;
+ private JTable table;
+ private ExternalFileTypeEntryEditor entryEditor;
+ private FileTypeTableModel tableModel;
+ private final JButton ok = new JButton(Localization.lang("OK"));
+ private final JButton cancel = new JButton(Localization.lang("Cancel"));
+ private final JButton add = new JButton(IconTheme.JabRefIcon.ADD_NOBOX.getIcon());
+ private final JButton remove = new JButton(IconTheme.JabRefIcon.REMOVE_NOBOX.getIcon());
+ private final JButton edit = new JButton(IconTheme.JabRefIcon.EDIT.getIcon());
+ private final JButton toDefaults = new JButton(Localization.lang("Default"));
+ private final EditListener editListener = new EditListener();
+
+
+ private ExternalFileTypeEditor(JFrame frame) {
+ super(frame, Localization.lang("Manage external file types"), true);
+ this.frame = frame;
+ init();
+ }
+
+ private ExternalFileTypeEditor(JDialog dialog) {
+ super(dialog, Localization.lang("Manage external file types"), true);
+ this.dialog = dialog;
+ init();
+ }
+
+ /**
+ * Update the editor to show the current settings in Preferences.
+ */
+ private void setValues() {
+ fileTypes.clear();
+ Collection<ExternalFileType> types = ExternalFileTypes.getInstance().getExternalFileTypeSelection();
+ for (ExternalFileType type : types) {
+ fileTypes.add(type.copy());
+ }
+ Collections.sort(fileTypes);
+ }
+
+ /**
+ * Store the list of external entry types to Preferences.
+ */
+ private void storeSettings() {
+ ExternalFileTypes.getInstance().setExternalFileTypes(fileTypes);
+ }
+
+ private void init() {
+
+ ok.addActionListener(e -> {
+ storeSettings();
+ dispose();
+ });
+ Action cancelAction = new AbstractAction() {
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ dispose();
+ }
+ };
+ cancel.addActionListener(cancelAction);
+ // The toDefaults resets the entire list to its default values.
+ toDefaults.addActionListener(e -> {
+ /*int reply = JOptionPane.showConfirmDialog(ExternalFileTypeEditor.this,
+ Globals.lang("All custom file types will be lost. Proceed?"),
+ Globals.lang("Reset file type definitions"), JOptionPane.YES_NO_OPTION,
+ JOptionPane.QUESTION_MESSAGE);*/
+ //if (reply == JOptionPane.YES_OPTION) {
+ List<ExternalFileType> list = ExternalFileTypes.getDefaultExternalFileTypes();
+ fileTypes.clear();
+ fileTypes.addAll(list);
+ Collections.sort(fileTypes);
+ //Globals.prefs.resetExternalFileTypesToDefault();
+ //setValues();
+ tableModel.fireTableDataChanged();
+ //}
+ });
+
+ add.addActionListener(e -> {
+ // Generate a new file type:
+ ExternalFileType type = new ExternalFileType("", "", "", "", "new",
+ IconTheme.JabRefIcon.FILE.getSmallIcon());
+ // Show the file type editor:
+ getEditor(type).setVisible(true);
+ if (entryEditor.okPressed()) {
+ // Ok was pressed. Add the new file type and update the table:
+ fileTypes.add(type);
+ tableModel.fireTableDataChanged();
+ }
+ });
+
+ remove.addActionListener(e -> {
+ int[] rows = table.getSelectedRows();
+ if (rows.length == 0) {
+ return;
+ }
+ for (int i = rows.length - 1; i >= 0; i--) {
+ fileTypes.remove(rows[i]);
+ }
+ tableModel.fireTableDataChanged();
+ if (!fileTypes.isEmpty()) {
+ int row = Math.min(rows[0], fileTypes.size() - 1);
+ table.setRowSelectionInterval(row, row);
+ }
+ });
+
+ edit.addActionListener(editListener);
+ fileTypes = new ArrayList<>();
+ setValues();
+
+ tableModel = new FileTypeTableModel();
+ table = new JTable(tableModel);
+ table.setDefaultRenderer(ImageIcon.class, new IconRenderer());
+ table.addMouseListener(new TableClickListener());
+
+ table.getColumnModel().getColumn(0).setMaxWidth(24);
+ table.getColumnModel().getColumn(0).setMinWidth(24);
+ table.getColumnModel().getColumn(1).setMinWidth(170);
+ table.getColumnModel().getColumn(2).setMinWidth(60);
+ table.getColumnModel().getColumn(3).setMinWidth(100);
+ table.getColumnModel().getColumn(0).setResizable(false);
+
+ JScrollPane sp = new JScrollPane(table);
+
+ JPanel upper = new JPanel();
+ upper.setLayout(new BorderLayout());
+ upper.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
+ upper.add(sp, BorderLayout.CENTER);
+ getContentPane().add(upper, BorderLayout.CENTER);
+
+ ButtonStackBuilder bs = new ButtonStackBuilder();
+ bs.addButton(add);
+ bs.addButton(remove);
+ bs.addButton(edit);
+ bs.addRelatedGap();
+ bs.addButton(toDefaults);
+ upper.add(bs.getPanel(), BorderLayout.EAST);
+
+ ButtonBarBuilder bb = new ButtonBarBuilder();
+ bb.addGlue();
+ bb.addButton(ok);
+ bb.addButton(cancel);
+ bb.addGlue();
+ bb.getPanel().setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
+ getContentPane().add(bb.getPanel(), BorderLayout.SOUTH);
+ pack();
+
+ // Key bindings:
+ ActionMap am = upper.getActionMap();
+ InputMap im = upper.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
+ im.put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE_DIALOG), "close");
+ am.put("close", cancelAction);
+ am = bb.getPanel().getActionMap();
+ im = bb.getPanel().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
+ im.put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE_DIALOG), "close");
+ am.put("close", cancelAction);
+
+ if (frame == null) {
+ setLocationRelativeTo(dialog);
+ } else {
+ setLocationRelativeTo(frame);
+ }
+ }
+
+ private ExternalFileTypeEntryEditor getEditor(ExternalFileType type) {
+ if (entryEditor == null) {
+ entryEditor = new ExternalFileTypeEntryEditor(ExternalFileTypeEditor.this, type);
+ } else {
+ entryEditor.setEntry(type);
+ }
+ return entryEditor;
+ }
+
+ /**
+ * Get an AbstractAction for opening the external file types editor.
+ * @param frame The JFrame used as parent window for the dialog.
+ * @return An Action for opening the editor.
+ */
+ public static AbstractAction getAction(JabRefFrame frame) {
+ return new EditExternalFileTypesAction(frame);
+ }
+
+ /**
+ * Get an AbstractAction for opening the external file types editor.
+ * @param dialog The JDialog used as parent window for the dialog.
+ * @return An Action for opening the editor.
+ */
+ public static AbstractAction getAction(JDialog dialog) {
+ return new EditExternalFileTypesAction(dialog);
+ }
+
+
+ class EditListener implements ActionListener {
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ int[] rows = table.getSelectedRows();
+ if (rows.length != 1) {
+ return;
+ }
+ getEditor(fileTypes.get(rows[0])).setVisible(true);
+ if (entryEditor.okPressed()) {
+ tableModel.fireTableDataChanged();
+ }
+ }
+ }
+
+ static class IconRenderer implements TableCellRenderer {
+
+ private final JLabel lab = new JLabel();
+
+
+ @Override
+ public Component getTableCellRendererComponent(JTable tab, Object value, boolean isSelected, boolean hasFocus,
+ int row, int column) {
+ lab.setText(null);
+ lab.setIcon((Icon) value);
+ return lab;
+ }
+ }
+
+ private class FileTypeTableModel extends AbstractTableModel {
+
+ @Override
+ public int getColumnCount() {
+ return 5;
+ }
+
+ @Override
+ public int getRowCount() {
+ return fileTypes.size();
+ }
+
+ @Override
+ public String getColumnName(int column) {
+ switch (column) {
+ case 0:
+ return " ";
+ case 1:
+ return Localization.lang("Name");
+ case 2:
+ return Localization.lang("Extension");
+ case 3:
+ return Localization.lang("MIME type");
+ default: // Five columns
+ return Localization.lang("Application");
+ }
+ }
+
+ @Override
+ public Class<?> getColumnClass(int columnIndex) {
+ if (columnIndex == 0) {
+ return ImageIcon.class;
+ } else {
+ return String.class;
+ }
+ }
+
+ @Override
+ public Object getValueAt(int rowIndex, int columnIndex) {
+ ExternalFileType type = fileTypes.get(rowIndex);
+ switch (columnIndex) {
+ case 0:
+ return type.getIcon();
+ case 1:
+ return type.getName();
+ case 2:
+ return type.getExtension();
+ case 3:
+ return type.getMimeType();
+ default:
+ return type.getOpenWithApplication();
+ }
+ }
+ }
+
+ class TableClickListener extends MouseAdapter {
+
+ private void handleClick(MouseEvent e) {
+ if (e.getClickCount() == 2) {
+ editListener.actionPerformed(null);
+ }
+ }
+
+ @Override
+ public void mouseClicked(MouseEvent e) {
+ handleClick(e);
+ }
+
+ @Override
+ public void mousePressed(MouseEvent e) {
+ handleClick(e);
+ }
+
+ @Override
+ public void mouseReleased(MouseEvent e) {
+ handleClick(e);
+ }
+ }
+
+ public static class EditExternalFileTypesAction extends MnemonicAwareAction {
+
+ private JabRefFrame frame;
+ private JDialog dialog;
+ private ExternalFileTypeEditor editor;
+
+
+ public EditExternalFileTypesAction(JabRefFrame frame) {
+ super();
+ putValue(Action.NAME, Localization.menuTitle("Manage external file types"));
+ this.frame = frame;
+ }
+
+ public EditExternalFileTypesAction(JDialog dialog) {
+ super();
+ putValue(Action.NAME, Localization.menuTitle("Manage external file types"));
+ this.dialog = dialog;
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (editor == null) {
+ if (frame == null) {
+ editor = new ExternalFileTypeEditor(dialog);
+ } else {
+ editor = new ExternalFileTypeEditor(frame);
+ }
+ }
+ editor.setValues();
+ editor.setVisible(true);
+ if ((frame != null) && (frame.getCurrentBasePanel() != null)) {
+ frame.getCurrentBasePanel().getMainTable().repaint();
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/gui/externalfiletype/ExternalFileTypeEntryEditor.java b/src/main/java/net/sf/jabref/gui/externalfiletype/ExternalFileTypeEntryEditor.java
new file mode 100644
index 0000000..69e0c1e
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/externalfiletype/ExternalFileTypeEntryEditor.java
@@ -0,0 +1,249 @@
+package net.sf.jabref.gui.externalfiletype;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.event.ActionListener;
+import java.nio.file.Path;
+import java.util.Optional;
+
+import javax.swing.BorderFactory;
+import javax.swing.ButtonGroup;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.JTextField;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+
+import net.sf.jabref.Globals;
+import net.sf.jabref.gui.FileDialog;
+import net.sf.jabref.gui.IconTheme;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.logic.util.OS;
+import net.sf.jabref.preferences.JabRefPreferences;
+
+import com.jgoodies.forms.builder.ButtonBarBuilder;
+import com.jgoodies.forms.builder.FormBuilder;
+import com.jgoodies.forms.layout.FormLayout;
+
+/**
+ * This class produces a dialog box for editing an external file type.
+ */
+public class ExternalFileTypeEntryEditor {
+
+ private JFrame fParent;
+ private JDialog dParent;
+ private JDialog diag;
+ private final JTextField extension = new JTextField();
+ private final JTextField name = new JTextField();
+ private final JTextField mimeType = new JTextField();
+ private final JTextField application = new JTextField();
+ private final JLabel icon = new JLabel(IconTheme.JabRefIcon.FILE.getSmallIcon());
+ private final JButton ok = new JButton(Localization.lang("OK"));
+ private final JButton cancel = new JButton(Localization.lang("Cancel"));
+ private final JRadioButton useDefault = new JRadioButton(Localization.lang("Default"));
+ private final JRadioButton other = new JRadioButton("");
+ private final String editFileTitle = Localization.lang("Edit file type");
+ private final String newFileTitle = Localization.lang("Add new file type");
+
+ private ExternalFileType entry;
+ private boolean okPressed;
+
+ private final ActionListener browsePressed = e -> {
+ String appDir = application.getText().trim();
+ if (appDir.isEmpty()) {
+ appDir = Globals.prefs.get(JabRefPreferences.WORKING_DIRECTORY);
+ }
+
+ Optional<Path> path = new FileDialog(fParent, appDir).showDialogAndGetSelectedFile();
+ path.ifPresent(applicationDir -> {
+ if (applicationDir.getParent() != null) {
+ Globals.prefs.put(JabRefPreferences.WORKING_DIRECTORY, applicationDir.getParent().toString());
+ }
+ application.setText(applicationDir.toString());
+ });
+ };
+
+ public ExternalFileTypeEntryEditor(JFrame parent, ExternalFileType entry) {
+ fParent = parent;
+ init(entry);
+ }
+
+ public ExternalFileTypeEntryEditor(JDialog parent, ExternalFileType entry) {
+ dParent = parent;
+ init(entry);
+ }
+
+ private void init(ExternalFileType inEntry) {
+ entry = inEntry;
+ icon.setText(null);
+
+ ButtonGroup bg = new ButtonGroup();
+ bg.add(useDefault);
+ bg.add(other);
+
+ FormBuilder builder = FormBuilder.create();
+ builder.layout(new FormLayout("left:pref, 4dlu, fill:150dlu, 4dlu, fill:pref",
+ "p, 2dlu, p, 2dlu, p, 2dlu, p, 2dlu, p, 2dlu, p"));
+ builder.add(Localization.lang("Icon")).xy(1, 1);
+ builder.add(icon).xy(3, 1);
+ builder.add(Localization.lang("Name")).xy(1, 3);
+ builder.add(name).xy(3, 3);
+ builder.add(Localization.lang("Extension")).xy(1, 5);
+ builder.add(extension).xy(3, 5);
+ builder.add(Localization.lang("MIME type")).xy(1, 7);
+ builder.add(mimeType).xy(3, 7);
+ builder.getPanel().setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
+ builder.add(Localization.lang("Application")).xy(1, 9);
+ JButton browseBut = new JButton(Localization.lang("Browse"));
+ if (OS.WINDOWS) {
+ builder.add(useDefault).xy(3, 9);
+ builder.appendRows("2dlu, p");
+ JPanel p1 = new JPanel();
+ builder.add(p1).xy(1, 11);
+ JPanel p2 = new JPanel();
+ application.setPreferredSize(new Dimension(300, application.getPreferredSize().height));
+ BorderLayout bl = new BorderLayout();
+ bl.setHgap(4);
+ p2.setLayout(bl);
+ p2.add(other, BorderLayout.WEST);
+ p2.add(application, BorderLayout.CENTER);
+ builder.add(p2).xy(3, 11);
+ builder.add(browseBut).xy(5, 11);
+ } else {
+ builder.add(application).xy(3, 9);
+ builder.add(browseBut).xy(5, 9);
+ }
+ ButtonBarBuilder bb = new ButtonBarBuilder();
+ bb.addGlue();
+ bb.addButton(ok);
+ bb.addButton(cancel);
+ bb.addGlue();
+
+ ok.addActionListener(e -> {
+ okPressed = true;
+
+ storeSettings(ExternalFileTypeEntryEditor.this.entry);
+ diag.dispose();
+
+ });
+ cancel.addActionListener(e -> diag.dispose());
+
+ if (OS.WINDOWS) {
+ application.getDocument().addDocumentListener(new DocumentListener() {
+
+ private void handle() {
+ if (application.getText().isEmpty()) {
+ useDefault.setSelected(true);
+ } else {
+ other.setSelected(true);
+ }
+ }
+
+ @Override
+ public void insertUpdate(DocumentEvent documentEvent) {
+ handle();
+ }
+
+ @Override
+ public void removeUpdate(DocumentEvent documentEvent) {
+ handle();
+ }
+
+ @Override
+ public void changedUpdate(DocumentEvent documentEvent) {
+ handle();
+ }
+ });
+ }
+
+ String title = editFileTitle;
+
+ if (entry.getName().isEmpty()) {
+ title = newFileTitle;
+ }
+
+ if (dParent == null) {
+ diag = new JDialog(fParent, title, true);
+ } else {
+ diag = new JDialog(dParent, title, true);
+ }
+ diag.getContentPane().add(builder.getPanel(), BorderLayout.CENTER);
+ diag.getContentPane().add(bb.getPanel(), BorderLayout.SOUTH);
+ diag.pack();
+
+ browseBut.addActionListener(browsePressed);
+
+ if (dParent == null) {
+ diag.setLocationRelativeTo(fParent);
+ } else {
+ diag.setLocationRelativeTo(dParent);
+ }
+
+ setValues(entry);
+ }
+
+ public void setEntry(ExternalFileType entry) {
+ this.entry = entry;
+ if (entry.getName().isEmpty()) {
+ diag.setTitle(newFileTitle);
+ } else {
+ diag.setTitle(editFileTitle);
+ }
+ setValues(entry);
+ }
+
+ public void setVisible(boolean visible) {
+ if (visible) {
+ okPressed = false;
+ }
+ diag.setVisible(visible);
+ }
+
+ private void setValues(ExternalFileType entry) {
+ name.setText(entry.getName());
+ extension.setText(entry.getExtension());
+ mimeType.setText(entry.getMimeType());
+ application.setText(entry.getOpenWithApplication());
+ icon.setIcon(entry.getIcon());
+ if (application.getText().isEmpty()) {
+ useDefault.setSelected(true);
+ } else {
+ other.setSelected(true);
+ }
+ }
+
+ private void storeSettings(ExternalFileType fileTypeEntry) {
+ fileTypeEntry.setName(name.getText().trim());
+ fileTypeEntry.setMimeType(mimeType.getText().trim());
+ // Set extension, but remove initial dot if user has added that:
+ String ext = extension.getText().trim();
+ if (!ext.isEmpty() && (ext.charAt(0) == '.')) {
+ fileTypeEntry.setExtension(ext.substring(1));
+ } else {
+ fileTypeEntry.setExtension(ext);
+ }
+
+ if (OS.WINDOWS) {
+ // On Windows, store application as empty if the "Default" option is selected,
+ // or if the application name is empty:
+ if (useDefault.isSelected() || application.getText().trim().isEmpty()) {
+ fileTypeEntry.setOpenWith("");
+ } else {
+ fileTypeEntry.setOpenWith(application.getText().trim());
+ }
+ } else {
+ fileTypeEntry.setOpenWith(application.getText().trim());
+ }
+ }
+
+ public boolean okPressed() {
+ return okPressed;
+ }
+
+
+
+}
diff --git a/src/main/java/net/sf/jabref/gui/externalfiletype/ExternalFileTypes.java b/src/main/java/net/sf/jabref/gui/externalfiletype/ExternalFileTypes.java
new file mode 100644
index 0000000..705f2c3
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/externalfiletype/ExternalFileTypes.java
@@ -0,0 +1,322 @@
+package net.sf.jabref.gui.externalfiletype;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import java.util.TreeSet;
+
+import net.sf.jabref.Globals;
+import net.sf.jabref.gui.IconTheme;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.entry.FileField;
+import net.sf.jabref.model.strings.StringUtil;
+import net.sf.jabref.preferences.JabRefPreferences;
+
+public final class ExternalFileTypes {
+
+ // This String is used in the encoded list in prefs of external file type
+ // modifications, in order to indicate a removed default file type:
+ private static final String FILE_TYPE_REMOVED_FLAG = "REMOVED";
+
+ // Map containing all registered external file types:
+ private final Set<ExternalFileType> externalFileTypes = new TreeSet<>();
+
+ private final ExternalFileType HTML_FALLBACK_TYPE = new ExternalFileType("URL", "html", "text/html", "", "www",
+ IconTheme.JabRefIcon.WWW.getSmallIcon());
+
+ // The only instance of this class:
+ private static ExternalFileTypes singleton;
+
+
+ public static ExternalFileTypes getInstance() {
+ if (ExternalFileTypes.singleton == null) {
+ ExternalFileTypes.singleton = new ExternalFileTypes();
+ }
+ return ExternalFileTypes.singleton;
+ }
+
+ private ExternalFileTypes() {
+ updateExternalFileTypes();
+ }
+
+ public static List<ExternalFileType> getDefaultExternalFileTypes() {
+ List<ExternalFileType> list = new ArrayList<>();
+ list.add(new ExternalFileType("PDF", "pdf", "application/pdf", "evince", "pdfSmall",
+ IconTheme.JabRefIcon.PDF_FILE.getSmallIcon()));
+ list.add(new ExternalFileType("PostScript", "ps", "application/postscript", "evince", "psSmall",
+ IconTheme.JabRefIcon.FILE.getSmallIcon()));
+ list.add(new ExternalFileType("Word", "doc", "application/msword", "oowriter", "openoffice",
+ IconTheme.JabRefIcon.FILE_WORD.getSmallIcon()));
+ list.add(new ExternalFileType("Word 2007+", "docx",
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "oowriter", "openoffice",
+ IconTheme.JabRefIcon.FILE_WORD.getSmallIcon()));
+ list.add(new ExternalFileType(Localization.lang("OpenDocument text"), "odt",
+ "application/vnd.oasis.opendocument.text", "oowriter", "openoffice", IconTheme.getImage("openoffice")));
+ list.add(new ExternalFileType("Excel", "xls", "application/excel", "oocalc", "openoffice",
+ IconTheme.JabRefIcon.FILE_EXCEL.getSmallIcon()));
+ list.add(new ExternalFileType("Excel 2007+", "xlsx",
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "oocalc", "openoffice",
+ IconTheme.JabRefIcon.FILE_EXCEL.getSmallIcon()));
+ list.add(new ExternalFileType(Localization.lang("OpenDocument spreadsheet"), "ods",
+ "application/vnd.oasis.opendocument.spreadsheet", "oocalc", "openoffice",
+ IconTheme.getImage("openoffice")));
+ list.add(new ExternalFileType("PowerPoint", "ppt", "application/vnd.ms-powerpoint", "ooimpress", "openoffice",
+ IconTheme.JabRefIcon.FILE_POWERPOINT.getSmallIcon()));
+ list.add(new ExternalFileType("PowerPoint 2007+", "pptx",
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation", "ooimpress", "openoffice",
+ IconTheme.JabRefIcon.FILE_POWERPOINT.getSmallIcon()));
+ list.add(new ExternalFileType(Localization.lang("OpenDocument presentation"), "odp",
+ "application/vnd.oasis.opendocument.presentation", "ooimpress", "openoffice",
+ IconTheme.getImage("openoffice")));
+ list.add(new ExternalFileType("Rich Text Format", "rtf", "application/rtf", "oowriter", "openoffice",
+ IconTheme.JabRefIcon.FILE_TEXT.getSmallIcon()));
+ list.add(new ExternalFileType(Localization.lang("%0 image", "PNG"), "png", "image/png", "gimp", "picture",
+ IconTheme.JabRefIcon.PICTURE.getSmallIcon()));
+ list.add(new ExternalFileType(Localization.lang("%0 image", "GIF"), "gif", "image/gif", "gimp", "picture",
+ IconTheme.JabRefIcon.PICTURE.getSmallIcon()));
+ list.add(new ExternalFileType(Localization.lang("%0 image", "JPG"), "jpg", "image/jpeg", "gimp", "picture",
+ IconTheme.JabRefIcon.PICTURE.getSmallIcon()));
+ list.add(new ExternalFileType("Djvu", "djvu", "image/vnd.djvu", "evince", "psSmall",
+ IconTheme.JabRefIcon.FILE.getSmallIcon()));
+ list.add(new ExternalFileType("Text", "txt", "text/plain", "emacs", "emacs",
+ IconTheme.JabRefIcon.FILE_TEXT.getSmallIcon()));
+ list.add(new ExternalFileType("LaTeX", "tex", "application/x-latex", "emacs", "emacs",
+ IconTheme.JabRefIcon.FILE_TEXT.getSmallIcon()));
+ list.add(new ExternalFileType("CHM", "chm", "application/mshelp", "gnochm", "www",
+ IconTheme.JabRefIcon.WWW.getSmallIcon()));
+ list.add(new ExternalFileType(Localization.lang("%0 image", "TIFF"), "tiff", "image/tiff", "gimp", "picture",
+ IconTheme.JabRefIcon.PICTURE.getSmallIcon()));
+ list.add(new ExternalFileType("URL", "html", "text/html", "firefox", "www",
+ IconTheme.JabRefIcon.WWW.getSmallIcon()));
+ list.add(new ExternalFileType("MHT", "mht", "multipart/related", "firefox", "www",
+ IconTheme.JabRefIcon.WWW.getSmallIcon()));
+ list.add(new ExternalFileType("ePUB", "epub", "application/epub+zip", "firefox", "www",
+ IconTheme.JabRefIcon.WWW.getSmallIcon()));
+
+ // On all OSes there is a generic application available to handle file opening,
+ // so we don't need the default application settings anymore:
+ for (ExternalFileType type : list) {
+ type.setOpenWith("");
+ }
+
+ return list;
+ }
+
+ public Set<ExternalFileType> getExternalFileTypeSelection() {
+ return externalFileTypes;
+ }
+
+ /**
+ * Look up the external file type registered with this name, if any.
+ *
+ * @param name The file type name.
+ * @return The ExternalFileType registered, or null if none.
+ */
+ public Optional<ExternalFileType> getExternalFileTypeByName(String name) {
+ for (ExternalFileType type : externalFileTypes) {
+ if (type.getName().equals(name)) {
+ return Optional.of(type);
+ }
+ }
+ // Return an instance that signifies an unknown file type:
+ return Optional.of(new UnknownExternalFileType(name));
+ }
+
+ /**
+ * Look up the external file type registered for this extension, if any.
+ *
+ * @param extension The file extension.
+ * @return The ExternalFileType registered, or null if none.
+ */
+ public Optional<ExternalFileType> getExternalFileTypeByExt(String extension) {
+ for (ExternalFileType type : externalFileTypes) {
+ if (type.getExtension().equalsIgnoreCase(extension)) {
+ return Optional.of(type);
+ }
+ }
+ return Optional.empty();
+ }
+
+ /**
+ * Returns true if there is an external file type registered for this extension.
+ *
+ * @param extension The file extension.
+ * @return true if an ExternalFileType with the extension exists, false otherwise
+ */
+ public boolean isExternalFileTypeByExt(String extension) {
+ for (ExternalFileType type : externalFileTypes) {
+ if (type.getExtension().equalsIgnoreCase(extension)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Look up the external file type name registered for this extension, if any.
+ *
+ * @param extension The file extension.
+ * @return The name of the ExternalFileType registered, or null if none.
+ */
+ public String getExternalFileTypeNameByExt(String extension) {
+ for (ExternalFileType type : externalFileTypes) {
+ if (type.getExtension().equalsIgnoreCase(extension)) {
+ return type.getName();
+ }
+ }
+ return "";
+ }
+
+ /**
+ * Look up the external file type registered for this filename, if any.
+ *
+ * @param filename The name of the file whose type to look up.
+ * @return The ExternalFileType registered, or null if none.
+ */
+ public Optional<ExternalFileType> getExternalFileTypeForName(String filename) {
+ int longestFound = -1;
+ ExternalFileType foundType = null;
+ for (ExternalFileType type : externalFileTypes) {
+ if (!type.getExtension().isEmpty() && filename.toLowerCase().endsWith(type.getExtension().toLowerCase())
+ && (type.getExtension().length() > longestFound)) {
+ longestFound = type.getExtension().length();
+ foundType = type;
+ }
+ }
+ return Optional.ofNullable(foundType);
+ }
+
+ /**
+ * Look up the external file type registered for this MIME type, if any.
+ *
+ * @param mimeType The MIME type.
+ * @return The ExternalFileType registered, or null if none. For the mime type "text/html", a valid file type is
+ * guaranteed to be returned.
+ */
+ public Optional<ExternalFileType> getExternalFileTypeByMimeType(String mimeType) {
+ for (ExternalFileType type : externalFileTypes) {
+ if (type.getMimeType().equalsIgnoreCase(mimeType)) {
+ return Optional.of(type);
+ }
+ }
+ if ("text/html".equalsIgnoreCase(mimeType)) {
+ return Optional.of(HTML_FALLBACK_TYPE);
+ } else {
+ return Optional.empty();
+ }
+ }
+
+ /**
+ * Reset the List of external file types after user customization.
+ *
+ * @param types The new List of external file types. This is the complete list, not just new entries.
+ */
+ public void setExternalFileTypes(List<ExternalFileType> types) {
+
+ // First find a list of the default types:
+ List<ExternalFileType> defTypes = getDefaultExternalFileTypes();
+ // Make a list of types that are unchanged:
+ List<ExternalFileType> unchanged = new ArrayList<>();
+
+ externalFileTypes.clear();
+ for (ExternalFileType type : types) {
+ externalFileTypes.add(type);
+
+ // See if we can find a type with matching name in the default type list:
+ ExternalFileType found = null;
+ for (ExternalFileType defType : defTypes) {
+ if (defType.getName().equals(type.getName())) {
+ found = defType;
+ break;
+ }
+ }
+ if (found != null) {
+ // Found it! Check if it is an exact match, or if it has been customized:
+ if (found.equals(type)) {
+ unchanged.add(type);
+ } else {
+ // It was modified. Remove its entry from the defaults list, since
+ // the type hasn't been removed:
+ defTypes.remove(found);
+ }
+ }
+ }
+
+ // Go through unchanged types. Remove them from the ones that should be stored,
+ // and from the list of defaults, since we don't need to mention these in prefs:
+ for (ExternalFileType type : unchanged) {
+ defTypes.remove(type);
+ types.remove(type);
+ }
+
+ // Now set up the array to write to prefs, containing all new types, all modified
+ // types, and a flag denoting each default type that has been removed:
+ String[][] array = new String[types.size() + defTypes.size()][];
+ int i = 0;
+ for (ExternalFileType type : types) {
+ array[i] = type.getStringArrayRepresentation();
+ i++;
+ }
+ for (ExternalFileType type : defTypes) {
+ array[i] = new String[] {type.getName(), FILE_TYPE_REMOVED_FLAG};
+ i++;
+ }
+ Globals.prefs.put(JabRefPreferences.EXTERNAL_FILE_TYPES, FileField.encodeStringArray(array));
+ }
+
+ /**
+ * Set up the list of external file types, either from default values, or from values recorded in Preferences.
+ */
+ private void updateExternalFileTypes() {
+ // First get a list of the default file types as a starting point:
+ List<ExternalFileType> types = getDefaultExternalFileTypes();
+ // If no changes have been stored, simply use the defaults:
+ if (Globals.prefs.get(JabRefPreferences.EXTERNAL_FILE_TYPES, null) == null) {
+ externalFileTypes.clear();
+ externalFileTypes.addAll(types);
+ return;
+ }
+ // Read the prefs information for file types:
+ String[][] vals = StringUtil
+ .decodeStringDoubleArray(Globals.prefs.get(JabRefPreferences.EXTERNAL_FILE_TYPES, ""));
+ for (String[] val : vals) {
+ if ((val.length == 2) && val[1].equals(FILE_TYPE_REMOVED_FLAG)) {
+ // This entry indicates that a default entry type should be removed:
+ ExternalFileType toRemove = null;
+ for (ExternalFileType type : types) {
+ if (type.getName().equals(val[0])) {
+ toRemove = type;
+ break;
+ }
+ }
+ // If we found it, remove it from the type list:
+ if (toRemove != null) {
+ types.remove(toRemove);
+ }
+ } else {
+ // A new or modified entry type. Construct it from the string array:
+ ExternalFileType type = ExternalFileType.buildFromArgs(val);
+ // Check if there is a default type with the same name. If so, this is a
+ // modification of that type, so remove the default one:
+ ExternalFileType toRemove = null;
+ for (ExternalFileType defType : types) {
+ if (type.getName().equals(defType.getName())) {
+ toRemove = defType;
+ break;
+ }
+ }
+ // If we found it, remove it from the type list:
+ if (toRemove != null) {
+ types.remove(toRemove);
+ }
+
+ // Then add the new one:
+ types.add(type);
+ }
+ }
+
+ // Finally, build the list of types based on the modified defaults list:
+ externalFileTypes.addAll(types);
+ }
+}
diff --git a/src/main/java/net/sf/jabref/gui/externalfiletype/UnknownExternalFileType.java b/src/main/java/net/sf/jabref/gui/externalfiletype/UnknownExternalFileType.java
new file mode 100644
index 0000000..effe436
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/externalfiletype/UnknownExternalFileType.java
@@ -0,0 +1,16 @@
+package net.sf.jabref.gui.externalfiletype;
+
+import net.sf.jabref.gui.IconTheme;
+
+/**
+ * This subclass of ExternalFileType is used to mark types that are unknown.
+ * This can be the case when a database is loaded which contains links to files
+ * of a type that has not been defined on this JabRef instance.
+ */
+public class UnknownExternalFileType extends ExternalFileType {
+
+ public UnknownExternalFileType(String name) {
+ super(name, "", "", "", "unknown", IconTheme.JabRefIcon.FILE.getSmallIcon());
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/gui/fieldeditors/EntryLinkListEditor.java b/src/main/java/net/sf/jabref/gui/fieldeditors/EntryLinkListEditor.java
new file mode 100644
index 0000000..3b08232
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/fieldeditors/EntryLinkListEditor.java
@@ -0,0 +1,563 @@
+package net.sf.jabref.gui.fieldeditors;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.FontMetrics;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+import javax.swing.AbstractAction;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JMenuItem;
+import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
+import javax.swing.JScrollPane;
+import javax.swing.JTable;
+import javax.swing.KeyStroke;
+import javax.swing.SwingUtilities;
+import javax.swing.table.DefaultTableModel;
+import javax.swing.table.TableCellRenderer;
+
+import net.sf.jabref.Globals;
+import net.sf.jabref.gui.IconTheme;
+import net.sf.jabref.gui.JabRefFrame;
+import net.sf.jabref.gui.autocompleter.AutoCompleteListener;
+import net.sf.jabref.gui.entryeditor.EntryEditor;
+import net.sf.jabref.gui.keyboard.KeyBinding;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.logic.layout.Layout;
+import net.sf.jabref.logic.layout.LayoutHelper;
+import net.sf.jabref.model.database.BibDatabase;
+import net.sf.jabref.model.database.BibDatabaseContext;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.EntryLinkList;
+import net.sf.jabref.model.entry.ParsedEntryLink;
+
+import com.jgoodies.forms.builder.FormBuilder;
+import com.jgoodies.forms.layout.FormLayout;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class EntryLinkListEditor extends JTable implements FieldEditor {
+ private static final Log LOGGER = LogFactory.getLog(EntryLinkListEditor.class);
+
+ private final FieldNameLabel label;
+ private final JabRefFrame frame;
+ private final BibDatabaseContext databaseContext;
+ private final String fieldName;
+ private final EntryEditor entryEditor;
+ private final JPanel panel;
+ private final EntryLinkListTableModel tableModel;
+ private final JPopupMenu menu = new JPopupMenu();
+ private final boolean singleEntry;
+ private final JButton add = new JButton(IconTheme.JabRefIcon.ADD_NOBOX.getSmallIcon());
+ private final JButton remove = new JButton(IconTheme.JabRefIcon.REMOVE_NOBOX.getSmallIcon());
+
+ private static final String layoutFormat = "\\begin{author}\\format[Authors(2,1),LatexToUnicode]{\\author}\\end{author}\\begin{title}, \"\\format[LatexToUnicode]{\\title}\"\\end{title}\\begin{year}, \\year\\end{year}";
+
+ public EntryLinkListEditor(JabRefFrame frame, BibDatabaseContext databaseContext, String fieldName, String content,
+ EntryEditor entryEditor, boolean singleEntry) {
+ this.frame = frame;
+ this.databaseContext = databaseContext;
+ this.fieldName = fieldName;
+ this.entryEditor = entryEditor;
+ this.singleEntry = singleEntry;
+ label = new FieldNameLabel(fieldName);
+ tableModel = new EntryLinkListTableModel(EntryLinkList.parse(content, databaseContext.getDatabase()));
+ setText(content);
+ setModel(tableModel);
+ JScrollPane sPane = new JScrollPane(this);
+ setTableHeader(null);
+ addMouseListener(new TableClickListener());
+
+ add.setToolTipText(("New entry link (INSERT)"));
+ remove.setToolTipText(("Remove entry link (DELETE)"));
+ add.setMargin(new Insets(0, 0, 0, 0));
+ remove.setMargin(new Insets(0, 0, 0, 0));
+ add.addActionListener(e -> addEntry());
+ remove.addActionListener(e -> removeEntries());
+
+ FormLayout layout = new FormLayout(
+ "fill:pref:grow,1dlu,fill:pref:grow",
+ "fill:pref,fill:pref,1dlu,fill:pref"
+ );
+ FormBuilder builder = FormBuilder.create().layout(layout);
+
+ if (!singleEntry) {
+ JButton up = new JButton(IconTheme.JabRefIcon.UP.getSmallIcon());
+ JButton down = new JButton(IconTheme.JabRefIcon.DOWN.getSmallIcon());
+ up.setMargin(new Insets(0, 0, 0, 0));
+ down.setMargin(new Insets(0, 0, 0, 0));
+ up.addActionListener(e -> moveEntry(-1));
+ down.addActionListener(e -> moveEntry(1));
+ builder.add(up).xy(1, 1);
+ builder.add(down).xy(1, 2);
+ }
+ builder.add(add).xy(3, 1);
+ builder.add(remove).xy(3, 2);
+ JButton button = new JButton(Localization.lang("Jump to entry"));
+ button.addActionListener(e -> jumpToEntry());
+ builder.add(button).xyw(1, 4, 3);
+
+ panel = new JPanel();
+ panel.setLayout(new BorderLayout());
+ panel.add(sPane, BorderLayout.CENTER);
+ panel.add(builder.getPanel(), BorderLayout.EAST);
+
+ // Add an input/action pair for deleting entries:
+ getInputMap().put(KeyStroke.getKeyStroke("DELETE"), "delete");
+ getActionMap().put("delete", new AbstractAction() {
+
+ @Override
+ public void actionPerformed(ActionEvent actionEvent) {
+ int row = getSelectedRow();
+ removeEntries();
+ row = Math.min(row, getRowCount() - 1);
+ if (row >= 0) {
+ setRowSelectionInterval(row, row);
+ }
+ }
+ });
+
+ // Add an input/action pair for inserting an entry:
+ getInputMap().put(KeyStroke.getKeyStroke("INSERT"), "insert");
+ getActionMap().put("insert", new AbstractAction() {
+
+ @Override
+ public void actionPerformed(ActionEvent actionEvent) {
+ int row = getSelectedRow();
+ addEntry();
+ setRowSelectionInterval(row, row);
+ }
+ });
+
+ // Add input/action pair for moving an entry up:
+ getInputMap().put(Globals.getKeyPrefs().getKey(KeyBinding.FILE_LIST_EDITOR_MOVE_ENTRY_UP), "move up");
+ getActionMap().put("move up", new AbstractAction() {
+
+ @Override
+ public void actionPerformed(ActionEvent actionEvent) {
+ moveEntry(-1);
+ }
+ });
+
+ // Add input/action pair for moving an entry down:
+ getInputMap().put(Globals.getKeyPrefs().getKey(KeyBinding.FILE_LIST_EDITOR_MOVE_ENTRY_DOWN), "move down");
+ getActionMap().put("move down", new AbstractAction() {
+
+ @Override
+ public void actionPerformed(ActionEvent actionEvent) {
+ moveEntry(1);
+ }
+ });
+
+ JMenuItem openLink = new JMenuItem(Localization.lang("Jump to entry"));
+ menu.add(openLink);
+ openLink.addActionListener(e -> jumpToEntry());
+
+ // Set table row height
+ FontMetrics metrics = getFontMetrics(getFont());
+ setRowHeight(Math.max(getRowHeight(), metrics.getHeight()));
+
+ updateButtonStates();
+ }
+
+
+ private void jumpToEntry() {
+ String entryKey = null;
+
+ if (singleEntry) {
+ ParsedEntryLink firstEntry = tableModel.getEntry(0);
+
+ if (firstEntry != null) {
+ entryKey = firstEntry.getKey();
+ }
+ } else {
+ int selectedRow = getSelectedRow();
+
+ if (selectedRow != -1) {
+ entryKey = tableModel.getEntry(selectedRow).getKey();
+ }
+ }
+
+ if (entryKey != null) {
+ frame.getCurrentBasePanel().getDatabase().getEntryByKey(entryKey).ifPresent(
+ e -> frame.getCurrentBasePanel().highlightEntry(e)
+ );
+ }
+ }
+
+ public void adjustColumnWidth() {
+ for (int column = 0; column < this.getColumnCount(); column++) {
+ int width = 0;
+ for (int row = 0; row < this.getRowCount(); row++) {
+ TableCellRenderer renderer = this.getCellRenderer(row, column);
+ Component comp = this.prepareRenderer(renderer, row, column);
+ width = Math.max(comp.getPreferredSize().width, width);
+ }
+ this.columnModel.getColumn(column).setPreferredWidth(width);
+ }
+ }
+
+ @Override
+ public String getFieldName() {
+ return fieldName;
+ }
+
+ /*
+ * Returns the component to be added to a container. Might be a JScrollPane
+ * or the component itself.
+ */
+ @Override
+ public JComponent getPane() {
+ return panel;
+ }
+
+ /*
+ * Returns the text component itself.
+ */
+ @Override
+ public JComponent getTextComponent() {
+ return this;
+ }
+
+ @Override
+ public JLabel getLabel() {
+ return label;
+ }
+
+ @Override
+ public void setLabelColor(Color color) {
+ label.setForeground(color);
+ }
+
+ @Override
+ public String getText() {
+ return tableModel.getText();
+ }
+
+ @Override
+ public void setText(String newText) {
+ tableModel.setContent(EntryLinkList.parse(newText, databaseContext.getDatabase()));
+ adjustColumnWidth();
+ updateButtonStates();
+ }
+
+ @Override
+ public void append(String text) {
+ // Do nothing
+ }
+
+ @Override
+ public void updateFont() {
+ // Do nothing
+ }
+
+ @Override
+ public void paste(String textToInsert) {
+ // Do nothing
+ }
+
+ @Override
+ public String getSelectedText() {
+ return null;
+ }
+
+
+ private void addEntry() {
+ int row = getSelectedRow();
+ if (row == -1) {
+ row = 0;
+ }
+ ParsedEntryLink entry = new ParsedEntryLink("", databaseContext.getDatabase());
+ tableModel.addEntry(row, entry);
+ entryEditor.updateField(this);
+ adjustColumnWidth();
+ updateButtonStates();
+ }
+
+
+ private void removeEntries() {
+ int[] rows = getSelectedRows();
+ if (rows != null) {
+ for (int i = rows.length - 1; i >= 0; i--) {
+ tableModel.removeEntry(rows[i]);
+ }
+ }
+ entryEditor.updateField(this);
+ adjustColumnWidth();
+ updateButtonStates();
+ }
+
+ private void updateButtonStates() {
+ if (singleEntry) {
+ if (tableModel.isEmpty()) {
+ add.setEnabled(true);
+ remove.setEnabled(false);
+ } else {
+ add.setEnabled(false);
+ remove.setEnabled(true);
+ }
+ }
+ }
+ private void moveEntry(int i) {
+ int[] sel = getSelectedRows();
+ if ((sel.length != 1) || (tableModel.getRowCount() < 2)) {
+ return;
+ }
+ int toIdx = sel[0] + i;
+ if (toIdx >= tableModel.getRowCount()) {
+ toIdx -= tableModel.getRowCount();
+ }
+ if (toIdx < 0) {
+ toIdx += tableModel.getRowCount();
+ }
+ ParsedEntryLink entry = tableModel.getEntry(sel[0]);
+ tableModel.removeEntry(sel[0]);
+ tableModel.addEntry(toIdx, entry);
+ entryEditor.updateField(this);
+ setRowSelectionInterval(toIdx, toIdx);
+ adjustColumnWidth();
+ }
+
+
+ class TableClickListener extends MouseAdapter {
+
+ @Override
+ public void mouseClicked(MouseEvent e) {
+ if ((e.getButton() == MouseEvent.BUTTON1) && (e.getClickCount() == 2)) {
+ int row = rowAtPoint(e.getPoint());
+ if (row >= 0) {
+ Optional<BibEntry> entry = tableModel.getEntry(row).getLinkedEntry();
+ if (entry.isPresent()) {
+ // Select entry in main table
+ frame.getCurrentBasePanel().highlightEntry(entry.get());
+ } else {
+ // Focus BibTeX key field
+ }
+ }
+ } else if (e.isPopupTrigger()) {
+ processPopupTrigger(e);
+ }
+ }
+
+ @Override
+ public void mousePressed(MouseEvent e) {
+ if (e.isPopupTrigger()) {
+ processPopupTrigger(e);
+ }
+ }
+
+ @Override
+ public void mouseReleased(MouseEvent e) {
+ if (e.isPopupTrigger()) {
+ processPopupTrigger(e);
+ }
+ }
+
+ private void processPopupTrigger(MouseEvent e) {
+ int row = rowAtPoint(e.getPoint());
+ if (row >= 0) {
+ setRowSelectionInterval(row, row);
+ menu.show(EntryLinkListEditor.this, e.getX(), e.getY());
+ }
+ }
+ }
+
+ @Override
+ public void undo() {
+ // Do nothing
+ }
+
+ @Override
+ public void redo() {
+ // Do nothing
+ }
+
+ @Override
+ public void setAutoCompleteListener(AutoCompleteListener listener) {
+ // Do nothing
+ }
+
+ @Override
+ public void clearAutoCompleteSuggestion() {
+ // Do nothing
+ }
+
+ @Override
+ public void setActiveBackgroundColor() {
+ // Do nothing
+ }
+
+ @Override
+ public void setValidBackgroundColor() {
+ // Do nothing
+ }
+
+ @Override
+ public void setInvalidBackgroundColor() {
+ // Do nothing
+ }
+
+ @Override
+ public void updateFontColor() {
+ // Do nothing
+ }
+
+
+ private class EntryLinkListTableModel extends DefaultTableModel {
+
+ private final List<ParsedEntryLink> internalList = Collections.synchronizedList(new ArrayList<>());
+
+
+ public EntryLinkListTableModel(List<ParsedEntryLink> originalList) {
+ addEntries(originalList);
+ }
+
+ public String getText() {
+ synchronized (internalList) {
+ String result = EntryLinkList.serialize(internalList);
+ return result;
+ }
+ }
+
+ public void addEntries(List<ParsedEntryLink> newList) {
+ internalList.addAll(newList);
+ if (SwingUtilities.isEventDispatchThread()) {
+ fireTableDataChanged();
+ } else {
+ SwingUtilities.invokeLater(() -> fireTableDataChanged());
+ }
+
+ }
+
+ public void setContent(List<ParsedEntryLink> newList) {
+
+ internalList.clear();
+ internalList.addAll(newList);
+ if (SwingUtilities.isEventDispatchThread()) {
+ fireTableDataChanged();
+ } else {
+ SwingUtilities.invokeLater(() -> fireTableDataChanged());
+ }
+ }
+
+ @Override
+ public int getColumnCount() {
+ return 2;
+ }
+
+ @Override
+ public int getRowCount() {
+ if (internalList == null) {
+ return 0;
+ }
+ synchronized (internalList) {
+ return internalList.size();
+ }
+ }
+
+ @Override
+ public Class<String> getColumnClass(int columnIndex) {
+ return String.class;
+ }
+
+ @Override
+ public Object getValueAt(int rowIndex, int columnIndex) {
+ synchronized (internalList) {
+ ParsedEntryLink entry = internalList.get(rowIndex);
+ switch (columnIndex) {
+ case 0:
+ return entry.getKey();
+ case 1:
+ return entry.getLinkedEntry()
+ .map(bibEntry -> formatEntry(bibEntry, entry.getDataBase()))
+ .orElse("Unknown entry");
+ default:
+ return null;
+ }
+ }
+ }
+
+ public ParsedEntryLink getEntry(int index) {
+ synchronized (internalList) {
+ return internalList.get(index);
+ }
+ }
+
+ public void removeEntry(int index) {
+ internalList.remove(index);
+ if (SwingUtilities.isEventDispatchThread()) {
+ fireTableRowsDeleted(index, index);
+ } else {
+ SwingUtilities.invokeLater(() -> fireTableRowsDeleted(index, index));
+ }
+ }
+
+ public boolean isEmpty() {
+ return internalList.isEmpty();
+ }
+
+ /**
+ * Add an entry to the table model, and fire a change event. The change event
+ * is fired on the event dispatch thread.
+ * @param index The row index to insert the entry at.
+ * @param entry The entry to insert.
+ */
+ public void addEntry(final int index, final ParsedEntryLink entry) {
+ synchronized (internalList) {
+ internalList.add(index, entry);
+ if (SwingUtilities.isEventDispatchThread()) {
+ fireTableDataChanged();
+ } else {
+ SwingUtilities.invokeLater(() -> fireTableDataChanged());
+ }
+ }
+ }
+
+ @Override
+ public boolean isCellEditable(int row, int column) {
+ return (column == 0);
+ }
+
+ @Override
+ public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
+ synchronized (internalList) {
+ if (columnIndex == 0) {
+ internalList.get(rowIndex).setKey((String) aValue);
+ if (SwingUtilities.isEventDispatchThread()) {
+ fireTableRowsUpdated(rowIndex, rowIndex);
+ } else {
+ SwingUtilities.invokeLater(() -> fireTableRowsUpdated(rowIndex, rowIndex));
+ }
+
+ }
+ }
+ }
+ }
+
+ private static String formatEntry(BibEntry entry, BibDatabase database) {
+ StringReader sr = new StringReader(layoutFormat);
+ try {
+ Layout layout = new LayoutHelper(sr,
+ Globals.prefs.getLayoutFormatterPreferences(Globals.journalAbbreviationLoader))
+ .getLayoutFromText();
+ return layout.doLayout(entry, database);
+ } catch (IOException e) {
+ LOGGER.warn("Problem generating entry layout", e);
+ }
+ return "";
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/gui/fieldeditors/FieldEditorFocusListener.java b/src/main/java/net/sf/jabref/gui/fieldeditors/FieldEditorFocusListener.java
index c063a33..b1bdae2 100644
--- a/src/main/java/net/sf/jabref/gui/fieldeditors/FieldEditorFocusListener.java
+++ b/src/main/java/net/sf/jabref/gui/fieldeditors/FieldEditorFocusListener.java
@@ -22,9 +22,7 @@ public class FieldEditorFocusListener implements FocusListener {
@Override
public void focusLost(FocusEvent event) {
- if (event.getSource() instanceof FieldEditor) {
- ((FieldEditor) event.getSource()).setValidBackgroundColor();
- } else {
+ if (!(event.getSource() instanceof FieldEditor)) {
((JComponent) event.getSource()).setBackground(GUIGlobals.validFieldBackgroundColor);
}
}
diff --git a/src/main/java/net/sf/jabref/gui/fieldeditors/FileListEditor.java b/src/main/java/net/sf/jabref/gui/fieldeditors/FileListEditor.java
index 172cb0d..74153dc 100644
--- a/src/main/java/net/sf/jabref/gui/fieldeditors/FileListEditor.java
+++ b/src/main/java/net/sf/jabref/gui/fieldeditors/FileListEditor.java
@@ -32,27 +32,26 @@ import javax.swing.KeyStroke;
import javax.swing.TransferHandler;
import javax.swing.table.TableCellRenderer;
-import net.sf.jabref.BibDatabaseContext;
import net.sf.jabref.Globals;
import net.sf.jabref.JabRefExecutorService;
-import net.sf.jabref.external.AutoSetLinks;
-import net.sf.jabref.external.DownloadExternalFile;
-import net.sf.jabref.external.ExternalFileType;
-import net.sf.jabref.external.ExternalFileTypes;
-import net.sf.jabref.external.MoveFileAction;
-import net.sf.jabref.gui.FileListEntry;
-import net.sf.jabref.gui.FileListEntryEditor;
-import net.sf.jabref.gui.FileListTableModel;
import net.sf.jabref.gui.IconTheme;
import net.sf.jabref.gui.JabRefFrame;
import net.sf.jabref.gui.actions.Actions;
import net.sf.jabref.gui.autocompleter.AutoCompleteListener;
import net.sf.jabref.gui.desktop.JabRefDesktop;
import net.sf.jabref.gui.entryeditor.EntryEditor;
+import net.sf.jabref.gui.externalfiles.AutoSetLinks;
+import net.sf.jabref.gui.externalfiles.DownloadExternalFile;
+import net.sf.jabref.gui.externalfiles.MoveFileAction;
+import net.sf.jabref.gui.externalfiletype.ExternalFileType;
+import net.sf.jabref.gui.externalfiletype.ExternalFileTypes;
+import net.sf.jabref.gui.filelist.FileListEntry;
+import net.sf.jabref.gui.filelist.FileListEntryEditor;
+import net.sf.jabref.gui.filelist.FileListTableModel;
import net.sf.jabref.gui.keyboard.KeyBinding;
-import net.sf.jabref.gui.util.GUIUtil;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.util.io.FileUtil;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.entry.BibEntry;
import com.jgoodies.forms.builder.FormBuilder;
@@ -88,8 +87,6 @@ public class FileListEditor extends JTable implements FieldEditor, DownloadExter
setTableHeader(null);
addMouseListener(new TableClickListener());
- GUIUtil.correctRowHeight(this);
-
JButton add = new JButton(IconTheme.JabRefIcon.ADD_NOBOX.getSmallIcon());
add.setToolTipText(Localization.lang("New file link (INSERT)"));
JButton remove = new JButton(IconTheme.JabRefIcon.REMOVE_NOBOX.getSmallIcon());
@@ -190,7 +187,8 @@ public class FileListEditor extends JTable implements FieldEditor, DownloadExter
path = Paths.get(entry.link).toString();
} else {
// relative to file folder
- for (String folder : databaseContext.getFileDirectory()) {
+ for (String folder : databaseContext
+ .getFileDirectories(Globals.prefs.getFileDirectoryPreferences())) {
Path file = Paths.get(folder, entry.link);
if (Files.exists(file)) {
path = file.toString();
@@ -229,7 +227,8 @@ public class FileListEditor extends JTable implements FieldEditor, DownloadExter
FileListEntry entry = tableModel.getEntry(row);
// null if file does not exist
- Optional<File> file = FileUtil.expandFilename(databaseContext, entry.link);
+ Optional<File> file = FileUtil.expandFilename(databaseContext, entry.link,
+ Globals.prefs.getFileDirectoryPreferences());
// transactional delete and unlink
try {
@@ -353,7 +352,7 @@ public class FileListEditor extends JTable implements FieldEditor, DownloadExter
}
private void addEntry() {
- List<String> defaultDirectory = databaseContext.getFileDirectory();
+ List<String> defaultDirectory = databaseContext.getFileDirectories(Globals.prefs.getFileDirectoryPreferences());
if (defaultDirectory.isEmpty() || (defaultDirectory.get(0) == null)) {
addEntry("");
} else {
@@ -458,7 +457,7 @@ public class FileListEditor extends JTable implements FieldEditor, DownloadExter
}
}
DownloadExternalFile def = new DownloadExternalFile(frame,
- frame.getCurrentBasePanel().getBibDatabaseContext(), bibtexKey.orElse(null));
+ frame.getCurrentBasePanel().getBibDatabaseContext(), entryEditor.getEntry());
try {
def.download(this);
} catch (IOException ex) {
diff --git a/src/main/java/net/sf/jabref/gui/fieldeditors/FileListEditorTransferHandler.java b/src/main/java/net/sf/jabref/gui/fieldeditors/FileListEditorTransferHandler.java
index feb8be0..28e76cd 100644
--- a/src/main/java/net/sf/jabref/gui/fieldeditors/FileListEditorTransferHandler.java
+++ b/src/main/java/net/sf/jabref/gui/fieldeditors/FileListEditorTransferHandler.java
@@ -15,10 +15,10 @@ import javax.swing.JComponent;
import javax.swing.SwingUtilities;
import javax.swing.TransferHandler;
-import net.sf.jabref.external.DroppedFileHandler;
-import net.sf.jabref.external.ExternalFileTypes;
import net.sf.jabref.gui.EntryContainer;
import net.sf.jabref.gui.JabRefFrame;
+import net.sf.jabref.gui.externalfiles.DroppedFileHandler;
+import net.sf.jabref.gui.externalfiletype.ExternalFileTypes;
import net.sf.jabref.gui.groups.EntryTableTransferHandler;
import net.sf.jabref.logic.util.io.FileUtil;
@@ -26,6 +26,7 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
class FileListEditorTransferHandler extends TransferHandler {
+
private DataFlavor urlFlavor;
private final DataFlavor stringFlavor;
private final JabRefFrame frame;
@@ -42,7 +43,8 @@ class FileListEditorTransferHandler extends TransferHandler {
* @param entryContainer
* @param textTransferHandler is an instance of javax.swing.plaf.basic.BasicTextUI.TextTransferHandler. That class is not visible. Therefore, we have to "cheat"
*/
- public FileListEditorTransferHandler(JabRefFrame frame, EntryContainer entryContainer, TransferHandler textTransferHandler) {
+ public FileListEditorTransferHandler(JabRefFrame frame, EntryContainer entryContainer,
+ TransferHandler textTransferHandler) {
this.frame = frame;
this.entryContainer = entryContainer;
this.textTransferHandler = textTransferHandler;
@@ -80,7 +82,9 @@ class FileListEditorTransferHandler extends TransferHandler {
List<File> files = new ArrayList<>();
// This flavor is used for dragged file links in Windows:
if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
- files.addAll((List<File>) t.getTransferData(DataFlavor.javaFileListFlavor));
+ @SuppressWarnings("unchecked")
+ List<File> transferedFiles = (List<File>) t.getTransferData(DataFlavor.javaFileListFlavor);
+ files.addAll(transferedFiles);
}
if (t.isDataFlavorSupported(urlFlavor)) {
@@ -139,8 +143,7 @@ class FileListEditorTransferHandler extends TransferHandler {
// accept this if any input flavor matches any of our supported flavors
for (DataFlavor inflav : transferFlavors) {
- if (inflav.match(urlFlavor) || inflav.match(stringFlavor)
- || inflav.match(DataFlavor.javaFileListFlavor)) {
+ if (inflav.match(urlFlavor) || inflav.match(stringFlavor) || inflav.match(DataFlavor.javaFileListFlavor)) {
return true;
}
}
diff --git a/src/main/java/net/sf/jabref/gui/fieldeditors/JTextAreaWithHighlighting.java b/src/main/java/net/sf/jabref/gui/fieldeditors/JTextAreaWithHighlighting.java
index 94ef4d0..0f91af8 100644
--- a/src/main/java/net/sf/jabref/gui/fieldeditors/JTextAreaWithHighlighting.java
+++ b/src/main/java/net/sf/jabref/gui/fieldeditors/JTextAreaWithHighlighting.java
@@ -6,7 +6,6 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.AbstractAction;
-import javax.swing.JTextArea;
import javax.swing.KeyStroke;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultHighlighter;
@@ -20,13 +19,14 @@ import javax.swing.undo.UndoManager;
import net.sf.jabref.Globals;
import net.sf.jabref.gui.actions.Actions;
import net.sf.jabref.gui.actions.PasteAction;
+import net.sf.jabref.gui.util.component.JTextAreaWithPlaceholder;
import net.sf.jabref.logic.search.SearchQueryHighlightListener;
import net.sf.jabref.preferences.JabRefPreferences;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-public class JTextAreaWithHighlighting extends JTextArea implements SearchQueryHighlightListener {
+public class JTextAreaWithHighlighting extends JTextAreaWithPlaceholder implements SearchQueryHighlightListener {
private static final Log LOGGER = LogFactory.getLog(JTextAreaWithHighlighting.class);
@@ -35,13 +35,22 @@ public class JTextAreaWithHighlighting extends JTextArea implements SearchQueryH
private UndoManager undo;
public JTextAreaWithHighlighting() {
- super();
- setupUndoRedo();
- setupPasteListener();
+ this("");
+ }
+
+ public JTextAreaWithHighlighting(String text) {
+ this(text, "");
}
- JTextAreaWithHighlighting(String text) {
- super(text);
+ /**
+ * Creates a text area with the ability to highlight parts of the content.
+ * It also defines a placeholder which will be displayed the content is empty.
+ *
+ * @param text
+ * @param placeholder
+ */
+ public JTextAreaWithHighlighting(String text, String placeholder) {
+ super(text, placeholder);
setupUndoRedo();
setupPasteListener();
}
diff --git a/src/main/java/net/sf/jabref/gui/fieldeditors/TextArea.java b/src/main/java/net/sf/jabref/gui/fieldeditors/TextArea.java
index fc38e39..bc7b093 100644
--- a/src/main/java/net/sf/jabref/gui/fieldeditors/TextArea.java
+++ b/src/main/java/net/sf/jabref/gui/fieldeditors/TextArea.java
@@ -36,7 +36,11 @@ public class TextArea extends JTextAreaWithHighlighting implements FieldEditor {
public TextArea(String fieldName, String content) {
- super(content);
+ this(fieldName, content, "");
+ }
+
+ public TextArea(String fieldName, String content, String title) {
+ super(content, title);
updateFont();
diff --git a/src/main/java/net/sf/jabref/gui/fieldeditors/TextField.java b/src/main/java/net/sf/jabref/gui/fieldeditors/TextField.java
index dd45590..8b9a93e 100644
--- a/src/main/java/net/sf/jabref/gui/fieldeditors/TextField.java
+++ b/src/main/java/net/sf/jabref/gui/fieldeditors/TextField.java
@@ -7,7 +7,6 @@ import java.lang.reflect.InvocationTargetException;
import javax.swing.AbstractAction;
import javax.swing.JComponent;
import javax.swing.JLabel;
-import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.text.Document;
import javax.swing.undo.CannotRedoException;
@@ -20,6 +19,7 @@ import net.sf.jabref.gui.actions.Actions;
import net.sf.jabref.gui.actions.PasteAction;
import net.sf.jabref.gui.autocompleter.AutoCompleteListener;
import net.sf.jabref.gui.fieldeditors.contextmenu.FieldTextMenu;
+import net.sf.jabref.gui.util.component.JTextFieldWithPlaceholder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -28,7 +28,7 @@ import org.apache.commons.logging.LogFactory;
* An implementation of the FieldEditor backed by a JTextField. Used for single-line input, only BibTex key at the
* moment?!
*/
-public class TextField extends JTextField implements FieldEditor {
+public class TextField extends JTextFieldWithPlaceholder implements FieldEditor {
private static final Log LOGGER = LogFactory.getLog(TextField.class);
@@ -39,7 +39,11 @@ public class TextField extends JTextField implements FieldEditor {
public TextField(String fieldName, String content, boolean changeColorOnFocus) {
- super(content);
+ this(fieldName, content, changeColorOnFocus, "");
+ }
+
+ public TextField(String fieldName, String content, boolean changeColorOnFocus, String title) {
+ super(content, title);
setupPasteListener();
setupUndoRedo();
diff --git a/src/main/java/net/sf/jabref/gui/fieldeditors/contextmenu/CaseChangeMenu.java b/src/main/java/net/sf/jabref/gui/fieldeditors/contextmenu/CaseChangeMenu.java
index d1c0847..067ecc0 100644
--- a/src/main/java/net/sf/jabref/gui/fieldeditors/contextmenu/CaseChangeMenu.java
+++ b/src/main/java/net/sf/jabref/gui/fieldeditors/contextmenu/CaseChangeMenu.java
@@ -6,9 +6,9 @@ import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.text.JTextComponent;
-import net.sf.jabref.logic.formatter.Formatter;
import net.sf.jabref.logic.formatter.Formatters;
import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.cleanup.Formatter;
public class CaseChangeMenu extends JMenu {
diff --git a/src/main/java/net/sf/jabref/gui/fieldeditors/contextmenu/ConversionMenu.java b/src/main/java/net/sf/jabref/gui/fieldeditors/contextmenu/ConversionMenu.java
index 16fddc3..b2c98b0 100644
--- a/src/main/java/net/sf/jabref/gui/fieldeditors/contextmenu/ConversionMenu.java
+++ b/src/main/java/net/sf/jabref/gui/fieldeditors/contextmenu/ConversionMenu.java
@@ -4,9 +4,9 @@ import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.text.JTextComponent;
-import net.sf.jabref.logic.formatter.Formatter;
import net.sf.jabref.logic.formatter.Formatters;
import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.cleanup.Formatter;
/**
* @author Oscar Gustafsson
diff --git a/src/main/java/net/sf/jabref/gui/fieldeditors/contextmenu/FieldTextMenu.java b/src/main/java/net/sf/jabref/gui/fieldeditors/contextmenu/FieldTextMenu.java
index 4e4c4f2..f7c713e 100644
--- a/src/main/java/net/sf/jabref/gui/fieldeditors/contextmenu/FieldTextMenu.java
+++ b/src/main/java/net/sf/jabref/gui/fieldeditors/contextmenu/FieldTextMenu.java
@@ -6,22 +6,26 @@ import java.awt.event.MouseListener;
import javax.swing.AbstractAction;
import javax.swing.Action;
+import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.text.JTextComponent;
import net.sf.jabref.gui.ClipBoardManager;
import net.sf.jabref.gui.actions.CopyAction;
+import net.sf.jabref.gui.actions.CopyDoiUrlAction;
import net.sf.jabref.gui.actions.PasteAction;
import net.sf.jabref.gui.fieldeditors.FieldEditor;
import net.sf.jabref.logic.formatter.bibtexfields.NormalizeNamesFormatter;
import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.logic.util.strings.StringUtil;
+import net.sf.jabref.model.entry.FieldName;
+import net.sf.jabref.model.strings.StringUtil;
public class FieldTextMenu implements MouseListener {
private final FieldEditor field;
private final JPopupMenu inputMenu = new JPopupMenu();
private final CopyAction copyAction;
private final PasteAction pasteAction;
+ private final JMenuItem doiMenuItem;
private ProtectedTermsMenu protectedTermsMenu;
@@ -32,6 +36,8 @@ public class FieldTextMenu implements MouseListener {
field = fieldComponent;
copyAction = new CopyAction((JTextComponent) field);
pasteAction = new PasteAction((JTextComponent) field);
+ CopyDoiUrlAction copyDoiAction = new CopyDoiUrlAction((JTextComponent) field);
+ doiMenuItem = new JMenuItem(copyDoiAction);
initMenu();
}
@@ -87,6 +93,12 @@ public class FieldTextMenu implements MouseListener {
if (protectedTermsMenu != null) {
protectedTermsMenu.updateFiles();
}
+
+ boolean isDOIField = field.getFieldName().equals(FieldName.DOI);
+ doiMenuItem.setVisible(isDOIField);
+ boolean isDoiFieldEmpty = field.getText().isEmpty();
+ doiMenuItem.setEnabled(!isDoiFieldEmpty);
+
inputMenu.show(e.getComponent(), e.getX(), e.getY());
}
}
@@ -94,6 +106,9 @@ public class FieldTextMenu implements MouseListener {
private void initMenu() {
inputMenu.add(pasteAction);
inputMenu.add(copyAction);
+ if (field.getTextComponent() instanceof JTextComponent) {
+ inputMenu.add(doiMenuItem);
+ }
inputMenu.addSeparator();
inputMenu.add(new ReplaceAction());
diff --git a/src/main/java/net/sf/jabref/gui/fieldeditors/contextmenu/ProtectedTermsMenu.java b/src/main/java/net/sf/jabref/gui/fieldeditors/contextmenu/ProtectedTermsMenu.java
index 4798476..2b8bb8e 100644
--- a/src/main/java/net/sf/jabref/gui/fieldeditors/contextmenu/ProtectedTermsMenu.java
+++ b/src/main/java/net/sf/jabref/gui/fieldeditors/contextmenu/ProtectedTermsMenu.java
@@ -10,11 +10,10 @@ import net.sf.jabref.gui.protectedterms.NewProtectedTermsFileDialog;
import net.sf.jabref.logic.formatter.casechanger.ProtectTermsFormatter;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.protectedterms.ProtectedTermsList;
-import net.sf.jabref.logic.protectedterms.ProtectedTermsPreferences;
public class ProtectedTermsMenu extends JMenu {
- private static final ProtectTermsFormatter formatter = new ProtectTermsFormatter();
+ private static final ProtectTermsFormatter formatter = new ProtectTermsFormatter(Globals.protectedTermsLoader);
private final JMenu externalFiles;
private final JTextComponent opener;
@@ -64,7 +63,7 @@ public class ProtectedTermsMenu extends JMenu {
dialog.setVisible(true);
if (dialog.isOKPressed()) {
// Update preferences with new list
- ProtectedTermsPreferences.toPreferences(Globals.prefs, Globals.protectedTermsLoader);
+ Globals.prefs.setProtectedTermsPreferences(Globals.protectedTermsLoader);
}
});
externalFiles.add(addToNewFileItem);
diff --git a/src/main/java/net/sf/jabref/gui/filelist/AttachFileAction.java b/src/main/java/net/sf/jabref/gui/filelist/AttachFileAction.java
new file mode 100644
index 0000000..89a46b8
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/filelist/AttachFileAction.java
@@ -0,0 +1,51 @@
+package net.sf.jabref.gui.filelist;
+
+import net.sf.jabref.gui.BasePanel;
+import net.sf.jabref.gui.actions.BaseAction;
+import net.sf.jabref.gui.undo.UndoableFieldChange;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldName;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: alver
+ * Date: 5/24/12
+ * Time: 8:48 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public class AttachFileAction implements BaseAction {
+
+ private final BasePanel panel;
+
+
+ public AttachFileAction(BasePanel panel) {
+ this.panel = panel;
+ }
+
+ @Override
+ public void action() {
+ if (panel.getSelectedEntries().size() != 1) {
+ panel.output(Localization.lang("This operation requires exactly one item to be selected."));
+ return;
+ }
+ BibEntry entry = panel.getSelectedEntries().get(0);
+ FileListEntry flEntry = new FileListEntry("", "");
+ FileListEntryEditor editor = new FileListEntryEditor(panel.frame(), flEntry, false, true,
+ panel.getBibDatabaseContext());
+ editor.setVisible(true, true);
+ if (editor.okPressed()) {
+ FileListTableModel model = new FileListTableModel();
+ entry.getField(FieldName.FILE).ifPresent(model::setContent);
+ model.addEntry(model.getRowCount(), flEntry);
+ String newVal = model.getStringRepresentation();
+
+ UndoableFieldChange ce = new UndoableFieldChange(entry, FieldName.FILE,
+ entry.getField(FieldName.FILE).orElse(null), newVal);
+ entry.setField(FieldName.FILE, newVal);
+ panel.getUndoManager().addEdit(ce);
+ panel.markBaseChanged();
+ }
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/gui/filelist/ConfirmCloseFileListEntryEditor.java b/src/main/java/net/sf/jabref/gui/filelist/ConfirmCloseFileListEntryEditor.java
new file mode 100644
index 0000000..27bedaf
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/filelist/ConfirmCloseFileListEntryEditor.java
@@ -0,0 +1,12 @@
+package net.sf.jabref.gui.filelist;
+
+/**
+ * An implementation of this interface is called to confirm whether a FileListEntryEditor
+ * is ready to close when Ok is pressed, or whether there is a problem that needs to be
+ * resolved first.
+ */
+ at FunctionalInterface
+public interface ConfirmCloseFileListEntryEditor {
+
+ boolean confirmClose(FileListEntry entry);
+}
diff --git a/src/main/java/net/sf/jabref/gui/filelist/FileListEntry.java b/src/main/java/net/sf/jabref/gui/filelist/FileListEntry.java
new file mode 100644
index 0000000..4fb7f88
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/filelist/FileListEntry.java
@@ -0,0 +1,45 @@
+package net.sf.jabref.gui.filelist;
+
+import java.util.Objects;
+import java.util.Optional;
+
+import net.sf.jabref.gui.externalfiletype.ExternalFileType;
+
+/**
+ * This class represents a file link for a Bibtex entry.
+ */
+public class FileListEntry {
+
+ public String description;
+ public String link;
+ public Optional<ExternalFileType> type;
+
+ public FileListEntry(String description, String link) {
+ this(description, link, Optional.empty());
+ }
+
+ public FileListEntry(String description, String link, ExternalFileType type) {
+ this.description = Objects.requireNonNull(description);
+ this.link = Objects.requireNonNull(link);
+ this.type = Optional.of(Objects.requireNonNull(type));
+ }
+
+ public FileListEntry(String description, String link, Optional<ExternalFileType> type) {
+ this.description = Objects.requireNonNull(description);
+ this.link = Objects.requireNonNull(link);
+ this.type = Objects.requireNonNull(type);
+ }
+
+ public String[] getStringArrayRepresentation() {
+ return new String[] {description, link, getTypeName()};
+ }
+
+ private String getTypeName() {
+ return this.type.isPresent() ? this.type.get().getName() : "";
+ }
+
+ @Override
+ public String toString() {
+ return description + " : " + link + " : " + type.orElse(null);
+ }
+}
diff --git a/src/main/java/net/sf/jabref/gui/filelist/FileListEntryEditor.java b/src/main/java/net/sf/jabref/gui/filelist/FileListEntryEditor.java
new file mode 100644
index 0000000..5878d53
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/filelist/FileListEntryEditor.java
@@ -0,0 +1,364 @@
+package net.sf.jabref.gui.filelist;
+
+import java.awt.BorderLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Collection;
+import java.util.List;
+import java.util.Optional;
+import java.util.regex.Pattern;
+
+import javax.swing.AbstractAction;
+import javax.swing.ActionMap;
+import javax.swing.BorderFactory;
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.InputMap;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JProgressBar;
+import javax.swing.JTextField;
+import javax.swing.SwingConstants;
+import javax.swing.SwingUtilities;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+
+import net.sf.jabref.Globals;
+import net.sf.jabref.gui.FileDialog;
+import net.sf.jabref.gui.JabRefFrame;
+import net.sf.jabref.gui.desktop.JabRefDesktop;
+import net.sf.jabref.gui.externalfiletype.ExternalFileType;
+import net.sf.jabref.gui.externalfiletype.ExternalFileTypes;
+import net.sf.jabref.gui.externalfiletype.UnknownExternalFileType;
+import net.sf.jabref.gui.keyboard.KeyBinding;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.logic.util.io.FileUtil;
+import net.sf.jabref.model.database.BibDatabaseContext;
+import net.sf.jabref.preferences.JabRefPreferences;
+
+import com.jgoodies.forms.builder.ButtonBarBuilder;
+import com.jgoodies.forms.builder.FormBuilder;
+import com.jgoodies.forms.layout.FormLayout;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * This class produces a dialog box for editing a single file link from a Bibtex entry.
+ *
+ * The information to be edited includes the file description, the link itself and the
+ * file type. The dialog also includes convenience buttons for quick linking.
+ *
+ * For use when downloading files, this class also offers a progress bar and a "Downloading..."
+ * label that can be hidden when the download is complete.
+ */
+public class FileListEntryEditor {
+ private static final Log LOGGER = LogFactory.getLog(FileListEntryEditor.class);
+
+ private JDialog diag;
+ private final JTextField link = new JTextField();
+ private final JTextField description = new JTextField();
+ private final JButton ok = new JButton(Localization.lang("OK"));
+
+ private final JComboBox<ExternalFileType> types;
+ private final JProgressBar prog = new JProgressBar(SwingConstants.HORIZONTAL);
+ private final JLabel downloadLabel = new JLabel(Localization.lang("Downloading..."));
+ private ConfirmCloseFileListEntryEditor externalConfirm;
+
+ private FileListEntry entry;
+ //Do not make this variable final, as then the lambda action listener will fail on compiöe
+ private BibDatabaseContext databaseContext;
+ private boolean okPressed;
+ private boolean okDisabledExternally;
+ private boolean openBrowseWhenShown;
+ private boolean dontOpenBrowseUntilDisposed;
+
+ //Do not make this variable final, as then the lambda action listener will fail on compile
+ private JabRefFrame frame;
+
+ private static final Pattern REMOTE_LINK_PATTERN = Pattern.compile("[a-z]+://.*");
+
+
+ public FileListEntryEditor(JabRefFrame frame, FileListEntry entry, boolean showProgressBar, boolean showOpenButton,
+ BibDatabaseContext databaseContext) {
+ this.entry = entry;
+ this.databaseContext = databaseContext;
+ this.frame = frame;
+
+ ActionListener okAction = e -> {
+ // If OK button is disabled, ignore this event:
+ if (!ok.isEnabled()) {
+ return;
+ }
+ // If necessary, ask the external confirm object whether we are ready to close.
+ if (externalConfirm != null) {
+ // Construct an updated FileListEntry:
+ storeSettings(entry);
+ if (!externalConfirm.confirmClose(entry)) {
+ return;
+ }
+ }
+ diag.dispose();
+ storeSettings(FileListEntryEditor.this.entry);
+ okPressed = true;
+ };
+ types = new JComboBox<>();
+ types.addItemListener(itemEvent -> {
+ if (!okDisabledExternally) {
+ ok.setEnabled(types.getSelectedItem() != null);
+ }
+ });
+
+ FormLayout fileDialog = new FormLayout(
+ "left:pref, 4dlu, fill:400dlu, 4dlu, fill:pref, 4dlu, fill:pref",
+ "p, 8dlu, p, 8dlu, p"
+ );
+ FormBuilder builder = FormBuilder.create().layout(fileDialog);
+ builder.add(Localization.lang("Link")).xy(1, 1);
+ builder.add(link).xy(3, 1);
+
+ final JButton browseBut = new JButton(Localization.lang("Browse"));
+ browseBut.addActionListener(browsePressed);
+ builder.add(browseBut).xy(5, 1);
+ JButton open = new JButton(Localization.lang("Open"));
+ if (showOpenButton) {
+ builder.add(open).xy(7, 1);
+ }
+ builder.add(Localization.lang("Description")).xy(1, 3);
+ builder.add(description).xyw(3, 3, 5);
+ builder.getPanel().setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
+ builder.add(Localization.lang("File type")).xy(1, 5);
+ builder.add(types).xyw(3, 5, 5);
+ if (showProgressBar) {
+ builder.appendRows("2dlu, p");
+ builder.add(downloadLabel).xy(1, 7);
+ builder.add(prog).xyw(3, 7, 3);
+ }
+
+ ButtonBarBuilder bb = new ButtonBarBuilder();
+ bb.addGlue();
+ bb.addRelatedGap();
+ bb.addButton(ok);
+ JButton cancel = new JButton(Localization.lang("Cancel"));
+ bb.addButton(cancel);
+ bb.addGlue();
+ bb.getPanel().setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
+
+ ok.addActionListener(okAction);
+ // Add OK action to the two text fields to simplify entering:
+ link.addActionListener(okAction);
+ description.addActionListener(okAction);
+
+ open.addActionListener(e -> openFile());
+
+ AbstractAction cancelAction = new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ diag.dispose();
+ }
+ };
+ cancel.addActionListener(cancelAction);
+
+ // Key bindings:
+ ActionMap am = builder.getPanel().getActionMap();
+ InputMap im = builder.getPanel().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
+ im.put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE_DIALOG), "close");
+ am.put("close", cancelAction);
+
+ link.getDocument().addDocumentListener(new DocumentListener() {
+
+ @Override
+ public void insertUpdate(DocumentEvent documentEvent) {
+ checkExtension();
+ }
+
+ @Override
+ public void removeUpdate(DocumentEvent documentEvent) {
+ // Do nothing
+ }
+
+ @Override
+ public void changedUpdate(DocumentEvent documentEvent) {
+ checkExtension();
+ }
+
+ });
+
+ diag = new JDialog(frame, Localization.lang("Save file"), true);
+ diag.getContentPane().add(builder.getPanel(), BorderLayout.CENTER);
+ diag.getContentPane().add(bb.getPanel(), BorderLayout.SOUTH);
+ diag.pack();
+ diag.setLocationRelativeTo(frame);
+ diag.addWindowListener(new WindowAdapter() {
+
+ @Override
+ public void windowActivated(WindowEvent event) {
+ if (openBrowseWhenShown && !dontOpenBrowseUntilDisposed) {
+ dontOpenBrowseUntilDisposed = true;
+ SwingUtilities.invokeLater(() -> browsePressed.actionPerformed(new ActionEvent(browseBut, 0, "")));
+ }
+ }
+
+ @Override
+ public void windowClosed(WindowEvent event) {
+ dontOpenBrowseUntilDisposed = false;
+ }
+ });
+ setValues(entry);
+ }
+
+ private void checkExtension() {
+ if ((types.getSelectedIndex() == -1) && (!link.getText().trim().isEmpty())) {
+
+ // Check if this looks like a remote link:
+ if (FileListEntryEditor.REMOTE_LINK_PATTERN.matcher(link.getText()).matches()) {
+ Optional<ExternalFileType> type = ExternalFileTypes.getInstance().getExternalFileTypeByExt("html");
+ if (type.isPresent()) {
+ types.setSelectedItem(type.get());
+ return;
+ }
+ }
+
+ // Try to guess the file type:
+ String theLink = link.getText().trim();
+ ExternalFileTypes.getInstance().getExternalFileTypeForName(theLink).ifPresent(types::setSelectedItem);
+ }
+ }
+
+ private void openFile() {
+ ExternalFileType type = (ExternalFileType) types.getSelectedItem();
+ if (type != null) {
+ try {
+ JabRefDesktop.openExternalFileAnyFormat(databaseContext, link.getText(), Optional.of(type));
+ } catch (IOException e) {
+ LOGGER.error("File could not be opened", e);
+ }
+ }
+ }
+
+ public void setExternalConfirm(ConfirmCloseFileListEntryEditor eC) {
+ this.externalConfirm = eC;
+ }
+
+ public void setOkEnabled(boolean enabled) {
+ okDisabledExternally = !enabled;
+ ok.setEnabled(enabled);
+ }
+
+ public JProgressBar getProgressBar() {
+ return prog;
+ }
+
+ public JLabel getProgressBarLabel() {
+ return downloadLabel;
+ }
+
+ public void setEntry(FileListEntry entry) {
+ this.entry = entry;
+ setValues(entry);
+ }
+
+ public void setVisible(boolean visible, boolean openBrowse) {
+ openBrowseWhenShown = openBrowse && Globals.prefs.getBoolean(JabRefPreferences.ALLOW_FILE_AUTO_OPEN_BROWSE);
+ if (visible) {
+ okPressed = false;
+ }
+ diag.setVisible(visible);
+ }
+
+ public boolean isVisible() {
+ return (diag != null) && diag.isVisible();
+ }
+
+ private void setValues(FileListEntry entry) {
+ description.setText(entry.description);
+ link.setText(entry.link);
+
+ Collection<ExternalFileType> list = ExternalFileTypes.getInstance().getExternalFileTypeSelection();
+
+ types.setModel(new DefaultComboBoxModel<>(list.toArray(new ExternalFileType[list.size()])));
+ types.setSelectedIndex(-1);
+ // See what is a reasonable selection for the type combobox:
+ if ((entry.type.isPresent()) && !(entry.type.get() instanceof UnknownExternalFileType)) {
+ types.setSelectedItem(entry.type.get());
+ } else if ((entry.link != null) && (!entry.link.isEmpty())) {
+ checkExtension();
+ }
+ }
+
+ private void storeSettings(FileListEntry listEntry) {
+ String descriptionText = this.description.getText().trim();
+ String fileLink = "";
+ // See if we should trim the file link to be relative to the file directory:
+ try {
+ List<String> dirs = databaseContext.getFileDirectories(Globals.prefs.getFileDirectoryPreferences());
+ if (dirs.isEmpty()) {
+ fileLink = this.link.getText().trim();
+ } else {
+ boolean found = false;
+ for (String dir : dirs) {
+ String canPath = (new File(dir)).getCanonicalPath();
+ File fl = new File(this.link.getText().trim());
+ if (fl.isAbsolute()) {
+ String flPath = fl.getCanonicalPath();
+ if ((flPath.length() > canPath.length()) && (flPath.startsWith(canPath))) {
+ fileLink = fl.getCanonicalPath().substring(canPath.length() + 1);
+ found = true;
+ break;
+ }
+ }
+ }
+ if (!found) {
+ fileLink = this.link.getText().trim();
+ }
+ }
+ } catch (IOException ex) {
+ // Don't think this should happen, but set the file link directly as a fallback:
+ fileLink = this.link.getText().trim();
+ }
+
+ ExternalFileType type = (ExternalFileType) types.getSelectedItem();
+
+ listEntry.description = descriptionText;
+ listEntry.type = Optional.ofNullable(type);
+ listEntry.link = fileLink;
+ }
+
+ public boolean okPressed() {
+ return okPressed;
+ }
+
+ private final ActionListener browsePressed = e -> {
+ String filePath = link.getText().trim();
+ Optional<File> file = FileUtil.expandFilename(this.databaseContext, filePath,
+ Globals.prefs.getFileDirectoryPreferences());
+ String workingDir;
+ // no file set yet or found
+ if (file.isPresent()) {
+ workingDir = file.get().getPath();
+ } else {
+ workingDir = Globals.prefs.get(JabRefPreferences.WORKING_DIRECTORY);
+ }
+
+ Optional<Path> path = new FileDialog(this.frame, workingDir).showDialogAndGetSelectedFile();
+
+ path.ifPresent(selection -> {
+ File newFile = selection.toFile();
+ // Store the directory for next time:
+ Globals.prefs.put(JabRefPreferences.WORKING_DIRECTORY, newFile.getPath());
+
+ // If the file is below the file directory, make the path relative:
+ List<String> fileDirs = this.databaseContext.getFileDirectories(Globals.prefs.getFileDirectoryPreferences());
+ newFile = FileUtil.shortenFileName(newFile, fileDirs);
+
+ link.setText(newFile.getPath());
+ link.requestFocus();
+ });
+ };
+}
diff --git a/src/main/java/net/sf/jabref/gui/filelist/FileListTableModel.java b/src/main/java/net/sf/jabref/gui/filelist/FileListTableModel.java
new file mode 100644
index 0000000..2df5736
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/filelist/FileListTableModel.java
@@ -0,0 +1,222 @@
+package net.sf.jabref.gui.filelist;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.StringJoiner;
+
+import javax.swing.JLabel;
+import javax.swing.SwingUtilities;
+import javax.swing.event.TableModelEvent;
+import javax.swing.table.AbstractTableModel;
+
+import net.sf.jabref.gui.externalfiletype.ExternalFileType;
+import net.sf.jabref.gui.externalfiletype.ExternalFileTypes;
+import net.sf.jabref.gui.externalfiletype.UnknownExternalFileType;
+import net.sf.jabref.logic.util.io.FileUtil;
+import net.sf.jabref.model.entry.FileField;
+import net.sf.jabref.model.entry.ParsedFileField;
+
+/**
+ * Data structure to contain a list of file links, parseable from a coded string.
+ * Doubles as a table model for the file list editor.
+ */
+public class FileListTableModel extends AbstractTableModel {
+
+ private final List<FileListEntry> list = new ArrayList<>();
+
+ @Override
+ public int getRowCount() {
+ synchronized (list) {
+ return list.size();
+ }
+ }
+
+ @Override
+ public int getColumnCount() {
+ return 3;
+ }
+
+ @Override
+ public Class<String> getColumnClass(int columnIndex) {
+ return String.class;
+ }
+
+ @Override
+ public Object getValueAt(int rowIndex, int columnIndex) {
+ synchronized (list) {
+ FileListEntry entry = list.get(rowIndex);
+ switch (columnIndex) {
+ case 0:
+ return entry.description;
+ case 1:
+ return entry.link;
+ default:
+ return entry.type.isPresent() ? entry.type.get().getName() : "";
+ }
+ }
+ }
+
+ public FileListEntry getEntry(int index) {
+ synchronized (list) {
+ return list.get(index);
+ }
+ }
+
+ public void setEntry(int index, FileListEntry entry) {
+ synchronized (list) {
+ list.set(index, entry);
+ fireTableRowsUpdated(index, index);
+ }
+ }
+
+ public void removeEntry(int index) {
+ synchronized (list) {
+ list.remove(index);
+ fireTableRowsDeleted(index, index);
+ }
+
+ }
+
+ /**
+ * Add an entry to the table model, and fire a change event. The change event
+ * is fired on the event dispatch thread.
+ * @param index The row index to insert the entry at.
+ * @param entry The entry to insert.
+ */
+ public void addEntry(final int index, final FileListEntry entry) {
+ synchronized (list) {
+ list.add(index, entry);
+ if (SwingUtilities.isEventDispatchThread()) {
+ fireTableRowsInserted(index, index);
+ } else {
+ SwingUtilities.invokeLater(() -> fireTableRowsInserted(index, index));
+ }
+ }
+
+ }
+
+ @Override
+ public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
+ // Do nothing
+ }
+
+ /**
+ * Set up the table contents based on the flat string representation of the file list
+ * @param value The string representation
+ */
+ public void setContent(String value) {
+ setContent(value, false, true);
+ }
+
+ public void setContentDontGuessTypes(String value) {
+ setContent(value, false, false);
+ }
+
+ private FileListEntry setContent(String val, boolean firstOnly, boolean deduceUnknownTypes) {
+ String value = val;
+ if (value == null) {
+ value = "";
+ }
+
+ List<ParsedFileField> fields = FileField.parse(value);
+ List<FileListEntry> files = new ArrayList<>();
+
+ for(ParsedFileField entry : fields) {
+ if (entry.isEmpty()) {
+ continue;
+ }
+
+ if (firstOnly) {
+ return decodeEntry(entry, deduceUnknownTypes);
+ } else {
+ files.add(decodeEntry(entry, deduceUnknownTypes));
+ }
+ }
+
+ synchronized (list) {
+ list.clear();
+ list.addAll(files);
+ }
+ fireTableChanged(new TableModelEvent(this));
+ return null;
+ }
+
+ /**
+ * Convenience method for finding a label corresponding to the type of the
+ * first file link in the given field content. The difference between using
+ * this method and using setContent() on an instance of FileListTableModel
+ * is a slight optimization: with this method, parsing is discontinued after
+ * the first entry has been found.
+ * @param content The file field content, as fed to this class' setContent() method.
+ * @return A JLabel set up with no text and the icon of the first entry's file type,
+ * or null if no entry was found or the entry had no icon.
+ */
+ public static JLabel getFirstLabel(String content) {
+ FileListTableModel tm = new FileListTableModel();
+ FileListEntry entry = tm.setContent(content, true, true);
+ if ((entry == null) || (!entry.type.isPresent())) {
+ return null;
+ }
+ return entry.type.get().getIconLabel();
+ }
+
+ private FileListEntry decodeEntry(ParsedFileField entry, boolean deduceUnknownType) {
+ Optional<ExternalFileType> type = ExternalFileTypes.getInstance().getExternalFileTypeByName(entry.getFileType());
+
+ if (deduceUnknownType && (type.get() instanceof UnknownExternalFileType)) {
+ // No file type was recognized. Try to find a usable file type based
+ // on mime type:
+ type = ExternalFileTypes.getInstance().getExternalFileTypeByMimeType(entry.getFileType());
+ if (!type.isPresent()) {
+ // No type could be found from mime type on the extension:
+ Optional<String> extension = FileUtil.getFileExtension(entry.getLink());
+ if (extension.isPresent()) {
+ Optional<ExternalFileType> typeGuess = ExternalFileTypes.getInstance()
+ .getExternalFileTypeByExt(extension.get());
+
+ if (typeGuess.isPresent()) {
+ type = typeGuess;
+ }
+ }
+ }
+ }
+
+ return new FileListEntry(entry.getDescription(), entry.getLink(), type);
+ }
+
+ /**
+ * Transform the file list shown in the table into a flat string representable
+ * as a BibTeX field:
+ * @return String representation.
+ */
+ public String getStringRepresentation() {
+ synchronized (list) {
+ String[][] array = new String[list.size()][];
+ int i = 0;
+ for (FileListEntry entry : list) {
+ array[i] = entry.getStringArrayRepresentation();
+ i++;
+ }
+ return FileField.encodeStringArray(array);
+ }
+ }
+
+ /**
+ * Transform the file list shown in the table into a HTML string representation
+ * suitable for displaying the contents in a tooltip.
+ * @return Tooltip representation.
+ */
+ public String getToolTipHTMLRepresentation() {
+ StringJoiner sb = new StringJoiner("<br>", "<html>", "</html>");
+
+ synchronized (list) {
+ for (FileListEntry entry : list) {
+ sb.add(String.format("%s (%s)", entry.description, entry.link));
+ }
+ }
+
+ return sb.toString();
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/gui/groups/AddToGroupAction.java b/src/main/java/net/sf/jabref/gui/groups/AddToGroupAction.java
index 0186f2b..66692d2 100644
--- a/src/main/java/net/sf/jabref/gui/groups/AddToGroupAction.java
+++ b/src/main/java/net/sf/jabref/gui/groups/AddToGroupAction.java
@@ -9,11 +9,11 @@ import javax.swing.AbstractAction;
import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.gui.undo.NamedCompound;
-import net.sf.jabref.logic.groups.AbstractGroup;
-import net.sf.jabref.logic.groups.EntriesGroupChange;
-import net.sf.jabref.logic.groups.GroupTreeNode;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.groups.AbstractGroup;
+import net.sf.jabref.model.groups.EntriesGroupChange;
+import net.sf.jabref.model.groups.GroupTreeNode;
public class AddToGroupAction extends AbstractAction {
diff --git a/src/main/java/net/sf/jabref/gui/groups/AutoGroupDialog.java b/src/main/java/net/sf/jabref/gui/groups/AutoGroupDialog.java
index 58b3f37..d0aeb14 100644
--- a/src/main/java/net/sf/jabref/gui/groups/AutoGroupDialog.java
+++ b/src/main/java/net/sf/jabref/gui/groups/AutoGroupDialog.java
@@ -27,15 +27,14 @@ import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.gui.JabRefFrame;
import net.sf.jabref.gui.keyboard.KeyBinding;
import net.sf.jabref.gui.undo.NamedCompound;
-import net.sf.jabref.logic.groups.ExplicitGroup;
-import net.sf.jabref.logic.groups.GroupHierarchyType;
-import net.sf.jabref.logic.groups.GroupTreeNode;
-import net.sf.jabref.logic.groups.GroupsUtil;
-import net.sf.jabref.logic.groups.KeywordGroup;
-import net.sf.jabref.logic.importer.util.ParseException;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.layout.format.LatexToUnicodeFormatter;
import net.sf.jabref.model.entry.FieldName;
+import net.sf.jabref.model.groups.ExplicitGroup;
+import net.sf.jabref.model.groups.GroupHierarchyType;
+import net.sf.jabref.model.groups.GroupTreeNode;
+import net.sf.jabref.model.groups.GroupsUtil;
+import net.sf.jabref.model.groups.KeywordGroup;
import com.jgoodies.forms.builder.ButtonBarBuilder;
import com.jgoodies.forms.builder.FormBuilder;
@@ -53,7 +52,8 @@ class AutoGroupDialog extends JDialog implements CaretListener {
Localization.lang("Generate groups from keywords in a BibTeX field"));
private final JRadioButton authors = new JRadioButton(Localization.lang("Generate groups for author last names"));
private final JRadioButton editors = new JRadioButton(Localization.lang("Generate groups for editor last names"));
- private final JCheckBox nd = new JCheckBox(Localization.lang("Use the following delimiter character(s):"));
+ private final JCheckBox useCustomDelimiter = new JCheckBox(
+ Localization.lang("Use the following delimiter character(s):"));
private final JButton ok = new JButton(Localization.lang("OK"));
private final GroupTreeNodeViewModel m_groupsRoot;
private final JabRefFrame frame;
@@ -72,60 +72,56 @@ class AutoGroupDialog extends JDialog implements CaretListener {
field.setText(defaultField);
remove.setText(defaultRemove);
deliminator.setText(defaultDeliminator);
- nd.setSelected(true);
- ActionListener okListener = new ActionListener() {
+ useCustomDelimiter.setSelected(true);
+ ActionListener okListener = e -> {
+ dispose();
+
+ try {
+ GroupTreeNode autoGroupsRoot = GroupTreeNode.fromGroup(
+ new ExplicitGroup(Localization.lang("Automatically created groups"),
+ GroupHierarchyType.INCLUDING,
+ Globals.prefs.getKeywordDelimiter()));
+ Set<String> keywords;
+ String fieldText = field.getText().toLowerCase().trim();
+ if (this.keywords.isSelected()) {
+ if (useCustomDelimiter.isSelected()) {
+ keywords = GroupsUtil.findDeliminatedWordsInField(panel.getDatabase(), fieldText,
+ deliminator.getText());
+ } else {
+ keywords = GroupsUtil.findAllWordsInField(panel.getDatabase(), fieldText, remove.getText());
- @Override
- public void actionPerformed(ActionEvent e) {
- dispose();
-
- try {
- GroupTreeNode autoGroupsRoot = GroupTreeNode.fromGroup(
- new ExplicitGroup(Localization.lang("Automatically created groups"),
- GroupHierarchyType.INCLUDING, Globals.prefs));
- Set<String> hs;
- String fieldText = field.getText();
- if (keywords.isSelected()) {
- if (nd.isSelected()) {
- hs = GroupsUtil.findDeliminatedWordsInField(panel.getDatabase(),
- field.getText().toLowerCase().trim(), deliminator.getText());
- } else {
- hs = GroupsUtil.findAllWordsInField(panel.getDatabase(), field.getText().toLowerCase().trim(),
- remove.getText());
-
- }
- } else if (authors.isSelected()) {
- List<String> fields = new ArrayList<>(2);
- fields.add(FieldName.AUTHOR);
- hs = GroupsUtil.findAuthorLastNames(panel.getDatabase(), fields);
- fieldText = FieldName.AUTHOR;
- } else { // editors.isSelected() as it is a radio button group.
- List<String> fields = new ArrayList<>(2);
- fields.add(FieldName.EDITOR);
- hs = GroupsUtil.findAuthorLastNames(panel.getDatabase(), fields);
- fieldText = FieldName.EDITOR;
}
+ } else if (authors.isSelected()) {
+ List<String> fields = new ArrayList<>(2);
+ fields.add(FieldName.AUTHOR);
+ keywords = GroupsUtil.findAuthorLastNames(panel.getDatabase(), fields);
+ fieldText = FieldName.AUTHOR;
+ } else { // editors.isSelected() as it is a radio button group.
+ List<String> fields = new ArrayList<>(2);
+ fields.add(FieldName.EDITOR);
+ keywords = GroupsUtil.findAuthorLastNames(panel.getDatabase(), fields);
+ fieldText = FieldName.EDITOR;
+ }
- LatexToUnicodeFormatter formatter = new LatexToUnicodeFormatter();
-
- for (String keyword : hs) {
- KeywordGroup group = new KeywordGroup(formatter.format(keyword), fieldText, keyword, false, false,
- GroupHierarchyType.INDEPENDENT, Globals.prefs);
- autoGroupsRoot.addChild(GroupTreeNode.fromGroup(group));
- }
+ LatexToUnicodeFormatter formatter = new LatexToUnicodeFormatter();
- autoGroupsRoot.moveTo(m_groupsRoot.getNode());
- NamedCompound ce = new NamedCompound(Localization.lang("Automatically create groups"));
- UndoableAddOrRemoveGroup undo = new UndoableAddOrRemoveGroup(m_groupsRoot, new GroupTreeNodeViewModel(autoGroupsRoot), UndoableAddOrRemoveGroup.ADD_NODE);
- ce.addEdit(undo);
-
- panel.markBaseChanged(); // a change always occurs
- frame.output(Localization.lang("Created groups."));
- ce.end();
- panel.getUndoManager().addEdit(ce);
- } catch (ParseException exception) {
- frame.showMessage(exception.getLocalizedMessage());
+ for (String keyword : keywords) {
+ KeywordGroup group = new KeywordGroup(formatter.format(keyword), fieldText, keyword, false, false,
+ GroupHierarchyType.INDEPENDENT, Globals.prefs.getKeywordDelimiter());
+ autoGroupsRoot.addChild(GroupTreeNode.fromGroup(group));
}
+
+ autoGroupsRoot.moveTo(m_groupsRoot.getNode());
+ NamedCompound ce = new NamedCompound(Localization.lang("Automatically create groups"));
+ UndoableAddOrRemoveGroup undo = new UndoableAddOrRemoveGroup(m_groupsRoot, new GroupTreeNodeViewModel(autoGroupsRoot), UndoableAddOrRemoveGroup.ADD_NODE);
+ ce.addEdit(undo);
+
+ panel.markBaseChanged(); // a change always occurs
+ frame.output(Localization.lang("Created groups."));
+ ce.end();
+ panel.getUndoManager().addEdit(ce);
+ } catch (IllegalArgumentException exception) {
+ frame.showMessage(exception.getLocalizedMessage());
}
};
remove.addActionListener(okListener);
@@ -162,7 +158,7 @@ class AutoGroupDialog extends JDialog implements CaretListener {
b.add(field).xy(5, 3);
b.add(Localization.lang("Characters to ignore") + ":").xy(3, 5);
b.add(remove).xy(5, 5);
- b.add(nd).xy(3, 7);
+ b.add(useCustomDelimiter).xy(3, 7);
b.add(deliminator).xy(5, 7);
b.add(authors).xyw(1, 9, 5);
b.add(editors).xyw(1, 11, 5);
diff --git a/src/main/java/net/sf/jabref/gui/groups/EntryTableTransferHandler.java b/src/main/java/net/sf/jabref/gui/groups/EntryTableTransferHandler.java
index d623bb2..838bb49 100644
--- a/src/main/java/net/sf/jabref/gui/groups/EntryTableTransferHandler.java
+++ b/src/main/java/net/sf/jabref/gui/groups/EntryTableTransferHandler.java
@@ -23,12 +23,12 @@ import javax.swing.JTable;
import javax.swing.TransferHandler;
import net.sf.jabref.JabRefExecutorService;
-import net.sf.jabref.external.DroppedFileHandler;
-import net.sf.jabref.external.ExternalFileType;
-import net.sf.jabref.external.ExternalFileTypes;
-import net.sf.jabref.external.TransferableFileLinkSelection;
import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.gui.JabRefFrame;
+import net.sf.jabref.gui.externalfiles.DroppedFileHandler;
+import net.sf.jabref.gui.externalfiles.TransferableFileLinkSelection;
+import net.sf.jabref.gui.externalfiletype.ExternalFileType;
+import net.sf.jabref.gui.externalfiletype.ExternalFileTypes;
import net.sf.jabref.gui.importer.ImportMenuItem;
import net.sf.jabref.gui.importer.actions.OpenDatabaseAction;
import net.sf.jabref.gui.maintable.MainTable;
@@ -124,6 +124,7 @@ public class EntryTableTransferHandler extends TransferHandler {
if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
// JOptionPane.showMessageDialog(null, "Received
// javaFileListFlavor");
+ @SuppressWarnings("unchecked")
List<File> l = (List<File>) t.getTransferData(DataFlavor.javaFileListFlavor);
return handleDraggedFiles(l, dropRow);
} else if (t.isDataFlavorSupported(urlFlavor)) {
diff --git a/src/main/java/net/sf/jabref/gui/groups/GroupAddRemoveDialog.java b/src/main/java/net/sf/jabref/gui/groups/GroupAddRemoveDialog.java
index bb3ef91..ddd0335 100644
--- a/src/main/java/net/sf/jabref/gui/groups/GroupAddRemoveDialog.java
+++ b/src/main/java/net/sf/jabref/gui/groups/GroupAddRemoveDialog.java
@@ -6,6 +6,7 @@ import java.awt.Component;
import java.awt.event.ActionEvent;
import java.util.Enumeration;
import java.util.List;
+import java.util.Optional;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
@@ -26,9 +27,9 @@ import net.sf.jabref.Globals;
import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.gui.actions.BaseAction;
import net.sf.jabref.gui.keyboard.KeyBinding;
-import net.sf.jabref.logic.groups.GroupTreeNode;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.groups.GroupTreeNode;
import com.jgoodies.forms.builder.ButtonBarBuilder;
@@ -55,9 +56,9 @@ public class GroupAddRemoveDialog implements BaseAction {
}
@Override
- public void action() throws Throwable {
- GroupTreeNode groups = panel.getBibDatabaseContext().getMetaData().getGroups();
- if (groups == null) {
+ public void action() throws Exception {
+ Optional<GroupTreeNode> groups = panel.getBibDatabaseContext().getMetaData().getGroups();
+ if (!groups.isPresent()) {
return;
}
@@ -69,7 +70,7 @@ public class GroupAddRemoveDialog implements BaseAction {
true);
JButton ok = new JButton(Localization.lang("OK"));
JButton cancel = new JButton(Localization.lang("Cancel"));
- tree = new JTree(new GroupTreeNodeViewModel(groups));
+ tree = new JTree(new GroupTreeNodeViewModel(groups.get()));
tree.setCellRenderer(new AddRemoveGroupTreeCellRenderer());
tree.setVisibleRowCount(22);
diff --git a/src/main/java/net/sf/jabref/gui/groups/GroupDialog.java b/src/main/java/net/sf/jabref/gui/groups/GroupDialog.java
index 3065a93..99c73ed 100644
--- a/src/main/java/net/sf/jabref/gui/groups/GroupDialog.java
+++ b/src/main/java/net/sf/jabref/gui/groups/GroupDialog.java
@@ -28,21 +28,19 @@ import javax.swing.SwingConstants;
import javax.swing.event.CaretListener;
import net.sf.jabref.Globals;
-import net.sf.jabref.gui.BasePanel;
-import net.sf.jabref.gui.FieldContentSelector;
import net.sf.jabref.gui.JabRefFrame;
import net.sf.jabref.gui.fieldeditors.TextField;
import net.sf.jabref.gui.keyboard.KeyBinding;
-import net.sf.jabref.logic.groups.AbstractGroup;
-import net.sf.jabref.logic.groups.ExplicitGroup;
-import net.sf.jabref.logic.groups.GroupHierarchyType;
-import net.sf.jabref.logic.groups.KeywordGroup;
-import net.sf.jabref.logic.groups.SearchGroup;
-import net.sf.jabref.logic.importer.util.ParseException;
+import net.sf.jabref.logic.groups.GroupDescriptions;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.search.SearchQuery;
-import net.sf.jabref.logic.util.strings.StringUtil;
import net.sf.jabref.model.entry.FieldName;
+import net.sf.jabref.model.groups.AbstractGroup;
+import net.sf.jabref.model.groups.ExplicitGroup;
+import net.sf.jabref.model.groups.GroupHierarchyType;
+import net.sf.jabref.model.groups.KeywordGroup;
+import net.sf.jabref.model.groups.SearchGroup;
+import net.sf.jabref.model.strings.StringUtil;
import net.sf.jabref.preferences.JabRefPreferences;
import com.jgoodies.forms.builder.ButtonBarBuilder;
@@ -111,7 +109,7 @@ class GroupDialog extends JDialog {
* @param editedGroup The group being edited, or null if a new group is to be
* created.
*/
- public GroupDialog(JabRefFrame jabrefFrame, BasePanel basePanel,
+ public GroupDialog(JabRefFrame jabrefFrame,
AbstractGroup editedGroup) {
super(jabrefFrame, Localization.lang("Edit group"), true);
@@ -143,7 +141,6 @@ class GroupDialog extends JDialog {
builderKG.nextLine();
builderKG.append(Localization.lang("Keyword"));
builderKG.append(keywordGroupSearchTerm);
- builderKG.append(new FieldContentSelector(jabrefFrame, basePanel, this, keywordGroupSearchTerm, null, true, ", "));
builderKG.nextLine();
builderKG.append(keywordGroupCaseSensitive, 3);
builderKG.nextLine();
@@ -265,14 +262,15 @@ class GroupDialog extends JDialog {
isOkPressed = true;
try {
if (explicitRadioButton.isSelected()) {
- resultingGroup = new ExplicitGroup(nameField.getText().trim(), getContext(), Globals.prefs);
+ resultingGroup = new ExplicitGroup(nameField.getText().trim(), getContext(),
+ Globals.prefs.getKeywordDelimiter());
} else if (keywordsRadioButton.isSelected()) {
// regex is correct, otherwise OK would have been disabled
// therefore I don't catch anything here
- resultingGroup = new KeywordGroup(nameField.getText().trim(), keywordGroupSearchField.getText().trim(),
- keywordGroupSearchTerm.getText().trim(), keywordGroupCaseSensitive.isSelected(), keywordGroupRegExp
- .isSelected(),
- getContext(), Globals.prefs);
+ resultingGroup = new KeywordGroup(nameField.getText().trim(),
+ keywordGroupSearchField.getText().trim(), keywordGroupSearchTerm.getText().trim(),
+ keywordGroupCaseSensitive.isSelected(), keywordGroupRegExp.isSelected(), getContext(),
+ Globals.prefs.getKeywordDelimiter());
} else if (searchRadioButton.isSelected()) {
try {
// regex is correct, otherwise OK would have been
@@ -285,7 +283,7 @@ class GroupDialog extends JDialog {
}
}
dispose();
- } catch (ParseException exception) {
+ } catch (IllegalArgumentException exception) {
jabrefFrame.showMessage(exception.getLocalizedMessage());
}
});
@@ -367,14 +365,14 @@ class GroupDialog extends JDialog {
if (keywordGroupRegExp.isSelected()) {
try {
Pattern.compile(s2);
- setDescription(KeywordGroup.getDescriptionForPreview(s1, s2, keywordGroupCaseSensitive.isSelected(),
+ setDescription(GroupDescriptions.getDescriptionForPreview(s1, s2, keywordGroupCaseSensitive.isSelected(),
keywordGroupRegExp.isSelected()));
} catch (PatternSyntaxException e) {
okEnabled = false;
setDescription(formatRegExException(s2, e));
}
} else {
- setDescription(KeywordGroup.getDescriptionForPreview(s1, s2, keywordGroupCaseSensitive.isSelected(),
+ setDescription(GroupDescriptions.getDescriptionForPreview(s1, s2, keywordGroupCaseSensitive.isSelected(),
keywordGroupRegExp.isSelected()));
}
} else {
@@ -405,7 +403,7 @@ class GroupDialog extends JDialog {
}
setNameFontItalic(true);
} else if (explicitRadioButton.isSelected()) {
- setDescription(ExplicitGroup.getDescriptionForPreview());
+ setDescription(GroupDescriptions.getDescriptionForPreview());
setNameFontItalic(false);
}
okButton.setEnabled(okEnabled);
diff --git a/src/main/java/net/sf/jabref/gui/groups/GroupSelector.java b/src/main/java/net/sf/jabref/gui/groups/GroupSelector.java
index ae7532d..958d3e2 100644
--- a/src/main/java/net/sf/jabref/gui/groups/GroupSelector.java
+++ b/src/main/java/net/sf/jabref/gui/groups/GroupSelector.java
@@ -8,6 +8,7 @@ import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
+import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
@@ -30,6 +31,7 @@ import javax.swing.JPopupMenu;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.JScrollPane;
import javax.swing.KeyStroke;
+import javax.swing.ScrollPaneConstants;
import javax.swing.SwingUtilities;
import javax.swing.border.TitledBorder;
import javax.swing.event.ChangeEvent;
@@ -44,29 +46,30 @@ import javax.swing.undo.AbstractUndoableEdit;
import javax.swing.undo.CompoundEdit;
import net.sf.jabref.Globals;
-import net.sf.jabref.MetaData;
-import net.sf.jabref.event.GroupUpdatedEvent;
import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.gui.IconTheme;
import net.sf.jabref.gui.JabRefFrame;
import net.sf.jabref.gui.SidePaneComponent;
import net.sf.jabref.gui.SidePaneManager;
import net.sf.jabref.gui.help.HelpAction;
+import net.sf.jabref.gui.keyboard.KeyBinding;
import net.sf.jabref.gui.maintable.MainTableDataModel;
import net.sf.jabref.gui.undo.NamedCompound;
import net.sf.jabref.gui.worker.AbstractWorker;
-import net.sf.jabref.logic.groups.AbstractGroup;
-import net.sf.jabref.logic.groups.AllEntriesGroup;
-import net.sf.jabref.logic.groups.EntriesGroupChange;
-import net.sf.jabref.logic.groups.GroupTreeNode;
-import net.sf.jabref.logic.groups.MoveGroupChange;
import net.sf.jabref.logic.help.HelpFile;
import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.logic.search.SearchMatcher;
-import net.sf.jabref.logic.search.matchers.MatcherSet;
-import net.sf.jabref.logic.search.matchers.MatcherSets;
-import net.sf.jabref.logic.search.matchers.NotMatcher;
import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.groups.AbstractGroup;
+import net.sf.jabref.model.groups.AllEntriesGroup;
+import net.sf.jabref.model.groups.EntriesGroupChange;
+import net.sf.jabref.model.groups.GroupTreeNode;
+import net.sf.jabref.model.groups.MoveGroupChange;
+import net.sf.jabref.model.groups.event.GroupUpdatedEvent;
+import net.sf.jabref.model.metadata.MetaData;
+import net.sf.jabref.model.search.SearchMatcher;
+import net.sf.jabref.model.search.matchers.MatcherSet;
+import net.sf.jabref.model.search.matchers.MatcherSets;
+import net.sf.jabref.model.search.matchers.NotMatcher;
import net.sf.jabref.preferences.JabRefPreferences;
import com.google.common.eventbus.Subscribe;
@@ -125,6 +128,8 @@ public class GroupSelector extends SidePaneComponent implements TreeSelectionLis
private final AddToGroupAction moveToGroup = new AddToGroupAction(true);
private final RemoveFromGroupAction removeFromGroup = new RemoveFromGroupAction();
+ private ToggleAction toggleAction;
+
/**
* The first element for each group defines which field to use for the quicksearch. The next two define the name and
@@ -133,6 +138,11 @@ public class GroupSelector extends SidePaneComponent implements TreeSelectionLis
public GroupSelector(JabRefFrame frame, SidePaneManager manager) {
super(manager, IconTheme.JabRefIcon.TOGGLE_GROUPS.getIcon(), Localization.lang("Groups"));
+ toggleAction = new ToggleAction(Localization.menuTitle("Toggle groups interface"),
+ Localization.lang("Toggle groups interface"),
+ Globals.getKeyPrefs().getKey(KeyBinding.TOGGLE_GROUPS_INTERFACE),
+ IconTheme.JabRefIcon.TOGGLE_GROUPS);
+
this.frame = frame;
hideNonHits = new JRadioButtonMenuItem(Localization.lang("Hide non-hits"),
!Globals.prefs.getBoolean(JabRefPreferences.GRAY_OUT_NON_HITS));
@@ -243,14 +253,13 @@ public class GroupSelector extends SidePaneComponent implements TreeSelectionLis
helpButton.setMargin(butIns);
openSettings.setMargin(butIns);
newButton.addActionListener(e -> {
- GroupDialog gd = new GroupDialog(frame, panel, null);
+ GroupDialog gd = new GroupDialog(frame, null);
gd.setVisible(true);
if (gd.okPressed()) {
AbstractGroup newGroup = gd.getResultingGroup();
groupsRoot.addNewGroup(newGroup, panel.getUndoManager());
panel.markBaseChanged();
frame.output(Localization.lang("Created group \"%0\".", newGroup.getName()));
- panel.getBibDatabaseContext().getMetaData().postChange();
}
});
andCb.addActionListener(e -> valueChanged(null));
@@ -316,8 +325,8 @@ public class GroupSelector extends SidePaneComponent implements TreeSelectionLis
groupsTree = new GroupsTree(this);
groupsTree.addTreeSelectionListener(this);
- JScrollPane groupsTreePane = new JScrollPane(groupsTree, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
- JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
+ JScrollPane groupsTreePane = new JScrollPane(groupsTree, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
+ ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
groupsTreePane.setBorder(BorderFactory.createEmptyBorder(0,0,0,0));
con.gridwidth = GridBagConstraints.REMAINDER;
con.weighty = 1;
@@ -331,19 +340,19 @@ public class GroupSelector extends SidePaneComponent implements TreeSelectionLis
setEditMode(editModeIndicator);
definePopup();
NodeAction moveNodeUpAction = new MoveNodeUpAction();
- moveNodeUpAction.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_UP, KeyEvent.CTRL_MASK));
+ moveNodeUpAction.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_UP, InputEvent.CTRL_MASK));
NodeAction moveNodeDownAction = new MoveNodeDownAction();
moveNodeDownAction.putValue(Action.ACCELERATOR_KEY,
- KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, KeyEvent.CTRL_MASK));
+ KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, InputEvent.CTRL_MASK));
NodeAction moveNodeLeftAction = new MoveNodeLeftAction();
moveNodeLeftAction.putValue(Action.ACCELERATOR_KEY,
- KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, KeyEvent.CTRL_MASK));
+ KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, InputEvent.CTRL_MASK));
NodeAction moveNodeRightAction = new MoveNodeRightAction();
moveNodeRightAction.putValue(Action.ACCELERATOR_KEY,
- KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, KeyEvent.CTRL_MASK));
+ KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, InputEvent.CTRL_MASK));
- setGroups(GroupTreeNode.fromGroup(new AllEntriesGroup()));
+ setGroups(GroupTreeNode.fromGroup(new AllEntriesGroup(Localization.lang("All entries"))));
}
private void definePopup() {
@@ -699,6 +708,7 @@ public class GroupSelector extends SidePaneComponent implements TreeSelectionLis
@Override
public void componentOpening() {
valueChanged(null);
+ Globals.prefs.putBoolean(JabRefPreferences.GROUP_SIDEPANE_VISIBLE, Boolean.TRUE);
}
@Override
@@ -711,7 +721,8 @@ public class GroupSelector extends SidePaneComponent implements TreeSelectionLis
if (panel != null) {// panel may be null if no file is open any more
panel.getMainTable().getTableModel().updateGroupingState(MainTableDataModel.DisplayOption.DISABLED);
}
- frame.groupToggle.setSelected(false);
+ getToggleAction().setSelected(false);
+ Globals.prefs.putBoolean(JabRefPreferences.GROUP_SIDEPANE_VISIBLE, Boolean.FALSE);
}
private void setGroups(GroupTreeNode groupsRoot) {
@@ -776,7 +787,7 @@ public class GroupSelector extends SidePaneComponent implements TreeSelectionLis
public void actionPerformed(ActionEvent e) {
final GroupTreeNodeViewModel node = getNodeToUse();
final AbstractGroup oldGroup = node.getNode().getGroup();
- final GroupDialog gd = new GroupDialog(frame, panel, oldGroup);
+ final GroupDialog gd = new GroupDialog(frame, oldGroup);
gd.setVisible(true);
if (gd.okPressed()) {
AbstractGroup newGroup = gd.getResultingGroup();
@@ -792,7 +803,6 @@ public class GroupSelector extends SidePaneComponent implements TreeSelectionLis
UndoableModifyGroup undo = new UndoableModifyGroup(GroupSelector.this, groupsRoot, node, newGroup);
Optional<EntriesGroupChange> addChange = node.getNode().setGroup(newGroup, keepPreviousAssignments,
panel.getDatabase().getEntries());
- panel.getBibDatabaseContext().getMetaData().postChange();
if (addChange.isPresent()) {
undoAddPreviousEntries = UndoableChangeEntriesOfGroup.getUndoableEdit(null, addChange.get());
}
@@ -824,7 +834,7 @@ public class GroupSelector extends SidePaneComponent implements TreeSelectionLis
@Override
public void actionPerformed(ActionEvent e) {
- final GroupDialog gd = new GroupDialog(frame, panel, null);
+ final GroupDialog gd = new GroupDialog(frame, null);
gd.setVisible(true);
if (!gd.okPressed()) {
return; // ignore
@@ -855,7 +865,7 @@ public class GroupSelector extends SidePaneComponent implements TreeSelectionLis
@Override
public void actionPerformed(ActionEvent e) {
- final GroupDialog gd = new GroupDialog(frame, panel, null);
+ final GroupDialog gd = new GroupDialog(frame, null);
gd.setVisible(true);
if (!gd.okPressed()) {
return; // ignore
@@ -871,7 +881,6 @@ public class GroupSelector extends SidePaneComponent implements TreeSelectionLis
panel.getUndoManager().addEdit(undo);
panel.markBaseChanged();
frame.output(Localization.lang("Added group \"%0\".", newGroup.getName()));
- panel.getBibDatabaseContext().getMetaData().postChange();
}
}
@@ -896,7 +905,6 @@ public class GroupSelector extends SidePaneComponent implements TreeSelectionLis
panel.getUndoManager().addEdit(undo);
panel.markBaseChanged();
frame.output(Localization.lang("Removed group \"%0\" and its subgroups.", group.getName()));
- panel.getBibDatabaseContext().getMetaData().postChange();
}
}
}
@@ -922,7 +930,6 @@ public class GroupSelector extends SidePaneComponent implements TreeSelectionLis
panel.getUndoManager().addEdit(undo);
panel.markBaseChanged();
frame.output(Localization.lang("Removed all subgroups of group \"%0\".", node.getName()));
- panel.getBibDatabaseContext().getMetaData().postChange();
}
}
}
@@ -950,7 +957,6 @@ public class GroupSelector extends SidePaneComponent implements TreeSelectionLis
panel.getUndoManager().addEdit(undo);
panel.markBaseChanged();
frame.output(Localization.lang("Removed group \"%0\".", group.getName()));
- panel.getBibDatabaseContext().getMetaData().postChange();
}
}
}
@@ -976,7 +982,6 @@ public class GroupSelector extends SidePaneComponent implements TreeSelectionLis
panel.getUndoManager().addEdit(undo);
panel.markBaseChanged();
frame.output(Localization.lang("Sorted immediate subgroups."));
- panel.getBibDatabaseContext().getMetaData().postChange();
}
}
@@ -995,7 +1000,6 @@ public class GroupSelector extends SidePaneComponent implements TreeSelectionLis
panel.getUndoManager().addEdit(undo);
panel.markBaseChanged();
frame.output(Localization.lang("Sorted all subgroups recursively."));
- panel.getBibDatabaseContext().getMetaData().postChange();
}
}
@@ -1212,16 +1216,17 @@ public class GroupSelector extends SidePaneComponent implements TreeSelectionLis
public void setActiveBasePanel(BasePanel panel) {
super.setActiveBasePanel(panel);
if (panel == null) { // hide groups
- frame.getSidePaneManager().hide("groups");
+ frame.getSidePaneManager().hide(GroupSelector.class);
return;
}
MetaData metaData = panel.getBibDatabaseContext().getMetaData();
- if (metaData.getGroups() == null) {
- GroupTreeNode newGroupsRoot = GroupTreeNode.fromGroup(new AllEntriesGroup());
+ if (metaData.getGroups().isPresent()) {
+ setGroups(metaData.getGroups().get());
+ } else {
+ GroupTreeNode newGroupsRoot = GroupTreeNode
+ .fromGroup(new AllEntriesGroup(Localization.lang("All entries")));
metaData.setGroups(newGroupsRoot);
setGroups(newGroupsRoot);
- } else {
- setGroups(metaData.getGroups());
}
metaData.registerListener(this);
@@ -1266,6 +1271,17 @@ public class GroupSelector extends SidePaneComponent implements TreeSelectionLis
@Subscribe
public void listen(GroupUpdatedEvent updateEvent) {
- setGroups(updateEvent.getMetaData().getGroups());
+ setGroups(updateEvent.getMetaData().getGroups().orElse(null));
}
+
+ @Override
+ public void grabFocus() {
+ groupsTree.grabFocus();
+ }
+
+ @Override
+ public ToggleAction getToggleAction() {
+ return toggleAction;
+ }
+
}
diff --git a/src/main/java/net/sf/jabref/gui/groups/GroupTreeCellRenderer.java b/src/main/java/net/sf/jabref/gui/groups/GroupTreeCellRenderer.java
index fcd12a7..7a66bc0 100644
--- a/src/main/java/net/sf/jabref/gui/groups/GroupTreeCellRenderer.java
+++ b/src/main/java/net/sf/jabref/gui/groups/GroupTreeCellRenderer.java
@@ -13,8 +13,8 @@ import javax.swing.JTree;
import javax.swing.border.Border;
import javax.swing.tree.DefaultTreeCellRenderer;
-import net.sf.jabref.logic.groups.GroupTreeNode;
-import net.sf.jabref.logic.util.strings.StringUtil;
+import net.sf.jabref.model.groups.GroupTreeNode;
+import net.sf.jabref.model.strings.StringUtil;
/**
* Renders a GroupTreeNode using its group's getName() method, rather that its toString() method.
diff --git a/src/main/java/net/sf/jabref/gui/groups/GroupTreeNodeViewModel.java b/src/main/java/net/sf/jabref/gui/groups/GroupTreeNodeViewModel.java
index 81ccd35..fa0dca8 100644
--- a/src/main/java/net/sf/jabref/gui/groups/GroupTreeNodeViewModel.java
+++ b/src/main/java/net/sf/jabref/gui/groups/GroupTreeNodeViewModel.java
@@ -22,16 +22,25 @@ import net.sf.jabref.JabRefGUI;
import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.gui.IconTheme;
import net.sf.jabref.gui.undo.CountingUndoManager;
-import net.sf.jabref.logic.groups.AbstractGroup;
-import net.sf.jabref.logic.groups.AllEntriesGroup;
-import net.sf.jabref.logic.groups.EntriesGroupChange;
-import net.sf.jabref.logic.groups.GroupTreeNode;
-import net.sf.jabref.logic.groups.MoveGroupChange;
+import net.sf.jabref.logic.groups.GroupDescriptions;
import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.groups.AbstractGroup;
+import net.sf.jabref.model.groups.AllEntriesGroup;
+import net.sf.jabref.model.groups.EntriesGroupChange;
+import net.sf.jabref.model.groups.ExplicitGroup;
+import net.sf.jabref.model.groups.GroupTreeNode;
+import net.sf.jabref.model.groups.KeywordGroup;
+import net.sf.jabref.model.groups.MoveGroupChange;
+import net.sf.jabref.model.groups.SearchGroup;
import net.sf.jabref.preferences.JabRefPreferences;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
public class GroupTreeNodeViewModel implements Transferable, TreeNode {
+ private static final Log LOGGER = LogFactory.getLog(GroupTreeNodeViewModel.class);
+
private static final Icon GROUP_REFINING_ICON = IconTheme.JabRefIcon.GROUP_REFINING.getSmallIcon();
private static final Icon GROUP_INCLUDING_ICON = IconTheme.JabRefIcon.GROUP_INCLUDING.getSmallIcon();
private static final Icon GROUP_REGULAR_ICON = null;
@@ -43,9 +52,9 @@ public class GroupTreeNodeViewModel implements Transferable, TreeNode {
DataFlavor df = null;
try {
df = new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType
- + ";class=net.sf.jabref.logic.groups.GroupTreeNode");
+ + ";class="+GroupTreeNode.class.getCanonicalName());
} catch (ClassNotFoundException e) {
- // never happens
+ LOGGER.error("Creating DataFlavor failed. This should not happen.", e);
}
FLAVOR = df;
FLAVORS = new DataFlavor[] {GroupTreeNodeViewModel.FLAVOR};
@@ -187,9 +196,19 @@ public class GroupTreeNodeViewModel implements Transferable, TreeNode {
}
public String getDescription() {
- return "<html>"
- + node.getGroup().getShortDescription(Globals.prefs.getBoolean(JabRefPreferences.GROUP_SHOW_DYNAMIC))
- + "</html>";
+ AbstractGroup group = node.getGroup();
+ String shortDescription = "";
+ boolean showDynamic = Globals.prefs.getBoolean(JabRefPreferences.GROUP_SHOW_DYNAMIC);
+ if (group instanceof ExplicitGroup) {
+ shortDescription = GroupDescriptions.getShortDescriptionExplicitGroup((ExplicitGroup) group);
+ } else if (group instanceof KeywordGroup) {
+ shortDescription = GroupDescriptions.getShortDescriptionKeywordGroup((KeywordGroup) group, showDynamic);
+ } else if (group instanceof SearchGroup) {
+ shortDescription = GroupDescriptions.getShortDescription((SearchGroup) group, showDynamic);
+ } else {
+ shortDescription = GroupDescriptions.getShortDescriptionAllEntriesGroup();
+ }
+ return "<html>" + shortDescription + "</html>";
}
public Icon getIcon() {
diff --git a/src/main/java/net/sf/jabref/gui/groups/GroupsTree.java b/src/main/java/net/sf/jabref/gui/groups/GroupsTree.java
index eea297d..c07093a 100644
--- a/src/main/java/net/sf/jabref/gui/groups/GroupsTree.java
+++ b/src/main/java/net/sf/jabref/gui/groups/GroupsTree.java
@@ -33,12 +33,11 @@ import javax.swing.ToolTipManager;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
-import net.sf.jabref.gui.util.GUIUtil;
-import net.sf.jabref.logic.groups.AbstractGroup;
-import net.sf.jabref.logic.groups.EntriesGroupChange;
-import net.sf.jabref.logic.groups.GroupTreeNode;
-import net.sf.jabref.logic.groups.MoveGroupChange;
import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.groups.AbstractGroup;
+import net.sf.jabref.model.groups.EntriesGroupChange;
+import net.sf.jabref.model.groups.GroupTreeNode;
+import net.sf.jabref.model.groups.MoveGroupChange;
public class GroupsTree extends JTree implements DragSourceListener,
DropTargetListener, DragGestureListener {
@@ -81,8 +80,6 @@ public class GroupsTree extends JTree implements DragSourceListener,
* @param groupSelector the parent UI component
*/
public GroupsTree(GroupSelector groupSelector) {
- GUIUtil.correctRowHeight(this);
-
this.groupSelector = groupSelector;
DragGestureRecognizer dgr = DragSource.getDefaultDragSource()
.createDefaultDragGestureRecognizer(this,
@@ -168,7 +165,7 @@ public class GroupsTree extends JTree implements DragSourceListener,
} else if (dtde
.isDataFlavorSupported(TransferableEntrySelection.FLAVOR_INTERNAL)) {
// check if node accepts explicit assignment
- if (path == null) {
+ if (target == null) {
dtde.rejectDrag();
} else {
// this would be the place to check if the dragging entries
diff --git a/src/main/java/net/sf/jabref/gui/groups/RemoveFromGroupAction.java b/src/main/java/net/sf/jabref/gui/groups/RemoveFromGroupAction.java
index e259597..9275f8a 100644
--- a/src/main/java/net/sf/jabref/gui/groups/RemoveFromGroupAction.java
+++ b/src/main/java/net/sf/jabref/gui/groups/RemoveFromGroupAction.java
@@ -6,8 +6,8 @@ import java.util.Optional;
import javax.swing.AbstractAction;
import net.sf.jabref.gui.BasePanel;
-import net.sf.jabref.logic.groups.EntriesGroupChange;
import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.groups.EntriesGroupChange;
public class RemoveFromGroupAction extends AbstractAction {
diff --git a/src/main/java/net/sf/jabref/gui/groups/TransferableEntrySelection.java b/src/main/java/net/sf/jabref/gui/groups/TransferableEntrySelection.java
index c5ed6a0..23b224b 100644
--- a/src/main/java/net/sf/jabref/gui/groups/TransferableEntrySelection.java
+++ b/src/main/java/net/sf/jabref/gui/groups/TransferableEntrySelection.java
@@ -11,7 +11,7 @@ import java.util.stream.Collectors;
import net.sf.jabref.model.entry.BibEntry;
-class TransferableEntrySelection implements Transferable {
+public class TransferableEntrySelection implements Transferable {
public static final DataFlavor FLAVOR_INTERNAL;
private static final DataFlavor FLAVOR_EXTERNAL;
diff --git a/src/main/java/net/sf/jabref/gui/groups/UndoableAddOrRemoveGroup.java b/src/main/java/net/sf/jabref/gui/groups/UndoableAddOrRemoveGroup.java
index 25db236..6b7d8aa 100644
--- a/src/main/java/net/sf/jabref/gui/groups/UndoableAddOrRemoveGroup.java
+++ b/src/main/java/net/sf/jabref/gui/groups/UndoableAddOrRemoveGroup.java
@@ -3,8 +3,8 @@ package net.sf.jabref.gui.groups;
import java.util.List;
import net.sf.jabref.gui.undo.AbstractUndoableJabRefEdit;
-import net.sf.jabref.logic.groups.GroupTreeNode;
import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.groups.GroupTreeNode;
class UndoableAddOrRemoveGroup extends AbstractUndoableJabRefEdit {
diff --git a/src/main/java/net/sf/jabref/gui/groups/UndoableChangeAssignment.java b/src/main/java/net/sf/jabref/gui/groups/UndoableChangeAssignment.java
index 521eeeb..e472f08 100644
--- a/src/main/java/net/sf/jabref/gui/groups/UndoableChangeAssignment.java
+++ b/src/main/java/net/sf/jabref/gui/groups/UndoableChangeAssignment.java
@@ -6,9 +6,9 @@ import java.util.Optional;
import java.util.Set;
import net.sf.jabref.gui.undo.AbstractUndoableJabRefEdit;
-import net.sf.jabref.logic.groups.GroupTreeNode;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.groups.GroupTreeNode;
/**
* @author jzieren
diff --git a/src/main/java/net/sf/jabref/gui/groups/UndoableChangeEntriesOfGroup.java b/src/main/java/net/sf/jabref/gui/groups/UndoableChangeEntriesOfGroup.java
index 3104404..9ff1a71 100644
--- a/src/main/java/net/sf/jabref/gui/groups/UndoableChangeEntriesOfGroup.java
+++ b/src/main/java/net/sf/jabref/gui/groups/UndoableChangeEntriesOfGroup.java
@@ -4,9 +4,9 @@ import javax.swing.undo.AbstractUndoableEdit;
import net.sf.jabref.gui.undo.NamedCompound;
import net.sf.jabref.gui.undo.UndoableFieldChange;
-import net.sf.jabref.logic.groups.EntriesGroupChange;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.model.FieldChange;
+import net.sf.jabref.model.groups.EntriesGroupChange;
public class UndoableChangeEntriesOfGroup {
diff --git a/src/main/java/net/sf/jabref/gui/groups/UndoableModifyGroup.java b/src/main/java/net/sf/jabref/gui/groups/UndoableModifyGroup.java
index cff6cb5..9bd6b91 100644
--- a/src/main/java/net/sf/jabref/gui/groups/UndoableModifyGroup.java
+++ b/src/main/java/net/sf/jabref/gui/groups/UndoableModifyGroup.java
@@ -3,9 +3,9 @@ package net.sf.jabref.gui.groups;
import java.util.List;
import net.sf.jabref.gui.undo.AbstractUndoableJabRefEdit;
-import net.sf.jabref.logic.groups.AbstractGroup;
-import net.sf.jabref.logic.groups.GroupTreeNode;
import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.groups.AbstractGroup;
+import net.sf.jabref.model.groups.GroupTreeNode;
class UndoableModifyGroup extends AbstractUndoableJabRefEdit {
diff --git a/src/main/java/net/sf/jabref/gui/groups/UndoableModifySubtree.java b/src/main/java/net/sf/jabref/gui/groups/UndoableModifySubtree.java
index 6dbd905..1a18a45 100644
--- a/src/main/java/net/sf/jabref/gui/groups/UndoableModifySubtree.java
+++ b/src/main/java/net/sf/jabref/gui/groups/UndoableModifySubtree.java
@@ -4,7 +4,7 @@ import java.util.List;
import java.util.Vector;
import net.sf.jabref.gui.undo.AbstractUndoableJabRefEdit;
-import net.sf.jabref.logic.groups.GroupTreeNode;
+import net.sf.jabref.model.groups.GroupTreeNode;
public class UndoableModifySubtree extends AbstractUndoableJabRefEdit {
diff --git a/src/main/java/net/sf/jabref/gui/groups/UndoableMoveGroup.java b/src/main/java/net/sf/jabref/gui/groups/UndoableMoveGroup.java
index e7ea82f..323fd85 100644
--- a/src/main/java/net/sf/jabref/gui/groups/UndoableMoveGroup.java
+++ b/src/main/java/net/sf/jabref/gui/groups/UndoableMoveGroup.java
@@ -4,9 +4,9 @@ import java.util.List;
import java.util.Objects;
import net.sf.jabref.gui.undo.AbstractUndoableJabRefEdit;
-import net.sf.jabref.logic.groups.GroupTreeNode;
-import net.sf.jabref.logic.groups.MoveGroupChange;
import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.groups.GroupTreeNode;
+import net.sf.jabref.model.groups.MoveGroupChange;
/**
* @author jzieren
diff --git a/src/main/java/net/sf/jabref/gui/groups/WarnAssignmentSideEffects.java b/src/main/java/net/sf/jabref/gui/groups/WarnAssignmentSideEffects.java
index 4584bea..04fe15a 100644
--- a/src/main/java/net/sf/jabref/gui/groups/WarnAssignmentSideEffects.java
+++ b/src/main/java/net/sf/jabref/gui/groups/WarnAssignmentSideEffects.java
@@ -7,11 +7,11 @@ import java.util.List;
import javax.swing.JOptionPane;
-import net.sf.jabref.logic.groups.AbstractGroup;
-import net.sf.jabref.logic.groups.KeywordGroup;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.model.entry.FieldName;
import net.sf.jabref.model.entry.InternalBibtexFields;
+import net.sf.jabref.model.groups.AbstractGroup;
+import net.sf.jabref.model.groups.KeywordGroup;
public class WarnAssignmentSideEffects {
diff --git a/src/main/java/net/sf/jabref/gui/help/AboutAction.java b/src/main/java/net/sf/jabref/gui/help/AboutAction.java
index 7646425..7f9b9c4 100644
--- a/src/main/java/net/sf/jabref/gui/help/AboutAction.java
+++ b/src/main/java/net/sf/jabref/gui/help/AboutAction.java
@@ -1,5 +1,6 @@
package net.sf.jabref.gui.help;
+import java.awt.Frame;
import java.awt.event.ActionEvent;
import javax.swing.Action;
@@ -8,17 +9,18 @@ import javax.swing.Icon;
import net.sf.jabref.gui.actions.MnemonicAwareAction;
public class AboutAction extends MnemonicAwareAction {
- private final AboutDialog dialog;
+ private final Frame parentFrame;
- public AboutAction(String title, AboutDialog dialog, String tooltip, Icon iconFile) {
+ public AboutAction(String title, Frame parentFrame, String tooltip, Icon iconFile) {
super(iconFile);
putValue(Action.NAME, title);
putValue(Action.SHORT_DESCRIPTION, tooltip);
- this.dialog = dialog;
+ this.parentFrame = parentFrame;
}
@Override
public void actionPerformed(ActionEvent e) {
+ AboutDialog dialog = new AboutDialog(parentFrame);
dialog.setVisible(true);
}
}
diff --git a/src/main/java/net/sf/jabref/gui/help/AboutDialog.java b/src/main/java/net/sf/jabref/gui/help/AboutDialog.java
index fdcdc26..3195a7a 100644
--- a/src/main/java/net/sf/jabref/gui/help/AboutDialog.java
+++ b/src/main/java/net/sf/jabref/gui/help/AboutDialog.java
@@ -4,6 +4,7 @@ import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
+import java.awt.Frame;
import java.util.Objects;
import javax.swing.Box;
@@ -21,16 +22,15 @@ import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;
import net.sf.jabref.Globals;
-import net.sf.jabref.gui.JabRefFrame;
import net.sf.jabref.gui.actions.CopyVersionToClipboardAction;
import net.sf.jabref.logic.l10n.Localization;
public class AboutDialog extends JDialog {
- public AboutDialog(JabRefFrame bf) {
- super(Objects.requireNonNull(bf), Localization.lang("About JabRef"), true);
+ public AboutDialog(Frame owner) {
+ super(Objects.requireNonNull(owner), Localization.lang("About JabRef"), true);
setSize(new Dimension(750, 600));
- setLocationRelativeTo(bf);
+ setLocationRelativeTo(owner);
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
@@ -74,8 +74,8 @@ public class AboutDialog extends JDialog {
String text = String.format("%n2003-%s%n%s%n%s%n%nDevelopers: %s%n%nAuthors: %s%n%nExternal Libraries: %s%nCode: %s",
Globals.BUILD_INFO.getYear(),
- "http://www.jabref.org",
- "GNU General Public License v2 or later",
+ "https://www.jabref.org",
+ "MIT License",
Globals.BUILD_INFO.getDevelopers(),
Globals.BUILD_INFO.getAuthors(),
"https://github.com/JabRef/jabref/blob/master/external-libraries.txt",
diff --git a/src/main/java/net/sf/jabref/gui/help/HelpAction.java b/src/main/java/net/sf/jabref/gui/help/HelpAction.java
index 33dea5b..9ea1e91 100644
--- a/src/main/java/net/sf/jabref/gui/help/HelpAction.java
+++ b/src/main/java/net/sf/jabref/gui/help/HelpAction.java
@@ -6,6 +6,10 @@ import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
import javax.swing.Action;
import javax.swing.Icon;
@@ -27,6 +31,12 @@ import net.sf.jabref.preferences.JabRefPreferences;
*/
public class HelpAction extends MnemonicAwareAction {
+ /**
+ * New languages of the help have to be added here
+ */
+ private static final Set<String> avaiableLangFiles = Stream.of("en", "de", "fr", "in", "ja")
+ .collect(Collectors.toCollection(HashSet::new));
+
private HelpFile helpPage;
@@ -67,6 +77,7 @@ public class HelpAction extends MnemonicAwareAction {
helpLabel.setForeground(Color.BLUE);
helpLabel.setCursor(new Cursor(Cursor.HAND_CURSOR));
helpLabel.addMouseListener(new MouseAdapter() {
+
@Override
public void mouseClicked(MouseEvent e) {
openHelpPage();
@@ -85,7 +96,16 @@ public class HelpAction extends MnemonicAwareAction {
}
private void openHelpPage() {
- String url = "https://help.jabref.org/" + Globals.prefs.get(JabRefPreferences.LANGUAGE) + "/" + helpPage.getPageName();
- JabRefDesktop.openBrowserShowPopup(url);
+ String lang = Globals.prefs.get(JabRefPreferences.LANGUAGE);
+ StringBuilder sb = new StringBuilder("https://help.jabref.org/");
+
+ if (avaiableLangFiles.contains(lang)) {
+ sb.append(lang);
+ sb.append("/");
+ } else {
+ sb.append("en/");
+ }
+ sb.append(helpPage.getPageName());
+ JabRefDesktop.openBrowserShowPopup(sb.toString());
}
}
diff --git a/src/main/java/net/sf/jabref/gui/help/NewVersionDialog.java b/src/main/java/net/sf/jabref/gui/help/NewVersionDialog.java
index 6b1c187..3c1451e 100644
--- a/src/main/java/net/sf/jabref/gui/help/NewVersionDialog.java
+++ b/src/main/java/net/sf/jabref/gui/help/NewVersionDialog.java
@@ -21,7 +21,7 @@ import net.sf.jabref.preferences.VersionPreferences;
public class NewVersionDialog extends JDialog {
- public NewVersionDialog(JFrame frame, Version currentVersion, Version latestVersion, Version toBeIgnored) {
+ public NewVersionDialog(JFrame frame, Version currentVersion, Version latestVersion) {
super(frame);
setTitle(Localization.lang("New version available"));
@@ -41,7 +41,7 @@ public class NewVersionDialog extends JDialog {
JButton btnIgnoreUpdate = new JButton(Localization.lang("Ignore this update"));
btnIgnoreUpdate.addActionListener(e -> {
- new VersionPreferences(Globals.prefs).setAsIgnoredVersion(toBeIgnored);
+ Globals.prefs.storeVersionPreferences(new VersionPreferences(latestVersion));
dispose();
});
diff --git a/src/main/java/net/sf/jabref/gui/importer/EntryFromExternalFileCreator.java b/src/main/java/net/sf/jabref/gui/importer/EntryFromExternalFileCreator.java
index 36675ff..1ec4f33 100644
--- a/src/main/java/net/sf/jabref/gui/importer/EntryFromExternalFileCreator.java
+++ b/src/main/java/net/sf/jabref/gui/importer/EntryFromExternalFileCreator.java
@@ -3,7 +3,7 @@ package net.sf.jabref.gui.importer;
import java.io.File;
import java.util.Optional;
-import net.sf.jabref.external.ExternalFileType;
+import net.sf.jabref.gui.externalfiletype.ExternalFileType;
import net.sf.jabref.model.entry.BibEntry;
/** EntryCreator for any predefined ExternalFileType.
diff --git a/src/main/java/net/sf/jabref/gui/importer/EntryFromFileCreator.java b/src/main/java/net/sf/jabref/gui/importer/EntryFromFileCreator.java
index 9adb7e5..0118939 100644
--- a/src/main/java/net/sf/jabref/gui/importer/EntryFromFileCreator.java
+++ b/src/main/java/net/sf/jabref/gui/importer/EntryFromFileCreator.java
@@ -6,11 +6,12 @@ import java.util.List;
import java.util.Optional;
import java.util.StringTokenizer;
+import net.sf.jabref.Globals;
import net.sf.jabref.JabRefGUI;
-import net.sf.jabref.external.ExternalFileType;
-import net.sf.jabref.external.ExternalFileTypes;
-import net.sf.jabref.gui.FileListEntry;
-import net.sf.jabref.gui.FileListTableModel;
+import net.sf.jabref.gui.externalfiletype.ExternalFileType;
+import net.sf.jabref.gui.externalfiletype.ExternalFileTypes;
+import net.sf.jabref.gui.filelist.FileListEntry;
+import net.sf.jabref.gui.filelist.FileListTableModel;
import net.sf.jabref.logic.util.io.FileUtil;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.FieldName;
@@ -140,7 +141,8 @@ public abstract class EntryFromFileCreator implements FileFilter {
Optional<ExternalFileType> fileType = ExternalFileTypes.getInstance()
.getExternalFileTypeByExt(externalFileType.getFieldName());
- List<String> possibleFilePaths = JabRefGUI.getMainFrame().getCurrentBasePanel().getBibDatabaseContext().getFileDirectory();
+ List<String> possibleFilePaths = JabRefGUI.getMainFrame().getCurrentBasePanel().getBibDatabaseContext()
+ .getFileDirectories(Globals.prefs.getFileDirectoryPreferences());
File shortenedFileName = FileUtil.shortenFileName(file, possibleFilePaths);
FileListEntry fileListEntry = new FileListEntry("", shortenedFileName.getPath(), fileType);
@@ -154,7 +156,7 @@ public abstract class EntryFromFileCreator implements FileFilter {
if ((value == null) || value.isEmpty()) {
return;
}
- Optional<String> oVal = entry.getFieldOptional(field);
+ Optional<String> oVal = entry.getField(field);
if (oVal.isPresent()) {
// TODO: find Jabref constant for delimter
if (!oVal.get().contains(value)) {
@@ -175,7 +177,7 @@ public abstract class EntryFromFileCreator implements FileFilter {
protected void addEntryDataToEntry(BibEntry entry, BibEntry e) {
for (String field : e.getFieldNames()) {
- e.getFieldOptional(field).ifPresent(fieldContent -> appendToField(entry, field, fieldContent));
+ e.getField(field).ifPresent(fieldContent -> appendToField(entry, field, fieldContent));
}
}
diff --git a/src/main/java/net/sf/jabref/gui/importer/EntryFromFileCreatorManager.java b/src/main/java/net/sf/jabref/gui/importer/EntryFromFileCreatorManager.java
index 7fdd1cf..68854a9 100644
--- a/src/main/java/net/sf/jabref/gui/importer/EntryFromFileCreatorManager.java
+++ b/src/main/java/net/sf/jabref/gui/importer/EntryFromFileCreatorManager.java
@@ -12,9 +12,9 @@ import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.undo.CompoundEdit;
-import net.sf.jabref.external.ExternalFileType;
-import net.sf.jabref.external.ExternalFileTypes;
import net.sf.jabref.gui.BasePanel;
+import net.sf.jabref.gui.externalfiletype.ExternalFileType;
+import net.sf.jabref.gui.externalfiletype.ExternalFileTypes;
import net.sf.jabref.gui.undo.UndoableInsertEntry;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.model.database.BibDatabase;
diff --git a/src/main/java/net/sf/jabref/gui/importer/EntryFromPDFCreator.java b/src/main/java/net/sf/jabref/gui/importer/EntryFromPDFCreator.java
index dca09b3..23e06fb 100644
--- a/src/main/java/net/sf/jabref/gui/importer/EntryFromPDFCreator.java
+++ b/src/main/java/net/sf/jabref/gui/importer/EntryFromPDFCreator.java
@@ -11,10 +11,9 @@ import java.util.Optional;
import net.sf.jabref.Globals;
import net.sf.jabref.JabRefGUI;
-import net.sf.jabref.external.ExternalFileType;
-import net.sf.jabref.external.ExternalFileTypes;
import net.sf.jabref.gui.IconTheme;
-import net.sf.jabref.logic.xmp.XMPPreferences;
+import net.sf.jabref.gui.externalfiletype.ExternalFileType;
+import net.sf.jabref.gui.externalfiletype.ExternalFileTypes;
import net.sf.jabref.logic.xmp.XMPUtil;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.pdfimport.PdfImporter;
@@ -97,7 +96,7 @@ public class EntryFromPDFCreator extends EntryFromFileCreator {
Calendar creationDate = pdfDocInfo.getCreationDate();
if (creationDate != null) {
// default time stamp follows ISO-8601. Reason: https://xkcd.com/1179/
- String date = LocalDate.of(creationDate.YEAR, creationDate.MONTH + 1, creationDate.DAY_OF_MONTH)
+ String date = LocalDate.of(Calendar.YEAR, Calendar.MONTH + 1, Calendar.DAY_OF_MONTH)
.format(DateTimeFormatter.ISO_LOCAL_DATE);
appendToField(entry, Globals.prefs.get(JabRefPreferences.TIME_STAMP_FIELD), date);
}
@@ -123,8 +122,7 @@ public class EntryFromPDFCreator extends EntryFromFileCreator {
*/
private void addEntryDataFromXMP(File aFile, BibEntry entry) {
try {
- List<BibEntry> entrys = XMPUtil.readXMP(aFile.getAbsoluteFile(),
- XMPPreferences.fromPreferences(Globals.prefs));
+ List<BibEntry> entrys = XMPUtil.readXMP(aFile.getAbsoluteFile(), Globals.prefs.getXMPPreferences());
addEntrysToEntry(entry, entrys);
} catch (IOException e) {
// no canceling here, just no data added.
diff --git a/src/main/java/net/sf/jabref/gui/importer/FetcherPreviewDialog.java b/src/main/java/net/sf/jabref/gui/importer/FetcherPreviewDialog.java
index 042e353..93683a0 100644
--- a/src/main/java/net/sf/jabref/gui/importer/FetcherPreviewDialog.java
+++ b/src/main/java/net/sf/jabref/gui/importer/FetcherPreviewDialog.java
@@ -302,4 +302,14 @@ public class FetcherPreviewDialog extends JDialog implements OutputPrinter {
public void showMessage(String message) {
JOptionPane.showMessageDialog(this, message);
}
+
+ /**
+ * Displays a dialog which tells the user that an error occurred while fetching entries
+ */
+ public void showErrorMessage(String fetcherTitle, String localizedMessage) {
+ showMessage(Localization.lang("Error while fetching from %0", fetcherTitle) + "\n" +
+ Localization.lang("Please try again later and/or check your network connection.") + "\n" +
+ localizedMessage,
+ Localization.lang("Search %0", fetcherTitle), JOptionPane.ERROR_MESSAGE);
+ }
}
diff --git a/src/main/java/net/sf/jabref/gui/importer/ImportCustomizationDialog.java b/src/main/java/net/sf/jabref/gui/importer/ImportCustomizationDialog.java
index ec3a367..6ba28b7 100644
--- a/src/main/java/net/sf/jabref/gui/importer/ImportCustomizationDialog.java
+++ b/src/main/java/net/sf/jabref/gui/importer/ImportCustomizationDialog.java
@@ -23,6 +23,7 @@ import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
+import javax.swing.ScrollPaneConstants;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableColumnModel;
@@ -31,15 +32,10 @@ import net.sf.jabref.gui.FileDialog;
import net.sf.jabref.gui.JabRefFrame;
import net.sf.jabref.gui.help.HelpAction;
import net.sf.jabref.gui.keyboard.KeyBinding;
-import net.sf.jabref.gui.util.FocusRequester;
-import net.sf.jabref.gui.util.GUIUtil;
import net.sf.jabref.logic.help.HelpFile;
-import net.sf.jabref.logic.importer.ImportFormatPreferences;
import net.sf.jabref.logic.importer.fileformat.CustomImporter;
-import net.sf.jabref.logic.importer.fileformat.ImportFormat;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.util.FileExtensions;
-import net.sf.jabref.logic.xmp.XMPPreferences;
import com.jgoodies.forms.builder.ButtonBarBuilder;
import org.apache.commons.logging.Log;
@@ -70,33 +66,29 @@ public class ImportCustomizationDialog extends JDialog {
cm.getColumn(1).setPreferredWidth(COL_1_WIDTH);
cm.getColumn(2).setPreferredWidth(COL_2_WIDTH);
cm.getColumn(3).setPreferredWidth(COL_3_WIDTH);
- JScrollPane sp = new JScrollPane(customImporterTable, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
- JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
+ JScrollPane sp = new JScrollPane(customImporterTable, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
+ ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
customImporterTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
customImporterTable.setPreferredScrollableViewportSize(getSize());
if (customImporterTable.getRowCount() > 0) {
customImporterTable.setRowSelectionInterval(0, 0);
}
- GUIUtil.correctRowHeight(customImporterTable);
-
JButton addFromFolderButton = new JButton(Localization.lang("Add from folder"));
addFromFolderButton.addActionListener(e -> {
- CustomImporter importer = new CustomImporter();
FileDialog dialog = new FileDialog(frame).withExtension(FileExtensions.CLASS);
dialog.setDefaultExtension(FileExtensions.CLASS);
Optional<Path> selectedFile = dialog.showDialogAndGetSelectedFile();
if (selectedFile.isPresent() && (selectedFile.get().getParent() != null)) {
- importer.setBasePath(selectedFile.get().getParent().toString());
-
- String chosenFileStr = selectedFile.toString();
+ String chosenFileStr = selectedFile.get().toString();
try {
- importer.setClassName(pathToClass(importer.getFileFromBasePath(), new File(chosenFileStr)));
- importer.setName(importer.getInstance().getFormatName());
- importer.setCliId(importer.getInstance().getId());
+ String basePath = selectedFile.get().getParent().toString();
+ String className = pathToClass(basePath, new File(chosenFileStr));
+ CustomImporter importer = new CustomImporter(basePath, className);
+
addOrReplaceImporter(importer);
customImporterTable.revalidate();
customImporterTable.repaint();
@@ -110,7 +102,7 @@ public class ImportCustomizationDialog extends JDialog {
}
});
addFromFolderButton
- .setToolTipText(Localization.lang("Add a (compiled) custom ImportFormat class from a class path.")
+ .setToolTipText(Localization.lang("Add a (compiled) custom Importer class from a class path.")
+ "\n" + Localization.lang("The path need not be on the classpath of JabRef."));
JButton addFromJarButton = new JButton(Localization.lang("Add from JAR"));
@@ -139,7 +131,7 @@ public class ImportCustomizationDialog extends JDialog {
}
});
addFromJarButton
- .setToolTipText(Localization.lang("Add a (compiled) custom ImportFormat class from a ZIP-archive.")
+ .setToolTipText(Localization.lang("Add a (compiled) custom Importer class from a ZIP-archive.")
+ "\n" + Localization.lang("The ZIP-archive need not be on the classpath of JabRef."));
JButton showDescButton = new JButton(Localization.lang("Show description"));
@@ -149,14 +141,7 @@ public class ImportCustomizationDialog extends JDialog {
JOptionPane.showMessageDialog(frame, Localization.lang("Please select an importer."));
} else {
CustomImporter importer = ((ImportTableModel) customImporterTable.getModel()).getImporter(row);
- try {
- ImportFormat importFormat = importer.getInstance();
- JOptionPane.showMessageDialog(frame, importFormat.getDescription());
- } catch (IOException | ClassNotFoundException | InstantiationException | IllegalAccessException exc) {
- LOGGER.warn("Could not instantiate importer " + importer.getName(), exc);
- JOptionPane.showMessageDialog(frame, Localization.lang("Could not instantiate %0 %1",
- importer.getName() + ":\n", exc.getMessage()));
- }
+ JOptionPane.showMessageDialog(frame, importer.getDescription());
}
});
@@ -169,8 +154,8 @@ public class ImportCustomizationDialog extends JDialog {
customImporterTable.removeRowSelectionInterval(row, row);
Globals.prefs.customImports
.remove(((ImportTableModel) customImporterTable.getModel()).getImporter(row));
- Globals.IMPORT_FORMAT_READER.resetImportFormats(ImportFormatPreferences.fromPreferences(Globals.prefs),
- XMPPreferences.fromPreferences(Globals.prefs));
+ Globals.IMPORT_FORMAT_READER.resetImportFormats(Globals.prefs.getImportFormatPreferences(),
+ Globals.prefs.getXMPPreferences());
customImporterTable.revalidate();
customImporterTable.repaint();
}
@@ -215,7 +200,7 @@ public class ImportCustomizationDialog extends JDialog {
this.setSize(getSize());
pack();
this.setLocationRelativeTo(frame);
- new FocusRequester(customImporterTable);
+ customImporterTable.requestFocus();
}
/*
@@ -235,11 +220,11 @@ public class ImportCustomizationDialog extends JDialog {
* @param path path that includes base-path as a prefix
* @return class name
*/
- private static String pathToClass(File basePath, File path) {
+ private static String pathToClass(String basePath, File path) {
String className = null;
File actualPath = path;
// remove leading basepath from path
- while (!actualPath.equals(basePath)) {
+ while (!actualPath.equals(new File(basePath))) {
className = actualPath.getName() + (className == null ? "" : "." + className);
actualPath = actualPath.getParentFile();
}
@@ -260,8 +245,8 @@ public class ImportCustomizationDialog extends JDialog {
*/
public void addOrReplaceImporter(CustomImporter importer) {
Globals.prefs.customImports.replaceImporter(importer);
- Globals.IMPORT_FORMAT_READER.resetImportFormats(ImportFormatPreferences.fromPreferences(Globals.prefs),
- XMPPreferences.fromPreferences(Globals.prefs));
+ Globals.IMPORT_FORMAT_READER.resetImportFormats(Globals.prefs.getImportFormatPreferences(),
+ Globals.prefs.getXMPPreferences());
((ImportTableModel) customImporterTable.getModel()).fireTableDataChanged();
}
@@ -272,7 +257,7 @@ public class ImportCustomizationDialog extends JDialog {
private class ImportTableModel extends AbstractTableModel {
private final String[] columnNames = new String[] {Localization.lang("Import name"),
- Localization.lang("Command line id"), Localization.lang("ImportFormat class"),
+ Localization.lang("Command line id"), Localization.lang("Importer class"),
Localization.lang("Contained in")};
@@ -283,11 +268,11 @@ public class ImportCustomizationDialog extends JDialog {
if (columnIndex == 0) {
value = importer.getName();
} else if (columnIndex == 1) {
- value = importer.getClidId();
+ value = importer.getName();
} else if (columnIndex == 2) {
value = importer.getClassName();
} else if (columnIndex == 3) {
- value = importer.getFileFromBasePath();
+ value = importer.getBasePath();
}
return value;
}
diff --git a/src/main/java/net/sf/jabref/gui/importer/ImportFileFilter.java b/src/main/java/net/sf/jabref/gui/importer/ImportFileFilter.java
index 99d3692..56b074c 100644
--- a/src/main/java/net/sf/jabref/gui/importer/ImportFileFilter.java
+++ b/src/main/java/net/sf/jabref/gui/importer/ImportFileFilter.java
@@ -9,20 +9,20 @@ import java.util.stream.Stream;
import javax.swing.filechooser.FileFilter;
import javax.swing.filechooser.FileNameExtensionFilter;
-import net.sf.jabref.logic.importer.fileformat.ImportFormat;
+import net.sf.jabref.logic.importer.Importer;
import net.sf.jabref.logic.util.FileExtensions;
class ImportFileFilter extends FileFilter implements Comparable<ImportFileFilter> {
private final String description;
private final FileNameExtensionFilter fileFilter;
- public ImportFileFilter(ImportFormat format) {
+ public ImportFileFilter(Importer format) {
FileExtensions extensions = format.getExtensions();
this.description = extensions.getDescription();
fileFilter = new FileNameExtensionFilter(extensions.getDescription(), extensions.getExtensions());
}
- public ImportFileFilter(String description, Collection<ImportFormat> formats) {
+ public ImportFileFilter(String description, Collection<Importer> formats) {
this.description = description;
List<FileExtensions> extensions = formats.stream().map(p -> p.getExtensions()).collect(Collectors.toList());
diff --git a/src/main/java/net/sf/jabref/gui/importer/ImportFormats.java b/src/main/java/net/sf/jabref/gui/importer/ImportFormats.java
index 4f3ba72..859efff 100644
--- a/src/main/java/net/sf/jabref/gui/importer/ImportFormats.java
+++ b/src/main/java/net/sf/jabref/gui/importer/ImportFormats.java
@@ -19,7 +19,7 @@ import net.sf.jabref.gui.FileDialog;
import net.sf.jabref.gui.JabRefFrame;
import net.sf.jabref.gui.actions.MnemonicAwareAction;
import net.sf.jabref.gui.keyboard.KeyBinding;
-import net.sf.jabref.logic.importer.fileformat.ImportFormat;
+import net.sf.jabref.logic.importer.Importer;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.util.FileExtensions;
import net.sf.jabref.preferences.JabRefPreferences;
@@ -59,7 +59,7 @@ public class ImportFormats {
@Override
public void actionPerformed(ActionEvent e) {
- SortedSet<ImportFormat> importers = Globals.IMPORT_FORMAT_READER.getImportFormats();
+ SortedSet<Importer> importers = Globals.IMPORT_FORMAT_READER.getImportFormats();
List<FileExtensions> extensions = importers.stream().map(p -> p.getExtensions()).collect(Collectors.toList());
FileDialog dialog = new FileDialog(frame, Globals.prefs.get(JabRefPreferences.IMPORT_WORKING_DIRECTORY));
// Add file filter for all supported types
@@ -81,7 +81,7 @@ public class ImportFormats {
return;
}
- Optional<ImportFormat> format = importers.stream()
+ Optional<Importer> format = importers.stream()
.filter(i -> Objects.equals(i.getExtensions().getDescription(), dialog.getFileFilter().getDescription()))
.findFirst();
ImportMenuItem importMenu = new ImportMenuItem(frame, newDatabase, format.orElse(null));
diff --git a/src/main/java/net/sf/jabref/gui/importer/ImportInspectionDialog.java b/src/main/java/net/sf/jabref/gui/importer/ImportInspectionDialog.java
index 0876036..e1c6a69 100644
--- a/src/main/java/net/sf/jabref/gui/importer/ImportInspectionDialog.java
+++ b/src/main/java/net/sf/jabref/gui/importer/ImportInspectionDialog.java
@@ -49,25 +49,23 @@ import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;
-import net.sf.jabref.BibDatabaseContext;
-import net.sf.jabref.Defaults;
import net.sf.jabref.Globals;
import net.sf.jabref.JabRefExecutorService;
-import net.sf.jabref.MetaData;
-import net.sf.jabref.external.DownloadExternalFile;
-import net.sf.jabref.external.ExternalFileMenuItem;
import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.gui.DuplicateResolverDialog;
import net.sf.jabref.gui.DuplicateResolverDialog.DuplicateResolverResult;
import net.sf.jabref.gui.EntryMarker;
-import net.sf.jabref.gui.FileListEntry;
-import net.sf.jabref.gui.FileListEntryEditor;
-import net.sf.jabref.gui.FileListTableModel;
import net.sf.jabref.gui.GUIGlobals;
import net.sf.jabref.gui.IconTheme;
import net.sf.jabref.gui.JabRefFrame;
import net.sf.jabref.gui.PreviewPanel;
import net.sf.jabref.gui.desktop.JabRefDesktop;
+import net.sf.jabref.gui.externalfiles.AutoSetLinks;
+import net.sf.jabref.gui.externalfiles.DownloadExternalFile;
+import net.sf.jabref.gui.externalfiletype.ExternalFileMenuItem;
+import net.sf.jabref.gui.filelist.FileListEntry;
+import net.sf.jabref.gui.filelist.FileListEntryEditor;
+import net.sf.jabref.gui.filelist.FileListTableModel;
import net.sf.jabref.gui.groups.GroupTreeNodeViewModel;
import net.sf.jabref.gui.groups.UndoableChangeEntriesOfGroup;
import net.sf.jabref.gui.help.HelpAction;
@@ -76,30 +74,31 @@ import net.sf.jabref.gui.renderer.GeneralRenderer;
import net.sf.jabref.gui.undo.NamedCompound;
import net.sf.jabref.gui.undo.UndoableInsertEntry;
import net.sf.jabref.gui.undo.UndoableRemoveEntry;
-import net.sf.jabref.gui.util.GUIUtil;
import net.sf.jabref.gui.util.comparator.IconComparator;
import net.sf.jabref.gui.util.component.CheckBoxMessage;
import net.sf.jabref.logic.bibtex.comparator.FieldComparator;
-import net.sf.jabref.logic.bibtexkeypattern.BibtexKeyPatternPreferences;
import net.sf.jabref.logic.bibtexkeypattern.BibtexKeyPatternUtil;
-import net.sf.jabref.logic.groups.AllEntriesGroup;
-import net.sf.jabref.logic.groups.EntriesGroupChange;
-import net.sf.jabref.logic.groups.GroupTreeNode;
import net.sf.jabref.logic.help.HelpFile;
import net.sf.jabref.logic.importer.ImportInspector;
import net.sf.jabref.logic.importer.OutputPrinter;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.util.UpdateField;
+import net.sf.jabref.model.Defaults;
import net.sf.jabref.model.DuplicateCheck;
import net.sf.jabref.model.database.BibDatabase;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.database.BibDatabaseMode;
import net.sf.jabref.model.entry.AuthorList;
import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.model.entry.EntryUtil;
import net.sf.jabref.model.entry.FieldName;
-import net.sf.jabref.model.entry.FieldProperties;
+import net.sf.jabref.model.entry.FieldProperty;
import net.sf.jabref.model.entry.IdGenerator;
import net.sf.jabref.model.entry.InternalBibtexFields;
+import net.sf.jabref.model.groups.AllEntriesGroup;
+import net.sf.jabref.model.groups.EntriesGroupChange;
+import net.sf.jabref.model.groups.GroupTreeNode;
+import net.sf.jabref.model.metadata.MetaData;
+import net.sf.jabref.model.strings.StringUtil;
import net.sf.jabref.preferences.JabRefPreferences;
import ca.odell.glazedlists.BasicEventList;
@@ -199,7 +198,7 @@ public class ImportInspectionDialog extends JDialog implements ImportInspector,
this.undoName = undoName;
this.newDatabase = newDatabase;
setIconImage(new ImageIcon(IconTheme.getIconUrl("jabrefIcon48")).getImage());
- preview = new PreviewPanel(null, bibDatabaseContext, Globals.prefs.get(JabRefPreferences.PREVIEW_0));
+ preview = new PreviewPanel(panel, bibDatabaseContext);
duplLabel.setToolTipText(Localization.lang("Possible duplicate of existing entry. Click to resolve."));
@@ -223,8 +222,6 @@ public class ImportInspectionDialog extends JDialog implements ImportInspector,
setupComparatorChooser();
glTable.addMouseListener(new TableClickListener());
- GUIUtil.correctRowHeight(glTable);
-
setWidths();
getContentPane().setLayout(new BorderLayout());
@@ -241,7 +238,7 @@ public class ImportInspectionDialog extends JDialog implements ImportInspector,
popup.add(deleteListener);
popup.addSeparator();
if (!newDatabase && (bibDatabaseContext != null)) {
- GroupTreeNode node = bibDatabaseContext.getMetaData().getGroups();
+ GroupTreeNode node = bibDatabaseContext.getMetaData().getGroups().get();
JMenu groupsAdd = new JMenu(Localization.lang("Add to group"));
groupsAdd.setEnabled(false); // Will get enabled if there are groups that can be added to.
insertNodes(groupsAdd, node);
@@ -251,7 +248,7 @@ public class ImportInspectionDialog extends JDialog implements ImportInspector,
// Add "Attach file" menu choices to right click menu:
popup.add(new LinkLocalFile());
popup.add(new DownloadFile());
- popup.add(new AutoSetLinks());
+ popup.add(new InternalAutoSetLinks());
popup.add(new AttachUrl());
getContentPane().add(centerPan, BorderLayout.CENTER);
@@ -439,13 +436,10 @@ public class ImportInspectionDialog extends JDialog implements ImportInspector,
}
/**
- * Generate key for the selected entry only.
+ * Generate key for an entry.
*/
- private void generateKeySelectedEntry() {
- if (selectionModel.getSelected().size() != 1) {
- return;
- }
- BibEntry entry = selectionModel.getSelected().get(0);
+ private void generateKeyForEntry(BibEntry entry) {
+
entries.getReadWriteLock().writeLock().lock();
try {
BibDatabase database;
@@ -465,8 +459,10 @@ public class ImportInspectionDialog extends JDialog implements ImportInspector,
database.insertEntry(entry);
// Generate a unique key:
- BibtexKeyPatternUtil.makeLabel(localMetaData, database, entry,
- BibtexKeyPatternPreferences.fromPreferences(Globals.prefs));
+ BibtexKeyPatternUtil.makeAndSetLabel(
+ localMetaData.getCiteKeyPattern(Globals.prefs.getBibtexKeyPatternPreferences().getKeyPattern()),
+ database, entry,
+ Globals.prefs.getBibtexKeyPatternPreferences());
// Remove the entry from the database again, since we only added it in
// order to
// make sure the key was unique:
@@ -507,8 +503,10 @@ public class ImportInspectionDialog extends JDialog implements ImportInspector,
entry.setId(IdGenerator.next());
database.insertEntry(entry);
- BibtexKeyPatternUtil.makeLabel(localMetaData, database, entry,
- BibtexKeyPatternPreferences.fromPreferences(Globals.prefs));
+ BibtexKeyPatternUtil.makeAndSetLabel(
+ localMetaData.getCiteKeyPattern(Globals.prefs.getBibtexKeyPatternPreferences().getKeyPattern()),
+ database, entry,
+ Globals.prefs.getBibtexKeyPatternPreferences());
// Add the generated key to our list: -- TODO: Why??
keys.add(entry.getCiteKeyOptional());
}
@@ -912,7 +910,7 @@ public class ImportInspectionDialog extends JDialog implements ImportInspector,
if (col == FILE_COL) {
if (entry.hasField(FieldName.FILE)) {
FileListTableModel tableModel = new FileListTableModel();
- entry.getFieldOptional(FieldName.FILE).ifPresent(tableModel::setContent);
+ entry.getField(FieldName.FILE).ifPresent(tableModel::setContent);
if (tableModel.getRowCount() == 0) {
return;
}
@@ -967,7 +965,7 @@ public class ImportInspectionDialog extends JDialog implements ImportInspector,
JPopupMenu menu = new JPopupMenu();
int count = 0;
FileListTableModel fileList = new FileListTableModel();
- entry.getFieldOptional(FieldName.FILE).ifPresent(fileList::setContent);
+ entry.getField(FieldName.FILE).ifPresent(fileList::setContent);
// If there are one or more links, open the first one:
for (int i = 0; i < fileList.getRowCount(); i++) {
FileListEntry flEntry = fileList.getEntry(i);
@@ -996,7 +994,7 @@ public class ImportInspectionDialog extends JDialog implements ImportInspector,
final int row = glTable.rowAtPoint(e.getPoint());
BibEntry entry = sortedList.get(row);
- entry.getFieldOptional(fieldName).ifPresent(link -> {
+ entry.getField(fieldName).ifPresent(link -> {
try {
JabRefDesktop.openExternalViewer(panel.getBibDatabaseContext(), link, fieldName);
} catch (IOException ex) {
@@ -1134,7 +1132,7 @@ public class ImportInspectionDialog extends JDialog implements ImportInspector,
}
BibEntry entry = selectionModel.getSelected().get(0);
String result = JOptionPane.showInputDialog(ImportInspectionDialog.this, Localization.lang("Enter URL"),
- entry.getFieldOptional(FieldName.URL).orElse(""));
+ entry.getField(FieldName.URL).orElse(""));
entries.getReadWriteLock().writeLock().lock();
try {
if (result != null) {
@@ -1167,21 +1165,19 @@ public class ImportInspectionDialog extends JDialog implements ImportInspector,
return;
}
entry = selectionModel.getSelected().get(0);
- Optional<String> bibtexKey = entry.getCiteKeyOptional();
- if (!bibtexKey.isPresent()) {
+ if (!entry.getCiteKeyOptional().isPresent()) {
int answer = JOptionPane.showConfirmDialog(frame,
Localization.lang("This entry has no BibTeX key. Generate key now?"),
Localization.lang("Download file"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);
if (answer == JOptionPane.OK_OPTION) {
- generateKeySelectedEntry();
- bibtexKey = entry.getCiteKeyOptional();
+ generateKeyForEntry(entry);
}
}
- DownloadExternalFile def = new DownloadExternalFile(frame, bibDatabaseContext, bibtexKey.get());
+ DownloadExternalFile def = new DownloadExternalFile(frame, bibDatabaseContext, entry);
try {
def.download(this);
} catch (IOException ex) {
- LOGGER.warn("Could not downlod file", ex);
+ LOGGER.warn("Could not download file", ex);
}
}
@@ -1189,7 +1185,7 @@ public class ImportInspectionDialog extends JDialog implements ImportInspector,
public void downloadComplete(FileListEntry file) {
ImportInspectionDialog.this.toFront(); // Hack
FileListTableModel localModel = new FileListTableModel();
- entry.getFieldOptional(FieldName.FILE).ifPresent(localModel::setContent);
+ entry.getField(FieldName.FILE).ifPresent(localModel::setContent);
localModel.addEntry(localModel.getRowCount(), file);
entries.getReadWriteLock().writeLock().lock();
try {
@@ -1201,9 +1197,9 @@ public class ImportInspectionDialog extends JDialog implements ImportInspector,
}
}
- private class AutoSetLinks extends JMenuItem implements ActionListener {
+ private class InternalAutoSetLinks extends JMenuItem implements ActionListener {
- public AutoSetLinks() {
+ public InternalAutoSetLinks() {
super(Localization.lang("Automatically set file links"));
addActionListener(this);
}
@@ -1219,18 +1215,18 @@ public class ImportInspectionDialog extends JDialog implements ImportInspector,
Localization.lang("This entry has no BibTeX key. Generate key now?"),
Localization.lang("Download file"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);
if (answer == JOptionPane.OK_OPTION) {
- generateKeySelectedEntry();
+ generateKeyForEntry(entry);
} else {
return; // Can't go on without the bibtex key.
}
}
final FileListTableModel localModel = new FileListTableModel();
- entry.getFieldOptional(FieldName.FILE).ifPresent(localModel::setContent);
+ entry.getField(FieldName.FILE).ifPresent(localModel::setContent);
// We have a static utility method for searching for all relevant
// links:
JDialog diag = new JDialog(ImportInspectionDialog.this, true);
- JabRefExecutorService.INSTANCE.execute(
- net.sf.jabref.external.AutoSetLinks.autoSetLinks(entry, localModel, bibDatabaseContext, e -> {
+ JabRefExecutorService.INSTANCE
+ .execute(AutoSetLinks.autoSetLinks(entry, localModel, bibDatabaseContext, e -> {
if (e.getID() > 0) {
entries.getReadWriteLock().writeLock().lock();
@@ -1241,7 +1237,7 @@ public class ImportInspectionDialog extends JDialog implements ImportInspector,
}
glTable.repaint();
}
- }, diag));
+ } , diag));
}
}
@@ -1267,7 +1263,7 @@ public class ImportInspectionDialog extends JDialog implements ImportInspector,
editor.setVisible(true, true);
if (editor.okPressed()) {
FileListTableModel localModel = new FileListTableModel();
- entry.getFieldOptional(FieldName.FILE).ifPresent(localModel::setContent);
+ entry.getField(FieldName.FILE).ifPresent(localModel::setContent);
localModel.addEntry(localModel.getRowCount(), flEntry);
entries.getReadWriteLock().writeLock().lock();
try {
@@ -1283,7 +1279,7 @@ public class ImportInspectionDialog extends JDialog implements ImportInspector,
public void downloadComplete(FileListEntry file) {
ImportInspectionDialog.this.toFront(); // Hack
FileListTableModel localModel = new FileListTableModel();
- entry.getFieldOptional(FieldName.FILE).ifPresent(localModel::setContent);
+ entry.getField(FieldName.FILE).ifPresent(localModel::setContent);
localModel.addEntry(localModel.getRowCount(), file);
entries.getReadWriteLock().writeLock().lock();
try {
@@ -1414,7 +1410,7 @@ public class ImportInspectionDialog extends JDialog implements ImportInspector,
return Localization.lang("Keep");
}
if (i >= PAD) {
- return EntryUtil.capitalizeFirst(INSPECTION_FIELDS.get(i - PAD));
+ return StringUtil.capitalizeFirst(INSPECTION_FIELDS.get(i - PAD));
}
return "";
}
@@ -1430,7 +1426,7 @@ public class ImportInspectionDialog extends JDialog implements ImportInspector,
case FILE_COL:
if (entry.hasField(FieldName.FILE)) {
FileListTableModel model = new FileListTableModel();
- entry.getFieldOptional(FieldName.FILE).ifPresent(model::setContent);
+ entry.getField(FieldName.FILE).ifPresent(model::setContent);
fileLabel.setToolTipText(model.getToolTipHTMLRepresentation());
if ((model.getRowCount() > 0) && model.getEntry(0).type.isPresent()) {
fileLabel.setIcon(model.getEntry(0).type.get().getIcon());
@@ -1441,7 +1437,7 @@ public class ImportInspectionDialog extends JDialog implements ImportInspector,
}
case URL_COL:
if (entry.hasField(FieldName.URL)) {
- urlLabel.setToolTipText(entry.getFieldOptional(FieldName.URL).orElse(""));
+ urlLabel.setToolTipText(entry.getField(FieldName.URL).orElse(""));
return urlLabel;
} else {
return null;
@@ -1451,10 +1447,10 @@ public class ImportInspectionDialog extends JDialog implements ImportInspector,
}
} else {
String field = INSPECTION_FIELDS.get(i - PAD);
- if (InternalBibtexFields.getFieldExtras(field).contains(FieldProperties.PERSON_NAMES)) {
- return entry.getFieldOptional(field).map(AuthorList::fixAuthorNatbib).orElse("");
+ if (InternalBibtexFields.getFieldProperties(field).contains(FieldProperty.PERSON_NAMES)) {
+ return entry.getField(field).map(AuthorList::fixAuthorNatbib).orElse("");
} else {
- return entry.getFieldOptional(field).orElse(null);
+ return entry.getField(field).orElse(null);
}
}
}
@@ -1477,6 +1473,16 @@ public class ImportInspectionDialog extends JDialog implements ImportInspector,
JOptionPane.showMessageDialog(this, message);
}
+ /**
+ * Displays a dialog which tells the user that an error occurred while fetching entries
+ */
+ public void showErrorMessage(String fetcherTitle, String localizedException) {
+ showMessage(Localization.lang("Error while fetching from %0", fetcherTitle) + "\n" +
+ Localization.lang("Please try again later and/or check your network connection.") + "\n" +
+ localizedException,
+ Localization.lang("Search %0", fetcherTitle), JOptionPane.ERROR_MESSAGE);
+ }
+
public JabRefFrame getFrame() {
return frame;
}
diff --git a/src/main/java/net/sf/jabref/gui/importer/ImportMenuItem.java b/src/main/java/net/sf/jabref/gui/importer/ImportMenuItem.java
index 6ca6d8c..cd8e04b 100644
--- a/src/main/java/net/sf/jabref/gui/importer/ImportMenuItem.java
+++ b/src/main/java/net/sf/jabref/gui/importer/ImportMenuItem.java
@@ -19,9 +19,10 @@ import net.sf.jabref.gui.FileDialog;
import net.sf.jabref.gui.JabRefFrame;
import net.sf.jabref.gui.undo.NamedCompound;
import net.sf.jabref.gui.worker.AbstractWorker;
+import net.sf.jabref.logic.importer.ImportException;
import net.sf.jabref.logic.importer.ImportFormatReader;
+import net.sf.jabref.logic.importer.Importer;
import net.sf.jabref.logic.importer.ParserResult;
-import net.sf.jabref.logic.importer.fileformat.ImportFormat;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.util.UpdateField;
import net.sf.jabref.model.database.BibDatabase;
@@ -37,15 +38,15 @@ public class ImportMenuItem extends JMenuItem implements ActionListener {
private final JabRefFrame frame;
private final boolean openInNew;
- private final ImportFormat importer;
- private IOException importError;
+ private final Importer importer;
+ private Exception importError;
public ImportMenuItem(JabRefFrame frame, boolean openInNew) {
this(frame, openInNew, null);
}
- public ImportMenuItem(JabRefFrame frame, boolean openInNew, ImportFormat importer) {
- super(importer == null ? Localization.lang("Autodetect format") : importer.getFormatName());
+ public ImportMenuItem(JabRefFrame frame, boolean openInNew, Importer importer) {
+ super(importer == null ? Localization.lang("Autodetect format") : importer.getName());
this.importer = importer;
this.frame = frame;
this.openInNew = openInNew;
@@ -111,14 +112,14 @@ public class ImportMenuItem extends JMenuItem implements ActionListener {
// Unknown format:
frame.output(Localization.lang("Importing in unknown format") + "...");
// This import method never throws an IOException:
- imports.add(Globals.IMPORT_FORMAT_READER.importUnknownFormat(filename));
+ imports.add(Globals.IMPORT_FORMAT_READER.importUnknownFormat(file));
} else {
- frame.output(Localization.lang("Importing in %0 format", importer.getFormatName()) + "...");
+ frame.output(Localization.lang("Importing in %0 format", importer.getName()) + "...");
// Specific importer:
ParserResult pr = importer.importDatabase(file, Globals.prefs.getDefaultEncoding());
- imports.add(new ImportFormatReader.UnknownFormatImport(importer.getFormatName(), pr));
+ imports.add(new ImportFormatReader.UnknownFormatImport(importer.getName(), pr));
}
- } catch (IOException e) {
+ } catch (ImportException | IOException e) {
// This indicates that a specific importer was specified, and that
// this importer has thrown an IOException. We store the exception,
// so a relevant error message can be displayed.
diff --git a/src/main/java/net/sf/jabref/gui/importer/UnlinkedFilesCrawler.java b/src/main/java/net/sf/jabref/gui/importer/UnlinkedFilesCrawler.java
index 507ee75..cc72084 100644
--- a/src/main/java/net/sf/jabref/gui/importer/UnlinkedFilesCrawler.java
+++ b/src/main/java/net/sf/jabref/gui/importer/UnlinkedFilesCrawler.java
@@ -10,10 +10,10 @@ import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
-import net.sf.jabref.BibDatabaseContext;
import net.sf.jabref.gui.FindUnlinkedFilesDialog.CheckableTreeNode;
import net.sf.jabref.gui.FindUnlinkedFilesDialog.FileNodeWrapper;
import net.sf.jabref.model.database.BibDatabase;
+import net.sf.jabref.model.database.BibDatabaseContext;
/**
* Util class for searching files on the file system which are not linked to a provided {@link BibDatabase}.
diff --git a/src/main/java/net/sf/jabref/gui/importer/UnlinkedPDFFileFilter.java b/src/main/java/net/sf/jabref/gui/importer/UnlinkedPDFFileFilter.java
index acee257..7b71a8d 100644
--- a/src/main/java/net/sf/jabref/gui/importer/UnlinkedPDFFileFilter.java
+++ b/src/main/java/net/sf/jabref/gui/importer/UnlinkedPDFFileFilter.java
@@ -3,9 +3,11 @@ package net.sf.jabref.gui.importer;
import java.io.File;
import java.io.FileFilter;
-import net.sf.jabref.BibDatabaseContext;
+import net.sf.jabref.Globals;
import net.sf.jabref.logic.util.io.DatabaseFileLookup;
import net.sf.jabref.model.database.BibDatabase;
+import net.sf.jabref.model.database.BibDatabaseContext;
+import net.sf.jabref.model.entry.BibEntry;
/**
* {@link FileFilter} implementation, that allows only files which are not
@@ -28,7 +30,7 @@ public class UnlinkedPDFFileFilter implements FileFilter {
public UnlinkedPDFFileFilter(FileFilter fileFilter, BibDatabaseContext databaseContext) {
this.fileFilter = fileFilter;
- this.lookup = new DatabaseFileLookup(databaseContext);
+ this.lookup = new DatabaseFileLookup(databaseContext, Globals.prefs.getFileDirectoryPreferences());
}
@Override
diff --git a/src/main/java/net/sf/jabref/gui/importer/ZipFileChooser.java b/src/main/java/net/sf/jabref/gui/importer/ZipFileChooser.java
index 4bbf297..14012da 100644
--- a/src/main/java/net/sf/jabref/gui/importer/ZipFileChooser.java
+++ b/src/main/java/net/sf/jabref/gui/importer/ZipFileChooser.java
@@ -2,7 +2,6 @@ package net.sf.jabref.gui.importer;
import java.awt.BorderLayout;
import java.awt.Dimension;
-import java.io.IOException;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
@@ -24,13 +23,11 @@ import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
+import javax.swing.ScrollPaneConstants;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableColumnModel;
-import net.sf.jabref.gui.util.FocusRequester;
-import net.sf.jabref.gui.util.GUIUtil;
import net.sf.jabref.logic.importer.fileformat.CustomImporter;
-import net.sf.jabref.logic.importer.fileformat.ImportFormat;
import net.sf.jabref.logic.l10n.Localization;
import org.apache.commons.logging.Log;
@@ -62,14 +59,13 @@ class ZipFileChooser extends JDialog {
cm.getColumn(0).setPreferredWidth(200);
cm.getColumn(1).setPreferredWidth(150);
cm.getColumn(2).setPreferredWidth(100);
- JScrollPane sp = new JScrollPane(table, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
- JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
+ JScrollPane sp = new JScrollPane(table, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
+ ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
table.setPreferredScrollableViewportSize(new Dimension(500, 150));
if (table.getRowCount() > 0) {
table.setRowSelectionInterval(0, 0);
}
- GUIUtil.correctRowHeight(table);
// cancel: no entry is selected
JButton cancelButton = new JButton(Localization.lang("Cancel"));
@@ -83,21 +79,17 @@ class ZipFileChooser extends JDialog {
} else {
ZipFileChooserTableModel model = (ZipFileChooserTableModel) table.getModel();
ZipEntry tempZipEntry = model.getZipEntry(row);
- CustomImporter importer = new CustomImporter();
- importer.setBasePath(model.getZipFile().getName());
- String className = tempZipEntry.getName().substring(0, tempZipEntry.getName().lastIndexOf('.'))
- .replace("/", ".");
- importer.setClassName(className);
+ String className = tempZipEntry.getName().substring(0, tempZipEntry.getName().lastIndexOf('.')).replace(
+ "/", ".");
+
try {
- ImportFormat importFormat = importer.getInstance();
- importer.setName(importFormat.getFormatName());
- importer.setCliId(importFormat.getId());
+ CustomImporter importer = new CustomImporter(model.getZipFile().getName(), className);
importCustomizationDialog.addOrReplaceImporter(importer);
dispose();
- } catch (IOException | ClassNotFoundException | InstantiationException | IllegalAccessException exc) {
- LOGGER.warn("Could not instantiate importer: " + importer.getName(), exc);
+ } catch (ClassNotFoundException exc) {
+ LOGGER.warn("Could not instantiate importer: " + className, exc);
JOptionPane.showMessageDialog(this, Localization.lang("Could not instantiate %0 %1",
- importer.getName() + ":\n", exc.getMessage()));
+ className + ":\n", exc.getMessage()));
}
}
});
@@ -122,7 +114,7 @@ class ZipFileChooser extends JDialog {
this.setSize(getSize());
pack();
this.setLocationRelativeTo(importCustomizationDialog);
- new FocusRequester(table);
+ table.requestFocus();
}
/**
diff --git a/src/main/java/net/sf/jabref/gui/importer/actions/AppendDatabaseAction.java b/src/main/java/net/sf/jabref/gui/importer/actions/AppendDatabaseAction.java
index 894967c..6114524 100644
--- a/src/main/java/net/sf/jabref/gui/importer/actions/AppendDatabaseAction.java
+++ b/src/main/java/net/sf/jabref/gui/importer/actions/AppendDatabaseAction.java
@@ -9,7 +9,6 @@ import javax.swing.JOptionPane;
import net.sf.jabref.Globals;
import net.sf.jabref.JabRefExecutorService;
-import net.sf.jabref.MetaData;
import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.gui.FileDialog;
import net.sf.jabref.gui.JabRefFrame;
@@ -18,14 +17,8 @@ import net.sf.jabref.gui.actions.BaseAction;
import net.sf.jabref.gui.undo.NamedCompound;
import net.sf.jabref.gui.undo.UndoableInsertEntry;
import net.sf.jabref.gui.undo.UndoableInsertString;
-import net.sf.jabref.logic.groups.AllEntriesGroup;
-import net.sf.jabref.logic.groups.ExplicitGroup;
-import net.sf.jabref.logic.groups.GroupHierarchyType;
-import net.sf.jabref.logic.groups.GroupTreeNode;
-import net.sf.jabref.logic.importer.ImportFormatPreferences;
import net.sf.jabref.logic.importer.OpenDatabase;
import net.sf.jabref.logic.importer.ParserResult;
-import net.sf.jabref.logic.importer.util.ParseException;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.util.FileExtensions;
import net.sf.jabref.logic.util.UpdateField;
@@ -34,6 +27,10 @@ import net.sf.jabref.model.database.KeyCollisionException;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.BibtexString;
import net.sf.jabref.model.entry.IdGenerator;
+import net.sf.jabref.model.groups.AllEntriesGroup;
+import net.sf.jabref.model.groups.ExplicitGroup;
+import net.sf.jabref.model.groups.GroupHierarchyType;
+import net.sf.jabref.model.metadata.MetaData;
import net.sf.jabref.preferences.JabRefPreferences;
import org.apache.commons.logging.Log;
@@ -73,13 +70,12 @@ public class AppendDatabaseAction implements BaseAction {
// Run the actual open in a thread to prevent the program
// locking until the file is loaded.
JabRefExecutorService.INSTANCE.execute(
- () -> openIt(md.importEntries(), md.importStrings(), md.importGroups(), md.importSelectorWords()));
+ () -> openIt(md.importEntries(), md.importStrings(), md.importGroups()));
}
}
- private void openIt(boolean importEntries, boolean importStrings, boolean importGroups,
- boolean importSelectorWords) {
+ private void openIt(boolean importEntries, boolean importStrings, boolean importGroups) {
if (filesToOpen.isEmpty()) {
return;
}
@@ -88,9 +84,8 @@ public class AppendDatabaseAction implements BaseAction {
Globals.prefs.put(JabRefPreferences.WORKING_DIRECTORY, file.getParent());
// Should this be done _after_ we know it was successfully opened?
ParserResult pr = OpenDatabase.loadDatabase(file,
- ImportFormatPreferences.fromPreferences(Globals.prefs));
- AppendDatabaseAction.mergeFromBibtex(frame, panel, pr, importEntries, importStrings,
- importGroups, importSelectorWords);
+ Globals.prefs.getImportFormatPreferences());
+ AppendDatabaseAction.mergeFromBibtex(frame, panel, pr, importEntries, importStrings, importGroups);
panel.output(Localization.lang("Imported from database") + " '" + file.getPath() + "'");
} catch (IOException | KeyCollisionException ex) {
LOGGER.warn("Could not open database", ex);
@@ -101,7 +96,7 @@ public class AppendDatabaseAction implements BaseAction {
}
private static void mergeFromBibtex(JabRefFrame frame, BasePanel panel, ParserResult pr, boolean importEntries,
- boolean importStrings, boolean importGroups, boolean importSelectorWords) throws KeyCollisionException {
+ boolean importStrings, boolean importGroups) throws KeyCollisionException {
BibDatabase fromDatabase = pr.getDatabase();
List<BibEntry> appendedEntries = new ArrayList<>();
@@ -137,18 +132,16 @@ public class AppendDatabaseAction implements BaseAction {
}
if (importGroups) {
- GroupTreeNode newGroups = meta.getGroups();
- if (newGroups != null) {
-
+ meta.getGroups().ifPresent(newGroups -> {
// ensure that there is always only one AllEntriesGroup
if (newGroups.getGroup() instanceof AllEntriesGroup) {
// create a dummy group
try {
ExplicitGroup group = new ExplicitGroup("Imported", GroupHierarchyType.INDEPENDENT,
- Globals.prefs);
+ Globals.prefs.getKeywordDelimiter());
newGroups.setGroup(group);
group.add(appendedEntries);
- } catch (ParseException e) {
+ } catch (IllegalArgumentException e) {
LOGGER.error(e);
}
}
@@ -157,15 +150,7 @@ public class AppendDatabaseAction implements BaseAction {
// have been defined. therefore, no check for null is
// required here
frame.getGroupSelector().addGroups(newGroups, ce);
- }
- }
-
- if (importSelectorWords) {
- for (String s : meta) {
- if (s.startsWith(MetaData.SELECTOR_META_PREFIX)) {
- panel.getBibDatabaseContext().getMetaData().putData(s, meta.getData(s));
- }
- }
+ });
}
ce.end();
diff --git a/src/main/java/net/sf/jabref/gui/importer/actions/CheckForNewEntryTypesAction.java b/src/main/java/net/sf/jabref/gui/importer/actions/CheckForNewEntryTypesAction.java
index 17fb3fa..0eba5d1 100644
--- a/src/main/java/net/sf/jabref/gui/importer/actions/CheckForNewEntryTypesAction.java
+++ b/src/main/java/net/sf/jabref/gui/importer/actions/CheckForNewEntryTypesAction.java
@@ -5,13 +5,13 @@ import java.util.Iterator;
import javax.swing.JOptionPane;
-import net.sf.jabref.BibDatabaseContext;
-import net.sf.jabref.Defaults;
import net.sf.jabref.Globals;
import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.logic.importer.ParserResult;
import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.Defaults;
import net.sf.jabref.model.EntryTypes;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.database.BibDatabaseMode;
import net.sf.jabref.model.entry.CustomEntryType;
import net.sf.jabref.model.entry.EntryType;
diff --git a/src/main/java/net/sf/jabref/gui/importer/actions/ConvertLegacyExplicitGroups.java b/src/main/java/net/sf/jabref/gui/importer/actions/ConvertLegacyExplicitGroups.java
index 12bc757..a00ea6e 100644
--- a/src/main/java/net/sf/jabref/gui/importer/actions/ConvertLegacyExplicitGroups.java
+++ b/src/main/java/net/sf/jabref/gui/importer/actions/ConvertLegacyExplicitGroups.java
@@ -5,10 +5,10 @@ import java.util.List;
import java.util.Objects;
import net.sf.jabref.gui.BasePanel;
-import net.sf.jabref.logic.groups.ExplicitGroup;
-import net.sf.jabref.logic.groups.GroupTreeNode;
import net.sf.jabref.logic.importer.ParserResult;
import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.groups.ExplicitGroup;
+import net.sf.jabref.model.groups.GroupTreeNode;
/**
* Converts legacy explicit groups, where the group contained a list of assigned entries, to the new format,
@@ -18,20 +18,20 @@ public class ConvertLegacyExplicitGroups implements PostOpenAction {
@Override
public boolean isActionNecessary(ParserResult pr) {
- if(pr.getMetaData().getGroups() == null) {
- return false;
+ if (pr.getMetaData().getGroups().isPresent()) {
+ return !getExplicitGroupsWithLegacyKeys(pr.getMetaData().getGroups().orElse(null)).isEmpty();
}
- return !getExplicitGroupsWithLegacyKeys(pr.getMetaData().getGroups()).isEmpty();
+ return false;
}
@Override
public void performAction(BasePanel panel, ParserResult pr) {
Objects.requireNonNull(pr);
- if(pr.getMetaData().getGroups() == null) {
+ if (!pr.getMetaData().getGroups().isPresent()) {
return;
}
- for (ExplicitGroup group : getExplicitGroupsWithLegacyKeys(pr.getMetaData().getGroups())) {
+ for (ExplicitGroup group : getExplicitGroupsWithLegacyKeys(pr.getMetaData().getGroups().get())) {
for (String entryKey : group.getLegacyEntryKeys()) {
for (BibEntry entry : pr.getDatabase().getEntriesByKey(entryKey)) {
group.add(entry);
diff --git a/src/main/java/net/sf/jabref/gui/importer/actions/OpenDatabaseAction.java b/src/main/java/net/sf/jabref/gui/importer/actions/OpenDatabaseAction.java
index 2acead6..9bcf571 100644
--- a/src/main/java/net/sf/jabref/gui/importer/actions/OpenDatabaseAction.java
+++ b/src/main/java/net/sf/jabref/gui/importer/actions/OpenDatabaseAction.java
@@ -4,10 +4,12 @@ import java.awt.event.ActionEvent;
import java.io.File;
import java.io.IOException;
import java.nio.file.attribute.FileTime;
+import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
+import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
@@ -15,30 +17,30 @@ import javax.swing.Action;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
-import net.sf.jabref.BibDatabaseContext;
-import net.sf.jabref.Defaults;
import net.sf.jabref.Globals;
import net.sf.jabref.JabRefExecutorService;
-import net.sf.jabref.MetaData;
import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.gui.FileDialog;
import net.sf.jabref.gui.IconTheme;
import net.sf.jabref.gui.JabRefFrame;
import net.sf.jabref.gui.actions.MnemonicAwareAction;
+import net.sf.jabref.gui.autosaveandbackup.BackupUIManager;
import net.sf.jabref.gui.importer.ParserResultWarningDialog;
import net.sf.jabref.gui.keyboard.KeyBinding;
-import net.sf.jabref.logic.importer.ImportFormatPreferences;
+import net.sf.jabref.gui.shared.SharedDatabaseUIManager;
+import net.sf.jabref.logic.autosaveandbackup.BackupManager;
import net.sf.jabref.logic.importer.OpenDatabase;
import net.sf.jabref.logic.importer.ParserResult;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.util.FileExtensions;
-import net.sf.jabref.logic.util.io.AutoSaveUtil;
import net.sf.jabref.logic.util.io.FileBasedLock;
-import net.sf.jabref.logic.util.strings.StringUtil;
import net.sf.jabref.migrations.FileLinksUpgradeWarning;
import net.sf.jabref.model.database.BibDatabase;
-import net.sf.jabref.model.database.BibDatabaseMode;
+import net.sf.jabref.model.strings.StringUtil;
import net.sf.jabref.preferences.JabRefPreferences;
+import net.sf.jabref.shared.exception.DatabaseNotSupportedException;
+import net.sf.jabref.shared.exception.InvalidDBMSConnectionPropertiesException;
+import net.sf.jabref.shared.exception.NotASharedDatabaseException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -126,8 +128,8 @@ public class OpenDatabaseAction extends MnemonicAwareAction {
File file = iterator.next();
for (int i = 0; i < frame.getTabbedPane().getTabCount(); i++) {
BasePanel basePanel = frame.getBasePanelAt(i);
- if ((basePanel.getBibDatabaseContext().getDatabaseFile() != null)
- && basePanel.getBibDatabaseContext().getDatabaseFile().equals(file)) {
+ if ((basePanel.getBibDatabaseContext().getDatabaseFile().isPresent())
+ && basePanel.getBibDatabaseContext().getDatabaseFile().get().equals(file)) {
iterator.remove();
removed++;
// See if we removed the final one. If so, we must perhaps
@@ -158,7 +160,7 @@ public class OpenDatabaseAction extends MnemonicAwareAction {
// already open. If so, we may have to raise the correct tab:
else if (toRaise != null) {
frame.output(Localization.lang("File '%0' is already open.",
- toRaise.getBibDatabaseContext().getDatabaseFile().getPath()));
+ toRaise.getBibDatabaseContext().getDatabaseFile().get().getPath()));
frame.getTabbedPane().setSelectedComponent(toRaise);
}
@@ -172,111 +174,72 @@ public class OpenDatabaseAction extends MnemonicAwareAction {
if ((file != null) && file.exists()) {
File fileToLoad = file;
frame.output(Localization.lang("Opening") + ": '" + file.getPath() + "'");
- boolean tryingAutosave = false;
- boolean autoSaveFound = AutoSaveUtil.newerAutoSaveExists(file);
- if (autoSaveFound && !Globals.prefs.getBoolean(JabRefPreferences.PROMPT_BEFORE_USING_AUTOSAVE)) {
- // We have found a newer autosave, and the preferences say we should load
- // it without prompting, so we replace the fileToLoad:
- fileToLoad = AutoSaveUtil.getAutoSaveFile(file);
- tryingAutosave = true;
- } else if (autoSaveFound) {
- // We have found a newer autosave, but we are not allowed to use it without
- // prompting.
- int answer = JOptionPane
- .showConfirmDialog(
- null, "<html>"
- + Localization
- .lang("An autosave file was found for this database. This could indicate "
- + "that JabRef did not shut down cleanly last time the file was used.")
- + "<br>"
- + Localization
- .lang("Do you want to recover the database from the autosave file?")
- + "</html>",
- Localization.lang("Recover from autosave"), JOptionPane.YES_NO_OPTION);
- if (answer == JOptionPane.YES_OPTION) {
- fileToLoad = AutoSaveUtil.getAutoSaveFile(file);
- tryingAutosave = true;
- }
- }
- boolean done = false;
- while (!done) {
- String fileName = file.getPath();
- Globals.prefs.put(JabRefPreferences.WORKING_DIRECTORY, file.getParent());
- // Should this be done _after_ we know it was successfully opened?
+ String fileName = file.getPath();
+ Globals.prefs.put(JabRefPreferences.WORKING_DIRECTORY, file.getParent());
- if (FileBasedLock.hasLockFile(file.toPath())) {
- Optional<FileTime> modificationTime = FileBasedLock.getLockFileTimeStamp(file.toPath());
- if ((modificationTime.isPresent()) && ((System.currentTimeMillis()
+ if (FileBasedLock.hasLockFile(file.toPath())) {
+ Optional<FileTime> modificationTime = FileBasedLock.getLockFileTimeStamp(file.toPath());
+ if ((modificationTime.isPresent()) && ((System.currentTimeMillis()
- modificationTime.get().toMillis()) > FileBasedLock.LOCKFILE_CRITICAL_AGE)) {
- // The lock file is fairly old, so we can offer to "steal" the file:
- int answer = JOptionPane.showConfirmDialog(null,
- "<html>" + Localization.lang("Error opening file") + " '" + fileName + "'. "
+ // The lock file is fairly old, so we can offer to "steal" the file:
+ int answer = JOptionPane.showConfirmDialog(null,
+ "<html>" + Localization.lang("Error opening file") + " '" + fileName + "'. "
+ Localization.lang("File is locked by another JabRef instance.") + "<p>"
+ Localization.lang("Do you want to override the file lock?"),
- Localization.lang("File locked"), JOptionPane.YES_NO_OPTION);
- if (answer == JOptionPane.YES_OPTION) {
- FileBasedLock.deleteLockFile(file.toPath());
- } else {
- return;
- }
- } else if (!FileBasedLock.waitForFileLock(file.toPath())) {
- JOptionPane.showMessageDialog(null,
- Localization.lang("Error opening file") + " '" + fileName + "'. "
- + Localization.lang("File is locked by another JabRef instance."),
- Localization.lang("Error"), JOptionPane.ERROR_MESSAGE);
+ Localization.lang("File locked"), JOptionPane.YES_NO_OPTION);
+ if (answer == JOptionPane.YES_OPTION) {
+ FileBasedLock.deleteLockFile(file.toPath());
+ } else {
return;
}
-
+ } else if (!FileBasedLock.waitForFileLock(file.toPath())) {
+ JOptionPane.showMessageDialog(null,
+ Localization.lang("Error opening file") + " '" + fileName + "'. "
+ + Localization.lang("File is locked by another JabRef instance."),
+ Localization.lang("Error"), JOptionPane.ERROR_MESSAGE);
+ return;
}
- ParserResult result;
- String errorMessage = null;
- try {
- result = OpenDatabase.loadDatabase(fileToLoad,
- ImportFormatPreferences.fromPreferences(Globals.prefs));
- } catch (IOException ex) {
- LOGGER.error("Error loading database " + fileToLoad, ex);
- result = ParserResult.getNullResult();
- }
- if (result.isNullResult()) {
- JOptionPane.showMessageDialog(null, Localization.lang("Error opening file") + " '" + fileName + "'",
- Localization.lang("Error"), JOptionPane.ERROR_MESSAGE);
+ }
- String message = "<html>" + errorMessage + "<p>"
- + (tryingAutosave ? Localization.lang(
- "Error opening autosave of '%0'. Trying to load '%0' instead.",
- file.getName()) : ""/*Globals.lang("Error opening file '%0'.", file.getName())*/)
- + "</html>";
- JOptionPane.showMessageDialog(null, message, Localization.lang("Error opening file"),
- JOptionPane.ERROR_MESSAGE);
-
- if (tryingAutosave) {
- tryingAutosave = false;
- fileToLoad = file;
- } else {
- done = true;
- }
- continue;
- } else {
- done = true;
- }
+ if (BackupManager.checkForBackupFile(fileToLoad.toPath())) {
+ BackupUIManager.showRestoreBackupDialog(frame, fileToLoad.toPath());
+ }
- final BasePanel panel = addNewDatabase(result, file, raisePanel);
- if (tryingAutosave) {
- panel.markNonUndoableBaseChanged();
- }
+ ParserResult result;
+ try {
+ result = OpenDatabase.loadDatabase(fileToLoad, Globals.prefs.getImportFormatPreferences());
+ } catch (IOException ex) {
+ LOGGER.error("Error loading database " + fileToLoad, ex);
+ result = ParserResult.getNullResult();
+ JOptionPane.showMessageDialog(null, Localization.lang("Error opening file") + " '" + fileName + "'",
+ Localization.lang("Error"), JOptionPane.ERROR_MESSAGE);
+ }
- // After adding the database, go through our list and see if
- // any post open actions need to be done. For instance, checking
- // if we found new entry types that can be imported, or checking
- // if the database contents should be modified due to new features
- // in this version of JabRef:
- final ParserResult finalReferenceToResult = result;
- SwingUtilities.invokeLater(
- () -> OpenDatabaseAction.performPostOpenActions(panel, finalReferenceToResult, true));
+ if (result.getDatabase().isShared()) {
+ try {
+ new SharedDatabaseUIManager(frame).openSharedDatabaseFromParserResult(result);
+ } catch (SQLException | DatabaseNotSupportedException | InvalidDBMSConnectionPropertiesException |
+ NotASharedDatabaseException e) {
+ result.getDatabaseContext().clearDatabaseFile(); // do not open the original file
+ result.getDatabase().clearSharedDatabaseID();
+ LOGGER.error("Connection error", e);
+ JOptionPane.showMessageDialog(frame,
+ e.getMessage() + "\n\n" + Localization.lang("A local copy will be opened."),
+ Localization.lang("Connection error"), JOptionPane.WARNING_MESSAGE);
+ }
}
+ BasePanel panel = addNewDatabase(result, file, raisePanel);
+
+ // After adding the database, go through our list and see if
+ // any post open actions need to be done. For instance, checking
+ // if we found new entry types that can be imported, or checking
+ // if the database contents should be modified due to new features
+ // in this version of JabRef:
+ final ParserResult finalReferenceToResult = result;
+ SwingUtilities.invokeLater(() -> OpenDatabaseAction.performPostOpenActions(panel, finalReferenceToResult, true));
}
}
@@ -299,24 +262,23 @@ public class OpenDatabaseAction extends MnemonicAwareAction {
private BasePanel addNewDatabase(ParserResult result, final File file, boolean raisePanel) {
- String fileName = file.getPath();
BibDatabase database = result.getDatabase();
- MetaData meta = result.getMetaData();
if (result.hasWarnings()) {
JabRefExecutorService.INSTANCE
.execute(() -> ParserResultWarningDialog.showParserResultWarningDialog(result, frame));
}
- Defaults defaults = new Defaults(
- BibDatabaseMode.fromPreference(Globals.prefs.getBoolean(JabRefPreferences.BIBLATEX_DEFAULT_MODE)));
- BasePanel basePanel = new BasePanel(frame, new BibDatabaseContext(database, meta, file, defaults));
+ BasePanel basePanel = new BasePanel(frame, result.getDatabaseContext());
// file is set to null inside the EventDispatcherThread
SwingUtilities.invokeLater(() -> frame.addTab(basePanel, raisePanel));
- frame.output(Localization.lang("Opened database") + " '" + fileName + "' " + Localization.lang("with") + " "
- + database.getEntryCount() + " " + Localization.lang("entries") + ".");
+ if (Objects.nonNull(file)) {
+ frame.output(Localization.lang("Opened database") + " '" + file.getPath() + "' " + Localization.lang("with")
+ + " "
+ + database.getEntryCount() + " " + Localization.lang("entries") + ".");
+ }
return basePanel;
}
diff --git a/src/main/java/net/sf/jabref/gui/importer/fetcher/ACMPortalFetcher.java b/src/main/java/net/sf/jabref/gui/importer/fetcher/ACMPortalFetcher.java
index 97fb71d..e5ed524 100644
--- a/src/main/java/net/sf/jabref/gui/importer/fetcher/ACMPortalFetcher.java
+++ b/src/main/java/net/sf/jabref/gui/importer/fetcher/ACMPortalFetcher.java
@@ -5,7 +5,6 @@ import java.awt.GridLayout;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
-import java.net.ConnectException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
@@ -31,7 +30,6 @@ import net.sf.jabref.logic.formatter.bibtexfields.HtmlToLatexFormatter;
import net.sf.jabref.logic.formatter.bibtexfields.UnitsToLatexFormatter;
import net.sf.jabref.logic.formatter.casechanger.ProtectTermsFormatter;
import net.sf.jabref.logic.help.HelpFile;
-import net.sf.jabref.logic.importer.ImportFormatPreferences;
import net.sf.jabref.logic.importer.ImportInspector;
import net.sf.jabref.logic.importer.OutputPrinter;
import net.sf.jabref.logic.importer.fileformat.BibtexParser;
@@ -139,8 +137,7 @@ public class ACMPortalFetcher implements PreviewEntryFetcher {
}
if (hits == 0) {
- status.showMessage(Localization.lang("No entries found for the search string '%0'",
- terms),
+ status.showMessage(Localization.lang("No entries found for the search string '%0'", terms),
Localization.lang("Search %0", getTitle()), JOptionPane.INFORMATION_MESSAGE);
return false;
} else if (hits > 20) {
@@ -158,19 +155,11 @@ public class ACMPortalFetcher implements PreviewEntryFetcher {
return true;
- } catch (MalformedURLException e) {
- LOGGER.warn("Problem with ACM fetcher URL", e);
- } catch (ConnectException e) {
- status.showMessage(Localization.lang("Could not connect to %0", getTitle()),
- Localization.lang("Search %0", getTitle()), JOptionPane.ERROR_MESSAGE);
- LOGGER.warn("Problem with ACM connection", e);
} catch (IOException e) {
- status.showMessage(e.getMessage(),
- Localization.lang("Search %0", getTitle()), JOptionPane.ERROR_MESSAGE);
- LOGGER.warn("Problem with ACM Portal", e);
+ LOGGER.error("Error while fetching from " + getTitle(), e);
+ preview.showErrorMessage(this.getTitle(), e.getLocalizedMessage());
+ return false;
}
- return false;
-
}
@Override
@@ -182,7 +171,7 @@ public class ACMPortalFetcher implements PreviewEntryFetcher {
if (selentry.getValue()) {
downloadEntryBibTeX(selentry.getKey(), fetchAbstract).ifPresent(entry -> {
// Convert from HTML and optionally add curly brackets around key words to keep the case
- entry.getFieldOptional(FieldName.TITLE).ifPresent(title -> {
+ entry.getField(FieldName.TITLE).ifPresent(title -> {
title = title.replace("\\&", "&").replace("\\#", "#");
title = convertHTMLChars(title);
@@ -198,7 +187,7 @@ public class ACMPortalFetcher implements PreviewEntryFetcher {
entry.setField(FieldName.TITLE, title);
});
- entry.getFieldOptional(FieldName.ABSTRACT)
+ entry.getField(FieldName.ABSTRACT)
.ifPresent(abstr -> entry.setField(FieldName.ABSTRACT, convertHTMLChars(abstr)));
inspector.addEntry(entry);
});
@@ -324,7 +313,7 @@ public class ACMPortalFetcher implements PreviewEntryFetcher {
Collection<BibEntry> items = null;
try (BufferedReader in = new BufferedReader(
new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) {
- items = BibtexParser.parse(in, ImportFormatPreferences.fromPreferences(Globals.prefs)).getDatabase()
+ items = BibtexParser.parse(in, Globals.prefs.getImportFormatPreferences()).getDatabase()
.getEntries();
} catch (IOException e) {
LOGGER.info("Download of BibTeX information from ACM Portal failed.", e);
@@ -388,9 +377,8 @@ public class ACMPortalFetcher implements PreviewEntryFetcher {
} catch (NumberFormatException ex) {
throw new IOException("Cannot parse number of hits");
}
- } else {
- LOGGER.info("Unmatched! " + substring);
}
+ LOGGER.info("Unmatched! " + substring);
}
throw new IOException("Cannot parse number of hits");
}
diff --git a/src/main/java/net/sf/jabref/gui/importer/fetcher/ADSFetcher.java b/src/main/java/net/sf/jabref/gui/importer/fetcher/ADSFetcher.java
deleted file mode 100644
index 79d2740..0000000
--- a/src/main/java/net/sf/jabref/gui/importer/fetcher/ADSFetcher.java
+++ /dev/null
@@ -1,166 +0,0 @@
-package net.sf.jabref.gui.importer.fetcher;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedReader;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.nio.charset.Charset;
-
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.xml.stream.XMLInputFactory;
-import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.XMLStreamReader;
-
-import net.sf.jabref.Globals;
-import net.sf.jabref.logic.help.HelpFile;
-import net.sf.jabref.logic.importer.ImportFormatPreferences;
-import net.sf.jabref.logic.importer.ImportInspector;
-import net.sf.jabref.logic.importer.OutputPrinter;
-import net.sf.jabref.logic.importer.ParserResult;
-import net.sf.jabref.logic.importer.fileformat.BibtexParser;
-import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.model.database.BibDatabase;
-import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.model.entry.FieldName;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- *
- * This class handles accessing and obtaining BibTeX entry
- * from ADS(The NASA Astrophysics Data System).
- * Fetching using DOI(Document Object Identifier) is only supported.
- *
- * @author Ryo IGARASHI
- */
-public class ADSFetcher implements EntryFetcher {
-
- private static final Log LOGGER = LogFactory.getLog(ADSFetcher.class);
-
-
- @Override
- public JPanel getOptionsPanel() {
- return null;
- }
-
- @Override
- public HelpFile getHelpPage() {
- return HelpFile.FETCHER_ADS;
- }
-
- @Override
- public String getTitle() {
- return "ADS from ADS-DOI";
- }
-
- @Override
- public boolean processQuery(String query, ImportInspector dialog, OutputPrinter status) {
- try {
- /* Remove "doi:" scheme identifier */
- /* Allow fetching only 1 key */
- String key = query.replaceAll("^(doi:|DOI:)", "");
- /* Query ADS and load the results into the BibDatabase */
- status.setStatus(Localization.lang("Processing %0", key));
- BibDatabase bd = importADSEntries(key, status);
- if ((bd != null) && bd.hasEntries()) {
- /* Add the entry to the inspection dialog */
- for (BibEntry entry : bd.getEntries()) {
- importADSAbstract(key, entry, status);
- dialog.addEntry(entry);
- }
- } else {
- return false;
- }
- } catch (Exception e) {
- status.setStatus(Localization.lang("Error while fetching from %0", "ADS") + ": " + e.getMessage());
- LOGGER.warn("Error while fetching from ADS", e);
- }
- return true;
- }
-
- @Override
- public void stopFetching() {
- // Do nothing
- }
-
- private BibDatabase importADSEntries(String key, OutputPrinter status) {
- String url = constructUrl(key);
- try {
- URL ADSUrl = new URL(url + "&data_type=BIBTEX");
- HttpURLConnection ADSConnection = (HttpURLConnection) ADSUrl.openConnection();
- ADSConnection.setRequestProperty("User-Agent", "JabRef");
- try (BufferedReader reader = new BufferedReader(
- new InputStreamReader(ADSConnection.getInputStream(), Charset.forName("ISO-8859-1")))) {
- ParserResult pr = BibtexParser.parse(reader, ImportFormatPreferences.fromPreferences(Globals.prefs));
- return pr.getDatabase();
- }
- } catch (FileNotFoundException e) {
- status.showMessage(
- Localization.lang("'%0' is not a valid ADS bibcode.", key) + "\n\n" + Localization
- .lang("Note: A full text search is currently not supported for %0", getTitle()),
- getTitle(), JOptionPane.ERROR_MESSAGE);
- LOGGER.debug("File not found", e);
- } catch (IOException e) {
- status.showMessage(Localization.lang("An exception occurred while accessing '%0'", url) + "\n\n" + e,
- getTitle(), JOptionPane.ERROR_MESSAGE);
- LOGGER.debug("Problem accessing URL", e);
- } catch (RuntimeException e) {
- status.showMessage(
- Localization.lang("An error occurred while fetching from ADS (%0):", url) + "\n\n" + e.getMessage(),
- getTitle(), JOptionPane.ERROR_MESSAGE);
- LOGGER.warn("Problem fetching from ADS", e);
- }
- return null;
- }
-
- private static String constructUrl(String key) {
- return "http://adsabs.harvard.edu/doi/" + key;
- }
-
- private void importADSAbstract(String key, BibEntry entry, OutputPrinter status) {
- /* TODO: construct ADSUrl from BibEntry */
- String url = constructUrl(key);
- try {
- URL ADSUrl = new URL(url + "&data_type=XML");
- HttpURLConnection ADSConnection = (HttpURLConnection) ADSUrl.openConnection();
- ADSConnection.setRequestProperty("User-Agent", "JabRef");
- BufferedInputStream bis = new BufferedInputStream(ADSConnection.getInputStream());
-
- XMLInputFactory factory = XMLInputFactory.newInstance();
- XMLStreamReader reader = factory.createXMLStreamReader(bis);
- boolean isAbstract = false;
- StringBuilder abstractSB = new StringBuilder();
- while (reader.hasNext()) {
- reader.next();
- if (reader.isStartElement() &&
- FieldName.ABSTRACT.equals(reader.getLocalName())) {
- isAbstract = true;
- }
- if (isAbstract && reader.isCharacters()) {
- abstractSB.append(reader.getText());
- }
- if (isAbstract && reader.isEndElement()) {
- isAbstract = false;
- }
- }
- String abstractText = abstractSB.toString();
- abstractText = abstractText.replace("\n", " ");
- entry.setField(FieldName.ABSTRACT, abstractText);
- } catch (XMLStreamException e) {
- status.showMessage(Localization.lang("An error occurred while parsing abstract"), getTitle(),
- JOptionPane.ERROR_MESSAGE);
- } catch (IOException e) {
- status.showMessage(Localization.lang("An exception occurred while accessing '%0'", url) + "\n\n" + e,
- getTitle(), JOptionPane.ERROR_MESSAGE);
- } catch (RuntimeException e) {
- status.showMessage(
- Localization.lang("An error occurred while fetching from ADS (%0):", url) + "\n\n" + e.getMessage(),
- getTitle(), JOptionPane.ERROR_MESSAGE);
- }
- }
-}
diff --git a/src/main/java/net/sf/jabref/gui/importer/fetcher/CiteSeerXFetcher.java b/src/main/java/net/sf/jabref/gui/importer/fetcher/CiteSeerXFetcher.java
index 3815b8b..43cacb6 100644
--- a/src/main/java/net/sf/jabref/gui/importer/fetcher/CiteSeerXFetcher.java
+++ b/src/main/java/net/sf/jabref/gui/importer/fetcher/CiteSeerXFetcher.java
@@ -11,6 +11,7 @@ import java.util.regex.Pattern;
import javax.swing.JPanel;
import net.sf.jabref.Globals;
+import net.sf.jabref.gui.importer.ImportInspectionDialog;
import net.sf.jabref.logic.formatter.bibtexfields.NormalizeNamesFormatter;
import net.sf.jabref.logic.help.HelpFile;
import net.sf.jabref.logic.importer.ImportInspector;
@@ -63,7 +64,8 @@ public class CiteSeerXFetcher implements EntryFetcher {
return true;
} catch (IOException e) {
- LOGGER.warn("Could not download", e);
+ LOGGER.error("Error while fetching from " + getTitle(), e);
+ ((ImportInspectionDialog)inspector).showErrorMessage(this.getTitle(), e.getLocalizedMessage());
return false;
}
}
diff --git a/src/main/java/net/sf/jabref/gui/importer/fetcher/DBLPFetcher.java b/src/main/java/net/sf/jabref/gui/importer/fetcher/DBLPFetcher.java
deleted file mode 100644
index 2a640a6..0000000
--- a/src/main/java/net/sf/jabref/gui/importer/fetcher/DBLPFetcher.java
+++ /dev/null
@@ -1,164 +0,0 @@
-package net.sf.jabref.gui.importer.fetcher;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-
-import javax.swing.JPanel;
-
-import net.sf.jabref.Globals;
-import net.sf.jabref.logic.help.HelpFile;
-import net.sf.jabref.logic.importer.ImportFormatPreferences;
-import net.sf.jabref.logic.importer.ImportInspector;
-import net.sf.jabref.logic.importer.OutputPrinter;
-import net.sf.jabref.logic.importer.fileformat.BibtexParser;
-import net.sf.jabref.logic.importer.util.DBLPHelper;
-import net.sf.jabref.logic.net.URLDownload;
-import net.sf.jabref.model.DuplicateCheck;
-import net.sf.jabref.model.entry.BibEntry;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-public class DBLPFetcher implements EntryFetcher {
-
- private static final Log LOGGER = LogFactory.getLog(DBLPFetcher.class);
-
- private static final String URL_START = "http://www.dblp.org/search/api/";
- private static final String URL_PART1 = "?q=";
- private static final String URL_END = "&h=1000&c=4&f=0&format=json";
-
- private volatile boolean shouldContinue;
- private String query;
- private final DBLPHelper helper = new DBLPHelper(ImportFormatPreferences.fromPreferences(Globals.prefs));
-
-
- @Override
- public void stopFetching() {
- shouldContinue = false;
- }
-
- @Override
- public boolean processQuery(String newQuery, ImportInspector inspector,
- OutputPrinter status) {
-
- final HashMap<String, Boolean> bibentryKnown = new HashMap<>();
-
- boolean res = false;
- this.query = newQuery;
-
- shouldContinue = true;
-
- // we save the duplicate check threshold
- // we need to overcome the "smart" approach of this heuristic
- // and we will set it back afterwards, so maybe someone is happy again
- double saveThreshold = DuplicateCheck.duplicateThreshold;
-
- try {
-
- String address = makeSearchURL();
- URLDownload dl = new URLDownload(address);
-
- String page = dl.downloadToString(Globals.prefs.getDefaultEncoding());
-
- String[] lines = page.split("\n");
- List<String> bibtexUrlList = new ArrayList<>();
- for (final String line : lines) {
- if (line.startsWith("\"url\"")) {
- String addr = line.replace("\"url\":\"", "");
- addr = addr.substring(0, addr.length() - 2);
- bibtexUrlList.add(addr);
- }
- }
-
- DuplicateCheck.duplicateThreshold = Double.MAX_VALUE;
-
- // 2014-11-08
- // DBLP now shows the BibTeX entry using ugly HTML entities
- // but they also offer the download of a BIB file
- // we find this in the page which we get from "url"
- // and this BIB file is then in "biburl"
-
- int count = 1;
- for (String urlStr : bibtexUrlList) {
- if (!shouldContinue) {
- break;
- }
-
- final String bibtexHTMLPage = new URLDownload(urlStr)
- .downloadToString(Globals.prefs.getDefaultEncoding());
-
- final String[] htmlLines = bibtexHTMLPage.split("\n");
-
- for (final String line : htmlLines) {
- if (line.contains("biburl")) {
- int sidx = line.indexOf('{');
- int eidx = line.indexOf('}');
- // now we take everything within the curly braces
- String bibtexUrl = line.substring(sidx + 1, eidx);
-
- // we do not access dblp.uni-trier.de as they will complain
- bibtexUrl = bibtexUrl.replace("dblp.uni-trier.de", "www.dblp.org");
-
- final String bibtexPage = new URLDownload(bibtexUrl)
- .downloadToString(Globals.prefs.getDefaultEncoding());
-
- Collection<BibEntry> bibtexEntries = BibtexParser.fromString(bibtexPage,
- ImportFormatPreferences.fromPreferences(Globals.prefs));
-
- for (BibEntry be : bibtexEntries) {
-
- if (!bibentryKnown.containsKey(be.getCiteKey())) {
-
- inspector.addEntry(be);
- bibentryKnown.put(be.getCiteKey(), true);
- }
-
- }
- }
- }
-
- inspector.setProgress(count, bibtexUrlList.size());
- count++;
- }
-
-
- // everything went smooth
- res = true;
-
- } catch (IOException e) {
- LOGGER.warn("Communcation problems", e);
- status.showMessage(e.getMessage());
- } finally {
- // Restore the threshold
- DuplicateCheck.duplicateThreshold = saveThreshold;
- }
-
- return res;
- }
-
- private String makeSearchURL() {
- StringBuilder sb = new StringBuilder(DBLPFetcher.URL_START).append(DBLPFetcher.URL_PART1);
- String cleanedQuery = helper.cleanDBLPQuery(query);
- sb.append(cleanedQuery).append(DBLPFetcher.URL_END);
- return sb.toString();
- }
-
- @Override
- public String getTitle() {
- return "DBLP";
- }
-
- @Override
- public HelpFile getHelpPage() {
- return HelpFile.FETCHER_DBLP;
- }
-
- @Override
- public JPanel getOptionsPanel() {
- return null;
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/gui/importer/fetcher/DOAJFetcher.java b/src/main/java/net/sf/jabref/gui/importer/fetcher/DOAJFetcher.java
index 0d6b379..62294db 100644
--- a/src/main/java/net/sf/jabref/gui/importer/fetcher/DOAJFetcher.java
+++ b/src/main/java/net/sf/jabref/gui/importer/fetcher/DOAJFetcher.java
@@ -4,13 +4,13 @@ import javax.swing.JOptionPane;
import javax.swing.JPanel;
import net.sf.jabref.Globals;
+import net.sf.jabref.gui.importer.ImportInspectionDialog;
import net.sf.jabref.logic.help.HelpFile;
import net.sf.jabref.logic.importer.ImportInspector;
import net.sf.jabref.logic.importer.OutputPrinter;
import net.sf.jabref.logic.importer.util.JSONEntryParser;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.preferences.JabRefPreferences;
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.JsonNode;
@@ -44,31 +44,25 @@ public class DOAJFetcher implements EntryFetcher {
HttpResponse<JsonNode> jsonResponse;
jsonResponse = Unirest.get(SEARCH_URL + query + "?pageSize=1").header("accept", "application/json").asJson();
JSONObject jo = jsonResponse.getBody().getObject();
- int hits = jo.getInt("total");
- int numberToFetch = 0;
- if (hits > 0) {
- if (hits > MAX_PER_PAGE) {
- while (true) {
- String strCount = JOptionPane
- .showInputDialog(
- Localization.lang("References found") + ": " + hits + " "
- + Localization.lang("Number of references to fetch?"),
- Integer.toString(hits));
+ int numberToFetch = jo.getInt("total");
+ if (numberToFetch > 0) {
+ if (numberToFetch > MAX_PER_PAGE) {
+ boolean numberEntered = false;
+ do {
+ String strCount = JOptionPane.showInputDialog(Localization.lang("%0 references found. Number of references to fetch?", String.valueOf(numberToFetch)));
if (strCount == null) {
- status.setStatus(Localization.lang("%0 import canceled", "DOAJ"));
+ status.setStatus(Localization.lang("%0 import canceled", getTitle()));
return false;
}
try {
numberToFetch = Integer.parseInt(strCount.trim());
- break;
+ numberEntered = true;
} catch (NumberFormatException ex) {
status.showMessage(Localization.lang("Please enter a valid number"));
}
- }
- } else {
- numberToFetch = hits;
+ } while (!numberEntered);
}
int fetched = 0; // Keep track of number of items fetched for the progress bar
@@ -86,7 +80,7 @@ public class DOAJFetcher implements EntryFetcher {
for (int i = 0; i < results.length(); i++) {
JSONObject bibJsonEntry = results.getJSONObject(i).getJSONObject("bibjson");
BibEntry entry = jsonConverter.parseBibJSONtoBibtex(bibJsonEntry,
- Globals.prefs.get(JabRefPreferences.KEYWORD_SEPARATOR));
+ Globals.prefs.getKeywordDelimiter());
inspector.addEntry(entry);
fetched++;
inspector.setProgress(fetched, numberToFetch);
@@ -96,15 +90,14 @@ public class DOAJFetcher implements EntryFetcher {
return true;
} else {
status.showMessage(Localization.lang("No entries found for the search string '%0'", query),
- Localization.lang("Search %0", "DOAJ"), JOptionPane.INFORMATION_MESSAGE);
+ Localization.lang("Search %0", getTitle()), JOptionPane.INFORMATION_MESSAGE);
return false;
}
} catch (UnirestException e) {
- LOGGER.warn("Problem searching DOAJ", e);
- status.setStatus(Localization.lang("%0 import canceled", "DOAJ"));
+ LOGGER.error("Error while fetching from " + getTitle(), e);
+ ((ImportInspectionDialog)inspector).showErrorMessage(this.getTitle(), e.getLocalizedMessage());
return false;
}
-
}
@Override
diff --git a/src/main/java/net/sf/jabref/gui/importer/fetcher/DOItoBibTeXFetcher.java b/src/main/java/net/sf/jabref/gui/importer/fetcher/DOItoBibTeXFetcher.java
deleted file mode 100644
index e3aa02f..0000000
--- a/src/main/java/net/sf/jabref/gui/importer/fetcher/DOItoBibTeXFetcher.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package net.sf.jabref.gui.importer.fetcher;
-
-import java.util.Optional;
-
-import javax.swing.JPanel;
-
-import net.sf.jabref.Globals;
-import net.sf.jabref.logic.help.HelpFile;
-import net.sf.jabref.logic.importer.ImportFormatPreferences;
-import net.sf.jabref.logic.importer.ImportInspector;
-import net.sf.jabref.logic.importer.OutputPrinter;
-import net.sf.jabref.logic.importer.ParserResult;
-import net.sf.jabref.logic.importer.fetcher.DOItoBibTeX;
-import net.sf.jabref.model.entry.BibEntry;
-
-public class DOItoBibTeXFetcher implements EntryFetcher {
-
-
- @Override
- public void stopFetching() {
- // not needed as the fetching is a single HTTP GET
- }
-
- @Override
- public boolean processQuery(String query, ImportInspector inspector, OutputPrinter status) {
- ParserResult parserResult = new ParserResult();
- Optional<BibEntry> entry = DOItoBibTeX.getEntryFromDOI(query, parserResult,
- ImportFormatPreferences.fromPreferences(Globals.prefs));
- if (parserResult.hasWarnings()) {
- status.showMessage(parserResult.getErrorMessage());
- }
- entry.ifPresent(e -> inspector.addEntry(e));
-
- return entry.isPresent();
- }
-
- @Override
- public String getTitle() {
- return "DOI to BibTeX";
- }
-
- @Override
- public HelpFile getHelpPage() {
- return HelpFile.FETCHER_DOI_TO_BIBTEX;
- }
-
- @Override
- public JPanel getOptionsPanel() {
- // no additional options available
- return null;
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/gui/importer/fetcher/DiVAtoBibTeXFetcher.java b/src/main/java/net/sf/jabref/gui/importer/fetcher/DiVAtoBibTeXFetcher.java
deleted file mode 100644
index ba844e5..0000000
--- a/src/main/java/net/sf/jabref/gui/importer/fetcher/DiVAtoBibTeXFetcher.java
+++ /dev/null
@@ -1,129 +0,0 @@
-package net.sf.jabref.gui.importer.fetcher;
-
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLEncoder;
-import java.nio.charset.StandardCharsets;
-import java.util.Optional;
-
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-
-import net.sf.jabref.Globals;
-import net.sf.jabref.logic.formatter.bibtexfields.UnicodeToLatexFormatter;
-import net.sf.jabref.logic.formatter.bibtexfields.UnitsToLatexFormatter;
-import net.sf.jabref.logic.formatter.casechanger.ProtectTermsFormatter;
-import net.sf.jabref.logic.help.HelpFile;
-import net.sf.jabref.logic.importer.ImportFormatPreferences;
-import net.sf.jabref.logic.importer.ImportInspector;
-import net.sf.jabref.logic.importer.OutputPrinter;
-import net.sf.jabref.logic.importer.fileformat.BibtexParser;
-import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.logic.net.URLDownload;
-import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.model.entry.FieldName;
-import net.sf.jabref.preferences.JabRefPreferences;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-public class DiVAtoBibTeXFetcher implements EntryFetcher {
-
- private static final Log LOGGER = LogFactory.getLog(DiVAtoBibTeXFetcher.class);
-
- private static final String URL_PATTERN = "http://www.diva-portal.org/smash/getreferences?referenceFormat=BibTex&pids=%s";
- private final ProtectTermsFormatter protectTermsFormatter = new ProtectTermsFormatter();
- private final UnitsToLatexFormatter unitsToLatexFormatter = new UnitsToLatexFormatter();
-
- @Override
- public void stopFetching() {
- // nothing needed as the fetching is a single HTTP GET
- }
-
- @Override
- public boolean processQuery(String query, ImportInspector inspector, OutputPrinter status) {
- String q;
- try {
- q = URLEncoder.encode(query, StandardCharsets.UTF_8.name());
- } catch (UnsupportedEncodingException e) {
- // this should never happen
- status.setStatus(Localization.lang("Error"));
- LOGGER.warn("Encoding issues", e);
- return false;
- }
-
- String urlString = String.format(DiVAtoBibTeXFetcher.URL_PATTERN, q);
-
- // Send the request
- URL url;
- try {
- url = new URL(urlString);
- } catch (MalformedURLException e) {
- LOGGER.warn("Bad URL", e);
- return false;
- }
-
- String bibtexString;
- try {
- URLDownload dl = new URLDownload(url);
-
- bibtexString = dl.downloadToString(StandardCharsets.UTF_8);
- } catch (FileNotFoundException e) {
- status.showMessage(Localization.lang("Unknown DiVA entry: '%0'.",
- query),
- Localization.lang("Get BibTeX entry from DiVA"), JOptionPane.INFORMATION_MESSAGE);
- return false;
- } catch (IOException e) {
- LOGGER.warn("Communication problems", e);
- return false;
- }
-
- Optional<BibEntry> entry = BibtexParser.singleFromString(bibtexString,
- ImportFormatPreferences.fromPreferences(Globals.prefs));
- if (entry.isPresent()) {
- // Optionally add curly brackets around key words to keep the case
- entry.get().getFieldOptional(FieldName.TITLE).ifPresent(title -> {
- // Unit formatting
- if (Globals.prefs.getBoolean(JabRefPreferences.USE_UNIT_FORMATTER_ON_SEARCH)) {
- title = unitsToLatexFormatter.format(title);
- }
-
- // Case keeping
- if (Globals.prefs.getBoolean(JabRefPreferences.USE_CASE_KEEPER_ON_SEARCH)) {
- title = protectTermsFormatter.format(title);
- }
- entry.get().setField(FieldName.TITLE, title);
- });
-
- entry.get().getFieldOptional(FieldName.INSTITUTION).ifPresent(
- institution -> entry.get().setField(FieldName.INSTITUTION,
- new UnicodeToLatexFormatter().format(institution)));
- // Do not use the provided key
- // entry.clearField(InternalBibtexFields.KEY_FIELD);
- inspector.addEntry(entry.get());
-
- return true;
- }
- return false;
- }
-
- @Override
- public String getTitle() {
- return "DiVA";
- }
-
- @Override
- public HelpFile getHelpPage() {
- return HelpFile.FETCHER_DIVA_TO_BIBTEX;
- }
-
- @Override
- public JPanel getOptionsPanel() {
- // no additional options available
- return null;
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/gui/importer/fetcher/EntryFetcher.java b/src/main/java/net/sf/jabref/gui/importer/fetcher/EntryFetcher.java
index 7bf0dab..ca76297 100644
--- a/src/main/java/net/sf/jabref/gui/importer/fetcher/EntryFetcher.java
+++ b/src/main/java/net/sf/jabref/gui/importer/fetcher/EntryFetcher.java
@@ -8,9 +8,11 @@ import net.sf.jabref.logic.importer.ImportInspector;
import net.sf.jabref.logic.importer.OutputPrinter;
/**
+ * @deprecated
+ * Use {@link SearchBasedEntryFetcher} instead <br>
* Implement this interface to add another activeFetcher (something that grabs records
* from the Web for JabRef). Have a look at the existing implemenations
- * OAI2Fetcher, IEEEXploreFetcher, MedlineFetcher, JStorFetcher and
+ * OAI2Fetcher, IEEEXploreFetcher, JStorFetcher and
* CiteSeerEntryFetcher.
*
* Note: You also need to implement the method stopFetching from
@@ -19,7 +21,7 @@ import net.sf.jabref.logic.importer.OutputPrinter;
* A Fetcher should not execute any GUI Operations, because it might be run in
* headless mode, but rather use the OutputPrinter for talking to the user.
*/
- at Deprecated // use SearchBasedFetcher instead
+ at Deprecated
public interface EntryFetcher extends ImportInspectionDialog.CallBack {
/**
diff --git a/src/main/java/net/sf/jabref/gui/importer/fetcher/EntryFetchers.java b/src/main/java/net/sf/jabref/gui/importer/fetcher/EntryFetchers.java
index 48b54a9..20d8068 100644
--- a/src/main/java/net/sf/jabref/gui/importer/fetcher/EntryFetchers.java
+++ b/src/main/java/net/sf/jabref/gui/importer/fetcher/EntryFetchers.java
@@ -1,40 +1,71 @@
package net.sf.jabref.gui.importer.fetcher;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
+import net.sf.jabref.Globals;
+import net.sf.jabref.logic.importer.EntryBasedFetcher;
+import net.sf.jabref.logic.importer.IdBasedFetcher;
import net.sf.jabref.logic.importer.fetcher.ArXiv;
+import net.sf.jabref.logic.importer.fetcher.AstrophysicsDataSystem;
+import net.sf.jabref.logic.importer.fetcher.DBLPFetcher;
+import net.sf.jabref.logic.importer.fetcher.DiVA;
+import net.sf.jabref.logic.importer.fetcher.DoiFetcher;
+import net.sf.jabref.logic.importer.fetcher.GoogleScholar;
import net.sf.jabref.logic.importer.fetcher.GvkFetcher;
+import net.sf.jabref.logic.importer.fetcher.IsbnFetcher;
+import net.sf.jabref.logic.importer.fetcher.MathSciNet;
+import net.sf.jabref.logic.importer.fetcher.MedlineFetcher;
+import net.sf.jabref.logic.importer.fetcher.zbMATH;
import net.sf.jabref.logic.journals.JournalAbbreviationLoader;
public class EntryFetchers {
private final List<EntryFetcher> entryFetchers = new LinkedList<>();
-
public EntryFetchers(JournalAbbreviationLoader abbreviationLoader) {
- entryFetchers.add(new ADSFetcher());
entryFetchers.add(new CiteSeerXFetcher());
- entryFetchers.add(new DBLPFetcher());
- entryFetchers.add(new DiVAtoBibTeXFetcher());
- entryFetchers.add(new DOItoBibTeXFetcher());
+ entryFetchers.add(new SearchBasedEntryFetcher(new DBLPFetcher(Globals.prefs.getImportFormatPreferences())));
entryFetchers.add(new IEEEXploreFetcher(abbreviationLoader));
entryFetchers.add(new INSPIREFetcher());
- entryFetchers.add(new ISBNtoBibTeXFetcher());
- entryFetchers.add(new MedlineFetcher());
// entryFetchers.add(new OAI2Fetcher()); - new arXiv fetcher in place, see below
// entryFetchers.add(new ScienceDirectFetcher()); currently not working - removed see #409
entryFetchers.add(new ACMPortalFetcher());
- entryFetchers.add(new GoogleScholarFetcher());
entryFetchers.add(new DOAJFetcher());
entryFetchers.add(new SpringerFetcher());
- entryFetchers.add(new SearchBasedEntryFetcher(new ArXiv()));
+ entryFetchers.add(new SearchBasedEntryFetcher(new ArXiv(Globals.prefs.getImportFormatPreferences())));
entryFetchers.add(new SearchBasedEntryFetcher(new GvkFetcher()));
+ entryFetchers.add(new SearchBasedEntryFetcher(new MedlineFetcher()));
+ entryFetchers.add(
+ new SearchBasedEntryFetcher(new AstrophysicsDataSystem(Globals.prefs.getImportFormatPreferences())));
+ entryFetchers.add(new SearchBasedEntryFetcher(new MathSciNet(Globals.prefs.getImportFormatPreferences())));
+ entryFetchers.add(new SearchBasedEntryFetcher(new zbMATH(Globals.prefs.getImportFormatPreferences())));
+ entryFetchers.add(new SearchBasedEntryFetcher(new GoogleScholar(Globals.prefs.getImportFormatPreferences())));
}
public List<EntryFetcher> getEntryFetchers() {
return Collections.unmodifiableList(this.entryFetchers);
}
+
+ public static ArrayList<IdBasedFetcher> getIdFetchers() {
+ ArrayList<IdBasedFetcher> list = new ArrayList<>();
+ list.add(new AstrophysicsDataSystem(Globals.prefs.getImportFormatPreferences()));
+ list.add(new IsbnFetcher(Globals.prefs.getImportFormatPreferences()));
+ list.add(new DiVA(Globals.prefs.getImportFormatPreferences()));
+ list.add(new DoiFetcher(Globals.prefs.getImportFormatPreferences()));
+ list.add(new MedlineFetcher());
+ list.sort((fetcher1, fetcher2) -> fetcher1.getName().compareTo(fetcher2.getName()));
+ return list;
+ }
+
+ public static ArrayList<EntryBasedFetcher> getEntryBasedFetchers() {
+ ArrayList<EntryBasedFetcher> list = new ArrayList<>();
+ list.add(new AstrophysicsDataSystem(Globals.prefs.getImportFormatPreferences()));
+ list.add(new MathSciNet(Globals.prefs.getImportFormatPreferences()));
+ list.sort((fetcher1, fetcher2) -> fetcher1.getName().compareTo(fetcher2.getName()));
+ return list;
+ }
}
diff --git a/src/main/java/net/sf/jabref/gui/importer/fetcher/GeneralFetcher.java b/src/main/java/net/sf/jabref/gui/importer/fetcher/GeneralFetcher.java
index 3c4e0e5..0897baa 100644
--- a/src/main/java/net/sf/jabref/gui/importer/fetcher/GeneralFetcher.java
+++ b/src/main/java/net/sf/jabref/gui/importer/fetcher/GeneralFetcher.java
@@ -12,8 +12,6 @@ import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
-import javax.swing.AbstractAction;
-import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComboBox;
@@ -31,7 +29,6 @@ import net.sf.jabref.gui.help.HelpAction;
import net.sf.jabref.gui.importer.FetcherPreviewDialog;
import net.sf.jabref.gui.importer.ImportInspectionDialog;
import net.sf.jabref.gui.keyboard.KeyBinding;
-import net.sf.jabref.gui.util.FocusRequester;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.util.OS;
import net.sf.jabref.preferences.JabRefPreferences;
@@ -45,15 +42,13 @@ public class GeneralFetcher extends SidePaneComponent implements ActionListener
private final JPanel optionsPanel = new JPanel(optionsCards);
private final JPanel optPanel = new JPanel(new BorderLayout());
- private final SidePaneManager sidePaneManager;
- private final Action action;
+ private final ToggleAction action;
private final JabRefFrame frame;
private EntryFetcher activeFetcher;
- public GeneralFetcher(SidePaneManager p0, JabRefFrame frame) {
- super(p0, IconTheme.JabRefIcon.WWW.getSmallIcon(), Localization.lang("Web search"));
- this.sidePaneManager = p0;
+ public GeneralFetcher(JabRefFrame frame, SidePaneManager sidePaneManager) {
+ super(sidePaneManager, IconTheme.JabRefIcon.WWW.getSmallIcon(), Localization.lang("Web search"));
this.frame = frame;
List<EntryFetcher> fetchers = new EntryFetchers(Globals.journalAbbreviationLoader).getEntryFetchers();
EntryFetcher[] fetcherArray = fetchers.toArray(new EntryFetcher[fetchers.size()]);
@@ -76,7 +71,7 @@ public class GeneralFetcher extends SidePaneComponent implements ActionListener
HelpAction help = new HelpAction(activeFetcher.getHelpPage());
JButton helpBut = help.getHelpButton();
helpBut.setEnabled(activeFetcher.getHelpPage() != null);
-
+
fetcherChoice.addActionListener(actionEvent -> {
activeFetcher = fetcherArray[fetcherChoice.getSelectedIndex()];
Globals.prefs.putInt(JabRefPreferences.SELECTED_FETCHER_INDEX, fetcherChoice.getSelectedIndex());
@@ -94,9 +89,10 @@ public class GeneralFetcher extends SidePaneComponent implements ActionListener
revalidate();
});
- action = new FetcherAction();
-
-
+ action = new ToggleAction(Localization.lang("Web search"),
+ Localization.lang("Toggle web search interface"),
+ Globals.getKeyPrefs().getKey(KeyBinding.WEB_SEARCH),
+ IconTheme.JabRefIcon.WWW);
helpBut.setMargin(new Insets(0, 0, 0, 0));
tf.setPreferredSize(new Dimension(1, tf.getPreferredSize().height));
@@ -109,7 +105,7 @@ public class GeneralFetcher extends SidePaneComponent implements ActionListener
JButton reset = new JButton(Localization.lang("Reset"));
reset.addActionListener(event -> {
tf.setText("");
- new FocusRequester(tf);
+ tf.requestFocus();
});
JPanel main = new JPanel();
@@ -146,11 +142,8 @@ public class GeneralFetcher extends SidePaneComponent implements ActionListener
gbl.setConstraints(helpBut, con);
main.add(helpBut);
- JPanel pan = new JPanel();
- if (pan != null) {
- gbl.setConstraints(optPanel, con);
- main.add(optPanel);
- }
+ gbl.setConstraints(optPanel, con);
+ main.add(optPanel);
main.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
add(main, BorderLayout.CENTER);
@@ -162,7 +155,8 @@ public class GeneralFetcher extends SidePaneComponent implements ActionListener
return tf;
}
- public Action getAction() {
+ @Override
+ public ToggleAction getToggleAction() {
return action;
}
@@ -229,37 +223,15 @@ public class GeneralFetcher extends SidePaneComponent implements ActionListener
}
}
-
- class FetcherAction extends AbstractAction {
-
- public FetcherAction() {
- super(Localization.lang("Web search"), IconTheme.JabRefIcon.WWW.getSmallIcon());
- //if ((activeFetcher.getKeyName() != null) && (activeFetcher.getKeyName().length() > 0))
- putValue(Action.ACCELERATOR_KEY, Globals.getKeyPrefs().getKey(KeyBinding.WEB_SEARCH));
- putValue(Action.LARGE_ICON_KEY, IconTheme.JabRefIcon.WWW.getIcon());
- putValue(Action.SHORT_DESCRIPTION, Localization.lang("Toggle web search interface"));
- }
-
- @Override
- public void actionPerformed(ActionEvent e) {
- if (!sidePaneManager.hasComponent(GeneralFetcher.this.getTitle())) {
- sidePaneManager.register(GeneralFetcher.this.getTitle(), GeneralFetcher.this);
- }
-
- if (frame.getTabbedPane().getTabCount() > 0) {
- sidePaneManager.toggle(GeneralFetcher.this.getTitle());
- if (sidePaneManager.isComponentVisible(GeneralFetcher.this.getTitle())) {
- new FocusRequester(getTextField());
- }
- }
- }
+ @Override
+ public void grabFocus() {
+ getTextField().grabFocus();
}
-
@Override
public void componentClosing() {
super.componentClosing();
- frame.setFetcherToggle(false);
+ getToggleAction().setSelected(false);
Globals.prefs.putBoolean(JabRefPreferences.WEB_SEARCH_VISIBLE, Boolean.FALSE);
}
diff --git a/src/main/java/net/sf/jabref/gui/importer/fetcher/GoogleScholarFetcher.java b/src/main/java/net/sf/jabref/gui/importer/fetcher/GoogleScholarFetcher.java
deleted file mode 100644
index 1effe29..0000000
--- a/src/main/java/net/sf/jabref/gui/importer/fetcher/GoogleScholarFetcher.java
+++ /dev/null
@@ -1,309 +0,0 @@
-package net.sf.jabref.gui.importer.fetcher;
-
-import java.io.IOException;
-import java.io.StringReader;
-import java.io.UnsupportedEncodingException;
-import java.net.MalformedURLException;
-import java.net.URLEncoder;
-import java.nio.charset.StandardCharsets;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-
-import net.sf.jabref.Globals;
-import net.sf.jabref.gui.importer.FetcherPreviewDialog;
-import net.sf.jabref.logic.help.HelpFile;
-import net.sf.jabref.logic.importer.ImportFormatPreferences;
-import net.sf.jabref.logic.importer.ImportInspector;
-import net.sf.jabref.logic.importer.OutputPrinter;
-import net.sf.jabref.logic.importer.ParserResult;
-import net.sf.jabref.logic.importer.fileformat.BibtexParser;
-import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.logic.net.URLDownload;
-import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.model.entry.FieldName;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-public class GoogleScholarFetcher implements PreviewEntryFetcher {
-
- private static final Log LOGGER = LogFactory.getLog(GoogleScholarFetcher.class);
-
- private boolean hasRunConfig;
- private static final int MAX_ENTRIES_TO_LOAD = 50;
- private static final String QUERY_MARKER = "___QUERY___";
- private static final String URL_START = "https://scholar.google.com";
- private static final String URL_SETTING = "https://scholar.google.com/scholar_settings";
- private static final String URL_SETPREFS = "https://scholar.google.com/scholar_setprefs";
- private static final String SEARCH_URL = GoogleScholarFetcher.URL_START + "/scholar?q=" + GoogleScholarFetcher.QUERY_MARKER
- + "&hl=en&btnG=Search&oe=utf-8";
-
- private static final Pattern BIBTEX_LINK_PATTERN = Pattern.compile("<a href=\"([^\"]*)\"[^>]*>[A-Za-z ]*BibTeX");
- private static final Pattern TITLE_START_PATTERN = Pattern.compile("<div class=\"gs_ri\">");
- private static final Pattern LINK_PATTERN = Pattern.compile("<h3 class=\"gs_rt\"><a href=\"([^\"]*)\">");
- private static final Pattern TITLE_END_PATTERN = Pattern.compile("<div class=\"gs_fl\">");
-
- private static final Pattern INPUT_PATTERN = Pattern.compile("<input type=([^ ]+) name=([^ ]+) value=([^> ]+)");
-
- private final Map<String, String> entryLinks = new HashMap<>();
-
- private boolean stopFetching;
-
-
- @Override
- public int getWarningLimit() {
- return 10;
- }
-
- @Override
- public int getPreferredPreviewHeight() {
- return 100;
- }
-
- @Override
- public boolean processQuery(String query, ImportInspector inspector, OutputPrinter status) {
- return false;
- }
-
- @Override
- public boolean processQueryGetPreview(String query, FetcherPreviewDialog preview, OutputPrinter status) {
- entryLinks.clear();
- stopFetching = false;
- try {
- if (!hasRunConfig) {
- runConfig();
- hasRunConfig = true;
- }
- Map<String, JLabel> citations = getCitations(query);
- for (Map.Entry<String, JLabel> linkEntry : citations.entrySet()) {
- preview.addEntry(linkEntry.getKey(), linkEntry.getValue());
- }
-
- return true;
- } catch (IOException e) {
- LOGGER.warn("Error fetching from Google Scholar", e);
- status.showMessage(Localization.lang("Error while fetching from %0", "Google Scholar"));
- return false;
- }
- }
-
- @Override
- public void getEntries(Map<String, Boolean> selection, ImportInspector inspector) {
- int toDownload = 0;
- for (Map.Entry<String, Boolean> selEntry : selection.entrySet()) {
- boolean isSelected = selEntry.getValue();
- if (isSelected) {
- toDownload++;
- }
- }
- if (toDownload == 0) {
- return;
- }
-
- int downloaded = 0;
-
- for (Map.Entry<String, Boolean> selEntry : selection.entrySet()) {
- if (stopFetching) {
- break;
- }
- inspector.setProgress(downloaded, toDownload);
- boolean isSelected = selEntry.getValue();
- if (isSelected) {
- downloaded++;
- try {
- BibEntry entry = downloadEntry(selEntry.getKey());
- inspector.addEntry(entry);
- } catch (IOException e) {
- LOGGER.warn("Cannot download entry from Google scholar", e);
- }
- }
- }
-
- }
-
- @Override
- public String getTitle() {
- return "Google Scholar";
- }
-
- @Override
- public HelpFile getHelpPage() {
- return HelpFile.FETCHER_GOOGLE_SCHOLAR;
- }
-
- @Override
- public JPanel getOptionsPanel() {
- return null;
- }
-
- @Override
- public void stopFetching() {
- stopFetching = true;
- }
-
- private static void runConfig() throws IOException {
- try {
- new URLDownload("http://scholar.google.com").downloadToString(StandardCharsets.UTF_8);
- String settingsPage = new URLDownload(GoogleScholarFetcher.URL_SETTING)
- .downloadToString(StandardCharsets.UTF_8);
- // Get the form items and their values from the page:
- Map<String, String> formItems = GoogleScholarFetcher.getFormElements(settingsPage);
- // Override the important ones:
- formItems.put("scis", "yes");
- formItems.put("scisf", "4");
- formItems.put("num", String.valueOf(GoogleScholarFetcher.MAX_ENTRIES_TO_LOAD));
- String request = formItems.entrySet().stream().map(Object::toString)
- .collect(Collectors.joining("&", GoogleScholarFetcher.URL_SETPREFS + "?", "&submit="));
- // Download the URL to set preferences:
- new URLDownload(request).downloadToString(Globals.prefs.getDefaultEncoding());
-
- } catch (UnsupportedEncodingException ex) {
- LOGGER.error("Unsupported encoding.", ex);
- }
- }
-
- /**
- * @param query The search term to query Google Scholar for.
- * @return a list of IDs
- * @throws java.io.IOException
- */
- private Map<String, JLabel> getCitations(String query) throws IOException {
- String urlQuery;
- LinkedHashMap<String, JLabel> res = new LinkedHashMap<>();
-
- urlQuery = GoogleScholarFetcher.SEARCH_URL.replace(GoogleScholarFetcher.QUERY_MARKER,
- URLEncoder.encode(query, StandardCharsets.UTF_8.name()));
- int count = 1;
- String nextPage;
- while (((nextPage = getCitationsFromUrl(urlQuery, res)) != null) && (count < 2)) {
- urlQuery = nextPage;
- count++;
- if (stopFetching) {
- break;
- }
- }
- return res;
- }
-
- private String getCitationsFromUrl(String urlQuery, Map<String, JLabel> ids) throws IOException {
- String cont = new URLDownload(urlQuery).downloadToString(StandardCharsets.UTF_8);
- Matcher m = GoogleScholarFetcher.BIBTEX_LINK_PATTERN.matcher(cont);
- int lastRegionStart = 0;
-
- while (m.find()) {
- String link = m.group(1).replace("&", "&");
- link = link+"&oe=utf-8"; // append param 'oe=utf-8' to tell google to serve UTF-8 encoded results
- String pText;
- String part = cont.substring(lastRegionStart, m.start());
- Matcher titleS = GoogleScholarFetcher.TITLE_START_PATTERN.matcher(part);
- Matcher titleE = GoogleScholarFetcher.TITLE_END_PATTERN.matcher(part);
- boolean fS = titleS.find();
- boolean fE = titleE.find();
- if (fS && fE) {
- if (titleS.end() < titleE.start()) {
- pText = part.substring(titleS.end(), titleE.start());
- } else {
- pText = part;
- }
- } else {
- pText = link;
- }
-
- pText = pText.replace("[PDF]", "");
- JLabel preview = new JLabel("<html>" + pText + "</html>");
- ids.put(link, preview);
-
- // See if we can extract the link Google Scholar puts on the entry's title.
- // That will be set as "url" for the entry if downloaded:
- Matcher linkMatcher = GoogleScholarFetcher.LINK_PATTERN.matcher(pText);
- if (linkMatcher.find()) {
- entryLinks.put(link, linkMatcher.group(1));
- }
-
- lastRegionStart = m.end();
- }
-
- /*m = NEXT_PAGE_PATTERN.matcher(cont);
- if (m.find()) {
- System.out.println("NEXT: "+URL_START+m.group(1).replace("&", "&"));
- return URL_START+m.group(1).replace("&", "&");
- }
- else*/
- return null;
- }
-
- private BibEntry downloadEntry(String link) throws IOException {
- try {
- String s = new URLDownload(link).downloadToString(StandardCharsets.UTF_8);
- BibtexParser bp = new BibtexParser(new StringReader(s),
- ImportFormatPreferences.fromPreferences(Globals.prefs));
- ParserResult pr = bp.parse();
- if ((pr != null) && (pr.getDatabase() != null)) {
- Collection<BibEntry> entries = pr.getDatabase().getEntries();
- if (entries.size() == 1) {
- BibEntry entry = entries.iterator().next();
- entry.clearField(BibEntry.KEY_FIELD);
- // If the entry's url field is not set, and we have stored an url for this
- // entry, set it:
- if (!entry.hasField(FieldName.URL)) {
- String storedUrl = entryLinks.get(link);
- if (storedUrl != null) {
- entry.setField(FieldName.URL, storedUrl);
- }
- }
-
- // Clean up some remaining HTML code from Elsevier(?) papers
- // Search for: Poincare algebra
- // to see an example
- entry.getFieldOptional(FieldName.TITLE).ifPresent(title -> {
- String newtitle = title.replaceAll("<.?i>([^<]*)</i>", "$1");
- if (!newtitle.equals(title)) {
- entry.setField(FieldName.TITLE, newtitle);
- }
- });
- return entry;
- } else if (entries.isEmpty()) {
- LOGGER.warn("No entry found! (" + link + ")");
- return null;
- } else {
- LOGGER.debug(entries.size() + " entries found! (" + link + ")");
- return null;
- }
- }
- LOGGER.warn("Parser failed! (" + link + ")");
- return null;
- } catch (MalformedURLException ex) {
- LOGGER.error("Malformed URL.", ex);
- return null;
- }
- }
-
-
-
- private static Map<String, String> getFormElements(String page) {
- Matcher m = GoogleScholarFetcher.INPUT_PATTERN.matcher(page);
- Map<String, String> items = new HashMap<>();
- while (m.find()) {
- String name = m.group(2);
- if ((name.length() > 2) && (name.charAt(0) == '"')
- && (name.charAt(name.length() - 1) == '"')) {
- name = name.substring(1, name.length() - 1);
- }
- String value = m.group(3);
- if ((value.length() > 2) && (value.charAt(0) == '"')
- && (value.charAt(value.length() - 1) == '"')) {
- value = value.substring(1, value.length() - 1);
- }
- items.put(name, value);
- }
- return items;
- }
-}
diff --git a/src/main/java/net/sf/jabref/gui/importer/fetcher/IEEEXploreFetcher.java b/src/main/java/net/sf/jabref/gui/importer/fetcher/IEEEXploreFetcher.java
index f84b594..9df5b94 100644
--- a/src/main/java/net/sf/jabref/gui/importer/fetcher/IEEEXploreFetcher.java
+++ b/src/main/java/net/sf/jabref/gui/importer/fetcher/IEEEXploreFetcher.java
@@ -2,11 +2,8 @@ package net.sf.jabref.gui.importer.fetcher;
import java.awt.BorderLayout;
import java.io.IOException;
-import java.net.ConnectException;
import java.net.CookieHandler;
import java.net.CookieManager;
-import java.net.MalformedURLException;
-import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
@@ -22,16 +19,15 @@ import javax.swing.JOptionPane;
import javax.swing.JPanel;
import net.sf.jabref.Globals;
+import net.sf.jabref.gui.importer.ImportInspectionDialog;
import net.sf.jabref.logic.formatter.bibtexfields.HtmlToLatexFormatter;
import net.sf.jabref.logic.formatter.bibtexfields.UnitsToLatexFormatter;
import net.sf.jabref.logic.formatter.casechanger.ProtectTermsFormatter;
import net.sf.jabref.logic.help.HelpFile;
-import net.sf.jabref.logic.importer.ImportFormatPreferences;
import net.sf.jabref.logic.importer.ImportInspector;
import net.sf.jabref.logic.importer.OutputPrinter;
import net.sf.jabref.logic.importer.fileformat.BibtexParser;
import net.sf.jabref.logic.journals.JournalAbbreviationLoader;
-import net.sf.jabref.logic.journals.JournalAbbreviationPreferences;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.net.URLDownload;
import net.sf.jabref.model.entry.BibEntry;
@@ -151,12 +147,7 @@ public class IEEEXploreFetcher implements EntryFetcher {
//parse the page into Bibtex entries
Collection<BibEntry> parsedBibtexCollection = BibtexParser.fromString(bibtexPage,
- ImportFormatPreferences.fromPreferences(Globals.prefs));
- if (parsedBibtexCollection == null) {
- status.showMessage(Localization.lang("Error while fetching from %0", getTitle()),
- DIALOG_TITLE, JOptionPane.INFORMATION_MESSAGE);
- return false;
- }
+ Globals.prefs.getImportFormatPreferences());
int nEntries = parsedBibtexCollection.size();
Iterator<BibEntry> parsedBibtexCollectionIterator = parsedBibtexCollection.iterator();
while (parsedBibtexCollectionIterator.hasNext() && shouldContinue) {
@@ -167,14 +158,9 @@ public class IEEEXploreFetcher implements EntryFetcher {
return true;
- } catch (MalformedURLException e) {
- LOGGER.warn("Bad URL", e);
- } catch (ConnectException | UnknownHostException e) {
- status.showMessage(Localization.lang("Could not connect to %0", getTitle()), DIALOG_TITLE,
- JOptionPane.ERROR_MESSAGE);
} catch (IOException | JSONException e) {
- status.showMessage(e.getMessage(), DIALOG_TITLE, JOptionPane.ERROR_MESSAGE);
- LOGGER.warn("Search IEEEXplore: " + e.getMessage(), e);
+ LOGGER.error("Error while fetching from " + getTitle(), e);
+ ((ImportInspectionDialog)dialog).showErrorMessage(this.getTitle(), e.getLocalizedMessage());
}
return false;
@@ -257,9 +243,9 @@ public class IEEEXploreFetcher implements EntryFetcher {
}
// clean up title
- entry.getFieldOptional(FieldName.TITLE).ifPresent(title -> {
+ entry.getField(FieldName.TITLE).ifPresent(dirtyTitle -> {
// USe the alt-text and replace image links
- title = title.replaceAll("[ ]?img src=[^ ]+ alt=\"([^\"]+)\">[ ]?", "\\$$1\\$");
+ String title = dirtyTitle.replaceAll("[ ]?img src=[^ ]+ alt=\"([^\"]+)\">[ ]?", "\\$$1\\$");
// Try to sort out most of the /spl / conversions
// Deal with this specific nested type first
title = title.replaceAll("/sub /spl infin//", "\\$_\\\\infty\\$");
@@ -289,8 +275,8 @@ public class IEEEXploreFetcher implements EntryFetcher {
});
// clean up author
- entry.getFieldOptional(FieldName.AUTHOR).ifPresent(author -> {
- author = author.replaceAll("\\s+", " ");
+ entry.getField(FieldName.AUTHOR).ifPresent(dirtyAuthor -> {
+ String author = dirtyAuthor.replaceAll("\\s+", " ");
//reorder the "Jr." "Sr." etc to the correct ordering
String[] authorSplit = author.split("(^\\s*|\\s*$|\\s+and\\s+)");
@@ -308,8 +294,8 @@ public class IEEEXploreFetcher implements EntryFetcher {
});
// clean up month
- entry.getFieldOptional(FieldName.MONTH).filter(month -> !month.isEmpty()).ifPresent(month -> {
- month = month.replace(".", "");
+ entry.getField(FieldName.MONTH).filter(month -> !month.isEmpty()).ifPresent(dirtyMonth -> {
+ String month = dirtyMonth.replace(".", "");
month = month.toLowerCase();
Matcher mm = MONTH_PATTERN.matcher(month);
@@ -341,7 +327,7 @@ public class IEEEXploreFetcher implements EntryFetcher {
});
// clean up pages
- entry.getFieldOptional(FieldName.PAGES).ifPresent(pages -> {
+ entry.getField(FieldName.PAGES).ifPresent(pages -> {
String[] pageNumbers = pages.split("-");
if (pageNumbers.length == 2) {
if (pageNumbers[0].equals(pageNumbers[1])) {// single page
@@ -362,7 +348,7 @@ public class IEEEXploreFetcher implements EntryFetcher {
sourceField = FieldName.BOOKTITLE;
}
if (entry.hasField(sourceField)) {
- String fullName = entry.getFieldOptional(sourceField).get();
+ String fullName = entry.getField(sourceField).get();
if ("article".equals(type)) {
int ind = fullName.indexOf(": Accepted for future publication");
if (ind > 0) {
@@ -377,7 +363,7 @@ public class IEEEXploreFetcher implements EntryFetcher {
if (parts.length == 3) {
fullName += parts[2];
}
- entry.getFieldOptional(FieldName.NOTE).filter(note -> "Early Access".equals(note)).ifPresent(note -> {
+ entry.getField(FieldName.NOTE).filter(note -> "Early Access".equals(note)).ifPresent(note -> {
entry.setField(FieldName.YEAR, "to be published");
entry.clearField(FieldName.MONTH);
entry.clearField(FieldName.PAGES);
@@ -421,7 +407,7 @@ public class IEEEXploreFetcher implements EntryFetcher {
fullName = fullName.trim();
if (Globals.prefs.getBoolean(JabRefPreferences.USE_IEEE_ABRV)) {
fullName = abbreviationLoader
- .getRepository(JournalAbbreviationPreferences.fromPreferences(Globals.prefs))
+ .getRepository(Globals.prefs.getJournalAbbreviationPreferences())
.getMedlineAbbreviation(fullName)
.orElse(fullName);
}
@@ -455,7 +441,7 @@ public class IEEEXploreFetcher implements EntryFetcher {
fullName = fullName.trim();
fullName = fullName.replaceAll("^[tT]he ", "").replaceAll("^\\d{4} ", "").replaceAll("[,.]$", "");
- Optional<String> year = entry.getFieldOptional(FieldName.YEAR);
+ Optional<String> year = entry.getField(FieldName.YEAR);
if (year.isPresent()) {
fullName = fullName.replaceAll(", " + year.get() + "\\.?", "");
}
@@ -469,10 +455,10 @@ public class IEEEXploreFetcher implements EntryFetcher {
}
// clean up abstract
- entry.getFieldOptional(FieldName.ABSTRACT).ifPresent(abstr -> {
+ entry.getField(FieldName.ABSTRACT).ifPresent(dirtyAbstr -> {
// Try to sort out most of the /spl / conversions
// Deal with this specific nested type first
- abstr = abstr.replaceAll("/sub /spl infin//", "\\$_\\\\infty\\$");
+ String abstr = dirtyAbstr.replaceAll("/sub /spl infin//", "\\$_\\\\infty\\$");
abstr = abstr.replaceAll("/sup /spl infin//", "\\$\\^\\\\infty\\$");
// Replace general expressions
abstr = abstr.replaceAll("/[sS]pl ([^/]+)/", "\\$\\\\$1\\$");
@@ -488,11 +474,11 @@ public class IEEEXploreFetcher implements EntryFetcher {
});
// Clean up url
- entry.getFieldOptional(FieldName.URL)
+ entry.getField(FieldName.URL)
.ifPresent(url -> entry.setField(FieldName.URL, "http://ieeexplore.ieee.org" + url.replace("tp=&", "")));
// Replace ; as keyword separator
- entry.getFieldOptional(FieldName.KEYWORDS).ifPresent(keys -> entry.setField(FieldName.KEYWORDS,
+ entry.getField(FieldName.KEYWORDS).ifPresent(keys -> entry.setField(FieldName.KEYWORDS,
keys.replace(";", Globals.prefs.get(JabRefPreferences.KEYWORD_SEPARATOR))));
return entry;
}
diff --git a/src/main/java/net/sf/jabref/gui/importer/fetcher/INSPIREFetcher.java b/src/main/java/net/sf/jabref/gui/importer/fetcher/INSPIREFetcher.java
index 7ff9459..d59bfe0 100644
--- a/src/main/java/net/sf/jabref/gui/importer/fetcher/INSPIREFetcher.java
+++ b/src/main/java/net/sf/jabref/gui/importer/fetcher/INSPIREFetcher.java
@@ -7,15 +7,13 @@ import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
-import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
-import javax.swing.JOptionPane;
import javax.swing.JPanel;
import net.sf.jabref.Globals;
+import net.sf.jabref.gui.importer.ImportInspectionDialog;
import net.sf.jabref.logic.help.HelpFile;
-import net.sf.jabref.logic.importer.ImportFormatPreferences;
import net.sf.jabref.logic.importer.ImportInspector;
import net.sf.jabref.logic.importer.OutputPrinter;
import net.sf.jabref.logic.importer.ParserResult;
@@ -101,25 +99,18 @@ public class INSPIREFetcher implements EntryFetcher {
* @param key The OAI2 key to fetch from ArXiv.
* @return The imported BibEntry or null if none.
*/
- private BibDatabase importInspireEntries(String key, OutputPrinter frame) {
+ private BibDatabase importInspireEntries(String key, OutputPrinter frame) throws IOException {
String url = constructUrl(key);
- try {
- HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
- conn.setRequestProperty("User-Agent", "JabRef");
- InputStream inputStream = conn.getInputStream();
-
- try (INSPIREBibtexFilterReader reader = new INSPIREBibtexFilterReader(
- new InputStreamReader(inputStream, Charset.forName("UTF-8")))) {
+ HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
+ conn.setRequestProperty("User-Agent", "JabRef");
+ InputStream inputStream = conn.getInputStream();
- ParserResult pr = BibtexParser.parse(reader, ImportFormatPreferences.fromPreferences(Globals.prefs));
+ try (INSPIREBibtexFilterReader reader = new INSPIREBibtexFilterReader(
+ new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
- return pr.getDatabase();
- }
- } catch (RuntimeException | IOException e) {
- frame.showMessage(Localization.lang("An exception occurred while accessing '%0'", url) + "\n\n" + e,
- getTitle(), JOptionPane.ERROR_MESSAGE);
+ ParserResult pr = BibtexParser.parse(reader, Globals.prefs.getImportFormatPreferences());
+ return pr.getDatabase();
}
- return null;
}
@@ -151,24 +142,20 @@ public class INSPIREFetcher implements EntryFetcher {
* @see java.lang.Runnable
*/
@Override
- public boolean processQuery(String query, ImportInspector dialog, OutputPrinter frame) {
+ public boolean processQuery(String query, ImportInspector dialog, OutputPrinter status) {
try {
- frame.setStatus(Localization.lang("Fetching entries from Inspire"));
+ status.setStatus(Localization.lang("Fetching entries from Inspire"));
/* query the archive and load the results into the BibEntry */
- BibDatabase bd = importInspireEntries(query, frame);
+ BibDatabase bd = importInspireEntries(query, status);
- frame.setStatus(Localization.lang("Adding fetched entries"));
+ status.setStatus(Localization.lang("Adding fetched entries"));
/* add the entry to the inspection dialog */
- if (bd == null) {
- LOGGER.warn("Error while fetching from Inspire");
- } else {
- bd.getEntries().forEach(dialog::addEntry);
- }
- /* inform the inspection dialog, that we're done */
+ bd.getEntries().forEach(dialog::addEntry);
+ return true;
} catch (Exception e) {
- frame.showMessage(Localization.lang("Error while fetching from %0", "Inspire") + ": " + e.getMessage());
- LOGGER.warn("Error while fetching from Inspire", e);
+ LOGGER.error("Error while fetching from " + getTitle(), e);
+ ((ImportInspectionDialog)dialog).showErrorMessage(this.getTitle(), e.getLocalizedMessage());
}
- return true;
+ return false;
}
}
diff --git a/src/main/java/net/sf/jabref/gui/importer/fetcher/ISBNtoBibTeXFetcher.java b/src/main/java/net/sf/jabref/gui/importer/fetcher/ISBNtoBibTeXFetcher.java
deleted file mode 100644
index 5158fc3..0000000
--- a/src/main/java/net/sf/jabref/gui/importer/fetcher/ISBNtoBibTeXFetcher.java
+++ /dev/null
@@ -1,154 +0,0 @@
-package net.sf.jabref.gui.importer.fetcher;
-
-import java.io.FileNotFoundException;
-import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLEncoder;
-import java.net.UnknownHostException;
-import java.nio.charset.StandardCharsets;
-import java.util.Optional;
-import java.util.Scanner;
-
-import javax.swing.JPanel;
-
-import net.sf.jabref.Globals;
-import net.sf.jabref.logic.formatter.bibtexfields.UnitsToLatexFormatter;
-import net.sf.jabref.logic.formatter.casechanger.ProtectTermsFormatter;
-import net.sf.jabref.logic.help.HelpFile;
-import net.sf.jabref.logic.importer.ImportFormatPreferences;
-import net.sf.jabref.logic.importer.ImportInspector;
-import net.sf.jabref.logic.importer.OutputPrinter;
-import net.sf.jabref.logic.importer.fileformat.BibtexParser;
-import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.model.entry.FieldName;
-import net.sf.jabref.preferences.JabRefPreferences;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * This class uses ebook.de's ISBN to BibTeX Converter to convert an ISBN to a BibTeX entry <br />
- * There is no separate web-based converter available, just that API
- */
-public class ISBNtoBibTeXFetcher implements EntryFetcher {
-
- private static final Log LOGGER = LogFactory.getLog(ISBNtoBibTeXFetcher.class);
-
- private static final String URL_PATTERN = "http://www.ebook.de/de/tools/isbn2bibtex?isbn=%s";
- private final ProtectTermsFormatter protectTermsFormatter = new ProtectTermsFormatter();
- private final UnitsToLatexFormatter unitsToLatexFormatter = new UnitsToLatexFormatter();
-
-
- @Override
- public void stopFetching() {
- // nothing needed as the fetching is a single HTTP GET
- }
-
- @Override
- public boolean processQuery(String query, ImportInspector inspector, OutputPrinter status) {
- Optional<BibEntry> entry = getEntryFromISBN(query, status);
- if (entry.isPresent()) {
- inspector.addEntry(entry.get());
- return true;
- }
- return false;
-
- }
-
- public Optional<BibEntry> getEntryFromISBN(String query, OutputPrinter status) {
- String q;
- try {
- q = URLEncoder.encode(query, StandardCharsets.UTF_8.name());
- } catch (UnsupportedEncodingException e) {
- // this should never happen
- if (status != null) {
- status.setStatus(Localization.lang("Error"));
- }
- LOGGER.warn("Shouldn't happen...", e);
- return Optional.empty();
- }
-
- String urlString = String.format(ISBNtoBibTeXFetcher.URL_PATTERN, q);
-
- // Send the request
- URL url;
- try {
- url = new URL(urlString);
- } catch (MalformedURLException e) {
- LOGGER.warn("Bad URL when fetching ISBN info", e);
- return Optional.empty();
- }
-
- try(InputStream source = url.openStream()) {
- String bibtexString;
- try(Scanner scan = new Scanner(source)) {
- bibtexString = scan.useDelimiter("\\A").next();
- }
-
- Optional<BibEntry> bibEntry = BibtexParser.singleFromString(bibtexString,
- ImportFormatPreferences.fromPreferences(Globals.prefs));
- bibEntry.ifPresent(entry -> {
- // Remove the added " Seiten" from the "pagetotal" field
- entry.getFieldOptional(FieldName.PAGETOTAL)
- .ifPresent(pagetotal -> entry.setField(FieldName.PAGETOTAL, pagetotal.replace(" Seiten", "")));
-
- // Optionally add curly brackets around key words to keep the case
- entry.getFieldOptional(FieldName.TITLE).ifPresent(title -> {
- // Unit formatting
- if (Globals.prefs.getBoolean(JabRefPreferences.USE_UNIT_FORMATTER_ON_SEARCH)) {
- title = unitsToLatexFormatter.format(title);
- }
-
- // Case keeping
- if (Globals.prefs.getBoolean(JabRefPreferences.USE_CASE_KEEPER_ON_SEARCH)) {
- title = protectTermsFormatter.format(title);
- }
- entry.setField(FieldName.TITLE, title);
- });
- });
- return bibEntry;
- } catch (FileNotFoundException e) {
- // invalid ISBN --> 404--> FileNotFoundException
- if (status != null) {
- status.showMessage(Localization.lang("No entry found for ISBN %0 at www.ebook.de", query));
- }
- LOGGER.debug("No ISBN info found", e);
- return Optional.empty();
- } catch (UnknownHostException e) {
- // It is very unlikely that ebook.de is an unknown host
- // It is more likely that we don't have an internet connection
- if (status != null) {
- status.showMessage(Localization.lang("No_internet_connection."));
- }
- LOGGER.debug("No internet connection", e);
- return Optional.empty();
- } catch (Exception e) {
- if (status != null) {
- status.showMessage(e.toString());
- }
- LOGGER.warn("Problem getting info for ISBN", e);
- return Optional.empty();
- }
- }
-
- @Override
- public String getTitle() {
- return "ISBN to BibTeX";
-
- }
-
- @Override
- public HelpFile getHelpPage() {
- return HelpFile.FETCHER_ISBN_TO_BIBTEX;
- }
-
- @Override
- public JPanel getOptionsPanel() {
- // no additional options available
- return null;
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/gui/importer/fetcher/IdBasedEntryFetcher.java b/src/main/java/net/sf/jabref/gui/importer/fetcher/IdBasedEntryFetcher.java
new file mode 100644
index 0000000..9a0a90e
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/importer/fetcher/IdBasedEntryFetcher.java
@@ -0,0 +1,65 @@
+package net.sf.jabref.gui.importer.fetcher;
+
+import java.util.Objects;
+import java.util.Optional;
+
+import javax.swing.JPanel;
+
+import net.sf.jabref.gui.importer.ImportInspectionDialog;
+import net.sf.jabref.logic.help.HelpFile;
+import net.sf.jabref.logic.importer.FetcherException;
+import net.sf.jabref.logic.importer.IdBasedFetcher;
+import net.sf.jabref.logic.importer.ImportInspector;
+import net.sf.jabref.logic.importer.OutputPrinter;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.entry.BibEntry;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class IdBasedEntryFetcher implements EntryFetcher {
+
+ private static final Log LOGGER = LogFactory.getLog(IdBasedEntryFetcher.class);
+ private final IdBasedFetcher fetcher;
+
+ public IdBasedEntryFetcher(IdBasedFetcher fetcher) {
+ this.fetcher = Objects.requireNonNull(fetcher);
+ }
+
+ @Override
+ public boolean processQuery(String query, ImportInspector inspector, OutputPrinter status) {
+
+ status.setStatus(Localization.lang("Processing %0", query));
+ try {
+ Optional<BibEntry> match = fetcher.performSearchById(query);
+ match.ifPresent(inspector::addEntry);
+ return match.isPresent();
+ } catch (FetcherException e) {
+ LOGGER.error("Error while fetching from " + getTitle(), e);
+ ((ImportInspectionDialog)inspector).showErrorMessage(this.getTitle(), e.getLocalizedMessage());
+ }
+
+ return false;
+ }
+
+ @Override
+ public String getTitle() {
+ return fetcher.getName();
+ }
+
+ @Override
+ public HelpFile getHelpPage() {
+ return fetcher.getHelpPage();
+ }
+
+ @Override
+ public JPanel getOptionsPanel() {
+ // not supported
+ return null;
+ }
+
+ @Override
+ public void stopFetching() {
+ // not supported
+ }
+}
diff --git a/src/main/java/net/sf/jabref/gui/importer/fetcher/MedlineFetcher.java b/src/main/java/net/sf/jabref/gui/importer/fetcher/MedlineFetcher.java
deleted file mode 100644
index c0da745..0000000
--- a/src/main/java/net/sf/jabref/gui/importer/fetcher/MedlineFetcher.java
+++ /dev/null
@@ -1,257 +0,0 @@
-package net.sf.jabref.gui.importer.fetcher;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLConnection;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-
-import net.sf.jabref.logic.help.HelpFile;
-import net.sf.jabref.logic.importer.ImportInspector;
-import net.sf.jabref.logic.importer.OutputPrinter;
-import net.sf.jabref.logic.importer.ParserResult;
-import net.sf.jabref.logic.importer.fileformat.MedlineImporter;
-import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.model.entry.BibEntry;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * Fetch or search from Pubmed http://www.ncbi.nlm.nih.gov/sites/entrez/
- *
- */
-public class MedlineFetcher implements EntryFetcher {
-
- private static final Log LOGGER = LogFactory.getLog(MedlineFetcher.class);
-
- private static final Pattern PART1_PATTERN = Pattern.compile(", ");
- private static final Pattern PART2_PATTERN = Pattern.compile(",");
-
- private static final Pattern ID_PATTERN = Pattern.compile("<Id>(\\d+)</Id>");
- private static final Pattern COUNT_PATTERN = Pattern.compile("<Count>(\\d+)<\\/Count>");
- private static final Pattern RET_MAX_PATTERN = Pattern.compile("<RetMax>(\\d+)<\\/RetMax>");
- private static final Pattern RET_START_PATTERN = Pattern.compile("<RetStart>(\\d+)<\\/RetStart>");
-
-
-
- /**
- * How many entries to query in one request
- */
- private static final int PACING = 20;
-
- private boolean shouldContinue;
- private static String toSearchTerm(String in) {
- // This can probably be simplified using simple String.replace()...
- String result = in;
- Matcher matcher;
- matcher = PART1_PATTERN.matcher(result);
- result = matcher.replaceAll("\\+AND\\+");
- matcher = PART2_PATTERN.matcher(result);
- result = matcher.replaceAll("\\+AND\\+");
- result = result.replace(" ", "+");
- return result;
- }
-
- /**
- * Gets the initial list of ids
- */
- private SearchResult getIds(String term, int start, int pacing) {
-
- String baseUrl = "http://eutils.ncbi.nlm.nih.gov/entrez/eutils";
- String medlineUrl = baseUrl + "/esearch.fcgi?db=pubmed&retmax=" + Integer.toString(pacing) +
- "&retstart=" + Integer.toString(start) + "&term=";
-
-
- boolean doCount = true;
- SearchResult result = new SearchResult();
- try {
- URL ncbi = new URL(medlineUrl + term);
- // get the ids
- BufferedReader in = new BufferedReader(new InputStreamReader(ncbi.openStream()));
- String inLine;
- while ((inLine = in.readLine()) != null) {
-
- // get the count
- Matcher idMatcher = ID_PATTERN.matcher(inLine);
- if (idMatcher.find()) {
- result.addID(idMatcher.group(1));
- }
- Matcher retMaxMatcher = RET_MAX_PATTERN.matcher(inLine);
- if (retMaxMatcher.find()) {
- result.retmax = Integer.parseInt(retMaxMatcher.group(1));
- }
- Matcher retStartMatcher = RET_START_PATTERN.matcher(inLine);
- if (retStartMatcher.find()) {
- result.retstart = Integer.parseInt(retStartMatcher.group(1));
- }
- Matcher countMatcher = COUNT_PATTERN.matcher(inLine);
- if (doCount && countMatcher.find()) {
- result.count = Integer.parseInt(countMatcher.group(1));
- doCount = false;
- }
- }
- } catch (MalformedURLException e) { // new URL() failed
- LOGGER.warn("Bad url", e);
- } catch (IOException e) { // openConnection() failed
- LOGGER.warn("Connection failed", e);
- }
- return result;
- }
-
- @Override
- public void stopFetching() {
- shouldContinue = false;
- }
-
- @Override
- public HelpFile getHelpPage() {
- return HelpFile.FETCHER_MEDLINE;
- }
-
- @Override
- public JPanel getOptionsPanel() {
- // No Option Panel
- return null;
- }
-
- @Override
- public String getTitle() {
- return "Medline";
- }
-
- @Override
- public boolean processQuery(String query, ImportInspector iIDialog, OutputPrinter frameOP) {
-
- shouldContinue = true;
-
- String cleanQuery = query.trim().replace(';', ',');
-
- if (cleanQuery.matches("\\d+[,\\d+]*")) {
- frameOP.setStatus(Localization.lang("Fetching Medline by id..."));
-
- List<BibEntry> bibs = fetchMedline(cleanQuery, frameOP);
-
- if (bibs.isEmpty()) {
- frameOP.showMessage(Localization.lang("No references found"));
- }
-
- for (BibEntry entry : bibs) {
- iIDialog.addEntry(entry);
- }
- return true;
- }
-
- if (!query.isEmpty()) {
- frameOP.setStatus(Localization.lang("Fetching Medline by term..."));
-
- String searchTerm = toSearchTerm(query);
-
- // get the ids from entrez
- SearchResult result = getIds(searchTerm, 0, 1);
-
- if (result.count == 0) {
- frameOP.showMessage(Localization.lang("No references found"));
- return false;
- }
-
- int numberToFetch = result.count;
- if (numberToFetch > MedlineFetcher.PACING) {
-
- while (true) {
- String strCount = JOptionPane.showInputDialog(Localization.lang("References found") +
- ": " + numberToFetch + " " +
- Localization.lang("Number of references to fetch?"), Integer
- .toString(numberToFetch));
-
- if (strCount == null) {
- frameOP.setStatus(Localization.lang("%0 import canceled", "Medline"));
- return false;
- }
-
- try {
- numberToFetch = Integer.parseInt(strCount.trim());
- break;
- } catch (NumberFormatException ex) {
- frameOP.showMessage(Localization.lang("Please enter a valid number"));
- }
- }
- }
-
- for (int i = 0; i < numberToFetch; i += MedlineFetcher.PACING) {
- if (!shouldContinue) {
- break;
- }
-
- int noToFetch = Math.min(MedlineFetcher.PACING, numberToFetch - i);
-
- // get the ids from entrez
- result = getIds(searchTerm, i, noToFetch);
-
- List<BibEntry> bibs = fetchMedline(result.ids, frameOP);
- for (BibEntry entry : bibs) {
- iIDialog.addEntry(entry);
- }
- iIDialog.setProgress(i + noToFetch, numberToFetch);
- }
- return true;
- }
- frameOP.showMessage(
- Localization.lang("Please enter a comma separated list of Medline IDs (numbers) or search terms."),
- Localization.lang("Input error"), JOptionPane.ERROR_MESSAGE);
- return false;
- }
-
- /**
- * Fetch and parse an medline item from eutils.ncbi.nlm.nih.gov.
- *
- * @param id One or several ids, separated by ","
- *
- * @return Will return an empty list on error.
- */
- private static List<BibEntry> fetchMedline(String id, OutputPrinter status) {
- String baseUrl = "http://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=pubmed&retmode=xml&rettype=citation&id=" +
- id;
- try {
- URL url = new URL(baseUrl);
- URLConnection data = url.openConnection();
- ParserResult result = new MedlineImporter().importDatabase(
- new BufferedReader(new InputStreamReader(data.getInputStream())));
- if (result.hasWarnings()) {
- status.showMessage(result.getErrorMessage());
- }
- return result.getDatabase().getEntries();
- } catch (IOException e) {
- return new ArrayList<>();
- }
- }
-
- static class SearchResult {
-
- public int count;
-
- public int retmax;
-
- public int retstart;
-
- public String ids = "";
-
-
- public void addID(String id) {
- if (ids.isEmpty()) {
- ids = id;
- } else {
- ids += "," + id;
- }
- }
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/gui/importer/fetcher/OAI2Fetcher.java b/src/main/java/net/sf/jabref/gui/importer/fetcher/OAI2Fetcher.java
index fe7d1f7..38bcaaf 100644
--- a/src/main/java/net/sf/jabref/gui/importer/fetcher/OAI2Fetcher.java
+++ b/src/main/java/net/sf/jabref/gui/importer/fetcher/OAI2Fetcher.java
@@ -16,6 +16,7 @@ import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
+import net.sf.jabref.gui.importer.ImportInspectionDialog;
import net.sf.jabref.logic.help.HelpFile;
import net.sf.jabref.logic.importer.ImportInspector;
import net.sf.jabref.logic.importer.OutputPrinter;
@@ -57,7 +58,6 @@ public class OAI2Fetcher implements EntryFetcher {
private final String oai2PrefixIdentifier;
private final String oai2ArchiveName;
private boolean shouldContinue = true;
- private OutputPrinter status;
private long waitTime = -1;
private Date lastCall;
@@ -158,7 +158,7 @@ public class OAI2Fetcher implements EntryFetcher {
* The OAI2 key to fetch from ArXiv.
* @return The imported BibEntry or null if none.
*/
- public BibEntry importOai2Entry(String key) {
+ protected BibEntry importOai2Entry(String key) throws IOException, SAXException {
/**
* Fix for problem reported in mailing-list:
* https://sourceforge.net/forum/message.php?msg_id=4087158
@@ -166,53 +166,36 @@ public class OAI2Fetcher implements EntryFetcher {
String fixedKey = OAI2Fetcher.fixKey(key);
String url = constructUrl(fixedKey);
- try {
- URL oai2Url = new URL(url);
- HttpURLConnection oai2Connection = (HttpURLConnection) oai2Url.openConnection();
- oai2Connection.setRequestProperty("User-Agent", "JabRef");
-
- /* create an empty BibEntry and set the oai2identifier field */
- BibEntry be = new BibEntry(IdGenerator.next(), "article");
- be.setField(OAI2Fetcher.OAI2_IDENTIFIER_FIELD, fixedKey);
- DefaultHandler handlerBase = new OAI2Handler(be);
-
- try (InputStream inputStream = oai2Connection.getInputStream()) {
-
- /* parse the result */
- saxParser.parse(inputStream, handlerBase);
-
- /* Correct line breaks and spacing */
- for (String name : be.getFieldNames()) {
- be.getFieldOptional(name)
- .ifPresent(content -> be.setField(name, OAI2Handler.correctLineBreaks(content)));
- }
+ URL oai2Url = new URL(url);
+ HttpURLConnection oai2Connection = (HttpURLConnection) oai2Url.openConnection();
+ oai2Connection.setRequestProperty("User-Agent", "JabRef");
+
+ /* create an empty BibEntry and set the oai2identifier field */
+ BibEntry entry = new BibEntry(IdGenerator.next(), "article");
+ entry.setField(OAI2Fetcher.OAI2_IDENTIFIER_FIELD, fixedKey);
+ DefaultHandler handlerBase = new OAI2Handler(entry);
+
+ try (InputStream inputStream = oai2Connection.getInputStream()) {
+ /* parse the result */
+ saxParser.parse(inputStream, handlerBase);
+
+ /* Correct line breaks and spacing */
+ for (String name : entry.getFieldNames()) {
+ entry.getField(name)
+ .ifPresent(content -> entry.setField(name, OAI2Handler.correctLineBreaks(content)));
+ }
- if (fixedKey.matches("\\d\\d\\d\\d\\..*")) {
- be.setField(FieldName.YEAR, "20" + fixedKey.substring(0, 2));
+ if (fixedKey.matches("\\d\\d\\d\\d\\..*")) {
+ entry.setField(FieldName.YEAR, "20" + fixedKey.substring(0, 2));
- int monthNumber = Integer.parseInt(fixedKey.substring(2, 4));
- MonthUtil.Month month = MonthUtil.getMonthByNumber(monthNumber);
- if (month.isValid()) {
- be.setField(FieldName.MONTH, month.bibtexFormat);
- }
+ int monthNumber = Integer.parseInt(fixedKey.substring(2, 4));
+ MonthUtil.Month month = MonthUtil.getMonthByNumber(monthNumber);
+ if (month.isValid()) {
+ entry.setField(FieldName.MONTH, month.bibtexFormat);
}
}
- return be;
- } catch (IOException e) {
- status.showMessage(Localization.lang("An exception occurred while accessing '%0'", url) + "\n\n" + e,
- getTitle(), JOptionPane.ERROR_MESSAGE);
- } catch (SAXException e) {
- status.showMessage(
- Localization.lang("A SAX exception occurred while parsing '%0':", url) + "\n\n" + e.getMessage(),
- getTitle(), JOptionPane.ERROR_MESSAGE);
- } catch (RuntimeException e) {
- status.showMessage(
- Localization.lang("Error while fetching from %0", "OAI2 source (" + url + "):") + "\n\n"
- + e.getMessage() + "\n\n" + Localization
- .lang("Note: A full text search is currently not supported for %0", getTitle()),
- getTitle(), JOptionPane.ERROR_MESSAGE);
}
- return null;
+ return entry;
}
@Override
@@ -232,10 +215,7 @@ public class OAI2Fetcher implements EntryFetcher {
}
@Override
- public boolean processQuery(String query, ImportInspector dialog, OutputPrinter statusOP) {
-
- status = statusOP;
-
+ public boolean processQuery(String query, ImportInspector dialog, OutputPrinter status) {
try {
shouldContinue = true;
@@ -268,7 +248,16 @@ public class OAI2Fetcher implements EntryFetcher {
}
/* query the archive and load the results into the BibEntry */
- BibEntry be = importOai2Entry(key);
+ BibEntry be = null;
+ try {
+ be = importOai2Entry(key);
+ } catch (SAXException e) {
+ String url = constructUrl(OAI2Fetcher.fixKey(key));
+ LOGGER.error("Error while fetching from " + getTitle(), e);
+ ((ImportInspectionDialog)dialog).showMessage(Localization.lang("Error while fetching from %0", getTitle()) +"\n"+
+ Localization.lang("A SAX exception occurred while parsing '%0':", url),
+ Localization.lang("Search %0", getTitle()), JOptionPane.ERROR_MESSAGE);
+ }
if (shouldWait()) {
lastCall = new Date();
@@ -284,10 +273,10 @@ public class OAI2Fetcher implements EntryFetcher {
}
return true;
- } catch (Exception e) {
- status.setStatus(Localization.lang("Error while fetching from %0", "OAI2"));
- LOGGER.error("Error while fetching from OAI2", e);
- }
+ } catch (IOException | InterruptedException e) {
+ LOGGER.error("Error while fetching from " + getTitle(), e);
+ ((ImportInspectionDialog)dialog).showErrorMessage(this.getTitle(), e.getLocalizedMessage());
+ }
return false;
}
diff --git a/src/main/java/net/sf/jabref/gui/importer/fetcher/PreviewEntryFetcher.java b/src/main/java/net/sf/jabref/gui/importer/fetcher/PreviewEntryFetcher.java
index 50fb34d..5a68541 100644
--- a/src/main/java/net/sf/jabref/gui/importer/fetcher/PreviewEntryFetcher.java
+++ b/src/main/java/net/sf/jabref/gui/importer/fetcher/PreviewEntryFetcher.java
@@ -9,7 +9,7 @@ import net.sf.jabref.logic.importer.OutputPrinter;
/**
*
*/
-interface PreviewEntryFetcher extends EntryFetcher {
+public interface PreviewEntryFetcher extends EntryFetcher {
boolean processQueryGetPreview(String query, FetcherPreviewDialog preview,
OutputPrinter status);
diff --git a/src/main/java/net/sf/jabref/gui/importer/fetcher/ScienceDirectFetcher.java b/src/main/java/net/sf/jabref/gui/importer/fetcher/ScienceDirectFetcher.java
index 7f4019a..e9f816f 100644
--- a/src/main/java/net/sf/jabref/gui/importer/fetcher/ScienceDirectFetcher.java
+++ b/src/main/java/net/sf/jabref/gui/importer/fetcher/ScienceDirectFetcher.java
@@ -12,8 +12,8 @@ import javax.swing.JOptionPane;
import javax.swing.JPanel;
import net.sf.jabref.Globals;
+import net.sf.jabref.gui.importer.ImportInspectionDialog;
import net.sf.jabref.logic.help.HelpFile;
-import net.sf.jabref.logic.importer.ImportFormatPreferences;
import net.sf.jabref.logic.importer.ImportInspector;
import net.sf.jabref.logic.importer.OutputPrinter;
import net.sf.jabref.logic.importer.fetcher.BibsonomyScraper;
@@ -87,7 +87,7 @@ public class ScienceDirectFetcher implements EntryFetcher {
if (stopFetching) {
break;
}
- BibsonomyScraper.getEntry(cit, ImportFormatPreferences.fromPreferences(Globals.prefs))
+ BibsonomyScraper.getEntry(cit, Globals.prefs.getImportFormatPreferences())
.ifPresent(dialog::addEntry);
dialog.setProgress(++i, citations.size());
}
@@ -96,8 +96,7 @@ public class ScienceDirectFetcher implements EntryFetcher {
} catch (IOException e) {
LOGGER.warn("Communcation problems", e);
- status.showMessage(
- Localization.lang("Error while fetching from %0", SCIENCE_DIRECT) + ": " + e.getMessage());
+ ((ImportInspectionDialog)dialog).showErrorMessage(this.getTitle(), e.getLocalizedMessage());
}
return false;
}
diff --git a/src/main/java/net/sf/jabref/gui/importer/fetcher/SearchBasedEntryFetcher.java b/src/main/java/net/sf/jabref/gui/importer/fetcher/SearchBasedEntryFetcher.java
index fef5fca..fdd27fc 100644
--- a/src/main/java/net/sf/jabref/gui/importer/fetcher/SearchBasedEntryFetcher.java
+++ b/src/main/java/net/sf/jabref/gui/importer/fetcher/SearchBasedEntryFetcher.java
@@ -5,6 +5,7 @@ import java.util.Objects;
import javax.swing.JPanel;
+import net.sf.jabref.gui.importer.ImportInspectionDialog;
import net.sf.jabref.logic.help.HelpFile;
import net.sf.jabref.logic.importer.FetcherException;
import net.sf.jabref.logic.importer.ImportInspector;
@@ -37,8 +38,8 @@ public class SearchBasedEntryFetcher implements EntryFetcher{
matches.forEach(inspector::addEntry);
return !matches.isEmpty();
} catch (FetcherException e) {
- status.setStatus(Localization.lang("Error while fetching from %0", fetcher.getName()));
- LOGGER.error("Error while fetching from" + fetcher.getName(), e);
+ LOGGER.error("Error while fetching from " + getTitle(), e);
+ ((ImportInspectionDialog)inspector).showErrorMessage(this.getTitle(), e.getLocalizedMessage());
}
return false;
diff --git a/src/main/java/net/sf/jabref/gui/importer/fetcher/SpringerFetcher.java b/src/main/java/net/sf/jabref/gui/importer/fetcher/SpringerFetcher.java
index 09db1e6..bd58379 100644
--- a/src/main/java/net/sf/jabref/gui/importer/fetcher/SpringerFetcher.java
+++ b/src/main/java/net/sf/jabref/gui/importer/fetcher/SpringerFetcher.java
@@ -1,26 +1,27 @@
package net.sf.jabref.gui.importer.fetcher;
- import java.io.UnsupportedEncodingException;
- import java.net.URLEncoder;
+import java.io.IOException;
+import java.net.URLEncoder;
- import javax.swing.JOptionPane;
- import javax.swing.JPanel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import net.sf.jabref.gui.importer.ImportInspectionDialog;
import net.sf.jabref.logic.help.HelpFile;
import net.sf.jabref.logic.importer.ImportInspector;
import net.sf.jabref.logic.importer.OutputPrinter;
import net.sf.jabref.logic.importer.util.JSONEntryParser;
import net.sf.jabref.logic.l10n.Localization;
- import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.BibEntry;
- import com.mashape.unirest.http.HttpResponse;
- import com.mashape.unirest.http.JsonNode;
- import com.mashape.unirest.http.Unirest;
- import com.mashape.unirest.http.exceptions.UnirestException;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- import org.json.JSONArray;
- import org.json.JSONObject;
+import com.mashape.unirest.http.HttpResponse;
+import com.mashape.unirest.http.JsonNode;
+import com.mashape.unirest.http.Unirest;
+import com.mashape.unirest.http.exceptions.UnirestException;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.json.JSONArray;
+import org.json.JSONObject;
public class SpringerFetcher implements EntryFetcher {
@@ -47,16 +48,12 @@ public class SpringerFetcher implements EntryFetcher {
.header("accept", "application/json")
.asJson();
JSONObject jo = jsonResponse.getBody().getObject();
- int hits = jo.getJSONArray("result").getJSONObject(0).getInt("total");
- int numberToFetch = 0;
- if (hits > 0) {
- if (hits > MAX_PER_PAGE) {
- while (true) {
- String strCount = JOptionPane
- .showInputDialog(
- Localization.lang("References found") + ": " + hits + " "
- + Localization.lang("Number of references to fetch?"),
- Integer.toString(hits));
+ int numberToFetch = jo.getJSONArray("result").getJSONObject(0).getInt("total");
+ if (numberToFetch > 0) {
+ if (numberToFetch > MAX_PER_PAGE) {
+ boolean numberEntered = false;
+ do {
+ String strCount = JOptionPane.showInputDialog(Localization.lang("%0 references found. Number of references to fetch?", String.valueOf(numberToFetch)));
if (strCount == null) {
status.setStatus(Localization.lang("%0 import canceled", getTitle()));
@@ -65,13 +62,11 @@ public class SpringerFetcher implements EntryFetcher {
try {
numberToFetch = Integer.parseInt(strCount.trim());
- break;
+ numberEntered = true;
} catch (NumberFormatException ex) {
status.showMessage(Localization.lang("Please enter a valid number"));
}
- }
- } else {
- numberToFetch = hits;
+ } while (!numberEntered);
}
int fetched = 0; // Keep track of number of items fetched for the progress bar
@@ -102,10 +97,9 @@ public class SpringerFetcher implements EntryFetcher {
Localization.lang("Search %0", getTitle()), JOptionPane.INFORMATION_MESSAGE);
return false;
}
- } catch (UnirestException e) {
- LOGGER.warn("Problem searching Springer", e);
- } catch (UnsupportedEncodingException e) {
- LOGGER.warn("Cannot encode query", e);
+ } catch (IOException | UnirestException e) {
+ LOGGER.error("Error while fetching from " + getTitle(), e);
+ ((ImportInspectionDialog)inspector).showErrorMessage(this.getTitle(), e.getLocalizedMessage());
}
return false;
diff --git a/src/main/java/net/sf/jabref/gui/importer/worker/AutosaveStartupPrompter.java b/src/main/java/net/sf/jabref/gui/importer/worker/AutosaveStartupPrompter.java
deleted file mode 100644
index 2891dea..0000000
--- a/src/main/java/net/sf/jabref/gui/importer/worker/AutosaveStartupPrompter.java
+++ /dev/null
@@ -1,101 +0,0 @@
-package net.sf.jabref.gui.importer.worker;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.swing.JOptionPane;
-
-import net.sf.jabref.BibDatabaseContext;
-import net.sf.jabref.Globals;
-import net.sf.jabref.gui.BasePanel;
-import net.sf.jabref.gui.JabRefFrame;
-import net.sf.jabref.gui.importer.ParserResultWarningDialog;
-import net.sf.jabref.logic.importer.ImportFormatPreferences;
-import net.sf.jabref.logic.importer.OpenDatabase;
-import net.sf.jabref.logic.importer.ParserResult;
-import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.logic.util.io.AutoSaveUtil;
-import net.sf.jabref.preferences.JabRefPreferences;
-
-/**
- * Runnable task that prompts the user for what to do about files loaded at startup,
- * where an autosave file was found. The task should be run on the EDT after startup.
- */
-public class AutosaveStartupPrompter implements Runnable {
-
- private final JabRefFrame frame;
- private final List<File> files;
-
-
- public AutosaveStartupPrompter(JabRefFrame frame, List<File> files) {
-
- this.frame = frame;
- this.files = files;
- }
-
- @Override
- public void run() {
- boolean first = frame.getBasePanelCount() == 0;
- List<ParserResult> loaded = new ArrayList<>();
- Map<ParserResult, Integer> location = new HashMap<>();
- for (File file : files) {
- File fileToLoad = file;
- boolean tryingAutosave;
- if (Globals.prefs.getBoolean(JabRefPreferences.PROMPT_BEFORE_USING_AUTOSAVE)) {
- int answer = JOptionPane.showConfirmDialog(null, "<html>" +
- Localization.lang("An autosave file was found for this database. This could indicate "
- + "that JabRef did not shut down cleanly last time the file was used.") + "<br>"
- + Localization.lang("Do you want to recover the database from the autosave file?") + "</html>",
- Localization.lang("Autosave of file '%0'", file.getName()), JOptionPane.YES_NO_OPTION);
- tryingAutosave = answer == JOptionPane.YES_OPTION;
- } else {
- tryingAutosave = true;
- }
-
- if (tryingAutosave) {
- fileToLoad = AutoSaveUtil.getAutoSaveFile(file);
- }
- boolean done = false;
- ParserResult pr;
- do {
- pr = OpenDatabase.loadDatabaseOrAutoSave(fileToLoad.getPath(), true,
- ImportFormatPreferences.fromPreferences(Globals.prefs));
- if (pr.isInvalid()) {
- loaded.add(pr);
- BibDatabaseContext databaseContext = pr.getDatabaseContext();
- databaseContext.setDatabaseFile(file);
- BasePanel panel = frame.addTab(databaseContext, first);
- location.put(pr, frame.getBasePanelCount() - 1);
- if (tryingAutosave) {
- panel.markNonUndoableBaseChanged();
- }
-
- first = false;
- done = true;
- } else {
- if (tryingAutosave) {
- JOptionPane.showMessageDialog(frame,
- Localization.lang("Error opening autosave of '%0'. Trying to load '%0' instead.", file.getName()),
- Localization.lang("Error opening file"), JOptionPane.ERROR_MESSAGE);
- tryingAutosave = false;
- fileToLoad = file;
- } else {
- String message = "<html>" + pr.getErrorMessage() + "<p>"
- + Localization.lang("Error opening file '%0'.", file.getName()) + "</html>";
- JOptionPane.showMessageDialog(frame,
- message, Localization.lang("Error opening file"), JOptionPane.ERROR_MESSAGE);
- done = true;
- }
-
- }
- } while (!done);
-
- if (!pr.isInvalid()) {
- ParserResultWarningDialog.showParserResultWarningDialog(pr, frame);
- }
- }
- }
-}
diff --git a/src/main/java/net/sf/jabref/gui/journals/AbbreviateAction.java b/src/main/java/net/sf/jabref/gui/journals/AbbreviateAction.java
index 489bd0d..1e5e78b 100644
--- a/src/main/java/net/sf/jabref/gui/journals/AbbreviateAction.java
+++ b/src/main/java/net/sf/jabref/gui/journals/AbbreviateAction.java
@@ -6,7 +6,6 @@ import net.sf.jabref.Globals;
import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.gui.undo.NamedCompound;
import net.sf.jabref.gui.worker.AbstractWorker;
-import net.sf.jabref.logic.journals.JournalAbbreviationPreferences;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.InternalBibtexFields;
@@ -39,7 +38,7 @@ public class AbbreviateAction extends AbstractWorker {
}
UndoableAbbreviator undoableAbbreviator = new UndoableAbbreviator(Globals.journalAbbreviationLoader
- .getRepository(JournalAbbreviationPreferences.fromPreferences(Globals.prefs)), iso);
+ .getRepository(Globals.prefs.getJournalAbbreviationPreferences()), iso);
NamedCompound ce = new NamedCompound(Localization.lang("Abbreviate journal names"));
int count = 0;
diff --git a/src/main/java/net/sf/jabref/gui/journals/ManageJournalsPanel.java b/src/main/java/net/sf/jabref/gui/journals/ManageJournalsPanel.java
index 907b06e..826219b 100644
--- a/src/main/java/net/sf/jabref/gui/journals/ManageJournalsPanel.java
+++ b/src/main/java/net/sf/jabref/gui/journals/ManageJournalsPanel.java
@@ -7,7 +7,6 @@ import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
-
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -43,18 +42,15 @@ import javax.swing.JTextField;
import javax.swing.table.AbstractTableModel;
import net.sf.jabref.Globals;
-
import net.sf.jabref.gui.FileDialog;
import net.sf.jabref.gui.IconTheme;
import net.sf.jabref.gui.JabRefFrame;
import net.sf.jabref.gui.help.HelpAction;
import net.sf.jabref.gui.keyboard.KeyBinding;
import net.sf.jabref.gui.net.MonitoredURLDownload;
-import net.sf.jabref.gui.util.GUIUtil;
import net.sf.jabref.logic.help.HelpFile;
import net.sf.jabref.logic.journals.Abbreviation;
import net.sf.jabref.logic.journals.JournalAbbreviationLoader;
-import net.sf.jabref.logic.journals.JournalAbbreviationPreferences;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.util.OS;
import net.sf.jabref.preferences.JabRefPreferences;
@@ -175,8 +171,7 @@ class ManageJournalsPanel extends JPanel {
viewBuiltin.addActionListener(e -> {
JTable table = new JTable(JournalAbbreviationsUtil.getTableModel(Globals.journalAbbreviationLoader
- .getRepository(JournalAbbreviationPreferences.fromPreferences(Globals.prefs)).getAbbreviations()));
- GUIUtil.correctRowHeight(table);
+ .getRepository(Globals.prefs.getJournalAbbreviationPreferences()).getAbbreviations()));
JScrollPane pane = new JScrollPane(table);
JOptionPane.showMessageDialog(null, pane, Localization.lang("Journal list preview"),
@@ -311,7 +306,6 @@ class ManageJournalsPanel extends JPanel {
tableModel.setJournals(userAbbreviations);
userTable = new JTable(tableModel);
- GUIUtil.correctRowHeight(userTable);
userTable.addMouseListener(tableModel.getMouseListener());
userPanel.add(new JScrollPane(userTable), BorderLayout.CENTER);
@@ -379,7 +373,7 @@ class ManageJournalsPanel extends JPanel {
Globals.prefs.putStringList(JabRefPreferences.EXTERNAL_JOURNAL_LISTS, extFiles);
// Update journal abbreviation loader
- Globals.journalAbbreviationLoader.update(JournalAbbreviationPreferences.fromPreferences(Globals.prefs));
+ Globals.journalAbbreviationLoader.update(Globals.prefs.getJournalAbbreviationPreferences());
}
@@ -570,7 +564,6 @@ class ManageJournalsPanel extends JPanel {
.readJournalListFromFile(new File(tf.getText()));
JTable table = new JTable(JournalAbbreviationsUtil.getTableModel(abbreviations));
- GUIUtil.correctRowHeight(table);
JScrollPane pane = new JScrollPane(table);
JOptionPane.showMessageDialog(null, pane, Localization.lang("Journal list preview"),
diff --git a/src/main/java/net/sf/jabref/gui/journals/UnabbreviateAction.java b/src/main/java/net/sf/jabref/gui/journals/UnabbreviateAction.java
index 9486ac3..1e8c129 100644
--- a/src/main/java/net/sf/jabref/gui/journals/UnabbreviateAction.java
+++ b/src/main/java/net/sf/jabref/gui/journals/UnabbreviateAction.java
@@ -6,7 +6,6 @@ import net.sf.jabref.Globals;
import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.gui.undo.NamedCompound;
import net.sf.jabref.gui.worker.AbstractWorker;
-import net.sf.jabref.logic.journals.JournalAbbreviationPreferences;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.InternalBibtexFields;
@@ -37,7 +36,7 @@ public class UnabbreviateAction extends AbstractWorker {
}
UndoableUnabbreviator undoableAbbreviator = new UndoableUnabbreviator(Globals.journalAbbreviationLoader
- .getRepository(JournalAbbreviationPreferences.fromPreferences(Globals.prefs)));
+ .getRepository(Globals.prefs.getJournalAbbreviationPreferences()));
NamedCompound ce = new NamedCompound(Localization.lang("Unabbreviate journal names"));
int count = 0;
diff --git a/src/main/java/net/sf/jabref/gui/journals/UndoableAbbreviator.java b/src/main/java/net/sf/jabref/gui/journals/UndoableAbbreviator.java
index 29956e9..72dba5a 100644
--- a/src/main/java/net/sf/jabref/gui/journals/UndoableAbbreviator.java
+++ b/src/main/java/net/sf/jabref/gui/journals/UndoableAbbreviator.java
@@ -32,7 +32,7 @@ public class UndoableAbbreviator {
if (!entry.hasField(fieldName)) {
return false;
}
- String text = entry.getFieldOptional(fieldName).get();
+ String text = entry.getField(fieldName).get();
String origText = text;
if (database != null) {
text = database.resolveForStrings(text);
diff --git a/src/main/java/net/sf/jabref/gui/journals/UndoableUnabbreviator.java b/src/main/java/net/sf/jabref/gui/journals/UndoableUnabbreviator.java
index f3f675a..100a5c3 100644
--- a/src/main/java/net/sf/jabref/gui/journals/UndoableUnabbreviator.java
+++ b/src/main/java/net/sf/jabref/gui/journals/UndoableUnabbreviator.java
@@ -29,7 +29,7 @@ public class UndoableUnabbreviator {
if (!entry.hasField(fieldName)) {
return false;
}
- String text = entry.getFieldOptional(fieldName).get();
+ String text = entry.getField(fieldName).get();
String origText = text;
if (database != null) {
text = database.resolveForStrings(text);
diff --git a/src/main/java/net/sf/jabref/gui/keyboard/KeyBinding.java b/src/main/java/net/sf/jabref/gui/keyboard/KeyBinding.java
index 6e39a12..7ae5136 100644
--- a/src/main/java/net/sf/jabref/gui/keyboard/KeyBinding.java
+++ b/src/main/java/net/sf/jabref/gui/keyboard/KeyBinding.java
@@ -4,14 +4,13 @@ import net.sf.jabref.logic.l10n.Localization;
public enum KeyBinding {
- ABBREVIATE(
- "Abbreviate", Localization.lang("Abbreviate journal names"), "ctrl alt A"),
+ ABBREVIATE("Abbreviate", Localization.lang("Abbreviate journal names"), "ctrl alt A"),
+ ACCEPT("Accept", Localization.lang("Accept"), "ctrl ENTER"),
AUTOGENERATE_BIBTEX_KEYS("Autogenerate BibTeX keys", Localization.lang("Autogenerate BibTeX keys"), "ctrl G"),
- AUTOMATICALLY_LINK_FILES(
- "Automatically link files", Localization.lang("Automatically set file links"), "F7"),
+ AUTOMATICALLY_LINK_FILES("Automatically link files", Localization.lang("Automatically set file links"), "F7"),
BACK("Back", Localization.lang("Back"), "alt LEFT"),
- CLEANUP(
- "Cleanup", Localization.lang("Cleanup entries"), "F8"),
+ CHECK_INTEGRITY("Check integrity", Localization.menuTitle("Check integrity"), "ctrl F8"),
+ CLEANUP("Cleanup", Localization.lang("Cleanup entries"), "F8"),
CLEAR_SEARCH("Clear search", Localization.lang("Clear search"), "ESCAPE"),
CLOSE_DATABASE("Close database", Localization.lang("Close database"), "ctrl W"),
CLOSE_DIALOG("Close dialog", Localization.lang("Close dialog"), "ESCAPE"),
@@ -20,6 +19,7 @@ public enum KeyBinding {
COPY_CITE_BIBTEX_KEY("Copy \\cite{BibTeX key}", Localization.lang("Copy \\cite{BibTeX key}"), "ctrl K"),
COPY_BIBTEX_KEY("Copy BibTeX key", Localization.lang("Copy BibTeX key"), "ctrl shift K"),
COPY_BIBTEX_KEY_AND_TITLE("Copy BibTeX key and title", Localization.lang("Copy BibTeX key and title"), "ctrl shift alt K"),
+ COPY_BIBTEX_KEY_AND_LINK("Copy BibTeX key and link", Localization.lang("Copy BibTeX key and link"), "ctrl alt K"),
COPY_PREVIEW("Copy preview", Localization.lang("Copy preview"), "ctrl shift C"),
CUT("Cut", Localization.lang("Cut"), "ctrl X"),
DECREASE_TABLE_FONT_SIZE("Decrease table font size", Localization.lang("Decrease table font size"), "ctrl MINUS"),
@@ -38,6 +38,7 @@ public enum KeyBinding {
FIND_UNLINKED_FILES("Find unlinked files", Localization.lang("Find unlinked files"), "shift F7"),
FOCUS_ENTRY_TABLE("Focus entry table", Localization.lang("Focus entry table"), "alt 1"),
FORWARD("Forward", Localization.lang("Forward"), "alt RIGHT"),
+ GLOBAL_SEARCH("Search globally", Localization.lang("Search globally"), "ctrl shift F"),
HELP("Help", Localization.lang("Help"), "F1"),
IMPORT_INTO_CURRENT_DATABASE("Import into current database", Localization.lang("Import into current database"), "ctrl I"),
IMPORT_INTO_NEW_DATABASE("Import into new database", Localization.lang("Import into new database"), "ctrl alt I"),
@@ -53,32 +54,34 @@ public enum KeyBinding {
NEW_PROCEEDINGS("New proceedings", Localization.lang("New proceedings"), "ctrl shift P"),
NEW_UNPUBLISHED("New unpublished", Localization.lang("New unpublished"), "ctrl shift U"),
NEW_TECHREPORT("New technical report", Localization.lang("New technical report"), "ctrl shift R"),
+ NEXT_PREVIEW_LAYOUT("Next preview layout", Localization.lang("Next preview layout"), "F9"),
NEXT_TAB("Next tab", Localization.lang("Next tab"), "ctrl PAGE_DOWN"),
OPEN_CONSOLE("Open terminal here", Localization.lang("Open terminal here"), "ctrl shift L"),
OPEN_DATABASE("Open database", Localization.lang("Open database"), "ctrl O"),
OPEN_FILE("Open file", Localization.lang("Open file"), "F4"),
OPEN_FOLDER("Open folder", Localization.lang("Open folder"), "ctrl shift O"),
+ OPEN_OPEN_OFFICE_LIBRE_OFFICE_CONNECTION("Open OpenOffice/LibreOffice connection", Localization.lang("Open OpenOffice/LibreOffice connection"), "alt 0"),
OPEN_URL_OR_DOI("Open URL or DOI", Localization.lang("Open URL or DOI"), "F3"),
PASTE("Paste", Localization.lang("Paste"), "ctrl V"),
PULL_CHANGES_FROM_SHARED_DATABASE("Pull changes from shared database", Localization.lang("Pull changes from shared database"), "ctrl shift R"),
PREAMBLE_EDITOR_STORE_CHANGES("Preamble editor, store changes", Localization.lang("Preamble editor, store changes"), "alt S"),
+ PREVIOUS_PREVIEW_LAYOUT("Previous preview layout", Localization.lang("Previous preview layout"), "shift F9"),
PREVIOUS_TAB("Previous tab", Localization.lang("Previous tab"), "ctrl PAGE_UP"),
PUSH_TO_APPLICATION("Push to application", Localization.lang("Push to application"), "ctrl L"),
QUIT_JABREF("Quit JabRef", Localization.lang("Quit JabRef"), "ctrl Q"),
REDO("Redo", Localization.lang("Redo"), "ctrl Y"),
- REFRESH_OO(
- "Refresh OO", Localization.lang("Refresh OpenOffice/LibreOffice"), "ctrl alt O"),
+ REFRESH_OO("Refresh OO", Localization.lang("Refresh OpenOffice/LibreOffice"), "ctrl alt O"),
REPLACE_STRING("Replace string", Localization.lang("Replace string"), "ctrl R"),
RESOLVE_DUPLICATE_BIBTEX_KEYS("Resolve duplicate BibTeX keys", Localization.lang("Resolve duplicate BibTeX keys"), "ctrl shift D"),
SAVE_ALL("Save all", Localization.lang("Save all"), "ctrl alt S"),
SAVE_DATABASE("Save database", Localization.lang("Save database"), "ctrl S"),
- SAVE_DATABASE_AS(
- "Save database as ...", Localization.lang("Save database as..."), "ctrl shift S"),
+ SAVE_DATABASE_AS("Save database as ...", Localization.lang("Save database as..."), "ctrl shift S"),
SEARCH("Search", Localization.lang("Search"), "ctrl F"),
SELECT_ALL("Select all", Localization.lang("Select all"), "ctrl A"),
+ SELECT_FIRST_ENTRY("Select first entry", Localization.lang("Select first entry"), "HOME"),
+ SELECT_LAST_ENTRY("Select last entry", Localization.lang("Select last entry"), "END"),
STRING_DIALOG_ADD_STRING("String dialog, add string", Localization.lang("String dialog, add string"), "ctrl N"),
STRING_DIALOG_REMOVE_STRING("String dialog, remove string", Localization.lang("String dialog, remove string"), "shift DELETE"),
- SWITCH_PREVIEW_LAYOUT("Switch preview layout", Localization.lang("Switch preview layout"), "F9"),
SYNCHRONIZE_FILES("Synchronize files", Localization.lang("Synchronize files"), "ctrl shift F7"),
TOGGLE_ENTRY_PREVIEW("Toggle entry preview", Localization.lang("Toggle entry preview"), "alt 2"),
TOGGLE_GROUPS_INTERFACE("Toggle groups interface", Localization.lang("Toggle groups interface"), "alt 3"),
@@ -86,8 +89,7 @@ public enum KeyBinding {
UNDO("Undo", Localization.lang("Undo"), "ctrl Z"),
UNMARK_ENTRIES("Unmark entries", Localization.lang("Unmark entries"), "ctrl shift M"),
WEB_SEARCH("Web search", Localization.lang("Web search"), "alt 4"),
- WRITE_XMP("Write XMP", Localization.lang("Write XMP"), "F6"),
- OPEN_OPEN_OFFICE_LIBRE_OFFICE_CONNECTION("Open OpenOffice/LibreOffice connection", Localization.lang("Open OpenOffice/LibreOffice connection"), "alt 0"),;
+ WRITE_XMP("Write XMP", Localization.lang("Write XMP"), "F6");
private final String key;
private final String localization;
diff --git a/src/main/java/net/sf/jabref/gui/keyboard/KeyBindingsDialog.java b/src/main/java/net/sf/jabref/gui/keyboard/KeyBindingsDialog.java
index 78c972f..4618d66 100644
--- a/src/main/java/net/sf/jabref/gui/keyboard/KeyBindingsDialog.java
+++ b/src/main/java/net/sf/jabref/gui/keyboard/KeyBindingsDialog.java
@@ -15,7 +15,6 @@ import javax.swing.ListSelectionModel;
import javax.swing.table.TableColumnModel;
import net.sf.jabref.Globals;
-import net.sf.jabref.gui.util.GUIUtil;
import net.sf.jabref.logic.l10n.Localization;
/**
@@ -79,7 +78,6 @@ public class KeyBindingsDialog extends JDialog {
table.setColumnSelectionAllowed(false);
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
table.setAutoCreateRowSorter(true);
- GUIUtil.correctRowHeight(table);
return table;
}
diff --git a/src/main/java/net/sf/jabref/gui/keyboard/KeyBindingsListener.java b/src/main/java/net/sf/jabref/gui/keyboard/KeyBindingsListener.java
index 2181653..5805b38 100644
--- a/src/main/java/net/sf/jabref/gui/keyboard/KeyBindingsListener.java
+++ b/src/main/java/net/sf/jabref/gui/keyboard/KeyBindingsListener.java
@@ -2,6 +2,9 @@ package net.sf.jabref.gui.keyboard;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
+import java.util.ArrayList;
+import java.util.Locale;
+import java.util.stream.Collectors;
/**
* respond to grabKey and display the key binding
@@ -16,51 +19,93 @@ public class KeyBindingsListener extends KeyAdapter {
@Override
public void keyPressed(KeyEvent evt) {
- // first check if anything is selected if not the return
+
+ boolean isFunctionKey = false;
+ boolean isEscapeKey = false;
+ boolean isDeleteKey = false;
+
+ // first check if anything is selected if not then return
final int selRow = table.getSelectedRow();
boolean isAnyRowSelected = selRow >= 0;
if (!isAnyRowSelected) {
return;
}
- final String modifier = KeyEvent.getKeyModifiersText(evt.getModifiers());
+ final String modifier = getModifierText(evt);
// VALIDATE code and modifier
// all key bindings must have a modifier: ctrl alt etc
if ("".equals(modifier)) {
int kc = evt.getKeyCode();
- boolean isFunctionKey = (kc >= KeyEvent.VK_F1) && (kc <= KeyEvent.VK_F12);
- boolean isEscapeKey = kc == KeyEvent.VK_ESCAPE;
- boolean isDeleteKey = kc == KeyEvent.VK_DELETE;
+ isFunctionKey = (kc >= KeyEvent.VK_F1) && (kc <= KeyEvent.VK_F12);
+ isEscapeKey = kc == KeyEvent.VK_ESCAPE;
+ isDeleteKey = kc == KeyEvent.VK_DELETE;
if (!(isFunctionKey || isEscapeKey || isDeleteKey)) {
- return; // need a modifier except for function, escape and delete keys
+ // need a modifier except for function, escape and delete keys
+ return;
}
}
- final String code = KeyEvent.getKeyText(evt.getKeyCode());
- // second key cannot be a modifiers
- if ("Tab".equals(code)
- || "Backspace".equals(code)
- || "Enter".equals(code)
- || "Space".equals(code)
- || "Ctrl".equals(code)
- || "Shift".equals(code)
- || "Alt".equals(code)) {
+ int code = evt.getKeyCode();
+ String newKey;
+ //skip the event triggered only by a modifier, tab, backspace or enter because these normally have preset
+ // functionality if they alone are pressed
+ if (code == KeyEvent.VK_ALT ||
+ code == KeyEvent.VK_TAB ||
+ code == KeyEvent.VK_BACK_SPACE ||
+ code == KeyEvent.VK_ENTER ||
+ code == KeyEvent.VK_SPACE ||
+ code == KeyEvent.VK_CONTROL ||
+ code == KeyEvent.VK_SHIFT ||
+ code == KeyEvent.VK_META) {
return;
}
-
- // COMPUTE new key binding
- String newKey;
if ("".equals(modifier)) {
- newKey = code;
+ if (isFunctionKey) {
+ newKey = KeyEvent.getKeyText(code);
+ } else if (isEscapeKey) {
+ newKey = "ESCAPE";
+ } else if (isDeleteKey) {
+ newKey = "DELETE";
+ } else {
+ return;
+ }
} else {
- newKey = modifier.toLowerCase().replace("+", " ") + " " + code;
+ newKey = modifier.toLowerCase(Locale.ENGLISH) + " " + KeyEvent.getKeyText(code);
}
-
- // SHOW new key binding
+ //SHOW new key binding
//find which key is selected and set its value
table.setValueAt(newKey, selRow, 1);
table.revalidate();
table.repaint();
}
+
+ /**
+ * Collects th English translations of all modifiers and returns them separated by a space
+ *
+ * @param evt the KeyEvent that was triggered to set the KeyBindings
+ * @return a String containing the modifier keys text
+ */
+ private String getModifierText(KeyEvent evt) {
+ ArrayList<String> modifiersList = new ArrayList<>();
+
+ if (evt.isControlDown()) {
+ modifiersList.add("ctrl");
+ }
+ if (evt.isAltDown()) {
+ modifiersList.add("alt");
+ }
+ if (evt.isShiftDown()) {
+ modifiersList.add("shift");
+ }
+ if (evt.isAltGraphDown()) {
+ modifiersList.add("alt gr");
+ }
+ if (evt.isMetaDown()) {
+ modifiersList.add("meta");
+ }
+ //Now build the String with all the modifier texts
+ String modifiersAsString = modifiersList.stream().collect(Collectors.joining(" "));
+ return modifiersAsString;
+ }
}
diff --git a/src/main/java/net/sf/jabref/gui/maintable/ListSynchronizer.java b/src/main/java/net/sf/jabref/gui/maintable/ListSynchronizer.java
index 85504fa..1abaef6 100644
--- a/src/main/java/net/sf/jabref/gui/maintable/ListSynchronizer.java
+++ b/src/main/java/net/sf/jabref/gui/maintable/ListSynchronizer.java
@@ -1,9 +1,9 @@
package net.sf.jabref.gui.maintable;
+import net.sf.jabref.model.database.event.EntryAddedEvent;
+import net.sf.jabref.model.database.event.EntryRemovedEvent;
import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.model.event.EntryAddedEvent;
-import net.sf.jabref.model.event.EntryChangedEvent;
-import net.sf.jabref.model.event.EntryRemovedEvent;
+import net.sf.jabref.model.entry.event.EntryChangedEvent;
import ca.odell.glazedlists.EventList;
import com.google.common.eventbus.Subscribe;
@@ -40,12 +40,12 @@ public class ListSynchronizer {
public void listen(EntryChangedEvent entryChangedEvent) {
lock();
try {
- int index = list.indexOf(entryChangedEvent.getBibEntry());
- if (index != -1) {
- // SpecialFieldUtils.syncSpecialFieldsFromKeywords update an entry during
- // DatabaseChangeEvent.ADDED_ENTRY
- // thus,
- list.set(index, entryChangedEvent.getBibEntry());
+ // cannot use list#indexOf b/c it won't distinguish between duplicates
+ for (int i = 0; i < list.size(); i++) {
+ if (list.get(i) == entryChangedEvent.getBibEntry()) {
+ list.set(i, entryChangedEvent.getBibEntry());
+ break;
+ }
}
} finally {
unlock();
diff --git a/src/main/java/net/sf/jabref/gui/maintable/MainTable.java b/src/main/java/net/sf/jabref/gui/maintable/MainTable.java
index 1d70e0a..d445859 100644
--- a/src/main/java/net/sf/jabref/gui/maintable/MainTable.java
+++ b/src/main/java/net/sf/jabref/gui/maintable/MainTable.java
@@ -1,22 +1,20 @@
package net.sf.jabref.gui.maintable;
import java.awt.Color;
-import java.awt.Component;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
-import java.awt.event.KeyAdapter;
-import java.awt.event.KeyEvent;
+import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Comparator;
-import java.util.HashSet;
import java.util.List;
import java.util.Optional;
-import java.util.Set;
+import javax.swing.AbstractAction;
+import javax.swing.ActionMap;
import javax.swing.BorderFactory;
-import javax.swing.JLabel;
+import javax.swing.InputMap;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JTable;
@@ -34,6 +32,7 @@ import net.sf.jabref.gui.GUIGlobals;
import net.sf.jabref.gui.JabRefFrame;
import net.sf.jabref.gui.groups.EntryTableTransferHandler;
import net.sf.jabref.gui.groups.GroupMatcher;
+import net.sf.jabref.gui.keyboard.KeyBinding;
import net.sf.jabref.gui.renderer.CompleteRenderer;
import net.sf.jabref.gui.renderer.GeneralRenderer;
import net.sf.jabref.gui.renderer.IncompleteRenderer;
@@ -48,12 +47,13 @@ import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.BibtexSingleField;
import net.sf.jabref.model.entry.EntryType;
import net.sf.jabref.model.entry.FieldName;
-import net.sf.jabref.model.entry.SpecialFields;
+import net.sf.jabref.model.entry.specialfields.SpecialField;
import net.sf.jabref.preferences.JabRefPreferences;
import ca.odell.glazedlists.EventList;
import ca.odell.glazedlists.SortedList;
import ca.odell.glazedlists.event.ListEventListener;
+import ca.odell.glazedlists.gui.AbstractTableComparatorChooser;
import ca.odell.glazedlists.matchers.Matcher;
import ca.odell.glazedlists.swing.DefaultEventSelectionModel;
import ca.odell.glazedlists.swing.GlazedListsSwing;
@@ -61,14 +61,6 @@ import ca.odell.glazedlists.swing.TableComparatorChooser;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-/**
- * The central table which displays the bibtex entries.
- *
- * User: alver
- * Date: Oct 12, 2005
- * Time: 10:29:39 PM
- *
- */
public class MainTable extends JTable {
private static final Log LOGGER = LogFactory.getLog(MainTable.class);
@@ -149,7 +141,7 @@ public class MainTable extends JTable {
this.setTableHeader(new PreventDraggingJTableHeader(this, tableFormat));
comparatorChooser = this.createTableComparatorChooser(this, model.getSortedForUserDefinedTableColumnSorting(),
- TableComparatorChooser.MULTIPLE_COLUMN_KEYBOARD);
+ AbstractTableComparatorChooser.MULTIPLE_COLUMN_KEYBOARD);
this.tableColumnListener = new PersistenceTableColumnListener(this);
@@ -169,7 +161,51 @@ public class MainTable extends JTable {
model.updateMarkingState(Globals.prefs.getBoolean(JabRefPreferences.FLOAT_MARKED_ENTRIES));
setWidths();
- addKeyListener(new TableKeyListener());
+ //Override 'selectNextColumnCell' and 'selectPreviousColumnCell' to move rows instead of cells on TAB
+ ActionMap actionMap = getActionMap();
+ InputMap inputMap = getInputMap();
+ actionMap.put("selectNextColumnCell", new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ panel.selectNextEntry();
+ }
+ });
+ actionMap.put("selectPreviousColumnCell", new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ panel.selectPreviousEntry();
+ }
+ });
+ actionMap.put("selectNextRow", new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ panel.selectNextEntry();
+ }
+ });
+ actionMap.put("selectPreviousRow", new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ panel.selectPreviousEntry();
+ }
+ });
+
+ String selectFirst = "selectFirst";
+ inputMap.put(Globals.getKeyPrefs().getKey(KeyBinding.SELECT_FIRST_ENTRY), selectFirst);
+ actionMap.put(selectFirst, new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ panel.selectFirstEntry();
+ }
+ });
+
+ String selectLast = "selectLast";
+ inputMap.put(Globals.getKeyPrefs().getKey(KeyBinding.SELECT_LAST_ENTRY), selectLast);
+ actionMap.put(selectLast, new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ panel.selectLastEntry();
+ }
+ });
}
public void addSelectionListener(ListEventListener<BibEntry> listener) {
@@ -186,18 +222,14 @@ public class MainTable extends JTable {
@Override
public String getToolTipText(MouseEvent e) {
-
- // Set tooltip text for all columns which are not fully displayed
-
- String toolTipText = null;
+ String toolTipText = super.getToolTipText(e);
Point p = e.getPoint();
int col = columnAtPoint(p);
int row = rowAtPoint(p);
- Component comp = prepareRenderer(getCellRenderer(row, col), row, col);
Rectangle bounds = getCellRect(row, col, false);
-
- Dimension d = comp.getPreferredSize();
+ Dimension d = prepareRenderer(getCellRenderer(row, col), row, col).getPreferredSize();
+ // if the content of the cell is bigger than the cell itself render it as the tooltip (thus throwing the original tooltip away)
if ((d != null) && (d.width > bounds.width) && (getValueAt(row, col) != null)) {
toolTipText = getValueAt(row, col).toString();
}
@@ -254,7 +286,6 @@ public class MainTable extends JTable {
MainTable.incRenderer.setNumber(row);
renderer = MainTable.incRenderer;
}
- renderer.setHorizontalAlignment(JLabel.CENTER);
} else if (tableColorCodes || tableResolvedColorCodes) {
CellRendererMode status = getCellStatus(row, column, tableResolvedColorCodes);
if (status == CellRendererMode.REQUIRED) {
@@ -285,7 +316,7 @@ public class MainTable extends JTable {
cm.getColumn(0).setPreferredWidth(ncWidth);
for (int i = 1; i < cm.getColumnCount(); i++) {
MainTableColumn mainTableColumn = tableFormat.getTableColumn(cm.getColumn(i).getModelIndex());
- if (SpecialFields.FIELDNAME_RANKING.equals(mainTableColumn.getColumnName())) {
+ if (SpecialField.RANKING.getFieldName().equals(mainTableColumn.getColumnName())) {
cm.getColumn(i).setPreferredWidth(GUIGlobals.WIDTH_ICON_COL_RANKING);
cm.getColumn(i).setMinWidth(GUIGlobals.WIDTH_ICON_COL_RANKING);
cm.getColumn(i).setMaxWidth(GUIGlobals.WIDTH_ICON_COL_RANKING);
@@ -365,7 +396,7 @@ public class MainTable extends JTable {
comparators = comparatorChooser.getComparatorsForColumn(i);
comparators.clear();
- if (SpecialFields.FIELDNAME_RANKING.equals(tableColumn.getColumnName())) {
+ if (SpecialField.RANKING.getFieldName().equals(tableColumn.getColumnName())) {
comparators.add(new RankingFieldComparator());
} else if (tableColumn.isIconColumn()) {
comparators.add(new IconComparator(tableColumn.getBibtexFields()));
@@ -487,11 +518,14 @@ public class MainTable extends JTable {
}
public int findEntry(BibEntry entry) {
- return model.getTableRows().indexOf(entry);
- }
-
- public int findLastEntry(BibEntry entry) {
- return model.getTableRows().lastIndexOf(entry);
+ EventList<BibEntry> tableRows = model.getTableRows();
+ for (int row = 0; row < tableRows.size(); row++) {
+ BibEntry bibEntry = tableRows.get(row);
+ if (entry == bibEntry) { // NOPMD (equals doesn't recognise duplicates)
+ return row;
+ }
+ }
+ return -1;
}
/**
@@ -507,30 +541,39 @@ public class MainTable extends JTable {
}
private boolean matches(int row, Matcher<BibEntry> m) {
- return m.matches(getBibEntry(row));
+ Optional<BibEntry> bibEntry = getBibEntry(row);
+
+ if (bibEntry.isPresent()) {
+ return m.matches(bibEntry.get());
+ }
+ return m.matches(null);
}
private boolean isComplete(int row) {
- try {
- BibEntry entry = getBibEntry(row);
- TypedBibEntry typedEntry = new TypedBibEntry(entry, panel.getBibDatabaseContext());
+ Optional<BibEntry> bibEntry = getBibEntry(row);
+
+ if (bibEntry.isPresent()) {
+ TypedBibEntry typedEntry = new TypedBibEntry(bibEntry.get(), panel.getBibDatabaseContext());
return typedEntry.hasAllRequiredFields();
- } catch (NullPointerException ex) {
- return true;
}
+ return true;
}
private int isMarked(int row) {
- try {
- BibEntry be = getBibEntry(row);
- return EntryMarker.isMarked(be);
- } catch (NullPointerException ex) {
- return 0;
+ Optional<BibEntry> bibEntry = getBibEntry(row);
+
+ if (bibEntry.isPresent()) {
+ return EntryMarker.isMarked(bibEntry.get());
}
+ return 0;
}
- private BibEntry getBibEntry(int row) {
- return model.getTableRows().get(row);
+ private Optional<BibEntry> getBibEntry(int row) {
+ try {
+ return Optional.of(model.getTableRows().get(row));
+ } catch (IndexOutOfBoundsException e) {
+ return Optional.empty();
+ }
}
public void scrollTo(int y) {
@@ -648,28 +691,6 @@ public class MainTable extends JTable {
}
/**
- * KeyEvent handling of Tab
- */
- private class TableKeyListener extends KeyAdapter {
-
- private final Set<Integer> pressed = new HashSet<>();
-
- @Override
- public void keyPressed(KeyEvent e) {
- pressed.add(e.getExtendedKeyCode());
- if (pressed.contains(KeyEvent.VK_TAB)) {
- int change = pressed.contains(KeyEvent.VK_SHIFT) ? -1 : 1;
- setSelected((getSelectedRow() + change + getRowCount()) % getRowCount());
- }
- }
-
- @Override
- public void keyReleased(KeyEvent e) {
- pressed.remove(e.getExtendedKeyCode());
- }
- }
-
- /**
* Morten Alver: This override is a workaround NullPointerException when
* dragging stuff into the table. I found this in a forum, but have no idea
* why it works.
diff --git a/src/main/java/net/sf/jabref/gui/maintable/MainTableColumn.java b/src/main/java/net/sf/jabref/gui/maintable/MainTableColumn.java
index 6dbbc73..69476c0 100644
--- a/src/main/java/net/sf/jabref/gui/maintable/MainTableColumn.java
+++ b/src/main/java/net/sf/jabref/gui/maintable/MainTableColumn.java
@@ -12,7 +12,7 @@ import net.sf.jabref.logic.layout.format.LatexToUnicodeFormatter;
import net.sf.jabref.model.database.BibDatabase;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.FieldName;
-import net.sf.jabref.model.entry.FieldProperties;
+import net.sf.jabref.model.entry.FieldProperty;
import net.sf.jabref.model.entry.InternalBibtexFields;
public class MainTableColumn {
@@ -94,9 +94,9 @@ public class MainTableColumn {
Optional<String> content = Optional.empty();
for (String field : bibtexFields) {
- content = BibDatabase.getResolvedField(field, entry, database.orElse(null));
+ content = entry.getResolvedFieldOrAlias(field, database.orElse(null));
if (content.isPresent()) {
- isNameColumn = InternalBibtexFields.getFieldExtras(field).contains(FieldProperties.PERSON_NAMES);
+ isNameColumn = InternalBibtexFields.getFieldProperties(field).contains(FieldProperty.PERSON_NAMES);
break;
}
}
@@ -127,9 +127,9 @@ public class MainTableColumn {
* The reasons for being different are (combinations may also happen):
* - The entry has a crossref where the field content is obtained from
* - The field has a string in it (which getColumnValue() resolves)
- * - There are some alias fields. For example, if the entry has a date field but no year field, getResolvedField()
- * will return the year value from the date field when queried for year
- *
+ * - There are some alias fields. For example, if the entry has a date field but no year field,
+ * {@link BibEntry#getResolvedFieldOrAlias(String, BibDatabase)} will return the year value from the date field
+ * when queried for year
*
* @param entry the BibEntry
* @return true if the value returned by getColumnValue() is resolved as outlined above
@@ -147,8 +147,8 @@ public class MainTableColumn {
|| BibEntry.KEY_FIELD.equals(field)) {
return false;
} else {
- plainFieldContent = entry.getFieldOptional(field);
- resolvedFieldContent = BibDatabase.getResolvedField(field, entry, database.orElse(null));
+ plainFieldContent = entry.getField(field);
+ resolvedFieldContent = entry.getResolvedFieldOrAlias(field, database.orElse(null));
}
if (resolvedFieldContent.isPresent()) {
diff --git a/src/main/java/net/sf/jabref/gui/maintable/MainTableDataModel.java b/src/main/java/net/sf/jabref/gui/maintable/MainTableDataModel.java
index 649cca6..27251a4 100644
--- a/src/main/java/net/sf/jabref/gui/maintable/MainTableDataModel.java
+++ b/src/main/java/net/sf/jabref/gui/maintable/MainTableDataModel.java
@@ -6,12 +6,12 @@ import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
-import net.sf.jabref.BibDatabaseContext;
import net.sf.jabref.gui.groups.GroupMatcher;
import net.sf.jabref.gui.search.HitOrMissComparator;
import net.sf.jabref.gui.search.matchers.EverythingMatcher;
import net.sf.jabref.gui.search.matchers.SearchMatcher;
import net.sf.jabref.gui.util.comparator.IsMarkedComparator;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.entry.BibEntry;
import ca.odell.glazedlists.BasicEventList;
diff --git a/src/main/java/net/sf/jabref/gui/maintable/MainTableFormat.java b/src/main/java/net/sf/jabref/gui/maintable/MainTableFormat.java
index d5ca77c..51a6adb 100644
--- a/src/main/java/net/sf/jabref/gui/maintable/MainTableFormat.java
+++ b/src/main/java/net/sf/jabref/gui/maintable/MainTableFormat.java
@@ -79,21 +79,22 @@ public class MainTableFormat implements TableFormat<BibEntry> {
// clear existing column configuration
tableColumns.clear();
+ SpecialMainTableColumnsBuilder builder = new SpecialMainTableColumnsBuilder();
// Add numbering column to tableColumns
- tableColumns.add(SpecialMainTableColumns.NUMBER_COL);
+ tableColumns.add(builder.buildNumberColumn());
// Add all file based columns
if (Globals.prefs.getBoolean(JabRefPreferences.FILE_COLUMN)) {
- tableColumns.add(SpecialMainTableColumns.FILE_COLUMN);
+ tableColumns.add(builder.buildFileColumn());
}
if (Globals.prefs.getBoolean(JabRefPreferences.URL_COLUMN)) {
if (Globals.prefs.getBoolean(JabRefPreferences.PREFER_URL_DOI)) {
- tableColumns.add(SpecialMainTableColumns
+ tableColumns.add(builder
.createIconColumn(JabRefPreferences.URL_COLUMN, MainTableFormat.DOI_FIRST,
new JLabel(IconTheme.JabRefIcon.DOI.getSmallIcon())));
} else {
- tableColumns.add(SpecialMainTableColumns
+ tableColumns.add(builder
.createIconColumn(JabRefPreferences.URL_COLUMN, MainTableFormat.URL_FIRST,
new JLabel(IconTheme.JabRefIcon.WWW.getSmallIcon())));
}
@@ -101,7 +102,7 @@ public class MainTableFormat implements TableFormat<BibEntry> {
}
if (Globals.prefs.getBoolean(JabRefPreferences.ARXIV_COLUMN)) {
- tableColumns.add(SpecialMainTableColumns
+ tableColumns.add(builder
.createIconColumn(JabRefPreferences.ARXIV_COLUMN, MainTableFormat.ARXIV,
new JLabel(IconTheme.JabRefIcon.WWW.getSmallIcon())));
}
@@ -109,7 +110,7 @@ public class MainTableFormat implements TableFormat<BibEntry> {
if (Globals.prefs.getBoolean(JabRefPreferences.EXTRA_FILE_COLUMNS)) {
List<String> desiredColumns = Globals.prefs.getStringList(JabRefPreferences.LIST_OF_FILE_COLUMNS);
for (String desiredColumn : desiredColumns) {
- tableColumns.add(SpecialMainTableColumns.createFileIconColumn(desiredColumn));
+ tableColumns.add(builder.createFileIconColumn(desiredColumn));
}
}
@@ -129,22 +130,22 @@ public class MainTableFormat implements TableFormat<BibEntry> {
// Add the "special" icon columns (e.g., ranking, file, ...) that are enabled in preferences.
if (Globals.prefs.getBoolean(JabRefPreferences.SPECIALFIELDSENABLED)) {
if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_RANKING)) {
- tableColumns.add(SpecialMainTableColumns.RANKING_COLUMN);
+ tableColumns.add(builder.buildRankingColumn());
}
if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_RELEVANCE)) {
- tableColumns.add(SpecialMainTableColumns.RELEVANCE_COLUMN);
+ tableColumns.add(builder.buildRelevanceColumn());
}
if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_QUALITY)) {
- tableColumns.add(SpecialMainTableColumns.QUALITY_COLUMN);
+ tableColumns.add(builder.buildQualityColumn());
}
if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_PRIORITY)) {
- tableColumns.add(SpecialMainTableColumns.PRIORITY_COLUMN);
+ tableColumns.add(builder.buildPriorityColumn());
}
if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_PRINTED)) {
- tableColumns.add(SpecialMainTableColumns.PRINTED_COLUMN);
+ tableColumns.add(builder.buildPrintedColumn());
}
if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_READ)) {
- tableColumns.add(SpecialMainTableColumns.READ_STATUS_COLUMN);
+ tableColumns.add(builder.buildReadStatusColumn());
}
}
diff --git a/src/main/java/net/sf/jabref/gui/maintable/MainTableSelectionListener.java b/src/main/java/net/sf/jabref/gui/maintable/MainTableSelectionListener.java
index 5c3e923..ba94056 100644
--- a/src/main/java/net/sf/jabref/gui/maintable/MainTableSelectionListener.java
+++ b/src/main/java/net/sf/jabref/gui/maintable/MainTableSelectionListener.java
@@ -20,26 +20,29 @@ import javax.swing.Timer;
import net.sf.jabref.Globals;
import net.sf.jabref.JabRefExecutorService;
import net.sf.jabref.JabRefGUI;
-import net.sf.jabref.external.ExternalFileMenuItem;
-import net.sf.jabref.external.ExternalFileType;
import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.gui.BasePanelMode;
-import net.sf.jabref.gui.FileListEntry;
-import net.sf.jabref.gui.FileListTableModel;
import net.sf.jabref.gui.GUIGlobals;
import net.sf.jabref.gui.IconTheme;
import net.sf.jabref.gui.PreviewPanel;
+import net.sf.jabref.gui.actions.CopyDoiUrlAction;
import net.sf.jabref.gui.desktop.JabRefDesktop;
import net.sf.jabref.gui.entryeditor.EntryEditor;
+import net.sf.jabref.gui.externalfiletype.ExternalFileMenuItem;
+import net.sf.jabref.gui.externalfiletype.ExternalFileType;
+import net.sf.jabref.gui.filelist.FileListEntry;
+import net.sf.jabref.gui.filelist.FileListTableModel;
import net.sf.jabref.gui.menus.RightClickMenu;
-import net.sf.jabref.gui.util.FocusRequester;
+import net.sf.jabref.gui.specialfields.SpecialFieldMenuAction;
+import net.sf.jabref.gui.specialfields.SpecialFieldValueViewModel;
+import net.sf.jabref.gui.specialfields.SpecialFieldViewModel;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.util.OS;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.FieldName;
-import net.sf.jabref.preferences.JabRefPreferences;
-import net.sf.jabref.specialfields.SpecialFieldValue;
-import net.sf.jabref.specialfields.SpecialFieldsUtils;
+import net.sf.jabref.model.entry.specialfields.SpecialField;
+import net.sf.jabref.model.entry.specialfields.SpecialFieldValue;
+import net.sf.jabref.preferences.PreviewPreferences;
import ca.odell.glazedlists.EventList;
import ca.odell.glazedlists.event.ListEvent;
@@ -54,14 +57,12 @@ import org.apache.commons.logging.LogFactory;
public class MainTableSelectionListener implements ListEventListener<BibEntry>, MouseListener,
KeyListener, FocusListener {
- private final PreviewPanel[] previewPanel;
private final MainTable table;
private final BasePanel panel;
private final EventList<BibEntry> tableRows;
- private int activePreview = Globals.prefs.getInt(JabRefPreferences.ACTIVE_PREVIEW);
private PreviewPanel preview;
- private boolean previewActive = Globals.prefs.getBoolean(JabRefPreferences.PREVIEW_ENABLED);
+ private boolean previewActive = Globals.prefs.getPreviewPreferences().isPreviewPanelEnabled();
private boolean workingOnPreview;
private boolean enabled = true;
@@ -79,27 +80,19 @@ public class MainTableSelectionListener implements ListEventListener<BibEntry>,
this.table = table;
this.panel = panel;
this.tableRows = table.getTableModel().getTableRows();
- previewPanel = new PreviewPanel[] {
- new PreviewPanel(panel.getBibDatabaseContext(), null, panel,
- Globals.prefs.get(JabRefPreferences.PREVIEW_0)),
- new PreviewPanel(panel.getBibDatabaseContext(), null, panel,
- Globals.prefs.get(JabRefPreferences.PREVIEW_1))};
-
- panel.getSearchBar().getSearchQueryHighlightObservable().addSearchListener(previewPanel[0]);
- panel.getSearchBar().getSearchQueryHighlightObservable().addSearchListener(previewPanel[1]);
-
- this.preview = previewPanel[activePreview];
+ PreviewPanel previewPanel = panel.getPreviewPanel();
+ if (previewPanel != null){
+ preview = previewPanel;
+ } else {
+ preview = new PreviewPanel(panel.getBibDatabaseContext(), null, panel);
+ panel.frame().getGlobalSearchBar().getSearchQueryHighlightObservable().addSearchListener(preview);
+ }
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
- public void updatePreviews() {
- previewPanel[0].updateLayout(Globals.prefs.get(JabRefPreferences.PREVIEW_0));
- previewPanel[1].updateLayout(Globals.prefs.get(JabRefPreferences.PREVIEW_1));
- }
-
@Override
public void listChanged(ListEvent<BibEntry> e) {
if (!enabled) {
@@ -112,6 +105,12 @@ public class MainTableSelectionListener implements ListEventListener<BibEntry>,
}
final BibEntry newSelected = selected.get(0);
+ if ((panel.getMode() == BasePanelMode.SHOWING_EDITOR || panel.getMode() == BasePanelMode.WILL_SHOW_EDITOR)
+ && panel.getCurrentEditor() != null && newSelected == panel.getCurrentEditor().getEntry()) {
+ // entry already selected and currently editing it, do not steal the focus from the selected textfield
+ return;
+ }
+
if (newSelected != null) {
final BasePanelMode mode = panel.getMode(); // What is the panel already showing?
if ((mode == BasePanelMode.WILL_SHOW_EDITOR) || (mode == BasePanelMode.SHOWING_EDITOR)) {
@@ -121,13 +120,9 @@ public class MainTableSelectionListener implements ListEventListener<BibEntry>,
if (oldEditor != null) {
visName = oldEditor.getVisiblePanelName();
}
- // Get an old or new editor for the entry to edit:
+ // Get a new editor for the entry to edit:
EntryEditor newEditor = panel.getEntryEditor(newSelected);
- if (oldEditor != null) {
- oldEditor.setMovingToDifferentEntry();
- }
-
// Show the new editor unless it was already visible:
if (!Objects.equals(newEditor, oldEditor) || (mode != BasePanelMode.SHOWING_EDITOR)) {
@@ -136,6 +131,9 @@ public class MainTableSelectionListener implements ListEventListener<BibEntry>,
}
panel.showEntryEditor(newEditor);
SwingUtilities.invokeLater(() -> table.ensureVisible(table.getSelectedRow()));
+ } else {
+ // if not used destroy the EntryEditor
+ newEditor.setMovingToDifferentEntry();
}
} else {
// Either nothing or a preview was shown. Update the preview.
@@ -187,12 +185,10 @@ public class MainTableSelectionListener implements ListEventListener<BibEntry>,
public void editSignalled(BibEntry entry) {
final BasePanelMode mode = panel.getMode();
- EntryEditor editor = panel.getEntryEditor(entry);
if (mode != BasePanelMode.SHOWING_EDITOR) {
- panel.showEntryEditor(editor);
- panel.adjustSplitter();
+ panel.showEntryEditor(panel.getEntryEditor(entry));
}
- new FocusRequester(editor);
+ panel.getCurrentEditor().requestFocus();
}
@Override
@@ -248,7 +244,7 @@ public class MainTableSelectionListener implements ListEventListener<BibEntry>,
}
// Check if the clicked colum is a specialfield column
- if (modelColumn.isIconColumn() && (SpecialFieldsUtils.isSpecialField(modelColumn.getColumnName()))) {
+ if (modelColumn.isIconColumn() && (SpecialField.isSpecialField(modelColumn.getColumnName()))) {
// handle specialfield
handleSpecialFieldLeftClick(e, modelColumn.getColumnName());
} else if (modelColumn.isIconColumn()) { // left click on icon field
@@ -270,7 +266,7 @@ public class MainTableSelectionListener implements ListEventListener<BibEntry>,
for (String fieldName : fieldNames) {
// Check if field is present, if not skip this field
if (entry.hasField(fieldName)) {
- String link = entry.getFieldOptional(fieldName).get();
+ String link = entry.getField(fieldName).get();
// See if this is a simple file link field, or if it is a file-list
// field that can specify a list of links:
@@ -315,9 +311,10 @@ public class MainTableSelectionListener implements ListEventListener<BibEntry>,
}
});
} else if (modelColumn.getBibtexFields().contains(FieldName.CROSSREF)) { // Clicking on crossref column
- tableRows.get(row).getFieldOptional(FieldName.CROSSREF)
+ tableRows.get(row).getField(FieldName.CROSSREF)
.ifPresent(crossref -> panel.getDatabase().getEntryByKey(crossref).ifPresent(entry -> panel.highlightEntry(entry)));
}
+ panel.frame().updateEnabledState();
}
/**
@@ -329,15 +326,15 @@ public class MainTableSelectionListener implements ListEventListener<BibEntry>,
*/
private void handleSpecialFieldLeftClick(MouseEvent e, String columnName) {
if ((e.getClickCount() == 1)) {
- SpecialFieldsUtils.getSpecialFieldInstanceFromFieldName(columnName).ifPresent(field -> {
+ SpecialField.getSpecialFieldInstanceFromFieldName(columnName).ifPresent(field -> {
// special field found
if (field.isSingleValueField()) {
// directly execute toggle action instead of showing a menu with one action
- field.getValues().get(0).getAction(panel.frame()).action();
+ new SpecialFieldViewModel(field).getSpecialFieldAction(field.getValues().get(0), panel.frame()).action();
} else {
JPopupMenu menu = new JPopupMenu();
for (SpecialFieldValue val : field.getValues()) {
- menu.add(val.getMenuAction(panel.frame()));
+ menu.add(new SpecialFieldMenuAction(new SpecialFieldValueViewModel(val), panel.frame()));
}
menu.show(table, e.getX(), e.getY());
}
@@ -381,7 +378,7 @@ public class MainTableSelectionListener implements ListEventListener<BibEntry>,
if (FieldName.FILE.equals(field)) {
// We use a FileListTableModel to parse the field content:
FileListTableModel fileList = new FileListTableModel();
- entry.getFieldOptional(field).ifPresent(fileList::setContent);
+ entry.getField(field).ifPresent(fileList::setContent);
for (int i = 0; i < fileList.getRowCount(); i++) {
FileListEntry flEntry = fileList.getEntry(i);
if (column.isFileFilter()
@@ -398,11 +395,11 @@ public class MainTableSelectionListener implements ListEventListener<BibEntry>,
showDefaultPopup = false;
}
} else {
- if (SpecialFieldsUtils.isSpecialField(column.getColumnName())) {
+ if (SpecialField.isSpecialField(column.getColumnName())) {
// full pop should be shown as left click already shows short popup
showDefaultPopup = true;
} else {
- Optional<String> content = entry.getFieldOptional(field);
+ Optional<String> content = entry.getField(field);
if (content.isPresent()) {
Icon icon;
JLabel iconLabel = GUIGlobals.getTableIcon(field);
@@ -413,6 +410,9 @@ public class MainTableSelectionListener implements ListEventListener<BibEntry>,
}
menu.add(new ExternalFileMenuItem(panel.frame(), entry, content.get(), content.get(), icon,
panel.getBibDatabaseContext(), field));
+ if (field.equals(FieldName.DOI)) {
+ menu.add(new CopyDoiUrlAction(content.get()));
+ }
showDefaultPopup = false;
}
}
@@ -434,7 +434,7 @@ public class MainTableSelectionListener implements ListEventListener<BibEntry>,
panel.hideBottomComponent();
}
panel.adjustSplitter();
- new FocusRequester(table);
+ table.requestFocus();
}
@Override
@@ -458,19 +458,26 @@ public class MainTableSelectionListener implements ListEventListener<BibEntry>,
}
}
- public void switchPreview() {
- if (activePreview < (previewPanel.length - 1)) {
- activePreview++;
- } else {
- activePreview = 0;
- }
- Globals.prefs.putInt(JabRefPreferences.ACTIVE_PREVIEW, activePreview);
- if (previewActive) {
- this.preview = previewPanel[activePreview];
+ public void nextPreviewStyle(){
+ cyclePreview(Globals.prefs.getPreviewPreferences().getPreviewCyclePosition() + 1);
+ }
- if (!table.getSelected().isEmpty()) {
- updatePreview(table.getSelected().get(0), true);
- }
+ 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);
+
+ preview.updateLayout();
+ preview.update();
+ panel.showPreview(preview);
+ if (!table.getSelected().isEmpty()) {
+ updatePreview(table.getSelected().get(0), true);
}
}
@@ -529,6 +536,7 @@ public class MainTableSelectionListener implements ListEventListener<BibEntry>,
} else if (e.getKeyChar() == KeyEvent.VK_ESCAPE) {
lastPressedCount = 0;
}
+ panel.frame().updateEnabledState();
}
@Override
diff --git a/src/main/java/net/sf/jabref/gui/maintable/SpecialMainTableColumns.java b/src/main/java/net/sf/jabref/gui/maintable/SpecialMainTableColumns.java
deleted file mode 100644
index f56921a..0000000
--- a/src/main/java/net/sf/jabref/gui/maintable/SpecialMainTableColumns.java
+++ /dev/null
@@ -1,190 +0,0 @@
-package net.sf.jabref.gui.maintable;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.Optional;
-
-import javax.swing.JLabel;
-
-import net.sf.jabref.external.ExternalFileType;
-import net.sf.jabref.gui.FileListTableModel;
-import net.sf.jabref.gui.GUIGlobals;
-import net.sf.jabref.gui.IconTheme;
-import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.model.entry.FieldName;
-import net.sf.jabref.model.entry.SpecialFields;
-import net.sf.jabref.specialfields.Printed;
-import net.sf.jabref.specialfields.Priority;
-import net.sf.jabref.specialfields.Quality;
-import net.sf.jabref.specialfields.Rank;
-import net.sf.jabref.specialfields.ReadStatus;
-import net.sf.jabref.specialfields.Relevance;
-
-public class SpecialMainTableColumns {
-
- public static final MainTableColumn NUMBER_COL = new MainTableColumn(FieldName.NUMBER_COL) {
-
- @Override
- public Object getColumnValue(BibEntry entry) {
- return "#";
- }
-
- @Override
- public String getDisplayName() {
- return "#";
- }
- };
-
- public static final MainTableColumn RANKING_COLUMN = new MainTableColumn(SpecialFields.FIELDNAME_RANKING,
- Collections.singletonList(SpecialFields.FIELDNAME_RANKING),
- new JLabel(SpecialFields.FIELDNAME_RANKING)) {
-
- @Override
- public Object getColumnValue(BibEntry entry) {
-
- return entry.getFieldOptional(SpecialFields.FIELDNAME_RANKING)
- .flatMap(Rank.getInstance()::parse).map(rank -> rank.createLabel()).orElse(null);
- }
- };
-
- public static final MainTableColumn PRIORITY_COLUMN = new MainTableColumn(SpecialFields.FIELDNAME_PRIORITY,
- Collections.singletonList(SpecialFields.FIELDNAME_PRIORITY),
- new JLabel(Priority.getInstance().getRepresentingIcon())) {
-
- @Override
- public Object getColumnValue(BibEntry entry) {
-
- return entry.getFieldOptional(SpecialFields.FIELDNAME_PRIORITY)
- .flatMap(Priority.getInstance()::parse).map(prio -> prio.createLabel()).orElse(null);
- }
- };
-
- public static final MainTableColumn READ_STATUS_COLUMN = new MainTableColumn(SpecialFields.FIELDNAME_READ,
- Collections.singletonList(SpecialFields.FIELDNAME_READ),
- new JLabel(ReadStatus.getInstance().getRepresentingIcon())) {
-
- @Override
- public Object getColumnValue(BibEntry entry) {
-
- return entry.getFieldOptional(SpecialFields.FIELDNAME_READ)
- .flatMap(ReadStatus.getInstance()::parse).map(status -> status.createLabel()).orElse(null);
- }
- };
-
- public static final MainTableColumn RELEVANCE_COLUMN = createIconColumn(SpecialFields.FIELDNAME_RELEVANCE,
- Collections.singletonList(SpecialFields.FIELDNAME_RELEVANCE),
- new JLabel(Relevance.getInstance().getRepresentingIcon()));
-
- public static final MainTableColumn PRINTED_COLUMN = createIconColumn(SpecialFields.FIELDNAME_PRINTED,
- Collections.singletonList(SpecialFields.FIELDNAME_PRINTED),
- new JLabel(Printed.getInstance().getRepresentingIcon()));
-
- public static final MainTableColumn QUALITY_COLUMN = createIconColumn(SpecialFields.FIELDNAME_QUALITY,
- Collections.singletonList(SpecialFields.FIELDNAME_QUALITY),
- new JLabel(Quality.getInstance().getRepresentingIcon()));
-
-
- public static final MainTableColumn FILE_COLUMN = new MainTableColumn(FieldName.FILE,
- Collections.singletonList(FieldName.FILE), new JLabel(IconTheme.JabRefIcon.FILE.getSmallIcon())) {
-
- @Override
- public Object getColumnValue(BibEntry entry) {
- // We use a FileListTableModel to parse the field content:
- FileListTableModel fileList = new FileListTableModel();
- entry.getFieldOptional(FieldName.FILE).ifPresent(fileList::setContent);
- if (fileList.getRowCount() > 1) {
- return new JLabel(IconTheme.JabRefIcon.FILE_MULTIPLE.getSmallIcon());
- } else if (fileList.getRowCount() == 1) {
- Optional<ExternalFileType> type = fileList.getEntry(0).type;
- if (type.isPresent()) {
- return type.get().getIconLabel();
- } else {
- return new JLabel(IconTheme.JabRefIcon.FILE.getSmallIcon());
- }
- }
-
- return null;
- }
- };
-
- /**
- * Creates a MainTableColumn which shows an icon instead textual content
- *
- * @param columnName the name of the column
- * @param fields the entry fields which should be shown
- * @return the crated MainTableColumn
- */
- public static MainTableColumn createIconColumn(String columnName, List<String> fields, JLabel iconLabel) {
- return new MainTableColumn(columnName, fields, iconLabel) {
-
- @Override
- public Object getColumnValue(BibEntry entry) {
- JLabel iconLabel = null;
- boolean iconFound = false;
-
- // check for each field whether content is available
- for (String field : fields) {
- if (entry.hasField(field)) {
- if (iconFound) {
- return new JLabel(IconTheme.JabRefIcon.FILE_MULTIPLE.getSmallIcon());
- } else {
- iconLabel = GUIGlobals.getTableIcon(field);
- iconFound = true;
- }
-
- }
- }
- return iconLabel;
- }
- };
- }
-
- /**
- * create a MainTableColumn for specific file types.
- *
- * Shows the icon for the given type (or the FILE_MULTIPLE icon)
- *
- * @param externalFileTypeName the name of the externalFileType
- *
- * @return the created MainTableColumn
- */
- public static MainTableColumn createFileIconColumn(String externalFileTypeName) {
-
-
-
- return new MainTableColumn(externalFileTypeName, Collections.singletonList(FieldName.FILE), new JLabel()) {
-
- @Override
- public boolean isFileFilter() {
- return true;
- }
-
- @Override
- public String getDisplayName() {
- return externalFileTypeName;
- }
-
- @Override
- public Object getColumnValue(BibEntry entry) {
-
- boolean iconFound = false;
- JLabel iconLabel = null;
- FileListTableModel fileList = new FileListTableModel();
- entry.getFieldOptional(FieldName.FILE).ifPresent(fileList::setContent);
- for (int i = 0; i < fileList.getRowCount(); i++) {
- if ((fileList.getEntry(i).type.isPresent())
- && externalFileTypeName.equalsIgnoreCase(fileList.getEntry(i).type.get().getName())) {
- if (iconFound) {
- // already found another file of the desired type - show FILE_MULTIPLE Icon
- return new JLabel(IconTheme.JabRefIcon.FILE_MULTIPLE.getSmallIcon());
- } else {
- iconLabel = fileList.getEntry(i).type.get().getIconLabel();
- iconFound = true;
- }
- }
- }
- return iconLabel;
- }
- };
- }
-}
diff --git a/src/main/java/net/sf/jabref/gui/maintable/SpecialMainTableColumnsBuilder.java b/src/main/java/net/sf/jabref/gui/maintable/SpecialMainTableColumnsBuilder.java
new file mode 100644
index 0000000..9ddeec6
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/maintable/SpecialMainTableColumnsBuilder.java
@@ -0,0 +1,204 @@
+package net.sf.jabref.gui.maintable;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+import javax.swing.JLabel;
+
+import net.sf.jabref.gui.GUIGlobals;
+import net.sf.jabref.gui.IconTheme;
+import net.sf.jabref.gui.externalfiletype.ExternalFileType;
+import net.sf.jabref.gui.filelist.FileListTableModel;
+import net.sf.jabref.gui.specialfields.SpecialFieldValueViewModel;
+import net.sf.jabref.gui.specialfields.SpecialFieldViewModel;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldName;
+import net.sf.jabref.model.entry.specialfields.SpecialField;
+
+class SpecialMainTableColumnsBuilder {
+
+ MainTableColumn buildNumberColumn() {
+
+ return new MainTableColumn(FieldName.NUMBER_COL) {
+
+ @Override
+ public Object getColumnValue(BibEntry entry) {
+ return "#";
+ }
+
+ @Override
+ public String getDisplayName() {
+ return "#";
+ }
+ }
+
+ ;
+ }
+
+ MainTableColumn buildRankingColumn() {
+
+ return new MainTableColumn(SpecialField.RANKING.getFieldName(),
+ Collections.singletonList(SpecialField.RANKING.getFieldName()),
+ new JLabel(SpecialField.RANKING.getFieldName())) {
+
+ @Override
+ public Object getColumnValue(BibEntry entry) {
+
+ return entry.getField(SpecialField.RANKING.getFieldName())
+ .flatMap(SpecialField.RANKING::parse).map(rank -> new SpecialFieldValueViewModel(rank).createSpecialFieldValueLabel()).orElse(null);
+ }
+ };
+ }
+
+ MainTableColumn buildPriorityColumn() {
+ return new MainTableColumn(SpecialField.PRIORITY.getFieldName(),
+ Collections.singletonList(SpecialField.PRIORITY.getFieldName()),
+ new JLabel(new SpecialFieldViewModel(SpecialField.PRIORITY).getRepresentingIcon())) {
+
+ @Override
+ public Object getColumnValue(BibEntry entry) {
+
+ return entry.getField(SpecialField.PRIORITY.getFieldName())
+ .flatMap(SpecialField.PRIORITY::parse).map(prio -> new SpecialFieldValueViewModel(prio).createSpecialFieldValueLabel()).orElse(null);
+ }
+ };
+ }
+
+ MainTableColumn buildReadStatusColumn() {
+ return new MainTableColumn(SpecialField.READ_STATUS.getFieldName(),
+ Collections.singletonList(SpecialField.READ_STATUS.getFieldName()),
+ new JLabel(new SpecialFieldViewModel(SpecialField.READ_STATUS).getRepresentingIcon())) {
+
+ @Override
+ public Object getColumnValue(BibEntry entry) {
+
+ return entry.getField(SpecialField.READ_STATUS.getFieldName())
+ .flatMap(SpecialField.READ_STATUS::parse).map(status -> new SpecialFieldValueViewModel(status).createSpecialFieldValueLabel()).orElse(null);
+ }
+ };
+ }
+
+ MainTableColumn buildRelevanceColumn() {
+ return createIconColumn(SpecialField.RELEVANCE.getFieldName(),
+ Collections.singletonList(SpecialField.RELEVANCE.getFieldName()),
+ new JLabel(new SpecialFieldViewModel(SpecialField.RELEVANCE).getRepresentingIcon()));
+ }
+
+ MainTableColumn buildPrintedColumn() {
+ return createIconColumn(SpecialField.PRINTED.getFieldName(),
+ Collections.singletonList(SpecialField.PRINTED.getFieldName()),
+ new JLabel(new SpecialFieldViewModel(SpecialField.PRINTED).getRepresentingIcon()));
+ }
+
+ MainTableColumn buildQualityColumn() {
+ return createIconColumn(SpecialField.QUALITY.getFieldName(),
+ Collections.singletonList(SpecialField.QUALITY.getFieldName()),
+ new JLabel(new SpecialFieldViewModel(SpecialField.QUALITY).getRepresentingIcon()));
+ }
+
+ MainTableColumn buildFileColumn() {
+
+ return new MainTableColumn(FieldName.FILE,
+ Collections.singletonList(FieldName.FILE), new JLabel(IconTheme.JabRefIcon.FILE.getSmallIcon())) {
+
+ @Override
+ public Object getColumnValue(BibEntry entry) {
+ // We use a FileListTableModel to parse the field content:
+ FileListTableModel fileList = new FileListTableModel();
+ entry.getField(FieldName.FILE).ifPresent(fileList::setContent);
+ if (fileList.getRowCount() > 1) {
+ return new JLabel(IconTheme.JabRefIcon.FILE_MULTIPLE.getSmallIcon());
+ } else if (fileList.getRowCount() == 1) {
+ Optional<ExternalFileType> type = fileList.getEntry(0).type;
+ if (type.isPresent()) {
+ return type.get().getIconLabel();
+ } else {
+ return new JLabel(IconTheme.JabRefIcon.FILE.getSmallIcon());
+ }
+ }
+
+ return null;
+ }
+ };
+ }
+
+ /**
+ * Creates a MainTableColumn which shows an icon instead textual content
+ *
+ * @param columnName the name of the column
+ * @param fields the entry fields which should be shown
+ * @return the crated MainTableColumn
+ */
+ MainTableColumn createIconColumn(String columnName, List<String> fields, JLabel iconLabel) {
+ return new MainTableColumn(columnName, fields, iconLabel) {
+
+ @Override
+ public Object getColumnValue(BibEntry entry) {
+ JLabel iconLabel = null;
+ boolean iconFound = false;
+
+ // check for each field whether content is available
+ for (String field : fields) {
+ if (entry.hasField(field)) {
+ if (iconFound) {
+ return new JLabel(IconTheme.JabRefIcon.FILE_MULTIPLE.getSmallIcon());
+ } else {
+ iconLabel = GUIGlobals.getTableIcon(field);
+ iconFound = true;
+ }
+
+ }
+ }
+ return iconLabel;
+ }
+ };
+ }
+
+ /**
+ * create a MainTableColumn for specific file types.
+ * <p>
+ * Shows the icon for the given type (or the FILE_MULTIPLE icon)
+ *
+ * @param externalFileTypeName the name of the externalFileType
+ * @return the created MainTableColumn
+ */
+ MainTableColumn createFileIconColumn(String externalFileTypeName) {
+
+
+ return new MainTableColumn(externalFileTypeName, Collections.singletonList(FieldName.FILE), new JLabel()) {
+
+ @Override
+ public boolean isFileFilter() {
+ return true;
+ }
+
+ @Override
+ public String getDisplayName() {
+ return externalFileTypeName;
+ }
+
+ @Override
+ public Object getColumnValue(BibEntry entry) {
+
+ boolean iconFound = false;
+ JLabel iconLabel = null;
+ FileListTableModel fileList = new FileListTableModel();
+ entry.getField(FieldName.FILE).ifPresent(fileList::setContent);
+ for (int i = 0; i < fileList.getRowCount(); i++) {
+ if ((fileList.getEntry(i).type.isPresent())
+ && externalFileTypeName.equalsIgnoreCase(fileList.getEntry(i).type.get().getName())) {
+ if (iconFound) {
+ // already found another file of the desired type - show FILE_MULTIPLE Icon
+ return new JLabel(IconTheme.JabRefIcon.FILE_MULTIPLE.getSmallIcon());
+ } else {
+ iconLabel = fileList.getEntry(i).type.get().getIconLabel();
+ iconFound = true;
+ }
+ }
+ }
+ return iconLabel;
+ }
+ };
+ }
+}
diff --git a/src/main/java/net/sf/jabref/gui/menus/FileHistoryMenu.java b/src/main/java/net/sf/jabref/gui/menus/FileHistoryMenu.java
index ef21c19..afc1668 100644
--- a/src/main/java/net/sf/jabref/gui/menus/FileHistoryMenu.java
+++ b/src/main/java/net/sf/jabref/gui/menus/FileHistoryMenu.java
@@ -8,7 +8,6 @@ import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
-import net.sf.jabref.Globals;
import net.sf.jabref.JabRefExecutorService;
import net.sf.jabref.gui.JabRefFrame;
import net.sf.jabref.logic.l10n.Localization;
@@ -19,10 +18,11 @@ public class FileHistoryMenu extends JMenu implements ActionListener {
private final FileHistory history;
private final JabRefFrame frame;
+ private final JabRefPreferences prefs;
public FileHistoryMenu(JabRefPreferences prefs, JabRefFrame frame) {
- String name = Localization.menuTitle("Recent files");
+ String name = Localization.menuTitle("Recent databases");
int i = name.indexOf('&');
if (i >= 0) {
setText(name.substring(0, i) + name.substring(i + 1));
@@ -33,11 +33,12 @@ public class FileHistoryMenu extends JMenu implements ActionListener {
}
this.frame = frame;
- history = Globals.prefs.getFileHistory();
- if (history.size() > 0) {
- setItems();
- } else {
+ this.prefs = prefs;
+ history = prefs.getFileHistory();
+ if (history.isEmpty()) {
setEnabled(false);
+ } else {
+ setItems();
}
}
@@ -74,7 +75,7 @@ public class FileHistoryMenu extends JMenu implements ActionListener {
public void storeHistory() {
- Globals.prefs.storeFileHistory(history);
+ prefs.storeFileHistory(history);
}
@Override
diff --git a/src/main/java/net/sf/jabref/gui/menus/RightClickMenu.java b/src/main/java/net/sf/jabref/gui/menus/RightClickMenu.java
index 1806d3c..57e0a67 100644
--- a/src/main/java/net/sf/jabref/gui/menus/RightClickMenu.java
+++ b/src/main/java/net/sf/jabref/gui/menus/RightClickMenu.java
@@ -7,8 +7,8 @@ import java.util.List;
import java.util.Optional;
import javax.swing.AbstractAction;
+import javax.swing.Action;
import javax.swing.Icon;
-import javax.swing.JCheckBoxMenuItem;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
@@ -19,25 +19,22 @@ import javax.swing.event.PopupMenuListener;
import net.sf.jabref.Globals;
import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.gui.EntryMarker;
-import net.sf.jabref.gui.FileListTableModel;
import net.sf.jabref.gui.IconTheme;
import net.sf.jabref.gui.JabRefFrame;
import net.sf.jabref.gui.actions.Actions;
+import net.sf.jabref.gui.filelist.FileListTableModel;
+import net.sf.jabref.gui.keyboard.KeyBinding;
import net.sf.jabref.gui.mergeentries.FetchAndMergeEntry;
+import net.sf.jabref.gui.specialfields.SpecialFieldMenuAction;
+import net.sf.jabref.gui.specialfields.SpecialFieldValueViewModel;
+import net.sf.jabref.gui.specialfields.SpecialFieldViewModel;
import net.sf.jabref.gui.worker.MarkEntriesAction;
-import net.sf.jabref.logic.groups.GroupTreeNode;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.FieldName;
+import net.sf.jabref.model.entry.specialfields.SpecialField;
+import net.sf.jabref.model.entry.specialfields.SpecialFieldValue;
import net.sf.jabref.preferences.JabRefPreferences;
-import net.sf.jabref.specialfields.Printed;
-import net.sf.jabref.specialfields.Priority;
-import net.sf.jabref.specialfields.Quality;
-import net.sf.jabref.specialfields.Rank;
-import net.sf.jabref.specialfields.ReadStatus;
-import net.sf.jabref.specialfields.Relevance;
-import net.sf.jabref.specialfields.SpecialField;
-import net.sf.jabref.specialfields.SpecialFieldValue;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -49,8 +46,6 @@ public class RightClickMenu extends JPopupMenu implements PopupMenuListener {
private final JMenuItem groupAdd;
private final JMenuItem groupRemove;
private final JMenuItem groupMoveTo;
- private final JCheckBoxMenuItem floatMarked = new JCheckBoxMenuItem(Localization.lang("Float marked entries"),
- Globals.prefs.getBoolean(JabRefPreferences.FLOAT_MARKED_ENTRIES));
public RightClickMenu(JabRefFrame frame, BasePanel panel) {
@@ -68,49 +63,53 @@ public class RightClickMenu extends JPopupMenu implements PopupMenuListener {
addPopupMenuListener(this);
JMenu copySpecialMenu = new JMenu(Localization.lang("Copy") + "...");
- copySpecialMenu.add(new GeneralAction(Actions.COPY_KEY, Localization.lang("Copy BibTeX key")));
- copySpecialMenu.add(new GeneralAction(Actions.COPY_CITE_KEY, Localization.lang("Copy \\cite{BibTeX key}")));
- copySpecialMenu
- .add(new GeneralAction(Actions.COPY_KEY_AND_TITLE, Localization.lang("Copy BibTeX key and title")));
+ copySpecialMenu.add(new GeneralAction(Actions.COPY_KEY, Localization.lang("Copy BibTeX key"), KeyBinding.COPY_BIBTEX_KEY));
+ copySpecialMenu.add(new GeneralAction(Actions.COPY_CITE_KEY, Localization.lang("Copy \\cite{BibTeX key}"), KeyBinding.COPY_CITE_BIBTEX_KEY));
+ copySpecialMenu.add(new GeneralAction(Actions.COPY_KEY_AND_TITLE, Localization.lang("Copy BibTeX key and title"), KeyBinding.COPY_BIBTEX_KEY_AND_TITLE));
+ copySpecialMenu.add(new GeneralAction(Actions.COPY_KEY_AND_LINK, Localization.lang("Copy BibTeX key and link"), KeyBinding.COPY_BIBTEX_KEY_AND_LINK));
copySpecialMenu.add(new GeneralAction(Actions.EXPORT_TO_CLIPBOARD, Localization.lang("Export to clipboard"),
IconTheme.JabRefIcon.EXPORT_TO_CLIPBOARD.getSmallIcon()));
- add(new GeneralAction(Actions.COPY, Localization.lang("Copy"), IconTheme.JabRefIcon.COPY.getSmallIcon()));
+ add(new GeneralAction(Actions.COPY, Localization.lang("Copy"), IconTheme.JabRefIcon.COPY.getSmallIcon(), KeyBinding.COPY));
add(copySpecialMenu);
- add(new GeneralAction(Actions.PASTE, Localization.lang("Paste"), IconTheme.JabRefIcon.PASTE.getSmallIcon()));
- add(new GeneralAction(Actions.CUT, Localization.lang("Cut"), IconTheme.JabRefIcon.CUT.getSmallIcon()));
- add(new GeneralAction(Actions.DELETE, Localization.lang("Delete"), IconTheme.JabRefIcon.DELETE_ENTRY.getSmallIcon()));
- add(new GeneralAction(Actions.PRINT_PREVIEW, Localization.lang("Print entry preview"), IconTheme.JabRefIcon.PRINTED.getSmallIcon()));
+ add(new GeneralAction(Actions.PASTE, Localization.lang("Paste"), IconTheme.JabRefIcon.PASTE.getSmallIcon(), KeyBinding.PASTE));
+ add(new GeneralAction(Actions.CUT, Localization.lang("Cut"), IconTheme.JabRefIcon.CUT.getSmallIcon(), KeyBinding.CUT));
+ add(new GeneralAction(Actions.DELETE, Localization.lang("Delete"), IconTheme.JabRefIcon.DELETE_ENTRY.getSmallIcon(), KeyBinding.DELETE_ENTRY));
+ GeneralAction printPreviewAction = new GeneralAction(Actions.PRINT_PREVIEW, Localization.lang("Print entry preview"), IconTheme.JabRefIcon.PRINTED.getSmallIcon());
+ printPreviewAction.setEnabled(!multiple);
+ add(printPreviewAction);
+
addSeparator();
add(new GeneralAction(Actions.SEND_AS_EMAIL, Localization.lang("Send as email"), IconTheme.JabRefIcon.EMAIL.getSmallIcon()));
addSeparator();
JMenu markSpecific = JabRefFrame.subMenu(Localization.menuTitle("Mark specific color"));
+ markSpecific.setIcon(IconTheme.JabRefIcon.MARK_ENTRIES.getSmallIcon());
for (int i = 0; i < EntryMarker.MAX_MARKING_LEVEL; i++) {
markSpecific.add(new MarkEntriesAction(frame, i).getMenuItem());
}
if (multiple) {
- add(new GeneralAction(Actions.MARK_ENTRIES, Localization.lang("Mark entries"), IconTheme.JabRefIcon.MARK_ENTRIES.getSmallIcon()));
+ add(new GeneralAction(Actions.MARK_ENTRIES, Localization.lang("Mark entries"), IconTheme.JabRefIcon.MARK_ENTRIES.getSmallIcon(), KeyBinding.MARK_ENTRIES));
add(markSpecific);
- add(new GeneralAction(Actions.UNMARK_ENTRIES, Localization.lang("Unmark entries"), IconTheme.JabRefIcon.UNMARK_ENTRIES.getSmallIcon()));
+ add(new GeneralAction(Actions.UNMARK_ENTRIES, Localization.lang("Unmark entries"), IconTheme.JabRefIcon.UNMARK_ENTRIES.getSmallIcon(), KeyBinding.UNMARK_ENTRIES));
} else if (be != null) {
- Optional<String> marked = be.getFieldOptional(FieldName.MARKED_INTERNAL);
+ Optional<String> marked = be.getField(FieldName.MARKED_INTERNAL);
// We have to check for "" too as the marked field may be empty
if ((!marked.isPresent()) || marked.get().isEmpty()) {
- add(new GeneralAction(Actions.MARK_ENTRIES, Localization.lang("Mark entry"), IconTheme.JabRefIcon.MARK_ENTRIES.getSmallIcon()));
+ add(new GeneralAction(Actions.MARK_ENTRIES, Localization.lang("Mark entry"), IconTheme.JabRefIcon.MARK_ENTRIES.getSmallIcon(), KeyBinding.MARK_ENTRIES));
add(markSpecific);
} else {
add(markSpecific);
- add(new GeneralAction(Actions.UNMARK_ENTRIES, Localization.lang("Unmark entry"), IconTheme.JabRefIcon.UNMARK_ENTRIES.getSmallIcon()));
+ add(new GeneralAction(Actions.UNMARK_ENTRIES, Localization.lang("Unmark entry"), IconTheme.JabRefIcon.UNMARK_ENTRIES.getSmallIcon(), KeyBinding.UNMARK_ENTRIES));
}
}
if (Globals.prefs.getBoolean(JabRefPreferences.SPECIALFIELDSENABLED)) {
if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_RANKING)) {
JMenu rankingMenu = new JMenu();
- RightClickMenu.populateSpecialFieldMenu(rankingMenu, Rank.getInstance(), frame);
+ RightClickMenu.populateSpecialFieldMenu(rankingMenu, SpecialField.RANKING, frame);
add(rankingMenu);
}
@@ -118,24 +117,24 @@ public class RightClickMenu extends JPopupMenu implements PopupMenuListener {
// if multiple values are selected ("if (multiple)"), two options (set / clear) should be offered
// if one value is selected either set or clear should be offered
if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_RELEVANCE)) {
- add(Relevance.getInstance().getValues().get(0).getMenuAction(frame));
+ add(new SpecialFieldMenuAction(new SpecialFieldValueViewModel(SpecialField.RELEVANCE.getValues().get(0)), frame));
}
if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_QUALITY)) {
- add(Quality.getInstance().getValues().get(0).getMenuAction(frame));
+ add(new SpecialFieldMenuAction(new SpecialFieldValueViewModel(SpecialField.QUALITY.getValues().get(0)), frame));
}
if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_PRINTED)) {
- add(Printed.getInstance().getValues().get(0).getMenuAction(frame));
+ add(new SpecialFieldMenuAction(new SpecialFieldValueViewModel(SpecialField.PRINTED.getValues().get(0)), frame));
}
if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_PRIORITY)) {
JMenu priorityMenu = new JMenu();
- RightClickMenu.populateSpecialFieldMenu(priorityMenu, Priority.getInstance(), frame);
+ RightClickMenu.populateSpecialFieldMenu(priorityMenu, SpecialField.PRIORITY, frame);
add(priorityMenu);
}
if (Globals.prefs.getBoolean(JabRefPreferences.SHOWCOLUMN_READ)) {
JMenu readStatusMenu = new JMenu();
- RightClickMenu.populateSpecialFieldMenu(readStatusMenu, ReadStatus.getInstance(), frame);
+ RightClickMenu.populateSpecialFieldMenu(readStatusMenu, SpecialField.READ_STATUS, frame);
add(readStatusMenu);
}
@@ -143,56 +142,43 @@ public class RightClickMenu extends JPopupMenu implements PopupMenuListener {
addSeparator();
- add(new GeneralAction(Actions.OPEN_FOLDER, Localization.lang("Open folder")) {
- {
- if (!isFieldSetForSelectedEntry(FieldName.FILE)) {
- this.setEnabled(false);
- }
- }
- });
+ GeneralAction openFolderAction = new GeneralAction(Actions.OPEN_FOLDER, Localization.lang("Open folder"),
+ KeyBinding.OPEN_FOLDER);
+ openFolderAction.setEnabled(isFieldSetForSelectedEntry(FieldName.FILE));
+ add(openFolderAction);
- add(new GeneralAction(Actions.OPEN_EXTERNAL_FILE, Localization.lang("Open file"), getFileIconForSelectedEntry()) {
- {
- if (!isFieldSetForSelectedEntry(FieldName.FILE)) {
- this.setEnabled(false);
- }
- }
- });
+ GeneralAction openFileAction = new GeneralAction(Actions.OPEN_EXTERNAL_FILE, Localization.lang("Open file"),
+ getFileIconForSelectedEntry(), KeyBinding.OPEN_FILE);
+ openFileAction.setEnabled(isFieldSetForSelectedEntry(FieldName.FILE));
+ add(openFileAction);
- add(new GeneralAction(Actions.OPEN_URL, Localization.lang("Open URL or DOI"), IconTheme.JabRefIcon.WWW.getSmallIcon()) {
- {
- if(!(isFieldSetForSelectedEntry(FieldName.URL) || isFieldSetForSelectedEntry(FieldName.DOI))) {
- this.setEnabled(false);
- }
- }
- });
+ GeneralAction openUrlAction = new GeneralAction(Actions.OPEN_URL, Localization.lang("Open URL or DOI"),
+ IconTheme.JabRefIcon.WWW.getSmallIcon(), KeyBinding.OPEN_URL_OR_DOI);
+ openUrlAction.setEnabled(isFieldSetForSelectedEntry(FieldName.URL) || isFieldSetForSelectedEntry(FieldName.DOI));
+ add(openUrlAction);
addSeparator();
add(typeMenu);
- add(new GeneralAction(Actions.MERGE_WITH_FETCHED_ENTRY,
- Localization.lang("Get BibTeX data from %0", FetchAndMergeEntry.getDisplayNameOfSupportedFields())) {
- {
- if (!(isAnyFieldSetForSelectedEntry(FetchAndMergeEntry.SUPPORTED_FIELDS))) {
- this.setEnabled(false);
- }
- }
- });
+ GeneralAction mergeFetchedEntryAction = new GeneralAction(Actions.MERGE_WITH_FETCHED_ENTRY,
+ Localization.lang("Get BibTeX data from %0", FetchAndMergeEntry.getDisplayNameOfSupportedFields()));
+ mergeFetchedEntryAction.setEnabled(isAnyFieldSetForSelectedEntry(FetchAndMergeEntry.SUPPORTED_FIELDS));
+ add(mergeFetchedEntryAction);
+
add(frame.getMassSetField());
- add(new GeneralAction(Actions.ADD_FILE_LINK, Localization.lang("Attach file"), IconTheme.JabRefIcon.ATTACH_FILE.getSmallIcon()));
- add(frame.getManageKeywords());
- add(new GeneralAction(Actions.MERGE_ENTRIES,
- Localization.lang("Merge entries") + "...",
- IconTheme.JabRefIcon.MERGE_ENTRIES.getSmallIcon()) {
- {
- if (!(areExactlyTwoEntriesSelected())) {
- this.setEnabled(false);
- }
- }
+ GeneralAction attachFileAction = new GeneralAction(Actions.ADD_FILE_LINK, Localization.lang("Attach file"),
+ IconTheme.JabRefIcon.ATTACH_FILE.getSmallIcon());
+ attachFileAction.setEnabled(!multiple);
+ add(attachFileAction);
- });
+ add(frame.getManageKeywords());
+
+ GeneralAction mergeEntriesAction = new GeneralAction(Actions.MERGE_ENTRIES,
+ Localization.lang("Merge entries") + "...", IconTheme.JabRefIcon.MERGE_ENTRIES.getSmallIcon());
+ mergeEntriesAction.setEnabled(areExactlyTwoEntriesSelected());
+ add(mergeEntriesAction);
addSeparator(); // for "add/move/remove to/from group" entries (appended here)
@@ -221,10 +207,11 @@ public class RightClickMenu extends JPopupMenu implements PopupMenuListener {
* Then cycle through all available values, and add them.
*/
public static void populateSpecialFieldMenu(JMenu menu, SpecialField field, JabRefFrame frame) {
- menu.setText(field.getMenuString());
- menu.setIcon(((IconTheme.FontBasedIcon) field.getRepresentingIcon()).createSmallIcon());
+ SpecialFieldViewModel viewModel = new SpecialFieldViewModel(field);
+ menu.setText(viewModel.getLocalization());
+ menu.setIcon(viewModel.getRepresentingIcon());
for (SpecialFieldValue val : field.getValues()) {
- menu.add(val.getMenuAction(frame));
+ menu.add(new SpecialFieldMenuAction(new SpecialFieldValueViewModel(val), frame));
}
}
@@ -234,16 +221,11 @@ public class RightClickMenu extends JPopupMenu implements PopupMenuListener {
@Override
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
panel.storeCurrentEdit();
- GroupTreeNode groups = panel.getBibDatabaseContext().getMetaData().getGroups();
- if (groups == null) {
- groupAdd.setEnabled(false);
- groupRemove.setEnabled(false);
- groupMoveTo.setEnabled(false);
- } else {
- groupAdd.setEnabled(true);
- groupRemove.setEnabled(true);
- groupMoveTo.setEnabled(true);
- }
+
+ boolean groupsPresent = panel.getBibDatabaseContext().getMetaData().getGroups().isPresent();
+ groupAdd.setEnabled(groupsPresent);
+ groupRemove.setEnabled(groupsPresent);
+ groupMoveTo.setEnabled(groupsPresent);
}
@@ -273,7 +255,7 @@ public class RightClickMenu extends JPopupMenu implements PopupMenuListener {
if (panel.getMainTable().getSelectedRowCount() == 1) {
BibEntry entry = panel.getMainTable().getSelected().get(0);
if(entry.hasField(FieldName.FILE)) {
- JLabel label = FileListTableModel.getFirstLabel(entry.getFieldOptional(FieldName.FILE).get());
+ JLabel label = FileListTableModel.getFirstLabel(entry.getField(FieldName.FILE).get());
if (label != null) {
return label.getIcon();
}
@@ -296,6 +278,18 @@ public class RightClickMenu extends JPopupMenu implements PopupMenuListener {
this.command = command;
}
+ public GeneralAction(String command, String name, KeyBinding key) {
+ super(name);
+ this.command = command;
+ putValue(Action.ACCELERATOR_KEY, Globals.getKeyPrefs().getKey(key));
+ }
+
+ public GeneralAction(String command, String name, Icon icon, KeyBinding key) {
+ super(name, icon);
+ this.command = command;
+ putValue(Action.ACCELERATOR_KEY, Globals.getKeyPrefs().getKey(key));
+ }
+
@Override
public void actionPerformed(ActionEvent e) {
try {
diff --git a/src/main/java/net/sf/jabref/gui/mergeentries/EntryFetchAndMergeWorker.java b/src/main/java/net/sf/jabref/gui/mergeentries/EntryFetchAndMergeWorker.java
new file mode 100644
index 0000000..1f3c04f
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/mergeentries/EntryFetchAndMergeWorker.java
@@ -0,0 +1,64 @@
+package net.sf.jabref.gui.mergeentries;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.concurrent.ExecutionException;
+
+import javax.swing.SwingWorker;
+
+import net.sf.jabref.gui.BasePanel;
+import net.sf.jabref.logic.importer.EntryBasedFetcher;
+import net.sf.jabref.logic.importer.FetcherException;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.entry.BibEntry;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class EntryFetchAndMergeWorker extends SwingWorker<Optional<BibEntry>, Void> {
+
+ private static final Log LOGGER = LogFactory.getLog(EntryFetchAndMergeWorker.class);
+
+ private final BasePanel panel;
+ private final BibEntry entry;
+ private final EntryBasedFetcher fetcher;
+
+ public EntryFetchAndMergeWorker(BasePanel panel, BibEntry entry, EntryBasedFetcher fetcher) {
+ this.panel = Objects.requireNonNull(panel);
+ this.entry = Objects.requireNonNull(entry);
+ this.fetcher = Objects.requireNonNull(fetcher);
+ }
+
+ @Override
+ protected Optional<BibEntry> doInBackground() throws Exception {
+ try {
+ List<BibEntry> fetchedEntries = fetcher.performSearch(entry);
+ return fetchedEntries.stream().findFirst();
+ } catch (FetcherException e) {
+ LOGGER.error("Info cannot be found", e);
+ return Optional.empty();
+ }
+ }
+
+ @Override
+ protected void done() {
+ if (isCancelled()) {
+ return;
+ }
+
+ try {
+ Optional<BibEntry> fetchedEntry = get();
+ if (fetchedEntry.isPresent()) {
+ MergeFetchedEntryDialog dialog = new MergeFetchedEntryDialog(panel, entry, fetchedEntry.get(),
+ fetcher.getName());
+ dialog.setVisible(true);
+ } else {
+ panel.frame().setStatus(Localization.lang("Could not find any bibliographic information."));
+ }
+ } catch (InterruptedException | ExecutionException e) {
+ LOGGER.error("Error while fetching Entry", e);
+ }
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/gui/mergeentries/FetchAndMergeEntry.java b/src/main/java/net/sf/jabref/gui/mergeentries/FetchAndMergeEntry.java
index a66b536..58bfcc3 100644
--- a/src/main/java/net/sf/jabref/gui/mergeentries/FetchAndMergeEntry.java
+++ b/src/main/java/net/sf/jabref/gui/mergeentries/FetchAndMergeEntry.java
@@ -2,16 +2,9 @@ package net.sf.jabref.gui.mergeentries;
import java.util.Arrays;
import java.util.List;
-import java.util.Optional;
import java.util.stream.Collectors;
-import net.sf.jabref.Globals;
import net.sf.jabref.gui.BasePanel;
-import net.sf.jabref.gui.importer.fetcher.ISBNtoBibTeXFetcher;
-import net.sf.jabref.logic.importer.FetcherException;
-import net.sf.jabref.logic.importer.ImportFormatPreferences;
-import net.sf.jabref.logic.importer.fetcher.ArXiv;
-import net.sf.jabref.logic.importer.fetcher.DOItoBibTeX;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.FieldName;
@@ -43,48 +36,19 @@ public class FetchAndMergeEntry {
* @param panel - current BasePanel
* @param fields - List of fields to get information from, one at a time in given order
*/
-
public FetchAndMergeEntry(BibEntry entry, BasePanel panel, List<String> fields) {
for (String field : fields) {
- Optional<String> fieldContent = entry.getFieldOptional(field);
-
- // Get better looking name for status messages
- String type = FieldName.getDisplayName(field);
-
- if (fieldContent.isPresent()) {
- Optional<BibEntry> fetchedEntry = Optional.empty();
- // Get entry based on field
- if (FieldName.DOI.equals(field)) {
- fetchedEntry = new DOItoBibTeX().getEntryFromDOI(fieldContent.get(),
- ImportFormatPreferences.fromPreferences(Globals.prefs));
- } else if (FieldName.ISBN.equals(field)) {
- fetchedEntry = new ISBNtoBibTeXFetcher().getEntryFromISBN(fieldContent.get(), null);
- } else if (FieldName.EPRINT.equals(field)) {
- try {
- fetchedEntry = new ArXiv().performSearchById(fieldContent.get());
- } catch (FetcherException e) {
- panel.frame().setStatus(
- Localization.lang("Cannot get info based on given %0:_%1", type, fieldContent.get()));
- }
- }
-
- if (fetchedEntry.isPresent()) {
- MergeFetchedEntryDialog dialog = new MergeFetchedEntryDialog(panel, entry, fetchedEntry.get(),
- type);
- dialog.setVisible(true);
- } else {
- panel.frame()
- .setStatus(Localization.lang("Cannot get info based on given %0:_%1", type,
- fieldContent.get()));
- }
+ if (entry.hasField(field)) {
+ new FetchAndMergeWorker(panel, entry, field).execute();
} else {
- panel.frame().setStatus(Localization.lang("No %0 found", type));
+ panel.frame().setStatus(Localization.lang("No %0 found", FieldName.getDisplayName(field)));
}
}
}
public static String getDisplayNameOfSupportedFields() {
- return FieldName.orFields(SUPPORTED_FIELDS.stream().map(fieldName -> FieldName.getDisplayName(fieldName))
+ return FieldName.orFields(SUPPORTED_FIELDS.stream()
+ .map(FieldName::getDisplayName)
.collect(Collectors.toList()));
}
}
diff --git a/src/main/java/net/sf/jabref/gui/mergeentries/FetchAndMergeWorker.java b/src/main/java/net/sf/jabref/gui/mergeentries/FetchAndMergeWorker.java
new file mode 100644
index 0000000..3a8118f
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/mergeentries/FetchAndMergeWorker.java
@@ -0,0 +1,77 @@
+package net.sf.jabref.gui.mergeentries;
+
+import java.util.Objects;
+import java.util.Optional;
+import java.util.concurrent.ExecutionException;
+
+import javax.swing.SwingWorker;
+
+import net.sf.jabref.Globals;
+import net.sf.jabref.gui.BasePanel;
+import net.sf.jabref.logic.importer.FetcherException;
+import net.sf.jabref.logic.importer.IdBasedFetcher;
+import net.sf.jabref.logic.importer.WebFetchers;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldName;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+
+public class FetchAndMergeWorker extends SwingWorker<Optional<BibEntry>, Void> {
+
+ private static final Log LOGGER = LogFactory.getLog(FetchAndMergeWorker.class);
+
+ private final BasePanel panel;
+ private final BibEntry entry;
+ private final String field;
+ private final Optional<String> fieldContent;
+
+
+ public FetchAndMergeWorker(BasePanel panel, BibEntry entry, String field) {
+ this.panel = Objects.requireNonNull(panel);
+ this.entry = Objects.requireNonNull(entry);
+ this.field = Objects.requireNonNull(field);
+
+ this.fieldContent = entry.getField(field);
+ }
+
+ @Override
+ protected Optional<BibEntry> doInBackground() throws Exception {
+ Optional<IdBasedFetcher> fetcher = WebFetchers.getIdBasedFetcherForField(field, Globals.prefs.getImportFormatPreferences());
+
+ try {
+ Optional<String> fieldContentValue = fieldContent;
+ if (fieldContentValue.isPresent() && fetcher.isPresent()) {
+ return fetcher.get().performSearchById(fieldContentValue.get());
+ } else {
+ return Optional.empty();
+ }
+ } catch (FetcherException e) {
+ LOGGER.error("Info cannot be found", e);
+ return Optional.empty();
+ }
+ }
+
+ @Override
+ protected void done() {
+ if (isCancelled()) {
+ return;
+ }
+
+ try {
+ String type = FieldName.getDisplayName(field);
+ Optional<BibEntry> fetchedEntry = get();
+ if (fetchedEntry.isPresent()) {
+ MergeFetchedEntryDialog dialog = new MergeFetchedEntryDialog(panel, entry, fetchedEntry.get(), type);
+ dialog.setVisible(true);
+ } else {
+ panel.frame().setStatus(Localization.lang("Cannot get info based on given %0: %1", type, fieldContent.get()));
+ }
+ } catch (InterruptedException | ExecutionException e) {
+ LOGGER.error("Error while fetching Entry", e);
+ }
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/gui/mergeentries/MergeEntries.java b/src/main/java/net/sf/jabref/gui/mergeentries/MergeEntries.java
index 5eeb83e..1b19f58 100644
--- a/src/main/java/net/sf/jabref/gui/mergeentries/MergeEntries.java
+++ b/src/main/java/net/sf/jabref/gui/mergeentries/MergeEntries.java
@@ -24,6 +24,7 @@ import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JTextArea;
import javax.swing.JTextPane;
+import javax.swing.ScrollPaneConstants;
import javax.swing.SwingUtilities;
import net.sf.jabref.Globals;
@@ -31,10 +32,8 @@ import net.sf.jabref.gui.PreviewPanel;
import net.sf.jabref.gui.util.component.DiffHighlightingTextPane;
import net.sf.jabref.logic.bibtex.BibEntryWriter;
import net.sf.jabref.logic.bibtex.LatexFieldFormatter;
-import net.sf.jabref.logic.bibtex.LatexFieldFormatterPreferences;
import net.sf.jabref.logic.formatter.casechanger.SentenceCaseFormatter;
import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.logic.util.strings.DiffHighlighting;
import net.sf.jabref.model.database.BibDatabaseMode;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.InternalBibtexFields;
@@ -168,8 +167,8 @@ public class MergeEntries {
// Create and add scrollpane
- scrollPane = new JScrollPane(mergePanel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
- JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
+ scrollPane = new JScrollPane(mergePanel, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
+ ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
scrollPane.setBorder(BorderFactory.createEmptyBorder());
updateTextPanes(allFields);
mainPanel.add(scrollPane, CELL_CONSTRAINTS.xyw(1, 4, 11));
@@ -180,7 +179,7 @@ public class MergeEntries {
// Setup a PreviewPanel and a Bibtex source box for the merged entry
mainPanel.add(boldFontLabel(Localization.lang("Merged entry")), CELL_CONSTRAINTS.xyw(1, 6, 6));
- entryPreview = new PreviewPanel(null, mergedEntry, null, Globals.prefs.get(JabRefPreferences.PREVIEW_0));
+ entryPreview = new PreviewPanel(null, mergedEntry, null);
mainPanel.add(entryPreview, CELL_CONSTRAINTS.xyw(1, 8, 6));
mainPanel.add(boldFontLabel(Localization.lang("Merged BibTeX source code")), CELL_CONSTRAINTS.xyw(8, 6, 4));
@@ -214,8 +213,8 @@ public class MergeEntries {
for (String field : allFields) {
JLabel label = boldFontLabel(new SentenceCaseFormatter().format(field));
mergePanel.add(label, CELL_CONSTRAINTS.xy(1, (2 * row) - 1, "left, top"));
- Optional<String> leftString = leftEntry.getFieldOptional(field);
- Optional<String> rightString = rightEntry.getFieldOptional(field);
+ Optional<String> leftString = leftEntry.getField(field);
+ Optional<String> rightString = rightEntry.getField(field);
if (leftString.equals(rightString)) {
identicalFields.add(field);
} else {
@@ -272,7 +271,7 @@ public class MergeEntries {
mergePanel.add(boldFontLabel(Localization.lang("Entry type")), CELL_CONSTRAINTS.xy(1, 1));
JTextPane leftTypeDisplay = new DiffHighlightingTextPane();
- leftTypeDisplay.setText(DiffHighlighting.HTML_START + leftEntry.getType() + DiffHighlighting.HTML_END);
+ leftTypeDisplay.setText(leftEntry.getType());
mergePanel.add(leftTypeDisplay, CELL_CONSTRAINTS.xy(3, 1));
if (leftEntry.getType().equals(rightEntry.getType())) {
identicalTypes = true;
@@ -290,13 +289,14 @@ public class MergeEntries {
typeRadioButtons.get(0).setSelected(true);
}
JTextPane rightTypeDisplay = new DiffHighlightingTextPane();
- rightTypeDisplay.setText(DiffHighlighting.HTML_START + rightEntry.getType() + DiffHighlighting.HTML_END);
+ rightTypeDisplay.setText(rightEntry.getType());
mergePanel.add(rightTypeDisplay, CELL_CONSTRAINTS.xy(11, 1));
}
private void setupHeadingRows() {
mainPanel.add(boldFontLabel(Localization.lang("Use")), CELL_CONSTRAINTS.xyw(4, 1, 7, "center, bottom"));
mainPanel.add(diffMode, CELL_CONSTRAINTS.xy(11, 1, "right, bottom"));
+ diffMode.setVisible(false);
// Set headings
for (int i = 0; i < 6; i++) {
@@ -360,35 +360,13 @@ public class MergeEntries {
private void updateTextPanes(Collection<String> fields) {
int oldScrollPaneValue = scrollPane.getVerticalScrollBar().getValue();
for (String field : fields) {
- String leftString = leftEntry.getFieldOptional(field).orElse("");
- String rightString = rightEntry.getFieldOptional(field).orElse("");
- switch (diffMode.getSelectedIndex()) {
- case 0: // Plain text
- break;
- case 1: // Latexdiff style - word
- rightString = DiffHighlighting.generateDiffHighlighting(leftString, rightString, " ");
- break;
- case 2: // Latexdiff style - character
- rightString = DiffHighlighting.generateDiffHighlighting(leftString, rightString, "");
- break;
- case 3: // Symmetric style - word
- String tmpLeftString = DiffHighlighting.generateSymmetricHighlighting(leftString, rightString, " ");
- rightString = DiffHighlighting.generateSymmetricHighlighting(rightString, leftString, " ");
- leftString = tmpLeftString;
- break;
- case 4: // Symmetric style - character
- tmpLeftString = DiffHighlighting.generateSymmetricHighlighting(leftString, rightString, "");
- rightString = DiffHighlighting.generateSymmetricHighlighting(rightString, leftString, "");
- leftString = tmpLeftString;
- break;
- default: // Shouldn't happen
- break;
- }
+ String leftString = leftEntry.getField(field).orElse("");
+ String rightString = rightEntry.getField(field).orElse("");
if ((leftString != null) && leftTextPanes.containsKey(field)) {
- leftTextPanes.get(field).setText(DiffHighlighting.HTML_START + leftString + DiffHighlighting.HTML_END);
+ leftTextPanes.get(field).setText(leftString);
}
if ((rightString != null) && rightTextPanes.containsKey(field)) {
- rightTextPanes.get(field).setText(DiffHighlighting.HTML_START + rightString + DiffHighlighting.HTML_END);
+ rightTextPanes.get(field).setText(rightString);
}
}
SwingUtilities.invokeLater(() -> scrollPane.getVerticalScrollBar()
@@ -428,9 +406,9 @@ public class MergeEntries {
// Check the potentially different fields
for (String field : differentFields) {
if (radioButtons.get(field).get(0).isSelected()) {
- mergedEntry.setField(field, leftEntry.getFieldOptional(field).get()); // Will only happen if field exists
+ mergedEntry.setField(field, leftEntry.getField(field).get()); // Will only happen if field exists
} else if (radioButtons.get(field).get(2).isSelected()) {
- mergedEntry.setField(field, rightEntry.getFieldOptional(field).get()); // Will only happen if field exists
+ mergedEntry.setField(field, rightEntry.getField(field).get()); // Will only happen if field exists
} else {
mergedEntry.clearField(field);
}
@@ -442,7 +420,7 @@ public class MergeEntries {
// Update the BibTeX source view
StringWriter writer = new StringWriter();
try {
- new BibEntryWriter(new LatexFieldFormatter(LatexFieldFormatterPreferences.fromPreferences(Globals.prefs)),
+ new BibEntryWriter(new LatexFieldFormatter(Globals.prefs.getLatexFieldFormatterPreferences()),
false).write(mergedEntry, writer, databaseType);
} catch (IOException ex) {
LOGGER.error("Error in entry", ex);
diff --git a/src/main/java/net/sf/jabref/gui/mergeentries/MergeEntriesDialog.java b/src/main/java/net/sf/jabref/gui/mergeentries/MergeEntriesDialog.java
index 020c8cd..14de109 100644
--- a/src/main/java/net/sf/jabref/gui/mergeentries/MergeEntriesDialog.java
+++ b/src/main/java/net/sf/jabref/gui/mergeentries/MergeEntriesDialog.java
@@ -11,7 +11,7 @@ import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.gui.undo.NamedCompound;
import net.sf.jabref.gui.undo.UndoableInsertEntry;
import net.sf.jabref.gui.undo.UndoableRemoveEntry;
-import net.sf.jabref.gui.util.PositionWindow;
+import net.sf.jabref.gui.util.WindowLocation;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.preferences.JabRefPreferences;
@@ -113,10 +113,10 @@ public class MergeEntriesDialog extends JDialog {
layout.insertColumn(1, ColumnSpec.decode(MARGIN));
- PositionWindow pw = new PositionWindow(this, JabRefPreferences.MERGEENTRIES_POS_X,
+ WindowLocation pw = new WindowLocation(this, JabRefPreferences.MERGEENTRIES_POS_X,
JabRefPreferences.MERGEENTRIES_POS_Y, JabRefPreferences.MERGEENTRIES_SIZE_X,
JabRefPreferences.MERGEENTRIES_SIZE_Y);
- pw.setWindowPosition();
+ pw.displayWindowAtStoredLocation();
// Show what we've got
setVisible(true);
diff --git a/src/main/java/net/sf/jabref/gui/mergeentries/MergeFetchedEntryDialog.java b/src/main/java/net/sf/jabref/gui/mergeentries/MergeFetchedEntryDialog.java
index 24cd4f1..a6d7261 100644
--- a/src/main/java/net/sf/jabref/gui/mergeentries/MergeFetchedEntryDialog.java
+++ b/src/main/java/net/sf/jabref/gui/mergeentries/MergeFetchedEntryDialog.java
@@ -1,9 +1,12 @@
package net.sf.jabref.gui.mergeentries;
+import java.awt.event.ActionEvent;
import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;
+import javax.swing.AbstractAction;
+import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JSeparator;
@@ -12,7 +15,7 @@ import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.gui.undo.NamedCompound;
import net.sf.jabref.gui.undo.UndoableChangeType;
import net.sf.jabref.gui.undo.UndoableFieldChange;
-import net.sf.jabref.gui.util.PositionWindow;
+import net.sf.jabref.gui.util.WindowLocation;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.InternalBibtexFields;
@@ -25,7 +28,7 @@ import com.jgoodies.forms.layout.FormLayout;
import com.jgoodies.forms.layout.RowSpec;
/**
- * Dialog for merging Bibtex entry with data fetched from DOI
+ * Dialog for merging Bibtex entry with fetched data
*/
public class MergeFetchedEntryDialog extends JDialog {
@@ -70,15 +73,11 @@ public class MergeFetchedEntryDialog extends JDialog {
// Create buttons
ButtonBarBuilder bb = new ButtonBarBuilder();
bb.addGlue();
- JButton cancel = new JButton(Localization.lang("Cancel"));
- cancel.setActionCommand("cancel");
- cancel.addActionListener(e -> buttonPressed(e.getActionCommand()));
- JButton replaceentry = new JButton(Localization.lang("Replace original entry"));
- replaceentry.setActionCommand("done");
- replaceentry.addActionListener(e -> buttonPressed(e.getActionCommand()));
+ JButton cancel = new JButton(new CancelAction());
+ JButton replaceEntry = new JButton(new ReplaceAction());
- bb.addButton(new JButton[] {replaceentry, cancel});
+ bb.addButton(replaceEntry, cancel);
this.add(bb.getPanel(), cc.xy(1, 5));
// Add some margin around the layout
@@ -87,25 +86,34 @@ public class MergeFetchedEntryDialog extends JDialog {
layout.insertRow(1, RowSpec.decode(MARGIN));
layout.insertColumn(1, ColumnSpec.decode(MARGIN));
- PositionWindow pw = new PositionWindow(this, JabRefPreferences.MERGEENTRIES_POS_X,
+ WindowLocation pw = new WindowLocation(this, JabRefPreferences.MERGEENTRIES_POS_X,
JabRefPreferences.MERGEENTRIES_POS_Y, JabRefPreferences.MERGEENTRIES_SIZE_X,
JabRefPreferences.MERGEENTRIES_SIZE_Y);
- pw.setWindowPosition();
+ pw.displayWindowAtStoredLocation();
}
- /**
- * Act on button pressed
- *
- * @param button Button pressed
- */
- private void buttonPressed(String button) {
- BibEntry mergedEntry = mergeEntries.getMergeEntry();
+ private class CancelAction extends AbstractAction {
+ CancelAction(){
+ putValue(Action.NAME, Localization.lang("Cancel"));
+ }
- if ("cancel".equals(button)) {
- // Canceled, throw it away
+ @Override
+ public void actionPerformed(ActionEvent e) {
panel.output(Localization.lang("Canceled merging entries"));
- } else if ("done".equals(button)) {
+ dispose();
+ }
+ }
+
+ private class ReplaceAction extends AbstractAction {
+ ReplaceAction(){
+ putValue(Action.NAME, Localization.lang("Replace original entry"));
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ BibEntry mergedEntry = mergeEntries.getMergeEntry();
+
// Updated the original entry with the new fields
Set<String> jointFields = new TreeSet<>(mergedEntry.getFieldNames());
Set<String> originalFields = new TreeSet<>(originalEntry.getFieldNames());
@@ -123,8 +131,8 @@ public class MergeFetchedEntryDialog extends JDialog {
// fields
for (String field : jointFields) {
- Optional<String> originalString = originalEntry.getFieldOptional(field);
- Optional<String> mergedString = mergedEntry.getFieldOptional(field);
+ Optional<String> originalString = originalEntry.getField(field);
+ Optional<String> mergedString = mergedEntry.getField(field);
if (!originalString.isPresent() || !originalString.equals(mergedString)) {
originalEntry.setField(field, mergedString.get()); // mergedString always present
ce.addEdit(new UndoableFieldChange(originalEntry, field, originalString.orElse(null),
@@ -136,7 +144,7 @@ public class MergeFetchedEntryDialog extends JDialog {
// Remove fields which are not in the merged entry, unless they are internal fields
for (String field : originalFields) {
if (!jointFields.contains(field) && !InternalBibtexFields.isInternalField(field)) {
- Optional<String> originalString = originalEntry.getFieldOptional(field);
+ Optional<String> originalString = originalEntry.getField(field);
originalEntry.clearField(field);
ce.addEdit(new UndoableFieldChange(originalEntry, field, originalString.get(), null)); // originalString always present
edited = true;
@@ -152,7 +160,8 @@ public class MergeFetchedEntryDialog extends JDialog {
} else {
panel.output(Localization.lang("No information added"));
}
+
+ dispose();
}
- dispose();
}
}
diff --git a/src/main/java/net/sf/jabref/gui/mergeentries/MergeWithFetchedEntryAction.java b/src/main/java/net/sf/jabref/gui/mergeentries/MergeWithFetchedEntryAction.java
new file mode 100644
index 0000000..6986543
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/mergeentries/MergeWithFetchedEntryAction.java
@@ -0,0 +1,34 @@
+package net.sf.jabref.gui.mergeentries;
+
+import javax.swing.JOptionPane;
+
+import net.sf.jabref.gui.BasePanel;
+import net.sf.jabref.gui.actions.BaseAction;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldName;
+
+public class MergeWithFetchedEntryAction implements BaseAction {
+
+ private final BasePanel basePanel;
+
+ public MergeWithFetchedEntryAction(BasePanel basePanel) {
+ this.basePanel = basePanel;
+ }
+
+ @Override
+ public void action() {
+ if (basePanel.getMainTable().getSelectedEntries().size() == 1) {
+ BibEntry originalEntry = basePanel.getMainTable().getSelectedEntries().get(0);
+ new FetchAndMergeEntry(originalEntry, basePanel, FetchAndMergeEntry.SUPPORTED_FIELDS);
+ } else {
+ JOptionPane.showMessageDialog(basePanel.frame(),
+ Localization.lang("This operation requires exactly one item to be selected."),
+ Localization.lang("Merge entry with %0 information",
+ FieldName.orFields(FieldName.getDisplayName(FieldName.DOI),
+ FieldName.getDisplayName(FieldName.ISBN),
+ FieldName.getDisplayName(FieldName.EPRINT))),
+ JOptionPane.INFORMATION_MESSAGE);
+ }
+ }
+}
diff --git a/src/main/java/net/sf/jabref/gui/openoffice/CitationManager.java b/src/main/java/net/sf/jabref/gui/openoffice/CitationManager.java
index 730054e..d13967c 100644
--- a/src/main/java/net/sf/jabref/gui/openoffice/CitationManager.java
+++ b/src/main/java/net/sf/jabref/gui/openoffice/CitationManager.java
@@ -22,7 +22,6 @@ import javax.swing.JTextField;
import net.sf.jabref.Globals;
import net.sf.jabref.gui.JabRefFrame;
import net.sf.jabref.gui.keyboard.KeyBinding;
-import net.sf.jabref.gui.util.GUIUtil;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.openoffice.CitationEntry;
@@ -73,7 +72,6 @@ class CitationManager {
}
tableModel = new DefaultEventTableModel<>(list, new CitationEntryFormat());
table = new JTable(tableModel);
- GUIUtil.correctRowHeight(table);
diag.add(new JScrollPane(table), BorderLayout.CENTER);
diff --git a/src/main/java/net/sf/jabref/gui/openoffice/OOBibBase.java b/src/main/java/net/sf/jabref/gui/openoffice/OOBibBase.java
index f552601..855abb6 100644
--- a/src/main/java/net/sf/jabref/gui/openoffice/OOBibBase.java
+++ b/src/main/java/net/sf/jabref/gui/openoffice/OOBibBase.java
@@ -248,11 +248,11 @@ class OOBibBase {
} catch (Exception e) {
throw new CreationException(e.getMessage());
}
- XDesktop xDesktop = UnoRuntime.queryInterface(XDesktop.class, desktop);
+ XDesktop resultDesktop = UnoRuntime.queryInterface(XDesktop.class, desktop);
UnoRuntime.queryInterface(XComponentLoader.class, desktop);
- return xDesktop;
+ return resultDesktop;
}
private List<XTextDocument> getTextDocuments() throws NoSuchElementException, WrappedTargetException {
@@ -339,7 +339,7 @@ class OOBibBase {
}
String keyString = String.join(",",
- entries.stream().map(BibEntry::getCiteKey).collect(Collectors.toList()));
+ entries.stream().map(entry -> entry.getCiteKeyOptional().orElse("")).collect(Collectors.toList()));
// Insert bookmark:
String bName = getUniqueReferenceMarkName(keyString,
withText ? inParenthesis ? OOBibBase.AUTHORYEAR_PAR : OOBibBase.AUTHORYEAR_INTEXT : OOBibBase.INVISIBLE_CIT);
@@ -469,7 +469,7 @@ class OOBibBase {
// Rebuild the list of cited keys according to the sort order:
cited.clear();
for (BibEntry entry : entries.keySet()) {
- cited.add(entry.getCiteKey());
+ cited.add(entry.getCiteKeyOptional().orElse(null));
}
names = Arrays.asList(xReferenceMarks.getElementNames());
} else {
@@ -525,8 +525,8 @@ class OOBibBase {
StringBuilder sb = new StringBuilder();
normCitMarkers[i] = new String[keys.length];
for (int j = 0; j < keys.length; j++) {
- normCitMarkers[i][j] = cEntries[j].getCiteKey();
- sb.append(cEntries[j].getCiteKey());
+ normCitMarkers[i][j] = cEntries[j].getCiteKeyOptional().orElse(null);
+ sb.append(cEntries[j].getCiteKeyOptional().orElse(""));
if (j < (keys.length - 1)) {
sb.append(',');
}
@@ -583,7 +583,7 @@ class OOBibBase {
}
// Update key list to match the new sorting:
for (int j = 0; j < cEntries.length; j++) {
- bibtexKeys[i][j] = cEntries[j].getCiteKey();
+ bibtexKeys[i][j] = cEntries[j].getCiteKeyOptional().orElse(null);
}
}
@@ -1013,7 +1013,7 @@ class OOBibBase {
Layout layout = style.getReferenceFormat(entry.getKey().getType());
layout.setPostFormatter(POSTFORMATTER);
OOUtil.insertFullReferenceAtCurrentLocation(text, cursor, layout, parFormat, entry.getKey(),
- entry.getValue(), uniquefiers.get(entry.getKey().getCiteKey()));
+ entry.getValue(), uniquefiers.get(entry.getKey().getCiteKeyOptional().orElse(null)));
}
}
@@ -1266,8 +1266,8 @@ class OOBibBase {
}
}
Collections.sort(entries, new FieldComparator(FieldName.YEAR));
- String keyString = String.join(",",
- entries.stream().map(BibEntry::getCiteKey).collect(Collectors.toList()));
+ String keyString = String.join(",", entries.stream().map(entry -> entry.getCiteKeyOptional().orElse(""))
+ .collect(Collectors.toList()));
// Insert bookmark:
String bName = getUniqueReferenceMarkName(keyString, OOBibBase.AUTHORYEAR_PAR);
insertReferenceMark(bName, "tmp", mxDocCursor, true, style);
@@ -1368,7 +1368,7 @@ class OOBibBase {
// Insert a copy of the entry
resultDatabase.insertEntry(clonedEntry);
// Check if the cloned entry has a crossref field
- clonedEntry.getFieldOptional(FieldName.CROSSREF).ifPresent(crossref -> {
+ clonedEntry.getField(FieldName.CROSSREF).ifPresent(crossref -> {
// If the crossref entry is not already in the database
if (!resultDatabase.getEntryByKey(crossref).isPresent()) {
// Add it if it is in the current database
diff --git a/src/main/java/net/sf/jabref/gui/openoffice/OpenOfficePanel.java b/src/main/java/net/sf/jabref/gui/openoffice/OpenOfficePanel.java
index fc5d266..39d97f6 100644
--- a/src/main/java/net/sf/jabref/gui/openoffice/OpenOfficePanel.java
+++ b/src/main/java/net/sf/jabref/gui/openoffice/OpenOfficePanel.java
@@ -31,8 +31,6 @@ import javax.swing.JPopupMenu;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.JTextField;
-import net.sf.jabref.BibDatabaseContext;
-import net.sf.jabref.Defaults;
import net.sf.jabref.Globals;
import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.gui.FileDialog;
@@ -49,13 +47,14 @@ import net.sf.jabref.logic.bibtexkeypattern.BibtexKeyPatternPreferences;
import net.sf.jabref.logic.bibtexkeypattern.BibtexKeyPatternUtil;
import net.sf.jabref.logic.help.HelpFile;
import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.logic.layout.LayoutFormatterPreferences;
import net.sf.jabref.logic.openoffice.OOBibStyle;
import net.sf.jabref.logic.openoffice.OpenOfficePreferences;
import net.sf.jabref.logic.openoffice.StyleLoader;
import net.sf.jabref.logic.openoffice.UndefinedParagraphFormatException;
import net.sf.jabref.logic.util.OS;
+import net.sf.jabref.model.Defaults;
import net.sf.jabref.model.database.BibDatabase;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.database.BibDatabaseMode;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.preferences.JabRefPreferences;
@@ -83,7 +82,7 @@ public class OpenOfficePanel extends AbstractWorker {
private static final Log LOGGER = LogFactory.getLog(OpenOfficePanel.class);
- private OOPanel comp;
+ private OpenOfficeSidePanel sidePane;
private JDialog diag;
private final JButton connect;
private final JButton manualConnect;
@@ -102,7 +101,6 @@ public class OpenOfficePanel extends AbstractWorker {
HelpFile.OPENOFFICE_LIBREOFFICE).getHelpButton();
private OOBibBase ooBase;
private JabRefFrame frame;
- private SidePaneManager manager;
private OOBibStyle style;
private StyleSelectDialog styleDialog;
private boolean dialogOkPressed;
@@ -112,10 +110,8 @@ public class OpenOfficePanel extends AbstractWorker {
private final OpenOfficePreferences preferences;
private final StyleLoader loader;
- private static OpenOfficePanel instance;
-
- private OpenOfficePanel() {
+ public OpenOfficePanel(JabRefFrame jabRefFrame, SidePaneManager spManager) {
Icon connectImage = IconTheme.JabRefIcon.CONNECT_OPEN_OFFICE.getSmallIcon();
connect = new JButton(connectImage);
@@ -133,38 +129,13 @@ public class OpenOfficePanel extends AbstractWorker {
update.setPreferredSize(new Dimension(24, 24));
preferences = new OpenOfficePreferences(Globals.prefs);
loader = new StyleLoader(preferences,
- LayoutFormatterPreferences.fromPreferences(Globals.prefs, Globals.journalAbbreviationLoader),
+ Globals.prefs.getLayoutFormatterPreferences(Globals.journalAbbreviationLoader),
Globals.prefs.getDefaultEncoding());
- }
-
- public static OpenOfficePanel getInstance() {
- if (OpenOfficePanel.instance == null) {
- OpenOfficePanel.instance = new OpenOfficePanel();
- }
- return OpenOfficePanel.instance;
- }
- public SidePaneComponent getSidePaneComponent() {
- return comp;
- }
-
- public void init(JabRefFrame jabRefFrame, SidePaneManager spManager) {
this.frame = jabRefFrame;
- this.manager = spManager;
- comp = new OOPanel(spManager, IconTheme.getImage("openoffice"), "OpenOffice/LibreOffice", this);
+ sidePane = new OpenOfficeSidePanel(spManager, IconTheme.getImage("openoffice"), "OpenOffice/LibreOffice", preferences);
initPanel();
- spManager.register(getName(), comp);
- }
-
- public JMenuItem getMenuItem() {
- if (preferences.showPanel()) {
- manager.show(getName());
- }
- JMenuItem item = new JMenuItem(Localization.lang("OpenOffice/LibreOffice connection"),
- IconTheme.getImage("openoffice"));
- item.addActionListener(event -> manager.show(getName()));
- item.setAccelerator(Globals.getKeyPrefs().getKey(KeyBinding.OPEN_OPEN_OFFICE_LIBRE_OFFICE_CONNECTION));
- return item;
+ spManager.register(sidePane);
}
private void initPanel() {
@@ -327,7 +298,7 @@ public class OpenOfficePanel extends AbstractWorker {
mainBuilder.add(settingsB).xy(1, 10);
JPanel content = new JPanel();
- comp.setContentContainer(content);
+ sidePane.setContentContainer(content);
content.setLayout(new BorderLayout());
content.add(mainBuilder.getPanel(), BorderLayout.CENTER);
@@ -534,6 +505,8 @@ public class OpenOfficePanel extends AbstractWorker {
dialogOkPressed = false;
final JDialog cDiag = new JDialog(frame, Localization.lang("Set connection parameters"), true);
+
+ // Path fields
final JTextField ooPath = new JTextField(30);
JButton browseOOPath = new JButton(Localization.lang("Browse"));
ooPath.setText(preferences.getOOPath());
@@ -576,9 +549,9 @@ public class OpenOfficePanel extends AbstractWorker {
builder.add(browseOOJars).xy(5, 3);
}
builder.padding("5dlu, 5dlu, 5dlu, 5dlu");
- ButtonBarBuilder bb = new ButtonBarBuilder();
- JButton ok = new JButton(Localization.lang("OK"));
- JButton cancel = new JButton(Localization.lang("Cancel"));
+
+ cDiag.getContentPane().add(builder.getPanel(), BorderLayout.CENTER);
+
ActionListener tfListener = e -> {
preferences.updateConnectionParams(ooPath.getText(), ooExec.getText(), ooJars.getText());
cDiag.dispose();
@@ -587,22 +560,28 @@ public class OpenOfficePanel extends AbstractWorker {
ooPath.addActionListener(tfListener);
ooExec.addActionListener(tfListener);
ooJars.addActionListener(tfListener);
+
+ // Buttons
+ JButton ok = new JButton(Localization.lang("OK"));
+ JButton cancel = new JButton(Localization.lang("Cancel"));
+
ok.addActionListener(e -> {
preferences.updateConnectionParams(ooPath.getText(), ooExec.getText(), ooJars.getText());
dialogOkPressed = true;
cDiag.dispose();
});
-
cancel.addActionListener(e -> cDiag.dispose());
+ ButtonBarBuilder bb = new ButtonBarBuilder();
bb.addGlue();
bb.addRelatedGap();
bb.addButton(ok);
bb.addButton(cancel);
bb.addGlue();
bb.padding("5dlu, 5dlu, 5dlu, 5dlu");
- cDiag.getContentPane().add(builder.getPanel(), BorderLayout.CENTER);
cDiag.getContentPane().add(bb.getPanel(), BorderLayout.SOUTH);
+
+ // Finish and show dialog
cDiag.pack();
cDiag.setLocationRelativeTo(frame);
cDiag.setVisible(true);
@@ -621,15 +600,15 @@ public class OpenOfficePanel extends AbstractWorker {
Boolean inParenthesis = inParenthesisIn;
String pageInfo = null;
if (addPageInfo) {
- AdvancedCiteDialog acd = new AdvancedCiteDialog(frame);
- acd.showDialog();
- if (acd.canceled()) {
+ AdvancedCiteDialog citeDialog = new AdvancedCiteDialog(frame);
+ citeDialog.showDialog();
+ if (citeDialog.canceled()) {
return;
}
- if (!acd.getPageInfo().isEmpty()) {
- pageInfo = acd.getPageInfo();
+ if (!citeDialog.getPageInfo().isEmpty()) {
+ pageInfo = citeDialog.getPageInfo();
}
- inParenthesis = acd.isInParenthesisCite();
+ inParenthesis = citeDialog.isInParenthesisCite();
}
@@ -700,17 +679,19 @@ public class OpenOfficePanel extends AbstractWorker {
BasePanel panel = frame.getCurrentBasePanel();
if ((answer == JOptionPane.OK_OPTION) && (panel != null)) {
// Generate keys
- BibtexKeyPatternPreferences prefs = BibtexKeyPatternPreferences.fromPreferences(Globals.prefs);
+ BibtexKeyPatternPreferences prefs = Globals.prefs.getBibtexKeyPatternPreferences();
NamedCompound undoCompound = new NamedCompound(Localization.lang("Cite"));
for (BibEntry entry : entries) {
if (!entry.getCiteKeyOptional().isPresent()) {
// Generate key
BibtexKeyPatternUtil
- .makeLabel(panel.getBibDatabaseContext().getMetaData(), panel.getDatabase(), entry,
+ .makeAndSetLabel(
+ panel.getBibDatabaseContext().getMetaData().getCiteKeyPattern(prefs.getKeyPattern()),
+ panel.getDatabase(), entry,
prefs);
// Add undo change
undoCompound.addEdit(
- new UndoableKeyChange(panel.getDatabase(), entry, null, entry.getCiteKeyOptional().get()));
+ new UndoableKeyChange(entry, null, entry.getCiteKeyOptional().get()));
}
}
undoCompound.end();
@@ -797,40 +778,8 @@ public class OpenOfficePanel extends AbstractWorker {
menu.show(settingsB, 0, settingsB.getHeight());
}
- public String getName() {
- return "OpenOffice/LibreOffice";
- }
-
-
- private class OOPanel extends SidePaneComponent {
-
- private final OpenOfficePanel openOfficePanel;
-
-
- public OOPanel(SidePaneManager sidePaneManager, Icon url, String s, OpenOfficePanel panel) {
- super(sidePaneManager, url, s);
- openOfficePanel = panel;
- }
-
- @Override
- public String getName() {
- return openOfficePanel.getName();
- }
-
- @Override
- public void componentClosing() {
- preferences.setShowPanel(false);
- }
-
- @Override
- public void componentOpening() {
- preferences.setShowPanel(true);
- }
-
- @Override
- public int getRescalingWeight() {
- return 0;
- }
+ public SidePaneComponent.ToggleAction getToggleAction() {
+ return sidePane.getToggleAction();
}
}
diff --git a/src/main/java/net/sf/jabref/gui/openoffice/OpenOfficeSidePanel.java b/src/main/java/net/sf/jabref/gui/openoffice/OpenOfficeSidePanel.java
new file mode 100644
index 0000000..5c3797c
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/openoffice/OpenOfficeSidePanel.java
@@ -0,0 +1,52 @@
+package net.sf.jabref.gui.openoffice;
+
+import javax.swing.Icon;
+
+import net.sf.jabref.Globals;
+import net.sf.jabref.gui.SidePaneComponent;
+import net.sf.jabref.gui.SidePaneManager;
+import net.sf.jabref.gui.keyboard.KeyBinding;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.logic.openoffice.OpenOfficePreferences;
+
+public class OpenOfficeSidePanel extends SidePaneComponent {
+
+ private OpenOfficePreferences preferences;
+ private final ToggleAction toggleAction;
+
+
+ public OpenOfficeSidePanel(SidePaneManager sidePaneManager, Icon icon, String title, OpenOfficePreferences preferences) {
+ super(sidePaneManager, icon, title);
+ this.preferences = preferences;
+ sidePaneManager.register(this);
+ if (preferences.showPanel()) {
+ manager.show(OpenOfficeSidePanel.class);
+ }
+
+ toggleAction = new ToggleAction(Localization.lang("OpenOffice/LibreOffice connection"),
+ Localization.lang("OpenOffice/LibreOffice connection"),
+ Globals.getKeyPrefs().getKey(KeyBinding.OPEN_OPEN_OFFICE_LIBRE_OFFICE_CONNECTION),
+ icon);
+ }
+
+ @Override
+ public void componentClosing() {
+ preferences.setShowPanel(false);
+ }
+
+ @Override
+ public void componentOpening() {
+ preferences.setShowPanel(true);
+ }
+
+ @Override
+ public int getRescalingWeight() {
+ return 0;
+ }
+
+ @Override
+ public ToggleAction getToggleAction() {
+ return toggleAction;
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/gui/openoffice/StyleSelectDialog.java b/src/main/java/net/sf/jabref/gui/openoffice/StyleSelectDialog.java
index 094827d..382ba26 100644
--- a/src/main/java/net/sf/jabref/gui/openoffice/StyleSelectDialog.java
+++ b/src/main/java/net/sf/jabref/gui/openoffice/StyleSelectDialog.java
@@ -32,25 +32,24 @@ import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.table.TableColumnModel;
-import net.sf.jabref.BibDatabaseContext;
import net.sf.jabref.Globals;
-import net.sf.jabref.external.ExternalFileType;
-import net.sf.jabref.external.ExternalFileTypes;
-import net.sf.jabref.external.UnknownExternalFileType;
import net.sf.jabref.gui.FileDialog;
import net.sf.jabref.gui.IconTheme;
import net.sf.jabref.gui.JabRefFrame;
import net.sf.jabref.gui.PreviewPanel;
import net.sf.jabref.gui.desktop.JabRefDesktop;
+import net.sf.jabref.gui.externalfiletype.ExternalFileType;
+import net.sf.jabref.gui.externalfiletype.ExternalFileTypes;
+import net.sf.jabref.gui.externalfiletype.UnknownExternalFileType;
import net.sf.jabref.gui.keyboard.KeyBinding;
-import net.sf.jabref.gui.util.GUIUtil;
-import net.sf.jabref.gui.util.PositionWindow;
+import net.sf.jabref.gui.util.WindowLocation;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.openoffice.OOBibStyle;
import net.sf.jabref.logic.openoffice.OpenOfficePreferences;
import net.sf.jabref.logic.openoffice.StyleLoader;
import net.sf.jabref.logic.util.FileExtensions;
import net.sf.jabref.logic.util.TestEntry;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.preferences.JabRefPreferences;
@@ -134,7 +133,7 @@ class StyleSelectDialog {
// Create a preview panel for previewing styles
// Must be done before creating the table to avoid NPEs
- preview = new PreviewPanel(null, null, "");
+ preview = new PreviewPanel(null, null);
// Use the test entry from the Preview settings tab in Preferences:
preview.setEntry(prevEntry);
@@ -199,9 +198,9 @@ class StyleSelectDialog {
diag.pack();
- PositionWindow pw = new PositionWindow(diag, JabRefPreferences.STYLES_POS_X, JabRefPreferences.STYLES_POS_Y,
+ WindowLocation pw = new WindowLocation(diag, JabRefPreferences.STYLES_POS_X, JabRefPreferences.STYLES_POS_Y,
JabRefPreferences.STYLES_SIZE_X, JabRefPreferences.STYLES_SIZE_Y);
- pw.setWindowPosition();
+ pw.displayWindowAtStoredLocation();
}
private void setupTable() {
@@ -215,7 +214,6 @@ class StyleSelectDialog {
cm.getColumn(0).setPreferredWidth(100);
cm.getColumn(1).setPreferredWidth(200);
cm.getColumn(2).setPreferredWidth(80);
- GUIUtil.correctRowHeight(table);
selectionModel = (DefaultEventSelectionModel<OOBibStyle>) GlazedListsSwing
.eventSelectionModelWithThreadProxyList(sortedStyles);
diff --git a/src/main/java/net/sf/jabref/gui/plaintextimport/TextInputDialog.java b/src/main/java/net/sf/jabref/gui/plaintextimport/TextInputDialog.java
index 69defc4..344fc1e 100644
--- a/src/main/java/net/sf/jabref/gui/plaintextimport/TextInputDialog.java
+++ b/src/main/java/net/sf/jabref/gui/plaintextimport/TextInputDialog.java
@@ -48,6 +48,7 @@ import javax.swing.JTextArea;
import javax.swing.JTextPane;
import javax.swing.JToolBar;
import javax.swing.ListSelectionModel;
+import javax.swing.ScrollPaneConstants;
import javax.swing.border.TitledBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
@@ -70,8 +71,6 @@ import net.sf.jabref.gui.undo.NamedCompound;
import net.sf.jabref.gui.util.component.OverlayPanel;
import net.sf.jabref.logic.bibtex.BibEntryWriter;
import net.sf.jabref.logic.bibtex.LatexFieldFormatter;
-import net.sf.jabref.logic.bibtex.LatexFieldFormatterPreferences;
-import net.sf.jabref.logic.importer.ImportFormatPreferences;
import net.sf.jabref.logic.importer.ParserResult;
import net.sf.jabref.logic.importer.fileformat.FreeCiteImporter;
import net.sf.jabref.logic.l10n.Localization;
@@ -82,7 +81,7 @@ import net.sf.jabref.model.EntryTypes;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.EntryType;
import net.sf.jabref.model.entry.FieldName;
-import net.sf.jabref.model.entry.FieldProperties;
+import net.sf.jabref.model.entry.FieldProperty;
import net.sf.jabref.model.entry.InternalBibtexFields;
import net.sf.jabref.preferences.JabRefPreferences;
@@ -92,13 +91,13 @@ import org.apache.commons.logging.LogFactory;
/**
* import from plain text => simple mark/copy/paste into bibtex entry
- *
+ * <p>
* TODO
- * - change colors and fonts
- * - delete selected text
- * - make textarea editable
- * - create several bibtex entries in dialog
- * - if the dialog works with an existing entry (right click menu item), the cancel option doesn't work well
+ * - change colors and fonts
+ * - delete selected text
+ * - make textarea editable
+ * - create several bibtex entries in dialog
+ * - if the dialog works with an existing entry (right click menu item), the cancel option doesn't work well
*/
public class TextInputDialog extends JDialog {
@@ -165,7 +164,7 @@ public class TextInputDialog extends JDialog {
JTabbedPane tabbed = new JTabbedPane();
tabbed.add(rawPanel, Localization.lang("Raw source"));
- tabbed.add(sourcePanel, Localization.lang("BibTeX source"));
+ tabbed.add(sourcePanel, Localization.lang("%0 source", frame.getCurrentBasePanel().getBibDatabaseContext().getMode().getFormattedName()));
// Panel Layout
panel1.setLayout(new BorderLayout());
@@ -243,7 +242,7 @@ public class TextInputDialog extends JDialog {
JLabel desc = new JLabel("<html><h3>" + Localization.lang("Plain text import") + "</h3><p>"
+ Localization.lang("This is a simple copy and paste dialog. First load or paste some text into "
- + "the text input area.<br>After that, you can mark text and assign it to a BibTeX field.")
+ + "the text input area.<br>After that, you can mark text and assign it to a BibTeX field.")
+ "</p></html>");
desc.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
@@ -269,7 +268,7 @@ public class TextInputDialog extends JDialog {
inputPanel.setMinimumSize(new Dimension(10, 10));
JScrollPane fieldScroller = new JScrollPane(fieldList);
- fieldScroller.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
+ fieldScroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
// insert buttons
insertButton.addActionListener(event -> insertTextForTag(override.isSelected()));
@@ -371,7 +370,7 @@ public class TextInputDialog extends JDialog {
sourcePreview.setEditable(false);
sourcePreview.setFont(new Font("Monospaced", Font.PLAIN, Globals.prefs.getInt(JabRefPreferences.FONT_SIZE)));
JScrollPane paneScrollPane = new JScrollPane(sourcePreview);
- paneScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
+ paneScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
paneScrollPane.setPreferredSize(new Dimension(500, 255));
paneScrollPane.setMinimumSize(new Dimension(10, 10));
@@ -423,16 +422,16 @@ public class TextInputDialog extends JDialog {
markedTextStore.appendPosition(fieldName, selectionStart, selectionEnd);
// get old text from BibTeX tag
- Optional<String> old = entry.getFieldOptional(fieldName);
+ Optional<String> old = entry.getField(fieldName);
// merge old and selected text
if (old.isPresent()) {
// insert a new name with an additional "and"
- if (InternalBibtexFields.getFieldExtras(fieldName).contains(FieldProperties.PERSON_NAMES)) {
+ if (InternalBibtexFields.getFieldProperties(fieldName).contains(FieldProperty.PERSON_NAMES)) {
entry.setField(fieldName, old.get() + " and " + txt);
} else if (FieldName.KEYWORDS.equals(fieldName)) {
// Add keyword
- entry.addKeyword(txt, Globals.prefs.get(JabRefPreferences.KEYWORD_SEPARATOR));
+ entry.addKeyword(txt, Globals.prefs.getKeywordDelimiter());
} else {
entry.setField(fieldName, old.get() + txt);
}
@@ -453,10 +452,11 @@ public class TextInputDialog extends JDialog {
/**
* tries to parse the pasted reference with freecite
+ *
* @return true if successful, false otherwise
*/
private boolean parseWithFreeCiteAndAddEntries() {
- FreeCiteImporter fimp = new FreeCiteImporter(ImportFormatPreferences.fromPreferences(Globals.prefs));
+ FreeCiteImporter fimp = new FreeCiteImporter(Globals.prefs.getImportFormatPreferences());
String text = textPane.getText();
// we have to remove line breaks (but keep empty lines)
@@ -493,7 +493,7 @@ public class TextInputDialog extends JDialog {
private void updateSourceView() {
StringWriter sw = new StringWriter(200);
try {
- new BibEntryWriter(new LatexFieldFormatter(LatexFieldFormatterPreferences.fromPreferences(Globals.prefs)),
+ new BibEntryWriter(new LatexFieldFormatter(Globals.prefs.getLatexFieldFormatterPreferences()),
false).write(entry, sw, frame.getCurrentBasePanel().getBibDatabaseContext().getMode());
sourcePreview.setText(sw.getBuffer().toString());
} catch (IOException ex) {
@@ -636,9 +636,9 @@ public class TextInputDialog extends JDialog {
*/
@Override
public Component getListCellRendererComponent(JList<?> list, Object value, // value to display
- int index, // cell index
- boolean iss, // is the cell selected
- boolean chf) // the list and the cell have the focus
+ int index, // cell index
+ boolean iss, // is the cell selected
+ boolean chf) // the list and the cell have the focus
{
/* The DefaultListCellRenderer class will take care of
* the JLabels text property, it's foreground and background
diff --git a/src/main/java/net/sf/jabref/gui/preftabs/AdvancedTab.java b/src/main/java/net/sf/jabref/gui/preftabs/AdvancedTab.java
index ff003d0..8a9b569 100644
--- a/src/main/java/net/sf/jabref/gui/preftabs/AdvancedTab.java
+++ b/src/main/java/net/sf/jabref/gui/preftabs/AdvancedTab.java
@@ -14,7 +14,6 @@ import net.sf.jabref.Globals;
import net.sf.jabref.gui.help.HelpAction;
import net.sf.jabref.gui.remote.JabRefMessageHandler;
import net.sf.jabref.logic.help.HelpFile;
-import net.sf.jabref.logic.journals.JournalAbbreviationPreferences;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.remote.RemotePreferences;
import net.sf.jabref.logic.remote.RemoteUtil;
@@ -37,7 +36,7 @@ class AdvancedTab extends JPanel implements PrefsTab {
public AdvancedTab(JabRefPreferences prefs) {
preferences = prefs;
- remotePreferences = new RemotePreferences(preferences);
+ remotePreferences = prefs.getRemotePreferences();
useRemoteServer = new JCheckBox(Localization.lang("Listen for remote operation on port") + ':');
useIEEEAbrv = new JCheckBox(Localization.lang("Use IEEE LaTeX abbreviations"));
@@ -105,7 +104,7 @@ class AdvancedTab extends JPanel implements PrefsTab {
public void storeSettings() {
if (preferences.getBoolean(JabRefPreferences.USE_IEEE_ABRV) != useIEEEAbrv.isSelected()) {
preferences.putBoolean(JabRefPreferences.USE_IEEE_ABRV, useIEEEAbrv.isSelected());
- Globals.journalAbbreviationLoader.update(JournalAbbreviationPreferences.fromPreferences(preferences));
+ Globals.journalAbbreviationLoader.update(Globals.prefs.getJournalAbbreviationPreferences());
}
storeRemoteSettings();
@@ -133,6 +132,7 @@ class AdvancedTab extends JPanel implements PrefsTab {
} else {
Globals.REMOTE_LISTENER.stop();
}
+ preferences.setRemotePreferences(remotePreferences);
}
private Optional<Integer> getPortAsInt() {
diff --git a/src/main/java/net/sf/jabref/gui/preftabs/AppearancePrefsTab.java b/src/main/java/net/sf/jabref/gui/preftabs/AppearancePrefsTab.java
index 135c077..a86c691 100644
--- a/src/main/java/net/sf/jabref/gui/preftabs/AppearancePrefsTab.java
+++ b/src/main/java/net/sf/jabref/gui/preftabs/AppearancePrefsTab.java
@@ -63,8 +63,9 @@ class AppearancePrefsTab extends JPanel implements PrefsTab {
// Try to find L&F
Class.forName(l);
lookAndFeels.add(l);
- } catch (ClassNotFoundException ignored) {
- // Ignored
+ } catch (ClassNotFoundException|IllegalAccessError ignored) {
+ // LookAndFeel class does not exist or we don't have rights to access it
+ // Ignore it
}
}
return lookAndFeels;
@@ -182,7 +183,7 @@ class AppearancePrefsTab extends JPanel implements PrefsTab {
overrideFonts.addActionListener(e -> fontSize.setEnabled(overrideFonts.isSelected()));
fontButton.addActionListener(
- e -> new FontSelectorDialog(null, GUIGlobals.currentFont).getSelectedFont().ifPresent(x -> usedFont = x));
+ e -> new FontSelectorDialog(null, usedFont).getSelectedFont().ifPresent(x -> usedFont = x));
JPanel pan = builder.getPanel();
pan.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
diff --git a/src/main/java/net/sf/jabref/gui/preftabs/EntryEditorPrefsTab.java b/src/main/java/net/sf/jabref/gui/preftabs/EntryEditorPrefsTab.java
index b2f0bf7..f511833 100644
--- a/src/main/java/net/sf/jabref/gui/preftabs/EntryEditorPrefsTab.java
+++ b/src/main/java/net/sf/jabref/gui/preftabs/EntryEditorPrefsTab.java
@@ -13,8 +13,6 @@ import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerNumberModel;
-import net.sf.jabref.gui.BasePanel;
-import net.sf.jabref.gui.JabRefFrame;
import net.sf.jabref.gui.keyboard.EmacsKeyBindings;
import net.sf.jabref.logic.autocompleter.AutoCompleteFirstNameMode;
import net.sf.jabref.logic.autocompleter.AutoCompletePreferences;
@@ -39,21 +37,16 @@ class EntryEditorPrefsTab extends JPanel implements PrefsTab {
private final JRadioButton firstNameModeFull;
private final JRadioButton firstNameModeAbbr;
private final JRadioButton firstNameModeBoth;
- private boolean oldAutoCompFF;
- private boolean oldAutoCompLF;
- private boolean oldAutoCompFModeAbbr;
- private boolean oldAutoCompFModeFull;
private final JSpinner shortestToComplete;
private final JTextField autoCompFields;
private final JabRefPreferences prefs;
private final AutoCompletePreferences autoCompletePreferences;
- private final JabRefFrame frame;
- public EntryEditorPrefsTab(JabRefFrame frame, JabRefPreferences prefs) {
+
+ public EntryEditorPrefsTab(JabRefPreferences prefs) {
this.prefs = prefs;
autoCompletePreferences = new AutoCompletePreferences(prefs);
- this.frame = frame;
setLayout(new BorderLayout());
autoOpenForm = new JCheckBox(Localization.lang("Open editor when a new entry is created"));
@@ -175,8 +168,6 @@ class EntryEditorPrefsTab extends JPanel implements PrefsTab {
} else {
autoCompBoth.setSelected(true);
}
- oldAutoCompFF = autoCompFF.isSelected();
- oldAutoCompLF = autoCompLF.isSelected();
switch (autoCompletePreferences.getFirstnameMode()) {
case ONLY_ABBREVIATED:
@@ -189,9 +180,6 @@ class EntryEditorPrefsTab extends JPanel implements PrefsTab {
firstNameModeBoth.setSelected(true);
break;
}
- // one field less than the option is enough. If one filed changes, another one also changes.
- oldAutoCompFModeAbbr = firstNameModeAbbr.isSelected();
- oldAutoCompFModeFull = firstNameModeFull.isSelected();
// similar for emacs CTRL-a and emacs mode
emacsRebindCtrlA.setEnabled(emacsMode.isSelected());
@@ -225,9 +213,6 @@ class EntryEditorPrefsTab extends JPanel implements PrefsTab {
EmacsKeyBindings.load();
}
}
- // We want to know if the following settings have been modified:
- boolean oldAutoComplete = prefs.getBoolean(JabRefPreferences.AUTO_COMPLETE);
- String oldAutoCompFields = autoCompletePreferences.getCompleteNamesAsString();
autoCompletePreferences.setShortestLengthToComplete((Integer) shortestToComplete.getValue());
prefs.putBoolean(JabRefPreferences.AUTO_COMPLETE, autoComplete.isSelected());
autoCompletePreferences.setCompleteNames(autoCompFields.getText());
@@ -250,18 +235,6 @@ class EntryEditorPrefsTab extends JPanel implements PrefsTab {
} else {
autoCompletePreferences.setFirstnameMode(AutoCompleteFirstNameMode.BOTH);
}
-
- // We need to remove all entry editors from cache if the source panel setting
- // or the autocompletion settings have been changed:
- if ((oldAutoComplete != autoComplete.isSelected())
- || !oldAutoCompFields.equals(autoCompFields.getText()) ||
- (oldAutoCompFF != autoCompFF.isSelected()) || (oldAutoCompLF != autoCompLF.isSelected()) ||
- (oldAutoCompFModeAbbr != firstNameModeAbbr.isSelected()) ||
- (oldAutoCompFModeFull != firstNameModeFull.isSelected())) {
- for (BasePanel panel : frame.getBasePanelList()) {
- panel.getEntryEditors().clear();
- }
- }
}
@Override
diff --git a/src/main/java/net/sf/jabref/gui/preftabs/ExternalTab.java b/src/main/java/net/sf/jabref/gui/preftabs/ExternalTab.java
index 3ed33ee..6002e19 100644
--- a/src/main/java/net/sf/jabref/gui/preftabs/ExternalTab.java
+++ b/src/main/java/net/sf/jabref/gui/preftabs/ExternalTab.java
@@ -17,8 +17,8 @@ import javax.swing.JRadioButton;
import javax.swing.JTextField;
import net.sf.jabref.Globals;
-import net.sf.jabref.external.ExternalFileTypeEditor;
import net.sf.jabref.gui.JabRefFrame;
+import net.sf.jabref.gui.externalfiletype.ExternalFileTypeEditor;
import net.sf.jabref.gui.push.PushToApplication;
import net.sf.jabref.gui.push.PushToApplicationButton;
import net.sf.jabref.logic.l10n.Localization;
diff --git a/src/main/java/net/sf/jabref/gui/preftabs/FileSortTab.java b/src/main/java/net/sf/jabref/gui/preftabs/FileSortTab.java
index 2bb75cb..326d273 100644
--- a/src/main/java/net/sf/jabref/gui/preftabs/FileSortTab.java
+++ b/src/main/java/net/sf/jabref/gui/preftabs/FileSortTab.java
@@ -10,7 +10,6 @@ import javax.swing.JPanel;
import javax.swing.JRadioButton;
import net.sf.jabref.gui.SaveOrderConfigDisplay;
-import net.sf.jabref.logic.config.SaveOrderConfig;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.preferences.JabRefPreferences;
@@ -91,7 +90,7 @@ class FileSortTab extends JPanel implements PrefsTab {
boolean selected = prefs.getBoolean(JabRefPreferences.EXPORT_IN_SPECIFIED_ORDER);
exportOrderPanel.setEnabled(selected);
- exportOrderPanel.setSaveOrderConfig(SaveOrderConfig.loadExportSaveOrderFromPreferences(prefs));
+ exportOrderPanel.setSaveOrderConfig(prefs.loadExportSaveOrder());
}
@Override
@@ -99,7 +98,7 @@ class FileSortTab extends JPanel implements PrefsTab {
prefs.putBoolean(JabRefPreferences.EXPORT_IN_ORIGINAL_ORDER, exportInOriginalOrder.isSelected());
prefs.putBoolean(JabRefPreferences.EXPORT_IN_SPECIFIED_ORDER, exportInSpecifiedOrder.isSelected());
- exportOrderPanel.getSaveOrderConfig().storeAsExportSaveOrderInPreferences(prefs);
+ prefs.storeExportSaveOrder(exportOrderPanel.getSaveOrderConfig());
}
@Override
diff --git a/src/main/java/net/sf/jabref/gui/preftabs/FileTab.java b/src/main/java/net/sf/jabref/gui/preftabs/FileTab.java
index 09aaf5f..280fd16 100644
--- a/src/main/java/net/sf/jabref/gui/preftabs/FileTab.java
+++ b/src/main/java/net/sf/jabref/gui/preftabs/FileTab.java
@@ -3,6 +3,9 @@ package net.sf.jabref.gui.preftabs;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ItemListener;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
@@ -10,21 +13,19 @@ import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
+import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
-import javax.swing.JSpinner;
import javax.swing.JTextField;
-import javax.swing.SpinnerNumberModel;
-import net.sf.jabref.Globals;
import net.sf.jabref.gui.FileDialog;
import net.sf.jabref.gui.JabRefFrame;
import net.sf.jabref.gui.help.HelpAction;
import net.sf.jabref.logic.help.HelpFile;
import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.logic.layout.format.FileLinkPreferences;
import net.sf.jabref.logic.util.OS;
import net.sf.jabref.model.entry.FieldName;
+import net.sf.jabref.model.metadata.FileDirectoryPreferences;
import net.sf.jabref.preferences.JabRefPreferences;
import com.jgoodies.forms.builder.DefaultFormBuilder;
@@ -40,17 +41,14 @@ class FileTab extends JPanel implements PrefsTab {
private final JabRefFrame frame;
private final JCheckBox backup;
+ private final JCheckBox localAutoSave;
private final JCheckBox openLast;
- private final JCheckBox autoSave;
- private final JCheckBox promptBeforeUsingAutoSave;
private final JComboBox<String> newlineSeparator;
private final JCheckBox reformatFileOnSaveAndExport;
private final JRadioButton resolveStringsStandard;
private final JRadioButton resolveStringsAll;
private final JTextField nonWrappableFields;
private final JTextField doNotResolveStringsFor;
- private final JSpinner autoSaveInterval;
- private boolean origAutoSaveSetting;
private final JTextField fileDir;
private final JCheckBox bibLocAsPrimaryDir;
@@ -83,9 +81,7 @@ class FileTab extends JPanel implements PrefsTab {
openLast = new JCheckBox(Localization.lang("Open last edited databases at startup"));
backup = new JCheckBox(Localization.lang("Backup old file when saving"));
- autoSave = new JCheckBox(Localization.lang("Autosave"));
- promptBeforeUsingAutoSave = new JCheckBox(Localization.lang("Prompt before recovering a database from an autosave file"));
- autoSaveInterval = new JSpinner(new SpinnerNumberModel(1, 1, 60, 1));
+ localAutoSave = new JCheckBox(Localization.lang("Autosave local databases"));
resolveStringsAll = new JRadioButton(Localization.lang("Resolve strings for all fields except") + ":");
resolveStringsStandard = new JRadioButton(Localization.lang("Resolve strings for standard BibTeX fields only"));
ButtonGroup bg = new ButtonGroup();
@@ -100,11 +96,6 @@ class FileTab extends JPanel implements PrefsTab {
nonWrappableFields = new JTextField(25);
doNotResolveStringsFor = new JTextField(30);
- autoSave.addChangeListener(e -> {
- autoSaveInterval.setEnabled(autoSave.isSelected());
- promptBeforeUsingAutoSave.setEnabled(autoSave.isSelected());
- });
-
FormLayout layout = new FormLayout("left:pref, 4dlu, fill:150dlu, 4dlu, fill:pref", ""); // left:pref, 4dlu, fill:pref
DefaultFormBuilder builder = new DefaultFormBuilder(layout);
@@ -166,7 +157,7 @@ class FileTab extends JPanel implements PrefsTab {
builder.nextLine();
builder.appendSeparator(Localization.lang("Autosave"));
- builder.append(autoSave, 1);
+ builder.append(localAutoSave, 1);
JButton help = new HelpAction(HelpFile.AUTOSAVE).getHelpButton();
help.setPreferredSize(new Dimension(24, 24));
JPanel hPan = new JPanel();
@@ -174,11 +165,6 @@ class FileTab extends JPanel implements PrefsTab {
hPan.add(help, BorderLayout.EAST);
builder.append(hPan);
builder.nextLine();
- builder.append(Localization.lang("Autosave interval (minutes)") + ":");
- builder.append(autoSaveInterval);
- builder.nextLine();
- builder.append(promptBeforeUsingAutoSave);
- builder.nextLine();
JPanel pan = builder.getPanel();
pan.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
@@ -189,7 +175,7 @@ class FileTab extends JPanel implements PrefsTab {
@Override
public void setValues() {
- fileDir.setText(prefs.get(FieldName.FILE + FileLinkPreferences.DIR_SUFFIX));
+ fileDir.setText(prefs.get(FieldName.FILE + FileDirectoryPreferences.DIR_SUFFIX));
bibLocAsPrimaryDir.setSelected(prefs.getBoolean(JabRefPreferences.BIB_LOC_AS_PRIMARY_DIR));
runAutoFileSearch.setSelected(prefs.getBoolean(JabRefPreferences.RUN_AUTOMATIC_FILE_SEARCH));
allowFileAutoOpenBrowse.setSelected(prefs.getBoolean(JabRefPreferences.ALLOW_FILE_AUTO_OPEN_BROWSE));
@@ -221,15 +207,12 @@ class FileTab extends JPanel implements PrefsTab {
doNotResolveStringsFor.setText(prefs.get(JabRefPreferences.DO_NOT_RESOLVE_STRINGS_FOR));
nonWrappableFields.setText(prefs.get(JabRefPreferences.NON_WRAPPABLE_FIELDS));
- autoSave.setSelected(prefs.getBoolean(JabRefPreferences.AUTO_SAVE));
- promptBeforeUsingAutoSave.setSelected(prefs.getBoolean(JabRefPreferences.PROMPT_BEFORE_USING_AUTOSAVE));
- autoSaveInterval.setValue(prefs.getInt(JabRefPreferences.AUTO_SAVE_INTERVAL));
- origAutoSaveSetting = autoSave.isSelected();
+ localAutoSave.setSelected(prefs.getBoolean(JabRefPreferences.LOCAL_AUTO_SAVE));
}
@Override
public void storeSettings() {
- prefs.put(FieldName.FILE + FileLinkPreferences.DIR_SUFFIX, fileDir.getText());
+ prefs.put(FieldName.FILE + FileDirectoryPreferences.DIR_SUFFIX, fileDir.getText());
prefs.putBoolean(JabRefPreferences.BIB_LOC_AS_PRIMARY_DIR, bibLocAsPrimaryDir.isSelected());
prefs.putBoolean(JabRefPreferences.RUN_AUTOMATIC_FILE_SEARCH, runAutoFileSearch.isSelected());
prefs.putBoolean(JabRefPreferences.ALLOW_FILE_AUTO_OPEN_BROWSE, allowFileAutoOpenBrowse.isSelected());
@@ -256,34 +239,28 @@ class FileTab extends JPanel implements PrefsTab {
OS.NEWLINE = newline;
prefs.putBoolean(JabRefPreferences.REFORMAT_FILE_ON_SAVE_AND_EXPORT, reformatFileOnSaveAndExport.isSelected());
- prefs.putBoolean(JabRefPreferences.BACKUP, backup.isSelected());
prefs.putBoolean(JabRefPreferences.OPEN_LAST_EDITED, openLast.isSelected());
prefs.putBoolean(JabRefPreferences.RESOLVE_STRINGS_ALL_FIELDS, resolveStringsAll.isSelected());
prefs.put(JabRefPreferences.DO_NOT_RESOLVE_STRINGS_FOR, doNotResolveStringsFor.getText().trim());
- prefs.putBoolean(JabRefPreferences.AUTO_SAVE, autoSave.isSelected());
- prefs.putBoolean(JabRefPreferences.PROMPT_BEFORE_USING_AUTOSAVE, promptBeforeUsingAutoSave.isSelected());
- prefs.putInt(JabRefPreferences.AUTO_SAVE_INTERVAL, (Integer) autoSaveInterval.getValue());
doNotResolveStringsFor.setText(prefs.get(JabRefPreferences.DO_NOT_RESOLVE_STRINGS_FOR));
- boolean updateSpecialFields = false;
if (!nonWrappableFields.getText().trim().equals(prefs.get(JabRefPreferences.NON_WRAPPABLE_FIELDS))) {
prefs.put(JabRefPreferences.NON_WRAPPABLE_FIELDS, nonWrappableFields.getText());
- updateSpecialFields = true;
- }
-
- // See if we should start or stop the auto save manager:
- if (!origAutoSaveSetting && autoSave.isSelected()) {
- Globals.startAutoSaveManager(frame);
- }
- else if (origAutoSaveSetting && !autoSave.isSelected()) {
- Globals.stopAutoSaveManager();
}
+ prefs.putBoolean(JabRefPreferences.LOCAL_AUTO_SAVE, localAutoSave.isSelected());
}
@Override
public boolean validateSettings() {
- return true;
+ Path path = Paths.get(fileDir.getText());
+ boolean valid = Files.exists(path) && Files.isDirectory(path);
+ if (!valid) {
+ String content = String.format("%s -> %s %n %n %s: %n %s", Localization.lang("File"),
+ Localization.lang("Main file directory"), Localization.lang("Directory not found"), path);
+ JOptionPane.showMessageDialog(this.frame, content, Localization.lang("Error"), JOptionPane.ERROR_MESSAGE);
+ }
+ return valid;
}
@Override
diff --git a/src/main/java/net/sf/jabref/gui/preftabs/ImportSettingsTab.java b/src/main/java/net/sf/jabref/gui/preftabs/ImportSettingsTab.java
index e5a91f0..ddba7a9 100644
--- a/src/main/java/net/sf/jabref/gui/preftabs/ImportSettingsTab.java
+++ b/src/main/java/net/sf/jabref/gui/preftabs/ImportSettingsTab.java
@@ -25,14 +25,9 @@ public class ImportSettingsTab extends JPanel implements PrefsTab {
public static final int DEFAULT_STYLE = ImportDialog.CONTENT;
- private static final String[] DEFAULT_FILENAMEPATTERNS_DISPLAY = new String[] {
- "bibtexkey",
- "bibtexkey - title",
- };
- public static final String[] DEFAULT_FILENAMEPATTERNS = new String[] {
- "\\bibtexkey",
- "\\bibtexkey\\begin{title} - \\format[RemoveBrackets]{\\title}\\end{title}"
- };
+ private static final String[] DEFAULT_FILENAMEPATTERNS_DISPLAY = new String[] {"bibtexkey", "bibtexkey - title",};
+ public static final String[] DEFAULT_FILENAMEPATTERNS = new String[] {"\\bibtexkey",
+ "\\bibtexkey\\begin{title} - \\format[RemoveBrackets]{\\title}\\end{title}"};
private final JabRefPreferences prefs;
private final JRadioButton radioButtonXmp;
@@ -44,6 +39,8 @@ public class ImportSettingsTab extends JPanel implements PrefsTab {
private final JTextField fileNamePattern;
private final JButton selectFileNamePattern;
+ private final JTextField fileDirPattern;
+
public ImportSettingsTab(JabRefPreferences prefs) {
this.prefs = Objects.requireNonNull(prefs);
@@ -60,9 +57,11 @@ public class ImportSettingsTab extends JPanel implements PrefsTab {
bg.add(radioButtonPDFcontent);
bg.add(radioButtononlyAttachPDF);
- useDefaultPDFImportStyle = new JCheckBox(Localization.lang("Always use this PDF import style (and do not ask for each import)"));
+ useDefaultPDFImportStyle = new JCheckBox(
+ Localization.lang("Always use this PDF import style (and do not ask for each import)"));
fileNamePattern = new JTextField(50);
+ fileDirPattern = new JTextField(50);
selectFileNamePattern = new JButton(Localization.lang("Choose pattern"));
selectFileNamePattern.addActionListener(e -> openFilePatternMenu());
@@ -90,6 +89,7 @@ public class ImportSettingsTab extends JPanel implements PrefsTab {
builder.appendSeparator(Localization.lang("Default PDF file link action"));
builder.nextLine();
builder.append(pan);
+
JPanel pan2 = new JPanel();
JLabel lab = new JLabel(Localization.lang("Filename format pattern").concat(":"));
pan2.add(lab);
@@ -97,6 +97,15 @@ public class ImportSettingsTab extends JPanel implements PrefsTab {
pan2.add(selectFileNamePattern);
builder.append(pan2);
+ JPanel pan3 = new JPanel();
+ JLabel lbfileDirPattern = new JLabel(Localization.lang("File directory pattern").concat(":"));
+ pan3.add(lbfileDirPattern);
+ pan3.add(fileDirPattern);
+
+ builder.nextLine();
+ builder.append(pan);
+ builder.append(pan3);
+
pan = builder.getPanel();
pan.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
add(pan, BorderLayout.CENTER);
@@ -104,6 +113,7 @@ public class ImportSettingsTab extends JPanel implements PrefsTab {
@Override
public void setValues() {
+
useDefaultPDFImportStyle.setSelected(prefs.getBoolean(JabRefPreferences.IMPORT_ALWAYSUSE));
int style = prefs.getInt(JabRefPreferences.IMPORT_DEFAULT_PDF_IMPORT_STYLE);
switch (style) {
@@ -125,6 +135,9 @@ public class ImportSettingsTab extends JPanel implements PrefsTab {
break;
}
fileNamePattern.setText(prefs.get(JabRefPreferences.IMPORT_FILENAMEPATTERN));
+
+ String pattern = "";
+ fileDirPattern.setText(prefs.get(JabRefPreferences.IMPORT_FILEDIRPATTERN));
}
@Override
@@ -142,6 +155,7 @@ public class ImportSettingsTab extends JPanel implements PrefsTab {
}
prefs.putInt(JabRefPreferences.IMPORT_DEFAULT_PDF_IMPORT_STYLE, style);
prefs.put(JabRefPreferences.IMPORT_FILENAMEPATTERN, fileNamePattern.getText());
+ prefs.put(JabRefPreferences.IMPORT_FILEDIRPATTERN, fileDirPattern.getText());
}
@Override
diff --git a/src/main/java/net/sf/jabref/gui/preftabs/NameFormatterTab.java b/src/main/java/net/sf/jabref/gui/preftabs/NameFormatterTab.java
index 36e0bb9..41248ad 100644
--- a/src/main/java/net/sf/jabref/gui/preftabs/NameFormatterTab.java
+++ b/src/main/java/net/sf/jabref/gui/preftabs/NameFormatterTab.java
@@ -23,7 +23,6 @@ import javax.swing.table.TableModel;
import net.sf.jabref.gui.IconTheme;
import net.sf.jabref.gui.OSXCompatibleToolbar;
import net.sf.jabref.gui.help.HelpAction;
-import net.sf.jabref.gui.util.GUIUtil;
import net.sf.jabref.logic.help.HelpFile;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.layout.format.NameFormatter;
@@ -155,7 +154,6 @@ public class NameFormatterTab extends JPanel implements PrefsTab {
};
table = new JTable(tableModel);
- GUIUtil.correctRowHeight(table);
TableColumnModel columnModel = table.getColumnModel();
columnModel.getColumn(0).setPreferredWidth(140);
@@ -200,8 +198,8 @@ public class NameFormatterTab extends JPanel implements PrefsTab {
@Override
public void setValues() {
tableRows.clear();
- List<String> names = prefs.getStringList(NameFormatter.NAME_FORMATER_KEY);
- List<String> formats = prefs.getStringList(NameFormatter.NAME_FORMATTER_VALUE);
+ List<String> names = prefs.getStringList(JabRefPreferences.NAME_FORMATER_KEY);
+ List<String> formats = prefs.getStringList(JabRefPreferences.NAME_FORMATTER_VALUE);
for (int i = 0; i < names.size(); i++) {
if (i < formats.size()) {
@@ -317,8 +315,8 @@ public class NameFormatterTab extends JPanel implements PrefsTab {
}
// Finally, we store the new preferences.
- prefs.putStringList(NameFormatter.NAME_FORMATER_KEY, names);
- prefs.putStringList(NameFormatter.NAME_FORMATTER_VALUE, formats);
+ prefs.putStringList(JabRefPreferences.NAME_FORMATER_KEY, names);
+ prefs.putStringList(JabRefPreferences.NAME_FORMATTER_VALUE, formats);
}
}
diff --git a/src/main/java/net/sf/jabref/gui/preftabs/NetworkTab.java b/src/main/java/net/sf/jabref/gui/preftabs/NetworkTab.java
index d6bb7a3..6267a96 100644
--- a/src/main/java/net/sf/jabref/gui/preftabs/NetworkTab.java
+++ b/src/main/java/net/sf/jabref/gui/preftabs/NetworkTab.java
@@ -96,7 +96,7 @@ public class NetworkTab extends JPanel implements PrefsTab {
@Override
public void setValues() {
- ProxyPreferences proxyPreferences = ProxyPreferences.loadFromPreferences(preferences);
+ ProxyPreferences proxyPreferences = preferences.getProxyPreferences();
useProxyCheckBox.setSelected(proxyPreferences.isUseProxy());
hostnameTextField.setText(proxyPreferences.getHostname());
portTextField.setText(proxyPreferences.getPort());
@@ -121,7 +121,7 @@ public class NetworkTab extends JPanel implements PrefsTab {
if (!proxyPreferences.equals(oldProxyPreferences)) {
ProxyRegisterer.register(proxyPreferences);
}
- proxyPreferences.storeInPreferences(preferences);
+ preferences.storeProxyPreferences(proxyPreferences);
}
@Override
diff --git a/src/main/java/net/sf/jabref/gui/preftabs/PreferencesDialog.java b/src/main/java/net/sf/jabref/gui/preftabs/PreferencesDialog.java
index 340abaf..8572cda 100644
--- a/src/main/java/net/sf/jabref/gui/preftabs/PreferencesDialog.java
+++ b/src/main/java/net/sf/jabref/gui/preftabs/PreferencesDialog.java
@@ -36,11 +36,13 @@ import net.sf.jabref.logic.layout.LayoutFormatterPreferences;
import net.sf.jabref.logic.util.FileExtensions;
import net.sf.jabref.preferences.JabRefPreferences;
import net.sf.jabref.preferences.JabRefPreferencesFilter;
+import net.sf.jabref.shared.prefs.SharedDatabasePreferences;
import com.jgoodies.forms.builder.ButtonBarBuilder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
/**
* Preferences dialog. Contains a TabbedPane, and tabs will be defined in
* separate classes. Tabs MUST implement the PrefsTab interface, since this
@@ -84,14 +86,14 @@ public class PreferencesDialog extends JDialog {
tabs.add(new NetworkTab(prefs));
tabs.add(new FileTab(frame, prefs));
tabs.add(new FileSortTab(prefs));
- tabs.add(new EntryEditorPrefsTab(frame, prefs));
+ tabs.add(new EntryEditorPrefsTab(prefs));
tabs.add(new GroupsPrefsTab(prefs));
tabs.add(new AppearancePrefsTab(prefs));
tabs.add(new ExternalTab(frame, this, prefs));
tabs.add(new TablePrefsTab(prefs));
tabs.add(new TableColumnsTab(prefs, parent));
tabs.add(new BibtexKeyPatternPrefTab(prefs, parent.getCurrentBasePanel()));
- tabs.add(new PreviewPrefsTab(prefs));
+ tabs.add(new PreviewPrefsTab());
tabs.add(new NameFormatterTab(prefs));
tabs.add(new ImportSettingsTab(prefs));
tabs.add(new XmpPrefsTab(prefs));
@@ -152,25 +154,11 @@ public class PreferencesDialog extends JDialog {
// Import and export actions:
exportPreferences.setToolTipText(Localization.lang("Export preferences to file"));
- exportPreferences.addActionListener(e -> {
- FileDialog dialog = new FileDialog(frame, System.getProperty("user.home")).withExtension(FileExtensions.XML);
- dialog.setDefaultExtension(FileExtensions.XML);
- Optional<Path> path = dialog.saveNewFile();
-
- path.ifPresent(exportFile -> {
- try {
- prefs.exportPreferences(exportFile.toString());
- } catch (JabRefException ex) {
- LOGGER.warn(ex.getMessage(), ex);
- JOptionPane.showMessageDialog(PreferencesDialog.this, ex.getLocalizedMessage(),
- Localization.lang("Export preferences"), JOptionPane.ERROR_MESSAGE);
- }
- });
- });
+ exportPreferences.addActionListener(new ExportAction());
importPreferences.setToolTipText(Localization.lang("Import preferences from file"));
importPreferences.addActionListener(e -> {
- FileDialog dialog = new FileDialog(frame, System.getProperty("user.home")).withExtension(FileExtensions.XML);
+ FileDialog dialog = new FileDialog(frame, getPrefsExportPath()).withExtension(FileExtensions.XML);
dialog.setDefaultExtension(FileExtensions.XML);
Optional<Path> fileName = dialog.showDialogAndGetSelectedFile();
@@ -181,6 +169,7 @@ public class PreferencesDialog extends JDialog {
JOptionPane.showMessageDialog(PreferencesDialog.this,
Localization.lang("You must restart JabRef for this to come into effect."),
Localization.lang("Import preferences"), JOptionPane.WARNING_MESSAGE);
+ this.dispose();
} catch (JabRefException ex) {
LOGGER.warn(ex.getMessage(), ex);
JOptionPane.showMessageDialog(PreferencesDialog.this, ex.getLocalizedMessage(),
@@ -190,13 +179,14 @@ public class PreferencesDialog extends JDialog {
});
showPreferences.addActionListener(
- e -> new PreferencesFilterDialog(new JabRefPreferencesFilter(Globals.prefs), frame).setVisible(true));
+ e -> new PreferencesFilterDialog(new JabRefPreferencesFilter(prefs), frame).setVisible(true));
resetPreferences.addActionListener(e -> {
if (JOptionPane.showConfirmDialog(PreferencesDialog.this,
Localization.lang("Are you sure you want to reset all settings to default values?"),
Localization.lang("Reset preferences"), JOptionPane.OK_CANCEL_OPTION) == JOptionPane.OK_OPTION) {
try {
prefs.clear();
+ new SharedDatabasePreferences().clear();
JOptionPane.showMessageDialog(PreferencesDialog.this,
Localization.lang("You must restart JabRef for this to come into effect."),
Localization.lang("Reset preferences"), JOptionPane.WARNING_MESSAGE);
@@ -215,19 +205,44 @@ public class PreferencesDialog extends JDialog {
}
+ private String getPrefsExportPath() {
+ return Globals.prefs.get(JabRefPreferences.PREFS_EXPORT_PATH);
+ }
+
private void updateAfterPreferenceChanges() {
setValues();
Map<String, ExportFormat> customFormats = Globals.prefs.customExports.getCustomExportFormats(Globals.prefs,
Globals.journalAbbreviationLoader);
- LayoutFormatterPreferences layoutPreferences = LayoutFormatterPreferences.fromPreferences(Globals.prefs,
- Globals.journalAbbreviationLoader);
+ LayoutFormatterPreferences layoutPreferences = Globals.prefs
+ .getLayoutFormatterPreferences(Globals.journalAbbreviationLoader);
SavePreferences savePreferences = SavePreferences.loadForExportFromPreferences(Globals.prefs);
ExportFormats.initAllExports(customFormats, layoutPreferences, savePreferences);
- frame.removeCachedEntryEditors();
Globals.prefs.updateEntryEditorTabList();
}
+ private void storeAllSettings(){
+ // First check that all tabs are ready to close:
+ Component[] preferenceTabs = main.getComponents();
+ for (Component tab: preferenceTabs) {
+ if (!((PrefsTab) tab).validateSettings()) {
+ return; // If not, break off.
+ }
+ }
+ // Then store settings and close:
+ for (Component tab: preferenceTabs) {
+ ((PrefsTab) tab).storeSettings();
+ }
+ Globals.prefs.flush();
+
+ setVisible(false);
+ MainTable.updateRenderers();
+ GUIGlobals.updateEntryEditorColors();
+ frame.setupAllTables();
+ frame.getGroupSelector().revalidateGroups(); // icons may have changed
+ frame.output(Localization.lang("Preferences recorded."));
+ }
+
class OkAction extends AbstractAction {
@@ -237,27 +252,33 @@ public class PreferencesDialog extends JDialog {
@Override
public void actionPerformed(ActionEvent e) {
+ storeAllSettings();
+ }
+ }
- // First check that all tabs are ready to close:
- int count = main.getComponentCount();
- Component[] comps = main.getComponents();
- for (int i = 0; i < count; i++) {
- if (!((PrefsTab) comps[i]).validateSettings()) {
- return; // If not, break off.
- }
- }
- // Then store settings and close:
- for (int i = 0; i < count; i++) {
- ((PrefsTab) comps[i]).storeSettings();
- }
- Globals.prefs.flush();
+ class ExportAction extends AbstractAction {
- setVisible(false);
- MainTable.updateRenderers();
- GUIGlobals.updateEntryEditorColors();
- frame.setupAllTables();
- frame.getGroupSelector().revalidateGroups(); // icons may have changed
- frame.output(Localization.lang("Preferences recorded."));
+ public ExportAction() {
+ super("Export");
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ FileDialog dialog = new FileDialog(frame).withExtension(FileExtensions.XML);
+ dialog.setDefaultExtension(FileExtensions.XML);
+ Optional<Path> path = dialog.saveNewFile();
+
+ path.ifPresent(exportFile -> {
+ try {
+ storeAllSettings();
+ Globals.prefs.exportPreferences(exportFile.toString());
+ Globals.prefs.put(JabRefPreferences.PREFS_EXPORT_PATH, exportFile.toString());
+ } catch (JabRefException ex) {
+ LOGGER.warn(ex.getMessage(), ex);
+ JOptionPane.showMessageDialog(PreferencesDialog.this, ex.getLocalizedMessage(),
+ Localization.lang("Export preferences"), JOptionPane.WARNING_MESSAGE);
+ }
+ });
}
}
diff --git a/src/main/java/net/sf/jabref/gui/preftabs/PreferencesFilterDialog.java b/src/main/java/net/sf/jabref/gui/preftabs/PreferencesFilterDialog.java
index 4e2a83f..8a44cf7 100644
--- a/src/main/java/net/sf/jabref/gui/preftabs/PreferencesFilterDialog.java
+++ b/src/main/java/net/sf/jabref/gui/preftabs/PreferencesFilterDialog.java
@@ -2,6 +2,7 @@ package net.sf.jabref.gui.preftabs;
import java.awt.BorderLayout;
import java.awt.Dimension;
+import java.awt.FlowLayout;
import java.util.List;
import java.util.Objects;
@@ -15,7 +16,6 @@ import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import net.sf.jabref.gui.WrapLayout;
-import net.sf.jabref.gui.util.GUIUtil;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.preferences.JabRefPreferencesFilter;
@@ -39,7 +39,7 @@ class PreferencesFilterDialog extends JDialog {
panel.setLayout(new BorderLayout());
JPanel northPanel = new JPanel();
- northPanel.setLayout(new WrapLayout(WrapLayout.LEFT));
+ northPanel.setLayout(new WrapLayout(FlowLayout.LEFT));
showOnlyDeviatingPreferenceOptions = new JCheckBox(Localization.lang("Show only preferences deviating from their default value"), false);
showOnlyDeviatingPreferenceOptions.addChangeListener(x -> updateModel());
northPanel.add(showOnlyDeviatingPreferenceOptions);
@@ -49,7 +49,6 @@ class PreferencesFilterDialog extends JDialog {
table = new JTable();
table.setAutoCreateRowSorter(true);
- GUIUtil.correctRowHeight(table);
updateModel();
panel.add(new JScrollPane(table), BorderLayout.CENTER);
diff --git a/src/main/java/net/sf/jabref/gui/preftabs/PreviewPrefsTab.java b/src/main/java/net/sf/jabref/gui/preftabs/PreviewPrefsTab.java
index 4f2a8a1..3cbfc99 100644
--- a/src/main/java/net/sf/jabref/gui/preftabs/PreviewPrefsTab.java
+++ b/src/main/java/net/sf/jabref/gui/preftabs/PreviewPrefsTab.java
@@ -1,186 +1,218 @@
package net.sf.jabref.gui.preftabs;
+import java.awt.BorderLayout;
import java.awt.Dimension;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.Insets;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import javax.swing.BoxLayout;
+import javax.swing.DefaultListModel;
import javax.swing.JButton;
-import javax.swing.JLabel;
+import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
-import javax.swing.JSeparator;
import javax.swing.JTextArea;
-import javax.swing.SwingConstants;
+import javax.swing.ListSelectionModel;
+import javax.swing.SwingWorker;
+import net.sf.jabref.Globals;
+import net.sf.jabref.JabRefGUI;
+import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.gui.PreviewPanel;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.util.TestEntry;
-import net.sf.jabref.preferences.JabRefPreferences;
+import net.sf.jabref.preferences.PreviewPreferences;
+import com.jgoodies.forms.builder.FormBuilder;
+import com.jgoodies.forms.factories.Paddings;
+import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-class PreviewPrefsTab extends JPanel implements PrefsTab {
-
- private static final Log LOGGER = LogFactory.getLog(PrefsTab.class);
-
- private final JabRefPreferences prefs;
-
- private final JTextArea layout1 = new JTextArea("", 1, 1);
- private final JTextArea layout2 = new JTextArea("", 1, 1);
-
- private final JButton testButton = new JButton(Localization.lang("Test"));
- private final JButton defaultButton = new JButton(Localization.lang("Default"));
- private final JButton testButton2 = new JButton(Localization.lang("Test"));
- private final JButton defaultButton2 = new JButton(Localization.lang("Default"));
-
- private final JPanel firstPanel = new JPanel();
- private final JScrollPane firstScrollPane = new JScrollPane(layout1);
-
- private final JPanel secondPanel = new JPanel();
- private final JScrollPane secondScrollPane = new JScrollPane(layout2);
-
-
- public PreviewPrefsTab(JabRefPreferences prefs) {
- this.prefs = prefs;
-
- GridBagLayout layout = new GridBagLayout();
- firstPanel.setLayout(layout);
- secondPanel.setLayout(layout);
-
- setLayout(layout);
- JLabel lab = new JLabel(Localization.lang("Preview") + " 1");
- GridBagConstraints layoutConstraints = new GridBagConstraints();
- layoutConstraints.anchor = GridBagConstraints.WEST;
- layoutConstraints.gridwidth = GridBagConstraints.REMAINDER;
- layoutConstraints.fill = GridBagConstraints.BOTH;
- layoutConstraints.weightx = 1;
- layoutConstraints.weighty = 0;
- layoutConstraints.insets = new Insets(2, 2, 2, 2);
- layout.setConstraints(lab, layoutConstraints);
- layoutConstraints.weighty = 1;
- layout.setConstraints(firstScrollPane, layoutConstraints);
- firstPanel.add(firstScrollPane);
- layoutConstraints.weighty = 0;
- layoutConstraints.gridwidth = 1;
- layoutConstraints.weightx = 0;
- layoutConstraints.fill = GridBagConstraints.NONE;
- layoutConstraints.anchor = GridBagConstraints.WEST;
- layout.setConstraints(testButton, layoutConstraints);
- firstPanel.add(testButton);
- layout.setConstraints(defaultButton, layoutConstraints);
- firstPanel.add(defaultButton);
- layoutConstraints.gridwidth = GridBagConstraints.REMAINDER;
- JPanel newPan = new JPanel();
- layoutConstraints.weightx = 1;
- layout.setConstraints(newPan, layoutConstraints);
- firstPanel.add(newPan);
- lab = new JLabel(Localization.lang("Preview") + " 2");
- layout.setConstraints(lab, layoutConstraints);
- // p2.add(lab);
- layoutConstraints.weighty = 1;
- layoutConstraints.fill = GridBagConstraints.BOTH;
- layout.setConstraints(secondScrollPane, layoutConstraints);
- secondPanel.add(secondScrollPane);
- layoutConstraints.weighty = 0;
- layoutConstraints.weightx = 0;
- layoutConstraints.fill = GridBagConstraints.NONE;
- layoutConstraints.gridwidth = 1;
- layout.setConstraints(testButton2, layoutConstraints);
- secondPanel.add(testButton2);
- layout.setConstraints(defaultButton2, layoutConstraints);
- secondPanel.add(defaultButton2);
- layoutConstraints.gridwidth = 1;
- newPan = new JPanel();
- layoutConstraints.weightx = 1;
- layout.setConstraints(newPan, layoutConstraints);
- secondPanel.add(newPan);
-
- layoutConstraints.weightx = 1;
- layoutConstraints.weighty = 0;
- layoutConstraints.fill = GridBagConstraints.BOTH;
- layoutConstraints.gridwidth = GridBagConstraints.REMAINDER;
- lab = new JLabel(Localization.lang("Preview") + " 1");
- layout.setConstraints(lab, layoutConstraints);
- add(lab);
- layoutConstraints.weighty = 1;
- layout.setConstraints(firstPanel, layoutConstraints);
- add(firstPanel);
- lab = new JLabel(Localization.lang("Preview") + " 2");
- layoutConstraints.weighty = 0;
- JSeparator sep = new JSeparator(SwingConstants.HORIZONTAL);
- layout.setConstraints(sep, layoutConstraints);
- add(sep);
- layout.setConstraints(lab, layoutConstraints);
- add(lab);
- layoutConstraints.weighty = 1;
- layout.setConstraints(secondPanel, layoutConstraints);
- add(secondPanel);
- layoutConstraints.weighty = 0;
-
- defaultButton.addActionListener(e -> {
- String tmp = layout1.getText().replace("\n", "__NEWLINE__");
- PreviewPrefsTab.this.prefs.remove(JabRefPreferences.PREVIEW_0);
- layout1.setText(PreviewPrefsTab.this.prefs.get(JabRefPreferences.PREVIEW_0).replace("__NEWLINE__", "\n"));
- PreviewPrefsTab.this.prefs.put(JabRefPreferences.PREVIEW_0, tmp);
+
+public class PreviewPrefsTab extends JPanel implements PrefsTab {
+
+ private static final Log LOGGER = LogFactory.getLog(PreviewPrefsTab.class);
+
+ private final DefaultListModel<Object> availableModel = new DefaultListModel<>();
+ private final DefaultListModel<Object> chosenModel = new DefaultListModel<>();
+
+ private final JList<Object> available = new JList<>(availableModel);
+ private final JList<Object> chosen = new JList<>(chosenModel);
+
+ private final JButton btnRight = new JButton("»");
+ private final JButton btnLeft = new JButton("«");
+ private final JButton btnUp = new JButton(Localization.lang("Up"));
+ private final JButton btnDown = new JButton(Localization.lang("Down"));
+
+
+ private final JTextArea layout = new JTextArea("", 1, 1);
+ private final JButton btnTest = new JButton(Localization.lang("Test"));
+ private final JButton btnDefault = new JButton(Localization.lang("Default"));
+ private final JScrollPane scrollPane = new JScrollPane(layout);
+
+
+ public PreviewPrefsTab() {
+ setupLogic();
+ setupGui();
+ }
+
+ private void setupLogic(){
+ chosen.getSelectionModel().addListSelectionListener(event -> {
+ boolean selectionEmpty = ((ListSelectionModel) event.getSource()).isSelectionEmpty();
+ btnLeft.setEnabled(!selectionEmpty);
+ btnDown.setEnabled(!selectionEmpty);
+ btnUp.setEnabled(!selectionEmpty);
+ });
+
+ available.getSelectionModel()
+ .addListSelectionListener(e -> btnRight.setEnabled(!((ListSelectionModel) e.getSource()).isSelectionEmpty()));
+
+ btnRight.addActionListener(event -> {
+ for (Object object : available.getSelectedValuesList()) {
+ availableModel.removeElement(object);
+ chosenModel.addElement(object);
+ }
});
- defaultButton2.addActionListener(e -> {
- String tmp = layout2.getText().replace("\n", "__NEWLINE__");
- PreviewPrefsTab.this.prefs.remove(JabRefPreferences.PREVIEW_1);
- layout2.setText(PreviewPrefsTab.this.prefs.get(JabRefPreferences.PREVIEW_1).replace("__NEWLINE__", "\n"));
- PreviewPrefsTab.this.prefs.put(JabRefPreferences.PREVIEW_1, tmp);
+ btnLeft.addActionListener(event -> {
+ for (Object object : chosen.getSelectedValuesList()) {
+ availableModel.addElement(object);
+ chosenModel.removeElement(object);
+ }
});
- testButton.addActionListener(e -> {
- try {
- PreviewPanel testPanel = new PreviewPanel(null, TestEntry.getTestEntry(), null, layout1.getText());
- testPanel.setPreferredSize(new Dimension(800, 350));
- JOptionPane.showMessageDialog(null, testPanel, Localization.lang("Preview"), JOptionPane.PLAIN_MESSAGE);
- } catch (StringIndexOutOfBoundsException ex) {
- LOGGER.warn("Parsing error.", ex);
- JOptionPane.showMessageDialog(null,
- Localization.lang("Parsing error") + ": " + Localization.lang("illegal backslash expression")
- + ".\n" + ex.getMessage(),
- Localization.lang("Parsing error"), JOptionPane.ERROR_MESSAGE);
+ btnUp.addActionListener(event -> {
+ List<Integer> newSelectedIndices = new ArrayList<>();
+ for (int oldIndex : chosen.getSelectedIndices()) {
+ boolean alreadyTaken = newSelectedIndices.contains(oldIndex - 1);
+ int newIndex = (oldIndex > 0 && !alreadyTaken) ? oldIndex - 1 : oldIndex;
+ chosenModel.add(newIndex, chosenModel.remove(oldIndex));
+ newSelectedIndices.add(newIndex);
}
+ chosen.setSelectedIndices(ArrayUtils.toPrimitive(newSelectedIndices.toArray(new Integer[newSelectedIndices.size()])));
});
- testButton2.addActionListener(e -> {
+ btnDown.addActionListener(event -> {
+ List<Integer> newSelectedIndices = new ArrayList<>();
+ int[] selectedIndices = chosen.getSelectedIndices();
+ for (int i = selectedIndices.length - 1; i >= 0; i--) {
+ int oldIndex = selectedIndices[i];
+ boolean alreadyTaken = newSelectedIndices.contains(oldIndex + 1);
+ int newIndex = (oldIndex < chosenModel.getSize() - 1 && !alreadyTaken) ? oldIndex + 1 : oldIndex;
+ chosenModel.add(newIndex, chosenModel.remove(oldIndex));
+ newSelectedIndices.add(newIndex);
+ }
+ chosen.setSelectedIndices(ArrayUtils.toPrimitive(newSelectedIndices.toArray(new Integer[newSelectedIndices.size()])));
+ });
+
+
+ btnDefault.addActionListener(event -> layout.setText(Globals.prefs.getPreviewPreferences()
+ .getPreviewStyleDefault().replace("__NEWLINE__", "\n")));
+
+ btnTest.addActionListener(event -> {
try {
- PreviewPanel testPanel = new PreviewPanel(null, TestEntry.getTestEntry(), null,
- layout2.getText());
- testPanel.setPreferredSize(new Dimension(800, 350));
- JOptionPane.showMessageDialog(null, new JScrollPane(testPanel), Localization.lang("Preview"),
- JOptionPane.PLAIN_MESSAGE);
- } catch (StringIndexOutOfBoundsException ex) {
- LOGGER.warn("Parsing error.", ex);
+ PreviewPanel testPane = new PreviewPanel(null, TestEntry.getTestEntry(), null)
+ .setFixedLayout(layout.getText());
+ testPane.setPreferredSize(new Dimension(800, 350));
+ JOptionPane.showMessageDialog(PreviewPrefsTab.this, new JScrollPane(testPane), Localization.lang("Preview"), JOptionPane.PLAIN_MESSAGE);
+ } catch (StringIndexOutOfBoundsException exception) {
+ LOGGER.warn("Parsing error.", exception);
JOptionPane.showMessageDialog(null,
Localization.lang("Parsing error") + ": " + Localization.lang("illegal backslash expression")
- + ".\n" + ex.getMessage(),
+ + ".\n" + exception.getMessage(),
Localization.lang("Parsing error"), JOptionPane.ERROR_MESSAGE);
}
});
}
+ private void setupGui(){
+ JPanel chooseStyle = FormBuilder.create()
+ .columns("0:grow, $lcgap, pref, $lcgap, 0:grow")
+ .rows("pref, $lg, fill:pref:grow, $lg, pref:grow, $lg, pref:grow, $lg, pref:grow")
+ .padding(Paddings.DIALOG)
+
+ .addSeparator(Localization.lang("Current Preview")).xyw(1, 1, 5)
+ .add(available).xywh(1, 3, 1, 7)
+ .add(chosen).xywh(5, 3, 1, 7)
+
+ .add(btnRight).xy(3, 3, "fill, bottom")
+ .add(btnLeft).xy(3, 5, "fill, top")
+ .add(btnUp).xy(3, 7, "fill, bottom")
+ .add(btnDown).xy(3, 9, "fill, top")
+ .build();
+
+ JPanel preview = FormBuilder.create()
+ .columns("pref:grow, $lcgap, pref, $lcgap, pref")
+ .rows("pref, $lg, fill:pref:grow")
+ .padding(Paddings.DIALOG)
+
+ .addSeparator(Localization.lang("Preview")).xy(1, 1)
+ .add(btnTest).xy(3, 1)
+ .add(btnDefault).xy(5, 1)
+ .add(scrollPane).xyw(1, 3, 5)
+ .build();
+
+ setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
+ add(chooseStyle, BorderLayout.CENTER);
+ add(preview, BorderLayout.PAGE_END);
+ }
@Override
public void setValues() {
- layout1.setText(prefs.get(JabRefPreferences.PREVIEW_0).replace("__NEWLINE__", "\n"));
- layout2.setText(prefs.get(JabRefPreferences.PREVIEW_1).replace("__NEWLINE__", "\n"));
+ PreviewPreferences previewPreferences = Globals.prefs.getPreviewPreferences();
+
+ chosenModel.clear();
+ boolean isPreviewChosen = false;
+ for (String style : previewPreferences.getPreviewCycle()) {
+ if (isPreviewChosen) {
+ LOGGER.error("Preview is already in the list, something went wrong");
+ continue;
+ }
+ isPreviewChosen = true;
+ chosenModel.addElement(Localization.lang("Preview"));
+ }
+
+ availableModel.clear();
+ if (!isPreviewChosen){
+ availableModel.addElement(Localization.lang("Preview"));
+ }
+
+ btnLeft.setEnabled(!chosen.isSelectionEmpty());
+ btnRight.setEnabled(!available.isSelectionEmpty());
+ btnUp.setEnabled(!chosen.isSelectionEmpty());
+ btnDown.setEnabled(!chosen.isSelectionEmpty());
+
+ layout.setText(Globals.prefs.getPreviewPreferences().getPreviewStyle().replace("__NEWLINE__", "\n"));
}
@Override
public void storeSettings() {
- prefs.put(JabRefPreferences.PREVIEW_0, layout1.getText().replace("\n", "__NEWLINE__"));
- prefs.put(JabRefPreferences.PREVIEW_1, layout2.getText().replace("\n", "__NEWLINE__"));
+ List<String> styles = new ArrayList<>();
+ Enumeration<Object> elements = chosenModel.elements();
+ while (elements.hasMoreElements()) {
+ Object obj = elements.nextElement();
+ styles.add("Preview");
+ }
+ PreviewPreferences previewPreferences = Globals.prefs.getPreviewPreferences()
+ .getBuilder()
+ .withPreviewCycle(styles)
+ .withPreviewStyle(layout.getText().replace("\n", "__NEWLINE__"))
+ .build();
+ Globals.prefs.storePreviewPreferences(previewPreferences);
+
+ // update preview
+ for (BasePanel basePanel : JabRefGUI.getMainFrame().getBasePanelList()) {
+ basePanel.getPreviewPanel().updateLayout();
+ }
}
@Override
public boolean validateSettings() {
- return true;
+ return !chosenModel.isEmpty();
}
@Override
diff --git a/src/main/java/net/sf/jabref/gui/preftabs/TableColumnsTab.java b/src/main/java/net/sf/jabref/gui/preftabs/TableColumnsTab.java
index 3076d8e..3548580 100644
--- a/src/main/java/net/sf/jabref/gui/preftabs/TableColumnsTab.java
+++ b/src/main/java/net/sf/jabref/gui/preftabs/TableColumnsTab.java
@@ -30,14 +30,13 @@ import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;
-import net.sf.jabref.external.ExternalFileType;
-import net.sf.jabref.external.ExternalFileTypes;
import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.gui.IconTheme;
import net.sf.jabref.gui.JabRefFrame;
import net.sf.jabref.gui.OSXCompatibleToolbar;
+import net.sf.jabref.gui.externalfiletype.ExternalFileType;
+import net.sf.jabref.gui.externalfiletype.ExternalFileTypes;
import net.sf.jabref.gui.help.HelpAction;
-import net.sf.jabref.gui.util.GUIUtil;
import net.sf.jabref.logic.help.HelpFile;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.model.entry.BibtexSingleField;
@@ -233,7 +232,6 @@ class TableColumnsTab extends JPanel implements PrefsTab {
TableColumnModel cm = colSetup.getColumnModel();
cm.getColumn(0).setPreferredWidth(140);
cm.getColumn(1).setPreferredWidth(80);
- GUIUtil.correctRowHeight(colSetup);
FormLayout layout = new FormLayout
("1dlu, 8dlu, left:pref, 4dlu, fill:pref","");
diff --git a/src/main/java/net/sf/jabref/gui/preftabs/XmpPrefsTab.java b/src/main/java/net/sf/jabref/gui/preftabs/XmpPrefsTab.java
index d08e6fb..fe559df 100644
--- a/src/main/java/net/sf/jabref/gui/preftabs/XmpPrefsTab.java
+++ b/src/main/java/net/sf/jabref/gui/preftabs/XmpPrefsTab.java
@@ -24,7 +24,6 @@ import javax.swing.table.TableModel;
import net.sf.jabref.gui.IconTheme;
import net.sf.jabref.gui.OSXCompatibleToolbar;
-import net.sf.jabref.gui.util.GUIUtil;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.preferences.JabRefPreferences;
@@ -111,7 +110,6 @@ class XmpPrefsTab extends JPanel implements PrefsTab {
};
table = new JTable(tableModel);
- GUIUtil.correctRowHeight(table);
TableColumnModel columnModel = table.getColumnModel();
columnModel.getColumn(0).setPreferredWidth(140);
diff --git a/src/main/java/net/sf/jabref/gui/protectedterms/NewProtectedTermsFileDialog.java b/src/main/java/net/sf/jabref/gui/protectedterms/NewProtectedTermsFileDialog.java
index 49324d0..4d872a3 100644
--- a/src/main/java/net/sf/jabref/gui/protectedterms/NewProtectedTermsFileDialog.java
+++ b/src/main/java/net/sf/jabref/gui/protectedterms/NewProtectedTermsFileDialog.java
@@ -19,7 +19,6 @@ import net.sf.jabref.Globals;
import net.sf.jabref.gui.FileDialog;
import net.sf.jabref.gui.JabRefFrame;
import net.sf.jabref.gui.keyboard.KeyBinding;
-
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.protectedterms.ProtectedTermsLoader;
import net.sf.jabref.logic.util.FileExtensions;
diff --git a/src/main/java/net/sf/jabref/gui/protectedterms/ProtectedTermsDialog.java b/src/main/java/net/sf/jabref/gui/protectedterms/ProtectedTermsDialog.java
index b52b3d2..43bdc8f 100644
--- a/src/main/java/net/sf/jabref/gui/protectedterms/ProtectedTermsDialog.java
+++ b/src/main/java/net/sf/jabref/gui/protectedterms/ProtectedTermsDialog.java
@@ -34,30 +34,27 @@ import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumnModel;
-import net.sf.jabref.BibDatabaseContext;
import net.sf.jabref.Globals;
-import net.sf.jabref.external.ExternalFileType;
-import net.sf.jabref.external.ExternalFileTypes;
-import net.sf.jabref.external.UnknownExternalFileType;
import net.sf.jabref.gui.FileDialog;
import net.sf.jabref.gui.IconTheme;
import net.sf.jabref.gui.JabRefFrame;
import net.sf.jabref.gui.desktop.JabRefDesktop;
+import net.sf.jabref.gui.externalfiletype.ExternalFileType;
+import net.sf.jabref.gui.externalfiletype.ExternalFileTypes;
+import net.sf.jabref.gui.externalfiletype.UnknownExternalFileType;
import net.sf.jabref.gui.keyboard.KeyBinding;
-import net.sf.jabref.gui.util.GUIUtil;
-import net.sf.jabref.gui.util.PositionWindow;
+import net.sf.jabref.gui.util.WindowLocation;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.protectedterms.ProtectedTermsList;
import net.sf.jabref.logic.protectedterms.ProtectedTermsLoader;
-import net.sf.jabref.logic.protectedterms.ProtectedTermsPreferences;
import net.sf.jabref.logic.util.FileExtensions;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.preferences.JabRefPreferences;
import com.jgoodies.forms.builder.ButtonBarBuilder;
import com.jgoodies.forms.builder.FormBuilder;
import com.jgoodies.forms.layout.FormLayout;
-
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -152,7 +149,7 @@ public class ProtectedTermsDialog {
@Override
public void actionPerformed(ActionEvent event) {
// Restore from preferences
- loader.update(ProtectedTermsPreferences.fromPreferences(Globals.prefs));
+ loader.update(Globals.prefs.getProtectedTermsPreferences());
diag.dispose();
}
};
@@ -175,13 +172,12 @@ public class ProtectedTermsDialog {
diag.pack();
- PositionWindow pw = new PositionWindow(diag, JabRefPreferences.TERMS_POS_X, JabRefPreferences.TERMS_POS_Y,
+ WindowLocation pw = new WindowLocation(diag, JabRefPreferences.TERMS_POS_X, JabRefPreferences.TERMS_POS_Y,
JabRefPreferences.TERMS_SIZE_X, JabRefPreferences.TERMS_SIZE_Y);
- pw.setWindowPosition();
+ pw.displayWindowAtStoredLocation();
}
private void setupTable() {
-
tableModel = new TermTableModel();
table = new JTable(tableModel);
TableColumnModel cm = table.getColumnModel();
@@ -189,7 +185,6 @@ public class ProtectedTermsDialog {
cm.getColumn(0).setMaxWidth((cm.getColumn(0).getPreferredWidth() * 11) / 10);
cm.getColumn(1).setPreferredWidth(100);
cm.getColumn(2).setPreferredWidth(100);
- GUIUtil.correctRowHeight(table);
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
table.addMouseListener(new MouseAdapter() {
@@ -496,6 +491,6 @@ public class ProtectedTermsDialog {
private void storePreferences() {
- ProtectedTermsPreferences.toPreferences(Globals.prefs, loader);
+ Globals.prefs.setProtectedTermsPreferences(loader);
}
}
diff --git a/src/main/java/net/sf/jabref/gui/push/AbstractPushToApplication.java b/src/main/java/net/sf/jabref/gui/push/AbstractPushToApplication.java
index 762612c..5673603 100644
--- a/src/main/java/net/sf/jabref/gui/push/AbstractPushToApplication.java
+++ b/src/main/java/net/sf/jabref/gui/push/AbstractPushToApplication.java
@@ -8,12 +8,12 @@ import javax.swing.JPanel;
import javax.swing.JTextField;
import net.sf.jabref.Globals;
-import net.sf.jabref.MetaData;
import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.gui.FileDialog;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.model.database.BibDatabase;
import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.metadata.MetaData;
import net.sf.jabref.preferences.JabRefPreferences;
import com.jgoodies.forms.builder.FormBuilder;
diff --git a/src/main/java/net/sf/jabref/gui/push/PushToApplication.java b/src/main/java/net/sf/jabref/gui/push/PushToApplication.java
index 713b4aa..524304a 100644
--- a/src/main/java/net/sf/jabref/gui/push/PushToApplication.java
+++ b/src/main/java/net/sf/jabref/gui/push/PushToApplication.java
@@ -5,10 +5,10 @@ import java.util.List;
import javax.swing.Icon;
import javax.swing.JPanel;
-import net.sf.jabref.MetaData;
import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.model.database.BibDatabase;
import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.metadata.MetaData;
/**
* Class that defines interaction with an external application in the form of "pushing" selected entries to it.
diff --git a/src/main/java/net/sf/jabref/gui/push/PushToEmacs.java b/src/main/java/net/sf/jabref/gui/push/PushToEmacs.java
index 93aaac7..21767dc 100644
--- a/src/main/java/net/sf/jabref/gui/push/PushToEmacs.java
+++ b/src/main/java/net/sf/jabref/gui/push/PushToEmacs.java
@@ -5,20 +5,19 @@ import java.io.InputStream;
import java.util.List;
import javax.swing.Icon;
-import javax.swing.JCheckBox;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import net.sf.jabref.Globals;
import net.sf.jabref.JabRefExecutorService;
-import net.sf.jabref.MetaData;
import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.gui.IconTheme;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.util.OS;
import net.sf.jabref.model.database.BibDatabase;
import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.metadata.MetaData;
import net.sf.jabref.preferences.JabRefPreferences;
import org.apache.commons.logging.Log;
@@ -32,7 +31,6 @@ public class PushToEmacs extends AbstractPushToApplication implements PushToAppl
private static final Log LOGGER = LogFactory.getLog(PushToEmacs.class);
private final JTextField additionalParams = new JTextField(30);
- private final JCheckBox useEmacs23 = new JCheckBox();
@Override
@@ -48,7 +46,6 @@ public class PushToEmacs extends AbstractPushToApplication implements PushToAppl
@Override
public JPanel getSettingsPanel() {
additionalParams.setText(Globals.prefs.get(JabRefPreferences.EMACS_ADDITIONAL_PARAMETERS));
- useEmacs23.setSelected(Globals.prefs.getBoolean(JabRefPreferences.EMACS_23));
return super.getSettingsPanel();
}
@@ -56,7 +53,6 @@ public class PushToEmacs extends AbstractPushToApplication implements PushToAppl
public void storeSettings() {
super.storeSettings();
Globals.prefs.put(JabRefPreferences.EMACS_ADDITIONAL_PARAMETERS, additionalParams.getText());
- Globals.prefs.putBoolean(JabRefPreferences.EMACS_23, useEmacs23.isSelected());
}
@Override
@@ -65,8 +61,6 @@ public class PushToEmacs extends AbstractPushToApplication implements PushToAppl
builder.appendRows("2dlu, p, 2dlu, p");
builder.add(Localization.lang("Additional parameters") + ":").xy(1, 3);
builder.add(additionalParams).xy(3, 3);
- builder.add(Localization.lang("Use EMACS 23 insertion string") + ":").xy(1, 5);
- builder.add(useEmacs23).xy(3, 5);
settings = builder.build();
}
@@ -93,21 +87,16 @@ public class PushToEmacs extends AbstractPushToApplication implements PushToAppl
System.arraycopy(addParams, 0, com, 1, addParams.length);
String prefix;
String suffix;
- if (Globals.prefs.getBoolean(JabRefPreferences.EMACS_23)) {
- prefix = "(with-current-buffer (window-buffer) (insert ";
- suffix = "))";
- } else {
- prefix = "(insert ";
- suffix = ")";
- }
+ prefix = "(with-current-buffer (window-buffer) (insert ";
+ suffix = "))";
com[com.length - 1] = OS.WINDOWS ?
- // Windows gnuclient escaping:
+ // Windows gnuclient/emacsclient escaping:
// java string: "(insert \\\"\\\\cite{Blah2001}\\\")";
// so cmd receives: (insert \"\\cite{Blah2001}\")
// so emacs receives: (insert "\cite{Blah2001}")
prefix.concat("\\\"\\" + getCiteCommand().replaceAll("\\\\", "\\\\\\\\") + "{" + keys + "}\\\"").concat(suffix) :
- // Linux gnuclient escaping:
+ // Linux gnuclient/emacslient escaping:
// java string: "(insert \"\\\\cite{Blah2001}\")"
// so sh receives: (insert "\\cite{Blah2001}")
// so emacs receives: (insert "\cite{Blah2001}")
diff --git a/src/main/java/net/sf/jabref/gui/push/PushToLyx.java b/src/main/java/net/sf/jabref/gui/push/PushToLyx.java
index f5500c2..d6ed3df 100644
--- a/src/main/java/net/sf/jabref/gui/push/PushToLyx.java
+++ b/src/main/java/net/sf/jabref/gui/push/PushToLyx.java
@@ -12,12 +12,12 @@ import javax.swing.JPanel;
import net.sf.jabref.Globals;
import net.sf.jabref.JabRefExecutorService;
-import net.sf.jabref.MetaData;
import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.gui.IconTheme;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.model.database.BibDatabase;
import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.metadata.MetaData;
import net.sf.jabref.preferences.JabRefPreferences;
import org.apache.commons.logging.Log;
diff --git a/src/main/java/net/sf/jabref/gui/push/PushToVim.java b/src/main/java/net/sf/jabref/gui/push/PushToVim.java
index a5ef744..2bc6381 100644
--- a/src/main/java/net/sf/jabref/gui/push/PushToVim.java
+++ b/src/main/java/net/sf/jabref/gui/push/PushToVim.java
@@ -11,12 +11,12 @@ import javax.swing.JTextField;
import net.sf.jabref.Globals;
import net.sf.jabref.JabRefExecutorService;
-import net.sf.jabref.MetaData;
import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.gui.IconTheme;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.model.database.BibDatabase;
import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.metadata.MetaData;
import net.sf.jabref.preferences.JabRefPreferences;
import org.apache.commons.logging.Log;
diff --git a/src/main/java/net/sf/jabref/gui/search/GlobalSearchBar.java b/src/main/java/net/sf/jabref/gui/search/GlobalSearchBar.java
new file mode 100644
index 0000000..3661c9a
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/search/GlobalSearchBar.java
@@ -0,0 +1,425 @@
+package net.sf.jabref.gui.search;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.Font;
+import java.awt.event.ActionEvent;
+import java.io.File;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+import javax.swing.AbstractAction;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JToggleButton;
+import javax.swing.JToolBar;
+import javax.swing.SwingUtilities;
+
+import net.sf.jabref.Globals;
+import net.sf.jabref.gui.BasePanel;
+import net.sf.jabref.gui.GUIGlobals;
+import net.sf.jabref.gui.IconTheme;
+import net.sf.jabref.gui.JabRefFrame;
+import net.sf.jabref.gui.OSXCompatibleToolbar;
+import net.sf.jabref.gui.autocompleter.AutoCompleteSupport;
+import net.sf.jabref.gui.help.HelpAction;
+import net.sf.jabref.gui.keyboard.KeyBinding;
+import net.sf.jabref.gui.maintable.MainTable;
+import net.sf.jabref.gui.maintable.MainTableDataModel;
+import net.sf.jabref.gui.util.component.JTextFieldWithPlaceholder;
+import net.sf.jabref.logic.autocompleter.AutoCompleter;
+import net.sf.jabref.logic.help.HelpFile;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.logic.search.SearchQuery;
+import net.sf.jabref.logic.search.SearchQueryHighlightObservable;
+import net.sf.jabref.logic.util.OS;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.preferences.SearchPreferences;
+
+public class GlobalSearchBar extends JPanel {
+
+ private static final Color NEUTRAL_COLOR = Color.WHITE;
+ private static final Color NO_RESULTS_COLOR = new Color(232, 202, 202);
+ private static final Color RESULTS_FOUND_COLOR = new Color(217, 232, 202);
+ private static final Color ADVANCED_SEARCH_COLOR = new Color(102, 255, 255);
+
+ private final JabRefFrame frame;
+
+ private final JLabel searchIcon = new JLabel(IconTheme.JabRefIcon.SEARCH.getSmallIcon());
+ private final JTextFieldWithPlaceholder searchField = new JTextFieldWithPlaceholder(Localization.lang("Search") + "...");
+ private JButton openCurrentResultsInDialog = new JButton(IconTheme.JabRefIcon.OPEN_IN_NEW_WINDOW.getSmallIcon());
+
+ private final JToggleButton caseSensitive;
+ private final JToggleButton regularExp;
+ private final JButton searchModeButton = new JButton();
+ private final JLabel currentResults = new JLabel("");
+
+ private AutoCompleteSupport<String> autoCompleteSupport = new AutoCompleteSupport<>(searchField);
+ private final SearchQueryHighlightObservable searchQueryHighlightObservable = new SearchQueryHighlightObservable();
+
+ private SearchWorker searchWorker;
+ private GlobalSearchWorker globalSearchWorker;
+
+ private SearchResultFrame searchResultFrame;
+
+ private SearchDisplayMode searchDisplayMode;
+
+ /**
+ * if this flag is set the searchbar won't be selected after the next search
+ */
+ private boolean dontSelectSearchBar;
+
+
+ public GlobalSearchBar(JabRefFrame frame) {
+ super();
+ this.frame = Objects.requireNonNull(frame);
+ SearchPreferences searchPreferences = new SearchPreferences(Globals.prefs);
+ searchDisplayMode = searchPreferences.getSearchMode();
+
+ // fits the standard "found x entries"-message thus hinders the searchbar to jump around while searching if the frame width is too small
+ currentResults.setPreferredSize(new Dimension(150, 5));
+ currentResults.setFont(currentResults.getFont().deriveFont(Font.BOLD));
+ searchField.setColumns(30);
+
+ JToggleButton globalSearch = new JToggleButton(IconTheme.JabRefIcon.GLOBAL_SEARCH.getSmallIcon(), searchPreferences.isGlobalSearch());
+ globalSearch.setToolTipText(Localization.lang("Search in all open databases"));
+
+ // default action to be performed for toggling globalSearch
+ AbstractAction globalSearchStandardAction = new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ searchPreferences.setGlobalSearch(globalSearch.isSelected());
+ updateOpenCurrentResultsTooltip(globalSearch.isSelected());
+ }
+ };
+
+ // additional action for global search shortcut
+ AbstractAction globalSearchShortCutAction = new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ globalSearch.setSelected(true);
+ globalSearchStandardAction.actionPerformed(new ActionEvent(this, 0, "fire standard action"));
+ focus();
+ }
+ };
+
+ String searchGlobalByKey = "searchGlobalByKey";
+ globalSearch.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(Globals.getKeyPrefs().getKey(KeyBinding.GLOBAL_SEARCH), searchGlobalByKey);
+ globalSearch.getActionMap().put(searchGlobalByKey, globalSearchShortCutAction);
+
+ globalSearch.addActionListener(globalSearchStandardAction);
+
+ openCurrentResultsInDialog.setDisabledIcon(IconTheme.JabRefIcon.OPEN_IN_NEW_WINDOW.getSmallIcon().createDisabledIcon());
+ openCurrentResultsInDialog.addActionListener(event -> {
+ if (globalSearch.isSelected()) {
+ performGlobalSearch();
+ } else {
+ openLocalFindingsInExternalPanel();
+ }
+ });
+ openCurrentResultsInDialog.setEnabled(false);
+ updateOpenCurrentResultsTooltip(globalSearch.isSelected());
+
+ regularExp = new JToggleButton(IconTheme.JabRefIcon.REG_EX.getSmallIcon(),
+ searchPreferences.isRegularExpression());
+ regularExp.setToolTipText(Localization.lang("regular expression"));
+ regularExp.addActionListener(event -> {
+ searchPreferences.setRegularExpression(regularExp.isSelected());
+ performSearch();
+ });
+
+ caseSensitive = new JToggleButton(IconTheme.JabRefIcon.CASE_SENSITIVE.getSmallIcon(),
+ searchPreferences.isCaseSensitive());
+ caseSensitive.setToolTipText(Localization.lang("Case sensitive"));
+ caseSensitive.addActionListener(event -> {
+ searchPreferences.setCaseSensitive(caseSensitive.isSelected());
+ performSearch();
+ });
+
+ updateSearchModeButtonText();
+ searchModeButton.addActionListener(event -> toggleSearchModeAndSearch());
+
+ JButton clearSearchButton = new JButton(IconTheme.JabRefIcon.CLOSE.getSmallIcon());
+ clearSearchButton.setToolTipText(Localization.lang("Clear"));
+ clearSearchButton.addActionListener(event -> endSearch());
+
+ searchField.addFocusListener(Globals.getFocusListener());
+ searchField.addActionListener(event -> performSearch());
+ JTextFieldChangeListenerUtil.addChangeListener(searchField, e -> performSearch());
+
+ String endSearch = "endSearch";
+ searchField.getInputMap().put(Globals.getKeyPrefs().getKey(KeyBinding.CLEAR_SEARCH), endSearch);
+ searchField.getActionMap().put(endSearch, new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ if (autoCompleteSupport.isVisible()) {
+ autoCompleteSupport.setVisible(false);
+ } else {
+ endSearch();
+ }
+ }
+ });
+
+ autoCompleteSupport.install();
+
+ String acceptSearch = "acceptSearch";
+ searchField.getInputMap().put(Globals.getKeyPrefs().getKey(KeyBinding.ACCEPT), acceptSearch);
+ searchField.getActionMap().put(acceptSearch, new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ autoCompleteSupport.setVisible(false);
+ BasePanel currentBasePanel = frame.getCurrentBasePanel();
+ Globals.getFocusListener().setFocused(currentBasePanel.getMainTable());
+ currentBasePanel.getMainTable().requestFocus();
+ }
+ });
+
+ setLayout(new FlowLayout(FlowLayout.RIGHT));
+ JToolBar toolBar = new OSXCompatibleToolbar();
+ toolBar.setFloatable(false);
+ if (OS.OS_X) {
+ searchField.putClientProperty("JTextField.variant", "search");
+ toolBar.add(searchField);
+ } else {
+ toolBar.add(searchIcon);
+ toolBar.add(searchField);
+ toolBar.add(clearSearchButton);
+ }
+ toolBar.addSeparator();
+ toolBar.add(openCurrentResultsInDialog);
+ toolBar.addSeparator();
+ toolBar.add(globalSearch);
+ toolBar.add(regularExp);
+ toolBar.add(caseSensitive);
+ toolBar.add(searchModeButton);
+ toolBar.addSeparator();
+ toolBar.add(new HelpAction(HelpFile.SEARCH));
+ toolBar.addSeparator();
+ toolBar.add(currentResults);
+ this.add(toolBar);
+ }
+
+ public void performGlobalSearch() {
+ BasePanel currentBasePanel = frame.getCurrentBasePanel();
+ if (currentBasePanel == null || validateSearchResultFrame(true)) {
+ return;
+ }
+
+ if (globalSearchWorker != null) {
+ globalSearchWorker.cancel(true);
+ }
+
+ if (searchField.getText().isEmpty()) {
+ focus();
+ return;
+ }
+
+ globalSearchWorker = new GlobalSearchWorker(currentBasePanel.frame(), getSearchQuery());
+ globalSearchWorker.execute();
+ }
+
+ private void openLocalFindingsInExternalPanel() {
+ BasePanel currentBasePanel = frame.getCurrentBasePanel();
+ if (currentBasePanel == null || validateSearchResultFrame(false)) {
+ return;
+ }
+
+ if (searchField.getText().isEmpty()) {
+ focus();
+ return;
+ }
+
+ SearchResultFrame searchDialog = new SearchResultFrame(currentBasePanel.frame(),
+ Localization.lang("Search results in database %0 for %1", currentBasePanel.getBibDatabaseContext()
+ .getDatabaseFile().map(File::getName).orElse(GUIGlobals.UNTITLED_TITLE),
+ this.getSearchQuery().localize()),
+ getSearchQuery(), false);
+ List<BibEntry> entries = currentBasePanel.getDatabase().getEntries().stream()
+ .filter(BibEntry::isSearchHit)
+ .collect(Collectors.toList());
+ searchDialog.addEntries(entries, currentBasePanel);
+ searchDialog.selectFirstEntry();
+ searchDialog.setVisible(true);
+ }
+
+ private boolean validateSearchResultFrame(boolean globalSearch) {
+ if (searchResultFrame != null) {
+ if (searchResultFrame.isGlobalSearch() == globalSearch && isStillValidQuery(searchResultFrame.getSearchQuery())) {
+ searchResultFrame.focus();
+ return true;
+ } else {
+ searchResultFrame.dispose();
+ return false;
+ }
+ }
+
+ return false;
+ }
+
+ private void toggleSearchModeAndSearch() {
+ int nextSearchMode = (searchDisplayMode.ordinal() + 1) % SearchDisplayMode.values().length;
+ searchDisplayMode = SearchDisplayMode.values()[nextSearchMode];
+ new SearchPreferences(Globals.prefs).setSearchMode(searchDisplayMode);
+ updateSearchModeButtonText();
+ performSearch();
+ }
+
+ private void updateSearchModeButtonText() {
+ searchModeButton.setText(searchDisplayMode.getDisplayName());
+ searchModeButton.setToolTipText(searchDisplayMode.getToolTipText());
+ }
+
+ public void endSearch() {
+ BasePanel currentBasePanel = frame.getCurrentBasePanel();
+ if (currentBasePanel != null) {
+ clearSearch(currentBasePanel);
+ MainTable mainTable = frame.getCurrentBasePanel().getMainTable();
+ Globals.getFocusListener().setFocused(mainTable);
+ mainTable.requestFocus();
+ SwingUtilities.invokeLater(() -> mainTable.ensureVisible(mainTable.getSelectedRow()));
+ }
+ }
+
+ /**
+ * Focuses the search field if it is not focused.
+ */
+ public void focus() {
+ if (!searchField.hasFocus()) {
+ searchField.requestFocus();
+ searchField.selectAll();
+ }
+ }
+
+ private void clearSearch(BasePanel currentBasePanel) {
+ currentResults.setText("");
+ searchField.setText("");
+ searchField.setBackground(NEUTRAL_COLOR);
+ searchIcon.setIcon(IconTheme.JabRefIcon.SEARCH.getSmallIcon());
+ searchQueryHighlightObservable.reset();
+ openCurrentResultsInDialog.setEnabled(false);
+
+ if (currentBasePanel != null) {
+ currentBasePanel.getMainTable().getTableModel().updateSearchState(MainTableDataModel.DisplayOption.DISABLED);
+ }
+
+ if (dontSelectSearchBar){
+ dontSelectSearchBar = false;
+ return;
+ }
+ focus();
+ }
+
+ public void performSearch() {
+ BasePanel currentBasePanel = frame.getCurrentBasePanel();
+ if (currentBasePanel == null) {
+ return;
+ }
+
+ if (searchWorker != null) {
+ searchWorker.cancel(true);
+ }
+
+ // An empty search field should cause the search to be cleared.
+ if (searchField.getText().isEmpty()) {
+ clearSearch(currentBasePanel);
+ return;
+ }
+
+ SearchQuery searchQuery = getSearchQuery();
+ if (!searchQuery.isValid()) {
+ informUserAboutInvalidSearchQuery();
+ return;
+ }
+
+ searchWorker = new SearchWorker(currentBasePanel, searchQuery, searchDisplayMode);
+ searchWorker.execute();
+ }
+
+ private void informUserAboutInvalidSearchQuery() {
+ searchField.setBackground(NO_RESULTS_COLOR);
+
+ searchQueryHighlightObservable.reset();
+
+ BasePanel currentBasePanel = frame.getCurrentBasePanel();
+ currentBasePanel.getMainTable().getTableModel().updateSearchState(MainTableDataModel.DisplayOption.DISABLED);
+
+ searchIcon.setIcon(IconTheme.JabRefIcon.SEARCH.getSmallIcon().createWithNewColor(NO_RESULTS_COLOR));
+ String illegalSearch = Localization.lang("Search failed: illegal search expression");
+ searchIcon.setToolTipText(illegalSearch);
+ currentResults.setText(illegalSearch);
+ openCurrentResultsInDialog.setEnabled(false);
+ }
+
+ public void setAutoCompleter(AutoCompleter<String> searchCompleter) {
+ this.autoCompleteSupport.setAutoCompleter(searchCompleter);
+ }
+
+ public SearchQueryHighlightObservable getSearchQueryHighlightObservable() {
+ return searchQueryHighlightObservable;
+ }
+
+ public boolean isStillValidQuery(SearchQuery query) {
+ return query.getQuery().equals(this.searchField.getText())
+ && (query.isRegularExpression() == regularExp.isSelected())
+ && (query.isCaseSensitive() == caseSensitive.isSelected());
+ }
+
+ private SearchQuery getSearchQuery() {
+ SearchQuery searchQuery = new SearchQuery(this.searchField.getText(), this.caseSensitive.isSelected(), this.regularExp.isSelected());
+ this.frame.getCurrentBasePanel().setCurrentSearchQuery(searchQuery);
+ return searchQuery;
+ }
+
+ public void updateResults(int matched, String description, boolean grammarBasedSearch) {
+ if (matched == 0) {
+ currentResults.setText(Localization.lang("No results found."));
+ this.searchField.setBackground(NO_RESULTS_COLOR);
+ } else {
+ currentResults.setText(Localization.lang("Found %0 results.", String.valueOf(matched)));
+ this.searchField.setBackground(RESULTS_FOUND_COLOR);
+ }
+ this.searchField.setToolTipText("<html>" + description + "</html>");
+
+ if (grammarBasedSearch) {
+ searchIcon.setIcon(IconTheme.JabRefIcon.SEARCH.getSmallIcon().createWithNewColor(ADVANCED_SEARCH_COLOR));
+ searchIcon.setToolTipText(Localization.lang("Advanced search active."));
+ } else {
+ searchIcon.setIcon(IconTheme.JabRefIcon.SEARCH.getSmallIcon());
+ searchIcon.setToolTipText(Localization.lang("Normal search active."));
+ }
+
+ openCurrentResultsInDialog.setEnabled(true);
+ }
+
+ public void setSearchResultFrame(SearchResultFrame searchResultFrame) {
+ this.searchResultFrame = searchResultFrame;
+ }
+
+ public void setSearchTerm(String searchTerm, boolean dontSelectSearchBar) {
+ if (searchTerm.equals(searchField.getText())){
+ return;
+ }
+
+ setDontSelectSearchBar(dontSelectSearchBar);
+ searchField.setText(searchTerm);
+ // to hinder the autocomplete window to popup
+ autoCompleteSupport.setVisible(false);
+ }
+
+ public void setDontSelectSearchBar(boolean dontSelectSearchBar) {
+ this.dontSelectSearchBar = dontSelectSearchBar;
+ }
+
+ private void updateOpenCurrentResultsTooltip(boolean globalSearchEnabled) {
+ if (globalSearchEnabled) {
+ openCurrentResultsInDialog.setToolTipText(Localization.lang("Show global search results in a window"));
+ } else {
+ openCurrentResultsInDialog.setToolTipText(Localization.lang("Show search results in a window"));
+ }
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/gui/search/GlobalSearchWorker.java b/src/main/java/net/sf/jabref/gui/search/GlobalSearchWorker.java
index 31d3aae..78bed8a 100644
--- a/src/main/java/net/sf/jabref/gui/search/GlobalSearchWorker.java
+++ b/src/main/java/net/sf/jabref/gui/search/GlobalSearchWorker.java
@@ -1,51 +1,69 @@
package net.sf.jabref.gui.search;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
+import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
+import javax.swing.SwingWorker;
+
import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.gui.JabRefFrame;
-import net.sf.jabref.gui.worker.AbstractWorker;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.search.SearchQuery;
import net.sf.jabref.model.entry.BibEntry;
-class GlobalSearchWorker extends AbstractWorker {
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+
+class GlobalSearchWorker extends SwingWorker<Map<BasePanel, List<BibEntry>>, Void> {
+
+ private static final Log LOGGER = LogFactory.getLog(GlobalSearchWorker.class);
private final JabRefFrame frame;
private final SearchQuery searchQuery;
- private final SearchResultsDialog dialog;
+ private final SearchResultFrame dialog;
public GlobalSearchWorker(JabRefFrame frame, SearchQuery query) {
this.frame = Objects.requireNonNull(frame);
this.searchQuery = Objects.requireNonNull(query);
- dialog = new SearchResultsDialog(frame,
+ dialog = new SearchResultFrame(frame,
Localization.lang("Search results in all databases for %0",
- this.searchQuery.localize()));
+ this.searchQuery.localize()),
+ searchQuery, true);
+ frame.getGlobalSearchBar().setSearchResultFrame(dialog);
}
- /* (non-Javadoc)
- * @see net.sf.jabref.Worker#run()
- */
@Override
- public void run() {
- // Search all databases
- for (int i = 0; i < frame.getTabbedPane().getTabCount(); i++) {
- BasePanel basePanel = frame.getBasePanelAt(i);
- List<BibEntry> matches = basePanel.getDatabase().getEntries().stream().filter(searchQuery::isMatch).collect(Collectors.toList());
- dialog.addEntries(matches, basePanel);
+ protected Map<BasePanel, List<BibEntry>> doInBackground() throws Exception {
+ Map<BasePanel, List<BibEntry>> matches = new HashMap<>();
+ for (BasePanel basePanel : frame.getBasePanelList()) {
+ matches.put(basePanel, basePanel.getDatabase().getEntries().parallelStream()
+ .filter(searchQuery::isMatch)
+ .collect(Collectors.toList()));
}
+ return matches;
}
- /* (non-Javadoc)
- * @see net.sf.jabref.AbstractWorker#update()
- */
@Override
- public void update() {
- dialog.selectFirstEntry();
- dialog.setVisible(true);
+ protected void done() {
+ if (isCancelled()) {
+ return;
+ }
+
+ try {
+ for (Map.Entry<BasePanel, List<BibEntry>> match : get().entrySet()) {
+ dialog.addEntries(match.getValue(), match.getKey());
+ }
+ dialog.selectFirstEntry();
+ dialog.setVisible(true);
+ } catch (InterruptedException | ExecutionException e) {
+ LOGGER.error("something went wrong during the search", e);
+ }
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/net/sf/jabref/gui/search/JTextFieldChangeListenerUtil.java b/src/main/java/net/sf/jabref/gui/search/JTextFieldChangeListenerUtil.java
index 2ebffb8..0bb4030 100644
--- a/src/main/java/net/sf/jabref/gui/search/JTextFieldChangeListenerUtil.java
+++ b/src/main/java/net/sf/jabref/gui/search/JTextFieldChangeListenerUtil.java
@@ -1,6 +1,7 @@
package net.sf.jabref.gui.search;
import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
import java.util.Objects;
import javax.swing.JTextArea;
diff --git a/src/main/java/net/sf/jabref/gui/search/SearchBar.java b/src/main/java/net/sf/jabref/gui/search/SearchBar.java
deleted file mode 100644
index 5ac6ac9..0000000
--- a/src/main/java/net/sf/jabref/gui/search/SearchBar.java
+++ /dev/null
@@ -1,367 +0,0 @@
-package net.sf.jabref.gui.search;
-
-import java.awt.Color;
-import java.awt.Component;
-import java.awt.Container;
-import java.awt.FlowLayout;
-import java.awt.Font;
-import java.awt.event.KeyAdapter;
-import java.awt.event.KeyEvent;
-import java.util.List;
-import java.util.Objects;
-import java.util.stream.Collectors;
-
-import javax.swing.JButton;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.JToggleButton;
-import javax.swing.JToolBar;
-
-import net.sf.jabref.Globals;
-import net.sf.jabref.gui.BasePanel;
-import net.sf.jabref.gui.IconTheme;
-import net.sf.jabref.gui.OSXCompatibleToolbar;
-import net.sf.jabref.gui.WrapLayout;
-import net.sf.jabref.gui.autocompleter.AutoCompleteSupport;
-import net.sf.jabref.gui.help.HelpAction;
-import net.sf.jabref.gui.maintable.MainTableDataModel;
-import net.sf.jabref.gui.util.component.JTextFieldWithUnfocusedText;
-import net.sf.jabref.gui.worker.AbstractWorker;
-import net.sf.jabref.logic.autocompleter.AutoCompleter;
-import net.sf.jabref.logic.help.HelpFile;
-import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.logic.search.SearchQuery;
-import net.sf.jabref.logic.search.SearchQueryHighlightObservable;
-import net.sf.jabref.logic.util.OS;
-import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.preferences.JabRefPreferences;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * The search bar at the top of the screen allowing the user to search his database.
- */
-public class SearchBar extends JPanel {
-
- private static final Log LOGGER = LogFactory.getLog(SearchBar.class);
-
- private static final Color NO_RESULTS_COLOR = new Color(232, 202, 202);
- private static final Color RESULTS_FOUND_COLOR = new Color(217, 232, 202);
- private static final Color ADVANCED_SEARCH_COLOR = new Color(102, 255, 255);
-
- private final JButton openCurrentResultsInDialog;
- private final JButton globalSearch;
- private final JButton searchModeButton;
-
- private final BasePanel basePanel;
-
- private final SearchQueryHighlightObservable searchQueryHighlightObservable;
- private final JTextFieldWithUnfocusedText searchField = new JTextFieldWithUnfocusedText(
- Localization.lang("Search") + "...");
-
- private SearchMode searchMode = getSearchModeFromSettings();
-
- private final JToggleButton caseSensitive;
- private final JToggleButton regularExp;
-
- private final JLabel currentResults = new JLabel("");
-
- private AutoCompleteSupport<String> autoCompleteSupport;
- private final JLabel searchIcon;
- private SearchWorker searchWorker;
-
-
- /**
- * Initializes the search bar.
- *
- * @param basePanel the base panel
- */
- public SearchBar(BasePanel basePanel) {
- super();
-
- this.basePanel = Objects.requireNonNull(basePanel);
- this.searchQueryHighlightObservable = new SearchQueryHighlightObservable();
-
- currentResults.setFont(currentResults.getFont().deriveFont(Font.BOLD));
-
- caseSensitive = new JToggleButton(IconTheme.JabRefIcon.CASE_SENSITIVE.getSmallIcon(),
- Globals.prefs.getBoolean(JabRefPreferences.SEARCH_CASE_SENSITIVE));
- caseSensitive.setToolTipText(Localization.lang("Case sensitive"));
- caseSensitive.addActionListener(e -> {
- performSearch();
- updatePreferences();
- });
-
- regularExp = new JToggleButton(IconTheme.JabRefIcon.REG_EX.getSmallIcon(),
- Globals.prefs.getBoolean(JabRefPreferences.SEARCH_REG_EXP));
- regularExp.setToolTipText(Localization.lang("regular expression"));
- regularExp.addActionListener(e -> {
- performSearch();
- updatePreferences();
- });
-
- openCurrentResultsInDialog = new JButton(IconTheme.JabRefIcon.OPEN_IN_NEW_WINDOW.getSmallIcon());
- openCurrentResultsInDialog.setToolTipText(Localization.lang("Show search results in a window"));
- openCurrentResultsInDialog.addActionListener(ae -> {
- SearchResultsDialog searchDialog = new SearchResultsDialog(basePanel.frame(),
- Localization.lang("Search results in database %0 for %1",
- basePanel.getBibDatabaseContext().getDatabaseFile().getName(),
- this.getSearchQuery().localize()));
- List<BibEntry> entries = basePanel.getDatabase().getEntries().stream().filter(BibEntry::isSearchHit)
- .collect(Collectors.toList());
- searchDialog.addEntries(entries, basePanel);
- searchDialog.selectFirstEntry();
- searchDialog.setVisible(true);
- });
- openCurrentResultsInDialog.setEnabled(false);
-
- // Init controls
- setLayout(new WrapLayout(FlowLayout.LEFT));
-
- searchIcon = new JLabel(IconTheme.JabRefIcon.SEARCH.getSmallIcon());
- this.add(searchIcon);
- initSearchField();
- if (OS.OS_X) {
- searchField.putClientProperty("JTextField.variant", "search");
- }
- this.add(searchField);
-
- JButton clearSearchButton = new JButton(IconTheme.JabRefIcon.CLOSE.getSmallIcon());
- clearSearchButton.setToolTipText(Localization.lang("Clear"));
- clearSearchButton.addActionListener(l -> endSearch());
-
- this.add(clearSearchButton);
-
- searchModeButton = new JButton();
- updateSearchModeButtonText();
- searchModeButton.addActionListener(l -> toggleSearchModeAndSearch());
-
- JToolBar toolBar = new OSXCompatibleToolbar();
- toolBar.setFloatable(false);
- toolBar.add(clearSearchButton);
- toolBar.addSeparator();
- toolBar.add(regularExp);
- toolBar.add(caseSensitive);
- toolBar.addSeparator();
- toolBar.add(searchModeButton);
- toolBar.addSeparator();
- toolBar.add(openCurrentResultsInDialog);
- globalSearch = new JButton(Localization.lang("Search globally"));
- globalSearch.setToolTipText(Localization.lang("Search in all open databases"));
- globalSearch.addActionListener(l -> {
- AbstractWorker worker = new GlobalSearchWorker(basePanel.frame(), getSearchQuery());
- worker.run();
- worker.update();
- });
- globalSearch.setEnabled(false);
- toolBar.add(globalSearch);
- toolBar.addSeparator();
- toolBar.add(new HelpAction(HelpFile.SEARCH));
-
- this.add(toolBar);
- this.add(currentResults);
-
- paintBackgroundWhite(this);
- }
-
- private void paintBackgroundWhite(Container container) {
- container.setBackground(Color.WHITE);
- for (Component component : container.getComponents()) {
- component.setBackground(Color.WHITE);
-
- if (component instanceof Container) {
- paintBackgroundWhite((Container) component);
- }
- }
- }
-
- private static SearchMode getSearchModeFromSettings() {
- if (Globals.prefs.getBoolean(JabRefPreferences.SEARCH_MODE_FILTER)) {
- return SearchMode.FILTER;
- } else if (Globals.prefs.getBoolean(JabRefPreferences.SEARCH_MODE_FLOAT)) {
- return SearchMode.FLOAT;
- } else {
- return SearchMode.FILTER;
- }
- }
-
- private void toggleSearchModeAndSearch() {
- this.searchMode = searchMode == SearchMode.FILTER ? SearchMode.FLOAT : SearchMode.FILTER;
- updatePreferences();
- updateSearchModeButtonText();
- performSearch();
- }
-
- private void updateSearchModeButtonText() {
- searchModeButton.setText(searchMode.getDisplayName());
- searchModeButton.setToolTipText(searchMode.getToolTipText());
- }
-
- /**
- * Initializes the search text field
- */
- private void initSearchField() {
- searchField.setColumns(30);
- searchField.addKeyListener(new KeyAdapter() {
-
- @Override
- public void keyReleased(KeyEvent e) {
- if (e.getExtendedKeyCode() == KeyEvent.VK_ESCAPE) {
- endSearch();
- }
- }
- });
-
- // Add autocompleter
- autoCompleteSupport = new AutoCompleteSupport<>(searchField);
- autoCompleteSupport.install();
-
- // Add the global focus listener, so a menu item can see if this field was focused when an action was called.
- searchField.addFocusListener(Globals.getFocusListener());
-
- // Search if user press enter
- searchField.addActionListener(e -> performSearch());
-
- // Subscribe to changes to the text in the search field in order to "live search"
- JTextFieldChangeListenerUtil.addChangeListener(searchField, e -> performSearch());
-
- }
-
- private void endSearch() {
- // first focus request is necessary so that the UI stays nice
- basePanel.getMainTable().requestFocus();
- clearSearch();
- basePanel.getMainTable().requestFocus();
- }
-
- /**
- * Save current settings.
- */
- private void updatePreferences() {
- Globals.prefs.putBoolean(JabRefPreferences.SEARCH_MODE_FLOAT, searchMode == SearchMode.FLOAT);
- Globals.prefs.putBoolean(JabRefPreferences.SEARCH_MODE_FILTER, searchMode == SearchMode.FILTER);
-
- Globals.prefs.putBoolean(JabRefPreferences.SEARCH_CASE_SENSITIVE, caseSensitive.isSelected());
- Globals.prefs.putBoolean(JabRefPreferences.SEARCH_REG_EXP, regularExp.isSelected());
- }
-
- /**
- * Focuses the search field if it is not focused.
- */
- public void focus() {
- if (!searchField.hasFocus()) {
- searchField.requestFocus();
- }
- }
-
- /**
- * Clears the current search. This includes resetting the search text.
- */
- private void clearSearch() {
- searchField.setText("");
- searchField.setBackground(Color.WHITE);
-
- searchQueryHighlightObservable.reset();
-
- this.currentResults.setText("");
-
- basePanel.getMainTable().getTableModel().updateSearchState(MainTableDataModel.DisplayOption.DISABLED);
-
- globalSearch.setEnabled(false);
- openCurrentResultsInDialog.setEnabled(false);
-
- searchIcon.setIcon(IconTheme.JabRefIcon.SEARCH.getSmallIcon());
- }
-
- /**
- * Performs a new search based on the current search query.
- */
- private void performSearch() {
- if (searchWorker != null) {
- searchWorker.cancel(true);
- }
-
- // An empty search field should cause the search to be cleared.
- if (searchField.getText().isEmpty()) {
- clearSearch();
- return;
- }
-
- SearchQuery searchQuery = getSearchQuery();
- LOGGER.debug("Searching " + searchQuery + " in " + basePanel.getTabTitle());
-
- if (!searchQuery.isValid()) {
- informUserAboutInvalidSearchQuery();
-
- return;
- }
-
- searchWorker = new SearchWorker(basePanel, searchQuery, searchMode);
- searchWorker.execute();
- }
-
- private void informUserAboutInvalidSearchQuery() {
- searchField.setBackground(NO_RESULTS_COLOR);
-
- searchQueryHighlightObservable.reset();
-
- globalSearch.setEnabled(false);
- openCurrentResultsInDialog.setEnabled(false);
-
- basePanel.getMainTable().getTableModel().updateSearchState(MainTableDataModel.DisplayOption.DISABLED);
-
- searchIcon.setIcon(IconTheme.JabRefIcon.SEARCH.getSmallIcon().createWithNewColor(NO_RESULTS_COLOR));
- searchIcon.setToolTipText(Localization.lang("Search failed: illegal search expression"));
-
- currentResults.setText(Localization.lang("Search failed: illegal search expression"));
- }
-
- /**
- * Sets the autocompleter used in the search field.
- *
- * @param searchCompleter the autocompleter
- */
- public void setAutoCompleter(AutoCompleter<String> searchCompleter) {
- this.autoCompleteSupport.setAutoCompleter(searchCompleter);
- }
-
- public SearchQueryHighlightObservable getSearchQueryHighlightObservable() {
- return searchQueryHighlightObservable;
- }
-
- boolean isStillValidQuery(SearchQuery query) {
- return query.getQuery().equals(this.searchField.getText())
- && (query.isRegularExpression() == regularExp.isSelected())
- && (query.isCaseSensitive() == caseSensitive.isSelected());
- }
-
- private SearchQuery getSearchQuery() {
- return new SearchQuery(this.searchField.getText(), this.caseSensitive.isSelected(),
- this.regularExp.isSelected());
- }
-
- void updateResults(int matched, String description, boolean grammarBasedSearch) {
- if (matched == 0) {
- // nothing found
- this.currentResults.setText(Localization.lang("No results found."));
- this.searchField.setBackground(NO_RESULTS_COLOR);
- } else {
- // specific set found, could be all
- this.currentResults.setText(Localization.lang("Found %0 results.", String.valueOf(matched)));
- this.searchField.setBackground(RESULTS_FOUND_COLOR);
- }
- this.searchField.setToolTipText("<html>" + description + "</html>");
-
- if (grammarBasedSearch) {
- searchIcon.setIcon(IconTheme.JabRefIcon.SEARCH.getSmallIcon().createWithNewColor(ADVANCED_SEARCH_COLOR));
- searchIcon.setToolTipText(Localization.lang("Advanced search active."));
- } else {
- searchIcon.setIcon(IconTheme.JabRefIcon.SEARCH.getSmallIcon());
- searchIcon.setToolTipText(Localization.lang("Normal search active."));
- }
-
- globalSearch.setEnabled(true);
- openCurrentResultsInDialog.setEnabled(true);
- }
-}
diff --git a/src/main/java/net/sf/jabref/gui/search/SearchDisplayMode.java b/src/main/java/net/sf/jabref/gui/search/SearchDisplayMode.java
new file mode 100644
index 0000000..6ca05cb
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/search/SearchDisplayMode.java
@@ -0,0 +1,29 @@
+package net.sf.jabref.gui.search;
+
+import net.sf.jabref.logic.l10n.Localization;
+
+/**
+ * Collects the possible search modes
+ */
+public enum SearchDisplayMode {
+
+ FLOAT(Localization.lang("Float"), Localization.lang("Gray out non-hits")),
+ FILTER(Localization.lang("Filter"), Localization.lang("Hide non-hits"));
+
+ private final String displayName;
+ private final String toolTipText;
+
+ SearchDisplayMode(String displayName, String toolTipText) {
+ this.displayName = displayName;
+ this.toolTipText = toolTipText;
+ }
+
+ public String getDisplayName() {
+ return displayName;
+ }
+
+ public String getToolTipText() {
+ return toolTipText;
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/gui/search/SearchMode.java b/src/main/java/net/sf/jabref/gui/search/SearchMode.java
deleted file mode 100644
index 3bb5210..0000000
--- a/src/main/java/net/sf/jabref/gui/search/SearchMode.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package net.sf.jabref.gui.search;
-
-import net.sf.jabref.logic.l10n.Localization;
-
-/**
- * Collects the possible search modes
- */
-public enum SearchMode {
-
- FLOAT(Localization.lang("Float"),
- Localization.lang("Gray out non-hits")),
- FILTER(Localization.lang("Filter"),
- Localization.lang("Hide non-hits"))
- ;
-
- private final String displayName;
- private final String toolTipText;
-
- SearchMode(String displayName, String toolTipText) {
- this.displayName = displayName;
- this.toolTipText = toolTipText;
- }
-
- public String getDisplayName() {
- return displayName;
- }
-
- public String getToolTipText() {
- return toolTipText;
- }
-}
\ No newline at end of file
diff --git a/src/main/java/net/sf/jabref/gui/search/SearchResultFrame.java b/src/main/java/net/sf/jabref/gui/search/SearchResultFrame.java
new file mode 100644
index 0000000..7442b7a
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/search/SearchResultFrame.java
@@ -0,0 +1,641 @@
+package net.sf.jabref.gui.search;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Rectangle;
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+
+import javax.swing.AbstractAction;
+import javax.swing.ActionMap;
+import javax.swing.InputMap;
+import javax.swing.JComponent;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPopupMenu;
+import javax.swing.JScrollPane;
+import javax.swing.JSplitPane;
+import javax.swing.JTable;
+import javax.swing.KeyStroke;
+import javax.swing.SwingUtilities;
+import javax.swing.table.TableColumnModel;
+
+import net.sf.jabref.Globals;
+import net.sf.jabref.gui.BasePanel;
+import net.sf.jabref.gui.GUIGlobals;
+import net.sf.jabref.gui.IconTheme;
+import net.sf.jabref.gui.JabRefFrame;
+import net.sf.jabref.gui.PreviewPanel;
+import net.sf.jabref.gui.TransferableBibtexEntry;
+import net.sf.jabref.gui.desktop.JabRefDesktop;
+import net.sf.jabref.gui.externalfiletype.ExternalFileMenuItem;
+import net.sf.jabref.gui.filelist.FileListEntry;
+import net.sf.jabref.gui.filelist.FileListTableModel;
+import net.sf.jabref.gui.keyboard.KeyBinding;
+import net.sf.jabref.gui.maintable.MainTableNameFormatter;
+import net.sf.jabref.gui.renderer.GeneralRenderer;
+import net.sf.jabref.gui.util.comparator.IconComparator;
+import net.sf.jabref.logic.bibtex.comparator.EntryComparator;
+import net.sf.jabref.logic.bibtex.comparator.FieldComparator;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.logic.search.SearchQuery;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldName;
+import net.sf.jabref.model.entry.FieldProperty;
+import net.sf.jabref.model.entry.InternalBibtexFields;
+import net.sf.jabref.model.strings.StringUtil;
+import net.sf.jabref.preferences.SearchPreferences;
+
+import ca.odell.glazedlists.BasicEventList;
+import ca.odell.glazedlists.EventList;
+import ca.odell.glazedlists.SortedList;
+import ca.odell.glazedlists.event.ListEvent;
+import ca.odell.glazedlists.event.ListEventListener;
+import ca.odell.glazedlists.gui.AbstractTableComparatorChooser;
+import ca.odell.glazedlists.gui.AdvancedTableFormat;
+import ca.odell.glazedlists.swing.DefaultEventSelectionModel;
+import ca.odell.glazedlists.swing.DefaultEventTableModel;
+import ca.odell.glazedlists.swing.GlazedListsSwing;
+import ca.odell.glazedlists.swing.TableComparatorChooser;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Dialog to display search results, potentially from more than one BasePanel, with
+ * possibility to preview and to locate each entry in the main window.
+ */
+public class SearchResultFrame {
+
+ private static final Log LOGGER = LogFactory.getLog(SearchResultFrame.class);
+
+ private final JabRefFrame frame;
+
+ private JFrame searchResultFrame;
+ private static final String[] FIELDS = new String[] {
+ FieldName.AUTHOR, FieldName.TITLE, FieldName.YEAR, FieldName.JOURNAL
+ };
+ private static final int DATABASE_COL = 0;
+ private static final int FILE_COL = 1;
+ private static final int URL_COL = 2;
+ private static final int PAD = 3;
+ private final JLabel fileLabel = new JLabel(IconTheme.JabRefIcon.FILE.getSmallIcon());
+ private final JLabel urlLabel = new JLabel(IconTheme.JabRefIcon.WWW.getSmallIcon());
+
+ private final JSplitPane contentPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
+
+ private final Rectangle toRect = new Rectangle(0, 0, 1, 1);
+ private final EventList<BibEntry> entries = new BasicEventList<>();
+
+ private final Map<BibEntry, BasePanel> entryHome = new HashMap<>();
+ private DefaultEventTableModel<BibEntry> model;
+
+ private SortedList<BibEntry> sortedEntries;
+ private JTable entryTable;
+ private PreviewPanel preview;
+
+ private SearchQuery searchQuery;
+ private boolean globalSearch;
+
+
+ public SearchResultFrame(JabRefFrame frame, String title, SearchQuery searchQuery, boolean globalSearch) {
+ this.frame = Objects.requireNonNull(frame);
+ this.searchQuery = searchQuery;
+ this.globalSearch = globalSearch;
+ frame.getGlobalSearchBar().setSearchResultFrame(this);
+ init(Objects.requireNonNull(title));
+ }
+
+ private void init(String title) {
+ searchResultFrame = new JFrame();
+ searchResultFrame.setTitle(title);
+ searchResultFrame.setIconImage(IconTheme.getImage("jabrefIcon48").getImage());
+
+ preview = new PreviewPanel(null, null);
+
+ sortedEntries = new SortedList<>(entries, new EntryComparator(false, true, FieldName.AUTHOR));
+ model = (DefaultEventTableModel<BibEntry>) GlazedListsSwing.eventTableModelWithThreadProxyList(sortedEntries,
+ new EntryTableFormat());
+ entryTable = new JTable(model);
+
+ GeneralRenderer renderer = new GeneralRenderer(Color.white);
+ entryTable.setDefaultRenderer(JLabel.class, renderer);
+ entryTable.setDefaultRenderer(String.class, renderer);
+ setWidths();
+ TableComparatorChooser<BibEntry> tableSorter =
+ TableComparatorChooser.install(entryTable, sortedEntries,
+ AbstractTableComparatorChooser.MULTIPLE_COLUMN_KEYBOARD);
+ setupComparatorChooser(tableSorter);
+ JScrollPane sp = new JScrollPane(entryTable);
+
+ final DefaultEventSelectionModel<BibEntry> selectionModel = (DefaultEventSelectionModel<BibEntry>) GlazedListsSwing
+ .eventSelectionModelWithThreadProxyList(sortedEntries);
+ entryTable.setSelectionModel(selectionModel);
+ selectionModel.getSelected().addListEventListener(new EntrySelectionListener());
+ entryTable.addMouseListener(new TableClickListener());
+
+ contentPane.setTopComponent(sp);
+ contentPane.setBottomComponent(preview);
+
+ // Key bindings:
+ AbstractAction closeAction = new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ dispose();
+ }
+ };
+
+ ActionMap actionMap = contentPane.getActionMap();
+ InputMap inputMap = contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
+ inputMap.put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE_DIALOG), "close");
+ inputMap.put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE_DATABASE), "close");
+ actionMap.put("close", closeAction);
+
+ actionMap = entryTable.getActionMap();
+ inputMap = entryTable.getInputMap();
+ //Override 'selectNextColumnCell' and 'selectPreviousColumnCell' to move rows instead of cells on TAB
+ actionMap.put("selectNextColumnCell", new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ selectNextEntry();
+ }
+ });
+ actionMap.put("selectPreviousColumnCell", new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ selectPreviousEntry();
+ }
+ });
+ actionMap.put("selectNextRow", new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ selectNextEntry();
+ }
+ });
+ actionMap.put("selectPreviousRow", new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ selectPreviousEntry();
+ }
+ });
+
+ String selectFirst = "selectFirst";
+ inputMap.put(Globals.getKeyPrefs().getKey(KeyBinding.SELECT_FIRST_ENTRY), selectFirst);
+ actionMap.put(selectFirst, new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ selectFirstEntry();
+ }
+ });
+
+ String selectLast = "selectLast";
+ inputMap.put(Globals.getKeyPrefs().getKey(KeyBinding.SELECT_LAST_ENTRY), selectLast);
+ actionMap.put(selectLast, new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent event) {
+ selectLastEntry();
+ }
+ });
+
+ actionMap.put("copy", new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (!selectionModel.getSelected().isEmpty()) {
+ List<BibEntry> bes = selectionModel.getSelected();
+ TransferableBibtexEntry trbe = new TransferableBibtexEntry(bes);
+ // ! look at ClipBoardManager
+ Toolkit.getDefaultToolkit().getSystemClipboard()
+ .setContents(trbe, frame.getCurrentBasePanel());
+ frame.output(Localization.lang("Copied") + ' ' + (bes.size() > 1 ? bes.size() + " "
+ + Localization.lang("entries")
+ : "1 " + Localization.lang("entry") + '.'));
+ }
+ }
+ });
+
+ // override standard enter-action; enter opens the selected entry
+ entryTable.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "Enter");
+ actionMap.put("Enter", new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent ae) {
+ BibEntry entry = sortedEntries.get(entryTable.getSelectedRow());
+ selectEntryInBasePanel(entry);
+ }
+ });
+
+ searchResultFrame.addWindowListener(new WindowAdapter() {
+ @Override
+ public void windowOpened(WindowEvent e) {
+ contentPane.setDividerLocation(0.5f);
+ }
+
+ @Override
+ public void windowClosing(WindowEvent event) {
+ dispose();
+ }
+ });
+
+ searchResultFrame.getContentPane().add(contentPane, BorderLayout.CENTER);
+
+ // Remember and default to last size:
+ SearchPreferences searchPreferences = new SearchPreferences(Globals.prefs);
+ searchResultFrame.setSize(searchPreferences.getSeachDialogWidth(), searchPreferences.getSeachDialogHeight());
+ searchResultFrame.setLocation(searchPreferences.getSearchDialogPosX(), searchPreferences.getSearchDialogPosY());
+
+ searchResultFrame.addComponentListener(new ComponentAdapter() {
+ @Override
+ public void componentResized(ComponentEvent e) {
+ new SearchPreferences(Globals.prefs)
+ .setSearchDialogWidth(searchResultFrame.getSize().width)
+ .setSearchDialogHeight(searchResultFrame.getSize().height);
+ }
+
+ @Override
+ public void componentMoved(ComponentEvent e) {
+ new SearchPreferences(Globals.prefs)
+ .setSearchDialogPosX(searchResultFrame.getLocation().x)
+ .setSearchDialogPosY(searchResultFrame.getLocation().y);
+ }
+ });
+ }
+
+ /**
+ * Control the visibility of the dialog.
+ * @param visible true to show dialog, false to hide.
+ */
+ public void setVisible(boolean visible) {
+ searchResultFrame.setVisible(visible);
+ }
+
+ public void selectFirstEntry() {
+ selectEntry(0);
+ }
+
+ public void selectLastEntry() {
+ selectEntry(entryTable.getRowCount() - 1);
+ }
+
+ public void selectPreviousEntry() {
+ selectEntry((entryTable.getSelectedRow() - 1 + entryTable.getRowCount()) % entryTable.getRowCount());
+ }
+
+ public void selectNextEntry() {
+ selectEntry((entryTable.getSelectedRow() + 1) % entryTable.getRowCount());
+ }
+
+ public void selectEntry(int index) {
+ if (index >= 0 && index < entryTable.getRowCount()) {
+ entryTable.changeSelection(index, 0, false, false);
+ } else {
+ contentPane.setDividerLocation(1.0f);
+ }
+ }
+
+ /**
+ * Set up the comparators for each column, so the user can modify sort order
+ * by clicking the column labels.
+ * @param comparatorChooser The comparator chooser controlling the sort order.
+ */
+ private void setupComparatorChooser(TableComparatorChooser<BibEntry> comparatorChooser) {
+ List<Comparator> comparators;
+ // Icon columns:
+ for (int i = 0; i < PAD; i++) {
+ comparators = comparatorChooser.getComparatorsForColumn(i);
+ comparators.clear();
+ if (i == FILE_COL) {
+ comparators.add(new IconComparator(Collections.singletonList(FieldName.FILE)));
+ } else if (i == URL_COL) {
+ comparators.add(new IconComparator(Collections.singletonList(FieldName.URL)));
+ } else if (i == DATABASE_COL) {
+ comparators.add((entry1, entry2) -> {
+ String databaseTitle1 = entryHome.get(entry1).getTabTitle();
+ String databaseTitle2 = entryHome.get(entry2).getTabTitle();
+ return databaseTitle1.compareTo(databaseTitle2);
+ });
+ }
+
+ }
+ // Remaining columns:
+ for (int i = PAD; i < (PAD + FIELDS.length); i++) {
+ comparators = comparatorChooser.getComparatorsForColumn(i);
+ comparators.clear();
+ comparators.add(new FieldComparator(FIELDS[i - PAD]));
+ }
+
+ sortedEntries.getReadWriteLock().writeLock().lock();
+ comparatorChooser.appendComparator(PAD, 0, false);
+ sortedEntries.getReadWriteLock().writeLock().unlock();
+
+ }
+
+ /**
+ * Set column widths according to which field is shown, and lock icon columns
+ * to a suitable width.
+ */
+ private void setWidths() {
+ TableColumnModel cm = entryTable.getColumnModel();
+ for (int i = 0; i < PAD + FIELDS.length; i++) {
+ switch (i) {
+ case FILE_COL:
+ case URL_COL:
+ cm.getColumn(i).setPreferredWidth(GUIGlobals.WIDTH_ICON_COL);
+ cm.getColumn(i).setMinWidth(GUIGlobals.WIDTH_ICON_COL);
+ cm.getColumn(i).setMaxWidth(GUIGlobals.WIDTH_ICON_COL);
+ break;
+ case DATABASE_COL: {
+ int width = InternalBibtexFields.getFieldLength(FieldName.AUTHOR);
+ cm.getColumn(i).setPreferredWidth(width);
+ break;
+ }
+ default: {
+ int width = InternalBibtexFields.getFieldLength(FIELDS[i - PAD]);
+ cm.getColumn(i).setPreferredWidth(width);
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * Add a list of entries to the table.
+ * @param newEntries The list of entries.
+ * @param panel A reference to the BasePanel where the entries belong.
+ */
+ public void addEntries(List<BibEntry> newEntries, BasePanel panel) {
+ for (BibEntry entry : newEntries) {
+ addEntry(entry, panel);
+ }
+ }
+
+ /**
+ * Add a single entry to the table.
+ * @param entry The entry to add.
+ * @param panel A reference to the BasePanel where the entry belongs.
+ */
+ private void addEntry(BibEntry entry, BasePanel panel) {
+ entries.add(entry);
+ entryHome.put(entry, panel);
+
+ if (preview.getEntry() == null || !preview.getBasePanel().isPresent()){
+ preview.setEntry(entry);
+ preview.setBasePanel(panel);
+ preview.setDatabaseContext(panel.getBibDatabaseContext());
+ }
+ }
+
+ private void selectEntryInBasePanel(BibEntry entry){
+ BasePanel basePanel = entryHome.get(entry);
+ frame.showBasePanel(basePanel);
+ basePanel.requestFocus();
+ basePanel.highlightEntry(entry);
+ }
+
+ public void dispose(){
+ frame.getGlobalSearchBar().setSearchResultFrame(null);
+ searchResultFrame.dispose();
+ frame.getGlobalSearchBar().focus();
+ }
+
+ public void focus(){
+ entryTable.requestFocus();
+ }
+
+ public SearchQuery getSearchQuery() {
+ return searchQuery;
+ }
+
+ public boolean isGlobalSearch() {
+ return globalSearch;
+ }
+
+ /**
+ * Mouse listener for the entry table. Processes icon clicks to open external
+ * files or urls, as well as the opening of the context menu.
+ */
+ class TableClickListener extends MouseAdapter {
+
+ @Override
+ public void mouseReleased(MouseEvent e) {
+ if (e.isPopupTrigger()) {
+ processPopupTrigger(e);
+ }
+ }
+
+ @Override
+ public void mousePressed(MouseEvent e) {
+ if (e.isPopupTrigger()) {
+ processPopupTrigger(e);
+ return;
+ }
+
+ // First find the row on which the user has clicked.
+ final int row = entryTable.rowAtPoint(e.getPoint());
+
+ // A double click on an entry should highlight the entry in its BasePanel:
+ if (e.getClickCount() == 2) {
+ selectEntryInBasePanel(model.getElementAt(row));
+ }
+ }
+
+ @Override
+ public void mouseClicked(MouseEvent e) {
+ if (e.isPopupTrigger()) {
+ processPopupTrigger(e);
+ return;
+ }
+ //if (e.)
+ final int col = entryTable.columnAtPoint(e.getPoint());
+ final int row = entryTable.rowAtPoint(e.getPoint());
+ if (col < PAD) {
+ BibEntry entry = sortedEntries.get(row);
+ BasePanel p = entryHome.get(entry);
+ switch (col) {
+ case FILE_COL:
+ if (entry.hasField(FieldName.FILE)) {
+ FileListTableModel tableModel = new FileListTableModel();
+ entry.getField(FieldName.FILE).ifPresent(tableModel::setContent);
+ if (tableModel.getRowCount() == 0) {
+ return;
+ }
+ FileListEntry fl = tableModel.getEntry(0);
+ (new ExternalFileMenuItem(frame, entry, "", fl.link, null,
+ p.getBibDatabaseContext(), fl.type)).actionPerformed(null);
+ }
+ break;
+ case URL_COL:
+ entry.getField(FieldName.URL).ifPresent(link -> { try {
+ JabRefDesktop.openExternalViewer(p.getBibDatabaseContext(), link, FieldName.URL);
+ } catch (IOException ex) {
+ LOGGER.warn("Could not open viewer", ex);
+ }
+ });
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ /**
+ * If the user has signalled the opening of a context menu, the event
+ * gets redirected to this method. Here we open a file link menu if the
+ * user is pointing at a file link icon. Otherwise a general context
+ * menu should be shown.
+ * @param e The triggering mouse event.
+ */
+ public void processPopupTrigger(MouseEvent e) {
+ BibEntry entry = sortedEntries.get(entryTable.rowAtPoint(e.getPoint()));
+ BasePanel p = entryHome.get(entry);
+ int col = entryTable.columnAtPoint(e.getPoint());
+ JPopupMenu menu = new JPopupMenu();
+ int count = 0;
+
+ if (col == FILE_COL) {
+ // We use a FileListTableModel to parse the field content:
+ FileListTableModel fileList = new FileListTableModel();
+ entry.getField(FieldName.FILE).ifPresent(fileList::setContent);
+ // If there are one or more links, open the first one:
+ for (int i = 0; i < fileList.getRowCount(); i++) {
+ FileListEntry flEntry = fileList.getEntry(i);
+ String description = flEntry.description;
+ if ((description == null) || (description.trim().isEmpty())) {
+ description = flEntry.link;
+ }
+ menu.add(new ExternalFileMenuItem(p.frame(), entry, description, flEntry.link,
+ flEntry.type.get().getIcon(), p.getBibDatabaseContext(), flEntry.type));
+ count++;
+ }
+
+ }
+
+ if (count > 0) {
+ menu.show(entryTable, e.getX(), e.getY());
+ }
+ }
+ }
+
+ /**
+ * The listener for the Glazed list monitoring the current selection.
+ * When selection changes, we need to update the preview panel.
+ */
+ private class EntrySelectionListener implements ListEventListener<BibEntry> {
+
+ @Override
+ public void listChanged(ListEvent<BibEntry> listEvent) {
+ if (listEvent.getSourceList().size() == 1) {
+ BibEntry entry = listEvent.getSourceList().get(0);
+ // Find out which BasePanel the selected entry belongs to:
+ BasePanel basePanel = entryHome.get(entry);
+ // Update the preview's database context:
+ preview.setDatabaseContext(basePanel.getBibDatabaseContext());
+ // Update the preview's entry:
+ preview.setEntry(entry);
+ preview.setBasePanel(entryHome.get(entry));
+ preview.setDatabaseContext(entryHome.get(entry).getBibDatabaseContext());
+ contentPane.setDividerLocation(0.5f);
+ SwingUtilities.invokeLater(() -> preview.scrollRectToVisible(toRect));
+ }
+ }
+ }
+
+ /**
+ * TableFormat for the table shown in the dialog. Handles the display of entry
+ * fields and icons for linked files and urls.
+ */
+ private class EntryTableFormat implements AdvancedTableFormat<BibEntry> {
+
+ @Override
+ public int getColumnCount() {
+ return PAD + FIELDS.length;
+ }
+
+ @Override
+ public String getColumnName(int column) {
+ if (column >= PAD) {
+ return StringUtil.capitalizeFirst(FIELDS[column - PAD]);
+ } else if (column == DATABASE_COL){
+ return Localization.lang("Database");
+ } else {
+ return "";
+ }
+ }
+
+ @Override
+ public Object getColumnValue(BibEntry entry, int column) {
+ if (column < PAD) {
+ switch (column) {
+ case DATABASE_COL:
+ return entryHome.get(entry).getTabTitle();
+ case FILE_COL:
+ if (entry.hasField(FieldName.FILE)) {
+ FileListTableModel tmpModel = new FileListTableModel();
+ entry.getField(FieldName.FILE).ifPresent(tmpModel::setContent);
+ fileLabel.setToolTipText(tmpModel.getToolTipHTMLRepresentation());
+ if (tmpModel.getRowCount() > 0) {
+ if (tmpModel.getEntry(0).type.isPresent()) {
+ fileLabel.setIcon(tmpModel.getEntry(0).type.get().getIcon());
+ } else {
+ fileLabel.setIcon(IconTheme.JabRefIcon.FILE.getSmallIcon());
+ }
+ }
+ return fileLabel;
+ } else {
+ return null;
+ }
+ case URL_COL: {
+ Optional<String> urlField = entry.getField(FieldName.URL);
+ if (urlField.isPresent()) {
+ urlLabel.setToolTipText(urlField.get());
+ return urlLabel;
+ }
+ return null;
+ }
+ default:
+ return null;
+ }
+ }
+ else {
+ String field = FIELDS[column - PAD];
+ String fieldContent = entry.getLatexFreeField(field).orElse("");
+
+ if (InternalBibtexFields.getFieldProperties(field).contains(FieldProperty.PERSON_NAMES)) {
+ // For name fields, tap into a MainTableFormat instance and use
+ // the same name formatting as is used in the entry table:
+ return MainTableNameFormatter.formatName(fieldContent);
+ }
+ return fieldContent;
+ }
+ }
+
+ @Override
+ public Class<?> getColumnClass(int i) {
+ switch (i) {
+ case FILE_COL:
+ case URL_COL:
+ return JLabel.class;
+ default:
+ return String.class;
+ }
+ }
+
+ @Override
+ public Comparator<?> getColumnComparator(int i) {
+ return null;
+ }
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/gui/search/SearchResultsDialog.java b/src/main/java/net/sf/jabref/gui/search/SearchResultsDialog.java
deleted file mode 100644
index 826ee35..0000000
--- a/src/main/java/net/sf/jabref/gui/search/SearchResultsDialog.java
+++ /dev/null
@@ -1,501 +0,0 @@
-package net.sf.jabref.gui.search;
-
-import java.awt.BorderLayout;
-import java.awt.Color;
-import java.awt.Dimension;
-import java.awt.Rectangle;
-import java.awt.Toolkit;
-import java.awt.event.ActionEvent;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
-import java.io.IOException;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-
-import javax.swing.AbstractAction;
-import javax.swing.ActionMap;
-import javax.swing.InputMap;
-import javax.swing.JComponent;
-import javax.swing.JDialog;
-import javax.swing.JLabel;
-import javax.swing.JPopupMenu;
-import javax.swing.JScrollPane;
-import javax.swing.JSplitPane;
-import javax.swing.JTable;
-import javax.swing.SwingUtilities;
-import javax.swing.table.TableColumnModel;
-
-import net.sf.jabref.Globals;
-import net.sf.jabref.external.ExternalFileMenuItem;
-import net.sf.jabref.gui.BasePanel;
-import net.sf.jabref.gui.FileListEntry;
-import net.sf.jabref.gui.FileListTableModel;
-import net.sf.jabref.gui.GUIGlobals;
-import net.sf.jabref.gui.IconTheme;
-import net.sf.jabref.gui.JabRefFrame;
-import net.sf.jabref.gui.PreviewPanel;
-import net.sf.jabref.gui.TransferableBibtexEntry;
-import net.sf.jabref.gui.desktop.JabRefDesktop;
-import net.sf.jabref.gui.keyboard.KeyBinding;
-import net.sf.jabref.gui.maintable.MainTableNameFormatter;
-import net.sf.jabref.gui.renderer.GeneralRenderer;
-import net.sf.jabref.gui.util.GUIUtil;
-import net.sf.jabref.gui.util.comparator.IconComparator;
-import net.sf.jabref.logic.bibtex.comparator.EntryComparator;
-import net.sf.jabref.logic.bibtex.comparator.FieldComparator;
-import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.model.entry.EntryUtil;
-import net.sf.jabref.model.entry.FieldName;
-import net.sf.jabref.model.entry.FieldProperties;
-import net.sf.jabref.model.entry.InternalBibtexFields;
-import net.sf.jabref.preferences.JabRefPreferences;
-
-import ca.odell.glazedlists.BasicEventList;
-import ca.odell.glazedlists.EventList;
-import ca.odell.glazedlists.SortedList;
-import ca.odell.glazedlists.event.ListEvent;
-import ca.odell.glazedlists.event.ListEventListener;
-import ca.odell.glazedlists.gui.AbstractTableComparatorChooser;
-import ca.odell.glazedlists.gui.AdvancedTableFormat;
-import ca.odell.glazedlists.swing.DefaultEventSelectionModel;
-import ca.odell.glazedlists.swing.DefaultEventTableModel;
-import ca.odell.glazedlists.swing.GlazedListsSwing;
-import ca.odell.glazedlists.swing.TableComparatorChooser;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * Dialog to display search results, potentially from more than one BasePanel, with
- * possibility to preview and to locate each entry in the main window.
- */
-public class SearchResultsDialog {
-
- private static final Log LOGGER = LogFactory.getLog(SearchResultsDialog.class);
-
- private final JabRefFrame frame;
-
- private JDialog diag;
- private static final String[] FIELDS = new String[] {
- FieldName.AUTHOR, FieldName.TITLE, FieldName.YEAR, FieldName.JOURNAL
- };
- private static final int FILE_COL = 0;
- private static final int URL_COL = 1;
- private static final int PAD = 2;
- private final JLabel fileLabel = new JLabel(IconTheme.JabRefIcon.FILE.getSmallIcon());
- private final JLabel urlLabel = new JLabel(IconTheme.JabRefIcon.WWW.getSmallIcon());
-
- private final JSplitPane contentPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
-
- private final Rectangle toRect = new Rectangle(0, 0, 1, 1);
- private final EventList<BibEntry> entries = new BasicEventList<>();
-
- private final Map<BibEntry, BasePanel> entryHome = new HashMap<>();
- private DefaultEventTableModel<BibEntry> model;
-
- private SortedList<BibEntry> sortedEntries;
- private JTable entryTable;
- private PreviewPanel preview;
-
-
- public SearchResultsDialog(JabRefFrame frame, String title) {
- this.frame = Objects.requireNonNull(frame);
- init(Objects.requireNonNull(title));
- }
-
- private void init(String title) {
- diag = new JDialog(frame, title, false);
-
- int activePreview = Globals.prefs.getInt(JabRefPreferences.ACTIVE_PREVIEW);
- String layoutFile = activePreview == 0 ? Globals.prefs.get(JabRefPreferences.PREVIEW_0) : Globals.prefs
- .get(JabRefPreferences.PREVIEW_1);
- preview = new PreviewPanel(null, null, layoutFile);
-
- sortedEntries = new SortedList<>(entries, new EntryComparator(false, true, FieldName.AUTHOR));
- model = (DefaultEventTableModel<BibEntry>) GlazedListsSwing.eventTableModelWithThreadProxyList(sortedEntries,
- new EntryTableFormat());
- entryTable = new JTable(model);
- GUIUtil.correctRowHeight(entryTable);
-
- GeneralRenderer renderer = new GeneralRenderer(Color.white);
- entryTable.setDefaultRenderer(JLabel.class, renderer);
- entryTable.setDefaultRenderer(String.class, renderer);
- setWidths();
- TableComparatorChooser<BibEntry> tableSorter =
- TableComparatorChooser.install(entryTable, sortedEntries,
- AbstractTableComparatorChooser.MULTIPLE_COLUMN_KEYBOARD);
- setupComparatorChooser(tableSorter);
- JScrollPane sp = new JScrollPane(entryTable);
-
- final DefaultEventSelectionModel<BibEntry> selectionModel = (DefaultEventSelectionModel<BibEntry>) GlazedListsSwing
- .eventSelectionModelWithThreadProxyList(sortedEntries);
- entryTable.setSelectionModel(selectionModel);
- selectionModel.getSelected().addListEventListener(new EntrySelectionListener());
- entryTable.addMouseListener(new TableClickListener());
-
- contentPane.setTopComponent(sp);
- contentPane.setBottomComponent(preview);
-
- // Key bindings:
- AbstractAction closeAction = new AbstractAction() {
-
- @Override
- public void actionPerformed(ActionEvent e) {
- diag.dispose();
- }
- };
- ActionMap am = contentPane.getActionMap();
- InputMap im = contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
- im.put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE_DIALOG), "close");
- am.put("close", closeAction);
-
- entryTable.getActionMap().put("copy", new AbstractAction() {
-
- @Override
- public void actionPerformed(ActionEvent e) {
- if (!selectionModel.getSelected().isEmpty()) {
- List<BibEntry> bes = selectionModel.getSelected();
- TransferableBibtexEntry trbe = new TransferableBibtexEntry(bes);
- // ! look at ClipBoardManager
- Toolkit.getDefaultToolkit().getSystemClipboard()
- .setContents(trbe, frame.getCurrentBasePanel());
- frame.output(Localization.lang("Copied") + ' ' + (bes.size() > 1 ? bes.size() + " "
- + Localization.lang("entries")
- : "1 " + Localization.lang("entry") + '.'));
- }
- }
- });
-
- diag.addWindowListener(new WindowAdapter() {
-
- @Override
- public void windowOpened(WindowEvent e) {
- contentPane.setDividerLocation(0.5f);
- }
-
- @Override
- public void windowClosing(WindowEvent event) {
- Globals.prefs.putInt(JabRefPreferences.SEARCH_DIALOG_WIDTH, diag.getSize().width);
- Globals.prefs.putInt(JabRefPreferences.SEARCH_DIALOG_HEIGHT, diag.getSize().height);
- }
- });
-
- diag.getContentPane().add(contentPane, BorderLayout.CENTER);
- // Remember and default to last size:
- diag.setSize(new Dimension(Globals.prefs.getInt(JabRefPreferences.SEARCH_DIALOG_WIDTH), Globals.prefs
- .getInt(JabRefPreferences.SEARCH_DIALOG_HEIGHT)));
- diag.setLocationRelativeTo(frame);
- }
-
- /**
- * Control the visibility of the dialog.
- * @param visible true to show dialog, false to hide.
- */
- public void setVisible(boolean visible) {
- diag.setVisible(visible);
- }
-
- public void selectFirstEntry() {
- if (entryTable.getRowCount() > 0) {
- entryTable.setRowSelectionInterval(0, 0);
- } else {
- contentPane.setDividerLocation(1.0f);
- }
- }
-
- /**
- * Set up the comparators for each column, so the user can modify sort order
- * by clicking the column labels.
- * @param comparatorChooser The comparator chooser controlling the sort order.
- */
- private void setupComparatorChooser(TableComparatorChooser<BibEntry> comparatorChooser) {
- // First column:
- List<Comparator> comparators = comparatorChooser.getComparatorsForColumn(0);
- comparators.clear();
-
- comparators = comparatorChooser.getComparatorsForColumn(1);
- comparators.clear();
-
- // Icon columns:
- for (int i = 0; i < PAD; i++) {
- comparators = comparatorChooser.getComparatorsForColumn(i);
- comparators.clear();
- if (i == FILE_COL) {
- comparators.add(new IconComparator(Collections.singletonList(FieldName.FILE)));
- } else if (i == URL_COL) {
- comparators.add(new IconComparator(Collections.singletonList(FieldName.URL)));
- }
-
- }
- // Remaining columns:
- for (int i = PAD; i < (PAD + FIELDS.length); i++) {
- comparators = comparatorChooser.getComparatorsForColumn(i);
- comparators.clear();
- comparators.add(new FieldComparator(FIELDS[i - PAD]));
- }
-
- sortedEntries.getReadWriteLock().writeLock().lock();
- comparatorChooser.appendComparator(PAD, 0, false);
- sortedEntries.getReadWriteLock().writeLock().unlock();
-
- }
-
- /**
- * Set column widths according to which field is shown, and lock icon columns
- * to a suitable width.
- */
- private void setWidths() {
- TableColumnModel cm = entryTable.getColumnModel();
- for (int i = 0; i < PAD; i++) {
- cm.getColumn(i).setPreferredWidth(GUIGlobals.WIDTH_ICON_COL);
- cm.getColumn(i).setMinWidth(GUIGlobals.WIDTH_ICON_COL);
- cm.getColumn(i).setMaxWidth(GUIGlobals.WIDTH_ICON_COL);
- }
-
- for (int i = 0; i < FIELDS.length; i++) {
- int width = InternalBibtexFields.getFieldLength(FIELDS[i]);
- cm.getColumn(i + PAD).setPreferredWidth(width);
- }
- }
-
- /**
- * Add a list of entries to the table.
- * @param newEntries The list of entries.
- * @param panel A reference to the BasePanel where the entries belong.
- */
- public void addEntries(List<BibEntry> newEntries, BasePanel panel) {
- for (BibEntry entry : newEntries) {
- addEntry(entry, panel);
- }
- }
-
- /**
- * Add a single entry to the table.
- * @param entry The entry to add.
- * @param panel A reference to the BasePanel where the entry belongs.
- */
- private void addEntry(BibEntry entry, BasePanel panel) {
- entries.add(entry);
- entryHome.put(entry, panel);
- }
-
- /**
- * Mouse listener for the entry table. Processes icon clicks to open external
- * files or urls, as well as the opening of the context menu.
- */
- class TableClickListener extends MouseAdapter {
-
- @Override
- public void mouseReleased(MouseEvent e) {
- if (e.isPopupTrigger()) {
- processPopupTrigger(e);
- }
- }
-
- @Override
- public void mousePressed(MouseEvent e) {
- if (e.isPopupTrigger()) {
- processPopupTrigger(e);
- return;
- }
-
- // First find the row on which the user has clicked.
- final int row = entryTable.rowAtPoint(e.getPoint());
-
- // A double click on an entry should highlight the entry in its BasePanel:
- if (e.getClickCount() == 2) {
- // Get the selected entry:
- BibEntry toShow = model.getElementAt(row);
- // Look up which BasePanel it belongs to:
- BasePanel p = entryHome.get(toShow);
- // Show the correct tab in the main window:
- frame.showBasePanel(p);
- // Highlight the entry:
- p.highlightEntry(toShow);
- }
- }
-
- @Override
- public void mouseClicked(MouseEvent e) {
- if (e.isPopupTrigger()) {
- processPopupTrigger(e);
- return;
- }
- //if (e.)
- final int col = entryTable.columnAtPoint(e.getPoint());
- final int row = entryTable.rowAtPoint(e.getPoint());
- if (col < PAD) {
- BibEntry entry = sortedEntries.get(row);
- BasePanel p = entryHome.get(entry);
- switch (col) {
- case FILE_COL:
- if (entry.hasField(FieldName.FILE)) {
- FileListTableModel tableModel = new FileListTableModel();
- entry.getFieldOptional(FieldName.FILE).ifPresent(tableModel::setContent);
- if (tableModel.getRowCount() == 0) {
- return;
- }
- FileListEntry fl = tableModel.getEntry(0);
- (new ExternalFileMenuItem(frame, entry, "", fl.link, null,
- p.getBibDatabaseContext(), fl.type)).actionPerformed(null);
- }
- break;
- case URL_COL:
- entry.getFieldOptional(FieldName.URL).ifPresent(link -> { try {
- JabRefDesktop.openExternalViewer(p.getBibDatabaseContext(), link, FieldName.URL);
- } catch (IOException ex) {
- LOGGER.warn("Could not open viewer", ex);
- }
- });
- break;
- default:
- break;
- }
- }
- }
-
- /**
- * If the user has signalled the opening of a context menu, the event
- * gets redirected to this method. Here we open a file link menu if the
- * user is pointing at a file link icon. Otherwise a general context
- * menu should be shown.
- * @param e The triggering mouse event.
- */
- public void processPopupTrigger(MouseEvent e) {
- BibEntry entry = sortedEntries.get(entryTable.rowAtPoint(e.getPoint()));
- BasePanel p = entryHome.get(entry);
- int col = entryTable.columnAtPoint(e.getPoint());
- JPopupMenu menu = new JPopupMenu();
- int count = 0;
-
- if (col == FILE_COL) {
- // We use a FileListTableModel to parse the field content:
- FileListTableModel fileList = new FileListTableModel();
- entry.getFieldOptional(FieldName.FILE).ifPresent(fileList::setContent);
- // If there are one or more links, open the first one:
- for (int i = 0; i < fileList.getRowCount(); i++) {
- FileListEntry flEntry = fileList.getEntry(i);
- String description = flEntry.description;
- if ((description == null) || (description.trim().isEmpty())) {
- description = flEntry.link;
- }
- menu.add(new ExternalFileMenuItem(p.frame(), entry, description, flEntry.link,
- flEntry.type.get().getIcon(), p.getBibDatabaseContext(), flEntry.type));
- count++;
- }
-
- }
-
- if (count > 0) {
- menu.show(entryTable, e.getX(), e.getY());
- }
- }
- }
-
- /**
- * The listener for the Glazed list monitoring the current selection.
- * When selection changes, we need to update the preview panel.
- */
- private class EntrySelectionListener implements ListEventListener<BibEntry> {
-
- @Override
- public void listChanged(ListEvent<BibEntry> listEvent) {
- if (listEvent.getSourceList().size() == 1) {
- BibEntry entry = listEvent.getSourceList().get(0);
- // Find out which BasePanel the selected entry belongs to:
- BasePanel p = entryHome.get(entry);
- // Update the preview's database context:
- preview.setDatabaseContext(p.getBibDatabaseContext());
- // Update the preview's entry:
- preview.setEntry(entry);
- contentPane.setDividerLocation(0.5f);
- SwingUtilities.invokeLater(() -> preview.scrollRectToVisible(toRect));
- }
- }
- }
-
- /**
- * TableFormat for the table shown in the dialog. Handles the display of entry
- * fields and icons for linked files and urls.
- */
- private class EntryTableFormat implements AdvancedTableFormat<BibEntry> {
-
- @Override
- public int getColumnCount() {
- return PAD + FIELDS.length;
- }
-
- @Override
- public String getColumnName(int column) {
- if (column >= PAD) {
- return EntryUtil.capitalizeFirst(FIELDS[column - PAD]);
- } else {
- return "";
- }
- }
-
- @Override
- public Object getColumnValue(BibEntry entry, int column) {
- if (column < PAD) {
- switch (column) {
- case FILE_COL:
- if (entry.hasField(FieldName.FILE)) {
- FileListTableModel tmpModel = new FileListTableModel();
- entry.getFieldOptional(FieldName.FILE).ifPresent(tmpModel::setContent);
- fileLabel.setToolTipText(tmpModel.getToolTipHTMLRepresentation());
- if (tmpModel.getRowCount() > 0) {
- if (tmpModel.getEntry(0).type.isPresent()) {
- fileLabel.setIcon(tmpModel.getEntry(0).type.get().getIcon());
- } else {
- fileLabel.setIcon(IconTheme.JabRefIcon.FILE.getSmallIcon());
- }
- }
- return fileLabel;
- } else {
- return null;
- }
- case URL_COL:
- if (entry.hasField(FieldName.URL)) {
- urlLabel.setToolTipText(entry.getFieldOptional(FieldName.URL).get());
- return urlLabel;
- } else {
- return null;
- }
- default:
- return null;
- }
- }
- else {
- String field = FIELDS[column - PAD];
- if (InternalBibtexFields.getFieldExtras(field).contains(FieldProperties.PERSON_NAMES)) {
- // For name fields, tap into a MainTableFormat instance and use
- // the same name formatting as is used in the entry table:
- if (frame.getCurrentBasePanel() != null) {
- return MainTableNameFormatter.formatName(entry.getFieldOptional(field).orElse(null));
- }
- }
- return entry.getFieldOptional(field).orElse(null);
- }
- }
-
- @Override
- public Class<?> getColumnClass(int i) {
- if (i < PAD) {
- return JLabel.class;
- } else {
- return String.class;
- }
- }
-
- @Override
- public Comparator<?> getColumnComparator(int i) {
- return null;
- }
- }
-}
diff --git a/src/main/java/net/sf/jabref/gui/search/SearchWorker.java b/src/main/java/net/sf/jabref/gui/search/SearchWorker.java
index 355627d..3c1291d 100644
--- a/src/main/java/net/sf/jabref/gui/search/SearchWorker.java
+++ b/src/main/java/net/sf/jabref/gui/search/SearchWorker.java
@@ -1,6 +1,5 @@
package net.sf.jabref.gui.search;
-import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ExecutionException;
@@ -8,7 +7,9 @@ import java.util.stream.Collectors;
import javax.swing.SwingWorker;
+import net.sf.jabref.JabRefGUI;
import net.sf.jabref.gui.BasePanel;
+import net.sf.jabref.gui.BasePanelMode;
import net.sf.jabref.gui.maintable.MainTableDataModel;
import net.sf.jabref.logic.search.SearchQuery;
import net.sf.jabref.model.database.BibDatabase;
@@ -17,6 +18,7 @@ import net.sf.jabref.model.entry.BibEntry;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
/**
* Not reusable. Always create a new instance for each search!
*/
@@ -28,22 +30,21 @@ class SearchWorker extends SwingWorker<List<BibEntry>, Void> {
private final BibDatabase database;
private final SearchQuery searchQuery;
- private final SearchMode mode;
+ private final SearchDisplayMode searchDisplayMode;
- SearchWorker(BasePanel basePanel, SearchQuery searchQuery, SearchMode mode) {
+ public SearchWorker(BasePanel basePanel, SearchQuery searchQuery, SearchDisplayMode searchDisplayMode) {
this.basePanel = Objects.requireNonNull(basePanel);
this.database = Objects.requireNonNull(basePanel.getDatabase());
this.searchQuery = Objects.requireNonNull(searchQuery);
- this.mode = Objects.requireNonNull(mode);
- LOGGER.debug("Search (" + this.mode.getDisplayName() + "): " + this.searchQuery);
+ this.searchDisplayMode = Objects.requireNonNull(searchDisplayMode);
+ LOGGER.debug("Search (" + this.searchDisplayMode.getDisplayName() + "): " + this.searchQuery);
}
@Override
protected List<BibEntry> doInBackground() throws Exception {
- // Search the current database
- List<BibEntry> matchedEntries = new LinkedList<>();
- matchedEntries.addAll(database.getEntries().stream().filter(searchQuery::isMatch).collect(Collectors.toList()));
- return matchedEntries;
+ return database.getEntries().parallelStream()
+ .filter(searchQuery::isMatch)
+ .collect(Collectors.toList());
}
@Override
@@ -60,9 +61,10 @@ class SearchWorker extends SwingWorker<List<BibEntry>, Void> {
}
private void updateUIWithSearchResult(List<BibEntry> matchedEntries) {
+ GlobalSearchBar globalSearchBar = JabRefGUI.getMainFrame().getGlobalSearchBar();
// check if still the current query
- if (!basePanel.getSearchBar().isStillValidQuery(searchQuery)) {
+ if (!globalSearchBar.isStillValidQuery(searchQuery)) {
// do not update - another search was already issued
return;
}
@@ -71,33 +73,43 @@ class SearchWorker extends SwingWorker<List<BibEntry>, Void> {
for (BibEntry entry : basePanel.getDatabase().getEntries()) {
entry.setSearchHit(false);
}
-
+ // and mark
for (BibEntry entry : matchedEntries) {
entry.setSearchHit(true);
}
basePanel.getMainTable().getTableModel().updateSearchState(MainTableDataModel.DisplayOption.DISABLED);
-
// Show the result in the chosen way:
- switch (mode) {
- case FLOAT:
- basePanel.getMainTable().getTableModel().updateSearchState(MainTableDataModel.DisplayOption.FLOAT);
- break;
- case FILTER:
- basePanel.getMainTable().getTableModel().updateSearchState(MainTableDataModel.DisplayOption.FILTER);
- break;
- default:
- break;
+ switch (searchDisplayMode) {
+ case FLOAT:
+ basePanel.getMainTable().getTableModel().updateSearchState(MainTableDataModel.DisplayOption.FLOAT);
+ break;
+ case FILTER:
+ basePanel.getMainTable().getTableModel().updateSearchState(MainTableDataModel.DisplayOption.FILTER);
+ break;
+ default:
+ LOGGER.error("Following searchDisplayMode was not defined: " + searchDisplayMode);
+ break;
}
- // select first match (i.e., row) if there is any
- int hits = matchedEntries.size();
- if ((hits > 0) && (basePanel.getMainTable().getRowCount() > 0)) {
- basePanel.getMainTable().setSelected(0);
+ // only selects the first match if the selected entries are no hits or no entry is selected
+ // and no editor is open (to avoid jumping around when editing an entry)
+ if (basePanel.getMode() != BasePanelMode.SHOWING_EDITOR && basePanel.getMode() != BasePanelMode.WILL_SHOW_EDITOR) {
+ List<BibEntry> selectedEntries = basePanel.getSelectedEntries();
+ boolean isHitSelected = selectedEntries.stream().anyMatch(BibEntry::isSearchHit);
+ if (!isHitSelected && !matchedEntries.isEmpty()) {
+ for (int i = 0; i < basePanel.getMainTable().getRowCount(); i++) {
+ BibEntry entry = basePanel.getMainTable().getEntryAt(i);
+ if (entry.isSearchHit()) {
+ basePanel.getMainTable().setSelected(i);
+ break;
+ }
+ }
+ }
}
- basePanel.getSearchBar().updateResults(hits, searchQuery.getDescription(), searchQuery.isGrammarBasedSearch());
- basePanel.getSearchBar().getSearchQueryHighlightObservable().fireSearchlistenerEvent(searchQuery);
+ globalSearchBar.updateResults(matchedEntries.size(), searchQuery.getDescription(), searchQuery.isGrammarBasedSearch());
+ globalSearchBar.getSearchQueryHighlightObservable().fireSearchlistenerEvent(searchQuery);
}
}
diff --git a/src/main/java/net/sf/jabref/gui/shared/ConnectToSharedDatabaseDialog.java b/src/main/java/net/sf/jabref/gui/shared/ConnectToSharedDatabaseDialog.java
new file mode 100644
index 0000000..b320eca
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/shared/ConnectToSharedDatabaseDialog.java
@@ -0,0 +1,475 @@
+package net.sf.jabref.gui.shared;
+
+import java.awt.FlowLayout;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+import java.io.UnsupportedEncodingException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.security.GeneralSecurityException;
+import java.sql.SQLException;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.BorderFactory;
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JPasswordField;
+import javax.swing.JTextField;
+import javax.swing.KeyStroke;
+
+import net.sf.jabref.JabRefException;
+import net.sf.jabref.JabRefGUI;
+import net.sf.jabref.gui.BasePanel;
+import net.sf.jabref.gui.FileDialog;
+import net.sf.jabref.gui.JabRefFrame;
+import net.sf.jabref.gui.exporter.SaveDatabaseAction;
+import net.sf.jabref.gui.help.HelpAction;
+import net.sf.jabref.logic.help.HelpFile;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.logic.util.FileExtensions;
+import net.sf.jabref.model.database.BibDatabaseContext;
+import net.sf.jabref.model.database.DatabaseLocation;
+import net.sf.jabref.shared.DBMSConnection;
+import net.sf.jabref.shared.DBMSConnectionProperties;
+import net.sf.jabref.shared.DBMSType;
+import net.sf.jabref.shared.exception.DatabaseNotSupportedException;
+import net.sf.jabref.shared.exception.InvalidDBMSConnectionPropertiesException;
+import net.sf.jabref.shared.prefs.SharedDatabasePreferences;
+import net.sf.jabref.shared.security.Password;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class ConnectToSharedDatabaseDialog extends JDialog {
+
+ private static final Log LOGGER = LogFactory.getLog(ConnectToSharedDatabaseDialog.class);
+
+ private final JabRefFrame frame;
+
+ private final GridBagLayout gridBagLayout = new GridBagLayout();
+ private final GridBagConstraints gridBagConstraints = new GridBagConstraints();
+ private final JPanel connectionPanel = new JPanel();
+ private final JPanel filePanel = new JPanel();
+ private final JPanel buttonPanel = new JPanel();
+
+ private final JLabel databaseTypeLabel = new JLabel(Localization.lang("Database type") + ":");
+ private final JLabel hostPortLabel = new JLabel(Localization.lang("Host") + "/" + Localization.lang("Port") + ":");
+ private final JLabel databaseLabel = new JLabel(Localization.lang("Database") + ":");
+ private final JLabel userLabel = new JLabel(Localization.lang("User") + ":");
+ private final JLabel passwordLabel = new JLabel(Localization.lang("Password") + ":");
+
+ private final JTextField hostField = new JTextField(12);
+ private final JTextField portField = new JTextField(4);
+ private final JTextField userField = new JTextField(14);
+ private final JTextField databaseField = new JTextField(14);
+ private final JTextField fileLocationField = new JTextField(20);
+
+ private final JPasswordField passwordField = new JPasswordField(14);
+ private final JComboBox<DBMSType> dbmsTypeDropDown = new JComboBox<>();
+
+ private final JButton connectButton = new JButton(Localization.lang("Connect"));
+ private final JButton cancelButton = new JButton(Localization.lang("Cancel"));
+ private final JButton browseButton = new JButton(Localization.lang("Browse"));
+ private final JButton helpButton = new HelpAction(HelpFile.SQL_DATABASE).getHelpButton();
+
+ private final JCheckBox rememberPassword = new JCheckBox(Localization.lang("Remember password?"));
+ private final JCheckBox autosaveFile = new JCheckBox(Localization.lang("Automatically save the database to"));
+
+ private final SharedDatabasePreferences prefs = new SharedDatabasePreferences();
+
+ private DBMSConnectionProperties connectionProperties;
+
+
+ /**
+ * @param frame the JabRef Frame
+ */
+ public ConnectToSharedDatabaseDialog(JabRefFrame frame) {
+ super(frame, Localization.lang("Connect to shared database"));
+ this.frame = frame;
+ initLayout();
+ updateEnableState();
+ applyPreferences();
+ setupActions();
+ pack();
+ setLocationRelativeTo(frame);
+ }
+
+ public void openSharedDatabase() {
+
+ if (isSharedDatabaseAlreadyPresent()) {
+ JOptionPane.showMessageDialog(ConnectToSharedDatabaseDialog.this,
+ Localization.lang("You are already connected to a database using entered connection details."),
+ Localization.lang("Warning"), JOptionPane.WARNING_MESSAGE);
+ return;
+ }
+
+ if (autosaveFile.isSelected()) {
+
+ Path localFilePath = Paths.get(fileLocationField.getText());
+
+ if (Files.exists(localFilePath) && !Files.isDirectory(localFilePath)) {
+ int answer = JOptionPane.showConfirmDialog(this,
+ Localization.lang("'%0' exists. Overwrite file?", localFilePath.getFileName().toString()),
+ Localization.lang("Existing file"), JOptionPane.YES_NO_OPTION);
+ if (answer == JOptionPane.NO_OPTION) {
+ fileLocationField.requestFocus();
+ return;
+ }
+ }
+ }
+
+ setLoadingConnectButtonText(true);
+
+ try {
+ BasePanel panel = new SharedDatabaseUIManager(frame).openNewSharedDatabaseTab(connectionProperties);
+ setPreferences();
+ dispose();
+ if (!fileLocationField.getText().isEmpty()) {
+ try {
+ new SaveDatabaseAction(panel, Paths.get(fileLocationField.getText())).runCommand();
+ } catch (Throwable e) {
+ LOGGER.error("Error while saving the database", e);
+ }
+ }
+
+ return; // setLoadingConnectButtonText(false) should not be reached regularly.
+ } catch (SQLException | InvalidDBMSConnectionPropertiesException exception) {
+ JOptionPane.showMessageDialog(ConnectToSharedDatabaseDialog.this, exception.getMessage(),
+ Localization.lang("Connection error"), JOptionPane.ERROR_MESSAGE);
+ } catch (DatabaseNotSupportedException exception) {
+ new MigrationHelpDialog(this).setVisible(true);
+ }
+
+ setLoadingConnectButtonText(false);
+ }
+
+ /**
+ * Defines and sets the different actions up.
+ */
+ private void setupActions() {
+
+ Action openAction = new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ try {
+ checkFields();
+
+ connectionProperties = new DBMSConnectionProperties();
+ connectionProperties.setType((DBMSType) dbmsTypeDropDown.getSelectedItem());
+ connectionProperties.setHost(hostField.getText());
+ connectionProperties.setPort(Integer.parseInt(portField.getText()));
+ connectionProperties.setDatabase(databaseField.getText());
+ connectionProperties.setUser(userField.getText());
+ connectionProperties.setPassword(new String(passwordField.getPassword())); //JPasswordField.getPassword() does not return a String, but a char array.
+
+ openSharedDatabase();
+ } catch (JabRefException exception) {
+ JOptionPane.showMessageDialog(ConnectToSharedDatabaseDialog.this, exception.getMessage(),
+ Localization.lang("Warning"), JOptionPane.WARNING_MESSAGE);
+ }
+ }
+ };
+ connectButton.addActionListener(openAction);
+ cancelButton.addActionListener(e -> dispose());
+
+ /**
+ * Set up a listener which updates the default port number once the selection in dbmsTypeDropDown has changed.
+ */
+ Action dbmsTypeDropDownAction = new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ portField.setText(Integer.toString(((DBMSType) dbmsTypeDropDown.getSelectedItem()).getDefaultPort()));
+ }
+ };
+ dbmsTypeDropDown.addActionListener(dbmsTypeDropDownAction);
+
+ // Add enter button action listener
+ connectButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0),
+ "Enter_pressed");
+ connectButton.getActionMap().put("Enter_pressed", openAction);
+ browseButton.addActionListener(e -> showFileChooser());
+ autosaveFile.addActionListener(e -> updateEnableState());
+ }
+
+ /**
+ * Fetches possibly saved data and configures the control elements respectively.
+ */
+ private void applyPreferences() {
+ Optional<String> sharedDatabaseType = prefs.getType();
+ Optional<String> sharedDatabaseHost = prefs.getHost();
+ Optional<String> sharedDatabasePort = prefs.getPort();
+ Optional<String> sharedDatabaseName = prefs.getName();
+ Optional<String> sharedDatabaseUser = prefs.getUser();
+ Optional<String> sharedDatabasePassword = prefs.getPassword();
+ boolean sharedDatabaseRememberPassword = prefs.getRememberPassword();
+
+ if (sharedDatabaseType.isPresent()) {
+ Optional<DBMSType> dbmsType = DBMSType.fromString(sharedDatabaseType.get());
+ if (dbmsType.isPresent()) {
+ dbmsTypeDropDown.setSelectedItem(dbmsType.get());
+ }
+ }
+
+ if (sharedDatabaseHost.isPresent()) {
+ hostField.setText(sharedDatabaseHost.get());
+ }
+
+ if (sharedDatabasePort.isPresent()) {
+ portField.setText(sharedDatabasePort.get());
+ } else {
+ portField.setText(Integer.toString(((DBMSType) dbmsTypeDropDown.getSelectedItem()).getDefaultPort()));
+ }
+
+ if (sharedDatabaseName.isPresent()) {
+ databaseField.setText(sharedDatabaseName.get());
+ }
+
+ if (sharedDatabaseUser.isPresent()) {
+ userField.setText(sharedDatabaseUser.get());
+ }
+
+ if (sharedDatabasePassword.isPresent() && sharedDatabaseUser.isPresent()) {
+ try {
+ passwordField.setText(new Password(sharedDatabasePassword.get().toCharArray(), sharedDatabaseUser.get()).decrypt());
+ } catch (GeneralSecurityException | UnsupportedEncodingException e) {
+ LOGGER.error("Could not read the password due to decryption problems.", e);
+ }
+ }
+
+ rememberPassword.setSelected(sharedDatabaseRememberPassword);
+ }
+
+ /**
+ * Set up the layout and position the control units in their right place.
+ */
+ private void initLayout() {
+
+ setResizable(false);
+
+ Insets defautInsets = new Insets(4, 15, 4, 4);
+
+ connectionPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), Localization.lang("Connection")));
+ connectionPanel.setLayout(gridBagLayout);
+
+ Set<DBMSType> availableDBMSTypes = DBMSConnection.getAvailableDBMSTypes();
+ DefaultComboBoxModel<DBMSType> comboBoxModel = new DefaultComboBoxModel<>(
+ availableDBMSTypes.toArray(new DBMSType[availableDBMSTypes.size()]));
+
+ dbmsTypeDropDown.setModel(comboBoxModel);
+
+ gridBagConstraints.insets = defautInsets;
+ gridBagConstraints.fill = GridBagConstraints.BOTH;
+ gridBagLayout.setConstraints(connectionPanel, gridBagConstraints);
+
+ //1. column
+ gridBagConstraints.gridx = 0;
+ gridBagConstraints.gridy = 0;
+ connectionPanel.add(databaseTypeLabel, gridBagConstraints);
+
+ gridBagConstraints.gridy = 1;
+ connectionPanel.add(hostPortLabel, gridBagConstraints);
+
+ gridBagConstraints.gridy = 2;
+ connectionPanel.add(databaseLabel, gridBagConstraints);
+
+ gridBagConstraints.gridy = 3;
+ connectionPanel.add(userLabel, gridBagConstraints);
+
+ gridBagConstraints.gridy = 4;
+ connectionPanel.add(passwordLabel, gridBagConstraints);
+
+ // 2. column
+ gridBagConstraints.gridwidth = 2;
+
+ gridBagConstraints.gridx = 1;
+ gridBagConstraints.gridy = 0;
+ connectionPanel.add(dbmsTypeDropDown, gridBagConstraints);
+
+ gridBagConstraints.gridy = 1;
+ gridBagConstraints.gridwidth = 1; // the hostField is smaller than the others.
+ gridBagConstraints.insets = new Insets(4, 15, 4, 0);
+ connectionPanel.add(hostField, gridBagConstraints);
+
+ gridBagConstraints.gridy = 2;
+ gridBagConstraints.gridwidth = 2;
+ gridBagConstraints.insets = defautInsets;
+ connectionPanel.add(databaseField, gridBagConstraints);
+
+ gridBagConstraints.gridy = 3;
+ connectionPanel.add(userField, gridBagConstraints);
+
+ gridBagConstraints.gridy = 4;
+ connectionPanel.add(passwordField, gridBagConstraints);
+
+ gridBagConstraints.gridy = 5;
+ connectionPanel.add(rememberPassword, gridBagConstraints);
+
+ // 3. column
+ gridBagConstraints.gridx = 2;
+ gridBagConstraints.gridy = 1;
+ gridBagConstraints.gridwidth = 1;
+ gridBagConstraints.insets = new Insets(4, 0, 4, 4);
+ connectionPanel.add(portField, gridBagConstraints);
+
+ // help button
+ gridBagConstraints.gridx = 0;
+ gridBagConstraints.gridy = 6;
+ gridBagConstraints.insets = new Insets(10, 10, 0, 0);
+ JPanel helpPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
+ helpPanel.add(helpButton);
+
+ // add panel
+ getContentPane().setLayout(gridBagLayout);
+ gridBagConstraints.gridx = 0;
+ gridBagConstraints.gridy = 0;
+ gridBagConstraints.gridwidth = 1;
+ gridBagConstraints.insets = new Insets(5, 5, 5, 5);
+ gridBagLayout.setConstraints(connectionPanel, gridBagConstraints);
+ getContentPane().add(connectionPanel);
+
+ // filePanel
+ filePanel.setBorder(
+ BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), Localization.lang("File")));
+ filePanel.setLayout(gridBagLayout);
+
+ gridBagConstraints.gridx = 0;
+ gridBagConstraints.gridy = 0;
+ gridBagConstraints.gridwidth = 2;
+
+ filePanel.add(autosaveFile, gridBagConstraints);
+ gridBagConstraints.gridx = 1;
+ gridBagConstraints.gridy = 1;
+ gridBagConstraints.gridwidth = 1;
+ filePanel.add(fileLocationField, gridBagConstraints);
+ gridBagConstraints.gridx = 2;
+ filePanel.add(browseButton, gridBagConstraints);
+
+ gridBagConstraints.gridx = 0;
+ gridBagConstraints.gridy = 1;
+ gridBagConstraints.insets = new Insets(5, 5, 5, 5);
+ gridBagLayout.setConstraints(filePanel, gridBagConstraints);
+ getContentPane().add(filePanel);
+
+ // buttonPanel
+ buttonPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
+
+ buttonPanel.add(connectButton);
+ buttonPanel.add(cancelButton);
+ buttonPanel.add(helpPanel);
+
+ gridBagConstraints.gridy = 2;
+ gridBagConstraints.insets = new Insets(5, 5, 5, 5);
+ gridBagLayout.setConstraints(buttonPanel, gridBagConstraints);
+ getContentPane().add(buttonPanel);
+
+ setModal(true); // Owner window should be disabled while this dialog is opened.
+ }
+
+ /**
+ * Saves the data from this dialog persistently to facilitate the usage.
+ */
+ private void setPreferences() {
+ prefs.setType(dbmsTypeDropDown.getSelectedItem().toString());
+ prefs.setHost(hostField.getText());
+ prefs.setPort(portField.getText());
+ prefs.setName(databaseField.getText());
+ prefs.setUser(userField.getText());
+
+ if (rememberPassword.isSelected()) {
+ try {
+ prefs.setPassword(new Password(passwordField.getPassword(), userField.getText()).encrypt());
+ } catch (GeneralSecurityException | UnsupportedEncodingException e) {
+ LOGGER.error("Could not store the password due to encryption problems.", e);
+ }
+ } else {
+ prefs.clearPassword(); // for the case that the password is already set
+ }
+
+ prefs.setRememberPassword(rememberPassword.isSelected());
+ }
+
+ private boolean isEmptyField(JTextField field) {
+ return field.getText().trim().length() == 0;
+ }
+
+ /**
+ * Checks every required text field for emptiness.
+ */
+ private void checkFields() throws JabRefException {
+ if (isEmptyField(hostField)) {
+ hostField.requestFocus();
+ throw new JabRefException(Localization.lang("Required field \"%0\" is empty.", Localization.lang("Host")));
+ }
+ if (isEmptyField(portField)) {
+ portField.requestFocus();
+ throw new JabRefException(Localization.lang("Required field \"%0\" is empty.", Localization.lang("Port")));
+ }
+ if (isEmptyField(databaseField)) {
+ databaseField.requestFocus();
+ throw new JabRefException(
+ Localization.lang("Required field \"%0\" is empty.", Localization.lang("Database")));
+ }
+ if (isEmptyField(userField)) {
+ userField.requestFocus();
+ throw new JabRefException(Localization.lang("Required field \"%0\" is empty.", Localization.lang("User")));
+ }
+ if (autosaveFile.isSelected() && isEmptyField(fileLocationField)) {
+ fileLocationField.requestFocus();
+ throw new JabRefException(Localization.lang("Please enter a valid file path."));
+ }
+ }
+
+ /**
+ * Sets the connectButton according to the current connection state.
+ */
+ private void setLoadingConnectButtonText(boolean isLoading) {
+ connectButton.setEnabled(!isLoading);
+ if (isLoading) {
+ connectButton.setText(Localization.lang("Connecting..."));
+ } else {
+ connectButton.setText(Localization.lang("Connect"));
+ }
+ }
+
+ /**
+ * Checks whether a database with the given @link {@link DBMSConnectionProperties} is already opened.
+ */
+ private boolean isSharedDatabaseAlreadyPresent() {
+ List<BasePanel> panels = JabRefGUI.getMainFrame().getBasePanelList();
+ return panels.parallelStream().anyMatch(panel -> {
+ BibDatabaseContext context = panel.getBibDatabaseContext();
+ return ((context.getLocation() == DatabaseLocation.SHARED) &&
+ this.connectionProperties.equals(context.getDBMSSynchronizer()
+ .getDBProcessor().getDBMSConnectionProperties()));
+ });
+ }
+
+ private void showFileChooser() {
+ FileDialog dialog = new FileDialog(this);
+ dialog.withExtension(FileExtensions.BIBTEX_DB);
+ dialog.setDefaultExtension(FileExtensions.BIBTEX_DB);
+
+ Optional<Path> path = dialog.showDialogAndGetSelectedFile();
+ path.ifPresent(p -> fileLocationField.setText(p.toString()));
+ }
+
+ private void updateEnableState() {
+ fileLocationField.setEnabled(autosaveFile.isSelected());
+ browseButton.setEnabled(autosaveFile.isSelected());
+ }
+}
diff --git a/src/main/java/net/sf/jabref/gui/shared/MergeSharedEntryDialog.java b/src/main/java/net/sf/jabref/gui/shared/MergeSharedEntryDialog.java
index 33c2350..52173f7 100644
--- a/src/main/java/net/sf/jabref/gui/shared/MergeSharedEntryDialog.java
+++ b/src/main/java/net/sf/jabref/gui/shared/MergeSharedEntryDialog.java
@@ -10,6 +10,7 @@ import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
+import javax.swing.WindowConstants;
import javax.swing.border.EmptyBorder;
import net.sf.jabref.gui.JabRefFrame;
@@ -76,7 +77,7 @@ public class MergeSharedEntryDialog {
buttonPanel.add(cancelButton, BorderLayout.EAST);
mergeDialog.add(buttonPanel, BorderLayout.SOUTH);
- mergeDialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
+ mergeDialog.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
mergeDialog.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
diff --git a/src/main/java/net/sf/jabref/gui/shared/MigrationHelpDialog.java b/src/main/java/net/sf/jabref/gui/shared/MigrationHelpDialog.java
index 35f13d3..427077f 100644
--- a/src/main/java/net/sf/jabref/gui/shared/MigrationHelpDialog.java
+++ b/src/main/java/net/sf/jabref/gui/shared/MigrationHelpDialog.java
@@ -24,7 +24,7 @@ import net.sf.jabref.logic.l10n.Localization;
public class MigrationHelpDialog extends JDialog {
- public MigrationHelpDialog(OpenSharedDatabaseDialog openSharedDatabaseDialog) {
+ public MigrationHelpDialog(ConnectToSharedDatabaseDialog openSharedDatabaseDialog) {
super(openSharedDatabaseDialog, Localization.lang("Migration help information"));
setModal(true);
diff --git a/src/main/java/net/sf/jabref/gui/shared/OpenSharedDatabaseDialog.java b/src/main/java/net/sf/jabref/gui/shared/OpenSharedDatabaseDialog.java
deleted file mode 100644
index 88c63e4..0000000
--- a/src/main/java/net/sf/jabref/gui/shared/OpenSharedDatabaseDialog.java
+++ /dev/null
@@ -1,350 +0,0 @@
-package net.sf.jabref.gui.shared;
-
-import java.awt.FlowLayout;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.Insets;
-import java.awt.event.ActionEvent;
-import java.awt.event.KeyEvent;
-import java.sql.SQLException;
-import java.util.Optional;
-import java.util.Set;
-
-import javax.swing.AbstractAction;
-import javax.swing.Action;
-import javax.swing.BorderFactory;
-import javax.swing.DefaultComboBoxModel;
-import javax.swing.JButton;
-import javax.swing.JComboBox;
-import javax.swing.JComponent;
-import javax.swing.JDialog;
-import javax.swing.JLabel;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JPasswordField;
-import javax.swing.JTextField;
-import javax.swing.KeyStroke;
-
-import net.sf.jabref.BibDatabaseContext;
-import net.sf.jabref.Defaults;
-import net.sf.jabref.Globals;
-import net.sf.jabref.JabRefException;
-import net.sf.jabref.gui.JabRefFrame;
-import net.sf.jabref.gui.help.HelpAction;
-import net.sf.jabref.logic.help.HelpFile;
-import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.model.database.BibDatabaseMode;
-import net.sf.jabref.model.database.DatabaseLocation;
-import net.sf.jabref.shared.DBMSConnectionProperties;
-import net.sf.jabref.shared.DBMSConnector;
-import net.sf.jabref.shared.DBMSType;
-import net.sf.jabref.shared.exception.DatabaseNotSupportedException;
-
-public class OpenSharedDatabaseDialog extends JDialog {
-
- private final JabRefFrame frame;
-
- private final GridBagLayout gridBagLayout = new GridBagLayout();
- private final GridBagConstraints gridBagConstraints = new GridBagConstraints();
- private final JPanel connectionPanel = new JPanel();
- private final JPanel buttonPanel = new JPanel();
-
- private final JLabel databaseTypeLabel = new JLabel(Localization.lang("Database type") + ":");
- private final JLabel hostPortLabel = new JLabel(Localization.lang("Host") + "/" + Localization.lang("Port") + ":");
- private final JLabel databaseLabel = new JLabel(Localization.lang("Database") + ":");
- private final JLabel userLabel = new JLabel(Localization.lang("User") + ":");
- private final JLabel passwordLabel = new JLabel(Localization.lang("Password") + ":");
-
- private final JTextField hostField = new JTextField(12);
- private final JTextField portField = new JTextField(4);
- private final JTextField userField = new JTextField(14);
- private final JTextField databaseField = new JTextField(14);
-
- private final JPasswordField passwordField = new JPasswordField(14);
- private final JComboBox<DBMSType> dbmsTypeDropDown = new JComboBox<>();
-
- private final JButton connectButton = new JButton(Localization.lang("Connect"));
- private final JButton cancelButton = new JButton(Localization.lang("Cancel"));
- private final JButton helpButton = new HelpAction(HelpFile.SQL_DATABASE).getHelpButton();
-
- private static final String SHARED_DATABASE_TYPE = "sharedDatabaseType";
- private static final String SHARED_DATABASE_HOST = "sharedDatabaseHost";
- private static final String SHARED_DATABASE_PORT = "sharedDatabasePort";
- private static final String SHARED_DATABASE_NAME = "sharedDatabaseName";
- private static final String SHARED_DATABASE_USER = "sharedDatabaseUser";
-
- private DBMSConnectionProperties connectionProperties;
- private BibDatabaseContext bibDatabaseContext;
-
- /**
- * @param frame the JabRef Frame
- */
- public OpenSharedDatabaseDialog(JabRefFrame frame) {
- super(frame, Localization.lang("Open shared database"));
- this.frame = frame;
- initLayout();
- applyGlobalPrefs();
- setupActions();
- pack();
- setLocationRelativeTo(frame);
- }
-
- public void openSharedDatabase() {
- setLoadingConnectButtonText(true);
-
- try {
- bibDatabaseContext.getDBSynchronizer().openSharedDatabase(connectionProperties);
- frame.addTab(bibDatabaseContext, true);
- setGlobalPrefs();
- bibDatabaseContext.getDBSynchronizer().registerListener(new SharedDatabaseUIManager(frame));
- frame.output(Localization.lang("Connection_to_%0_server_established.", connectionProperties.getType().toString()));
- dispose();
- return; // setLoadingConnectButtonText(false) should not be reached regularly.
- } catch (ClassNotFoundException exception) {
- JOptionPane.showMessageDialog(OpenSharedDatabaseDialog.this, exception.getMessage(),
- Localization.lang("Driver error"), JOptionPane.ERROR_MESSAGE);
- } catch (SQLException exception) {
- JOptionPane.showMessageDialog(OpenSharedDatabaseDialog.this, exception.getMessage(),
- Localization.lang("Connection error"), JOptionPane.ERROR_MESSAGE);
- } catch (DatabaseNotSupportedException exception) {
- new MigrationHelpDialog(this).setVisible(true);
- }
-
- setLoadingConnectButtonText(false);
- }
-
- /**
- * Defines and sets the different actions up.
- */
- private void setupActions() {
-
- Action openAction = new AbstractAction() {
- @Override
- public void actionPerformed(ActionEvent e) {
- try {
- checkFields();
- BibDatabaseMode selectedMode = Globals.prefs.getDefaultBibDatabaseMode();
-
- bibDatabaseContext = new BibDatabaseContext(new Defaults(selectedMode),
- DatabaseLocation.SHARED);
-
- connectionProperties = new DBMSConnectionProperties();
- connectionProperties.setType((DBMSType) dbmsTypeDropDown.getSelectedItem());
- connectionProperties.setHost(hostField.getText());
- connectionProperties.setPort(Integer.parseInt(portField.getText()));
- connectionProperties.setDatabase(databaseField.getText());
- connectionProperties.setUser(userField.getText());
- connectionProperties.setPassword(new String(passwordField.getPassword())); //JPasswordField.getPassword() does not return a String, but a char array.
-
- openSharedDatabase();
- } catch (JabRefException exception) {
- JOptionPane.showMessageDialog(OpenSharedDatabaseDialog.this, exception.getMessage(),
- Localization.lang("Warning"), JOptionPane.WARNING_MESSAGE);
- }
- }
- };
- connectButton.addActionListener(openAction);
- cancelButton.addActionListener(e -> dispose());
-
- /**
- * Set up a listener which updates the default port number once the selection in dbmsTypeDropDown has changed.
- */
- Action dbmsTypeDropDownAction = new AbstractAction() {
- @Override
- public void actionPerformed(ActionEvent e) {
- portField.setText(Integer.toString(((DBMSType) dbmsTypeDropDown.getSelectedItem()).getDefaultPort()));
- }
- };
- dbmsTypeDropDown.addActionListener(dbmsTypeDropDownAction);
-
- // Add enter button action listener
- connectButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0),
- "Enter_pressed");
- connectButton.getActionMap().put("Enter_pressed", openAction);
-
- }
-
- /**
- * Fetches possibly saved data and configures the control elements respectively.
- */
- private void applyGlobalPrefs() {
- Optional<String> sharedDatabaseType = Globals.prefs.getAsOptional(SHARED_DATABASE_TYPE);
- Optional<String> sharedDatabaseHost = Globals.prefs.getAsOptional(SHARED_DATABASE_HOST);
- Optional<String> sharedDatabasePort = Globals.prefs.getAsOptional(SHARED_DATABASE_PORT);
- Optional<String> sharedDatabaseName = Globals.prefs.getAsOptional(SHARED_DATABASE_NAME);
- Optional<String> sharedDatabaseUser = Globals.prefs.getAsOptional(SHARED_DATABASE_USER);
-
- if (sharedDatabaseType.isPresent()) {
- Optional<DBMSType> dbmsType = DBMSType.fromString(sharedDatabaseType.get());
- if (dbmsType.isPresent()) {
- dbmsTypeDropDown.setSelectedItem(dbmsType.get());
- }
- }
-
- if (sharedDatabaseHost.isPresent()) {
- hostField.setText(sharedDatabaseHost.get());
- }
-
- if (sharedDatabasePort.isPresent()) {
- portField.setText(sharedDatabasePort.get());
- } else {
- portField.setText(Integer.toString(((DBMSType) dbmsTypeDropDown.getSelectedItem()).getDefaultPort()));
- }
-
- if (sharedDatabaseName.isPresent()) {
- databaseField.setText(sharedDatabaseName.get());
- }
-
- if (sharedDatabaseUser.isPresent()) {
- userField.setText(sharedDatabaseUser.get());
- }
- }
-
- /**
- * Set up the layout and position the control units in their right place.
- */
- private void initLayout() {
-
- setResizable(false);
-
- Insets defautInsets = new Insets(4, 15, 4, 4);
-
- connectionPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), Localization.lang("Connection")));
- connectionPanel.setLayout(gridBagLayout);
-
- Set<DBMSType> availableDBMSTypes = DBMSConnector.getAvailableDBMSTypes();
- DefaultComboBoxModel<DBMSType> comboBoxModel = new DefaultComboBoxModel<>(
- availableDBMSTypes.toArray(new DBMSType[availableDBMSTypes.size()]));
-
- dbmsTypeDropDown.setModel(comboBoxModel);
-
- gridBagConstraints.insets = defautInsets;
- gridBagConstraints.fill = GridBagConstraints.BOTH;
- gridBagLayout.setConstraints(connectionPanel, gridBagConstraints);
-
- //1. column
- gridBagConstraints.gridx = 0;
- gridBagConstraints.gridy = 0;
- connectionPanel.add(databaseTypeLabel, gridBagConstraints);
-
- gridBagConstraints.gridy = 1;
- connectionPanel.add(hostPortLabel, gridBagConstraints);
-
- gridBagConstraints.gridy = 2;
- connectionPanel.add(databaseLabel, gridBagConstraints);
-
- gridBagConstraints.gridy = 3;
- connectionPanel.add(userLabel, gridBagConstraints);
-
- gridBagConstraints.gridy = 4;
- connectionPanel.add(passwordLabel, gridBagConstraints);
-
- // 2. column
- gridBagConstraints.gridwidth = 2;
-
- gridBagConstraints.gridx = 1;
- gridBagConstraints.gridy = 0;
- connectionPanel.add(dbmsTypeDropDown, gridBagConstraints);
-
- gridBagConstraints.gridy = 1;
- gridBagConstraints.gridwidth = 1; // the hostField is smaller than the others.
- gridBagConstraints.insets = new Insets(4, 15, 4, 0);
- connectionPanel.add(hostField, gridBagConstraints);
-
- gridBagConstraints.gridy = 2;
- gridBagConstraints.gridwidth = 2;
- gridBagConstraints.insets = defautInsets;
- connectionPanel.add(databaseField, gridBagConstraints);
-
- gridBagConstraints.gridy = 3;
- connectionPanel.add(userField, gridBagConstraints);
-
- gridBagConstraints.gridy = 4;
- connectionPanel.add(passwordField, gridBagConstraints);
-
- // 3. column
- gridBagConstraints.gridx = 2;
- gridBagConstraints.gridy = 1;
- gridBagConstraints.gridwidth = 1;
- gridBagConstraints.insets = new Insets(4, 0, 4, 4);
- connectionPanel.add(portField, gridBagConstraints);
-
- // help button
- gridBagConstraints.gridx = 0;
- gridBagConstraints.gridy = 5;
- gridBagConstraints.insets = new Insets(10, 10, 0, 0);
- JPanel helpPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
- helpPanel.add(helpButton);
- connectionPanel.add(helpPanel, gridBagConstraints);
-
- // control buttons
- gridBagConstraints.gridx = 1;
- gridBagConstraints.gridwidth = 2;
- buttonPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
- buttonPanel.add(connectButton);
- buttonPanel.add(cancelButton);
- connectionPanel.add(buttonPanel, gridBagConstraints);
-
- // add panel
- getContentPane().setLayout(gridBagLayout);
- gridBagConstraints.gridx = 0;
- gridBagConstraints.gridy = 0;
- gridBagConstraints.gridwidth = 1;
- gridBagConstraints.insets = new Insets(5, 5, 5, 5);
- gridBagLayout.setConstraints(connectionPanel, gridBagConstraints);
- getContentPane().add(connectionPanel);
-
- setModal(true); // Owner window should be disabled while this dialog is opened.
- }
-
- /**
- * Saves the data from this dialog persistently to facilitate the usage.
- */
- public void setGlobalPrefs() {
- Globals.prefs.put(SHARED_DATABASE_TYPE, ((DBMSType) dbmsTypeDropDown.getSelectedItem()).toString());
- Globals.prefs.put(SHARED_DATABASE_HOST, hostField.getText());
- Globals.prefs.put(SHARED_DATABASE_PORT, portField.getText());
- Globals.prefs.put(SHARED_DATABASE_NAME, databaseField.getText());
- Globals.prefs.put(SHARED_DATABASE_USER, userField.getText());
- }
-
- private boolean isEmptyField(JTextField field) {
- return field.getText().trim().length() == 0;
- }
-
- /**
- * Checks every required text field for emptiness.
- */
- private void checkFields() throws JabRefException {
- if (isEmptyField(hostField)) {
- hostField.requestFocus();
- throw new JabRefException(Localization.lang("Required_field_\"%0\"_is_empty.", Localization.lang("Host")));
- }
- if (isEmptyField(portField)) {
- portField.requestFocus();
- throw new JabRefException(Localization.lang("Required_field_\"%0\"_is_empty.", Localization.lang("Port")));
- }
- if (isEmptyField(databaseField)) {
- databaseField.requestFocus();
- throw new JabRefException(
- Localization.lang("Required_field_\"%0\"_is_empty.", Localization.lang("Database")));
- }
- if (isEmptyField(userField)) {
- userField.requestFocus();
- throw new JabRefException(Localization.lang("Required_field_\"%0\"_is_empty.", Localization.lang("User")));
- }
- }
-
- /**
- * Sets the connectButton according to the current connection state.
- */
- private void setLoadingConnectButtonText(boolean isLoading) {
- connectButton.setEnabled(!isLoading);
- if (isLoading) {
- connectButton.setText(Localization.lang("Connecting..."));
- } else {
- connectButton.setText(Localization.lang("Connect"));
- }
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/gui/shared/SharedDatabaseUIManager.java b/src/main/java/net/sf/jabref/gui/shared/SharedDatabaseUIManager.java
index cadc64f..a81e0aa 100644
--- a/src/main/java/net/sf/jabref/gui/shared/SharedDatabaseUIManager.java
+++ b/src/main/java/net/sf/jabref/gui/shared/SharedDatabaseUIManager.java
@@ -1,26 +1,43 @@
package net.sf.jabref.gui.shared;
+import java.sql.SQLException;
+import java.util.Objects;
+import java.util.Optional;
+
import javax.swing.JOptionPane;
+import javax.swing.SwingUtilities;
+import net.sf.jabref.Globals;
+import net.sf.jabref.JabRefGUI;
+import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.gui.JabRefFrame;
+import net.sf.jabref.gui.entryeditor.EntryEditor;
+import net.sf.jabref.gui.undo.UndoableRemoveEntry;
+import net.sf.jabref.logic.importer.ParserResult;
import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.Defaults;
+import net.sf.jabref.model.database.BibDatabaseContext;
+import net.sf.jabref.model.database.BibDatabaseMode;
import net.sf.jabref.model.database.DatabaseLocation;
-import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.shared.DBMSConnectionProperties;
import net.sf.jabref.shared.DBMSSynchronizer;
import net.sf.jabref.shared.event.ConnectionLostEvent;
import net.sf.jabref.shared.event.SharedEntryNotPresentEvent;
import net.sf.jabref.shared.event.UpdateRefusedEvent;
+import net.sf.jabref.shared.exception.DatabaseNotSupportedException;
+import net.sf.jabref.shared.exception.InvalidDBMSConnectionPropertiesException;
+import net.sf.jabref.shared.exception.NotASharedDatabaseException;
+import net.sf.jabref.shared.prefs.SharedDatabasePreferences;
import com.google.common.eventbus.Subscribe;
public class SharedDatabaseUIManager {
private final JabRefFrame jabRefFrame;
- private final DBMSSynchronizer dbmsSynchronizer;
+ private DBMSSynchronizer dbmsSynchronizer;
public SharedDatabaseUIManager(JabRefFrame jabRefFrame) {
this.jabRefFrame = jabRefFrame;
- this.dbmsSynchronizer = jabRefFrame.getCurrentBasePanel().getBibDatabaseContext().getDBSynchronizer();
}
@Subscribe
@@ -38,10 +55,10 @@ public class SharedDatabaseUIManager {
if (answer == 0) {
jabRefFrame.closeCurrentTab();
- OpenSharedDatabaseDialog openSharedDatabaseDialog = new OpenSharedDatabaseDialog(jabRefFrame);
- openSharedDatabaseDialog.setVisible(true);
+ ConnectToSharedDatabaseDialog connectToSharedDatabaseDialog = new ConnectToSharedDatabaseDialog(jabRefFrame);
+ connectToSharedDatabaseDialog.setVisible(true);
} else if (answer == 1) {
- connectionLostEvent.getBibDatabaseContext().updateDatabaseLocation(DatabaseLocation.LOCAL);
+ connectionLostEvent.getBibDatabaseContext().convertToLocalDatabase();
jabRefFrame.refreshTitleAndTabs();
jabRefFrame.updateEnabledState();
jabRefFrame.output(Localization.lang("Working offline."));
@@ -61,23 +78,68 @@ public class SharedDatabaseUIManager {
}
@Subscribe
- public void listen(SharedEntryNotPresentEvent sharedEntryNotPresentEvent) {
- BibEntry bibEntry = sharedEntryNotPresentEvent.getBibEntry();
+ public void listen(SharedEntryNotPresentEvent event) {
+ BasePanel panel = jabRefFrame.getCurrentBasePanel();
+ EntryEditor entryEditor = panel.getCurrentEditor();
- String[] options = {Localization.lang("Keep"), Localization.lang("Delete")};
+ panel.getUndoManager().addEdit(new UndoableRemoveEntry(panel.getDatabase(), event.getBibEntry(), panel));
- int answer = JOptionPane.showOptionDialog(jabRefFrame,
- Localization.lang("The BibEntry you currently work on has been deleted on the shared side. "
- + "Hit \"Keep\" to recover the entry.") + "\n\n",
- Localization.lang("Update refused"), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE,
- null, options, options[0]);
+ if (Objects.nonNull(entryEditor) && (entryEditor.getEntry() == event.getBibEntry())) {
+ JOptionPane.showMessageDialog(jabRefFrame,
+ Localization.lang("The BibEntry you currently work on has been deleted on the shared side.")
+ + "\n" + Localization.lang("You can restore the entry using the \"Undo\" operation."),
+ Localization.lang("Shared entry is no longer present"), JOptionPane.INFORMATION_MESSAGE);
- if (answer == 0) {
- dbmsSynchronizer.getDBProcessor().insertEntry(bibEntry);
- } else if (answer == 1) {
- jabRefFrame.getCurrentBasePanel().hideBottomComponent();
+ SwingUtilities.invokeLater(() -> panel.hideBottomComponent());
}
- dbmsSynchronizer.pullChanges();
}
+ /**
+ * Opens a new shared database tab with the given {@link DBMSConnectionProperties}.
+ *
+ * @param dbmsConnectionProperties Connection data
+ * @param raiseTab If <code>true</code> the new tab gets selected.
+ * @return BasePanel which also used by {@link SaveDatabaseAction}
+ */
+ public BasePanel openNewSharedDatabaseTab(DBMSConnectionProperties dbmsConnectionProperties)
+ throws SQLException, DatabaseNotSupportedException, InvalidDBMSConnectionPropertiesException {
+ JabRefFrame frame = JabRefGUI.getMainFrame();
+ BibDatabaseMode selectedMode = Globals.prefs.getDefaultBibDatabaseMode();
+ BibDatabaseContext bibDatabaseContext = new BibDatabaseContext(new Defaults(selectedMode), DatabaseLocation.SHARED,
+ Globals.prefs.getKeywordDelimiter(), Globals.prefs.getKeyPattern());
+
+ dbmsSynchronizer = bibDatabaseContext.getDBMSSynchronizer();
+ dbmsSynchronizer.openSharedDatabase(dbmsConnectionProperties);
+ dbmsSynchronizer.registerListener(this);
+ frame.output(Localization.lang("Connection_to_%0_server_established.", dbmsConnectionProperties.getType().toString()));
+ return frame.addTab(bibDatabaseContext, true);
+ }
+
+ public void openSharedDatabaseFromParserResult(ParserResult parserResult)
+ throws SQLException, DatabaseNotSupportedException, InvalidDBMSConnectionPropertiesException,
+ NotASharedDatabaseException {
+
+ Optional<String> sharedDatabaseIDOptional = parserResult.getDatabase().getSharedDatabaseID();
+
+ if (!sharedDatabaseIDOptional.isPresent()) {
+ throw new NotASharedDatabaseException();
+ }
+
+ String sharedDatabaseID = sharedDatabaseIDOptional.get();
+ DBMSConnectionProperties dbmsConnectionProperties = new DBMSConnectionProperties(new SharedDatabasePreferences(sharedDatabaseID));
+
+ JabRefFrame frame = JabRefGUI.getMainFrame();
+ BibDatabaseMode selectedMode = Globals.prefs.getDefaultBibDatabaseMode();
+ BibDatabaseContext bibDatabaseContext = new BibDatabaseContext(new Defaults(selectedMode), DatabaseLocation.SHARED,
+ Globals.prefs.getKeywordDelimiter(), Globals.prefs.getKeyPattern());
+
+ bibDatabaseContext.getDatabase().setSharedDatabaseID(sharedDatabaseID);
+ bibDatabaseContext.setDatabaseFile(parserResult.getDatabaseContext().getDatabaseFile().orElse(null));
+
+ dbmsSynchronizer = bibDatabaseContext.getDBMSSynchronizer();
+ dbmsSynchronizer.openSharedDatabase(dbmsConnectionProperties);
+ dbmsSynchronizer.registerListener(this);
+ parserResult.setDatabaseContext(bibDatabaseContext);
+ frame.output(Localization.lang("Connection_to_%0_server_established.", dbmsConnectionProperties.getType().toString()));
+ }
}
diff --git a/src/main/java/net/sf/jabref/gui/specialfields/SpecialFieldAction.java b/src/main/java/net/sf/jabref/gui/specialfields/SpecialFieldAction.java
new file mode 100644
index 0000000..0d92b91
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/specialfields/SpecialFieldAction.java
@@ -0,0 +1,105 @@
+package net.sf.jabref.gui.specialfields;
+
+import java.util.List;
+import java.util.Objects;
+
+import net.sf.jabref.Globals;
+import net.sf.jabref.gui.JabRefFrame;
+import net.sf.jabref.gui.actions.BaseAction;
+import net.sf.jabref.gui.undo.NamedCompound;
+import net.sf.jabref.gui.undo.UndoableFieldChange;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.logic.specialfields.SpecialFieldsUtils;
+import net.sf.jabref.model.FieldChange;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.specialfields.SpecialField;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class SpecialFieldAction implements BaseAction {
+
+ private final JabRefFrame frame;
+ private final SpecialField specialField;
+ private final String value;
+ private final boolean nullFieldIfValueIsTheSame;
+ private final String undoText;
+
+ private static final Log LOGGER = LogFactory.getLog(SpecialFieldAction.class);
+
+
+ /**
+ * @param nullFieldIfValueIsTheSame - false also causes that doneTextPattern has two place holders %0 for the value and %1 for the sum of entries
+ */
+ public SpecialFieldAction(
+ JabRefFrame frame,
+ SpecialField specialField,
+ String value,
+ boolean nullFieldIfValueIsTheSame,
+ String undoText) {
+ this.frame = frame;
+ this.specialField = specialField;
+ this.value = value;
+ this.nullFieldIfValueIsTheSame = nullFieldIfValueIsTheSame;
+ this.undoText = undoText;
+ }
+
+ @Override
+ public void action() {
+ try {
+ List<BibEntry> bes = frame.getCurrentBasePanel().getSelectedEntries();
+ if ((bes == null) || bes.isEmpty()) {
+ return;
+ }
+ NamedCompound ce = new NamedCompound(undoText);
+ for (BibEntry be : bes) {
+ // if (value==null) and then call nullField has been omitted as updatefield also handles value==null
+ List<FieldChange> changes = SpecialFieldsUtils.updateField(specialField, value, be, nullFieldIfValueIsTheSame, Globals.prefs.isKeywordSyncEnabled(), Globals.prefs.getKeywordDelimiter());
+ for(FieldChange change: changes) {
+ ce.addEdit(new UndoableFieldChange(change));
+ }
+ }
+ ce.end();
+ if (ce.hasEdits()) {
+ frame.getCurrentBasePanel().getUndoManager().addEdit(ce);
+ frame.getCurrentBasePanel().markBaseChanged();
+ frame.getCurrentBasePanel().updateEntryEditorIfShowing();
+ String outText;
+ if (nullFieldIfValueIsTheSame || value == null) {
+ outText = getTextDone(specialField, Integer.toString(bes.size()));
+ } else {
+ outText = getTextDone(specialField, value, Integer.toString(bes.size()));
+ }
+ frame.output(outText);
+ } else {
+ // if user does not change anything with his action, we do not do anything either
+ // even no output message
+ }
+ } catch (Throwable ex) {
+ LOGGER.error("Problem setting special fields", ex);
+ }
+ }
+
+ private String getTextDone(SpecialField field, String... params) {
+ Objects.requireNonNull(params);
+
+ SpecialFieldViewModel viewModel = new SpecialFieldViewModel(field);
+
+ if (field.isSingleValueField() && (params.length == 1) && (params[0] != null)) {
+ // Single value fields can be toggled only
+ return Localization.lang("Toggled '%0' for %1 entries", viewModel.getLocalization(), params[0]);
+ } else if (!field.isSingleValueField() && (params.length == 2) && (params[0] != null) && (params[1] != null)) {
+ // setting a multi value special field - the setted value is displayed, too
+ String[] allParams = {viewModel.getLocalization(), params[0], params[1]};
+ return Localization.lang("Set '%0' to '%1' for %2 entries", allParams);
+ } else if (!field.isSingleValueField() && (params.length == 1) && (params[0] != null)) {
+ // clearing a multi value specialfield
+ return Localization.lang("Cleared '%0' for %1 entries", viewModel.getLocalization(), params[0]);
+ } else {
+ // invalid usage
+ LOGGER.info("Creation of special field status change message failed: illegal argument combination.");
+ return "";
+ }
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/gui/specialfields/SpecialFieldDatabaseChangeListener.java b/src/main/java/net/sf/jabref/gui/specialfields/SpecialFieldDatabaseChangeListener.java
new file mode 100644
index 0000000..4a81131
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/specialfields/SpecialFieldDatabaseChangeListener.java
@@ -0,0 +1,44 @@
+package net.sf.jabref.gui.specialfields;
+
+import java.util.List;
+
+import net.sf.jabref.Globals;
+import net.sf.jabref.gui.undo.NamedCompound;
+import net.sf.jabref.gui.undo.UndoableFieldChange;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.logic.specialfields.SpecialFieldsUtils;
+import net.sf.jabref.model.FieldChange;
+import net.sf.jabref.model.database.event.EntryAddedEvent;
+import net.sf.jabref.model.entry.BibEntry;
+
+import com.google.common.eventbus.Subscribe;
+
+public class SpecialFieldDatabaseChangeListener {
+
+ private static SpecialFieldDatabaseChangeListener INSTANCE;
+
+ public static SpecialFieldDatabaseChangeListener getInstance() {
+ if (SpecialFieldDatabaseChangeListener.INSTANCE == null) {
+ SpecialFieldDatabaseChangeListener.INSTANCE = new SpecialFieldDatabaseChangeListener();
+ }
+ return SpecialFieldDatabaseChangeListener.INSTANCE;
+ }
+
+ @Subscribe
+ public void listen(EntryAddedEvent event) {
+ if (Globals.prefs.isKeywordSyncEnabled()) {
+ final BibEntry entry = event.getBibEntry();
+ // NamedCompount code similar to SpecialFieldUpdateListener
+ NamedCompound nc = new NamedCompound(Localization.lang("Synchronized special fields based on keywords"));
+ List<FieldChange> changes = SpecialFieldsUtils.syncSpecialFieldsFromKeywords(entry, Globals.prefs.getKeywordDelimiter());
+ for(FieldChange change: changes) {
+ nc.addEdit(new UndoableFieldChange(change));
+ }
+
+ // Don't insert the compound into the undoManager,
+ // it would be added before the component which undoes the insertion of the entry and creates heavy problems
+ // (which prohibits the undo the deleting multiple entries)
+ }
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/gui/specialfields/SpecialFieldDropDown.java b/src/main/java/net/sf/jabref/gui/specialfields/SpecialFieldDropDown.java
new file mode 100644
index 0000000..af62c01
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/specialfields/SpecialFieldDropDown.java
@@ -0,0 +1,102 @@
+package net.sf.jabref.gui.specialfields;
+
+import java.awt.Dimension;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.JButton;
+import javax.swing.JMenuItem;
+import javax.swing.JPopupMenu;
+
+import net.sf.jabref.gui.BasePanel;
+import net.sf.jabref.gui.JabRefFrame;
+import net.sf.jabref.logic.util.OS;
+import net.sf.jabref.model.entry.specialfields.SpecialField;
+import net.sf.jabref.model.entry.specialfields.SpecialFieldValue;
+
+import com.jgoodies.looks.HeaderStyle;
+import com.jgoodies.looks.Options;
+
+
+public class SpecialFieldDropDown {
+
+ public static JButton generateSpecialFieldButtonWithDropDown(SpecialField field, JabRefFrame frame) {
+ Dimension buttonDim = new Dimension(23, 23);
+ SpecialFieldViewModel viewModel = new SpecialFieldViewModel(field);
+ JButton button = new JButton(viewModel.getRepresentingIcon());
+ button.setToolTipText(viewModel.getLocalization());
+ button.setPreferredSize(buttonDim);
+ if (!OS.OS_X) {
+ button.setMargin(new Insets(1, 0, 2, 0));
+ }
+ button.setBorder(null);
+ button.setBorderPainted(false);
+ button.setRolloverEnabled(true);
+ button.setOpaque(false);
+ button.setBounds(0, 0, buttonDim.width, buttonDim.height);
+ button.setSize(buttonDim);
+ button.setMinimumSize(buttonDim);
+ button.setMaximumSize(buttonDim);
+ button.putClientProperty(Options.HEADER_STYLE_KEY, HeaderStyle.BOTH);
+ button.addActionListener(new MenuButtonActionListener(field, frame, button, buttonDim));
+ return button;
+ }
+
+
+ private static class MenuButtonActionListener implements ActionListener {
+
+ private JPopupMenu popup;
+ private final Dimension dim;
+ private final JabRefFrame frame;
+ private final SpecialField field;
+ private final JButton button;
+
+
+ public MenuButtonActionListener(SpecialField field, JabRefFrame frame, JButton button, Dimension dim) {
+ this.field = field;
+ this.dim = dim;
+ this.frame = frame;
+ this.button = button;
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (popup == null) {
+ popup = new JPopupMenu();
+ for (SpecialFieldValue val : field.getValues()) {
+ SpecialFieldValueViewModel viewModel = new SpecialFieldValueViewModel(val);
+ JMenuItem item = new JMenuItem(viewModel.getSpecialFieldValueIcon());
+ item.setText(viewModel.getMenuString());
+ item.setToolTipText(viewModel.getToolTipText());
+ item.addActionListener(new PopupitemActionListener(frame.getCurrentBasePanel(), new SpecialFieldValueViewModel(val).getActionName()));
+ item.setMargin(new Insets(0, 0, 0, 0));
+ popup.add(item);
+ }
+ }
+ popup.show(button, 0, dim.height);
+ }
+
+
+ private class PopupitemActionListener implements ActionListener {
+
+ private final BasePanel panel;
+ private final String actionName;
+
+
+ public PopupitemActionListener(BasePanel panel, String actionName) {
+ this.panel = panel;
+ this.actionName = actionName;
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ panel.runCommand(actionName);
+ popup.setVisible(false);
+ }
+
+ }
+
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/gui/specialfields/SpecialFieldMenuAction.java b/src/main/java/net/sf/jabref/gui/specialfields/SpecialFieldMenuAction.java
new file mode 100644
index 0000000..762d480
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/specialfields/SpecialFieldMenuAction.java
@@ -0,0 +1,27 @@
+package net.sf.jabref.gui.specialfields;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+
+import net.sf.jabref.gui.JabRefFrame;
+
+public class SpecialFieldMenuAction extends AbstractAction {
+
+ private final JabRefFrame frame;
+ private final String actionName;
+
+
+ public SpecialFieldMenuAction(SpecialFieldValueViewModel val, JabRefFrame frame) {
+ super(val.getMenuString(), val.getSpecialFieldValueIcon());
+ this.frame = frame;
+ this.actionName = val.getActionName();
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent evt) {
+ if (frame.getCurrentBasePanel() != null) {
+ frame.getCurrentBasePanel().runCommand(actionName);
+ }
+ }
+}
diff --git a/src/main/java/net/sf/jabref/gui/specialfields/SpecialFieldUpdateListener.java b/src/main/java/net/sf/jabref/gui/specialfields/SpecialFieldUpdateListener.java
new file mode 100644
index 0000000..07a89c8
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/specialfields/SpecialFieldUpdateListener.java
@@ -0,0 +1,54 @@
+package net.sf.jabref.gui.specialfields;
+
+import javax.swing.SwingUtilities;
+
+import net.sf.jabref.Globals;
+import net.sf.jabref.JabRefGUI;
+import net.sf.jabref.logic.specialfields.SpecialFieldsUtils;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldName;
+import net.sf.jabref.model.entry.event.FieldChangedEvent;
+import net.sf.jabref.model.entry.specialfields.SpecialField;
+
+import com.google.common.eventbus.Subscribe;
+
+/**
+ * Listener triggering
+ * * an update of keywords if special field has been updated
+ * * an update of special fields if keywords have been updated
+ */
+public class SpecialFieldUpdateListener {
+
+ private static SpecialFieldUpdateListener INSTANCE;
+
+ @Subscribe
+ public void listen(FieldChangedEvent fieldChangedEvent) {
+ final BibEntry entry = fieldChangedEvent.getBibEntry();
+ final String fieldName = fieldChangedEvent.getFieldName();
+ // Source editor cycles through all entries
+ // if we immediately updated the fields, the entry editor would detect a subsequent change as a user change
+ // and re-fire this event
+ // e.g., "keyword = {prio1}, priority = {prio2}" and a change at keyword to prio3 would not succeed.
+ SwingUtilities.invokeLater(() -> {
+ if (FieldName.KEYWORDS.equals(fieldName)) {
+ SpecialFieldsUtils.syncSpecialFieldsFromKeywords(entry, Globals.prefs.getKeywordDelimiter());
+ SwingUtilities
+ .invokeLater(() -> JabRefGUI.getMainFrame().getCurrentBasePanel().updateEntryEditorIfShowing());
+ } else {
+ if (SpecialField.isSpecialField(fieldName)) {
+ SpecialFieldsUtils.syncKeywordsFromSpecialFields(entry, Globals.prefs.isKeywordSyncEnabled(), Globals.prefs.getKeywordDelimiter());
+ SwingUtilities.invokeLater(
+ () -> JabRefGUI.getMainFrame().getCurrentBasePanel().updateEntryEditorIfShowing());
+ }
+ }
+ });
+ }
+
+ public static SpecialFieldUpdateListener getInstance() {
+ if (SpecialFieldUpdateListener.INSTANCE == null) {
+ SpecialFieldUpdateListener.INSTANCE = new SpecialFieldUpdateListener();
+ }
+ return SpecialFieldUpdateListener.INSTANCE;
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/gui/specialfields/SpecialFieldValueViewModel.java b/src/main/java/net/sf/jabref/gui/specialfields/SpecialFieldValueViewModel.java
new file mode 100644
index 0000000..7ee3de1
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/specialfields/SpecialFieldValueViewModel.java
@@ -0,0 +1,187 @@
+package net.sf.jabref.gui.specialfields;
+
+import java.util.Objects;
+
+import javax.swing.Icon;
+import javax.swing.JLabel;
+
+import net.sf.jabref.gui.IconTheme;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.entry.specialfields.SpecialFieldValue;
+
+public class SpecialFieldValueViewModel {
+
+ private final SpecialFieldValue value;
+
+ public SpecialFieldValueViewModel(SpecialFieldValue value){
+ Objects.requireNonNull(value);
+
+ this.value = value;
+ }
+
+ public Icon getSpecialFieldValueIcon() {
+
+ switch (value) {
+ case PRINTED:
+ return IconTheme.JabRefIcon.PRINTED.getSmallIcon();
+ case CLEAR_PRIORITY:
+ return null;
+ case PRIORITY_HIGH:
+ return IconTheme.JabRefIcon.PRIORITY_HIGH.getSmallIcon();
+ case PRIORITY_MEDIUM:
+ return IconTheme.JabRefIcon.PRIORITY_MEDIUM.getSmallIcon();
+ case PRIORITY_LOW:
+ return IconTheme.JabRefIcon.PRIORITY_LOW.getSmallIcon();
+ case QUALITY_ASSURED:
+ return IconTheme.JabRefIcon.QUALITY_ASSURED.getSmallIcon();
+ case CLEAR_RANK:
+ return null;
+ case RANK_1:
+ return IconTheme.JabRefIcon.RANK1.getSmallIcon();
+ case RANK_2:
+ return IconTheme.JabRefIcon.RANK2.getSmallIcon();
+ case RANK_3:
+ return IconTheme.JabRefIcon.RANK3.getSmallIcon();
+ case RANK_4:
+ return IconTheme.JabRefIcon.RANK4.getSmallIcon();
+ case RANK_5:
+ return IconTheme.JabRefIcon.RANK5.getSmallIcon();
+ case CLEAR_READ_STATUS:
+ return null;
+ case READ:
+ return IconTheme.JabRefIcon.READ_STATUS_READ.getSmallIcon();
+ case SKIMMED:
+ return IconTheme.JabRefIcon.READ_STATUS_SKIMMED.getSmallIcon();
+ case RELEVANT:
+ return IconTheme.JabRefIcon.RELEVANCE.getSmallIcon();
+ default:
+ throw new IllegalArgumentException("There is no icon mapping for special field value " + value);
+ }
+ }
+
+ public JLabel createSpecialFieldValueLabel() {
+ JLabel label = new JLabel(getSpecialFieldValueIcon());
+ label.setToolTipText(getToolTipText());
+ return label;
+ }
+
+ public String getMenuString() {
+
+ switch(value){
+ case PRINTED:
+ return Localization.lang("Toggle print status");
+ case CLEAR_PRIORITY:
+ return Localization.lang("Clear priority");
+ case PRIORITY_HIGH:
+ return Localization.lang("Set priority to high");
+ case PRIORITY_MEDIUM:
+ return Localization.lang("Set priority to medium");
+ case PRIORITY_LOW:
+ return Localization.lang("Set priority to low");
+ case QUALITY_ASSURED:
+ return Localization.lang("Toggle quality assured");
+ case CLEAR_RANK:
+ return Localization.lang("Clear rank");
+ case RANK_1:
+ return "";
+ case RANK_2:
+ return "";
+ case RANK_3:
+ return "";
+ case RANK_4:
+ return "";
+ case RANK_5:
+ return "";
+ case CLEAR_READ_STATUS:
+ return Localization.lang("Clear read status");
+ case READ:
+ return Localization.lang("Set read status to read");
+ case SKIMMED:
+ return Localization.lang("Set read status to skimmed");
+ case RELEVANT:
+ return Localization.lang("Toggle relevance");
+ default:
+ throw new IllegalArgumentException("There is no tooltip localization for special field value " + value);
+ }
+ }
+
+ public String getToolTipText() {
+
+ switch(value){
+ case PRINTED:
+ return Localization.lang("Toggle print status");
+ case CLEAR_PRIORITY:
+ return Localization.lang("No priority information");
+ case PRIORITY_HIGH:
+ return Localization.lang("Priority high");
+ case PRIORITY_MEDIUM:
+ return Localization.lang("Priority medium");
+ case PRIORITY_LOW:
+ return Localization.lang("Priority low");
+ case QUALITY_ASSURED:
+ return Localization.lang("Toggle quality assured");
+ case CLEAR_RANK:
+ return Localization.lang("No rank information");
+ case RANK_1:
+ return Localization.lang("One star");
+ case RANK_2:
+ return Localization.lang("Two stars");
+ case RANK_3:
+ return Localization.lang("Three stars");
+ case RANK_4:
+ return Localization.lang("Four stars");
+ case RANK_5:
+ return Localization.lang("Five stars");
+ case CLEAR_READ_STATUS:
+ return Localization.lang("No read status information");
+ case READ:
+ return Localization.lang("Read status read");
+ case SKIMMED:
+ return Localization.lang("Read status skimmed");
+ case RELEVANT:
+ return Localization.lang("Toggle relevance");
+ default:
+ throw new IllegalArgumentException("There is no tooltip localization for special field value " + value);
+ }
+ }
+
+ public String getActionName() {
+
+ switch(value){
+ case PRINTED:
+ return "togglePrinted";
+ case CLEAR_PRIORITY:
+ return "clearPriority";
+ case PRIORITY_HIGH:
+ return "setPriority1";
+ case PRIORITY_MEDIUM:
+ return "setPriority2";
+ case PRIORITY_LOW:
+ return "setPriority3";
+ case QUALITY_ASSURED:
+ return "toggleQualityAssured";
+ case CLEAR_RANK:
+ return "clearRank";
+ case RANK_1:
+ return "setRank1";
+ case RANK_2:
+ return "setRank2";
+ case RANK_3:
+ return "setRank3";
+ case RANK_4:
+ return "setRank4";
+ case RANK_5:
+ return "setRank5";
+ case CLEAR_READ_STATUS:
+ return "clearReadStatus";
+ case READ:
+ return "setReadStatusToRead";
+ case SKIMMED:
+ return "setReadStatusToSkimmed";
+ case RELEVANT:
+ return "toggleRelevance";
+ default:
+ throw new IllegalArgumentException("There is no action name for special field value " + value);
+ }
+ }
+}
diff --git a/src/main/java/net/sf/jabref/gui/specialfields/SpecialFieldViewModel.java b/src/main/java/net/sf/jabref/gui/specialfields/SpecialFieldViewModel.java
new file mode 100644
index 0000000..85e4b63
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/specialfields/SpecialFieldViewModel.java
@@ -0,0 +1,69 @@
+package net.sf.jabref.gui.specialfields;
+
+import java.util.Objects;
+
+import javax.swing.Icon;
+
+import net.sf.jabref.gui.IconTheme;
+import net.sf.jabref.gui.JabRefFrame;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.entry.specialfields.SpecialField;
+import net.sf.jabref.model.entry.specialfields.SpecialFieldValue;
+
+
+public class SpecialFieldViewModel {
+
+ private final SpecialField field;
+
+ public SpecialFieldViewModel(SpecialField field){
+ Objects.requireNonNull(field);
+ this.field = field;
+ }
+
+ public SpecialFieldAction getSpecialFieldAction(SpecialFieldValue value, JabRefFrame frame){
+ return new SpecialFieldAction(frame, field, value.getFieldValue().orElse(null),
+ // if field contains only one value, it has to be nulled
+ // otherwise, another setting does not empty the field
+ field.getValues().size() == 1,
+ getLocalization());
+ }
+
+ public Icon getRepresentingIcon() {
+ switch (field) {
+ case PRINTED:
+ return IconTheme.JabRefIcon.PRINTED.getSmallIcon();
+ case PRIORITY:
+ return IconTheme.JabRefIcon.PRIORITY.getSmallIcon();
+ case QUALITY:
+ return IconTheme.JabRefIcon.QUALITY.getSmallIcon();
+ case RANKING:
+ return IconTheme.JabRefIcon.RANKING.getIcon();
+ case READ_STATUS:
+ return IconTheme.JabRefIcon.READ_STATUS.getSmallIcon();
+ case RELEVANCE:
+ return IconTheme.JabRefIcon.RELEVANCE.getSmallIcon();
+ default:
+ throw new IllegalArgumentException("There is no icon mapping for special field " + field);
+ }
+ }
+
+ public String getLocalization(){
+ switch (field) {
+ case PRINTED:
+ return Localization.lang("Printed");
+ case PRIORITY:
+ return Localization.lang("Priority");
+ case QUALITY:
+ return Localization.lang("Quality");
+ case RANKING:
+ return Localization.lang("Rank");
+ case READ_STATUS:
+ return Localization.lang("Read status");
+ case RELEVANCE:
+ return Localization.lang("Relevance");
+ default:
+ throw new IllegalArgumentException("There is no icon mapping for special field " + field);
+ }
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/gui/undo/UndoableChangeType.java b/src/main/java/net/sf/jabref/gui/undo/UndoableChangeType.java
index b25dd73..709480a 100644
--- a/src/main/java/net/sf/jabref/gui/undo/UndoableChangeType.java
+++ b/src/main/java/net/sf/jabref/gui/undo/UndoableChangeType.java
@@ -1,8 +1,8 @@
package net.sf.jabref.gui.undo;
import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.logic.util.strings.StringUtil;
import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.strings.StringUtil;
/**
* This class represents the change of type for an entry.
diff --git a/src/main/java/net/sf/jabref/gui/undo/UndoableFieldChange.java b/src/main/java/net/sf/jabref/gui/undo/UndoableFieldChange.java
index 61c004d..391a6ad 100644
--- a/src/main/java/net/sf/jabref/gui/undo/UndoableFieldChange.java
+++ b/src/main/java/net/sf/jabref/gui/undo/UndoableFieldChange.java
@@ -1,9 +1,9 @@
package net.sf.jabref.gui.undo;
import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.logic.util.strings.StringUtil;
import net.sf.jabref.model.FieldChange;
import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.strings.StringUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
diff --git a/src/main/java/net/sf/jabref/gui/undo/UndoableInsertEntry.java b/src/main/java/net/sf/jabref/gui/undo/UndoableInsertEntry.java
index c9aed60..a028c09 100644
--- a/src/main/java/net/sf/jabref/gui/undo/UndoableInsertEntry.java
+++ b/src/main/java/net/sf/jabref/gui/undo/UndoableInsertEntry.java
@@ -2,9 +2,9 @@ package net.sf.jabref.gui.undo;
import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.logic.util.strings.StringUtil;
import net.sf.jabref.model.database.BibDatabase;
import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.strings.StringUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
diff --git a/src/main/java/net/sf/jabref/gui/undo/UndoableInsertString.java b/src/main/java/net/sf/jabref/gui/undo/UndoableInsertString.java
index a735af7..186bcc5 100644
--- a/src/main/java/net/sf/jabref/gui/undo/UndoableInsertString.java
+++ b/src/main/java/net/sf/jabref/gui/undo/UndoableInsertString.java
@@ -2,10 +2,10 @@ package net.sf.jabref.gui.undo;
import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.logic.util.strings.StringUtil;
import net.sf.jabref.model.database.BibDatabase;
import net.sf.jabref.model.database.KeyCollisionException;
import net.sf.jabref.model.entry.BibtexString;
+import net.sf.jabref.model.strings.StringUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
diff --git a/src/main/java/net/sf/jabref/gui/undo/UndoableKeyChange.java b/src/main/java/net/sf/jabref/gui/undo/UndoableKeyChange.java
index 6c11f80..861ef1e 100644
--- a/src/main/java/net/sf/jabref/gui/undo/UndoableKeyChange.java
+++ b/src/main/java/net/sf/jabref/gui/undo/UndoableKeyChange.java
@@ -1,9 +1,8 @@
package net.sf.jabref.gui.undo;
import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.logic.util.strings.StringUtil;
-import net.sf.jabref.model.database.BibDatabase;
import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.strings.StringUtil;
/**
* This class represents a change in any field value. The relevant
@@ -13,14 +12,11 @@ import net.sf.jabref.model.entry.BibEntry;
public class UndoableKeyChange extends AbstractUndoableJabRefEdit {
private final BibEntry entry;
- private final BibDatabase base;
private final String oldValue;
private final String newValue;
- public UndoableKeyChange(BibDatabase base, BibEntry entry,
- String oldValue, String newValue) {
- this.base = base;
+ public UndoableKeyChange(BibEntry entry, String oldValue, String newValue) {
this.entry = entry;
this.oldValue = oldValue;
this.newValue = newValue;
@@ -31,27 +27,18 @@ public class UndoableKeyChange extends AbstractUndoableJabRefEdit {
return Localization.lang("change key from %0 to %1",
StringUtil.boldHTML(oldValue, Localization.lang("undefined")),
StringUtil.boldHTML(newValue, Localization.lang("undefined")));
-
}
@Override
public void undo() {
super.undo();
-
- // Revert the change.
- set(oldValue);
+ entry.setCiteKey(oldValue);
}
@Override
public void redo() {
super.redo();
-
- // Redo the change.
- set(newValue);
- }
-
- private void set(String to) {
- base.setCiteKeyForEntry(entry, to);
+ entry.setCiteKey(newValue);
}
}
diff --git a/src/main/java/net/sf/jabref/gui/undo/UndoableRemoveEntry.java b/src/main/java/net/sf/jabref/gui/undo/UndoableRemoveEntry.java
index 3726445..d0541dd 100644
--- a/src/main/java/net/sf/jabref/gui/undo/UndoableRemoveEntry.java
+++ b/src/main/java/net/sf/jabref/gui/undo/UndoableRemoveEntry.java
@@ -1,11 +1,11 @@
package net.sf.jabref.gui.undo;
-import net.sf.jabref.event.source.EntryEventSource;
import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.logic.util.strings.StringUtil;
import net.sf.jabref.model.database.BibDatabase;
import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.event.EntryEventSource;
+import net.sf.jabref.model.strings.StringUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
diff --git a/src/main/java/net/sf/jabref/gui/undo/UndoableRemoveString.java b/src/main/java/net/sf/jabref/gui/undo/UndoableRemoveString.java
index cfa2505..130d2a0 100644
--- a/src/main/java/net/sf/jabref/gui/undo/UndoableRemoveString.java
+++ b/src/main/java/net/sf/jabref/gui/undo/UndoableRemoveString.java
@@ -2,10 +2,10 @@ package net.sf.jabref.gui.undo;
import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.logic.util.strings.StringUtil;
import net.sf.jabref.model.database.BibDatabase;
import net.sf.jabref.model.database.KeyCollisionException;
import net.sf.jabref.model.entry.BibtexString;
+import net.sf.jabref.model.strings.StringUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
diff --git a/src/main/java/net/sf/jabref/gui/undo/UndoableStringChange.java b/src/main/java/net/sf/jabref/gui/undo/UndoableStringChange.java
index 963dfc9..fd34cf7 100644
--- a/src/main/java/net/sf/jabref/gui/undo/UndoableStringChange.java
+++ b/src/main/java/net/sf/jabref/gui/undo/UndoableStringChange.java
@@ -2,8 +2,8 @@ package net.sf.jabref.gui.undo;
import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.logic.util.strings.StringUtil;
import net.sf.jabref.model.entry.BibtexString;
+import net.sf.jabref.model.strings.StringUtil;
public class UndoableStringChange extends AbstractUndoableJabRefEdit {
diff --git a/src/main/java/net/sf/jabref/gui/util/FocusRequester.java b/src/main/java/net/sf/jabref/gui/util/FocusRequester.java
deleted file mode 100644
index 2592144..0000000
--- a/src/main/java/net/sf/jabref/gui/util/FocusRequester.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package net.sf.jabref.gui.util;
-
-import java.awt.Component;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-public class FocusRequester implements Runnable {
-
- private static final Log LOGGER = LogFactory.getLog(FocusRequester.class);
-
- private final Component comp;
-
- public FocusRequester(Component comp) {
- if (comp == null) {
- Thread.dumpStack();
- }
-
- this.comp = comp;
-
- run();
- }
-
- @Override
- public void run() {
- LOGGER.debug("requesting focus for " + comp);
- comp.requestFocus();
- }
-}
diff --git a/src/main/java/net/sf/jabref/gui/util/GUIUtil.java b/src/main/java/net/sf/jabref/gui/util/GUIUtil.java
deleted file mode 100644
index 6f17fa6..0000000
--- a/src/main/java/net/sf/jabref/gui/util/GUIUtil.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package net.sf.jabref.gui.util;
-
-import java.awt.FontMetrics;
-
-import javax.swing.JTable;
-import javax.swing.JTree;
-
-public final class GUIUtil {
-
- private GUIUtil() {
- // Private constructor as all methods are static
- }
-
- /**
- * Update table row height to the best possible considering font size changes on the current platform
- *
- * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4760081
- *
- * @param table
- */
- public static void correctRowHeight(JTable table) {
- // Fix tree row height
- FontMetrics metrics = table.getFontMetrics(table.getFont());
- table.setRowHeight(Math.max(table.getRowHeight(), metrics.getHeight()));
- }
-
- /**
- * Update tree row height to the best possible considering font size changes on the current platform
- *
- * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4760081
- *
- * @param table
- */
- public static void correctRowHeight(JTree tree) {
- // Fix tree row height
- FontMetrics metrics = tree.getFontMetrics(tree.getFont());
- tree.setRowHeight(Math.max(tree.getRowHeight(), metrics.getHeight()));
- }
-}
diff --git a/src/main/java/net/sf/jabref/gui/util/PositionWindow.java b/src/main/java/net/sf/jabref/gui/util/PositionWindow.java
deleted file mode 100644
index bfd6442..0000000
--- a/src/main/java/net/sf/jabref/gui/util/PositionWindow.java
+++ /dev/null
@@ -1,111 +0,0 @@
-package net.sf.jabref.gui.util;
-
-import java.awt.Dimension;
-import java.awt.GraphicsEnvironment;
-import java.awt.Point;
-import java.awt.Rectangle;
-import java.awt.Toolkit;
-import java.awt.Window;
-import java.awt.event.ComponentAdapter;
-import java.awt.event.ComponentEvent;
-
-import net.sf.jabref.Globals;
-
-public class PositionWindow {
-
- private final String posXKey;
- private final String posYKey;
- private final String sizeXKey;
- private final String sizeYKey;
- private final Window window;
-
-
- public PositionWindow(Window window, String posXKey, String posYKey, String sizeXKey, String sizeYKey) {
- this.posXKey = posXKey;
- this.posYKey = posYKey;
- this.sizeXKey = sizeXKey;
- this.sizeYKey = sizeYKey;
- this.window = window;
- // Set up a ComponentListener that saves the last size and position of the dialog
- window.addComponentListener(new ComponentAdapter() {
-
- @Override
- public void componentResized(ComponentEvent e) {
- // Save dialog position
- storeWindowPosition();
- }
-
- @Override
- public void componentMoved(ComponentEvent e) {
- // Save dialog position
- storeWindowPosition();
- }
- });
-
- }
-
-
- public void setWindowPosition() {
-
- int sizeX = Globals.prefs.getInt(sizeXKey);
- int sizeY = Globals.prefs.getInt(sizeYKey);
- int posX = Globals.prefs.getInt(posXKey);
- int posY = Globals.prefs.getInt(posYKey);
-
- //
- // Fix for [ 1738920 ] Windows Position in Multi-Monitor environment
- //
- // Do not put a window outside the screen if the preference values are wrong.
- //
- // Useful reference: http://www.exampledepot.com/egs/java.awt/screen_ScreenSize.html?l=rel
- // googled on forums.java.sun.com graphicsenvironment second screen java
- //
- if (GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices().length >= 1) {
- Rectangle bounds = GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()[0]
- .getDefaultConfiguration().getBounds();
- Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
-
- // Make sure we are not above or to the left of the screen bounds:
- if (posX < bounds.x) {
- posX = bounds.x;
- }
- if (posY < bounds.y) {
- posY = bounds.y;
- }
-
- int height = (int) dim.getHeight();
- int width = (int) dim.getWidth();
-
- if ((posX + sizeX) > width) {
- if (sizeX <= width) {
- posX = width - sizeX;
- } else {
- posX = Globals.prefs.getIntDefault(posXKey);
- sizeX = Globals.prefs.getIntDefault(sizeXKey);
- }
- }
-
- if ((posY + sizeY) > height) {
- if (sizeY <= height) {
- posY = height - sizeY;
- } else {
- posY = Globals.prefs.getIntDefault(posYKey);
- sizeY = Globals.prefs.getIntDefault(sizeYKey);
- }
- }
- }
- window.setLocation(posX, posY);
- window.setSize(sizeX, sizeY);
-
- }
-
- public void storeWindowPosition() {
- Point p = window.getLocation();
- Dimension d = window.getSize();
- Globals.prefs.putInt(posXKey, p.x);
- Globals.prefs.putInt(posYKey, p.y);
- Globals.prefs.putInt(sizeXKey, d.width);
- Globals.prefs.putInt(sizeYKey, d.height);
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/gui/util/WindowLocation.java b/src/main/java/net/sf/jabref/gui/util/WindowLocation.java
new file mode 100644
index 0000000..c3b361f
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/util/WindowLocation.java
@@ -0,0 +1,163 @@
+package net.sf.jabref.gui.util;
+
+import java.awt.Dimension;
+import java.awt.Frame;
+import java.awt.GraphicsDevice;
+import java.awt.GraphicsEnvironment;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.Window;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
+
+import javax.swing.JFrame;
+
+import net.sf.jabref.Globals;
+
+/**
+ * Restores and saves the position of non-modal windows inside the JabRef preferences.
+ *
+ * Includes multi-monitor support.
+ * If a windows is placed on another monitor than the main one, it tries to restore that position afterwards.
+ * If the stored position in a multi-monitor setup is not available anymore, it places the window on an equivalent position on the main monitor.
+ */
+public class WindowLocation {
+ private final String posXKey;
+ private final String posYKey;
+ private final String sizeXKey;
+ private final String sizeYKey;
+ private final Window window;
+
+ public WindowLocation(Window window, String posXKey, String posYKey, String sizeXKey, String sizeYKey) {
+ this.window = window;
+ this.posXKey = posXKey;
+ this.posYKey = posYKey;
+ this.sizeXKey = sizeXKey;
+ this.sizeYKey = sizeYKey;
+
+ // set up a ComponentListener that saves the last size and position of the dialog
+ window.addComponentListener(new ComponentAdapter() {
+ @Override
+ public void componentResized(ComponentEvent e) {
+ storeCurrentWindowLocation();
+ }
+
+ @Override
+ public void componentMoved(ComponentEvent e) {
+ storeCurrentWindowLocation();
+ }
+ });
+ }
+
+ public void displayWindowAtStoredLocation() {
+ WindowPosition storedPosition = getStoredLocation();
+
+ // preference values are wrong/not in multi-monitor setup anymore
+ if(!isDisplayable(storedPosition)) {
+ // adapt position to be inside available boundaries
+ storedPosition = adaptPosition(storedPosition);
+ }
+
+ setWindowLocation(storedPosition);
+ }
+
+ public void storeCurrentWindowLocation() {
+ // maximizing is handled explicitely
+ if (window instanceof Frame) {
+ Frame frame = (Frame) window;
+ if (frame.getExtendedState() == Frame.MAXIMIZED_BOTH) {
+ return;
+ }
+ }
+ Point location = window.getLocation();
+ Dimension dimensions = window.getSize();
+
+ Globals.prefs.putInt(posXKey, location.x);
+ Globals.prefs.putInt(posYKey, location.y);
+ Globals.prefs.putInt(sizeXKey, dimensions.width);
+ Globals.prefs.putInt(sizeYKey, dimensions.height);
+ }
+
+ private WindowPosition getStoredLocation() {
+ int sizeX = Globals.prefs.getInt(sizeXKey);
+ int sizeY = Globals.prefs.getInt(sizeYKey);
+ int posX = Globals.prefs.getInt(posXKey);
+ int posY = Globals.prefs.getInt(posYKey);
+
+ return new WindowPosition(posX, posY, sizeX, sizeY);
+ }
+
+ private void setWindowLocation(WindowPosition storedPosition) {
+ window.setLocation(storedPosition.posX, storedPosition.posY);
+ window.setSize(storedPosition.sizeX, storedPosition.sizeY);
+ }
+
+ private boolean isDisplayable(WindowPosition position) {
+ JFrame frame = new JFrame();
+ frame.setBounds(position.posX, position.posY, position.sizeX, position.sizeY);
+
+ return getVirtualBounds().contains(frame.getBounds());
+ }
+
+ private Rectangle getVirtualBounds() {
+ Rectangle bounds = new Rectangle(0, 0, 0, 0);
+ GraphicsDevice[] devices = GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices();
+
+ for (GraphicsDevice device : devices) {
+ bounds.add(device.getDefaultConfiguration().getBounds());
+ }
+ return bounds;
+ }
+
+ private WindowPosition adaptPosition(WindowPosition position) {
+ if (isDisplayable(position)) {
+ return position;
+ }
+
+ // current algorithm:
+ // 1. try to move to main screen
+ // 2. use default sizes on main monitor
+ GraphicsDevice mainScreen = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
+ int mainScreenHeight = mainScreen.getDisplayMode().getHeight();
+ int mainScreenWidth = mainScreen.getDisplayMode().getWidth();
+
+ int newPosX = position.posX;
+ int newPosY = position.posY;
+ int newSizeX = position.sizeX;
+ int newSizeY = position.sizeY;
+
+ if ((position.posX + position.sizeX) > mainScreenWidth) {
+ if (position.sizeX <= mainScreenWidth) {
+ newPosX = mainScreenWidth - position.sizeX;
+ } else {
+ newPosX = Globals.prefs.getIntDefault(posXKey);
+ newSizeX = Globals.prefs.getIntDefault(sizeXKey);
+ }
+ }
+
+ if ((position.posY + position.sizeY) > mainScreenHeight) {
+ if (position.sizeY <= mainScreenHeight) {
+ newPosY = mainScreenHeight - position.sizeY;
+ } else {
+ newPosY = Globals.prefs.getIntDefault(posYKey);
+ newSizeY = Globals.prefs.getIntDefault(sizeYKey);
+ }
+ }
+
+ return new WindowPosition(newPosX, newPosY, newSizeX, newSizeY);
+ }
+
+ static class WindowPosition {
+ public final int posX;
+ public final int posY;
+ public final int sizeX;
+ public final int sizeY;
+
+ public WindowPosition(int posX, int posY, int sizeX, int sizeY) {
+ this.posX = posX;
+ this.posY = posY;
+ this.sizeX = sizeX;
+ this.sizeY = sizeY;
+ }
+ }
+}
diff --git a/src/main/java/net/sf/jabref/gui/util/comparator/FirstColumnComparator.java b/src/main/java/net/sf/jabref/gui/util/comparator/FirstColumnComparator.java
index b7f1e98..a960d8c 100644
--- a/src/main/java/net/sf/jabref/gui/util/comparator/FirstColumnComparator.java
+++ b/src/main/java/net/sf/jabref/gui/util/comparator/FirstColumnComparator.java
@@ -2,8 +2,8 @@ package net.sf.jabref.gui.util.comparator;
import java.util.Comparator;
-import net.sf.jabref.BibDatabaseContext;
import net.sf.jabref.logic.TypedBibEntry;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.entry.BibEntry;
public class FirstColumnComparator implements Comparator<BibEntry> {
diff --git a/src/main/java/net/sf/jabref/gui/util/comparator/IconComparator.java b/src/main/java/net/sf/jabref/gui/util/comparator/IconComparator.java
index 06dd099..dee5930 100644
--- a/src/main/java/net/sf/jabref/gui/util/comparator/IconComparator.java
+++ b/src/main/java/net/sf/jabref/gui/util/comparator/IconComparator.java
@@ -22,8 +22,8 @@ public class IconComparator implements Comparator<BibEntry> {
public int compare(BibEntry e1, BibEntry e2) {
for (String field : fields) {
- Optional<String> val1 = e1.getFieldOptional(field);
- Optional<String> val2 = e2.getFieldOptional(field);
+ Optional<String> val1 = e1.getField(field);
+ Optional<String> val2 = e2.getField(field);
if (val1.isPresent()) {
if (val2.isPresent()) {
// val1 is not null AND val2 is not null
diff --git a/src/main/java/net/sf/jabref/gui/util/comparator/RankingFieldComparator.java b/src/main/java/net/sf/jabref/gui/util/comparator/RankingFieldComparator.java
index b006d5c..987d807 100644
--- a/src/main/java/net/sf/jabref/gui/util/comparator/RankingFieldComparator.java
+++ b/src/main/java/net/sf/jabref/gui/util/comparator/RankingFieldComparator.java
@@ -4,7 +4,7 @@ import java.util.Comparator;
import java.util.Optional;
import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.model.entry.SpecialFields;
+import net.sf.jabref.model.entry.specialfields.SpecialField;
/**
* Comparator that handles the ranking icon column
@@ -17,8 +17,8 @@ public class RankingFieldComparator implements Comparator<BibEntry> {
@Override
public int compare(BibEntry e1, BibEntry e2) {
- Optional<String> val1 = e1.getFieldOptional(SpecialFields.FIELDNAME_RANKING);
- Optional<String> val2 = e2.getFieldOptional(SpecialFields.FIELDNAME_RANKING);
+ Optional<String> val1 = e1.getField(SpecialField.RANKING.getFieldName());
+ Optional<String> val2 = e2.getField(SpecialField.RANKING.getFieldName());
if (val1.isPresent()) {
if (val2.isPresent()) {
// val1 is not null AND val2 is not null
diff --git a/src/main/java/net/sf/jabref/gui/util/component/JTextAreaWithPlaceholder.java b/src/main/java/net/sf/jabref/gui/util/component/JTextAreaWithPlaceholder.java
new file mode 100644
index 0000000..d928ccc
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/util/component/JTextAreaWithPlaceholder.java
@@ -0,0 +1,90 @@
+package net.sf.jabref.gui.util.component;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+
+import javax.swing.JTextArea;
+import javax.swing.UIManager;
+
+/**
+ * A text area which displays a predefined text the same way as {@link JTextFieldWithPlaceholder} does.
+ */
+public class JTextAreaWithPlaceholder extends JTextArea implements KeyListener {
+
+ private final String textWhenNotFocused;
+
+ public JTextAreaWithPlaceholder() {
+ this("");
+ }
+
+ /**
+ * Additionally to {@link JTextAreaWithPlaceholder#JTextAreaWithPlaceholder(String)}
+ * this also sets the initial text of the text field component.
+ *
+ * @param content as the text of the textfield
+ * @param placeholder as the placeholder of the textfield
+ */
+ public JTextAreaWithPlaceholder(String content, String placeholder) {
+ this(placeholder);
+ setText(content);
+ }
+
+ /**
+ * This will create a {@link JTextArea} with a placeholder text. The placeholder
+ * will always be displayed if the text of the {@link JTextArea} is empty.
+ *
+ * @param placeholder as the placeholder of the textarea
+ */
+ public JTextAreaWithPlaceholder(String placeholder) {
+ super();
+ this.setEditable(true);
+ this.setText("");
+ this.textWhenNotFocused = placeholder;
+ }
+
+ @Override
+ protected void paintComponent(Graphics graphics) {
+ super.paintComponent(graphics);
+
+ if (this.getText().isEmpty()) {
+ Font prev = graphics.getFont();
+ Color prevColor = graphics.getColor();
+ graphics.setColor(UIManager.getColor("textInactiveText"));
+ int textHeight = graphics.getFontMetrics().getHeight();
+ int x = this.getInsets().left;
+ Graphics2D g2d = (Graphics2D) graphics;
+ RenderingHints hints = g2d.getRenderingHints();
+ g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+ g2d.drawString(textWhenNotFocused, x, textHeight + this.getInsets().top);
+ g2d.setRenderingHints(hints);
+ graphics.setFont(prev);
+ graphics.setColor(prevColor);
+ }
+ }
+
+ @Override
+ public void keyTyped(KeyEvent e) {
+ if (this.getText().isEmpty()) {
+ this.repaint();
+ }
+ }
+
+ @Override
+ public void keyPressed(KeyEvent e) {
+ if (this.getText().isEmpty()) {
+ this.repaint();
+ }
+ }
+
+ @Override
+ public void keyReleased(KeyEvent e) {
+ if (this.getText().isEmpty()) {
+ this.repaint();
+ }
+ }
+}
diff --git a/src/main/java/net/sf/jabref/gui/util/component/JTextFieldWithPlaceholder.java b/src/main/java/net/sf/jabref/gui/util/component/JTextFieldWithPlaceholder.java
new file mode 100644
index 0000000..f867c97
--- /dev/null
+++ b/src/main/java/net/sf/jabref/gui/util/component/JTextFieldWithPlaceholder.java
@@ -0,0 +1,91 @@
+package net.sf.jabref.gui.util.component;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+
+import javax.swing.JTextField;
+import javax.swing.UIManager;
+
+/**
+ * A text field which displays a predefined text (e.g. "Search") if the text field is empty.
+ * This is similar to a html5 input element with a defined placeholder attribute.
+ * Implementation based on https://gmigdos.wordpress.com/2010/03/30/java-a-custom-jtextfield-for-searching/
+ */
+public class JTextFieldWithPlaceholder extends JTextField implements KeyListener {
+
+ private final String textWhenNotFocused;
+
+ /**
+ * Additionally to {@link JTextFieldWithPlaceholder#JTextFieldWithPlaceholder(String)}
+ * this also sets the initial text of the text field component.
+ *
+ * @param content as the text of the textfield
+ * @param placeholder as the placeholder of the textfield
+ */
+ public JTextFieldWithPlaceholder(String content, String placeholder) {
+ this(placeholder);
+ setText(content);
+ }
+
+ /**
+ * This will create a {@link JTextField} with a placeholder text. The placeholder
+ * will always be displayed if the text of the {@link JTextField} is empty.
+ *
+ * @param placeholder as the placeholder of the textfield
+ */
+ public JTextFieldWithPlaceholder(String placeholder) {
+ super();
+ this.setEditable(true);
+ this.setText("");
+ this.textWhenNotFocused = placeholder;
+ }
+
+ @Override
+ protected void paintComponent(Graphics graphics) {
+ super.paintComponent(graphics);
+
+ if (this.getText().isEmpty()) {
+ int height = this.getHeight();
+ Font prev = graphics.getFont();
+ Color prevColor = graphics.getColor();
+ graphics.setColor(UIManager.getColor("textInactiveText"));
+ int textHeight = graphics.getFontMetrics().getHeight();
+ int textBottom = (((height - textHeight) / 2) + textHeight) - 4;
+ int x = this.getInsets().left;
+ Graphics2D g2d = (Graphics2D) graphics;
+ RenderingHints hints = g2d.getRenderingHints();
+ g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+ g2d.drawString(textWhenNotFocused, x, textBottom);
+ g2d.setRenderingHints(hints);
+ graphics.setFont(prev);
+ graphics.setColor(prevColor);
+ }
+ }
+
+ @Override
+ public void keyTyped(KeyEvent e) {
+ if (this.getText().isEmpty()) {
+ this.repaint();
+ }
+ }
+
+ @Override
+ public void keyPressed(KeyEvent e) {
+ if (this.getText().isEmpty()) {
+ this.repaint();
+ }
+ }
+
+ @Override
+ public void keyReleased(KeyEvent e) {
+ if (this.getText().isEmpty()) {
+ this.repaint();
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/net/sf/jabref/gui/util/component/JTextFieldWithUnfocusedText.java b/src/main/java/net/sf/jabref/gui/util/component/JTextFieldWithUnfocusedText.java
deleted file mode 100644
index cb25794..0000000
--- a/src/main/java/net/sf/jabref/gui/util/component/JTextFieldWithUnfocusedText.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package net.sf.jabref.gui.util.component;
-
-import java.awt.Color;
-import java.awt.Font;
-import java.awt.Graphics;
-import java.awt.Graphics2D;
-import java.awt.RenderingHints;
-import java.awt.event.FocusEvent;
-import java.awt.event.FocusListener;
-
-import javax.swing.JTextField;
-import javax.swing.UIManager;
-
-/**
- * A text field which displays a predefined text (e.g. "Search") if it has not the focus and no text is entered.
- * Implementation based on https://gmigdos.wordpress.com/2010/03/30/java-a-custom-jtextfield-for-searching/
- */
-public class JTextFieldWithUnfocusedText extends JTextField implements FocusListener {
-
- private final String textWhenNotFocused;
-
- public JTextFieldWithUnfocusedText(String textWhenNotFocused) {
- super();
- this.setEditable(true);
- this.setText("");
- this.textWhenNotFocused = textWhenNotFocused;
- this.addFocusListener(this);
- }
-
- @Override
- protected void paintComponent(Graphics g) {
- super.paintComponent(g);
-
- if (!this.hasFocus() && this.getText().isEmpty()) {
- int height = this.getHeight();
- Font prev = g.getFont();
- Color prevColor = g.getColor();
- g.setColor(UIManager.getColor("textInactiveText"));
- int h = g.getFontMetrics().getHeight();
- int textBottom = (((height - h) / 2) + h) - 4;
- int x = this.getInsets().left;
- Graphics2D g2d = (Graphics2D) g;
- RenderingHints hints = g2d.getRenderingHints();
- g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
- g2d.drawString(textWhenNotFocused, x, textBottom);
- g2d.setRenderingHints(hints);
- g.setFont(prev);
- g.setColor(prevColor);
- }
- }
-
- @Override
- public void focusGained(FocusEvent e) {
- this.repaint();
- }
-
- @Override
- public void focusLost(FocusEvent e) {
- this.repaint();
- }
-
-}
\ No newline at end of file
diff --git a/src/main/java/net/sf/jabref/gui/util/component/OverlayPanel.java b/src/main/java/net/sf/jabref/gui/util/component/OverlayPanel.java
index 55bab80..4d0f2ad 100644
--- a/src/main/java/net/sf/jabref/gui/util/component/OverlayPanel.java
+++ b/src/main/java/net/sf/jabref/gui/util/component/OverlayPanel.java
@@ -10,6 +10,7 @@ import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.OverlayLayout;
+import javax.swing.ScrollPaneConstants;
/**
* Supports an underlying text for JComponent
@@ -30,7 +31,7 @@ public class OverlayPanel extends JPanel {
JScrollPane scroller = new JScrollPane(overlay);
scroller.setLocation(0, 0);
- scroller.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
+ scroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
add(label);
add(scroller);
diff --git a/src/main/java/net/sf/jabref/gui/util/component/VerticalLabelUI.java b/src/main/java/net/sf/jabref/gui/util/component/VerticalLabelUI.java
index ec41745..3c9e563 100644
--- a/src/main/java/net/sf/jabref/gui/util/component/VerticalLabelUI.java
+++ b/src/main/java/net/sf/jabref/gui/util/component/VerticalLabelUI.java
@@ -10,6 +10,7 @@ import java.awt.Rectangle;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JLabel;
+import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicLabelUI;
/**
@@ -33,6 +34,7 @@ public class VerticalLabelUI extends BasicLabelUI {
private Rectangle verticalIconR = new Rectangle();
private Rectangle verticalTextR = new Rectangle();
+
/**
* Constructs a <code>VerticalLabelUI</code> with the desired rotation.
* <P>
@@ -61,8 +63,7 @@ public class VerticalLabelUI extends BasicLabelUI {
* @see ComponentUI#getBaselineResizeBehavior(javax.swing.JComponent)
*/
@Override
- public Component.BaselineResizeBehavior getBaselineResizeBehavior(
- JComponent c) {
+ public Component.BaselineResizeBehavior getBaselineResizeBehavior(JComponent c) {
super.getBaselineResizeBehavior(c);
return Component.BaselineResizeBehavior.OTHER;
}
@@ -74,17 +75,15 @@ public class VerticalLabelUI extends BasicLabelUI {
* Icon, int, int, int, int, Rectangle, Rectangle, Rectangle, int)}
*/
@Override
- protected String layoutCL(JLabel label, FontMetrics fontMetrics,
- String text, Icon icon, Rectangle viewR, Rectangle iconR,
- Rectangle textR) {
+ protected String layoutCL(JLabel label, FontMetrics fontMetrics, String text, Icon icon, Rectangle viewR,
+ Rectangle iconR, Rectangle textR) {
String result = text;
verticalViewR = transposeRectangle(viewR, verticalViewR);
verticalIconR = transposeRectangle(iconR, verticalIconR);
verticalTextR = transposeRectangle(textR, verticalTextR);
- result = super.layoutCL(label, fontMetrics, result, icon,
- verticalViewR, verticalIconR, verticalTextR);
+ result = super.layoutCL(label, fontMetrics, result, icon, verticalViewR, verticalIconR, verticalTextR);
copyRectangle(verticalViewR, viewR);
copyRectangle(verticalIconR, iconR);
diff --git a/src/main/java/net/sf/jabref/gui/worker/AbstractWorker.java b/src/main/java/net/sf/jabref/gui/worker/AbstractWorker.java
index 66e989b..ba68bed 100644
--- a/src/main/java/net/sf/jabref/gui/worker/AbstractWorker.java
+++ b/src/main/java/net/sf/jabref/gui/worker/AbstractWorker.java
@@ -23,7 +23,7 @@ public abstract class AbstractWorker implements Worker, CallBack {
}
- public void init() throws Throwable {
+ public void init() throws Exception {
// Do nothing
}
diff --git a/src/main/java/net/sf/jabref/gui/worker/SendAsEMailAction.java b/src/main/java/net/sf/jabref/gui/worker/SendAsEMailAction.java
index e73b705..2aed058 100644
--- a/src/main/java/net/sf/jabref/gui/worker/SendAsEMailAction.java
+++ b/src/main/java/net/sf/jabref/gui/worker/SendAsEMailAction.java
@@ -15,7 +15,6 @@ import net.sf.jabref.gui.JabRefFrame;
import net.sf.jabref.gui.desktop.JabRefDesktop;
import net.sf.jabref.logic.bibtex.BibEntryWriter;
import net.sf.jabref.logic.bibtex.LatexFieldFormatter;
-import net.sf.jabref.logic.bibtex.LatexFieldFormatterPreferences;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.util.io.FileUtil;
import net.sf.jabref.model.entry.BibEntry;
@@ -67,7 +66,7 @@ public class SendAsEMailAction extends AbstractWorker {
// write the entries using sw, which is used later to form the email content
BibEntryWriter bibtexEntryWriter = new BibEntryWriter(
- new LatexFieldFormatter(LatexFieldFormatterPreferences.fromPreferences(Globals.prefs)), true);
+ new LatexFieldFormatter(Globals.prefs.getLatexFieldFormatterPreferences()), true);
for (BibEntry entry : bes) {
try {
@@ -83,8 +82,8 @@ public class SendAsEMailAction extends AbstractWorker {
// the unofficial "mailto:attachment" property
boolean openFolders = JabRefPreferences.getInstance().getBoolean(JabRefPreferences.OPEN_FOLDERS_OF_ATTACHED_FILES);
- List<File> fileList = FileUtil.getListOfLinkedFiles(bes,
- frame.getCurrentBasePanel().getBibDatabaseContext().getFileDirectory());
+ List<File> fileList = FileUtil.getListOfLinkedFiles(bes, frame.getCurrentBasePanel().getBibDatabaseContext()
+ .getFileDirectories(Globals.prefs.getFileDirectoryPreferences()));
for (File f : fileList) {
attachments.add(f.getPath());
if (openFolders) {
diff --git a/src/main/java/net/sf/jabref/gui/worker/VersionWorker.java b/src/main/java/net/sf/jabref/gui/worker/VersionWorker.java
index 567d49e..465f847 100644
--- a/src/main/java/net/sf/jabref/gui/worker/VersionWorker.java
+++ b/src/main/java/net/sf/jabref/gui/worker/VersionWorker.java
@@ -1,7 +1,10 @@
package net.sf.jabref.gui.worker;
import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
import java.util.Objects;
+import java.util.Optional;
import java.util.concurrent.ExecutionException;
import javax.swing.JOptionPane;
@@ -15,15 +18,30 @@ import net.sf.jabref.logic.util.Version;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-public class VersionWorker extends SwingWorker<Version, Void> {
+
+/**
+ * This worker checks if there is a new version of JabRef available.
+ * If there is it will display a Dialog to the User offering him multiple Options to proceed
+ * (see changelog, go to the download page, ignore this version, and remind later).
+ *
+ * If the versions check is executed manually and this is the latest version it will also display a dialog to inform the user.
+ */
+public class VersionWorker extends SwingWorker<List<Version>, Void> {
private static final Log LOGGER = LogFactory.getLog(VersionWorker.class);
private final JabRefFrame mainFrame;
+
+ /** If this versions check is executed automatically (eg. on startup) or manually by the user */
private final boolean manualExecution;
+
+ /** The current version of the installed JabRef */
private final Version installedVersion;
+
+ /** The version which was previously ignored by the user */
private final Version toBeIgnored;
+
public VersionWorker(JabRefFrame mainFrame, boolean manualExecution, Version installedVersion, Version toBeIgnored) {
this.mainFrame = Objects.requireNonNull(mainFrame);
this.manualExecution = manualExecution;
@@ -32,12 +50,12 @@ public class VersionWorker extends SwingWorker<Version, Void> {
}
@Override
- protected Version doInBackground() throws Exception {
+ protected List<Version> doInBackground() throws Exception {
try {
- return Version.getLatestVersion();
+ return Version.getAllAvailableVersions();
} catch (IOException ioException) {
LOGGER.warn("Could not connect to the updateserver.", ioException);
- return null;
+ return Collections.emptyList();
}
}
@@ -48,38 +66,52 @@ public class VersionWorker extends SwingWorker<Version, Void> {
}
try {
- Version latestVersion = this.get();
-
- if (latestVersion == null){
- String couldNotConnect = Localization.lang("Could not connect to the update server.");
- String tryLater = Localization.lang("Please try again later and/or check your network connection.");
- if (manualExecution) {
- JOptionPane.showMessageDialog(this.mainFrame, couldNotConnect + "\n" + tryLater,
- couldNotConnect, JOptionPane.ERROR_MESSAGE);
- }
- this.mainFrame.output(couldNotConnect + " " + tryLater);
- return;
- }
+ List<Version> availableVersions = this.get();
- // only respect the ignored version on automated version checks
- if (latestVersion.equals(toBeIgnored) && !manualExecution) {
- return;
+ // couldn't find any version, connection problems?
+ if (availableVersions.isEmpty()) {
+ showConnectionError();
+ } else {
+ showUpdateInfo(availableVersions);
}
- boolean newer = latestVersion.isNewerThan(installedVersion);
- if (newer){
- new NewVersionDialog(this.mainFrame, installedVersion, latestVersion, toBeIgnored);
- return;
- }
+ } catch (InterruptedException | ExecutionException e) {
+ LOGGER.error("Error while checking for updates", e);
+ }
+ }
+
+ /**
+ * prints the connection problem to the status bar and shows a dialog if it was executed manually
+ */
+ private void showConnectionError() {
+ String couldNotConnect = Localization.lang("Could not connect to the update server.");
+ String tryLater = Localization.lang("Please try again later and/or check your network connection.");
+ if (manualExecution) {
+ JOptionPane.showMessageDialog(this.mainFrame, couldNotConnect + "\n" + tryLater,
+ couldNotConnect, JOptionPane.ERROR_MESSAGE);
+ }
+ this.mainFrame.output(couldNotConnect + " " + tryLater);
+ }
+
+ /**
+ * Prints up-to-date to the status bar (and shows a dialog it was executed manually) if there is now new version.
+ * Shows a "New Version" Dialog to the user if there is.
+ */
+ private void showUpdateInfo(List<Version> availableVersions) {
+ // the newer version, excluding any non-stable versions, except if the installed one is unstable too
+ Optional<Version> newerVersion = installedVersion.shouldBeUpdatedTo(availableVersions);
+ // no new version could be found, only respect the ignored version on automated version checks
+ if (!newerVersion.isPresent() || (newerVersion.get().equals(toBeIgnored) && !manualExecution)) {
String upToDate = Localization.lang("JabRef is up-to-date.");
if (manualExecution) {
JOptionPane.showMessageDialog(this.mainFrame, upToDate, upToDate, JOptionPane.INFORMATION_MESSAGE);
}
this.mainFrame.output(upToDate);
- } catch (InterruptedException | ExecutionException e) {
- LOGGER.error("Error while checking for updates", e);
+ } else {
+ // notify the user about a newer version
+ new NewVersionDialog(this.mainFrame, installedVersion, newerVersion.get());
}
}
diff --git a/src/main/java/net/sf/jabref/logic/TypedBibEntry.java b/src/main/java/net/sf/jabref/logic/TypedBibEntry.java
index c0cc3fa..7072011 100644
--- a/src/main/java/net/sf/jabref/logic/TypedBibEntry.java
+++ b/src/main/java/net/sf/jabref/logic/TypedBibEntry.java
@@ -5,17 +5,17 @@ import java.util.List;
import java.util.Objects;
import java.util.Optional;
-import net.sf.jabref.BibDatabaseContext;
import net.sf.jabref.model.EntryTypes;
import net.sf.jabref.model.FieldChange;
import net.sf.jabref.model.database.BibDatabase;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.database.BibDatabaseMode;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.EntryType;
-import net.sf.jabref.model.entry.EntryUtil;
import net.sf.jabref.model.entry.FieldName;
import net.sf.jabref.model.entry.FileField;
import net.sf.jabref.model.entry.ParsedFileField;
+import net.sf.jabref.model.strings.StringUtil;
public class TypedBibEntry {
@@ -58,7 +58,7 @@ public class TypedBibEntry {
if (entryType.isPresent()) {
return entryType.get().getName();
} else {
- return EntryUtil.capitalizeFirst(entry.getType());
+ return StringUtil.capitalizeFirst(entry.getType());
}
}
@@ -69,7 +69,7 @@ public class TypedBibEntry {
*/
public List<ParsedFileField> getFiles() {
//Extract the path
- Optional<String> oldValue = entry.getFieldOptional(FieldName.FILE);
+ Optional<String> oldValue = entry.getField(FieldName.FILE);
if (!oldValue.isPresent()) {
return new ArrayList<>();
}
@@ -79,7 +79,7 @@ public class TypedBibEntry {
public Optional<FieldChange> setFiles(List<ParsedFileField> files) {
- Optional<String> oldValue = entry.getFieldOptional(FieldName.FILE);
+ Optional<String> oldValue = entry.getField(FieldName.FILE);
String newValue = FileField.getStringRepresentation(files);
if(oldValue.isPresent() && oldValue.get().equals(newValue)) {
diff --git a/src/main/java/net/sf/jabref/logic/autocompleter/AbstractAutoCompleter.java b/src/main/java/net/sf/jabref/logic/autocompleter/AbstractAutoCompleter.java
index 2edb7e9..53498d0 100644
--- a/src/main/java/net/sf/jabref/logic/autocompleter/AbstractAutoCompleter.java
+++ b/src/main/java/net/sf/jabref/logic/autocompleter/AbstractAutoCompleter.java
@@ -9,6 +9,8 @@ import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
+import net.sf.jabref.logic.layout.format.LatexToUnicodeFormatter;
+
/**
* Delivers possible completions for a given string.
*
@@ -103,6 +105,8 @@ public abstract class AbstractAutoCompleter implements AutoCompleter<String> {
return;
}
+ word = new LatexToUnicodeFormatter().format(word);
+
indexCaseSensitive.add(word);
// insensitive treatment
diff --git a/src/main/java/net/sf/jabref/logic/autocompleter/AutoCompletePreferences.java b/src/main/java/net/sf/jabref/logic/autocompleter/AutoCompletePreferences.java
index 45ec40f..e9ec9b8 100644
--- a/src/main/java/net/sf/jabref/logic/autocompleter/AutoCompletePreferences.java
+++ b/src/main/java/net/sf/jabref/logic/autocompleter/AutoCompletePreferences.java
@@ -23,7 +23,7 @@ public class AutoCompletePreferences {
defaults.put(AUTOCOMPLETER_FIRSTNAME_MODE, AutoCompleteFirstNameMode.BOTH.name());
defaults.put(AUTOCOMPLETER_FIRST_LAST, Boolean.FALSE); // "Autocomplete names in 'Firstname Lastname' format only"
defaults.put(AUTOCOMPLETER_LAST_FIRST, Boolean.FALSE); // "Autocomplete names in 'Lastname, Firstname' format only"
- defaults.put(AUTOCOMPLETER_COMPLETE_FIELDS, "author;editor;title;journal;publisher;keywords;crossref");
+ defaults.put(AUTOCOMPLETER_COMPLETE_FIELDS, "author;editor;title;journal;publisher;keywords");
}
public AutoCompletePreferences(JabRefPreferences preferences) {
@@ -86,6 +86,6 @@ public class AutoCompletePreferences {
}
public JournalAbbreviationPreferences getJournalAbbreviationPreferences() {
- return JournalAbbreviationPreferences.fromPreferences(preferences);
+ return preferences.getJournalAbbreviationPreferences();
}
}
\ No newline at end of file
diff --git a/src/main/java/net/sf/jabref/logic/autocompleter/AutoCompleterFactory.java b/src/main/java/net/sf/jabref/logic/autocompleter/AutoCompleterFactory.java
index b38a0f2..488d986 100644
--- a/src/main/java/net/sf/jabref/logic/autocompleter/AutoCompleterFactory.java
+++ b/src/main/java/net/sf/jabref/logic/autocompleter/AutoCompleterFactory.java
@@ -4,7 +4,7 @@ import java.util.Objects;
import net.sf.jabref.logic.journals.JournalAbbreviationLoader;
import net.sf.jabref.model.entry.FieldName;
-import net.sf.jabref.model.entry.FieldProperties;
+import net.sf.jabref.model.entry.FieldProperty;
import net.sf.jabref.model.entry.InternalBibtexFields;
/**
@@ -26,11 +26,11 @@ public class AutoCompleterFactory {
public AutoCompleter<String> getFor(String fieldName) {
Objects.requireNonNull(fieldName);
- if (InternalBibtexFields.getFieldExtras(fieldName).contains(FieldProperties.PERSON_NAMES)) {
+ if (InternalBibtexFields.getFieldProperties(fieldName).contains(FieldProperty.PERSON_NAMES)) {
return new NameFieldAutoCompleter(fieldName, preferences);
- } else if (InternalBibtexFields.getFieldExtras(fieldName).contains(FieldProperties.SINGLE_ENTRY_LINK)) {
+ } else if (InternalBibtexFields.getFieldProperties(fieldName).contains(FieldProperty.SINGLE_ENTRY_LINK)) {
return new BibtexKeyAutoCompleter(preferences);
- } else if (InternalBibtexFields.getFieldExtras(fieldName).contains(FieldProperties.JOURNAL_NAME)
+ } else if (InternalBibtexFields.getFieldProperties(fieldName).contains(FieldProperty.JOURNAL_NAME)
|| FieldName.PUBLISHER.equals(fieldName)) {
return new JournalAutoCompleter(fieldName, preferences, abbreviationLoader);
} else {
diff --git a/src/main/java/net/sf/jabref/logic/autocompleter/ContentAutoCompleters.java b/src/main/java/net/sf/jabref/logic/autocompleter/ContentAutoCompleters.java
index 2951af3..e5501d7 100644
--- a/src/main/java/net/sf/jabref/logic/autocompleter/ContentAutoCompleters.java
+++ b/src/main/java/net/sf/jabref/logic/autocompleter/ContentAutoCompleters.java
@@ -1,10 +1,8 @@
package net.sf.jabref.logic.autocompleter;
import java.util.List;
-import java.util.Map;
import java.util.Objects;
-import net.sf.jabref.MetaData;
import net.sf.jabref.logic.journals.JournalAbbreviationLoader;
import net.sf.jabref.model.database.BibDatabase;
@@ -13,7 +11,7 @@ public class ContentAutoCompleters extends AutoCompleters {
public ContentAutoCompleters() {
}
- public ContentAutoCompleters(BibDatabase database, MetaData metaData, AutoCompletePreferences preferences,
+ public ContentAutoCompleters(BibDatabase database, AutoCompletePreferences preferences,
JournalAbbreviationLoader abbreviationLoader) {
Objects.requireNonNull(preferences);
@@ -25,18 +23,5 @@ public class ContentAutoCompleters extends AutoCompleters {
}
addDatabase(database);
-
- addContentSelectorValuesToAutoCompleters(metaData);
- }
-
- /**
- * For all fields with both autocompletion and content selector, add content selector
- * values to the autocompleter list:
- */
- public void addContentSelectorValuesToAutoCompleters(MetaData metaData) {
- for (Map.Entry<String, AutoCompleter<String>> entry : this.autoCompleters.entrySet()) {
- AutoCompleter<String> ac = entry.getValue();
- metaData.getContentSelectors(entry.getKey()).forEach(ac::addItemToIndex);
- }
}
}
diff --git a/src/main/java/net/sf/jabref/logic/autocompleter/DefaultAutoCompleter.java b/src/main/java/net/sf/jabref/logic/autocompleter/DefaultAutoCompleter.java
index b8a950e..e0a577c 100644
--- a/src/main/java/net/sf/jabref/logic/autocompleter/DefaultAutoCompleter.java
+++ b/src/main/java/net/sf/jabref/logic/autocompleter/DefaultAutoCompleter.java
@@ -41,7 +41,7 @@ class DefaultAutoCompleter extends AbstractAutoCompleter {
return;
}
- entry.getFieldOptional(fieldName).ifPresent(fieldValue -> {
+ entry.getField(fieldName).ifPresent(fieldValue -> {
StringTokenizer tok = new StringTokenizer(fieldValue, SEPARATING_CHARS);
while (tok.hasMoreTokens()) {
addItemToIndex(tok.nextToken());
diff --git a/src/main/java/net/sf/jabref/logic/autocompleter/EntireFieldAutoCompleter.java b/src/main/java/net/sf/jabref/logic/autocompleter/EntireFieldAutoCompleter.java
index 3a71c0d..602dd6d 100644
--- a/src/main/java/net/sf/jabref/logic/autocompleter/EntireFieldAutoCompleter.java
+++ b/src/main/java/net/sf/jabref/logic/autocompleter/EntireFieldAutoCompleter.java
@@ -38,6 +38,6 @@ class EntireFieldAutoCompleter extends AbstractAutoCompleter {
return;
}
- entry.getFieldOptional(fieldName).ifPresent(fieldValue -> addItemToIndex(fieldValue.trim()));
+ entry.getField(fieldName).ifPresent(fieldValue -> addItemToIndex(fieldValue.trim()));
}
}
diff --git a/src/main/java/net/sf/jabref/logic/autocompleter/NameFieldAutoCompleter.java b/src/main/java/net/sf/jabref/logic/autocompleter/NameFieldAutoCompleter.java
index d80ee7a..e9fe1a2 100644
--- a/src/main/java/net/sf/jabref/logic/autocompleter/NameFieldAutoCompleter.java
+++ b/src/main/java/net/sf/jabref/logic/autocompleter/NameFieldAutoCompleter.java
@@ -76,7 +76,7 @@ class NameFieldAutoCompleter extends AbstractAutoCompleter {
return;
}
for (String fieldName : fieldNames) {
- entry.getFieldOptional(fieldName).ifPresent(fieldValue -> {
+ entry.getField(fieldName).ifPresent(fieldValue -> {
AuthorList authorList = AuthorList.parse(fieldValue);
for (Author author : authorList.getAuthors()) {
handleAuthor(author);
diff --git a/src/main/java/net/sf/jabref/logic/autosaveandbackup/AutosaveManager.java b/src/main/java/net/sf/jabref/logic/autosaveandbackup/AutosaveManager.java
new file mode 100644
index 0000000..65908e2
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/autosaveandbackup/AutosaveManager.java
@@ -0,0 +1,94 @@
+package net.sf.jabref.logic.autosaveandbackup;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+import net.sf.jabref.model.database.BibDatabaseContext;
+import net.sf.jabref.model.database.event.AutosaveEvent;
+import net.sf.jabref.model.database.event.BibDatabaseContextChangedEvent;
+
+import com.google.common.eventbus.EventBus;
+import com.google.common.eventbus.Subscribe;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Saves the given {@link BibDatabaseContext} on every {@link BibDatabaseContextChangedEvent} by posting a new {@link AutosaveEvent}.
+ * An intelligent {@link ExecutorService} with a {@link BlockingQueue} prevents a high load while saving and rejects all redundant save tasks.
+ */
+public class AutosaveManager {
+
+ private static final Log LOGGER = LogFactory.getLog(AutosaveManager.class);
+
+ private static Set<AutosaveManager> runningInstances = new HashSet<>();
+
+ private final BibDatabaseContext bibDatabaseContext;
+ private final BlockingQueue<Runnable> workerQueue;
+ private final ExecutorService executor;
+ private final EventBus eventBus;
+
+
+ private AutosaveManager(BibDatabaseContext bibDatabaseContext) {
+ this.bibDatabaseContext = bibDatabaseContext;
+ this.workerQueue = new ArrayBlockingQueue<>(1);
+ this.executor = new ThreadPoolExecutor(1, 1, 0, TimeUnit.SECONDS, workerQueue);
+ this.eventBus = new EventBus();
+ }
+
+ @Subscribe
+ public synchronized void listen(@SuppressWarnings("unused") BibDatabaseContextChangedEvent event) {
+ try {
+ executor.submit(() -> {
+ eventBus.post(new AutosaveEvent());
+ });
+ } catch (RejectedExecutionException e) {
+ LOGGER.debug("Rejecting autosave while another save process is already running.");
+ }
+ }
+
+ private void shutdown() {
+ bibDatabaseContext.getDatabase().unregisterListener(this);
+ bibDatabaseContext.getMetaData().unregisterListener(this);
+ executor.shutdown();
+ }
+
+ /**
+ * Starts the Autosaver which is associated with the given {@link BibDatabaseContext}.
+ *
+ * @param bibDatabaseContext Associated {@link BibDatabaseContext}
+ */
+ public static AutosaveManager start(BibDatabaseContext bibDatabaseContext) {
+ AutosaveManager autosaver = new AutosaveManager(bibDatabaseContext);
+ bibDatabaseContext.getDatabase().registerListener(autosaver);
+ bibDatabaseContext.getMetaData().registerListener(autosaver);
+ runningInstances.add(autosaver);
+ return autosaver;
+ }
+
+ /**
+ * Shuts down the Autosaver which is associated with the given {@link BibDatabaseContext}.
+ *
+ * @param bibDatabaseContext Associated {@link BibDatabaseContext}
+ */
+ public static void shutdown(BibDatabaseContext bibDatabaseContext) {
+ runningInstances.stream().filter(instance -> instance.bibDatabaseContext == bibDatabaseContext).findAny()
+ .ifPresent(instance -> {
+ instance.shutdown();
+ runningInstances.remove(instance);
+ });
+ }
+
+ public void registerListener(Object listener) {
+ eventBus.register(listener);
+ }
+
+ public void unregisterListener(Object listener) {
+ eventBus.unregister(listener);
+ }
+}
diff --git a/src/main/java/net/sf/jabref/logic/autosaveandbackup/BackupManager.java b/src/main/java/net/sf/jabref/logic/autosaveandbackup/BackupManager.java
new file mode 100644
index 0000000..ce24b0c
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/autosaveandbackup/BackupManager.java
@@ -0,0 +1,163 @@
+package net.sf.jabref.logic.autosaveandbackup;
+
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
+import java.util.HashSet;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+import net.sf.jabref.logic.exporter.BibtexDatabaseWriter;
+import net.sf.jabref.logic.exporter.FileSaveSession;
+import net.sf.jabref.logic.exporter.SaveException;
+import net.sf.jabref.logic.exporter.SavePreferences;
+import net.sf.jabref.logic.util.io.FileUtil;
+import net.sf.jabref.model.database.BibDatabaseContext;
+import net.sf.jabref.model.database.event.BibDatabaseContextChangedEvent;
+import net.sf.jabref.preferences.JabRefPreferences;
+
+import com.google.common.eventbus.Subscribe;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Backups the given bib database file from {@link BibDatabaseContext} on every {@link BibDatabaseContextChangedEvent}.
+ * An intelligent {@link ExecutorService} with a {@link BlockingQueue} prevents a high load while making backups and
+ * rejects all redundant backup tasks.
+ * This class does not manage the .bak file which is created when opening a database.
+ */
+public class BackupManager {
+
+ private static final Log LOGGER = LogFactory.getLog(BackupManager.class);
+
+ private static final String BACKUP_EXTENSION = ".sav";
+
+ private static Set<BackupManager> runningInstances = new HashSet<>();
+
+ private final BibDatabaseContext bibDatabaseContext;
+ private final JabRefPreferences preferences;
+ private final ExecutorService executor;
+ private final Runnable backupTask = () -> determineBackupPath().ifPresent(this::performBackup);
+
+
+ private BackupManager(BibDatabaseContext bibDatabaseContext) {
+ this.bibDatabaseContext = bibDatabaseContext;
+ this.preferences = JabRefPreferences.getInstance();
+ BlockingQueue<Runnable> workerQueue = new ArrayBlockingQueue<>(1);
+ this.executor = new ThreadPoolExecutor(1, 1, 0, TimeUnit.SECONDS, workerQueue);
+
+ // Listen for change events
+ bibDatabaseContext.getDatabase().registerListener(this);
+ bibDatabaseContext.getMetaData().registerListener(this);
+ }
+
+ static Path getBackupPath(Path originalPath) {
+ return FileUtil.addExtension(originalPath, BACKUP_EXTENSION);
+ }
+
+ /**
+ * Starts the BackupManager which is associated with the given {@link BibDatabaseContext}.
+ * As long as no database file is present in {@link BibDatabaseContext}, the {@link BackupManager} will do nothing.
+ *
+ * @param bibDatabaseContext Associated {@link BibDatabaseContext}
+ */
+ public static BackupManager start(BibDatabaseContext bibDatabaseContext) {
+ BackupManager backupManager = new BackupManager(bibDatabaseContext);
+ backupManager.startBackupTask();
+ runningInstances.add(backupManager);
+ return backupManager;
+ }
+
+ /**
+ * Shuts down the BackupManager which is associated with the given {@link BibDatabaseContext}.
+ *
+ * @param bibDatabaseContext Associated {@link BibDatabaseContext}
+ */
+ public static void shutdown(BibDatabaseContext bibDatabaseContext) {
+ runningInstances.stream().filter(instance -> instance.bibDatabaseContext == bibDatabaseContext).forEach(
+ BackupManager::shutdown);
+ runningInstances.removeIf(instance -> instance.bibDatabaseContext == bibDatabaseContext);
+ }
+
+ /**
+ * Checks whether a backup file exists for the given database file.
+ *
+ * @param originalPath Path to the file a backup should be checked for.
+ */
+ public static boolean checkForBackupFile(Path originalPath) {
+ Path backupPath = getBackupPath(originalPath);
+ return Files.exists(backupPath) && !Files.isDirectory(backupPath);
+ }
+
+ /**
+ * Restores the backup file by copying and overwriting the original one.
+ *
+ * @param originalPath Path to the file which should be equalized to the backup file.
+ */
+ public static void restoreBackup(Path originalPath) {
+ Path backupPath = getBackupPath(originalPath);
+ try {
+ Files.copy(backupPath, originalPath, StandardCopyOption.REPLACE_EXISTING);
+ } catch (IOException e) {
+ LOGGER.error("Error while restoring the backup file.", e);
+ }
+ }
+
+ private Optional<Path> determineBackupPath() {
+ return bibDatabaseContext.getDatabasePath().map(BackupManager::getBackupPath);
+ }
+
+ private void performBackup(Path backupPath) {
+ try {
+ Charset charset = bibDatabaseContext.getMetaData().getEncoding().orElse(preferences.getDefaultEncoding());
+ SavePreferences savePreferences = SavePreferences.loadForSaveFromPreferences(preferences).withEncoding
+ (charset).withMakeBackup(false);
+ new BibtexDatabaseWriter<>(FileSaveSession::new).saveDatabase(bibDatabaseContext, savePreferences).commit
+ (backupPath);
+ } catch (SaveException e) {
+ LOGGER.error("Error while saving file.", e);
+ }
+ }
+
+ @Subscribe
+ public synchronized void listen(@SuppressWarnings("unused") BibDatabaseContextChangedEvent event) {
+ startBackupTask();
+ }
+
+ private void startBackupTask() {
+ try {
+ executor.submit(backupTask);
+ } catch (RejectedExecutionException e) {
+ LOGGER.debug("Rejecting while another backup process is already running.");
+ }
+ }
+
+ /**
+ * Unregisters the BackupManager from the eventBus of {@link BibDatabaseContext} and deletes the backup file.
+ * This method should only be used when closing a database/JabRef legally.
+ */
+ private void shutdown() {
+ bibDatabaseContext.getDatabase().unregisterListener(this);
+ bibDatabaseContext.getMetaData().unregisterListener(this);
+ executor.shutdown();
+ determineBackupPath().ifPresent(this::deleteBackupFile);
+ }
+
+ private void deleteBackupFile(Path backupPath) {
+ try {
+ if (Files.exists(backupPath) && !Files.isDirectory(backupPath)) {
+ Files.delete(backupPath);
+ }
+ } catch (IOException e) {
+ LOGGER.error("Error while deleting the backup file.", e);
+ }
+ }
+}
diff --git a/src/main/java/net/sf/jabref/logic/auxparser/AuxParser.java b/src/main/java/net/sf/jabref/logic/auxparser/AuxParser.java
index 7844b4d..b6bb122 100644
--- a/src/main/java/net/sf/jabref/logic/auxparser/AuxParser.java
+++ b/src/main/java/net/sf/jabref/logic/auxparser/AuxParser.java
@@ -24,6 +24,15 @@ import org.apache.commons.logging.LogFactory;
* LaTeX Aux to BibTeX Parser
* <p>
* Extracts a subset of BibTeX entries from a BibDatabase that are included in an AUX file.
+ * Also supports nested AUX files (latex \\include).
+ *
+ * There exists no specification of the AUX file.
+ * Every package, class or document can write to the AUX file.
+ * The AUX file consists of LaTeX macros and is read at the \begin{document} and again at the \end{document}.
+ *
+ * BibTeX citation: \citation{x,y,z}
+ * Biblatex citation: \abx at aux@cite{x,y,z}
+ * Nested AUX files: \@input{x}
*/
public class AuxParser {
private static final Log LOGGER = LogFactory.getLog(AuxParser.class);
@@ -54,18 +63,6 @@ public class AuxParser {
return parseAuxFile();
}
- /*
- * Parses the AUX file and extracts all BIB keys.
- * Also supports nested AUX files (latex \\include).
- *
- * There exists no specification of the AUX file.
- * Every package, class or document can write to the AUX file.
- * The AUX file consists of LaTeX macros and is read at the \begin{document} and again at the \end{document}.
- *
- * BibTeX citation: \citation{x,y,z}
- * Biblatex citation: \abx at aux@cite{x,y,z}
- * Nested AUX files: \@input{x}
- */
private AuxParserResult parseAuxFile() {
AuxParserResult result = new AuxParserResult(masterDatabase);
@@ -82,33 +79,8 @@ public class AuxParser {
String line;
while ((line = br.readLine()) != null) {
- Matcher citeMatch = CITE_PATTERN.matcher(line);
-
- while (citeMatch.find()) {
- String keyString = citeMatch.group(2);
- String[] keys = keyString.split(",");
-
- for (String key : keys) {
- result.getUniqueKeys().add(key.trim());
- }
- }
-
- Matcher inputMatch = INPUT_PATTERN.matcher(line);
-
- while (inputMatch.find()) {
- String inputString = inputMatch.group(1);
-
- String inputFile = inputString;
- Path rootPath = new File(auxFile).toPath().getParent();
- if (rootPath != null) {
- inputFile = rootPath.resolve(inputString).toString();
- }
-
- if (!fileList.contains(inputFile)) {
- fileList.add(inputFile);
- result.increaseNestedAuxFilesCounter();
- }
- }
+ matchCitation(result, line);
+ matchNestedAux(result, fileList, line);
}
} catch (FileNotFoundException e) {
LOGGER.info("Cannot locate input file", e);
@@ -123,6 +95,38 @@ public class AuxParser {
return result;
}
+ private void matchNestedAux(AuxParserResult result, List<String> fileList, String line) {
+ Matcher inputMatch = INPUT_PATTERN.matcher(line);
+
+ while (inputMatch.find()) {
+ String inputString = inputMatch.group(1);
+
+ String inputFile = inputString;
+ Path rootPath = new File(auxFile).toPath().getParent();
+ if (rootPath != null) {
+ inputFile = rootPath.resolve(inputString).toString();
+ }
+
+ if (!fileList.contains(inputFile)) {
+ fileList.add(inputFile);
+ result.increaseNestedAuxFilesCounter();
+ }
+ }
+ }
+
+ private void matchCitation(AuxParserResult result, String line) {
+ Matcher citeMatch = CITE_PATTERN.matcher(line);
+
+ while (citeMatch.find()) {
+ String keyString = citeMatch.group(2);
+ String[] keys = keyString.split(",");
+
+ for (String key : keys) {
+ result.getUniqueKeys().add(key.trim());
+ }
+ }
+ }
+
/*
* Try to find an equivalent BibTeX entry inside the reference database for all keys inside the AUX file.
*/
@@ -149,8 +153,8 @@ public class AuxParser {
* Resolves and adds CrossRef entries
*/
private void resolveCrossReferences(BibEntry entry, AuxParserResult result) {
- entry.getFieldOptional(FieldName.CROSSREF).ifPresent(crossref -> {
- if (!result.getUniqueKeys().contains(crossref)) {
+ entry.getField(FieldName.CROSSREF).ifPresent(crossref -> {
+ if (!result.getGeneratedBibDatabase().getEntryByKey(crossref).isPresent()) {
Optional<BibEntry> refEntry = masterDatabase.getEntryByKey(crossref);
if (refEntry.isPresent()) {
diff --git a/src/main/java/net/sf/jabref/logic/bibtex/BibEntryWriter.java b/src/main/java/net/sf/jabref/logic/bibtex/BibEntryWriter.java
index 7905480..ef71187 100644
--- a/src/main/java/net/sf/jabref/logic/bibtex/BibEntryWriter.java
+++ b/src/main/java/net/sf/jabref/logic/bibtex/BibEntryWriter.java
@@ -11,13 +11,12 @@ import java.util.function.Predicate;
import net.sf.jabref.logic.TypedBibEntry;
import net.sf.jabref.logic.util.OS;
-import net.sf.jabref.logic.util.strings.StringUtil;
import net.sf.jabref.model.EntryTypes;
import net.sf.jabref.model.database.BibDatabaseMode;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.EntryType;
import net.sf.jabref.model.entry.InternalBibtexFields;
-
+import net.sf.jabref.model.strings.StringUtil;
public class BibEntryWriter {
@@ -143,7 +142,7 @@ public class BibEntryWriter {
* @throws IOException In case of an IO error
*/
private void writeField(BibEntry entry, Writer out, String name, int indentation) throws IOException {
- Optional<String> field = entry.getFieldOptional(name);
+ Optional<String> field = entry.getField(name);
// only write field if is is not empty
// field.ifPresent does not work as an IOException may be thrown
if (field.isPresent() && !field.get().trim().isEmpty()) {
diff --git a/src/main/java/net/sf/jabref/logic/bibtex/FieldContentParser.java b/src/main/java/net/sf/jabref/logic/bibtex/FieldContentParser.java
index f8b1e92..a44b9f7 100644
--- a/src/main/java/net/sf/jabref/logic/bibtex/FieldContentParser.java
+++ b/src/main/java/net/sf/jabref/logic/bibtex/FieldContentParser.java
@@ -1,11 +1,13 @@
package net.sf.jabref.logic.bibtex;
import java.util.HashSet;
+import java.util.Objects;
import java.util.Set;
import java.util.regex.Pattern;
-import net.sf.jabref.logic.util.strings.StringUtil;
+import net.sf.jabref.logic.util.OS;
import net.sf.jabref.model.entry.FieldName;
+import net.sf.jabref.model.strings.StringUtil;
/**
* This class provides the reformatting needed when reading BibTeX fields formatted
@@ -21,6 +23,8 @@ public class FieldContentParser {
public FieldContentParser(FieldContentParserPreferences prefs) {
+ Objects.requireNonNull(prefs);
+
multiLineFields = new HashSet<>();
// the following two are also coded in net.sf.jabref.logic.bibtex.LatexFieldFormatter.format(String, String)
multiLineFields.add(FieldName.ABSTRACT);
@@ -40,7 +44,7 @@ public class FieldContentParser {
if (multiLineFields.contains(bibtexField)) {
// Unify line breaks
- return StringUtil.unifyLineBreaksToConfiguredLineBreaks(fieldContent);
+ return StringUtil.unifyLineBreaks(fieldContent, OS.NEWLINE);
}
return WHITESPACE.matcher(fieldContent).replaceAll(" ");
diff --git a/src/main/java/net/sf/jabref/logic/bibtex/FieldContentParserPreferences.java b/src/main/java/net/sf/jabref/logic/bibtex/FieldContentParserPreferences.java
index 486d258..d434082 100644
--- a/src/main/java/net/sf/jabref/logic/bibtex/FieldContentParserPreferences.java
+++ b/src/main/java/net/sf/jabref/logic/bibtex/FieldContentParserPreferences.java
@@ -3,8 +3,6 @@ package net.sf.jabref.logic.bibtex;
import java.util.Collections;
import java.util.List;
-import net.sf.jabref.preferences.JabRefPreferences;
-
public class FieldContentParserPreferences {
private final List<String> nonWrappableFields;
@@ -23,8 +21,4 @@ public class FieldContentParserPreferences {
return nonWrappableFields;
}
- public static FieldContentParserPreferences fromPreferences(JabRefPreferences jabRefPreferences) {
- return new FieldContentParserPreferences(
- jabRefPreferences.getStringList(JabRefPreferences.NON_WRAPPABLE_FIELDS));
- }
}
diff --git a/src/main/java/net/sf/jabref/logic/bibtex/LatexFieldFormatter.java b/src/main/java/net/sf/jabref/logic/bibtex/LatexFieldFormatter.java
index 9df71f1..1d1d4dd 100644
--- a/src/main/java/net/sf/jabref/logic/bibtex/LatexFieldFormatter.java
+++ b/src/main/java/net/sf/jabref/logic/bibtex/LatexFieldFormatter.java
@@ -4,8 +4,8 @@ import java.util.ArrayList;
import java.util.List;
import net.sf.jabref.logic.util.OS;
-import net.sf.jabref.logic.util.strings.StringUtil;
import net.sf.jabref.model.entry.InternalBibtexFields;
+import net.sf.jabref.model.strings.StringUtil;
/**
* Currently the only implementation of net.sf.jabref.exporter.FieldFormatter
@@ -250,7 +250,7 @@ public class LatexFieldFormatter {
}
private void putIn(String s) {
- stringBuilder.append(StringUtil.wrap(s, prefs.getLineLength()));
+ stringBuilder.append(StringUtil.wrap(s, prefs.getLineLength(), OS.NEWLINE));
}
private static void checkBraces(String text) throws IllegalArgumentException {
diff --git a/src/main/java/net/sf/jabref/logic/bibtex/LatexFieldFormatterPreferences.java b/src/main/java/net/sf/jabref/logic/bibtex/LatexFieldFormatterPreferences.java
index 1cfa749..57bd42a 100644
--- a/src/main/java/net/sf/jabref/logic/bibtex/LatexFieldFormatterPreferences.java
+++ b/src/main/java/net/sf/jabref/logic/bibtex/LatexFieldFormatterPreferences.java
@@ -3,8 +3,6 @@ package net.sf.jabref.logic.bibtex;
import java.util.Collections;
import java.util.List;
-import net.sf.jabref.preferences.JabRefPreferences;
-
public class LatexFieldFormatterPreferences {
private final boolean resolveStringsAllFields;
@@ -25,12 +23,6 @@ public class LatexFieldFormatterPreferences {
this(true, Collections.emptyList(), new FieldContentParserPreferences());
}
- public static LatexFieldFormatterPreferences fromPreferences(JabRefPreferences prefs) {
- return new LatexFieldFormatterPreferences(prefs.getBoolean(JabRefPreferences.RESOLVE_STRINGS_ALL_FIELDS),
- prefs.getStringList(JabRefPreferences.DO_NOT_RESOLVE_STRINGS_FOR),
- FieldContentParserPreferences.fromPreferences(prefs));
- }
-
public boolean isResolveStringsAllFields() {
return resolveStringsAllFields;
}
diff --git a/src/main/java/net/sf/jabref/logic/bibtex/comparator/CrossRefEntryComparator.java b/src/main/java/net/sf/jabref/logic/bibtex/comparator/CrossRefEntryComparator.java
index a090eb3..8d1470b 100644
--- a/src/main/java/net/sf/jabref/logic/bibtex/comparator/CrossRefEntryComparator.java
+++ b/src/main/java/net/sf/jabref/logic/bibtex/comparator/CrossRefEntryComparator.java
@@ -15,17 +15,14 @@ public class CrossRefEntryComparator implements Comparator<BibEntry> {
@Override
public int compare(BibEntry e1, BibEntry e2) {
+ boolean crEntry1 = e1.hasField(FieldName.CROSSREF);
+ boolean crEntry2 = e2.hasField(FieldName.CROSSREF);
- Boolean b1 = e1.hasField(FieldName.CROSSREF);
- Boolean b2 = e2.hasField(FieldName.CROSSREF);
-
- if ((!b1) && (!b2)) {
- return 0; // secComparator.compare(e1, e2);
- }
- if (b1 && b2) {
- return 0; // secComparator.compare(e1, e2);
+ if ((crEntry1 && crEntry2) || (!crEntry1 && !crEntry2)) {
+ return 0;
}
- if (!b1) {
+
+ if (!crEntry1) {
return 1;
} else {
return -1;
diff --git a/src/main/java/net/sf/jabref/logic/bibtex/comparator/EntryComparator.java b/src/main/java/net/sf/jabref/logic/bibtex/comparator/EntryComparator.java
index c0915b8..f516ee1 100644
--- a/src/main/java/net/sf/jabref/logic/bibtex/comparator/EntryComparator.java
+++ b/src/main/java/net/sf/jabref/logic/bibtex/comparator/EntryComparator.java
@@ -5,7 +5,7 @@ import java.util.Objects;
import net.sf.jabref.model.entry.AuthorList;
import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.model.entry.FieldProperties;
+import net.sf.jabref.model.entry.FieldProperty;
import net.sf.jabref.model.entry.InternalBibtexFields;
/**
@@ -13,8 +13,7 @@ import net.sf.jabref.model.entry.InternalBibtexFields;
* structured as a node in a linked list of comparators, where each node can contain a link to a new comparator that
* decides the ordering (by recursion) if this one can't find a difference. The next node, if any, is given at
* construction time, and an arbitrary number of nodes can be included. If the entries are equal by this comparator, and
- * there is no next entry, the entries' unique IDs will decide the ordering. Consequently, this comparator can never
- * return 0 unless the entries are the same object.
+ * there is no next entry, the entries' unique IDs will decide the ordering.
*/
public class EntryComparator implements Comparator<BibEntry> {
@@ -25,31 +24,33 @@ public class EntryComparator implements Comparator<BibEntry> {
private final Comparator<BibEntry> next;
- public EntryComparator(boolean binary, boolean desc, String field, Comparator<BibEntry> next) {
+ public EntryComparator(boolean binary, boolean descending, String field, Comparator<BibEntry> next) {
this.binary = binary;
this.sortField = field;
- this.descending = desc;
+ this.descending = descending;
this.next = next;
this.numeric = InternalBibtexFields.isNumeric(sortField);
}
- public EntryComparator(boolean binary, boolean desc, String field) {
+ public EntryComparator(boolean binary, boolean descending, String field) {
this.binary = binary;
this.sortField = field;
- this.descending = desc;
+ this.descending = descending;
this.next = null;
this.numeric = InternalBibtexFields.isNumeric(sortField);
}
@Override
public int compare(BibEntry e1, BibEntry e2) {
-
+ // default equals
+ // TODO: with the new default equals this does not only return 0 for identical objects,
+ // but for all objects that have the same id and same fields
if (Objects.equals(e1, e2)) {
return 0;
}
- Object f1 = e1.getField(sortField);
- Object f2 = e2.getField(sortField);
+ Object f1 = e1.getField(sortField).orElse(null);
+ Object f2 = e2.getField(sortField).orElse(null);
if (binary) {
// We just separate on set and unset fields:
@@ -62,7 +63,7 @@ public class EntryComparator implements Comparator<BibEntry> {
// If the field is author or editor, we rearrange names so they are
// sorted according to last name.
- if (InternalBibtexFields.getFieldExtras(sortField).contains(FieldProperties.PERSON_NAMES)) {
+ if (InternalBibtexFields.getFieldProperties(sortField).contains(FieldProperty.PERSON_NAMES)) {
if (f1 != null) {
f1 = AuthorList.fixAuthorForAlphabetization((String) f1).toLowerCase();
}
@@ -87,12 +88,14 @@ public class EntryComparator implements Comparator<BibEntry> {
}
}
- if ((f1 == null) && (f2 == null)) {
- return next == null ? idCompare(e1, e2) : next.compare(e1, e2);
- }
- if ((f1 != null) && (f2 == null)) {
- return -1;
+ if (f2 == null) {
+ if (f1 == null) {
+ return next == null ? idCompare(e1, e2) : next.compare(e1, e2);
+ } else {
+ return -1;
+ }
}
+
if (f1 == null) { // f2 != null here automatically
return 1;
}
diff --git a/src/main/java/net/sf/jabref/logic/bibtex/comparator/FieldComparator.java b/src/main/java/net/sf/jabref/logic/bibtex/comparator/FieldComparator.java
index 0f86057..d032ad4 100644
--- a/src/main/java/net/sf/jabref/logic/bibtex/comparator/FieldComparator.java
+++ b/src/main/java/net/sf/jabref/logic/bibtex/comparator/FieldComparator.java
@@ -8,14 +8,14 @@ import java.util.Locale;
import java.util.Objects;
import java.util.Optional;
-import net.sf.jabref.logic.config.SaveOrderConfig;
-import net.sf.jabref.logic.util.strings.StringUtil;
import net.sf.jabref.model.entry.AuthorList;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.FieldName;
-import net.sf.jabref.model.entry.FieldProperties;
+import net.sf.jabref.model.entry.FieldProperty;
import net.sf.jabref.model.entry.InternalBibtexFields;
import net.sf.jabref.model.entry.MonthUtil;
+import net.sf.jabref.model.metadata.SaveOrderConfig;
+import net.sf.jabref.model.strings.StringUtil;
/**
* A comparator for BibEntry fields
@@ -62,7 +62,7 @@ public class FieldComparator implements Comparator<BibEntry> {
private FieldType determineFieldType() {
if(BibEntry.TYPE_HEADER.equals(this.field[0])) {
return FieldType.TYPE;
- } else if (InternalBibtexFields.getFieldExtras(this.field[0]).contains(FieldProperties.PERSON_NAMES)) {
+ } else if (InternalBibtexFields.getFieldProperties(this.field[0]).contains(FieldProperty.PERSON_NAMES)) {
return FieldType.NAME;
} else if (FieldName.YEAR.equals(this.field[0])) {
return FieldType.YEAR;
@@ -75,7 +75,7 @@ public class FieldComparator implements Comparator<BibEntry> {
private String getField(BibEntry entry) {
for (String aField : field) {
- Optional<String> o = entry.getFieldOrAlias(aField);
+ Optional<String> o = entry.getFieldOrAliasLatexFree(aField);
if (o.isPresent()) {
return o.get();
}
@@ -108,7 +108,7 @@ public class FieldComparator implements Comparator<BibEntry> {
return -multiplier;
}
- // Now we now that both f1 and f2 are != null
+ // Now we know that both f1 and f2 are != null
if (fieldType == FieldType.NAME) {
f1 = AuthorList.fixAuthorForAlphabetization(f1);
f2 = AuthorList.fixAuthorForAlphabetization(f2);
diff --git a/src/main/java/net/sf/jabref/logic/bibtexkeypattern/BibtexKeyPatternPreferences.java b/src/main/java/net/sf/jabref/logic/bibtexkeypattern/BibtexKeyPatternPreferences.java
index c158a08..c634b08 100644
--- a/src/main/java/net/sf/jabref/logic/bibtexkeypattern/BibtexKeyPatternPreferences.java
+++ b/src/main/java/net/sf/jabref/logic/bibtexkeypattern/BibtexKeyPatternPreferences.java
@@ -1,38 +1,27 @@
package net.sf.jabref.logic.bibtexkeypattern;
import net.sf.jabref.model.bibtexkeypattern.GlobalBibtexKeyPattern;
-import net.sf.jabref.preferences.JabRefPreferences;
public class BibtexKeyPatternPreferences {
- private final String defaultBibtexKeyPattern;
private final String keyPatternRegex;
private final String keyPatternReplacement;
private final boolean alwaysAddLetter;
private final boolean firstLetterA;
private final boolean enforceLegalKey;
private final GlobalBibtexKeyPattern keyPattern;
+ private Character keywordDelimiter;
- public BibtexKeyPatternPreferences(String defaultBibtexKeyPattern, String keyPatternRegex, String keyPatternReplacement,
- boolean alwaysAddLetter, boolean firstLetterA, boolean enforceLegalKey,
- GlobalBibtexKeyPattern keyPattern) {
- this.defaultBibtexKeyPattern = defaultBibtexKeyPattern;
+ public BibtexKeyPatternPreferences(String keyPatternRegex, String keyPatternReplacement, boolean alwaysAddLetter,
+ boolean firstLetterA, boolean enforceLegalKey, GlobalBibtexKeyPattern keyPattern,
+ Character keywordDelimiter) {
this.keyPatternRegex = keyPatternRegex;
this.keyPatternReplacement = keyPatternReplacement;
this.alwaysAddLetter = alwaysAddLetter;
this.firstLetterA = firstLetterA;
this.enforceLegalKey = enforceLegalKey;
this.keyPattern = keyPattern;
- }
-
- public static BibtexKeyPatternPreferences fromPreferences(JabRefPreferences jabRefPreferences) {
- return new BibtexKeyPatternPreferences(jabRefPreferences.get(JabRefPreferences.DEFAULT_BIBTEX_KEY_PATTERN),
- jabRefPreferences.get(JabRefPreferences.KEY_PATTERN_REGEX),
- jabRefPreferences.get(JabRefPreferences.KEY_PATTERN_REPLACEMENT),
- jabRefPreferences.getBoolean(JabRefPreferences.KEY_GEN_ALWAYS_ADD_LETTER),
- jabRefPreferences.getBoolean(JabRefPreferences.KEY_GEN_FIRST_LETTER_A),
- jabRefPreferences.getBoolean(JabRefPreferences.ENFORCE_LEGAL_BIBTEX_KEY),
- jabRefPreferences.getKeyPattern());
+ this.keywordDelimiter = keywordDelimiter;
}
public String getKeyPatternRegex() {
@@ -55,9 +44,11 @@ public class BibtexKeyPatternPreferences {
return enforceLegalKey;
}
- public String getDefaultBibtexKeyPattern() { return defaultBibtexKeyPattern;}
-
public GlobalBibtexKeyPattern getKeyPattern() {
return keyPattern;
}
+
+ public Character getKeywordDelimiter() {
+ return keywordDelimiter;
+ }
}
diff --git a/src/main/java/net/sf/jabref/logic/bibtexkeypattern/BibtexKeyPatternUtil.java b/src/main/java/net/sf/jabref/logic/bibtexkeypattern/BibtexKeyPatternUtil.java
index 01da29d..7178b03 100644
--- a/src/main/java/net/sf/jabref/logic/bibtexkeypattern/BibtexKeyPatternUtil.java
+++ b/src/main/java/net/sf/jabref/logic/bibtexkeypattern/BibtexKeyPatternUtil.java
@@ -2,21 +2,27 @@ package net.sf.jabref.logic.bibtexkeypattern;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
-import java.util.Set;
+import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import net.sf.jabref.MetaData;
+import net.sf.jabref.logic.formatter.Formatters;
import net.sf.jabref.logic.formatter.casechanger.Word;
-import net.sf.jabref.logic.layout.format.RemoveLatexCommands;
-import net.sf.jabref.logic.util.strings.StringUtil;
+import net.sf.jabref.logic.layout.format.RemoveLatexCommandsFormatter;
+import net.sf.jabref.model.bibtexkeypattern.AbstractBibtexKeyPattern;
+import net.sf.jabref.model.cleanup.Formatter;
import net.sf.jabref.model.database.BibDatabase;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.entry.AuthorList;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.FieldName;
+import net.sf.jabref.model.entry.Keyword;
+import net.sf.jabref.model.entry.KeywordList;
+import net.sf.jabref.model.strings.StringUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -26,29 +32,17 @@ import org.apache.commons.logging.LogFactory;
* This is the utility class of the LabelPattern package.
*/
public class BibtexKeyPatternUtil {
+ private static final Log LOGGER = LogFactory.getLog(BibtexKeyPatternUtil.class);
private static final String STARTING_CAPITAL_PATTERN = "[^A-Z]";
// All single characters that we can use for extending a key to make it unique:
private static final String CHARS = "abcdefghijklmnopqrstuvwxyz";
- private static final Log LOGGER = LogFactory.getLog(BibtexKeyPatternUtil.class);
-
private static final Pattern REGEX_PATTERN = Pattern.compile(".*\\(\\{([A-Z]+)\\}\\).*");
private static final int CHARS_OF_FIRST = 5;
- private static BibDatabase database;
-
- /**
- * Required for LabelPatternUtilTest
- *
- * @param db the DB to use as global database
- */
- public static void setDataBase(BibDatabase db) {
- database = db;
- }
-
private static String normalize(String content) {
List<String> tokens = new ArrayList<>();
int b = 0;
@@ -369,24 +363,25 @@ public class BibtexKeyPatternUtil {
*
* The given database is used to avoid duplicate keys.
*
- * @param dBase a <code>BibDatabase</code>
+ * @param citeKeyPattern
+ * @param database a <code>BibDatabase</code>
* @param entry a <code>BibEntry</code>
* @return modified BibEntry
*/
- public static void makeLabel(MetaData metaData, BibDatabase dBase, BibEntry entry,
+ public static void makeAndSetLabel(AbstractBibtexKeyPattern citeKeyPattern, BibDatabase database, BibEntry entry,
BibtexKeyPatternPreferences bibtexKeyPatternPreferences) {
- database = dBase;
+ String newKey = makeLabel(citeKeyPattern, database, entry, bibtexKeyPatternPreferences);
+ entry.setCiteKey(newKey);
+ }
+
+ private static String makeLabel(AbstractBibtexKeyPattern citeKeyPattern, BibDatabase database, BibEntry entry, BibtexKeyPatternPreferences bibtexKeyPatternPreferences) {
String key;
StringBuilder stringBuilder = new StringBuilder();
- boolean forceUpper = false;
- boolean forceLower = false;
-
try {
// get the type of entry
String entryType = entry.getType();
// Get the arrayList corresponding to the type
- List<String> typeList = new ArrayList<>(
- metaData.getBibtexKeyPattern(bibtexKeyPatternPreferences.getKeyPattern()).getValue(entryType));
+ List<String> typeList = new ArrayList<>(citeKeyPattern.getValue(entryType));
if (!typeList.isEmpty()) {
typeList.remove(0);
}
@@ -399,12 +394,11 @@ public class BibtexKeyPatternUtil {
} else if (field) {
// check whether there is a modifier on the end such as
// ":lower"
- String[] parts = parseFieldMarker(typeListEntry);
-
- String label = makeLabel(entry, parts[0]);
+ List<String> parts = parseFieldMarker(typeListEntry);
+ String label = makeLabel(entry, parts.get(0), bibtexKeyPatternPreferences.getKeywordDelimiter(), database);
// apply modifier if present
- if (parts.length > 1) {
+ if (parts.size() > 1) {
label = applyModifiers(label, parts, 1);
}
@@ -428,15 +422,8 @@ public class BibtexKeyPatternUtil {
key = key.replaceAll(regex, replacement);
}
- if (forceUpper) {
- key = key.toUpperCase(Locale.ENGLISH);
- }
- if (forceLower) {
- key = key.toLowerCase(Locale.ENGLISH);
- }
-
String oldKey = entry.getCiteKeyOptional().orElse(null);
- int occurrences = database.getNumberOfKeyOccurrences(key);
+ int occurrences = database.getDuplicationChecker().getNumberOfKeyOccurrences(key);
if (Objects.equals(oldKey, key)) {
occurrences--; // No change, so we can accept one dupe.
@@ -445,50 +432,28 @@ public class BibtexKeyPatternUtil {
boolean alwaysAddLetter = bibtexKeyPatternPreferences.isAlwaysAddLetter();
boolean firstLetterA = bibtexKeyPatternPreferences.isFirstLetterA();
+ String newKey;
if (!alwaysAddLetter && (occurrences == 0)) {
- // No dupes found, so we can just go ahead.
- if (!key.equals(oldKey)) {
- if (database.containsEntryWithId(entry.getId())) {
- database.setCiteKeyForEntry(entry, key);
- } else {
- // entry does not (yet) exist in the database, just update the entry
- entry.setCiteKey(key);
- }
- }
-
+ newKey = key;
} else {
// The key is already in use, so we must modify it.
- int number = 0;
- if (!alwaysAddLetter && !firstLetterA) {
- number = 1;
- }
+ int number = !alwaysAddLetter && !firstLetterA ? 1 : 0;
+ String moddedKey;
- String moddedKey = key + getAddition(number);
- occurrences = database.getNumberOfKeyOccurrences(moddedKey);
-
- if (Objects.equals(oldKey, moddedKey)) {
- occurrences--;
- }
-
- while (occurrences > 0) {
- number++;
+ do {
moddedKey = key + getAddition(number);
+ number++;
- occurrences = database.getNumberOfKeyOccurrences(moddedKey);
+ occurrences = database.getDuplicationChecker().getNumberOfKeyOccurrences(moddedKey);
+ // only happens if #getAddition() is buggy
if (Objects.equals(oldKey, moddedKey)) {
occurrences--;
}
- }
+ } while (occurrences > 0);
- if (!moddedKey.equals(oldKey)) {
- if (database.containsEntryWithId(entry.getId())) {
- database.setCiteKeyForEntry(entry, moddedKey);
- } else {
- // entry does not (yet) exist in the database, just update the entry
- entry.setCiteKey(moddedKey);
- }
- }
+ newKey = moddedKey;
}
+ return newKey;
}
/**
@@ -498,17 +463,13 @@ public class BibtexKeyPatternUtil {
* @param offset The number of initial items in the modifiers array to skip.
* @return The modified label.
*/
- public static String applyModifiers(String label, String[] parts, int offset) {
+ public static String applyModifiers(final String label, final List<String> parts, final int offset) {
String resultingLabel = label;
- if (parts.length > offset) {
- for (int j = offset; j < parts.length; j++) {
- String modifier = parts[j];
-
- if ("lower".equals(modifier)) {
- resultingLabel = resultingLabel.toLowerCase(Locale.ENGLISH);
- } else if ("upper".equals(modifier)) {
- resultingLabel = resultingLabel.toUpperCase(Locale.ENGLISH);
- } else if ("abbr".equals(modifier)) {
+ if (parts.size() > offset) {
+ for (int j = offset; j < parts.size(); j++) {
+ String modifier = parts.get(j);
+
+ if ("abbr".equals(modifier)) {
// Abbreviate - that is,
StringBuilder abbreviateSB = new StringBuilder();
String[] words = resultingLabel.replaceAll("[\\{\\}']", "")
@@ -518,25 +479,32 @@ public class BibtexKeyPatternUtil {
abbreviateSB.append(word.charAt(0));
}
}
- resultingLabel = abbreviateSB.toString();
-
- } else if (!modifier.isEmpty() && (modifier.charAt(0) == '(') && modifier.endsWith(")")) {
- // Alternate text modifier in parentheses. Should be inserted if
- // the label is empty:
- if (resultingLabel.isEmpty() && (modifier.length() > 2)) {
- return modifier.substring(1, modifier.length() - 1);
- }
-
+ resultingLabel = abbreviateSB.toString();
} else {
- LOGGER.info("Key generator warning: unknown modifier '"
- + modifier + "'.");
+ Optional<Formatter> formatter = Formatters.getFormatterForModifier(modifier);
+ if (formatter.isPresent()) {
+ resultingLabel = formatter.get().format(label);
+ } else if (!modifier.isEmpty() && modifier.length()>= 2 && (modifier.charAt(0) == '(') && modifier.endsWith(")")) {
+ // Alternate text modifier in parentheses. Should be inserted if
+ // the label is empty:
+ if (label.isEmpty() && (modifier.length() > 2)) {
+ resultingLabel = modifier.substring(1, modifier.length() - 1);
+ } else {
+ resultingLabel = label;
+ }
+ } else {
+ LOGGER.info("Key generator warning: unknown modifier '"
+ + modifier + "'.");
+ resultingLabel = label;
+ }
}
}
}
+
return resultingLabel;
}
- public static String makeLabel(BibEntry entry, String value) {
+ public static String makeLabel(BibEntry entry, String value, Character keywordDelimiter, BibDatabase database) {
String val = value;
try {
if (val.startsWith("auth") || val.startsWith("pureauth")) {
@@ -551,7 +519,7 @@ public class BibtexKeyPatternUtil {
* form "pureauth..." which does not do this fallback
* substitution of editor.
*/
- String authString = entry.getFieldOptional(FieldName.AUTHOR)
+ String authString = entry.getField(FieldName.AUTHOR)
.map(authorString -> normalize(database.resolveForStrings(authorString))).orElse("");
if (val.startsWith("pure")) {
@@ -561,7 +529,7 @@ public class BibtexKeyPatternUtil {
}
if (authString.isEmpty()) {
- authString = entry.getFieldOptional(FieldName.EDITOR)
+ authString = entry.getField(FieldName.EDITOR)
.map(authorString -> normalize(database.resolveForStrings(authorString))).orElse("");
}
@@ -587,86 +555,69 @@ public class BibtexKeyPatternUtil {
return oneAuthorPlusIni(authString);
} else if (val.matches("authIni[\\d]+")) {
int num = Integer.parseInt(val.substring(7));
- String s = authIniN(authString, num);
- return s == null ? "" : s;
+ return authIniN(authString, num);
} else if ("auth.auth.ea".equals(val)) {
- String s = authAuthEa(authString);
- return s == null ? "" : s;
+ return authAuthEa(authString);
} else if ("auth.etal".equals(val)) {
- String s = authEtal(authString, ".", ".etal");
- return s == null ? "" : s;
+ return authEtal(authString, ".", ".etal");
} else if ("authEtAl".equals(val)) {
- String s = authEtal(authString, "", "EtAl");
- return s == null ? "" : s;
+ return authEtal(authString, "", "EtAl");
} else if ("authshort".equals(val)) {
- String s = authshort(authString);
- return s == null ? "" : s;
+ return authshort(authString);
} else if (val.matches("auth[\\d]+_[\\d]+")) {
String[] nums = val.substring(4).split("_");
- String s = authNofMth(authString, Integer.parseInt(nums[0]),
+ return authNofMth(authString, Integer.parseInt(nums[0]),
Integer.parseInt(nums[1]));
- return s == null ? "" : s;
} else if (val.matches("auth\\d+")) {
// authN. First N chars of the first author's last
// name.
String fa = firstAuthor(authString);
- if (fa == null) {
- return "";
- }
int num = Integer.parseInt(val.substring(4));
if (num > fa.length()) {
num = fa.length();
}
return fa.substring(0, num);
} else if (val.matches("authors\\d+")) {
- String s = nAuthors(authString, Integer.parseInt(val.substring(7)));
- return s == null ? "" : s;
+ return nAuthors(authString, Integer.parseInt(val.substring(7)));
} else {
// This "auth" business was a dead end, so just
// use it literally:
- return getField(entry, val);
+ return entry.getFieldOrAlias(val).orElse("");
}
} else if (val.startsWith("ed")) {
// Gather all markers starting with "ed" here, so we
// don't have to check all the time.
if ("edtr".equals(val)) {
- return firstAuthor(entry.getFieldOptional(FieldName.EDITOR).orElse(""));
+ return firstAuthor(entry.getField(FieldName.EDITOR).orElse(""));
} else if ("edtrForeIni".equals(val)) {
- return firstAuthorForenameInitials(entry.getFieldOptional(FieldName.EDITOR).orElse(""));
+ return firstAuthorForenameInitials(entry.getField(FieldName.EDITOR).orElse(""));
} else if ("editors".equals(val)) {
- return allAuthors(entry.getFieldOptional(FieldName.EDITOR).orElse(""));
+ return allAuthors(entry.getField(FieldName.EDITOR).orElse(""));
// Last author's last name
} else if ("editorLast".equals(val)) {
- return lastAuthor(entry.getFieldOptional(FieldName.EDITOR).orElse(""));
+ return lastAuthor(entry.getField(FieldName.EDITOR).orElse(""));
} else if ("editorLastForeIni".equals(val)) {
- return lastAuthorForenameInitials(entry.getFieldOptional(FieldName.EDITOR).orElse(""));
+ return lastAuthorForenameInitials(entry.getField(FieldName.EDITOR).orElse(""));
} else if ("editorIni".equals(val)) {
- return oneAuthorPlusIni(entry.getFieldOptional(FieldName.EDITOR).orElse(""));
+ return oneAuthorPlusIni(entry.getField(FieldName.EDITOR).orElse(""));
} else if (val.matches("edtrIni[\\d]+")) {
int num = Integer.parseInt(val.substring(7));
- String s = authIniN(entry.getFieldOptional(FieldName.EDITOR).orElse(""), num);
- return s == null ? "" : s;
+ return authIniN(entry.getField(FieldName.EDITOR).orElse(""), num);
} else if (val.matches("edtr[\\d]+_[\\d]+")) {
String[] nums = val.substring(4).split("_");
- String s = authNofMth(entry.getFieldOptional(FieldName.EDITOR).orElse(""),
+ return authNofMth(entry.getField(FieldName.EDITOR).orElse(""),
Integer.parseInt(nums[0]),
Integer.parseInt(nums[1]) - 1);
- return s == null ? "" : s;
} else if ("edtr.edtr.ea".equals(val)) {
- String s = authAuthEa(entry.getFieldOptional(FieldName.EDITOR).orElse(""));
- return s == null ? "" : s;
+ return authAuthEa(entry.getField(FieldName.EDITOR).orElse(""));
} else if ("edtrshort".equals(val)) {
- String s = authshort(entry.getFieldOptional(FieldName.EDITOR).orElse(""));
- return s == null ? "" : s;
+ return authshort(entry.getField(FieldName.EDITOR).orElse(""));
}
// authN. First N chars of the first author's last
// name.
else if (val.matches("edtr\\d+")) {
- String fa = firstAuthor(entry.getFieldOptional(FieldName.EDITOR).orElse(""));
- if (fa == null) {
- return "";
- }
+ String fa = firstAuthor(entry.getField(FieldName.EDITOR).orElse(""));
int num = Integer.parseInt(val.substring(4));
if (num > fa.length()) {
num = fa.length();
@@ -675,41 +626,42 @@ public class BibtexKeyPatternUtil {
} else {
// This "ed" business was a dead end, so just
// use it literally:
- return getField(entry, val);
+ return entry.getFieldOrAlias(val).orElse("");
}
} else if ("firstpage".equals(val)) {
- return firstPage(entry.getFieldOptional(FieldName.PAGES).orElse(""));
+ return firstPage(entry.getField(FieldName.PAGES).orElse(""));
} else if ("lastpage".equals(val)) {
- return lastPage(entry.getFieldOptional(FieldName.PAGES).orElse(""));
+ return lastPage(entry.getField(FieldName.PAGES).orElse(""));
} else if ("shorttitle".equals(val)) {
- return getTitleWords(3, entry.getFieldOptional(FieldName.TITLE).orElse(""));
+ return getTitleWords(3, entry.getField(FieldName.TITLE).orElse(""));
} else if ("shorttitleINI".equals(val)) {
return keepLettersAndDigitsOnly(
- applyModifiers(getTitleWordsWithSpaces(3, entry.getFieldOptional(FieldName.TITLE).orElse("")),
- new String[] {"abbr"}, 0));
+ applyModifiers(getTitleWordsWithSpaces(3, entry.getField(FieldName.TITLE).orElse("")),
+ Collections.singletonList("abbr"), 0));
} else if ("veryshorttitle".equals(val)) {
- return getTitleWords(1, entry.getFieldOptional(FieldName.TITLE).orElse(""));
+ return getTitleWords(1, entry.getField(FieldName.TITLE).orElse(""));
} else if ("shortyear".equals(val)) {
- String ss = entry.getFieldOrAlias(FieldName.YEAR).orElse("");
- if (ss.isEmpty()) {
- return ss;
- } else if (ss.startsWith("in") || ss.startsWith("sub")) {
+ String yearString = entry.getFieldOrAlias(FieldName.YEAR).orElse("");
+ if (yearString.isEmpty()) {
+ return yearString;
+ // In press/in preparation/submitted
+ } else if (yearString.startsWith("in") || yearString.startsWith("sub")) {
return "IP";
- } else if (ss.length() > 2) {
- return ss.substring(ss.length() - 2);
+ } else if (yearString.length() > 2) {
+ return yearString.substring(yearString.length() - 2);
} else {
- return ss;
+ return yearString;
}
} else if (val.matches("keyword\\d+")) {
// according to LabelPattern.php, it returns keyword number n
int num = Integer.parseInt(val.substring(7));
- Set<String> separatedKeywords = entry.getKeywords();
+ KeywordList separatedKeywords = entry.getKeywords(keywordDelimiter);
if (separatedKeywords.size() < num) {
// not enough keywords
return "";
} else {
// num counts from 1 to n, but index in arrayList count from 0 to n-1
- return new ArrayList<>(separatedKeywords).get(num-1);
+ return separatedKeywords.get(num-1).toString();
}
} else if (val.matches("keywords\\d*")) {
// return all keywords, not separated
@@ -719,13 +671,12 @@ public class BibtexKeyPatternUtil {
} else {
num = Integer.MAX_VALUE;
}
- Set<String> separatedKeywords = entry.getKeywords();
+ KeywordList separatedKeywords = entry.getKeywords(keywordDelimiter);
StringBuilder sb = new StringBuilder();
int i = 0;
- for (String keyword : separatedKeywords) {
+ for (Keyword keyword : separatedKeywords) {
// remove all spaces
- keyword = keyword.replaceAll("\\s+", "");
- sb.append(keyword);
+ sb.append(keyword.toString().replaceAll("\\s+", ""));
i++;
if (i >= num) {
@@ -735,7 +686,7 @@ public class BibtexKeyPatternUtil {
return sb.toString();
} else {
// we haven't seen any special demands
- return getField(entry, val);
+ return entry.getFieldOrAlias(val).orElse("");
}
} catch (NullPointerException ex) {
LOGGER.debug("Problem making label", ex);
@@ -745,17 +696,6 @@ public class BibtexKeyPatternUtil {
}
/**
- * Look up a field of a BibEntry, returning its String value, or an
- * empty string if it isn't set.
- * @param entry The entry.
- * @param field The field to look up.
- * @return The field value.
- */
- private static String getField(BibEntry entry, String field) {
- return entry.getFieldOrAlias(field).orElse("");
- }
-
- /**
* Computes an appendix to a BibTeX key that could make it unique. We use
* a-z for numbers 0-25, and then aa-az, ba-bz, etc.
*
@@ -780,7 +720,7 @@ public class BibtexKeyPatternUtil {
}
private static String getTitleWordsWithSpaces(int number, String title) {
- String ss = new RemoveLatexCommands().format(title);
+ String ss = new RemoveLatexCommandsFormatter().format(title);
StringBuilder stringBuilder = new StringBuilder();
StringBuilder current;
int piv = 0;
@@ -866,8 +806,7 @@ public class BibtexKeyPatternUtil {
if (authorList.isEmpty()) {
return "";
}
- String s = authorList.getAuthor(0).getFirstAbbr();
- return s == null ? "" : s.substring(0, 1);
+ return authorList.getAuthor(0).getFirstAbbr().map(s -> s.substring(0, 1)).orElse("");
}
/**
@@ -926,8 +865,8 @@ public class BibtexKeyPatternUtil {
if (authorList.isEmpty()) {
return "";
}
- String s = authorList.getAuthor(authorList.getNumberOfAuthors() - 1).getFirstAbbr();
- return s == null ? "" : s.substring(0, 1);
+ return authorList.getAuthor(authorList.getNumberOfAuthors() - 1).getFirstAbbr().map(s -> s.substring(0, 1))
+ .orElse("");
}
/**
@@ -1285,37 +1224,38 @@ public class BibtexKeyPatternUtil {
* @param arg The argument string.
* @return An array of strings representing the parts of the marker
*/
- private static String[] parseFieldMarker(String arg) {
+ private static List<String> parseFieldMarker(String arg) {
List<String> parts = new ArrayList<>();
StringBuilder current = new StringBuilder();
boolean escaped = false;
int inParenthesis = 0;
for (int i = 0; i < arg.length(); i++) {
- if ((arg.charAt(i) == ':') && !escaped && (inParenthesis == 0)) {
+ char currentChar = arg.charAt(i);
+ if ((currentChar == ':') && !escaped && (inParenthesis == 0)) {
parts.add(current.toString());
current = new StringBuilder();
- } else if ((arg.charAt(i) == '(') && !escaped) {
+ } else if ((currentChar == '(') && !escaped) {
inParenthesis++;
- current.append(arg.charAt(i));
- } else if ((arg.charAt(i) == ')') && !escaped && (inParenthesis > 0)) {
+ current.append(currentChar);
+ } else if ((currentChar == ')') && !escaped && (inParenthesis > 0)) {
inParenthesis--;
- current.append(arg.charAt(i));
- } else if (arg.charAt(i) == '\\') {
+ current.append(currentChar);
+ } else if (currentChar == '\\') {
if (escaped) {
escaped = false;
- current.append(arg.charAt(i));
+ current.append(currentChar);
} else {
escaped = true;
}
} else if (escaped) {
- current.append(arg.charAt(i));
+ current.append(currentChar);
escaped = false;
} else {
- current.append(arg.charAt(i));
+ current.append(currentChar);
}
}
parts.add(current.toString());
- return parts.toArray(new String[parts.size()]);
+ return parts;
}
@@ -1360,4 +1300,10 @@ public class BibtexKeyPatternUtil {
return StringUtil.replaceSpecialCharacters(newKey.toString());
}
+ public static String makeLabel(BibDatabaseContext bibDatabaseContext,
+ BibEntry entry,
+ BibtexKeyPatternPreferences bibtexKeyPatternPreferences) {
+ AbstractBibtexKeyPattern citeKeyPattern = bibDatabaseContext.getMetaData().getCiteKeyPattern(bibtexKeyPatternPreferences.getKeyPattern());
+ return makeLabel(citeKeyPattern, bibDatabaseContext.getDatabase(), entry, bibtexKeyPatternPreferences);
+ }
}
diff --git a/src/main/java/net/sf/jabref/logic/bst/VM.java b/src/main/java/net/sf/jabref/logic/bst/VM.java
index be4d7ef..0d31021 100644
--- a/src/main/java/net/sf/jabref/logic/bst/VM.java
+++ b/src/main/java/net/sf/jabref/logic/bst/VM.java
@@ -64,7 +64,7 @@ public class VM implements Warn {
private StringBuilder bbl;
- private String preamble;
+ private String preamble = "";
private static final Pattern ADD_PERIOD_PATTERN = Pattern.compile("([^\\.\\?\\!\\}\\s])(\\}|\\s)*$");
@@ -298,7 +298,7 @@ public class VM implements Warn {
if (context == null) {
throw new VMException("Must have an entry to cite$");
}
- stack.push(context.getBibtexEntry().getCiteKey());
+ stack.push(context.getBibtexEntry().getCiteKeyOptional().orElse(null));
});
/**
@@ -471,11 +471,7 @@ public class VM implements Warn {
* @PREAMBLE strings read from the database files.
*/
buildInFunctions.put("preamble$", context -> {
- if (preamble == null) {
- stack.push("");
- } else {
- stack.push(preamble);
- }
+ stack.push(preamble);
});
/**
@@ -836,7 +832,7 @@ public class VM implements Warn {
public String run(BibDatabase db) {
- preamble = db.getPreamble();
+ preamble = db.getPreamble().orElse("");
return run(db.getEntries());
}
@@ -919,7 +915,7 @@ public class VM implements Warn {
for (BstEntry e : entries) {
for (Map.Entry<String, String> mEntry : e.getFields().entrySet()) {
- String fieldValue = e.getBibtexEntry().getField(mEntry.getKey());
+ String fieldValue = e.getBibtexEntry().getField(mEntry.getKey()).orElse(null);
mEntry.setValue(fieldValue);
}
diff --git a/src/main/java/net/sf/jabref/logic/cleanup/BiblatexCleanup.java b/src/main/java/net/sf/jabref/logic/cleanup/BiblatexCleanup.java
index 4b7e05e..9a098de 100644
--- a/src/main/java/net/sf/jabref/logic/cleanup/BiblatexCleanup.java
+++ b/src/main/java/net/sf/jabref/logic/cleanup/BiblatexCleanup.java
@@ -3,12 +3,13 @@ package net.sf.jabref.logic.cleanup;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
-import java.util.Optional;
import net.sf.jabref.model.FieldChange;
+import net.sf.jabref.model.cleanup.CleanupJob;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.EntryConverter;
import net.sf.jabref.model.entry.FieldName;
+import net.sf.jabref.model.strings.StringUtil;
/**
* Converts the entry to BibLatex format.
@@ -21,35 +22,24 @@ public class BiblatexCleanup implements CleanupJob {
for (Map.Entry<String, String> alias : EntryConverter.FIELD_ALIASES_TEX_TO_LTX.entrySet()) {
String oldFieldName = alias.getKey();
String newFieldName = alias.getValue();
- entry.getFieldOptional(oldFieldName).ifPresent(oldValue -> {
- if (!oldValue.isEmpty() && (!entry.getFieldOptional(newFieldName).isPresent())) {
+ entry.getField(oldFieldName).ifPresent(oldValue -> {
+ if (!oldValue.isEmpty() && (!entry.getField(newFieldName).isPresent())) {
// There is content in the old field and no value in the new, so just copy
- entry.setField(newFieldName, oldValue);
- changes.add(new FieldChange(entry, newFieldName, null, oldValue));
-
- entry.clearField(oldFieldName);
- changes.add(new FieldChange(entry, oldFieldName, oldValue, null));
+ entry.setField(newFieldName, oldValue).ifPresent(changes::add);
+ entry.clearField(oldFieldName).ifPresent(changes::add);
}
});
}
-
// Dates: create date out of year and month, save it and delete old fields
- entry.getFieldOptional(FieldName.DATE).ifPresent(date -> {
- if (date.isEmpty()) {
- entry.getFieldOrAlias(FieldName.DATE).ifPresent(newDate -> {
- Optional<String> oldYear = entry.getFieldOptional(FieldName.YEAR);
- Optional<String> oldMonth = entry.getFieldOptional(FieldName.MONTH);
-
- entry.setField(FieldName.DATE, newDate);
- entry.clearField(FieldName.YEAR);
- entry.clearField(FieldName.MONTH);
-
- changes.add(new FieldChange(entry, FieldName.DATE, null, newDate));
- changes.add(new FieldChange(entry, FieldName.YEAR, oldYear.orElse(null), null));
- changes.add(new FieldChange(entry, FieldName.MONTH, oldMonth.orElse(null), null));
- });
- }
- });
+ // If there already exists a non blank/empty value for the field date, it is not overwritten
+ if (StringUtil.isBlank(entry.getField(FieldName.DATE))) {
+ entry.getFieldOrAlias(FieldName.DATE).ifPresent(newDate -> {
+ entry.setField(FieldName.DATE, newDate).ifPresent(changes::add);
+ entry.clearField(FieldName.YEAR).ifPresent(changes::add);
+ entry.clearField(FieldName.MONTH).ifPresent(changes::add);
+ });
+ }
return changes;
}
+
}
diff --git a/src/main/java/net/sf/jabref/logic/cleanup/CleanupJob.java b/src/main/java/net/sf/jabref/logic/cleanup/CleanupJob.java
deleted file mode 100644
index f3a6eb2..0000000
--- a/src/main/java/net/sf/jabref/logic/cleanup/CleanupJob.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package net.sf.jabref.logic.cleanup;
-
-import java.util.List;
-
-import net.sf.jabref.model.FieldChange;
-import net.sf.jabref.model.entry.BibEntry;
-
- at FunctionalInterface
-public interface CleanupJob {
-
- /**
- * Cleanup the entry.
- */
- List<FieldChange> cleanup(BibEntry entry);
-
-}
diff --git a/src/main/java/net/sf/jabref/logic/cleanup/CleanupPreferences.java b/src/main/java/net/sf/jabref/logic/cleanup/CleanupPreferences.java
new file mode 100644
index 0000000..125825b
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/cleanup/CleanupPreferences.java
@@ -0,0 +1,37 @@
+package net.sf.jabref.logic.cleanup;
+
+import net.sf.jabref.logic.layout.LayoutFormatterPreferences;
+import net.sf.jabref.model.metadata.FileDirectoryPreferences;
+
+public class CleanupPreferences {
+
+ private final String fileNamePattern;
+ private final String fileDirPattern;
+ private final LayoutFormatterPreferences layoutFormatterPreferences;
+ private final FileDirectoryPreferences fileDirectoryPreferences;
+
+
+ public CleanupPreferences(String fileNamePattern, String fileDirPattern,
+ LayoutFormatterPreferences layoutFormatterPreferences, FileDirectoryPreferences fileDirectoryPreferences) {
+ this.fileNamePattern = fileNamePattern;
+ this.fileDirPattern = fileDirPattern;
+ this.layoutFormatterPreferences = layoutFormatterPreferences;
+ this.fileDirectoryPreferences = fileDirectoryPreferences;
+ }
+
+ public String getFileNamePattern() {
+ return fileNamePattern;
+ }
+
+ public String getFileDirPattern() {
+ return fileDirPattern;
+ }
+
+ public LayoutFormatterPreferences getLayoutFormatterPreferences() {
+ return layoutFormatterPreferences;
+ }
+
+ public FileDirectoryPreferences getFileDirectoryPreferences() {
+ return fileDirectoryPreferences;
+ }
+}
diff --git a/src/main/java/net/sf/jabref/logic/cleanup/CleanupPreset.java b/src/main/java/net/sf/jabref/logic/cleanup/CleanupPreset.java
index 7c30acf..580a862 100644
--- a/src/main/java/net/sf/jabref/logic/cleanup/CleanupPreset.java
+++ b/src/main/java/net/sf/jabref/logic/cleanup/CleanupPreset.java
@@ -5,7 +5,8 @@ import java.util.EnumSet;
import java.util.Objects;
import java.util.Set;
-import net.sf.jabref.logic.exporter.FieldFormatterCleanups;
+import net.sf.jabref.logic.util.OS;
+import net.sf.jabref.model.cleanup.FieldFormatterCleanups;
import net.sf.jabref.preferences.JabRefPreferences;
public class CleanupPreset {
@@ -63,7 +64,7 @@ public class CleanupPreset {
activeJobs.add(CleanupStep.FIX_FILE_LINKS);
}
- FieldFormatterCleanups formatterCleanups = FieldFormatterCleanups.parse(
+ FieldFormatterCleanups formatterCleanups = Cleanups.parse(
preferences.getStringList(JabRefPreferences.CLEANUP_FORMATTERS));
return new CleanupPreset(activeJobs, formatterCleanups);
@@ -118,7 +119,7 @@ public class CleanupPreset {
preferences.putBoolean(JabRefPreferences.CLEANUP_CONVERT_TO_BIBLATEX, isActive(CleanupStep.CONVERT_TO_BIBLATEX));
preferences.putBoolean(JabRefPreferences.CLEANUP_FIX_FILE_LINKS, isActive(CleanupStep.FIX_FILE_LINKS));
- preferences.putStringList(JabRefPreferences.CLEANUP_FORMATTERS, formatterCleanups.getAsStringList());
+ preferences.putStringList(JabRefPreferences.CLEANUP_FORMATTERS, formatterCleanups.getAsStringList(OS.NEWLINE));
}
private Boolean isActive(CleanupStep step) {
diff --git a/src/main/java/net/sf/jabref/logic/cleanup/CleanupWorker.java b/src/main/java/net/sf/jabref/logic/cleanup/CleanupWorker.java
index cbb03bd..8b39603 100644
--- a/src/main/java/net/sf/jabref/logic/cleanup/CleanupWorker.java
+++ b/src/main/java/net/sf/jabref/logic/cleanup/CleanupWorker.java
@@ -1,29 +1,32 @@
package net.sf.jabref.logic.cleanup;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
import java.util.Objects;
-import net.sf.jabref.BibDatabaseContext;
import net.sf.jabref.logic.layout.LayoutFormatterPreferences;
import net.sf.jabref.model.FieldChange;
+import net.sf.jabref.model.cleanup.CleanupJob;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.model.entry.FieldName;
+import net.sf.jabref.model.metadata.FileDirectoryPreferences;
public class CleanupWorker {
private final BibDatabaseContext databaseContext;
private final String fileNamePattern;
+ private final String fileDirPattern;
private final LayoutFormatterPreferences prefs;
+ private final FileDirectoryPreferences fileDirectoryPreferences;
private int unsuccessfulRenames;
- public CleanupWorker(BibDatabaseContext databaseContext, String fileNamePattern,
- LayoutFormatterPreferences prefs) {
+ public CleanupWorker(BibDatabaseContext databaseContext, CleanupPreferences cleanupPreferences) {
this.databaseContext = databaseContext;
- this.fileNamePattern = fileNamePattern;
- this.prefs = prefs;
+ this.fileNamePattern = cleanupPreferences.getFileNamePattern();
+ this.fileDirPattern = cleanupPreferences.getFileDirPattern();
+ this.prefs = cleanupPreferences.getLayoutFormatterPreferences();
+ this.fileDirectoryPreferences = cleanupPreferences.getFileDirectoryPreferences();
}
public int getUnsuccessfulRenames() {
@@ -48,7 +51,7 @@ public class CleanupWorker {
List<CleanupJob> jobs = new ArrayList<>();
if (preset.isCleanUpUpgradeExternalLinks()) {
- jobs.add(new UpgradePdfPsToFileCleanup(Arrays.asList(FieldName.PDF, FieldName.PS)));
+ jobs.add(new UpgradePdfPsToFileCleanup());
}
if (preset.isCleanUpDOI()) {
jobs.add(new DoiCleanup());
@@ -60,14 +63,14 @@ public class CleanupWorker {
jobs.add(new FileLinksCleanup());
}
if (preset.isMovePDF()) {
- jobs.add(new MoveFilesCleanup(databaseContext));
+ jobs.add(new MoveFilesCleanup(databaseContext, fileDirectoryPreferences));
}
if (preset.isMakePathsRelative()) {
- jobs.add(new RelativePathsCleanup(databaseContext));
+ jobs.add(new RelativePathsCleanup(databaseContext, fileDirectoryPreferences));
}
if (preset.isRenamePDF()) {
RenamePdfCleanup cleaner = new RenamePdfCleanup(preset.isRenamePdfOnlyRelativePaths(), databaseContext,
- fileNamePattern, prefs);
+ fileNamePattern, fileDirPattern, prefs, fileDirectoryPreferences);
jobs.add(cleaner);
unsuccessfulRenames += cleaner.getUnsuccessfulRenames();
}
diff --git a/src/main/java/net/sf/jabref/logic/cleanup/Cleanups.java b/src/main/java/net/sf/jabref/logic/cleanup/Cleanups.java
new file mode 100644
index 0000000..e7adeb4
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/cleanup/Cleanups.java
@@ -0,0 +1,140 @@
+package net.sf.jabref.logic.cleanup;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import net.sf.jabref.logic.formatter.Formatters;
+import net.sf.jabref.logic.formatter.IdentityFormatter;
+import net.sf.jabref.logic.formatter.bibtexfields.HtmlToLatexFormatter;
+import net.sf.jabref.logic.formatter.bibtexfields.HtmlToUnicodeFormatter;
+import net.sf.jabref.logic.formatter.bibtexfields.NormalizeDateFormatter;
+import net.sf.jabref.logic.formatter.bibtexfields.NormalizeMonthFormatter;
+import net.sf.jabref.logic.formatter.bibtexfields.NormalizePagesFormatter;
+import net.sf.jabref.logic.formatter.bibtexfields.OrdinalsToSuperscriptFormatter;
+import net.sf.jabref.logic.formatter.bibtexfields.UnicodeToLatexFormatter;
+import net.sf.jabref.logic.layout.format.LatexToUnicodeFormatter;
+import net.sf.jabref.model.cleanup.FieldFormatterCleanup;
+import net.sf.jabref.model.cleanup.FieldFormatterCleanups;
+import net.sf.jabref.model.cleanup.Formatter;
+import net.sf.jabref.model.entry.FieldName;
+import net.sf.jabref.model.strings.StringUtil;
+
+public class Cleanups {
+
+ public static final FieldFormatterCleanups DEFAULT_SAVE_ACTIONS;
+ public static final FieldFormatterCleanups RECOMMEND_BIBTEX_ACTIONS;
+ public static final FieldFormatterCleanups RECOMMEND_BIBLATEX_ACTIONS;
+ public static List<Formatter> availableFormatters;
+
+
+ static {
+ availableFormatters = new ArrayList<>();
+ availableFormatters.addAll(Formatters.ALL);
+
+ List<FieldFormatterCleanup> defaultFormatters = new ArrayList<>();
+ defaultFormatters.add(new FieldFormatterCleanup(FieldName.PAGES, new NormalizePagesFormatter()));
+ defaultFormatters.add(new FieldFormatterCleanup(FieldName.DATE, new NormalizeDateFormatter()));
+ defaultFormatters.add(new FieldFormatterCleanup(FieldName.MONTH, new NormalizeMonthFormatter()));
+ DEFAULT_SAVE_ACTIONS = new FieldFormatterCleanups(false, defaultFormatters);
+
+ List<FieldFormatterCleanup> recommendedBibTeXFormatters = new ArrayList<>();
+ recommendedBibTeXFormatters.addAll(defaultFormatters);
+ recommendedBibTeXFormatters.add(new FieldFormatterCleanup(FieldName.TITLE, new HtmlToLatexFormatter()));
+ recommendedBibTeXFormatters.add(new FieldFormatterCleanup(FieldName.TITLE, new UnicodeToLatexFormatter()));
+ recommendedBibTeXFormatters.add(new FieldFormatterCleanup(FieldName.BOOKTITLE, new UnicodeToLatexFormatter()));
+ recommendedBibTeXFormatters.add(new FieldFormatterCleanup(FieldName.JOURNAL, new UnicodeToLatexFormatter()));
+ recommendedBibTeXFormatters.add(new FieldFormatterCleanup(FieldName.AUTHOR, new UnicodeToLatexFormatter()));
+ recommendedBibTeXFormatters.add(new FieldFormatterCleanup(FieldName.EDITOR, new UnicodeToLatexFormatter()));
+ recommendedBibTeXFormatters.add(new FieldFormatterCleanup(FieldName.INTERNAL_ALL_TEXT_FIELDS_FIELD, new OrdinalsToSuperscriptFormatter()));
+ RECOMMEND_BIBTEX_ACTIONS = new FieldFormatterCleanups(false, recommendedBibTeXFormatters);
+
+ List<FieldFormatterCleanup> recommendedBibLaTeXFormatters = new ArrayList<>();
+ recommendedBibLaTeXFormatters.addAll(defaultFormatters);
+ recommendedBibLaTeXFormatters.add(new FieldFormatterCleanup(FieldName.TITLE, new HtmlToUnicodeFormatter()));
+ recommendedBibLaTeXFormatters.add(new FieldFormatterCleanup(FieldName.INTERNAL_ALL_TEXT_FIELDS_FIELD, new LatexToUnicodeFormatter()));
+ recommendedBibLaTeXFormatters.add(new FieldFormatterCleanup(FieldName.INTERNAL_ALL_TEXT_FIELDS_FIELD, new OrdinalsToSuperscriptFormatter()));
+ RECOMMEND_BIBLATEX_ACTIONS = new FieldFormatterCleanups(false, recommendedBibLaTeXFormatters);
+ }
+
+ public static List<Formatter> getAvailableFormatters() {
+ return Collections.unmodifiableList(availableFormatters);
+ }
+
+ public static List<FieldFormatterCleanup> parse(String formatterString) {
+
+ if ((formatterString == null) || formatterString.isEmpty()) {
+ // no save actions defined in the meta data
+ return new ArrayList<>();
+ }
+
+ List<FieldFormatterCleanup> actions = new ArrayList<>();
+
+ //read concrete actions
+ int startIndex = 0;
+
+ // first remove all newlines for easier parsing
+ String remainingString = formatterString;
+
+ remainingString = StringUtil.unifyLineBreaks(remainingString, "");
+ try {
+ while (startIndex < formatterString.length()) {
+ // read the field name
+ int currentIndex = remainingString.indexOf('[');
+ String fieldKey = remainingString.substring(0, currentIndex);
+ int endIndex = remainingString.indexOf(']');
+ startIndex += endIndex + 1;
+
+ //read each formatter
+ int tokenIndex = remainingString.indexOf(',');
+ do {
+ boolean doBreak = false;
+ if ((tokenIndex == -1) || (tokenIndex > endIndex)) {
+ tokenIndex = remainingString.indexOf(']');
+ doBreak = true;
+ }
+
+ String formatterKey = remainingString.substring(currentIndex + 1, tokenIndex);
+ actions.add(new FieldFormatterCleanup(fieldKey, getFormatterFromString(formatterKey)));
+
+ remainingString = remainingString.substring(tokenIndex + 1);
+ if (remainingString.startsWith("]") || doBreak) {
+ break;
+ }
+ tokenIndex = remainingString.indexOf(',');
+
+ currentIndex = -1;
+ } while (true);
+
+
+ }
+ } catch (StringIndexOutOfBoundsException ignore) {
+ // if this exception occurs, the remaining part of the save actions string is invalid.
+ // Thus we stop parsing and take what we have parsed until now
+ return actions;
+ }
+ return actions;
+ }
+
+ public static FieldFormatterCleanups parse(List<String> formatterMetaList) {
+
+ if ((formatterMetaList != null) && (formatterMetaList.size() >= 2)) {
+ boolean enablementStatus = FieldFormatterCleanups.ENABLED.equals(formatterMetaList.get(0));
+ String formatterString = formatterMetaList.get(1);
+ return new FieldFormatterCleanups(enablementStatus, parse(formatterString));
+ } else {
+ // return default actions
+ return DEFAULT_SAVE_ACTIONS;
+ }
+
+ }
+
+ private static Formatter getFormatterFromString(String formatterName) {
+ for (Formatter formatter : availableFormatters) {
+ if (formatterName.equals(formatter.getKey())) {
+ return formatter;
+ }
+ }
+ return new IdentityFormatter();
+ }
+}
diff --git a/src/main/java/net/sf/jabref/logic/cleanup/DoiCleanup.java b/src/main/java/net/sf/jabref/logic/cleanup/DoiCleanup.java
index 85fbdb1..19268ae 100644
--- a/src/main/java/net/sf/jabref/logic/cleanup/DoiCleanup.java
+++ b/src/main/java/net/sf/jabref/logic/cleanup/DoiCleanup.java
@@ -8,6 +8,8 @@ import java.util.Optional;
import net.sf.jabref.logic.formatter.bibtexfields.ClearFormatter;
import net.sf.jabref.logic.util.DOI;
import net.sf.jabref.model.FieldChange;
+import net.sf.jabref.model.cleanup.CleanupJob;
+import net.sf.jabref.model.cleanup.FieldFormatterCleanup;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.FieldName;
@@ -28,7 +30,7 @@ public class DoiCleanup implements CleanupJob {
// First check if the Doi Field is empty
if (entry.hasField(FieldName.DOI)) {
- String doiFieldValue = entry.getFieldOptional(FieldName.DOI).orElse(null);
+ String doiFieldValue = entry.getField(FieldName.DOI).orElse(null);
Optional<DOI> doi = DOI.build(doiFieldValue);
@@ -43,18 +45,18 @@ public class DoiCleanup implements CleanupJob {
// Doi field seems to contain Doi -> cleanup note, url, ee field
for (String field : FIELDS) {
- entry.getFieldOptional(field).flatMap(DOI::build)
+ entry.getField(field).flatMap(DOI::build)
.ifPresent(unused -> removeFieldValue(entry, field, changes));
}
}
} else {
// As the Doi field is empty we now check if note, url, or ee field contains a Doi
for (String field : FIELDS) {
- Optional<DOI> doi = entry.getFieldOptional(field).flatMap(DOI::build);
+ Optional<DOI> doi = entry.getField(field).flatMap(DOI::build);
if (doi.isPresent()) {
// update Doi
- String oldValue = entry.getFieldOptional(FieldName.DOI).orElse(null);
+ String oldValue = entry.getField(FieldName.DOI).orElse(null);
String newValue = doi.get().getDOI();
entry.setField(FieldName.DOI, newValue);
diff --git a/src/main/java/net/sf/jabref/logic/cleanup/FieldFormatterCleanup.java b/src/main/java/net/sf/jabref/logic/cleanup/FieldFormatterCleanup.java
deleted file mode 100644
index 9c8fd81..0000000
--- a/src/main/java/net/sf/jabref/logic/cleanup/FieldFormatterCleanup.java
+++ /dev/null
@@ -1,106 +0,0 @@
-package net.sf.jabref.logic.cleanup;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-
-import net.sf.jabref.event.source.EntryEventSource;
-import net.sf.jabref.logic.formatter.Formatter;
-import net.sf.jabref.model.FieldChange;
-import net.sf.jabref.model.entry.BibEntry;
-
-/**
- * Formats a given entry field with the specified formatter.
- */
-public class FieldFormatterCleanup implements CleanupJob {
-
- private final String field;
- private final Formatter formatter;
-
- public FieldFormatterCleanup(String field, Formatter formatter) {
- this.field = field;
- this.formatter = formatter;
- }
-
- @Override
- public List<FieldChange> cleanup(BibEntry entry) {
- if ("all".equalsIgnoreCase(field)) {
- return cleanupAllFields(entry);
- } else {
- return cleanupSingleField(field, entry);
- }
- }
-
- /**
- * Runs the formatter on the specified field in the given entry.
- *
- * If the formatter returns an empty string, then the field is removed.
- * @param fieldKey the field on which to run the formatter
- * @param entry the entry to be cleaned up
- * @return a list of changes of the entry
- */
- private List<FieldChange> cleanupSingleField(String fieldKey, BibEntry entry) {
- if (!entry.hasField(fieldKey)) {
- // Not set -> nothing to do
- return new ArrayList<>();
- }
- String oldValue = entry.getFieldOptional(fieldKey).orElse(null);
-
- // Run formatter
- String newValue = formatter.format(oldValue);
-
- if (oldValue.equals(newValue)) {
- return new ArrayList<>();
- } else {
- if(newValue.isEmpty()) {
- entry.clearField(fieldKey);
- newValue = null;
- } else {
- entry.setField(fieldKey, newValue, EntryEventSource.SAVE_ACTION);
- }
- FieldChange change = new FieldChange(entry, fieldKey, oldValue, newValue);
- return Collections.singletonList(change);
- }
- }
-
- private List<FieldChange> cleanupAllFields(BibEntry entry) {
- List<FieldChange> fieldChanges = new ArrayList<>();
-
- for (String fieldKey : entry.getFieldNames()) {
- fieldChanges.addAll(cleanupSingleField(fieldKey, entry));
- }
-
- return fieldChanges;
- }
-
- public String getField() {
- return field;
- }
-
- public Formatter getFormatter() {
- return formatter;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o instanceof FieldFormatterCleanup) {
- FieldFormatterCleanup that = (FieldFormatterCleanup) o;
- return Objects.equals(field, that.field) && Objects.equals(formatter, that.formatter);
- }
- return false;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(field, formatter);
- }
-
- @Override
- public String toString() {
- return field + ": " + formatter.getName();
- }
-}
diff --git a/src/main/java/net/sf/jabref/logic/cleanup/FileLinksCleanup.java b/src/main/java/net/sf/jabref/logic/cleanup/FileLinksCleanup.java
index 76dd8dd..842efd0 100644
--- a/src/main/java/net/sf/jabref/logic/cleanup/FileLinksCleanup.java
+++ b/src/main/java/net/sf/jabref/logic/cleanup/FileLinksCleanup.java
@@ -5,6 +5,7 @@ import java.util.List;
import java.util.Optional;
import net.sf.jabref.model.FieldChange;
+import net.sf.jabref.model.cleanup.CleanupJob;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.FieldName;
import net.sf.jabref.model.entry.FileField;
@@ -17,7 +18,7 @@ public class FileLinksCleanup implements CleanupJob {
@Override
public List<FieldChange> cleanup(BibEntry entry) {
- Optional<String> oldValue = entry.getFieldOptional(FieldName.FILE);
+ Optional<String> oldValue = entry.getField(FieldName.FILE);
if (!oldValue.isPresent()) {
return Collections.emptyList();
}
diff --git a/src/main/java/net/sf/jabref/logic/cleanup/ISSNCleanup.java b/src/main/java/net/sf/jabref/logic/cleanup/ISSNCleanup.java
index 11edf08..348238c 100644
--- a/src/main/java/net/sf/jabref/logic/cleanup/ISSNCleanup.java
+++ b/src/main/java/net/sf/jabref/logic/cleanup/ISSNCleanup.java
@@ -6,6 +6,7 @@ import java.util.Optional;
import net.sf.jabref.logic.util.ISSN;
import net.sf.jabref.model.FieldChange;
+import net.sf.jabref.model.cleanup.CleanupJob;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.FieldName;
@@ -14,7 +15,7 @@ public class ISSNCleanup implements CleanupJob {
@Override
public List<FieldChange> cleanup(BibEntry entry) {
- Optional<String> issnString = entry.getFieldOptional(FieldName.ISSN);
+ Optional<String> issnString = entry.getField(FieldName.ISSN);
if (!issnString.isPresent()) {
return Collections.emptyList();
}
diff --git a/src/main/java/net/sf/jabref/logic/cleanup/MoveFieldCleanup.java b/src/main/java/net/sf/jabref/logic/cleanup/MoveFieldCleanup.java
new file mode 100644
index 0000000..a07d89e
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/cleanup/MoveFieldCleanup.java
@@ -0,0 +1,32 @@
+package net.sf.jabref.logic.cleanup;
+
+import java.util.List;
+import java.util.Optional;
+
+import net.sf.jabref.logic.util.OptionalUtil;
+import net.sf.jabref.model.FieldChange;
+import net.sf.jabref.model.cleanup.CleanupJob;
+import net.sf.jabref.model.entry.BibEntry;
+
+/**
+ * Moves the content of one field to another field.
+ */
+public class MoveFieldCleanup implements CleanupJob {
+
+ private String sourceField;
+ private String targetField;
+
+ public MoveFieldCleanup(String sourceField, String targetField) {
+ this.sourceField = sourceField;
+ this.targetField = targetField;
+ }
+
+ @Override
+ public List<FieldChange> cleanup(BibEntry entry) {
+
+ Optional<FieldChange> setFieldChange = entry.getField(sourceField).flatMap(
+ value -> entry.setField(targetField, value));
+ Optional<FieldChange> clearFieldChange = entry.clearField(sourceField);
+ return OptionalUtil.toList(setFieldChange, clearFieldChange);
+ }
+}
diff --git a/src/main/java/net/sf/jabref/logic/cleanup/MoveFilesCleanup.java b/src/main/java/net/sf/jabref/logic/cleanup/MoveFilesCleanup.java
index 80d4684..a57b0ed 100644
--- a/src/main/java/net/sf/jabref/logic/cleanup/MoveFilesCleanup.java
+++ b/src/main/java/net/sf/jabref/logic/cleanup/MoveFilesCleanup.java
@@ -7,19 +7,24 @@ import java.util.List;
import java.util.Objects;
import java.util.Optional;
-import net.sf.jabref.BibDatabaseContext;
import net.sf.jabref.logic.TypedBibEntry;
import net.sf.jabref.logic.util.io.FileUtil;
import net.sf.jabref.model.FieldChange;
+import net.sf.jabref.model.cleanup.CleanupJob;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.ParsedFileField;
+import net.sf.jabref.model.metadata.FileDirectoryPreferences;
public class MoveFilesCleanup implements CleanupJob {
private final BibDatabaseContext databaseContext;
+ private final FileDirectoryPreferences fileDirectoryPreferences;
- public MoveFilesCleanup(BibDatabaseContext databaseContext) {
+
+ public MoveFilesCleanup(BibDatabaseContext databaseContext, FileDirectoryPreferences fileDirectoryPreferences) {
this.databaseContext = Objects.requireNonNull(databaseContext);
+ this.fileDirectoryPreferences = Objects.requireNonNull(fileDirectoryPreferences);
}
@Override
@@ -28,7 +33,7 @@ public class MoveFilesCleanup implements CleanupJob {
return Collections.emptyList();
}
- List<String> paths = databaseContext.getFileDirectory();
+ List<String> paths = databaseContext.getFileDirectories(fileDirectoryPreferences);
String defaultFileDirectory = databaseContext.getMetaData().getDefaultFileDirectory().get();
Optional<File> targetDirectory = FileUtil.expandFilename(defaultFileDirectory, paths);
if(!targetDirectory.isPresent()) {
diff --git a/src/main/java/net/sf/jabref/logic/cleanup/RelativePathsCleanup.java b/src/main/java/net/sf/jabref/logic/cleanup/RelativePathsCleanup.java
index a1a617d..70c9149 100644
--- a/src/main/java/net/sf/jabref/logic/cleanup/RelativePathsCleanup.java
+++ b/src/main/java/net/sf/jabref/logic/cleanup/RelativePathsCleanup.java
@@ -7,19 +7,24 @@ import java.util.List;
import java.util.Objects;
import java.util.Optional;
-import net.sf.jabref.BibDatabaseContext;
import net.sf.jabref.logic.TypedBibEntry;
import net.sf.jabref.logic.util.io.FileUtil;
import net.sf.jabref.model.FieldChange;
+import net.sf.jabref.model.cleanup.CleanupJob;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.ParsedFileField;
+import net.sf.jabref.model.metadata.FileDirectoryPreferences;
public class RelativePathsCleanup implements CleanupJob {
private final BibDatabaseContext databaseContext;
+ private final FileDirectoryPreferences fileDirectoryPreferences;
- public RelativePathsCleanup(BibDatabaseContext databaseContext) {
+
+ public RelativePathsCleanup(BibDatabaseContext databaseContext, FileDirectoryPreferences fileDirectoryPreferences) {
this.databaseContext = Objects.requireNonNull(databaseContext);
+ this.fileDirectoryPreferences = Objects.requireNonNull(fileDirectoryPreferences);
}
@Override
@@ -31,7 +36,8 @@ public class RelativePathsCleanup implements CleanupJob {
for (ParsedFileField fileEntry : fileList) {
String oldFileName = fileEntry.getLink();
- String newFileName = FileUtil.shortenFileName(new File(oldFileName), databaseContext.getFileDirectory())
+ String newFileName = FileUtil
+ .shortenFileName(new File(oldFileName), databaseContext.getFileDirectories(fileDirectoryPreferences))
.toString();
ParsedFileField newFileEntry = fileEntry;
diff --git a/src/main/java/net/sf/jabref/logic/cleanup/RenamePdfCleanup.java b/src/main/java/net/sf/jabref/logic/cleanup/RenamePdfCleanup.java
index def724b..6eba724 100644
--- a/src/main/java/net/sf/jabref/logic/cleanup/RenamePdfCleanup.java
+++ b/src/main/java/net/sf/jabref/logic/cleanup/RenamePdfCleanup.java
@@ -1,37 +1,50 @@
package net.sf.jabref.logic.cleanup;
import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
-import net.sf.jabref.BibDatabaseContext;
import net.sf.jabref.logic.TypedBibEntry;
import net.sf.jabref.logic.layout.LayoutFormatterPreferences;
-import net.sf.jabref.logic.util.OS;
import net.sf.jabref.logic.util.io.FileUtil;
import net.sf.jabref.model.FieldChange;
+import net.sf.jabref.model.cleanup.CleanupJob;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.ParsedFileField;
+import net.sf.jabref.model.metadata.FileDirectoryPreferences;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
public class RenamePdfCleanup implements CleanupJob {
+ private static final Log LOGGER = LogFactory.getLog(RenamePdfCleanup.class);
+
private final BibDatabaseContext databaseContext;
private final boolean onlyRelativePaths;
private final String fileNamePattern;
+ private final String fileDirPattern;
private final LayoutFormatterPreferences prefs;
-
+ private final FileDirectoryPreferences fileDirectoryPreferences;
private int unsuccessfulRenames;
-
- public RenamePdfCleanup(boolean onlyRelativePaths, BibDatabaseContext databaseContext,
- String fileNamePattern, LayoutFormatterPreferences prefs) {
+ public RenamePdfCleanup(boolean onlyRelativePaths, BibDatabaseContext databaseContext, String fileNamePattern,
+ String fileDirPattern, LayoutFormatterPreferences prefs,
+ FileDirectoryPreferences fileDirectoryPreferences) {
this.databaseContext = Objects.requireNonNull(databaseContext);
this.onlyRelativePaths = onlyRelativePaths;
this.fileNamePattern = Objects.requireNonNull(fileNamePattern);
+ this.fileDirPattern = Objects.requireNonNull(fileDirPattern);
this.prefs = Objects.requireNonNull(prefs);
+ this.fileDirectoryPreferences = fileDirectoryPreferences;
}
@Override
@@ -49,59 +62,83 @@ public class RenamePdfCleanup implements CleanupJob {
continue;
}
- StringBuilder newFilename = new StringBuilder(FileUtil
+ StringBuilder targetFileName = new StringBuilder(FileUtil
.createFileNameFromPattern(databaseContext.getDatabase(), entry, fileNamePattern, prefs).trim());
+ String targetDirName = "";
+ if (!fileDirPattern.isEmpty()) {
+ targetDirName = FileUtil.createFileNameFromPattern(databaseContext.getDatabase(), entry, fileDirPattern,
+ prefs);
+ }
+
//Add extension to newFilename
- newFilename.append('.').append(FileUtil.getFileExtension(realOldFilename).orElse("pdf"));
+ targetFileName.append('.').append(FileUtil.getFileExtension(realOldFilename).orElse("pdf"));
//get new Filename with path
//Create new Path based on old Path and new filename
Optional<File> expandedOldFile = FileUtil.expandFilename(realOldFilename,
- databaseContext.getFileDirectory());
+ databaseContext.getFileDirectories(fileDirectoryPreferences));
+
if ((!expandedOldFile.isPresent()) || (expandedOldFile.get().getParent() == null)) {
// something went wrong. Just skip this entry
newFileList.add(flEntry);
continue;
}
- String newPath = expandedOldFile.get().getParent().concat(OS.FILE_SEPARATOR).concat(newFilename.toString());
-
- String expandedOldFilePath = expandedOldFile.get().toString();
- boolean pathsDifferOnlyByCase = newPath.equalsIgnoreCase(expandedOldFilePath)
- && !newPath.equals(expandedOldFilePath);
- if (new File(newPath).exists() && !pathsDifferOnlyByCase) {
- // we do not overwrite files
- // Since File.exists is sometimes not case-sensitive, the check pathsDifferOnlyByCase ensures that we
- // nonetheless rename files to a new name which just differs by case.
- // TODO: we could check here if the newPath file is linked with the current entry. And if not, we could add a link
- newFileList.add(flEntry);
- continue;
- }
+ Path newPath = null;
+ Optional<Path> dir = databaseContext.getFirstExistingFileDir(fileDirectoryPreferences);
+ if (dir.isPresent()) {
+
+ newPath = dir.get().resolve(targetDirName).resolve(targetFileName.toString());
+
+ String expandedOldFilePath = expandedOldFile.get().toString();
+ boolean pathsDifferOnlyByCase = newPath.toString().equalsIgnoreCase(expandedOldFilePath)
+ && !newPath.equals(expandedOldFilePath);
+
+ if (Files.exists(newPath) && !pathsDifferOnlyByCase) {
+ // we do not overwrite files
+ // Since File.exists is sometimes not case-sensitive, the check pathsDifferOnlyByCase ensures that we
+ // nonetheless rename files to a new name which just differs by case.
+ // TODO: we could check here if the newPath file is linked with the current entry. And if not, we could add a link
+ newFileList.add(flEntry);
+ continue;
+ }
+
+ try {
+ if (!Files.exists(newPath)) {
+ Files.createDirectories(newPath);
+ }
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ LOGGER.error("Could no create target necessary target directoires for renaming", e);
+ }
+ //do rename
+ boolean renameSuccessful = FileUtil.renameFile(Paths.get(expandedOldFilePath), newPath, true);
+ if (renameSuccessful) {
+ changed = true;
- //do rename
- boolean renameSuccessful = FileUtil.renameFile(expandedOldFilePath, newPath);
+ //Change the path for this entry
+ String description = flEntry.getDescription();
+ String type = flEntry.getFileType();
- if (renameSuccessful) {
- changed = true;
+ Optional<Path> settingsDir = databaseContext.getFirstExistingFileDir(fileDirectoryPreferences);
+ if (settingsDir.isPresent()) {
- //Change the path for this entry
- String description = flEntry.getDescription();
- String type = flEntry.getFileType();
+ Path parent = settingsDir.get();
+ String newFileEntryFileName;
+ if ((parent == null)) {
+ newFileEntryFileName = targetFileName.toString();
- // we cannot use "newPath" to generate a FileListEntry as newPath is absolute, but we want to keep relative paths whenever possible
- File parent = (new File(realOldFilename)).getParentFile();
- String newFileEntryFileName;
- if ((parent == null) || databaseContext.getFileDirectory().contains(parent.getAbsolutePath())) {
- newFileEntryFileName = newFilename.toString();
+ } else {
+ newFileEntryFileName = parent.relativize(newPath).toString();
+ }
+
+ newFileList.add(new ParsedFileField(description, newFileEntryFileName, type));
+ }
} else {
- newFileEntryFileName = parent.toString().concat(OS.FILE_SEPARATOR).concat(newFilename.toString());
+ unsuccessfulRenames++;
}
- newFileList.add(new ParsedFileField(description, newFileEntryFileName, type));
- } else {
- unsuccessfulRenames++;
}
}
-
if (changed) {
Optional<FieldChange> change = typedEntry.setFiles(newFileList);
//we put an undo of the field content here
@@ -113,7 +150,6 @@ public class RenamePdfCleanup implements CleanupJob {
return Collections.emptyList();
}
}
-
return Collections.emptyList();
}
diff --git a/src/main/java/net/sf/jabref/logic/cleanup/UpgradePdfPsToFileCleanup.java b/src/main/java/net/sf/jabref/logic/cleanup/UpgradePdfPsToFileCleanup.java
index d9a20a7..8a811cd 100644
--- a/src/main/java/net/sf/jabref/logic/cleanup/UpgradePdfPsToFileCleanup.java
+++ b/src/main/java/net/sf/jabref/logic/cleanup/UpgradePdfPsToFileCleanup.java
@@ -2,25 +2,29 @@ package net.sf.jabref.logic.cleanup;
import java.io.File;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
-import java.util.Objects;
+import java.util.Map;
-import net.sf.jabref.external.ExternalFileTypes;
import net.sf.jabref.model.FieldChange;
+import net.sf.jabref.model.cleanup.CleanupJob;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.FieldName;
import net.sf.jabref.model.entry.FileField;
import net.sf.jabref.model.entry.ParsedFileField;
/**
- * Collects file links from the given set of fields, and add them to the list contained in the file field.
+ * Collects file links from the ps and pdf fields, and add them to the list contained in the file field.
*/
public class UpgradePdfPsToFileCleanup implements CleanupJob {
- private final List<String> fields;
+ // Field name and file type name (from ExternalFileTypes)
+ private final Map<String, String> fields = new HashMap<>();
- public UpgradePdfPsToFileCleanup(List<String> fields) {
- this.fields = Objects.requireNonNull(fields);
+
+ public UpgradePdfPsToFileCleanup() {
+ fields.put(FieldName.PDF, "PDF");
+ fields.put(FieldName.PS, "PostScript");
}
@Override
@@ -28,22 +32,21 @@ public class UpgradePdfPsToFileCleanup implements CleanupJob {
List<FieldChange> changes = new ArrayList<>();
// If there are already links in the file field, keep those on top:
- String oldFileContent = entry.getFieldOptional(FieldName.FILE).orElse(null);
+ String oldFileContent = entry.getField(FieldName.FILE).orElse(null);
List<ParsedFileField> fileList = new ArrayList<>(FileField.parse(oldFileContent));
int oldItemCount = fileList.size();
- for (String field : fields) {
- entry.getFieldOptional(field).ifPresent(o -> {
+ for (Map.Entry<String, String> field : fields.entrySet()) {
+ entry.getField(field.getKey()).ifPresent(o -> {
if (o.trim().isEmpty()) {
return;
}
File f = new File(o);
- ParsedFileField flEntry = new ParsedFileField(f.getName(), o,
- ExternalFileTypes.getInstance().getExternalFileTypeNameByExt(field));
+ ParsedFileField flEntry = new ParsedFileField(f.getName(), o, field.getValue());
fileList.add(flEntry);
- entry.clearField(field);
- changes.add(new FieldChange(entry, field, o, null));
+ entry.clearField(field.getKey());
+ changes.add(new FieldChange(entry, field.getKey(), o, null));
});
}
diff --git a/src/main/java/net/sf/jabref/logic/config/SaveOrderConfig.java b/src/main/java/net/sf/jabref/logic/config/SaveOrderConfig.java
deleted file mode 100644
index 3008a67..0000000
--- a/src/main/java/net/sf/jabref/logic/config/SaveOrderConfig.java
+++ /dev/null
@@ -1,219 +0,0 @@
-package net.sf.jabref.logic.config;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Objects;
-
-import net.sf.jabref.preferences.JabRefPreferences;
-
-/**
- * Stores the save order config from MetaData
- * <p>
- * Format: <choice>, pair of field + ascending (boolean)
- */
-public class SaveOrderConfig {
-
- public boolean saveInOriginalOrder;
-
- // quick hack for outside modifications
- public final SortCriterion[] sortCriteria = new SortCriterion[3];
-
- public static SaveOrderConfig parse(List<String> orderedData) {
- return new SaveOrderConfig(orderedData);
- }
-
- public static class SortCriterion {
-
- public String field;
- public boolean descending;
-
-
- public SortCriterion() {
- this.field = "";
- }
-
- public SortCriterion(String field, String descending) {
- this.field = field;
- this.descending = Boolean.parseBoolean(descending);
- }
-
- public SortCriterion(String field, boolean descending) {
- this.field = field;
- this.descending = descending;
- }
-
- @Override
- public String toString() {
- final StringBuilder sb = new StringBuilder("SortCriterion{");
- sb.append("field='").append(field).append('\'');
- sb.append(", descending=").append(descending);
- sb.append('}');
- return sb.toString();
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if ((o == null) || (getClass() != o.getClass())) {
- return false;
- }
- SortCriterion that = (SortCriterion) o;
- return Objects.equals(descending, that.descending) &&
- Objects.equals(field, that.field);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(field, descending);
- }
- }
-
- public SaveOrderConfig(boolean saveInOriginalOrder, SortCriterion first, SortCriterion second,
- SortCriterion third) {
- this.saveInOriginalOrder = saveInOriginalOrder;
- sortCriteria[0] = first;
- sortCriteria[1] = second;
- sortCriteria[2] = third;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o instanceof SaveOrderConfig) {
- SaveOrderConfig that = (SaveOrderConfig) o;
- boolean sortCriteriaEquals = sortCriteria[0].equals(that.sortCriteria[0])
- && sortCriteria[1].equals(that.sortCriteria[1]) && sortCriteria[2].equals(that.sortCriteria[2]);
-
- return Objects.equals(saveInOriginalOrder, that.saveInOriginalOrder) && sortCriteriaEquals;
- }
- return false;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(saveInOriginalOrder, Arrays.hashCode(sortCriteria));
- }
-
- public SaveOrderConfig() {
- // fill default values
- setSaveInOriginalOrder();
- sortCriteria[0] = new SortCriterion();
- sortCriteria[1] = new SortCriterion();
- sortCriteria[2] = new SortCriterion();
- }
-
- @Override
- public String toString() {
- final StringBuilder sb = new StringBuilder("SaveOrderConfig{");
- sb.append("saveInOriginalOrder=").append(saveInOriginalOrder);
- sb.append(", sortCriteria=").append(Arrays.toString(sortCriteria));
- sb.append('}');
- return sb.toString();
- }
-
- private SaveOrderConfig(List<String> data) {
- Objects.requireNonNull(data);
-
- if (data.isEmpty()) {
- throw new IllegalArgumentException();
- }
-
- String choice = data.get(0);
- if ("original".equals(choice)) {
- setSaveInOriginalOrder();
- } else {
- setSaveInSpecifiedOrder();
- }
-
- if (data.size() >= 3) {
- sortCriteria[0] = new SortCriterion(data.get(1), data.get(2));
- } else {
- sortCriteria[0] = new SortCriterion();
- }
- if (data.size() >= 5) {
- sortCriteria[1] = new SortCriterion(data.get(3), data.get(4));
- } else {
- sortCriteria[1] = new SortCriterion();
- }
- if (data.size() >= 7) {
- sortCriteria[2] = new SortCriterion(data.get(5), data.get(6));
- } else {
- sortCriteria[2] = new SortCriterion();
- }
- }
-
- public void setSaveInOriginalOrder() {
- this.saveInOriginalOrder = true;
- }
-
- public void setSaveInSpecifiedOrder() {
- this.saveInOriginalOrder = false;
- }
-
- public static SaveOrderConfig loadExportSaveOrderFromPreferences(JabRefPreferences preferences) {
- SaveOrderConfig config = new SaveOrderConfig();
- config.sortCriteria[0].field = preferences.get(JabRefPreferences.EXPORT_PRIMARY_SORT_FIELD);
- config.sortCriteria[0].descending = preferences.getBoolean(JabRefPreferences.EXPORT_PRIMARY_SORT_DESCENDING);
- config.sortCriteria[1].field = preferences.get(JabRefPreferences.EXPORT_SECONDARY_SORT_FIELD);
- config.sortCriteria[1].descending = preferences.getBoolean(JabRefPreferences.EXPORT_SECONDARY_SORT_DESCENDING);
- config.sortCriteria[2].field = preferences.get(JabRefPreferences.EXPORT_TERTIARY_SORT_FIELD);
- config.sortCriteria[2].descending = preferences.getBoolean(JabRefPreferences.EXPORT_TERTIARY_SORT_DESCENDING);
-
- return config;
- }
-
- public static SaveOrderConfig loadTableSaveOrderFromPreferences(JabRefPreferences preferences) {
- SaveOrderConfig config = new SaveOrderConfig();
- config.sortCriteria[0].field = preferences.get(JabRefPreferences.TABLE_PRIMARY_SORT_FIELD);
- config.sortCriteria[0].descending = preferences.getBoolean(JabRefPreferences.TABLE_PRIMARY_SORT_DESCENDING);
- config.sortCriteria[1].field = preferences.get(JabRefPreferences.TABLE_SECONDARY_SORT_FIELD);
- config.sortCriteria[1].descending = preferences.getBoolean(JabRefPreferences.TABLE_SECONDARY_SORT_DESCENDING);
- config.sortCriteria[2].field = preferences.get(JabRefPreferences.TABLE_TERTIARY_SORT_FIELD);
- config.sortCriteria[2].descending = preferences.getBoolean(JabRefPreferences.TABLE_TERTIARY_SORT_DESCENDING);
-
- return config;
- }
-
- public void storeAsExportSaveOrderInPreferences(JabRefPreferences preferences) {
- preferences.putBoolean(JabRefPreferences.EXPORT_PRIMARY_SORT_DESCENDING, sortCriteria[0].descending);
- preferences.putBoolean(JabRefPreferences.EXPORT_SECONDARY_SORT_DESCENDING, sortCriteria[1].descending);
- preferences.putBoolean(JabRefPreferences.EXPORT_TERTIARY_SORT_DESCENDING, sortCriteria[2].descending);
-
- preferences.put(JabRefPreferences.EXPORT_PRIMARY_SORT_FIELD, sortCriteria[0].field);
- preferences.put(JabRefPreferences.EXPORT_SECONDARY_SORT_FIELD, sortCriteria[1].field);
- preferences.put(JabRefPreferences.EXPORT_TERTIARY_SORT_FIELD, sortCriteria[2].field);
- }
-
- /**
- * Outputs the current configuration to be consumed later by the constructor
- */
- public List<String> getAsStringList() {
- List<String> res = new ArrayList<>(7);
- if (saveInOriginalOrder) {
- res.add("original");
- } else {
- res.add("specified");
- }
-
- res.add(sortCriteria[0].field);
- res.add(Boolean.toString(sortCriteria[0].descending));
- res.add(sortCriteria[1].field);
- res.add(Boolean.toString(sortCriteria[1].descending));
- res.add(sortCriteria[2].field);
- res.add(Boolean.toString(sortCriteria[2].descending));
-
- return res;
- }
-
- public static SaveOrderConfig getDefaultSaveOrder() {
- SaveOrderConfig standard = new SaveOrderConfig();
- standard.setSaveInOriginalOrder();
- return standard;
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/logic/exporter/BibDatabaseWriter.java b/src/main/java/net/sf/jabref/logic/exporter/BibDatabaseWriter.java
index 172177d..96d1643 100644
--- a/src/main/java/net/sf/jabref/logic/exporter/BibDatabaseWriter.java
+++ b/src/main/java/net/sf/jabref/logic/exporter/BibDatabaseWriter.java
@@ -17,23 +17,25 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
-import net.sf.jabref.BibDatabaseContext;
-import net.sf.jabref.MetaData;
import net.sf.jabref.logic.bibtex.LatexFieldFormatterPreferences;
import net.sf.jabref.logic.bibtex.comparator.BibtexStringComparator;
import net.sf.jabref.logic.bibtex.comparator.CrossRefEntryComparator;
import net.sf.jabref.logic.bibtex.comparator.FieldComparator;
import net.sf.jabref.logic.bibtex.comparator.FieldComparatorStack;
import net.sf.jabref.logic.bibtex.comparator.IdComparator;
-import net.sf.jabref.logic.config.SaveOrderConfig;
import net.sf.jabref.model.EntryTypes;
import net.sf.jabref.model.FieldChange;
+import net.sf.jabref.model.bibtexkeypattern.GlobalBibtexKeyPattern;
+import net.sf.jabref.model.cleanup.FieldFormatterCleanups;
import net.sf.jabref.model.database.BibDatabase;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.database.BibDatabaseMode;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.BibtexString;
import net.sf.jabref.model.entry.CustomEntryType;
import net.sf.jabref.model.entry.EntryType;
+import net.sf.jabref.model.metadata.MetaData;
+import net.sf.jabref.model.metadata.SaveOrderConfig;
public abstract class BibDatabaseWriter<E extends SaveSession> {
@@ -73,15 +75,15 @@ public abstract class BibDatabaseWriter<E extends SaveSession> {
List<Comparator<BibEntry>> comparators = new ArrayList<>();
Optional<SaveOrderConfig> saveOrder = getSaveOrder(preferences, metaData);
+ // Take care, using CrossRefEntry-Comparator, that referred entries occur after referring
+ // ones. This is a necessary requirement for BibTeX to be able to resolve referenced entries correctly.
+ comparators.add(new CrossRefEntryComparator());
+
if (! saveOrder.isPresent()) {
- // Take care, using CrossRefEntry-Comparator, that referred entries occur after referring
- // ones. Apart from crossref requirements, entries will be sorted based on their creation order,
- // utilizing the fact that IDs used for entries are increasing, sortable numbers.
- comparators.add(new CrossRefEntryComparator());
+ // entries will be sorted based on their internal IDs
comparators.add(new IdComparator());
} else {
- comparators.add(new CrossRefEntryComparator());
-
+ // use configured sorting strategy
comparators.add(new FieldComparator(saveOrder.get().sortCriteria[0]));
comparators.add(new FieldComparator(saveOrder.get().sortCriteria[1]));
comparators.add(new FieldComparator(saveOrder.get().sortCriteria[2]));
@@ -156,6 +158,12 @@ public abstract class BibDatabaseWriter<E extends SaveSession> {
session = saveSessionFactory.createSaveSession(preferences.getEncodingOrDefault(), preferences.getMakeBackup());
+ Optional<String> sharedDatabaseIDOptional = bibDatabaseContext.getDatabase().getSharedDatabaseID();
+
+ if (sharedDatabaseIDOptional.isPresent()) {
+ writeDatabaseID(sharedDatabaseIDOptional.get());
+ }
+
// Map to collect entry type definitions that we must save along with entries using them.
Map<String, EntryType> typesToWrite = new TreeMap<>();
@@ -165,7 +173,7 @@ public abstract class BibDatabaseWriter<E extends SaveSession> {
}
// Write preamble if there is one.
- writePreamble(bibDatabaseContext.getDatabase().getPreamble());
+ writePreamble(bibDatabaseContext.getDatabase().getPreamble().orElse(""));
// Write strings if there are any.
writeStrings(bibDatabaseContext.getDatabase(), preferences.isReformatFile(),
@@ -193,7 +201,7 @@ public abstract class BibDatabaseWriter<E extends SaveSession> {
if (preferences.getSaveType() != SavePreferences.DatabaseSaveType.PLAIN_BIBTEX) {
// Write meta data.
- writeMetaData(bibDatabaseContext.getMetaData());
+ writeMetaData(bibDatabaseContext.getMetaData(), preferences.getGlobalCiteKeyPattern());
// Write type definitions, if any:
writeEntryTypeDefinitions(typesToWrite);
@@ -220,10 +228,11 @@ public abstract class BibDatabaseWriter<E extends SaveSession> {
/**
* Writes all data to the specified writer, using each object's toString() method.
*/
- protected void writeMetaData(MetaData metaData) throws SaveException {
+ protected void writeMetaData(MetaData metaData, GlobalBibtexKeyPattern globalCiteKeyPattern) throws SaveException {
Objects.requireNonNull(metaData);
- Map<String, String> serializedMetaData = metaData.getAsStringMap();
+ Map<String, String> serializedMetaData = MetaDataSerializer.getSerializedStringMap(metaData,
+ globalCiteKeyPattern);
for(Map.Entry<String, String> metaItem : serializedMetaData.entrySet()) {
writeMetaDataItem(metaItem);
@@ -234,6 +243,8 @@ public abstract class BibDatabaseWriter<E extends SaveSession> {
protected abstract void writePreamble(String preamble) throws SaveException;
+ protected abstract void writeDatabaseID(String sharedDatabaseID) throws SaveException;
+
/**
* Write all strings in alphabetical order, modified to produce a safe (for
* BibTeX) order of the strings if they reference each other.
diff --git a/src/main/java/net/sf/jabref/logic/exporter/BibTeXMLExportFormat.java b/src/main/java/net/sf/jabref/logic/exporter/BibTeXMLExportFormat.java
new file mode 100644
index 0000000..78e0556
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/exporter/BibTeXMLExportFormat.java
@@ -0,0 +1,246 @@
+package net.sf.jabref.logic.exporter;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.math.BigInteger;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.datatype.DatatypeConfigurationException;
+import javax.xml.datatype.DatatypeFactory;
+import javax.xml.datatype.XMLGregorianCalendar;
+import javax.xml.namespace.QName;
+
+import net.sf.jabref.logic.importer.fileformat.bibtexml.Article;
+import net.sf.jabref.logic.importer.fileformat.bibtexml.Book;
+import net.sf.jabref.logic.importer.fileformat.bibtexml.Booklet;
+import net.sf.jabref.logic.importer.fileformat.bibtexml.Conference;
+import net.sf.jabref.logic.importer.fileformat.bibtexml.Entry;
+import net.sf.jabref.logic.importer.fileformat.bibtexml.File;
+import net.sf.jabref.logic.importer.fileformat.bibtexml.Inbook;
+import net.sf.jabref.logic.importer.fileformat.bibtexml.Incollection;
+import net.sf.jabref.logic.importer.fileformat.bibtexml.Inproceedings;
+import net.sf.jabref.logic.importer.fileformat.bibtexml.Manual;
+import net.sf.jabref.logic.importer.fileformat.bibtexml.Mastersthesis;
+import net.sf.jabref.logic.importer.fileformat.bibtexml.Misc;
+import net.sf.jabref.logic.importer.fileformat.bibtexml.Phdthesis;
+import net.sf.jabref.logic.importer.fileformat.bibtexml.Proceedings;
+import net.sf.jabref.logic.importer.fileformat.bibtexml.Techreport;
+import net.sf.jabref.logic.importer.fileformat.bibtexml.Unpublished;
+import net.sf.jabref.model.database.BibDatabaseContext;
+import net.sf.jabref.model.entry.BibEntry;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Export format for the BibTeXML format.
+ */
+public class BibTeXMLExportFormat extends ExportFormat {
+
+ private static final String BIBTEXML_NAMESPACE_URI = "http://bibtexml.sf.net/";
+ private static final Locale ENGLISH = Locale.ENGLISH;
+ private static final Log LOGGER = LogFactory.getLog(BibTeXMLExportFormat.class);
+ private JAXBContext context;
+
+
+ public BibTeXMLExportFormat() {
+ super("BibTeXML", "bibtexml", null, null, ".xml");
+ }
+
+ @Override
+ public void performExport(final BibDatabaseContext databaseContext, final String resultFile, final Charset encoding,
+ List<BibEntry> entries) throws SaveException {
+ Objects.requireNonNull(databaseContext);
+ Objects.requireNonNull(entries);
+ if (entries.isEmpty()) { // Only export if entries exist
+ return;
+ }
+
+ File file = new File();
+ for (BibEntry bibEntry : entries) {
+ Entry entry = new Entry();
+
+ bibEntry.getCiteKeyOptional().ifPresent(citeKey -> entry.setId(citeKey));
+
+ String type = bibEntry.getType().toLowerCase(ENGLISH);
+ switch (type) {
+ case "article":
+ parse(new Article(), bibEntry, entry);
+ break;
+ case "book":
+ parse(new Book(), bibEntry, entry);
+ break;
+ case "booklet":
+ parse(new Booklet(), bibEntry, entry);
+ break;
+ case "conference":
+ parse(new Conference(), bibEntry, entry);
+ break;
+ case "inbook":
+ parseInbook(new Inbook(), bibEntry, entry);
+ break;
+ case "incollection":
+ parse(new Incollection(), bibEntry, entry);
+ break;
+ case "inproceedings":
+ parse(new Inproceedings(), bibEntry, entry);
+ break;
+ case "mastersthesis":
+ parse(new Mastersthesis(), bibEntry, entry);
+ break;
+ case "manual":
+ parse(new Manual(), bibEntry, entry);
+ break;
+ case "misc":
+ parse(new Misc(), bibEntry, entry);
+ break;
+ case "phdthesis":
+ parse(new Phdthesis(), bibEntry, entry);
+ break;
+ case "proceedings":
+ parse(new Proceedings(), bibEntry, entry);
+ break;
+ case "techreport":
+ parse(new Techreport(), bibEntry, entry);
+ break;
+ case "unpublished":
+ parse(new Unpublished(), bibEntry, entry);
+ break;
+ default:
+ LOGGER.warn("unexpected type appeared");
+ break;
+ }
+ file.getEntry().add(entry);
+ }
+ createMarshallerAndWriteToFile(file, resultFile);
+ }
+
+ private void createMarshallerAndWriteToFile(File file, String resultFile) throws SaveException {
+ try {
+ if (context == null) {
+ context = JAXBContext.newInstance(File.class);
+ }
+ Marshaller marshaller = context.createMarshaller();
+ marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
+
+ marshaller.marshal(file, new java.io.File(resultFile));
+ } catch (JAXBException e) {
+ throw new SaveException(e);
+ }
+ }
+
+ /**
+ * Contains same logic as the {@link parse()} method, but inbook needs a special treatment, because
+ * the contents of inbook are stored in a List of JAXBElements. So we first need to create
+ * a JAXBElement for every field and then add it to the content list.
+ */
+ private void parseInbook(Inbook inbook, BibEntry bibEntry, Entry entry) {
+ Map<String, String> fieldMap = bibEntry.getFieldMap();
+ for (Map.Entry<String, String> entryField : fieldMap.entrySet()) {
+ String value = entryField.getValue();
+ String key = entryField.getKey();
+ if ("year".equals(key)) {
+ XMLGregorianCalendar calendar;
+ try {
+ calendar = DatatypeFactory.newInstance().newXMLGregorianCalendar(value);
+
+ JAXBElement<XMLGregorianCalendar> year = new JAXBElement<>(
+ new QName(BIBTEXML_NAMESPACE_URI, "year"), XMLGregorianCalendar.class, calendar);
+ inbook.getContent().add(year);
+ } catch (DatatypeConfigurationException e) {
+ LOGGER.error("A configuration error occured");
+ }
+ } else if ("number".equals(key)) {
+ JAXBElement<BigInteger> number = new JAXBElement<>(new QName(BIBTEXML_NAMESPACE_URI, "number"),
+ BigInteger.class, new BigInteger(value));
+ inbook.getContent().add(number);
+ } else {
+ JAXBElement<String> element = new JAXBElement<>(new QName(BIBTEXML_NAMESPACE_URI, key), String.class,
+ value);
+ inbook.getContent().add(element);
+ }
+ }
+
+ //set the entryType to the entry
+ entry.setInbook(inbook);
+ }
+
+ /**
+ * Generic method that gets an instance of an entry type (article, book, booklet ...). It also
+ * gets one bibEntry. Then the method checks all fields of the entry and then for all fields the method
+ * uses the set method of the entry type with the fieldname. So for example if a bib entry has the field
+ * author and the value for it is "Max Mustermann" and the given type is an article, then this method
+ * will invoke <Code>article.setAuthor("Max Mustermann")</Code>. <br>
+ * <br>
+ * The second part of this method is that the entry type will be set to the entry. So e.g., if the type is
+ * article then <Code>entry.setArticle(article)</Code> will be invoked.
+ *
+ * @param entryType The type parameterized type of the entry.
+ * @param bibEntry The bib entry, which fields will be set to the entryType.
+ * @param entry The bibtexml entry. The entryType will be set to this entry.
+ */
+ private <T> void parse(T entryType, BibEntry bibEntry, Entry entry) {
+ List<Method> declaredSetMethods = getListOfSetMethods(entryType);
+ Map<String, String> fieldMap = bibEntry.getFieldMap();
+ for (Map.Entry<String, String> entryField : fieldMap.entrySet()) {
+ String value = entryField.getValue();
+ String key = entryField.getKey();
+ for (Method method : declaredSetMethods) {
+ String methodNameWithoutSet = method.getName().replace("set", "").toLowerCase(ENGLISH);
+ try {
+
+ if ("year".equals(key) && key.equals(methodNameWithoutSet)) {
+ try {
+
+ XMLGregorianCalendar calendar = DatatypeFactory.newInstance()
+ .newXMLGregorianCalendar(value);
+ method.invoke(entryType, calendar);
+ } catch (DatatypeConfigurationException e) {
+ LOGGER.error("A configuration error occured");
+ }
+ break;
+ } else if ("number".equals(key) && key.equals(methodNameWithoutSet)) {
+ method.invoke(entryType, new BigInteger(value));
+ break;
+ } else if (key.equals(methodNameWithoutSet)) {
+ method.invoke(entryType, value);
+ break;
+ }
+ } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+ LOGGER.error("Could not invoke method", e);
+ }
+ }
+
+ //set the entryType to the entry
+ List<Method> entryMethods = getListOfSetMethods(entry);
+ for (Method method : entryMethods) {
+ String methodWithoutSet = method.getName().replace("set", "");
+ String simpleClassName = entryType.getClass().getSimpleName();
+
+ if (methodWithoutSet.equals(simpleClassName)) {
+ try {
+ method.invoke(entry, entryType);
+ } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+ LOGGER.warn("Could not set the type to the entry");
+ }
+ }
+ }
+ }
+ }
+
+ private <T> List<Method> getListOfSetMethods(T entryType) {
+ return Arrays.asList(entryType.getClass().getDeclaredMethods()).stream()
+ .filter(method -> method.getName().startsWith("set")).collect(Collectors.toList());
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/logic/exporter/BibtexDatabaseWriter.java b/src/main/java/net/sf/jabref/logic/exporter/BibtexDatabaseWriter.java
index 35125ee..90432aa 100644
--- a/src/main/java/net/sf/jabref/logic/exporter/BibtexDatabaseWriter.java
+++ b/src/main/java/net/sf/jabref/logic/exporter/BibtexDatabaseWriter.java
@@ -5,17 +5,17 @@ import java.io.Writer;
import java.nio.charset.Charset;
import java.util.Map;
-import net.sf.jabref.BibDatabaseContext;
-import net.sf.jabref.MetaData;
import net.sf.jabref.logic.bibtex.BibEntryWriter;
import net.sf.jabref.logic.bibtex.LatexFieldFormatter;
import net.sf.jabref.logic.bibtex.LatexFieldFormatterPreferences;
import net.sf.jabref.logic.util.OS;
-import net.sf.jabref.logic.util.strings.StringUtil;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.database.BibDatabaseMode;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.BibtexString;
import net.sf.jabref.model.entry.CustomEntryType;
+import net.sf.jabref.model.metadata.MetaData;
+import net.sf.jabref.model.strings.StringUtil;
public class BibtexDatabaseWriter<E extends SaveSession> extends BibDatabaseWriter<E> {
@@ -23,6 +23,7 @@ public class BibtexDatabaseWriter<E extends SaveSession> extends BibDatabaseWrit
private static final String COMMENT_PREFIX = "@Comment";
private static final String PREAMBLE_PREFIX = "@Preamble";
+ public static final String DATABASE_ID_PREFIX = "DBID:";
public BibtexDatabaseWriter(SaveSessionFactory<E> saveSessionFactory) {
super(saveSessionFactory);
@@ -137,6 +138,22 @@ public class BibtexDatabaseWriter<E extends SaveSession> extends BibDatabaseWrit
getWriter().write("% ");
getWriter().write(SavePreferences.ENCODING_PREFIX + encoding);
getWriter().write(OS.NEWLINE);
+
+ } catch (IOException e) {
+ throw new SaveException(e);
+ }
+ }
+
+ @Override
+ protected void writeDatabaseID(String sharedDatabaseID) throws SaveException {
+ try {
+ StringBuilder stringBuilder = new StringBuilder()
+ .append("% ")
+ .append(DATABASE_ID_PREFIX)
+ .append(" ")
+ .append(sharedDatabaseID)
+ .append(OS.NEWLINE);
+ getWriter().write(stringBuilder.toString());
} catch (IOException e) {
throw new SaveException(e);
}
diff --git a/src/main/java/net/sf/jabref/logic/exporter/CustomExportList.java b/src/main/java/net/sf/jabref/logic/exporter/CustomExportList.java
index 8a6ce5c..aad6d7c 100644
--- a/src/main/java/net/sf/jabref/logic/exporter/CustomExportList.java
+++ b/src/main/java/net/sf/jabref/logic/exporter/CustomExportList.java
@@ -63,7 +63,7 @@ public class CustomExportList {
list.clear();
int i = 0;
List<String> s;
- LayoutFormatterPreferences layoutPreferences = LayoutFormatterPreferences.fromPreferences(prefs, loader);
+ LayoutFormatterPreferences layoutPreferences = prefs.getLayoutFormatterPreferences(loader);
SavePreferences savePreferences = SavePreferences.loadForExportFromPreferences(prefs);
while (!((s = prefs.getStringList(JabRefPreferences.CUSTOM_EXPORT_FORMAT + i)).isEmpty())) {
Optional<ExportFormat> format = createFormat(s, layoutPreferences, savePreferences);
diff --git a/src/main/java/net/sf/jabref/logic/exporter/ExportFormat.java b/src/main/java/net/sf/jabref/logic/exporter/ExportFormat.java
index 258ed0e..2a0a069 100644
--- a/src/main/java/net/sf/jabref/logic/exporter/ExportFormat.java
+++ b/src/main/java/net/sf/jabref/logic/exporter/ExportFormat.java
@@ -16,11 +16,11 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
-import net.sf.jabref.BibDatabaseContext;
import net.sf.jabref.JabRefMain;
import net.sf.jabref.logic.layout.Layout;
import net.sf.jabref.logic.layout.LayoutFormatterPreferences;
import net.sf.jabref.logic.layout.LayoutHelper;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.entry.BibEntry;
import org.apache.commons.logging.Log;
@@ -179,18 +179,7 @@ public class ExportFormat implements IExportFormat {
return reader;
}
- /**
- * Perform the export of {@code database}.
- *
- * @param databaseContext the database to export from.
- * @param file the file to write the resulting export to
- * @param encoding The encoding of the database
- * @param entries Contains all entries that should be exported.
- * @throws IOException if a problem occurred while trying to write to {@code writer}
- * or read from required resources.
- * @throws Exception if any other error occurred during export.
- * @see net.sf.jabref.logic.exporter.IExportFormat#performExport(BibDatabaseContext, String, Charset, List)
- */
+
@Override
public void performExport(final BibDatabaseContext databaseContext, final String file,
final Charset encoding, List<BibEntry> entries) throws Exception {
diff --git a/src/main/java/net/sf/jabref/logic/exporter/ExportFormats.java b/src/main/java/net/sf/jabref/logic/exporter/ExportFormats.java
index 7b59204..1cc10f4 100644
--- a/src/main/java/net/sf/jabref/logic/exporter/ExportFormats.java
+++ b/src/main/java/net/sf/jabref/logic/exporter/ExportFormats.java
@@ -31,8 +31,6 @@ public class ExportFormats {
ExportFormats.putFormat(new ExportFormat("DIN 1505", "din1505", "din1505winword", "din1505", ".rtf",
layoutPreferences, savePreferences));
ExportFormats.putFormat(
- new ExportFormat("BibTeXML", "bibtexml", "bibtexml", null, ".xml", layoutPreferences, savePreferences));
- ExportFormats.putFormat(
new ExportFormat("BibO RDF", "bibordf", "bibordf", null, ".rdf", layoutPreferences, savePreferences));
ExportFormats.putFormat(new ExportFormat(Localization.lang("HTML table"), "tablerefs", "tablerefs", "tablerefs",
".html", layoutPreferences, savePreferences));
@@ -42,7 +40,7 @@ public class ExportFormats {
"tablerefsabsbib", "tablerefsabsbib", "tablerefsabsbib", ".html", layoutPreferences, savePreferences));
ExportFormats.putFormat(new ExportFormat("Harvard RTF", "harvard", "harvard", "harvard", ".rtf",
layoutPreferences, savePreferences));
- ExportFormats.putFormat(new ExportFormat("ISO 690", "iso690rtf", "iso690RTF", "iso690rtf", ".rtf",
+ ExportFormats.putFormat(new ExportFormat("ISO 690 RTF", "iso690rtf", "iso690RTF", "iso690rtf", ".rtf",
layoutPreferences, savePreferences));
ExportFormats.putFormat(new ExportFormat("ISO 690", "iso690txt", "iso690", "iso690txt", ".txt",
layoutPreferences, savePreferences));
@@ -56,6 +54,7 @@ public class ExportFormats {
ExportFormats.putFormat(
new ExportFormat("MIS Quarterly", "misq", "misq", "misq", ".rtf", layoutPreferences, savePreferences));
+ ExportFormats.putFormat(new BibTeXMLExportFormat());
ExportFormats.putFormat(new OpenOfficeDocumentCreator());
ExportFormats.putFormat(new OpenDocumentSpreadsheetCreator());
ExportFormats.putFormat(new MSBibExportFormat());
diff --git a/src/main/java/net/sf/jabref/logic/exporter/FieldFormatterCleanups.java b/src/main/java/net/sf/jabref/logic/exporter/FieldFormatterCleanups.java
deleted file mode 100644
index dc3de53..0000000
--- a/src/main/java/net/sf/jabref/logic/exporter/FieldFormatterCleanups.java
+++ /dev/null
@@ -1,228 +0,0 @@
-package net.sf.jabref.logic.exporter;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.StringJoiner;
-
-import net.sf.jabref.logic.cleanup.FieldFormatterCleanup;
-import net.sf.jabref.logic.formatter.Formatter;
-import net.sf.jabref.logic.formatter.Formatters;
-import net.sf.jabref.logic.formatter.IdentityFormatter;
-import net.sf.jabref.logic.formatter.bibtexfields.NormalizeMonthFormatter;
-import net.sf.jabref.logic.formatter.bibtexfields.NormalizePagesFormatter;
-import net.sf.jabref.logic.formatter.bibtexfields.OrdinalsToSuperscriptFormatter;
-import net.sf.jabref.logic.util.OS;
-import net.sf.jabref.logic.util.strings.StringUtil;
-import net.sf.jabref.model.FieldChange;
-import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.model.entry.FieldName;
-
-public class FieldFormatterCleanups {
-
- private final List<FieldFormatterCleanup> actions;
-
- private static List<Formatter> availableFormatters;
-
- private final boolean enabled;
-
- public static final FieldFormatterCleanups DEFAULT_SAVE_ACTIONS;
-
- static {
- availableFormatters = new ArrayList<>();
- availableFormatters.addAll(Formatters.ALL);
-
- List<FieldFormatterCleanup> defaultFormatters = new ArrayList<>();
- defaultFormatters.add(new FieldFormatterCleanup(FieldName.PAGES, new NormalizePagesFormatter()));
- defaultFormatters.add(new FieldFormatterCleanup(FieldName.MONTH, new NormalizeMonthFormatter()));
- defaultFormatters.add(new FieldFormatterCleanup(FieldName.BOOKTITLE, new OrdinalsToSuperscriptFormatter()));
- DEFAULT_SAVE_ACTIONS = new FieldFormatterCleanups(false, defaultFormatters);
- }
-
- public FieldFormatterCleanups(boolean enabled, String formatterString) {
- this(enabled, parse(formatterString));
- }
-
- public FieldFormatterCleanups(boolean enabled, List<FieldFormatterCleanup> actions) {
- this.enabled = enabled;
- this.actions = Objects.requireNonNull(actions);
- }
-
- public boolean isEnabled() {
- return enabled;
- }
-
- public List<FieldFormatterCleanup> getConfiguredActions() {
- return Collections.unmodifiableList(actions);
- }
-
- public List<Formatter> getAvailableFormatters() {
- return Collections.unmodifiableList(availableFormatters);
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if ((o == null) || (getClass() != o.getClass())) {
- return false;
- }
-
- FieldFormatterCleanups that = (FieldFormatterCleanups) o;
-
- if (enabled != that.enabled) {
- return false;
- }
- return actions.equals(that.actions);
-
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(actions, enabled);
- }
-
- public static List<FieldFormatterCleanup> parse(String formatterString) {
-
- if ((formatterString == null) || formatterString.isEmpty()) {
- // no save actions defined in the meta data
- return new ArrayList<>();
- }
-
- List<FieldFormatterCleanup> actions = new ArrayList<>();
-
- //read concrete actions
- int startIndex = 0;
-
- // first remove all newlines for easier parsing
- String remainingString = formatterString;
-
- remainingString = StringUtil.unifyLineBreaksToConfiguredLineBreaks(remainingString).replaceAll(OS.NEWLINE, "");
- try {
- while (startIndex < formatterString.length()) {
- // read the field name
- int currentIndex = remainingString.indexOf('[');
- String fieldKey = remainingString.substring(0, currentIndex);
- int endIndex = remainingString.indexOf(']');
- startIndex += endIndex + 1;
-
- //read each formatter
- int tokenIndex = remainingString.indexOf(',');
- do {
- boolean doBreak = false;
- if ((tokenIndex == -1) || (tokenIndex > endIndex)) {
- tokenIndex = remainingString.indexOf(']');
- doBreak = true;
- }
-
- String formatterKey = remainingString.substring(currentIndex + 1, tokenIndex);
- actions.add(new FieldFormatterCleanup(fieldKey, getFormatterFromString(formatterKey)));
-
- remainingString = remainingString.substring(tokenIndex + 1);
- if (remainingString.startsWith("]") || doBreak) {
- break;
- }
- tokenIndex = remainingString.indexOf(',');
-
- currentIndex = -1;
- } while (true);
-
-
- }
- } catch (StringIndexOutOfBoundsException ignore) {
- // if this exception occurs, the remaining part of the save actions string is invalid.
- // Thus we stop parsing and take what we have parsed until now
- return actions;
- }
- return actions;
- }
-
- public List<FieldChange> applySaveActions(BibEntry entry) {
- if (enabled) {
- return applyAllActions(entry);
- } else {
- return new ArrayList<>();
- }
- }
-
- private List<FieldChange> applyAllActions(BibEntry entry) {
- List<FieldChange> result = new ArrayList<>();
-
- for (FieldFormatterCleanup action : actions) {
- result.addAll(action.cleanup(entry));
- }
-
- return result;
- }
-
- private static Formatter getFormatterFromString(String formatterName) {
- for (Formatter formatter : availableFormatters) {
- if (formatterName.equals(formatter.getKey())) {
- return formatter;
- }
- }
- return new IdentityFormatter();
- }
-
- private static String getMetaDataString(List<FieldFormatterCleanup> actionList) {
- //first, group all formatters by the field for which they apply
- Map<String, List<String>> groupedByField = new HashMap<>();
- for (FieldFormatterCleanup cleanup : actionList) {
- String key = cleanup.getField();
-
- // add new list into the hashmap if needed
- if (!groupedByField.containsKey(key)) {
- groupedByField.put(key, new ArrayList<>());
- }
-
- //add the formatter to the map if it is not already there
- List<String> formattersForKey = groupedByField.get(key);
- if (!formattersForKey.contains(cleanup.getFormatter().getKey())) {
- formattersForKey.add(cleanup.getFormatter().getKey());
- }
- }
-
- // convert the contents of the hashmap into the correct serialization
- StringBuilder result = new StringBuilder();
- for (Map.Entry<String, List<String>> entry : groupedByField.entrySet()) {
- result.append(entry.getKey());
-
- StringJoiner joiner = new StringJoiner(",", "[", "]" + OS.NEWLINE);
- entry.getValue().forEach(joiner::add);
- result.append(joiner.toString());
- }
-
- return result.toString();
- }
-
- public List<String> getAsStringList() {
- List<String> stringRepresentation = new ArrayList<>();
-
- if (enabled) {
- stringRepresentation.add("enabled");
- } else {
- stringRepresentation.add("disabled");
- }
-
- String formatterString = FieldFormatterCleanups.getMetaDataString(actions);
- stringRepresentation.add(formatterString);
- return stringRepresentation;
- }
-
- public static FieldFormatterCleanups parse(List<String> formatterMetaList) {
-
- if ((formatterMetaList != null) && (formatterMetaList.size() >= 2)) {
- boolean enablementStatus = "enabled".equals(formatterMetaList.get(0));
- String formatterString = formatterMetaList.get(1);
- return new FieldFormatterCleanups(enablementStatus, formatterString);
- } else {
- // return default actions
- return FieldFormatterCleanups.DEFAULT_SAVE_ACTIONS;
- }
-
- }
-}
diff --git a/src/main/java/net/sf/jabref/logic/exporter/FileSaveSession.java b/src/main/java/net/sf/jabref/logic/exporter/FileSaveSession.java
index 3884106..1f47bc6 100644
--- a/src/main/java/net/sf/jabref/logic/exporter/FileSaveSession.java
+++ b/src/main/java/net/sf/jabref/logic/exporter/FileSaveSession.java
@@ -1,13 +1,13 @@
package net.sf.jabref.logic.exporter;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
+import java.nio.file.attribute.PosixFilePermission;
+import java.util.EnumSet;
+import java.util.Set;
-import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.util.io.FileBasedLock;
import net.sf.jabref.logic.util.io.FileUtil;
@@ -38,6 +38,7 @@ public class FileSaveSession extends SaveSession {
private static final String TEMP_SUFFIX = "save.bib";
private final Path temporaryFile;
+
public FileSaveSession(Charset encoding, boolean backup) throws SaveException {
this(encoding, backup, createTemporaryFile());
}
@@ -49,8 +50,8 @@ public class FileSaveSession extends SaveSession {
private static VerifyingWriter getWriterForFile(Charset encoding, Path file) throws SaveException {
try {
- return new VerifyingWriter(new FileOutputStream(file.toFile()), encoding);
- } catch (FileNotFoundException e) {
+ return new VerifyingWriter(Files.newOutputStream(file), encoding);
+ } catch (IOException e) {
throw new SaveException(e);
}
}
@@ -69,14 +70,8 @@ public class FileSaveSession extends SaveSession {
return;
}
if (backup && Files.exists(file)) {
- Path fileName = file.getFileName();
- Path backupFile = file.resolveSibling(fileName + BACKUP_EXTENSION);
- try {
- FileUtil.copyFile(file.toFile(), backupFile.toFile(), true);
- } catch (IOException ex) {
- LOGGER.error("Problem copying file", ex);
- throw SaveException.BACKUP_CREATION;
- }
+ Path backupFile = FileUtil.addExtension(file, BACKUP_EXTENSION);
+ FileUtil.copyFile(file, backupFile, true);
}
try {
// Always use a lock file
@@ -91,19 +86,31 @@ public class FileSaveSession extends SaveSession {
LOGGER.error("Error when creating lock file.", ex);
}
- FileUtil.copyFile(temporaryFile.toFile(), file.toFile(), true);
- } catch (IOException ex2) {
- // If something happens here, what can we do to correct the problem? The file is corrupted, but we still
- // have a clean copy in tmp. However, we just failed to copy tmp to file, so it's not likely that
- // repeating the action will have a different result.
- // On the other hand, our temporary file should still be clean, and won't be deleted.
- throw new SaveException("Save failed while committing changes: " + ex2.getMessage(),
- Localization.lang("Save failed while committing changes: %0", ex2.getMessage()));
+ // Try to save file permissions to restore them later (by default: allow everything)
+ Set<PosixFilePermission> oldFilePermissions = EnumSet.allOf(PosixFilePermission.class);
+ if (FileUtil.isPosixCompilant && Files.exists(file)) {
+ try {
+ oldFilePermissions = Files.getPosixFilePermissions(file);
+ } catch (IOException exception) {
+ LOGGER.warn("Error getting file permissions.", exception);
+ }
+ }
+
+ FileUtil.copyFile(temporaryFile, file, true);
+
+ // Restore file permissions
+ if (FileUtil.isPosixCompilant) {
+ try {
+ Files.setPosixFilePermissions(file, oldFilePermissions);
+ } catch (IOException exception) {
+ throw new SaveException(exception);
+ }
+ }
} finally {
FileBasedLock.deleteLockFile(file);
}
try {
- Files.delete(temporaryFile);
+ Files.deleteIfExists(temporaryFile);
} catch (IOException e) {
LOGGER.warn("Cannot delete temporary file", e);
}
@@ -112,7 +119,7 @@ public class FileSaveSession extends SaveSession {
@Override
public void cancel() {
try {
- Files.delete(temporaryFile);
+ Files.deleteIfExists(temporaryFile);
} catch (IOException e) {
LOGGER.warn("Cannot delete temporary file", e);
}
diff --git a/src/main/java/net/sf/jabref/logic/exporter/IExportFormat.java b/src/main/java/net/sf/jabref/logic/exporter/IExportFormat.java
index edf5f36..5d8536c 100644
--- a/src/main/java/net/sf/jabref/logic/exporter/IExportFormat.java
+++ b/src/main/java/net/sf/jabref/logic/exporter/IExportFormat.java
@@ -4,7 +4,7 @@ import java.nio.charset.Charset;
import java.nio.file.Path;
import java.util.List;
-import net.sf.jabref.BibDatabaseContext;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.entry.BibEntry;
public interface IExportFormat {
@@ -31,8 +31,8 @@ public interface IExportFormat {
* @param encoding
* The encoding to use.
* @param entries
- * (may be null) A list containing all entries that
- * should be exported. If null, all entries will be exported.
+ * A list containing all entries that
+ * should be exported. The list of entries must be non null
* @throws Exception
*/
void performExport(BibDatabaseContext databaseContext, String file, Charset encoding, List<BibEntry> entries)
@@ -45,8 +45,8 @@ public interface IExportFormat {
* @param databaseContext the database to export from.
* @param file the Path to the file to write to.The path should be an java.nio.Path
* @param encoding The encoding to use.
- * @param entries (may be null) A list containing all entries that
- * should be exported. If null, all entries will be exported.
+ * @param entries A list containing all entries that
+ * should be exported. The list of entries must be non null
* @throws Exception
*/
void performExport(BibDatabaseContext databaseContext, Path file, Charset encoding, List<BibEntry> entries)
diff --git a/src/main/java/net/sf/jabref/logic/exporter/MSBibExportFormat.java b/src/main/java/net/sf/jabref/logic/exporter/MSBibExportFormat.java
index de5082a..f26e100 100644
--- a/src/main/java/net/sf/jabref/logic/exporter/MSBibExportFormat.java
+++ b/src/main/java/net/sf/jabref/logic/exporter/MSBibExportFormat.java
@@ -15,8 +15,8 @@ import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
-import net.sf.jabref.BibDatabaseContext;
import net.sf.jabref.logic.msbib.MSBibDatabase;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.entry.BibEntry;
/**
@@ -43,7 +43,7 @@ class MSBibExportFormat extends ExportFormat {
try (VerifyingWriter ps = session.getWriter()) {
try {
- DOMSource source = new DOMSource(msBibDatabase.getDOM());
+ DOMSource source = new DOMSource(msBibDatabase.getDomForExport());
StreamResult result = new StreamResult(ps);
Transformer trans = TransformerFactory.newInstance().newTransformer();
trans.setOutputProperty(OutputKeys.INDENT, "yes");
diff --git a/src/main/java/net/sf/jabref/logic/exporter/MetaDataSerializer.java b/src/main/java/net/sf/jabref/logic/exporter/MetaDataSerializer.java
new file mode 100644
index 0000000..693e370
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/exporter/MetaDataSerializer.java
@@ -0,0 +1,107 @@
+package net.sf.jabref.logic.exporter;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import net.sf.jabref.logic.util.OS;
+import net.sf.jabref.model.bibtexkeypattern.AbstractBibtexKeyPattern;
+import net.sf.jabref.model.bibtexkeypattern.GlobalBibtexKeyPattern;
+import net.sf.jabref.model.cleanup.FieldFormatterCleanups;
+import net.sf.jabref.model.groups.GroupTreeNode;
+import net.sf.jabref.model.metadata.MetaData;
+import net.sf.jabref.model.strings.StringUtil;
+
+public class MetaDataSerializer {
+
+ /**
+ * Writes all data in the format <key, serialized data>.
+ */
+ public static Map<String, String> getSerializedStringMap(MetaData metaData,
+ GlobalBibtexKeyPattern globalCiteKeyPattern) {
+
+ // First write all meta data except groups
+ Map<String, List<String>> stringyMetaData = new HashMap<>();
+ metaData.getSaveOrderConfig().ifPresent(
+ saveOrderConfig -> stringyMetaData.put(MetaData.SAVE_ORDER_CONFIG, saveOrderConfig.getAsStringList()));
+ metaData.getSaveActions().ifPresent(
+ saveActions -> stringyMetaData.put(MetaData.SAVE_ACTIONS, saveActions.getAsStringList(OS.NEWLINE)));
+ if (metaData.isProtected()) {
+ stringyMetaData.put(MetaData.PROTECTED_FLAG_META, Collections.singletonList("true"));
+ }
+ stringyMetaData.putAll(serializeCiteKeyPattern(metaData, globalCiteKeyPattern));
+ metaData.getMode().ifPresent(
+ mode -> stringyMetaData.put(MetaData.DATABASE_TYPE, Collections.singletonList(mode.getAsString())));
+ metaData.getDefaultFileDirectory().ifPresent(
+ path -> stringyMetaData.put(MetaData.FILE_DIRECTORY, Collections.singletonList(path.trim())));
+ metaData.getUserFileDirectories().forEach((user, path) -> stringyMetaData
+ .put(MetaData.FILE_DIRECTORY + '-' + user, Collections.singletonList(path.trim())));
+
+ Map<String, String> serializedMetaData = serializeMetaData(stringyMetaData);
+
+ // Write groups if present.
+ // Skip this if only the root node exists (which is always the AllEntriesGroup).
+ metaData.getGroups().filter(root -> root.getNumberOfChildren() > 0).ifPresent(
+ root -> serializedMetaData.put(MetaData.GROUPSTREE, serializeGroups(root)));
+ return serializedMetaData;
+ }
+
+ private static Map<String, String> serializeMetaData(Map<String, List<String>> stringyMetaData) {
+ Map<String, String> serializedMetaData = new TreeMap<>();
+ for (Map.Entry<String, List<String>> metaItem : stringyMetaData.entrySet()) {
+ StringBuilder stringBuilder = new StringBuilder();
+ for (String dataItem : metaItem.getValue()) {
+ stringBuilder.append(StringUtil.quote(dataItem, MetaData.SEPARATOR_STRING, MetaData.ESCAPE_CHARACTER)).append(MetaData.SEPARATOR_STRING);
+
+ //in case of save actions, add an additional newline after the enabled flag
+ if (metaItem.getKey().equals(MetaData.SAVE_ACTIONS)
+ && (FieldFormatterCleanups.ENABLED.equals(dataItem)
+ || FieldFormatterCleanups.DISABLED.equals(dataItem))) {
+ stringBuilder.append(OS.NEWLINE);
+ }
+ }
+
+ String serializedItem = stringBuilder.toString();
+ // Only add non-empty values
+ if (!serializedItem.isEmpty() && !MetaData.SEPARATOR_STRING.equals(serializedItem)) {
+ serializedMetaData.put(metaItem.getKey(), serializedItem);
+ }
+ }
+ return serializedMetaData;
+ }
+
+ private static Map<String, List<String>> serializeCiteKeyPattern(MetaData metaData, GlobalBibtexKeyPattern globalCiteKeyPattern) {
+ Map<String, List<String>> stringyPattern = new HashMap<>();
+ AbstractBibtexKeyPattern citeKeyPattern = metaData.getCiteKeyPattern(globalCiteKeyPattern);
+ for (String key : citeKeyPattern.getAllKeys()) {
+ if (!citeKeyPattern.isDefaultValue(key)) {
+ List<String> data = new ArrayList<>();
+ data.add(citeKeyPattern.getValue(key).get(0));
+ String metaDataKey = MetaData.PREFIX_KEYPATTERN + key;
+ stringyPattern.put(metaDataKey, data);
+ }
+ }
+ if (citeKeyPattern.getDefaultValue() != null && !citeKeyPattern.getDefaultValue().isEmpty()) {
+ List<String> data = new ArrayList<>();
+ data.add(citeKeyPattern.getDefaultValue().get(0));
+ stringyPattern.put(MetaData.KEYPATTERNDEFAULT, data);
+ }
+ return stringyPattern;
+ }
+
+ private static String serializeGroups(GroupTreeNode root) {
+ StringBuilder stringBuilder = new StringBuilder();
+ stringBuilder.append(OS.NEWLINE);
+
+ for (String groupNode : root.getTreeAsString()) {
+ stringBuilder.append(StringUtil.quote(groupNode, MetaData.SEPARATOR_STRING, MetaData.ESCAPE_CHARACTER));
+ stringBuilder.append(MetaData.SEPARATOR_STRING);
+ stringBuilder.append(OS.NEWLINE);
+ }
+ return stringBuilder.toString();
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/logic/exporter/ModsExportFormat.java b/src/main/java/net/sf/jabref/logic/exporter/ModsExportFormat.java
index be8db05..2a11988 100644
--- a/src/main/java/net/sf/jabref/logic/exporter/ModsExportFormat.java
+++ b/src/main/java/net/sf/jabref/logic/exporter/ModsExportFormat.java
@@ -1,58 +1,443 @@
package net.sf.jabref.logic.exporter;
+import java.io.File;
import java.io.IOException;
+import java.math.BigInteger;
import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Paths;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
-import javax.xml.transform.OutputKeys;
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerException;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.TransformerFactoryConfigurationError;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.stream.StreamResult;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.namespace.QName;
-import net.sf.jabref.BibDatabaseContext;
-import net.sf.jabref.logic.mods.MODSDatabase;
+import net.sf.jabref.logic.importer.fileformat.mods.AbstractDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.CodeOrText;
+import net.sf.jabref.logic.importer.fileformat.mods.DateDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.DetailDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.ExtentDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.GenreDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.IdentifierDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.IssuanceDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.LanguageDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.LanguageTermDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.LocationDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.ModsCollectionDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.ModsDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.NameDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.NamePartDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.NoteDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.OriginInfoDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.PartDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.PhysicalLocationDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.PlaceDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.PlaceTermDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.RelatedItemDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.StringPlusLanguage;
+import net.sf.jabref.logic.importer.fileformat.mods.StringPlusLanguagePlusAuthority;
+import net.sf.jabref.logic.importer.fileformat.mods.StringPlusLanguagePlusSupplied;
+import net.sf.jabref.logic.importer.fileformat.mods.SubjectDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.TitleInfoDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.TypeOfResourceDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.UrlDefinition;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldName;
+
/**
* ExportFormat for exporting in MODS XML format.
*/
class ModsExportFormat extends ExportFormat {
+ private static final String MINUS = "-";
+ private static final String DOUBLE_MINUS = "--";
+ private static final String MODS_SCHEMA_LOCATION = "http://www.loc.gov/standards/mods/v3/mods-3-6.xsd";
+ protected static final String MODS_NAMESPACE_URI = "http://www.loc.gov/mods/v3";
+ private JAXBContext context;
+
+
public ModsExportFormat() {
super("MODS", "mods", null, null, ".xml");
}
@Override
- public void performExport(final BibDatabaseContext databaseContext, final String file,
- final Charset encoding, List<BibEntry> entries) throws SaveException {
+ public void performExport(final BibDatabaseContext databaseContext, final String file, final Charset encoding,
+ List<BibEntry> entries) throws SaveException, IOException {
Objects.requireNonNull(databaseContext);
Objects.requireNonNull(entries);
if (entries.isEmpty()) { // Only export if entries exist
return;
}
- SaveSession ss = new FileSaveSession(StandardCharsets.UTF_8, false);
- try (VerifyingWriter ps = ss.getWriter()) {
- MODSDatabase md = new MODSDatabase(databaseContext.getDatabase(), entries);
+ try {
+ ModsCollectionDefinition modsCollection = new ModsCollectionDefinition();
+ for (BibEntry bibEntry : entries) {
+ ModsDefinition mods = new ModsDefinition();
+ bibEntry.getCiteKeyOptional().ifPresent(citeKey -> addIdentifier("citekey", citeKey, mods));
+
+ Map<String, String> fieldMap = bibEntry.getFieldMap();
+ addGenre(bibEntry, mods);
+
+ OriginInfoDefinition originInfo = new OriginInfoDefinition();
+ PartDefinition partDefinition = new PartDefinition();
+ RelatedItemDefinition relatedItem = new RelatedItemDefinition();
+
+ for (Map.Entry<String, String> entry : fieldMap.entrySet()) {
+ String key = entry.getKey();
+ String value = entry.getValue();
+
+ switch (key) {
+
+ case FieldName.AUTHOR:
+ handleAuthors(mods, value);
+ break;
+ case "affiliation":
+ addAffiliation(mods, value);
+ break;
+ case FieldName.ABSTRACT:
+ addAbstract(mods, value);
+ break;
+ case FieldName.TITLE:
+ addTitle(mods, value);
+ break;
+ case FieldName.LANGUAGE:
+ addLanguage(mods, value);
+ break;
+ case FieldName.LOCATION:
+ addLocation(mods, value);
+ break;
+ case FieldName.URL:
+ addUrl(mods, value);
+ break;
+ case FieldName.NOTE:
+ addNote(mods, value);
+ break;
+ case FieldName.KEYWORDS:
+ addKeyWords(mods, value);
+ break;
+ case FieldName.VOLUME:
+ addDetail(FieldName.VOLUME, value, partDefinition);
+ break;
+ case FieldName.ISSUE:
+ addDetail(FieldName.ISSUE, value, partDefinition);
+ break;
+ case FieldName.PAGES:
+ addPages(partDefinition, value);
+ break;
+ case FieldName.URI:
+ addIdentifier(FieldName.URI, value, mods);
+ break;
+ case FieldName.ISBN:
+ addIdentifier(FieldName.ISBN, value, mods);
+ break;
+ case FieldName.ISSN:
+ addIdentifier(FieldName.ISSN, value, mods);
+ break;
+ case FieldName.DOI:
+ addIdentifier(FieldName.DOI, value, mods);
+ break;
+ case FieldName.PMID:
+ addIdentifier(FieldName.PMID, value, mods);
+ break;
+ case FieldName.JOURNAL:
+ addJournal(value, relatedItem);
+ break;
+ default:
+ break;
+ }
+
+ addOriginInformation(key, value, originInfo);
+ }
+ mods.getModsGroup().add(originInfo);
- try {
- DOMSource source = new DOMSource(md.getDOMrepresentation());
- StreamResult result = new StreamResult(ps);
- Transformer trans = TransformerFactory.newInstance().newTransformer();
- trans.setOutputProperty(OutputKeys.INDENT, "yes");
- trans.transform(source, result);
- } catch (TransformerException | IllegalArgumentException | TransformerFactoryConfigurationError e) {
- throw new Error(e);
+ addRelatedAndOriginInfoToModsGroup(relatedItem, partDefinition, mods);
+ modsCollection.getMods().add(mods);
}
- finalizeSaveSession(ss, Paths.get(file));
- } catch (IOException ex) {
+
+ JAXBElement<ModsCollectionDefinition> jaxbElement = new JAXBElement<>(
+ new QName(MODS_NAMESPACE_URI, "modsCollection"), ModsCollectionDefinition.class, modsCollection);
+
+ createMarshallerAndWriteToFile(file, jaxbElement);
+ } catch (JAXBException ex) {
throw new SaveException(ex);
}
}
+
+ private void createMarshallerAndWriteToFile(String file, JAXBElement<ModsCollectionDefinition> jaxbElement)
+ throws JAXBException {
+
+ if (context == null) {
+ context = JAXBContext.newInstance(ModsCollectionDefinition.class);
+ }
+ Marshaller marshaller = context.createMarshaller();
+ //format the output
+ marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
+ marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, MODS_SCHEMA_LOCATION);
+
+ // Write to File
+ marshaller.marshal(jaxbElement, new File(file));
+ }
+
+
+ private void addRelatedAndOriginInfoToModsGroup(RelatedItemDefinition relatedItem, PartDefinition partDefinition,
+ ModsDefinition mods) {
+
+ relatedItem.getModsGroup().add(partDefinition);
+ relatedItem.setAtType("host");
+ mods.getModsGroup().add(relatedItem);
+ TypeOfResourceDefinition typeOfResource = new TypeOfResourceDefinition();
+ typeOfResource.setValue("text");
+ mods.getModsGroup().add(typeOfResource);
+ }
+
+ private void addGenre(BibEntry bibEntry, ModsDefinition mods) {
+ GenreDefinition genre = new GenreDefinition();
+ genre.setValue(bibEntry.getType());
+ mods.getModsGroup().add(genre);
+ }
+
+ private void addAbstract(ModsDefinition mods, String value) {
+ AbstractDefinition abstractDefinition = new AbstractDefinition();
+ abstractDefinition.setValue(value);
+ mods.getModsGroup().add(abstractDefinition);
+ }
+
+ private void addTitle(ModsDefinition mods, String value) {
+ TitleInfoDefinition titleInfo = new TitleInfoDefinition();
+ StringPlusLanguage title = new StringPlusLanguage();
+ title.setValue(value);
+ JAXBElement<StringPlusLanguage> element = new JAXBElement<>(new QName(MODS_NAMESPACE_URI, "title"),
+ StringPlusLanguage.class, title);
+ titleInfo.getTitleOrSubTitleOrPartNumber().add(element);
+ mods.getModsGroup().add(titleInfo);
+ }
+
+ private void addAffiliation(ModsDefinition mods, String value) {
+ NameDefinition nameDefinition = new NameDefinition();
+ StringPlusLanguage affiliation = new StringPlusLanguage();
+ affiliation.setValue(value);
+ JAXBElement<StringPlusLanguage> element = new JAXBElement<>(new QName(MODS_NAMESPACE_URI, "affiliation"),
+ StringPlusLanguage.class, affiliation);
+ nameDefinition.getAffiliationOrRoleOrDescription().add(element);
+ mods.getModsGroup().add(nameDefinition);
+ }
+
+ private void addLocation(ModsDefinition mods, String value) {
+ LocationDefinition locationDefinition = new LocationDefinition();
+ //There can be more than one location
+ String[] locations = value.split(", ");
+ for (String location : locations) {
+ PhysicalLocationDefinition physicalLocation = new PhysicalLocationDefinition();
+ physicalLocation.setValue(location);
+ locationDefinition.getPhysicalLocation().add(physicalLocation);
+ }
+ mods.getModsGroup().add(locationDefinition);
+ }
+
+ private void addNote(ModsDefinition mods, String value) {
+ String[] notes = value.split(", ");
+ for (String note : notes) {
+ NoteDefinition noteDefinition = new NoteDefinition();
+ noteDefinition.setValue(note);
+ mods.getModsGroup().add(noteDefinition);
+ }
+ }
+
+ private void addUrl(ModsDefinition mods, String value) {
+ String[] urls = value.split(", ");
+ LocationDefinition location = new LocationDefinition();
+ for (String url : urls) {
+ UrlDefinition urlDefinition = new UrlDefinition();
+ urlDefinition.setValue(url);
+ location.getUrl().add(urlDefinition);
+ mods.getModsGroup().add(location);
+ }
+ }
+
+ private void addJournal(String value, RelatedItemDefinition relatedItem) {
+ TitleInfoDefinition titleInfo = new TitleInfoDefinition();
+ StringPlusLanguage title = new StringPlusLanguage();
+ title.setValue(value);
+ JAXBElement<StringPlusLanguage> element = new JAXBElement<>(new QName(MODS_NAMESPACE_URI, "title"),
+ StringPlusLanguage.class, title);
+ titleInfo.getTitleOrSubTitleOrPartNumber().add(element);
+ relatedItem.getModsGroup().add(titleInfo);
+ }
+
+ private void addLanguage(ModsDefinition mods, String value) {
+ LanguageDefinition language = new LanguageDefinition();
+ LanguageTermDefinition languageTerm = new LanguageTermDefinition();
+ languageTerm.setValue(value);
+ language.getLanguageTerm().add(languageTerm);
+ mods.getModsGroup().add(language);
+ }
+
+ private void addPages(PartDefinition partDefinition, String value) {
+ if (value.contains(DOUBLE_MINUS)) {
+ addStartAndEndPage(value, partDefinition, DOUBLE_MINUS);
+ } else if (value.contains(MINUS)) {
+ addStartAndEndPage(value, partDefinition, MINUS);
+ } else {
+ BigInteger total = new BigInteger(value);
+ ExtentDefinition extent = new ExtentDefinition();
+ extent.setTotal(total);
+ partDefinition.getDetailOrExtentOrDate().add(extent);
+ }
+ }
+
+ private void addKeyWords(ModsDefinition mods, String value) {
+ String[] keywords = value.split(", ");
+
+ for (String keyword : keywords) {
+ SubjectDefinition subject = new SubjectDefinition();
+ StringPlusLanguagePlusAuthority topic = new StringPlusLanguagePlusAuthority();
+ topic.setValue(keyword);
+ JAXBElement<?> element = new JAXBElement<>(new QName(MODS_NAMESPACE_URI, "topic"),
+ StringPlusLanguagePlusAuthority.class, topic);
+ subject.getTopicOrGeographicOrTemporal().add(element);
+ mods.getModsGroup().add(subject);
+ }
+ }
+
+ private void handleAuthors(ModsDefinition mods, String value) {
+ String[] authors = value.split("and");
+ for (String author : authors) {
+ NameDefinition name = new NameDefinition();
+ name.setAtType("personal");
+ NamePartDefinition namePart = new NamePartDefinition();
+ if (author.contains(",")) {
+ //if author contains "," then this indicates that the author has a forename and family name
+ int commaIndex = author.indexOf(',');
+ String familyName = author.substring(0, commaIndex);
+ namePart.setAtType("family");
+ namePart.setValue(familyName);
+
+ JAXBElement<NamePartDefinition> element = new JAXBElement<>(new QName(MODS_NAMESPACE_URI, "namePart"),
+ NamePartDefinition.class, namePart);
+ name.getNamePartOrDisplayFormOrAffiliation().add(element);
+
+ //now take care of the forenames
+ String forename = author.substring(commaIndex + 1, author.length());
+ String[] forenames = forename.split(" ");
+ for (String given : forenames) {
+ if (!given.isEmpty()) {
+ NamePartDefinition namePartDefinition = new NamePartDefinition();
+ namePartDefinition.setAtType("given");
+ namePartDefinition.setValue(given);
+ element = new JAXBElement<>(new QName(MODS_NAMESPACE_URI, "namePart"), NamePartDefinition.class,
+ namePartDefinition);
+ name.getNamePartOrDisplayFormOrAffiliation().add(element);
+ }
+ }
+ mods.getModsGroup().add(name);
+ } else {
+ //no "," indicates that there should only be a family name
+ namePart.setAtType("family");
+ namePart.setValue(author);
+ JAXBElement<NamePartDefinition> element = new JAXBElement<>(new QName(MODS_NAMESPACE_URI, "namePart"),
+ NamePartDefinition.class, namePart);
+ name.getNamePartOrDisplayFormOrAffiliation().add(element);
+ mods.getModsGroup().add(name);
+ }
+ }
+ }
+
+ private void addIdentifier(String key, String value, ModsDefinition mods) {
+ if ("citekey".equals(key)) {
+ mods.setID(value);
+ }
+ IdentifierDefinition identifier = new IdentifierDefinition();
+ identifier.setType(key);
+ identifier.setValue(value);
+ mods.getModsGroup().add(identifier);
+ }
+
+ private void addStartAndEndPage(String value, PartDefinition partDefinition, String minus) {
+ int minusIndex = value.indexOf(minus);
+ String startPage = value.substring(0, minusIndex);
+ String endPage = "";
+ if (MINUS.equals(minus)) {
+ endPage = value.substring(minusIndex + 1);
+ } else if (DOUBLE_MINUS.equals(minus)) {
+ endPage = value.substring(minusIndex + 2);
+ }
+
+ StringPlusLanguage start = new StringPlusLanguage();
+ start.setValue(startPage);
+ StringPlusLanguage end = new StringPlusLanguage();
+ end.setValue(endPage);
+ ExtentDefinition extent = new ExtentDefinition();
+ extent.setStart(start);
+ extent.setEnd(end);
+
+ partDefinition.getDetailOrExtentOrDate().add(extent);
+ }
+
+ private void addDetail(String detailName, String value, PartDefinition partDefinition) {
+ DetailDefinition detail = new DetailDefinition();
+ StringPlusLanguage detailType = new StringPlusLanguage();
+ detailType.setValue(value);
+ detail.setType(detailName);
+ JAXBElement<StringPlusLanguage> element = new JAXBElement<>(new QName(MODS_NAMESPACE_URI, "number"),
+ StringPlusLanguage.class, detailType);
+ detail.getNumberOrCaptionOrTitle().add(element);
+ partDefinition.getDetailOrExtentOrDate().add(detail);
+ }
+
+ private void addOriginInformation(String key, String value, OriginInfoDefinition originInfo) {
+ if (FieldName.YEAR.equals(key)) {
+ addDate("dateIssued", value, originInfo);
+ } else if ("created".equals(key)) {
+ addDate("dateCreated", value, originInfo);
+ } else if ("modified".equals(key)) {
+ addDate("dateModified", value, originInfo);
+ } else if ("captured".equals(key)) {
+ addDate("dateCaptured", value, originInfo);
+ } else if (FieldName.PUBLISHER.equals(key)) {
+ StringPlusLanguagePlusSupplied publisher = new StringPlusLanguagePlusSupplied();
+ publisher.setValue(value);
+ JAXBElement<StringPlusLanguagePlusSupplied> element = new JAXBElement<>(
+ new QName(MODS_NAMESPACE_URI, "publisher"), StringPlusLanguagePlusSupplied.class, publisher);
+ originInfo.getPlaceOrPublisherOrDateIssued().add(element);
+ } else if ("issuance".equals(key)) {
+ IssuanceDefinition issuance = IssuanceDefinition.fromValue(value);
+ JAXBElement<IssuanceDefinition> element = new JAXBElement<>(new QName(MODS_NAMESPACE_URI, "issuance"),
+ IssuanceDefinition.class, issuance);
+ originInfo.getPlaceOrPublisherOrDateIssued().add(element);
+ } else if ("address".equals(key)) {
+ PlaceDefinition placeDefinition = new PlaceDefinition();
+ //There can be more than one place, so we split to get all places and add them
+ String[] places = value.split(", ");
+ for (String place : places) {
+ PlaceTermDefinition placeTerm = new PlaceTermDefinition();
+ //There's no possibility to see from a bib entry whether it is code or text, but since it is in the bib entry
+ //we assume that it is text
+ placeTerm.setType(CodeOrText.TEXT);
+ placeTerm.setValue(place);
+ placeDefinition.getPlaceTerm().add(placeTerm);
+ }
+ JAXBElement<PlaceDefinition> element = new JAXBElement<>(new QName(MODS_NAMESPACE_URI, "place"),
+ PlaceDefinition.class, placeDefinition);
+ originInfo.getPlaceOrPublisherOrDateIssued().add(element);
+ } else if ("edition".equals(key)) {
+ StringPlusLanguagePlusSupplied edition = new StringPlusLanguagePlusSupplied();
+ edition.setValue(value);
+ JAXBElement<StringPlusLanguagePlusSupplied> element = new JAXBElement<>(
+ new QName(MODS_NAMESPACE_URI, "edition"), StringPlusLanguagePlusSupplied.class, edition);
+ originInfo.getPlaceOrPublisherOrDateIssued().add(element);
+ }
+ }
+
+ private void addDate(String dateName, String value, OriginInfoDefinition originInfo) {
+ DateDefinition dateIssued = new DateDefinition();
+ dateIssued.setKeyDate("yes");
+ dateIssued.setValue(value);
+ JAXBElement<DateDefinition> element = new JAXBElement<>(new QName(MODS_NAMESPACE_URI, dateName),
+ DateDefinition.class, dateIssued);
+ originInfo.getPlaceOrPublisherOrDateIssued().add(element);
+ }
}
diff --git a/src/main/java/net/sf/jabref/logic/exporter/OOCalcDatabase.java b/src/main/java/net/sf/jabref/logic/exporter/OOCalcDatabase.java
index 1f836a2..4e9a3bf 100644
--- a/src/main/java/net/sf/jabref/logic/exporter/OOCalcDatabase.java
+++ b/src/main/java/net/sf/jabref/logic/exporter/OOCalcDatabase.java
@@ -166,14 +166,14 @@ class OOCalcDatabase {
addTableCell(result, row, getField(e, FieldName.ORGANIZATION));
addTableCell(result, row, getField(e, FieldName.SCHOOL));
addTableCell(result, row, getField(e, FieldName.ANNOTE));
- addTableCell(result, row, getField(e, "assignee"));
- addTableCell(result, row, getField(e, "day"));
- addTableCell(result, row, getField(e, "dayfiled"));
- addTableCell(result, row, getField(e, "monthfiled"));
- addTableCell(result, row, getField(e, "yearfiled"));
+ addTableCell(result, row, getField(e, FieldName.ASSIGNEE));
+ addTableCell(result, row, getField(e, FieldName.DAY));
+ addTableCell(result, row, getField(e, FieldName.DAYFILED));
+ addTableCell(result, row, getField(e, FieldName.MONTHFILED));
+ addTableCell(result, row, getField(e, FieldName.YEARFILED));
addTableCell(result, row, getField(e, FieldName.LANGUAGE));
- addTableCell(result, row, getField(e, "nationality"));
- addTableCell(result, row, getField(e, "revision"));
+ addTableCell(result, row, getField(e, FieldName.NATIONALITY));
+ addTableCell(result, row, getField(e, FieldName.REVISION));
addTableCell(result, row, "");
addTableCell(result, row, "");
addTableCell(result, row, "");
@@ -193,7 +193,7 @@ class OOCalcDatabase {
}
private static String getField(BibEntry e, String field) {
- return e.getFieldOptional(field).orElse("");
+ return e.getField(field).orElse("");
}
private static void addTableCell(Document doc, Element parent, String content) {
diff --git a/src/main/java/net/sf/jabref/logic/exporter/OpenDocumentRepresentation.java b/src/main/java/net/sf/jabref/logic/exporter/OpenDocumentRepresentation.java
index 26cbebf..e27e339 100644
--- a/src/main/java/net/sf/jabref/logic/exporter/OpenDocumentRepresentation.java
+++ b/src/main/java/net/sf/jabref/logic/exporter/OpenDocumentRepresentation.java
@@ -148,13 +148,13 @@ class OpenDocumentRepresentation {
addTableCell(result, row, getField(e, BibEntry.KEY_FIELD));
addTableCell(result, row, new GetOpenOfficeType().format(e.getType()));
addTableCell(result, row, getField(e, FieldName.ADDRESS));
- addTableCell(result, row, getField(e, "assignee"));
+ addTableCell(result, row, getField(e, FieldName.ASSIGNEE));
addTableCell(result, row, getField(e, FieldName.ANNOTE));
addTableCell(result, row, getField(e, FieldName.AUTHOR));//new AuthorLastFirst().format(getField(e, FieldName.AUTHOR_FIELD)));
addTableCell(result, row, getField(e, FieldName.BOOKTITLE));
addTableCell(result, row, getField(e, FieldName.CHAPTER));
- addTableCell(result, row, getField(e, "day"));
- addTableCell(result, row, getField(e, "dayfiled"));
+ addTableCell(result, row, getField(e, FieldName.DAY));
+ addTableCell(result, row, getField(e, FieldName.DAYFILED));
addTableCell(result, row, getField(e, FieldName.EDITION));
addTableCell(result, row, getField(e, FieldName.EDITOR));//new AuthorLastFirst().format(getField(e, FieldName.EDITOR_FIELD)));
addTableCell(result, row, getField(e, FieldName.HOWPUBLISHED));
@@ -162,21 +162,21 @@ class OpenDocumentRepresentation {
addTableCell(result, row, getField(e, FieldName.JOURNAL));
addTableCell(result, row, getField(e, FieldName.LANGUAGE));
addTableCell(result, row, getField(e, FieldName.MONTH));
- addTableCell(result, row, getField(e, "monthfiled"));
- addTableCell(result, row, getField(e, "nationality"));
+ addTableCell(result, row, getField(e, FieldName.MONTHFILED));
+ addTableCell(result, row, getField(e, FieldName.NATIONALITY));
addTableCell(result, row, getField(e, FieldName.NOTE));
addTableCell(result, row, getField(e, FieldName.NUMBER));
addTableCell(result, row, getField(e, FieldName.ORGANIZATION));
addTableCell(result, row, getField(e, FieldName.PAGES));
addTableCell(result, row, getField(e, FieldName.PUBLISHER));
- addTableCell(result, row, getField(e, "revision"));
+ addTableCell(result, row, getField(e, FieldName.REVISION));
addTableCell(result, row, getField(e, FieldName.SCHOOL));
addTableCell(result, row, getField(e, FieldName.SERIES));
addTableCell(result, row, new RemoveWhitespace().format(new RemoveBrackets().format(getField(e, FieldName.TITLE))));
addTableCell(result, row, getField(e, "reporttype"));
addTableCell(result, row, getField(e, FieldName.VOLUME));
addTableCell(result, row, getField(e, FieldName.YEAR));
- addTableCell(result, row, getField(e, "yearfiled"));
+ addTableCell(result, row, getField(e, FieldName.YEARFILED));
addTableCell(result, row, getField(e, FieldName.URL));
addTableCell(result, row, "");
addTableCell(result, row, "");
@@ -199,7 +199,7 @@ class OpenDocumentRepresentation {
}
private String getField(BibEntry e, String field) {
- return BibDatabase.getResolvedField(field, e, database).orElse("");
+ return e.getResolvedFieldOrAlias(field, database).orElse("");
}
private void addTableCell(Document doc, Element parent, String content) {
diff --git a/src/main/java/net/sf/jabref/logic/exporter/OpenDocumentSpreadsheetCreator.java b/src/main/java/net/sf/jabref/logic/exporter/OpenDocumentSpreadsheetCreator.java
index 03e888d..1fa1152 100644
--- a/src/main/java/net/sf/jabref/logic/exporter/OpenDocumentSpreadsheetCreator.java
+++ b/src/main/java/net/sf/jabref/logic/exporter/OpenDocumentSpreadsheetCreator.java
@@ -25,9 +25,9 @@ import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
-import net.sf.jabref.BibDatabaseContext;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.model.database.BibDatabase;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.entry.BibEntry;
import org.apache.commons.logging.Log;
diff --git a/src/main/java/net/sf/jabref/logic/exporter/OpenOfficeDocumentCreator.java b/src/main/java/net/sf/jabref/logic/exporter/OpenOfficeDocumentCreator.java
index 3ffd4a4..bbf8a78 100644
--- a/src/main/java/net/sf/jabref/logic/exporter/OpenOfficeDocumentCreator.java
+++ b/src/main/java/net/sf/jabref/logic/exporter/OpenOfficeDocumentCreator.java
@@ -24,8 +24,8 @@ import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
-import net.sf.jabref.BibDatabaseContext;
import net.sf.jabref.model.database.BibDatabase;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.entry.BibEntry;
import org.apache.commons.logging.Log;
diff --git a/src/main/java/net/sf/jabref/logic/exporter/SavePreferences.java b/src/main/java/net/sf/jabref/logic/exporter/SavePreferences.java
index 507aafa..de3d710 100644
--- a/src/main/java/net/sf/jabref/logic/exporter/SavePreferences.java
+++ b/src/main/java/net/sf/jabref/logic/exporter/SavePreferences.java
@@ -1,9 +1,11 @@
package net.sf.jabref.logic.exporter;
import java.nio.charset.Charset;
+import java.util.Collections;
import net.sf.jabref.logic.bibtex.LatexFieldFormatterPreferences;
-import net.sf.jabref.logic.config.SaveOrderConfig;
+import net.sf.jabref.model.bibtexkeypattern.GlobalBibtexKeyPattern;
+import net.sf.jabref.model.metadata.SaveOrderConfig;
import net.sf.jabref.preferences.JabRefPreferences;
public class SavePreferences {
@@ -19,14 +21,16 @@ public class SavePreferences {
private final DatabaseSaveType saveType;
private final boolean takeMetadataSaveOrderInAccount;
private final LatexFieldFormatterPreferences latexFieldFormatterPreferences;
+ private final GlobalBibtexKeyPattern globalCiteKeyPattern;
public SavePreferences() {
- this(true, null, null, false, DatabaseSaveType.ALL, true, false, new LatexFieldFormatterPreferences());
+ this(true, null, null, false, DatabaseSaveType.ALL, true, false, new LatexFieldFormatterPreferences(),
+ new GlobalBibtexKeyPattern(Collections.emptyList()));
}
public SavePreferences(Boolean saveInOriginalOrder, SaveOrderConfig saveOrder, Charset encoding, Boolean makeBackup,
DatabaseSaveType saveType, Boolean takeMetadataSaveOrderInAccount, Boolean reformatFile,
- LatexFieldFormatterPreferences latexFieldFormatterPreferences) {
+ LatexFieldFormatterPreferences latexFieldFormatterPreferences, GlobalBibtexKeyPattern globalCiteKeyPattern) {
this.saveInOriginalOrder = saveInOriginalOrder;
this.saveOrder = saveOrder;
this.encoding = encoding;
@@ -35,6 +39,7 @@ public class SavePreferences {
this.takeMetadataSaveOrderInAccount = takeMetadataSaveOrderInAccount;
this.reformatFile = reformatFile;
this.latexFieldFormatterPreferences = latexFieldFormatterPreferences;
+ this.globalCiteKeyPattern = globalCiteKeyPattern;
}
public static SavePreferences loadForExportFromPreferences(JabRefPreferences preferences) {
@@ -42,9 +47,9 @@ public class SavePreferences {
SaveOrderConfig saveOrder = null;
if (!saveInOriginalOrder) {
if (preferences.getBoolean(JabRefPreferences.EXPORT_IN_SPECIFIED_ORDER)) {
- saveOrder = SaveOrderConfig.loadExportSaveOrderFromPreferences(preferences);
+ saveOrder = preferences.loadExportSaveOrder();
} else {
- saveOrder = SaveOrderConfig.loadTableSaveOrderFromPreferences(preferences);
+ saveOrder = preferences.loadTableSaveOrder();
}
}
Charset encoding = preferences.getDefaultEncoding();
@@ -52,10 +57,10 @@ public class SavePreferences {
DatabaseSaveType saveType = DatabaseSaveType.ALL;
Boolean takeMetadataSaveOrderInAccount = false;
Boolean reformatFile = preferences.getBoolean(JabRefPreferences.REFORMAT_FILE_ON_SAVE_AND_EXPORT);
- LatexFieldFormatterPreferences latexFieldFormatterPreferences = LatexFieldFormatterPreferences
- .fromPreferences(preferences);
+ LatexFieldFormatterPreferences latexFieldFormatterPreferences = preferences.getLatexFieldFormatterPreferences();
+ GlobalBibtexKeyPattern globalCiteKeyPattern = preferences.getKeyPattern();
return new SavePreferences(saveInOriginalOrder, saveOrder, encoding, makeBackup, saveType,
- takeMetadataSaveOrderInAccount, reformatFile, latexFieldFormatterPreferences);
+ takeMetadataSaveOrderInAccount, reformatFile, latexFieldFormatterPreferences, globalCiteKeyPattern);
}
public static SavePreferences loadForSaveFromPreferences(JabRefPreferences preferences) {
@@ -66,10 +71,10 @@ public class SavePreferences {
DatabaseSaveType saveType = DatabaseSaveType.ALL;
Boolean takeMetadataSaveOrderInAccount = true;
Boolean reformatFile = preferences.getBoolean(JabRefPreferences.REFORMAT_FILE_ON_SAVE_AND_EXPORT);
- LatexFieldFormatterPreferences latexFieldFormatterPreferences = LatexFieldFormatterPreferences
- .fromPreferences(preferences);
+ LatexFieldFormatterPreferences latexFieldFormatterPreferences = preferences.getLatexFieldFormatterPreferences();
+ GlobalBibtexKeyPattern globalCiteKeyPattern = preferences.getKeyPattern();
return new SavePreferences(saveInOriginalOrder, saveOrder, encoding, makeBackup, saveType,
- takeMetadataSaveOrderInAccount, reformatFile, latexFieldFormatterPreferences);
+ takeMetadataSaveOrderInAccount, reformatFile, latexFieldFormatterPreferences, globalCiteKeyPattern);
}
public Boolean getTakeMetadataSaveOrderInAccount() {
@@ -86,7 +91,8 @@ public class SavePreferences {
public SavePreferences withSaveInOriginalOrder(Boolean newSaveInOriginalOrder) {
return new SavePreferences(newSaveInOriginalOrder, this.saveOrder, this.encoding, this.makeBackup, this.saveType,
- this.takeMetadataSaveOrderInAccount, this.reformatFile, this.latexFieldFormatterPreferences);
+ this.takeMetadataSaveOrderInAccount, this.reformatFile, this.latexFieldFormatterPreferences,
+ globalCiteKeyPattern);
}
public boolean getMakeBackup() {
@@ -95,7 +101,8 @@ public class SavePreferences {
public SavePreferences withMakeBackup(Boolean newMakeBackup) {
return new SavePreferences(this.saveInOriginalOrder, this.saveOrder, this.encoding, newMakeBackup, this.saveType,
- this.takeMetadataSaveOrderInAccount, this.reformatFile, this.latexFieldFormatterPreferences);
+ this.takeMetadataSaveOrderInAccount, this.reformatFile, this.latexFieldFormatterPreferences,
+ globalCiteKeyPattern);
}
public Charset getEncoding() {
@@ -104,7 +111,8 @@ public class SavePreferences {
public SavePreferences withEncoding(Charset newEncoding) {
return new SavePreferences(this.saveInOriginalOrder, this.saveOrder, newEncoding, this.makeBackup, this.saveType,
- this.takeMetadataSaveOrderInAccount, this.reformatFile, this.latexFieldFormatterPreferences);
+ this.takeMetadataSaveOrderInAccount, this.reformatFile, this.latexFieldFormatterPreferences,
+ globalCiteKeyPattern);
}
public DatabaseSaveType getSaveType() {
@@ -113,7 +121,8 @@ public class SavePreferences {
public SavePreferences withSaveType(DatabaseSaveType newSaveType) {
return new SavePreferences(this.saveInOriginalOrder, this.saveOrder, this.encoding, this.makeBackup, newSaveType,
- this.takeMetadataSaveOrderInAccount, this.reformatFile, this.latexFieldFormatterPreferences);
+ this.takeMetadataSaveOrderInAccount, this.reformatFile, this.latexFieldFormatterPreferences,
+ globalCiteKeyPattern);
}
public Boolean isReformatFile() {
@@ -122,7 +131,8 @@ public class SavePreferences {
public SavePreferences withReformatFile(boolean newReformatFile) {
return new SavePreferences(this.saveInOriginalOrder, this.saveOrder, this.encoding, this.makeBackup,
- this.saveType, this.takeMetadataSaveOrderInAccount, newReformatFile, this.latexFieldFormatterPreferences);
+ this.saveType, this.takeMetadataSaveOrderInAccount, newReformatFile, this.latexFieldFormatterPreferences,
+ globalCiteKeyPattern);
}
public Charset getEncodingOrDefault() {
@@ -133,6 +143,10 @@ public class SavePreferences {
return latexFieldFormatterPreferences;
}
+ public GlobalBibtexKeyPattern getGlobalCiteKeyPattern() {
+ return globalCiteKeyPattern;
+ }
+
public enum DatabaseSaveType {
ALL,
PLAIN_BIBTEX
diff --git a/src/main/java/net/sf/jabref/logic/formatter/Formatter.java b/src/main/java/net/sf/jabref/logic/formatter/Formatter.java
deleted file mode 100644
index 6df8d46..0000000
--- a/src/main/java/net/sf/jabref/logic/formatter/Formatter.java
+++ /dev/null
@@ -1,74 +0,0 @@
-package net.sf.jabref.logic.formatter;
-
-/**
- * The Formatter is used for a Filter design-pattern. Implementing classes have to accept a String and returned a
- * formatted version of it.
- *
- * Example:
- *
- * "John von Neumann" => "von Neumann, John"
- *
- */
-public interface Formatter {
- /**
- * Returns a human readable name of the formatter usable for e.g. in the GUI
- *
- * @return the name of the formatter, always not null
- */
- String getName();
-
-
- /**
- * Returns a unique key for the formatter that can be used for its identification
- * @return the key of the formatter, always not null
- */
- String getKey();
-
- /**
- * Formats a field value by with a particular formatter transformation.
- *
- * Calling this method with a null argument results in a NullPointerException.
- *
- * @param value the input String
- * @return the formatted output String
- */
- String format(String value);
-
- /**
- * Returns a description of the formatter.
- *
- * @return the description string, always non empty
- */
- String getDescription();
-
- /**
- * Returns an example input string of the formatter.
- * This example is used as input to the formatter to demonstrate its functionality
- *
- * @return the example input string, always non empty
- */
- String getExampleInput();
-
- /**
- * Returns a default hashcode of the formatter based on its key.
- *
- * @return the hash of the key of the formatter
- */
- default int defaultHashCode() {
- return getKey().hashCode();
- }
-
- /**
- * Indicates whether some other object is the same formatter as this one based on the key.
- *
- * @param obj the object to compare the formatter to
- * @return true if the object is a formatter with the same key
- */
- default boolean defaultEquals(Object obj) {
- if(obj instanceof Formatter) {
- return getKey().equals(((Formatter)obj).getKey());
- } else {
- return false;
- }
- }
-}
diff --git a/src/main/java/net/sf/jabref/logic/formatter/Formatters.java b/src/main/java/net/sf/jabref/logic/formatter/Formatters.java
index 7f2f824..cbad07c 100644
--- a/src/main/java/net/sf/jabref/logic/formatter/Formatters.java
+++ b/src/main/java/net/sf/jabref/logic/formatter/Formatters.java
@@ -3,6 +3,8 @@ package net.sf.jabref.logic.formatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
import net.sf.jabref.logic.formatter.bibtexfields.ClearFormatter;
import net.sf.jabref.logic.formatter.bibtexfields.HtmlToLatexFormatter;
@@ -24,6 +26,7 @@ import net.sf.jabref.logic.formatter.casechanger.TitleCaseFormatter;
import net.sf.jabref.logic.formatter.casechanger.UpperCaseFormatter;
import net.sf.jabref.logic.formatter.minifier.MinifyNameListFormatter;
import net.sf.jabref.logic.layout.format.LatexToUnicodeFormatter;
+import net.sf.jabref.model.cleanup.Formatter;
public class Formatters {
@@ -58,6 +61,22 @@ public class Formatters {
public static final List<Formatter> ALL = new ArrayList<>();
+ public static Optional<Formatter> getFormatterForModifier(String modifier) {
+ Objects.requireNonNull(modifier);
+ Optional<Formatter> formatter = ALL.stream().filter(f -> f.getKey().equals(modifier)).findAny();
+ if (formatter.isPresent()) {
+ return formatter;
+ }
+ switch (modifier) {
+ case "lower":
+ return Optional.of(new LowerCaseFormatter());
+ case "upper":
+ return Optional.of(new UpperCaseFormatter());
+ default:
+ return Optional.empty();
+ }
+ }
+
static {
ALL.addAll(CONVERTERS);
ALL.addAll(CASE_CHANGERS);
diff --git a/src/main/java/net/sf/jabref/logic/formatter/IdentityFormatter.java b/src/main/java/net/sf/jabref/logic/formatter/IdentityFormatter.java
index 2bdfc03..23414f3 100644
--- a/src/main/java/net/sf/jabref/logic/formatter/IdentityFormatter.java
+++ b/src/main/java/net/sf/jabref/logic/formatter/IdentityFormatter.java
@@ -3,6 +3,7 @@ package net.sf.jabref.logic.formatter;
import java.util.Objects;
import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.cleanup.Formatter;
/**
* It may seem useless, but is needed as a fallback option
diff --git a/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/ClearFormatter.java b/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/ClearFormatter.java
index b0f3bf6..ced9023 100644
--- a/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/ClearFormatter.java
+++ b/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/ClearFormatter.java
@@ -2,8 +2,8 @@ package net.sf.jabref.logic.formatter.bibtexfields;
import java.util.Objects;
-import net.sf.jabref.logic.formatter.Formatter;
import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.cleanup.Formatter;
public class ClearFormatter implements Formatter {
diff --git a/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/HtmlToLatexFormatter.java b/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/HtmlToLatexFormatter.java
index 7010b08..56c0927 100644
--- a/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/HtmlToLatexFormatter.java
+++ b/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/HtmlToLatexFormatter.java
@@ -5,10 +5,10 @@ import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import net.sf.jabref.logic.formatter.Formatter;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.layout.LayoutFormatter;
-import net.sf.jabref.logic.util.strings.HTMLUnicodeConversionMaps;
+import net.sf.jabref.model.cleanup.Formatter;
+import net.sf.jabref.model.strings.HTMLUnicodeConversionMaps;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
diff --git a/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/HtmlToUnicodeFormatter.java b/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/HtmlToUnicodeFormatter.java
index e570fab..209b007 100644
--- a/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/HtmlToUnicodeFormatter.java
+++ b/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/HtmlToUnicodeFormatter.java
@@ -1,8 +1,8 @@
package net.sf.jabref.logic.formatter.bibtexfields;
-import net.sf.jabref.logic.formatter.Formatter;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.layout.LayoutFormatter;
+import net.sf.jabref.model.cleanup.Formatter;
import org.apache.commons.lang3.StringEscapeUtils;
diff --git a/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/LatexCleanupFormatter.java b/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/LatexCleanupFormatter.java
index ee143b3..0f8ed28 100644
--- a/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/LatexCleanupFormatter.java
+++ b/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/LatexCleanupFormatter.java
@@ -1,7 +1,7 @@
package net.sf.jabref.logic.formatter.bibtexfields;
-import net.sf.jabref.logic.formatter.Formatter;
import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.cleanup.Formatter;
public class LatexCleanupFormatter implements Formatter {
diff --git a/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/NormalizeDateFormatter.java b/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/NormalizeDateFormatter.java
index 76aa5cd..b0d5d7d 100644
--- a/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/NormalizeDateFormatter.java
+++ b/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/NormalizeDateFormatter.java
@@ -7,8 +7,8 @@ import java.util.Arrays;
import java.util.List;
import java.util.Optional;
-import net.sf.jabref.logic.formatter.Formatter;
import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.cleanup.Formatter;
/**
* This class transforms date to the format yyyy-mm-dd or yyyy-mm..
diff --git a/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/NormalizeMonthFormatter.java b/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/NormalizeMonthFormatter.java
index 48e7811..061b599 100644
--- a/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/NormalizeMonthFormatter.java
+++ b/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/NormalizeMonthFormatter.java
@@ -2,8 +2,8 @@ package net.sf.jabref.logic.formatter.bibtexfields;
import java.util.Objects;
-import net.sf.jabref.logic.formatter.Formatter;
import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.cleanup.Formatter;
import net.sf.jabref.model.entry.MonthUtil;
public class NormalizeMonthFormatter implements Formatter {
diff --git a/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/NormalizeNamesFormatter.java b/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/NormalizeNamesFormatter.java
index 3937ac5..8ba358d 100644
--- a/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/NormalizeNamesFormatter.java
+++ b/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/NormalizeNamesFormatter.java
@@ -1,7 +1,9 @@
package net.sf.jabref.logic.formatter.bibtexfields;
-import net.sf.jabref.logic.formatter.Formatter;
+import java.util.Objects;
+
import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.cleanup.Formatter;
import net.sf.jabref.model.entry.AuthorList;
/**
@@ -20,8 +22,9 @@ public class NormalizeNamesFormatter implements Formatter {
}
@Override
- public String format(String value) {
- AuthorList authorList = AuthorList.parse(value);
+ public String format(String nameList) {
+ Objects.requireNonNull(nameList);
+ AuthorList authorList = AuthorList.parse(nameList);
return authorList.getAsLastFirstNamesWithAnd(false);
}
diff --git a/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/NormalizePagesFormatter.java b/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/NormalizePagesFormatter.java
index baf3bd0..06982c8 100644
--- a/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/NormalizePagesFormatter.java
+++ b/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/NormalizePagesFormatter.java
@@ -4,8 +4,8 @@ import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import net.sf.jabref.logic.formatter.Formatter;
import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.cleanup.Formatter;
import com.google.common.base.Strings;
diff --git a/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/OrdinalsToSuperscriptFormatter.java b/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/OrdinalsToSuperscriptFormatter.java
index c692efd..93228f6 100644
--- a/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/OrdinalsToSuperscriptFormatter.java
+++ b/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/OrdinalsToSuperscriptFormatter.java
@@ -4,8 +4,8 @@ import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import net.sf.jabref.logic.formatter.Formatter;
import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.cleanup.Formatter;
/**
* This class transforms ordinal numbers into LaTex superscripts.
diff --git a/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/RemoveBracesFormatter.java b/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/RemoveBracesFormatter.java
index 834a9a1..2d1d303 100644
--- a/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/RemoveBracesFormatter.java
+++ b/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/RemoveBracesFormatter.java
@@ -2,8 +2,8 @@ package net.sf.jabref.logic.formatter.bibtexfields;
import java.util.Objects;
-import net.sf.jabref.logic.formatter.Formatter;
import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.cleanup.Formatter;
/**
* Removes all matching braces around the string.
diff --git a/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/UnicodeToLatexFormatter.java b/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/UnicodeToLatexFormatter.java
index 74ecc2c..ab1cc16 100644
--- a/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/UnicodeToLatexFormatter.java
+++ b/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/UnicodeToLatexFormatter.java
@@ -3,10 +3,10 @@ package net.sf.jabref.logic.formatter.bibtexfields;
import java.util.Map;
import java.util.Objects;
-import net.sf.jabref.logic.formatter.Formatter;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.layout.LayoutFormatter;
-import net.sf.jabref.logic.util.strings.HTMLUnicodeConversionMaps;
+import net.sf.jabref.model.cleanup.Formatter;
+import net.sf.jabref.model.strings.HTMLUnicodeConversionMaps;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
diff --git a/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/UnitsToLatexFormatter.java b/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/UnitsToLatexFormatter.java
index 8f3964f..cc5dc1e 100644
--- a/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/UnitsToLatexFormatter.java
+++ b/src/main/java/net/sf/jabref/logic/formatter/bibtexfields/UnitsToLatexFormatter.java
@@ -6,9 +6,9 @@ import java.util.Collections;
import java.util.List;
import java.util.Objects;
-import net.sf.jabref.logic.formatter.Formatter;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.util.strings.StringLengthComparator;
+import net.sf.jabref.model.cleanup.Formatter;
public class UnitsToLatexFormatter implements Formatter {
diff --git a/src/main/java/net/sf/jabref/logic/formatter/casechanger/CapitalizeFormatter.java b/src/main/java/net/sf/jabref/logic/formatter/casechanger/CapitalizeFormatter.java
index 856d25b..0424d5b 100644
--- a/src/main/java/net/sf/jabref/logic/formatter/casechanger/CapitalizeFormatter.java
+++ b/src/main/java/net/sf/jabref/logic/formatter/casechanger/CapitalizeFormatter.java
@@ -1,7 +1,7 @@
package net.sf.jabref.logic.formatter.casechanger;
-import net.sf.jabref.logic.formatter.Formatter;
import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.cleanup.Formatter;
public class CapitalizeFormatter implements Formatter {
diff --git a/src/main/java/net/sf/jabref/logic/formatter/casechanger/LowerCaseFormatter.java b/src/main/java/net/sf/jabref/logic/formatter/casechanger/LowerCaseFormatter.java
index 09f5ede..44adaca 100644
--- a/src/main/java/net/sf/jabref/logic/formatter/casechanger/LowerCaseFormatter.java
+++ b/src/main/java/net/sf/jabref/logic/formatter/casechanger/LowerCaseFormatter.java
@@ -1,7 +1,7 @@
package net.sf.jabref.logic.formatter.casechanger;
-import net.sf.jabref.logic.formatter.Formatter;
import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.cleanup.Formatter;
public class LowerCaseFormatter implements Formatter {
diff --git a/src/main/java/net/sf/jabref/logic/formatter/casechanger/ProtectTermsFormatter.java b/src/main/java/net/sf/jabref/logic/formatter/casechanger/ProtectTermsFormatter.java
index 7160598..2be5699 100644
--- a/src/main/java/net/sf/jabref/logic/formatter/casechanger/ProtectTermsFormatter.java
+++ b/src/main/java/net/sf/jabref/logic/formatter/casechanger/ProtectTermsFormatter.java
@@ -3,10 +3,10 @@ package net.sf.jabref.logic.formatter.casechanger;
import java.util.List;
import java.util.Objects;
-import net.sf.jabref.logic.formatter.Formatter;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.protectedterms.ProtectedTermsLoader;
import net.sf.jabref.logic.util.strings.StringLengthComparator;
+import net.sf.jabref.model.cleanup.Formatter;
public class ProtectTermsFormatter implements Formatter {
diff --git a/src/main/java/net/sf/jabref/logic/formatter/casechanger/SentenceCaseFormatter.java b/src/main/java/net/sf/jabref/logic/formatter/casechanger/SentenceCaseFormatter.java
index 5218c01..02d8447 100644
--- a/src/main/java/net/sf/jabref/logic/formatter/casechanger/SentenceCaseFormatter.java
+++ b/src/main/java/net/sf/jabref/logic/formatter/casechanger/SentenceCaseFormatter.java
@@ -1,7 +1,7 @@
package net.sf.jabref.logic.formatter.casechanger;
-import net.sf.jabref.logic.formatter.Formatter;
import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.cleanup.Formatter;
public class SentenceCaseFormatter implements Formatter {
diff --git a/src/main/java/net/sf/jabref/logic/formatter/casechanger/Title.java b/src/main/java/net/sf/jabref/logic/formatter/casechanger/Title.java
index 7f650ac..f12a5cc 100644
--- a/src/main/java/net/sf/jabref/logic/formatter/casechanger/Title.java
+++ b/src/main/java/net/sf/jabref/logic/formatter/casechanger/Title.java
@@ -1,5 +1,6 @@
package net.sf.jabref.logic.formatter.casechanger;
+import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
@@ -17,7 +18,7 @@ public final class Title {
}
public List<Word> getWords() {
- return words;
+ return Collections.unmodifiableList(words);
}
public Optional<Word> getFirstWord() {
diff --git a/src/main/java/net/sf/jabref/logic/formatter/casechanger/TitleCaseFormatter.java b/src/main/java/net/sf/jabref/logic/formatter/casechanger/TitleCaseFormatter.java
index 9734956..67d8001 100644
--- a/src/main/java/net/sf/jabref/logic/formatter/casechanger/TitleCaseFormatter.java
+++ b/src/main/java/net/sf/jabref/logic/formatter/casechanger/TitleCaseFormatter.java
@@ -1,7 +1,7 @@
package net.sf.jabref.logic.formatter.casechanger;
-import net.sf.jabref.logic.formatter.Formatter;
import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.cleanup.Formatter;
public class TitleCaseFormatter implements Formatter {
diff --git a/src/main/java/net/sf/jabref/logic/formatter/casechanger/UpperCaseFormatter.java b/src/main/java/net/sf/jabref/logic/formatter/casechanger/UpperCaseFormatter.java
index c0db90d..5d99d66 100644
--- a/src/main/java/net/sf/jabref/logic/formatter/casechanger/UpperCaseFormatter.java
+++ b/src/main/java/net/sf/jabref/logic/formatter/casechanger/UpperCaseFormatter.java
@@ -1,7 +1,7 @@
package net.sf.jabref.logic.formatter.casechanger;
-import net.sf.jabref.logic.formatter.Formatter;
import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.cleanup.Formatter;
public class UpperCaseFormatter implements Formatter {
diff --git a/src/main/java/net/sf/jabref/logic/formatter/minifier/MinifyNameListFormatter.java b/src/main/java/net/sf/jabref/logic/formatter/minifier/MinifyNameListFormatter.java
index f5316a5..cd7505e 100644
--- a/src/main/java/net/sf/jabref/logic/formatter/minifier/MinifyNameListFormatter.java
+++ b/src/main/java/net/sf/jabref/logic/formatter/minifier/MinifyNameListFormatter.java
@@ -2,8 +2,8 @@ package net.sf.jabref.logic.formatter.minifier;
import java.util.Objects;
-import net.sf.jabref.logic.formatter.Formatter;
import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.cleanup.Formatter;
/**
* Replaces three or more authors with and others
diff --git a/src/main/java/net/sf/jabref/logic/groups/AbstractGroup.java b/src/main/java/net/sf/jabref/logic/groups/AbstractGroup.java
deleted file mode 100644
index 1322c39..0000000
--- a/src/main/java/net/sf/jabref/logic/groups/AbstractGroup.java
+++ /dev/null
@@ -1,216 +0,0 @@
-package net.sf.jabref.logic.groups;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.Optional;
-
-import net.sf.jabref.logic.importer.util.ParseException;
-import net.sf.jabref.logic.search.SearchMatcher;
-import net.sf.jabref.model.database.BibDatabase;
-import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.preferences.JabRefPreferences;
-
-/**
- * A group of BibtexEntries.
- */
-public abstract class AbstractGroup implements SearchMatcher {
-
- /**
- * Character used for quoting in the string representation.
- */
- public static final char QUOTE_CHAR = '\\';
- /**
- * For separating units (e.g. name, which every group has) in the string
- * representation
- */
- public static final String SEPARATOR = ";";
- /**
- * The group's name (every type of group has one).
- */
- private String name;
- /**
- * The hierarchical context of the group (INDEPENDENT, REFINING, or
- * INCLUDING). Defaults to INDEPENDENT, which will be used if and
- * only if the context specified in the constructor is invalid.
- */
- private GroupHierarchyType context = GroupHierarchyType.INDEPENDENT;
-
- AbstractGroup(String name, GroupHierarchyType context) {
- this.name = name;
- setHierarchicalContext(context);
- }
-
- /**
- * Re-create a group instance from a textual representation.
- *
- * @param s The result from the group's toString() method.
- * @return New instance of the encoded group.
- * @throws ParseException If an error occurred and a group could not be created,
- * e.g. due to a malformed regular expression.
- */
- public static AbstractGroup fromString(String s, JabRefPreferences jabRefPreferences) throws ParseException {
- if (s.startsWith(KeywordGroup.ID)) {
- return KeywordGroup.fromString(s, jabRefPreferences);
- }
- if (s.startsWith(AllEntriesGroup.ID)) {
- return AllEntriesGroup.fromString(s);
- }
- if (s.startsWith(SearchGroup.ID)) {
- return SearchGroup.fromString(s);
- }
- if (s.startsWith(ExplicitGroup.ID)) {
- return ExplicitGroup.fromString(s, jabRefPreferences);
- }
- return null; // unknown group
- }
-
- public GroupHierarchyType getContext() {
- return context;
- }
-
- public abstract String getTypeId();
-
- /**
- * Returns this group's name, e.g. for display in a list/tree.
- */
- public final String getName() {
- return name;
- }
-
- /**
- * Sets the group's name.
- */
- public final void setName(String name) {
- this.name = name;
- }
-
- /**
- * @return true if this type of group supports the explicit adding of
- * entries.
- */
- public abstract boolean supportsAdd();
-
- /**
- * @return true if this type of group supports the explicit removal of
- * entries.
- */
- public abstract boolean supportsRemove();
-
- /**
- * Adds the specified entries to this group.
- *
- * @return If this group or one or more entries was/were modified as a
- * result of this operation, an object is returned that allows to
- * undo this change. null is returned otherwise.
- */
- public abstract Optional<EntriesGroupChange> add(List<BibEntry> entriesToAdd);
-
- public Optional<EntriesGroupChange> add(BibEntry entryToAdd) {
- return add(Collections.singletonList(entryToAdd));
- }
-
- /**
- * Removes the specified entries from this group.
- *
- * @return If this group or one or more entries was/were modified as a
- * result of this operation, an object is returned that allows to
- * undo this change. null is returned otherwise.
- */
- public abstract Optional<EntriesGroupChange> remove(List<BibEntry> entriesToRemove);
-
- /**
- * @return true if this group contains the specified entry, false otherwise.
- */
- public abstract boolean contains(BibEntry entry);
-
- @Override
- public boolean isMatch(BibEntry entry) {
- return contains(entry);
- }
-
- /**
- * @return true if this group contains any of the specified entries, false
- * otherwise.
- */
- public boolean containsAny(List<BibEntry> entries) {
- for (BibEntry entry : entries) {
- if (contains(entry)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * @return true if this group contains all of the specified entries, false
- * otherwise.
- */
- public boolean containsAll(List<BibEntry> entries) {
- for (BibEntry entry : entries) {
- if (!contains(entry)) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Returns true if this group is dynamic, i.e. uses a search definition or
- * equiv. that might match new entries, or false if this group contains a
- * fixed set of entries and thus will never match a new entry that was not
- * explicitly added to it.
- */
- public abstract boolean isDynamic();
-
- /**
- * Returns the group's hierarchical context.
- */
- public GroupHierarchyType getHierarchicalContext() {
- return context;
- }
-
- /**
- * Sets the groups's hierarchical context. If context is not a valid
- * value, the call is ignored.
- */
- public void setHierarchicalContext(GroupHierarchyType context) {
- if (context == null) {
- return;
- }
- this.context = context;
- }
-
- /**
- * Returns a lengthy textual description of this instance (for
- * the groups editor). The text is formatted in HTML.
- */
- public abstract String getDescription();
-
- /**
- * @return A deep copy of this object.
- */
- public abstract AbstractGroup deepCopy();
-
- /**
- * Returns a short description of the group in HTML (for a tooltip).
- */
- public abstract String getShortDescription(boolean showDynamic);
-
- // by general AbstractGroup contract, toString() must return
- // something from which this object can be reconstructed
- // using fromString(String).
-
- // by general AbstractGroup contract, equals() must be implemented
-
- /**
- * Update the group, if necessary, to handle the situation where the group
- * is applied to a different BibDatabase than it was created for. This
- * is for instance used when updating the group tree due to an external change.
- *
- * @param db The database to refresh for.
- */
- public void refreshForNewDatabase(BibDatabase db) {
- // Default is to do nothing. Group types that are affected by a change
- // of database must override this method.
- }
-}
diff --git a/src/main/java/net/sf/jabref/logic/groups/AllEntriesGroup.java b/src/main/java/net/sf/jabref/logic/groups/AllEntriesGroup.java
deleted file mode 100644
index c64d180..0000000
--- a/src/main/java/net/sf/jabref/logic/groups/AllEntriesGroup.java
+++ /dev/null
@@ -1,95 +0,0 @@
-package net.sf.jabref.logic.groups;
-
-import java.util.List;
-import java.util.Optional;
-
-import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.model.entry.BibEntry;
-
-/**
- * This group contains all entries. Always. At any time!
- */
-public class AllEntriesGroup extends AbstractGroup {
-
- public static final String ID = "AllEntriesGroup:";
-
- public AllEntriesGroup() {
- super(Localization.lang("All entries"), GroupHierarchyType.INDEPENDENT);
- }
-
- public static AbstractGroup fromString(String s) {
- if (!s.startsWith(AllEntriesGroup.ID)) {
- throw new IllegalArgumentException("AllEntriesGroup cannot be created from \"" + s + "\".");
- }
- return new AllEntriesGroup();
- }
-
- @Override
- public boolean supportsAdd() {
- return false;
- }
-
- @Override
- public boolean supportsRemove() {
- return false;
- }
-
- @Override
- public Optional<EntriesGroupChange> add(List<BibEntry> entriesToAdd) {
- // not supported -> ignore
- return Optional.empty();
- }
-
- @Override
- public Optional<EntriesGroupChange> remove(List<BibEntry> entriesToRemove) {
- // not supported -> ignore
- return Optional.empty();
- }
-
- @Override
- public AbstractGroup deepCopy() {
- return new AllEntriesGroup();
- }
-
- @Override
- public boolean equals(Object o) {
- return o instanceof AllEntriesGroup;
- }
-
- @Override
- public String toString() {
- return AllEntriesGroup.ID;
- }
-
- @Override
- public boolean contains(BibEntry entry) {
- return true;
- }
-
- @Override
- public boolean isDynamic() {
- // this is actually a special case; I define it as non-dynamic
- return false;
- }
-
- @Override
- public String getDescription() {
- return Localization.lang("This group contains all entries. It cannot be edited or removed.");
- }
-
- @Override
- public String getShortDescription(boolean showDynamic) {
- return Localization.lang("<b>All Entries</b> (this group cannot be edited or removed)");
- }
-
- @Override
- public String getTypeId() {
- return AllEntriesGroup.ID;
- }
-
- @Override
- public int hashCode() {
- // TODO Auto-generated method stub
- return super.hashCode();
- }
-}
diff --git a/src/main/java/net/sf/jabref/logic/groups/EntriesGroupChange.java b/src/main/java/net/sf/jabref/logic/groups/EntriesGroupChange.java
deleted file mode 100644
index 211cab5..0000000
--- a/src/main/java/net/sf/jabref/logic/groups/EntriesGroupChange.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package net.sf.jabref.logic.groups;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-
-import net.sf.jabref.model.FieldChange;
-import net.sf.jabref.model.entry.BibEntry;
-
-public class EntriesGroupChange {
-
- private Set<BibEntry> oldEntries;
- private Set<BibEntry> newEntries;
- private List<FieldChange> entryChanges;
-
- public EntriesGroupChange(Set<BibEntry> oldEntries, Set<BibEntry> newEntries) {
- this(oldEntries, newEntries, Collections.emptyList());
- }
-
- public EntriesGroupChange(List<FieldChange> entryChanges) {
- this(Collections.emptySet(), Collections.emptySet(), entryChanges);
- }
-
- public EntriesGroupChange(Set<BibEntry> oldEntries, Set<BibEntry> newEntries,
- List<FieldChange> entryChanges) {
- this.oldEntries = oldEntries;
- this.newEntries = newEntries;
- this.entryChanges = entryChanges;
- }
-
- public Set<BibEntry> getOldEntries() {
- return oldEntries;
- }
-
- public Set<BibEntry> getNewEntries() {
- return newEntries;
- }
-
- public Iterable<FieldChange> getEntryChanges() {
- return entryChanges;
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/logic/groups/ExplicitGroup.java b/src/main/java/net/sf/jabref/logic/groups/ExplicitGroup.java
deleted file mode 100644
index 8011f86..0000000
--- a/src/main/java/net/sf/jabref/logic/groups/ExplicitGroup.java
+++ /dev/null
@@ -1,171 +0,0 @@
-package net.sf.jabref.logic.groups;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-import java.util.Set;
-import java.util.TreeSet;
-
-import net.sf.jabref.logic.importer.util.ParseException;
-import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.logic.util.strings.QuotedStringTokenizer;
-import net.sf.jabref.logic.util.strings.StringUtil;
-import net.sf.jabref.model.entry.FieldName;
-import net.sf.jabref.preferences.JabRefPreferences;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * Select explicit bibtex entries. It is also known as static group.
- *
- * @author jzieren
- */
-public class ExplicitGroup extends KeywordGroup {
-
- public static final String ID = "ExplicitGroup:";
-
- private final List<String> legacyEntryKeys = new ArrayList<>();
-
- private static final Log LOGGER = LogFactory.getLog(ExplicitGroup.class);
-
- public ExplicitGroup(String name, GroupHierarchyType context, JabRefPreferences jabRefPreferences)
- throws ParseException {
- super(name, FieldName.GROUPS, name, true, false, context, jabRefPreferences);
- }
-
- public static ExplicitGroup fromString(String s, JabRefPreferences jabRefPreferences) throws ParseException {
- if (!s.startsWith(ExplicitGroup.ID)) {
- throw new IllegalArgumentException("ExplicitGroup cannot be created from \"" + s + "\".");
- }
- QuotedStringTokenizer tok = new QuotedStringTokenizer(s.substring(ExplicitGroup.ID.length()),
- AbstractGroup.SEPARATOR, AbstractGroup.QUOTE_CHAR);
-
- String name = tok.nextToken();
- int context = Integer.parseInt(tok.nextToken());
- ExplicitGroup newGroup = new ExplicitGroup(name, GroupHierarchyType.getByNumber(context), jabRefPreferences);
- newGroup.addLegacyEntryKeys(tok);
- return newGroup;
- }
-
- /**
- * Called only when created fromString.
- * JabRef used to store the entries of an explicit group in the serialization, e.g.
- * ExplicitGroup:GroupName\;0\;Key1\;Key2\;;
- * This method exists for backwards compatibility.
- */
- private void addLegacyEntryKeys(QuotedStringTokenizer tok) {
- while (tok.hasMoreTokens()) {
- String key = StringUtil.unquote(tok.nextToken(), AbstractGroup.QUOTE_CHAR);
- addLegacyEntryKey(key);
- }
- }
-
- public void addLegacyEntryKey(String key) {
- this.legacyEntryKeys.add(key);
- }
-
- @Override
- public AbstractGroup deepCopy() {
- try {
- ExplicitGroup copy = new ExplicitGroup(getName(), getContext(), jabRefPreferences);
- copy.legacyEntryKeys.addAll(legacyEntryKeys);
- return copy;
- } catch (ParseException exception) {
- // this should never happen, because the constructor obviously succeeded in creating _this_ instance!
- LOGGER.error("Internal error in ExplicitGroup.deepCopy(). "
- + "Please report this on https://github.com/JabRef/jabref/issues", exception);
- return null;
- }
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (!(o instanceof ExplicitGroup)) {
- return false;
- }
- ExplicitGroup other = (ExplicitGroup) o;
- return Objects.equals(getName(), other.getName()) && Objects.equals(getHierarchicalContext(),
- other.getHierarchicalContext()) && Objects.equals(getLegacyEntryKeys(), other.getLegacyEntryKeys());
- }
-
- /**
- * Returns a String representation of this group and its entries.
- */
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- sb.append(ExplicitGroup.ID).append(
- StringUtil.quote(getName(), AbstractGroup.SEPARATOR, AbstractGroup.QUOTE_CHAR)).
- append(AbstractGroup.SEPARATOR).append(getContext().ordinal()).append(AbstractGroup.SEPARATOR);
-
- // write legacy entry keys in well-defined order for CVS compatibility
- Set<String> sortedKeys = new TreeSet<>();
- sortedKeys.addAll(legacyEntryKeys);
-
- for (String sortedKey : sortedKeys) {
- sb.append(StringUtil.quote(sortedKey, AbstractGroup.SEPARATOR, AbstractGroup.QUOTE_CHAR)).append(
- AbstractGroup.SEPARATOR);
- }
- return sb.toString();
- }
-
- /**
- * Remove all stored cite keys, resulting in an empty group.
- */
- public void clearLegacyEntryKeys() {
- legacyEntryKeys.clear();
- }
-
- @Override
- public String getDescription() {
- return ExplicitGroup.getDescriptionForPreview();
- }
-
- public static String getDescriptionForPreview() {
- return Localization.lang("This group contains entries based on manual assignment. "
- + "Entries can be assigned to this group by selecting them "
- + "then using either drag and drop or the context menu. "
- + "Entries can be removed from this group by selecting them "
- + "then using the context menu.");
- }
-
- @Override
- public String getShortDescription(boolean showDynamic) {
- StringBuilder sb = new StringBuilder();
- sb.append("<b>").append(getName()).append("</b> -").append(Localization.lang("static group"));
- switch (getHierarchicalContext()) {
- case INCLUDING:
- sb.append(", ").append(Localization.lang("includes subgroups"));
- break;
- case REFINING:
- sb.append(", ").append(Localization.lang("refines supergroup"));
- break;
- default:
- break;
- }
- return sb.toString();
- }
-
- public List<String> getLegacyEntryKeys() {
- return legacyEntryKeys;
- }
-
- @Override
- public String getTypeId() {
- return ExplicitGroup.ID;
- }
-
- @Override
- public int hashCode() {
- return super.hashCode();
- }
-
- @Override
- public boolean isDynamic() {
- return false;
- }
-}
diff --git a/src/main/java/net/sf/jabref/logic/groups/GroupDescriptions.java b/src/main/java/net/sf/jabref/logic/groups/GroupDescriptions.java
new file mode 100644
index 0000000..b573927
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/groups/GroupDescriptions.java
@@ -0,0 +1,120 @@
+package net.sf.jabref.logic.groups;
+
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.groups.ExplicitGroup;
+import net.sf.jabref.model.groups.KeywordGroup;
+import net.sf.jabref.model.groups.SearchGroup;
+import net.sf.jabref.model.strings.StringUtil;
+
+public class GroupDescriptions {
+
+ public static String getDescriptionForPreview(String field, String expr, boolean caseSensitive, boolean regExp) {
+ String header = regExp ? Localization.lang("This group contains entries whose <b>%0</b> field contains the regular expression <b>%1</b>",
+ field, StringUtil.quoteForHTML(expr))
+ : Localization.lang("This group contains entries whose <b>%0</b> field contains the keyword <b>%1</b>",
+ field, StringUtil.quoteForHTML(expr));
+ String caseSensitiveText = caseSensitive ? Localization.lang("case sensitive") :
+ Localization.lang("case insensitive");
+ String footer = regExp ?
+ Localization.lang("Entries cannot be manually assigned to or removed from this group.")
+ : Localization.lang(
+ "Additionally, entries whose <b>%0</b> field does not contain "
+ + "<b>%1</b> can be assigned manually to this group by selecting them "
+ + "then using either drag and drop or the context menu. "
+ + "This process adds the term <b>%1</b> to "
+ + "each entry's <b>%0</b> field. "
+ + "Entries can be removed manually from this group by selecting them "
+ + "then using the context menu. "
+ + "This process removes the term <b>%1</b> from "
+ + "each entry's <b>%0</b> field.",
+ field, StringUtil.quoteForHTML(expr));
+ return String.format("%s (%s). %s", header, caseSensitiveText, footer);
+ }
+
+ public static String getShortDescriptionKeywordGroup(KeywordGroup keywordGroup, boolean showDynamic) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("<b>");
+ if (showDynamic) {
+ sb.append("<i>").append(StringUtil.quoteForHTML(keywordGroup.getName())).append("</i>");
+ } else {
+ sb.append(StringUtil.quoteForHTML(keywordGroup.getName()));
+ }
+ sb.append("</b> - ");
+ sb.append(Localization.lang("dynamic group"));
+ sb.append(" <b>");
+ sb.append(keywordGroup.getSearchField());
+ sb.append("</b> ");
+ sb.append(Localization.lang("contains"));
+ sb.append(" <b>");
+ sb.append(StringUtil.quoteForHTML(keywordGroup.getSearchExpression()));
+ sb.append("</b>)");
+ switch (keywordGroup.getHierarchicalContext()) {
+ case INCLUDING:
+ sb.append(", ").append(Localization.lang("includes subgroups"));
+ break;
+ case REFINING:
+ sb.append(", ").append(Localization.lang("refines supergroup"));
+ break;
+ default:
+ break;
+ }
+ return sb.toString();
+
+ }
+
+ public static String getDescriptionForPreview() {
+ return Localization.lang("This group contains entries based on manual assignment. "
+ + "Entries can be assigned to this group by selecting them "
+ + "then using either drag and drop or the context menu. "
+ + "Entries can be removed from this group by selecting them "
+ + "then using the context menu.");
+ }
+
+ public static String getShortDescriptionExplicitGroup(ExplicitGroup explicitGroup) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("<b>").append(explicitGroup.getName()).append("</b> - ").append(Localization.lang("static group"));
+ switch (explicitGroup.getHierarchicalContext()) {
+ case INCLUDING:
+ sb.append(", ").append(Localization.lang("includes subgroups"));
+ break;
+ case REFINING:
+ sb.append(", ").append(Localization.lang("refines supergroup"));
+ break;
+ default:
+ break;
+ }
+ return sb.toString();
+ }
+
+ public static String getShortDescriptionAllEntriesGroup() {
+ return Localization.lang("<b>All Entries</b> (this group cannot be edited or removed)");
+ }
+
+ public static String getShortDescription(SearchGroup searchGroup, boolean showDynamic) {
+
+ StringBuilder sb = new StringBuilder();
+ sb.append("<b>");
+ if (showDynamic) {
+ sb.append("<i>").append(StringUtil.quoteForHTML(searchGroup.getName())).append("</i>");
+ } else {
+ sb.append(StringUtil.quoteForHTML(searchGroup.getName()));
+ }
+ sb.append("</b> - ");
+ sb.append(Localization.lang("dynamic group"));
+ sb.append(" (");
+ sb.append(Localization.lang("search expression"));
+ sb.append(" <b>").append(StringUtil.quoteForHTML(searchGroup.getSearchExpression())).append("</b>)");
+ switch (searchGroup.getHierarchicalContext()) {
+ case INCLUDING:
+ sb.append(", ").append(Localization.lang("includes subgroups"));
+ break;
+ case REFINING:
+ sb.append(", ").append(Localization.lang("refines supergroup"));
+ break;
+ default:
+ break;
+ }
+ return sb.toString();
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/logic/groups/GroupHierarchyType.java b/src/main/java/net/sf/jabref/logic/groups/GroupHierarchyType.java
deleted file mode 100644
index a596f17..0000000
--- a/src/main/java/net/sf/jabref/logic/groups/GroupHierarchyType.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package net.sf.jabref.logic.groups;
-
-public enum GroupHierarchyType {
-
- /** Group's contents are independent of its hierarchical position. */
- INDEPENDENT,
-
- /**
- * Group's content is the intersection of its own content with its
- * supergroup's content.
- */
- REFINING, // INTERSECTION
-
- /**
- * Group's content is the union of its own content with its subgroups'
- * content.
- */
- INCLUDING; // UNION
-
- public static GroupHierarchyType getByNumber(int type) {
- GroupHierarchyType[] types = values();
- if(type >= 0 && type < types.length) {
- return types[type];
- } else {
- return null;
- }
- }
-}
diff --git a/src/main/java/net/sf/jabref/logic/groups/GroupTreeNode.java b/src/main/java/net/sf/jabref/logic/groups/GroupTreeNode.java
deleted file mode 100644
index 6ad4eef..0000000
--- a/src/main/java/net/sf/jabref/logic/groups/GroupTreeNode.java
+++ /dev/null
@@ -1,257 +0,0 @@
-package net.sf.jabref.logic.groups;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.stream.Collectors;
-
-import net.sf.jabref.logic.importer.util.ParseException;
-import net.sf.jabref.logic.search.SearchMatcher;
-import net.sf.jabref.logic.search.matchers.MatcherSet;
-import net.sf.jabref.logic.search.matchers.MatcherSets;
-import net.sf.jabref.model.database.BibDatabase;
-import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.preferences.JabRefPreferences;
-
-/**
- * A node in the groups tree that holds exactly one AbstractGroup.
- */
-public class GroupTreeNode extends TreeNode<GroupTreeNode> {
-
- private AbstractGroup group;
-
- /**
- * Creates this node and associates the specified group with it.
- *
- * @param group the group underlying this node
- */
- public GroupTreeNode(AbstractGroup group) {
- super(GroupTreeNode.class);
- setGroup(group);
- }
-
- public static GroupTreeNode fromGroup(AbstractGroup group) {
- return new GroupTreeNode(group);
- }
-
- /**
- * Returns the group underlying this node.
- *
- * @return the group associated with this node
- */
- public AbstractGroup getGroup() {
- return group;
- }
-
- /**
- * Associates the specified group with this node.
- *
- * @param newGroup the new group (has to be non-null)
- */
- @Deprecated // use other overload
- public void setGroup(AbstractGroup newGroup) {
- this.group = Objects.requireNonNull(newGroup);
- }
-
- /**
- * Associates the specified group with this node while also providing the possibility to modify previous matched
- * entries so that they are now matched by the new group.
- *
- * @param newGroup the new group (has to be non-null)
- * @param shouldKeepPreviousAssignments specifies whether previous matched entries should be carried over
- * @param entriesInDatabase list of entries in the database
- */
- public Optional<EntriesGroupChange> setGroup(AbstractGroup newGroup, boolean shouldKeepPreviousAssignments,
- List<BibEntry> entriesInDatabase) {
- AbstractGroup oldGroup = getGroup();
- setGroup(newGroup);
-
- // Keep assignments from previous group
- if (shouldKeepPreviousAssignments && newGroup.supportsAdd()) {
- List<BibEntry> entriesMatchedByOldGroup = entriesInDatabase.stream().filter(oldGroup::isMatch)
- .collect(Collectors.toList());
- if ((oldGroup instanceof ExplicitGroup) && (newGroup instanceof ExplicitGroup)) {
- // Rename of explicit group, so remove old group assignment
- oldGroup.remove(entriesMatchedByOldGroup);
- }
- return newGroup.add(entriesMatchedByOldGroup);
- }
- return Optional.empty();
- }
-
- /**
- * Returns a textual representation of this node and its children. This
- * representation contains both the tree structure and the textual
- * representations of the group associated with each node.
- * Every node is one entry in the list of strings.
- *
- * @return a representation of the tree based at this node as a list of strings
- */
- public List<String> getTreeAsString() {
-
- List<String> representation = new ArrayList<>();
-
- // Append myself
- representation.add(this.toString());
-
- // Append children
- for(GroupTreeNode child : getChildren()) {
- representation.addAll(child.getTreeAsString());
- }
-
- return representation;
- }
-
- /**
- * Update all groups, if necessary, to handle the situation where the group
- * tree is applied to a different BibDatabase than it was created for. This
- * is for instance used when updating the group tree due to an external change.
- *
- * @param db The database to refresh for.
- * @deprecated This method shouldn't be necessary anymore once explicit group memberships are saved directly in the entry.
- * TODO: Remove this method.
- */
- @Deprecated
- public void refreshGroupsForNewDatabase(BibDatabase db) {
- for (GroupTreeNode node : getChildren()) {
- node.group.refreshForNewDatabase(db);
- node.refreshGroupsForNewDatabase(db);
- }
- }
-
- /**
- * Creates a SearchRule that finds elements contained in this nodes group,
- * or the union of those elements in its own group and its
- * children's groups (recursively), or the intersection of the elements in
- * its own group and its parent's group (depending on the hierarchical settings stored in the involved groups)
- *
- * @return a SearchRule that finds the desired elements
- */
- public SearchMatcher getSearchRule() {
- return getSearchRule(group.getHierarchicalContext());
- }
-
- private SearchMatcher getSearchRule(GroupHierarchyType originalContext) {
- final GroupHierarchyType context = group.getHierarchicalContext();
- if (context == GroupHierarchyType.INDEPENDENT) {
- return group;
- }
- MatcherSet searchRule = MatcherSets.build(
- context == GroupHierarchyType.REFINING ? MatcherSets.MatcherType.AND : MatcherSets.MatcherType.OR);
- searchRule.addRule(group);
- if ((context == GroupHierarchyType.INCLUDING) && (originalContext != GroupHierarchyType.REFINING)) {
- for (GroupTreeNode child : getChildren()) {
- searchRule.addRule(child.getSearchRule(originalContext));
- }
- } else if ((context == GroupHierarchyType.REFINING) && !isRoot() && (originalContext
- != GroupHierarchyType.INCLUDING)) {
- searchRule.addRule(getParent().get().getSearchRule(originalContext));
- }
- return searchRule;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if ((o == null) || (getClass() != o.getClass())) {
- return false;
- }
- GroupTreeNode that = (GroupTreeNode) o;
- return Objects.equals(group, that.group);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(group);
- }
-
- public List<GroupTreeNode> getContainingGroups(List<BibEntry> entries, boolean requireAll) {
- List<GroupTreeNode> groups = new ArrayList<>();
-
- // Add myself if I contain the entries
- if(requireAll) {
- if(this.group.containsAll(entries)) {
- groups.add(this);
- }
- } else {
- if(this.group.containsAny(entries)) {
- groups.add(this);
- }
- }
-
- // Traverse children
- for(GroupTreeNode child : getChildren()) {
- groups.addAll(child.getContainingGroups(entries, requireAll));
- }
-
- return groups;
- }
-
- public List<GroupTreeNode> getMatchingGroups(List<BibEntry> entries) {
- List<GroupTreeNode> groups = new ArrayList<>();
-
- // Add myself if I contain the entries
- SearchMatcher matcher = getSearchRule();
- for (BibEntry entry : entries) {
- if (matcher.isMatch(entry)) {
- groups.add(this);
- break;
- }
- }
-
- // Traverse children
- for(GroupTreeNode child : getChildren()) {
- groups.addAll(child.getMatchingGroups(entries));
- }
-
- return groups;
- }
-
- public boolean supportsAddingEntries() {
- return group.supportsAdd();
- }
-
- public String getName() {
- return group.getName();
- }
-
- public GroupTreeNode addSubgroup(AbstractGroup group) {
- GroupTreeNode child = GroupTreeNode.fromGroup(group);
- addChild(child);
- return child;
- }
-
- @Override
- public String toString() {
- return String.valueOf(this.getLevel()) + ' ' + group.toString();
- }
-
- @Override
- public GroupTreeNode copyNode() {
- return GroupTreeNode.fromGroup(group);
- }
-
- public static GroupTreeNode parse(List<String> orderedData, JabRefPreferences jabRefPreferences)
- throws ParseException {
- return GroupsParser.importGroups(orderedData, jabRefPreferences);
- }
-
- /**
- * Determines the number of entries in the specified list which are matched by this group.
- * @param entries list of entries to be searched
- * @return number of hits
- */
- public int numberOfHits(List<BibEntry> entries) {
- int hits = 0;
- SearchMatcher matcher = getSearchRule();
- for (BibEntry entry : entries) {
- if (matcher.isMatch(entry)) {
- hits++;
- }
- }
- return hits;
- }
-}
diff --git a/src/main/java/net/sf/jabref/logic/groups/GroupsParser.java b/src/main/java/net/sf/jabref/logic/groups/GroupsParser.java
index 5377a96..f07a2fa 100644
--- a/src/main/java/net/sf/jabref/logic/groups/GroupsParser.java
+++ b/src/main/java/net/sf/jabref/logic/groups/GroupsParser.java
@@ -2,46 +2,169 @@ package net.sf.jabref.logic.groups;
import java.util.List;
-import net.sf.jabref.logic.importer.util.ParseException;
+import net.sf.jabref.logic.importer.ParseException;
import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.preferences.JabRefPreferences;
+import net.sf.jabref.logic.util.strings.QuotedStringTokenizer;
+import net.sf.jabref.model.groups.AbstractGroup;
+import net.sf.jabref.model.groups.AllEntriesGroup;
+import net.sf.jabref.model.groups.ExplicitGroup;
+import net.sf.jabref.model.groups.GroupHierarchyType;
+import net.sf.jabref.model.groups.GroupTreeNode;
+import net.sf.jabref.model.groups.KeywordGroup;
+import net.sf.jabref.model.groups.SearchGroup;
+import net.sf.jabref.model.strings.StringUtil;
/**
* Converts string representation of groups to a parsed {@link GroupTreeNode}.
*/
-class GroupsParser {
+public class GroupsParser {
- public static GroupTreeNode importGroups(List<String> orderedData, JabRefPreferences jabRefPreferences)
+ public static GroupTreeNode importGroups(List<String> orderedData, Character keywordSeparator)
throws ParseException {
- GroupTreeNode cursor = null;
- GroupTreeNode root = null;
- for (String string : orderedData) {
- // This allows to read databases that have been modified by, e.g., BibDesk
- string = string.trim();
- if (string.isEmpty()) {
- continue;
- }
+ try {
+ GroupTreeNode cursor = null;
+ GroupTreeNode root = null;
+ for (String string : orderedData) {
+ // This allows to read databases that have been modified by, e.g., BibDesk
+ string = string.trim();
+ if (string.isEmpty()) {
+ continue;
+ }
- int spaceIndex = string.indexOf(' ');
- if (spaceIndex <= 0) {
- throw new ParseException(Localization.lang("Expected \"%0\" to contain whitespace", string));
- }
- int level = Integer.parseInt(string.substring(0, spaceIndex));
- AbstractGroup group = AbstractGroup.fromString(string.substring(spaceIndex + 1), jabRefPreferences);
- GroupTreeNode newNode = GroupTreeNode.fromGroup(group);
- if (cursor == null) {
- // create new root
- cursor = newNode;
- root = cursor;
- } else {
- // insert at desired location
- while (level <= cursor.getLevel()) {
- cursor = cursor.getParent().get();
+ int spaceIndex = string.indexOf(' ');
+ if (spaceIndex <= 0) {
+ throw new ParseException("Expected \"" + string + "\" to contain whitespace");
+ }
+ int level = Integer.parseInt(string.substring(0, spaceIndex));
+ AbstractGroup group = GroupsParser.fromString(string.substring(spaceIndex + 1), keywordSeparator);
+ GroupTreeNode newNode = GroupTreeNode.fromGroup(group);
+ if (cursor == null) {
+ // create new root
+ cursor = newNode;
+ root = cursor;
+ } else {
+ // insert at desired location
+ while (level <= cursor.getLevel()) {
+ cursor = cursor.getParent().get();
+ }
+ cursor.addChild(newNode);
+ cursor = newNode;
}
- cursor.addChild(newNode);
- cursor = newNode;
}
+ return root;
+ } catch (ParseException e) {
+ throw new ParseException(Localization
+ .lang("Group tree could not be parsed. If you save the BibTeX database, all groups will be lost."),
+ e);
+ }
+ }
+
+ /**
+ * Re-create a group instance from a textual representation.
+ *
+ * @param s The result from the group's toString() method.
+ * @return New instance of the encoded group.
+ * @throws ParseException If an error occurred and a group could not be created,
+ * e.g. due to a malformed regular expression.
+ */
+ public static AbstractGroup fromString(String s, Character keywordSeparator)
+ throws ParseException {
+ if (s.startsWith(KeywordGroup.ID)) {
+ return GroupsParser.keywordGroupFromString(s, keywordSeparator);
}
- return root;
+ if (s.startsWith(AllEntriesGroup.ID)) {
+ return GroupsParser.allEntriesGroupFromString(s);
+ }
+ if (s.startsWith(SearchGroup.ID)) {
+ return GroupsParser.searchGroupFromString(s);
+ }
+ if (s.startsWith(ExplicitGroup.ID)) {
+ return GroupsParser.explicitGroupFromString(s, keywordSeparator);
+ }
+ return null; // unknown group
+ }
+
+ /**
+ * Parses s and recreates the KeywordGroup from it.
+ *
+ * @param s The String representation obtained from
+ * KeywordGroup.toString()
+ */
+ public static AbstractGroup keywordGroupFromString(String s, Character keywordSeparator) throws ParseException {
+ if (!s.startsWith(KeywordGroup.ID)) {
+ throw new IllegalArgumentException("KeywordGroup cannot be created from \"" + s + "\".");
+ }
+ QuotedStringTokenizer tok = new QuotedStringTokenizer(s.substring(KeywordGroup.ID
+ .length()), AbstractGroup.SEPARATOR, AbstractGroup.QUOTE_CHAR);
+
+ String name = tok.nextToken();
+ int context = Integer.parseInt(tok.nextToken());
+ String field = tok.nextToken();
+ String expression = tok.nextToken();
+ boolean caseSensitive = Integer.parseInt(tok.nextToken()) == 1;
+ boolean regExp = Integer.parseInt(tok.nextToken()) == 1;
+ return new KeywordGroup(StringUtil.unquote(name, AbstractGroup.QUOTE_CHAR),
+ StringUtil.unquote(field, AbstractGroup.QUOTE_CHAR),
+ StringUtil.unquote(expression, AbstractGroup.QUOTE_CHAR), caseSensitive, regExp,
+ GroupHierarchyType.getByNumber(context), keywordSeparator);
+ }
+
+ public static ExplicitGroup explicitGroupFromString(String s, Character keywordSeparator) throws ParseException {
+ if (!s.startsWith(ExplicitGroup.ID)) {
+ throw new IllegalArgumentException("ExplicitGroup cannot be created from \"" + s + "\".");
+ }
+ QuotedStringTokenizer tok = new QuotedStringTokenizer(s.substring(ExplicitGroup.ID.length()),
+ AbstractGroup.SEPARATOR, AbstractGroup.QUOTE_CHAR);
+
+ String name = tok.nextToken();
+ int context = Integer.parseInt(tok.nextToken());
+ ExplicitGroup newGroup = new ExplicitGroup(name, GroupHierarchyType.getByNumber(context), keywordSeparator);
+ GroupsParser.addLegacyEntryKeys(tok, newGroup);
+ return newGroup;
+ }
+
+ /**
+ * Called only when created fromString.
+ * JabRef used to store the entries of an explicit group in the serialization, e.g.
+ * ExplicitGroup:GroupName\;0\;Key1\;Key2\;;
+ * This method exists for backwards compatibility.
+ */
+ private static void addLegacyEntryKeys(QuotedStringTokenizer tok, ExplicitGroup group) {
+ while (tok.hasMoreTokens()) {
+ String key = StringUtil.unquote(tok.nextToken(), AbstractGroup.QUOTE_CHAR);
+ group.addLegacyEntryKey(key);
+ }
+ }
+
+ public static AbstractGroup allEntriesGroupFromString(String s) {
+ if (!s.startsWith(AllEntriesGroup.ID)) {
+ throw new IllegalArgumentException("AllEntriesGroup cannot be created from \"" + s + "\".");
+ }
+ return new AllEntriesGroup(Localization.lang("All entries"));
+ }
+
+ /**
+ * Parses s and recreates the SearchGroup from it.
+ *
+ * @param s The String representation obtained from
+ * SearchGroup.toString(), or null if incompatible
+ */
+ public static AbstractGroup searchGroupFromString(String s) {
+ if (!s.startsWith(SearchGroup.ID)) {
+ throw new IllegalArgumentException("SearchGroup cannot be created from \"" + s + "\".");
+ }
+ QuotedStringTokenizer tok = new QuotedStringTokenizer(s.substring(SearchGroup.ID.length()),
+ AbstractGroup.SEPARATOR, AbstractGroup.QUOTE_CHAR);
+
+ String name = tok.nextToken();
+ int context = Integer.parseInt(tok.nextToken());
+ String expression = tok.nextToken();
+ boolean caseSensitive = Integer.parseInt(tok.nextToken()) == 1;
+ boolean regExp = Integer.parseInt(tok.nextToken()) == 1;
+ // version 0 contained 4 additional booleans to specify search
+ // fields; these are ignored now, all fields are always searched
+ return new SearchGroup(StringUtil.unquote(name, AbstractGroup.QUOTE_CHAR),
+ StringUtil.unquote(expression, AbstractGroup.QUOTE_CHAR), caseSensitive, regExp,
+ GroupHierarchyType.getByNumber(context));
}
}
diff --git a/src/main/java/net/sf/jabref/logic/groups/GroupsUtil.java b/src/main/java/net/sf/jabref/logic/groups/GroupsUtil.java
deleted file mode 100644
index 5c3d74f..0000000
--- a/src/main/java/net/sf/jabref/logic/groups/GroupsUtil.java
+++ /dev/null
@@ -1,80 +0,0 @@
-package net.sf.jabref.logic.groups;
-
-import java.util.List;
-import java.util.Optional;
-import java.util.Set;
-import java.util.StringTokenizer;
-import java.util.TreeSet;
-import java.util.stream.Collectors;
-
-import net.sf.jabref.model.database.BibDatabase;
-import net.sf.jabref.model.entry.Author;
-import net.sf.jabref.model.entry.AuthorList;
-import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.model.entry.EntryUtil;
-
-public class GroupsUtil {
-
- public static Set<String> findDeliminatedWordsInField(BibDatabase db, String field, String deliminator) {
- Set<String> res = new TreeSet<>();
-
- for (BibEntry be : db.getEntries()) {
- be.getFieldOptional(field).ifPresent(fieldValue -> {
- StringTokenizer tok = new StringTokenizer(fieldValue.trim(), deliminator);
- while (tok.hasMoreTokens()) {
- res.add(EntryUtil.capitalizeFirst(tok.nextToken().trim()));
- }
- });
- }
- return res;
- }
-
- /**
- * Returns a Set containing all words used in the database in the given field type. Characters in
- * <code>remove</code> are not included.
- *
- * @param db a <code>BibDatabase</code> value
- * @param field a <code>String</code> value
- * @param remove a <code>String</code> value
- * @return a <code>Set</code> value
- */
- public static Set<String> findAllWordsInField(BibDatabase db, String field, String remove) {
- Set<String> res = new TreeSet<>();
- for (BibEntry be : db.getEntries()) {
- be.getFieldOptional(field).ifPresent(o -> {
- StringTokenizer tok = new StringTokenizer(o, remove, false);
- while (tok.hasMoreTokens()) {
- res.add(EntryUtil.capitalizeFirst(tok.nextToken().trim()));
- }
- });
- }
- return res;
- }
-
- /**
- * Finds all authors' last names in all the given fields for the given database.
- *
- * @param db The database.
- * @param fields The fields to look in.
- * @return a set containing the names.
- */
- public static Set<String> findAuthorLastNames(BibDatabase db, List<String> fields) {
- Set<String> res = new TreeSet<>();
- for (BibEntry be : db.getEntries()) {
- for (String field : fields) {
- be.getFieldOptional(field).ifPresent(val -> {
- if (!val.isEmpty()) {
- AuthorList al = AuthorList.parse(val);
- res.addAll(al.getAuthors().stream().map(Author::getLast).filter(Optional::isPresent)
- .map(Optional::get).filter(lastName -> !lastName.isEmpty())
- .collect(Collectors.toList()));
- }
- });
- }
- }
-
- return res;
- }
-
-
-}
diff --git a/src/main/java/net/sf/jabref/logic/groups/KeywordGroup.java b/src/main/java/net/sf/jabref/logic/groups/KeywordGroup.java
deleted file mode 100644
index 93d0038..0000000
--- a/src/main/java/net/sf/jabref/logic/groups/KeywordGroup.java
+++ /dev/null
@@ -1,395 +0,0 @@
-package net.sf.jabref.logic.groups;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Optional;
-import java.util.Set;
-import java.util.regex.Pattern;
-import java.util.regex.PatternSyntaxException;
-
-import net.sf.jabref.logic.importer.util.ParseException;
-import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.logic.util.strings.QuotedStringTokenizer;
-import net.sf.jabref.logic.util.strings.StringUtil;
-import net.sf.jabref.model.FieldChange;
-import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.model.entry.EntryUtil;
-import net.sf.jabref.preferences.JabRefPreferences;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * @author jzieren
- */
-public class KeywordGroup extends AbstractGroup {
-
- public static final String ID = "KeywordGroup:";
-
- private final String searchField;
- private final String searchExpression;
- private final boolean caseSensitive;
- private final boolean regExp;
- private Pattern pattern;
- private final List<String> searchWords;
- protected final JabRefPreferences jabRefPreferences;
-
- private static final Log LOGGER = LogFactory.getLog(KeywordGroup.class);
-
-
- /**
- * Creates a KeywordGroup with the specified properties.
- */
- public KeywordGroup(String name, String searchField,
- String searchExpression, boolean caseSensitive, boolean regExp,
- GroupHierarchyType context, JabRefPreferences jabRefPreferences) throws ParseException {
- super(name, context);
- this.searchField = searchField;
- this.searchExpression = searchExpression;
- this.caseSensitive = caseSensitive;
- this.regExp = regExp;
- if (this.regExp) {
- compilePattern();
- }
- this.jabRefPreferences = jabRefPreferences;
- this.searchWords = EntryUtil.getStringAsWords(searchExpression);
- }
-
- private void compilePattern() throws ParseException {
- try {
- pattern = caseSensitive ? Pattern.compile("\\b" + searchExpression + "\\b") : Pattern.compile(
- "\\b" + searchExpression + "\\b", Pattern.CASE_INSENSITIVE);
- } catch (PatternSyntaxException exception) {
- throw new ParseException(Localization.lang("Syntax error in regular-expression pattern", searchExpression));
- }
- }
-
- /**
- * Parses s and recreates the KeywordGroup from it.
- *
- * @param s The String representation obtained from
- * KeywordGroup.toString()
- */
- public static AbstractGroup fromString(String s, JabRefPreferences jabRefPreferences) throws ParseException {
- if (!s.startsWith(KeywordGroup.ID)) {
- throw new IllegalArgumentException("KeywordGroup cannot be created from \"" + s + "\".");
- }
- QuotedStringTokenizer tok = new QuotedStringTokenizer(s.substring(KeywordGroup.ID
- .length()), AbstractGroup.SEPARATOR, AbstractGroup.QUOTE_CHAR);
-
- String name = tok.nextToken();
- int context = Integer.parseInt(tok.nextToken());
- String field = tok.nextToken();
- String expression = tok.nextToken();
- boolean caseSensitive = Integer.parseInt(tok.nextToken()) == 1;
- boolean regExp = Integer.parseInt(tok.nextToken()) == 1;
- return new KeywordGroup(StringUtil.unquote(name, AbstractGroup.QUOTE_CHAR),
- StringUtil.unquote(field, AbstractGroup.QUOTE_CHAR),
- StringUtil.unquote(expression, AbstractGroup.QUOTE_CHAR), caseSensitive, regExp,
- GroupHierarchyType.getByNumber(context), jabRefPreferences);
- }
-
- /**
- * Returns a String representation of this object that can be used to
- * reconstruct it.
- */
- @Override
- public String toString() {
- return KeywordGroup.ID + StringUtil.quote(getName(), AbstractGroup.SEPARATOR, AbstractGroup.QUOTE_CHAR) +
- AbstractGroup.SEPARATOR
- + getContext().ordinal() + AbstractGroup.SEPARATOR
- + StringUtil.quote(searchField, AbstractGroup.SEPARATOR, AbstractGroup.QUOTE_CHAR) + AbstractGroup.SEPARATOR
- + StringUtil.quote(searchExpression, AbstractGroup.SEPARATOR, AbstractGroup.QUOTE_CHAR)
- + AbstractGroup.SEPARATOR + StringUtil.booleanToBinaryString(caseSensitive) + AbstractGroup.SEPARATOR
- + StringUtil.booleanToBinaryString(regExp) + AbstractGroup.SEPARATOR;
- }
-
- @Override
- public boolean supportsAdd() {
- return !regExp;
- }
-
- @Override
- public boolean supportsRemove() {
- return !regExp;
- }
-
- @Override
- public Optional<EntriesGroupChange> add(List<BibEntry> entriesToAdd) {
- if (!supportsAdd()) {
- return Optional.empty();
- }
- if ((entriesToAdd != null) && !(entriesToAdd.isEmpty())) {
- List<FieldChange> changes = new ArrayList<>();
- boolean modified = false;
- for (BibEntry entry : entriesToAdd) {
- if (!contains(entry)) {
- String oldContent = entry.getFieldOptional(searchField).orElse(null);
- String pre = jabRefPreferences.get(JabRefPreferences.KEYWORD_SEPARATOR);
- String newContent = (oldContent == null ? "" : oldContent
- + pre)
- + searchExpression;
- entry.setField(searchField, newContent);
-
- // Store change information.
- changes.add(new FieldChange(entry, searchField, oldContent, newContent));
- modified = true;
- }
- }
-
- return modified ? Optional.of(new EntriesGroupChange(changes)) : Optional.empty();
- }
-
- return Optional.empty();
- }
-
- @Override
- public Optional<EntriesGroupChange> remove(List<BibEntry> entriesToRemove) {
- if (!supportsRemove()) {
- return Optional.empty();
- }
-
- if ((entriesToRemove != null) && (!entriesToRemove.isEmpty())) {
- List<FieldChange> changes = new ArrayList<>();
- boolean modified = false;
- for (BibEntry entry : entriesToRemove) {
- if (contains(entry)) {
- String oldContent = entry.getFieldOptional(searchField).orElse(null);
- removeMatches(entry);
-
- // Store change information.
- changes.add(new FieldChange(entry, searchField, oldContent,
- entry.getFieldOptional(searchField).orElse(null)));
- modified = true;
- }
- }
-
- return modified ? Optional.of(new EntriesGroupChange(changes)) : Optional.empty();
- }
-
- return Optional.empty();
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (!(o instanceof KeywordGroup)) {
- return false;
- }
- KeywordGroup other = (KeywordGroup) o;
- return getName().equals(other.getName())
- && searchField.equals(other.searchField)
- && searchExpression.equals(other.searchExpression)
- && (caseSensitive == other.caseSensitive)
- && (regExp == other.regExp)
- && (getHierarchicalContext() == other.getHierarchicalContext());
- }
-
- @Override
- public boolean contains(BibEntry entry) {
- if (regExp) {
- Optional<String> content = entry.getFieldOptional(searchField);
- return content.map(value -> pattern.matcher(value).find()).orElse(false);
- }
-
- Set<String> words = entry.getFieldAsWords(searchField);
- if (words.isEmpty()) {
- return false;
- }
-
- if (caseSensitive) {
- return words.containsAll(searchWords);
- }
- return containsCaseInsensitive(searchWords, words);
- }
-
- private boolean containsCaseInsensitive(List<String> searchText, Set<String> words) {
- for (String searchWord : searchText) {
- if (!containsCaseInsensitive(searchWord, words)) {
- return false;
- }
- }
- return true;
- }
-
- private boolean containsCaseInsensitive(String text, Set<String> words) {
- for (String word : words) {
- if (word.equalsIgnoreCase(text)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Look for the given non-regexp string in another string, but check whether a
- * match concerns a complete word, not part of a word.
- *
- * @param word The word to look for.
- * @param text The string to look in.
- * @return true if the word was found, false otherwise.
- */
- public static boolean containsWord(String word, String text) {
- int piv = 0;
- while (piv < text.length()) {
- int index = text.indexOf(word, piv);
- if (index < 0) {
- return false;
- }
- // Found a match. See if it is a complete word:
- if (((index == 0) || !Character.isLetterOrDigit(text.charAt(index - 1))) &&
- (((index + word.length()) == text.length())
- || !Character.isLetterOrDigit(text.charAt(index + word.length())))) {
- return true;
- } else {
- piv = index + 1;
- }
- }
- return false;
- }
-
- /**
- * Removes matches of searchString in the entry's field. This is only
- * possible if the search expression is not a regExp.
- */
- private void removeMatches(BibEntry entry) {
- entry.getFieldOptional(searchField).ifPresent(content -> {
- StringBuffer sbOrig = new StringBuffer(content);
- StringBuffer sbLower = new StringBuffer(content.toLowerCase());
- StringBuffer haystack = caseSensitive ? sbOrig : sbLower;
- String needle = caseSensitive ? searchExpression : searchExpression.toLowerCase();
- int i;
- int j;
- int k;
- final String separator = jabRefPreferences.get(JabRefPreferences.KEYWORD_SEPARATOR);
- while ((i = haystack.indexOf(needle)) >= 0) {
- sbOrig.replace(i, i + needle.length(), "");
- sbLower.replace(i, i + needle.length(), "");
- // reduce spaces at i to 1
- j = i;
- k = i;
- while (((j - 1) >= 0) && (separator.indexOf(haystack.charAt(j - 1)) >= 0)) {
- --j;
- }
- while ((k < haystack.length()) && (separator.indexOf(haystack.charAt(k)) >= 0)) {
- ++k;
- }
- sbOrig.replace(j, k, (j >= 0) && (k < sbOrig.length()) ? separator : "");
- sbLower.replace(j, k, (j >= 0) && (k < sbOrig.length()) ? separator : "");
- }
-
- String result = sbOrig.toString().trim();
- if (result.isEmpty()) {
- entry.clearField(searchField);
- } else {
- entry.setField(searchField, result);
- }
- });
- }
-
- @Override
- public AbstractGroup deepCopy() {
- try {
- return new KeywordGroup(getName(), searchField, searchExpression,
- caseSensitive, regExp, getContext(), jabRefPreferences);
- } catch (ParseException exception) {
- // this should never happen, because the constructor obviously succeeded in creating _this_ instance!
- LOGGER.error("Internal error in KeywordGroup.deepCopy(). "
- + "Please report this on https://github.com/JabRef/jabref/issues", exception);
- return null;
- }
- }
-
- public boolean isCaseSensitive() {
- return caseSensitive;
- }
-
- public boolean isRegExp() {
- return regExp;
- }
-
- public String getSearchExpression() {
- return searchExpression;
- }
-
- public String getSearchField() {
- return searchField;
- }
-
- @Override
- public boolean isDynamic() {
- return true;
- }
-
- @Override
- public String getDescription() {
- return KeywordGroup.getDescriptionForPreview(searchField, searchExpression, caseSensitive, regExp);
- }
-
- public static String getDescriptionForPreview(String field, String expr, boolean caseSensitive, boolean regExp) {
- String header = regExp ? Localization.lang("This group contains entries whose <b>%0</b> field contains the regular expression <b>%1</b>",
- field, StringUtil.quoteForHTML(expr))
- : Localization.lang("This group contains entries whose <b>%0</b> field contains the keyword <b>%1</b>",
- field, StringUtil.quoteForHTML(expr));
- String caseSensitiveText = caseSensitive ? Localization.lang("case sensitive") :
- Localization.lang("case insensitive");
- String footer = regExp ?
- Localization.lang("Entries cannot be manually assigned to or removed from this group.")
- : Localization.lang(
- "Additionally, entries whose <b>%0</b> field does not contain "
- + "<b>%1</b> can be assigned manually to this group by selecting them "
- + "then using either drag and drop or the context menu. "
- + "This process adds the term <b>%1</b> to "
- + "each entry's <b>%0</b> field. "
- + "Entries can be removed manually from this group by selecting them "
- + "then using the context menu. "
- + "This process removes the term <b>%1</b> from "
- + "each entry's <b>%0</b> field.",
- field, StringUtil.quoteForHTML(expr));
- return String.format("%s (%s). %s", header, caseSensitiveText, footer);
- }
-
- @Override
- public String getShortDescription(boolean showDynamic) {
- StringBuilder sb = new StringBuilder();
- sb.append("<b>");
- if (showDynamic) {
- sb.append("<i>").append(StringUtil.quoteForHTML(getName())).append("</i>");
- } else {
- sb.append(StringUtil.quoteForHTML(getName()));
- }
- sb.append("</b> - ");
- sb.append(Localization.lang("dynamic group"));
- sb.append("<b>");
- sb.append(searchField);
- sb.append("</b>");
- sb.append(Localization.lang("contains"));
- sb.append(" <b>");
- sb.append(StringUtil.quoteForHTML(searchExpression));
- sb.append("</b>)");
- switch (getHierarchicalContext()) {
- case INCLUDING:
- sb.append(", ").append(Localization.lang("includes subgroups"));
- break;
- case REFINING:
- sb.append(", ").append(Localization.lang("refines supergroup"));
- break;
- default:
- break;
- }
- return sb.toString();
- }
-
- @Override
- public String getTypeId() {
- return KeywordGroup.ID;
- }
-
- @Override
- public int hashCode() {
- // TODO Auto-generated method stub
- return super.hashCode();
- }
-}
diff --git a/src/main/java/net/sf/jabref/logic/groups/MoveGroupChange.java b/src/main/java/net/sf/jabref/logic/groups/MoveGroupChange.java
deleted file mode 100644
index 0164331..0000000
--- a/src/main/java/net/sf/jabref/logic/groups/MoveGroupChange.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package net.sf.jabref.logic.groups;
-
-public class MoveGroupChange {
-
- private GroupTreeNode oldParent;
- private int oldChildIndex;
- private GroupTreeNode newParent;
- private int newChildIndex;
-
- /**
- * @param oldParent
- * @param oldChildIndex
- * @param newParent The new parent node to which the node will be moved.
- * @param newChildIndex The child index at newParent to which the node will be moved.
- */
- public MoveGroupChange(GroupTreeNode oldParent, int oldChildIndex, GroupTreeNode newParent, int newChildIndex) {
- this.oldParent = oldParent;
- this.oldChildIndex = oldChildIndex;
- this.newParent = newParent;
- this.newChildIndex = newChildIndex;
- }
-
- public GroupTreeNode getOldParent() {
- return oldParent;
- }
-
- public int getOldChildIndex() {
- return oldChildIndex;
- }
-
- public GroupTreeNode getNewParent() {
- return newParent;
- }
-
- public int getNewChildIndex() {
- return newChildIndex;
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/logic/groups/SearchGroup.java b/src/main/java/net/sf/jabref/logic/groups/SearchGroup.java
deleted file mode 100644
index 6c4270f..0000000
--- a/src/main/java/net/sf/jabref/logic/groups/SearchGroup.java
+++ /dev/null
@@ -1,192 +0,0 @@
-package net.sf.jabref.logic.groups;
-
-import java.util.List;
-import java.util.Optional;
-
-import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.logic.search.SearchQuery;
-import net.sf.jabref.logic.util.strings.QuotedStringTokenizer;
-import net.sf.jabref.logic.util.strings.StringUtil;
-import net.sf.jabref.model.entry.BibEntry;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * Internally, it consists of a search pattern.
- *
- * @author jzieren
- */
-public class SearchGroup extends AbstractGroup {
-
- public static final String ID = "SearchGroup:";
-
- private final SearchQuery query;
-
- private static final Log LOGGER = LogFactory.getLog(SearchGroup.class);
-
- /**
- * Creates a SearchGroup with the specified properties.
- */
- public SearchGroup(String name, String searchExpression, boolean caseSensitive, boolean regExp,
- GroupHierarchyType context) {
- super(name, context);
-
- this.query = new SearchQuery(searchExpression, caseSensitive, regExp);
- }
-
- /**
- * Parses s and recreates the SearchGroup from it.
- *
- * @param s The String representation obtained from
- * SearchGroup.toString(), or null if incompatible
- */
- public static AbstractGroup fromString(String s) {
- if (!s.startsWith(SearchGroup.ID)) {
- throw new IllegalArgumentException("SearchGroup cannot be created from \"" + s + "\".");
- }
- QuotedStringTokenizer tok = new QuotedStringTokenizer(s.substring(SearchGroup.ID.length()),
- AbstractGroup.SEPARATOR, AbstractGroup.QUOTE_CHAR);
-
- String name = tok.nextToken();
- int context = Integer.parseInt(tok.nextToken());
- String expression = tok.nextToken();
- boolean caseSensitive = Integer.parseInt(tok.nextToken()) == 1;
- boolean regExp = Integer.parseInt(tok.nextToken()) == 1;
- // version 0 contained 4 additional booleans to specify search
- // fields; these are ignored now, all fields are always searched
- return new SearchGroup(StringUtil.unquote(name, AbstractGroup.QUOTE_CHAR),
- StringUtil.unquote(expression, AbstractGroup.QUOTE_CHAR), caseSensitive, regExp,
- GroupHierarchyType.getByNumber(context));
- }
-
- @Override
- public String getTypeId() {
- return SearchGroup.ID;
- }
-
- /**
- * Returns a String representation of this object that can be used to
- * reconstruct it.
- */
- @Override
- public String toString() {
- return SearchGroup.ID + StringUtil.quote(getName(), AbstractGroup.SEPARATOR, AbstractGroup.QUOTE_CHAR)
- + AbstractGroup.SEPARATOR + getContext().ordinal() + AbstractGroup.SEPARATOR
- + StringUtil.quote(getSearchExpression(), AbstractGroup.SEPARATOR, AbstractGroup.QUOTE_CHAR)
- + AbstractGroup.SEPARATOR + StringUtil.booleanToBinaryString(isCaseSensitive())
- + AbstractGroup.SEPARATOR + StringUtil.booleanToBinaryString(isRegExp()) + AbstractGroup.SEPARATOR;
- }
-
- public String getSearchExpression() {
- return this.query.getQuery();
- }
-
- @Override
- public boolean supportsAdd() {
- return false;
- }
-
- @Override
- public boolean supportsRemove() {
- return false;
- }
-
- @Override
- public Optional<EntriesGroupChange> add(List<BibEntry> entriesToAdd) {
- throw new UnsupportedOperationException("Search group does not support adding entries.");
- }
-
- @Override
- public Optional<EntriesGroupChange> remove(List<BibEntry> entriesToRemove) {
- throw new UnsupportedOperationException("Search group does not support removing entries.");
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (!(o instanceof SearchGroup)) {
- return false;
- }
- SearchGroup other = (SearchGroup) o;
- return getName().equals(other.getName())
- && this.getSearchExpression().equals(other.getSearchExpression())
- && (this.isCaseSensitive() == other.isCaseSensitive())
- && (isRegExp() == other.isRegExp())
- && (getHierarchicalContext() == other.getHierarchicalContext());
- }
-
- @Override
- public boolean contains(BibEntry entry) {
- return this.query.isMatch(entry);
- }
-
- @Override
- public AbstractGroup deepCopy() {
- try {
- return new SearchGroup(getName(), getSearchExpression(), isCaseSensitive(),
- isRegExp(), getHierarchicalContext());
- } catch (Throwable t) {
- // this should never happen, because the constructor obviously
- // succeeded in creating _this_ instance!
- LOGGER.error("Internal error in SearchGroup.deepCopy(). "
- + "Please report this on https://github.com/JabRef/jabref/issues", t);
- return null;
- }
- }
-
- public boolean isCaseSensitive() {
- return this.query.isCaseSensitive();
- }
-
- public boolean isRegExp() {
- return this.query.isRegularExpression();
- }
-
- @Override
- public boolean isDynamic() {
- return true;
- }
-
- @Override
- public String getDescription() {
- return this.query.getDescription();
- }
-
- @Override
- public String getShortDescription(boolean showDynamic) {
- StringBuilder sb = new StringBuilder();
- sb.append("<b>");
- if (showDynamic) {
- sb.append("<i>").append(StringUtil.quoteForHTML(getName())).append("</i>");
- } else {
- sb.append(StringUtil.quoteForHTML(getName()));
- }
- sb.append("</b> - ");
- sb.append(Localization.lang("dynamic group"));
- sb.append(" (");
- sb.append(Localization.lang("search expression"));
- sb.append(" <b>").
- append(StringUtil.quoteForHTML(getSearchExpression())).append("</b>)");
- switch (getHierarchicalContext()) {
- case INCLUDING:
- sb.append(", ").append(Localization.lang("includes subgroups"));
- break;
- case REFINING:
- sb.append(", ").append(Localization.lang("refines supergroup"));
- break;
- default:
- break;
- }
- return sb.toString();
- }
-
- @Override
- public int hashCode() {
- // TODO Auto-generated method stub
- return super.hashCode();
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/logic/groups/TreeNode.java b/src/main/java/net/sf/jabref/logic/groups/TreeNode.java
deleted file mode 100644
index 491175b..0000000
--- a/src/main/java/net/sf/jabref/logic/groups/TreeNode.java
+++ /dev/null
@@ -1,606 +0,0 @@
-package net.sf.jabref.logic.groups;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.function.Consumer;
-
-/**
- * Represents a node in a tree.
- * <p>
- * Usually, tree nodes have a value property which allows access to the value stored in the node.
- * In contrast to this approach, the TreeNode<T> class is designed to be used as a base class which provides the
- * tree traversing functionality via inheritance.
- * <p>
- * Example usage:
- * private class BasicTreeNode extends TreeNode<BasicTreeNode> {
- * public BasicTreeNode() {
- * super(BasicTreeNode.class);
- * }
- * }
- * <p>
- * This class started out as a copy of javax.swing.tree.DefaultMutableTreeNode.
- *
- * @param <T> the type of the class
- */
-// We use some explicit casts of the form "(T) this". The constructor ensures that this cast is valid.
- at SuppressWarnings("unchecked") public abstract class TreeNode<T extends TreeNode<T>> {
-
- /**
- * This node's parent, or null if this node has no parent
- */
- private T parent;
- /**
- * Array of children, may be empty if this node has no children (but never null)
- */
- private final List<T> children;
-
- /**
- * Constructs a tree node without parent and no children.
- *
- * @param derivingClass class deriving from TreeNode<T>. It should always be "T.class".
- * We need this parameter since it is hard to get this information by other means.
- */
- public TreeNode(Class<T> derivingClass) {
- parent = null;
- children = new ArrayList<>();
-
- if (!derivingClass.isInstance(this)) {
- throw new UnsupportedOperationException("The class extending TreeNode<T> has to derive from T");
- }
- }
-
- /**
- * Get the path from the root node to this node.
- * <p>
- * The elements in the returned list represent the child index of each node in the path, starting at the root.
- * If this node is the root node, the returned list has zero elements.
- *
- * @return a list of numbers which represent an indexed path from the root node to this node
- */
- public List<Integer> getIndexedPathFromRoot() {
- if (parent == null) {
- return new ArrayList<>();
- }
-
- List<Integer> path = parent.getIndexedPathFromRoot();
- path.add(getPositionInParent());
- return path;
- }
-
- /**
- * Get the descendant of this node as indicated by the indexedPath.
- * <p>
- * If the path could not be traversed completely (i.e. one of the child indices did not exist),
- * an empty Optional will be returned.
- *
- * @param indexedPath sequence of child indices that describe a path from this node to one of its descendants.
- * Be aware that if indexedPath was obtained by getIndexedPathFromRoot(), this node should
- * usually be the root node.
- * @return descendant found by evaluating indexedPath
- */
- public Optional<T> getDescendant(List<Integer> indexedPath) {
- T cursor = (T) this;
- for (int index : indexedPath) {
- Optional<T> child = cursor.getChildAt(index);
- if (child.isPresent()) {
- cursor = child.get();
- } else {
- return Optional.empty();
- }
- }
- return Optional.of(cursor);
- }
-
- /**
- * Get the child index of this node in its parent.
- * <p>
- * If this node is a root, then an UnsupportedOperationException is thrown.
- * Use the isRoot method to check for this case.
- *
- * @return the child index of this node in its parent
- */
- public int getPositionInParent() {
- return getParent().orElseThrow(() -> new UnsupportedOperationException("Roots have no position in parent"))
- .getIndexOfChild((T) this).get();
- }
-
- /**
- * Gets the index of the specified child in this node's child list.
- * <p>
- * If the specified node is not a child of this node, returns an empty Optional.
- * This method performs a linear search and is O(n) where n is the number of children.
- *
- * @param childNode the node to search for among this node's children
- * @return an integer giving the index of the node in this node's child list
- * or an empty Optional if the specified node is a not a child of this node
- * @throws NullPointerException if childNode is null
- */
- public Optional<Integer> getIndexOfChild(T childNode) {
- Objects.requireNonNull(childNode);
- int index = children.indexOf(childNode);
- if (index == -1) {
- return Optional.empty();
- } else {
- return Optional.of(index);
- }
- }
-
- /**
- * Gets the number of levels above this node, i.e. the distance from the root to this node.
- * <p>
- * If this node is the root, returns 0.
- *
- * @return an int giving the number of levels above this node
- */
- public int getLevel() {
- if (parent == null) {
- return 0;
- }
- return parent.getLevel() + 1;
- }
-
- /**
- * Returns the number of children of this node.
- *
- * @return an int giving the number of children of this node
- */
- public int getNumberOfChildren() {
- return children.size();
- }
-
- /**
- * Removes this node from its parent and makes it a child of the specified node
- * by adding it to the end of children list.
- * In this way the whole subtree based at this node is moved to the given node.
- *
- * @param target the new parent
- * @throws NullPointerException if target is null
- * @throws ArrayIndexOutOfBoundsException if targetIndex is out of bounds
- * @throws UnsupportedOperationException if target is an descendant of this node
- */
- public void moveTo(T target) {
- Objects.requireNonNull(target);
-
- Optional<T> oldParent = getParent();
- if (oldParent.isPresent() && (oldParent.get() == target)) {
- this.moveTo(target, target.getNumberOfChildren() - 1);
- } else {
- this.moveTo(target, target.getNumberOfChildren());
- }
- }
-
- /**
- * Returns the path from the root, to get to this node. The last element in the path is this node.
- *
- * @return a list of nodes giving the path, where the first element in the path is the root
- * and the last element is this node.
- */
- public List<T> getPathFromRoot() {
- if (parent == null) {
- List<T> pathToMe = new ArrayList<>();
- pathToMe.add((T) this);
- return pathToMe;
- }
-
- List<T> path = parent.getPathFromRoot();
- path.add((T) this);
- return path;
- }
-
- /**
- * Returns the next sibling of this node in the parent's children list.
- * Returns an empty Optional if this node has no parent or if it is the parent's last child.
- * <p>
- * This method performs a linear search that is O(n) where n is the number of children.
- * To traverse the entire children collection, use the parent's getChildren() instead.
- *
- * @return the sibling of this node that immediately follows this node
- * @see #getChildren
- */
- public Optional<T> getNextSibling() {
- return getRelativeSibling(+1);
- }
-
- /**
- * Returns the previous sibling of this node in the parent's children list.
- * Returns an empty Optional if this node has no parent or is the parent's first child.
- * <p>
- * This method performs a linear search that is O(n) where n is the number of children.
- *
- * @return the sibling of this node that immediately precedes this node
- * @see #getChildren
- */
- public Optional<T> getPreviousSibling() {
- return getRelativeSibling(-1);
- }
-
- /**
- * Returns the sibling which is shiftIndex away from this node.
- */
- private Optional<T> getRelativeSibling(int shiftIndex) {
- if (parent == null) {
- return Optional.empty();
- } else {
- int indexInParent = getPositionInParent();
- int indexTarget = indexInParent + shiftIndex;
- if (parent.childIndexExists(indexTarget)) {
- return parent.getChildAt(indexTarget);
- } else {
- return Optional.empty();
- }
- }
- }
-
- /**
- * Returns this node's parent or an empty Optional if this node has no parent.
- *
- * @return this node's parent T, or an empty Optional if this node has no parent
- */
- public Optional<T> getParent() {
- return Optional.ofNullable(parent);
- }
-
- /**
- * Sets the parent node of this node.
- * <p>
- * This method does not add this node to the children collection of the new parent nor does it remove this node
- * from the old parent. You should probably call moveTo or remove to change the tree.
- *
- * @param parent the new parent
- */
- protected void setParent(T parent) {
- this.parent = parent;
- }
-
- /**
- * Returns the child at the specified index in this node's children collection.
- *
- * @param index an index into this node's children collection
- * @return the node in this node's children collection at the specified index,
- * or an empty Optional if the index does not point to a child
- */
- public Optional<T> getChildAt(int index) {
- return childIndexExists(index) ? Optional.of(children.get(index)) : Optional.empty();
- }
-
- /**
- * Returns whether the specified index is a valid index for a child.
- *
- * @param index the index to be tested
- * @return returns true when index is at least 0 and less then the count of children
- */
- protected boolean childIndexExists(int index) {
- return (index >= 0) && (index < children.size());
- }
-
- /**
- * Returns true if this node is the root of the tree.
- * The root is the only node in the tree with an empty parent; every tree has exactly one root.
- *
- * @return true if this node is the root of its tree
- */
- public boolean isRoot() {
- return parent == null;
- }
-
- /**
- * Returns true if this node is an ancestor of the given node.
- * <p>
- * A node is considered an ancestor of itself.
- *
- * @param anotherNode node to test
- * @return true if anotherNode is a descendant of this node
- * @throws NullPointerException if anotherNode is null
- * @see #isNodeDescendant
- */
- public boolean isAncestorOf(T anotherNode) {
- Objects.requireNonNull(anotherNode);
-
- if (anotherNode == this) {
- return true;
- } else {
- for (T child : children) {
- if (child.isAncestorOf(anotherNode)) {
- return true;
- }
- }
- return false;
- }
- }
-
- /**
- * Returns the root of the tree that contains this node. The root is the ancestor with an empty parent.
- * Thus a node without a parent is considered its own root.
- *
- * @return the root of the tree that contains this node
- */
- public T getRoot() {
- if (parent == null) {
- return (T) this;
- } else {
- return parent.getRoot();
- }
- }
-
- /**
- * Returns true if this node has no children.
- *
- * @return true if this node has no children
- */
- public boolean isLeaf() {
- return (getNumberOfChildren() == 0);
- }
-
- /**
- * Removes the subtree rooted at this node from the tree, giving this node an empty parent.
- * Does nothing if this node is the root of it tree.
- */
- public void removeFromParent() {
- if (parent != null) {
- parent.removeChild((T) this);
- }
- }
-
- /**
- * Removes all of this node's children, setting their parents to empty.
- * If this node has no children, this method does nothing.
- */
- public void removeAllChildren() {
- while (getNumberOfChildren() > 0) {
- removeChild(0);
- }
- }
-
- /**
- * Returns this node's first child if it exists (otherwise returns an empty Optional).
- *
- * @return the first child of this node
- */
- public Optional<T> getFirstChild() {
- return getChildAt(0);
- }
-
- /**
- * Returns this node's last child if it exists (otherwise returns an empty Optional).
- *
- * @return the last child of this node
- */
- public Optional<T> getLastChild() {
- return getChildAt(children.size() - 1);
- }
-
- /**
- * Returns true if anotherNode is a descendant of this node
- * -- if it is this node, one of this node's children, or a descendant of one of this node's children.
- * Note that a node is considered a descendant of itself.
- * <p>
- * If anotherNode is null, an exception is thrown.
- *
- * @param anotherNode node to test as descendant of this node
- * @return true if this node is an ancestor of anotherNode
- * @see #isAncestorOf
- */
- public boolean isNodeDescendant(T anotherNode) {
- Objects.requireNonNull(anotherNode);
-
- return this.isAncestorOf(anotherNode);
- }
-
- /**
- * Gets a forward-order list of this node's children.
- * <p>
- * The returned list is unmodifiable - use the add and remove methods to modify the nodes children.
- * However, changing the nodes children (for example by calling moveTo) is reflected in a change of
- * the list returned by getChildren. In other words, getChildren provides a read-only view on the children but
- * not a copy.
- *
- * @return a list of this node's children
- */
- public List<T> getChildren() {
- return Collections.unmodifiableList(children);
- }
-
- /**
- * Removes the given child from this node's child list, giving it an empty parent.
- *
- * @param child a child of this node to remove
- */
- public void removeChild(T child) {
- Objects.requireNonNull(child);
-
- children.remove(child);
- child.setParent(null);
-
- notifyAboutDescendantChange((T)this);
- }
-
- /**
- * Removes the child at the specified index from this node's children and sets that node's parent to empty.
- * <p>
- * Does nothing if the index does not point to a child.
- *
- * @param childIndex the index in this node's child array of the child to remove
- */
- public void removeChild(int childIndex) {
- Optional<T> child = getChildAt(childIndex);
- if (child.isPresent()) {
- children.remove(childIndex);
- child.get().setParent(null);
- }
-
- notifyAboutDescendantChange((T)this);
- }
-
- /**
- * Adds the node at the end the children collection. Also sets the parent of the given node to this node.
- * The given node is not allowed to already be in a tree (i.e. it has to have no parent).
- *
- * @param child the node to add
- * @return the child node
- */
- public T addChild(T child) {
- return addChild(child, children.size());
- }
-
- /**
- * Adds the node at the given position in the children collection. Also sets the parent of the given node to this node.
- * The given node is not allowed to already be in a tree (i.e. it has to have no parent).
- *
- * @param child the node to add
- * @param index the position where the node should be added
- * @return the child node
- * @throws IndexOutOfBoundsException if the index is out of range
- */
- public T addChild(T child, int index) {
- Objects.requireNonNull(child);
- if (child.getParent().isPresent()) {
- throw new UnsupportedOperationException("Cannot add a node which already has a parent, use moveTo instead");
- }
-
- child.setParent((T) this);
- children.add(index, child);
-
- notifyAboutDescendantChange((T)this);
-
- return child;
- }
-
- /**
- * Removes all children from this node and makes them a child of the specified node
- * by adding it to the specified position in the children list.
- *
- * @param target the new parent
- * @param targetIndex the position where the children should be inserted
- * @throws NullPointerException if target is null
- * @throws ArrayIndexOutOfBoundsException if targetIndex is out of bounds
- * @throws UnsupportedOperationException if target is an descendant of one of the children of this node
- */
- public void moveAllChildrenTo(T target, int targetIndex) {
- while (getNumberOfChildren() > 0) {
- getLastChild().get().moveTo(target, targetIndex);
- }
- }
-
- /**
- * Sorts the list of children according to the order induced by the specified {@link Comparator}.
- * <p>
- * All children must be mutually comparable using the specified comparator
- * (that is, {@code c.compare(e1, e2)} must not throw a {@code ClassCastException}
- * for any children {@code e1} and {@code e2} in the list).
- *
- * @param comparator the comparator used to compare the child nodes
- * @param recursive if true the whole subtree is sorted
- * @throws NullPointerException if the comparator is null
- */
- public void sortChildren(Comparator<? super T> comparator, boolean recursive) {
- Objects.requireNonNull(comparator);
-
- if (this.isLeaf()) {
- return; // nothing to sort
- }
-
- int j = getNumberOfChildren() - 1;
- int lastModified;
- while (j > 0) {
- lastModified = j + 1;
- j = -1;
- for (int i = 1; i < lastModified; ++i) {
- T child1 = getChildAt(i - 1).get();
- T child2 = getChildAt(i).get();
- if (comparator.compare(child1, child2) > 0) {
- child1.moveTo((T) this, i);
- j = i;
- }
- }
- }
- if (recursive) {
- for (T child : getChildren()) {
- child.sortChildren(comparator, true);
- }
- }
- }
-
- /**
- * Removes this node from its parent and makes it a child of the specified node
- * by adding it to the specified position in the children list.
- * In this way the whole subtree based at this node is moved to the given node.
- *
- * @param target the new parent
- * @param targetIndex the position where the children should be inserted
- * @throws NullPointerException if target is null
- * @throws ArrayIndexOutOfBoundsException if targetIndex is out of bounds
- * @throws UnsupportedOperationException if target is an descendant of this node
- */
- public void moveTo(T target, int targetIndex) {
- Objects.requireNonNull(target);
-
- // Check that the target node is not an ancestor of this node, because this would create loops in the tree
- if (this.isAncestorOf(target)) {
- throw new UnsupportedOperationException("the target cannot be a descendant of this node");
- }
-
- // Remove from previous parent
- Optional<T> oldParent = getParent();
- if (oldParent.isPresent()) {
- oldParent.get().removeChild((T) this);
- }
-
- // Add as child
- target.addChild((T) this, targetIndex);
- }
-
- /**
- * Creates a deep copy of this node and all of its children.
- *
- * @return a deep copy of the subtree
- */
- public T copySubtree() {
- T copy = copyNode();
- for (T child : getChildren()) {
- child.copySubtree().moveTo(copy);
- }
- return copy;
- }
-
- /**
- * Creates a copy of this node, completely separated from the tree (i.e. no children and no parent)
- *
- * @return a deep copy of this node
- */
- public abstract T copyNode();
-
- /**
- * The function which is invoked when something changed in the subtree.
- */
- private Consumer<T> onDescendantChanged = t -> {
- /* Do nothing */ };
-
- /**
- * Adds the given function to the list of subscribers which are notified when something changes in the subtree.
- *
- * The following events are supported (the text in parentheses specifies which node is passed as the source):
- * - addChild (new parent)
- * - removeChild (old parent)
- * - move (old parent and new parent)
- * @param subscriber function to be invoked upon a change
- */
- public void subscribeToDescendantChanged(Consumer<T> subscriber) {
- onDescendantChanged = onDescendantChanged.andThen(subscriber);
- }
-
- /**
- * Helper method which notifies all subscribers about a change in the subtree and bubbles the event to all parents.
- * @param source the node which changed
- */
- protected void notifyAboutDescendantChange(T source) {
- onDescendantChanged.accept(source);
-
- if(! isRoot()) {
- parent.notifyAboutDescendantChange(source);
- }
- }
-}
diff --git a/src/main/java/net/sf/jabref/logic/groups/UnsupportedVersionException.java b/src/main/java/net/sf/jabref/logic/groups/UnsupportedVersionException.java
deleted file mode 100644
index 429294d..0000000
--- a/src/main/java/net/sf/jabref/logic/groups/UnsupportedVersionException.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package net.sf.jabref.logic.groups;
-
-import net.sf.jabref.logic.l10n.Localization;
-
-class UnsupportedVersionException extends Exception {
-
- public UnsupportedVersionException(String groupType, int version) {
- super(Localization.lang("Unsupported version of class %0: %1", groupType, Integer.toString(version)));
- }
-}
diff --git a/src/main/java/net/sf/jabref/logic/help/HelpFile.java b/src/main/java/net/sf/jabref/logic/help/HelpFile.java
index 9d581da..2f98677 100644
--- a/src/main/java/net/sf/jabref/logic/help/HelpFile.java
+++ b/src/main/java/net/sf/jabref/logic/help/HelpFile.java
@@ -9,42 +9,42 @@ public enum HelpFile {
COMMAND_LINE(""),
//Empty because it refers to the TOC/index
CONTENTS(""),
- ENTRY_EDITOR("EntryEditorHelp"),
- STRING_EDITOR("StringEditorHelp"),
- SEARCH("SearchHelp"),
- GROUP("GroupsHelp"),
- CONTENT_SELECTOR("ContentSelectorHelp"),
- SPECIAL_FIELDS("SpecialFieldsHelp"),
+ ENTRY_EDITOR("EntryEditor"),
+ STRING_EDITOR("StringEditor"),
+ SEARCH("Search"),
+ GROUP("Groups"),
+ CONTENT_SELECTOR("ContentSelector"),
+ SPECIAL_FIELDS("SpecialFields"),
BIBTEX_KEY_PATTERN("BibtexKeyPatterns"),
- OWNER("OwnerHelp"),
- TIMESTAMP("TimeStampHelp"),
+ OWNER("Owner"),
+ TIMESTAMP("TimeStamp"),
CUSTOM_EXPORTS("CustomExports"),
CUSTOM_EXPORTS_NAME_FORMATTER("CustomExports#NameFormatter"),
CUSTOM_IMPORTS("CustomImports"),
GENERAL_FIELDS("GeneralFields"),
IMPORT_INSPECTION("ImportInspectionDialog"),
- REMOTE("RemoteHelp"),
+ REMOTE("Remote"),
JOURNAL_ABBREV("JournalAbbreviations"),
REGEX_SEARCH("ExternalFiles#RegularExpressionSearch"),
- PREVIEW("PreviewHelp"),
+ PREVIEW("Preview"),
AUTOSAVE("Autosave"),
//The help page covers both OO and LO.
OPENOFFICE_LIBREOFFICE("OpenOfficeIntegration"),
- FETCHER_ACM("ACMPortalHelp"),
- FETCHER_ADS("ADSHelp"),
- FETCHER_CITESEERX("CiteSeerHelp"),
- FETCHER_DBLP("DBLPHelp"),
- FETCHER_DIVA_TO_BIBTEX("DiVAtoBibTeXHelp"),
- FETCHER_DOAJ("DOAJHelp"),
- FETCHER_DOI_TO_BIBTEX("DOItoBibTeXHelp"),
- FETCHER_GOOGLE_SCHOLAR("GoogleScholarHelp"),
- FETCHER_GVK("GVKHelp"),
- FETCHER_IEEEXPLORE("IEEEXploreHelp"),
+ FETCHER_ACM("ACMPortal"),
+ FETCHER_ADS("ADS"),
+ FETCHER_CITESEERX("CiteSeer"),
+ FETCHER_DBLP("DBLP"),
+ FETCHER_DIVA_TO_BIBTEX("DiVAtoBibTeX"),
+ FETCHER_DOAJ("DOAJ"),
+ FETCHER_DOI_TO_BIBTEX("DOItoBibTeX"),
+ FETCHER_GOOGLE_SCHOLAR("GoogleScholar"),
+ FETCHER_GVK("GVK"),
+ FETCHER_IEEEXPLORE("IEEEXplore"),
FETCHER_INSPIRE("INSPIRE"),
- FETCHER_ISBN_TO_BIBTEX("ISBNtoBibTeXHelp"),
- FETCHER_MEDLINE("MedlineHelp"),
- FETCHER_OAI2_ARXIV("arXivHelp"),
- FETCHER_SPRINGER("SpringerHelp"),
+ FETCHER_ISBN_TO_BIBTEX("ISBNtoBibTeX"),
+ FETCHER_MEDLINE("Medline"),
+ FETCHER_OAI2_ARXIV("arXiv"),
+ FETCHER_SPRINGER("Springer"),
FETCHER_SCIENCEDIRECT(""),
FETCHER_BIBSONOMY_SCRAPER(""),
DATABASE_PROPERTIES("DatabaseProperties"),
diff --git a/src/main/java/net/sf/jabref/logic/importer/EntryBasedFetcher.java b/src/main/java/net/sf/jabref/logic/importer/EntryBasedFetcher.java
new file mode 100644
index 0000000..408be47
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/importer/EntryBasedFetcher.java
@@ -0,0 +1,21 @@
+package net.sf.jabref.logic.importer;
+
+import java.util.List;
+
+import net.sf.jabref.model.entry.BibEntry;
+
+/**
+ * Searches web resources for bibliographic information based on a {@link BibEntry}.
+ * Useful to complete an existing entry with fetched information.
+ * May return multiple search hits.
+ */
+public interface EntryBasedFetcher extends WebFetcher {
+
+ /**
+ * Looks for hits which are matched by the given {@link BibEntry}.
+ *
+ * @param entry entry to search bibliographic information for
+ * @return a list of {@link BibEntry}, which are matched by the query (may be empty)
+ */
+ List<BibEntry> performSearch(BibEntry entry) throws FetcherException;
+}
diff --git a/src/main/java/net/sf/jabref/logic/importer/EntryBasedParserFetcher.java b/src/main/java/net/sf/jabref/logic/importer/EntryBasedParserFetcher.java
new file mode 100644
index 0000000..3ba6e2c
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/importer/EntryBasedParserFetcher.java
@@ -0,0 +1,71 @@
+package net.sf.jabref.logic.importer;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.List;
+import java.util.Objects;
+
+import net.sf.jabref.model.cleanup.Formatter;
+import net.sf.jabref.model.entry.BibEntry;
+
+/**
+ * Provides a convenient interface for entry-based fetcher, which follow the usual three-step procedure:
+ * 1. Open a URL based on the entry
+ * 2. Parse the response to get a list of {@link BibEntry}
+ * 3. Post-process fetched entries
+ */
+public interface EntryBasedParserFetcher extends EntryBasedFetcher {
+
+ /**
+ * Constructs a URL based on the {@link BibEntry}.
+ * @param entry the entry to look information for
+ */
+ URL getURLForEntry(BibEntry entry) throws URISyntaxException, MalformedURLException, FetcherException;
+
+ /**
+ * Returns the parser used to convert the response to a list of {@link BibEntry}.
+ */
+ Parser getParser();
+
+ /**
+ * Performs a cleanup of the fetched entry.
+ *
+ * Only systematic errors of the fetcher should be corrected here
+ * (i.e. if information is consistently contained in the wrong field or the wrong format)
+ * but not cosmetic issues which may depend on the user's taste (for example, LateX code vs HTML in the abstract).
+ *
+ * Try to reuse existing {@link Formatter} for the cleanup. For example,
+ * {@code new FieldFormatterCleanup(FieldName.TITLE, new RemoveBracesFormatter()).cleanup(entry);}
+ *
+ * By default, no cleanup is done.
+ * @param entry the entry to be cleaned-up
+ */
+ default void doPostCleanup(BibEntry entry) {
+ // Do nothing by default
+ }
+
+ @Override
+ default List<BibEntry> performSearch(BibEntry entry) throws FetcherException {
+ Objects.requireNonNull(entry);
+
+ try (InputStream stream = new BufferedInputStream(getURLForEntry(entry).openStream())) {
+ List<BibEntry> fetchedEntries = getParser().parseEntries(stream);
+
+ // Post-cleanup
+ fetchedEntries.forEach(this::doPostCleanup);
+
+ return fetchedEntries;
+ } catch (URISyntaxException e) {
+ throw new FetcherException("Search URI is malformed", e);
+ } catch (IOException e) {
+ // TODO: Catch HTTP Response 401 errors and report that user has no rights to access resource
+ throw new FetcherException("An I/O exception occurred", e);
+ } catch (ParseException e) {
+ throw new FetcherException("An internal parser error occurred", e);
+ }
+ }
+}
diff --git a/src/main/java/net/sf/jabref/logic/importer/FetcherException.java b/src/main/java/net/sf/jabref/logic/importer/FetcherException.java
index 7bf7685..3d868d5 100644
--- a/src/main/java/net/sf/jabref/logic/importer/FetcherException.java
+++ b/src/main/java/net/sf/jabref/logic/importer/FetcherException.java
@@ -1,13 +1,19 @@
package net.sf.jabref.logic.importer;
-public class FetcherException extends Exception {
+import net.sf.jabref.JabRefException;
+public class FetcherException extends JabRefException {
- public FetcherException(String errorMessage, Exception cause) {
+
+ public FetcherException(String errorMessage, Throwable cause) {
super(errorMessage, cause);
}
public FetcherException(String errorMessage) {
super(errorMessage);
}
+
+ public FetcherException(String errorMessage, String localizedMessage, Throwable cause) {
+ super(errorMessage, localizedMessage, cause);
+ }
}
diff --git a/src/main/java/net/sf/jabref/logic/importer/FulltextFetcher.java b/src/main/java/net/sf/jabref/logic/importer/FulltextFetcher.java
index 0faa59b..ceda8b3 100644
--- a/src/main/java/net/sf/jabref/logic/importer/FulltextFetcher.java
+++ b/src/main/java/net/sf/jabref/logic/importer/FulltextFetcher.java
@@ -21,5 +21,5 @@ public interface FulltextFetcher {
* @throws NullPointerException if no BibTex entry is given
* @throws java.io.IOException
*/
- Optional<URL> findFullText(BibEntry entry) throws IOException;
+ Optional<URL> findFullText(BibEntry entry) throws IOException, FetcherException;
}
diff --git a/src/main/java/net/sf/jabref/logic/importer/FulltextFetchers.java b/src/main/java/net/sf/jabref/logic/importer/FulltextFetchers.java
index f3a5e9e..2786583 100644
--- a/src/main/java/net/sf/jabref/logic/importer/FulltextFetchers.java
+++ b/src/main/java/net/sf/jabref/logic/importer/FulltextFetchers.java
@@ -29,17 +29,17 @@ public class FulltextFetchers {
private final List<FulltextFetcher> finders = new ArrayList<>();
- public FulltextFetchers() {
+ public FulltextFetchers(ImportFormatPreferences importFormatPreferences) {
// Ordering is important, authorities first!
// Publisher
finders.add(new DoiResolution());
finders.add(new ScienceDirect());
finders.add(new SpringerLink());
finders.add(new ACS());
- finders.add(new ArXiv());
+ finders.add(new ArXiv(importFormatPreferences));
finders.add(new IEEE());
// Meta search
- finders.add(new GoogleScholar());
+ finders.add(new GoogleScholar(importFormatPreferences));
}
public FulltextFetchers(List<FulltextFetcher> fetcher) {
@@ -49,7 +49,7 @@ public class FulltextFetchers {
public Optional<URL> findFullTextPDF(BibEntry entry) {
// for accuracy, fetch DOI first but do not modify entry
BibEntry clonedEntry = (BibEntry) entry.clone();
- Optional<String> doi = clonedEntry.getFieldOptional(FieldName.DOI);
+ Optional<String> doi = clonedEntry.getField(FieldName.DOI);
if (!doi.isPresent() || !DOI.build(doi.get()).isPresent()) {
CrossRef.findDOI(clonedEntry).ifPresent(e -> clonedEntry.setField(FieldName.DOI, e.getDOI()));
@@ -62,7 +62,7 @@ public class FulltextFetchers {
if (result.isPresent() && MimeTypeDetector.isPdfContentType(result.get().toString())) {
return result;
}
- } catch (IOException e) {
+ } catch (IOException | FetcherException e) {
LOGGER.debug("Failed to find fulltext PDF at given URL", e);
}
}
diff --git a/src/main/java/net/sf/jabref/logic/importer/IdBasedFetcher.java b/src/main/java/net/sf/jabref/logic/importer/IdBasedFetcher.java
index fc71e63..de1df43 100644
--- a/src/main/java/net/sf/jabref/logic/importer/IdBasedFetcher.java
+++ b/src/main/java/net/sf/jabref/logic/importer/IdBasedFetcher.java
@@ -14,6 +14,7 @@ public interface IdBasedFetcher extends WebFetcher {
*
* @param identifier a string which uniquely identifies the item
* @return a {@link BibEntry} containing the bibliographic information (or an empty optional if no data was found)
+ * @throws FetcherException
*/
Optional<BibEntry> performSearchById(String identifier) throws FetcherException;
}
diff --git a/src/main/java/net/sf/jabref/logic/importer/IdBasedParserFetcher.java b/src/main/java/net/sf/jabref/logic/importer/IdBasedParserFetcher.java
new file mode 100644
index 0000000..ba3a83d
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/importer/IdBasedParserFetcher.java
@@ -0,0 +1,94 @@
+package net.sf.jabref.logic.importer;
+
+import java.io.BufferedInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.List;
+import java.util.Optional;
+
+import net.sf.jabref.model.cleanup.Formatter;
+import net.sf.jabref.model.entry.BibEntry;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jsoup.helper.StringUtil;
+
+/**
+ * Provides a convenient interface for ID-based fetcher, which follow the usual three-step procedure:
+ * 1. Open a URL based on the search query
+ * 2. Parse the response to get a list of {@link BibEntry}
+ * 3. Post-process fetched entries
+ */
+public interface IdBasedParserFetcher extends IdBasedFetcher {
+
+ Log LOGGER = LogFactory.getLog(IdBasedParserFetcher.class);
+
+ /**
+ * Constructs a URL based on the query.
+ * @param identifier the ID
+ */
+ URL getURLForID(String identifier) throws URISyntaxException, MalformedURLException, FetcherException;
+
+ /**
+ * Returns the parser used to convert the response to a list of {@link BibEntry}.
+ */
+ Parser getParser();
+
+ /**
+ * Performs a cleanup of the fetched entry.
+ *
+ * Only systematic errors of the fetcher should be corrected here
+ * (i.e. if information is consistently contained in the wrong field or the wrong format)
+ * but not cosmetic issues which may depend on the user's taste (for example, LateX code vs HTML in the abstract).
+ *
+ * Try to reuse existing {@link Formatter} for the cleanup. For example,
+ * {@code new FieldFormatterCleanup(FieldName.TITLE, new RemoveBracesFormatter()).cleanup(entry);}
+ *
+ * By default, no cleanup is done.
+ * @param entry the entry to be cleaned-up
+ */
+ default void doPostCleanup(BibEntry entry) {
+ // Do nothing by default
+ }
+
+ @Override
+ default Optional<BibEntry> performSearchById(String identifier) throws FetcherException {
+ if (StringUtil.isBlank(identifier)) {
+ return Optional.empty();
+ }
+
+ try (InputStream stream = new BufferedInputStream(getURLForID(identifier).openStream())) {
+ List<BibEntry> fetchedEntries = getParser().parseEntries(stream);
+
+ if (fetchedEntries.isEmpty()) {
+ return Optional.empty();
+ }
+
+ if (fetchedEntries.size() > 1) {
+ LOGGER.info("Fetcher " + getName() + "found more than one result for identifier " + identifier
+ + ". We will use the first entry.");
+ }
+
+ BibEntry entry = fetchedEntries.get(0);
+
+ // Post-cleanup
+ doPostCleanup(entry);
+
+ return Optional.of(entry);
+ } catch (URISyntaxException e) {
+ throw new FetcherException("Search URI is malformed", e);
+ } catch (FileNotFoundException e) {
+ LOGGER.debug("Id not found");
+ return Optional.empty();
+ } catch (IOException e) {
+ // TODO: Catch HTTP Response 401 errors and report that user has no rights to access resource
+ throw new FetcherException("An I/O exception occurred", e);
+ } catch (ParseException e) {
+ throw new FetcherException("An internal parser error occurred", e);
+ }
+ }
+}
diff --git a/src/main/java/net/sf/jabref/logic/importer/ImportException.java b/src/main/java/net/sf/jabref/logic/importer/ImportException.java
new file mode 100644
index 0000000..7f6ead2
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/importer/ImportException.java
@@ -0,0 +1,19 @@
+package net.sf.jabref.logic.importer;
+
+import net.sf.jabref.JabRefException;
+
+public class ImportException extends JabRefException {
+
+
+ public ImportException(String errorMessage, Exception cause) {
+ super(errorMessage, cause);
+ }
+
+ public ImportException(String errorMessage) {
+ super(errorMessage);
+ }
+
+ public ImportException(Exception cause) {
+ super(cause);
+ }
+}
diff --git a/src/main/java/net/sf/jabref/logic/importer/ImportFormatPreferences.java b/src/main/java/net/sf/jabref/logic/importer/ImportFormatPreferences.java
index 97c9deb..2fd36c1 100644
--- a/src/main/java/net/sf/jabref/logic/importer/ImportFormatPreferences.java
+++ b/src/main/java/net/sf/jabref/logic/importer/ImportFormatPreferences.java
@@ -6,37 +6,31 @@ import java.util.Set;
import net.sf.jabref.logic.bibtex.FieldContentParserPreferences;
import net.sf.jabref.logic.bibtexkeypattern.BibtexKeyPatternPreferences;
import net.sf.jabref.logic.importer.fileformat.CustomImporter;
-import net.sf.jabref.preferences.JabRefPreferences;
public class ImportFormatPreferences {
private final Set<CustomImporter> customImportList;
-
private final Charset encoding;
-
- private final String keywordSeparator;
-
+ private final Character keywordSeparator;
private final BibtexKeyPatternPreferences bibtexKeyPatternPreferences;
-
private final FieldContentParserPreferences fieldContentParserPreferences;
+ private final boolean keywordSyncEnabled;
- private final boolean useCaseKeeperOnSearch;
- private final boolean convertUnitsOnSearch;
-
-
- public ImportFormatPreferences(Set<CustomImporter> customImportList, Charset encoding,
- String keywordSeparator, BibtexKeyPatternPreferences bibtexKeyPatternPreferences,
- FieldContentParserPreferences fieldContentParserPreferences, boolean convertUnitsOnSearch,
- boolean useCaseKeeperOnSearch) {
+ public ImportFormatPreferences(Set<CustomImporter> customImportList, Charset encoding, Character keywordSeparator,
+ BibtexKeyPatternPreferences bibtexKeyPatternPreferences,
+ FieldContentParserPreferences fieldContentParserPreferences, boolean keywordSyncEnabled) {
this.customImportList = customImportList;
this.encoding = encoding;
this.keywordSeparator = keywordSeparator;
this.bibtexKeyPatternPreferences = bibtexKeyPatternPreferences;
this.fieldContentParserPreferences = fieldContentParserPreferences;
- this.convertUnitsOnSearch = convertUnitsOnSearch;
- this.useCaseKeeperOnSearch = useCaseKeeperOnSearch;
+ this.keywordSyncEnabled = keywordSyncEnabled;
}
+ /**
+ * @deprecated importer should not know about the other custom importers
+ */
+ @Deprecated
public Set<CustomImporter> getCustomImportList() {
return customImportList;
}
@@ -45,7 +39,7 @@ public class ImportFormatPreferences {
return encoding;
}
- public String getKeywordSeparator() {
+ public Character getKeywordSeparator() {
return keywordSeparator;
}
@@ -57,25 +51,16 @@ public class ImportFormatPreferences {
return fieldContentParserPreferences;
}
- public boolean isConvertUnitsOnSearch() {
- return convertUnitsOnSearch;
- }
-
- public boolean isUseCaseKeeperOnSearch() {
- return useCaseKeeperOnSearch;
- }
-
public ImportFormatPreferences withEncoding(Charset newEncoding) {
return new ImportFormatPreferences(customImportList, newEncoding, keywordSeparator, bibtexKeyPatternPreferences,
- fieldContentParserPreferences, convertUnitsOnSearch, useCaseKeeperOnSearch);
+ fieldContentParserPreferences, keywordSyncEnabled);
}
- static public ImportFormatPreferences fromPreferences(JabRefPreferences jabRefPreferences) {
- return new ImportFormatPreferences(jabRefPreferences.customImports, jabRefPreferences.getDefaultEncoding(),
- jabRefPreferences.get(JabRefPreferences.KEYWORD_SEPARATOR),
- BibtexKeyPatternPreferences.fromPreferences(jabRefPreferences),
- FieldContentParserPreferences.fromPreferences(jabRefPreferences),
- jabRefPreferences.getBoolean(JabRefPreferences.USE_UNIT_FORMATTER_ON_SEARCH),
- jabRefPreferences.getBoolean(JabRefPreferences.USE_CASE_KEEPER_ON_SEARCH));
+ /**
+ * @deprecated importer should not keyword synchronization; this is a post-import action
+ */
+ @Deprecated
+ public boolean isKeywordSyncEnabled() {
+ return keywordSyncEnabled;
}
}
diff --git a/src/main/java/net/sf/jabref/logic/importer/ImportFormatReader.java b/src/main/java/net/sf/jabref/logic/importer/ImportFormatReader.java
index d11024c..2f0b959 100644
--- a/src/main/java/net/sf/jabref/logic/importer/ImportFormatReader.java
+++ b/src/main/java/net/sf/jabref/logic/importer/ImportFormatReader.java
@@ -2,7 +2,6 @@ package net.sf.jabref.logic.importer;
import java.io.IOException;
import java.nio.file.Path;
-import java.nio.file.Paths;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
@@ -16,11 +15,11 @@ import net.sf.jabref.logic.importer.fileformat.CopacImporter;
import net.sf.jabref.logic.importer.fileformat.CustomImporter;
import net.sf.jabref.logic.importer.fileformat.EndnoteImporter;
import net.sf.jabref.logic.importer.fileformat.FreeCiteImporter;
-import net.sf.jabref.logic.importer.fileformat.ImportFormat;
import net.sf.jabref.logic.importer.fileformat.InspecImporter;
import net.sf.jabref.logic.importer.fileformat.IsiImporter;
import net.sf.jabref.logic.importer.fileformat.MedlineImporter;
import net.sf.jabref.logic.importer.fileformat.MedlinePlainImporter;
+import net.sf.jabref.logic.importer.fileformat.ModsImporter;
import net.sf.jabref.logic.importer.fileformat.MsBibImporter;
import net.sf.jabref.logic.importer.fileformat.OvidImporter;
import net.sf.jabref.logic.importer.fileformat.PdfContentImporter;
@@ -28,24 +27,21 @@ import net.sf.jabref.logic.importer.fileformat.PdfXmpImporter;
import net.sf.jabref.logic.importer.fileformat.RepecNepImporter;
import net.sf.jabref.logic.importer.fileformat.RisImporter;
import net.sf.jabref.logic.importer.fileformat.SilverPlatterImporter;
-import net.sf.jabref.logic.util.strings.StringUtil;
+import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.xmp.XMPPreferences;
import net.sf.jabref.model.database.BibDatabases;
import net.sf.jabref.model.entry.BibEntry;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
+import net.sf.jabref.model.strings.StringUtil;
public class ImportFormatReader {
- private static final Log LOGGER = LogFactory.getLog(ImportFormatReader.class);
public static final String BIBTEX_FORMAT = "BibTeX";
/**
* All import formats.
- * Sorted accordingly to {@link ImportFormat#compareTo}, which defaults to alphabetically by the name
+ * Sorted accordingly to {@link Importer#compareTo}, which defaults to alphabetically by the name
*/
- private final SortedSet<ImportFormat> formats = new TreeSet<>();
+ private final SortedSet<Importer> formats = new TreeSet<>();
private ImportFormatPreferences importFormatPreferences;
@@ -65,6 +61,7 @@ public class ImportFormatReader {
formats.add(new IsiImporter());
formats.add(new MedlineImporter());
formats.add(new MedlinePlainImporter());
+ formats.add(new ModsImporter());
formats.add(new MsBibImporter());
formats.add(new OvidImporter());
formats.add(new PdfContentImporter(importFormatPreferences));
@@ -73,17 +70,9 @@ public class ImportFormatReader {
formats.add(new RisImporter());
formats.add(new SilverPlatterImporter());
- /**
- * Get custom import formats
- */
+ // Get custom import formats
for (CustomImporter importer : importFormatPreferences.getCustomImportList()) {
- try {
- ImportFormat imFo = importer.getInstance();
- formats.add(imFo);
- } catch (IOException | ClassNotFoundException | InstantiationException | IllegalAccessException e) {
- LOGGER.error("Could not instantiate " + importer.getName()
- + " importer, will ignore it. Please check if the class is still available.", e);
- }
+ formats.add(importer);
}
}
@@ -96,8 +85,8 @@ public class ImportFormatReader {
* @param cliId CLI-Id
* @return Import Format or <code>null</code> if none matches
*/
- private Optional<ImportFormat> getByCliId(String cliId) {
- for (ImportFormat format : formats) {
+ private Optional<Importer> getByCliId(String cliId) {
+ for (Importer format : formats) {
if (format.getId().equals(cliId)) {
return Optional.of(format);
}
@@ -105,15 +94,18 @@ public class ImportFormatReader {
return Optional.empty();
}
- public ParserResult importFromFile(String format, Path file)
- throws IOException {
- Optional<ImportFormat> importer = getByCliId(format);
+ public ParserResult importFromFile(String format, Path file) throws ImportException {
+ Optional<Importer> importer = getByCliId(format);
if (!importer.isPresent()) {
- throw new IllegalArgumentException("Unknown import format: " + format);
+ throw new ImportException(Localization.lang("Unknown import format") + ": " + format);
}
- return importer.get().importDatabase(file, importFormatPreferences.getEncoding());
+ try {
+ return importer.get().importDatabase(file, importFormatPreferences.getEncoding());
+ } catch (IOException e) {
+ throw new ImportException(e);
+ }
}
/**
@@ -125,7 +117,7 @@ public class ImportFormatReader {
*
* @return all custom importers, elements are of type InputFormat
*/
- public SortedSet<ImportFormat> getImportFormats() {
+ public SortedSet<Importer> getImportFormats() {
return this.formats;
}
@@ -139,10 +131,10 @@ public class ImportFormatReader {
public String getImportFormatList() {
StringBuilder sb = new StringBuilder();
- for (ImportFormat imFo : formats) {
- int pad = Math.max(0, 14 - imFo.getFormatName().length());
+ for (Importer imFo : formats) {
+ int pad = Math.max(0, 14 - imFo.getName().length());
sb.append(" ");
- sb.append(imFo.getFormatName());
+ sb.append(imFo.getName());
sb.append(StringUtil.repeatSpaces(pad));
@@ -166,19 +158,15 @@ public class ImportFormatReader {
}
}
- public UnknownFormatImport importUnknownFormat(String filename) {
- return importUnknownFormat(Paths.get(filename));
- }
-
/**
* Tries to import a file by iterating through the available import filters,
* and keeping the import that seems most promising.
* <p/>
* If all fails this method attempts to read this file as bibtex.
*
- * @throws IOException
+ * @throws ImportException if the import fails (for example, if no suitable importer is found)
*/
- public UnknownFormatImport importUnknownFormat(Path filePath) {
+ public UnknownFormatImport importUnknownFormat(Path filePath) throws ImportException {
Objects.requireNonNull(filePath);
// First, see if it is a BibTeX file:
@@ -198,7 +186,7 @@ public class ImportFormatReader {
String bestFormatName = null;
// Cycle through all importers:
- for (ImportFormat imFo : getImportFormats()) {
+ for (Importer imFo : getImportFormats()) {
try {
if (!imFo.isRecognizedFormat(filePath, importFormatPreferences.getEncoding())) {
continue;
@@ -213,7 +201,7 @@ public class ImportFormatReader {
if (entryCount > bestResultCount) {
bestResult = entries;
bestResultCount = bestResult.size();
- bestFormatName = imFo.getFormatName();
+ bestFormatName = imFo.getName();
}
} catch (IOException ex) {
// The import did not succeed. Go on.
@@ -223,9 +211,10 @@ public class ImportFormatReader {
if (bestResult != null) {
// we found something
ParserResult parserResult = new ParserResult(bestResult);
+ parserResult.setFile(filePath.toFile());
return new UnknownFormatImport(bestFormatName, parserResult);
}
- return null;
+ throw new ImportException(Localization.lang("Could not find a suitable import format."));
}
}
diff --git a/src/main/java/net/sf/jabref/logic/importer/Importer.java b/src/main/java/net/sf/jabref/logic/importer/Importer.java
new file mode 100644
index 0000000..a4129c8
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/importer/Importer.java
@@ -0,0 +1,169 @@
+package net.sf.jabref.logic.importer;
+
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Path;
+import java.util.Objects;
+
+import net.sf.jabref.logic.util.FileExtensions;
+
+/**
+ * Role of an importer for JabRef.
+ */
+public abstract class Importer implements Comparable<Importer> {
+
+ /**
+ * Using this when I have no database open or when I read
+ * non bibtex file formats (used by the ImportFormatReader.java)
+ *
+ * TODO: Is this field really needed or would calling IdGenerator.next() suffice?
+ */
+ public static final String DEFAULT_BIBTEXENTRY_ID = "__ID";
+
+ /**
+ * Check whether the source is in the correct format for this importer.
+ *
+ * The effect of this method is primarily to avoid unnecessary processing of
+ * files when searching for a suitable import format. If this method returns
+ * false, the import routine will move on to the next import format.
+ *
+ * Thus the correct behaviour is to return false if it is certain that the file is
+ * not of the suitable type, and true otherwise. Returning true is the safe choice if not certain.
+ */
+ public abstract boolean isRecognizedFormat(BufferedReader input) throws IOException;
+
+ public boolean isRecognizedFormat(Path filePath, Charset encoding) throws IOException {
+ try (BufferedReader bufferedReader = getReader(filePath, encoding)) {
+ return isRecognizedFormat(bufferedReader);
+ }
+ }
+
+ /**
+ * Parse the database in the source.
+ *
+ * This method can be called in two different contexts - either when importing in
+ * a specified format, or when importing in unknown format. In the latter case,
+ * JabRef cycles through all available import formats. No error messages or feedback
+ * is displayed from individual import formats in this case.
+ *
+ * If importing in a specified format and an empty database is returned, JabRef reports
+ * that no entries were found.
+ *
+ * This method should never return null.
+ *
+ * @param input the input to read from
+ */
+ public abstract ParserResult importDatabase(BufferedReader input) throws IOException ;
+
+ /**
+ * Parse the database in the specified file.
+ *
+ * Importer having the facilities to detect the correct encoding of a file should overwrite this method,
+ * determine the encoding and then call {@link #importDatabase(BufferedReader)}.
+ *
+ * @param filePath the path to the file which should be imported
+ * @param encoding the encoding used to decode the file
+ */
+ public ParserResult importDatabase(Path filePath, Charset encoding) throws IOException {
+ try (BufferedReader bufferedReader = getReader(filePath, encoding)) {
+ ParserResult parserResult = importDatabase(bufferedReader);
+ parserResult.getMetaData().setEncoding(encoding);
+ parserResult.setFile(filePath.toFile());
+ return parserResult;
+ }
+ }
+
+ protected static BufferedReader getUTF8Reader(Path filePath) throws IOException {
+ return getReader(filePath, StandardCharsets.UTF_8);
+ }
+
+ protected static BufferedReader getUTF16Reader(Path filePath) throws IOException {
+ return getReader(filePath, StandardCharsets.UTF_16);
+ }
+
+ public static BufferedReader getReader(Path filePath, Charset encoding)
+ throws IOException {
+ InputStream stream = new FileInputStream(filePath.toFile());
+ return new BufferedReader(new InputStreamReader(stream, encoding));
+ }
+
+ /**
+ * Returns the name of this import format.
+ *
+ * <p>The name must be unique.</p>
+ *
+ * @return format name, must be unique and not <code>null</code>
+ */
+ public abstract String getName();
+
+
+ /**
+ * Returns the file extensions that this importer can read
+ * @return {@link FileExtensions} correspoding to the importer
+ */
+ public abstract FileExtensions getExtensions();
+
+ /**
+ * Returns a one-word ID which identifies this import format.
+ * Used for example, to identify the format when used from the command line.
+ *
+ * @return ID, must be unique and not <code>null</code>
+ */
+ public String getId() {
+ String id = getName();
+ StringBuilder result = new StringBuilder(id.length());
+ for (int i = 0; i < id.length(); i++) {
+ char c = id.charAt(i);
+ if (Character.isLetterOrDigit(c)) {
+ result.append(Character.toLowerCase(c));
+ }
+ }
+ return result.toString();
+ }
+
+ /**
+ * Returns the description of the import format.
+ *
+ * The description should specify
+ * <ul><li>
+ * what kind of entries from what sources and based on what specification it is able to import
+ * </li><li>
+ * by what criteria it {@link #isRecognizedFormat(BufferedReader) recognizes} an import format
+ * </li></ul>
+ *
+ * @return description of the import format
+ */
+ public abstract String getDescription();
+
+ @Override
+ public int hashCode() {
+ return getName().hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if(!(obj instanceof Importer)) {
+ return false;
+ }
+ Importer other = (Importer)obj;
+ return Objects.equals(this.getName(), other.getName());
+ }
+
+ @Override
+ public String toString() {
+ return getName();
+ }
+
+ @Override
+ public int compareTo(Importer o) {
+ return getName().compareTo(o.getName());
+ }
+}
diff --git a/src/main/java/net/sf/jabref/logic/importer/OpenDatabase.java b/src/main/java/net/sf/jabref/logic/importer/OpenDatabase.java
index fb33165..b8a885d 100644
--- a/src/main/java/net/sf/jabref/logic/importer/OpenDatabase.java
+++ b/src/main/java/net/sf/jabref/logic/importer/OpenDatabase.java
@@ -5,54 +5,35 @@ import java.io.IOException;
import net.sf.jabref.logic.importer.fileformat.BibtexImporter;
import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.logic.util.io.AutoSaveUtil;
+import net.sf.jabref.logic.specialfields.SpecialFieldsUtils;
import net.sf.jabref.logic.util.io.FileBasedLock;
import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.specialfields.SpecialFieldsUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class OpenDatabase {
-
public static final Log LOGGER = LogFactory.getLog(OpenDatabase.class);
-
/**
- * Load database (bib-file) or, if there exists, a newer autosave version, unless the flag is set to ignore the autosave
+ * Load database (bib-file)
*
* @param name Name of the BIB-file to open
- * @param ignoreAutosave true if autosave version of the file should be ignored
* @return ParserResult which never is null
*/
-
- public static ParserResult loadDatabaseOrAutoSave(String name, boolean ignoreAutosave,
- ImportFormatPreferences importFormatPreferences) {
- // String in OpenDatabaseAction.java
- LOGGER.info("Opening: " + name);
+ public static ParserResult loadDatabase(String name, ImportFormatPreferences importFormatPreferences) {
File file = new File(name);
+ LOGGER.info("Opening: " + name);
+
if (!file.exists()) {
ParserResult pr = new ParserResult(null, null, null);
pr.setFile(file);
pr.setInvalid(true);
LOGGER.error(Localization.lang("Error") + ": " + Localization.lang("File not found"));
return pr;
-
}
- try {
-
- if (!ignoreAutosave) {
- boolean autoSaveFound = AutoSaveUtil.newerAutoSaveExists(file);
- if (autoSaveFound) {
- // We have found a newer autosave. Make a note of this, so it can be
- // handled after startup:
- ParserResult postp = new ParserResult(null, null, null);
- postp.setPostponedAutosaveFound(true);
- postp.setFile(file);
- return postp;
- }
- }
+ try {
if (!FileBasedLock.waitForFileLock(file.toPath())) {
LOGGER.error(Localization.lang("Error opening file") + " '" + name + "'. "
+ "File is locked by another JabRef instance.");
@@ -72,10 +53,9 @@ public class OpenDatabase {
pr.setFile(file);
pr.setInvalid(true);
pr.setErrorMessage(ex.getMessage());
- LOGGER.info("Problem opening .bib-file", ex);
+ LOGGER.error("Problem opening .bib-file", ex);
return pr;
}
-
}
/**
@@ -83,18 +63,16 @@ public class OpenDatabase {
*/
public static ParserResult loadDatabase(File fileToOpen, ImportFormatPreferences importFormatPreferences)
throws IOException {
- // Open and parse file
ParserResult result = new BibtexImporter(importFormatPreferences).importDatabase(fileToOpen.toPath(),
importFormatPreferences.getEncoding());
- if (SpecialFieldsUtils.keywordSyncEnabled()) {
+ if (importFormatPreferences.isKeywordSyncEnabled()) {
for (BibEntry entry : result.getDatabase().getEntries()) {
- SpecialFieldsUtils.syncSpecialFieldsFromKeywords(entry);
+ SpecialFieldsUtils.syncSpecialFieldsFromKeywords(entry, importFormatPreferences.getKeywordSeparator());
}
LOGGER.debug("Synchronized special fields based on keywords");
}
return result;
}
-
}
diff --git a/src/main/java/net/sf/jabref/logic/importer/ParseException.java b/src/main/java/net/sf/jabref/logic/importer/ParseException.java
new file mode 100644
index 0000000..c3ee1b6
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/importer/ParseException.java
@@ -0,0 +1,16 @@
+package net.sf.jabref.logic.importer;
+
+public class ParseException extends Exception {
+
+ public ParseException(Throwable cause) {
+ super(cause);
+ }
+
+ public ParseException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public ParseException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/net/sf/jabref/logic/importer/Parser.java b/src/main/java/net/sf/jabref/logic/importer/Parser.java
new file mode 100644
index 0000000..049f1a3
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/importer/Parser.java
@@ -0,0 +1,14 @@
+package net.sf.jabref.logic.importer;
+
+import java.io.InputStream;
+import java.util.List;
+
+import net.sf.jabref.model.entry.BibEntry;
+
+/**
+ * A parser converts an {@link InputStream} into a list of {@link BibEntry}.
+ */
+public interface Parser {
+
+ List<BibEntry> parseEntries(InputStream inputStream) throws ParseException;
+}
diff --git a/src/main/java/net/sf/jabref/logic/importer/ParserResult.java b/src/main/java/net/sf/jabref/logic/importer/ParserResult.java
index 1a3bf98..d8edd7f 100644
--- a/src/main/java/net/sf/jabref/logic/importer/ParserResult.java
+++ b/src/main/java/net/sf/jabref/logic/importer/ParserResult.java
@@ -7,14 +7,15 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Optional;
-import net.sf.jabref.BibDatabaseContext;
-import net.sf.jabref.MetaData;
import net.sf.jabref.model.database.BibDatabase;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.database.BibDatabases;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.EntryType;
+import net.sf.jabref.model.metadata.MetaData;
public class ParserResult {
@@ -22,6 +23,7 @@ public class ParserResult {
private final BibDatabase base;
private MetaData metaData;
private final Map<String, EntryType> entryTypes;
+ private BibDatabaseContext bibDatabaseContext;
private File file;
private final List<String> warnings = new ArrayList<>();
@@ -29,7 +31,6 @@ public class ParserResult {
private String errorMessage;
- private boolean postponedAutosaveFound;
private boolean invalid;
private boolean toOpenTab;
@@ -49,6 +50,9 @@ public class ParserResult {
this.base = base;
this.metaData = metaData;
this.entryTypes = entryTypes;
+ if (Objects.nonNull(base) && Objects.nonNull(metaData)) {
+ this.bibDatabaseContext = new BibDatabaseContext(base, metaData, file);
+ }
}
public static ParserResult fromErrorMessage(String message) {
@@ -142,14 +146,6 @@ public class ParserResult {
return duplicateKeys;
}
- public boolean isPostponedAutosaveFound() {
- return postponedAutosaveFound;
- }
-
- public void setPostponedAutosaveFound(boolean postponedAutosaveFound) {
- this.postponedAutosaveFound = postponedAutosaveFound;
- }
-
public boolean isInvalid() {
return invalid;
}
@@ -167,7 +163,19 @@ public class ParserResult {
}
public BibDatabaseContext getDatabaseContext() {
- return new BibDatabaseContext(base, metaData, file);
+ if (this.bibDatabaseContext == null) {
+ this.bibDatabaseContext = new BibDatabaseContext(base, metaData, file);
+ }
+ return this.bibDatabaseContext;
+ }
+
+ public void setDatabaseContext(BibDatabaseContext bibDatabaseContext) {
+ Objects.requireNonNull(bibDatabaseContext);
+ this.bibDatabaseContext = bibDatabaseContext;
+ }
+
+ public boolean hasDatabaseContext() {
+ return Objects.nonNull(this.bibDatabaseContext);
}
public boolean isNullResult() {
diff --git a/src/main/java/net/sf/jabref/logic/importer/SearchBasedParserFetcher.java b/src/main/java/net/sf/jabref/logic/importer/SearchBasedParserFetcher.java
new file mode 100644
index 0000000..ed49f48
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/importer/SearchBasedParserFetcher.java
@@ -0,0 +1,75 @@
+package net.sf.jabref.logic.importer;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.Collections;
+import java.util.List;
+
+import net.sf.jabref.model.cleanup.Formatter;
+import net.sf.jabref.model.entry.BibEntry;
+
+import org.jsoup.helper.StringUtil;
+
+/**
+ * Provides a convenient interface for search-based fetcher, which follow the usual three-step procedure:
+ * 1. Open a URL based on the search query
+ * 2. Parse the response to get a list of {@link BibEntry}
+ * 3. Post-process fetched entries
+ */
+public interface SearchBasedParserFetcher extends SearchBasedFetcher {
+
+ /**
+ * Constructs a URL based on the query.
+ * @param query the search query
+ */
+ URL getURLForQuery(String query) throws URISyntaxException, MalformedURLException, FetcherException;
+
+ /**
+ * Returns the parser used to convert the response to a list of {@link BibEntry}.
+ */
+ Parser getParser();
+
+ /**
+ * Performs a cleanup of the fetched entry.
+ *
+ * Only systematic errors of the fetcher should be corrected here
+ * (i.e. if information is consistently contained in the wrong field or the wrong format)
+ * but not cosmetic issues which may depend on the user's taste (for example, LateX code vs HTML in the abstract).
+ *
+ * Try to reuse existing {@link Formatter} for the cleanup. For example,
+ * {@code new FieldFormatterCleanup(FieldName.TITLE, new RemoveBracesFormatter()).cleanup(entry);}
+ *
+ * By default, no cleanup is done.
+ * @param entry the entry to be cleaned-up
+ */
+ default void doPostCleanup(BibEntry entry) {
+ // Do nothing by default
+ }
+
+ @Override
+ default List<BibEntry> performSearch(String query) throws FetcherException {
+ if (StringUtil.isBlank(query)) {
+ return Collections.emptyList();
+ }
+
+ try (InputStream stream = new BufferedInputStream(getURLForQuery(query).openStream())) {
+ List<BibEntry> fetchedEntries = getParser().parseEntries(stream);
+
+ // Post-cleanup
+ fetchedEntries.forEach(this::doPostCleanup);
+
+ return fetchedEntries;
+ } catch (URISyntaxException e) {
+ throw new FetcherException("Search URI is malformed", e);
+ } catch (IOException e) {
+ // TODO: Catch HTTP Response 401 errors and report that user has no rights to access resource
+ throw new FetcherException("An I/O exception occurred", e);
+ } catch (ParseException e) {
+ throw new FetcherException("An internal parser error occurred", e);
+ }
+ }
+}
diff --git a/src/main/java/net/sf/jabref/logic/importer/WebFetcher.java b/src/main/java/net/sf/jabref/logic/importer/WebFetcher.java
index 1938918..0122373 100644
--- a/src/main/java/net/sf/jabref/logic/importer/WebFetcher.java
+++ b/src/main/java/net/sf/jabref/logic/importer/WebFetcher.java
@@ -20,5 +20,7 @@ public interface WebFetcher {
*
* @return the {@link HelpFile} enum constant for the help page
*/
- HelpFile getHelpPage();
+ default HelpFile getHelpPage() {
+ return null; // no help page by default
+ }
}
diff --git a/src/main/java/net/sf/jabref/logic/importer/WebFetchers.java b/src/main/java/net/sf/jabref/logic/importer/WebFetchers.java
new file mode 100644
index 0000000..4495e86
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/importer/WebFetchers.java
@@ -0,0 +1,29 @@
+package net.sf.jabref.logic.importer;
+
+import java.util.Optional;
+
+import net.sf.jabref.logic.importer.fetcher.ArXiv;
+import net.sf.jabref.logic.importer.fetcher.DoiFetcher;
+import net.sf.jabref.logic.importer.fetcher.IsbnFetcher;
+import net.sf.jabref.model.entry.FieldName;
+
+public class WebFetchers {
+
+ public static Optional<IdBasedFetcher> getIdBasedFetcherForField(String field, ImportFormatPreferences preferences) {
+ IdBasedFetcher fetcher;
+ switch (field) {
+ case FieldName.DOI:
+ fetcher = new DoiFetcher(preferences);
+ break;
+ case FieldName.ISBN:
+ fetcher = new IsbnFetcher(preferences);
+ break;
+ case FieldName.EPRINT:
+ fetcher = new ArXiv(preferences);
+ break;
+ default:
+ return Optional.empty();
+ }
+ return Optional.of(fetcher);
+ }
+}
diff --git a/src/main/java/net/sf/jabref/logic/importer/fetcher/ACS.java b/src/main/java/net/sf/jabref/logic/importer/fetcher/ACS.java
index 9c6db43..aabba6f 100644
--- a/src/main/java/net/sf/jabref/logic/importer/fetcher/ACS.java
+++ b/src/main/java/net/sf/jabref/logic/importer/fetcher/ACS.java
@@ -40,7 +40,7 @@ public class ACS implements FulltextFetcher {
Optional<URL> pdfLink = Optional.empty();
// DOI search
- Optional<DOI> doi = entry.getFieldOptional(FieldName.DOI).flatMap(DOI::build);
+ Optional<DOI> doi = entry.getField(FieldName.DOI).flatMap(DOI::build);
if(doi.isPresent()) {
String source = String.format(SOURCE, doi.get().getDOI());
diff --git a/src/main/java/net/sf/jabref/logic/importer/fetcher/ArXiv.java b/src/main/java/net/sf/jabref/logic/importer/fetcher/ArXiv.java
index db9ede7..f50584c 100644
--- a/src/main/java/net/sf/jabref/logic/importer/fetcher/ArXiv.java
+++ b/src/main/java/net/sf/jabref/logic/importer/fetcher/ArXiv.java
@@ -21,18 +21,18 @@ import net.sf.jabref.logic.help.HelpFile;
import net.sf.jabref.logic.importer.FetcherException;
import net.sf.jabref.logic.importer.FulltextFetcher;
import net.sf.jabref.logic.importer.IdBasedFetcher;
+import net.sf.jabref.logic.importer.ImportFormatPreferences;
import net.sf.jabref.logic.importer.SearchBasedFetcher;
import net.sf.jabref.logic.importer.util.OAI2Handler;
import net.sf.jabref.logic.util.DOI;
import net.sf.jabref.logic.util.io.XMLUtil;
-import net.sf.jabref.logic.util.strings.StringUtil;
import net.sf.jabref.model.database.BibDatabaseMode;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.BibtexEntryTypes;
import net.sf.jabref.model.entry.FieldName;
import net.sf.jabref.model.entry.ParsedFileField;
+import net.sf.jabref.model.strings.StringUtil;
-import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.client.utils.URIBuilder;
@@ -52,17 +52,21 @@ import org.xml.sax.SAXException;
* <a herf="https://gitlab.c3sl.ufpr.br/portalmec/dspace-portalmec/blob/aa209d15082a9870f9daac42c78a35490ce77b52/dspace-api/src/main/java/org/dspace/submit/lookup/ArXivService.java">dspace-portalmec</a>
*/
public class ArXiv implements FulltextFetcher, SearchBasedFetcher, IdBasedFetcher {
-
private static final Log LOGGER = LogFactory.getLog(ArXiv.class);
+
private static final String API_URL = "http://export.arxiv.org/api/query";
+ private final ImportFormatPreferences importFormatPreferences;
+ public ArXiv(ImportFormatPreferences importFormatPreferences) {
+ this.importFormatPreferences = importFormatPreferences;
+ }
@Override
public Optional<URL> findFullText(BibEntry entry) throws IOException {
Objects.requireNonNull(entry);
// 1. Eprint
- Optional<String> identifier = entry.getFieldOptional(FieldName.EPRINT);
+ Optional<String> identifier = entry.getField(FieldName.EPRINT);
if (StringUtil.isNotBlank(identifier)) {
try {
// Get pdf of entry with the specified id
@@ -77,7 +81,7 @@ public class ArXiv implements FulltextFetcher, SearchBasedFetcher, IdBasedFetche
}
// 2. DOI
- Optional<DOI> doi = entry.getFieldOptional(FieldName.DOI).flatMap(DOI::build);
+ Optional<DOI> doi = entry.getField(FieldName.DOI).flatMap(DOI::build);
if (doi.isPresent()) {
String doiString = doi.get().getDOI();
// Search for an entry in the ArXiv which is linked to the doi
@@ -149,11 +153,11 @@ public class ArXiv implements FulltextFetcher, SearchBasedFetcher, IdBasedFetche
try {
URIBuilder uriBuilder = new URIBuilder(API_URL);
// The arXiv API has problems with accents, so we remove them (i.e. Fréchet -> Frechet)
- if (StringUtils.isNotBlank(searchQuery)) {
- uriBuilder.addParameter("search_query", StringUtils.stripAccents(searchQuery));
+ if (StringUtil.isNotBlank(searchQuery)) {
+ uriBuilder.addParameter("search_query", StringUtil.stripAccents(searchQuery));
}
if (!ids.isEmpty()) {
- uriBuilder.addParameter("id_list", StringUtils.join(ids, ','));
+ uriBuilder.addParameter("id_list", String.join(",", ids));
}
uriBuilder.addParameter("start", String.valueOf(start));
uriBuilder.addParameter("max_results", String.valueOf(maxResults));
@@ -209,12 +213,14 @@ public class ArXiv implements FulltextFetcher, SearchBasedFetcher, IdBasedFetche
@Override
public List<BibEntry> performSearch(String query) throws FetcherException {
- return searchForEntries(query).stream().map(ArXivEntry::toBibEntry).collect(Collectors.toList());
+ return searchForEntries(query).stream().map(
+ (arXivEntry) -> arXivEntry.toBibEntry(importFormatPreferences.getKeywordSeparator())).collect(Collectors.toList());
}
@Override
public Optional<BibEntry> performSearchById(String identifier) throws FetcherException {
- return searchForEntryById(identifier).map(ArXivEntry::toBibEntry);
+ return searchForEntryById(identifier).map(
+ (arXivEntry) -> arXivEntry.toBibEntry(importFormatPreferences.getKeywordSeparator()));
}
@@ -327,12 +333,12 @@ public class ArXiv implements FulltextFetcher, SearchBasedFetcher, IdBasedFetche
});
}
- public BibEntry toBibEntry() {
+ public BibEntry toBibEntry(Character keywordDelimiter) {
BibEntry bibEntry = new BibEntry();
bibEntry.setType(BibtexEntryTypes.ARTICLE);
bibEntry.setField(FieldName.EPRINTTYPE, "arXiv");
- bibEntry.setField(FieldName.AUTHOR, StringUtils.join(authorNames, " and "));
- bibEntry.addKeywords(categories, ", "); // TODO: Should use separator value from preferences
+ bibEntry.setField(FieldName.AUTHOR, String.join(" and ", authorNames));
+ bibEntry.addKeywords(categories, keywordDelimiter);
getId().ifPresent(id -> bibEntry.setField(FieldName.EPRINT, id));
title.ifPresent(titleContent -> bibEntry.setField(FieldName.TITLE, titleContent));
doi.ifPresent(doiContent -> bibEntry.setField(FieldName.DOI, doiContent));
diff --git a/src/main/java/net/sf/jabref/logic/importer/fetcher/AstrophysicsDataSystem.java b/src/main/java/net/sf/jabref/logic/importer/fetcher/AstrophysicsDataSystem.java
new file mode 100644
index 0000000..e25f6d5
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/importer/fetcher/AstrophysicsDataSystem.java
@@ -0,0 +1,160 @@
+package net.sf.jabref.logic.importer.fetcher;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+import net.sf.jabref.logic.formatter.bibtexfields.ClearFormatter;
+import net.sf.jabref.logic.formatter.bibtexfields.NormalizeNamesFormatter;
+import net.sf.jabref.logic.formatter.bibtexfields.RemoveBracesFormatter;
+import net.sf.jabref.logic.help.HelpFile;
+import net.sf.jabref.logic.importer.EntryBasedParserFetcher;
+import net.sf.jabref.logic.importer.FetcherException;
+import net.sf.jabref.logic.importer.IdBasedParserFetcher;
+import net.sf.jabref.logic.importer.ImportFormatPreferences;
+import net.sf.jabref.logic.importer.ParseException;
+import net.sf.jabref.logic.importer.Parser;
+import net.sf.jabref.logic.importer.SearchBasedParserFetcher;
+import net.sf.jabref.logic.importer.fileformat.BibtexParser;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.cleanup.FieldFormatterCleanup;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldName;
+
+import org.apache.http.client.utils.URIBuilder;
+import org.jsoup.helper.StringUtil;
+
+/**
+ * Fetches data from the SAO/NASA Astrophysics Data System (http://www.adsabs.harvard.edu/)
+ *
+ * Search query-based: http://adsabs.harvard.edu/basic_search.html
+ * Entry -based: http://adsabs.harvard.edu/abstract_service.html
+ *
+ * There is also a new API (https://github.com/adsabs/adsabs-dev-api) but it returns JSON
+ * (or at least needs multiple calls to get BibTeX, status: September 2016)
+ */
+public class AstrophysicsDataSystem implements IdBasedParserFetcher, SearchBasedParserFetcher, EntryBasedParserFetcher {
+
+ private static String API_QUERY_URL = "http://adsabs.harvard.edu/cgi-bin/nph-basic_connect";
+ private static String API_ENTRY_URL = "http://adsabs.harvard.edu/cgi-bin/nph-abs_connect";
+ private static String API_DOI_URL = "http://adsabs.harvard.edu/doi/";
+
+ private final String patternRemoveDOI = "^(doi:|DOI:)";
+ private final ImportFormatPreferences preferences;
+
+ public AstrophysicsDataSystem(ImportFormatPreferences preferences) {
+ this.preferences = Objects.requireNonNull(preferences);
+ }
+
+ @Override
+ public String getName() {
+ return "SAO/NASA Astrophysics Data System";
+ }
+
+ private URIBuilder getBaseUrl(String apiUrl) throws URISyntaxException {
+ URIBuilder uriBuilder = new URIBuilder(apiUrl);
+ uriBuilder.addParameter("data_type", "BIBTEXPLUS");
+ uriBuilder.addParameter("start_nr", String.valueOf(1));
+ uriBuilder.addParameter("nr_to_return", String.valueOf(200));
+ return uriBuilder;
+ }
+
+ @Override
+ public URL getURLForQuery(String query) throws URISyntaxException, MalformedURLException, FetcherException {
+ URIBuilder uriBuilder = getBaseUrl(API_QUERY_URL);
+ uriBuilder.addParameter("qsearch", query);
+ return uriBuilder.build().toURL();
+ }
+
+ @Override
+ public URL getURLForEntry(BibEntry entry) throws URISyntaxException, MalformedURLException, FetcherException {
+ URIBuilder uriBuilder = getBaseUrl(API_ENTRY_URL);
+
+ // Search astronomy + physics + arXiv db
+ uriBuilder.addParameter("db_key", "AST");
+ uriBuilder.addParameter("db_key", "PHY");
+ uriBuilder.addParameter("db_key", "PRE");
+
+ // Add title search
+ entry.getFieldOrAlias(FieldName.TITLE).ifPresent(title -> {
+ uriBuilder.addParameter("ttl_logic", "OR");
+ uriBuilder.addParameter("title", title);
+ uriBuilder.addParameter("ttl_syn", "YES"); // Synonym replacement
+ uriBuilder.addParameter("ttl_wt", "0.3"); // Weight
+ uriBuilder.addParameter("ttl_wgt", "YES"); // Consider Weight
+ });
+
+ // Add author search
+ entry.getFieldOrAlias(FieldName.AUTHOR).ifPresent(author -> {
+ uriBuilder.addParameter("aut_logic", "OR");
+ uriBuilder.addParameter("author", author);
+ uriBuilder.addParameter("aut_syn", "YES"); // Synonym replacement
+ uriBuilder.addParameter("aut_wt", "1.0"); // Weight
+ uriBuilder.addParameter("aut_wgt", "YES"); // Consider weight
+ });
+
+ return uriBuilder.build().toURL();
+ }
+
+ @Override
+ public URL getURLForID(String identifier) throws URISyntaxException, MalformedURLException, FetcherException {
+ String key = identifier.replaceAll(patternRemoveDOI, "");
+ URIBuilder uriBuilder = new URIBuilder(API_DOI_URL + key);
+ uriBuilder.addParameter("data_type", "BIBTEXPLUS");
+ return uriBuilder.build().toURL();
+ }
+
+ @Override
+ public HelpFile getHelpPage() {
+ return HelpFile.FETCHER_ADS;
+ }
+
+ @Override
+ public Parser getParser() {
+ return new BibtexParser(preferences);
+ }
+
+ @Override
+ public List<BibEntry> performSearch(String query) throws FetcherException {
+ if (StringUtil.isBlank(query)) {
+ return Collections.emptyList();
+ }
+
+ try {
+ URLConnection connection = getURLForQuery(query).openConnection();
+ connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 5.1; rv:31.0) Gecko/20100101 Firefox/31.0");
+ try(InputStream stream = connection.getInputStream()) {
+ List<BibEntry> fetchedEntries = getParser().parseEntries(stream);
+
+ // Post-cleanup
+ fetchedEntries.forEach(this::doPostCleanup);
+ return fetchedEntries;
+ } catch (IOException e) {
+ throw new FetcherException("An I/O exception occurred", e);
+ }
+ } catch (URISyntaxException | MalformedURLException e) {
+ throw new FetcherException("Search URI is malformed", e);
+ } catch (IOException e) {
+ throw new FetcherException("An I/O exception occurred", e);
+ } catch (ParseException e) {
+ throw new FetcherException("Error occurred when parsing entry", Localization.lang("Error occurred when parsing entry"), e);
+ }
+ }
+
+ @Override
+ public void doPostCleanup(BibEntry entry) {
+ new FieldFormatterCleanup(FieldName.ABSTRACT, new RemoveBracesFormatter()).cleanup(entry);
+ new FieldFormatterCleanup(FieldName.TITLE, new RemoveBracesFormatter()).cleanup(entry);
+ new FieldFormatterCleanup(FieldName.AUTHOR, new NormalizeNamesFormatter()).cleanup(entry);
+
+ // Remove url to ADS page
+ new FieldFormatterCleanup("adsnote", new ClearFormatter()).cleanup(entry);
+ new FieldFormatterCleanup("adsurl", new ClearFormatter()).cleanup(entry);
+ }
+}
diff --git a/src/main/java/net/sf/jabref/logic/importer/fetcher/BibsonomyScraper.java b/src/main/java/net/sf/jabref/logic/importer/fetcher/BibsonomyScraper.java
index 8672c8d..f2a2ca5 100644
--- a/src/main/java/net/sf/jabref/logic/importer/fetcher/BibsonomyScraper.java
+++ b/src/main/java/net/sf/jabref/logic/importer/fetcher/BibsonomyScraper.java
@@ -1,13 +1,11 @@
package net.sf.jabref.logic.importer.fetcher;
import java.io.IOException;
-import java.io.StringReader;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Optional;
import net.sf.jabref.logic.importer.ImportFormatPreferences;
-import net.sf.jabref.logic.importer.ParserResult;
import net.sf.jabref.logic.importer.fileformat.BibtexParser;
import net.sf.jabref.logic.net.URLDownload;
import net.sf.jabref.model.entry.BibEntry;
@@ -39,14 +37,7 @@ public class BibsonomyScraper {
URL url = new URL(BibsonomyScraper.BIBSONOMY_SCRAPER + cleanURL + BibsonomyScraper.BIBSONOMY_SCRAPER_POST);
String bibtex = new URLDownload(url).downloadToString(StandardCharsets.UTF_8);
- BibtexParser bp = new BibtexParser(new StringReader(bibtex), importFormatPreferences);
- ParserResult pr = bp.parse();
- if ((pr != null) && pr.getDatabase().hasEntries()) {
- return Optional.of(pr.getDatabase().getEntries().iterator().next());
- } else {
- return Optional.empty();
- }
-
+ return BibtexParser.singleFromString(bibtex, importFormatPreferences);
} catch (IOException ex) {
LOGGER.warn("Could not download entry", ex);
return Optional.empty();
diff --git a/src/main/java/net/sf/jabref/logic/importer/fetcher/CrossRef.java b/src/main/java/net/sf/jabref/logic/importer/fetcher/CrossRef.java
index 948f398..19a472a 100644
--- a/src/main/java/net/sf/jabref/logic/importer/fetcher/CrossRef.java
+++ b/src/main/java/net/sf/jabref/logic/importer/fetcher/CrossRef.java
@@ -5,7 +5,6 @@ import java.util.Objects;
import java.util.Optional;
import net.sf.jabref.logic.formatter.bibtexfields.RemoveBracesFormatter;
-import net.sf.jabref.logic.layout.format.LatexToUnicodeFormatter;
import net.sf.jabref.logic.util.DOI;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.FieldName;
@@ -28,6 +27,7 @@ import org.json.JSONObject;
*/
public class CrossRef {
private static final Log LOGGER = LogFactory.getLog(CrossRef.class);
+ private static final RemoveBracesFormatter REMOVE_BRACES_FORMATTER = new RemoveBracesFormatter();
private static final String API_URL = "http://api.crossref.org";
private static final Levenshtein METRIC_DISTANCE = new Levenshtein();
@@ -38,7 +38,7 @@ public class CrossRef {
Optional<DOI> doi = Optional.empty();
// title is minimum requirement
- Optional<String> title = entry.getFieldOptional(FieldName.TITLE);
+ Optional<String> title = entry.getField(FieldName.TITLE);
if (!title.isPresent() || title.get().isEmpty()) {
return doi;
@@ -68,14 +68,14 @@ public class CrossRef {
private static String enhanceQuery(String query, BibEntry entry) {
StringBuilder enhancedQuery = new StringBuilder(query);
// author
- entry.getFieldOptional(FieldName.AUTHOR).ifPresent(author -> {
+ entry.getField(FieldName.AUTHOR).ifPresent(author -> {
if (!author.isEmpty()) {
enhancedQuery.append('+').append(author);
}
});
// year
- entry.getFieldOptional(FieldName.YEAR).ifPresent(year -> {
+ entry.getField(FieldName.YEAR).ifPresent(year -> {
if (!year.isEmpty()) {
enhancedQuery.append('+').append(year);
}
@@ -85,8 +85,7 @@ public class CrossRef {
}
private static boolean checkValidity(BibEntry entry, JSONArray result) {
- // TODO: use latex-free version instead in the future
- final String entryTitle = entry.getFieldOptional(FieldName.TITLE).map(CrossRef::removeLaTeX).orElse("");
+ final String entryTitle = REMOVE_BRACES_FORMATTER.format(entry.getLatexFreeField(FieldName.TITLE).orElse(""));
// currently only title-based
// title: [ "How the Mind Hurts and Heals the Body." ]
@@ -114,16 +113,6 @@ public class CrossRef {
}
}
- private static String removeLaTeX(String text) {
- String result;
- // remove braces
- result = new RemoveBracesFormatter().format(text);
- // convert to unicode
- result = new LatexToUnicodeFormatter().format(result);
-
- return result;
- }
-
private static double editDistanceIgnoreCase(String a, String b) {
// TODO: locale is dependent on the language of the strings?!
return METRIC_DISTANCE.distance(a.toLowerCase(Locale.ENGLISH), b.toLowerCase(Locale.ENGLISH));
diff --git a/src/main/java/net/sf/jabref/logic/importer/fetcher/DBLPFetcher.java b/src/main/java/net/sf/jabref/logic/importer/fetcher/DBLPFetcher.java
new file mode 100644
index 0000000..8cc9268
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/importer/fetcher/DBLPFetcher.java
@@ -0,0 +1,78 @@
+package net.sf.jabref.logic.importer.fetcher;
+
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.Objects;
+
+import net.sf.jabref.logic.cleanup.DoiCleanup;
+import net.sf.jabref.logic.formatter.bibtexfields.ClearFormatter;
+import net.sf.jabref.logic.help.HelpFile;
+import net.sf.jabref.logic.importer.FetcherException;
+import net.sf.jabref.logic.importer.ImportFormatPreferences;
+import net.sf.jabref.logic.importer.Parser;
+import net.sf.jabref.logic.importer.SearchBasedParserFetcher;
+import net.sf.jabref.logic.importer.fileformat.BibtexParser;
+import net.sf.jabref.model.cleanup.FieldFormatterCleanup;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldName;
+
+import org.apache.http.client.utils.URIBuilder;
+
+/**
+ * Fetches BibTeX data from DBLP (dblp.org)
+ *
+ * @see <a href="http://dblp.dagstuhl.de/faq/13501473">Basic API documentation</a>
+ */
+public class DBLPFetcher implements SearchBasedParserFetcher {
+
+ private static final String BASIC_SEARCH_URL = "http://www.dblp.org/search/api/";
+
+ private final ImportFormatPreferences importFormatPreferences;
+
+ public DBLPFetcher(ImportFormatPreferences importFormatPreferences) {
+ Objects.requireNonNull(importFormatPreferences);
+
+ this.importFormatPreferences = importFormatPreferences;
+ }
+
+ @Override
+ public URL getURLForQuery(String query) throws URISyntaxException, MalformedURLException, FetcherException {
+ URIBuilder uriBuilder = new URIBuilder(BASIC_SEARCH_URL);
+ uriBuilder.addParameter("q", query);
+ uriBuilder.addParameter("h", String.valueOf(100)); // number of hits
+ uriBuilder.addParameter("c", String.valueOf(0)); // no need for auto-completion
+ uriBuilder.addParameter("f", String.valueOf(0)); // "from", index of first hit to download
+ uriBuilder.addParameter("format", "bib1");
+
+ return uriBuilder.build().toURL();
+ }
+
+ @Override
+ public Parser getParser() {
+ return new BibtexParser(importFormatPreferences);
+ }
+
+ @Override
+ public void doPostCleanup(BibEntry entry) {
+ DoiCleanup doiCleaner = new DoiCleanup();
+
+ FieldFormatterCleanup clearTimestampFormatter = new FieldFormatterCleanup(FieldName.TIMESTAMP,
+ new ClearFormatter());
+
+ doiCleaner.cleanup(entry);
+ clearTimestampFormatter.cleanup(entry);
+
+ }
+
+ @Override
+ public String getName() {
+ return "DBLP";
+ }
+
+ @Override
+ public HelpFile getHelpPage() {
+ return HelpFile.FETCHER_DBLP;
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/logic/importer/fetcher/DOItoBibTeX.java b/src/main/java/net/sf/jabref/logic/importer/fetcher/DOItoBibTeX.java
deleted file mode 100644
index 1765a8f..0000000
--- a/src/main/java/net/sf/jabref/logic/importer/fetcher/DOItoBibTeX.java
+++ /dev/null
@@ -1,99 +0,0 @@
-package net.sf.jabref.logic.importer.fetcher;
-
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.nio.charset.StandardCharsets;
-import java.util.Optional;
-
-import net.sf.jabref.logic.formatter.bibtexfields.UnitsToLatexFormatter;
-import net.sf.jabref.logic.formatter.casechanger.ProtectTermsFormatter;
-import net.sf.jabref.logic.importer.ImportFormatPreferences;
-import net.sf.jabref.logic.importer.ParserResult;
-import net.sf.jabref.logic.importer.fileformat.BibtexParser;
-import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.logic.net.URLDownload;
-import net.sf.jabref.logic.util.DOI;
-import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.model.entry.FieldName;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-public class DOItoBibTeX {
-
- private static final Log LOGGER = LogFactory.getLog(DOItoBibTeX.class);
-
- private static final ProtectTermsFormatter protectTermsFormatter = new ProtectTermsFormatter();
- private static final UnitsToLatexFormatter unitsToLatexFormatter = new UnitsToLatexFormatter();
-
-
- public static Optional<BibEntry> getEntryFromDOI(String doiStr, ImportFormatPreferences importFormatPreferences) {
- return getEntryFromDOI(doiStr, null, importFormatPreferences);
- }
-
- public static Optional<BibEntry> getEntryFromDOI(String doiStr, ParserResult parserResult,
- ImportFormatPreferences importFormatPreferences) {
- Optional<DOI> doi = DOI.build(doiStr);
-
- if (!doi.isPresent()) {
- if (parserResult != null) {
- parserResult.addWarning(Localization.lang("Invalid DOI: '%0'.", doiStr));
- }
- return Optional.empty();
- }
-
- try {
- URL doiURL = new URL(doi.get().getURIAsASCIIString());
-
- // BibTeX data
- URLDownload download = new URLDownload(doiURL);
- download.addParameters("Accept", "application/x-bibtex");
- String bibtexString = download.downloadToString(StandardCharsets.UTF_8);
- bibtexString = cleanupEncoding(bibtexString);
-
- // BibTeX entry
- Optional<BibEntry> bibEntry = BibtexParser.singleFromString(bibtexString, importFormatPreferences);
-
- bibEntry.ifPresent(entry -> formatTitleField(entry, importFormatPreferences));
-
- return bibEntry;
- } catch (MalformedURLException e) {
- LOGGER.warn("Bad DOI URL", e);
- return Optional.empty();
- } catch (FileNotFoundException e) {
- if (parserResult != null) {
- parserResult.addWarning(Localization.lang("Unknown DOI: '%0'.", doi.get().getDOI()));
- }
- LOGGER.debug("Unknown DOI", e);
- return Optional.empty();
- } catch (IOException e) {
- LOGGER.warn("Communication problems", e);
- return Optional.empty();
- }
- }
-
- private static void formatTitleField(BibEntry entry, ImportFormatPreferences importFormatPreferences) {
- // Optionally add curly brackets around key words to keep the case
- entry.getFieldOptional(FieldName.TITLE).ifPresent(title -> {
- // Unit formatting
- if (importFormatPreferences.isConvertUnitsOnSearch()) {
- title = unitsToLatexFormatter.format(title);
- }
-
- // Case keeping
- if (importFormatPreferences.isUseCaseKeeperOnSearch()) {
- title = protectTermsFormatter.format(title);
- }
- entry.setField(FieldName.TITLE, title);
- });
- }
-
- private static String cleanupEncoding(String bibtex) {
- // Usually includes an en-dash in the page range. Char is in cp1252 but not
- // ISO 8859-1 (which is what latex expects). For convenience replace here.
- return bibtex.replaceAll("(pages=\\{[0-9]+)\u2013([0-9]+\\})", "$1--$2");
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/logic/importer/fetcher/DiVA.java b/src/main/java/net/sf/jabref/logic/importer/fetcher/DiVA.java
index 80d2f10..e0fac8b 100644
--- a/src/main/java/net/sf/jabref/logic/importer/fetcher/DiVA.java
+++ b/src/main/java/net/sf/jabref/logic/importer/fetcher/DiVA.java
@@ -1,17 +1,15 @@
package net.sf.jabref.logic.importer.fetcher;
-import java.io.IOException;
+import java.net.MalformedURLException;
import java.net.URISyntaxException;
-import java.nio.charset.StandardCharsets;
-import java.util.Optional;
+import java.net.URL;
import net.sf.jabref.logic.help.HelpFile;
import net.sf.jabref.logic.importer.FetcherException;
-import net.sf.jabref.logic.importer.IdBasedFetcher;
+import net.sf.jabref.logic.importer.IdBasedParserFetcher;
import net.sf.jabref.logic.importer.ImportFormatPreferences;
+import net.sf.jabref.logic.importer.Parser;
import net.sf.jabref.logic.importer.fileformat.BibtexParser;
-import net.sf.jabref.logic.net.URLDownload;
-import net.sf.jabref.model.entry.BibEntry;
import org.apache.http.client.utils.URIBuilder;
@@ -19,13 +17,10 @@ import org.apache.http.client.utils.URIBuilder;
* http://www.diva-portal.org/smash/aboutdiva.jsf?dswid=-3222
* DiVA portal contains research publications and student theses from 40 Swedish universities and research institutions.
*/
-public class DiVA implements IdBasedFetcher {
-
- private static final String URL = "http://www.diva-portal.org/smash/getreferences"; // ?referenceFormat=BibTex&pids=%s";
+public class DiVA implements IdBasedParserFetcher {
private final ImportFormatPreferences importFormatPreferences;
-
public DiVA(ImportFormatPreferences importFormatPreferences) {
this.importFormatPreferences = importFormatPreferences;
}
@@ -41,21 +36,18 @@ public class DiVA implements IdBasedFetcher {
}
@Override
- public Optional<BibEntry> performSearchById(String identifier) throws FetcherException {
- try {
- URIBuilder uriBuilder = new URIBuilder(URL);
-
- uriBuilder.addParameter("referenceFormat", "BibTex");
- uriBuilder.addParameter("pids", identifier);
+ public URL getURLForID(String identifier) throws URISyntaxException, MalformedURLException, FetcherException {
+ URIBuilder uriBuilder = new URIBuilder("http://www.diva-portal.org/smash/getreferences");
- URLDownload dl = new URLDownload(uriBuilder.build().toURL());
+ uriBuilder.addParameter("referenceFormat", "BibTex");
+ uriBuilder.addParameter("pids", identifier);
- String bibtexString = dl.downloadToString(StandardCharsets.UTF_8);
- return BibtexParser.singleFromString(bibtexString, importFormatPreferences);
+ return uriBuilder.build().toURL();
+ }
- } catch (URISyntaxException | IOException e) {
- throw new FetcherException("Problem getting information from DiVA", e);
- }
+ @Override
+ public Parser getParser() {
+ return new BibtexParser(importFormatPreferences);
}
public boolean isValidId(String identifier) {
diff --git a/src/main/java/net/sf/jabref/logic/importer/fetcher/DoiFetcher.java b/src/main/java/net/sf/jabref/logic/importer/fetcher/DoiFetcher.java
new file mode 100644
index 0000000..0542a0b
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/importer/fetcher/DoiFetcher.java
@@ -0,0 +1,63 @@
+package net.sf.jabref.logic.importer.fetcher;
+
+import java.io.IOException;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.Optional;
+
+import net.sf.jabref.logic.formatter.bibtexfields.NormalizePagesFormatter;
+import net.sf.jabref.logic.help.HelpFile;
+import net.sf.jabref.logic.importer.FetcherException;
+import net.sf.jabref.logic.importer.IdBasedFetcher;
+import net.sf.jabref.logic.importer.ImportFormatPreferences;
+import net.sf.jabref.logic.importer.fileformat.BibtexParser;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.logic.net.URLDownload;
+import net.sf.jabref.logic.util.DOI;
+import net.sf.jabref.model.entry.BibEntry;
+
+public class DoiFetcher implements IdBasedFetcher {
+
+ private ImportFormatPreferences preferences;
+
+ public DoiFetcher(ImportFormatPreferences preferences) {
+ this.preferences = preferences;
+ }
+
+ private String cleanupEncoding(String bibtex) {
+ return new NormalizePagesFormatter().format(bibtex);
+ }
+
+ @Override
+ public String getName() {
+ return "DOI";
+ }
+
+ @Override
+ public HelpFile getHelpPage() {
+ return HelpFile.FETCHER_DOI_TO_BIBTEX;
+ }
+
+ @Override
+ public Optional<BibEntry> performSearchById(String identifier) throws FetcherException {
+ Optional<DOI> doi = DOI.build(identifier);
+
+ try {
+ if (doi.isPresent()) {
+ URL doiURL = new URL(doi.get().getURIAsASCIIString());
+
+ // BibTeX data
+ URLDownload download = new URLDownload(doiURL);
+ download.addParameters("Accept", "application/x-bibtex");
+ String bibtexString = download.downloadToString(StandardCharsets.UTF_8);
+
+ // BibTeX entry
+ return BibtexParser.singleFromString(cleanupEncoding(bibtexString), preferences);
+ } else {
+ throw new FetcherException(Localization.lang("Invalid_DOI:_'%0'.", identifier));
+ }
+ } catch (IOException e) {
+ throw new FetcherException(Localization.lang("Invalid URL"), e);
+ }
+ }
+}
diff --git a/src/main/java/net/sf/jabref/logic/importer/fetcher/DoiResolution.java b/src/main/java/net/sf/jabref/logic/importer/fetcher/DoiResolution.java
index 9e1e0bc..7b1599f 100644
--- a/src/main/java/net/sf/jabref/logic/importer/fetcher/DoiResolution.java
+++ b/src/main/java/net/sf/jabref/logic/importer/fetcher/DoiResolution.java
@@ -33,7 +33,7 @@ public class DoiResolution implements FulltextFetcher {
Objects.requireNonNull(entry);
Optional<URL> pdfLink = Optional.empty();
- Optional<DOI> doi = entry.getFieldOptional(FieldName.DOI).flatMap(DOI::build);
+ Optional<DOI> doi = entry.getField(FieldName.DOI).flatMap(DOI::build);
if(doi.isPresent()) {
String sciLink = doi.get().getURIAsASCIIString();
diff --git a/src/main/java/net/sf/jabref/logic/importer/fetcher/GVKParser.java b/src/main/java/net/sf/jabref/logic/importer/fetcher/GVKParser.java
deleted file mode 100644
index 095c310..0000000
--- a/src/main/java/net/sf/jabref/logic/importer/fetcher/GVKParser.java
+++ /dev/null
@@ -1,486 +0,0 @@
-package net.sf.jabref.logic.importer.fetcher;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.LinkedList;
-import java.util.List;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-
-import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.model.entry.FieldName;
-import net.sf.jabref.model.entry.IdGenerator;
-
-import com.google.common.base.Strings;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-import org.xml.sax.SAXException;
-
-class GVKParser {
- private static final Log LOGGER = LogFactory.getLog(GVKParser.class);
-
- List<BibEntry> parseEntries(InputStream is)
- throws ParserConfigurationException, SAXException, IOException {
- DocumentBuilder dbuild = DocumentBuilderFactory.newInstance().newDocumentBuilder();
- Document content = dbuild.parse(is);
- return this.parseEntries(content);
- }
-
- List<BibEntry> parseEntries(Document content) {
- List<BibEntry> result = new LinkedList<>();
-
- // used for creating test cases
- // XMLUtil.printDocument(content);
-
- // Namespace srwNamespace = Namespace.getNamespace("srw","http://www.loc.gov/zing/srw/");
-
- // Schleife ueber allen Teilergebnissen
- //Element root = content.getDocumentElement();
- Element root = (Element) content.getElementsByTagName("zs:searchRetrieveResponse").item(0);
- Element srwrecords = getChild("zs:records", root);
- if (srwrecords == null) {
- // no records found -> return empty list
- return result;
- }
- List<Element> records = getChildren("zs:record", srwrecords);
- for (Element record : records) {
- Element e = getChild("zs:recordData", record);
- if (e != null) {
- e = getChild("record", e);
- if (e != null) {
- result.add(parseEntry(e));
- }
- }
- }
- return result;
- }
-
- private BibEntry parseEntry(Element e) {
- String author = null;
- String editor = null;
- String title = null;
- String publisher = null;
- String year = null;
- String address = null;
- String series = null;
- String edition = null;
- String isbn = null;
- String issn = null;
- String number = null;
- String pagetotal = null;
- String volume = null;
- String pages = null;
- String journal = null;
- String ppn = null;
- String booktitle = null;
- String url = null;
- String note = null;
-
- String quelle = "";
- String mak = "";
- String subtitle = "";
-
- String entryType = "book"; // Default
-
- // Alle relevanten Informationen einsammeln
-
- List<Element> datafields = getChildren("datafield", e);
- for (Element datafield : datafields) {
- String tag = datafield.getAttribute("tag");
- LOGGER.debug("tag: " + tag);
-
- // mak
- if ("002@".equals(tag)) {
- mak = getSubfield("0", datafield);
- if (mak == null) {
- mak = "";
- }
- }
-
- //ppn
- if ("003@".equals(tag)) {
- ppn = getSubfield("0", datafield);
- }
-
- //author
- if ("028A".equals(tag)) {
- String vorname = getSubfield("d", datafield);
- String nachname = getSubfield("a", datafield);
-
- if (author == null) {
- author = "";
- } else {
- author = author.concat(" and ");
- }
- author = author.concat(vorname + " " + nachname);
- }
- //author (weiterer)
- if ("028B".equals(tag)) {
- String vorname = getSubfield("d", datafield);
- String nachname = getSubfield("a", datafield);
-
- if (author == null) {
- author = "";
- } else {
- author = author.concat(" and ");
- }
- author = author.concat(vorname + " " + nachname);
- }
-
- //editor
- if ("028C".equals(tag)) {
- String vorname = getSubfield("d", datafield);
- String nachname = getSubfield("a", datafield);
-
- if (editor == null) {
- editor = "";
- } else {
- editor = editor.concat(" and ");
- }
- editor = editor.concat(vorname + " " + nachname);
- }
-
- //title and subtitle
- if ("021A".equals(tag)) {
- title = getSubfield("a", datafield);
- subtitle = getSubfield("d", datafield);
- }
-
- //publisher and address
- if ("033A".equals(tag)) {
- publisher = getSubfield("n", datafield);
- address = getSubfield("p", datafield);
- }
-
- //year
- if ("011@".equals(tag)) {
- year = getSubfield("a", datafield);
- }
-
- //year, volume, number, pages (year bei Zeitschriften (evtl. redundant mit 011@))
- if ("031A".equals(tag)) {
- year = getSubfield("j", datafield);
-
- volume = getSubfield("e", datafield);
- number = getSubfield("a", datafield);
- pages = getSubfield("h", datafield);
-
- }
-
- // 036D seems to contain more information than the other fields
- // overwrite information using that field
- // 036D also contains information normally found in 036E
- if ("036D".equals(tag)) {
- // 021 might have been present
- if (title != null) {
- // convert old title (contained in "a" of 021A) to volume
- if (title.startsWith("@")) {
- // "@" indicates a number
- title = title.substring(1);
- }
- number = title;
- }
- //title and subtitle
- title = getSubfield("a", datafield);
- subtitle = getSubfield("d", datafield);
- volume = getSubfield("l", datafield);
- }
-
- //series and number
- if ("036E".equals(tag)) {
- series = getSubfield("a", datafield);
- number = getSubfield("l", datafield);
- String kor = getSubfield("b", datafield);
-
- if (kor != null) {
- series = series + " / " + kor;
- }
- }
-
- //note
- if ("037A".equals(tag)) {
- note = getSubfield("a", datafield);
- }
-
- //edition
- if ("032@".equals(tag)) {
- edition = getSubfield("a", datafield);
- }
-
- //isbn
- if ("004A".equals(tag)) {
- final String isbn10 = getSubfield("0", datafield);
- final String isbn13 = getSubfield("A", datafield);
-
- if (isbn10 != null) {
- isbn = isbn10;
- }
-
- if (isbn13 != null) {
- isbn = isbn13;
- }
-
- }
-
- // Hochschulschriftenvermerk
- // Bei einer Verlagsdissertation ist der Ort schon eingetragen
- if ("037C".equals(tag)) {
- if (address == null) {
- address = getSubfield("b", datafield);
- if (address != null) {
- address = removeSortCharacters(address);
- }
- }
-
- String st = getSubfield("a", datafield);
- if ((st != null) && st.contains("Diss")) {
- entryType = "phdthesis";
- }
- }
-
- //journal oder booktitle
-
- /* Problematiken hier: Sowohl für Artikel in
- * Zeitschriften als für Beiträge in Büchern
- * wird 027D verwendet. Der Titel muß je nach
- * Fall booktitle oder journal zugeordnet
- * werden. Auch bei Zeitschriften werden hier
- * ggf. Verlag und Ort angegeben (sind dann
- * eigentlich überflüssig), während bei
- * Buchbeiträgen Verlag und Ort wichtig sind
- * (sonst in Kategorie 033A).
- */
- if ("027D".equals(tag)) {
- journal = getSubfield("a", datafield);
- booktitle = getSubfield("a", datafield);
- address = getSubfield("p", datafield);
- publisher = getSubfield("n", datafield);
- }
-
- //pagetotal
- if ("034D".equals(tag)) {
- pagetotal = getSubfield("a", datafield);
-
- if (pagetotal != null) {
- // S, S. etc. entfernen
- pagetotal = pagetotal.replaceAll(" S\\.?$", "");
- }
- }
-
- // Behandlung von Konferenzen
- if ("030F".equals(tag)) {
- address = getSubfield("k", datafield);
-
- if (!"proceedings".equals(entryType)) {
- subtitle = getSubfield("a", datafield);
- }
-
- entryType = "proceedings";
- }
-
- // Wenn eine Verlagsdiss vorliegt
- if ("phdthesis".equals(entryType) && (isbn != null)) {
- entryType = "book";
- }
-
- //Hilfskategorien zur Entscheidung @article
- //oder @incollection; hier könnte man auch die
- //ISBN herausparsen als Erleichterung für das
- //Auffinden der Quelle, die über die
- //SRU-Schnittstelle gelieferten Daten zur
- //Quelle unvollständig sind (z.B. nicht Serie
- //und Nummer angegeben werden)
- if ("039B".equals(tag)) {
- quelle = getSubfield("8", datafield);
- }
- if ("046R".equals(tag) && ((quelle == null) || quelle.isEmpty())) {
- quelle = getSubfield("a", datafield);
- }
-
- // URLs behandeln
- if ("009P".equals(tag) && ("03".equals(datafield.getAttribute("occurrence"))
- || "05".equals(datafield.getAttribute("occurrence"))) && (url == null)) {
- url = getSubfield("a", datafield);
- }
- }
-
- // Abfangen von Nulleintraegen
- if (quelle == null) {
- quelle = "";
- }
-
- // Nichtsortierzeichen entfernen
- if (author != null) {
- author = removeSortCharacters(author);
- }
- if (editor != null) {
- editor = removeSortCharacters(editor);
- }
- if (title != null) {
- title = removeSortCharacters(title);
- }
- if (subtitle != null) {
- subtitle = removeSortCharacters(subtitle);
- }
-
- // Dokumenttyp bestimmen und Eintrag anlegen
-
- if (mak.startsWith("As")) {
- entryType = BibEntry.DEFAULT_TYPE;
-
- if (quelle.contains("ISBN")) {
- entryType = "incollection";
- }
- if (quelle.contains("ZDB-ID")) {
- entryType = "article";
- }
- } else if (mak.isEmpty()) {
- entryType = BibEntry.DEFAULT_TYPE;
- } else if (mak.startsWith("O")) {
- entryType = BibEntry.DEFAULT_TYPE;
- // FIXME: online only available in Biblatex
- //entryType = "online";
- }
-
-
- /*
- * Wahrscheinlichkeit, dass ZDB-ID
- * vorhanden ist, ist größer als ISBN bei
- * Buchbeiträgen. Daher bei As?-Sätzen am besten immer
- * dann @incollection annehmen, wenn weder ISBN noch
- * ZDB-ID vorhanden sind.
- */
- BibEntry result = new BibEntry(IdGenerator.next(), entryType);
-
- // Zuordnung der Felder in Abhängigkeit vom Dokumenttyp
- if (author != null) {
- result.setField(FieldName.AUTHOR, author);
- }
- if (editor != null) {
- result.setField(FieldName.EDITOR, editor);
- }
- if (title != null) {
- result.setField(FieldName.TITLE, title);
- }
- if (!Strings.isNullOrEmpty(subtitle)) {
- // ensure that first letter is an upper case letter
- // there could be the edge case that the string is only one character long, therefore, this special treatment
- // this is Apache commons lang StringUtils.capitalize (https://commons.apache.org/proper/commons-lang/javadocs/api-release/org/apache/commons/lang3/StringUtils.html#capitalize%28java.lang.String%29), but we don't want to add an additional dependency ('org.apache.commons:commons-lang3:3.4')
- StringBuilder newSubtitle = new StringBuilder(
- Character.toString(Character.toUpperCase(subtitle.charAt(0))));
- if (subtitle.length() > 1) {
- newSubtitle.append(subtitle.substring(1));
- }
- result.setField(FieldName.SUBTITLE, newSubtitle.toString());
- }
- if (publisher != null) {
- result.setField(FieldName.PUBLISHER, publisher);
- }
- if (year != null) {
- result.setField(FieldName.YEAR, year);
- }
- if (address != null) {
- result.setField(FieldName.ADDRESS, address);
- }
- if (series != null) {
- result.setField(FieldName.SERIES, series);
- }
- if (edition != null) {
- result.setField(FieldName.EDITION, edition);
- }
- if (isbn != null) {
- result.setField(FieldName.ISBN, isbn);
- }
- if (issn != null) {
- result.setField(FieldName.ISSN, issn);
- }
- if (number != null) {
- result.setField(FieldName.NUMBER, number);
- }
- if (pagetotal != null) {
- result.setField(FieldName.PAGETOTAL, pagetotal);
- }
- if (pages != null) {
- result.setField(FieldName.PAGES, pages);
- }
- if (volume != null) {
- result.setField(FieldName.VOLUME, volume);
- }
- if (journal != null) {
- result.setField(FieldName.JOURNAL, journal);
- }
- if (ppn != null) {
- result.setField("ppn_GVK", ppn);
- }
- if (url != null) {
- result.setField(FieldName.URL, url);
- }
- if (note != null) {
- result.setField(FieldName.NOTE, note);
- }
-
- if ("article".equals(entryType) && (journal != null)) {
- result.setField(FieldName.JOURNAL, journal);
- } else if ("incollection".equals(entryType) && (booktitle != null)) {
- result.setField(FieldName.BOOKTITLE, booktitle);
- }
-
- return result;
- }
-
- private String getSubfield(String a, Element datafield) {
- List<Element> liste = getChildren("subfield", datafield);
-
- for (Element subfield : liste) {
- if (subfield.getAttribute("code").equals(a)) {
- return (subfield.getTextContent());
- }
- }
- return null;
- }
-
- private Element getChild(String name, Element e) {
- NodeList children = e.getChildNodes();
-
- int j = children.getLength();
- for (int i = 0; i < j; i++) {
- Node test = children.item(i);
- if (test.getNodeType() == Node.ELEMENT_NODE) {
- Element entry = (Element) test;
- if (entry.getTagName().equals(name)) {
- return entry;
- }
- }
- }
- return null;
- }
-
- private List<Element> getChildren(String name, Element e) {
- List<Element> result = new LinkedList<>();
- NodeList children = e.getChildNodes();
-
- int j = children.getLength();
- for (int i = 0; i < j; i++) {
- Node test = children.item(i);
- if (test.getNodeType() == Node.ELEMENT_NODE) {
- Element entry = (Element) test;
- if (entry.getTagName().equals(name)) {
- result.add(entry);
- }
- }
- }
-
- return result;
- }
-
- private String removeSortCharacters(String input) {
- return input.replaceAll("\\@", "");
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/logic/importer/fetcher/GoogleScholar.java b/src/main/java/net/sf/jabref/logic/importer/fetcher/GoogleScholar.java
index 46a7913..7bea2a3 100644
--- a/src/main/java/net/sf/jabref/logic/importer/fetcher/GoogleScholar.java
+++ b/src/main/java/net/sf/jabref/logic/importer/fetcher/GoogleScholar.java
@@ -1,18 +1,34 @@
package net.sf.jabref.logic.importer.fetcher;
import java.io.IOException;
+import java.io.StringReader;
+import java.net.HttpCookie;
+import java.net.URISyntaxException;
import java.net.URL;
-import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
import java.util.Objects;
import java.util.Optional;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import net.sf.jabref.logic.help.HelpFile;
+import net.sf.jabref.logic.importer.FetcherException;
import net.sf.jabref.logic.importer.FulltextFetcher;
+import net.sf.jabref.logic.importer.ImportFormatPreferences;
+import net.sf.jabref.logic.importer.ParserResult;
+import net.sf.jabref.logic.importer.SearchBasedFetcher;
+import net.sf.jabref.logic.importer.fileformat.BibtexParser;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.logic.net.URLDownload;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.FieldName;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.apache.http.client.utils.URIBuilder;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
@@ -20,14 +36,26 @@ import org.jsoup.select.Elements;
/**
* FulltextFetcher implementation that attempts to find a PDF URL at GoogleScholar.
*/
-public class GoogleScholar implements FulltextFetcher {
+public class GoogleScholar implements FulltextFetcher, SearchBasedFetcher {
private static final Log LOGGER = LogFactory.getLog(GoogleScholar.class);
- private static final String SEARCH_URL = "https://scholar.google.com//scholar?as_q=&as_epq=%s&as_occt=title";
+ private static final Pattern LINK_TO_BIB_PATTERN = Pattern.compile("(https:\\/\\/scholar.googleusercontent.com\\/scholar.bib[^\"]*)");
+
+ private static final String BASIC_SEARCH_URL = "https://scholar.google.com/scholar?";
+ private static final String SEARCH_IN_TITLE_URL = "https://scholar.google.com//scholar?";
+
private static final int NUM_RESULTS = 10;
+ private final ImportFormatPreferences importFormatPreferences;
+
+ public GoogleScholar(ImportFormatPreferences importFormatPreferences) {
+ Objects.requireNonNull(importFormatPreferences);
+
+ this.importFormatPreferences = importFormatPreferences;
+ }
+
@Override
- public Optional<URL> findFullText(BibEntry entry) throws IOException {
+ public Optional<URL> findFullText(BibEntry entry) throws IOException, FetcherException {
Objects.requireNonNull(entry);
Optional<URL> pdfLink = Optional.empty();
@@ -36,30 +64,123 @@ public class GoogleScholar implements FulltextFetcher {
return pdfLink;
}
- String url = String.format(SEARCH_URL,
- URLEncoder.encode(entry.getFieldOptional(FieldName.TITLE).orElse(null), StandardCharsets.UTF_8.name()));
-
- Document doc = Jsoup.connect(url)
- .userAgent("Mozilla/5.0 (Windows NT 5.1; rv:31.0) Gecko/20100101 Firefox/31.0") // don't identify as a crawler
- .get();
- // Check results for PDF link
- // TODO: link always on first result or none?
- for (int i = 0; i < NUM_RESULTS; i++) {
- Elements link = doc.select(String.format("#gs_ggsW%s a", i));
-
- if (link.first() != null) {
- String s = link.first().attr("href");
- // link present?
- if (!"".equals(s)) {
- // TODO: check title inside pdf + length?
- // TODO: report error function needed?! query -> result
- LOGGER.info("Fulltext PDF found @ Google: " + s);
- pdfLink = Optional.of(new URL(s));
- break;
+ try {
+ URIBuilder uriBuilder = new URIBuilder(SEARCH_IN_TITLE_URL);
+ uriBuilder.addParameter("as_q", "");
+ uriBuilder.addParameter("as_epq", entry.getField(FieldName.TITLE).orElse(null));
+ uriBuilder.addParameter("as_occt", "title");
+
+ Document doc = Jsoup.connect(uriBuilder.toString()).userAgent(
+ "Mozilla/5.0 (Windows NT 5.1; rv:31.0) Gecko/20100101 Firefox/31.0") // don't identify as a crawler
+ .get();
+ // Check results for PDF link
+ // TODO: link always on first result or none?
+ for (int i = 0; i < NUM_RESULTS; i++) {
+ Elements link = doc.select(String.format("#gs_ggsW%s a", i));
+
+ if (link.first() != null) {
+ String s = link.first().attr("href");
+ // link present?
+ if (!"".equals(s)) {
+ // TODO: check title inside pdf + length?
+ // TODO: report error function needed?! query -> result
+ LOGGER.info("Fulltext PDF found @ Google: " + s);
+ pdfLink = Optional.of(new URL(s));
+ break;
+ }
}
}
+ } catch (URISyntaxException e) {
+ throw new FetcherException("Building URI failed.", e);
}
return pdfLink;
}
+
+ @Override
+ public String getName() {
+ return "Google Scholar";
+ }
+
+ @Override
+ public HelpFile getHelpPage() {
+ return HelpFile.FETCHER_GOOGLE_SCHOLAR;
+ }
+
+ @Override
+ public List<BibEntry> performSearch(String query) throws FetcherException {
+ try {
+ obtainAndModifyCookie();
+ List<BibEntry> foundEntries = new ArrayList<>(10);
+
+ URIBuilder uriBuilder = new URIBuilder(BASIC_SEARCH_URL);
+ uriBuilder.addParameter("hl", "en");
+ uriBuilder.addParameter("btnG", "Search");
+ uriBuilder.addParameter("q", query);
+
+ addHitsFromQuery(foundEntries, uriBuilder.toString());
+
+ if(foundEntries.size()==10) {
+ uriBuilder.addParameter("start", "10");
+ addHitsFromQuery(foundEntries, uriBuilder.toString());
+ }
+
+ return foundEntries;
+ } catch (URISyntaxException e) {
+ throw new FetcherException("Error while fetching from "+getName(), e);
+ } catch (IOException e) {
+ // if there are too much requests from the same IP adress google is answering with a 503 and redirecting to a captcha challenge
+ // The caught IOException looks for example like this:
+ // java.io.IOException: Server returned HTTP response code: 503 for URL: https://ipv4.google.com/sorry/index?continue=https://scholar.google.com/scholar%3Fhl%3Den%26btnG%3DSearch%26q%3Dbpmn&hl=en&q=CGMSBI0NBDkYuqy9wAUiGQDxp4NLQCWbIEY1HjpH5zFJhv4ANPGdWj0
+ if (e.getMessage().contains("Server returned HTTP response code: 503 for URL")) {
+ throw new FetcherException("Fetching from Google Scholar failed.",
+ Localization.lang("This might be caused by reaching the traffic limitation of Google Scholar (see 'Help' for details)."), e);
+ } else {
+ throw new FetcherException("Error while fetching from "+getName(), e);
+ }
+ }
+ }
+
+ private void addHitsFromQuery(List<BibEntry> entryList, String queryURL) throws IOException, FetcherException {
+ String content = URLDownload.createURLDownloadWithBrowserUserAgent(queryURL)
+ .downloadToString(StandardCharsets.UTF_8);
+
+ Matcher matcher = LINK_TO_BIB_PATTERN.matcher(content);
+ while (matcher.find()) {
+ String citationsPageURL = matcher.group().replace("&", "&");
+ BibEntry newEntry = downloadEntry(citationsPageURL);
+ entryList.add(newEntry);
+ }
+ }
+
+ private BibEntry downloadEntry(String link) throws IOException, FetcherException {
+ String downloadedContent = URLDownload.createURLDownloadWithBrowserUserAgent(link).downloadToString(StandardCharsets.UTF_8);
+ BibtexParser parser = new BibtexParser(importFormatPreferences);
+ ParserResult result = parser.parse(new StringReader(downloadedContent));
+ if ((result == null) || (result.getDatabase() == null)) {
+ throw new FetcherException("Parsing entries from Google Scholar bib file failed.");
+ } else {
+ Collection<BibEntry> entries = result.getDatabase().getEntries();
+ if (entries.size() != 1) {
+ LOGGER.debug(entries.size() + " entries found! (" + link + ")");
+ throw new FetcherException("Parsing entries from Google Scholar bib file failed.");
+ } else {
+ BibEntry entry = entries.iterator().next();
+ return entry;
+ }
+ }
+ }
+
+ private void obtainAndModifyCookie() throws FetcherException {
+ try {
+ URLDownload downloader = URLDownload.createURLDownloadWithBrowserUserAgent("https://scholar.google.com");
+ List<HttpCookie> cookies = downloader.getCookieFromUrl();
+ for (HttpCookie cookie : cookies) {
+ // append "CF=4" which represents "Citation format bibtex"
+ cookie.setValue(cookie.getValue() + ":CF=4");
+ }
+ } catch (IOException e) {
+ throw new FetcherException("Cookie configuration for Google Scholar failed.", e);
+ }
+ }
}
diff --git a/src/main/java/net/sf/jabref/logic/importer/fetcher/GvkFetcher.java b/src/main/java/net/sf/jabref/logic/importer/fetcher/GvkFetcher.java
index c7167ce..98ecba2 100644
--- a/src/main/java/net/sf/jabref/logic/importer/fetcher/GvkFetcher.java
+++ b/src/main/java/net/sf/jabref/logic/importer/fetcher/GvkFetcher.java
@@ -1,30 +1,24 @@
package net.sf.jabref.logic.importer.fetcher;
-import java.io.IOException;
-import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Arrays;
import java.util.Collection;
-import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
-import javax.xml.parsers.ParserConfigurationException;
-
import net.sf.jabref.logic.help.HelpFile;
import net.sf.jabref.logic.importer.FetcherException;
-import net.sf.jabref.logic.importer.SearchBasedFetcher;
-import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.logic.importer.Parser;
+import net.sf.jabref.logic.importer.SearchBasedParserFetcher;
+import net.sf.jabref.logic.importer.fileformat.GvkParser;
import org.apache.http.client.utils.URIBuilder;
-import org.jsoup.helper.StringUtil;
-import org.xml.sax.SAXException;
-public class GvkFetcher implements SearchBasedFetcher {
+public class GvkFetcher implements SearchBasedParserFetcher {
private static final String URL_PATTERN = "http://sru.gbv.de/gvk?";
@@ -44,7 +38,7 @@ public class GvkFetcher implements SearchBasedFetcher {
return HelpFile.FETCHER_GVK;
}
- private String getSearchQueryStringForComplexQuery(List<String> queryList) throws FetcherException {
+ private String getSearchQueryStringForComplexQuery(List<String> queryList) {
String query = "";
boolean lastWasNoKey = false;
@@ -62,7 +56,7 @@ public class GvkFetcher implements SearchBasedFetcher {
return query.trim();
}
- protected String getSearchQueryString(String query) throws FetcherException {
+ protected String getSearchQueryString(String query) {
Objects.requireNonNull(query);
LinkedList<String> queryList = new LinkedList<>(Arrays.asList(query.split("\\s")));
@@ -74,7 +68,8 @@ public class GvkFetcher implements SearchBasedFetcher {
}
}
- protected URL getQueryURL(String query) throws URISyntaxException, MalformedURLException, FetcherException {
+ @Override
+ public URL getURLForQuery(String query) throws URISyntaxException, MalformedURLException, FetcherException {
String gvkQuery = getSearchQueryString(query);
URIBuilder uriBuilder = new URIBuilder(URL_PATTERN);
uriBuilder.addParameter("version", "1.1");
@@ -86,21 +81,9 @@ public class GvkFetcher implements SearchBasedFetcher {
return uriBuilder.build().toURL();
}
-
@Override
- public List<BibEntry> performSearch(String query) throws FetcherException {
- if (StringUtil.isBlank(query)) {
- return Collections.emptyList();
- }
-
- try (InputStream is = getQueryURL(query).openStream()) {
- return (new GVKParser()).parseEntries(is);
- } catch (URISyntaxException e) {
- throw new FetcherException("URI malformed error", e);
- } catch (IOException e) {
- throw new FetcherException("An I/O exception occurred", e);
- } catch (SAXException | ParserConfigurationException e) {
- throw new FetcherException("An internal parser error occurred", e);
- }
+ public Parser getParser() {
+ return new GvkParser();
}
+
}
diff --git a/src/main/java/net/sf/jabref/logic/importer/fetcher/IEEE.java b/src/main/java/net/sf/jabref/logic/importer/fetcher/IEEE.java
index 064d7d1..a309648 100644
--- a/src/main/java/net/sf/jabref/logic/importer/fetcher/IEEE.java
+++ b/src/main/java/net/sf/jabref/logic/importer/fetcher/IEEE.java
@@ -38,7 +38,7 @@ public class IEEE implements FulltextFetcher {
String stampString = "";
// Try URL first -- will primarily work for entries from the old IEEE search
- Optional<String> urlString = entry.getFieldOptional(FieldName.URL);
+ Optional<String> urlString = entry.getField(FieldName.URL);
if (urlString.isPresent()) {
// Is the URL a direct link to IEEE?
Matcher matcher = STAMP_PATTERN.matcher(urlString.get());
@@ -50,7 +50,7 @@ public class IEEE implements FulltextFetcher {
// If not, try DOI
if (stampString.isEmpty()) {
- Optional<DOI> doi = entry.getFieldOptional(FieldName.DOI).flatMap(DOI::build);
+ Optional<DOI> doi = entry.getField(FieldName.DOI).flatMap(DOI::build);
if (doi.isPresent() && doi.get().getDOI().startsWith(IEEE_DOI) && doi.get().getURI().isPresent()) {
// Download the HTML page from IEEE
String resolvedDOIPage = new URLDownload(doi.get().getURI().get().toURL())
diff --git a/src/main/java/net/sf/jabref/logic/importer/fetcher/IsbnFetcher.java b/src/main/java/net/sf/jabref/logic/importer/fetcher/IsbnFetcher.java
new file mode 100644
index 0000000..4814da7
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/importer/fetcher/IsbnFetcher.java
@@ -0,0 +1,70 @@
+package net.sf.jabref.logic.importer.fetcher;
+
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.net.URL;
+
+import net.sf.jabref.logic.formatter.bibtexfields.ClearFormatter;
+import net.sf.jabref.logic.formatter.bibtexfields.NormalizePagesFormatter;
+import net.sf.jabref.logic.help.HelpFile;
+import net.sf.jabref.logic.importer.FetcherException;
+import net.sf.jabref.logic.importer.IdBasedParserFetcher;
+import net.sf.jabref.logic.importer.ImportFormatPreferences;
+import net.sf.jabref.logic.importer.Parser;
+import net.sf.jabref.logic.importer.fileformat.BibtexParser;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.logic.util.ISBN;
+import net.sf.jabref.model.cleanup.FieldFormatterCleanup;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldName;
+
+import org.apache.http.client.utils.URIBuilder;
+
+/**
+ * Fetcher for ISBN using http://www.ebook.de.
+ */
+public class IsbnFetcher implements IdBasedParserFetcher {
+
+ private ImportFormatPreferences importFormatPreferences;
+
+ public IsbnFetcher(ImportFormatPreferences importFormatPreferences){
+ this.importFormatPreferences = importFormatPreferences;
+ }
+
+ @Override
+ public String getName() {
+ return "ISBN";
+ }
+
+ @Override
+ public HelpFile getHelpPage() {
+ return HelpFile.FETCHER_ISBN_TO_BIBTEX;
+ }
+
+ @Override
+ public URL getURLForID(String identifier) throws URISyntaxException, MalformedURLException, FetcherException {
+ ISBN isbn = new ISBN(identifier);
+ if (!isbn.isValid()) {
+ throw new FetcherException(Localization.lang("Invalid_ISBN:_'%0'.", identifier));
+ }
+
+ URIBuilder uriBuilder = new URIBuilder("http://www.ebook.de/de/tools/isbn2bibtex");
+ uriBuilder.addParameter("isbn", identifier);
+ return uriBuilder.build().toURL();
+ }
+
+ @Override
+ public Parser getParser() {
+ return new BibtexParser(importFormatPreferences);
+ }
+
+ @Override
+ public void doPostCleanup(BibEntry entry) {
+ new FieldFormatterCleanup(FieldName.URL, new ClearFormatter()).cleanup(entry);
+
+ // Fetcher returns page numbers as "30 Seiten" -> remove every non-digit character in the PAGETOTAL field
+ entry.getField(FieldName.PAGETOTAL).ifPresent(pages ->
+ entry.setField(FieldName.PAGETOTAL, pages.replaceAll("[\\D]", "")));
+ new FieldFormatterCleanup(FieldName.PAGETOTAL, new NormalizePagesFormatter()).cleanup(entry);
+ }
+}
diff --git a/src/main/java/net/sf/jabref/logic/importer/fetcher/MathSciNet.java b/src/main/java/net/sf/jabref/logic/importer/fetcher/MathSciNet.java
new file mode 100644
index 0000000..bb3d76d
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/importer/fetcher/MathSciNet.java
@@ -0,0 +1,101 @@
+package net.sf.jabref.logic.importer.fetcher;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+import net.sf.jabref.logic.cleanup.MoveFieldCleanup;
+import net.sf.jabref.logic.formatter.bibtexfields.ClearFormatter;
+import net.sf.jabref.logic.importer.EntryBasedParserFetcher;
+import net.sf.jabref.logic.importer.FetcherException;
+import net.sf.jabref.logic.importer.ImportFormatPreferences;
+import net.sf.jabref.logic.importer.Parser;
+import net.sf.jabref.logic.importer.SearchBasedParserFetcher;
+import net.sf.jabref.logic.importer.fileformat.BibtexParser;
+import net.sf.jabref.logic.util.OS;
+import net.sf.jabref.model.cleanup.FieldFormatterCleanup;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldName;
+
+import org.apache.http.client.utils.URIBuilder;
+
+/**
+ * Fetches data from the MathSciNet (http://www.ams.org/mathscinet)
+ */
+public class MathSciNet implements SearchBasedParserFetcher, EntryBasedParserFetcher {
+
+ private final ImportFormatPreferences preferences;
+
+ public MathSciNet(ImportFormatPreferences preferences) {
+ this.preferences = Objects.requireNonNull(preferences);
+ }
+
+ @Override
+ public String getName() {
+ return "MathSciNet";
+ }
+
+ /**
+ * We use MR Lookup (http://www.ams.org/mrlookup) instead of the usual search since this tool is also available
+ * without subscription and, moreover, is optimized for finding a publication based on partial information.
+ */
+ @Override
+ public URL getURLForEntry(BibEntry entry) throws URISyntaxException, MalformedURLException, FetcherException {
+ URIBuilder uriBuilder = new URIBuilder("http://www.ams.org/mrlookup");
+ uriBuilder.addParameter("format", "bibtex");
+
+ entry.getFieldOrAlias(FieldName.TITLE).ifPresent(title -> uriBuilder.addParameter("ti", title));
+ entry.getFieldOrAlias(FieldName.AUTHOR).ifPresent(author -> uriBuilder.addParameter("au", author));
+ entry.getFieldOrAlias(FieldName.JOURNAL).ifPresent(journal -> uriBuilder.addParameter("jrnl", journal));
+ entry.getFieldOrAlias(FieldName.YEAR).ifPresent(year -> uriBuilder.addParameter("year", year));
+
+ return uriBuilder.build().toURL();
+ }
+
+ @Override
+ public URL getURLForQuery(String query) throws URISyntaxException, MalformedURLException, FetcherException {
+ URIBuilder uriBuilder = new URIBuilder("http://www.ams.org/mathscinet/search/publications.html");
+ uriBuilder.addParameter("pg7", "ALLF"); // search all fields
+ uriBuilder.addParameter("s7", query); // query
+ uriBuilder.addParameter("r", "1"); // start index
+ uriBuilder.addParameter("extend", "1"); // should return up to 100 items (instead of default 10)
+ uriBuilder.addParameter("fmt", "bibtex"); // BibTeX format
+ return uriBuilder.build().toURL();
+ }
+
+ @Override
+ public Parser getParser() {
+
+ // MathSciNet returns the BibTeX result embedded in HTML
+ // So we extract the BibTeX string from the <pre>bibtex</pre> tags and pass the content to the BibTeX parser
+ return inputStream -> {
+ String response = new BufferedReader(new InputStreamReader(inputStream)).lines().collect(
+ Collectors.joining(OS.NEWLINE));
+
+ List<BibEntry> entries = new ArrayList<>();
+ BibtexParser bibtexParser = new BibtexParser(preferences);
+ Pattern pattern = Pattern.compile("<pre>(?s)(.*)</pre>");
+ Matcher matcher = pattern.matcher(response);
+ while (matcher.find()) {
+ String bibtexEntryString = matcher.group();
+ entries.addAll(bibtexParser.parseEntries(bibtexEntryString));
+ }
+ return entries;
+ };
+ }
+
+ @Override
+ public void doPostCleanup(BibEntry entry) {
+ new MoveFieldCleanup("fjournal", FieldName.JOURNAL).cleanup(entry);
+ new MoveFieldCleanup("mrclass", FieldName.KEYWORDS).cleanup(entry);
+ new FieldFormatterCleanup(FieldName.URL, new ClearFormatter()).cleanup(entry);
+ }
+}
diff --git a/src/main/java/net/sf/jabref/logic/importer/fetcher/MedlineFetcher.java b/src/main/java/net/sf/jabref/logic/importer/fetcher/MedlineFetcher.java
new file mode 100644
index 0000000..218f250
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/importer/fetcher/MedlineFetcher.java
@@ -0,0 +1,219 @@
+package net.sf.jabref.logic.importer.fetcher;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import net.sf.jabref.logic.help.HelpFile;
+import net.sf.jabref.logic.importer.FetcherException;
+import net.sf.jabref.logic.importer.IdBasedParserFetcher;
+import net.sf.jabref.logic.importer.Parser;
+import net.sf.jabref.logic.importer.ParserResult;
+import net.sf.jabref.logic.importer.SearchBasedFetcher;
+import net.sf.jabref.logic.importer.fileformat.MedlineImporter;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.entry.BibEntry;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.http.client.utils.URIBuilder;
+
+/**
+ * Fetch or search from PubMed <a href="http://www.ncbi.nlm.nih.gov/sites/entrez/">www.ncbi.nlm.nih.gov</a>
+ * The MedlineFetcher fetches the entries from the PubMed database.
+ * See <a href="http://help.jabref.org/en/MedlineRIS">help.jabref.org</a> for a detailed documentation of the available fields.
+ */
+public class MedlineFetcher implements IdBasedParserFetcher, SearchBasedFetcher {
+
+ private static final Log LOGGER = LogFactory.getLog(MedlineFetcher.class);
+
+ private static final int NUMBER_TO_FETCH = 50;
+ private static final String ID_URL = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi";
+ private static final String SEARCH_URL = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi";
+
+ private int numberOfResultsFound;
+
+
+ /**
+ * Replaces all commas in a given string with " AND "
+ *
+ * @param query input to remove commas
+ * @return input without commas
+ */
+ private static String replaceCommaWithAND(String query) {
+ return query.replaceAll(", ", " AND ").replaceAll(",", " AND ");
+ }
+
+ /**
+ * When using 'esearch.fcgi?db=<database>&term=<query>' we will get a list of IDs matching the query.
+ * Input: Any text query (&term)
+ * Output: List of UIDs matching the query
+ *
+ * @see <a href="https://www.ncbi.nlm.nih.gov/books/NBK25500/">www.ncbi.nlm.nih.gov/books/NBK25500/</a>
+ */
+ private List<String> getPubMedIdsFromQuery(String query) throws FetcherException {
+ boolean fetchIDs = false;
+ boolean firstOccurrenceOfCount = false;
+ List<String> idList = new ArrayList<>();
+ try {
+ URL ncbi = createSearchUrl(query);
+
+ XMLInputFactory inputFactory = XMLInputFactory.newFactory();
+ XMLStreamReader streamReader = inputFactory.createXMLStreamReader(ncbi.openStream());
+
+ fetchLoop: while (streamReader.hasNext()) {
+ int event = streamReader.getEventType();
+
+ switch (event) {
+ case XMLStreamConstants.START_ELEMENT:
+ if (streamReader.getName().toString().equals("Count")) {
+ firstOccurrenceOfCount = true;
+ }
+
+ if (streamReader.getName().toString().equals("IdList")) {
+ fetchIDs = true;
+ }
+ break;
+
+ case XMLStreamConstants.CHARACTERS:
+ if (firstOccurrenceOfCount) {
+ numberOfResultsFound = Integer.parseInt(streamReader.getText());
+ firstOccurrenceOfCount = false;
+ }
+
+ if (fetchIDs) {
+ idList.add(streamReader.getText());
+ }
+ break;
+
+ case XMLStreamConstants.END_ELEMENT:
+ //Everything relevant is listed before the IdList. So we break the loop right after the IdList tag closes.
+ if (streamReader.getName().toString().equals("IdList")) {
+ break fetchLoop;
+ }
+ }
+ streamReader.next();
+ }
+ streamReader.close();
+ return idList;
+ } catch (IOException | URISyntaxException e) {
+ throw new FetcherException("Unable to get PubMed IDs", Localization.lang("Unable to get PubMed IDs"), e);
+ } catch (XMLStreamException e) {
+ throw new FetcherException("Error while parsing ID list", Localization.lang("Error while parsing ID list"),
+ e);
+ }
+ }
+
+ @Override
+ public String getName() {
+ return "Medline";
+ }
+
+ @Override
+ public HelpFile getHelpPage() {
+ return HelpFile.FETCHER_MEDLINE;
+ }
+
+ @Override
+ public URL getURLForID(String identifier) throws URISyntaxException, MalformedURLException, FetcherException {
+ URIBuilder uriBuilder = new URIBuilder(ID_URL);
+ uriBuilder.addParameter("db", "pubmed");
+ uriBuilder.addParameter("retmode", "xml");
+ uriBuilder.addParameter("id", identifier);
+ return uriBuilder.build().toURL();
+ }
+
+ @Override
+ public Parser getParser() {
+ return new MedlineImporter();
+ }
+
+ @Override
+ public void doPostCleanup(BibEntry entry) {
+ entry.clearField("journal-abbreviation");
+ entry.clearField("status");
+ entry.clearField("copyright");
+ }
+
+ @Override
+ public List<BibEntry> performSearch(String query) throws FetcherException {
+ List<BibEntry> entryList = new LinkedList<>();
+
+ if (query.isEmpty()) {
+ return Collections.emptyList();
+ } else {
+ String searchTerm = replaceCommaWithAND(query);
+
+ //searching for pubmed ids matching the query
+ List<String> idList = getPubMedIdsFromQuery(searchTerm);
+
+ if (idList.isEmpty()) {
+ LOGGER.info("No results found.");
+ return Collections.emptyList();
+ }
+ if (numberOfResultsFound > NUMBER_TO_FETCH) {
+ LOGGER.info(
+ numberOfResultsFound + " results found. Only 50 relevant results will be fetched by default.");
+ }
+
+ //pass the list of ids to fetchMedline to download them. like a id fetcher for mutliple ids
+ entryList = fetchMedline(idList);
+
+ return entryList;
+ }
+ }
+
+ private URL createSearchUrl(String term) throws URISyntaxException, MalformedURLException {
+ term = replaceCommaWithAND(term);
+ URIBuilder uriBuilder = new URIBuilder(SEARCH_URL);
+ uriBuilder.addParameter("db", "pubmed");
+ uriBuilder.addParameter("sort", "relevance");
+ uriBuilder.addParameter("retmax", String.valueOf(NUMBER_TO_FETCH));
+ uriBuilder.addParameter("term", term);
+ return uriBuilder.build().toURL();
+ }
+
+ /**
+ * Fetch and parse an medline item from eutils.ncbi.nlm.nih.gov.
+ * The E-utilities generate a huge XML file containing all entries for the ids
+ *
+ * @param ids A list of IDs to search for.
+ * @return Will return an empty list on error.
+ */
+ private List<BibEntry> fetchMedline(List<String> ids) throws FetcherException {
+ try {
+ //Separate the IDs with a comma to search multiple entries
+ URL fetchURL = getURLForID(String.join(",", ids));
+ URLConnection data = fetchURL.openConnection();
+ ParserResult result = new MedlineImporter().importDatabase(
+ new BufferedReader(new InputStreamReader(data.getInputStream(), StandardCharsets.UTF_8)));
+ if (result.hasWarnings()) {
+ LOGGER.warn(result.getErrorMessage());
+ }
+ List<BibEntry> resultList = result.getDatabase().getEntries();
+ resultList.forEach(this::doPostCleanup);
+ return resultList;
+ } catch (URISyntaxException | MalformedURLException e) {
+ throw new FetcherException("Error while generating fetch URL",
+ Localization.lang("Error while generating fetch URL"), e);
+ } catch (IOException e) {
+ throw new FetcherException("Error while fetching from Medline",
+ Localization.lang("Error while fetching from %0", "Medline"), e);
+ }
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/logic/importer/fetcher/ScienceDirect.java b/src/main/java/net/sf/jabref/logic/importer/fetcher/ScienceDirect.java
index eac25e0..4998483 100644
--- a/src/main/java/net/sf/jabref/logic/importer/fetcher/ScienceDirect.java
+++ b/src/main/java/net/sf/jabref/logic/importer/fetcher/ScienceDirect.java
@@ -39,7 +39,7 @@ public class ScienceDirect implements FulltextFetcher {
Optional<URL> pdfLink = Optional.empty();
// Try unique DOI first
- Optional<DOI> doi = entry.getFieldOptional(FieldName.DOI).flatMap(DOI::build);
+ Optional<DOI> doi = entry.getField(FieldName.DOI).flatMap(DOI::build);
if(doi.isPresent()) {
// Available in catalog?
diff --git a/src/main/java/net/sf/jabref/logic/importer/fetcher/SpringerLink.java b/src/main/java/net/sf/jabref/logic/importer/fetcher/SpringerLink.java
index d4ef30b..70724ea 100644
--- a/src/main/java/net/sf/jabref/logic/importer/fetcher/SpringerLink.java
+++ b/src/main/java/net/sf/jabref/logic/importer/fetcher/SpringerLink.java
@@ -36,7 +36,7 @@ public class SpringerLink implements FulltextFetcher {
Optional<URL> pdfLink = Optional.empty();
// Try unique DOI first
- Optional<DOI> doi = entry.getFieldOptional(FieldName.DOI).flatMap(DOI::build);
+ Optional<DOI> doi = entry.getField(FieldName.DOI).flatMap(DOI::build);
if(doi.isPresent()) {
// Available in catalog?
diff --git a/src/main/java/net/sf/jabref/logic/importer/fetcher/zbMATH.java b/src/main/java/net/sf/jabref/logic/importer/fetcher/zbMATH.java
new file mode 100644
index 0000000..df7c18b
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/importer/fetcher/zbMATH.java
@@ -0,0 +1,131 @@
+package net.sf.jabref.logic.importer.fetcher;
+
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.security.SecureRandom;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Objects;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+
+import net.sf.jabref.logic.cleanup.MoveFieldCleanup;
+import net.sf.jabref.logic.formatter.bibtexfields.RemoveBracesFormatter;
+import net.sf.jabref.logic.importer.FetcherException;
+import net.sf.jabref.logic.importer.ImportFormatPreferences;
+import net.sf.jabref.logic.importer.Parser;
+import net.sf.jabref.logic.importer.SearchBasedParserFetcher;
+import net.sf.jabref.logic.importer.fileformat.BibtexParser;
+import net.sf.jabref.model.cleanup.FieldFormatterCleanup;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldName;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.http.client.utils.URIBuilder;
+
+/**
+ * Fetches data from the Zentralblatt Math (https://www.zbmath.org/)
+ */
+public class zbMATH implements SearchBasedParserFetcher {
+
+ private static final Log LOGGER = LogFactory.getLog(zbMATH.class);
+
+ private final ImportFormatPreferences preferences;
+
+ public zbMATH(ImportFormatPreferences preferences) {
+ this.preferences = Objects.requireNonNull(preferences);
+ }
+
+ @Override
+ public String getName() {
+ return "zbMATH";
+ }
+
+ /**
+ * TODO: Implement EntryBasedParserFetcher
+ * We use the zbMATH Citation matcher (https://www.zbmath.org/citationmatching/)
+ * instead of the usual search since this tool is optimized for finding a publication based on partial information.
+ */
+ /*
+ @Override
+ public URL getURLForEntry(BibEntry entry) throws URISyntaxException, MalformedURLException, FetcherException {
+ // Example: https://zbmath.org/citationmatching/match?q=Ratiu
+ }
+ */
+
+ @Override
+ public URL getURLForQuery(String query) throws URISyntaxException, MalformedURLException, FetcherException {
+ URIBuilder uriBuilder = new URIBuilder("https://zbmath.org/bibtexoutput/");
+ uriBuilder.addParameter("q", query); // search all fields
+ uriBuilder.addParameter("start", "0"); // start index
+ uriBuilder.addParameter("count", "200"); // should return up to 200 items (instead of default 100)
+
+ fixSSLVerification();
+
+ return uriBuilder.build().toURL();
+ }
+
+ /**
+ * Older java VMs does not automatically trust the zbMATH certificate. In this case the following exception is thrown:
+ * sun.security.validator.ValidatorException: PKIX path building failed:
+ * sun.security.provider.certpath.SunCertPathBuilderException: unable to find
+ * valid certification path to requested target
+ * JM > 8u101 may trust the certificate by default according to http://stackoverflow.com/a/34111150/873661
+ *
+ * We will fix this issue by accepting all (!) certificates. This is ugly; but as JabRef does not rely on
+ * security-relevant information this is kind of OK (no, actually it is not...).
+ *
+ * Taken from http://stackoverflow.com/a/6055903/873661
+ */
+ private void fixSSLVerification() {
+
+ LOGGER.warn("Fix SSL exception by accepting ALL certificates");
+
+ // Create a trust manager that does not validate certificate chains
+ TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
+
+ @Override
+ public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
+
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
+
+ }
+
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ return new X509Certificate[0];
+ }
+ } };
+
+ // Install the all-trusting trust manager
+ try {
+ SSLContext sc = SSLContext.getInstance("TLS");
+ sc.init(null, trustAllCerts, new SecureRandom());
+ HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
+ } catch (Exception e) {
+ LOGGER.error("SSL problem", e);
+ }
+ }
+
+ @Override
+ public Parser getParser() {
+ return new BibtexParser(preferences);
+ }
+
+ @Override
+ public void doPostCleanup(BibEntry entry) {
+ new MoveFieldCleanup("msc2010", FieldName.KEYWORDS).cleanup(entry);
+ new MoveFieldCleanup("fjournal", FieldName.JOURNAL).cleanup(entry);
+ new FieldFormatterCleanup(FieldName.JOURNAL, new RemoveBracesFormatter()).cleanup(entry);
+ new FieldFormatterCleanup(FieldName.TITLE, new RemoveBracesFormatter()).cleanup(entry);
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/logic/importer/fileformat/BibTeXMLImporter.java b/src/main/java/net/sf/jabref/logic/importer/fileformat/BibTeXMLImporter.java
index 2f22372..d17d49f 100644
--- a/src/main/java/net/sf/jabref/logic/importer/fileformat/BibTeXMLImporter.java
+++ b/src/main/java/net/sf/jabref/logic/importer/fileformat/BibTeXMLImporter.java
@@ -19,6 +19,7 @@ import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.datatype.XMLGregorianCalendar;
+import net.sf.jabref.logic.importer.Importer;
import net.sf.jabref.logic.importer.ParserResult;
import net.sf.jabref.logic.importer.fileformat.bibtexml.Entry;
import net.sf.jabref.logic.importer.fileformat.bibtexml.File;
@@ -37,7 +38,7 @@ import org.apache.commons.logging.LogFactory;
* check here for details on the format
* http://bibtexml.sourceforge.net/
*/
-public class BibTeXMLImporter extends ImportFormat {
+public class BibTeXMLImporter extends Importer {
private static final Log LOGGER = LogFactory.getLog(BibTeXMLImporter.class);
@@ -48,7 +49,7 @@ public class BibTeXMLImporter extends ImportFormat {
@Override
- public String getFormatName() {
+ public String getName() {
return "BibTeXML";
}
@@ -208,12 +209,10 @@ public class BibTeXMLImporter extends ImportFormat {
putIfValueNotNull(fields, localName, value);
} else if (elementValue instanceof BigInteger) {
BigInteger value = (BigInteger) elementValue;
- if (value != null) {
- if (FieldName.NUMBER.equals(localName)) {
- fields.put(FieldName.NUMBER, String.valueOf(value));
- } else if (FieldName.CHAPTER.equals(localName)) {
- fields.put(FieldName.CHAPTER, String.valueOf(value));
- }
+ if (FieldName.NUMBER.equals(localName)) {
+ fields.put(FieldName.NUMBER, String.valueOf(value));
+ } else if (FieldName.CHAPTER.equals(localName)) {
+ fields.put(FieldName.CHAPTER, String.valueOf(value));
}
} else if (elementValue instanceof XMLGregorianCalendar) {
XMLGregorianCalendar value = (XMLGregorianCalendar) elementValue;
diff --git a/src/main/java/net/sf/jabref/logic/importer/fileformat/BiblioscapeImporter.java b/src/main/java/net/sf/jabref/logic/importer/fileformat/BiblioscapeImporter.java
index 94e91ed..e7d43c1 100644
--- a/src/main/java/net/sf/jabref/logic/importer/fileformat/BiblioscapeImporter.java
+++ b/src/main/java/net/sf/jabref/logic/importer/fileformat/BiblioscapeImporter.java
@@ -8,6 +8,7 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
+import net.sf.jabref.logic.importer.Importer;
import net.sf.jabref.logic.importer.ParserResult;
import net.sf.jabref.logic.util.FileExtensions;
import net.sf.jabref.model.entry.BibEntry;
@@ -19,10 +20,10 @@ import net.sf.jabref.model.entry.FieldName;
* Biblioscape field types are ignored. Others are only included in the BibTeX
* field "comment".
*/
-public class BiblioscapeImporter extends ImportFormat {
+public class BiblioscapeImporter extends Importer {
@Override
- public String getFormatName() {
+ public String getName() {
return "Biblioscape";
}
diff --git a/src/main/java/net/sf/jabref/logic/importer/fileformat/BibtexImporter.java b/src/main/java/net/sf/jabref/logic/importer/fileformat/BibtexImporter.java
index 2c7281e..a9eb877 100644
--- a/src/main/java/net/sf/jabref/logic/importer/fileformat/BibtexImporter.java
+++ b/src/main/java/net/sf/jabref/logic/importer/fileformat/BibtexImporter.java
@@ -9,6 +9,7 @@ import java.util.Optional;
import net.sf.jabref.logic.exporter.SavePreferences;
import net.sf.jabref.logic.importer.ImportFormatPreferences;
+import net.sf.jabref.logic.importer.Importer;
import net.sf.jabref.logic.importer.ParserResult;
import net.sf.jabref.logic.util.FileExtensions;
@@ -18,7 +19,7 @@ import net.sf.jabref.logic.util.FileExtensions;
* It is NOT intended to import a BIB file. This is done via the option action, which treats the metadata fields
* The metadata is not required to be read here, as this class is NOT called at --import
*/
-public class BibtexImporter extends ImportFormat {
+public class BibtexImporter extends Importer {
// Signature written at the top of the .bib file in earlier versions.
private static final String SIGNATURE = "This file was created with JabRef";
@@ -70,7 +71,7 @@ public class BibtexImporter extends ImportFormat {
}
@Override
- public String getFormatName() {
+ public String getName() {
return "BibTeX";
}
diff --git a/src/main/java/net/sf/jabref/logic/importer/fileformat/BibtexParser.java b/src/main/java/net/sf/jabref/logic/importer/fileformat/BibtexParser.java
index 45775c7..218816e 100644
--- a/src/main/java/net/sf/jabref/logic/importer/fileformat/BibtexParser.java
+++ b/src/main/java/net/sf/jabref/logic/importer/fileformat/BibtexParser.java
@@ -1,9 +1,13 @@
package net.sf.jabref.logic.importer.fileformat;
+import java.io.BufferedReader;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
import java.io.PushbackReader;
import java.io.Reader;
import java.io.StringReader;
+import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
@@ -14,12 +18,14 @@ import java.util.Map;
import java.util.Objects;
import java.util.Optional;
-import net.sf.jabref.MetaData;
import net.sf.jabref.logic.bibtex.FieldContentParser;
+import net.sf.jabref.logic.exporter.BibtexDatabaseWriter;
import net.sf.jabref.logic.exporter.SavePreferences;
import net.sf.jabref.logic.importer.ImportFormatPreferences;
+import net.sf.jabref.logic.importer.ParseException;
+import net.sf.jabref.logic.importer.Parser;
import net.sf.jabref.logic.importer.ParserResult;
-import net.sf.jabref.logic.importer.util.ParseException;
+import net.sf.jabref.logic.importer.util.MetaDataParser;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.model.database.BibDatabase;
import net.sf.jabref.model.database.KeyCollisionException;
@@ -28,9 +34,10 @@ import net.sf.jabref.model.entry.BibtexString;
import net.sf.jabref.model.entry.CustomEntryType;
import net.sf.jabref.model.entry.EntryType;
import net.sf.jabref.model.entry.FieldName;
-import net.sf.jabref.model.entry.FieldProperties;
+import net.sf.jabref.model.entry.FieldProperty;
import net.sf.jabref.model.entry.IdGenerator;
import net.sf.jabref.model.entry.InternalBibtexFields;
+import net.sf.jabref.model.metadata.MetaData;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -50,11 +57,11 @@ import org.apache.commons.logging.LogFactory;
* <p>
* Can be used stand-alone.
*/
-public class BibtexParser {
+public class BibtexParser implements Parser {
private static final Log LOGGER = LogFactory.getLog(BibtexParser.class);
- private final PushbackReader pushbackReader;
+ private PushbackReader pushbackReader;
private BibDatabase database;
private Map<String, EntryType> entryTypes;
private boolean eof;
@@ -66,11 +73,9 @@ public class BibtexParser {
private final ImportFormatPreferences importFormatPreferences;
- public BibtexParser(Reader in, ImportFormatPreferences importFormatPreferences) {
- Objects.requireNonNull(in);
+ public BibtexParser(ImportFormatPreferences importFormatPreferences) {
this.importFormatPreferences = Objects.requireNonNull(importFormatPreferences);
fieldContentParser = new FieldContentParser(importFormatPreferences.getFieldContentParserPreferences());
- pushbackReader = new PushbackReader(in, BibtexParser.LOOKAHEAD);
}
/**
@@ -78,10 +83,10 @@ public class BibtexParser {
*
* @param in the Reader to read from
* @throws IOException
+ * @deprecated inline this method
*/
public static ParserResult parse(Reader in, ImportFormatPreferences importFormatPreferences) throws IOException {
- BibtexParser parser = new BibtexParser(in, importFormatPreferences);
- return parser.parse();
+ return new BibtexParser(importFormatPreferences).parse(in);
}
/**
@@ -89,13 +94,14 @@ public class BibtexParser {
*
* @param bibtexString
* @return Returns returns an empty collection if no entries where found or if an error occurred.
+ * @deprecated use parseEntries
*/
+ @Deprecated
public static List<BibEntry> fromString(String bibtexString, ImportFormatPreferences importFormatPreferences) {
- StringReader reader = new StringReader(bibtexString);
- BibtexParser parser = new BibtexParser(reader, importFormatPreferences);
+ BibtexParser parser = new BibtexParser(importFormatPreferences);
try {
- return parser.parse().getDatabase().getEntries();
+ return parser.parseEntries(bibtexString);
} catch (Exception e) {
LOGGER.warn("BibtexParser.fromString(String): " + e.getMessage(), e);
return Collections.emptyList();
@@ -119,6 +125,24 @@ public class BibtexParser {
return Optional.of(entries.iterator().next());
}
+ @Override
+ public List<BibEntry> parseEntries(InputStream inputStream) throws ParseException {
+ BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
+ return parseEntries(reader);
+ }
+
+ public List<BibEntry> parseEntries(Reader reader) throws ParseException {
+ try {
+ return parse(reader).getDatabase().getEntries();
+ } catch (IOException e) {
+ throw new ParseException(e);
+ }
+ }
+
+ public List<BibEntry> parseEntries(String bibtexString) throws ParseException {
+ return parseEntries(new StringReader(bibtexString));
+ }
+
/**
* Will parse the BibTex-Data found when reading from reader. Ignores any encoding supplied in the file by
* "Encoding: myEncoding".
@@ -130,14 +154,15 @@ public class BibtexParser {
* @return ParserResult
* @throws IOException
*/
- public ParserResult parse() throws IOException {
- // If we already parsed this, just return it.
- if (parserResult != null) {
- return parserResult;
- }
+ public ParserResult parse(Reader in) throws IOException {
+ Objects.requireNonNull(in);
+ pushbackReader = new PushbackReader(in, BibtexParser.LOOKAHEAD);
+
// Bibtex related contents.
initializeParserResult();
+ parseDatabaseID();
+
skipWhitespace();
try {
@@ -153,6 +178,28 @@ public class BibtexParser {
parserResult = new ParserResult(database, null, entryTypes);
}
+
+ private void parseDatabaseID() throws IOException {
+
+ while (!eof) {
+ skipWhitespace();
+ char c = (char) read();
+
+ if (c == '%') {
+ skipWhitespace();
+ String label = parseTextToken().trim();
+
+ if (label.equals(BibtexDatabaseWriter.DATABASE_ID_PREFIX)) {
+ skipWhitespace();
+ database.setSharedDatabaseID(parseTextToken().trim());
+ }
+ } else if (c == '@') {
+ unread(c);
+ break;
+ }
+ }
+ }
+
private ParserResult parseFileContent() throws IOException {
Map<String, String> meta = new HashMap<>();
@@ -187,7 +234,7 @@ public class BibtexParser {
// Instantiate meta data:
try {
- parserResult.setMetaData(MetaData.parse(meta));
+ parserResult.setMetaData(MetaDataParser.parse(meta, importFormatPreferences.getKeywordSeparator()));
} catch (ParseException exception) {
parserResult.addWarning(exception.getLocalizedMessage());
}
@@ -228,7 +275,7 @@ public class BibtexParser {
+ " (" + Localization.lang("Grouping may not work for this entry.") + ")");
}
} catch (IOException ex) {
- LOGGER.warn("Could not parse entry", ex);
+ LOGGER.debug("Could not parse entry", ex);
parserResult.addWarning(Localization.lang("Error occurred when parsing entry") + ": '" + ex.getMessage()
+ "'. " + Localization.lang("Skipped entry."));
@@ -307,26 +354,33 @@ public class BibtexParser {
// if there is no entry found, simply return the content (necessary to parse text remaining after the last entry)
if (indexOfAt == -1) {
return purgeEOFCharacters(result);
+ } else if (result.contains(BibtexDatabaseWriter.DATABASE_ID_PREFIX)) {
+ return purge(result, BibtexDatabaseWriter.DATABASE_ID_PREFIX);
} else if (result.contains(SavePreferences.ENCODING_PREFIX)) {
- // purge the encoding line if it exists
- int runningIndex = result.indexOf(SavePreferences.ENCODING_PREFIX);
- while (runningIndex < indexOfAt) {
- if (result.charAt(runningIndex) == '\n') {
- break;
- } else if (result.charAt(runningIndex) == '\r') {
- if (result.charAt(runningIndex + 1) == '\n') {
- runningIndex++;
- }
- break;
- }
- runningIndex++;
- }
- return result.substring(runningIndex + 1);
+ return purge(result, SavePreferences.ENCODING_PREFIX);
} else {
return result;
}
}
+ private String purge(String context, String stringToPurge) {
+ // purge the encoding line if it exists
+ int runningIndex = context.indexOf(stringToPurge);
+ int indexOfAt = context.indexOf("@");
+ while (runningIndex < indexOfAt) {
+ if (context.charAt(runningIndex) == '\n') {
+ break;
+ } else if (context.charAt(runningIndex) == '\r') {
+ if (context.charAt(runningIndex + 1) == '\n') {
+ runningIndex++;
+ }
+ break;
+ }
+ runningIndex++;
+ }
+ return context.substring(runningIndex + 1);
+ }
+
private String getPureTextFromFile() {
StringBuilder entry = new StringBuilder();
while (!pureTextFromFile.isEmpty()) {
@@ -541,8 +595,8 @@ public class BibtexParser {
// at least one online database exports bibtex like that, making
// it inconvenient
// for users if JabRef did not accept it.
- if (InternalBibtexFields.getFieldExtras(key).contains(FieldProperties.PERSON_NAMES)) {
- entry.setField(key, entry.getFieldOptional(key).get() + " and " + content);
+ if (InternalBibtexFields.getFieldProperties(key).contains(FieldProperty.PERSON_NAMES)) {
+ entry.setField(key, entry.getField(key).get() + " and " + content);
} else if (FieldName.KEYWORDS.equals(key)) {
//multiple keywords fields should be combined to one
entry.addKeyword(content, importFormatPreferences.getKeywordSeparator());
diff --git a/src/main/java/net/sf/jabref/logic/importer/fileformat/CopacImporter.java b/src/main/java/net/sf/jabref/logic/importer/fileformat/CopacImporter.java
index 62d72cb..52d5d24 100644
--- a/src/main/java/net/sf/jabref/logic/importer/fileformat/CopacImporter.java
+++ b/src/main/java/net/sf/jabref/logic/importer/fileformat/CopacImporter.java
@@ -7,6 +7,7 @@ import java.util.List;
import java.util.Objects;
import java.util.regex.Pattern;
+import net.sf.jabref.logic.importer.Importer;
import net.sf.jabref.logic.importer.ParserResult;
import net.sf.jabref.logic.util.FileExtensions;
import net.sf.jabref.model.entry.BibEntry;
@@ -19,12 +20,12 @@ import net.sf.jabref.model.entry.FieldName;
*
* http://copac.ac.uk/faq/#format
*/
-public class CopacImporter extends ImportFormat {
+public class CopacImporter extends Importer {
private static final Pattern COPAC_PATTERN = Pattern.compile("^\\s*TI- ");
@Override
- public String getFormatName() {
+ public String getName() {
return "Copac";
}
@@ -140,7 +141,7 @@ public class CopacImporter extends ImportFormat {
private static void setOrAppend(BibEntry b, String field, String value, String separator) {
if (b.hasField(field)) {
- b.setField(field, b.getFieldOptional(field).get() + separator + value);
+ b.setField(field, b.getField(field).get() + separator + value);
} else {
b.setField(field, value);
}
diff --git a/src/main/java/net/sf/jabref/logic/importer/fileformat/CustomImporter.java b/src/main/java/net/sf/jabref/logic/importer/fileformat/CustomImporter.java
index 200d2bd..f0f930f 100644
--- a/src/main/java/net/sf/jabref/logic/importer/fileformat/CustomImporter.java
+++ b/src/main/java/net/sf/jabref/logic/importer/fileformat/CustomImporter.java
@@ -1,92 +1,61 @@
package net.sf.jabref.logic.importer.fileformat;
-import java.io.File;
+import java.io.BufferedReader;
import java.io.IOException;
-import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
+import net.sf.jabref.logic.importer.Importer;
+import net.sf.jabref.logic.importer.ParserResult;
+import net.sf.jabref.logic.util.FileExtensions;
+
/**
* Object with data for a custom importer.
*
* <p>Is also responsible for instantiating the class loader.</p>
*/
-public class CustomImporter implements Comparable<CustomImporter> {
-
- private String name;
- private String cliId;
- private String className;
- private String basePath;
-
+public class CustomImporter extends Importer {
- public CustomImporter() {
- super();
- }
+ private final String className;
+ private final Path basePath;
- public CustomImporter(List<String> data) {
- this(data.get(0), data.get(1), data.get(2), data.get(3));
- }
+ private Importer importer;
- public CustomImporter(String name, String cliId, String className, String basePath) {
- this();
- this.name = name;
- this.cliId = cliId;
+ public CustomImporter(String basePath, String className) throws ClassNotFoundException {
+ this.basePath = Paths.get(basePath);
this.className = className;
- this.basePath = basePath;
- }
-
- public CustomImporter(ImportFormat importer) {
- this(importer.getFormatName(), importer.getId(), importer.getClass().getName(),
- "src/main/java/net/sf/jabref/logic/importer/fileformat/" + importer.getFormatName() + "Importer.java");
- }
-
- public String getName() {
- return this.name;
- }
-
- public void setName(String name) {
- this.name = name;
+ try {
+ importer = load(this.basePath.toUri().toURL(), this.className);
+ } catch (IOException | InstantiationException | IllegalAccessException exception) {
+ throw new ClassNotFoundException("", exception);
+ }
}
- public String getClidId() {
- return this.cliId;
+ private static Importer load(URL basePathURL, String className)
+ throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
+ try (URLClassLoader cl = new URLClassLoader(new URL[] {basePathURL})) {
+ Class<?> clazz = Class.forName(className, true, cl);
+ return (Importer) clazz.newInstance();
+ }
}
- public void setCliId(String cliId) {
- this.cliId = cliId;
+ public List<String> getAsStringList() {
+ return Arrays.asList(basePath.toString().replace('\\', '/'), className);
}
public String getClassName() {
- return this.className;
- }
-
- public void setClassName(String className) {
- this.className = className;
- }
-
- public void setBasePath(String basePath) {
- this.basePath = basePath;
+ return className;
}
- public String getBasePath() {
+ public Path getBasePath() {
return basePath;
}
- public File getFileFromBasePath() {
- return new File(basePath);
- }
-
- public URL getBasePathUrl() throws MalformedURLException {
- return getFileFromBasePath().toURI().toURL();
- }
-
- public List<String> getAsStringList() {
- return Arrays.asList(name, cliId, className, basePath);
- }
-
@Override
public boolean equals(Object other) {
@@ -99,32 +68,46 @@ public class CustomImporter implements Comparable<CustomImporter> {
}
CustomImporter otherImporter = (CustomImporter) other;
- return Objects.equals(name, otherImporter.name) && Objects.equals(cliId, otherImporter.cliId)
- && Objects.equals(className, otherImporter.className)
- && Objects.equals(basePath, otherImporter.basePath);
+ return Objects.equals(className, otherImporter.className) && Objects.equals(basePath, otherImporter.basePath);
}
@Override
- public int hashCode() {
- return Objects.hash(name, cliId, className, basePath);
+ public boolean isRecognizedFormat(BufferedReader input) throws IOException {
+ return importer.isRecognizedFormat(input);
}
@Override
- public int compareTo(CustomImporter o) {
- return this.getName().compareTo(o.getName());
+ public ParserResult importDatabase(BufferedReader input) throws IOException {
+ return importer.importDatabase(input);
}
@Override
- public String toString() {
- return this.name;
+ public String getName() {
+ return importer.getName();
}
- public ImportFormat getInstance() throws IOException, ClassNotFoundException,
- InstantiationException, IllegalAccessException {
- try (URLClassLoader cl = new URLClassLoader(new URL[] {getBasePathUrl()})) {
- Class<?> clazz = Class.forName(className, true, cl);
- ImportFormat importFormat = (ImportFormat) clazz.newInstance();
- return importFormat;
- }
+ @Override
+ public FileExtensions getExtensions() {
+ return importer.getExtensions();
+ }
+
+ @Override
+ public String getId() {
+ return importer.getId();
+ }
+
+ @Override
+ public String getDescription() {
+ return importer.getDescription();
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(className, basePath);
+ }
+
+ @Override
+ public String toString() {
+ return this.getName();
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/net/sf/jabref/logic/importer/fileformat/EndnoteImporter.java b/src/main/java/net/sf/jabref/logic/importer/fileformat/EndnoteImporter.java
index afc9a38..afb0ef0 100644
--- a/src/main/java/net/sf/jabref/logic/importer/fileformat/EndnoteImporter.java
+++ b/src/main/java/net/sf/jabref/logic/importer/fileformat/EndnoteImporter.java
@@ -10,6 +10,7 @@ import java.util.regex.Pattern;
import net.sf.jabref.logic.bibtexkeypattern.BibtexKeyPatternUtil;
import net.sf.jabref.logic.importer.ImportFormatPreferences;
+import net.sf.jabref.logic.importer.Importer;
import net.sf.jabref.logic.importer.ParserResult;
import net.sf.jabref.logic.util.FileExtensions;
import net.sf.jabref.model.entry.AuthorList;
@@ -24,7 +25,7 @@ import net.sf.jabref.model.entry.FieldName;
* check here for details on the format
* http://libguides.csuchico.edu/c.php?g=414245&p=2822898
*/
-public class EndnoteImporter extends ImportFormat {
+public class EndnoteImporter extends Importer {
private static final String ENDOFRECORD = "__EOREOR__";
@@ -38,7 +39,7 @@ public class EndnoteImporter extends ImportFormat {
}
@Override
- public String getFormatName() {
+ public String getName() {
return "Refer/Endnote";
}
diff --git a/src/main/java/net/sf/jabref/logic/importer/fileformat/FreeCiteImporter.java b/src/main/java/net/sf/jabref/logic/importer/fileformat/FreeCiteImporter.java
index b40e523..e709fff 100644
--- a/src/main/java/net/sf/jabref/logic/importer/fileformat/FreeCiteImporter.java
+++ b/src/main/java/net/sf/jabref/logic/importer/fileformat/FreeCiteImporter.java
@@ -22,6 +22,7 @@ import javax.xml.stream.XMLStreamReader;
import net.sf.jabref.JabRefGUI;
import net.sf.jabref.logic.bibtexkeypattern.BibtexKeyPatternUtil;
import net.sf.jabref.logic.importer.ImportFormatPreferences;
+import net.sf.jabref.logic.importer.Importer;
import net.sf.jabref.logic.importer.ParserResult;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.util.FileExtensions;
@@ -38,7 +39,7 @@ import org.apache.commons.logging.LogFactory;
* This importer parses text format citations using the online API of FreeCite -
* Open Source Citation Parser http://freecite.library.brown.edu/
*/
-public class FreeCiteImporter extends ImportFormat {
+public class FreeCiteImporter extends Importer {
private static final Log LOGGER = LogFactory.getLog(FreeCiteImporter.class);
@@ -189,7 +190,7 @@ public class FreeCiteImporter extends ImportFormat {
String note;
if (e.hasField(FieldName.NOTE)) {
// "note" could have been set during the parsing as FreeCite also returns "note"
- note = e.getFieldOptional(FieldName.NOTE).get().concat(OS.NEWLINE)
+ note = e.getField(FieldName.NOTE).get().concat(OS.NEWLINE)
.concat(noteSB.toString());
} else {
note = noteSB.toString();
@@ -202,8 +203,9 @@ public class FreeCiteImporter extends ImportFormat {
e.setType(type);
// autogenerate label (BibTeX key)
- BibtexKeyPatternUtil.makeLabel(
- JabRefGUI.getMainFrame().getCurrentBasePanel().getBibDatabaseContext().getMetaData(),
+ BibtexKeyPatternUtil.makeAndSetLabel(
+ JabRefGUI.getMainFrame().getCurrentBasePanel().getBibDatabaseContext().getMetaData()
+ .getCiteKeyPattern(importFormatPreferences.getBibtexKeyPatternPreferences().getKeyPattern()),
JabRefGUI.getMainFrame().getCurrentBasePanel().getDatabase(), e,
importFormatPreferences.getBibtexKeyPatternPreferences());
@@ -221,7 +223,7 @@ public class FreeCiteImporter extends ImportFormat {
}
@Override
- public String getFormatName() {
+ public String getName() {
return "text citations";
}
diff --git a/src/main/java/net/sf/jabref/logic/importer/fileformat/GvkParser.java b/src/main/java/net/sf/jabref/logic/importer/fileformat/GvkParser.java
new file mode 100644
index 0000000..bad541e
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/importer/fileformat/GvkParser.java
@@ -0,0 +1,492 @@
+package net.sf.jabref.logic.importer.fileformat;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import net.sf.jabref.logic.importer.ParseException;
+import net.sf.jabref.logic.importer.Parser;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldName;
+import net.sf.jabref.model.entry.IdGenerator;
+
+import com.google.common.base.Strings;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+public class GvkParser implements Parser {
+ private static final Log LOGGER = LogFactory.getLog(GvkParser.class);
+
+ @Override
+ public List<BibEntry> parseEntries(InputStream inputStream) throws ParseException {
+ try {
+ DocumentBuilder dbuild = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+ Document content = dbuild.parse(inputStream);
+ return this.parseEntries(content);
+ } catch (ParserConfigurationException|SAXException|IOException exception) {
+ throw new ParseException(exception);
+ }
+ }
+
+ private List<BibEntry> parseEntries(Document content) {
+ List<BibEntry> result = new LinkedList<>();
+
+ // used for creating test cases
+ // XMLUtil.printDocument(content);
+
+ // Namespace srwNamespace = Namespace.getNamespace("srw","http://www.loc.gov/zing/srw/");
+
+ // Schleife ueber allen Teilergebnissen
+ //Element root = content.getDocumentElement();
+ Element root = (Element) content.getElementsByTagName("zs:searchRetrieveResponse").item(0);
+ Element srwrecords = getChild("zs:records", root);
+ if (srwrecords == null) {
+ // no records found -> return empty list
+ return result;
+ }
+ List<Element> records = getChildren("zs:record", srwrecords);
+ for (Element record : records) {
+ Element e = getChild("zs:recordData", record);
+ if (e != null) {
+ e = getChild("record", e);
+ if (e != null) {
+ result.add(parseEntry(e));
+ }
+ }
+ }
+ return result;
+ }
+
+ private BibEntry parseEntry(Element e) {
+ String author = null;
+ String editor = null;
+ String title = null;
+ String publisher = null;
+ String year = null;
+ String address = null;
+ String series = null;
+ String edition = null;
+ String isbn = null;
+ String issn = null;
+ String number = null;
+ String pagetotal = null;
+ String volume = null;
+ String pages = null;
+ String journal = null;
+ String ppn = null;
+ String booktitle = null;
+ String url = null;
+ String note = null;
+
+ String quelle = "";
+ String mak = "";
+ String subtitle = "";
+
+ String entryType = "book"; // Default
+
+ // Alle relevanten Informationen einsammeln
+
+ List<Element> datafields = getChildren("datafield", e);
+ for (Element datafield : datafields) {
+ String tag = datafield.getAttribute("tag");
+ LOGGER.debug("tag: " + tag);
+
+ // mak
+ if ("002@".equals(tag)) {
+ mak = getSubfield("0", datafield);
+ if (mak == null) {
+ mak = "";
+ }
+ }
+
+ //ppn
+ if ("003@".equals(tag)) {
+ ppn = getSubfield("0", datafield);
+ }
+
+ //author
+ if ("028A".equals(tag)) {
+ String vorname = getSubfield("d", datafield);
+ String nachname = getSubfield("a", datafield);
+
+ if (author == null) {
+ author = "";
+ } else {
+ author = author.concat(" and ");
+ }
+ author = author.concat(vorname + " " + nachname);
+ }
+ //author (weiterer)
+ if ("028B".equals(tag)) {
+ String vorname = getSubfield("d", datafield);
+ String nachname = getSubfield("a", datafield);
+
+ if (author == null) {
+ author = "";
+ } else {
+ author = author.concat(" and ");
+ }
+ author = author.concat(vorname + " " + nachname);
+ }
+
+ //editor
+ if ("028C".equals(tag)) {
+ String vorname = getSubfield("d", datafield);
+ String nachname = getSubfield("a", datafield);
+
+ if (editor == null) {
+ editor = "";
+ } else {
+ editor = editor.concat(" and ");
+ }
+ editor = editor.concat(vorname + " " + nachname);
+ }
+
+ //title and subtitle
+ if ("021A".equals(tag)) {
+ title = getSubfield("a", datafield);
+ subtitle = getSubfield("d", datafield);
+ }
+
+ //publisher and address
+ if ("033A".equals(tag)) {
+ publisher = getSubfield("n", datafield);
+ address = getSubfield("p", datafield);
+ }
+
+ //year
+ if ("011@".equals(tag)) {
+ year = getSubfield("a", datafield);
+ }
+
+ //year, volume, number, pages (year bei Zeitschriften (evtl. redundant mit 011@))
+ if ("031A".equals(tag)) {
+ year = getSubfield("j", datafield);
+
+ volume = getSubfield("e", datafield);
+ number = getSubfield("a", datafield);
+ pages = getSubfield("h", datafield);
+
+ }
+
+ // 036D seems to contain more information than the other fields
+ // overwrite information using that field
+ // 036D also contains information normally found in 036E
+ if ("036D".equals(tag)) {
+ // 021 might have been present
+ if (title != null) {
+ // convert old title (contained in "a" of 021A) to volume
+ if (title.startsWith("@")) {
+ // "@" indicates a number
+ title = title.substring(1);
+ }
+ number = title;
+ }
+ //title and subtitle
+ title = getSubfield("a", datafield);
+ subtitle = getSubfield("d", datafield);
+ volume = getSubfield("l", datafield);
+ }
+
+ //series and number
+ if ("036E".equals(tag)) {
+ series = getSubfield("a", datafield);
+ number = getSubfield("l", datafield);
+ String kor = getSubfield("b", datafield);
+
+ if (kor != null) {
+ series = series + " / " + kor;
+ }
+ }
+
+ //note
+ if ("037A".equals(tag)) {
+ note = getSubfield("a", datafield);
+ }
+
+ //edition
+ if ("032@".equals(tag)) {
+ edition = getSubfield("a", datafield);
+ }
+
+ //isbn
+ if ("004A".equals(tag)) {
+ final String isbn10 = getSubfield("0", datafield);
+ final String isbn13 = getSubfield("A", datafield);
+
+ if (isbn10 != null) {
+ isbn = isbn10;
+ }
+
+ if (isbn13 != null) {
+ isbn = isbn13;
+ }
+
+ }
+
+ // Hochschulschriftenvermerk
+ // Bei einer Verlagsdissertation ist der Ort schon eingetragen
+ if ("037C".equals(tag)) {
+ if (address == null) {
+ address = getSubfield("b", datafield);
+ if (address != null) {
+ address = removeSortCharacters(address);
+ }
+ }
+
+ String st = getSubfield("a", datafield);
+ if ((st != null) && st.contains("Diss")) {
+ entryType = "phdthesis";
+ }
+ }
+
+ //journal oder booktitle
+
+ /* Problematiken hier: Sowohl für Artikel in
+ * Zeitschriften als für Beiträge in Büchern
+ * wird 027D verwendet. Der Titel muß je nach
+ * Fall booktitle oder journal zugeordnet
+ * werden. Auch bei Zeitschriften werden hier
+ * ggf. Verlag und Ort angegeben (sind dann
+ * eigentlich überflüssig), während bei
+ * Buchbeiträgen Verlag und Ort wichtig sind
+ * (sonst in Kategorie 033A).
+ */
+ if ("027D".equals(tag)) {
+ journal = getSubfield("a", datafield);
+ booktitle = getSubfield("a", datafield);
+ address = getSubfield("p", datafield);
+ publisher = getSubfield("n", datafield);
+ }
+
+ //pagetotal
+ if ("034D".equals(tag)) {
+ pagetotal = getSubfield("a", datafield);
+
+ if (pagetotal != null) {
+ // S, S. etc. entfernen
+ pagetotal = pagetotal.replaceAll(" S\\.?$", "");
+ }
+ }
+
+ // Behandlung von Konferenzen
+ if ("030F".equals(tag)) {
+ address = getSubfield("k", datafield);
+
+ if (!"proceedings".equals(entryType)) {
+ subtitle = getSubfield("a", datafield);
+ }
+
+ entryType = "proceedings";
+ }
+
+ // Wenn eine Verlagsdiss vorliegt
+ if ("phdthesis".equals(entryType) && (isbn != null)) {
+ entryType = "book";
+ }
+
+ //Hilfskategorien zur Entscheidung @article
+ //oder @incollection; hier könnte man auch die
+ //ISBN herausparsen als Erleichterung für das
+ //Auffinden der Quelle, die über die
+ //SRU-Schnittstelle gelieferten Daten zur
+ //Quelle unvollständig sind (z.B. nicht Serie
+ //und Nummer angegeben werden)
+ if ("039B".equals(tag)) {
+ quelle = getSubfield("8", datafield);
+ }
+ if ("046R".equals(tag) && ((quelle == null) || quelle.isEmpty())) {
+ quelle = getSubfield("a", datafield);
+ }
+
+ // URLs behandeln
+ if ("009P".equals(tag) && ("03".equals(datafield.getAttribute("occurrence"))
+ || "05".equals(datafield.getAttribute("occurrence"))) && (url == null)) {
+ url = getSubfield("a", datafield);
+ }
+ }
+
+ // Abfangen von Nulleintraegen
+ if (quelle == null) {
+ quelle = "";
+ }
+
+ // Nichtsortierzeichen entfernen
+ if (author != null) {
+ author = removeSortCharacters(author);
+ }
+ if (editor != null) {
+ editor = removeSortCharacters(editor);
+ }
+ if (title != null) {
+ title = removeSortCharacters(title);
+ }
+ if (subtitle != null) {
+ subtitle = removeSortCharacters(subtitle);
+ }
+
+ // Dokumenttyp bestimmen und Eintrag anlegen
+
+ if (mak.startsWith("As")) {
+ entryType = BibEntry.DEFAULT_TYPE;
+
+ if (quelle.contains("ISBN")) {
+ entryType = "incollection";
+ }
+ if (quelle.contains("ZDB-ID")) {
+ entryType = "article";
+ }
+ } else if (mak.isEmpty()) {
+ entryType = BibEntry.DEFAULT_TYPE;
+ } else if (mak.startsWith("O")) {
+ entryType = BibEntry.DEFAULT_TYPE;
+ // FIXME: online only available in Biblatex
+ //entryType = "online";
+ }
+
+
+ /*
+ * Wahrscheinlichkeit, dass ZDB-ID
+ * vorhanden ist, ist größer als ISBN bei
+ * Buchbeiträgen. Daher bei As?-Sätzen am besten immer
+ * dann @incollection annehmen, wenn weder ISBN noch
+ * ZDB-ID vorhanden sind.
+ */
+ BibEntry result = new BibEntry(IdGenerator.next(), entryType);
+
+ // Zuordnung der Felder in Abhängigkeit vom Dokumenttyp
+ if (author != null) {
+ result.setField(FieldName.AUTHOR, author);
+ }
+ if (editor != null) {
+ result.setField(FieldName.EDITOR, editor);
+ }
+ if (title != null) {
+ result.setField(FieldName.TITLE, title);
+ }
+ if (!Strings.isNullOrEmpty(subtitle)) {
+ // ensure that first letter is an upper case letter
+ // there could be the edge case that the string is only one character long, therefore, this special treatment
+ // this is Apache commons lang StringUtils.capitalize (https://commons.apache.org/proper/commons-lang/javadocs/api-release/org/apache/commons/lang3/StringUtils.html#capitalize%28java.lang.String%29), but we don't want to add an additional dependency ('org.apache.commons:commons-lang3:3.4')
+ StringBuilder newSubtitle = new StringBuilder(
+ Character.toString(Character.toUpperCase(subtitle.charAt(0))));
+ if (subtitle.length() > 1) {
+ newSubtitle.append(subtitle.substring(1));
+ }
+ result.setField(FieldName.SUBTITLE, newSubtitle.toString());
+ }
+ if (publisher != null) {
+ result.setField(FieldName.PUBLISHER, publisher);
+ }
+ if (year != null) {
+ result.setField(FieldName.YEAR, year);
+ }
+ if (address != null) {
+ result.setField(FieldName.ADDRESS, address);
+ }
+ if (series != null) {
+ result.setField(FieldName.SERIES, series);
+ }
+ if (edition != null) {
+ result.setField(FieldName.EDITION, edition);
+ }
+ if (isbn != null) {
+ result.setField(FieldName.ISBN, isbn);
+ }
+ if (issn != null) {
+ result.setField(FieldName.ISSN, issn);
+ }
+ if (number != null) {
+ result.setField(FieldName.NUMBER, number);
+ }
+ if (pagetotal != null) {
+ result.setField(FieldName.PAGETOTAL, pagetotal);
+ }
+ if (pages != null) {
+ result.setField(FieldName.PAGES, pages);
+ }
+ if (volume != null) {
+ result.setField(FieldName.VOLUME, volume);
+ }
+ if (journal != null) {
+ result.setField(FieldName.JOURNAL, journal);
+ }
+ if (ppn != null) {
+ result.setField("ppn_GVK", ppn);
+ }
+ if (url != null) {
+ result.setField(FieldName.URL, url);
+ }
+ if (note != null) {
+ result.setField(FieldName.NOTE, note);
+ }
+
+ if ("article".equals(entryType) && (journal != null)) {
+ result.setField(FieldName.JOURNAL, journal);
+ } else if ("incollection".equals(entryType) && (booktitle != null)) {
+ result.setField(FieldName.BOOKTITLE, booktitle);
+ }
+
+ return result;
+ }
+
+ private String getSubfield(String a, Element datafield) {
+ List<Element> liste = getChildren("subfield", datafield);
+
+ for (Element subfield : liste) {
+ if (subfield.getAttribute("code").equals(a)) {
+ return (subfield.getTextContent());
+ }
+ }
+ return null;
+ }
+
+ private Element getChild(String name, Element e) {
+ NodeList children = e.getChildNodes();
+
+ int j = children.getLength();
+ for (int i = 0; i < j; i++) {
+ Node test = children.item(i);
+ if (test.getNodeType() == Node.ELEMENT_NODE) {
+ Element entry = (Element) test;
+ if (entry.getTagName().equals(name)) {
+ return entry;
+ }
+ }
+ }
+ return null;
+ }
+
+ private List<Element> getChildren(String name, Element e) {
+ List<Element> result = new LinkedList<>();
+ NodeList children = e.getChildNodes();
+
+ int j = children.getLength();
+ for (int i = 0; i < j; i++) {
+ Node test = children.item(i);
+ if (test.getNodeType() == Node.ELEMENT_NODE) {
+ Element entry = (Element) test;
+ if (entry.getTagName().equals(name)) {
+ result.add(entry);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ private String removeSortCharacters(String input) {
+ return input.replaceAll("\\@", "");
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/logic/importer/fileformat/ImportFormat.java b/src/main/java/net/sf/jabref/logic/importer/fileformat/ImportFormat.java
deleted file mode 100644
index e862494..0000000
--- a/src/main/java/net/sf/jabref/logic/importer/fileformat/ImportFormat.java
+++ /dev/null
@@ -1,170 +0,0 @@
-package net.sf.jabref.logic.importer.fileformat;
-
-import java.io.BufferedReader;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Path;
-import java.util.Objects;
-
-import net.sf.jabref.logic.importer.ParserResult;
-import net.sf.jabref.logic.util.FileExtensions;
-
-/**
- * Role of an importer for JabRef.
- */
-public abstract class ImportFormat implements Comparable<ImportFormat> {
-
- /**
- * Using this when I have no database open or when I read
- * non bibtex file formats (used by the ImportFormatReader.java)
- *
- * TODO: Is this field really needed or would calling IdGenerator.next() suffice?
- */
- public static final String DEFAULT_BIBTEXENTRY_ID = "__ID";
-
- /**
- * Check whether the source is in the correct format for this importer.
- *
- * The effect of this method is primarily to avoid unnecessary processing of
- * files when searching for a suitable import format. If this method returns
- * false, the import routine will move on to the next import format.
- *
- * Thus the correct behaviour is to return false if it is certain that the file is
- * not of the suitable type, and true otherwise. Returning true is the safe choice if not certain.
- */
- protected abstract boolean isRecognizedFormat(BufferedReader input) throws IOException;
-
- public boolean isRecognizedFormat(Path filePath, Charset encoding) throws IOException {
- try (BufferedReader bufferedReader = getReader(filePath, encoding)) {
- return isRecognizedFormat(bufferedReader);
- }
- }
-
- /**
- * Parse the database in the source.
- *
- * This method can be called in two different contexts - either when importing in
- * a specified format, or when importing in unknown format. In the latter case,
- * JabRef cycles through all available import formats. No error messages or feedback
- * is displayed from individual import formats in this case.
- *
- * If importing in a specified format and an empty database is returned, JabRef reports
- * that no entries were found.
- *
- * This method should never return null.
- *
- * @param input the input to read from
- */
- protected abstract ParserResult importDatabase(BufferedReader input) throws IOException ;
-
- /**
- * Parse the database in the specified file.
- *
- * Importer having the facilities to detect the correct encoding of a file should overwrite this method,
- * determine the encoding and then call {@link #importDatabase(BufferedReader)}.
- *
- * @param filePath the path to the file which should be imported
- * @param encoding the encoding used to decode the file
- */
- public ParserResult importDatabase(Path filePath, Charset encoding) throws IOException {
- try (BufferedReader bufferedReader = getReader(filePath, encoding)) {
- ParserResult parserResult = importDatabase(bufferedReader);
- parserResult.getMetaData().setEncoding(encoding);
- parserResult.setFile(filePath.toFile());
- return parserResult;
- }
- }
-
- public static BufferedReader getUTF8Reader(Path filePath) throws IOException {
- return getReader(filePath, StandardCharsets.UTF_8);
- }
-
- public static BufferedReader getUTF16Reader(Path filePath) throws IOException {
- return getReader(filePath, StandardCharsets.UTF_16);
- }
-
- public static BufferedReader getReader(Path filePath, Charset encoding)
- throws IOException {
- InputStream stream = new FileInputStream(filePath.toFile());
- return new BufferedReader(new InputStreamReader(stream, encoding));
- }
-
- /**
- * Returns the name of this import format.
- *
- * <p>The name must be unique.</p>
- *
- * @return format name, must be unique and not <code>null</code>
- */
- public abstract String getFormatName();
-
-
- /**
- * Returns the file extensions that this importer can read
- * @return {@link FileExtensions} correspoding to the importer
- */
- public abstract FileExtensions getExtensions();
-
- /**
- * Returns a one-word ID which identifies this import format.
- * Used for example, to identify the format when used from the command line.
- *
- * @return ID, must be unique and not <code>null</code>
- */
- public String getId() {
- String id = getFormatName();
- StringBuilder result = new StringBuilder(id.length());
- for (int i = 0; i < id.length(); i++) {
- char c = id.charAt(i);
- if (Character.isLetterOrDigit(c)) {
- result.append(Character.toLowerCase(c));
- }
- }
- return result.toString();
- }
-
- /**
- * Returns the description of the import format.
- *
- * The description should specify
- * <ul><li>
- * what kind of entries from what sources and based on what specification it is able to import
- * </li><li>
- * by what criteria it {@link #isRecognizedFormat(BufferedReader) recognizes} an import format
- * </li></ul>
- *
- * @return description of the import format
- */
- public abstract String getDescription();
-
- @Override
- public int hashCode() {
- return getFormatName().hashCode();
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if(!(obj instanceof ImportFormat)) {
- return false;
- }
- ImportFormat other = (ImportFormat)obj;
- return Objects.equals(this.getFormatName(), other.getFormatName());
- }
-
- @Override
- public String toString() {
- return getFormatName();
- }
-
- @Override
- public int compareTo(ImportFormat o) {
- return getFormatName().compareTo(o.getFormatName());
- }
-}
diff --git a/src/main/java/net/sf/jabref/logic/importer/fileformat/InspecImporter.java b/src/main/java/net/sf/jabref/logic/importer/fileformat/InspecImporter.java
index a71010c..2061c11 100644
--- a/src/main/java/net/sf/jabref/logic/importer/fileformat/InspecImporter.java
+++ b/src/main/java/net/sf/jabref/logic/importer/fileformat/InspecImporter.java
@@ -8,6 +8,7 @@ import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
+import net.sf.jabref.logic.importer.Importer;
import net.sf.jabref.logic.importer.ParserResult;
import net.sf.jabref.logic.util.FileExtensions;
import net.sf.jabref.model.entry.AuthorList;
@@ -17,12 +18,12 @@ import net.sf.jabref.model.entry.FieldName;
/**
* INSPEC format importer.
*/
-public class InspecImporter extends ImportFormat {
+public class InspecImporter extends Importer {
private static final Pattern INSPEC_PATTERN = Pattern.compile("Record.*INSPEC.*");
@Override
- public String getFormatName() {
+ public String getName() {
return "INSPEC";
}
diff --git a/src/main/java/net/sf/jabref/logic/importer/fileformat/IsiImporter.java b/src/main/java/net/sf/jabref/logic/importer/fileformat/IsiImporter.java
index 60adce0..a4b70db 100644
--- a/src/main/java/net/sf/jabref/logic/importer/fileformat/IsiImporter.java
+++ b/src/main/java/net/sf/jabref/logic/importer/fileformat/IsiImporter.java
@@ -11,6 +11,7 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.sf.jabref.logic.formatter.casechanger.TitleCaseFormatter;
+import net.sf.jabref.logic.importer.Importer;
import net.sf.jabref.logic.importer.ParserResult;
import net.sf.jabref.logic.util.FileExtensions;
import net.sf.jabref.model.entry.BibEntry;
@@ -34,7 +35,7 @@ import net.sf.jabref.model.entry.MonthUtil;
* <li>Deal with capitalization correctly</li>
* </ul>
*/
-public class IsiImporter extends ImportFormat {
+public class IsiImporter extends Importer {
private static final Pattern SUB_SUP_PATTERN = Pattern.compile("/(sub|sup)\\s+(.*?)\\s*/");
@@ -44,7 +45,7 @@ public class IsiImporter extends ImportFormat {
@Override
- public String getFormatName() {
+ public String getName() {
return "ISI";
}
diff --git a/src/main/java/net/sf/jabref/logic/importer/fileformat/MedlineImporter.java b/src/main/java/net/sf/jabref/logic/importer/fileformat/MedlineImporter.java
index 95f21ee..6e1650c 100644
--- a/src/main/java/net/sf/jabref/logic/importer/fileformat/MedlineImporter.java
+++ b/src/main/java/net/sf/jabref/logic/importer/fileformat/MedlineImporter.java
@@ -2,8 +2,12 @@ package net.sf.jabref.logic.importer.fileformat;
import java.io.BufferedReader;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
import java.io.Serializable;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
@@ -18,10 +22,15 @@ import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
+import net.sf.jabref.logic.importer.Importer;
+import net.sf.jabref.logic.importer.ParseException;
+import net.sf.jabref.logic.importer.Parser;
import net.sf.jabref.logic.importer.ParserResult;
import net.sf.jabref.logic.importer.fileformat.medline.Abstract;
import net.sf.jabref.logic.importer.fileformat.medline.AbstractText;
import net.sf.jabref.logic.importer.fileformat.medline.AffiliationInfo;
+import net.sf.jabref.logic.importer.fileformat.medline.ArticleId;
+import net.sf.jabref.logic.importer.fileformat.medline.ArticleIdList;
import net.sf.jabref.logic.importer.fileformat.medline.ArticleTitle;
import net.sf.jabref.logic.importer.fileformat.medline.Author;
import net.sf.jabref.logic.importer.fileformat.medline.AuthorList;
@@ -64,10 +73,10 @@ import net.sf.jabref.logic.importer.fileformat.medline.Section;
import net.sf.jabref.logic.importer.fileformat.medline.Sections;
import net.sf.jabref.logic.importer.fileformat.medline.Text;
import net.sf.jabref.logic.util.FileExtensions;
-import net.sf.jabref.logic.util.strings.StringUtil;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.FieldName;
import net.sf.jabref.model.entry.IdGenerator;
+import net.sf.jabref.model.strings.StringUtil;
import com.google.common.base.Joiner;
import org.apache.commons.logging.Log;
@@ -75,11 +84,11 @@ import org.apache.commons.logging.LogFactory;
/**
* Importer for the Medline/Pubmed format.
- *
+ * <p>
* check here for details on the format
* https://www.nlm.nih.gov/bsd/licensee/elements_descriptions.html
*/
-public class MedlineImporter extends ImportFormat {
+public class MedlineImporter extends Importer implements Parser {
private static final Log LOGGER = LogFactory.getLog(MedlineImporter.class);
private static final String KEYWORD_SEPARATOR = "; ";
@@ -88,7 +97,7 @@ public class MedlineImporter extends ImportFormat {
@Override
- public String getFormatName() {
+ public String getName() {
return "Medline";
}
@@ -178,7 +187,7 @@ public class MedlineImporter extends ImportFormat {
Map<String, String> fields = new HashMap<>();
if (currentArticle.getBookDocument() != null) {
BookDocument bookDocument = currentArticle.getBookDocument();
- fields.put("pmid", bookDocument.getPMID().getContent());
+ fields.put(FieldName.PMID, bookDocument.getPMID().getContent());
if (bookDocument.getDateRevised() != null) {
DateRevised dateRevised = bookDocument.getDateRevised();
addDateRevised(fields, dateRevised);
@@ -318,6 +327,10 @@ public class MedlineImporter extends ImportFormat {
DateRevised dateRevised = article.getMedlineCitation().getDateRevised();
addDateRevised(fields, dateRevised);
putIfValueNotNull(fields, "pubstatus", article.getPubmedData().getPublicationStatus());
+ if (article.getPubmedData().getArticleIdList() != null) {
+ ArticleIdList articleIdList = article.getPubmedData().getArticleIdList();
+ addArticleIdList(fields, articleIdList);
+ }
}
}
if (article.getMedlineCitation() != null) {
@@ -335,7 +348,7 @@ public class MedlineImporter extends ImportFormat {
convertToDateFormat(dateCompleted.getYear(), dateCompleted.getMonth(), dateCompleted.getDay()));
}
- fields.put("pmid", medlineCitation.getPMID().getContent());
+ fields.put(FieldName.PMID, medlineCitation.getPMID().getContent());
fields.put(FieldName.OWNER, medlineCitation.getOwner());
addArticleInformation(fields, medlineCitation.getArticle().getContent());
@@ -386,6 +399,18 @@ public class MedlineImporter extends ImportFormat {
bibItems.add(entry);
}
+ private void addArticleIdList(Map<String, String> fields, ArticleIdList articleIdList) {
+ for (ArticleId id : articleIdList.getArticleId()) {
+ if (id.getIdType() != null) {
+ if ("pubmed".equals(id.getIdType())) {
+ fields.put("pmid", id.getContent());
+ } else {
+ fields.put(id.getIdType(), id.getContent());
+ }
+ }
+ }
+ }
+
private void addNotes(Map<String, String> fields, List<GeneralNote> generalNote) {
List<String> notes = new ArrayList<>();
for (GeneralNote note : generalNote) {
@@ -513,7 +538,9 @@ public class MedlineImporter extends ImportFormat {
putIfValueNotNull(fields, FieldName.JOURNAL, journal.getTitle());
ISSN issn = journal.getISSN();
- putIfValueNotNull(fields, FieldName.ISSN, issn.getContent());
+ if (issn != null) {
+ putIfValueNotNull(fields, FieldName.ISSN, issn.getContent());
+ }
JournalIssue journalIssue = journal.getJournalIssue();
putIfValueNotNull(fields, FieldName.VOLUME, journalIssue.getVolume());
@@ -539,6 +566,7 @@ public class MedlineImporter extends ImportFormat {
}
}
+
private void addElocationID(Map<String, String> fields, ELocationID eLocationID) {
if (FieldName.DOI.equals(eLocationID.getEIdType())) {
fields.put(FieldName.DOI, eLocationID.getContent());
@@ -641,7 +669,7 @@ public class MedlineImporter extends ImportFormat {
* Medline reports page ranges in a shorthand format.
* The last page is reported using only the digits which
* differ from the first page.
- * i.e. 12345-51 refers to the actual range 12345-12351
+ * i.e. 12345-51 refers to the actual range 12345-12351
*/
private String fixPageRange(String pageRange) {
int minusPos = pageRange.indexOf('-');
@@ -658,4 +686,15 @@ public class MedlineImporter extends ImportFormat {
return startPage + "--" + endPage;
}
+ @Override
+ public List<BibEntry> parseEntries(InputStream inputStream) throws ParseException {
+ try {
+ return importDatabase(
+ new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))).getDatabase().getEntries();
+
+ } catch (IOException e) {
+ LOGGER.error(e.getLocalizedMessage(), e);
+ }
+ return Collections.emptyList();
+ }
}
diff --git a/src/main/java/net/sf/jabref/logic/importer/fileformat/MedlinePlainImporter.java b/src/main/java/net/sf/jabref/logic/importer/fileformat/MedlinePlainImporter.java
index 1a25a0d..6bf291b 100644
--- a/src/main/java/net/sf/jabref/logic/importer/fileformat/MedlinePlainImporter.java
+++ b/src/main/java/net/sf/jabref/logic/importer/fileformat/MedlinePlainImporter.java
@@ -7,8 +7,10 @@ import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.Optional;
import java.util.regex.Pattern;
+import net.sf.jabref.logic.importer.Importer;
import net.sf.jabref.logic.importer.ParserResult;
import net.sf.jabref.logic.util.FileExtensions;
import net.sf.jabref.logic.util.OS;
@@ -24,7 +26,7 @@ import net.sf.jabref.model.entry.FieldName;
*
* @author vegeziel
*/
-public class MedlinePlainImporter extends ImportFormat {
+public class MedlinePlainImporter extends Importer {
private static final Pattern PMID_PATTERN = Pattern.compile("PMID.*-.*");
private static final Pattern PMC_PATTERN = Pattern.compile("PMC.*-.*");
@@ -34,7 +36,7 @@ public class MedlinePlainImporter extends ImportFormat {
@Override
- public String getFormatName() {
+ public String getName() {
return "MedlinePlain";
}
@@ -66,13 +68,12 @@ public class MedlinePlainImporter extends ImportFormat {
@Override
public ParserResult importDatabase(BufferedReader reader) throws IOException {
List<BibEntry> bibitems = new ArrayList<>();
- StringBuilder sb = new StringBuilder();
- String str;
- while ((str = reader.readLine()) != null) {
- sb.append(str);
- sb.append('\n');
- }
- String[] entries = sb.toString().replace("\u2013", "-").replace("\u2014", "--").replace("\u2015", "--")
+
+ //use optional here, so that no exception will be thrown if the file is empty
+ Optional<String> OptionalLines = reader.lines().reduce((line, nextline) -> line + "\n" + nextline);
+ String linesAsString = OptionalLines.isPresent() ? OptionalLines.get() : "";
+
+ String[] entries = linesAsString.replace("\u2013", "-").replace("\u2014", "--").replace("\u2015", "--")
.split("\\n\\n");
for (String entry1 : entries) {
diff --git a/src/main/java/net/sf/jabref/logic/importer/fileformat/ModsImporter.java b/src/main/java/net/sf/jabref/logic/importer/fileformat/ModsImporter.java
new file mode 100644
index 0000000..9210fb9
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/importer/fileformat/ModsImporter.java
@@ -0,0 +1,480 @@
+package net.sf.jabref.logic.importer.fileformat;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Unmarshaller;
+
+import net.sf.jabref.logic.importer.Importer;
+import net.sf.jabref.logic.importer.ParserResult;
+import net.sf.jabref.logic.importer.fileformat.mods.AbstractDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.DateDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.DetailDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.ExtentDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.GenreDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.HierarchicalGeographicDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.IdentifierDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.IssuanceDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.LanguageDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.LanguageTermDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.LocationDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.ModsCollectionDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.ModsDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.NameDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.NamePartDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.NoteDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.OriginInfoDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.PartDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.PhysicalLocationDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.PlaceDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.PlaceTermDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.RecordInfoDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.RelatedItemDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.StringPlusLanguage;
+import net.sf.jabref.logic.importer.fileformat.mods.StringPlusLanguagePlusAuthority;
+import net.sf.jabref.logic.importer.fileformat.mods.StringPlusLanguagePlusSupplied;
+import net.sf.jabref.logic.importer.fileformat.mods.SubjectDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.TitleInfoDefinition;
+import net.sf.jabref.logic.importer.fileformat.mods.UrlDefinition;
+import net.sf.jabref.logic.util.FileExtensions;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldName;
+import net.sf.jabref.preferences.JabRefPreferences;
+
+import com.google.common.base.Joiner;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Importer for the MODS format.<br>
+ * More details about the format can be found here <a href="http://www.loc.gov/standards/mods/">http://www.loc.gov/standards/mods/</a>. <br>
+ * The newest xml schema can also be found here <a href="www.loc.gov/standards/mods/mods-schemas.html.">www.loc.gov/standards/mods/mods-schemas.html.</a>.
+ */
+public class ModsImporter extends Importer {
+
+ private static final Log LOGGER = LogFactory.getLog(ModsImporter.class);
+ private static final String KEYWORD_SEPARATOR = JabRefPreferences.getInstance().getImportFormatPreferences()
+ .getKeywordSeparator() + " ";
+
+ private static final Pattern MODS_PATTERN = Pattern.compile("<mods .*>");
+ private JAXBContext context;
+
+
+ @Override
+ public boolean isRecognizedFormat(BufferedReader input) throws IOException {
+ return input.lines().anyMatch(line -> MODS_PATTERN.matcher(line).find());
+ }
+
+ @Override
+ public ParserResult importDatabase(BufferedReader input) throws IOException {
+ Objects.requireNonNull(input);
+
+ List<BibEntry> bibItems = new ArrayList<>();
+
+ try {
+ if (context == null) {
+ context = JAXBContext.newInstance("net.sf.jabref.logic.importer.fileformat.mods");
+ }
+ Unmarshaller unmarshaller = context.createUnmarshaller();
+
+ //The unmarshalled object is a jaxbElement.
+ JAXBElement<?> unmarshalledObject = (JAXBElement<?>) unmarshaller.unmarshal(input);
+
+ Optional<ModsCollectionDefinition> collection = getElement(unmarshalledObject.getValue(),
+ ModsCollectionDefinition.class);
+ Optional<ModsDefinition> mods = getElement(unmarshalledObject.getValue(), ModsDefinition.class);
+
+ if (collection.isPresent()) {
+ List<ModsDefinition> modsDefinitions = collection.get().getMods();
+ parseModsCollection(bibItems, modsDefinitions);
+ } else if (mods.isPresent()) {
+ ModsDefinition modsDefinition = mods.get();
+ parseMods(bibItems, modsDefinition);
+ } else {
+ LOGGER.warn("Not expected root element found");
+ }
+ } catch (JAXBException e) {
+ LOGGER.debug("could not parse document", e);
+ return ParserResult.fromErrorMessage(e.getLocalizedMessage());
+ }
+ return new ParserResult(bibItems);
+ }
+
+ private void parseModsCollection(List<BibEntry> bibItems, List<ModsDefinition> mods) {
+ for (ModsDefinition modsDefinition : mods) {
+ parseMods(bibItems, modsDefinition);
+ }
+ }
+
+ private void parseMods(List<BibEntry> bibItems, ModsDefinition modsDefinition) {
+ BibEntry entry = new BibEntry();
+ Map<String, String> fields = new HashMap<>();
+ if (modsDefinition.getID() != null) {
+ entry.setCiteKey(modsDefinition.getID());
+ }
+ if (modsDefinition.getModsGroup() != null) {
+ parseModsGroup(fields, modsDefinition.getModsGroup(), entry);
+ }
+ entry.setField(fields);
+ bibItems.add(entry);
+ }
+
+ private void parseModsGroup(Map<String, String> fields, List<Object> modsGroup, BibEntry entry) {
+ List<String> keywords = new ArrayList<>();
+ List<String> authors = new ArrayList<>();
+ List<String> notes = new ArrayList<>();
+
+ for (Object groupElement : modsGroup) {
+
+ //Get the element. Only one of the elements should be not an empty optional.
+ Optional<AbstractDefinition> abstractDefinition = getElement(groupElement, AbstractDefinition.class);
+ Optional<GenreDefinition> genreDefinition = getElement(groupElement, GenreDefinition.class);
+ Optional<LanguageDefinition> languageDefinition = getElement(groupElement, LanguageDefinition.class);
+ Optional<LocationDefinition> locationDefinition = getElement(groupElement, LocationDefinition.class);
+ Optional<NameDefinition> nameDefinition = getElement(groupElement, NameDefinition.class);
+ Optional<OriginInfoDefinition> originInfoDefinition = getElement(groupElement, OriginInfoDefinition.class);
+ Optional<RecordInfoDefinition> recordInfoDefinition = getElement(groupElement, RecordInfoDefinition.class);
+ Optional<NoteDefinition> noteDefinition = getElement(groupElement, NoteDefinition.class);
+ Optional<RelatedItemDefinition> relatedItemDefinition = getElement(groupElement,
+ RelatedItemDefinition.class);
+ Optional<SubjectDefinition> subjectDefinition = getElement(groupElement, SubjectDefinition.class);
+ Optional<IdentifierDefinition> identifierDefinition = getElement(groupElement, IdentifierDefinition.class);
+ Optional<TitleInfoDefinition> titleInfoDefinition = getElement(groupElement, TitleInfoDefinition.class);
+
+ //Now parse the information if the element is present
+ abstractDefinition
+ .ifPresent(abstractDef -> putIfValueNotNull(fields, FieldName.ABSTRACT, abstractDef.getValue()));
+
+ genreDefinition.ifPresent(genre -> entry.setType(genre.getValue()));
+
+ languageDefinition.ifPresent(
+ languageDef -> languageDef.getLanguageTerm().stream().map(LanguageTermDefinition::getValue)
+ .forEach(language -> putIfValueNotNull(fields, FieldName.LANGUAGE, language)));
+
+ locationDefinition.ifPresent(location -> parseLocationAndUrl(fields, location));
+
+ nameDefinition.ifPresent(name -> handleAuthorsInNamePart(name, authors, fields));
+
+ originInfoDefinition.ifPresent(originInfo -> originInfo.getPlaceOrPublisherOrDateIssued().stream()
+ .forEach(element -> putPlaceOrPublisherOrDate(fields, element.getName().getLocalPart(),
+ element.getValue())));
+
+ recordInfoDefinition.ifPresent(recordInfo -> parseRecordInfo(fields, recordInfo));
+
+ noteDefinition.ifPresent(note -> notes.add(note.getValue()));
+
+ relatedItemDefinition.ifPresent(relatedItem -> parseRelatedModsGroup(fields, relatedItem.getModsGroup()));
+
+ subjectDefinition
+ .ifPresent(subject -> parseTopic(fields, subject.getTopicOrGeographicOrTemporal(), keywords));
+
+ identifierDefinition.ifPresent(identifier -> parseIdentifier(fields, identifier, entry));
+
+ titleInfoDefinition.ifPresent(titleInfo -> parseTitle(fields, titleInfo.getTitleOrSubTitleOrPartNumber()));
+
+ }
+
+ //The element subject can appear more than one time, that's why the keywords has to be put out of the for loop
+ putIfListIsNotEmpty(fields, keywords, FieldName.KEYWORDS, KEYWORD_SEPARATOR);
+ //same goes for authors and notes
+ putIfListIsNotEmpty(fields, authors, FieldName.AUTHOR, " and ");
+ putIfListIsNotEmpty(fields, notes, FieldName.NOTE, ", ");
+
+ }
+
+ private void parseTitle(Map<String, String> fields, List<Object> titleOrSubTitleOrPartNumber) {
+ for (Object object : titleOrSubTitleOrPartNumber) {
+ if (object instanceof JAXBElement) {
+ @SuppressWarnings("unchecked")
+ JAXBElement<StringPlusLanguage> element = (JAXBElement<StringPlusLanguage>) object;
+ if ("title".equals(element.getName().getLocalPart())) {
+ StringPlusLanguage title = element.getValue();
+ fields.put(FieldName.TITLE, title.getValue());
+ }
+ }
+ }
+ }
+
+ private void parseIdentifier(Map<String, String> fields, IdentifierDefinition identifier, BibEntry entry) {
+ String type = identifier.getType();
+ if ("citekey".equals(type) && !entry.getCiteKeyOptional().isPresent()) {
+ entry.setCiteKey(identifier.getValue());
+ } else if (!"local".equals(type) && !"citekey".equals(type)) {
+ //put all identifiers (doi, issn, isbn,...) except of local and citekey
+ putIfValueNotNull(fields, identifier.getType(), identifier.getValue());
+ }
+ }
+
+ private void parseTopic(Map<String, String> fields, List<JAXBElement<?>> topicOrGeographicOrTemporal,
+ List<String> keywords) {
+ for (JAXBElement<?> jaxbElement : topicOrGeographicOrTemporal) {
+ Object value = jaxbElement.getValue();
+ String elementName = jaxbElement.getName().getLocalPart();
+ if (value instanceof HierarchicalGeographicDefinition) {
+ HierarchicalGeographicDefinition hierarchichalGeographic = (HierarchicalGeographicDefinition) value;
+ parseGeographicInformation(fields, hierarchichalGeographic);
+ } else if ((value instanceof StringPlusLanguagePlusAuthority) && "topic".equals(elementName)) {
+ StringPlusLanguagePlusAuthority topic = (StringPlusLanguagePlusAuthority) value;
+ keywords.add(topic.getValue().trim());
+ }
+ }
+ }
+
+ /**
+ * Returns an Optional which contains an instance of the given class, if the given element can be cast to this class.
+ * If the element can not be cast to the given class, then an empty optional will be returned.
+ *
+ * @param groupElement The element that should be cast
+ * @param clazz The class to which groupElement should be cast
+ * @return An Optional, that contains the groupElement as instance of clazz, if groupElement can be cast to clazz.
+ * An empty Optional, if groupElement can not be cast to clazz
+ */
+ private <T> Optional<T> getElement(Object groupElement, Class<T> clazz) {
+ if (clazz.isAssignableFrom(groupElement.getClass())) {
+ return Optional.of(clazz.cast(groupElement));
+ }
+ return Optional.empty();
+ }
+
+ private void parseGeographicInformation(Map<String, String> fields,
+ HierarchicalGeographicDefinition hierarchichalGeographic) {
+ List<JAXBElement<? extends StringPlusLanguage>> areaOrContinentOrCountry = hierarchichalGeographic
+ .getExtraTerrestrialAreaOrContinentOrCountry();
+ for (JAXBElement<? extends StringPlusLanguage> element : areaOrContinentOrCountry) {
+ String localName = element.getName().getLocalPart();
+ if ("city".equals(localName)) {
+ StringPlusLanguage city = element.getValue();
+ putIfValueNotNull(fields, "city", city.getValue());
+ } else if ("country".equals(localName)) {
+ StringPlusLanguage country = element.getValue();
+ putIfValueNotNull(fields, "country", country.getValue());
+ }
+ }
+ }
+
+ private void parseLocationAndUrl(Map<String, String> fields, LocationDefinition locationDefinition) {
+ List<String> locations = locationDefinition.getPhysicalLocation().stream()
+ .map(PhysicalLocationDefinition::getValue).collect(Collectors.toList());
+ putIfListIsNotEmpty(fields, locations, FieldName.LOCATION, ", ");
+
+ List<String> urls = locationDefinition.getUrl().stream().map(UrlDefinition::getValue)
+ .collect(Collectors.toList());
+ putIfListIsNotEmpty(fields, urls, FieldName.URL, ", ");
+ }
+
+ private void parseRecordInfo(Map<String, String> fields, RecordInfoDefinition recordInfo) {
+ List<JAXBElement<?>> recordContent = recordInfo.getRecordContentSourceOrRecordCreationDateOrRecordChangeDate();
+ for (JAXBElement<?> jaxbElement : recordContent) {
+ Object value = jaxbElement.getValue();
+ if (value instanceof StringPlusLanguagePlusAuthority) {
+ StringPlusLanguagePlusAuthority source = (StringPlusLanguagePlusAuthority) value;
+ putIfValueNotNull(fields, "source", source.getValue());
+ } else if (value instanceof LanguageDefinition) {
+ LanguageDefinition language = (LanguageDefinition) value;
+ List<LanguageTermDefinition> languageTerms = language.getLanguageTerm();
+ List<String> languages = languageTerms.stream().map(LanguageTermDefinition::getValue)
+ .collect(Collectors.toList());
+ putIfListIsNotEmpty(fields, languages, FieldName.LANGUAGE, ", ");
+ }
+ }
+ }
+
+ /**
+ * Puts the Information from the RelatedModsGroup. It has the same elements like the ModsGroup.
+ * But Informations like volume, issue and the pages appear here instead of in the ModsGroup.
+ * Also if there appears a title field, then this indicates that is the name of journal which the article belongs to.
+ */
+ private void parseRelatedModsGroup(Map<String, String> fields, List<Object> relatedModsGroup) {
+ for (Object groupElement : relatedModsGroup) {
+ if (groupElement instanceof PartDefinition) {
+ PartDefinition part = (PartDefinition) groupElement;
+ List<Object> detailOrExtentOrDate = part.getDetailOrExtentOrDate();
+ for (Object object : detailOrExtentOrDate) {
+ if (object instanceof DetailDefinition) {
+ DetailDefinition detail = (DetailDefinition) object;
+ List<JAXBElement<StringPlusLanguage>> numberOrCaptionOrTitle = detail
+ .getNumberOrCaptionOrTitle();
+
+ //In the for loop should only be the value of the element that belongs to the detail not be null
+ for (JAXBElement<StringPlusLanguage> jaxbElement : numberOrCaptionOrTitle) {
+ StringPlusLanguage value = jaxbElement.getValue();
+ //put details like volume, issue,...
+ putIfValueNotNull(fields, detail.getType(), value.getValue());
+ }
+ } else if (object instanceof ExtentDefinition) {
+ ExtentDefinition extentDefinition = (ExtentDefinition) object;
+ putPageInformation(extentDefinition, fields);
+ }
+ }
+ } else if (groupElement instanceof TitleInfoDefinition) {
+ TitleInfoDefinition titleInfo = (TitleInfoDefinition) groupElement;
+ List<Object> titleOrSubTitleOrPartNumber = titleInfo.getTitleOrSubTitleOrPartNumber();
+ for (Object object : titleOrSubTitleOrPartNumber) {
+ if (object instanceof JAXBElement) {
+ @SuppressWarnings("unchecked")
+ JAXBElement<StringPlusLanguage> element = (JAXBElement<StringPlusLanguage>) object;
+ if ("title".equals(element.getName().getLocalPart())) {
+ StringPlusLanguage journal = element.getValue();
+ fields.put(FieldName.JOURNAL, journal.getValue());
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private void putPageInformation(ExtentDefinition extentDefinition, Map<String, String> fields) {
+ if (extentDefinition.getTotal() != null) {
+ putIfValueNotNull(fields, FieldName.PAGES, String.valueOf(extentDefinition.getTotal()));
+ } else if (extentDefinition.getStart() != null) {
+ putIfValueNotNull(fields, FieldName.PAGES, extentDefinition.getStart().getValue());
+ if (extentDefinition.getEnd() != null) {
+ String endPage = extentDefinition.getEnd().getValue();
+ //if end appears, then there has to be a start page appeared, so get it and put it together with
+ //the end page
+ String startPage = fields.get(FieldName.PAGES);
+ fields.put(FieldName.PAGES, startPage + "-" + endPage);
+ }
+ }
+ }
+
+ private void putPlaceOrPublisherOrDate(Map<String, String> fields, String elementName, Object object) {
+ Optional<IssuanceDefinition> issuanceDefinition = getElement(object, IssuanceDefinition.class);
+ Optional<PlaceDefinition> placeDefinition = getElement(object, PlaceDefinition.class);
+ Optional<DateDefinition> dateDefinition = getElement(object, DateDefinition.class);
+ Optional<StringPlusLanguagePlusSupplied> publisherOrEdition = getElement(object,
+ StringPlusLanguagePlusSupplied.class);
+
+ issuanceDefinition.ifPresent(issuance -> putIfValueNotNull(fields, "issuance", issuance.value()));
+
+ List<String> places = new ArrayList<>();
+ placeDefinition
+ .ifPresent(place -> place.getPlaceTerm().stream().filter(placeTerm -> placeTerm.getValue() != null)
+ .map(PlaceTermDefinition::getValue).forEach(element -> places.add(element)));
+ putIfListIsNotEmpty(fields, places, FieldName.ADDRESS, ", ");
+
+ dateDefinition.ifPresent(date -> putDate(fields, elementName, date));
+
+ publisherOrEdition.ifPresent(pubOrEd -> putPublisherOrEdition(fields, elementName, pubOrEd));
+ }
+
+ private void putPublisherOrEdition(Map<String, String> fields, String elementName,
+ StringPlusLanguagePlusSupplied pubOrEd) {
+ if ("publisher".equals(elementName)) {
+ putIfValueNotNull(fields, FieldName.PUBLISHER, pubOrEd.getValue());
+ } else if ("edition".equals(elementName)) {
+ putIfValueNotNull(fields, FieldName.EDITION, pubOrEd.getValue());
+ }
+ }
+
+ private void putDate(Map<String, String> fields, String elementName, DateDefinition date) {
+ if (date.getValue() != null) {
+ switch (elementName) {
+
+ case "dateIssued":
+ //The first 4 digits of dateIssued should be the year
+ fields.put(FieldName.YEAR, date.getValue().substring(0, 4));
+ break;
+ case "dateCreated":
+ //If there was no year in date issued, then take the year from date created
+ if (fields.get(FieldName.YEAR) == null) {
+ fields.put(FieldName.YEAR, date.getValue().substring(0, 4));
+ }
+ fields.put("created", date.getValue());
+ break;
+ case "dateCaptured":
+ fields.put("captured", date.getValue());
+ break;
+ case "dateModified":
+ fields.put("modified", date.getValue());
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ private void putIfListIsNotEmpty(Map<String, String> fields, List<String> list, String key, String separator) {
+ if (!list.isEmpty()) {
+ fields.put(key, Joiner.on(separator).join(list));
+ }
+ }
+
+ private void handleAuthorsInNamePart(NameDefinition name, List<String> authors, Map<String, String> fields) {
+ List<JAXBElement<?>> namePartOrDisplayFormOrAffiliation = name.getNamePartOrDisplayFormOrAffiliation();
+ List<String> foreName = new ArrayList<>();
+ String familyName = "";
+ String author = "";
+ for (JAXBElement<?> element : namePartOrDisplayFormOrAffiliation) {
+ Object value = element.getValue();
+ String elementName = element.getName().getLocalPart();
+ if (value instanceof NamePartDefinition) {
+ NamePartDefinition namePart = (NamePartDefinition) value;
+ String type = namePart.getAtType();
+ if ((type == null) && (namePart.getValue() != null)) {
+ authors.add(namePart.getValue());
+ } else if ("family".equals(type) && (namePart.getValue() != null)) {
+ //family should come first, so if family appears we can set the author then comes before
+ //we have to check if forename and family name are not empty in case it's the first author
+ if (!foreName.isEmpty() && !familyName.isEmpty()) {
+ //now set and add the old author
+ author = familyName + ", " + Joiner.on(" ").join(foreName);
+ authors.add(author);
+ //remove old forenames
+ foreName.clear();
+ } else if (foreName.isEmpty() && !familyName.isEmpty()) {
+ authors.add(familyName);
+ }
+ familyName = namePart.getValue();
+ } else if ("given".equals(type) && (namePart.getValue() != null)) {
+ foreName.add(namePart.getValue());
+ }
+ } else if ((value instanceof StringPlusLanguage) && "affiliation".equals(elementName)) {
+ StringPlusLanguage affiliation = (StringPlusLanguage) value;
+ putIfValueNotNull(fields, "affiliation", affiliation.getValue());
+ }
+ }
+
+ //last author is not added, so do it here
+ if (!foreName.isEmpty() && !familyName.isEmpty()) {
+ author = familyName + ", " + Joiner.on(" ").join(foreName);
+ authors.add(author.trim());
+ foreName.clear();
+ } else if (foreName.isEmpty() && !familyName.isEmpty()) {
+ authors.add(familyName.trim());
+ }
+ }
+
+ private void putIfValueNotNull(Map<String, String> fields, String modsKey, String value) {
+ if (value != null) {
+ fields.put(modsKey, value);
+ }
+ }
+
+ @Override
+ public String getName() {
+ return "MODS";
+ }
+
+ @Override
+ public FileExtensions getExtensions() {
+ return FileExtensions.MODS;
+ }
+
+ @Override
+ public String getDescription() {
+ return "Importer for the MODS format";
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/logic/importer/fileformat/MsBibImporter.java b/src/main/java/net/sf/jabref/logic/importer/fileformat/MsBibImporter.java
index 77fad94..b27768f 100644
--- a/src/main/java/net/sf/jabref/logic/importer/fileformat/MsBibImporter.java
+++ b/src/main/java/net/sf/jabref/logic/importer/fileformat/MsBibImporter.java
@@ -7,6 +7,7 @@ import java.util.Objects;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
+import net.sf.jabref.logic.importer.Importer;
import net.sf.jabref.logic.importer.ParserResult;
import net.sf.jabref.logic.msbib.MSBibDatabase;
import net.sf.jabref.logic.util.FileExtensions;
@@ -20,7 +21,7 @@ import org.xml.sax.InputSource;
*
* ...
*/
-public class MsBibImporter extends ImportFormat {
+public class MsBibImporter extends Importer {
@Override
public boolean isRecognizedFormat(BufferedReader reader) throws IOException {
@@ -46,11 +47,11 @@ public class MsBibImporter extends ImportFormat {
Objects.requireNonNull(reader);
MSBibDatabase dbase = new MSBibDatabase();
- return new ParserResult(dbase.importEntries(reader));
+ return new ParserResult(dbase.importEntriesFromXml(reader));
}
@Override
- public String getFormatName() {
+ public String getName() {
return "MSBib";
}
diff --git a/src/main/java/net/sf/jabref/logic/importer/fileformat/OvidImporter.java b/src/main/java/net/sf/jabref/logic/importer/fileformat/OvidImporter.java
index da99894..e8d1793 100644
--- a/src/main/java/net/sf/jabref/logic/importer/fileformat/OvidImporter.java
+++ b/src/main/java/net/sf/jabref/logic/importer/fileformat/OvidImporter.java
@@ -9,6 +9,7 @@ import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import net.sf.jabref.logic.importer.Importer;
import net.sf.jabref.logic.importer.ParserResult;
import net.sf.jabref.logic.util.FileExtensions;
import net.sf.jabref.model.entry.AuthorList;
@@ -19,7 +20,7 @@ import net.sf.jabref.model.entry.IdGenerator;
/**
* Imports an Ovid file.
*/
-public class OvidImporter extends ImportFormat {
+public class OvidImporter extends Importer {
private static final Pattern OVID_SOURCE_PATTERN = Pattern
.compile("Source ([ \\w&\\-,:]+)\\.[ ]+([0-9]+)\\(([\\w\\-]+)\\):([0-9]+\\-?[0-9]+?)\\,.*([0-9][0-9][0-9][0-9])");
@@ -42,7 +43,7 @@ public class OvidImporter extends ImportFormat {
private static final int MAX_ITEMS = 50;
@Override
- public String getFormatName() {
+ public String getName() {
return "Ovid";
}
@@ -162,11 +163,11 @@ public class OvidImporter extends ImportFormat {
} else if ("Publication Type".equals(fieldName)) {
if (content.contains("Book")) {
- h.put("entrytype", "book");
+ h.put(BibEntry.TYPE_HEADER, "book");
} else if (content.contains("Journal")) {
- h.put("entrytype", "article");
+ h.put(BibEntry.TYPE_HEADER, "article");
} else if (content.contains("Conference Paper")) {
- h.put("entrytype", "inproceedings");
+ h.put(BibEntry.TYPE_HEADER, "inproceedings");
}
} else if (fieldName.startsWith("Language")) {
h.put(FieldName.LANGUAGE, content);
@@ -199,8 +200,8 @@ public class OvidImporter extends ImportFormat {
}
// Set the entrytype properly:
- String entryType = h.containsKey("entrytype") ? h.get("entrytype") : BibEntry.DEFAULT_TYPE;
- h.remove("entrytype");
+ String entryType = h.containsKey(BibEntry.TYPE_HEADER) ? h.get(BibEntry.TYPE_HEADER) : BibEntry.DEFAULT_TYPE;
+ h.remove(BibEntry.TYPE_HEADER);
if ("book".equals(entryType) && h.containsKey("chaptertitle")) {
// This means we have an "incollection" entry.
entryType = "incollection";
diff --git a/src/main/java/net/sf/jabref/logic/importer/fileformat/PdfContentImporter.java b/src/main/java/net/sf/jabref/logic/importer/fileformat/PdfContentImporter.java
index f4ca7d0..75e0f05 100644
--- a/src/main/java/net/sf/jabref/logic/importer/fileformat/PdfContentImporter.java
+++ b/src/main/java/net/sf/jabref/logic/importer/fileformat/PdfContentImporter.java
@@ -1,6 +1,7 @@
package net.sf.jabref.logic.importer.fileformat;
import java.io.BufferedReader;
+import java.io.FileInputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.nio.charset.Charset;
@@ -11,9 +12,11 @@ import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import net.sf.jabref.logic.importer.FetcherException;
import net.sf.jabref.logic.importer.ImportFormatPreferences;
+import net.sf.jabref.logic.importer.Importer;
import net.sf.jabref.logic.importer.ParserResult;
-import net.sf.jabref.logic.importer.fetcher.DOItoBibTeX;
+import net.sf.jabref.logic.importer.fetcher.DoiFetcher;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.util.DOI;
import net.sf.jabref.logic.util.FileExtensions;
@@ -35,7 +38,7 @@ import org.apache.pdfbox.util.PDFTextStripper;
* <p>
* Integrating XMP support is future work
*/
-public class PdfContentImporter extends ImportFormat {
+public class PdfContentImporter extends Importer {
private static final Pattern YEAR_EXTRACT_PATTERN = Pattern.compile("\\d{4}");
@@ -199,14 +202,14 @@ public class PdfContentImporter extends ImportFormat {
@Override
public ParserResult importDatabase(Path filePath, Charset defaultEncoding) {
final ArrayList<BibEntry> result = new ArrayList<>(1);
- try (PDDocument document = XMPUtil.loadWithAutomaticDecryption(filePath)) {
+ try (FileInputStream fileStream = new FileInputStream(filePath.toFile());
+ PDDocument document = XMPUtil.loadWithAutomaticDecryption(fileStream)) {
String firstPageContents = getFirstPageContents(document);
Optional<DOI> doi = DOI.findInText(firstPageContents);
if (doi.isPresent()) {
ParserResult parserResult = new ParserResult(result);
- Optional<BibEntry> entry = DOItoBibTeX.getEntryFromDOI(doi.get().getDOI(), parserResult,
- importFormatPreferences);
+ Optional<BibEntry> entry = new DoiFetcher(importFormatPreferences).performSearchById(doi.get().getDOI());
entry.ifPresent(parserResult.getDatabase()::insertEntry);
return parserResult;
}
@@ -477,6 +480,8 @@ public class PdfContentImporter extends ImportFormat {
return ParserResult.fromErrorMessage(Localization.lang("Decryption not supported."));
} catch(IOException exception) {
return ParserResult.fromErrorMessage(exception.getLocalizedMessage());
+ } catch (FetcherException e) {
+ return ParserResult.fromErrorMessage(e.getMessage());
}
return new ParserResult(result);
@@ -581,7 +586,7 @@ public class PdfContentImporter extends ImportFormat {
}
@Override
- public String getFormatName() {
+ public String getName() {
return "PDFcontent";
}
diff --git a/src/main/java/net/sf/jabref/logic/importer/fileformat/PdfXmpImporter.java b/src/main/java/net/sf/jabref/logic/importer/fileformat/PdfXmpImporter.java
index 9cb323f..175081f 100644
--- a/src/main/java/net/sf/jabref/logic/importer/fileformat/PdfXmpImporter.java
+++ b/src/main/java/net/sf/jabref/logic/importer/fileformat/PdfXmpImporter.java
@@ -6,6 +6,7 @@ import java.nio.charset.Charset;
import java.nio.file.Path;
import java.util.Objects;
+import net.sf.jabref.logic.importer.Importer;
import net.sf.jabref.logic.importer.ParserResult;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.util.FileExtensions;
@@ -13,9 +14,9 @@ import net.sf.jabref.logic.xmp.XMPPreferences;
import net.sf.jabref.logic.xmp.XMPUtil;
/**
- * Wraps the XMPUtility function to be used as an ImportFormat.
+ * Wraps the XMPUtility function to be used as an Importer.
*/
-public class PdfXmpImporter extends ImportFormat {
+public class PdfXmpImporter extends Importer {
private final XMPPreferences xmpPreferences;
@@ -25,7 +26,7 @@ public class PdfXmpImporter extends ImportFormat {
}
@Override
- public String getFormatName() {
+ public String getName() {
return Localization.lang("XMP-annotated PDF");
}
@@ -53,7 +54,7 @@ public class PdfXmpImporter extends ImportFormat {
}
@Override
- protected boolean isRecognizedFormat(BufferedReader reader) throws IOException {
+ public boolean isRecognizedFormat(BufferedReader reader) throws IOException {
Objects.requireNonNull(reader);
throw new UnsupportedOperationException(
"PdfXmpImporter does not support isRecognizedFormat(BufferedReader reader)."
@@ -77,7 +78,7 @@ public class PdfXmpImporter extends ImportFormat {
@Override
public String getDescription() {
- return "Wraps the XMPUtility function to be used as an ImportFormat.";
+ return "Wraps the XMPUtility function to be used as an Importer.";
}
}
diff --git a/src/main/java/net/sf/jabref/logic/importer/fileformat/RepecNepImporter.java b/src/main/java/net/sf/jabref/logic/importer/fileformat/RepecNepImporter.java
index b113264..4b8ca08 100644
--- a/src/main/java/net/sf/jabref/logic/importer/fileformat/RepecNepImporter.java
+++ b/src/main/java/net/sf/jabref/logic/importer/fileformat/RepecNepImporter.java
@@ -10,11 +10,11 @@ import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.GregorianCalendar;
-import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
import net.sf.jabref.logic.importer.ImportFormatPreferences;
+import net.sf.jabref.logic.importer.Importer;
import net.sf.jabref.logic.importer.ParserResult;
import net.sf.jabref.logic.util.FileExtensions;
import net.sf.jabref.model.entry.BibEntry;
@@ -144,7 +144,7 @@ import org.apache.commons.logging.LogFactory;
* @author andreas_sf at rudert-home dot de
* @see <a href="http://nep.repec.org">NEP</a>
*/
-public class RepecNepImporter extends ImportFormat {
+public class RepecNepImporter extends Importer {
private static final Log LOGGER = LogFactory.getLog(RepecNepImporter.class);
@@ -163,7 +163,7 @@ public class RepecNepImporter extends ImportFormat {
}
@Override
- public String getFormatName() {
+ public String getName() {
return "REPEC New Economic Papers (NEP)";
}
@@ -342,7 +342,7 @@ public class RepecNepImporter extends ImportFormat {
if ("Keywords".equals(keyword)) {
String content = readMultipleLines(in);
String[] keywords = content.split("[,;]");
- be.addKeywords(new LinkedHashSet<>(Arrays.asList(keywords)),
+ be.addKeywords(Arrays.asList(keywords),
importFormatPreferences.getKeywordSeparator());
// parse JEL field
} else if ("JEL".equals(keyword)) {
@@ -369,7 +369,7 @@ public class RepecNepImporter extends ImportFormat {
be.setField(FieldName.MONTH, String.valueOf(cal.get(Calendar.MONTH) + 1));
}
if ((date != null) && recognizedDateFormats[i - 1].contains("dd")) {
- be.setField("day", String.valueOf(cal.get(Calendar.DAY_OF_MONTH)));
+ be.setField(FieldName.DAY, String.valueOf(cal.get(Calendar.DAY_OF_MONTH)));
}
// parse URL field
diff --git a/src/main/java/net/sf/jabref/logic/importer/fileformat/RisImporter.java b/src/main/java/net/sf/jabref/logic/importer/fileformat/RisImporter.java
index bdff8f9..27d08b5 100644
--- a/src/main/java/net/sf/jabref/logic/importer/fileformat/RisImporter.java
+++ b/src/main/java/net/sf/jabref/logic/importer/fileformat/RisImporter.java
@@ -5,9 +5,12 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
+import java.util.Optional;
import java.util.regex.Pattern;
+import net.sf.jabref.logic.importer.Importer;
import net.sf.jabref.logic.importer.ParserResult;
import net.sf.jabref.logic.util.FileExtensions;
import net.sf.jabref.logic.util.OS;
@@ -22,12 +25,13 @@ import net.sf.jabref.model.entry.MonthUtil;
* Several Biblioscape field types are ignored. Others are only included in the BibTeX
* field "comment".
*/
-public class RisImporter extends ImportFormat {
+public class RisImporter extends Importer {
private static final Pattern RECOGNIZED_FORMAT_PATTERN = Pattern.compile("TY - .*");
+
@Override
- public String getFormatName() {
+ public String getName() {
return "RIS";
}
@@ -43,28 +47,19 @@ public class RisImporter extends ImportFormat {
@Override
public boolean isRecognizedFormat(BufferedReader reader) throws IOException {
- // Our strategy is to look for the "AU - *" line.
- String str;
- while ((str = reader.readLine()) != null) {
- if (RECOGNIZED_FORMAT_PATTERN.matcher(str).find()) {
- return true;
- }
- }
- return false;
+ // Our strategy is to look for the "TY - *" line.
+ return reader.lines().anyMatch(line -> RECOGNIZED_FORMAT_PATTERN.matcher(line).find());
}
@Override
public ParserResult importDatabase(BufferedReader reader) throws IOException {
List<BibEntry> bibitems = new ArrayList<>();
- StringBuilder sb = new StringBuilder();
- String line;
- while ((line = reader.readLine()) != null) {
- sb.append(line);
- sb.append('\n');
- }
+ //use optional here, so that no exception will be thrown if the file is empty
+ Optional<String> OptionalLines = reader.lines().reduce((line, nextline) -> line + "\n" + nextline);
+ String linesAsString = OptionalLines.isPresent() ? OptionalLines.get() : "";
- String[] entries = sb.toString().replace("\u2013", "-").replace("\u2014", "--").replace("\u2015", "--")
+ String[] entries = linesAsString.replace("\u2013", "-").replace("\u2014", "--").replace("\u2015", "--")
.split("ER -.*\\n");
for (String entry1 : entries) {
@@ -75,21 +70,20 @@ public class RisImporter extends ImportFormat {
String startPage = "";
String endPage = "";
String comment = "";
- Map<String, String> hm = new HashMap<>();
+ Map<String, String> fields = new HashMap<>();
- String[] fields = entry1.split("\n");
+ String[] lines = entry1.split("\n");
- for (int j = 0; j < fields.length; j++) {
- StringBuilder current = new StringBuilder(fields[j]);
+ for (int j = 0; j < lines.length; j++) {
+ StringBuilder current = new StringBuilder(lines[j]);
boolean done = false;
- while (!done && (j < (fields.length - 1))) {
- if ((fields[j + 1].length() >= 6) && !" - ".equals(fields[j + 1].substring(2, 6))) {
- if ((current.length() > 0)
- && !Character.isWhitespace(current.charAt(current.length() - 1))
- && !Character.isWhitespace(fields[j + 1].charAt(0))) {
+ while (!done && (j < (lines.length - 1))) {
+ if ((lines[j + 1].length() >= 6) && !" - ".equals(lines[j + 1].substring(2, 6))) {
+ if ((current.length() > 0) && !Character.isWhitespace(current.charAt(current.length() - 1))
+ && !Character.isWhitespace(lines[j + 1].charAt(0))) {
current.append(' ');
}
- current.append(fields[j + 1]);
+ current.append(lines[j + 1]);
j++;
} else {
done = true;
@@ -99,166 +93,170 @@ public class RisImporter extends ImportFormat {
if (entry.length() < 6) {
continue;
} else {
- String lab = entry.substring(0, 2);
- String val = entry.substring(6).trim();
- if ("TY".equals(lab)) {
- if ("BOOK".equals(val)) {
+ String tag = entry.substring(0, 2);
+ String value = entry.substring(6).trim();
+ if ("TY".equals(tag)) {
+ if ("BOOK".equals(value)) {
type = "book";
- } else if ("JOUR".equals(val) || "MGZN".equals(val)) {
+ } else if ("JOUR".equals(value) || "MGZN".equals(value)) {
type = "article";
- } else if ("THES".equals(val)) {
+ } else if ("THES".equals(value)) {
type = "phdthesis";
- } else if ("UNPB".equals(val)) {
+ } else if ("UNPB".equals(value)) {
type = "unpublished";
- } else if ("RPRT".equals(val)) {
+ } else if ("RPRT".equals(value)) {
type = "techreport";
- } else if ("CONF".equals(val)) {
+ } else if ("CONF".equals(value)) {
type = "inproceedings";
- } else if ("CHAP".equals(val)) {
+ } else if ("CHAP".equals(value)) {
type = "incollection";//"inbook";
+ } else if ("PAT".equals(value)) {
+ type = "patent";
} else {
type = "other";
}
- } else if ("T1".equals(lab) || "TI".equals(lab)) {
- String oldVal = hm.get(FieldName.TITLE);
+ } else if ("T1".equals(tag) || "TI".equals(tag)) {
+ String oldVal = fields.get(FieldName.TITLE);
if (oldVal == null) {
- hm.put(FieldName.TITLE, val);
+ fields.put(FieldName.TITLE, value);
} else {
if (oldVal.endsWith(":") || oldVal.endsWith(".") || oldVal.endsWith("?")) {
- hm.put(FieldName.TITLE, oldVal + " " + val);
+ fields.put(FieldName.TITLE, oldVal + " " + value);
} else {
- hm.put(FieldName.TITLE, oldVal + ": " + val);
+ fields.put(FieldName.TITLE, oldVal + ": " + value);
}
}
- hm.put(FieldName.TITLE, hm.get(FieldName.TITLE).replaceAll("\\s+", " ")); // Normalize whitespaces
- } else if ("T2".equals(lab) || "BT".equals(lab)) {
- hm.put(FieldName.BOOKTITLE, val);
- } else if ("T3".equals(lab)) {
- hm.put(FieldName.SERIES, val);
- } else if ("AU".equals(lab) || "A1".equals(lab)) {
+ fields.put(FieldName.TITLE, fields.get(FieldName.TITLE).replaceAll("\\s+", " ")); // Normalize whitespaces
+ } else if ("BT".equals(tag)) {
+ fields.put(FieldName.BOOKTITLE, value);
+ } else if ("T2".equals(tag) || "JO".equals(tag)) {
+ fields.put(FieldName.JOURNAL, value);
+ } else if ("T3".equals(tag)) {
+ fields.put(FieldName.SERIES, value);
+ } else if ("AU".equals(tag) || "A1".equals(tag)) {
if ("".equals(author)) {
- author = val;
+ author = value;
} else {
- author += " and " + val;
+ author += " and " + value;
}
- } else if ("A2".equals(lab)) {
- if ("".equals(editor)) {
- editor = val;
+ } else if ("A2".equals(tag) || "A3".equals(tag) || "A4".equals(tag)) {
+ if (editor.isEmpty()) {
+ editor = value;
} else {
- editor += " and " + val;
+ editor += " and " + value;
}
- } else if ("JA".equals(lab) || "JF".equals(lab) || "JO".equals(lab)) {
+ } else if ("JA".equals(tag) || "JF".equals(tag)) {
if ("inproceedings".equals(type)) {
- hm.put(FieldName.BOOKTITLE, val);
+ fields.put(FieldName.BOOKTITLE, value);
} else {
- hm.put(FieldName.JOURNAL, val);
+ fields.put(FieldName.JOURNAL, value);
}
- } else if ("SP".equals(lab)) {
- startPage = val;
- } else if ("PB".equals(lab)) {
+ } else if ("LA".equals(tag)) {
+ fields.put(FieldName.LANGUAGE, value);
+ } else if ("CA".equals(tag)) {
+ fields.put("caption", value);
+ } else if ("DB".equals(tag)) {
+ fields.put("database", value);
+ } else if ("IS".equals(tag)) {
+ fields.put(FieldName.NUMBER, value);
+ } else if ("SP".equals(tag)) {
+ startPage = value;
+ } else if ("PB".equals(tag)) {
if ("phdthesis".equals(type)) {
- hm.put(FieldName.SCHOOL, val);
+ fields.put(FieldName.SCHOOL, value);
} else {
- hm.put(FieldName.PUBLISHER, val);
+ fields.put(FieldName.PUBLISHER, value);
}
- } else if ("AD".equals(lab) || "CY".equals(lab)) {
- hm.put(FieldName.ADDRESS, val);
- } else if ("EP".equals(lab)) {
- endPage = val;
+ } else if ("AD".equals(tag) || "CY".equals(tag)) {
+ fields.put(FieldName.ADDRESS, value);
+ } else if ("EP".equals(tag)) {
+ endPage = value;
if (!endPage.isEmpty()) {
endPage = "--" + endPage;
}
- } else if ("SN".equals(lab)) {
- hm.put(FieldName.ISSN, val);
- } else if ("VL".equals(lab)) {
- hm.put(FieldName.VOLUME, val);
- } else if ("IS".equals(lab)) {
- hm.put(FieldName.NUMBER, val);
- } else if ("N2".equals(lab) || "AB".equals(lab)) {
- String oldAb = hm.get(FieldName.ABSTRACT);
+ } else if ("ET".equals(tag)) {
+ fields.put(FieldName.EDITION, value);
+ } else if ("SN".equals(tag)) {
+ fields.put(FieldName.ISSN, value);
+ } else if ("VL".equals(tag)) {
+ fields.put(FieldName.VOLUME, value);
+ } else if ("N2".equals(tag) || "AB".equals(tag)) {
+ String oldAb = fields.get(FieldName.ABSTRACT);
if (oldAb == null) {
- hm.put(FieldName.ABSTRACT, val);
+ fields.put(FieldName.ABSTRACT, value);
} else {
- hm.put(FieldName.ABSTRACT, oldAb + OS.NEWLINE + val);
+ fields.put(FieldName.ABSTRACT, oldAb + OS.NEWLINE + value);
}
- } else if ("UR".equals(lab)) {
- hm.put(FieldName.URL, val);
- } else if (("Y1".equals(lab) || "PY".equals(lab)) && (val.length() >= 4)) {
- String[] parts = val.split("/");
- hm.put(FieldName.YEAR, parts[0]);
+ } else if ("UR".equals(tag)) {
+ fields.put(FieldName.URL, value);
+ } else if (("Y1".equals(tag) || "PY".equals(tag) || "DA".equals(tag)) && (value.length() >= 4)) {
+ fields.put(FieldName.YEAR, value.substring(0, 4));
+ String[] parts = value.split("/");
if ((parts.length > 1) && !parts[1].isEmpty()) {
try {
-
int monthNumber = Integer.parseInt(parts[1]);
MonthUtil.Month month = MonthUtil.getMonthByNumber(monthNumber);
if (month.isValid()) {
- hm.put(FieldName.MONTH, month.bibtexFormat);
+ fields.put(FieldName.MONTH, month.bibtexFormat);
}
} catch (NumberFormatException ex) {
// The month part is unparseable, so we ignore it.
}
}
- } else if ("KW".equals(lab)) {
- if (hm.containsKey(FieldName.KEYWORDS)) {
- String kw = hm.get(FieldName.KEYWORDS);
- hm.put(FieldName.KEYWORDS, kw + ", " + val);
+ } else if ("KW".equals(tag)) {
+ if (fields.containsKey(FieldName.KEYWORDS)) {
+ String kw = fields.get(FieldName.KEYWORDS);
+ fields.put(FieldName.KEYWORDS, kw + ", " + value);
} else {
- hm.put(FieldName.KEYWORDS, val);
+ fields.put(FieldName.KEYWORDS, value);
}
- } else if ("U1".equals(lab) || "U2".equals(lab) || "N1".equals(lab)) {
+ } else if ("U1".equals(tag) || "U2".equals(tag) || "N1".equals(tag)) {
if (!comment.isEmpty()) {
comment = comment + " ";
}
- comment = comment + val;
+ comment = comment + value;
}
// Added ID import 2005.12.01, Morten Alver:
- else if ("ID".equals(lab)) {
- hm.put("refid", val);
- } else if ("M3".equals(lab)) {
- String doi = val;
- if (doi.startsWith("doi:")) {
- doi = doi.replaceAll("(?i)doi:", "").trim();
- hm.put(FieldName.DOI, doi);
- }
+ else if ("ID".equals(tag)) {
+ fields.put("refid", value);
+ } else if ("M3".equals(tag) || "DO".equals(tag)) {
+ addDoi(fields, value);
}
}
// fix authors
if (!author.isEmpty()) {
author = AuthorList.fixAuthorLastNameFirst(author);
- hm.put(FieldName.AUTHOR, author);
+ fields.put(FieldName.AUTHOR, author);
}
if (!editor.isEmpty()) {
editor = AuthorList.fixAuthorLastNameFirst(editor);
- hm.put(FieldName.EDITOR, editor);
+ fields.put(FieldName.EDITOR, editor);
}
if (!comment.isEmpty()) {
- hm.put("comment", comment);
+ fields.put("comment", comment);
}
- hm.put(FieldName.PAGES, startPage + endPage);
+ fields.put(FieldName.PAGES, startPage + endPage);
}
BibEntry b = new BibEntry(DEFAULT_BIBTEXENTRY_ID, type); // id assumes an existing database so don't
// Remove empty fields:
- List<String> toRemove = new ArrayList<>();
- for (Map.Entry<String, String> key : hm.entrySet()) {
- String content = key.getValue();
- if ((content == null) || content.trim().isEmpty()) {
- toRemove.add(key.getKey());
- }
- }
- for (String aToRemove : toRemove) {
- hm.remove(aToRemove);
-
- }
+ fields.entrySet().removeIf(key -> (key.getValue() == null) || key.getValue().trim().isEmpty());
// create one here
- b.setField(hm);
+ b.setField(fields);
bibitems.add(b);
}
-
return new ParserResult(bibitems);
}
+
+ private void addDoi(Map<String, String> hm, String val) {
+ String doi = val.toLowerCase(Locale.ENGLISH);
+ if (doi.startsWith("doi:")) {
+ doi = doi.replaceAll("(?i)doi:", "").trim();
+ hm.put(FieldName.DOI, doi);
+ }
+ }
}
diff --git a/src/main/java/net/sf/jabref/logic/importer/fileformat/SilverPlatterImporter.java b/src/main/java/net/sf/jabref/logic/importer/fileformat/SilverPlatterImporter.java
index 4f188d4..b442098 100644
--- a/src/main/java/net/sf/jabref/logic/importer/fileformat/SilverPlatterImporter.java
+++ b/src/main/java/net/sf/jabref/logic/importer/fileformat/SilverPlatterImporter.java
@@ -8,6 +8,7 @@ import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
+import net.sf.jabref.logic.importer.Importer;
import net.sf.jabref.logic.importer.ParserResult;
import net.sf.jabref.logic.util.FileExtensions;
import net.sf.jabref.model.entry.AuthorList;
@@ -18,12 +19,12 @@ import net.sf.jabref.model.entry.FieldName;
* Imports a SilverPlatter exported file. This is a poor format to parse,
* so it currently doesn't handle everything correctly.
*/
-public class SilverPlatterImporter extends ImportFormat {
+public class SilverPlatterImporter extends Importer {
private static final Pattern START_PATTERN = Pattern.compile("Record.*INSPEC.*");
@Override
- public String getFormatName() {
+ public String getName() {
return "SilverPlatter";
}
diff --git a/src/main/java/net/sf/jabref/logic/importer/fileformat/mods/package-info.java b/src/main/java/net/sf/jabref/logic/importer/fileformat/mods/package-info.java
new file mode 100644
index 0000000..0a3e5e5
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/importer/fileformat/mods/package-info.java
@@ -0,0 +1,14 @@
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4
+// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
+// Any modifications to this file will be lost upon recompilation of the source schema.
+// Generated on: 2016.09.28 at 06:51:34 PM CEST
+//
+
+// This needs to be in the src/main/java to ensure that the Namespace is mapped to the prefix "mods"
+// this can not be done by a gradle task at the moment
+ at javax.xml.bind.annotation.XmlSchema(namespace = "http://www.loc.gov/mods/v3", xmlns = {
+ @XmlNs(prefix = "mods", namespaceURI = "http://www.loc.gov/mods/v3")}, elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
+package net.sf.jabref.logic.importer.fileformat.mods;
+
+import javax.xml.bind.annotation.XmlNs;
diff --git a/src/main/java/net/sf/jabref/logic/importer/util/DBLPHelper.java b/src/main/java/net/sf/jabref/logic/importer/util/DBLPHelper.java
deleted file mode 100644
index b036187..0000000
--- a/src/main/java/net/sf/jabref/logic/importer/util/DBLPHelper.java
+++ /dev/null
@@ -1,93 +0,0 @@
-package net.sf.jabref.logic.importer.util;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import net.sf.jabref.logic.importer.ImportFormatPreferences;
-import net.sf.jabref.logic.importer.fileformat.BibtexParser;
-import net.sf.jabref.model.entry.BibEntry;
-
-public class DBLPHelper {
-
- private final DBLPQueryCleaner cleaner = new DBLPQueryCleaner();
- private static final String START_PATTERN = "<pre class=\"verbatim select-on-click\">";
- private static final String END_PATTERN = "</pre>";
-
- private final ImportFormatPreferences importFormatPreferences;
-
- /*
- * This is a small helper class that cleans the user submitted query. Right
- * now, we cannot search for ":" on dblp.org. So, we remove colons from the
- * user submitted search string. Also, the search is case sensitive if we
- * use capitals. So, we better change the text to lower case.
- */
-
- static class DBLPQueryCleaner {
-
- public String cleanQuery(final String query) {
- String cleaned = query;
-
- cleaned = cleaned.replace("-", " ").replace(" ", "%20").replace(":", "").toLowerCase();
-
- return cleaned;
- }
- }
-
-
- public DBLPHelper(ImportFormatPreferences importFormatPreferences) {
- this.importFormatPreferences = importFormatPreferences;
- }
-
- /**
- *
- * @param query
- * string with the user query
- * @return a string with the user query, but compatible with dblp.org
- */
- public String cleanDBLPQuery(String query) {
- return cleaner.cleanQuery(query);
- }
-
- /**
- * Takes an HTML file (as String) as input and extracts the bibtex
- * information. After that, it will convert it into a BibEntry and return
- * it (them).
- *
- * @param page
- * page as String
- * @return list of BibEntry
- */
- public List<BibEntry> getBibTexFromPage(final String page) {
- final List<BibEntry> bibtexList = new ArrayList<>();
-
- String tmpStr = page;
- int startIdx = tmpStr.indexOf(START_PATTERN);
- int endIdx = tmpStr.indexOf(END_PATTERN);
-
- // this entry exists for sure
- String entry1 = tmpStr.substring(startIdx + START_PATTERN.length(),
- endIdx);
- entry1 = cleanEntry(entry1);
- BibtexParser.singleFromString(entry1, importFormatPreferences).ifPresent(bibtexList::add);
-
- // let's see whether there is another entry (crossref)
- tmpStr = tmpStr
- .substring(endIdx + END_PATTERN.length(), tmpStr.length());
- startIdx = tmpStr.indexOf(START_PATTERN);
- if (startIdx != -1) {
- endIdx = tmpStr.indexOf(END_PATTERN);
- // this entry exists for sure
- String entry2 = tmpStr.substring(startIdx + START_PATTERN.length(),
- endIdx);
- entry2 = cleanEntry(entry2);
- BibtexParser.singleFromString(entry2, importFormatPreferences).ifPresent(bibtexList::add);
- }
-
- return bibtexList;
- }
-
- private String cleanEntry(final String bibEntry) {
- return bibEntry.replaceFirst("<a href=\".*\">DBLP</a>", "DBLP");
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/logic/importer/util/JSONEntryParser.java b/src/main/java/net/sf/jabref/logic/importer/util/JSONEntryParser.java
index 2b03753..ee70594 100644
--- a/src/main/java/net/sf/jabref/logic/importer/util/JSONEntryParser.java
+++ b/src/main/java/net/sf/jabref/logic/importer/util/JSONEntryParser.java
@@ -1,7 +1,6 @@
package net.sf.jabref.logic.importer.util;
import java.util.ArrayList;
-import java.util.LinkedHashSet;
import java.util.List;
import net.sf.jabref.model.entry.BibEntry;
@@ -23,7 +22,7 @@ public class JSONEntryParser {
* @param bibJsonEntry The JSONObject to convert
* @return the converted BibEntry
*/
- public BibEntry parseBibJSONtoBibtex(JSONObject bibJsonEntry, String keywordSeparator) {
+ public BibEntry parseBibJSONtoBibtex(JSONObject bibJsonEntry, Character keywordSeparator) {
// Fields that are directly accessible at the top level BibJson object
String[] singleFieldStrings = {FieldName.YEAR, FieldName.TITLE, FieldName.ABSTRACT, FieldName.MONTH};
@@ -90,13 +89,11 @@ public class JSONEntryParser {
// Keywords
if (bibJsonEntry.has("keywords")) {
JSONArray keywords = bibJsonEntry.getJSONArray("keywords");
- LinkedHashSet<String> keywordList = new LinkedHashSet<>();
for (int i = 0; i < keywords.length(); i++) {
if (!keywords.isNull(i)) {
- keywordList.add(keywords.getString(i));
+ entry.addKeyword(keywords.getString(i), keywordSeparator);
}
}
- entry.putKeywords(keywordList, keywordSeparator);
}
// Identifiers
@@ -218,7 +215,7 @@ public class JSONEntryParser {
}
// Clean up abstract (often starting with Abstract)
- entry.getFieldOptional(FieldName.ABSTRACT).ifPresent(abstractContents -> {
+ entry.getField(FieldName.ABSTRACT).ifPresent(abstractContents -> {
if (abstractContents.startsWith("Abstract")) {
entry.setField(FieldName.ABSTRACT, abstractContents.substring(8));
}
diff --git a/src/main/java/net/sf/jabref/logic/importer/util/MetaDataParser.java b/src/main/java/net/sf/jabref/logic/importer/util/MetaDataParser.java
new file mode 100644
index 0000000..ae88f7e
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/importer/util/MetaDataParser.java
@@ -0,0 +1,156 @@
+package net.sf.jabref.logic.importer.util;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+import net.sf.jabref.logic.cleanup.Cleanups;
+import net.sf.jabref.logic.groups.GroupsParser;
+import net.sf.jabref.logic.importer.ParseException;
+import net.sf.jabref.model.database.BibDatabaseMode;
+import net.sf.jabref.model.metadata.MetaData;
+import net.sf.jabref.model.metadata.SaveOrderConfig;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class MetaDataParser {
+
+ private static final Log LOGGER = LogFactory.getLog(MetaDataParser.class);
+
+
+ /**
+ * Parses the given data map and returns a new resulting {@link MetaData} instance.
+ */
+ public static MetaData parse(Map<String, String> data, Character keywordSeparator) throws ParseException {
+ return parse(new MetaData(), data, keywordSeparator);
+ }
+
+ /**
+ * Parses the data map and changes the given {@link MetaData} instance respectively.
+ */
+ public static MetaData parse(MetaData metaData, Map<String, String> data, Character keywordSeparator) throws ParseException {
+ List<String> defaultCiteKeyPattern = new ArrayList<>();
+ Map<String, List<String>> nonDefaultCiteKeyPatterns = new HashMap<>();
+
+ for (Map.Entry<String, String> entry : data.entrySet()) {
+ List<String> value = getAsList(entry.getValue());
+
+ if (entry.getKey().startsWith("selector_")) {
+ // Ignore old content selector metadata
+ continue;
+ }
+ if (entry.getKey().startsWith(MetaData.PREFIX_KEYPATTERN)) {
+ String entryType = entry.getKey().substring(MetaData.PREFIX_KEYPATTERN.length());
+ nonDefaultCiteKeyPatterns.put(entryType, Collections.singletonList(getSingleItem(value)));
+ continue;
+ }
+ if (entry.getKey().startsWith(MetaData.FILE_DIRECTORY + '-')) {
+ // The user name comes directly after "FILE_DIRECTORY-"
+ String user = entry.getKey().substring(MetaData.FILE_DIRECTORY.length() + 1);
+ metaData.setUserFileDirectory(user, getSingleItem(value));
+ continue;
+ }
+
+ switch (entry.getKey()) {
+ case MetaData.GROUPSTREE:
+ metaData.setGroups(GroupsParser.importGroups(value, keywordSeparator));
+ break;
+ case MetaData.SAVE_ACTIONS:
+ metaData.setSaveActions(Cleanups.parse(value));
+ break;
+ case MetaData.DATABASE_TYPE:
+ metaData.setMode(BibDatabaseMode.parse(getSingleItem(value)));
+ break;
+ case MetaData.KEYPATTERNDEFAULT:
+ defaultCiteKeyPattern = Collections.singletonList(getSingleItem(value));
+ break;
+ case MetaData.PROTECTED_FLAG_META:
+ if (Boolean.parseBoolean(getSingleItem(value))) {
+ metaData.markAsProtected();
+ } else {
+ metaData.markAsNotProtected();
+ }
+ break;
+ case MetaData.FILE_DIRECTORY:
+ metaData.setDefaultFileDirectory(getSingleItem(value));
+ break;
+ case MetaData.SAVE_ORDER_CONFIG:
+ metaData.setSaveOrderConfig(SaveOrderConfig.parse(value));
+ break;
+ case "groupsversion":
+ case "groups":
+ // These keys were used in previous JabRef versions, we will not support them anymore -> ignored
+ break;
+
+ }
+ }
+ if (!defaultCiteKeyPattern.isEmpty() || !nonDefaultCiteKeyPatterns.isEmpty()) {
+ metaData.setCiteKeyPattern(defaultCiteKeyPattern, nonDefaultCiteKeyPatterns);
+ }
+
+ return metaData;
+ }
+
+ /**
+ * Returns the first item in the list.
+ * If the specified list does not contain exactly one item, then a {@link ParseException} will be thrown.
+ * @param value
+ * @return
+ */
+ private static String getSingleItem(List<String> value) throws ParseException {
+ if (value.size() == 1) {
+ return value.get(0);
+ } else {
+ throw new ParseException("Expected a single item but received " + value.toString());
+ }
+ }
+
+ private static List<String> getAsList(String value) throws ParseException {
+ StringReader valueReader = new StringReader(value);
+ List<String> orderedValue = new ArrayList<>();
+
+ // We must allow for ; and \ in escape sequences.
+ try {
+ Optional<String> unit;
+ while ((unit = getNextUnit(valueReader)).isPresent()) {
+ orderedValue.add(unit.get());
+ }
+ } catch (IOException ex) {
+ LOGGER.error("Weird error while parsing meta data.", ex);
+ throw new ParseException("Weird error while parsing meta data.", ex);
+ }
+ return orderedValue;
+ }
+
+ /**
+ * Reads the next unit. Units are delimited by ';' (MetaData.SEPARATOR_CHARACTER).
+ */
+ private static Optional<String> getNextUnit(Reader reader) throws IOException {
+ int c;
+ boolean escape = false;
+ StringBuilder res = new StringBuilder();
+ while ((c = reader.read()) != -1) {
+ if (escape) {
+ res.append((char) c);
+ escape = false;
+ } else if (c == MetaData.ESCAPE_CHARACTER) {
+ escape = true;
+ } else if (c == MetaData.SEPARATOR_CHARACTER) {
+ break;
+ } else {
+ res.append((char) c);
+ }
+ }
+ if (res.length() > 0) {
+ return Optional.of(res.toString());
+ }
+ return Optional.empty();
+ }
+}
diff --git a/src/main/java/net/sf/jabref/logic/importer/util/OAI2Handler.java b/src/main/java/net/sf/jabref/logic/importer/util/OAI2Handler.java
index bb9ee65..7ba4b20 100644
--- a/src/main/java/net/sf/jabref/logic/importer/util/OAI2Handler.java
+++ b/src/main/java/net/sf/jabref/logic/importer/util/OAI2Handler.java
@@ -78,7 +78,7 @@ public class OAI2Handler extends DefaultHandler {
pages = pages.replace(" ", "");
entry.setField(FieldName.PAGES, pages);
} else if ("datestamp".equals(qualifiedName)) {
- Optional<String> year = entry.getFieldOptional(FieldName.YEAR);
+ Optional<String> year = entry.getField(FieldName.YEAR);
if (!year.isPresent() || year.get().isEmpty()) {
entry.setField(FieldName.YEAR, content.replaceFirst("-.*", ""));
}
diff --git a/src/main/java/net/sf/jabref/logic/importer/util/ParseException.java b/src/main/java/net/sf/jabref/logic/importer/util/ParseException.java
deleted file mode 100644
index 3099bf7..0000000
--- a/src/main/java/net/sf/jabref/logic/importer/util/ParseException.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package net.sf.jabref.logic.importer.util;
-
-public class ParseException extends Exception {
-
- public ParseException(String message, Throwable cause) {
- super(message, cause);
- }
-
- public ParseException(String message) {
- super(message);
- }
-}
diff --git a/src/main/java/net/sf/jabref/logic/integrity/ASCIICharacterChecker.java b/src/main/java/net/sf/jabref/logic/integrity/ASCIICharacterChecker.java
new file mode 100644
index 0000000..d762c55
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/integrity/ASCIICharacterChecker.java
@@ -0,0 +1,30 @@
+package net.sf.jabref.logic.integrity;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import net.sf.jabref.logic.integrity.IntegrityCheck.Checker;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.entry.BibEntry;
+
+import com.google.common.base.CharMatcher;
+
+public class ASCIICharacterChecker implements Checker {
+
+ /**
+ * Detect any non ASCII encoded characters, e.g., umlauts or unicode in the fields
+ */
+ @Override
+ public List<IntegrityMessage> check(BibEntry entry) {
+ List<IntegrityMessage> results = new ArrayList<>();
+ for (Map.Entry<String, String> field : entry.getFieldMap().entrySet()) {
+ boolean asciiOnly = CharMatcher.ascii().matchesAllOf(field.getValue());
+ if (!asciiOnly) {
+ results.add(new IntegrityMessage(Localization.lang("Non-ASCII encoded character found"), entry,
+ field.getKey()));
+ }
+ }
+ return results;
+ }
+}
diff --git a/src/main/java/net/sf/jabref/logic/integrity/AbbreviationChecker.java b/src/main/java/net/sf/jabref/logic/integrity/AbbreviationChecker.java
new file mode 100644
index 0000000..2935a6d
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/integrity/AbbreviationChecker.java
@@ -0,0 +1,34 @@
+package net.sf.jabref.logic.integrity;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+import net.sf.jabref.logic.integrity.IntegrityCheck.Checker;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.entry.BibEntry;
+
+public class AbbreviationChecker implements Checker {
+
+ private final String field;
+
+
+ public AbbreviationChecker(String field) {
+ this.field = field;
+ }
+
+ @Override
+ public List<IntegrityMessage> check(BibEntry entry) {
+ Optional<String> value = entry.getField(field);
+ if (!value.isPresent()) {
+ return Collections.emptyList();
+ }
+
+ if (value.get().contains(".")) {
+ return Collections
+ .singletonList(new IntegrityMessage(Localization.lang("abbreviation detected"), entry, field));
+ }
+
+ return Collections.emptyList();
+ }
+}
diff --git a/src/main/java/net/sf/jabref/logic/integrity/AuthorNameChecker.java b/src/main/java/net/sf/jabref/logic/integrity/AuthorNameChecker.java
new file mode 100644
index 0000000..fa80f2c
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/integrity/AuthorNameChecker.java
@@ -0,0 +1,36 @@
+package net.sf.jabref.logic.integrity;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+import net.sf.jabref.logic.integrity.IntegrityCheck.Checker;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldProperty;
+import net.sf.jabref.model.entry.InternalBibtexFields;
+
+public class AuthorNameChecker implements Checker {
+
+ @Override
+ public List<IntegrityMessage> check(BibEntry entry) {
+ List<IntegrityMessage> result = new ArrayList<>();
+ for (String field : entry.getFieldNames()) {
+ if (InternalBibtexFields.getFieldProperties(field).contains(FieldProperty.PERSON_NAMES)) {
+ Optional<String> value = entry.getField(field);
+ if (!value.isPresent()) {
+ return Collections.emptyList();
+ }
+
+ String valueTrimmedAndLowerCase = value.get().trim().toLowerCase();
+ if (valueTrimmedAndLowerCase.startsWith("and ") || valueTrimmedAndLowerCase.startsWith(",")) {
+ result.add(new IntegrityMessage(Localization.lang("should start with a name"), entry, field));
+ } else if (valueTrimmedAndLowerCase.endsWith(" and") || valueTrimmedAndLowerCase.endsWith(",")) {
+ result.add(new IntegrityMessage(Localization.lang("should end with a name"), entry, field));
+ }
+ }
+ }
+ return result;
+ }
+}
diff --git a/src/main/java/net/sf/jabref/logic/integrity/BibStringChecker.java b/src/main/java/net/sf/jabref/logic/integrity/BibStringChecker.java
new file mode 100644
index 0000000..4780d99
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/integrity/BibStringChecker.java
@@ -0,0 +1,45 @@
+package net.sf.jabref.logic.integrity;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import net.sf.jabref.logic.integrity.IntegrityCheck.Checker;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldProperty;
+import net.sf.jabref.model.entry.InternalBibtexFields;
+
+public class BibStringChecker implements Checker {
+
+ // Detect # if it doesn't have a \ in front of it or if it starts the string
+ private static final Pattern UNESCAPED_HASH = Pattern.compile("(?<!\\\\)#|^#");
+
+
+ /**
+ * Checks, if there is an even number of unescaped #
+ */
+ @Override
+ public List<IntegrityMessage> check(BibEntry entry) {
+ List<IntegrityMessage> results = new ArrayList<>();
+
+ Map<String, String> fields = entry.getFieldMap();
+
+ for (Map.Entry<String, String> field : fields.entrySet()) {
+ if (!InternalBibtexFields.getFieldProperties(field.getKey()).contains(FieldProperty.VERBATIM)) {
+ Matcher hashMatcher = UNESCAPED_HASH.matcher(field.getValue());
+ int hashCount = 0;
+ while (hashMatcher.find()) {
+ hashCount++;
+ }
+ if ((hashCount & 1) == 1) { // Check if odd
+ results.add(new IntegrityMessage(Localization.lang("odd number of unescaped '#'"), entry,
+ field.getKey()));
+ }
+ }
+ }
+ return results;
+ }
+}
diff --git a/src/main/java/net/sf/jabref/logic/integrity/BiblatexPagesChecker.java b/src/main/java/net/sf/jabref/logic/integrity/BiblatexPagesChecker.java
new file mode 100644
index 0000000..3f03252
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/integrity/BiblatexPagesChecker.java
@@ -0,0 +1,50 @@
+package net.sf.jabref.logic.integrity;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.function.Predicate;
+import java.util.regex.Pattern;
+
+import net.sf.jabref.logic.integrity.IntegrityCheck.Checker;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldName;
+
+/**
+* Same as {@link PagesChecker} but allows single dash as well
+*/
+public class BiblatexPagesChecker implements Checker {
+
+ private static final String PAGES_EXP = "" + "\\A" // begin String
+ + "\\d+" // number
+ + "(?:" // non-capture group
+ + "\\+|\\-{1,2}\\d+" // + or --number (range)
+ + ")?" // optional group
+ + "(?:" // non-capture group
+ + "," // comma
+ + "\\d+(?:\\+|\\-{1,2}\\d+)?" // repeat former pattern
+ + ")*" // repeat group 0,*
+ + "\\z"; // end String
+
+ private static final Predicate<String> VALID_PAGE_NUMBER = Pattern.compile(PAGES_EXP).asPredicate();
+
+
+ /**
+ * Checks, if the page numbers String conforms to the BibTex manual
+ */
+ @Override
+ public List<IntegrityMessage> check(BibEntry entry) {
+ Optional<String> value = entry.getField(FieldName.PAGES);
+ if (!value.isPresent()) {
+ return Collections.emptyList();
+ }
+
+ if (!VALID_PAGE_NUMBER.test(value.get().trim())) {
+ return Collections.singletonList(new IntegrityMessage(
+ Localization.lang("should contain a valid page number range"), entry, FieldName.PAGES));
+ }
+
+ return Collections.emptyList();
+ }
+}
diff --git a/src/main/java/net/sf/jabref/logic/integrity/BibtexkeyChecker.java b/src/main/java/net/sf/jabref/logic/integrity/BibtexkeyChecker.java
new file mode 100644
index 0000000..57410de
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/integrity/BibtexkeyChecker.java
@@ -0,0 +1,34 @@
+package net.sf.jabref.logic.integrity;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+import net.sf.jabref.logic.integrity.IntegrityCheck.Checker;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldName;
+import net.sf.jabref.model.strings.StringUtil;
+
+public class BibtexkeyChecker implements Checker {
+
+ @Override
+ public List<IntegrityMessage> check(BibEntry entry) {
+ Optional<String> valuekey = entry.getCiteKeyOptional();
+ Optional<String> valueauthor = entry.getField(FieldName.AUTHOR);
+ Optional<String> valuetitle = entry.getField(FieldName.TITLE);
+ Optional<String> valueyear = entry.getField(FieldName.YEAR);
+ String authortitleyear = entry.getAuthorTitleYear(100);
+
+ if (!valueauthor.isPresent() || !valuetitle.isPresent() || !valueyear.isPresent()) {
+ return Collections.emptyList();
+ }
+
+ if (StringUtil.isBlank(valuekey)) {
+ return Collections.singletonList(new IntegrityMessage(
+ Localization.lang("empty BibTeX key") + ": " + authortitleyear, entry, BibEntry.KEY_FIELD));
+ }
+
+ return Collections.emptyList();
+ }
+}
diff --git a/src/main/java/net/sf/jabref/logic/integrity/BibtexkeyDeviationChecker.java b/src/main/java/net/sf/jabref/logic/integrity/BibtexkeyDeviationChecker.java
new file mode 100644
index 0000000..7ac55a1
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/integrity/BibtexkeyDeviationChecker.java
@@ -0,0 +1,45 @@
+package net.sf.jabref.logic.integrity;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+import net.sf.jabref.logic.bibtexkeypattern.BibtexKeyPatternPreferences;
+import net.sf.jabref.logic.bibtexkeypattern.BibtexKeyPatternUtil;
+import net.sf.jabref.logic.integrity.IntegrityCheck.Checker;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.database.BibDatabaseContext;
+import net.sf.jabref.model.entry.BibEntry;
+
+public class BibtexkeyDeviationChecker implements Checker {
+
+ private final BibDatabaseContext bibDatabaseContext;
+ private final BibtexKeyPatternPreferences bibtexKeyPatternPreferences;
+
+ public BibtexkeyDeviationChecker(BibDatabaseContext bibDatabaseContext, BibtexKeyPatternPreferences bibtexKeyPatternPreferences) {
+ this.bibDatabaseContext = Objects.requireNonNull(bibDatabaseContext);
+ this.bibtexKeyPatternPreferences = Objects.requireNonNull(bibtexKeyPatternPreferences);
+ }
+
+ @Override
+ public List<IntegrityMessage> check(BibEntry entry) {
+ Optional<String> valuekey = entry.getCiteKeyOptional();
+ if (!valuekey.isPresent()) {
+ return Collections.emptyList();
+ }
+
+ String key = valuekey.get();
+
+ // generate new key
+ String generatedKey = BibtexKeyPatternUtil.makeLabel(bibDatabaseContext, entry, bibtexKeyPatternPreferences);
+
+ if (!Objects.equals(key, generatedKey)) {
+ return Collections.singletonList(new IntegrityMessage(
+ Localization.lang("BibTeX key %0 deviates from generated key %1", key, generatedKey), entry, BibEntry.KEY_FIELD));
+ }
+
+ return Collections.emptyList();
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/logic/integrity/BooktitleChecker.java b/src/main/java/net/sf/jabref/logic/integrity/BooktitleChecker.java
new file mode 100644
index 0000000..4f8b02a
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/integrity/BooktitleChecker.java
@@ -0,0 +1,30 @@
+package net.sf.jabref.logic.integrity;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+import java.util.Optional;
+
+import net.sf.jabref.logic.integrity.IntegrityCheck.Checker;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldName;
+
+public class BooktitleChecker implements Checker {
+
+ @Override
+ public List<IntegrityMessage> check(BibEntry entry) {
+ String field = FieldName.BOOKTITLE;
+ Optional<String> value = entry.getField(field);
+ if (!value.isPresent()) {
+ return Collections.emptyList();
+ }
+
+ if (value.get().toLowerCase(Locale.ENGLISH).endsWith("conference on")) {
+ return Collections.singletonList(
+ new IntegrityMessage(Localization.lang("booktitle ends with 'conference on'"), entry, field));
+ }
+
+ return Collections.emptyList();
+ }
+}
diff --git a/src/main/java/net/sf/jabref/logic/integrity/BracketChecker.java b/src/main/java/net/sf/jabref/logic/integrity/BracketChecker.java
new file mode 100644
index 0000000..94d79ac
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/integrity/BracketChecker.java
@@ -0,0 +1,50 @@
+package net.sf.jabref.logic.integrity;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+import net.sf.jabref.logic.integrity.IntegrityCheck.Checker;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.entry.BibEntry;
+
+public class BracketChecker implements Checker {
+
+ private final String field;
+
+
+ public BracketChecker(String field) {
+ this.field = field;
+ }
+
+ @Override
+ public List<IntegrityMessage> check(BibEntry entry) {
+ Optional<String> value = entry.getField(field);
+ if (!value.isPresent()) {
+ return Collections.emptyList();
+ }
+
+ // metaphor: integer-based stack (push + / pop -)
+ int counter = 0;
+ for (char a : value.get().trim().toCharArray()) {
+ if (a == '{') {
+ counter++;
+ } else if (a == '}') {
+ if (counter == 0) {
+ return Collections.singletonList(
+ new IntegrityMessage(Localization.lang("unexpected closing curly bracket"), entry, field));
+ } else {
+ counter--;
+ }
+ }
+ }
+
+ if (counter > 0) {
+ return Collections.singletonList(
+ new IntegrityMessage(Localization.lang("unexpected opening curly bracket"), entry, field));
+ }
+
+ return Collections.emptyList();
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/logic/integrity/DOIValidityChecker.java b/src/main/java/net/sf/jabref/logic/integrity/DOIValidityChecker.java
new file mode 100644
index 0000000..ebcdd33
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/integrity/DOIValidityChecker.java
@@ -0,0 +1,22 @@
+package net.sf.jabref.logic.integrity;
+
+import java.util.Collections;
+import java.util.List;
+
+import net.sf.jabref.logic.integrity.IntegrityCheck.Checker;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.logic.util.DOI;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldName;
+
+public class DOIValidityChecker implements Checker {
+
+ @Override
+ public List<IntegrityMessage> check(BibEntry entry) {
+ final String field = FieldName.DOI;
+ return entry.getField(field)
+ .filter(d -> !DOI.isValid(d))
+ .map(d -> Collections.singletonList(new IntegrityMessage(Localization.lang("DOI %0 is invalid", d), entry, field)))
+ .orElse(Collections.emptyList());
+ }
+}
diff --git a/src/main/java/net/sf/jabref/logic/integrity/EditionChecker.java b/src/main/java/net/sf/jabref/logic/integrity/EditionChecker.java
new file mode 100644
index 0000000..eb2f0e4
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/integrity/EditionChecker.java
@@ -0,0 +1,60 @@
+package net.sf.jabref.logic.integrity;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.function.Predicate;
+import java.util.regex.Pattern;
+
+import net.sf.jabref.logic.integrity.IntegrityCheck.Checker;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.database.BibDatabaseContext;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldName;
+
+public class EditionChecker implements Checker {
+
+ private static final Predicate<String> FIRST_LETTER_CAPITALIZED = Pattern.compile("^[A-Z]").asPredicate();
+ private static final Predicate<String> ONLY_NUMERALS_OR_LITERALS = Pattern.compile("^([0-9]+|[^0-9].+)$")
+ .asPredicate();
+
+ private final BibDatabaseContext bibDatabaseContextEdition;
+
+
+ public EditionChecker(BibDatabaseContext bibDatabaseContext) {
+ this.bibDatabaseContextEdition = Objects.requireNonNull(bibDatabaseContext);
+ }
+
+ /**
+ * Checks, if field contains only an integer or a literal (BibLaTeX mode)
+ * Checks, if the first letter is capitalized (BibTeX mode)
+ * BibLaTeX package documentation:
+ * The edition of a printed publication. This must be an integer, not an ordinal.
+ * It is also possible to give the edition as a literal string, for example "Third, revised and expanded edition".
+ * Official BibTeX specification:
+ * The edition of a book-for example, "Second".
+ * This should be an ordinal, and should have the first letter capitalized.
+ */
+ @Override
+ public List<IntegrityMessage> check(BibEntry entry) {
+ Optional<String> value = entry.getField(FieldName.EDITION);
+ if (!value.isPresent()) {
+ return Collections.emptyList();
+ }
+
+ //BibLaTeX
+ if (bibDatabaseContextEdition.isBiblatexMode() && !ONLY_NUMERALS_OR_LITERALS.test(value.get().trim())) {
+ return Collections.singletonList(new IntegrityMessage(
+ Localization.lang("should contain an integer or a literal"), entry, FieldName.EDITION));
+ }
+
+ //BibTeX
+ if (!bibDatabaseContextEdition.isBiblatexMode() && !FIRST_LETTER_CAPITALIZED.test(value.get().trim())) {
+ return Collections.singletonList(new IntegrityMessage(
+ Localization.lang("should have the first letter capitalized"), entry, FieldName.EDITION));
+ }
+
+ return Collections.emptyList();
+ }
+}
diff --git a/src/main/java/net/sf/jabref/logic/integrity/EntryLinkChecker.java b/src/main/java/net/sf/jabref/logic/integrity/EntryLinkChecker.java
new file mode 100644
index 0000000..8d9b4ed
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/integrity/EntryLinkChecker.java
@@ -0,0 +1,51 @@
+package net.sf.jabref.logic.integrity;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.Set;
+
+import net.sf.jabref.logic.integrity.IntegrityCheck.Checker;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.database.BibDatabase;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldProperty;
+import net.sf.jabref.model.entry.InternalBibtexFields;
+
+
+public class EntryLinkChecker implements Checker {
+
+ private final BibDatabase database;
+
+
+ public EntryLinkChecker(BibDatabase database) {
+ this.database = Objects.requireNonNull(database);
+ }
+
+ @Override
+ public List<IntegrityMessage> check(BibEntry entry) {
+ List<IntegrityMessage> result = new ArrayList<>();
+ for (Entry<String,String> field : entry.getFieldMap().entrySet()) {
+ Set<FieldProperty> properties = InternalBibtexFields.getFieldProperties(field.getKey());
+ if (properties.contains(FieldProperty.SINGLE_ENTRY_LINK)) {
+ if (!database.getEntryByKey(field.getValue()).isPresent()) {
+ result.add(new IntegrityMessage(Localization.lang("Referenced BibTeX key does not exist"), entry,
+ field.getKey()));
+ }
+ } else if (properties.contains(FieldProperty.MULTIPLE_ENTRY_LINK)) {
+ List<String> keys = new ArrayList<>(Arrays.asList(field.getValue().split(",")));
+ for (String key : keys) {
+ if (!database.getEntryByKey(key).isPresent()) {
+ result.add(new IntegrityMessage(
+ Localization.lang("Referenced BibTeX key does not exist") + ": " + key, entry,
+ field.getKey()));
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/logic/integrity/FileChecker.java b/src/main/java/net/sf/jabref/logic/integrity/FileChecker.java
new file mode 100644
index 0000000..dbbbb2a
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/integrity/FileChecker.java
@@ -0,0 +1,51 @@
+package net.sf.jabref.logic.integrity;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import net.sf.jabref.logic.integrity.IntegrityCheck.Checker;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.logic.util.io.FileUtil;
+import net.sf.jabref.model.database.BibDatabaseContext;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldName;
+import net.sf.jabref.model.entry.FileField;
+import net.sf.jabref.model.entry.ParsedFileField;
+import net.sf.jabref.model.metadata.FileDirectoryPreferences;
+
+public class FileChecker implements Checker {
+
+ private final BibDatabaseContext context;
+ private final FileDirectoryPreferences fileDirectoryPreferences;
+
+
+ public FileChecker(BibDatabaseContext context, FileDirectoryPreferences fileDirectoryPreferences) {
+ this.context = context;
+ this.fileDirectoryPreferences = fileDirectoryPreferences;
+ }
+
+ @Override
+ public List<IntegrityMessage> check(BibEntry entry) {
+ Optional<String> value = entry.getField(FieldName.FILE);
+ if (!value.isPresent()) {
+ return Collections.emptyList();
+ }
+
+ List<ParsedFileField> parsedFileFields = FileField.parse(value.get()).stream()
+ .filter(p -> !(p.getLink().startsWith("http://") || p.getLink().startsWith("https://")))
+ .collect(Collectors.toList());
+
+ for (ParsedFileField p : parsedFileFields) {
+ Optional<File> file = FileUtil.expandFilename(context, p.getLink(), fileDirectoryPreferences);
+ if ((!file.isPresent()) || !file.get().exists()) {
+ return Collections.singletonList(new IntegrityMessage(
+ Localization.lang("link should refer to a correct file path"), entry, FieldName.FILE));
+ }
+ }
+
+ return Collections.emptyList();
+ }
+}
diff --git a/src/main/java/net/sf/jabref/logic/integrity/HTMLCharacterChecker.java b/src/main/java/net/sf/jabref/logic/integrity/HTMLCharacterChecker.java
new file mode 100644
index 0000000..e9be617
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/integrity/HTMLCharacterChecker.java
@@ -0,0 +1,39 @@
+package net.sf.jabref.logic.integrity;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import net.sf.jabref.logic.integrity.IntegrityCheck.Checker;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldProperty;
+import net.sf.jabref.model.entry.InternalBibtexFields;
+
+public class HTMLCharacterChecker implements Checker {
+ // Detect any HTML encoded character,
+ private static final Pattern HTML_CHARACTER_PATTERN = Pattern.compile("&[#\\p{Alnum}]+;");
+
+ /**
+ * Checks, if there are any HTML encoded characters in nonverbatim fields.
+ */
+ @Override
+ public List<IntegrityMessage> check(BibEntry entry) {
+ List<IntegrityMessage> results = new ArrayList<>();
+ for (Map.Entry<String, String> field : entry.getFieldMap().entrySet()) {
+ // skip verbatim fields
+ if (InternalBibtexFields.getFieldProperties(field.getKey()).contains(FieldProperty.VERBATIM)) {
+ continue;
+ }
+
+ Matcher characterMatcher = HTML_CHARACTER_PATTERN.matcher(field.getValue());
+ if (characterMatcher.find()) {
+ results.add(
+ new IntegrityMessage(Localization.lang("HTML encoded character found"), entry, field.getKey()));
+ }
+ }
+ return results;
+ }
+}
diff --git a/src/main/java/net/sf/jabref/logic/integrity/HowpublishedChecker.java b/src/main/java/net/sf/jabref/logic/integrity/HowpublishedChecker.java
new file mode 100644
index 0000000..e9d7587
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/integrity/HowpublishedChecker.java
@@ -0,0 +1,48 @@
+package net.sf.jabref.logic.integrity;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.function.Predicate;
+import java.util.regex.Pattern;
+
+import net.sf.jabref.logic.integrity.IntegrityCheck.Checker;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.database.BibDatabaseContext;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldName;
+
+public class HowpublishedChecker implements Checker {
+
+ private static final Predicate<String> FIRST_LETTER_CAPITALIZED = Pattern.compile("^[A-Z]").asPredicate();
+
+ private final BibDatabaseContext bibDatabaseContextEdition;
+
+
+ public HowpublishedChecker(BibDatabaseContext bibDatabaseContext) {
+ this.bibDatabaseContextEdition = Objects.requireNonNull(bibDatabaseContext);
+ }
+
+ /**
+ * BibLaTeX package documentation (Section 4.9.1):
+ * The BibLaTeX package will automatically capitalize the first word when required at the beginning of a sentence.
+ * Official BibTeX specification:
+ * howpublished: How something strange has been published. The first word should be capitalized.
+ */
+ @Override
+ public List<IntegrityMessage> check(BibEntry entry) {
+ Optional<String> value = entry.getField(FieldName.HOWPUBLISHED);
+ if (!value.isPresent()) {
+ return Collections.emptyList();
+ }
+
+ //BibTeX
+ if (!bibDatabaseContextEdition.isBiblatexMode() && !FIRST_LETTER_CAPITALIZED.test(value.get().trim())) {
+ return Collections.singletonList(new IntegrityMessage(
+ Localization.lang("should have the first letter capitalized"), entry, FieldName.HOWPUBLISHED));
+ }
+
+ return Collections.emptyList();
+ }
+}
diff --git a/src/main/java/net/sf/jabref/logic/integrity/ISBNChecker.java b/src/main/java/net/sf/jabref/logic/integrity/ISBNChecker.java
index 81642f3..d6c7bc8 100644
--- a/src/main/java/net/sf/jabref/logic/integrity/ISBNChecker.java
+++ b/src/main/java/net/sf/jabref/logic/integrity/ISBNChecker.java
@@ -20,7 +20,7 @@ public class ISBNChecker implements Checker {
}
// Check that the ISBN is on the correct form
- ISBN isbn = new ISBN(entry.getFieldOptional(FieldName.ISBN).get());
+ ISBN isbn = new ISBN(entry.getField(FieldName.ISBN).get());
if (!isbn.isValidFormat()) {
return Collections.singletonList(
diff --git a/src/main/java/net/sf/jabref/logic/integrity/ISSNChecker.java b/src/main/java/net/sf/jabref/logic/integrity/ISSNChecker.java
index 4529793..e397670 100644
--- a/src/main/java/net/sf/jabref/logic/integrity/ISSNChecker.java
+++ b/src/main/java/net/sf/jabref/logic/integrity/ISSNChecker.java
@@ -3,7 +3,6 @@ package net.sf.jabref.logic.integrity;
import java.util.Collections;
import java.util.List;
-
import net.sf.jabref.logic.integrity.IntegrityCheck.Checker;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.util.ISSN;
@@ -21,7 +20,7 @@ public class ISSNChecker implements Checker {
}
// Check that the ISSN is on the correct form
- String issnString = entry.getFieldOptional(FieldName.ISSN).get().trim();
+ String issnString = entry.getField(FieldName.ISSN).get().trim();
ISSN issn = new ISSN(issnString);
if (!issn.isValidFormat()) {
diff --git a/src/main/java/net/sf/jabref/logic/integrity/IntegrityCheck.java b/src/main/java/net/sf/jabref/logic/integrity/IntegrityCheck.java
index 5ffd007..618d5b6 100644
--- a/src/main/java/net/sf/jabref/logic/integrity/IntegrityCheck.java
+++ b/src/main/java/net/sf/jabref/logic/integrity/IntegrityCheck.java
@@ -1,36 +1,29 @@
package net.sf.jabref.logic.integrity;
-import java.io.File;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
-import java.util.Locale;
-import java.util.Map;
import java.util.Objects;
-import java.util.Optional;
-import java.util.function.Predicate;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-import net.sf.jabref.BibDatabaseContext;
-import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.logic.util.io.FileUtil;
+import net.sf.jabref.logic.bibtexkeypattern.BibtexKeyPatternPreferences;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.FieldName;
-import net.sf.jabref.model.entry.FieldProperties;
-import net.sf.jabref.model.entry.FileField;
import net.sf.jabref.model.entry.InternalBibtexFields;
-import net.sf.jabref.model.entry.ParsedFileField;
-
-import com.google.common.base.CharMatcher;
+import net.sf.jabref.model.metadata.FileDirectoryPreferences;
public class IntegrityCheck {
private final BibDatabaseContext bibDatabaseContext;
+ private final FileDirectoryPreferences fileDirectoryPreferences;
+ private final BibtexKeyPatternPreferences bibtexKeyPatternPreferences;
- public IntegrityCheck(BibDatabaseContext bibDatabaseContext) {
+ public IntegrityCheck(BibDatabaseContext bibDatabaseContext,
+ FileDirectoryPreferences fileDirectoryPreferences,
+ BibtexKeyPatternPreferences bibtexKeyPatternPreferences
+ ) {
this.bibDatabaseContext = Objects.requireNonNull(bibDatabaseContext);
+ this.fileDirectoryPreferences = Objects.requireNonNull(fileDirectoryPreferences);
+ this.bibtexKeyPatternPreferences = Objects.requireNonNull(bibtexKeyPatternPreferences);
}
public List<IntegrityMessage> checkBibtexDatabase() {
@@ -57,14 +50,20 @@ public class IntegrityCheck {
result.addAll(new TitleChecker().check(entry));
result.addAll(new PagesChecker().check(entry));
result.addAll(new ASCIICharacterChecker().check(entry));
+ result.addAll(new NoBibtexFieldChecker().check(entry));
} else {
result.addAll(new BiblatexPagesChecker().check(entry));
}
result.addAll(new BracketChecker(FieldName.TITLE).check(entry));
result.addAll(new YearChecker().check(entry));
+ result.addAll(new BibtexkeyChecker().check(entry));
+ result.addAll(new EditionChecker(bibDatabaseContext).check(entry));
+ result.addAll(new NoteChecker(bibDatabaseContext).check(entry));
+ result.addAll(new HowpublishedChecker(bibDatabaseContext).check(entry));
+ result.addAll(new MonthChecker(bibDatabaseContext).check(entry));
result.addAll(new UrlChecker().check(entry));
- result.addAll(new FileChecker(bibDatabaseContext).check(entry));
+ result.addAll(new FileChecker(bibDatabaseContext, fileDirectoryPreferences).check(entry));
result.addAll(new TypeChecker().check(entry));
for (String journalField : InternalBibtexFields.getJournalNameFields()) {
result.addAll(new AbbreviationChecker(journalField).check(entry));
@@ -77,6 +76,9 @@ public class IntegrityCheck {
result.addAll(new BooktitleChecker().check(entry));
result.addAll(new ISSNChecker().check(entry));
result.addAll(new ISBNChecker().check(entry));
+ result.addAll(new DOIValidityChecker().check(entry));
+ result.addAll(new EntryLinkChecker(bibDatabaseContext.getDatabase()).check(entry));
+ result.addAll(new BibtexkeyDeviationChecker(bibDatabaseContext, bibtexKeyPatternPreferences).check(entry));
return result;
}
@@ -86,387 +88,4 @@ public class IntegrityCheck {
public interface Checker {
List<IntegrityMessage> check(BibEntry entry);
}
-
- private static class TypeChecker implements Checker {
-
- @Override
- public List<IntegrityMessage> check(BibEntry entry) {
- Optional<String> value = entry.getFieldOptional(FieldName.PAGES);
- if (!value.isPresent()) {
- return Collections.emptyList();
- }
-
- if ("proceedings".equalsIgnoreCase(entry.getType())) {
- return Collections.singletonList(new IntegrityMessage(Localization.lang("wrong entry type as proceedings has page numbers"), entry, FieldName.PAGES));
- }
-
- return Collections.emptyList();
- }
- }
-
- private static class BooktitleChecker implements Checker {
-
- @Override
- public List<IntegrityMessage> check(BibEntry entry) {
- String field = FieldName.BOOKTITLE;
- Optional<String> value = entry.getFieldOptional(field);
- if (!value.isPresent()) {
- return Collections.emptyList();
- }
-
- if (value.get().toLowerCase(Locale.ENGLISH).endsWith("conference on")) {
- return Collections.singletonList(new IntegrityMessage(Localization.lang("booktitle ends with 'conference on'"), entry, field));
- }
-
- return Collections.emptyList();
- }
- }
-
- private static class AbbreviationChecker implements Checker {
-
- private final String field;
-
- private AbbreviationChecker(String field) {
- this.field = field;
- }
-
- @Override
- public List<IntegrityMessage> check(BibEntry entry) {
- Optional<String> value = entry.getFieldOptional(field);
- if (!value.isPresent()) {
- return Collections.emptyList();
- }
-
- if (value.get().contains(".")) {
- return Collections.singletonList(new IntegrityMessage(Localization.lang("abbreviation detected"), entry, field));
- }
-
- return Collections.emptyList();
- }
- }
-
- private static class FileChecker implements Checker {
-
- private final BibDatabaseContext context;
-
- private FileChecker(BibDatabaseContext context) {
- this.context = context;
- }
-
- @Override
- public List<IntegrityMessage> check(BibEntry entry) {
- Optional<String> value = entry.getFieldOptional(FieldName.FILE);
- if (!value.isPresent()) {
- return Collections.emptyList();
- }
-
- List<ParsedFileField> parsedFileFields = FileField.parse(value.get()).stream()
- .filter(p -> !(p.getLink().startsWith("http://") || p.getLink().startsWith("https://")))
- .collect(Collectors.toList());
-
- for (ParsedFileField p : parsedFileFields) {
- Optional<File> file = FileUtil.expandFilename(context, p.getLink());
- if ((!file.isPresent()) || !file.get().exists()) {
- return Collections.singletonList(
- new IntegrityMessage(Localization.lang("link should refer to a correct file path"), entry,
- FieldName.FILE));
- }
- }
-
- return Collections.emptyList();
- }
- }
-
- private static class UrlChecker implements Checker {
-
- @Override
- public List<IntegrityMessage> check(BibEntry entry) {
- Optional<String> value = entry.getFieldOptional(FieldName.URL);
- if (!value.isPresent()) {
- return Collections.emptyList();
- }
-
- if (!value.get().contains("://")) {
- return Collections.singletonList(new IntegrityMessage(Localization.lang("should contain a protocol") + ": http[s]://, file://, ftp://, ...", entry, FieldName.URL));
- }
-
- return Collections.emptyList();
- }
- }
-
- private static class AuthorNameChecker implements Checker {
-
- @Override
- public List<IntegrityMessage> check(BibEntry entry) {
- List<IntegrityMessage> result = new ArrayList<>();
- for (String field : entry.getFieldNames()) {
- if (InternalBibtexFields.getFieldExtras(field).contains(FieldProperties.PERSON_NAMES)) {
- Optional<String> value = entry.getFieldOptional(field);
- if (!value.isPresent()) {
- return Collections.emptyList();
- }
-
- String valueTrimmedAndLowerCase = value.get().trim().toLowerCase();
- if (valueTrimmedAndLowerCase.startsWith("and ") || valueTrimmedAndLowerCase.startsWith(",")) {
- result.add(new IntegrityMessage(Localization.lang("should start with a name"), entry, field));
- } else if (valueTrimmedAndLowerCase.endsWith(" and") || valueTrimmedAndLowerCase.endsWith(",")) {
- result.add(new IntegrityMessage(Localization.lang("should end with a name"), entry, field));
- }
- }
- }
- return result;
- }
- }
-
- private static class BracketChecker implements Checker {
-
- private final String field;
-
- private BracketChecker(String field) {
- this.field = field;
- }
-
- @Override
- public List<IntegrityMessage> check(BibEntry entry) {
- Optional<String> value = entry.getFieldOptional(field);
- if (!value.isPresent()) {
- return Collections.emptyList();
- }
-
- // metaphor: integer-based stack (push + / pop -)
- int counter = 0;
- for (char a : value.get().trim().toCharArray()) {
- if (a == '{') {
- counter++;
- } else if (a == '}') {
- if (counter == 0) {
- return Collections.singletonList(new IntegrityMessage(Localization.lang("unexpected closing curly bracket"), entry, field));
- } else {
- counter--;
- }
- }
- }
-
- if (counter > 0) {
- return Collections.singletonList(new IntegrityMessage(Localization.lang("unexpected opening curly bracket"), entry, field));
- }
-
- return Collections.emptyList();
- }
-
- }
-
- private static class TitleChecker implements Checker {
-
- private static final Pattern INSIDE_CURLY_BRAKETS = Pattern.compile("\\{[^}\\{]*\\}");
- private static final Predicate<String> HAS_CAPITAL_LETTERS = Pattern.compile("[\\p{Lu}\\p{Lt}]").asPredicate();
-
- @Override
- public List<IntegrityMessage> check(BibEntry entry) {
- Optional<String> value = entry.getFieldOptional(FieldName.TITLE);
- if (!value.isPresent()) {
- return Collections.emptyList();
- }
-
-
- /*
- * Algorithm:
- * - remove trailing whitespaces
- * - ignore first letter as this can always be written in caps
- * - remove everything that is in brackets
- * - check if at least one capital letter is in the title
- */
- String valueTrimmed = value.get().trim();
- String valueIgnoringFirstLetter = valueTrimmed.startsWith("{") ? valueTrimmed : valueTrimmed.substring(1);
- String valueOnlySpacesWithinCurlyBraces = valueIgnoringFirstLetter;
- while (true) {
- Matcher matcher = INSIDE_CURLY_BRAKETS.matcher(valueOnlySpacesWithinCurlyBraces);
- if (!matcher.find()) {
- break;
- }
- valueOnlySpacesWithinCurlyBraces = matcher.replaceAll("");
- }
-
- boolean hasCapitalLettersThatBibtexWillConvertToSmallerOnes = HAS_CAPITAL_LETTERS.test(valueOnlySpacesWithinCurlyBraces);
-
- if (hasCapitalLettersThatBibtexWillConvertToSmallerOnes) {
- return Collections.singletonList(new IntegrityMessage(Localization.lang("large capitals are not masked using curly brackets {}"), entry, FieldName.TITLE));
- }
-
- return Collections.emptyList();
- }
- }
-
- private static class YearChecker implements Checker {
-
- private static final Predicate<String> CONTAINS_FOUR_DIGIT = Pattern.compile("([^0-9]|^)[0-9]{4}([^0-9]|$)").asPredicate();
-
- /**
- * Checks, if the number String contains a four digit year
- */
- @Override
- public List<IntegrityMessage> check(BibEntry entry) {
- Optional<String> value = entry.getFieldOptional(FieldName.YEAR);
- if (!value.isPresent()) {
- return Collections.emptyList();
- }
-
- if (!CONTAINS_FOUR_DIGIT.test(value.get().trim())) {
- return Collections.singletonList(new IntegrityMessage(Localization.lang("should contain a four digit number"), entry, FieldName.YEAR));
- }
-
- return Collections.emptyList();
- }
- }
-
- /**
- * From BibTex manual:
- * One or more page numbers or range of numbers, such as 42--111 or 7,41,73--97 or 43+
- * (the '+' in this last example indicates pages following that don't form a simple range).
- * To make it easier to maintain Scribe-compatible databases, the standard styles convert
- * a single dash (as in 7-33) to the double dash used in TEX to denote number ranges (as in 7--33).
- */
- private static class PagesChecker implements Checker {
-
- private static final String PAGES_EXP = ""
- + "\\A" // begin String
- + "\\d+" // number
- + "(?:" // non-capture group
- + "\\+|\\-{2}\\d+" // + or --number (range)
- + ")?" // optional group
- + "(?:" // non-capture group
- + "," // comma
- + "\\d+(?:\\+|\\-{2}\\d+)?" // repeat former pattern
- + ")*" // repeat group 0,*
- + "\\z"; // end String
-
- private static final Predicate<String> VALID_PAGE_NUMBER = Pattern.compile(PAGES_EXP).asPredicate();
-
- /**
- * Checks, if the page numbers String conforms to the BibTex manual
- */
- @Override
- public List<IntegrityMessage> check(BibEntry entry) {
- Optional<String> value = entry.getFieldOptional(FieldName.PAGES);
- if (!value.isPresent()) {
- return Collections.emptyList();
- }
-
- if (!VALID_PAGE_NUMBER.test(value.get().trim())) {
- return Collections.singletonList(new IntegrityMessage(Localization.lang("should contain a valid page number range"), entry, FieldName.PAGES));
- }
-
- return Collections.emptyList();
- }
- }
-
- /**
- * Same as {@link PagesChecker} but allows single dash as well
- */
- private static class BiblatexPagesChecker implements Checker {
-
- private static final String PAGES_EXP = ""
- + "\\A" // begin String
- + "\\d+" // number
- + "(?:" // non-capture group
- + "\\+|\\-{1,2}\\d+" // + or --number (range)
- + ")?" // optional group
- + "(?:" // non-capture group
- + "," // comma
- + "\\d+(?:\\+|\\-{1,2}\\d+)?" // repeat former pattern
- + ")*" // repeat group 0,*
- + "\\z"; // end String
-
- private static final Predicate<String> VALID_PAGE_NUMBER = Pattern.compile(PAGES_EXP).asPredicate();
-
- /**
- * Checks, if the page numbers String conforms to the BibTex manual
- */
- @Override
- public List<IntegrityMessage> check(BibEntry entry) {
- Optional<String> value = entry.getFieldOptional(FieldName.PAGES);
- if (!value.isPresent()) {
- return Collections.emptyList();
- }
-
- if (!VALID_PAGE_NUMBER.test(value.get().trim())) {
- return Collections.singletonList(new IntegrityMessage(Localization.lang("should contain a valid page number range"), entry, FieldName.PAGES));
- }
-
- return Collections.emptyList();
- }
- }
-
- private static class BibStringChecker implements Checker {
-
- // Detect # if it doesn't have a \ in front of it or if it starts the string
- private static final Pattern UNESCAPED_HASH = Pattern.compile("(?<!\\\\)#|^#");
-
- /**
- * Checks, if there is an even number of unescaped #
- */
- @Override
- public List<IntegrityMessage> check(BibEntry entry) {
- List<IntegrityMessage> results = new ArrayList<>();
-
- Map<String, String> fields = entry.getFieldMap();
-
-
- for (Map.Entry<String, String> field : fields.entrySet()) {
- if (!InternalBibtexFields.getFieldExtras(field.getKey()).contains(FieldProperties.VERBATIM)) {
- Matcher hashMatcher = UNESCAPED_HASH.matcher(field.getValue());
- int hashCount = 0;
- while (hashMatcher.find()) {
- hashCount++;
- }
- if ((hashCount & 1) == 1) { // Check if odd
- results.add(new IntegrityMessage(Localization.lang("odd number of unescaped '#'"), entry,
- field.getKey()));
- }
- }
- }
- return results;
- }
- }
-
- private static class HTMLCharacterChecker implements Checker {
-
- // Detect any HTML encoded character,
- private static final Pattern HTML_CHARACTER_PATTERN = Pattern.compile("&[#\\p{Alnum}]+;");
-
- /**
- * Checks, if there are any HTML encoded characters in the fields
- */
- @Override
- public List<IntegrityMessage> check(BibEntry entry) {
- List<IntegrityMessage> results = new ArrayList<>();
- for (Map.Entry<String, String> field : entry.getFieldMap().entrySet()) {
- Matcher characterMatcher = HTML_CHARACTER_PATTERN.matcher(field.getValue());
- if (characterMatcher.find()) {
- results.add(new IntegrityMessage(Localization.lang("HTML encoded character found"), entry,
- field.getKey()));
- }
- }
- return results;
- }
- }
-
- private static class ASCIICharacterChecker implements Checker {
- /**
- * Detect any non ASCII encoded characters, e.g., umlauts or unicode in the fields
- */
- @Override
- public List<IntegrityMessage> check(BibEntry entry) {
- List<IntegrityMessage> results = new ArrayList<>();
- for (Map.Entry<String, String> field : entry.getFieldMap().entrySet()) {
- boolean asciiOnly = CharMatcher.ascii().matchesAllOf(field.getValue());
- if (!asciiOnly) {
- results.add(new IntegrityMessage(Localization.lang("Non-ASCII encoded character found"), entry,
- field.getKey()));
- }
- }
- return results;
- }
- }
-
}
diff --git a/src/main/java/net/sf/jabref/logic/integrity/MonthChecker.java b/src/main/java/net/sf/jabref/logic/integrity/MonthChecker.java
new file mode 100644
index 0000000..7718f7b
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/integrity/MonthChecker.java
@@ -0,0 +1,61 @@
+package net.sf.jabref.logic.integrity;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.function.Predicate;
+import java.util.regex.Pattern;
+
+import net.sf.jabref.logic.integrity.IntegrityCheck.Checker;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.database.BibDatabaseContext;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldName;
+
+public class MonthChecker implements Checker {
+
+ private static final Predicate<String> ONLY_AN_INTEGER = Pattern.compile("[1-9]|10|11|12")
+ .asPredicate();
+ private static final Predicate<String> MONTH_NORMALIZED = Pattern
+ .compile("#jan#|#feb#|#mar#|#apr#|#may#|#jun#|#jul#|#aug#|#sep#|#oct#|#nov#|#dec#")
+ .asPredicate();
+
+ private final BibDatabaseContext bibDatabaseContextMonth;
+
+
+ public MonthChecker(BibDatabaseContext bibDatabaseContext) {
+ this.bibDatabaseContextMonth = Objects.requireNonNull(bibDatabaseContext);
+ }
+
+ /**
+ * BibLaTeX package documentation (Section 2.3.9):
+ * The month field is an integer field.
+ * The bibliography style converts the month to a language-dependent string as required.
+ * For backwards compatibility, you may also use the following three-letter abbreviations in the month field:
+ * jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec.
+ * Note that these abbreviations are BibTeX strings which must be given without any braces or quotes.
+ */
+ @Override
+ public List<IntegrityMessage> check(BibEntry entry) {
+ Optional<String> value = entry.getField(FieldName.MONTH);
+ if (!value.isPresent()) {
+ return Collections.emptyList();
+ }
+
+ //BibLaTeX
+ if (bibDatabaseContextMonth.isBiblatexMode()
+ && !(ONLY_AN_INTEGER.test(value.get().trim()) || MONTH_NORMALIZED.test(value.get().trim()))) {
+ return Collections.singletonList(new IntegrityMessage(
+ Localization.lang("should be an integer or normalized"), entry, FieldName.MONTH));
+ }
+
+ //BibTeX
+ if (!bibDatabaseContextMonth.isBiblatexMode() && !MONTH_NORMALIZED.test(value.get().trim())) {
+ return Collections.singletonList(new IntegrityMessage(
+ Localization.lang("should be normalized"), entry, FieldName.MONTH));
+ }
+
+ return Collections.emptyList();
+ }
+}
diff --git a/src/main/java/net/sf/jabref/logic/integrity/NoBibtexFieldChecker.java b/src/main/java/net/sf/jabref/logic/integrity/NoBibtexFieldChecker.java
new file mode 100644
index 0000000..e6b0e44
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/integrity/NoBibtexFieldChecker.java
@@ -0,0 +1,31 @@
+package net.sf.jabref.logic.integrity;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+import net.sf.jabref.logic.integrity.IntegrityCheck.Checker;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldName;
+
+public class NoBibtexFieldChecker implements Checker {
+
+ /**
+ * BibLaTeX package documentation (Section 2.1.1):
+ * The title of the periodical is given in the journaltitle field.
+ */
+ @Override
+ public List<IntegrityMessage> check(BibEntry entry) {
+ Optional<String> value = entry.getField(FieldName.JOURNALTITLE);
+
+ //BibTeX
+ if (!value.isPresent()) {
+ return Collections.emptyList();
+ }
+ else {
+ return Collections.singletonList(
+ new IntegrityMessage(Localization.lang("BibLaTeX field only"), entry, FieldName.JOURNALTITLE));
+ }
+ }
+}
diff --git a/src/main/java/net/sf/jabref/logic/integrity/NoteChecker.java b/src/main/java/net/sf/jabref/logic/integrity/NoteChecker.java
new file mode 100644
index 0000000..a278671
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/integrity/NoteChecker.java
@@ -0,0 +1,48 @@
+package net.sf.jabref.logic.integrity;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.function.Predicate;
+import java.util.regex.Pattern;
+
+import net.sf.jabref.logic.integrity.IntegrityCheck.Checker;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.database.BibDatabaseContext;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldName;
+
+public class NoteChecker implements Checker {
+
+ private static final Predicate<String> FIRST_LETTER_CAPITALIZED = Pattern.compile("^[A-Z]").asPredicate();
+
+ private final BibDatabaseContext bibDatabaseContextEdition;
+
+
+ public NoteChecker(BibDatabaseContext bibDatabaseContext) {
+ this.bibDatabaseContextEdition = Objects.requireNonNull(bibDatabaseContext);
+ }
+
+ /**
+ * BibLaTeX package documentation (Section 4.9.1):
+ * The BibLaTeX package will automatically capitalize the first word when required at the beginning of a sentence.
+ * Official BibTeX specification:
+ * note: Any additional information that can help the reader. The first word should be capitalized.
+ */
+ @Override
+ public List<IntegrityMessage> check(BibEntry entry) {
+ Optional<String> value = entry.getField(FieldName.NOTE);
+ if (!value.isPresent()) {
+ return Collections.emptyList();
+ }
+
+ //BibTeX
+ if (!bibDatabaseContextEdition.isBiblatexMode() && !FIRST_LETTER_CAPITALIZED.test(value.get().trim())) {
+ return Collections.singletonList(new IntegrityMessage(
+ Localization.lang("should have the first letter capitalized"), entry, FieldName.NOTE));
+ }
+
+ return Collections.emptyList();
+ }
+}
diff --git a/src/main/java/net/sf/jabref/logic/integrity/PagesChecker.java b/src/main/java/net/sf/jabref/logic/integrity/PagesChecker.java
new file mode 100644
index 0000000..92a06da
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/integrity/PagesChecker.java
@@ -0,0 +1,54 @@
+package net.sf.jabref.logic.integrity;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.function.Predicate;
+import java.util.regex.Pattern;
+
+import net.sf.jabref.logic.integrity.IntegrityCheck.Checker;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldName;
+
+/**
+ * From BibTex manual:
+ * One or more page numbers or range of numbers, such as 42--111 or 7,41,73--97 or 43+
+ * (the '+' in this last example indicates pages following that don't form a simple range).
+ * To make it easier to maintain Scribe-compatible databases, the standard styles convert
+ * a single dash (as in 7-33) to the double dash used in TEX to denote number ranges (as in 7--33).
+ */
+public class PagesChecker implements Checker {
+
+ private static final String PAGES_EXP = "" + "\\A" // begin String
+ + "\\d+" // number
+ + "(?:" // non-capture group
+ + "\\+|\\-{2}\\d+" // + or --number (range)
+ + ")?" // optional group
+ + "(?:" // non-capture group
+ + "," // comma
+ + "\\d+(?:\\+|\\-{2}\\d+)?" // repeat former pattern
+ + ")*" // repeat group 0,*
+ + "\\z"; // end String
+
+ private static final Predicate<String> VALID_PAGE_NUMBER = Pattern.compile(PAGES_EXP).asPredicate();
+
+
+ /**
+ * Checks, if the page numbers String conforms to the BibTex manual
+ */
+ @Override
+ public List<IntegrityMessage> check(BibEntry entry) {
+ Optional<String> value = entry.getField(FieldName.PAGES);
+ if (!value.isPresent()) {
+ return Collections.emptyList();
+ }
+
+ if (!VALID_PAGE_NUMBER.test(value.get().trim())) {
+ return Collections.singletonList(new IntegrityMessage(
+ Localization.lang("should contain a valid page number range"), entry, FieldName.PAGES));
+ }
+
+ return Collections.emptyList();
+ }
+}
diff --git a/src/main/java/net/sf/jabref/logic/integrity/TitleChecker.java b/src/main/java/net/sf/jabref/logic/integrity/TitleChecker.java
new file mode 100644
index 0000000..49dfc41
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/integrity/TitleChecker.java
@@ -0,0 +1,57 @@
+package net.sf.jabref.logic.integrity;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.function.Predicate;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import net.sf.jabref.logic.integrity.IntegrityCheck.Checker;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldName;
+
+public class TitleChecker implements Checker {
+
+ private static final Pattern INSIDE_CURLY_BRAKETS = Pattern.compile("\\{[^}\\{]*\\}");
+ private static final Predicate<String> HAS_CAPITAL_LETTERS = Pattern.compile("[\\p{Lu}\\p{Lt}]").asPredicate();
+
+
+ @Override
+ public List<IntegrityMessage> check(BibEntry entry) {
+ Optional<String> value = entry.getField(FieldName.TITLE);
+ if (!value.isPresent()) {
+ return Collections.emptyList();
+ }
+
+ /*
+ * Algorithm:
+ * - remove trailing whitespaces
+ * - ignore first letter as this can always be written in caps
+ * - remove everything that is in brackets
+ * - check if at least one capital letter is in the title
+ */
+ String valueTrimmed = value.get().trim();
+ String valueIgnoringFirstLetter = valueTrimmed.startsWith("{") ? valueTrimmed : valueTrimmed.substring(1);
+ String valueOnlySpacesWithinCurlyBraces = valueIgnoringFirstLetter;
+ while (true) {
+ Matcher matcher = INSIDE_CURLY_BRAKETS.matcher(valueOnlySpacesWithinCurlyBraces);
+ if (!matcher.find()) {
+ break;
+ }
+ valueOnlySpacesWithinCurlyBraces = matcher.replaceAll("");
+ }
+
+ boolean hasCapitalLettersThatBibtexWillConvertToSmallerOnes = HAS_CAPITAL_LETTERS
+ .test(valueOnlySpacesWithinCurlyBraces);
+
+ if (hasCapitalLettersThatBibtexWillConvertToSmallerOnes) {
+ return Collections.singletonList(
+ new IntegrityMessage(Localization.lang("capital letters are not masked using curly brackets {}"),
+ entry, FieldName.TITLE));
+ }
+
+ return Collections.emptyList();
+ }
+}
diff --git a/src/main/java/net/sf/jabref/logic/integrity/TypeChecker.java b/src/main/java/net/sf/jabref/logic/integrity/TypeChecker.java
new file mode 100644
index 0000000..45cd0c7
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/integrity/TypeChecker.java
@@ -0,0 +1,28 @@
+package net.sf.jabref.logic.integrity;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+import net.sf.jabref.logic.integrity.IntegrityCheck.Checker;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldName;
+
+public class TypeChecker implements Checker {
+
+ @Override
+ public List<IntegrityMessage> check(BibEntry entry) {
+ Optional<String> value = entry.getField(FieldName.PAGES);
+ if (!value.isPresent()) {
+ return Collections.emptyList();
+ }
+
+ if ("proceedings".equalsIgnoreCase(entry.getType())) {
+ return Collections.singletonList(new IntegrityMessage(
+ Localization.lang("wrong entry type as proceedings has page numbers"), entry, FieldName.PAGES));
+ }
+
+ return Collections.emptyList();
+ }
+}
diff --git a/src/main/java/net/sf/jabref/logic/integrity/UrlChecker.java b/src/main/java/net/sf/jabref/logic/integrity/UrlChecker.java
new file mode 100644
index 0000000..d0dec07
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/integrity/UrlChecker.java
@@ -0,0 +1,29 @@
+package net.sf.jabref.logic.integrity;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+import net.sf.jabref.logic.integrity.IntegrityCheck.Checker;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldName;
+
+public class UrlChecker implements Checker {
+
+ @Override
+ public List<IntegrityMessage> check(BibEntry entry) {
+ Optional<String> value = entry.getField(FieldName.URL);
+ if (!value.isPresent()) {
+ return Collections.emptyList();
+ }
+
+ if (!value.get().contains("://")) {
+ return Collections.singletonList(new IntegrityMessage(
+ Localization.lang("should contain a protocol") + ": http[s]://, file://, ftp://, ...", entry,
+ FieldName.URL));
+ }
+
+ return Collections.emptyList();
+ }
+}
diff --git a/src/main/java/net/sf/jabref/logic/integrity/YearChecker.java b/src/main/java/net/sf/jabref/logic/integrity/YearChecker.java
new file mode 100644
index 0000000..1ffcf3e
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/integrity/YearChecker.java
@@ -0,0 +1,49 @@
+package net.sf.jabref.logic.integrity;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.function.Predicate;
+import java.util.regex.Pattern;
+
+import net.sf.jabref.logic.integrity.IntegrityCheck.Checker;
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldName;
+
+public class YearChecker implements Checker {
+
+ private static final Predicate<String> CONTAINS_FOUR_DIGIT = Pattern.compile("([^0-9]|^)[0-9]{4}([^0-9]|$)")
+ .asPredicate();
+ private static final Predicate<String> ENDS_WITH_FOUR_DIGIT = Pattern.compile("[0-9]{4}$").asPredicate();
+ private static final String PUNCTUATION_MARKS = "[(){},.;!?<>%&$]";
+
+
+ /**
+ * Checks, if the number String contains a four digit year and ends with it.
+ * Official bibtex spec:
+ * Generally it should consist of four numerals, such as 1984, although the standard styles
+ * can handle any year whose last four nonpunctuation characters are numerals, such as ‘(about 1984)’.
+ * Source: http://ftp.fernuni-hagen.de/ftp-dir/pub/mirrors/www.ctan.org/biblio/bibtex/base/btxdoc.pdf
+ */
+ @Override
+ public List<IntegrityMessage> check(BibEntry entry) {
+ Optional<String> value = entry.getField(FieldName.YEAR);
+ if (!value.isPresent()) {
+ return Collections.emptyList();
+ }
+
+ if (!CONTAINS_FOUR_DIGIT.test(value.get().trim())) {
+ return Collections.singletonList(new IntegrityMessage(
+ Localization.lang("should contain a four digit number"), entry, FieldName.YEAR));
+ }
+
+ if (!ENDS_WITH_FOUR_DIGIT.test(value.get().replaceAll(PUNCTUATION_MARKS, ""))) {
+ return Collections.singletonList(
+ new IntegrityMessage(Localization.lang("last four nonpunctuation characters should be numerals"),
+ entry, FieldName.YEAR));
+ }
+
+ return Collections.emptyList();
+ }
+}
diff --git a/src/main/java/net/sf/jabref/logic/journals/JournalAbbreviationPreferences.java b/src/main/java/net/sf/jabref/logic/journals/JournalAbbreviationPreferences.java
index 3ba35a8..d79d3e6 100644
--- a/src/main/java/net/sf/jabref/logic/journals/JournalAbbreviationPreferences.java
+++ b/src/main/java/net/sf/jabref/logic/journals/JournalAbbreviationPreferences.java
@@ -3,8 +3,6 @@ package net.sf.jabref.logic.journals;
import java.nio.charset.Charset;
import java.util.List;
-import net.sf.jabref.preferences.JabRefPreferences;
-
public class JournalAbbreviationPreferences {
private final List<String> externalJournalLists;
@@ -21,13 +19,6 @@ public class JournalAbbreviationPreferences {
this.defaultEncoding = defaultEncoding;
}
- public static JournalAbbreviationPreferences fromPreferences(JabRefPreferences jabRefPreferences) {
- return new JournalAbbreviationPreferences(
- jabRefPreferences.getStringList(JabRefPreferences.EXTERNAL_JOURNAL_LISTS),
- jabRefPreferences.get(JabRefPreferences.PERSONAL_JOURNAL_LIST),
- jabRefPreferences.getBoolean(JabRefPreferences.USE_IEEE_ABRV), jabRefPreferences.getDefaultEncoding());
- }
-
public List<String> getExternalJournalLists() {
return externalJournalLists;
}
diff --git a/src/main/java/net/sf/jabref/logic/l10n/Languages.java b/src/main/java/net/sf/jabref/logic/l10n/Languages.java
index 783a882..1c35378 100644
--- a/src/main/java/net/sf/jabref/logic/l10n/Languages.java
+++ b/src/main/java/net/sf/jabref/logic/l10n/Languages.java
@@ -1,5 +1,6 @@
package net.sf.jabref.logic.l10n;
+import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
@@ -32,20 +33,21 @@ public class Languages {
LANGUAGES.put("Simplified Chinese", "zh");
}
- public static Optional<String> convertToKnownLocale(String language) {
- if(!LANGUAGES.values().contains(Objects.requireNonNull(language))) {
- if(language.contains("_")) {
- String lang = language.split("_")[0];
- if(LANGUAGES.values().contains(lang)) {
- return Optional.of(lang);
- } else {
- return Optional.empty();
- }
- } else {
+ public static Optional<Locale> convertToSupportedLocale(String language) {
+ Objects.requireNonNull(language);
+
+ if (!LANGUAGES.values().contains(language)) {
+ if (!language.contains("_")) {
return Optional.empty();
}
- } else {
- return Optional.of(language);
+
+ String lang = language.split("_")[0];
+ if (!LANGUAGES.values().contains(lang)) {
+ return Optional.empty();
+ }
+ return Optional.of(new Locale(lang));
}
+
+ return Optional.of(new Locale(language));
}
}
diff --git a/src/main/java/net/sf/jabref/logic/l10n/Localization.java b/src/main/java/net/sf/jabref/logic/l10n/Localization.java
index d70fba9..864f55f 100644
--- a/src/main/java/net/sf/jabref/logic/l10n/Localization.java
+++ b/src/main/java/net/sf/jabref/logic/l10n/Localization.java
@@ -13,46 +13,36 @@ import org.apache.commons.logging.LogFactory;
public class Localization {
private static final Log LOGGER = LogFactory.getLog(Localization.class);
- public static final String RESOURCE_PREFIX = "l10n/JabRef";
- public static final String MENU_RESOURCE_PREFIX = "l10n/Menu";
+ protected static final String RESOURCE_PREFIX = "l10n/JabRef";
+ protected static final String MENU_RESOURCE_PREFIX = "l10n/Menu";
private static ResourceBundle messages;
private static ResourceBundle menuTitles;
public static void setLanguage(String language) {
- Optional<String> knownLanguage = Languages.convertToKnownLocale(language);
+ Optional<Locale> knownLanguage = Languages.convertToSupportedLocale(language);
if(!knownLanguage.isPresent()) {
LOGGER.warn("Language " + language + " is not supported by JabRef (Default:" + Locale.getDefault()+ ")");
setLanguage("en");
return;
}
- String[] languageParts = knownLanguage.get().split("_");
- Locale locale;
- if (languageParts.length == 1) {
- locale = new Locale(languageParts[0]);
- } else if (languageParts.length == 2) {
- locale = new Locale(languageParts[0], languageParts[1]);
- } else {
- locale = Locale.ENGLISH;
- }
-
+ Locale locale = knownLanguage.get();
Locale.setDefault(locale);
javax.swing.JComponent.setDefaultLocale(locale);
try {
createResourceBundles(locale);
- } catch (MissingResourceException e) {
- // SHOULD NOT HAPPEN AS WE HAVE SCRIPTS TO COVER FOR THIS
- LOGGER.warn("Could not find bundles for language " + locale + ", switching to full english language", e);
+ } catch (MissingResourceException ex) {
+ // should not happen as we have scripts to enforce this
+ LOGGER.warn("Could not find bundles for language " + locale + ", switching to full english language", ex);
setLanguage("en");
}
}
private static void createResourceBundles(Locale locale) {
messages = ResourceBundle.getBundle(RESOURCE_PREFIX, locale, new EncodingControl(StandardCharsets.UTF_8));
- menuTitles = ResourceBundle.getBundle(MENU_RESOURCE_PREFIX, locale,
- new EncodingControl(StandardCharsets.UTF_8));
+ menuTitles = ResourceBundle.getBundle(MENU_RESOURCE_PREFIX, locale, new EncodingControl(StandardCharsets.UTF_8));
}
/**
diff --git a/src/main/java/net/sf/jabref/logic/layout/Layout.java b/src/main/java/net/sf/jabref/logic/layout/Layout.java
index ef1cfd7..23fe08b 100644
--- a/src/main/java/net/sf/jabref/logic/layout/Layout.java
+++ b/src/main/java/net/sf/jabref/logic/layout/Layout.java
@@ -3,11 +3,9 @@ package net.sf.jabref.logic.layout;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
-import java.util.Optional;
-import java.util.regex.Pattern;
-import net.sf.jabref.BibDatabaseContext;
import net.sf.jabref.model.database.BibDatabase;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.entry.BibEntry;
import org.apache.commons.logging.Log;
@@ -85,21 +83,17 @@ public class Layout {
}
}
- public String doLayout(BibEntry bibtex, BibDatabase database) {
- return doLayout(bibtex, database, Optional.empty());
- }
-
/**
* Returns the processed bibtex entry. If the database argument is
* null, no string references will be resolved. Otherwise all valid
* string references will be replaced by the strings' contents. Even
* recursive string references are resolved.
*/
- public String doLayout(BibEntry bibtex, BibDatabase database, Optional<Pattern> highlightPattern) {
+ public String doLayout(BibEntry bibtex, BibDatabase database) {
StringBuilder sb = new StringBuilder(100);
for (LayoutEntry layoutEntry : layoutEntries) {
- String fieldText = layoutEntry.doLayout(bibtex, database, highlightPattern);
+ String fieldText = layoutEntry.doLayout(bibtex, database);
// 2005.05.05 M. Alver
// The following change means we treat null fields as "". This is to fix the
diff --git a/src/main/java/net/sf/jabref/logic/layout/LayoutEntry.java b/src/main/java/net/sf/jabref/logic/layout/LayoutEntry.java
index 2a9f49b..8d6b974 100644
--- a/src/main/java/net/sf/jabref/logic/layout/LayoutEntry.java
+++ b/src/main/java/net/sf/jabref/logic/layout/LayoutEntry.java
@@ -8,9 +8,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
-import java.util.regex.Pattern;
-import net.sf.jabref.BibDatabaseContext;
import net.sf.jabref.logic.formatter.bibtexfields.HtmlToLatexFormatter;
import net.sf.jabref.logic.formatter.bibtexfields.UnicodeToLatexFormatter;
import net.sf.jabref.logic.layout.format.AuthorAbbreviator;
@@ -63,7 +61,7 @@ import net.sf.jabref.logic.layout.format.Ordinal;
import net.sf.jabref.logic.layout.format.RTFChars;
import net.sf.jabref.logic.layout.format.RemoveBrackets;
import net.sf.jabref.logic.layout.format.RemoveBracketsAddComma;
-import net.sf.jabref.logic.layout.format.RemoveLatexCommands;
+import net.sf.jabref.logic.layout.format.RemoveLatexCommandsFormatter;
import net.sf.jabref.logic.layout.format.RemoveTilde;
import net.sf.jabref.logic.layout.format.RemoveWhitespace;
import net.sf.jabref.logic.layout.format.Replace;
@@ -76,16 +74,17 @@ import net.sf.jabref.logic.layout.format.WrapContent;
import net.sf.jabref.logic.layout.format.WrapFileLinks;
import net.sf.jabref.logic.layout.format.XMLChars;
import net.sf.jabref.logic.openoffice.OOPreFormatter;
-import net.sf.jabref.logic.search.MatchesHighlighter;
-import net.sf.jabref.logic.util.strings.StringUtil;
import net.sf.jabref.model.database.BibDatabase;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.strings.StringUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
class LayoutEntry {
-
+ private static final Log LOGGER = LogFactory.getLog(LayoutEntry.class);
+
private List<LayoutFormatter> option;
// Formatter to be run after other formatters:
@@ -99,11 +98,8 @@ class LayoutEntry {
private final List<String> invalidFormatter = new ArrayList<>();
- private static final Log LOGGER = LogFactory.getLog(LayoutEntry.class);
-
private final LayoutFormatterPreferences prefs;
-
public LayoutEntry(StringInt si, LayoutFormatterPreferences prefs) {
this.prefs = prefs;
type = si.i;
@@ -177,23 +173,18 @@ class LayoutEntry {
for (LayoutEntry layoutEntry : layoutEntries) {
invalidFormatter.addAll(layoutEntry.getInvalidFormatters());
}
-
}
public void setPostFormatter(LayoutFormatter formatter) {
this.postFormatter = formatter;
}
- private String doLayout(BibEntry bibtex, BibDatabase database) {
- return doLayout(bibtex, database, Optional.empty());
- }
-
- public String doLayout(BibEntry bibtex, BibDatabase database, Optional<Pattern> highlightPattern) {
+ public String doLayout(BibEntry bibtex, BibDatabase database) {
switch (type) {
case LayoutHelper.IS_LAYOUT_TEXT:
return text;
case LayoutHelper.IS_SIMPLE_FIELD:
- String value = BibDatabase.getResolvedField(text, bibtex, database).orElse("");
+ String value = bibtex.getResolvedFieldOrAlias(text, database).orElse("");
// If a post formatter has been set, call it:
if (postFormatter != null) {
@@ -202,7 +193,7 @@ class LayoutEntry {
return value;
case LayoutHelper.IS_FIELD_START:
case LayoutHelper.IS_GROUP_START:
- return handleFieldOrGroupStart(bibtex, database, highlightPattern);
+ return handleFieldOrGroupStart(bibtex, database);
case LayoutHelper.IS_FIELD_END:
case LayoutHelper.IS_GROUP_END:
return "";
@@ -212,7 +203,7 @@ class LayoutEntry {
// Printing the encoding name is not supported in entry layouts, only
// in begin/end layouts. This prevents breakage if some users depend
// on a field called "encoding". We simply return this field instead:
- return BibDatabase.getResolvedField("encoding", bibtex, database).orElse(null);
+ return bibtex.getResolvedFieldOrAlias("encoding", database).orElse(null);
default:
return "";
}
@@ -231,8 +222,8 @@ class LayoutEntry {
} else {
// changed section begin - arudert
// resolve field (recognized by leading backslash) or text
- fieldEntry = text.startsWith("\\") ? BibDatabase
- .getResolvedField(text.substring(1), bibtex, database)
+ fieldEntry = text.startsWith("\\") ? bibtex
+ .getResolvedFieldOrAlias(text.substring(1), database)
.orElse("") : BibDatabase.getText(text, database);
// changed section end - arudert
}
@@ -251,16 +242,16 @@ class LayoutEntry {
return fieldEntry;
}
- private String handleFieldOrGroupStart(BibEntry bibtex, BibDatabase database, Optional<Pattern> highlightPattern) {
+ private String handleFieldOrGroupStart(BibEntry bibtex, BibDatabase database) {
Optional<String> field;
if (type == LayoutHelper.IS_GROUP_START) {
- field = BibDatabase.getResolvedField(text, bibtex, database);
+ field = bibtex.getResolvedFieldOrAlias(text, database);
} else if (text.matches(".*(;|(\\&+)).*")) {
// split the strings along &, && or ; for AND formatter
String[] parts = text.split("\\s*(;|(\\&+))\\s*");
field = Optional.empty();
for (String part : parts) {
- field = BibDatabase.getResolvedField(part, bibtex, database);
+ field = bibtex.getResolvedFieldOrAlias(part, database);
if (!field.isPresent()) {
break;
}
@@ -270,7 +261,7 @@ class LayoutEntry {
String[] parts = text.split("\\s*(\\|+)\\s*");
field = Optional.empty();
for (String part : parts) {
- field = BibDatabase.getResolvedField(part, bibtex, database);
+ field = bibtex.getResolvedFieldOrAlias(part, database);
if (field.isPresent()) {
break;
}
@@ -315,17 +306,7 @@ class LayoutEntry {
sb.append(fieldText.substring(eol));
}
} else {
- /*
- * if fieldText is not null and the bibtexentry is marked
- * as a searchhit, try to highlight the searched words
- *
- */
- if (bibtex.isSearchHit()) {
- sb.append(MatchesHighlighter.highlightWordsWithHTML(fieldText, highlightPattern));
- } else {
- sb.append(fieldText);
- }
-
+ sb.append(fieldText);
}
}
@@ -377,12 +358,10 @@ class LayoutEntry {
return encoding.displayName();
case LayoutHelper.IS_FILENAME:
- File f = databaseContext.getDatabaseFile();
- return f == null ? "" : f.getName();
+ return databaseContext.getDatabaseFile().map(File::getName).orElse("");
case LayoutHelper.IS_FILEPATH:
- File f2 = databaseContext.getDatabaseFile();
- return f2 == null ? "" : f2.getPath();
+ return databaseContext.getDatabaseFile().map(File::getPath).orElse("");
default:
break;
@@ -409,7 +388,6 @@ class LayoutEntry {
}
}
-
}
private LayoutFormatter getLayoutFormatterByName(String name) throws Exception {
@@ -512,7 +490,7 @@ class LayoutEntry {
case "RemoveBracketsAddComma":
return new RemoveBracketsAddComma();
case "RemoveLatexCommands":
- return new RemoveLatexCommands();
+ return new RemoveLatexCommandsFormatter();
case "RemoveTilde":
return new RemoveTilde();
case "RemoveWhitespace":
@@ -620,7 +598,6 @@ class LayoutEntry {
char[] c = calls.toCharArray();
int i = 0;
-
while (i < c.length) {
int start = i;
@@ -635,6 +612,7 @@ class LayoutEntry {
// Skip the brace
i++;
+ int bracelevel = 0;
if (i < c.length) {
if (c[i] == '"') {
@@ -646,9 +624,14 @@ class LayoutEntry {
int startParam = i;
i++;
boolean escaped = false;
- while (((i + 1) < c.length) && !(!escaped && (c[i] == '"') && (c[i + 1] == ')'))) {
+ while (((i + 1) < c.length)
+ && !(!escaped && (c[i] == '"') && (c[i + 1] == ')') && (bracelevel == 0))) {
if (c[i] == '\\') {
escaped = !escaped;
+ } else if (c[i] == '(') {
+ bracelevel++;
+ } else if (c[i] == ')') {
+ bracelevel--;
} else {
escaped = false;
}
@@ -664,14 +647,18 @@ class LayoutEntry {
int startParam = i;
- while ((i < c.length) && (c[i] != ')')) {
+ while ((i < c.length) && (!((c[i] == ')') && (bracelevel == 0)))) {
+ if (c[i] == '(') {
+ bracelevel++;
+ } else if (c[i] == ')') {
+ bracelevel--;
+ }
i++;
}
String param = calls.substring(startParam, i);
result.add(Arrays.asList(method, param));
-
}
} else {
// Incorrectly terminated open brace
diff --git a/src/main/java/net/sf/jabref/logic/layout/LayoutFormatterPreferences.java b/src/main/java/net/sf/jabref/logic/layout/LayoutFormatterPreferences.java
index f28dde6..a35362b 100644
--- a/src/main/java/net/sf/jabref/logic/layout/LayoutFormatterPreferences.java
+++ b/src/main/java/net/sf/jabref/logic/layout/LayoutFormatterPreferences.java
@@ -2,14 +2,12 @@ package net.sf.jabref.logic.layout;
import java.util.HashMap;
import java.util.Map;
-import java.util.Objects;
import java.util.Optional;
import net.sf.jabref.logic.journals.JournalAbbreviationLoader;
import net.sf.jabref.logic.journals.JournalAbbreviationPreferences;
import net.sf.jabref.logic.layout.format.FileLinkPreferences;
import net.sf.jabref.logic.layout.format.NameFormatterPreferences;
-import net.sf.jabref.preferences.JabRefPreferences;
public class LayoutFormatterPreferences {
@@ -28,16 +26,6 @@ public class LayoutFormatterPreferences {
this.journalAbbreviationLoader = journalAbbreviationLoader;
}
- public static LayoutFormatterPreferences fromPreferences(JabRefPreferences jabRefPreferences,
- JournalAbbreviationLoader journalAbbreviationLoader) {
- Objects.requireNonNull(jabRefPreferences);
- Objects.requireNonNull(journalAbbreviationLoader);
- return new LayoutFormatterPreferences(NameFormatterPreferences.fromPreferences(jabRefPreferences),
- JournalAbbreviationPreferences.fromPreferences(jabRefPreferences),
- FileLinkPreferences.fromPreferences(jabRefPreferences),
- journalAbbreviationLoader);
- }
-
public NameFormatterPreferences getNameFormatterPreferences() {
return nameFormatterPreferences;
}
diff --git a/src/main/java/net/sf/jabref/logic/layout/format/Authors.java b/src/main/java/net/sf/jabref/logic/layout/format/Authors.java
index 863013f..da42509 100644
--- a/src/main/java/net/sf/jabref/logic/layout/format/Authors.java
+++ b/src/main/java/net/sf/jabref/logic/layout/format/Authors.java
@@ -267,7 +267,7 @@ public class Authors extends AbstractParamLayoutFormatter {
String firstNameResult = "";
if (a.getFirst().isPresent()) {
if (abbreviate) {
- firstNameResult = a.getFirstAbbr();
+ firstNameResult = a.getFirstAbbr().orElse("");
if (firstInitialOnly && (firstNameResult.length() > 2)) {
firstNameResult = firstNameResult.substring(0, 2);
diff --git a/src/main/java/net/sf/jabref/logic/layout/format/FileLinkPreferences.java b/src/main/java/net/sf/jabref/logic/layout/format/FileLinkPreferences.java
index 3f87e1f..9eac7a6 100644
--- a/src/main/java/net/sf/jabref/logic/layout/format/FileLinkPreferences.java
+++ b/src/main/java/net/sf/jabref/logic/layout/format/FileLinkPreferences.java
@@ -1,28 +1,16 @@
package net.sf.jabref.logic.layout.format;
-import java.util.Collections;
import java.util.List;
-import net.sf.jabref.model.entry.FieldName;
-import net.sf.jabref.preferences.JabRefPreferences;
-
public class FileLinkPreferences {
private final List<String> generatedDirForDatabase;
private final List<String> fileDirForDatabase;
- public static final String DIR_SUFFIX = "Directory";
-
-
public FileLinkPreferences(List<String> generatedDirForDatabase, List<String> fileDirForDatabase) {
this.generatedDirForDatabase = generatedDirForDatabase;
this.fileDirForDatabase = fileDirForDatabase;
}
- public static FileLinkPreferences fromPreferences(JabRefPreferences prefs) {
- return new FileLinkPreferences(Collections.singletonList(prefs.get(FieldName.FILE + FileLinkPreferences.DIR_SUFFIX)),
- prefs.fileDirForDatabase);
- }
-
public List<String> getGeneratedDirForDatabase() {
return generatedDirForDatabase;
}
diff --git a/src/main/java/net/sf/jabref/logic/layout/format/HTMLChars.java b/src/main/java/net/sf/jabref/logic/layout/format/HTMLChars.java
index 6dc557a..b0dece1 100644
--- a/src/main/java/net/sf/jabref/logic/layout/format/HTMLChars.java
+++ b/src/main/java/net/sf/jabref/logic/layout/format/HTMLChars.java
@@ -3,8 +3,8 @@ package net.sf.jabref.logic.layout.format;
import java.util.Map;
import net.sf.jabref.logic.layout.LayoutFormatter;
-import net.sf.jabref.logic.util.strings.HTMLUnicodeConversionMaps;
-import net.sf.jabref.logic.util.strings.StringUtil;
+import net.sf.jabref.model.strings.HTMLUnicodeConversionMaps;
+import net.sf.jabref.model.strings.StringUtil;
/**
* This formatter escapes characters so they are suitable for HTML.
diff --git a/src/main/java/net/sf/jabref/logic/layout/format/LatexToUnicodeFormatter.java b/src/main/java/net/sf/jabref/logic/layout/format/LatexToUnicodeFormatter.java
index e50f878..7ed2203 100644
--- a/src/main/java/net/sf/jabref/logic/layout/format/LatexToUnicodeFormatter.java
+++ b/src/main/java/net/sf/jabref/logic/layout/format/LatexToUnicodeFormatter.java
@@ -1,13 +1,9 @@
package net.sf.jabref.logic.layout.format;
-import java.util.Map;
-
-import net.sf.jabref.logic.formatter.Formatter;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.layout.LayoutFormatter;
-import net.sf.jabref.logic.util.OS;
-import net.sf.jabref.logic.util.strings.HTMLUnicodeConversionMaps;
-import net.sf.jabref.logic.util.strings.StringUtil;
+import net.sf.jabref.model.cleanup.Formatter;
+import net.sf.jabref.model.strings.LatexToUnicode;
/**
* This formatter converts LaTeX character sequences their equivalent unicode characters,
@@ -15,8 +11,8 @@ import net.sf.jabref.logic.util.strings.StringUtil;
*/
public class LatexToUnicodeFormatter implements LayoutFormatter, Formatter {
- private static final Map<String, String> CHARS = HTMLUnicodeConversionMaps.LATEX_UNICODE_CONVERSION_MAP;
- private static final Map<String, String> ACCENTS = HTMLUnicodeConversionMaps.UNICODE_ESCAPED_ACCENTS;
+ private final LatexToUnicode formatter = new LatexToUnicode();
+
@Override
public String getName() {
@@ -30,186 +26,7 @@ public class LatexToUnicodeFormatter implements LayoutFormatter, Formatter {
@Override
public String format(String inField) {
- if (inField.isEmpty()) {
- return "";
- }
- int i;
- // TODO: document what does this do
- String field = inField.replaceAll("&|\\\\&", "&").replaceAll("[\\n]{1,}", "<p>").replace("\\$", "$") // Replace \$ with $
- .replaceAll("\\$([^\\$]*)\\$", "\\{$1\\}");
-
- StringBuilder sb = new StringBuilder();
- StringBuilder currentCommand = null;
-
- char c;
- boolean escaped = false;
- boolean incommand = false;
-
- for (i = 0; i < field.length(); i++) {
- c = field.charAt(i);
- if (escaped && (c == '\\')) {
- sb.append('\\');
- escaped = false;
- } else if (c == '\\') {
- if (incommand) {
- /* Close Command */
- String command = currentCommand.toString();
- String result = LatexToUnicodeFormatter.CHARS.get(command);
- if (result == null) {
- sb.append(command);
- } else {
- sb.append(result);
- }
-
- }
- escaped = true;
- incommand = true;
- currentCommand = new StringBuilder();
- } else if (!incommand && ((c == '{') || (c == '}'))) {
- // Swallow the brace.
- } else if (Character.isLetter(c) || (c == '%')
- || StringUtil.SPECIAL_COMMAND_CHARS.contains(String.valueOf(c))) {
- escaped = false;
-
- if (!incommand) {
- sb.append(c);
- } else {
- currentCommand.append(c);
- if ((currentCommand.length() == 1)
- && StringUtil.SPECIAL_COMMAND_CHARS.contains(currentCommand.toString())
- && !(i >= (field.length() - 1))) {
- // This indicates that we are in a command of the type
- // \^o or \~{n}
-
- String command = currentCommand.toString();
- i++;
- c = field.charAt(i);
- String commandBody;
- if (c == '{') {
- String part = StringUtil.getPart(field, i, false);
- i += part.length();
- commandBody = part;
- } else {
- commandBody = field.substring(i, i + 1);
- }
- String result = LatexToUnicodeFormatter.CHARS.get(command + commandBody);
-
- if (result == null) {
- // Use combining accents if argument is single character or empty
- if (commandBody.length() <= 1) {
- String accent = LatexToUnicodeFormatter.ACCENTS.get(command);
- if (accent == null) {
- // Shouldn't happen
- sb.append(commandBody);
- } else {
- sb.append(commandBody).append(accent);
- }
- }
- } else {
- sb.append(result);
- }
-
- incommand = false;
- escaped = false;
- } else {
- // Are we already at the end of the string?
- if ((i + 1) == field.length()) {
- String command = currentCommand.toString();
- String result = LatexToUnicodeFormatter.CHARS.get(command);
- /* If found, then use translated version. If not,
- * then keep
- * the text of the parameter intact.
- */
- if (result == null) {
- sb.append(command);
- } else {
- sb.append(result);
- }
-
- }
- }
- }
- } else {
- if (!incommand) {
- sb.append(c);
- } else if (Character.isWhitespace(c) || (c == '{') || (c == '}')) {
- // First test if we are already at the end of the string.
- // if (i >= field.length()-1)
- // break testContent;
-
- String command = currentCommand.toString();
-
- if (c == '{') {
- String argument = StringUtil.getPart(field, i, true);
- i += argument.length();
- // handle common case of general latex command
- String result = LatexToUnicodeFormatter.CHARS.get(command + argument);
-
- // If found, then use translated version. If not, then keep
- // the
- // text of the parameter intact.
- if (result == null) {
- // Use combining accents if argument is single character or empty
- if (argument.length() <= 1) {
- String accent = LatexToUnicodeFormatter.ACCENTS.get(command);
- if (accent == null) {
- if (argument.isEmpty()) {
- // Empty argument, may be used as separator as in \LaTeX{}, so keep the command
- sb.append(command);
- } else {
- sb.append(argument);
- }
- } else {
- sb.append(argument).append(accent);
- }
- } else {
- sb.append(argument);
- }
- } else {
- sb.append(result);
- }
- } else if (c == '}') {
- // This end brace terminates a command. This can be the case in
- // constructs like {\aa}. The correct behaviour should be to
- // substitute the evaluated command and swallow the brace:
- String result = LatexToUnicodeFormatter.CHARS.get(command);
-
- if (result == null) {
- // If the command is unknown, just print it:
- sb.append(command);
- } else {
- sb.append(result);
- }
-
- } else {
- String result = LatexToUnicodeFormatter.CHARS.get(command);
-
- if (result == null) {
- sb.append(command);
- } else {
- sb.append(result);
- }
- sb.append(' ');
- }
- } else {
- /*
- * TODO: this point is reached, apparently, if a command is
- * terminated in a strange way, such as with "$\omega$".
- * Also, the command "\&" causes us to get here. The former
- * issue is maybe a little difficult to address, since it
- * involves the LaTeX math mode. We don't have a complete
- * LaTeX parser, so maybe it's better to ignore these
- * commands?
- */
- }
-
- incommand = false;
- escaped = false;
- }
- }
-
- return sb.toString().replace("&", "&").replace("<p>", OS.NEWLINE).replace("$", "$").replace("~",
- "\u00A0");
+ return formatter.format(inField);
}
@Override
diff --git a/src/main/java/net/sf/jabref/logic/layout/format/NameFormatter.java b/src/main/java/net/sf/jabref/logic/layout/format/NameFormatter.java
index 3e35969..c3d7d0f 100644
--- a/src/main/java/net/sf/jabref/logic/layout/format/NameFormatter.java
+++ b/src/main/java/net/sf/jabref/logic/layout/format/NameFormatter.java
@@ -3,6 +3,7 @@ package net.sf.jabref.logic.layout.format;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import net.sf.jabref.logic.bst.BibtexNameFormatter;
import net.sf.jabref.logic.layout.LayoutFormatter;
@@ -77,10 +78,6 @@ public class NameFormatter implements LayoutFormatter {
private String parameter = NameFormatter.DEFAULT_FORMAT;
- public static final String NAME_FORMATER_KEY = "nameFormatterNames";
-
- public static final String NAME_FORMATTER_VALUE = "nameFormatterFormats";
-
private static String format(String toFormat, AuthorList al, String[] formats) {
StringBuilder sb = new StringBuilder();
@@ -169,6 +166,7 @@ public class NameFormatter implements LayoutFormatter {
}
public static Map<String, String> getNameFormatters(NameFormatterPreferences prefs) {
+ Objects.requireNonNull(prefs);
Map<String, String> result = new HashMap<>();
diff --git a/src/main/java/net/sf/jabref/logic/layout/format/NameFormatterPreferences.java b/src/main/java/net/sf/jabref/logic/layout/format/NameFormatterPreferences.java
index 2c6a9b7..536fb41 100644
--- a/src/main/java/net/sf/jabref/logic/layout/format/NameFormatterPreferences.java
+++ b/src/main/java/net/sf/jabref/logic/layout/format/NameFormatterPreferences.java
@@ -2,8 +2,6 @@ package net.sf.jabref.logic.layout.format;
import java.util.List;
-import net.sf.jabref.preferences.JabRefPreferences;
-
public class NameFormatterPreferences {
private final List<String> nameFormatterKey;
@@ -15,11 +13,6 @@ public class NameFormatterPreferences {
this.nameFormatterValue = nameFormatterValue;
}
- public static NameFormatterPreferences fromPreferences(JabRefPreferences jabRefPreferences) {
- return new NameFormatterPreferences(jabRefPreferences.getStringList(NameFormatter.NAME_FORMATER_KEY),
- jabRefPreferences.getStringList(NameFormatter.NAME_FORMATTER_VALUE));
- }
-
public List<String> getNameFormatterKey() {
return nameFormatterKey;
}
diff --git a/src/main/java/net/sf/jabref/logic/layout/format/RTFChars.java b/src/main/java/net/sf/jabref/logic/layout/format/RTFChars.java
index 01c7b86..a90ca72 100644
--- a/src/main/java/net/sf/jabref/logic/layout/format/RTFChars.java
+++ b/src/main/java/net/sf/jabref/logic/layout/format/RTFChars.java
@@ -3,7 +3,7 @@ package net.sf.jabref.logic.layout.format;
import net.sf.jabref.logic.layout.LayoutFormatter;
import net.sf.jabref.logic.layout.StringInt;
import net.sf.jabref.logic.util.strings.RtfCharMap;
-import net.sf.jabref.logic.util.strings.StringUtil;
+import net.sf.jabref.model.strings.StringUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -24,6 +24,7 @@ import org.apache.commons.logging.LogFactory;
* 5.) Replace --- by \emdash and -- by \endash.
*/
public class RTFChars implements LayoutFormatter {
+
private static final Log LOGGER = LogFactory.getLog(LayoutFormatter.class);
private static final RtfCharMap RTF_CHARS = new RtfCharMap();
@@ -114,7 +115,7 @@ public class RTFChars implements LayoutFormatter {
// Then look for italics etc.,
// but first check if we are already at the end of the string.
- if (i >= field.length() - 1) {
+ if (i >= (field.length() - 1)) {
break testContent;
}
@@ -155,7 +156,7 @@ public class RTFChars implements LayoutFormatter {
if (c < 128) {
sb.append(c);
} else {
- sb.append("\\u").append((long) c).append('?');
+ sb.append("\\u").append((long) c).append(transformSpecialCharacter(c));
}
}
@@ -199,4 +200,148 @@ public class RTFChars implements LayoutFormatter {
// the wrong "}" at the end is removed by "format(res)"
return new StringInt(format(res), part.length());
}
+
+ /**
+ * This method transforms the unicode of a special character into its base character: 233 (é) - > e
+ * @param c long
+ * @return returns the basic character of the given unicode
+ */
+ private String transformSpecialCharacter(long c) {
+ if (((192 <= c) && (c <= 197)) || (c == 256) || (c == 258) || (c == 260)) {
+ return "A";
+ }
+ if (((224 <= c) && (c <= 229)) || (c == 257) || (c == 259) || (c == 261)) {
+ return "a";
+ }
+ if ((199 == c) || (262 == c) || (264 == c) || (266 == c) || (268 == c)) {
+ return "C";
+ }
+ if ((231 == c) || (263 == c) || (265 == c) || (267 == c) || (269 == c)) {
+ return "c";
+ }
+ if ((208 == c) || (272 == c)) {
+ return "D";
+ }
+ if ((240 == c) || (273 == c)) {
+ return "d";
+ }
+ if (((200 <= c) && (c <= 203)) || (274 == c) || (276 == c) || (278 == c) || (280 == c) || (282 == c)) {
+ return "E";
+ }
+ if (((232 <= c) && (c <= 235)) || (275 == c) || (277 == c) || (279 == c) || (281 == c) || (283 == c)) {
+ return "e";
+ }
+ if (((284 == c) || (286 == c)) || (288 == c) || (290 == c) || (330 == c)) {
+ return "G";
+ }
+ if ((285 == c) || (287 == c) || (289 == c) || (291 == c) || (331 == c)) {
+ return "g";
+ }
+ if ((292 == c) || (294 == c)) {
+ return "H";
+ }
+ if ((293 == c) || (295 == c)) {
+ return "h";
+ }
+ if (((204 <= c) && (c <= 207)) || (296 == c) || (298 == c) || (300 == c) || (302 == c) || (304 == c)) {
+ return "I";
+ }
+ if (((236 <= c) && (c <= 239)) || (297 == c) || (299 == c) || (301 == c) || (303 == c)) {
+ return "i";
+ }
+ if (308 == c) {
+ return "J";
+ }
+ if (309 == c) {
+ return "j";
+ }
+ if (310 == c) {
+ return "K";
+ }
+ if (311 == c) {
+ return "k";
+ }
+ if ((313 == c) || (315 == c) || (319 == c)) {
+ return "L";
+ }
+ if ((314 == c) || (316 == c) || (320 == c) || (322 == c)) {
+ return "l";
+ }
+ if ((209 == c) || (323 == c) || (325 == c) || (327 == c)) {
+ return "N";
+ }
+ if ((241 == c) || (324 == c) || (326 == c) || (328 == c)) {
+ return "n";
+ }
+ if (((210 <= c) && (c <= 214)) || (c == 216) || (332 == c) || (334 == c)) {
+ return "O";
+ }
+ if (((242 <= c) && (c <= 248) && (247 != c)) || (333 == c) || (335 == c)) {
+ return "o";
+ }
+ if ((340 == c) || (342 == c) || (344 == c)) {
+ return "R";
+ }
+ if ((341 == c) || (343 == c) || (345 == c)) {
+ return "r";
+ }
+ if ((346 == c) || (348 == c) || (350 == c) || (352 == c)) {
+ return "S";
+ }
+ if ((347 == c) || (349 == c) || (351 == c) || (353 == c)) {
+ return "s";
+ }
+ if ((354 == c) || (356 == c) || (358 == c)) {
+ return "T";
+ }
+ if ((355 == c) || (359 == c)) {
+ return "t";
+ }
+ if (((217 <= c) && (c <= 220)) || (360 == c) || (362 == c) || (364 == c) || (366 == c) || (370 == c)) {
+ return "U";
+ }
+ if (((249 <= c) && (c <= 251)) || (361 == c) || (363 == c) || (365 == c) || (367 == c) || (371 == c)) {
+ return "u";
+ }
+ if (372 == c) {
+ return "W";
+ }
+ if (373 == c) {
+ return "w";
+ }
+ if ((374 == c) || (376 == c) || (221 == c)) {
+ return "Y";
+ }
+ if ((375 == c) || (255 == c)) {
+ return "y";
+ }
+ if ((377 == c) || (379 == c) || (381 == c)) {
+ return "Z";
+ }
+ if ((378 == c) || (380 == c) || (382 == c)) {
+ return "z";
+ }
+ if (198 == c) {
+ return "AE";
+ }
+ if (230 == c) {
+ return "ae";
+ }
+ if (338 == c) {
+ return "OE";
+ }
+ if (339 == c) {
+ return "oe";
+ }
+ if (222 == c) {
+ return "TH";
+ }
+ if (223 == c) {
+ return "ss";
+ }
+ if (161 == c) {
+ return "!";
+ }
+ return "?";
+ }
}
diff --git a/src/main/java/net/sf/jabref/logic/layout/format/RemoveLatexCommands.java b/src/main/java/net/sf/jabref/logic/layout/format/RemoveLatexCommands.java
deleted file mode 100644
index 30c2028..0000000
--- a/src/main/java/net/sf/jabref/logic/layout/format/RemoveLatexCommands.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package net.sf.jabref.logic.layout.format;
-
-import net.sf.jabref.logic.layout.LayoutFormatter;
-import net.sf.jabref.logic.util.strings.StringUtil;
-
-public class RemoveLatexCommands implements LayoutFormatter {
-
-
- @Override
- public String format(String field) {
-
- StringBuilder sb = new StringBuilder("");
- StringBuilder currentCommand = null;
- char c;
- boolean escaped = false;
- boolean incommand = false;
- int i;
- for (i = 0; i < field.length(); i++) {
- c = field.charAt(i);
- if (escaped && (c == '\\')) {
- sb.append('\\');
- escaped = false;
- } else if (c == '\\') {
- escaped = true;
- incommand = true;
- currentCommand = new StringBuilder();
- } else if (!incommand && ((c == '{') || (c == '}'))) {
- // Swallow the brace.
- } else if (Character.isLetter(c) ||
- StringUtil.SPECIAL_COMMAND_CHARS.contains(String.valueOf(c))) {
- escaped = false;
- if (incommand) {
- currentCommand.append(c);
- if ((currentCommand.length() == 1)
- && StringUtil.SPECIAL_COMMAND_CHARS.contains(currentCommand.toString())) {
- // This indicates that we are in a command of the type \^o or \~{n}
- incommand = false;
- escaped = false;
-
- }
- } else {
- sb.append(c);
- }
- } else if (Character.isLetter(c)) {
- escaped = false;
- if (incommand) {
- // We are in a command, and should not keep the letter.
- currentCommand.append(c);
- } else {
- sb.append(c);
- }
- } else {
- if (!incommand || (!Character.isWhitespace(c) && (c != '{'))) {
- sb.append(c);
- } else {
- if (c != '{') {
- sb.append(c);
- }
- }
- incommand = false;
- escaped = false;
- }
- }
-
- return sb.toString();
- }
-}
diff --git a/src/main/java/net/sf/jabref/logic/layout/format/RemoveLatexCommandsFormatter.java b/src/main/java/net/sf/jabref/logic/layout/format/RemoveLatexCommandsFormatter.java
new file mode 100644
index 0000000..7ba309a
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/layout/format/RemoveLatexCommandsFormatter.java
@@ -0,0 +1,65 @@
+package net.sf.jabref.logic.layout.format;
+
+import net.sf.jabref.logic.layout.LayoutFormatter;
+import net.sf.jabref.model.strings.StringUtil;
+
+public class RemoveLatexCommandsFormatter implements LayoutFormatter {
+
+ @Override
+ public String format(String field) {
+ StringBuilder sb = new StringBuilder("");
+ StringBuilder currentCommand = null;
+ char c;
+ boolean escaped = false;
+ boolean incommand = false;
+ int i;
+ for (i = 0; i < field.length(); i++) {
+ c = field.charAt(i);
+ if (escaped && (c == '\\')) {
+ sb.append('\\');
+ escaped = false;
+ } else if (c == '\\') {
+ escaped = true;
+ incommand = true;
+ currentCommand = new StringBuilder();
+ } else if (!incommand && ((c == '{') || (c == '}'))) {
+ // Swallow the brace.
+ } else if (Character.isLetter(c) || StringUtil.SPECIAL_COMMAND_CHARS.contains(String.valueOf(c))) {
+ escaped = false;
+ if (incommand) {
+ currentCommand.append(c);
+ if ((currentCommand.length() == 1)
+ && StringUtil.SPECIAL_COMMAND_CHARS.contains(currentCommand.toString())) {
+ // This indicates that we are in a command of the type \^o or \~{n}
+ incommand = false;
+ escaped = false;
+
+ }
+ } else {
+ sb.append(c);
+ }
+ } else if (Character.isLetter(c)) {
+ escaped = false;
+ if (incommand) {
+ // We are in a command, and should not keep the letter.
+ currentCommand.append(c);
+ } else {
+ sb.append(c);
+ }
+ } else {
+ if (!incommand || (!Character.isWhitespace(c) && (c != '{'))) {
+ sb.append(c);
+ } else {
+ if (c != '{') {
+ sb.append(c);
+ }
+ }
+ incommand = false;
+ escaped = false;
+ }
+ }
+
+ return sb.toString();
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/logic/layout/format/RisKeywords.java b/src/main/java/net/sf/jabref/logic/layout/format/RisKeywords.java
index a882528..28bf495 100644
--- a/src/main/java/net/sf/jabref/logic/layout/format/RisKeywords.java
+++ b/src/main/java/net/sf/jabref/logic/layout/format/RisKeywords.java
@@ -1,9 +1,9 @@
package net.sf.jabref.logic.layout.format;
-import java.util.Set;
-
import net.sf.jabref.logic.layout.LayoutFormatter;
import net.sf.jabref.logic.util.OS;
+import net.sf.jabref.model.entry.Keyword;
+import net.sf.jabref.model.entry.KeywordList;
public class RisKeywords implements LayoutFormatter {
@@ -13,11 +13,11 @@ public class RisKeywords implements LayoutFormatter {
return "";
}
StringBuilder sb = new StringBuilder();
- Set<String> keywords = net.sf.jabref.model.entry.EntryUtil.getSeparatedKeywords(s);
+ KeywordList keywords = KeywordList.parse(s, ',');
int i = 0;
- for (String keyword : keywords) {
+ for (Keyword keyword : keywords) {
sb.append("KW - ");
- sb.append(keyword);
+ sb.append(keyword.toString());
if (i < (keywords.size() - 1)) {
sb.append(OS.NEWLINE);
}
diff --git a/src/main/java/net/sf/jabref/logic/layout/format/WrapFileLinks.java b/src/main/java/net/sf/jabref/logic/layout/format/WrapFileLinks.java
index e6c6a93..4b3248c 100644
--- a/src/main/java/net/sf/jabref/logic/layout/format/WrapFileLinks.java
+++ b/src/main/java/net/sf/jabref/logic/layout/format/WrapFileLinks.java
@@ -159,7 +159,7 @@ public class WrapFileLinks extends AbstractParamLayoutFormatter {
// but that is not available from a formatter. Therefore, as an
// ugly hack, the export routine has set a global variable before
// starting the export, which contains the database's file directory:
- if (prefs.getFileDirForDatabase() == null) {
+ if ((prefs.getFileDirForDatabase() == null) || prefs.getFileDirForDatabase().isEmpty()) {
dirs = prefs.getGeneratedDirForDatabase();
} else {
dirs = prefs.getFileDirForDatabase();
diff --git a/src/main/java/net/sf/jabref/logic/logging/JabRefLogger.java b/src/main/java/net/sf/jabref/logic/logging/JabRefLogger.java
index 3c0cb62..6d90d82 100644
--- a/src/main/java/net/sf/jabref/logic/logging/JabRefLogger.java
+++ b/src/main/java/net/sf/jabref/logic/logging/JabRefLogger.java
@@ -9,7 +9,6 @@ import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.LoggerConfig;
public class JabRefLogger {
-
private static final Log LOGGER = LogFactory.getLog(JabRefLogger.class);
public static void setDebug() {
diff --git a/src/main/java/net/sf/jabref/logic/mods/MODSDatabase.java b/src/main/java/net/sf/jabref/logic/mods/MODSDatabase.java
deleted file mode 100644
index 64971b5..0000000
--- a/src/main/java/net/sf/jabref/logic/mods/MODSDatabase.java
+++ /dev/null
@@ -1,73 +0,0 @@
-package net.sf.jabref.logic.mods;
-
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-
-import net.sf.jabref.model.database.BibDatabase;
-import net.sf.jabref.model.entry.BibEntry;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-
-/**
- * @author Michael Wrighton
- *
- */
-public class MODSDatabase {
-
- private Set<MODSEntry> entries;
-
- private static final Log LOGGER = LogFactory.getLog(MODSDatabase.class);
-
- public MODSDatabase() {
- // maybe make this sorted later...
- entries = new HashSet<>();
- }
-
- public MODSDatabase(BibDatabase database, List<BibEntry> entries) {
- if (entries == null) {
- addEntries(database.getEntries());
- } else {
- addEntries(entries);
- }
- }
-
- private void addEntries(List<BibEntry> entriesToAdd) {
- entries = new HashSet<>();
- for (BibEntry entry : entriesToAdd) {
- MODSEntry newMods = new MODSEntry(entry);
- entries.add(newMods);
- }
- }
-
- public Document getDOMrepresentation() {
- Document result = null;
- try {
- DocumentBuilder dbuild = DocumentBuilderFactory.
- newInstance().
- newDocumentBuilder();
- result = dbuild.newDocument();
- Element modsCollection = result.createElement("modsCollection");
- modsCollection.setAttribute("xmlns", "http://www.loc.gov/mods/v3");
- modsCollection.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
- modsCollection.setAttribute("xsi:schemaLocation", "http://www.loc.gov/mods/v3 http://www.loc.gov/standards/mods/v3/mods-3-0.xsd");
-
- for (MODSEntry entry : entries) {
- Node node = entry.getDOMrepresentation(result);
- modsCollection.appendChild(node);
- }
-
- result.appendChild(modsCollection);
- } catch (Exception e) {
- LOGGER.info("Could not get DOM representation", e);
- }
- return result;
- }
-}
diff --git a/src/main/java/net/sf/jabref/logic/mods/MODSEntry.java b/src/main/java/net/sf/jabref/logic/mods/MODSEntry.java
deleted file mode 100644
index a70193e..0000000
--- a/src/main/java/net/sf/jabref/logic/mods/MODSEntry.java
+++ /dev/null
@@ -1,319 +0,0 @@
-package net.sf.jabref.logic.mods;
-
-import java.io.StringWriter;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.transform.OutputKeys;
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.stream.StreamResult;
-
-import net.sf.jabref.logic.layout.LayoutFormatter;
-import net.sf.jabref.logic.layout.format.XMLChars;
-import net.sf.jabref.logic.util.strings.StringUtil;
-import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.model.entry.FieldName;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-
-/**
- * @author Michael Wrighton
- *
- */
-class MODSEntry {
-
- private String entryType = "mods"; // could also be relatedItem
- private String id;
- private List<PersonName> authors;
-
- // should really be handled with an enum
- private String issuance = "monographic";
- private PageNumbers pages;
-
- private String publisher;
- private String date;
-
- private String title;
-
- private String number;
- private String volume;
- private String genre;
- private String place;
- private final Set<String> handledExtensions;
-
- private MODSEntry host;
- private final Map<String, String> extensionFields;
-
- private static final String BIBTEX = "bibtex_";
-
- private static final boolean CHARFORMAT = false;
-
- private static final Log LOGGER = LogFactory.getLog(MODSEntry.class);
-
- private final LayoutFormatter chars = new XMLChars();
-
-
- private MODSEntry() {
- extensionFields = new HashMap<>();
- handledExtensions = new HashSet<>();
-
- }
-
- public MODSEntry(BibEntry bibtex) {
- this();
- handledExtensions.add(MODSEntry.BIBTEX + FieldName.PUBLISHER);
- handledExtensions.add(MODSEntry.BIBTEX + FieldName.TITLE);
- handledExtensions.add(MODSEntry.BIBTEX + BibEntry.KEY_FIELD);
- handledExtensions.add(MODSEntry.BIBTEX + "author");
- populateFromBibtex(bibtex);
- }
-
- private void populateFromBibtex(BibEntry bibtex) {
- if (bibtex.hasField(FieldName.TITLE)) {
- if (CHARFORMAT) {
- title = chars.format(bibtex.getFieldOptional(FieldName.TITLE).get());
- } else {
- title = bibtex.getFieldOptional(FieldName.TITLE).get();
- }
- }
-
- if (bibtex.hasField(FieldName.PUBLISHER)) {
- if (CHARFORMAT) {
- publisher = chars.format(bibtex.getFieldOptional(FieldName.PUBLISHER).get());
- } else {
- publisher = bibtex.getFieldOptional(FieldName.PUBLISHER).get();
- }
- }
-
- if (bibtex.hasField(BibEntry.KEY_FIELD)) {
- id = bibtex.getCiteKey();
- }
- if (bibtex.hasField("place")) { // TODO: "place" is the MODS version, in BibTeX: "address", BibLaTeX: "location"?
- if (CHARFORMAT) {
- place = chars.format(bibtex.getField("place"));
- } else {
- place = bibtex.getField("place");
- }
- }
-
- date = getDate(bibtex);
- genre = getMODSgenre(bibtex);
- if (bibtex.hasField(FieldName.AUTHOR)) {
- authors = getAuthors(bibtex.getFieldOptional(FieldName.AUTHOR).get());
- }
- if ("article".equals(bibtex.getType()) || "inproceedings".equals(bibtex.getType())) {
- host = new MODSEntry();
- host.entryType = "relatedItem";
- host.title = bibtex.getField(FieldName.BOOKTITLE);
- host.publisher = bibtex.getField(FieldName.PUBLISHER);
- host.number = bibtex.getField(FieldName.NUMBER);
- if (bibtex.hasField(FieldName.VOLUME)) {
- host.volume = bibtex.getFieldOptional(FieldName.VOLUME).get();
- }
- host.issuance = "continuing";
- if (bibtex.hasField(FieldName.PAGES)) {
- host.pages = new PageNumbers(bibtex.getFieldOptional(FieldName.PAGES).get());
- }
- }
-
- populateExtensionFields(bibtex);
-
- }
-
- private void populateExtensionFields(BibEntry e) {
-
- for (Entry<String, String> field : e.getFieldMap().entrySet()) {
- extensionFields.put(MODSEntry.BIBTEX + field.getKey(), field.getValue());
- }
- }
-
- private List<PersonName> getAuthors(String authors) {
- List<PersonName> result = new LinkedList<>();
-
- if (authors.contains(" and ")) {
- String[] names = authors.split(" and ");
- for (String name : names) {
- if (CHARFORMAT) {
- result.add(new PersonName(chars.format(name)));
- } else {
- result.add(new PersonName(name));
- }
- }
- } else {
- if (CHARFORMAT) {
- result.add(new PersonName(chars.format(authors)));
- } else {
- result.add(new PersonName(authors));
- }
- }
- return result;
- }
-
- /* construct a MODS date object */
- private static String getDate(BibEntry bibtex) {
- StringBuilder result = new StringBuilder();
- bibtex.getFieldOptional(FieldName.YEAR).ifPresent(result::append);
- bibtex.getFieldOptional(FieldName.MONTH).ifPresent(result.append('-')::append);
- return result.toString();
- }
-
- // must be from http://www.loc.gov/marc/sourcecode/genre/genrelist.html
- private static String getMODSgenre(BibEntry bibtex) {
- /**
- * <pre> String result; if (bibtexType.equals("Mastersthesis")) result =
- * "theses"; else result = "conference publication"; // etc... </pre>
- */
- return bibtex.getType();
- }
-
- private Node getDOMrepresentation() {
- Node result;
- try {
- DocumentBuilder d = DocumentBuilderFactory.newInstance().newDocumentBuilder();
-
- result = getDOMrepresentation(d.newDocument());
- } catch (Exception e) {
- throw new Error(e);
- }
- return result;
- }
-
- public Element getDOMrepresentation(Document d) {
- try {
- Element mods = d.createElement(entryType);
- mods.setAttribute("version", "3.0");
- // mods.setAttribute("xmlns:xlink:", "http://www.w3.org/1999/xlink");
- // title
- if (title != null) {
- Element titleInfo = d.createElement("titleInfo");
- Element mainTitle = d.createElement("title");
- mainTitle.appendChild(d.createTextNode(StringUtil.stripNonValidXMLCharacters(title)));
- titleInfo.appendChild(mainTitle);
- mods.appendChild(titleInfo);
- }
- if (authors != null) {
- for (PersonName name : authors) {
- Element modsName = d.createElement("name");
- modsName.setAttribute("type", "personal");
- if (name.getSurname() != null) {
- Element namePart = d.createElement("namePart");
- namePart.setAttribute("type", "family");
- namePart.appendChild(
- d.createTextNode(StringUtil.stripNonValidXMLCharacters(name.getSurname())));
- modsName.appendChild(namePart);
- }
- if (name.getGivenNames() != null) {
- Element namePart = d.createElement("namePart");
- namePart.setAttribute("type", "given");
- namePart.appendChild(
- d.createTextNode(StringUtil.stripNonValidXMLCharacters(name.getGivenNames())));
- modsName.appendChild(namePart);
- }
- Element role = d.createElement("role");
- Element roleTerm = d.createElement("roleTerm");
- roleTerm.setAttribute("type", "text");
- roleTerm.appendChild(d.createTextNode("author"));
- role.appendChild(roleTerm);
- modsName.appendChild(role);
- mods.appendChild(modsName);
- }
- }
- //publisher
- Element originInfo = d.createElement("originInfo");
- mods.appendChild(originInfo);
- if (this.publisher != null) {
- Element publisher = d.createElement(FieldName.PUBLISHER);
- publisher.appendChild(d.createTextNode(StringUtil.stripNonValidXMLCharacters(this.publisher)));
- originInfo.appendChild(publisher);
- }
- if (date != null) {
- Element dateIssued = d.createElement("dateIssued");
- dateIssued.appendChild(d.createTextNode(StringUtil.stripNonValidXMLCharacters(date)));
- originInfo.appendChild(dateIssued);
- }
- Element issuance = d.createElement("issuance");
- issuance.appendChild(d.createTextNode(StringUtil.stripNonValidXMLCharacters(this.issuance)));
- originInfo.appendChild(issuance);
-
- if (id != null) {
- Element idref = d.createElement("identifier");
- idref.appendChild(d.createTextNode(StringUtil.stripNonValidXMLCharacters(id)));
- mods.appendChild(idref);
- mods.setAttribute("ID", id);
-
- }
- Element typeOfResource = d.createElement("typeOfResource");
- String type = "text";
- typeOfResource.appendChild(d.createTextNode(StringUtil.stripNonValidXMLCharacters(type)));
- mods.appendChild(typeOfResource);
-
- if (genre != null) {
- Element genreElement = d.createElement("genre");
- genreElement.setAttribute("authority", "marc");
- genreElement.appendChild(d.createTextNode(StringUtil.stripNonValidXMLCharacters(genre)));
- mods.appendChild(genreElement);
- }
-
- if (host != null) {
- Element relatedItem = host.getDOMrepresentation(d);
- relatedItem.setAttribute("type", "host");
- mods.appendChild(relatedItem);
- }
- if (pages != null) {
- mods.appendChild(pages.getDOMrepresentation(d));
- }
-
- /* now generate extension fields for unhandled data */
- for (Map.Entry<String, String> theEntry : extensionFields.entrySet()) {
- Element extension = d.createElement("extension");
- String field = theEntry.getKey();
- String value = theEntry.getValue();
- if (handledExtensions.contains(field)) {
- continue;
- }
- Element theData = d.createElement(field);
- theData.appendChild(d.createTextNode(StringUtil.stripNonValidXMLCharacters(value)));
- extension.appendChild(theData);
- mods.appendChild(extension);
- }
- return mods;
- } catch (Exception e) {
- LOGGER.warn("Exception caught...", e);
- throw new Error(e);
- }
- // return result;
- }
-
- /*
- * render as XML
- *
- */
- @Override
- public String toString() {
- StringWriter sresult = new StringWriter();
- try {
- DOMSource source = new DOMSource(getDOMrepresentation());
- StreamResult result = new StreamResult(sresult);
- Transformer trans = TransformerFactory.newInstance().newTransformer();
- trans.setOutputProperty(OutputKeys.INDENT, "yes");
- trans.transform(source, result);
- } catch (Exception e) {
- throw new Error(e);
- }
- return sresult.toString();
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/logic/mods/PageNumbers.java b/src/main/java/net/sf/jabref/logic/mods/PageNumbers.java
deleted file mode 100644
index 4223755..0000000
--- a/src/main/java/net/sf/jabref/logic/mods/PageNumbers.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package net.sf.jabref.logic.mods;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-
-public class PageNumbers {
- private String freeform;
- private int start;
- private int end;
-
- private static final Pattern PAGE_PATTERN = Pattern.compile("\\s*(\\d+)\\s*-{1,2}\\s*(\\d+)\\s*");
-
- public PageNumbers(String pages) {
- parsePageNums(pages);
- }
-
- private void parsePageNums(String pages) {
- Matcher matcher = PAGE_PATTERN.matcher(pages);
- if (matcher.matches()) {
- start = Integer.parseInt(matcher.group(1));
- end = Integer.parseInt(matcher.group(2));
- } else {
- freeform = pages;
- }
- }
-
- public Element getDOMrepresentation(Document document) {
- Element result = document.createElement("extent");
- result.setAttribute("unit", "page");
- if (freeform == null) {
- Element tmpStart = document.createElement("start");
- Element tmpEnd = document.createElement("end");
- tmpStart.appendChild(document.createTextNode(String.valueOf(this.start)));
- tmpEnd.appendChild(document.createTextNode(String.valueOf(this.end)));
- result.appendChild(tmpStart);
- result.appendChild(tmpEnd);
- } else {
- Node textNode = document.createTextNode(freeform);
- result.appendChild(textNode);
- }
- return result;
- }
-
- public String toString(String separator) {
- if (freeform != null) {
- return freeform;
- }
- return start + separator + end;
- }
-
- @Override
- public String toString() {
- return toString("-");
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/logic/mods/PersonName.java b/src/main/java/net/sf/jabref/logic/mods/PersonName.java
deleted file mode 100644
index 82accf3..0000000
--- a/src/main/java/net/sf/jabref/logic/mods/PersonName.java
+++ /dev/null
@@ -1,128 +0,0 @@
-package net.sf.jabref.logic.mods;
-
-import java.util.List;
-
-import net.sf.jabref.logic.util.strings.StringUtil;
-import net.sf.jabref.model.entry.AuthorList;
-
-/**
- * @author Michael Wrighton, S M Mahbub Murshed
- *
- * S M Mahbub Murshed : added few functions for convenience. May 15, 2007
- *
- * History
- * Dec 16, 2011 - Changed parseName(String) to export authorname with
- * more than 3 names correctly
- *
- */
-public class PersonName {
-
- private String givenName;
- private String surname;
- private String middleName;
-
-
- public PersonName() {
- // Empty constructor
- }
-
- public PersonName(String name) {
- parseName(name);
- }
-
- public PersonName(String firstName, String middleName, String lastName) {
- givenName = firstName;
- this.middleName = middleName;
- surname = lastName;
- }
-
- private void parseName(String author) {
- String authorMod = AuthorList.fixAuthorLastNameFirst(author, false);
-
- //Formating names and replacing escape Char for ',' back to a comma
- // XMLChars xmlChars = new XMLChars();
- // authorMod = xmlChars.format(authorMod).replace(",", ",");
-
- int endOfLastName = authorMod.indexOf(',');
-
- // Tokenize just the firstName and middleNames as we have the surname
- // before the comma.
- List<String> names = StringUtil.tokenizeToList(authorMod.substring(endOfLastName + 1).trim(), " \n\r");
- if (endOfLastName >= 0) {
- names.add(authorMod.substring(0, endOfLastName));
- }
-
- int amountOfNames = names.size();
-
- if (amountOfNames == 1) {
- surname = names.get(0);
- } else if (amountOfNames == 2) {
- givenName = names.get(0);
- surname = names.get(1);
- }
- else {
- givenName = names.get(0);
- middleName = "";
- for (int i = 1; i < (amountOfNames - 1); i++) {
- middleName += ' ' + names.get(i);
- }
- middleName = middleName.trim();
- surname = names.get(amountOfNames - 1);
- }
- }
-
- public String getGivenNames() {
- StringBuilder result = new StringBuilder();
- if (givenName != null) {
- result.append(givenName);
- }
- if (middleName != null) {
- result.append(' ').append(middleName);
- }
- return result.toString();
- }
-
- public String getSurname() {
- return surname;
- }
-
- public void setSurname(String lastName) {
- surname = lastName;
- }
-
- public String getFirstname() {
- return givenName;
- }
-
- public void setFirstname(String firstName) {
- givenName = firstName;
- }
-
- public String getMiddlename() {
- return middleName;
- }
-
- public void setMiddlename(String middleName) {
- this.middleName = middleName;
- }
-
- public String getFullname() {
- StringBuilder fullName = new StringBuilder();
- if ((givenName != null) && !givenName.isEmpty()) {
- fullName.append(givenName).append(' ');
- }
- if ((middleName != null) && !middleName.isEmpty()) {
- fullName.append(middleName).append(' ');
- }
- if ((surname != null) && !surname.isEmpty()) {
- fullName.append(surname);
- }
-
- return fullName.toString().trim();
- }
-
- @Override
- public String toString() {
- return surname;
- }
-}
diff --git a/src/main/java/net/sf/jabref/logic/msbib/BibTeXConverter.java b/src/main/java/net/sf/jabref/logic/msbib/BibTeXConverter.java
index 8241433..2da41bc 100644
--- a/src/main/java/net/sf/jabref/logic/msbib/BibTeXConverter.java
+++ b/src/main/java/net/sf/jabref/logic/msbib/BibTeXConverter.java
@@ -7,8 +7,7 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
-import net.sf.jabref.logic.importer.fileformat.ImportFormat;
-import net.sf.jabref.logic.mods.PersonName;
+import net.sf.jabref.logic.importer.Importer;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.FieldName;
import net.sf.jabref.model.entry.MonthUtil;
@@ -19,13 +18,18 @@ public class BibTeXConverter {
private static final String MSBIB_PREFIX = "msbib-";
+ /**
+ * Converts an {@link MSBibEntry} to a {@link BibEntry} for import
+ * @param entry The MsBibEntry to convert
+ * @return The bib entry
+ */
public static BibEntry convert(MSBibEntry entry) {
BibEntry result;
Map<String, String> fieldValues = new HashMap<>();
String bibTexEntryType = MSBibMapping.getBibLaTeXEntryType(entry.getType());
if (entry.getCiteKey() == null) {
- result = new BibEntry(ImportFormat.DEFAULT_BIBTEXENTRY_ID, bibTexEntryType);
+ result = new BibEntry(Importer.DEFAULT_BIBTEXENTRY_ID, bibTexEntryType);
} else {
// TODO: the cite key should not be the ID?!
@@ -72,7 +76,7 @@ public class BibTeXConverter {
parseStandardNumber(entry.standardNumber, fieldValues);
if (entry.address != null) {
- fieldValues.put(FieldName.ADDRESS, entry.address);
+ fieldValues.put(FieldName.LOCATION, entry.address);
}
// TODO: ConferenceName is saved as booktitle when converting from MSBIB to BibTeX
if (entry.conferenceName != null) {
diff --git a/src/main/java/net/sf/jabref/logic/msbib/MSBibConverter.java b/src/main/java/net/sf/jabref/logic/msbib/MSBibConverter.java
index e70242a..247e4e0 100644
--- a/src/main/java/net/sf/jabref/logic/msbib/MSBibConverter.java
+++ b/src/main/java/net/sf/jabref/logic/msbib/MSBibConverter.java
@@ -4,9 +4,6 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
-import net.sf.jabref.logic.layout.format.LatexToUnicodeFormatter;
-import net.sf.jabref.logic.mods.PageNumbers;
-import net.sf.jabref.logic.mods.PersonName;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.FieldName;
@@ -26,7 +23,7 @@ public class MSBibConverter {
for (String field : entry.getFieldNames()) {
// clean field
- String unicodeField = removeLaTeX(entry.getFieldOptional(field).orElse(""));
+ String unicodeField = entry.getLatexFreeField(field).orElse("");
if (MSBibMapping.getMSBibField(field) != null) {
result.fields.put(MSBibMapping.getMSBibField(field), unicodeField);
@@ -34,43 +31,45 @@ public class MSBibConverter {
}
// Duplicate: also added as BookTitle
- entry.getFieldOptional(FieldName.BOOKTITLE).ifPresent(booktitle -> result.conferenceName = booktitle);
- entry.getFieldOptional(FieldName.PAGES).ifPresent(pages -> result.pages = new PageNumbers(pages));
- entry.getFieldOptional(MSBIB_PREFIX + "accessed").ifPresent(accesed -> result.dateAccessed = accesed);
+ entry.getField(FieldName.BOOKTITLE).ifPresent(booktitle -> result.conferenceName = booktitle);
+ entry.getField(FieldName.PAGES).ifPresent(pages -> result.pages = new PageNumbers(pages));
+ entry.getField(MSBIB_PREFIX + "accessed").ifPresent(accesed -> result.dateAccessed = accesed);
// TODO: currently this can never happen
if ("SoundRecording".equals(msbibType)) {
- result.albumTitle = entry.getFieldOptional(FieldName.TITLE).orElse(null);
+ result.albumTitle = entry.getField(FieldName.TITLE).orElse(null);
}
// TODO: currently this can never happen
if ("Interview".equals(msbibType)) {
- result.broadcastTitle = entry.getFieldOptional(FieldName.TITLE).orElse(null);
+ result.broadcastTitle = entry.getField(FieldName.TITLE).orElse(null);
+ }
+
+ if (!entry.getField(FieldName.ISSUE).isPresent()) {
+ result.number = entry.getField(FieldName.NUMBER).orElse(null);
}
if ("Patent".equalsIgnoreCase(entry.getType())) {
- result.patentNumber = entry.getFieldOptional(FieldName.NUMBER).orElse(null);
+ result.patentNumber = entry.getField(FieldName.NUMBER).orElse(null);
+ result.number = null;
}
result.journalName = entry.getFieldOrAlias(FieldName.JOURNAL).orElse(null);
result.month = entry.getFieldOrAlias(FieldName.MONTH).orElse(null);
- if (!entry.getFieldOptional(FieldName.YEAR).isPresent()) {
+ if (!entry.getField(FieldName.YEAR).isPresent()) {
result.year = entry.getFieldOrAlias(FieldName.YEAR).orElse(null);
}
- if (!entry.getFieldOptional(FieldName.ISSUE).isPresent()) {
- result.number = entry.getFieldOptional(FieldName.NUMBER).orElse(null);
- }
// Value must be converted
//Currently only english is supported
- entry.getFieldOptional(FieldName.LANGUAGE)
+ entry.getField(FieldName.LANGUAGE)
.ifPresent(lang -> result.fields.put("LCID", String.valueOf(MSBibMapping.getLCID(lang))));
StringBuilder sbNumber = new StringBuilder();
- entry.getFieldOptional(FieldName.ISBN).ifPresent(isbn -> sbNumber.append(" ISBN: " + isbn));
- entry.getFieldOptional(FieldName.ISSN).ifPresent(issn -> sbNumber.append(" ISSN: " + issn));
- entry.getFieldOptional("lccn").ifPresent(lccn -> sbNumber.append("LCCN: " + lccn));
- entry.getFieldOptional("mrnumber").ifPresent(mrnumber -> sbNumber.append(" MRN: " + mrnumber));
+ entry.getField(FieldName.ISBN).ifPresent(isbn -> sbNumber.append(" ISBN: " + isbn));
+ entry.getField(FieldName.ISSN).ifPresent(issn -> sbNumber.append(" ISSN: " + issn));
+ entry.getField("lccn").ifPresent(lccn -> sbNumber.append("LCCN: " + lccn));
+ entry.getField("mrnumber").ifPresent(mrnumber -> sbNumber.append(" MRN: " + mrnumber));
result.standardNumber = sbNumber.toString();
if (result.standardNumber.isEmpty()) {
@@ -79,8 +78,8 @@ public class MSBibConverter {
result.address = entry.getFieldOrAlias(FieldName.ADDRESS).orElse(null);
- if (entry.getFieldOptional(FieldName.TYPE).isPresent()) {
- result.thesisType = entry.getFieldOptional(FieldName.TYPE).get();
+ if (entry.getField(FieldName.TYPE).isPresent()) {
+ result.thesisType = entry.getField(FieldName.TYPE).get();
} else {
if ("techreport".equalsIgnoreCase(entry.getType())) {
@@ -96,16 +95,16 @@ public class MSBibConverter {
// TODO: currently this can never happen
if (("InternetSite".equals(msbibType) || "DocumentFromInternetSite".equals(msbibType))) {
- result.internetSiteTitle = entry.getFieldOptional(FieldName.TITLE).orElse(null);
+ result.internetSiteTitle = entry.getField(FieldName.TITLE).orElse(null);
}
// TODO: currently only Misc can happen
if ("ElectronicSource".equals(msbibType) || "Art".equals(msbibType) || "Misc".equals(msbibType)) {
- result.publicationTitle = entry.getFieldOptional(FieldName.TITLE).orElse(null);
+ result.publicationTitle = entry.getField(FieldName.TITLE).orElse(null);
}
- entry.getFieldOptional(FieldName.AUTHOR).ifPresent(authors -> result.authors = getAuthors(authors));
- entry.getFieldOptional(FieldName.EDITOR).ifPresent(editors -> result.editors = getAuthors(editors));
+ entry.getLatexFreeField(FieldName.AUTHOR).ifPresent(authors -> result.authors = getAuthors(authors));
+ entry.getLatexFreeField(FieldName.EDITOR).ifPresent(editors -> result.editors = getAuthors(editors));
return result;
}
@@ -113,8 +112,6 @@ public class MSBibConverter {
private static List<PersonName> getAuthors(String authors) {
List<PersonName> result = new ArrayList<>();
- authors = removeLaTeX(authors);
-
if (authors.toUpperCase(Locale.ENGLISH).contains(" AND ")) {
String[] names = authors.split(" (?i)and ");
for (String name : names) {
@@ -126,7 +123,4 @@ public class MSBibConverter {
return result;
}
- private static String removeLaTeX(String text) {
- return new LatexToUnicodeFormatter().format(text);
- }
}
diff --git a/src/main/java/net/sf/jabref/logic/msbib/MSBibDatabase.java b/src/main/java/net/sf/jabref/logic/msbib/MSBibDatabase.java
index beb7a95..1eeb5e7 100644
--- a/src/main/java/net/sf/jabref/logic/msbib/MSBibDatabase.java
+++ b/src/main/java/net/sf/jabref/logic/msbib/MSBibDatabase.java
@@ -26,7 +26,7 @@ import org.xml.sax.SAXException;
/**
* Microsoft Word bibliography.
- *
+ * The class is uesed both for import and export
* See http://www.ecma-international.org/publications/standards/Ecma-376.htm
*/
public class MSBibDatabase {
@@ -39,20 +39,33 @@ public class MSBibDatabase {
private Set<MSBibEntry> entries;
+ /**
+ * Creates a {@link MSBibDatabase} for <b>import</b>
+ */
public MSBibDatabase() {
entries = new HashSet<>();
}
// TODO: why an additonal entry list? entries are included inside database!
+ /**
+ * Creates a new {@link MSBibDatabase} for <b>export</b>
+ * @param database The bib database
+ * @param entries List of {@link BibEntry}
+ */
public MSBibDatabase(BibDatabase database, List<BibEntry> entries) {
if (entries == null) {
- addEntries(database.getEntries());
+ addEntriesForExport(database.getEntries());
} else {
- addEntries(entries);
+ addEntriesForExport(entries);
}
}
- public List<BibEntry> importEntries(BufferedReader reader) {
+ /**
+ * Imports entries from an office xml file
+ * @param reader
+ * @return List of {@link BibEntry}
+ */
+ public List<BibEntry> importEntriesFromXml(BufferedReader reader) {
entries = new HashSet<>();
Document inputDocument;
try {
@@ -83,7 +96,7 @@ public class MSBibDatabase {
return bibitems;
}
- private void addEntries(List<BibEntry> entriesToAdd) {
+ private void addEntriesForExport(List<BibEntry> entriesToAdd) {
entries = new HashSet<>();
for (BibEntry entry : entriesToAdd) {
MSBibEntry newMods = MSBibConverter.convert(entry);
@@ -91,7 +104,11 @@ public class MSBibDatabase {
}
}
- public Document getDOM() {
+ /**
+ * Gets the assembled dom for export
+ * @return XML Document
+ */
+ public Document getDomForExport() {
Document document = null;
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
@@ -106,7 +123,7 @@ public class MSBibDatabase {
rootNode.setAttribute("SelectedStyle", "");
for (MSBibEntry entry : entries) {
- Node node = entry.getDOM(document);
+ Node node = entry.getEntryDom(document);
rootNode.appendChild(node);
}
document.appendChild(rootNode);
diff --git a/src/main/java/net/sf/jabref/logic/msbib/MSBibEntry.java b/src/main/java/net/sf/jabref/logic/msbib/MSBibEntry.java
index f42a586..935c46d 100644
--- a/src/main/java/net/sf/jabref/logic/msbib/MSBibEntry.java
+++ b/src/main/java/net/sf/jabref/logic/msbib/MSBibEntry.java
@@ -7,9 +7,7 @@ import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import net.sf.jabref.logic.mods.PageNumbers;
-import net.sf.jabref.logic.mods.PersonName;
-import net.sf.jabref.logic.util.strings.StringUtil;
+import net.sf.jabref.model.strings.StringUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
@@ -64,24 +62,32 @@ class MSBibEntry {
private String bibtexEntryType;
- // reduced subset, supports only "CITY , STATE, COUNTRY"
- // \b(\w+)\s?[,]?\s?(\w+)\s?[,]?\s?(\w+)\b
- // WORD SPACE , SPACE WORD SPACE , SPACE WORD
- // tested using http://www.javaregex.com/test.html
- private static final Pattern ADDRESS_PATTERN = Pattern.compile("\\b(\\w+)\\s?[,]?\\s?(\\w+)\\s?[,]?\\s?(\\w+)\\b");
-
- // Allows 20.3-2007|||20/3- 2007 etc.
- // (\d{1,2})\s?[.,-/]\s?(\d{1,2})\s?[.,-/]\s?(\d{2,4})
- // 1-2 DIGITS SPACE SEPERATOR SPACE 1-2 DIGITS SPACE SEPERATOR SPACE 2-4 DIGITS
- // tested using http://www.javaregex.com/test.html
+ /**
+ * reduced subset, supports only "CITY , STATE, COUNTRY" <br>
+ * <b>\b(\w+)\s?[,]?\s?(\w+)\s?[,]?\s?(\w*)\b</b> <br>
+ * WORD SPACE , SPACE WORD SPACE (Can be zero or more) , SPACE WORD (Can be zero or more) <br>
+ * Matches both single locations (only city) like Berlin and full locations like Stroudsburg, PA, USA <br>
+ * tested using http://www.regexpal.com/
+ */
+ private final Pattern ADDRESS_PATTERN = Pattern.compile("\\b(\\w+)\\s?[,]?\\s?(\\w*)\\s?[,]?\\s?(\\w*)\\b");
+
+ /**
+ * Allows 20.3-2007|||20/3- 2007 etc.
+ * <b>(\d{1,2})\s?[.,-/]\s?(\d{1,2})\s?[.,-/]\s?(\d{2,4})</b>
+ * 1-2 DIGITS SPACE SEPERATOR SPACE 1-2 DIGITS SPACE SEPERATOR SPACE 2-4 DIGITS
+ */
private static final Pattern DATE_PATTERN = Pattern
.compile("(\\d{1,2})\\s*[.,-/]\\s*(\\d{1,2})\\s*[.,-/]\\s*(\\d{2,4})");
public MSBibEntry() {
-
+ //empty
}
+ /**
+ * Createa new {@link MsBibEntry} to import from an xml element
+ * @param entry
+ */
public MSBibEntry(Element entry) {
populateFromXml(entry);
}
@@ -128,14 +134,17 @@ class MSBibEntry {
String city = getXmlElementTextContent("City", entry);
String state = getXmlElementTextContent("StateProvince", entry);
String country = getXmlElementTextContent("CountryRegion", entry);
+
StringBuilder addressBuffer = new StringBuilder();
if (city != null) {
- addressBuffer.append(city).append(", ");
+ addressBuffer.append(city);
}
- if (state != null) {
- addressBuffer.append(state).append(' ');
+ if (((state != null) && !state.isEmpty()) && ((city != null) && !city.isEmpty())) {
+ addressBuffer.append(",").append(' ');
+ addressBuffer.append(state);
}
- if (country != null) {
+ if ((country != null) && !country.isEmpty()) {
+ addressBuffer.append(",").append(' ');
addressBuffer.append(country);
}
address = addressBuffer.toString().trim();
@@ -231,7 +240,12 @@ class MSBibEntry {
return result;
}
- public Element getDOM(Document document) {
+ /**
+ * Gets the dom representation for one entry, used for export
+ * @param document XmlDocument
+ * @return XmlElement represenation of one entry
+ */
+ public Element getEntryDom(Document document) {
Element rootNode = document.createElementNS(MSBibDatabase.NAMESPACE, MSBibDatabase.PREFIX + "Source");
for (Map.Entry<String, String> entry : fields.entrySet()) {
@@ -277,6 +291,8 @@ class MSBibEntry {
addField(document, rootNode, "JournalName", journalName);
addField(document, rootNode, "PatentNumber", patentNumber);
+ addField(document, rootNode, "Number", number);
+
addField(document, rootNode, "StandardNumber", standardNumber);
addField(document, rootNode, "ConferenceName", conferenceName);
@@ -318,18 +334,18 @@ class MSBibEntry {
allAuthors.appendChild(authorTop);
}
- private void addAddress(Document document, Element parent, String address) {
- if (address == null) {
+ private void addAddress(Document document, Element parent, String addressToSplit) {
+ if (addressToSplit == null) {
return;
}
- Matcher matcher = ADDRESS_PATTERN.matcher(address);
+ Matcher matcher = ADDRESS_PATTERN.matcher(addressToSplit);
if (matcher.matches() && (matcher.groupCount() >= 3)) {
addField(document, parent, "City", matcher.group(1));
addField(document, parent, "StateProvince", matcher.group(2));
addField(document, parent, "CountryRegion", matcher.group(3));
} else {
- addField(document, parent, "City", address);
+ addField(document, parent, "City", addressToSplit);
}
}
}
diff --git a/src/main/java/net/sf/jabref/logic/msbib/MSBibMapping.java b/src/main/java/net/sf/jabref/logic/msbib/MSBibMapping.java
index 1a62f3a..d1e36b3 100644
--- a/src/main/java/net/sf/jabref/logic/msbib/MSBibMapping.java
+++ b/src/main/java/net/sf/jabref/logic/msbib/MSBibMapping.java
@@ -32,6 +32,9 @@ public class MSBibMapping {
biblatexToMsBib.put(FieldName.EDITION, "Edition");
biblatexToMsBib.put(FieldName.PUBLISHER, "Publisher");
biblatexToMsBib.put(FieldName.BOOKTITLE, "BookTitle");
+ biblatexToMsBib.put("shorttitle", "ShortTitle");
+ biblatexToMsBib.put(FieldName.NOTE, "Comments");
+
//biblatexToMsBib.put(FieldName.BOOKTITLE, "ConferenceName");
//biblatexToMsBib.put(FieldName.PAGES, "Pages");
biblatexToMsBib.put(FieldName.CHAPTER, "ChapterNumber");
@@ -42,6 +45,7 @@ public class MSBibMapping {
biblatexToMsBib.put(FieldName.DOI, "DOI");
biblatexToMsBib.put(FieldName.URL, "URL");
// BibTeX/Biblatex only fields
+
biblatexToMsBib.put(FieldName.SERIES, BIBTEX_PREFIX + "Series");
biblatexToMsBib.put(FieldName.ABSTRACT, BIBTEX_PREFIX + "Abstract");
biblatexToMsBib.put(FieldName.KEYWORDS, BIBTEX_PREFIX + "KeyWords");
@@ -54,11 +58,12 @@ public class MSBibMapping {
biblatexToMsBib.put("size", BIBTEX_PREFIX + "Size");
biblatexToMsBib.put("intype", BIBTEX_PREFIX + "InType");
biblatexToMsBib.put("paper", BIBTEX_PREFIX + "Paper");
- biblatexToMsBib.put("shorttitle", "ShortTitle");
+ biblatexToMsBib.put(FieldName.KEY, BIBTEX_PREFIX + "Key");
+
// MSBib only fields
biblatexToMsBib.put(MSBIB_PREFIX + "numberofvolume", "NumberVolumes");
biblatexToMsBib.put(MSBIB_PREFIX + "periodical", "PeriodicalTitle");
- biblatexToMsBib.put(MSBIB_PREFIX + "day", "Day");
+ biblatexToMsBib.put(MSBIB_PREFIX + FieldName.DAY, "Day");
biblatexToMsBib.put(MSBIB_PREFIX + "accessed", "Accessed");
biblatexToMsBib.put(MSBIB_PREFIX + "medium", "Medium");
biblatexToMsBib.put(MSBIB_PREFIX + "recordingnumber", "RecordingNumber");
diff --git a/src/main/java/net/sf/jabref/logic/msbib/PageNumbers.java b/src/main/java/net/sf/jabref/logic/msbib/PageNumbers.java
new file mode 100644
index 0000000..8342046
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/msbib/PageNumbers.java
@@ -0,0 +1,60 @@
+package net.sf.jabref.logic.msbib;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+public class PageNumbers {
+ private String freeform;
+ private int start;
+ private int end;
+
+ private static final Pattern PAGE_PATTERN = Pattern.compile("\\s*(\\d+)\\s*-{1,2}\\s*(\\d+)\\s*");
+
+ public PageNumbers(String pages) {
+ parsePageNums(pages);
+ }
+
+ private void parsePageNums(String pages) {
+ Matcher matcher = PAGE_PATTERN.matcher(pages);
+ if (matcher.matches()) {
+ start = Integer.parseInt(matcher.group(1));
+ end = Integer.parseInt(matcher.group(2));
+ } else {
+ freeform = pages;
+ }
+ }
+
+ public Element getDOMrepresentation(Document document) {
+ Element result = document.createElement("extent");
+ result.setAttribute("unit", "page");
+ if (freeform == null) {
+ Element tmpStart = document.createElement("start");
+ Element tmpEnd = document.createElement("end");
+ tmpStart.appendChild(document.createTextNode(String.valueOf(this.start)));
+ tmpEnd.appendChild(document.createTextNode(String.valueOf(this.end)));
+ result.appendChild(tmpStart);
+ result.appendChild(tmpEnd);
+ } else {
+ Node textNode = document.createTextNode(freeform);
+ result.appendChild(textNode);
+ }
+ return result;
+ }
+
+ public String toString(String separator) {
+ if (freeform != null) {
+ return freeform;
+ }
+ return start + separator + end;
+ }
+
+ @Override
+ public String toString() {
+ return toString("-");
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/logic/msbib/PersonName.java b/src/main/java/net/sf/jabref/logic/msbib/PersonName.java
new file mode 100644
index 0000000..65644c3
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/msbib/PersonName.java
@@ -0,0 +1,128 @@
+package net.sf.jabref.logic.msbib;
+
+import java.util.List;
+
+import net.sf.jabref.model.entry.AuthorList;
+import net.sf.jabref.model.strings.StringUtil;
+
+/**
+ * @author Michael Wrighton, S M Mahbub Murshed
+ *
+ * S M Mahbub Murshed : added few functions for convenience. May 15, 2007
+ *
+ * History
+ * Dec 16, 2011 - Changed parseName(String) to export authorname with
+ * more than 3 names correctly
+ *
+ */
+public class PersonName {
+
+ private String givenName;
+ private String surname;
+ private String middleName;
+
+
+ public PersonName() {
+ // Empty constructor
+ }
+
+ public PersonName(String name) {
+ parseName(name);
+ }
+
+ public PersonName(String firstName, String middleName, String lastName) {
+ givenName = firstName;
+ this.middleName = middleName;
+ surname = lastName;
+ }
+
+ private void parseName(String author) {
+ String authorMod = AuthorList.fixAuthorLastNameFirst(author, false);
+
+ //Formating names and replacing escape Char for ',' back to a comma
+ // XMLChars xmlChars = new XMLChars();
+ // authorMod = xmlChars.format(authorMod).replace(",", ",");
+
+ int endOfLastName = authorMod.indexOf(',');
+
+ // Tokenize just the firstName and middleNames as we have the surname
+ // before the comma.
+ List<String> names = StringUtil.tokenizeToList(authorMod.substring(endOfLastName + 1).trim(), " \n\r");
+ if (endOfLastName >= 0) {
+ names.add(authorMod.substring(0, endOfLastName));
+ }
+
+ int amountOfNames = names.size();
+
+ if (amountOfNames == 1) {
+ surname = names.get(0);
+ } else if (amountOfNames == 2) {
+ givenName = names.get(0);
+ surname = names.get(1);
+ }
+ else {
+ givenName = names.get(0);
+ middleName = "";
+ for (int i = 1; i < (amountOfNames - 1); i++) {
+ middleName += ' ' + names.get(i);
+ }
+ middleName = middleName.trim();
+ surname = names.get(amountOfNames - 1);
+ }
+ }
+
+ public String getGivenNames() {
+ StringBuilder result = new StringBuilder();
+ if (givenName != null) {
+ result.append(givenName);
+ }
+ if (middleName != null) {
+ result.append(' ').append(middleName);
+ }
+ return result.toString();
+ }
+
+ public String getSurname() {
+ return surname;
+ }
+
+ public void setSurname(String lastName) {
+ surname = lastName;
+ }
+
+ public String getFirstname() {
+ return givenName;
+ }
+
+ public void setFirstname(String firstName) {
+ givenName = firstName;
+ }
+
+ public String getMiddlename() {
+ return middleName;
+ }
+
+ public void setMiddlename(String middleName) {
+ this.middleName = middleName;
+ }
+
+ public String getFullname() {
+ StringBuilder fullName = new StringBuilder();
+ if ((givenName != null) && !givenName.isEmpty()) {
+ fullName.append(givenName).append(' ');
+ }
+ if ((middleName != null) && !middleName.isEmpty()) {
+ fullName.append(middleName).append(' ');
+ }
+ if ((surname != null) && !surname.isEmpty()) {
+ fullName.append(surname);
+ }
+
+ return fullName.toString().trim();
+ }
+
+ @Override
+ public String toString() {
+ return surname;
+ }
+}
diff --git a/src/main/java/net/sf/jabref/logic/net/ProxyPreferences.java b/src/main/java/net/sf/jabref/logic/net/ProxyPreferences.java
index 78b2d31..c09cd68 100644
--- a/src/main/java/net/sf/jabref/logic/net/ProxyPreferences.java
+++ b/src/main/java/net/sf/jabref/logic/net/ProxyPreferences.java
@@ -2,8 +2,6 @@ package net.sf.jabref.logic.net;
import java.util.Objects;
-import net.sf.jabref.preferences.JabRefPreferences;
-
public class ProxyPreferences {
private final Boolean useProxy;
@@ -47,25 +45,6 @@ public class ProxyPreferences {
return password;
}
- public void storeInPreferences(JabRefPreferences preferences) {
- preferences.putBoolean(JabRefPreferences.PROXY_USE, isUseProxy());
- preferences.put(JabRefPreferences.PROXY_HOSTNAME, getHostname());
- preferences.put(JabRefPreferences.PROXY_PORT, getPort());
- preferences.putBoolean(JabRefPreferences.PROXY_USE_AUTHENTICATION, isUseAuthentication());
- preferences.put(JabRefPreferences.PROXY_USERNAME, getUsername());
- preferences.put(JabRefPreferences.PROXY_PASSWORD, getPassword());
- }
-
- public static ProxyPreferences loadFromPreferences(JabRefPreferences preferences) {
- Boolean useProxy = preferences.getBoolean(JabRefPreferences.PROXY_USE);
- String hostname = preferences.get(JabRefPreferences.PROXY_HOSTNAME);
- String port = preferences.get(JabRefPreferences.PROXY_PORT);
- Boolean useAuthentication = preferences.getBoolean(JabRefPreferences.PROXY_USE_AUTHENTICATION);
- String username = preferences.get(JabRefPreferences.PROXY_USERNAME);
- String password = preferences.get(JabRefPreferences.PROXY_PASSWORD);
- return new ProxyPreferences(useProxy, hostname, port, useAuthentication, username, password);
- }
-
@Override
public int hashCode() {
return Objects.hash(hostname, password, port, useAuthentication, useProxy, username);
diff --git a/src/main/java/net/sf/jabref/logic/net/URLDownload.java b/src/main/java/net/sf/jabref/logic/net/URLDownload.java
index d022704..fd88a14 100644
--- a/src/main/java/net/sf/jabref/logic/net/URLDownload.java
+++ b/src/main/java/net/sf/jabref/logic/net/URLDownload.java
@@ -1,25 +1,35 @@
package net.sf.jabref.logic.net;
import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
-import java.io.OutputStream;
import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;
+import java.net.CookieHandler;
+import java.net.CookieManager;
+import java.net.CookiePolicy;
+import java.net.HttpCookie;
+import java.net.HttpURLConnection;
import java.net.MalformedURLException;
+import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
+import net.sf.jabref.logic.util.io.FileUtil;
+
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -38,15 +48,21 @@ import org.apache.commons.logging.LogFactory;
* @author Simon Harrer
*/
public class URLDownload {
-
- private final URL source;
-
private static final Log LOGGER = LogFactory.getLog(URLDownload.class);
+ private static final String USER_AGENT= "JabRef";
+
+ private final URL source;
private final Map<String, String> parameters = new HashMap<>();
private String postData = "";
+ public static URLDownload createURLDownloadWithBrowserUserAgent(String address) throws MalformedURLException {
+ URLDownload downloader = new URLDownload(address);
+ downloader.addParameters("User-Agent", "Mozilla/5.0 (Windows NT 5.1; rv:31.0) Gecko/20100101 Firefox/31.0");
+ return downloader;
+ }
+
/**
* @param address the URL to download from
* @throws MalformedURLException if no protocol is specified in the address, or an unknown protocol is found
@@ -60,9 +76,7 @@ public class URLDownload {
*/
public URLDownload(URL source) {
this.source = source;
-
- addParameters("User-Agent", "JabRef");
-
+ addParameters("User-Agent", USER_AGENT);
}
public URL getSource() {
@@ -95,7 +109,7 @@ public class URLDownload {
}
private URLConnection openConnection() throws IOException {
- URLConnection connection = source.openConnection();
+ HttpURLConnection connection = (HttpURLConnection) source.openConnection();
for (Map.Entry<String, String> entry : parameters.entrySet()) {
connection.setRequestProperty(entry.getKey(), entry.getValue());
}
@@ -106,6 +120,20 @@ public class URLDownload {
}
}
+
+ // normally, 3xx is redirect
+ int status = connection.getResponseCode();
+ if (status != HttpURLConnection.HTTP_OK) {
+ if (status == HttpURLConnection.HTTP_MOVED_TEMP
+ || status == HttpURLConnection.HTTP_MOVED_PERM
+ || status == HttpURLConnection.HTTP_SEE_OTHER) {
+ // get redirect url from "location" header field
+ String newUrl = connection.getHeaderField("Location");
+ // open the new connnection again
+ connection = (HttpURLConnection) new URLDownload(newUrl).openConnection();
+ }
+ }
+
// this does network i/o: GET + read returned headers
connection.connect();
@@ -130,6 +158,23 @@ public class URLDownload {
}
}
+ public List<HttpCookie> getCookieFromUrl() throws IOException {
+ CookieManager cookieManager = new CookieManager();
+ CookieHandler.setDefault(cookieManager);
+ cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
+
+ URLConnection con = openConnection();
+ con.getHeaderFields(); // must be read to store the cookie
+
+ try {
+ return cookieManager.getCookieStore().get(source.toURI());
+ } catch (URISyntaxException e) {
+ LOGGER.error("Unable to convert download URL to URI", e);
+ return Collections.emptyList();
+ }
+
+ }
+
private void copy(InputStream in, Writer out, Charset encoding) throws IOException {
InputStream monitoredInputStream = monitorInputStream(in);
Reader r = new InputStreamReader(monitoredInputStream, encoding);
@@ -143,28 +188,42 @@ public class URLDownload {
}
}
+ /**
+ * @deprecated use {@link #downloadToFile(Path)}
+ */
+ @Deprecated
public void downloadToFile(File destination) throws IOException {
+ downloadToFile(destination.toPath());
+ }
- try (InputStream input = new BufferedInputStream(openConnection().getInputStream());
- OutputStream output = new BufferedOutputStream(new FileOutputStream(destination))) {
- copy(input, output);
+ public void downloadToFile(Path destination) throws IOException {
+
+ try (InputStream input = monitorInputStream(new BufferedInputStream(openConnection().getInputStream()))) {
+ Files.copy(input, destination, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
LOGGER.warn("Could not copy input", e);
throw e;
}
}
- private void copy(InputStream in, OutputStream out) throws IOException {
- try (InputStream monitorInputStream = monitorInputStream(in)) {
- byte[] buffer = new byte[512];
- while (true) {
- int bytesRead = monitorInputStream.read(buffer);
- if (bytesRead == -1) {
- break;
- }
- out.write(buffer, 0, bytesRead);
- }
- }
+ /**
+ * Downloads the web resource to a temporary file.
+ *
+ * @return the path to the downloaded file.
+ */
+ public Path downloadToTemporaryFile() throws IOException {
+ // Determine file name and extension from source url
+ String sourcePath = source.getPath();
+
+ // Take everything after the last '/' as name + extension
+ String fileNameWithExtension = sourcePath.substring(sourcePath.lastIndexOf('/') + 1);
+ String fileName = FileUtil.getFileName(fileNameWithExtension);
+ String extension = "." + FileUtil.getFileExtension(fileNameWithExtension).orElse("tmp");
+
+ // Create temporary file and download to it
+ Path file = Files.createTempFile(fileName, extension);
+ downloadToFile(file);
+ return file;
}
protected InputStream monitorInputStream(InputStream in) {
diff --git a/src/main/java/net/sf/jabref/logic/openoffice/OOBibStyle.java b/src/main/java/net/sf/jabref/logic/openoffice/OOBibStyle.java
index 448158d..a05a63b 100644
--- a/src/main/java/net/sf/jabref/logic/openoffice/OOBibStyle.java
+++ b/src/main/java/net/sf/jabref/logic/openoffice/OOBibStyle.java
@@ -26,12 +26,12 @@ import net.sf.jabref.logic.layout.Layout;
import net.sf.jabref.logic.layout.LayoutFormatter;
import net.sf.jabref.logic.layout.LayoutFormatterPreferences;
import net.sf.jabref.logic.layout.LayoutHelper;
-import net.sf.jabref.logic.util.strings.StringUtil;
import net.sf.jabref.model.database.BibDatabase;
import net.sf.jabref.model.entry.Author;
import net.sf.jabref.model.entry.AuthorList;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.FieldName;
+import net.sf.jabref.model.strings.StringUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -717,7 +717,7 @@ public class OOBibStyle implements Comparable<OOBibStyle> {
String authorField = getStringCitProperty(AUTHOR_FIELD);
String[] fields = field.split(FieldName.FIELD_SEPARATOR);
for (String s : fields) {
- Optional<String> content = BibDatabase.getResolvedField(s, entry, database);
+ Optional<String> content = entry.getResolvedFieldOrAlias(s, database);
if ((content.isPresent()) && !content.get().trim().isEmpty()) {
if (field.equals(authorField) && StringUtil.isInCurlyBrackets(content.get())) {
diff --git a/src/main/java/net/sf/jabref/logic/openoffice/OOPreFormatter.java b/src/main/java/net/sf/jabref/logic/openoffice/OOPreFormatter.java
index d694056..75fe970 100644
--- a/src/main/java/net/sf/jabref/logic/openoffice/OOPreFormatter.java
+++ b/src/main/java/net/sf/jabref/logic/openoffice/OOPreFormatter.java
@@ -3,8 +3,8 @@ package net.sf.jabref.logic.openoffice;
import java.util.Map;
import net.sf.jabref.logic.layout.LayoutFormatter;
-import net.sf.jabref.logic.util.strings.HTMLUnicodeConversionMaps;
-import net.sf.jabref.logic.util.strings.StringUtil;
+import net.sf.jabref.model.strings.HTMLUnicodeConversionMaps;
+import net.sf.jabref.model.strings.StringUtil;
/**
* This formatter preprocesses JabRef fields before they are run through the layout of the
diff --git a/src/main/java/net/sf/jabref/logic/openoffice/OOUtil.java b/src/main/java/net/sf/jabref/logic/openoffice/OOUtil.java
index 1804173..faf9dbc 100644
--- a/src/main/java/net/sf/jabref/logic/openoffice/OOUtil.java
+++ b/src/main/java/net/sf/jabref/logic/openoffice/OOUtil.java
@@ -72,7 +72,7 @@ public class OOUtil {
WrappedTargetException, IllegalArgumentException {
// Backup the value of the uniq field, just in case the entry already has it:
- Optional<String> oldUniqVal = entry.getFieldOptional(UNIQUEFIER_FIELD);
+ Optional<String> oldUniqVal = entry.getField(UNIQUEFIER_FIELD);
// Set the uniq field with the supplied uniquefier:
diff --git a/src/main/java/net/sf/jabref/logic/protectedterms/ProtectedTermsPreferences.java b/src/main/java/net/sf/jabref/logic/protectedterms/ProtectedTermsPreferences.java
index e10fecc..fe1c742 100644
--- a/src/main/java/net/sf/jabref/logic/protectedterms/ProtectedTermsPreferences.java
+++ b/src/main/java/net/sf/jabref/logic/protectedterms/ProtectedTermsPreferences.java
@@ -1,10 +1,7 @@
package net.sf.jabref.logic.protectedterms;
-import java.util.ArrayList;
import java.util.List;
-import net.sf.jabref.preferences.JabRefPreferences;
-
public class ProtectedTermsPreferences {
private final List<String> enabledInternalTermLists;
@@ -21,15 +18,6 @@ public class ProtectedTermsPreferences {
this.disabledExternalTermLists = disabledExternalTermLists;
}
- public static ProtectedTermsPreferences fromPreferences(JabRefPreferences jabRefPreferences) {
- return new ProtectedTermsPreferences(
- jabRefPreferences.getStringList(JabRefPreferences.PROTECTED_TERMS_ENABLED_INTERNAL),
- jabRefPreferences.getStringList(JabRefPreferences.PROTECTED_TERMS_ENABLED_EXTERNAL),
- jabRefPreferences.getStringList(JabRefPreferences.PROTECTED_TERMS_DISABLED_INTERNAL),
- jabRefPreferences.getStringList(JabRefPreferences.PROTECTED_TERMS_DISABLED_EXTERNAL));
- }
-
-
public List<String> getEnabledInternalTermLists() {
return enabledInternalTermLists;
}
@@ -46,32 +34,4 @@ public class ProtectedTermsPreferences {
return disabledExternalTermLists;
}
- public static void toPreferences(JabRefPreferences jabRefPreferences, ProtectedTermsLoader loader) {
- List<String> enabledExternalList = new ArrayList<>();
- List<String> disabledExternalList = new ArrayList<>();
- List<String> enabledInternalList = new ArrayList<>();
- List<String> disabledInternalList = new ArrayList<>();
-
- for (ProtectedTermsList list : loader.getProtectedTermsLists()) {
- if (list.isInternalList()) {
- if (list.isEnabled()) {
- enabledInternalList.add(list.getLocation());
- } else {
- disabledInternalList.add(list.getLocation());
- }
- } else {
- if (list.isEnabled()) {
- enabledExternalList.add(list.getLocation());
- } else {
- disabledExternalList.add(list.getLocation());
- }
- }
- }
-
- jabRefPreferences.putStringList(JabRefPreferences.PROTECTED_TERMS_ENABLED_EXTERNAL, enabledExternalList);
- jabRefPreferences.putStringList(JabRefPreferences.PROTECTED_TERMS_DISABLED_EXTERNAL, disabledExternalList);
- jabRefPreferences.putStringList(JabRefPreferences.PROTECTED_TERMS_ENABLED_INTERNAL, enabledInternalList);
- jabRefPreferences.putStringList(JabRefPreferences.PROTECTED_TERMS_DISABLED_INTERNAL, disabledInternalList);
-
- }
}
diff --git a/src/main/java/net/sf/jabref/logic/remote/RemotePreferences.java b/src/main/java/net/sf/jabref/logic/remote/RemotePreferences.java
index 5ad66fa..f68f780 100644
--- a/src/main/java/net/sf/jabref/logic/remote/RemotePreferences.java
+++ b/src/main/java/net/sf/jabref/logic/remote/RemotePreferences.java
@@ -1,33 +1,33 @@
package net.sf.jabref.logic.remote;
-import net.sf.jabref.preferences.JabRefPreferences;
-
/**
* Place for handling the preferences for the remote communication
*/
public class RemotePreferences {
- private final JabRefPreferences preferences;
+ private int port;
+ private boolean useRemoteServer;
- public RemotePreferences(JabRefPreferences preferences) {
- this.preferences = preferences;
+ public RemotePreferences(int port, boolean useRemoteServer) {
+ this.port = port;
+ this.useRemoteServer = useRemoteServer;
}
public int getPort() {
- return preferences.getInt(JabRefPreferences.REMOTE_SERVER_PORT);
+ return port;
}
public void setPort(int port) {
- preferences.putInt(JabRefPreferences.REMOTE_SERVER_PORT, port);
+ this.port = port;
}
public boolean useRemoteServer() {
- return preferences.getBoolean(JabRefPreferences.USE_REMOTE_SERVER);
+ return useRemoteServer;
}
public void setUseRemoteServer(boolean useRemoteServer) {
- preferences.putBoolean(JabRefPreferences.USE_REMOTE_SERVER, useRemoteServer);
+ this.useRemoteServer = useRemoteServer;
}
public boolean isDifferentPort(int otherPort) {
diff --git a/src/main/java/net/sf/jabref/logic/remote/server/RemoteListenerServerLifecycle.java b/src/main/java/net/sf/jabref/logic/remote/server/RemoteListenerServerLifecycle.java
index dac8f84..630d8e5 100644
--- a/src/main/java/net/sf/jabref/logic/remote/server/RemoteListenerServerLifecycle.java
+++ b/src/main/java/net/sf/jabref/logic/remote/server/RemoteListenerServerLifecycle.java
@@ -26,6 +26,7 @@ public class RemoteListenerServerLifecycle implements AutoCloseable {
if (isOpen()) {
remoteListenerServerThread.interrupt();
remoteListenerServerThread = null;
+ JabRefExecutorService.INSTANCE.stopRemoteThread();
}
}
@@ -56,7 +57,7 @@ public class RemoteListenerServerLifecycle implements AutoCloseable {
public void start() {
if (isOpen() && isNotStartedBefore()) {
// threads can only be started when in state NEW
- JabRefExecutorService.INSTANCE.executeInOwnThread(remoteListenerServerThread);
+ JabRefExecutorService.INSTANCE.manageRemoteThread(remoteListenerServerThread);
}
}
diff --git a/src/main/java/net/sf/jabref/logic/search/MatchesHighlighter.java b/src/main/java/net/sf/jabref/logic/search/MatchesHighlighter.java
deleted file mode 100644
index c0ff4a0..0000000
--- a/src/main/java/net/sf/jabref/logic/search/MatchesHighlighter.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package net.sf.jabref.logic.search;
-
-import java.util.Objects;
-import java.util.Optional;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-public class MatchesHighlighter {
-
- // used at highlighting in preview area.
- // Color chosen similar to JTextComponent.getSelectionColor(), which is
- // used at highlighting words at the editor
- public static final String HIGHLIGHT_COLOR = "#3399FF";
-
- /**
- * Will return the text that was called by the method with HTML tags to highlight each word the user has searched
- * for and will skip the highlight process if the first Char isn't a letter or a digit.
- * <p>
- * This check is a quick hack to avoid highlighting of HTML tags It does not always work, but it does its job mostly
- *
- * @param text This is a String in which we search for different words
- * @param wordsToHighlight List of all words which must be highlighted
- * @return String that was called by the method, with HTML Tags if a word was found
- */
- public static String highlightWordsWithHTML(String text, Optional<Pattern> highlightPattern) {
- Objects.requireNonNull(highlightPattern);
- Objects.requireNonNull(text);
-
- if (text.isEmpty() || !highlightPattern.isPresent()) {
- return text;
- }
-
- Matcher matcher = highlightPattern.get().matcher(text);
-
- StringBuffer sb = new StringBuffer();
- boolean foundSomething = false;
-
- while (matcher.find()) {
- String found = matcher.group();
- // color the search keyword
- // put first String Part and then html + word + html to a StringBuffer
- matcher.appendReplacement(sb, "<span style=\"background-color:" + HIGHLIGHT_COLOR + ";\">" + found + "</span>");
- foundSomething = true;
- }
-
- if (foundSomething) {
- matcher.appendTail(sb);
- text = sb.toString();
- }
-
- return text;
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/logic/search/SearchMatcher.java b/src/main/java/net/sf/jabref/logic/search/SearchMatcher.java
deleted file mode 100644
index 41fe6d0..0000000
--- a/src/main/java/net/sf/jabref/logic/search/SearchMatcher.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package net.sf.jabref.logic.search;
-
-import net.sf.jabref.model.entry.BibEntry;
-
- at FunctionalInterface
-public interface SearchMatcher {
-
- boolean isMatch(BibEntry entry);
-
-}
diff --git a/src/main/java/net/sf/jabref/logic/search/SearchQuery.java b/src/main/java/net/sf/jabref/logic/search/SearchQuery.java
index f1b5ef9..7329519 100644
--- a/src/main/java/net/sf/jabref/logic/search/SearchQuery.java
+++ b/src/main/java/net/sf/jabref/logic/search/SearchQuery.java
@@ -1,15 +1,18 @@
package net.sf.jabref.logic.search;
+import java.util.Collections;
+import java.util.List;
import java.util.Objects;
import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.logic.search.rules.ContainBasedSearchRule;
-import net.sf.jabref.logic.search.rules.GrammarBasedSearchRule;
-import net.sf.jabref.logic.search.rules.SearchRule;
-import net.sf.jabref.logic.search.rules.SearchRules;
-import net.sf.jabref.logic.search.rules.describer.SearchDescriber;
import net.sf.jabref.logic.search.rules.describer.SearchDescribers;
import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.search.SearchMatcher;
+import net.sf.jabref.model.search.rules.ContainBasedSearchRule;
+import net.sf.jabref.model.search.rules.GrammarBasedSearchRule;
+import net.sf.jabref.model.search.rules.SearchRule;
+import net.sf.jabref.model.search.rules.SearchRules;
+import net.sf.jabref.model.search.rules.SentenceAnalyzer;
public class SearchQuery implements SearchMatcher {
@@ -23,8 +26,8 @@ public class SearchQuery implements SearchMatcher {
this.query = Objects.requireNonNull(query);
this.caseSensitive = caseSensitive;
this.regularExpression = regularExpression;
- this.rule = Objects.requireNonNull(getSearchRule());
- this.description = Objects.requireNonNull(getSearchDescriber().getDescription());
+ this.rule = SearchRules.getSearchRuleByQuery(query, caseSensitive, regularExpression);
+ this.description = SearchDescribers.getSearchDescriberFor(rule, query).getDescription();
}
@Override
@@ -34,23 +37,15 @@ public class SearchQuery implements SearchMatcher {
@Override
public boolean isMatch(BibEntry entry) {
- return this.getRule().applyRule(getQuery(), entry);
+ return rule.applyRule(getQuery(), entry);
}
public boolean isValid() {
- return this.getRule().validateSearchStrings(getQuery());
+ return rule.validateSearchStrings(getQuery());
}
public boolean isContainsBasedSearch() {
- return this.getRule() instanceof ContainBasedSearchRule;
- }
-
- private SearchRule getSearchRule() {
- return SearchRules.getSearchRuleByQuery(getQuery(), isCaseSensitive(), isRegularExpression());
- }
-
- private SearchDescriber getSearchDescriber() {
- return SearchDescribers.getSearchDescriberFor(getSearchRule(), getQuery());
+ return rule instanceof ContainBasedSearchRule;
}
private String getCaseSensitiveDescription() {
@@ -93,7 +88,7 @@ public class SearchQuery implements SearchMatcher {
}
public boolean isGrammarBasedSearch() {
- return this.getRule() instanceof GrammarBasedSearchRule;
+ return rule instanceof GrammarBasedSearchRule;
}
public String getQuery() {
@@ -112,7 +107,17 @@ public class SearchQuery implements SearchMatcher {
return description;
}
- private SearchRule getRule() {
- return rule;
+ /**
+ * Returns a list of words this query searches for.
+ * The returned strings can be a regular expression.
+ */
+ public List<String> getSearchWords() {
+ if (isRegularExpression()) {
+ return Collections.singletonList(getQuery());
+ } else {
+ // Parses the search query for valid words and returns a list these words.
+ // For example, "The great Vikinger" will give ["The","great","Vikinger"]
+ return (new SentenceAnalyzer(getQuery())).getWords();
+ }
}
}
diff --git a/src/main/java/net/sf/jabref/logic/search/SearchQueryHighlightListener.java b/src/main/java/net/sf/jabref/logic/search/SearchQueryHighlightListener.java
index 2e38e07..961b7ef 100644
--- a/src/main/java/net/sf/jabref/logic/search/SearchQueryHighlightListener.java
+++ b/src/main/java/net/sf/jabref/logic/search/SearchQueryHighlightListener.java
@@ -3,6 +3,8 @@ package net.sf.jabref.logic.search;
import java.util.Optional;
import java.util.regex.Pattern;
+import com.google.common.eventbus.Subscribe;
+
/**
* Every Listener that wants to receive events from a search needs to
* implement this interface
@@ -18,5 +20,6 @@ public interface SearchQueryHighlightListener {
*
* @param words null if nothing is searched for
*/
+ @Subscribe
void highlightPattern(Optional<Pattern> highlightPattern);
}
diff --git a/src/main/java/net/sf/jabref/logic/search/SearchQueryHighlightObservable.java b/src/main/java/net/sf/jabref/logic/search/SearchQueryHighlightObservable.java
index 0deafe7..d7e4144 100644
--- a/src/main/java/net/sf/jabref/logic/search/SearchQueryHighlightObservable.java
+++ b/src/main/java/net/sf/jabref/logic/search/SearchQueryHighlightObservable.java
@@ -1,18 +1,16 @@
package net.sf.jabref.logic.search;
-import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.StringJoiner;
import java.util.regex.Pattern;
-import net.sf.jabref.logic.search.rules.SentenceAnalyzer;
+import com.google.common.eventbus.EventBus;
public class SearchQueryHighlightObservable {
- private final List<SearchQueryHighlightListener> listeners = new ArrayList<>();
+ private final EventBus eventBus = new EventBus();
private Optional<Pattern> pattern = Optional.empty();
@@ -20,47 +18,21 @@ public class SearchQueryHighlightObservable {
* Adds a SearchQueryHighlightListener to the search bar. The added listener is immediately informed about the current search.
* Subscribers will be notified about searches.
*
- * @param l SearchQueryHighlightListener to be added
+ * @param newListener SearchQueryHighlightListener to be added
*/
- public void addSearchListener(SearchQueryHighlightListener l) {
- Objects.requireNonNull(l);
+ public void addSearchListener(SearchQueryHighlightListener newListener) {
+ Objects.requireNonNull(newListener);
- if (listeners.contains(l)) {
- return;
- } else {
- listeners.add(l);
- }
-
- // fire event for the new subscriber
- l.highlightPattern(pattern);
- }
+ eventBus.register(newListener);
+ newListener.highlightPattern(pattern);
- public int getListenerCount() {
- return listeners.size();
}
- /**
- * Remove a SearchQueryHighlightListener
- *
- * @param l SearchQueryHighlightListener to be removed
- */
- public void removeSearchListener(SearchQueryHighlightListener l) {
- Objects.requireNonNull(l);
-
- listeners.remove(l);
- }
+ public void removeSearchListener(SearchQueryHighlightListener listener) {
+ Objects.requireNonNull(listener);
- /**
- * Parses the search query for valid words and returns a list these words. For example, "The great Vikinger" will
- * give ["The","great","Vikinger"]
- *
- * @param searchText the search query
- * @return list of words found in the search query
- */
- private List<String> getSearchwords(String searchText) {
- return (new SentenceAnalyzer(searchText)).getWords();
+ eventBus.unregister(listener);
}
-
/**
* Fires an event if a search was started (or cleared)
*
@@ -70,13 +42,8 @@ public class SearchQueryHighlightObservable {
Objects.requireNonNull(searchQuery);
// Parse the search string to words
- if (searchQuery.isGrammarBasedSearch()) {
- pattern = Optional.empty();
- } else if (searchQuery.isRegularExpression()) {
- pattern = getPatternForWords(Collections.singletonList(searchQuery.getQuery()), true, searchQuery.isCaseSensitive());
- } else {
- pattern = getPatternForWords(getSearchwords(searchQuery.getQuery()), searchQuery.isRegularExpression(), searchQuery.isCaseSensitive());
- }
+ pattern = getPatternForWords(searchQuery.getSearchWords(), searchQuery.isRegularExpression(),
+ searchQuery.isCaseSensitive());
update();
}
@@ -88,9 +55,7 @@ public class SearchQueryHighlightObservable {
private void update() {
// Fire an event for every listener
- for (SearchQueryHighlightListener s : listeners) {
- s.highlightPattern(pattern);
- }
+ eventBus.post(pattern);
}
// Returns a regular expression pattern in the form (w1)|(w2)| ... wi are escaped if no regular expression search is enabled
diff --git a/src/main/java/net/sf/jabref/logic/search/matchers/AndMatcher.java b/src/main/java/net/sf/jabref/logic/search/matchers/AndMatcher.java
deleted file mode 100644
index 48da99c..0000000
--- a/src/main/java/net/sf/jabref/logic/search/matchers/AndMatcher.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package net.sf.jabref.logic.search.matchers;
-
-import net.sf.jabref.logic.search.SearchMatcher;
-import net.sf.jabref.model.entry.BibEntry;
-
-/**
- * Subclass of MatcherSet that ANDs or ORs between its rules, returning 0 or
- * 1.
- */
-public class AndMatcher extends MatcherSet {
-
- @Override
- public boolean isMatch(BibEntry bibEntry) {
- int score = 0;
-
- // We let each rule add a maximum of 1 to the score.
- for (SearchMatcher rule : matchers) {
- if(rule.isMatch(bibEntry)) {
- score++;
- }
- }
-
- // Then an AND rule demands that score == number of rules
- return score == matchers.size();
- }
-}
diff --git a/src/main/java/net/sf/jabref/logic/search/matchers/MatcherSet.java b/src/main/java/net/sf/jabref/logic/search/matchers/MatcherSet.java
deleted file mode 100644
index 8b3737e..0000000
--- a/src/main/java/net/sf/jabref/logic/search/matchers/MatcherSet.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package net.sf.jabref.logic.search.matchers;
-
-import java.util.List;
-import java.util.Objects;
-import java.util.Vector;
-
-import net.sf.jabref.logic.search.SearchMatcher;
-
-public abstract class MatcherSet implements SearchMatcher {
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
-
- MatcherSet that = (MatcherSet) o;
-
- return matchers.equals(that.matchers);
-
- }
-
- @Override
- public int hashCode() {
- return matchers.hashCode();
- }
-
- protected final List<SearchMatcher> matchers = new Vector<>();
-
- public void addRule(SearchMatcher newRule) {
- matchers.add(Objects.requireNonNull(newRule));
- }
-
- @Override
- public String toString() {
- final StringBuilder sb = new StringBuilder("MatcherSet{");
- sb.append("matchers=").append(matchers);
- sb.append('}');
- return sb.toString();
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/logic/search/matchers/MatcherSets.java b/src/main/java/net/sf/jabref/logic/search/matchers/MatcherSets.java
deleted file mode 100644
index cc23a9e..0000000
--- a/src/main/java/net/sf/jabref/logic/search/matchers/MatcherSets.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package net.sf.jabref.logic.search.matchers;
-
-
-public class MatcherSets {
-
- public enum MatcherType {
- AND,
- OR
- }
-
- public static MatcherSet build(MatcherType ruleSet) {
- if (ruleSet == MatcherType.AND) {
- return new AndMatcher();
- } else {
- return new OrMatcher();
- }
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/logic/search/matchers/NotMatcher.java b/src/main/java/net/sf/jabref/logic/search/matchers/NotMatcher.java
deleted file mode 100644
index 9b9d4ac..0000000
--- a/src/main/java/net/sf/jabref/logic/search/matchers/NotMatcher.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package net.sf.jabref.logic.search.matchers;
-
-import java.util.Objects;
-
-import net.sf.jabref.logic.search.SearchMatcher;
-import net.sf.jabref.model.entry.BibEntry;
-
-/**
- * Inverts the search result.
- * <p>
- * Example:
- * false --> true
- * true --> false
- */
-public class NotMatcher implements SearchMatcher {
-
- private final SearchMatcher otherMatcher;
-
- public NotMatcher(SearchMatcher otherMatcher) {
- this.otherMatcher = Objects.requireNonNull(otherMatcher);
- }
-
- @Override
- public boolean isMatch(BibEntry entry) {
- return !otherMatcher.isMatch(entry);
- }
-}
diff --git a/src/main/java/net/sf/jabref/logic/search/matchers/OrMatcher.java b/src/main/java/net/sf/jabref/logic/search/matchers/OrMatcher.java
deleted file mode 100644
index 27454b9..0000000
--- a/src/main/java/net/sf/jabref/logic/search/matchers/OrMatcher.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package net.sf.jabref.logic.search.matchers;
-
-import net.sf.jabref.logic.search.SearchMatcher;
-import net.sf.jabref.model.entry.BibEntry;
-
-/**
- * Subclass of MatcherSet that ANDs or ORs between its rules, returning 0 or
- * 1.
- */
-public class OrMatcher extends MatcherSet {
-
- @Override
- public boolean isMatch(BibEntry bibEntry) {
- int score = 0;
-
- // We let each rule add a maximum of 1 to the score.
- for (SearchMatcher rule : matchers) {
- if(rule.isMatch(bibEntry)) {
- score++;
- }
- }
-
- // OR rule demands score > 0.
- return score > 0;
- }
-}
diff --git a/src/main/java/net/sf/jabref/logic/search/rules/ContainBasedSearchRule.java b/src/main/java/net/sf/jabref/logic/search/rules/ContainBasedSearchRule.java
deleted file mode 100644
index e35b7b3..0000000
--- a/src/main/java/net/sf/jabref/logic/search/rules/ContainBasedSearchRule.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package net.sf.jabref.logic.search.rules;
-
-import java.util.Iterator;
-import java.util.List;
-
-import net.sf.jabref.logic.layout.format.RemoveLatexCommands;
-import net.sf.jabref.model.entry.BibEntry;
-
-/**
- * Search rule for contain-based search.
- */
-public class ContainBasedSearchRule implements SearchRule {
-
- private static final RemoveLatexCommands REMOVE_LATEX_COMMANDS = new RemoveLatexCommands();
-
- private final boolean caseSensitive;
-
- public ContainBasedSearchRule(boolean caseSensitive) {
- this.caseSensitive = caseSensitive;
- }
-
- public boolean isCaseSensitive() {
- return caseSensitive;
- }
-
- @Override
- public boolean validateSearchStrings(String query) {
- return true;
- }
-
- @Override
- public boolean applyRule(String query, BibEntry bibEntry) {
-
- String searchString = query;
- if (!caseSensitive) {
- searchString = searchString.toLowerCase();
- }
-
- List<String> unmatchedWords = new SentenceAnalyzer(searchString).getWords();
-
- for (String fieldContent : bibEntry.getFieldValues()) {
- String formattedFieldContent = ContainBasedSearchRule.REMOVE_LATEX_COMMANDS.format(fieldContent);
- if (!caseSensitive) {
- formattedFieldContent = formattedFieldContent.toLowerCase();
- }
-
- Iterator<String> unmatchedWordsIterator = unmatchedWords.iterator();
- while (unmatchedWordsIterator.hasNext()) {
- String word = unmatchedWordsIterator.next();
- if(formattedFieldContent.contains(word)) {
- unmatchedWordsIterator.remove();
- }
- }
-
- if(unmatchedWords.isEmpty()) {
- return true;
- }
- }
-
- return false; // Didn't match all words.
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/logic/search/rules/GrammarBasedSearchRule.java b/src/main/java/net/sf/jabref/logic/search/rules/GrammarBasedSearchRule.java
deleted file mode 100644
index 6e049c8..0000000
--- a/src/main/java/net/sf/jabref/logic/search/rules/GrammarBasedSearchRule.java
+++ /dev/null
@@ -1,243 +0,0 @@
-package net.sf.jabref.logic.search.rules;
-
-import java.util.List;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Set;
-import java.util.function.Predicate;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-
-import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.search.SearchBaseVisitor;
-import net.sf.jabref.search.SearchLexer;
-import net.sf.jabref.search.SearchParser;
-
-import org.antlr.v4.runtime.ANTLRInputStream;
-import org.antlr.v4.runtime.BailErrorStrategy;
-import org.antlr.v4.runtime.BaseErrorListener;
-import org.antlr.v4.runtime.CommonTokenStream;
-import org.antlr.v4.runtime.RecognitionException;
-import org.antlr.v4.runtime.Recognizer;
-import org.antlr.v4.runtime.misc.ParseCancellationException;
-import org.antlr.v4.runtime.tree.ParseTree;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * The search query must be specified in an expression that is acceptable by the Search.g4 grammar.
- */
-public class GrammarBasedSearchRule implements SearchRule {
-
- private static final Log LOGGER = LogFactory.getLog(GrammarBasedSearchRule.class);
-
- private final boolean caseSensitiveSearch;
- private final boolean regExpSearch;
-
- private ParseTree tree;
- private String query;
-
-
- public static class ThrowingErrorListener extends BaseErrorListener {
-
- public static final ThrowingErrorListener INSTANCE = new ThrowingErrorListener();
-
- @Override
- public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol,
- int line, int charPositionInLine, String msg, RecognitionException e)
- throws ParseCancellationException {
- throw new ParseCancellationException("line " + line + ":" + charPositionInLine + " " + msg);
- }
- }
-
- public GrammarBasedSearchRule(boolean caseSensitiveSearch, boolean regExpSearch) throws RecognitionException {
- this.caseSensitiveSearch = caseSensitiveSearch;
- this.regExpSearch = regExpSearch;
- }
-
- public static boolean isValid(boolean caseSensitive, boolean regExp, String query) {
- return new GrammarBasedSearchRule(caseSensitive, regExp).validateSearchStrings(query);
- }
-
- public boolean isCaseSensitiveSearch() {
- return this.caseSensitiveSearch;
- }
-
- public boolean isRegExpSearch() {
- return this.regExpSearch;
- }
-
- public ParseTree getTree() {
- return this.tree;
- }
-
- public String getQuery() {
- return this.query;
- }
-
- private void init(String query) throws ParseCancellationException {
- if (Objects.equals(this.query, query)) {
- return;
- }
-
- SearchLexer lexer = new SearchLexer(new ANTLRInputStream(query));
- lexer.removeErrorListeners(); // no infos on file system
- lexer.addErrorListener(ThrowingErrorListener.INSTANCE);
- SearchParser parser = new SearchParser(new CommonTokenStream(lexer));
- parser.removeErrorListeners(); // no infos on file system
- parser.addErrorListener(ThrowingErrorListener.INSTANCE);
- parser.setErrorHandler(new BailErrorStrategy()); // ParseCancelationException on parse errors
- tree = parser.start();
- this.query = query;
- }
-
- @Override
- public boolean applyRule(String query, BibEntry bibEntry) {
- try {
- return new BibtexSearchVisitor(caseSensitiveSearch, regExpSearch, bibEntry).visit(tree);
- } catch (Exception e) {
- LOGGER.debug("Search failed", e);
- return false;
- }
- }
-
- @Override
- public boolean validateSearchStrings(String query) {
- try {
- init(query);
- return true;
- } catch (ParseCancellationException e) {
- return false;
- }
- }
-
- public enum ComparisonOperator {
- EXACT, CONTAINS, DOES_NOT_CONTAIN;
-
- public static ComparisonOperator build(String value) {
- if ("CONTAINS".equalsIgnoreCase(value) || "=".equals(value)) {
- return CONTAINS;
- } else if ("MATCHES".equalsIgnoreCase(value) || "==".equals(value)) {
- return EXACT;
- } else {
- return DOES_NOT_CONTAIN;
- }
- }
- }
-
- public static class Comparator {
-
- private final ComparisonOperator operator;
- private final Pattern fieldPattern;
- private final Pattern valuePattern;
-
- public Comparator(String field, String value, ComparisonOperator operator, boolean caseSensitive, boolean regex) {
- this.operator = operator;
-
- int option = caseSensitive ? 0 : Pattern.CASE_INSENSITIVE;
- this.fieldPattern = Pattern.compile(regex ? field : "\\Q" + field + "\\E", option);
- this.valuePattern = Pattern.compile(regex ? value : "\\Q" + value + "\\E", option);
- }
-
- public boolean compare(BibEntry entry) {
- // special case for searching for entrytype=phdthesis
- if (fieldPattern.matcher("entrytype").matches()) {
- return matchFieldValue(entry.getType());
- }
-
- // specification of fieldsKeys to search is done in the search expression itself
- Set<String> fieldsKeys = entry.getFieldNames();
-
- List<String> matchedFieldKeys = fieldsKeys.stream().filter(matchFieldKey()).collect(Collectors.toList());
-
- for (String field : matchedFieldKeys) {
- Optional<String> fieldValue = entry.getFieldOptional(field);
- if (fieldValue.isPresent()) {
- if (matchFieldValue(fieldValue.get())) {
- return true;
- }
- }
- }
-
- // special case of asdf!=whatever and entry does not contain asdf
- return matchedFieldKeys.isEmpty() && (operator == ComparisonOperator.DOES_NOT_CONTAIN);
- }
-
- private Predicate<String> matchFieldKey() {
- return s -> fieldPattern.matcher(s).matches();
- }
-
- public boolean matchFieldValue(String content) {
- Matcher matcher = valuePattern.matcher(content);
- if (operator == ComparisonOperator.CONTAINS) {
- return matcher.find();
- } else if (operator == ComparisonOperator.EXACT) {
- return matcher.matches();
- } else if (operator == ComparisonOperator.DOES_NOT_CONTAIN) {
- return !matcher.find();
- } else {
- throw new IllegalStateException("MUST NOT HAPPEN");
- }
- }
-
- }
-
- /**
- * Search results in boolean. It may be later on converted to an int.
- */
- static class BibtexSearchVisitor extends SearchBaseVisitor<Boolean> {
-
- private final boolean caseSensitive;
- private final boolean regex;
-
- private final BibEntry entry;
-
- public BibtexSearchVisitor(boolean caseSensitive, boolean regex, BibEntry bibEntry) {
- this.caseSensitive = caseSensitive;
- this.regex = regex;
- this.entry = bibEntry;
- }
-
- public boolean comparison(String field, ComparisonOperator operator, String value) {
- return new Comparator(field, value, operator, caseSensitive, regex).compare(entry);
- }
-
- @Override
- public Boolean visitStart(SearchParser.StartContext ctx) {
- return visit(ctx.expression());
- }
-
- @Override
- public Boolean visitComparison(SearchParser.ComparisonContext ctx) {
- // remove possible enclosing " symbols
- String right = ctx.right.getText();
- if(right.startsWith("\"") && right.endsWith("\"")) {
- right = right.substring(1, right.length() - 1);
- }
-
- return comparison(ctx.left.getText(), ComparisonOperator.build(ctx.operator.getText()), right);
-
- }
-
- @Override
- public Boolean visitUnaryExpression(SearchParser.UnaryExpressionContext ctx) {
- return !visit(ctx.expression()); // negate
- }
-
- @Override
- public Boolean visitParenExpression(SearchParser.ParenExpressionContext ctx) {
- return visit(ctx.expression()); // ignore parenthesis
- }
-
- @Override
- public Boolean visitBinaryExpression(SearchParser.BinaryExpressionContext ctx) {
- if ("AND".equalsIgnoreCase(ctx.operator.getText())) {
- return visit(ctx.left) && visit(ctx.right); // and
- } else {
- return visit(ctx.left) || visit(ctx.right); // or
- }
- }
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/logic/search/rules/RegexBasedSearchRule.java b/src/main/java/net/sf/jabref/logic/search/rules/RegexBasedSearchRule.java
deleted file mode 100644
index 9cecfce..0000000
--- a/src/main/java/net/sf/jabref/logic/search/rules/RegexBasedSearchRule.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package net.sf.jabref.logic.search.rules;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.regex.PatternSyntaxException;
-
-import net.sf.jabref.logic.layout.format.RemoveLatexCommands;
-import net.sf.jabref.model.entry.BibEntry;
-
-/**
- * Search rule for regex-based search.
- */
-public class RegexBasedSearchRule implements SearchRule {
-
- private static final RemoveLatexCommands REMOVE_LATEX_COMMANDS = new RemoveLatexCommands();
-
- private final boolean caseSensitive;
-
- public RegexBasedSearchRule(boolean caseSensitive) {
- this.caseSensitive = caseSensitive;
- }
-
- public boolean isCaseSensitive() {
- return caseSensitive;
- }
-
- @Override
- public boolean validateSearchStrings(String query) {
- String searchString = query;
- if (!caseSensitive) {
- searchString = searchString.toLowerCase();
- }
-
- try {
- Pattern.compile(searchString, caseSensitive ? 0 : Pattern.CASE_INSENSITIVE);
- } catch (PatternSyntaxException ex) {
- return false;
- }
- return true;
- }
-
- @Override
- public boolean applyRule(String query, BibEntry bibEntry) {
- Pattern pattern;
-
- try {
- pattern = Pattern.compile(query, caseSensitive ? 0 : Pattern.CASE_INSENSITIVE);
- } catch (PatternSyntaxException ex) {
- return false;
- }
-
- for (String field : bibEntry.getFieldNames()) {
- if (bibEntry.hasField(field)) {
- String fieldContent = RegexBasedSearchRule.REMOVE_LATEX_COMMANDS
- .format(bibEntry.getFieldOptional(field).get());
- String fieldContentNoBrackets = RegexBasedSearchRule.REMOVE_LATEX_COMMANDS.format(fieldContent);
- Matcher m = pattern.matcher(fieldContentNoBrackets);
- if (m.find()) {
- return true;
- }
- }
-
- }
- return false;
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/logic/search/rules/SearchRule.java b/src/main/java/net/sf/jabref/logic/search/rules/SearchRule.java
deleted file mode 100644
index d015a59..0000000
--- a/src/main/java/net/sf/jabref/logic/search/rules/SearchRule.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package net.sf.jabref.logic.search.rules;
-
-import net.sf.jabref.model.entry.BibEntry;
-
-public interface SearchRule {
-
- boolean applyRule(String query, BibEntry bibEntry);
-
- boolean validateSearchStrings(String query);
-}
diff --git a/src/main/java/net/sf/jabref/logic/search/rules/SearchRules.java b/src/main/java/net/sf/jabref/logic/search/rules/SearchRules.java
deleted file mode 100644
index c3182de..0000000
--- a/src/main/java/net/sf/jabref/logic/search/rules/SearchRules.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package net.sf.jabref.logic.search.rules;
-
-public class SearchRules {
-
- /**
- * Returns the appropriate search rule that fits best to the given parameter.
- */
- public static SearchRule getSearchRuleByQuery(String query, boolean caseSensitive, boolean regex) {
- // this searches specified fields if specified,
- // and all fields otherwise
- SearchRule searchExpression = new GrammarBasedSearchRule(caseSensitive, regex);
- if (searchExpression.validateSearchStrings(query)) {
- return searchExpression;
- } else {
- return getSearchRule(caseSensitive, regex);
- }
- }
-
- private static SearchRule getSearchRule(boolean caseSensitive, boolean regex) {
- if (regex) {
- return new RegexBasedSearchRule(caseSensitive);
- } else {
- return new ContainBasedSearchRule(caseSensitive);
- }
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/logic/search/rules/SentenceAnalyzer.java b/src/main/java/net/sf/jabref/logic/search/rules/SentenceAnalyzer.java
deleted file mode 100644
index 63dafb5..0000000
--- a/src/main/java/net/sf/jabref/logic/search/rules/SentenceAnalyzer.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package net.sf.jabref.logic.search.rules;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class SentenceAnalyzer {
-
- public static final char ESCAPE_CHAR = '\\';
- public static final char QUOTE_CHAR = '"';
-
- private final String query;
-
- public SentenceAnalyzer(String query) {
- this.query = query;
- }
-
- public List<String> getWords() {
- List<String> result = new ArrayList<>();
-
- StringBuilder stringBuilder = new StringBuilder();
- boolean escaped = false;
- boolean quoted = false;
- for(char c : query.toCharArray()) {
- // Check if we are entering an escape sequence:
- if (!escaped && c == ESCAPE_CHAR) {
- escaped = true;
- } else {
- // See if we have reached the end of a word:
- if (!escaped && !quoted && Character.isWhitespace(c)) {
- if (stringBuilder.length() > 0) {
- result.add(stringBuilder.toString());
- stringBuilder = new StringBuilder();
- }
- } else if (c == QUOTE_CHAR) {
- // Whether it is a start or end quote, store the current
- // word if any:
- if (stringBuilder.length() > 0) {
- result.add(stringBuilder.toString());
- stringBuilder = new StringBuilder();
- }
- quoted = !quoted;
- } else {
- // All other possibilities exhausted, we add the char to
- // the current word:
- stringBuilder.append(c);
- }
- escaped = false;
- }
- }
- // Finished with the loop. If we have a current word, add it:
- if (stringBuilder.length() > 0) {
- result.add(stringBuilder.toString());
- }
-
- return result;
- }
-}
diff --git a/src/main/java/net/sf/jabref/logic/search/rules/describer/ContainsAndRegexBasedSearchRuleDescriber.java b/src/main/java/net/sf/jabref/logic/search/rules/describer/ContainsAndRegexBasedSearchRuleDescriber.java
index a9fb11b..97325fa 100644
--- a/src/main/java/net/sf/jabref/logic/search/rules/describer/ContainsAndRegexBasedSearchRuleDescriber.java
+++ b/src/main/java/net/sf/jabref/logic/search/rules/describer/ContainsAndRegexBasedSearchRuleDescriber.java
@@ -4,8 +4,8 @@ import java.util.LinkedList;
import java.util.List;
import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.logic.search.rules.SentenceAnalyzer;
-import net.sf.jabref.logic.util.strings.StringUtil;
+import net.sf.jabref.model.search.rules.SentenceAnalyzer;
+import net.sf.jabref.model.strings.StringUtil;
public class ContainsAndRegexBasedSearchRuleDescriber implements SearchDescriber {
diff --git a/src/main/java/net/sf/jabref/logic/search/rules/describer/GrammarBasedSearchRuleDescriber.java b/src/main/java/net/sf/jabref/logic/search/rules/describer/GrammarBasedSearchRuleDescriber.java
index 26f77dc..58e055a 100644
--- a/src/main/java/net/sf/jabref/logic/search/rules/describer/GrammarBasedSearchRuleDescriber.java
+++ b/src/main/java/net/sf/jabref/logic/search/rules/describer/GrammarBasedSearchRuleDescriber.java
@@ -1,11 +1,12 @@
package net.sf.jabref.logic.search.rules.describer;
import java.util.Objects;
+import java.util.Optional;
import java.util.regex.Pattern;
import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.logic.search.rules.GrammarBasedSearchRule;
-import net.sf.jabref.logic.util.strings.StringUtil;
+import net.sf.jabref.model.search.rules.GrammarBasedSearchRule;
+import net.sf.jabref.model.strings.StringUtil;
import net.sf.jabref.search.SearchBaseVisitor;
import net.sf.jabref.search.SearchParser;
@@ -57,8 +58,13 @@ public class GrammarBasedSearchRuleDescriber implements SearchDescriber {
@Override
public String visitComparison(SearchParser.ComparisonContext context) {
- final String field = StringUtil.unquote(context.left.getText(), '"');
+ final Optional<SearchParser.NameContext> fieldDescriptor = Optional.ofNullable(context.left);
final String value = StringUtil.unquote(context.right.getText(), '"');
+ if (!fieldDescriptor.isPresent()) {
+ return new ContainsAndRegexBasedSearchRuleDescriber(caseSensitive, regExp, value).getDescription();
+ }
+
+ final String field = StringUtil.unquote(fieldDescriptor.get().getText(), '"');
final GrammarBasedSearchRule.ComparisonOperator operator = GrammarBasedSearchRule.ComparisonOperator.build(context.operator.getText());
final boolean regExpFieldSpec = !Pattern.matches("\\w+", field);
diff --git a/src/main/java/net/sf/jabref/logic/search/rules/describer/SearchDescribers.java b/src/main/java/net/sf/jabref/logic/search/rules/describer/SearchDescribers.java
index 66badad..4f71c39 100644
--- a/src/main/java/net/sf/jabref/logic/search/rules/describer/SearchDescribers.java
+++ b/src/main/java/net/sf/jabref/logic/search/rules/describer/SearchDescribers.java
@@ -1,9 +1,9 @@
package net.sf.jabref.logic.search.rules.describer;
-import net.sf.jabref.logic.search.rules.ContainBasedSearchRule;
-import net.sf.jabref.logic.search.rules.GrammarBasedSearchRule;
-import net.sf.jabref.logic.search.rules.RegexBasedSearchRule;
-import net.sf.jabref.logic.search.rules.SearchRule;
+import net.sf.jabref.model.search.rules.ContainBasedSearchRule;
+import net.sf.jabref.model.search.rules.GrammarBasedSearchRule;
+import net.sf.jabref.model.search.rules.RegexBasedSearchRule;
+import net.sf.jabref.model.search.rules.SearchRule;
public class SearchDescribers {
diff --git a/src/main/java/net/sf/jabref/logic/specialfields/SpecialFieldsUtils.java b/src/main/java/net/sf/jabref/logic/specialfields/SpecialFieldsUtils.java
new file mode 100644
index 0000000..c951037
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/specialfields/SpecialFieldsUtils.java
@@ -0,0 +1,125 @@
+package net.sf.jabref.logic.specialfields;
+
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+import net.sf.jabref.logic.util.UpdateField;
+import net.sf.jabref.model.FieldChange;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldName;
+import net.sf.jabref.model.entry.Keyword;
+import net.sf.jabref.model.entry.KeywordList;
+import net.sf.jabref.model.entry.specialfields.SpecialField;
+
+/**
+ * @deprecated the class should be refactored and partly integrated into BibEntry
+ * instead of synchronizing special fields with the keyword field, the BibEntry class should have a method
+ * setSpecialField(field, newValue, syncToKeyword) which directly performs the correct action
+ * i.e.sets the field to newValue(in the case syncToKeyword=false)or adds newValue to keywords(sync=true)
+ */
+
+ at Deprecated
+public class SpecialFieldsUtils {
+
+ /**
+ * @param field - Field to be handled
+ * @param value - may be null to state that field should be emptied
+ * @param entry - BibTeXEntry to be handled
+ * @param nullFieldIfValueIsTheSame - true: field is nulled if value is the same than the current value in be
+ */
+ public static List<FieldChange> updateField(SpecialField field, String value, BibEntry entry, boolean nullFieldIfValueIsTheSame, boolean isKeywordSyncEnabled, Character keywordDelimiter) {
+ List<FieldChange> fieldChanges = new ArrayList<>();
+
+ UpdateField.updateField(entry, field.getFieldName(), value, nullFieldIfValueIsTheSame)
+ .ifPresent(fieldChange -> fieldChanges.add(fieldChange));
+ // we cannot use "value" here as updateField has side effects: "nullFieldIfValueIsTheSame" nulls the field if value is the same
+ fieldChanges.addAll(SpecialFieldsUtils.exportFieldToKeywords(field, entry, isKeywordSyncEnabled, keywordDelimiter));
+
+ return fieldChanges;
+ }
+
+ private static List<FieldChange> exportFieldToKeywords(SpecialField specialField, BibEntry entry, boolean isKeywordSyncEnabled, Character keywordDelimiter) {
+ List<FieldChange> fieldChanges = new ArrayList<>();
+
+ if (!isKeywordSyncEnabled) {
+ return fieldChanges;
+ }
+
+ Optional<Keyword> newValue = entry.getField(specialField.getFieldName()).map(Keyword::new);
+ KeywordList keyWords = specialField.getKeyWords();
+
+ Optional<FieldChange> change = entry.replaceKeywords(keyWords, newValue, keywordDelimiter);
+ change.ifPresent(changeValue -> fieldChanges.add(changeValue));
+
+ return fieldChanges;
+ }
+
+ /**
+ * Update keywords according to values of special fields
+ */
+ public static List<FieldChange> syncKeywordsFromSpecialFields(BibEntry entry, boolean isKeywordSyncEnabled, Character keywordDelimiter) {
+ List<FieldChange> fieldChanges = new ArrayList<>();
+
+ for(SpecialField field: SpecialField.values()) {
+ fieldChanges.addAll(SpecialFieldsUtils.exportFieldToKeywords(field, entry, isKeywordSyncEnabled, keywordDelimiter));
+ }
+
+ return fieldChanges;
+ }
+
+ private static List<FieldChange> importKeywordsForField(KeywordList keywordList, SpecialField field, BibEntry entry) {
+ List<FieldChange> fieldChanges = new ArrayList<>();
+ KeywordList values = field.getKeyWords();
+ Optional<Keyword> newValue = Optional.empty();
+ for (Keyword keyword : values) {
+ if (keywordList.contains(keyword)) {
+ newValue = Optional.of(keyword);
+ break;
+ }
+ }
+
+ UpdateField.updateNonDisplayableField(entry, field.getFieldName(), newValue.map(Keyword::toString).orElse(null))
+ .ifPresent(fieldChange -> {
+ fieldChanges.add(fieldChange);
+ });
+ return fieldChanges;
+ }
+
+ /**
+ * updates field values according to keywords
+ */
+ public static List<FieldChange> syncSpecialFieldsFromKeywords(BibEntry entry, Character keywordDelimiter) {
+ List<FieldChange> fieldChanges = new ArrayList<>();
+ if (!entry.hasField(FieldName.KEYWORDS)) {
+ return fieldChanges;
+ }
+
+ KeywordList keywordList = entry.getKeywords(keywordDelimiter);
+
+ for(SpecialField field: SpecialField.values()) {
+ fieldChanges.addAll(SpecialFieldsUtils.importKeywordsForField(keywordList, field, entry));
+ }
+
+ return fieldChanges;
+ }
+
+ public static void synchronizeSpecialFields(KeywordList keywordsToAdd, KeywordList keywordsToRemove) {
+ // we need to check whether a special field is added
+ // for each field:
+ // check if something is added
+ // if yes, add all keywords of that special fields to the keywords to be removed
+
+ KeywordList clone;
+
+ // Priority
+ clone = keywordsToAdd.createClone();
+ for(SpecialField field: SpecialField.values()){
+ clone.retainAll(field.getKeyWords());
+ if(!clone.isEmpty()) {
+ keywordsToRemove.addAll(field.getKeyWords());
+ }
+ }
+ }
+}
diff --git a/src/main/java/net/sf/jabref/logic/util/BuildInfo.java b/src/main/java/net/sf/jabref/logic/util/BuildInfo.java
index 6a29d83..876a8c2 100644
--- a/src/main/java/net/sf/jabref/logic/util/BuildInfo.java
+++ b/src/main/java/net/sf/jabref/logic/util/BuildInfo.java
@@ -2,6 +2,8 @@ package net.sf.jabref.logic.util;
import java.io.IOException;
import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
import java.util.Properties;
public class BuildInfo {
@@ -18,6 +20,7 @@ public class BuildInfo {
private final String developers;
private final String year;
+
public BuildInfo() {
this("/build.properties");
}
@@ -25,15 +28,17 @@ public class BuildInfo {
public BuildInfo(String path) {
Properties properties = new Properties();
- try (InputStream stream = getClass().getResourceAsStream(path)) {
- if(stream != null) {
- properties.load(stream);
+ try (InputStream stream = BuildInfo.class.getResourceAsStream(path)) {
+ if (stream != null) {
+ try (InputStreamReader reader = new InputStreamReader(stream, StandardCharsets.UTF_8)) {
+ properties.load(reader);
+ }
}
} catch (IOException ignored) {
// nothing to do -> default already set
}
- version = new Version(properties.getProperty("version", UNKNOWN_VERSION));
+ version = Version.parse(properties.getProperty("version"));
authors = properties.getProperty("authors", "");
year = properties.getProperty("year", "");
developers = properties.getProperty("developers", "");
diff --git a/src/main/java/net/sf/jabref/logic/util/DOI.java b/src/main/java/net/sf/jabref/logic/util/DOI.java
index 9903939..bc74e4a 100644
--- a/src/main/java/net/sf/jabref/logic/util/DOI.java
+++ b/src/main/java/net/sf/jabref/logic/util/DOI.java
@@ -107,6 +107,16 @@ public class DOI {
}
/**
+ * Determines whether a DOI is valid or not
+ *
+ * @param doi the DOI string
+ * @return true if DOI is valid, false otherwise
+ */
+ public static boolean isValid(String doi ){
+ return build(doi).isPresent();
+ }
+
+ /**
* Tries to find a DOI inside the given text.
*
* @param text the Text which might contain a DOI
diff --git a/src/main/java/net/sf/jabref/logic/util/FileExtensions.java b/src/main/java/net/sf/jabref/logic/util/FileExtensions.java
index 7b9c19a..5f746dd 100644
--- a/src/main/java/net/sf/jabref/logic/util/FileExtensions.java
+++ b/src/main/java/net/sf/jabref/logic/util/FileExtensions.java
@@ -15,12 +15,14 @@ public enum FileExtensions {
BIBTEXML(Localization.lang("%0 file", "BibTeXML"), "bibx", "xml"),
BILBIOSCAPE(Localization.lang("%0 file", "Biblioscape"), "txt"),
COPAC(Localization.lang("%0 file", "Copac"), "txt"),
+ CITATION_STYLE(Localization.lang("%0 file", "CSL"), "csl"),
ENDNOTE(Localization.lang("%0 file", "Endnote/Refer"), "ref", "enw"),
FREECITE(Localization.lang("%0 file", "FreeCite"), "txt", "xml"),
INSPEC(Localization.lang("%0 file", "INSPEC"), "txt"),
ISI(Localization.lang("%0 file", "ISI"), "isi", "txt"),
MEDLINE(Localization.lang("%0 file", "Medline"), "nbib", "xml"),
MEDLINE_PLAIN(Localization.lang("%0 file", "MedlinePlain"), "nbib", "txt"),
+ MODS(Localization.lang("%0 file", "MODS"), "xml"),
MSBIB(Localization.lang("%0 file", "MSBib"), "xml"),
OVID(Localization.lang("%0 file", "Ovid"), "txt"),
PDF_CONTENT(Localization.lang("%0 file", "PDF content "), "pdf"),
diff --git a/src/main/java/net/sf/jabref/logic/util/ISBN.java b/src/main/java/net/sf/jabref/logic/util/ISBN.java
index 6068824..b9b632f 100644
--- a/src/main/java/net/sf/jabref/logic/util/ISBN.java
+++ b/src/main/java/net/sf/jabref/logic/util/ISBN.java
@@ -73,4 +73,7 @@ public class ISBN {
return (sum % 10) == 0;
}
+ public boolean isValid() {
+ return isValidFormat() && isValidChecksum();
+ }
}
diff --git a/src/main/java/net/sf/jabref/logic/util/OptionalUtil.java b/src/main/java/net/sf/jabref/logic/util/OptionalUtil.java
new file mode 100644
index 0000000..826ac86
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/util/OptionalUtil.java
@@ -0,0 +1,23 @@
+package net.sf.jabref.logic.util;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+public class OptionalUtil {
+
+ public static <T> List<T> toList(Optional<T> value) {
+ if (value.isPresent()) {
+ return Collections.singletonList(value.get());
+ } else {
+ return Collections.emptyList();
+ }
+ }
+
+ @SafeVarargs
+ public static <T> List<T> toList(Optional<T>... values) {
+ return Stream.of(values).flatMap(optional -> toList(optional).stream()).collect(Collectors.toList());
+ }
+}
diff --git a/src/main/java/net/sf/jabref/logic/util/UpdateField.java b/src/main/java/net/sf/jabref/logic/util/UpdateField.java
index 1c0a977..4548aa6 100644
--- a/src/main/java/net/sf/jabref/logic/util/UpdateField.java
+++ b/src/main/java/net/sf/jabref/logic/util/UpdateField.java
@@ -48,7 +48,7 @@ public class UpdateField {
String writtenValue = null;
String oldValue = null;
if (be.hasField(field)) {
- oldValue = be.getFieldOptional(field).get();
+ oldValue = be.getField(field).get();
if ((newValue == null) || (oldValue.equals(newValue) && nullFieldIfValueIsTheSame)) {
// If the new field value is null or the old and the new value are the same and flag is set
// Clear the field
diff --git a/src/main/java/net/sf/jabref/logic/util/Version.java b/src/main/java/net/sf/jabref/logic/util/Version.java
index 4e13af7..4fcb41b 100644
--- a/src/main/java/net/sf/jabref/logic/util/Version.java
+++ b/src/main/java/net/sf/jabref/logic/util/Version.java
@@ -5,11 +5,16 @@ import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Objects;
+import java.util.Optional;
+import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.json.JSONArray;
import org.json.JSONObject;
/**
@@ -17,51 +22,88 @@ import org.json.JSONObject;
*/
public class Version {
- public static final String JABREF_DOWNLOAD_URL = "http://www.fosshub.com/JabRef.html";
private static final Log LOGGER = LogFactory.getLog(Version.class);
- private static final String JABREF_GITHUB_URL = "https://api.github.com/repos/JabRef/jabref/releases/latest";
+ private static final Version UNKNOWN_VERSION = new Version();
+
+ private final static Pattern VERSION_PATTERN = Pattern.compile("(?<major>\\d+)(\\.(?<minor>\\d+))?(\\.(?<patch>\\d+))?(?<stage>-alpha|-beta)?(?<dev>-?dev)?.*");
+
+ public static final String JABREF_DOWNLOAD_URL = "https://downloads.jabref.org";
+ private static final String JABREF_GITHUB_RELEASES = "https://api.github.com/repos/JabRef/JabRef/releases";
+
private String fullVersion = BuildInfo.UNKNOWN_VERSION;
- private int major;
- private int minor;
- private int patch;
+ private int major = -1;
+ private int minor = -1;
+ private int patch = -1;
+ private DevelopmentStage developmentStage = DevelopmentStage.UNKNOWN;
private boolean isDevelopmentVersion;
+ /** Dummy constructor to create a local object (and {@link Version#UNKNOWN_VERSION}) */
+ private Version() {}
+
/**
- * @param version must be in form of X.X (e.g., 3.3; 3.4dev)
+ * @param version must be in form of following pattern: {@code (\d+)(\.(\d+))?(\.(\d+))?(-alpha|-beta)?(-?dev)?} (e.g., 3.3; 3.4-dev)
+ * @return the parsed version or {@link Version#UNKNOWN_VERSION} if an error occurred
*/
- public Version(String version) {
+ public static Version parse(String version) {
if ((version == null) || "".equals(version) || version.equals(BuildInfo.UNKNOWN_VERSION)
|| "${version}".equals(version)) {
- return;
+ return UNKNOWN_VERSION;
}
- String[] versionParts = version.split("dev");
- String[] versionNumbers = versionParts[0].split(Pattern.quote("."));
- try {
- this.major = Integer.parseInt(versionNumbers[0]);
- this.minor = versionNumbers.length >= 2 ? Integer.parseInt(versionNumbers[1]) : 0;
- this.patch = versionNumbers.length >= 3 ? Integer.parseInt(versionNumbers[2]) : 0;
- this.fullVersion = version;
- this.isDevelopmentVersion = version.contains("dev");
- } catch (NumberFormatException exception) {
- LOGGER.warn("Invalid version string used: " + version, exception);
+ Version parsedVersion= new Version();
+
+ parsedVersion.fullVersion = version;
+ Matcher matcher = VERSION_PATTERN.matcher(version);
+ if (matcher.find()) {
+ try {
+ parsedVersion.major = Integer.parseInt(matcher.group("major"));
+
+ String minorString = matcher.group("minor");
+ parsedVersion.minor = minorString == null ? 0 : Integer.parseInt(minorString);
+
+ String patchString = matcher.group("patch");
+ parsedVersion.patch = patchString == null ? 0 : Integer.parseInt(patchString);
+
+ String versionStageString = matcher.group("stage");
+ parsedVersion.developmentStage = versionStageString == null ? DevelopmentStage.STABLE : DevelopmentStage.parse(versionStageString);
+ parsedVersion.isDevelopmentVersion = matcher.group("dev") != null;
+ } catch (NumberFormatException e) {
+ LOGGER.warn("Invalid version string used: " + version, e);
+ return UNKNOWN_VERSION;
+ } catch (IllegalArgumentException e) {
+ LOGGER.warn("Invalid version pattern is used", e);
+ return UNKNOWN_VERSION;
+ }
+ } else {
+ LOGGER.warn("Version could not be recognized by the pattern");
+ return UNKNOWN_VERSION;
}
+ return parsedVersion;
}
/**
- * Grabs the latest release version from the JabRef GitHub repository
+ * Grabs all the available releases from the GitHub repository
+ *
+ * @throws IOException
*/
- public static Version getLatestVersion() throws IOException {
- URLConnection connection = new URL(JABREF_GITHUB_URL).openConnection();
+ public static List<Version> getAllAvailableVersions() throws IOException {
+ URLConnection connection = new URL(JABREF_GITHUB_RELEASES).openConnection();
connection.setRequestProperty("Accept-Charset", "UTF-8");
BufferedReader rd = new BufferedReader(new InputStreamReader(connection.getInputStream()));
- JSONObject obj = new JSONObject(rd.readLine());
- return new Version(obj.getString("tag_name").replaceFirst("v", ""));
+
+ List<Version> versions = new ArrayList<>();
+ JSONArray objects = new JSONArray(rd.readLine());
+ for (int i = 0; i < objects.length(); i++) {
+ JSONObject jsonObject = objects.getJSONObject(i);
+ Version version = Version.parse(jsonObject.getString("tag_name").replaceFirst("v", ""));
+ versions.add(version);
+ }
+ return versions;
}
/**
- * @return true iff this version is newer than the passed one
+ * @return true if this version is newer than the passed one
*/
public boolean isNewerThan(Version otherVersion) {
Objects.requireNonNull(otherVersion);
@@ -71,17 +113,66 @@ public class Version {
return false;
} else if (otherVersion.getFullVersion().equals(BuildInfo.UNKNOWN_VERSION)) {
return false;
- } else if (this.getMajor() > otherVersion.getMajor()) {
+ }
+
+ // compare the majors
+ if (this.getMajor() > otherVersion.getMajor()) {
return true;
} else if (this.getMajor() == otherVersion.getMajor()) {
+ // if the majors are equal compare the minors
if (this.getMinor() > otherVersion.getMinor()) {
return true;
- } else {
- return (this.getMinor() == otherVersion.getMinor()) && (this.getPatch() > otherVersion.getPatch());
+ } else if (this.getMinor() == otherVersion.getMinor()) {
+ // if the minors are equal compare the patch numbers
+ if (this.getPatch() > otherVersion.getPatch()) {
+ return true;
+ } else if (this.getPatch() == otherVersion.getPatch()) {
+ // if the patch numbers are equal compare the development stages
+ if (this.developmentStage.isMoreStableThan(otherVersion.developmentStage)) {
+ return true;
+ } else if (this.developmentStage == otherVersion.developmentStage) {
+ // if the stage is equal check if this version is in development and the other is not
+ return !this.isDevelopmentVersion && otherVersion.isDevelopmentVersion;
+ }
+ }
}
- } else {
+ }
+ return false;
+ }
+
+
+ /**
+ * Checks if this version should be updated to one of the given ones.
+ * Ignoring the other Version if this one is Stable and the other one is not.
+ *
+ * @return The version this one should be updated to, or an empty Optional
+ */
+ public Optional<Version> shouldBeUpdatedTo(List<Version> availableVersions ) {
+ Optional<Version> newerVersion = Optional.empty();
+ for (Version version : availableVersions) {
+ if (this.shouldBeUpdatedTo(version)
+ && (!newerVersion.isPresent() || version.isNewerThan(newerVersion.get()))) {
+ newerVersion = Optional.of(version);
+ }
+ }
+ return newerVersion;
+ }
+
+ /**
+ * Checks if this version should be updated to the given one.
+ * Ignoring the other Version if this one is Stable and the other one is not.
+ *
+ * @return True if this version should be updated to the given one
+ * */
+ public boolean shouldBeUpdatedTo(Version otherVersion) {
+ // ignoring the other version if it is not stable, except if this version itself is not stable
+ if (developmentStage == Version.DevelopmentStage.STABLE
+ && otherVersion.developmentStage != Version.DevelopmentStage.STABLE) {
return false;
}
+
+ // check if the other version is newer than given one
+ return otherVersion.isNewerThan(this);
}
public String getFullVersion() {
@@ -105,12 +196,31 @@ public class Version {
}
/**
- * @return The link to the changelog on github to this specific version
+ * @return The link to the changelog on GitHub to this specific version
* (https://github.com/JabRef/jabref/blob/vX.X/CHANGELOG.md)
*/
public String getChangelogUrl() {
- String version = this.getMajor() + "." + this.getMinor() + (this.getPatch() != 0 ? "." + this.getPatch() : "");
- return "https://github.com/JabRef/jabref/blob/v" + version + "/CHANGELOG.md";
+ if (isDevelopmentVersion) {
+ return "https://github.com/JabRef/jabref/blob/master/CHANGELOG.md#unreleased";
+ } else {
+ StringBuilder changelogLink = new StringBuilder()
+ .append("https://github.com/JabRef/jabref/blob/v")
+ .append(this.getMajor())
+ .append(".")
+ .append(this.getMinor());
+
+ if (this.getPatch() != 0) {
+ changelogLink
+ .append(".")
+ .append(this.getPatch());
+ }
+
+ changelogLink
+ .append(this.developmentStage.stage)
+ .append("/CHANGELOG.md");
+
+ return changelogLink.toString();
+ }
}
@Override
@@ -122,9 +232,8 @@ public class Version {
return false;
}
- Version otherVersion = (Version) other;
- // till all the information are stripped from the fullverison this should suffice
- return this.getFullVersion().equals(otherVersion.getFullVersion());
+ // till all the information are stripped from the fullversion this should suffice
+ return this.getFullVersion().equals(((Version) other).getFullVersion());
}
@Override
@@ -137,4 +246,43 @@ public class Version {
return this.getFullVersion();
}
+
+ public enum DevelopmentStage {
+ UNKNOWN("", 0),
+ ALPHA("-alpha", 1),
+ BETA("-beta", 2),
+ STABLE("", 3);
+
+ /** describes how stable this stage is, the higher the better */
+ private final int stability;
+ private final String stage;
+
+ DevelopmentStage(String stage, int stability) {
+ this.stage = stage;
+ this.stability = stability;
+ }
+
+ public static DevelopmentStage parse(String stage) {
+ if (stage == null) {
+ LOGGER.warn("The stage cannot be null");
+ return UNKNOWN;
+ } else if (stage.equals(STABLE.stage)) {
+ return STABLE;
+ } else if (stage.equals(ALPHA.stage)) {
+ return ALPHA;
+ } else if (stage.equals(BETA.stage)) {
+ return BETA;
+ }
+ LOGGER.warn("Unknown development stage: " + stage);
+ return UNKNOWN;
+ }
+
+ /**
+ * @return true if this stage is more stable than the {@code otherStage}
+ */
+ public boolean isMoreStableThan(DevelopmentStage otherStage) {
+ return this.stability > otherStage.stability;
+ }
+ }
+
}
diff --git a/src/main/java/net/sf/jabref/logic/util/io/AutoSaveUtil.java b/src/main/java/net/sf/jabref/logic/util/io/AutoSaveUtil.java
deleted file mode 100644
index a6c9945..0000000
--- a/src/main/java/net/sf/jabref/logic/util/io/AutoSaveUtil.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package net.sf.jabref.logic.util.io;
-
-import java.io.File;
-
-public class AutoSaveUtil {
-
- /**
- * Get a File object pointing to the autosave file corresponding to the given file.
- * @param f The database file.
- * @return its corresponding autosave file.
- */
- public static File getAutoSaveFile(File f) {
- return new File(f.getParentFile(), ".$" + f.getName() + '$');
- }
-
- /**
- * Check if a newer autosave exists for the given file.
- * @param f The file to check.
- * @return true if an autosave is found, and if the autosave is newer
- * than the given file.
- */
- public static boolean newerAutoSaveExists(File f) {
- File asFile = getAutoSaveFile(f);
- return asFile.exists() && (asFile.lastModified() > f.lastModified());
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/logic/util/io/DatabaseFileLookup.java b/src/main/java/net/sf/jabref/logic/util/io/DatabaseFileLookup.java
index ec7d7d8..6cb0af3 100644
--- a/src/main/java/net/sf/jabref/logic/util/io/DatabaseFileLookup.java
+++ b/src/main/java/net/sf/jabref/logic/util/io/DatabaseFileLookup.java
@@ -8,12 +8,13 @@ import java.util.Objects;
import java.util.Optional;
import java.util.Set;
-import net.sf.jabref.BibDatabaseContext;
import net.sf.jabref.model.database.BibDatabase;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.FieldName;
import net.sf.jabref.model.entry.FileField;
import net.sf.jabref.model.entry.ParsedFileField;
+import net.sf.jabref.model.metadata.FileDirectoryPreferences;
/**
* Search class for files. <br>
@@ -34,9 +35,10 @@ public class DatabaseFileLookup {
*
* @param database A {@link BibDatabase}.
*/
- public DatabaseFileLookup(BibDatabaseContext databaseContext) {
+ public DatabaseFileLookup(BibDatabaseContext databaseContext, FileDirectoryPreferences fileDirectoryPreferences) {
Objects.requireNonNull(databaseContext);
- possibleFilePaths = Optional.ofNullable(databaseContext.getFileDirectory()).orElse(new ArrayList<>());
+ possibleFilePaths = Optional.ofNullable(databaseContext.getFileDirectories(fileDirectoryPreferences))
+ .orElse(new ArrayList<>());
for (BibEntry entry : databaseContext.getDatabase().getEntries()) {
fileCache.addAll(parseFileField(entry));
@@ -64,7 +66,7 @@ public class DatabaseFileLookup {
private List<File> parseFileField(BibEntry entry) {
Objects.requireNonNull(entry);
- List<ParsedFileField> entries = FileField.parse(entry.getFieldOptional(FieldName.FILE).orElse(null));
+ List<ParsedFileField> entries = FileField.parse(entry.getField(FieldName.FILE).orElse(null));
List<File> fileLinks = new ArrayList<>();
for (ParsedFileField field : entries) {
diff --git a/src/main/java/net/sf/jabref/logic/util/io/FileUtil.java b/src/main/java/net/sf/jabref/logic/util/io/FileUtil.java
index 65cf990..83c1657 100644
--- a/src/main/java/net/sf/jabref/logic/util/io/FileUtil.java
+++ b/src/main/java/net/sf/jabref/logic/util/io/FileUtil.java
@@ -1,12 +1,12 @@
package net.sf.jabref.logic.util.io;
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.io.StringReader;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -20,16 +20,17 @@ import java.util.Stack;
import java.util.Vector;
import java.util.regex.Pattern;
-import net.sf.jabref.BibDatabaseContext;
import net.sf.jabref.logic.layout.Layout;
import net.sf.jabref.logic.layout.LayoutFormatterPreferences;
import net.sf.jabref.logic.layout.LayoutHelper;
import net.sf.jabref.logic.util.OS;
import net.sf.jabref.model.database.BibDatabase;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.FieldName;
import net.sf.jabref.model.entry.FileField;
import net.sf.jabref.model.entry.ParsedFileField;
+import net.sf.jabref.model.metadata.FileDirectoryPreferences;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -41,6 +42,9 @@ public class FileUtil {
private static final Pattern SLASH = Pattern.compile("/");
private static final Pattern BACKSLASH = Pattern.compile("\\\\");
+ public static final boolean isPosixCompilant = FileSystems.getDefault().supportedFileAttributeViews().contains(
+ "posix");
+
/**
* Returns the extension of a file or Optional.empty() if the file does not have one (no . in name).
*
@@ -52,21 +56,46 @@ public class FileUtil {
}
/**
- * Returns the extension of a file name or Optional.empty() if the file does not have one (no . in name).
+ * Returns the extension of a file name or Optional.empty() if the file does not have one (no "." in name).
*
* @param fileName
- * @return The extension, trimmed and in lowercase.
+ * @return The extension (without leading dot), trimmed and in lowercase.
*/
public static Optional<String> getFileExtension(String fileName) {
- int pos = fileName.lastIndexOf('.');
- if ((pos > 0) && (pos < (fileName.length() - 1))) {
- return Optional.of(fileName.substring(pos + 1).trim().toLowerCase());
+ int dotPosition = fileName.lastIndexOf('.');
+ if ((dotPosition > 0) && (dotPosition < (fileName.length() - 1))) {
+ return Optional.of(fileName.substring(dotPosition + 1).trim().toLowerCase());
} else {
return Optional.empty();
}
}
/**
+ * Returns the name part of a file name (i.e., everything in front of last ".").
+ */
+ public static String getFileName(String fileNameWithExtension) {
+ int dotPosition = fileNameWithExtension.lastIndexOf('.');
+ if (dotPosition >= 0) {
+ return fileNameWithExtension.substring(0, dotPosition);
+ } else {
+ return fileNameWithExtension;
+ }
+ }
+
+ /**
+ * Adds an extension to the given file name. The original extension is not replaced. That means,
+ * "demo.bib", ".sav" gets "demo.bib.sav" and not "demo.sav"
+ *
+ * @param path the path to add the extension to
+ * @param extension the extension to add
+ * @return the with the modified file name
+ */
+ public static Path addExtension(Path path, String extension) {
+ Path fileName = path.getFileName();
+ return path.resolveSibling(fileName + extension);
+ }
+
+ /**
* Creates the minimal unique path substring for each file among multiple file paths.
*
* @param paths the file paths
@@ -110,46 +139,62 @@ public class FileUtil {
/**
* Copies a file.
*
- * @param source File Source file
- * @param dest File Destination file
- * @param deleteIfExists boolean Determines whether the copy goes on even if the file
- * exists.
- * @return boolean Whether the copy succeeded, or was stopped due to the
- * file already existing.
+ * @param pathToSourceFile Path Source file
+ * @param pathToDestinationFile Path Destination file
+ * @param replaceExisting boolean Determines whether the copy goes on even if the file exists.
+ * @return boolean Whether the copy succeeded, or was stopped due to the file already existing.
* @throws IOException
*/
- public static boolean copyFile(File source, File dest, boolean deleteIfExists) throws IOException {
+ public static boolean copyFile(Path pathToSourceFile, Path pathToDestinationFile, boolean replaceExisting) {
// Check if the file already exists.
- if (dest.exists() && !deleteIfExists) {
+ if (!Files.exists(pathToSourceFile)) {
+ LOGGER.error("Path to the source file doesn't exist.");
return false;
}
- try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(source));
- BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(dest))) {
-
-
- int el;
- while ((el = in.read()) >= 0) {
- out.write(el);
- }
- out.flush();
+ if (Files.exists(pathToDestinationFile) && !replaceExisting) {
+ LOGGER.error("Path to the destination file is not exists and the file shouldn't be replace.");
+ return false;
+ }
+ try {
+ return Files.copy(pathToSourceFile, pathToDestinationFile, StandardCopyOption.REPLACE_EXISTING) != null;
+ } catch (IOException e) {
+ LOGGER.error("Copying Files failed.", e);
+ return false;
}
- return true;
}
/**
- * @param fileName
- * @param destFilename
- * @return
+ * Renames a given file
+ *
+ * @param fromFile The source filename to rename
+ * @param toFile The target fileName
+ * @return True if the rename was successful, false if an exception occurred
*/
- public static boolean renameFile(String fileName, String destFilename) {
- // File (or directory) with old name
- File fromFile = new File(fileName);
-
- // File (or directory) with new name
- File toFile = new File(destFilename);
+ public static boolean renameFile(Path fromFile, Path toFile) {
+ return renameFile(fromFile, toFile, false);
+ }
- // Rename file (or directory)
- return fromFile.renameTo(toFile);
+ /**
+ * Renames a given file
+ *
+ * @param fromFile The source filename to rename
+ * @param toFile The target fileName
+ * @param replaceExisting Wether to replace existing files or not
+ * @return True if the rename was successful, false if an exception occurred
+ *
+ */
+ public static boolean renameFile(Path fromFile, Path toFile, boolean replaceExisting) {
+ try {
+ if (replaceExisting) {
+ return Files.move(fromFile, fromFile.resolveSibling(toFile),
+ StandardCopyOption.REPLACE_EXISTING) != null;
+ } else {
+ return Files.move(fromFile, fromFile.resolveSibling(toFile)) != null;
+ }
+ } catch (IOException e) {
+ LOGGER.error("Renaming Files failed", e);
+ return false;
+ }
}
/**
@@ -165,12 +210,13 @@ public class FileUtil {
* @param databaseContext The database this file belongs to.
* @param name The filename, may also be a relative path to the file
*/
- public static Optional<File> expandFilename(final BibDatabaseContext databaseContext, String name) {
+ public static Optional<File> expandFilename(final BibDatabaseContext databaseContext, String name,
+ FileDirectoryPreferences fileDirectoryPreferences) {
Optional<String> extension = getFileExtension(name);
// Find the default directory for this field type, if any:
- List<String> directories = databaseContext.getFileDirectory(extension.orElse(null));
+ List<String> directories = databaseContext.getFileDirectories(extension.orElse(null), fileDirectoryPreferences);
// Include the standard "file" directory:
- List<String> fileDir = databaseContext.getFileDirectory();
+ List<String> fileDir = databaseContext.getFileDirectories(fileDirectoryPreferences);
// Include the directory of the BIB file:
List<String> al = new ArrayList<>();
for (String dir : directories) {
@@ -299,8 +345,8 @@ public class FileUtil {
}
}
- public static Map<BibEntry, List<File>> findAssociatedFiles(List<BibEntry> entries,
- List<String> extensions, List<File> directories, boolean autolinkExactKeyOnly) {
+ public static Map<BibEntry, List<File>> findAssociatedFiles(List<BibEntry> entries, List<String> extensions,
+ List<File> directories, boolean autolinkExactKeyOnly) {
Map<BibEntry, List<File>> result = new HashMap<>();
// First scan directories
@@ -355,7 +401,7 @@ public class FileUtil {
List<File> result = new ArrayList<>();
for (BibEntry entry : bes) {
- entry.getFieldOptional(FieldName.FILE).ifPresent(fileField -> {
+ entry.getField(FieldName.FILE).ifPresent(fileField -> {
List<ParsedFileField> fileList = FileField.parse(fileField);
for (ParsedFileField file : fileList) {
expandFilename(file.getLink(), fileDirs).ifPresent(result::add);
@@ -375,9 +421,10 @@ public class FileUtil {
* @param prefs the layout preferences
* @return a suggested fileName
*/
- public static String createFileNameFromPattern(BibDatabase database, BibEntry entry,
- String fileNamePattern, LayoutFormatterPreferences prefs) {
- String targetName = entry.getCiteKeyOptional().orElse("default");
+ public static String createFileNameFromPattern(BibDatabase database, BibEntry entry, String fileNamePattern,
+ LayoutFormatterPreferences prefs) {
+ String targetName = null;
+
StringReader sr = new StringReader(fileNamePattern);
Layout layout = null;
try {
@@ -388,9 +435,12 @@ public class FileUtil {
if (layout != null) {
targetName = layout.doLayout(entry, database);
}
+
+ if ((targetName == null) || targetName.isEmpty()) {
+ targetName = entry.getCiteKeyOptional().orElse("default");
+ }
//Removes illegal characters from filename
targetName = FileNameCleaner.cleanFileName(targetName);
return targetName;
}
-
}
diff --git a/src/main/java/net/sf/jabref/logic/util/io/RegExpFileSearch.java b/src/main/java/net/sf/jabref/logic/util/io/RegExpFileSearch.java
new file mode 100644
index 0000000..1ad837e
--- /dev/null
+++ b/src/main/java/net/sf/jabref/logic/util/io/RegExpFileSearch.java
@@ -0,0 +1,343 @@
+package net.sf.jabref.logic.util.io;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import net.sf.jabref.logic.bibtexkeypattern.BibtexKeyPatternUtil;
+import net.sf.jabref.model.database.BibDatabase;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.strings.StringUtil;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: alver
+ * Date: Apr 12, 2008
+ * Time: 1:46:44 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public class RegExpFileSearch {
+
+ private static final Log LOGGER = LogFactory.getLog(RegExpFileSearch.class);
+
+ private static final String EXT_MARKER = "__EXTENSION__";
+
+ private static final Pattern ESCAPE_PATTERN = Pattern.compile("([^\\\\])\\\\([^\\\\])");
+
+ private static final Pattern SQUARE_BRACKETS_PATTERN = Pattern.compile("\\[.*?\\]");
+
+
+ /**
+ * Search for file links for a set of entries using regexp. Lists of extensions and directories
+ * are given.
+ * @param entries The entries to search for.
+ * @param extensions The extensions that are acceptable.
+ * @param directories The root directories to search.
+ * @param regExp The expression deciding which names are acceptable.
+ * @param keywordDelimiter
+ * @return A map linking each given entry to a list of files matching the given criteria.
+ */
+ public static Map<BibEntry, List<File>> findFilesForSet(List<BibEntry> entries, List<String> extensions,
+ List<File> directories, String regExp, Character keywordDelimiter) {
+
+ Map<BibEntry, List<File>> res = new HashMap<>();
+ for (BibEntry entry : entries) {
+ res.put(entry, findFiles(entry, extensions, directories, regExp, keywordDelimiter));
+ }
+ return res;
+ }
+
+ /**
+ * Method for searching for files using regexp. A list of extensions and directories can be
+ * given.
+ * @param entry The entry to search for.
+ * @param extensions The extensions that are acceptable.
+ * @param directories The root directories to search.
+ * @param regularExpression The expression deciding which names are acceptable.
+ * @param keywordDelimiter
+ * @return A list of files paths matching the given criteria.
+ */
+ private static List<File> findFiles(BibEntry entry, List<String> extensions, List<File> directories,
+ String regularExpression, Character keywordDelimiter) {
+
+ String extensionRegExp = '(' + String.join("|", extensions) + ')';
+
+ return findFile(entry, directories, regularExpression, extensionRegExp, keywordDelimiter);
+ }
+
+ /**
+ * Searches the given directory and filename pattern for a file for the
+ * BibTeX entry.
+ *
+ * Used to fix:
+ *
+ * http://sourceforge.net/tracker/index.php?func=detail&aid=1503410&group_id=92314&atid=600309
+ *
+ * Requirements:
+ * - Be able to find the associated PDF in a set of given directories.
+ * - Be able to return a relative path or absolute path.
+ * - Be fast.
+ * - Allow for flexible naming schemes in the PDFs.
+ *
+ * Syntax scheme for file:
+ * <ul>
+ * <li>* Any subDir</li>
+ * <li>** Any subDir (recursive)</li>
+ * <li>[key] Key from BibTeX file and database</li>
+ * <li>.* Anything else is taken to be a Regular expression.</li>
+ * </ul>
+ *
+ * @param keywordDelimiter
+ * @param entry
+ * non-null
+ * @param dirs
+ * A set of root directories to start the search from. Paths are
+ * returned relative to these directories if relative is set to
+ * true. These directories will not be expanded or anything. Use
+ * the file attribute for this.
+ * @param file
+ * non-null
+ *
+ * @return Will return the first file found to match the given criteria or
+ * null if none was found.
+ */
+ private static List<File> findFile(BibEntry entry, List<File> dirs, String file, String extensionRegExp,
+ Character keywordDelimiter) {
+ List<File> res = new ArrayList<>();
+ for (File directory : dirs) {
+ res.addAll(findFile(entry, directory.getPath(), file, extensionRegExp, keywordDelimiter));
+ }
+ return res;
+ }
+
+ /**
+ * Internal Version of findFile, which also accepts a current directory to
+ * base the search on.
+ *
+ */
+ private static List<File> findFile(BibEntry entry, String directory, String file, String extensionRegExp,
+ Character keywordDelimiter) {
+
+ File root;
+ if (directory == null) {
+ root = new File(".");
+ } else {
+ root = new File(directory);
+ }
+ if (!root.exists()) {
+ return Collections.emptyList();
+ }
+ List<File> fileList = RegExpFileSearch.findFile(entry, root, file, extensionRegExp, keywordDelimiter);
+
+ List<File> result = new ArrayList<>();
+ for (File tmpFile : fileList) {
+ try {
+ /**
+ * [ 1601651 ] PDF subdirectory - missing first character
+ *
+ * http://sourceforge.net/tracker/index.php?func=detail&aid=1601651&group_id=92314&atid=600306
+ */
+ // Changed by M. Alver 2007.01.04:
+ // Remove first character if it is a directory separator character:
+ String tmp = tmpFile.getCanonicalPath().substring(root.getCanonicalPath().length());
+ if ((tmp.length() > 1) && (tmp.charAt(0) == File.separatorChar)) {
+ tmp = tmp.substring(1);
+ }
+ result.add(new File(tmp));
+
+ } catch (IOException e) {
+ LOGGER.warn("Problem searching", e);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * The actual work-horse. Will find absolute filepaths starting from the
+ * given directory using the given regular expression string for search.
+ */
+ private static List<File> findFile(BibEntry entry, File directory, String file, String extensionRegExp,
+ Character keywordDelimiter) {
+
+ List<File> res = new ArrayList<>();
+
+ String fileName = file;
+ File actualDirectory;
+ if (fileName.startsWith("/")) {
+ actualDirectory = new File(".");
+ fileName = fileName.substring(1);
+ } else {
+ actualDirectory = directory;
+ }
+
+ // Escape handling...
+ Matcher m = ESCAPE_PATTERN.matcher(fileName);
+ StringBuffer s = new StringBuffer();
+ while (m.find()) {
+ m.appendReplacement(s, m.group(1) + '/' + m.group(2));
+ }
+ m.appendTail(s);
+ fileName = s.toString();
+ String[] fileParts = fileName.split("/");
+
+ if (fileParts.length == 0) {
+ return res;
+ }
+
+ for (int i = 0; i < (fileParts.length - 1); i++) {
+
+ String dirToProcess = fileParts[i];
+ dirToProcess = expandBrackets(dirToProcess, entry, null, keywordDelimiter);
+
+ if (dirToProcess.matches("^.:$")) { // Windows Drive Letter
+ actualDirectory = new File(dirToProcess + '/');
+ continue;
+ }
+ if (".".equals(dirToProcess)) { // Stay in current directory
+ continue;
+ }
+ if ("..".equals(dirToProcess)) {
+ actualDirectory = new File(actualDirectory.getParent());
+ continue;
+ }
+ if ("*".equals(dirToProcess)) { // Do for all direct subdirs
+
+ File[] subDirs = actualDirectory.listFiles();
+ if (subDirs != null) {
+ String restOfFileString = StringUtil.join(fileParts, "/", i + 1, fileParts.length);
+ for (File subDir : subDirs) {
+ if (subDir.isDirectory()) {
+ res.addAll(findFile(entry, subDir, restOfFileString, extensionRegExp, keywordDelimiter));
+ }
+ }
+ }
+ }
+ // Do for all direct and indirect subdirs
+ if ("**".equals(dirToProcess)) {
+ List<File> toDo = new LinkedList<>();
+ toDo.add(actualDirectory);
+
+ String restOfFileString = StringUtil.join(fileParts, "/", i + 1, fileParts.length);
+
+ while (!toDo.isEmpty()) {
+
+ // Get all subdirs of each of the elements found in toDo
+ File[] subDirs = toDo.remove(0).listFiles();
+ if (subDirs == null) {
+ continue;
+ }
+
+ toDo.addAll(Arrays.asList(subDirs));
+
+ for (File subDir : subDirs) {
+ if (!subDir.isDirectory()) {
+ continue;
+ }
+ res.addAll(findFile(entry, subDir, restOfFileString, extensionRegExp, keywordDelimiter));
+ }
+ }
+
+ } // End process directory information
+ }
+
+ // Last step: check if the given file can be found in this directory
+ String filePart = fileParts[fileParts.length - 1].replace("[extension]", EXT_MARKER);
+ String filenameToLookFor = expandBrackets(filePart, entry, null, keywordDelimiter).replaceAll(EXT_MARKER, extensionRegExp);
+ final Pattern toMatch = Pattern.compile('^' + filenameToLookFor.replaceAll("\\\\\\\\", "\\\\") + '$',
+ Pattern.CASE_INSENSITIVE);
+
+ File[] matches = actualDirectory.listFiles((arg0, arg1) -> {
+ return toMatch.matcher(arg1).matches();
+ });
+ if ((matches != null) && (matches.length > 0)) {
+ Collections.addAll(res, matches);
+ }
+ return res;
+ }
+
+ /**
+ * Takes a string that contains bracketed expression and expands each of these using getFieldAndFormat.
+ * <p>
+ * Unknown Bracket expressions are silently dropped.
+ *
+ * @param bracketString
+ * @param entry
+ * @param database
+ * @param keywordDelimiter
+ * @return
+ */
+ public static String expandBrackets(String bracketString, BibEntry entry, BibDatabase database,
+ Character keywordDelimiter) {
+ Matcher m = SQUARE_BRACKETS_PATTERN.matcher(bracketString);
+ StringBuffer s = new StringBuffer();
+ while (m.find()) {
+ String replacement = getFieldAndFormat(m.group(), entry, database, keywordDelimiter);
+ m.appendReplacement(s, replacement);
+ }
+ m.appendTail(s);
+
+ return s.toString();
+ }
+
+ /**
+ * Accepts a string like [author:lower] or [title:abbr] or [auth], whereas the first part signifies the bibtex-field
+ * to get, or the key generator field marker to use, while the others are the modifiers that will be applied.
+ *
+ * @param fieldAndFormat
+ * @param entry
+ * @param database
+ * @param keywordDelimiter
+ * @return
+ */
+ public static String getFieldAndFormat(String fieldAndFormat, BibEntry entry, BibDatabase database,
+ Character keywordDelimiter) {
+
+ String strippedFieldAndFormat = StringUtil.stripBrackets(fieldAndFormat);
+
+ int colon = strippedFieldAndFormat.indexOf(':');
+
+ String beforeColon;
+ String afterColon;
+ if (colon == -1) {
+ beforeColon = strippedFieldAndFormat;
+ afterColon = null;
+ } else {
+ beforeColon = strippedFieldAndFormat.substring(0, colon);
+ afterColon = strippedFieldAndFormat.substring(colon + 1);
+ }
+ beforeColon = beforeColon.trim();
+
+ if (beforeColon.isEmpty()) {
+ return "";
+ }
+
+ // If no field value was found, try to interpret it as a key generator field marker:
+ String fieldValue = entry.getResolvedFieldOrAlias(beforeColon, database)
+ .orElse(BibtexKeyPatternUtil.makeLabel(entry, beforeColon, keywordDelimiter, database));
+
+ if (fieldValue == null) {
+ return "";
+ }
+
+ if ((afterColon == null) || afterColon.isEmpty()) {
+ return fieldValue;
+ }
+
+ List<String> parts = Arrays.asList(afterColon.split(":"));
+ fieldValue = BibtexKeyPatternUtil.applyModifiers(fieldValue, parts, 0);
+
+ return fieldValue;
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/logic/util/strings/DiffHighlighting.java b/src/main/java/net/sf/jabref/logic/util/strings/DiffHighlighting.java
deleted file mode 100644
index ba6463b..0000000
--- a/src/main/java/net/sf/jabref/logic/util/strings/DiffHighlighting.java
+++ /dev/null
@@ -1,101 +0,0 @@
-package net.sf.jabref.logic.util.strings;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-
-import difflib.Delta;
-import difflib.DiffUtils;
-
-public class DiffHighlighting {
-
- private static final String ADDITION_START = "<span class=add>";
- private static final String REMOVAL_START = "<span class=del>";
- private static final String CHANGE_START = "<span class=change>";
- private static final String TAG_END = "</span>";
-
- public static final String HTML_START = "<html><body>";
- public static final String HTML_END = "</body></html>";
-
-
- public static String generateDiffHighlighting(String baseString, String modifiedString, String separator) {
- Objects.requireNonNull(separator);
- if ((baseString != null) && (modifiedString != null)) {
- List<String> stringList = new ArrayList<>(Arrays.asList(baseString.split(separator)));
- List<Delta<String>> deltaList = new ArrayList<>(
- DiffUtils.diff(stringList, Arrays.asList(modifiedString.split(separator))).getDeltas());
- Collections.reverse(deltaList);
- for (Delta<String> delta : deltaList) {
- int startPos = delta.getOriginal().getPosition();
- List<String> lines = delta.getOriginal().getLines();
- int offset = 0;
- switch (delta.getType()) {
- case CHANGE:
- for (String line : lines) {
- stringList.set(startPos + offset, (offset == 0 ? DiffHighlighting.REMOVAL_START : "") + line);
- offset++;
- }
- stringList.set((startPos + offset) - 1,
- stringList.get((startPos + offset) - 1) + DiffHighlighting.TAG_END + separator + DiffHighlighting.ADDITION_START
- + String.join(separator, delta.getRevised().getLines()) + DiffHighlighting.TAG_END);
- break;
- case DELETE:
- for (String line : lines) {
- stringList.set(startPos + offset, (offset == 0 ? DiffHighlighting.REMOVAL_START : "") + line);
- offset++;
- }
- stringList.set((startPos + offset) - 1,
- stringList.get((startPos + offset) - 1) + DiffHighlighting.TAG_END);
- break;
- case INSERT:
- stringList.add(delta.getOriginal().getPosition(),
- DiffHighlighting.ADDITION_START + String.join(separator, delta.getRevised().getLines()) + DiffHighlighting.TAG_END);
- break;
- default:
- break;
- }
- }
- return String.join(separator, stringList);
- }
- return modifiedString;
- }
-
- public static String generateSymmetricHighlighting(String baseString, String modifiedString, String separator) {
- if ((baseString != null) && (modifiedString != null)) {
- List<String> stringList = new ArrayList<>(Arrays.asList(baseString.split(separator)));
- List<Delta<String>> deltaList = new ArrayList<>(DiffUtils
- .diff(stringList, new ArrayList<>(Arrays.asList(modifiedString.split(separator)))).getDeltas());
- Collections.reverse(deltaList);
- for (Delta<String> delta : deltaList) {
- int startPos = delta.getOriginal().getPosition();
- List<String> lines = delta.getOriginal().getLines();
- int offset = 0;
- switch (delta.getType()) {
- case CHANGE:
- for (String line : lines) {
- stringList.set(startPos + offset, (offset == 0 ? DiffHighlighting.CHANGE_START : "") + line);
- offset++;
- }
- stringList.set((startPos + offset) - 1, stringList.get((startPos + offset) - 1) + DiffHighlighting.TAG_END);
- break;
- case DELETE:
- for (String line : lines) {
- stringList.set(startPos + offset, (offset == 0 ? DiffHighlighting.ADDITION_START : "") + line);
- offset++;
- }
- stringList.set((startPos + offset) - 1, stringList.get((startPos + offset) - 1) + DiffHighlighting.TAG_END);
- break;
- case INSERT:
- break;
- default:
- break;
- }
- }
- return String.join(separator, stringList);
- }
- return modifiedString;
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/logic/util/strings/HTMLUnicodeConversionMaps.java b/src/main/java/net/sf/jabref/logic/util/strings/HTMLUnicodeConversionMaps.java
deleted file mode 100644
index 19b9aae..0000000
--- a/src/main/java/net/sf/jabref/logic/util/strings/HTMLUnicodeConversionMaps.java
+++ /dev/null
@@ -1,904 +0,0 @@
-package net.sf.jabref.logic.util.strings;
-
-import java.util.HashMap;
-import java.util.Map;
-
-public class HTMLUnicodeConversionMaps {
-
- /* Portions © International Organization for Standardization 1986:
- Permission to copy in any form is granted for use with
- conforming SGML systems and applications as defined in
- ISO 8879, provided this notice is included in all copies.
- */
-
- // most of the LaTeX commands can be read at http://en.wikibooks.org/wiki/LaTeX/Accents
- // The symbols can be seen at http://www.fileformat.info/info/unicode/char/a4/index.htm. Replace "a4" with the U+ number
- // http://detexify.kirelabs.org/classify.html and http://www.ctan.org/tex-archive/info/symbols/comprehensive/ might help to find the right LaTeX command
- // http://llg.cubic.org/docs/ent2latex.html and http://www.w3.org/TR/xml-entity-names/byalpha.html are also useful
- // as well as http://www.w3.org/Math/characters/unicode.xml
-
- // An array of arrays of strings in the format:
- // {"decimal number of HTML entity", "text HTML entity", "corresponding LaTeX command"}
- // Leaving a field empty is OK as it then will not be included
- private static final String[][] CONVERSION_LIST = new String[][] {{"160", "nbsp", "{~}"}, // no-break space = non-breaking space,
- // U+00A0 ISOnum
- {"161", "iexcl", "{\\textexclamdown}"}, // inverted exclamation mark, U+00A1 ISOnum
- {"162", "cent", "{\\textcent}"}, // cent sign, U+00A2 ISOnum
- {"163", "pound", "{\\pounds}"}, // pound sign, U+00A3 ISOnum
- {"164", "curren", "{\\textcurrency}"}, // currency sign, U+00A4 ISOnum
- {"165", "yen", "{\\textyen}"}, // yen sign = yuan sign, U+00A5 ISOnum
- {"166", "brvbar", "{\\textbrokenbar}"}, // broken bar = broken vertical bar,
- // U+00A6 ISOnum
- {"167", "sect", "{{\\S}}"}, // section sign, U+00A7 ISOnum
- {"168", "uml", "{\\\"{}}"}, // diaeresis = spacing diaeresis,
- // U+00A8 ISOdia
- {"169", "copy", "{\\copyright}"}, // copyright sign, U+00A9 ISOnum
- {"170", "ordf", "{\\textordfeminine}"}, // feminine ordinal indicator, U+00AA ISOnum
- {"171", "laquo", "{\\guillemotleft}"}, // left-pointing double angle quotation mark
- // = left pointing guillemet, U+00AB ISOnum
- {"172", "not", "$\\neg$"}, // not sign, U+00AC ISOnum
- {"173", "shy", "\\-"}, // soft hyphen = discretionary hyphen,
- // U+00AD ISOnum
- {"174", "reg", "{\\textregistered}"}, // registered sign = registered trade mark sign,
- // U+00AE ISOnum
- {"175", "macr", "{\\={}}"}, // macron = spacing macron = overline
- // = APL overbar, U+00AF ISOdia
- {"176", "deg", "{$^{\\circ}$}"}, // degree sign, U+00B0 ISOnum
- {"177", "plusmn", "$\\pm$"}, // plus-minus sign = plus-or-minus sign,
- // U+00B1 ISOnum
- {"178", "sup2", "\\textsuperscript{2}"}, // superscript two = superscript digit two
- // = squared, U+00B2 ISOnum
- {"179", "sup3", "\\textsuperscript{3}"}, // superscript three = superscript digit three
- // = cubed, U+00B3 ISOnum
- {"180", "acute", "{\\'{}}"}, // acute accent = spacing acute,
- // U+00B4 ISOdia
- {"181", "micro", "$\\mu$"}, // micro sign, U+00B5 ISOnum
- {"", "mu", "$\\mu$"}, // micro sign, U+00B5 ISOnum
- {"182", "para", "{{\\P}}"}, // pilcrow sign = paragraph sign,
- // U+00B6 ISOnum
- {"183", "middot", "$\\cdot$"}, // middle dot = Georgian comma
- // = Greek middle dot, U+00B7 ISOnum
- {"184", "cedil", "{\\c{}}"}, // cedilla = spacing cedilla, U+00B8 ISOdia
- {"185", "sup1", "\\textsuperscript{1}"}, // superscript one = superscript digit one,
- // U+00B9 ISOnum
- {"186", "ordm", "{\\textordmasculine}"}, // masculine ordinal indicator,
- // U+00BA ISOnum
- {"187", "raquo", "{\\guillemotright}"}, // right-pointing double angle quotation mark
- // = right pointing guillemet, U+00BB ISOnum
- {"188", "frac14", "$\\sfrac{1}{4}$"}, // vulgar fraction one quarter
- // = fraction one quarter, U+00BC ISOnum
- {"189", "frac12", "$\\sfrac{1}{2}$"}, // vulgar fraction one half
- // = fraction one half, U+00BD ISOnum
- {"190", "frac34", "$\\sfrac{3}{4}$"}, // vulgar fraction three quarters
- // = fraction three quarters, U+00BE ISOnum
- {"191", "iquest", "{\\textquestiondown}"}, // inverted question mark
- // = turned question mark, U+00BF ISOnum
- {"192", "Agrave", "{{\\`{A}}}"}, // latin capital letter A with grave
- // = latin capital letter A grave,
- // U+00C0 ISOlat1
- {"193", "Aacute", "{{\\'{A}}}"}, // latin capital letter A with acute,
- // U+00C1 ISOlat1
- {"194", "Acirc", "{{\\^{A}}}"}, // latin capital letter A with circumflex,
- // U+00C2 ISOlat1
- {"195", "Atilde", "{{\\~{A}}}"}, // latin capital letter A with tilde,
- // U+00C3 ISOlat1
- {"196", "Auml", "{{\\\"{A}}}"}, // latin capital letter A with diaeresis,
- // U+00C4 ISOlat1
- {"197", "Aring", "{{\\AA}}"}, // latin capital letter A with ring above
- // = latin capital letter A ring,
- // U+00C5 ISOlat1
- {"198", "AElig", "{{\\AE}}"}, // latin capital letter AE
- // = latin capital ligature AE,
- // U+00C6 ISOlat1
- {"199", "Ccedil", "{{\\c{C}}}"}, // latin capital letter C with cedilla,
- // U+00C7 ISOlat1
- {"200", "Egrave", "{{\\`{E}}}"}, // latin capital letter E with grave,
- // U+00C8 ISOlat1
- {"201", "Eacute", "{{\\'{E}}}"}, // latin capital letter E with acute,
- // U+00C9 ISOlat1
- {"202", "Ecirc", "{{\\^{E}}}"}, // latin capital letter E with circumflex,
- // U+00CA ISOlat1
- {"203", "Euml", "{{\\\"{E}}}"}, // latin capital letter E with diaeresis,
- // U+00CB ISOlat1
- {"204", "Igrave", "{{\\`{I}}}"}, // latin capital letter I with grave,
- // U+00CC ISOlat1
- {"205", "Iacute", "{{\\'{I}}}"}, // latin capital letter I with acute,
- // U+00CD ISOlat1
- {"206", "Icirc", "{{\\^{I}}}"}, // latin capital letter I with circumflex,
- // U+00CE ISOlat1
- {"207", "Iuml", "{{\\\"{I}}}"}, // latin capital letter I with diaeresis,
- // U+00CF ISOlat1
- {"208", "ETH", "{{\\DH}}"}, // latin capital letter ETH, U+00D0 ISOlat1
- {"209", "Ntilde", "{{\\~{N}}}"}, // latin capital letter N with tilde,
- // U+00D1 ISOlat1
- {"210", "Ograve", "{{\\`{O}}}"}, // latin capital letter O with grave,
- // U+00D2 ISOlat1
- {"211", "Oacute", "{{\\'{O}}}"}, // latin capital letter O with acute,
- // U+00D3 ISOlat1
- {"212", "Ocirc", "{{\\^{O}}}"}, // latin capital letter O with circumflex,
- // U+00D4 ISOlat1
- {"213", "Otilde", "{{\\~{O}}}"}, // latin capital letter O with tilde,
- // U+00D5 ISOlat1
- {"214", "Ouml", "{{\\\"{O}}}"}, // latin capital letter O with diaeresis,
- // U+00D6 ISOlat1
- {"215", "times", "$\\times$"}, // multiplication sign, U+00D7 ISOnum
- {"216", "Oslash", "{{\\O}}"}, // latin capital letter O with stroke
- // = latin capital letter O slash,
- // U+00D8 ISOlat1
- {"217", "Ugrave", "{{\\`{U}}}"}, // latin capital letter U with grave,
- // U+00D9 ISOlat1
- {"218", "Uacute", "{{\\'{U}}}"}, // latin capital letter U with acute,
- // U+00DA ISOlat1
- {"219", "Ucirc", "{{\\^{U}}}"}, // latin capital letter U with circumflex,
- // U+00DB ISOlat1
- {"220", "Uuml", "{{\\\"{U}}}"}, // latin capital letter U with diaeresis,
- // U+00DC ISOlat1
- {"221", "Yacute", "{{\\'{Y}}}"}, // latin capital letter Y with acute,
- // U+00DD ISOlat1
- {"222", "THORN", "{{\\TH}}"}, // latin capital letter THORN,
- // U+00DE ISOlat1
- {"223", "szlig", "{\\ss}"}, // latin small letter sharp s = ess-zed,
- // U+00DF ISOlat1
- {"224", "agrave", "{\\`{a}}"}, // latin small letter a with grave
- // = latin small letter a grave,
- // U+00E0 ISOlat1
- {"225", "aacute", "{\\'{a}}"}, // latin small letter a with acute,
- // U+00E1 ISOlat1
- {"226", "acirc", "{\\^{a}}"}, // latin small letter a with circumflex,
- // U+00E2 ISOlat1
- {"227", "atilde", "{\\~{a}}"}, // latin small letter a with tilde,
- // U+00E3 ISOlat1
- {"228", "auml", "{\\\"{a}}"}, // latin small letter a with diaeresis,
- // U+00E4 ISOlat1
- {"229", "aring", "{{\\aa}}"}, // latin small letter a with ring above
- // = latin small letter a ring,
- // U+00E5 ISOlat1
- {"230", "aelig", "{\\ae}"}, // latin small letter ae
- // = latin small ligature ae, U+00E6 ISOlat1
- {"231", "ccedil", "{\\c{c}}"}, // latin small letter c with cedilla,
- // U+00E7 ISOlat1
- {"232", "egrave", "{\\`{e}}"}, // latin small letter e with grave,
- // U+00E8 ISOlat1
- {"233", "eacute", "{\\'{e}}"}, // latin small letter e with acute,
- // U+00E9 ISOlat1
- {"234", "ecirc", "{\\^{e}}"}, // latin small letter e with circumflex,
- // U+00EA ISOlat1
- {"235", "euml", "{\\\"{e}}"}, // latin small letter e with diaeresis,
- // U+00EB ISOlat1
- {"236", "igrave", "{\\`{i}}"}, // latin small letter i with grave,
- // U+00EC ISOlat1
- {"237", "iacute", "{\\'{i}}"}, // latin small letter i with acute,
- // U+00ED ISOlat1
- {"238", "icirc", "{\\^{i}}"}, // latin small letter i with circumflex,
- // U+00EE ISOlat1
- {"239", "iuml", "{\\\"{i}}"}, // latin small letter i with diaeresis,
- // U+00EF ISOlat1
- {"240", "eth", "{\\dh}"}, // latin small letter eth, U+00F0 ISOlat1
- {"241", "ntilde", "{\\~{n}}"}, // latin small letter n with tilde,
- // U+00F1 ISOlat1
- {"242", "ograve", "{\\`{o}}"}, // latin small letter o with grave,
- // U+00F2 ISOlat1
- {"243", "oacute", "{\\'{o}}"}, // latin small letter o with acute,
- // U+00F3 ISOlat1
- {"244", "ocirc", "{\\^{o}}"}, // latin small letter o with circumflex,
- // U+00F4 ISOlat1
- {"245", "otilde", "{\\~{o}}"}, // latin small letter o with tilde,
- // U+00F5 ISOlat1
- {"246", "ouml", "{\\\"{o}}"}, // latin small letter o with diaeresis,
- // U+00F6 ISOlat1
- {"247", "divide", "$\\div$"}, // division sign, U+00F7 ISOnum
- {"248", "oslash", "{\\o}"}, // latin small letter o with stroke,
- // = latin small letter o slash,
- // U+00F8 ISOlat1
- {"249", "ugrave", "{\\`{u}}"}, // latin small letter u with grave,
- // U+00F9 ISOlat1
- {"250", "uacute", "{\\'{u}}"}, // latin small letter u with acute,
- // U+00FA ISOlat1
- {"251", "ucirc", "{\\^{u}}"}, // latin small letter u with circumflex,
- // U+00FB ISOlat1
- {"252", "uuml", "{\\\"{u}}"}, // latin small letter u with diaeresis,
- // U+00FC ISOlat1
- {"253", "yacute", "{\\'{y}}"}, // latin small letter y with acute,
- // U+00FD ISOlat1
- {"254", "thorn", "{\\th}"}, // latin small letter thorn,
- // U+00FE ISOlat1
- {"255", "yuml", "{\\\"{y}}"}, // latin small letter y with diaeresis,
- // U+00FF ISOlat1
-
- /* Greek */
- {"913", "Alpha", "{{$\\Alpha$}}"}, // greek capital letter alpha, U+0391
- {"914", "Beta", "{{$\\Beta$}}"}, // greek capital letter beta, U+0392
- {"915", "Gamma", "{{$\\Gamma$}}"}, // greek capital letter gamma,
- // U+0393 ISOgrk3
- {"916", "Delta", "{{$\\Delta$}}"}, // greek capital letter delta,
- // U+0394 ISOgrk3
- {"917", "Epsilon", "{{$\\Epsilon$}}"}, // greek capital letter epsilon, U+0395
- {"918", "Zeta", "{{$\\Zeta$}}"}, // greek capital letter zeta, U+0396
- {"919", "Eta", "{{$\\Eta$}}"}, // greek capital letter eta, U+0397
- {"920", "Theta", "{{$\\Theta$}}"}, // greek capital letter theta,
- // U+0398 ISOgrk3
- {"921", "Iota", "{{$\\Iota$}}"}, // greek capital letter iota, U+0399
- {"922", "Kappa", "{{$\\Kappa$}}"}, // greek capital letter kappa, U+039A
- {"923", "Lambda", "{{$\\Lambda$}}"}, // greek capital letter lambda,
- // U+039B ISOgrk3
- {"924", "Mu", "{{$\\Mu$}}"}, // greek capital letter mu, U+039C
- {"925", "Nu", "{{$\\Nu$}}"}, // greek capital letter nu, U+039D
- {"926", "Xi", "{{$\\Xi$}}"}, // greek capital letter xi, U+039E ISOgrk3
- {"927", "Omicron", "{{$\\Omicron$}}"}, // greek capital letter omicron, U+039F
- {"928", "Pi", "{{$\\Pi$}}"}, // greek capital letter pi, U+03A0 ISOgrk3
- {"929", "Rho", "{{$\\Rho$}}"}, // greek capital letter rho, U+03A1
- /* there is no Sigmaf, and no U+03A2 character either */
- {"931", "Sigma", "{{$\\Sigma$}}"}, // greek capital letter sigma,
- // U+03A3 ISOgrk3
- {"932", "Tau", "{{$\\Tau$}}"}, // greek capital letter tau, U+03A4
- {"933", "Upsilon", "{{$\\Upsilon$}}"}, // greek capital letter upsilon,
- // U+03A5 ISOgrk3
- {"934", "Phi", "{{$\\Phi$}}"}, // greek capital letter phi,
- // U+03A6 ISOgrk3
- {"935", "Chi", "{{$\\Chi$}}"}, // greek capital letter chi, U+03A7
- {"936", "Psi", "{{$\\Psi$}}"}, // greek capital letter psi,
- // U+03A8 ISOgrk3
- {"937", "Omega", "{{$\\Omega$}}"}, // greek capital letter omega,
- // U+03A9 ISOgrk3
-
- {"945", "alpha", "$\\alpha$"}, // greek small letter alpha,
- // U+03B1 ISOgrk3
- {"946", "beta", "$\\beta$"}, // greek small letter beta, U+03B2 ISOgrk3
- {"947", "gamma", "$\\gamma$"}, // greek small letter gamma,
- // U+03B3 ISOgrk3
- {"948", "delta", "$\\delta$"}, // greek small letter delta,
- // U+03B4 ISOgrk3
- {"949", "epsilon", "$\\epsilon$"}, // greek small letter epsilon,
- // U+03B5 ISOgrk3
- {"950", "zeta", "$\\zeta$"}, // greek small letter zeta, U+03B6 ISOgrk3
- {"951", "eta", "$\\eta$"}, // greek small letter eta, U+03B7 ISOgrk3
- {"952", "theta", "$\\theta$"}, // greek small letter theta,
- // U+03B8 ISOgrk3
- {"953", "iota", "$\\iota$"}, // greek small letter iota, U+03B9 ISOgrk3
- {"954", "kappa", "$\\kappa$"}, // greek small letter kappa,
- // U+03BA ISOgrk3
- {"955", "lambda", "$\\lambda$"}, // greek small letter lambda,
- // U+03BB ISOgrk3
- {"956", "mu", "$\\mu$"}, // greek small letter mu, U+03BC ISOgrk3
- {"957", "nu", "$\\nu$"}, // greek small letter nu, U+03BD ISOgrk3
- {"958", "xi", "$\\xi$"}, // greek small letter xi, U+03BE ISOgrk3
- {"959", "omicron", "$\\omicron$"}, // greek small letter omicron, U+03BF NEW
- {"960", "pi", "$\\phi$"}, // greek small letter pi, U+03C0 ISOgrk3
- {"961", "rho", "$\\rho$"}, // greek small letter rho, U+03C1 ISOgrk3
- {"962", "sigmaf", "$\\varsigma$"}, // greek small letter final sigma,
- // U+03C2 ISOgrk3
- {"963", "sigma", "$\\sigma$"}, // greek small letter sigma,
- // U+03C3 ISOgrk3
- {"964", "tau", "$\\tau$"}, // greek small letter tau, U+03C4 ISOgrk3
- {"965", "upsilon", "$\\upsilon$"}, // greek small letter upsilon,
- {"", "upsi", "$\\upsilon$"}, // alias
- // U+03C5 ISOgrk3
- {"966", "phi", "$\\phi$"}, // greek small letter phi, U+03C6 ISOgrk3
- {"967", "chi", "$\\chi$"}, // greek small letter chi, U+03C7 ISOgrk3
- {"968", "psi", "$\\psi$"}, // greek small letter psi, U+03C8 ISOgrk3
- {"969", "omega", "$\\omega$"}, // greek small letter omega,
- // U+03C9 ISOgrk3
- {"977", "thetasym", "$\\vartheta$"}, // greek small letter theta symbol,
- {"", "thetav", "$\\vartheta$"}, // greek small letter theta symbol,
- {"", "vartheta", "$\\vartheta$"}, // greek small letter theta symbol,
- // U+03D1 NEW
- {"978", "upsih", "{{$\\Upsilon$}}"}, // greek upsilon with hook symbol,
- // U+03D2 NEW
- {"982", "piv", "$\\varphi$"}, // greek pi symbol, U+03D6 ISOgrk3
-
- /* General Punctuation */
- {"8226", "bull", "$\\bullet$"}, // bullet = black small circle,
- // U+2022 ISOpub
- /* bullet is NOT the same as bullet operator, U+2219 */
- {"8230", "hellip", "{\\ldots}"}, // horizontal ellipsis = three dot leader,
- // U+2026 ISOpub
- {"8242", "prime", "$\\prime$"}, // prime = minutes = feet, U+2032 ISOtech
- {"8243", "Prime", "$\\prime\\prime$"}, // double prime = seconds = inches,
- // U+2033 ISOtech
- {"8254", "oline", "{\\={}}"}, // overline = spacing overscore,
- // U+203E NEW
- {"8260", "frasl", "/"}, // fraction slash, U+2044 NEW
-
- /* Letterlike Symbols */
- {"8472", "weierp", "$\\wp$"}, // script capital P = power set
- // = Weierstrass p, U+2118 ISOamso
- {"8465", "image", "{{$\\Im$}}"}, // blackletter capital I = imaginary part,
- // U+2111 ISOamso
- {"8476", "real", "{{$\\Re$}}"}, // blackletter capital R = real part symbol,
- // U+211C ISOamso
- {"8482", "trade", "{\\texttrademark}"}, // trade mark sign, U+2122 ISOnum
- {"8501", "alefsym", "$\\aleph$"}, // alef symbol = first transfinite cardinal,
- // U+2135 NEW
- /* alef symbol is NOT the same as hebrew letter alef,
- U+05D0 although the same glyph could be used to depict both characters */
- /* Arrows */
- {"8592", "larr", "$\\leftarrow$"}, // leftwards arrow, U+2190 ISOnum
- {"8593", "uarr", "$\\uparrow$"}, // upwards arrow, U+2191 ISOnum
- {"8594", "rarr", "$\\rightarrow$"}, // rightwards arrow, U+2192 ISOnum
- {"8595", "darr", "$\\downarrow$"}, // downwards arrow, U+2193 ISOnum
- {"8596", "harr", "$\\leftrightarrow$"}, // left right arrow, U+2194 ISOamsa
- {"8629", "crarr", "$\\dlsh$"}, // downwards arrow with corner leftwards
- // = carriage return, U+21B5 NEW - require mathabx
- {"8656", "lArr", "{{$\\Leftarrow$}}"}, // leftwards double arrow, U+21D0 ISOtech
- /* ISO 10646 does not say that lArr is the same as the 'is implied by' arrow
- but also does not have any other character for that function. So ? lArr can
- be used for 'is implied by' as ISOtech suggests */
- {"8657", "uArr", "{{$\\Uparrow$}}"}, // upwards double arrow, U+21D1 ISOamsa
- {"8658", "rArr", "{{$\\Rightarrow$}}"}, // rightwards double arrow,
- // U+21D2 ISOtech
- /* ISO 10646 does not say this is the 'implies' character but does not have
- another character with this function so ?
- rArr can be used for 'implies' as ISOtech suggests */
- {"8659", "dArr", "{{$\\Downarrow$}}"}, // downwards double arrow, U+21D3 ISOamsa
- {"8660", "hArr", "{{$\\Leftrightarrow$}}"}, // left right double arrow,
- // U+21D4 ISOamsa
-
- /* Mathematical Operators */
- {"8704", "forall", "$\\forall$"}, // for all, U+2200 ISOtech
- {"8706", "part", "$\\partial$"}, // partial differential, U+2202 ISOtech
- {"8707", "exist", "$\\exists$"}, // there exists, U+2203 ISOtech
- {"8709", "empty", "$\\emptyset$"}, // empty set = null set = diameter,
- // U+2205 ISOamso
- {"8711", "nabla", "$\\nabla$"}, // nabla = backward difference,
- // U+2207 ISOtech
- {"8712", "isin", "$\\in$"}, // element of, U+2208 ISOtech
- {"8713", "notin", "$\\notin$"}, // not an element of, U+2209 ISOtech
- {"8715", "ni", "$\\ni$"}, // contains as member, U+220B ISOtech
- /* should there be a more memorable name than 'ni'? */
- {"8719", "prod", "$\\prod$"}, // n-ary product = product sign,
- // U+220F ISOamsb
- /* prod is NOT the same character as U+03A0 'greek capital letter pi' though
- the same glyph might be used for both */
- {"8721", "sum", "$\\sum$"}, // n-ary sumation, U+2211 ISOamsb
- /* sum is NOT the same character as U+03A3 'greek capital letter sigma'
- though the same glyph might be used for both */
- {"8722", "minus", "$-$"}, // minus sign, U+2212 ISOtech
- {"8727", "lowast", "$\\ast$"}, // asterisk operator, U+2217 ISOtech
- {"8730", "radic", "$\\sqrt{}$"}, // square root = radical sign,
- // U+221A ISOtech
- {"8733", "prop", "$\\propto$"}, // proportional to, U+221D ISOtech
- {"8734", "infin", "$\\infty$"}, // infinity, U+221E ISOtech
- {"8736", "ang", "$\\angle$"}, // angle, U+2220 ISOamso
- {"8743", "and", "$\\land$"}, // logical and = wedge, U+2227 ISOtech
- {"8744", "or", "$\\lor$"}, // logical or = vee, U+2228 ISOtech
- {"8745", "cap", "$\\cap$"}, // intersection = cap, U+2229 ISOtech
- {"8746", "cup", "$\\cup$"}, // union = cup, U+222A ISOtech
- {"8747", "int", "$\\int$"}, // integral, U+222B ISOtech
- {"8756", "there4", "$\\therefore$"}, // therefore, U+2234 ISOtech; AMSSymb
- {"8764", "sim", "$\\sim$"}, // tilde operator = varies with = similar to,
- // U+223C ISOtech
- /* tilde operator is NOT the same character as the tilde, U+007E,
- although the same glyph might be used to represent both */
- {"8773", "cong", "$\\cong$"}, // approximately equal to, U+2245 ISOtech
- {"8776", "asymp", "$\\approx$"}, // almost equal to = asymptotic to,
- // U+2248 ISOamsr
- {"8800", "ne", "$\\neq$"}, // not equal to, U+2260 ISOtech
- {"8801", "equiv", "$\\equiv$"}, // identical to, U+2261 ISOtech
- {"8804", "le", "$\\leq$"}, // less-than or equal to, U+2264 ISOtech
- {"8805", "ge", "$\\geq$"}, // greater-than or equal to,
- // U+2265 ISOtech
- {"8834", "sub", "$\\subset$"}, // subset of, U+2282 ISOtech
- {"8835", "sup", "$\\supset$"}, // superset of, U+2283 ISOtech
- /* note that nsup, 'not a superset of, U+2283' is not covered by the Symbol
- font encoding and is not included. Should it be, for symmetry?
- It is in ISOamsn */
- {"8836", "nsub", "$\\not\\subset$"}, // not a subset of, U+2284 ISOamsn
- {"8838", "sube", "$\\subseteq$"}, // subset of or equal to, U+2286 ISOtech
- {"8839", "supe", "$\\supseteq$"}, // superset of or equal to,
- // U+2287 ISOtech
- {"8853", "oplus", "$\\oplus$"}, // circled plus = direct sum,
- // U+2295 ISOamsb
- {"8855", "otimes", "$\\otimes$"}, // circled times = vector product,
- // U+2297 ISOamsb
- {"8869", "perp", "$\\perp$"}, // up tack = orthogonal to = perpendicular,
- // U+22A5 ISOtech
- {"8901", "sdot", "$\\cdot$"}, // dot operator, U+22C5 ISOamsb
- /* dot operator is NOT the same character as U+00B7 middle dot */
- {"8968", "lceil", "$\\lceil$"}, // left ceiling = apl upstile,
- // U+2308 ISOamsc
- {"8969", "rceil", "$\\rceil$"}, // right ceiling, U+2309 ISOamsc
- {"8970", "lfloor", "$\\lfloor$"}, // left floor = apl downstile,
- // U+230A ISOamsc
- {"8971", "rfloor", "$\\rfloor$"}, // right floor, U+230B ISOamsc
-
- /* Miscellaneous Technical */
- {"9001", "lang", "$\\langle$"}, // left-pointing angle bracket = bra,
- // U+2329 ISOtech
- /* lang is NOT the same character as U+003C 'less than'
- or U+2039 'single left-pointing angle quotation mark' */
- {"9002", "rang", "$\\rangle$"}, // right-pointing angle bracket = ket,
- // U+232A ISOtech
- /* rang is NOT the same character as U+003E 'greater than'
- or U+203A 'single right-pointing angle quotation mark' */
- /* Geometric Shapes */
- {"9674", "loz", "$\\lozenge$"}, // lozenge, U+25CA ISOpub
-
- /* Miscellaneous Symbols */
- {"9824", "spades", "$\\spadesuit$"}, // black spade suit, U+2660 ISOpub
- /* black here seems to mean filled as opposed to hollow */
- {"9827", "clubs", "$\\clubsuit$"}, // black club suit = shamrock,
- // U+2663 ISOpub
- {"9829", "hearts", "$\\heartsuit$"}, // black heart suit = valentine,
- // U+2665 ISOpub
- {"9830", "diams", "$\\diamondsuit$"}, // black diamond suit, U+2666 ISOpub
- {"34", "quot", "\""}, // quotation mark = APL quote,
- // U+0022 ISOnum
- {"38", "amp", "\\&"}, // ampersand, U+0026 ISOnum
- {"60", "lt", "$<$"}, // less-than sign, U+003C ISOnum
- {"62", "gt", "$>$"}, // greater-than sign, U+003E ISOnum
-
-
- /* General Punctuation */
- {"8194", "ensp", "\\hspace{0.5em}"}, // en space, U+2002 ISOpub
- {"8195", "emsp", "\\hspace{1em}"}, // em space, U+2003 ISOpub
- {"8201", "thinsp", "\\hspace{0.167em}"}, // thin space, U+2009 ISOpub
- {"8202", "", "\\hspace{0.1em}"}, // hair space, U+2010 ISOpub
- {"8204", "zwnj", "\\/{}"}, // zero width non-joiner,
- // U+200C NEW RFC 2070
- {"8205", "zwj", ""}, // zero width joiner, U+200D NEW RFC 2070
- {"8206", "lrm", ""}, // left-to-right mark, U+200E NEW RFC 2070
- {"8207", "rlm", ""}, // right-to-left mark, U+200F NEW RFC 2070
- {"8211", "ndash", "--"}, // en dash, U+2013 ISOpub
- {"8212", "mdash", "---"}, // em dash, U+2014 ISOpub
- {"8216", "lsquo", "{\\textquoteleft}"}, // left single quotation mark,
- // U+2018 ISOnum
- {"8217", "rsquo", "{\\textquoteright}"}, // right single quotation mark,
- // U+2019 ISOnum
- {"8218", "sbquo", "{\\quotesinglbase}"}, // single low-9 quotation mark, U+201A NEW
- {"8220", "ldquo", "{\\textquotedblleft}"}, // left double quotation mark,
- // U+201C ISOnum
- {"8221", "rdquo", "{\\textquotedblright}"}, // right double quotation mark,
- // U+201D ISOnum
- {"8222", "bdquo", "{\\quotedblbase}"}, // double low-9 quotation mark, U+201E NEW
- {"8224", "dagger", "{\\dag}"}, // dagger, U+2020 ISOpub
- {"8225", "Dagger", "{\\ddag}"}, // double dagger, U+2021 ISOpub
- {"8240", "permil", "{\\textperthousand}"}, // per mille sign, U+2030 ISOtech
- {"8249", "lsaquo", "{\\guilsinglleft}"}, // single left-pointing angle quotation mark,
- // U+2039 ISO proposed
- /* lsaquo is proposed but not yet ISO standardized */
- {"8250", "rsaquo", "{\\guilsinglright}"}, // single right-pointing angle quotation mark,
- // U+203A ISO proposed
- /* rsaquo is proposed but not yet ISO standardized */
- {"8364", "euro", "{\\texteuro}"}, // euro sign, U+20AC NEW
-
- /* Manually added */
- {"35", "", "\\#"}, // Hash
- {"36", "dollar", "\\$"}, // Dollar
- {"37", "percnt", "\\%"}, // Percent
- {"39", "apos", "'"}, // Apostrophe
- {"40", "lpar", "("}, // Left bracket
- {"41", "rpar", ")"}, // Right bracket
- {"42", "", "*"}, // Asterisk
- {"43", "plus", "+"}, // Plus
- {"44", "comma", ","}, // Comma
- {"45", "hyphen", "-"}, // Hyphen
- {"46", "period", "."}, // Period
- {"47", "slash", "/"}, // Slash (solidus)
- {"58", "colon", ":"}, // Colon
- {"59", "semi", ";"}, // Semi colon
- {"61", "equals", "="}, // Equals to
- {"91", "lsqb", "["}, // Left square bracket
- {"92", "bsol", "{\\textbackslash}"}, // Backslash
- {"93", "rsqb", "]"}, // Right square bracket
- {"94", "Hat", "{\\^{}}"}, // Circumflex
- {"95", "lowbar", "\\_"}, // Underscore
- {"96", "grave", "{\\`{}}"}, // Grave
- {"123", "lbrace", "\\{"}, // Left curly bracket
- {"", "lcub", "\\{"}, // Left curly bracket
- {"124", "vert", "|"}, // Vertical bar
- {"", "verbar", "|"}, // Vertical bar
- {"", "VerticalLine", "|"}, // Vertical bar
- {"125", "rbrace", "\\}"}, // Right curly bracket
- {"", "rcub", "\\}"}, // Right curly bracket
- // {"138", "", "{{\\v{S}}}"}, // Line tabulation set
- // {"141", "", ""}, // Reverse line feed
- {"145", "", "`"}, // Apostrophe
- {"146", "", "'"}, // Apostrophe
- {"147", "", "``"}, // Quotation mark
- {"148", "", "''"}, // Quotation mark
- {"150", "", "--"}, // En dash
- // {"154", "", "{\\v{s}}"}, // Single character introducer
- {"256", "", "{{\\={A}}}"}, // capital A with macron
- {"257", "", "{\\={a}}"}, // small a with macron
- {"258", "", "{{\\u{A}}}"}, // capital A with breve
- {"259", "", "{\\u{a}}"}, // small a with breve
- {"260", "Aogon", "{{\\k{A}}}"}, // capital A with ogonek
- {"261", "aogon", "{\\k{a}}"}, // small a with ogonek
- {"262", "Cacute", "{{\\'{C}}}"}, // capital C with acute
- {"263", "cacute", "{\\'{c}}"}, // small C with acute
- {"264", "Ccirc", "{{\\^{C}}}"}, // capital C with circumflex
- {"265", "ccirc", "{\\^{c}}"}, // small C with circumflex
- {"266", "Cdot", "{{\\.{C}}}"}, // capital C with dot above
- {"267", "cdot", "{\\.{c}}"}, // small C with dot above
- {"268", "Ccaron", "{{\\v{C}}}"}, // capital C with caron
- {"269", "ccaron", "{\\v{c}}"}, // small C with caron
- {"270", "", "{{\\v{D}}}"}, // capital D with caron
- {"271", "", "{\\v{d}}"}, // small d with caron
- {"272", "Dstrok", "{{\\DJ}}"}, // capital D with stroke
- {"273", "dstrok", "{{\\dj}}"}, // small d with stroke
- {"274", "", "{{\\={E}}}"}, // capital E with macron
- {"275", "", "{\\={e}}"}, // small e with macron
- {"276", "", "{{\\u{E}}}"}, // capital E with breve
- {"277", "", "{\\u{e}}"}, // small e with breve
- {"278", "", "{{\\.{E}}}"}, // capital E with dot above
- {"279", "", "{\\.{e}}"}, // small e with dot above
- {"280", "Eogon", "{{\\k{E}}}"}, // capital E with ogonek
- {"281", "eogon", "{\\k{e}}"}, // small e with ogonek
- {"282", "", "{{\\v{E}}}"}, // capital E with caron
- {"283", "", "{\\v{e}}"}, // small e with caron
- {"284", "", "{{\\^{G}}}"}, // capital G with circumflex
- {"285", "", "{\\^{g}}"}, // small g with circumflex
- {"286", "", "{{\\u{G}}}"}, // capital G with breve
- {"287", "", "{\\u{g}}"}, // small g with breve
- {"288", "", "{{\\.{G}}}"}, // capital G with dot above
- {"289", "", "{\\.{g}}"}, // small g with dot above
- {"290", "", "{{\\c{G}}}"}, // capital G with cedilla
- {"291", "", "{\\c{g}}"}, // small g with cedilla
- {"292", "", "{{\\^{H}}}"}, // capital H with circumflex
- {"293", "", "{\\^{h}}"}, // small h with circumflex
- {"294", "", "{{\\B{H}}}"}, // capital H with stroke
- {"295", "", "{\\B{h}}"}, // small h with stroke
- {"296", "", "{{\\~{I}}}"}, // capital I with tilde
- {"297", "", "{\\~{\\i}}"}, // small i with tilde
- {"298", "Imacr", "{{\\={I}}}"}, // capital I with macron
- {"299", "imacr", "{\\={\\i}}"}, // small i with macron
- {"300", "", "{{\\u{I}}}"}, // capital I with breve
- {"301", "", "{\\u{\\i}}"}, // small i with breve
- {"302", "Iogon", "{{\\k{I}}}"}, // capital I with ogonek
- {"303", "iogon", "{\\k{i}}"}, // small i with ogonek
- {"304", "Idot", "{{\\.{I}}}"}, // capital I with dot above
- {"305", "inodot", "{\\i}"}, // Small i without the dot
- {"", "imath", "{\\i}"}, // Small i without the dot
- {"306", "", "{{\\IJ}}"}, // Dutch di-graph IJ
- {"307", "", "{{\\ij}}"}, // Dutch di-graph ij
- {"308", "", "{{\\^{J}}}"}, // capital J with circumflex
- {"309", "", "{\\^{\\j}}"}, // small j with circumflex
- {"310", "", "{{\\c{K}}}"}, // capital K with cedilla
- {"311", "", "{\\c{k}}"}, // small k with cedilla
- {"312", "", "{\\textkra}"}, // Letter kra
- {"313", "", "{{\\'{L}}}"}, // capital L with acute
- {"314", "", "{\\'{l}}"}, // small l with acute
- {"315", "", "{{\\c{L}}}"}, // capital L with cedilla
- {"316", "", "{\\c{l}}"}, // small l with cedilla
- {"317", "", "{{\\v{L}}}"}, // capital L with caron
- {"318", "", "{\\v{l}}"}, // small l with caron
- //{"319", "Lmidot", "{\\Lmidot}"}, // upper case L with mid dot
- //{"320", "lmidot", "{\\lmidot}"}, // lower case l with mid dot
- {"321", "Lstrok", "{{\\L}}"}, // upper case L with stroke
- {"322", "lstrok", "{{\\l}}"}, // lower case l with stroke
- {"323", "Nacute", "{{\\'{N}}}"}, // upper case N with acute
- {"324", "nacute", "{{\\'{n}}}"}, // lower case n with acute
- {"325", "", "{{\\c{N}}}"}, // capital N with cedilla
- {"326", "", "{\\c{n}}"}, // small n with cedilla
- {"327", "", "{{\\v{N}}}"}, // capital N with caron
- {"328", "", "{\\v{n}}"}, // small n with caron
- {"329", "", "{'n}"}, // small n preceded with apostroph
- {"330", "", "{{\\NG}}"}, // upper case letter Eng
- {"331", "", "{{\\ng}}"}, // lower case letter Eng
- {"332", "Omacro", "{{\\={O}}}"}, // the capital letter O with macron
- {"333", "omacro", "{\\={o}}"}, // the small letter o with macron
- {"334", "", "{{\\u{O}}}"}, // the capital letter O with breve
- {"335", "", "{\\u{o}}"}, // the small letter o with breve
- {"336", "", "{{\\H{O}}}"}, // the capital letter O with double acute
- {"337", "", "{\\H{o}}"}, // the small letter o with double acute
- {"338", "OElig", "{{\\OE}}"}, // OE-ligature
- {"339", "oelig", "{{\\oe}}"}, // oe-ligature
- {"340", "", "{{\\'{R}}}"}, // upper case R with acute
- {"341", "", "{{\\'{r}}}"}, // lower case r with acute
- {"342", "", "{{\\c{R}}}"}, // upper case R with cedilla
- {"343", "", "{{\\c{r}}}"}, // lower case r with cedilla
- {"344", "", "{{\\v{R}}}"}, // upper case R with caron
- {"345", "", "{{\\v{r}}}"}, // lower case r with caron
- {"346", "", "{{\\'{S}}}"}, // upper case S with acute
- {"347", "", "{{\\'{s}}}"}, // lower case s with acute
- {"348", "Scirc", "{{\\^{S}}}"}, // upper case S with circumflex
- {"349", "scirc", "{\\^{s}}"}, // lower case s with circumflex
- {"350", "Scedil", "{{\\c{S}}}"}, // upper case S with cedilla
- {"351", "scedil", "{\\c{s}}"}, // lower case s with cedilla
- {"352", "Scaron", "{{\\v{S}}}"}, // latin capital letter S with caron,
- {"353", "scaron", "{\\v{s}}"}, // latin small letter s with caron,
- {"354", "", "{{\\c{T}}}"}, // upper case T with cedilla
- {"355", "", "{{\\c{T}}}"}, // lower case t with cedilla
- {"356", "", "{{\\v{T}}}"}, // latin capital letter T with caron,
- {"357", "", "{\\v{t}}"}, // latin small letter t with caron,
- {"358", "", "{{\\B{T}}}"}, // latin capital letter T with stroke,
- {"359", "", "{\\B{t}}"}, // latin small letter t with stroke,
- {"360", "", "{{\\~{U}}}"}, // capital U with tilde
- {"361", "", "{\\~{u}}"}, // small u with tilde
- {"362", "", "{{\\={U}}}"}, // capital U with macron
- {"363", "", "{\\={u}}"}, // small u with macron
- {"364", "", "{{\\u{U}}}"}, // capital U with breve
- {"365", "", "{\\u{u}}"}, // small u with breve
- {"366", "", "{{\\r{U}}}"}, // capital U with ring
- {"367", "", "{\\r{u}}"}, // small u with ring
- {"368", "", "{{\\={U}}}"}, // capital U with double acute
- {"369", "", "{\\={u}}"}, // small u with double acute
- {"370", "Uogon", "{{\\k{U}}}"}, // capital U with ogonek
- {"371", "uogon", "{\\k{u}}"}, // small u with ogonek
- {"372", "", "{{\\^{W}}}"}, // capital W with circumflex
- {"373", "", "{\\^{w}}"}, // small w with circumflex
- {"374", "", "{{\\^{Y}}}"}, // capital Y with circumflex
- {"375", "", "{\\^{y}}"}, // small y with circumflex
- {"376", "Yuml", "{{\\\"{Y}}}"}, // latin capital letter Y with diaeresis,
- {"377", "", "{{\\'{Z}}}"}, // capital Z with acute
- {"378", "", "{\\'{z}}"}, // small z with acute
- {"379", "", "{{\\.{Z}}}"}, // capital Z with dot above
- {"380", "", "{\\.{z}}"}, // small z with dot above
- {"381", "Zcaron", "{{\\v{Z}}}"}, // capital Z with caron
- {"382", "zcaron", "{\\v{z}}"}, // small z with caron
- // {"383", "", ""}, // long s
- {"384", "", "{\\B{b}}"}, // small b with stroke
-
- {"402", "fnof", "\\textit{f}"}, // latin small f with hook = function
-
- {"405", "", "{{\\hv}}"}, // small letter Hv
-
- {"416", "", "{{\\OHORN}}"}, // capital O with horn
- {"417", "", "{{\\ohorn}}"}, // small o with horn
-
- {"431", "", "{{\\UHORN}}"}, // capital U with horn
- {"432", "", "{{\\uhorn}}"}, // small u with horn
-
- {"490", "Oogon", "{{\\k{O}}}"}, // capital letter O with ogonek
- {"491", "oogon", "{\\k{o}}"}, // small letter o with ogonek
- {"492", "", "{{\\k{\\={O}}}}"}, // capital letter O with ogonek and macron
- {"493", "", "{\\k{\\={o}}}"}, // small letter o with ogonek and macron
-
- {"536", "", "{{\\cb{S}}}"}, // capital letter S with comma below, require combelow
- {"537", "", "{\\cb{s}}"}, // small letter S with comma below, require combelow
- {"538", "", "{{\\cb{T}}}"}, // capital letter T with comma below, require combelow
- {"539", "", "{\\cb{t}}"}, // small letter T with comma below, require combelow
- {"710", "circ", "{\\^{}}"}, // modifier letter circumflex accent,
- {"726", "", "+"}, // Modifier plus sign
- {"727", "", "-"}, // Modifier minus sign
- {"728", "breve", "{\\u{}}"}, // Breve
- {"", "Breve", "{\\u{}}"}, // Breve
- {"729", "dot", "{\\.{}}"}, // Dot above
- {"730", "ring", "{\\r{}}"}, // Ring above
- {"731", "ogon", "{\\k{}}"}, // Ogonek
- {"732", "tilde", "\\~{}"}, // Small tilde
- {"733", "dblac", "{{\\H{}}}"}, // Double acute
- {"949", "epsi", "$\\epsilon$"}, // Epsilon - double check
- {"1013", "epsiv", "$\\varepsilonup$"}, // lunate epsilon, requires txfonts
- //{"1055", "", "{{\\cyrchar\\CYRP}}"}, // Cyrillic capital Pe
- //{"1082", "", "{\\cyrchar\\cyrk}"}, // Cyrillic small Ka
- // {"2013", "", ""}, // NKO letter FA -- Maybe en dash = 0x2013?
- // {"2014", "", ""}, // NKO letter FA -- Maybe em dash = 0x2014?
- {"8192", "", "\\hspace{0.5em}"}, // en quad
- {"8193", "", "\\hspace{1em}"}, // em quad
- {"8196", "", "\\hspace{0.333em}"}, // Three-Per-Em Space
- {"8197", "", "\\hspace{0.25em}"}, // Four-Per-Em Space
- {"8198", "", "\\hspace{0.167em}"}, // Six-Per-Em Space
- {"8208", "hyphen", "-"}, // Hyphen
- {"8229", "nldr", "\\.{}\\.{}"}, // Double dots - en leader
- {"8241", "", "{\\textpertenthousand}"}, // per ten thousands sign
- {"8244", "", "{$\\prime\\prime\\prime$}"}, // triple prime
- {"8251", "", "{\\textreferencemark}"}, {"8253", "", "{\\textinterrobang}"},
- {"8320", "", "$_{0}$"}, // sub-script 0
- {"8321", "", "$_{1}$"}, // sub-script 1
- {"8322", "", "$_{2}$"}, // sub-script 2
- {"8323", "", "$_{3}$"}, // sub-script 3
- {"8324", "", "$_{4}$"}, // sub-script 4
- {"8325", "", "$_{5}$"}, // sub-script 5
- {"8326", "", "$_{6}$"}, // sub-script 6
- {"8327", "", "$_{7}$"}, // sub-script 7
- {"8328", "", "$_{8}$"}, // sub-script 8
- {"8329", "", "$_{9}$"}, // sub-script 9
- {"8330", "", "$_{+}$"}, // sub-script +
- {"8331", "", "$_{-}$"}, // sub-script -
- {"8332", "", "$_{-}$"}, // sub-script =
- {"8333", "", "$_{(}$"}, // sub-script (
- {"8334", "", "$_{)}$"}, // sub-script )
- {"8450", "complexes", "$\\mathbb{C}$"}, // double struck capital C -- requires e.g. amsfonts
- {"8451", "", "{\\textcelsius}"}, // Degree Celsius
- {"8459", "Hscr", "{{$\\mathcal{H}$}}"}, // script capital H -- possibly use \mathscr
- {"8460", "Hfr", "{{$\\mathbb{H}$}}"}, // black letter capital H -- requires e.g. amsfonts
- {"8466", "Lscr", "{{$\\mathcal{L}$}}"}, // script capital L -- possibly use \mathscr
- {"8467", "ell", "{$\\ell$}"}, // script small l
- {"8469", "naturals", "{{$\\mathbb{N}$}}"}, // double struck capital N -- requires e.g. amsfonts
- {"8474", "Qopf", "{{$\\mathbb{Q}$}}"}, // double struck capital Q -- requires e.g. amsfonts
- {"8477", "reals", "{{$\\mathbb{R}$}}"}, // double struck capital R -- requires e.g. amsfonts
- {"8486", "", "${{\\Omega}}$"}, // Omega
- {"8491", "angst", "{{\\AA}}"}, // Angstrom
- {"8496", "Escr", "{{$\\mathcal{E}$}}"}, // script capital E
- {"8531", "frac13", "$\\sfrac{1}{3}$"}, // Vulgar fraction one third
- {"8532", "frac23", "$\\sfrac{2}{3}$"}, // Vulgar fraction two thirds
- {"8533", "frac15", "$\\sfrac{1}{5}$"}, // Vulgar fraction one fifth
- {"8534", "frac25", "$\\sfrac{2}{5}$"}, // Vulgar fraction two fifths
- {"8535", "frac35", "$\\sfrac{3}{5}$"}, // Vulgar fraction three fifths
- {"8536", "frac45", "$\\sfrac{4}{5}$"}, // Vulgar fraction four fifths
- {"8537", "frac16", "$\\sfrac{1}{6}$"}, // Vulgar fraction one sixth
- {"8538", "frac56", "$\\sfrac{5}{6}$"}, // Vulgar fraction five sixths
- {"8539", "frac18", "$\\sfrac{1}{8}$"}, // Vulgar fraction one eighth
- {"8540", "frac38", "$\\sfrac{3}{8}$"}, // Vulgar fraction three eighths
- {"8541", "frac58", "$\\sfrac{5}{8}$"}, // Vulgar fraction five eighths
- {"8542", "frac78", "$\\sfrac{7}{8}$"}, // Vulgar fraction seven eighths
- {"8710", "", "$\\triangle$"}, // Increment - could use a more appropriate symbol
- {"8714", "", "$\\in$"}, // Small element in
- {"8723", "mp", "$\\mp$"}, // Minus-plus
- {"8729", "bullet", "$\\bullet$"}, // Bullet operator
- {"8741", "", "$\\parallel$"}, // Parallel to
- {"8758", "ratio", ":"}, // Colon/ratio
- {"8771", "sime", "$\\simeq$"}, // almost equal to = asymptotic to,
- {"8776", "ap", "$\\approx$"}, // almost equal to = asymptotic to,
- {"8810", "ll", "$\\ll$"}, // Much less than
- {"", "Lt", "$\\ll$"}, // Much less than
- {"8811", "gg", "$\\gg$"}, // Much greater than
- {"", "Gt", "$\\gg$"}, // Much greater than
- {"8818", "lsim", "$\\lesssim$"}, // Less than or equivalent to
- {"8819", "gsim", "$\\gtrsim$"}, // Greater than or equivalent to
- {"8862", "boxplus", "$\\boxplus$"}, // Boxed plus -- requires amssymb
- {"8863", "boxminus", "$\\boxminus$"}, // Boxed minus -- requires amssymb
- {"8864", "boxtimes", "$\\boxtimes$"}, // Boxed times -- requires amssymb
- {"8882", "vltri", "$\\triangleleft$"}, // Left triangle
- {"8883", "vrtri", "$\\triangleright$"}, // Right triangle
- {"8896", "xwedge", "$\\bigwedge$"}, // Big wedge
- {"8897", "xvee", "$\\bigvee$"}, // Big vee
- {"8942", "vdots", "$\\vdots$"}, // vertical ellipsis U+22EE
- {"8943", "cdots", "$\\cdots$"}, // midline horizontal ellipsis U+22EF
- /*{"8944", "", "$\\ddots$"}, // up right diagonal ellipsis U+22F0 */
- {"8945", "ddots", "$\\ddots$"}, // down right diagonal ellipsis U+22F1
-
- {"9426", "circledc", "{\\copyright}"}, // circled small letter C
- {"9633", "square", "$\\square$"}, // White square
- {"9651", "xutri", "$\\bigtriangleup$"}, // White up-pointing big triangle
- {"9653", "utri", "$\\triangle$"}, // White up-pointing small triangle -- \vartriangle probably
- // better but requires amssymb
- {"10877", "les", "$\\leqslant$"}, // Less than slanted equal -- requires amssymb
- {"10878", "ges", "$\\geqslant$"}, // Less than slanted equal -- requires amssymb
- {"64256", "", "ff"}, // ff ligature (which LaTeX solves by itself)
- {"64257", "", "fi"}, // fi ligature (which LaTeX solves by itself)
- {"64258", "", "fl"}, // fl ligature (which LaTeX solves by itself)
- {"64259", "", "ffi"}, // ffi ligature (which LaTeX solves by itself)
- {"64260", "", "ffl"}, // ffl ligature (which LaTeX solves by itself)
- {"119978", "Oscr", "$\\mathcal{O}$"}, // script capital O -- possibly use \mathscr
- {"119984", "Uscr", "$\\mathcal{U}$"} // script capital U -- possibly use \mathscr
-
- };
- // List of combining accents
- private static final String[][] ACCENT_LIST = new String[][] {{"768", "`"}, // Grave
- {"769", "'"}, // Acute
- {"770", "^"}, // Circumflex
- {"771", "~"}, // Tilde
- {"772", "="}, // Macron
- {"773", "="}, // Overline - not completely correct
- {"774", "u"}, // Breve
- {"775", "."}, // Dot above
- {"776", "\""}, // Diaeresis
- {"777", "h"}, // Hook above
- {"778", "r"}, // Ring
- {"779", "H"}, // Double acute
- {"780", "v"}, // Caron
- {"781", "|"}, // Vertical line above
- {"782", "U"}, // Double vertical line above
- {"783", "G"}, // Double grave
- {"784", "textdotbreve"}, // Candrabindu
- {"785", "t"}, // Inverted breve
- // {"786", ""}, // Turned comma above
- // {"787", ""}, // Comma above
- {"788", "textrevcommaabove"}, // Reversed comma above
- {"789", "textcommaabover"}, // Comma above right
- {"790", "textsubgrave"}, // Grave accent below -requires tipa
- {"791", "textsubacute"}, // Acute accent below - requires tipa
- {"792", "textadvancing"}, // Left tack below - requires tipa
- {"793", "textretracting"}, // Right tack below - requires tipa
- {"794", "textlangleabove"}, // Left angle above
- {"795", "textrighthorn"}, // Horn
- {"796", "textsublhalfring"}, // Left half ring below - requires tipa
- {"797", "textraising"}, // Up tack below - requires tipa
- {"798", "textlowering"}, // Down tack below - requires tipa
- {"799", "textsubplus"}, // Plus sign below - requires tipa
- {"800", "textsubbar"}, // Minus sign below
- {"801", "textpalhookbelow"}, // Palatalized hook below
- {"802", "M"}, // Retroflex hook below - textrethookbelow?
- {"803", "d"}, // Dot below
- {"804", "textsubumlaut"}, // Diaeresis below - requires tipa
- {"805", "textsubring"}, // Ring below - requires tipa
- {"806", "cb"}, // Comma below - requires combelow
- {"807", "c"}, // Cedilla
- {"808", "k"}, // Ogonek
- {"809", "textsyllabic"}, // Vertical line below - requires tipa
- {"810", "textsubbridge"}, // Bridge below - requires tipa
- {"811", "textsubw"}, // Inverted double arch below - requires tipa
- {"812", "textsubwedge"}, // Caron below
- {"813", "textsubcircum"}, // Circumflex accent below - requires tipa
- {"814", "textsubbreve"}, // Breve below
- {"815", "textsubarch"}, // Inverted breve below - requires tipa
- {"816", "textsubtilde"}, // Tilde below - requires tipa
- {"817", "b"}, // Macron below - not completely correct
- {"818", "b"}, // Underline
- {"819", "subdoublebar"}, // Double low line -- requires extraipa
- {"820", "textsuperimposetilde"}, // Tilde overlay - requires tipa
- {"821", "B"}, // Short stroke overlay - textsstrokethru?
- {"822", "textlstrokethru"}, // Long stroke overlay
- {"823", "textsstrikethru"}, // Short solidus overlay
- {"824", "textlstrikethru"}, // Long solidus overlay
- {"825", "textsubrhalfring"}, // Right half ring below - requires tipa
- {"826", "textinvsubbridge"}, // inverted bridge below - requires tipa
- {"827", "textsubsquare"}, // Square below - requires tipa
- {"828", "textseagull"}, // Seagull below - requires tipa
- {"829", "textovercross"}, // X above - requires tipa
- // {"830", ""}, // Vertical tilde
- // {"831", ""}, // Double overline
- // {"832", ""}, // Grave tone mark
- // {"833", ""}, // Acute tone mark
- // {"834", ""}, // Greek perispomeni
- // {"835", ""}, // Greek koronis
- // {"836", ""}, // Greek dialytika tonos
- // {"837", ""}, // Greek ypogegrammeni
- {"838", "overbridge"}, // Bridge above - requires extraipa
- {"839", "subdoublebar"}, // Equals sign below - requires extraipa
- {"840", "subdoublevert"}, // Double vertical line below - requires extraipa
- {"841", "subcorner"}, // Left angle below - requires extraipa
- {"842", "crtilde"}, // Not tilde above - requires extraipa
- {"843", "dottedtilde"}, // Homothetic above - requires extraipa
- {"844", "doubletilde"}, // Almost equal to above - requires extraipa
- {"845", "spreadlips"}, // Left right arrow below - requires extraipa
- {"846", "whistle"}, // Upwards arrow below - requires extraipa
- {"861", "textdoublebreve"}, // Double breve
- {"862", "textdoublemacron"}, // Double macron
- {"863", "textdoublemacronbelow"}, // Double macron below
- {"864", "textdoubletilde"}, // Double tilde
- {"865", "texttoptiebar"}, // Double inverted breve
- {"866", "sliding"}, // Double rightwards arrow below - requires extraipa
- };
-
- public static final Map<String, String> HTML_LATEX_CONVERSION_MAP = new HashMap<>();
- public static final Map<Integer, String> ESCAPED_ACCENTS = new HashMap<>();
- public static final Map<String, String> UNICODE_ESCAPED_ACCENTS = new HashMap<>();
- public static final Map<Integer, String> NUMERICAL_LATEX_CONVERSION_MAP = new HashMap<>();
- public static final Map<String, String> UNICODE_LATEX_CONVERSION_MAP = new HashMap<>();
- public static final Map<String, String> LATEX_HTML_CONVERSION_MAP = new HashMap<>();
- public static final Map<String, String> LATEX_UNICODE_CONVERSION_MAP = new HashMap<>();
-
-
- static {
- for (String[] aConversionList : CONVERSION_LIST) {
- if (!(aConversionList[2].isEmpty())) {
- String strippedLaTeX = cleanLaTeX(aConversionList[2]);
- if (!(aConversionList[1].isEmpty())) {
- HTML_LATEX_CONVERSION_MAP.put("&" + aConversionList[1] + ";", aConversionList[2]);
- if (!strippedLaTeX.isEmpty()) {
- LATEX_HTML_CONVERSION_MAP.put(strippedLaTeX, "&" + aConversionList[1] + ";");
- }
- } else if (!(aConversionList[0].isEmpty()) && !strippedLaTeX.isEmpty()) {
- LATEX_HTML_CONVERSION_MAP.put(strippedLaTeX, "&#" + aConversionList[0] + ";");
- }
- if (!(aConversionList[0].isEmpty())) {
- NUMERICAL_LATEX_CONVERSION_MAP.put(Integer.decode(aConversionList[0]), aConversionList[2]);
- if (Integer.decode(aConversionList[0]) > 128) {
- String unicodeSymbol = String.valueOf(Character.toChars(Integer.decode(aConversionList[0])));
- UNICODE_LATEX_CONVERSION_MAP.put(unicodeSymbol, aConversionList[2]);
- if (!strippedLaTeX.isEmpty()) {
- LATEX_UNICODE_CONVERSION_MAP.put(strippedLaTeX, unicodeSymbol);
- }
- }
- }
- }
- }
- for (String[] anAccentList : ACCENT_LIST) {
- ESCAPED_ACCENTS.put(Integer.decode(anAccentList[0]), anAccentList[1]);
- UNICODE_ESCAPED_ACCENTS.put(anAccentList[1],
- String.valueOf(Character.toChars(Integer.decode(anAccentList[0]))));
- }
- // Manually added values which are killed by cleanLaTeX
- LATEX_HTML_CONVERSION_MAP.put("$", "$");
- LATEX_UNICODE_CONVERSION_MAP.put("$", "$");
-
- // Manual corrections
- LATEX_HTML_CONVERSION_MAP.put("AA", "Å"); // Overwritten by Å which is less supported
- LATEX_UNICODE_CONVERSION_MAP.put("AA", "Å"); // Overwritten by Ångstrom symbol
-
- // Manual additions
- // Support relax to the extent that it is simply removed
- LATEX_HTML_CONVERSION_MAP.put("relax", "");
- LATEX_UNICODE_CONVERSION_MAP.put("relax", "");
-
- }
-
- private static String cleanLaTeX(String escapedString) {
- // Get rid of \{}$ from the LaTeX-string
- return escapedString.replaceAll("[\\\\\\{\\}\\$]", "");
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/logic/util/strings/RtfCharMap.java b/src/main/java/net/sf/jabref/logic/util/strings/RtfCharMap.java
index 2e26c9b..2f8bed5 100644
--- a/src/main/java/net/sf/jabref/logic/util/strings/RtfCharMap.java
+++ b/src/main/java/net/sf/jabref/logic/util/strings/RtfCharMap.java
@@ -2,18 +2,21 @@ package net.sf.jabref.logic.util.strings;
import java.util.HashMap;
-public class RtfCharMap extends HashMap<String, String> {
+public class RtfCharMap {
+
+ private HashMap<String, String> rtfMap = new HashMap<>();
+
public RtfCharMap () {
put("`a", "\\'e0");
put("`e", "\\'e8");
put("`i", "\\'ec");
put("`o", "\\'f2");
put("`u", "\\'f9");
- put("?a", "\\'e1");
- put("?e", "\\'e9");
- put("?i", "\\'ed");
- put("?o", "\\'f3");
- put("?u", "\\'fa");
+ put("'a", "\\'e1");
+ put("'e", "\\'e9");
+ put("'i", "\\'ed");
+ put("'o", "\\'f3");
+ put("'u", "\\'fa");
put("^a", "\\'e2");
put("^e", "\\'ea");
put("^i", "\\'ee");
@@ -30,11 +33,11 @@ public class RtfCharMap extends HashMap<String, String> {
put("`I", "\\'cc");
put("`O", "\\'d2");
put("`U", "\\'d9");
- put("?A", "\\'c1");
- put("?E", "\\'c9");
- put("?I", "\\'cd");
- put("?O", "\\'d3");
- put("?U", "\\'da");
+ put("'A", "\\'c1");
+ put("'E", "\\'c9");
+ put("'I", "\\'cd");
+ put("'O", "\\'d3");
+ put("'U", "\\'da");
put("^A", "\\'c2");
put("^E", "\\'ca");
put("^I", "\\'ce");
@@ -49,79 +52,58 @@ public class RtfCharMap extends HashMap<String, String> {
// Use UNICODE characters for RTF-Chars which can not be found in the
// standard codepage
- put("`A", "\\u192A"); // "Agrave"
- put("'A", "\\u193A"); // "Aacute"
- put("^A", "\\u194A"); // "Acirc"
+ put("S", "\\u167S"); // Section sign
+ put("`!", "\\u161!"); // Inverted exclamation point
+ put("pounds","\\u163?"); // Pound sign
+ put("copyright","\\u169?"); // Copyright sign
+ put("P", "\\u182P"); // Paragraph sign
+ put("`?", "\\u191?"); // Inverted question mark
put("~A", "\\u195A"); // "Atilde"
- put("\"A", "\\u196A"); // "Auml"
put("AA", "\\u197A"); // "Aring"
// RTFCHARS.put("AE", "{\\uc2\\u198AE}"); // "AElig"
- put("AE", "{\\u198A}"); // "AElig"
+ put("AE", "{\\u198AE}"); // "AElig"
+
put("cC", "\\u199C"); // "Ccedil"
- put("`E", "\\u200E"); // "Egrave"
- put("'E", "\\u201E"); // "Eacute"
- put("^E", "\\u202E"); // "Ecirc"
- put("\"E", "\\u203E"); // "Euml"
- put("`I", "\\u204I"); // "Igrave
- put("'I", "\\u205I"); // "Iacute"
- put("^I", "\\u206I"); // "Icirc"
- put("\"I", "\\u207I"); // "Iuml"
+
put("DH", "\\u208D"); // "ETH"
+
put("~N", "\\u209N"); // "Ntilde"
- put("`O", "\\u210O"); // "Ograve"
- put("'O", "\\u211O"); // "Oacute"
- put("^O", "\\u212O"); // "Ocirc"
+
put("~O", "\\u213O"); // "Otilde"
- put("\"O", "\\u214O"); // "Ouml"
// According to ISO 8859-1 the "\times" symbol should be placed here
// (#215).
// Omitting this, because it is a mathematical symbol.
put("O", "\\u216O"); // "Oslash"
// RTFCHARS.put("O", "\\'d8");
put("o", "\\'f8");
- put("`U", "\\u217U"); // "Ugrave"
- put("'U", "\\u218U"); // "Uacute"
- put("^U", "\\u219U"); // "Ucirc"
- put("\"U", "\\u220U"); // "Uuml"
+
put("'Y", "\\u221Y"); // "Yacute"
- put("TH", "{\\uc2\\u222TH}"); // "THORN"
- put("ss", "{\\uc2\\u223ss}"); // "szlig"
+
+ put("TH", "\\u222TH"); // "THORN"
+
+ put("ss", "\\u223ss"); // "szlig"
//RTFCHARS.put("ss", "AFFEN"); // "szlig"
- put("`a", "\\u224a"); // "agrave"
- put("'a", "\\u225a"); // "aacute"
- put("^a", "\\u226a"); // "acirc"
+
put("~a", "\\u227a"); // "atilde"
- put("\"a", "\\u228a"); // "auml"
put("aa", "\\u229a"); // "aring"
// RTFCHARS.put("ae", "{\\uc2\\u230ae}"); // "aelig" \\u230e6
- put("ae", "{\\u230a}"); // "aelig" \\u230e6
+ put("ae", "{\\u230ae}"); // "aelig" \\u230e6
+
put("cc", "\\u231c"); // "ccedil"
- put("`e", "\\u232e"); // "egrave"
- put("'e", "\\u233e"); // "eacute"
- put("^e", "\\u234e"); // "ecirc"
- put("\"e", "\\u235e"); // "euml"
- put("`i", "\\u236i"); // "igrave"
- put("'i", "\\u237i"); // "iacute"
- put("^i", "\\u238i"); // "icirc"
- put("\"i", "\\u239i"); // "iuml"
+
put("dh", "\\u240d"); // "eth"
- put("~n", "\\u241n"); // "ntilde"
- put("`o", "\\u242o"); // "ograve"
- put("'o", "\\u243o"); // "oacute"
- put("^o", "\\u244o"); // "ocirc"
+
put("~o", "\\u245o"); // "otilde"
- put("\"o", "\\u246o"); // "ouml"
// According to ISO 8859-1 the "\div" symbol should be placed here
// (#247).
// Omitting this, because it is a mathematical symbol.
put("o", "\\u248o"); // "oslash"
- put("`u", "\\u249u"); // "ugrave"
- put("'u", "\\u250u"); // "uacute"
- put("^u", "\\u251u"); // "ucirc"
+
// RTFCHARS.put("\"u", "\\u252"); // "uuml" exists in standard
// codepage
+
put("'y", "\\u253y"); // "yacute"
- put("th", "{\\uc2\\u254th}"); // "thorn"
+ put("th", "\\u254th"); // "thorn"
put("\"y", "\\u255y"); // "yuml"
put("=A", "\\u256A"); // "Amacr"
@@ -130,6 +112,7 @@ public class RtfCharMap extends HashMap<String, String> {
put("ua", "\\u259a"); // "abreve"
put("kA", "\\u260A"); // "Aogon"
put("ka", "\\u261a"); // "aogon"
+
put("'C", "\\u262C"); // "Cacute"
put("'c", "\\u263c"); // "cacute"
put("^C", "\\u264C"); // "Ccirc"
@@ -138,10 +121,12 @@ public class RtfCharMap extends HashMap<String, String> {
put(".c", "\\u267c"); // "cdot"
put("vC", "\\u268C"); // "Ccaron"
put("vc", "\\u269c"); // "ccaron"
+
put("vD", "\\u270D"); // "Dcaron"
// Symbol #271 (d) has no special Latex command
put("DJ", "\\u272D"); // "Dstrok"
put("dj", "\\u273d"); // "dstrok"
+
put("=E", "\\u274E"); // "Emacr"
put("=e", "\\u275e"); // "emacr"
put("uE", "\\u276E"); // "Ebreve"
@@ -152,6 +137,7 @@ public class RtfCharMap extends HashMap<String, String> {
put("ke", "\\u281e"); // "eogon"
put("vE", "\\u282E"); // "Ecaron"
put("ve", "\\u283e"); // "ecaron"
+
put("^G", "\\u284G"); // "Gcirc"
put("^g", "\\u285g"); // "gcirc"
put("uG", "\\u286G"); // "Gbreve"
@@ -160,10 +146,12 @@ public class RtfCharMap extends HashMap<String, String> {
put(".g", "\\u289g"); // "gdot"
put("cG", "\\u290G"); // "Gcedil"
put("'g", "\\u291g"); // "gacute"
+
put("^H", "\\u292H"); // "Hcirc"
put("^h", "\\u293h"); // "hcirc"
put("Hstrok", "\\u294H"); // "Hstrok"
put("hstrok", "\\u295h"); // "hstrok"
+
put("~I", "\\u296I"); // "Itilde"
put("~i", "\\u297i"); // "itilde"
put("=I", "\\u298I"); // "Imacr"
@@ -173,13 +161,15 @@ public class RtfCharMap extends HashMap<String, String> {
put("kI", "\\u302I"); // "Iogon"
put("ki", "\\u303i"); // "iogon"
put(".I", "\\u304I"); // "Idot"
- put("i", "\\u305i"); // "inodot"
+
// Symbol #306 (IJ) has no special Latex command
// Symbol #307 (ij) has no special Latex command
put("^J", "\\u308J"); // "Jcirc"
put("^j", "\\u309j"); // "jcirc"
+
put("cK", "\\u310K"); // "Kcedil"
put("ck", "\\u311k"); // "kcedil"
+
// Symbol #312 (k) has no special Latex command
put("'L", "\\u313L"); // "Lacute"
put("'l", "\\u314l"); // "lacute"
@@ -191,29 +181,36 @@ public class RtfCharMap extends HashMap<String, String> {
put("lmidot", "\\u320l"); // "lmidot"
put("L", "\\u321L"); // "Lstrok"
put("l", "\\u322l"); // "lstrok"
+
put("'N", "\\u323N"); // "Nacute"
put("'n", "\\u324n"); // "nacute"
put("cN", "\\u325N"); // "Ncedil"
put("cn", "\\u326n"); // "ncedil"
put("vN", "\\u327N"); // "Ncaron"
put("vn", "\\u328n"); // "ncaron"
+
// Symbol #329 (n) has no special Latex command
put("NG", "\\u330G"); // "ENG"
put("ng", "\\u331g"); // "eng"
+
put("=O", "\\u332O"); // "Omacr"
put("=o", "\\u333o"); // "omacr"
put("uO", "\\u334O"); // "Obreve"
put("uo", "\\u335o"); // "obreve"
+
put("HO", "\\u336?"); // "Odblac"
put("Ho", "\\u337?"); // "odblac"
- put("OE", "{\\uc2\\u338OE}"); // "OElig"
- put("oe", "{\\uc2\\u339oe}"); // "oelig"
+
+ put("OE", "{\\u338OE}"); // "OElig"
+ put("oe", "{\\u339oe}"); // "oelig"
+
put("'R", "\\u340R"); // "Racute"
put("'r", "\\u341r"); // "racute"
put("cR", "\\u342R"); // "Rcedil"
put("cr", "\\u343r"); // "rcedil"
put("vR", "\\u344R"); // "Rcaron"
put("vr", "\\u345r"); // "rcaron"
+
put("'S", "\\u346S"); // "Sacute"
put("'s", "\\u347s"); // "sacute"
put("^S", "\\u348S"); // "Scirc"
@@ -222,12 +219,14 @@ public class RtfCharMap extends HashMap<String, String> {
put("cs", "\\u351s"); // "scedil"
put("vS", "\\u352S"); // "Scaron"
put("vs", "\\u353s"); // "scaron"
+
put("cT", "\\u354T"); // "Tcedil"
put("ct", "\\u355t"); // "tcedil"
put("vT", "\\u356T"); // "Tcaron"
// Symbol #357 (t) has no special Latex command
put("Tstrok", "\\u358T"); // "Tstrok"
put("tstrok", "\\u359t"); // "tstrok"
+
put("~U", "\\u360U"); // "Utilde"
put("~u", "\\u361u"); // "utilde"
put("=U", "\\u362U"); // "Umacr"
@@ -236,15 +235,20 @@ public class RtfCharMap extends HashMap<String, String> {
put("uu", "\\u365u"); // "ubreve"
put("rU", "\\u366U"); // "Uring"
put("ru", "\\u367u"); // "uring"
+
put("HU", "\\u368?"); // "Odblac"
put("Hu", "\\u369?"); // "odblac"
+
put("kU", "\\u370U"); // "Uogon"
put("ku", "\\u371u"); // "uogon"
+
put("^W", "\\u372W"); // "Wcirc"
put("^w", "\\u373w"); // "wcirc"
+
put("^Y", "\\u374Y"); // "Ycirc"
put("^y", "\\u375y"); // "ycirc"
put("\"Y", "\\u376Y"); // "Yuml"
+
put("'Z", "\\u377Z"); // "Zacute"
put("'z", "\\u378z"); // "zacute"
put(".Z", "\\u379Z"); // "Zdot"
@@ -253,4 +257,13 @@ public class RtfCharMap extends HashMap<String, String> {
put("vz", "\\u382z"); // "zcaron"
// Symbol #383 (f) has no special Latex command
}
+
+ private void put(String key, String value) {
+ rtfMap.put(key, value);
+ }
+
+ public String get(String key) {
+ return rtfMap.get(key);
+ }
+
}
diff --git a/src/main/java/net/sf/jabref/logic/util/strings/StringUtil.java b/src/main/java/net/sf/jabref/logic/util/strings/StringUtil.java
deleted file mode 100644
index eff06b4..0000000
--- a/src/main/java/net/sf/jabref/logic/util/strings/StringUtil.java
+++ /dev/null
@@ -1,676 +0,0 @@
-package net.sf.jabref.logic.util.strings;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.StringTokenizer;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import net.sf.jabref.logic.util.OS;
-
-import com.google.common.base.CharMatcher;
-import org.apache.commons.lang3.StringUtils;
-
-public class StringUtil {
-
- // Non-letters which are used to denote accents in LaTeX-commands, e.g., in {\"{a}}
- public static final String SPECIAL_COMMAND_CHARS = "\"`^~'=.|";
-
- // contains all possible line breaks, not omitting any break such as "\\n"
- private static final Pattern LINE_BREAKS = Pattern.compile("\\r\\n|\\r|\\n");
-
- private static final Pattern BRACED_TITLE_CAPITAL_PATTERN = Pattern.compile("\\{[A-Z]+\\}");
-
- private static final UnicodeToReadableCharMap UNICODE_CHAR_MAP = new UnicodeToReadableCharMap();
-
- /**
- * Returns the string, after shaving off whitespace at the beginning and end,
- * and removing (at most) one pair of braces or " surrounding it.
- *
- * @param toShave
- * @return
- */
-
- public static String shaveString(String toShave) {
- if ((toShave == null) || (toShave.isEmpty())) {
- return "";
- }
- String shaved = toShave.trim();
- if (isInCurlyBrackets(shaved) || isInCitationMarks(shaved)) {
- return shaved.substring(1, shaved.length() - 1);
- }
- return shaved;
- }
-
- /**
- * Concatenate all strings in the array from index 'from' to 'to' (excluding
- * to) with the given separator.
- * <p>
- * Example:
- * <p>
- * String[] s = "ab/cd/ed".split("/"); join(s, "\\", 0, s.length) ->
- * "ab\\cd\\ed"
- *
- * @param strings
- * @param separator
- * @param from
- * @param to Excluding strings[to]
- * @return
- */
- public static String join(String[] strings, String separator, int from, int to) {
- if ((strings.length == 0) || (from >= to)) {
- return "";
- }
-
- int updatedFrom = Math.max(from, 0);
- int updatedTo = Math.min(strings.length, to);
-
- StringBuilder stringBuilder = new StringBuilder();
- for (int i = updatedFrom; i < (updatedTo - 1); i++) {
- stringBuilder.append(strings[i]).append(separator);
- }
- return stringBuilder.append(strings[updatedTo - 1]).toString();
- }
-
- /**
- * Removes optional square brackets from the string s
- *
- * @param toStrip
- * @return
- */
- public static String stripBrackets(String toStrip) {
- if (isInSquareBrackets(toStrip)) {
- return toStrip.substring(1, toStrip.length() - 1);
- }
- return toStrip;
- }
-
- /**
- * extends the filename with a default Extension, if no Extension '.x' could
- * be found
- */
- public static String getCorrectFileName(String orgName, String defaultExtension) {
- if (orgName == null) {
- return "";
- }
-
-
- if (orgName.toLowerCase().endsWith("." + defaultExtension.toLowerCase())) {
- return orgName;
- }
-
- int hiddenChar = orgName.indexOf('.', 1); // hidden files Linux/Unix (?)
- if (hiddenChar < 1) {
- return orgName + "." + defaultExtension;
- }
-
- return orgName;
- }
-
- /**
- * Creates a substring from a text
- *
- * @param text
- * @param startIndex
- * @param terminateOnEndBraceOnly
- * @return
- */
- public static String getPart(String text, int startIndex, boolean terminateOnEndBraceOnly) {
- char c;
- int count = 0;
-
- StringBuilder part = new StringBuilder();
-
- // advance to first char and skip whitespace
- int index = startIndex + 1;
- while ((index < text.length()) && Character.isWhitespace(text.charAt(index))) {
- index++;
- }
-
- // then grab whatever is the first token (counting braces)
- while (index < text.length()) {
- c = text.charAt(index);
- if (!terminateOnEndBraceOnly && (count == 0) && Character.isWhitespace(c)) {
- // end argument and leave whitespace for further processing
- break;
- }
- if ((c == '}') && (--count < 0)) {
- break;
- } else if (c == '{') {
- count++;
- }
- part.append(c);
- index++;
- }
- return part.toString();
- }
-
- /**
- * Formats field contents for output. Must be "symmetric" with the parse method above,
- * so stored and reloaded fields are not mangled.
- *
- * @param in
- * @param wrapAmount
- * @return the wrapped String.
- */
- public static String wrap(String in, int wrapAmount) {
-
- String[] lines = in.split("\n");
- StringBuilder result = new StringBuilder();
- // remove all whitespace at the end of the string, this especially includes \r created when the field content has \r\n as line separator
- addWrappedLine(result, CharMatcher.WHITESPACE.trimTrailingFrom(lines[0]), wrapAmount); // See
- for (int i = 1; i < lines.length; i++) {
-
- if (lines[i].trim().isEmpty()) {
- result.append(OS.NEWLINE);
- result.append('\t');
- } else {
- result.append(OS.NEWLINE);
- result.append('\t');
- result.append(OS.NEWLINE);
- result.append('\t');
- // remove all whitespace at the end of the string, this especially includes \r created when the field content has \r\n as line separator
- String line = CharMatcher.WHITESPACE.trimTrailingFrom(lines[i]);
- addWrappedLine(result, line, wrapAmount);
- }
- }
- return result.toString();
- }
-
- private static void addWrappedLine(StringBuilder result, String line, int wrapAmount) {
- // Set our pointer to the beginning of the new line in the StringBuffer:
- int length = result.length();
- // Add the line, unmodified:
- result.append(line);
-
- while (length < result.length()) {
- int current = result.indexOf(" ", length + wrapAmount);
- if ((current < 0) || (current >= result.length())) {
- break;
- }
-
- result.deleteCharAt(current);
- result.insert(current, OS.NEWLINE + "\t");
- length = current + OS.NEWLINE.length();
-
- }
- }
-
- /**
- * Quotes each and every character, e.g. '!' as !. Used for verbatim
- * display of arbitrary strings that may contain HTML entities.
- */
- public static String quoteForHTML(String toQuote) {
- StringBuilder result = new StringBuilder();
- for (int i = 0; i < toQuote.length(); ++i) {
- result.append("&#").append((int) toQuote.charAt(i)).append(';');
- }
- return result.toString();
- }
-
- /**
- * Unquote special characters.
- *
- * @param toUnquote The String which may contain quoted special characters.
- * @param quoteChar The quoting character.
- * @return A String with all quoted characters unquoted.
- */
- public static String unquote(String toUnquote, char quoteChar) {
- StringBuilder result = new StringBuilder();
- char c;
- boolean quoted = false;
- for (int i = 0; i < toUnquote.length(); ++i) {
- c = toUnquote.charAt(i);
- if (quoted) { // append literally...
- if (c != '\n') {
- result.append(c);
- }
- quoted = false;
- } else if (c == quoteChar) {
- // quote char
- quoted = true;
- } else {
- result.append(c);
- }
- }
- return result.toString();
- }
-
- public static String booleanToBinaryString(boolean expression) {
- return expression ? "1" : "0";
- }
-
- /**
- * Decodes an encoded double String array back into array form. The array
- * is assumed to be square, and delimited by the characters ';' (first dim) and
- * ':' (second dim).
- * @param value The encoded String to be decoded.
- * @return The decoded String array.
- */
- public static String[][] decodeStringDoubleArray(String value) {
- List<List<String>> newList = new ArrayList<>();
- StringBuilder sb = new StringBuilder();
- List<String> thisEntry = new ArrayList<>();
- boolean escaped = false;
- for (int i = 0; i < value.length(); i++) {
- char c = value.charAt(i);
- if (!escaped && (c == '\\')) {
- escaped = true;
- continue;
- } else if (!escaped && (c == ':')) {
- thisEntry.add(sb.toString());
- sb = new StringBuilder();
- } else if (!escaped && (c == ';')) {
- thisEntry.add(sb.toString());
- sb = new StringBuilder();
- newList.add(thisEntry);
- thisEntry = new ArrayList<>();
- } else {
- sb.append(c);
- }
- escaped = false;
- }
- if (sb.length() > 0) {
- thisEntry.add(sb.toString());
- }
- if (!thisEntry.isEmpty()) {
- newList.add(thisEntry);
- }
-
- // Convert to String[][]:
- String[][] res = new String[newList.size()][];
- for (int i = 0; i < res.length; i++) {
- res[i] = new String[newList.get(i).size()];
- for (int j = 0; j < res[i].length; j++) {
- res[i][j] = newList.get(i).get(j);
- }
- }
- return res;
- }
-
- /**
- * Wrap all uppercase letters, or sequences of uppercase letters, in curly
- * braces. Ignore letters within a pair of # character, as these are part of
- * a string label that should not be modified.
- *
- * @param s
- * The string to modify.
- * @return The resulting string after wrapping capitals.
- */
- public static String putBracesAroundCapitals(String s) {
-
- boolean inString = false;
- boolean isBracing = false;
- boolean escaped = false;
- int inBrace = 0;
- StringBuilder buf = new StringBuilder();
- for (int i = 0; i < s.length(); i++) {
- // Update variables based on special characters:
- int c = s.charAt(i);
- if (c == '{') {
- inBrace++;
- } else if (c == '}') {
- inBrace--;
- } else if (!escaped && (c == '#')) {
- inString = !inString;
- }
-
- // See if we should start bracing:
- if ((inBrace == 0) && !isBracing && !inString && Character.isLetter((char) c)
- && Character.isUpperCase((char) c)) {
-
- buf.append('{');
- isBracing = true;
- }
-
- // See if we should close a brace set:
- if (isBracing && !(Character.isLetter((char) c) && Character.isUpperCase((char) c))) {
-
- buf.append('}');
- isBracing = false;
- }
-
- // Add the current character:
- buf.append((char) c);
-
- // Check if we are entering an escape sequence:
- escaped = (c == '\\') && !escaped;
-
- }
- // Check if we have an unclosed brace:
- if (isBracing) {
- buf.append('}');
- }
-
- return buf.toString();
- }
-
- /**
- * This method looks for occurrences of capital letters enclosed in an
- * arbitrary number of pairs of braces, e.g. "{AB}" or "{{T}}". All of these
- * pairs of braces are removed.
- *
- * @param s
- * The String to analyze.
- * @return A new String with braces removed.
- */
- public static String removeBracesAroundCapitals(String s) {
- String current = s;
- String previous = s;
- while ((current = removeSingleBracesAroundCapitals(current)).length() < previous.length()) {
- previous = current;
- }
- return current;
- }
-
- /**
- * This method looks for occurrences of capital letters enclosed in one pair
- * of braces, e.g. "{AB}". All these are replaced by only the capitals in
- * between the braces.
- *
- * @param s
- * The String to analyze.
- * @return A new String with braces removed.
- */
- private static String removeSingleBracesAroundCapitals(String s) {
-
- Matcher mcr = BRACED_TITLE_CAPITAL_PATTERN.matcher(s);
- StringBuffer buf = new StringBuffer();
- while (mcr.find()) {
- String replaceStr = mcr.group();
- mcr.appendReplacement(buf, replaceStr.substring(1, replaceStr.length() - 1));
- }
- mcr.appendTail(buf);
- return buf.toString();
- }
-
- /**
- * Replaces all platform-dependent line breaks by OS.NEWLINE line breaks.
- *
- * We do NOT use UNIX line breaks as the user explicitly configures its linebreaks and this method is used in bibtex field writing
- *
- * <example>
- * Legacy Macintosh \r -> OS.NEWLINE
- * Windows \r\n -> OS.NEWLINE
- * </example>
- *
- * @return a String with only OS.NEWLINE as line breaks
- */
- public static String unifyLineBreaksToConfiguredLineBreaks(String s) {
- return LINE_BREAKS.matcher(s).replaceAll(OS.NEWLINE);
- }
-
- /**
- * Checks if the given String has exactly one pair of surrounding curly braces <br>
- * Strings with escaped characters in curly braces at the beginning and end are respected, too
- * @param toCheck The string to check
- * @return True, if the check was succesful. False otherwise.
- */
- public static boolean isInCurlyBrackets(String toCheck) {
- int count = 0;
- int brackets = 0;
- if ((toCheck == null) || toCheck.isEmpty()) {
- return false;
- } else {
- if ((toCheck.charAt(0) == '{') && (toCheck.charAt(toCheck.length() - 1) == '}')) {
- for (char c : toCheck.toCharArray()) {
- if (c == '{') {
- if (brackets == 0) {
- count++;
- }
- brackets++;
- } else if (c == '}') {
- brackets--;
- }
- }
-
- return count == 1;
- }
- return false;
- }
-
- }
-
- public static boolean isInSquareBrackets(String toCheck) {
- if ((toCheck == null) || toCheck.isEmpty()) {
- return false; // In case of null or empty string
- } else {
- return (toCheck.charAt(0) == '[') && (toCheck.charAt(toCheck.length() - 1) == ']');
- }
- }
-
- public static boolean isInCitationMarks(String toCheck) {
- if ((toCheck == null) || (toCheck.length() <= 1)) {
- return false; // In case of null, empty string, or a single citation mark
- } else {
- return (toCheck.charAt(0) == '"') && (toCheck.charAt(toCheck.length() - 1) == '"');
- }
- }
-
- /**
- * Optimized method for converting a String into an Integer
- *
- * From http://stackoverflow.com/questions/1030479/most-efficient-way-of-converting-string-to-integer-in-java
- *
- * @param str the String holding an Integer value
- * @throws NumberFormatException if str cannot be parsed to an int
- * @return the int value of str
- */
- public static int intValueOf(String str) {
- int idx = 0;
- int end;
- boolean sign = false;
- char ch;
-
- if ((str == null) || ((end = str.length()) == 0) || ((((ch = str.charAt(0)) < '0') || (ch > '9')) && (!(sign = ch == '-') || (++idx == end) || ((ch = str.charAt(idx)) < '0') || (ch > '9')))) {
- throw new NumberFormatException(str);
- }
-
- int ival = 0;
- for (;; ival *= 10) {
- ival += '0' - ch;
- if (++idx == end) {
- return sign ? ival : -ival;
- }
- if (((ch = str.charAt(idx)) < '0') || (ch > '9')) {
- throw new NumberFormatException(str);
- }
- }
- }
-
- /**
- * Optimized method for converting a String into an Integer
- *
- * From http://stackoverflow.com/questions/1030479/most-efficient-way-of-converting-string-to-integer-in-java
- *
- * @param str the String holding an Integer value
- * @return the int value of str or Optional.empty() if not possible
- */
- public static Optional<Integer> intValueOfOptional(String str) {
- int idx = 0;
- int end;
- boolean sign = false;
- char ch;
-
- if ((str == null) || ((end = str.length()) == 0) || ((((ch = str.charAt(0)) < '0') || (ch > '9')) && (!(sign = ch == '-') || (++idx == end) || ((ch = str.charAt(idx)) < '0') || (ch > '9')))) {
- return Optional.empty();
- }
-
- int ival = 0;
- for (;; ival *= 10) {
- ival += '0' - ch;
- if (++idx == end) {
- return Optional.of(sign ? ival : -ival);
- }
- if (((ch = str.charAt(idx)) < '0') || (ch > '9')) {
- return Optional.empty();
- }
- }
- }
-
- /**
- * This method ensures that the output String has only
- * valid XML unicode characters as specified by the
- * XML 1.0 standard. For reference, please see
- * <a href="http://www.w3.org/TR/2000/REC-xml-20001006#NT-Char">the
- * standard</a>. This method will return an empty
- * String if the input is null or empty.
- * <p>
- * URL: http://cse-mjmcl.cse.bris.ac.uk/blog/2007/02/14/1171465494443.html
- *
- * @param in The String whose non-valid characters we want to remove.
- * @return The in String, stripped of non-valid characters.
- */
- public static String stripNonValidXMLCharacters(String in) {
- if ((in == null) || in.isEmpty()) {
- return ""; // vacancy test.
- }
- StringBuilder out = new StringBuilder(); // Used to hold the output.
- char current; // Used to reference the current character.
-
- for (int i = 0; i < in.length(); i++) {
- current = in.charAt(i); // NOTE: No IndexOutOfBoundsException caught here; it should not happen.
- if ((current == 0x9) || (current == 0xA) || (current == 0xD) || ((current >= 0x20) && (current <= 0xD7FF))
- || ((current >= 0xE000) && (current <= 0xFFFD))) {
- out.append(current);
- }
- }
- return out.toString();
- }
-
- /*
- * @param buf String to be tokenized
- * @param delimstr Delimiter string
- * @return list {@link java.util.List} of <tt>String</tt>
- */
- public static List<String> tokenizeToList(String buf, String delimstr) {
- List<String> list = new ArrayList<>();
- String buffer = buf + '\n';
-
- StringTokenizer st = new StringTokenizer(buffer, delimstr);
-
- while (st.hasMoreTokens()) {
- list.add(st.nextToken());
- }
-
- return list;
- }
-
- /**
- * Quote special characters.
- *
- * @param toQuote The String which may contain special characters.
- * @param specials A String containing all special characters except the quoting
- * character itself, which is automatically quoted.
- * @param quoteChar The quoting character.
- * @return A String with every special character (including the quoting
- * character itself) quoted.
- */
- public static String quote(String toQuote, String specials, char quoteChar) {
- if (toQuote == null) {
- return "";
- }
-
- StringBuilder result = new StringBuilder();
- char c;
- boolean isSpecial;
- for (int i = 0; i < toQuote.length(); ++i) {
- c = toQuote.charAt(i);
-
- isSpecial = (c == quoteChar);
- // If non-null specials performs logic-or with specials.indexOf(c) >= 0
- isSpecial |= ((specials != null) && (specials.indexOf(c) >= 0));
-
- if (isSpecial) {
- result.append(quoteChar);
- }
- result.append(c);
- }
- return result.toString();
- }
-
- public static String limitStringLength(String s, int maxLength) {
- if (s == null) {
- return "";
- }
-
- if (s.length() <= maxLength) {
- return s;
- }
-
- return s.substring(0, maxLength - 3) + "...";
- }
-
- /**
- * Replace non-English characters like umlauts etc. with a sensible letter or letter combination that bibtex can
- * accept. The basis for replacement is the HashMap UnicodeToReadableCharMap.
- */
- public static String replaceSpecialCharacters(String s) {
- String result = s;
- for (Map.Entry<String, String> chrAndReplace : UNICODE_CHAR_MAP.entrySet()) {
- result = result.replace(chrAndReplace.getKey(), chrAndReplace.getValue());
- }
- return result;
- }
-
- /**
- * Return a String with n spaces
- *
- * @param n Number of spaces
- * @return String with n spaces
- */
- public static String repeatSpaces(int n) {
- return repeat(n, ' ');
- }
-
- /**
- * Return a String with n copies of the char c
- *
- * @param n Number of copies
- * @param c char to copy
- * @return String with n copies of c
- */
- public static String repeat(int n, char c) {
- StringBuilder resultSB = new StringBuilder(n);
-
- for (int i = 0; i < n; i++) {
- resultSB.append(c);
- }
-
- return resultSB.toString();
-
- }
-
- public static boolean isNullOrEmpty(String toTest) {
- return ((toTest == null) || toTest.isEmpty());
- }
-
- public static boolean isNotBlank(Optional<String> string) {
- return string.isPresent() && isNotBlank(string.get());
- }
-
- public static boolean isNotBlank(String string) {
- return StringUtils.isNotBlank(string);
- }
-
- /**
- * Return string enclosed in HTML bold tags
- */
- public static String boldHTML(String input) {
- return "<b>" + input + "</b>";
- }
-
- /**
- * Return string enclosed in HTML bold tags if not null, otherwise return alternative text in HTML bold tags
- */
- public static String boldHTML(String input, String alternative) {
-
- if (input == null) {
- return "<b>" + alternative + "</b>";
- }
- return "<b>" + input + "</b>";
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/logic/util/strings/UnicodeToReadableCharMap.java b/src/main/java/net/sf/jabref/logic/util/strings/UnicodeToReadableCharMap.java
deleted file mode 100644
index c6b5325..0000000
--- a/src/main/java/net/sf/jabref/logic/util/strings/UnicodeToReadableCharMap.java
+++ /dev/null
@@ -1,241 +0,0 @@
-package net.sf.jabref.logic.util.strings;
-
-import java.util.HashMap;
-
-public class UnicodeToReadableCharMap extends HashMap<String, String> {
- public UnicodeToReadableCharMap() {
- put("\u00C0", "A");
- put("\u00C1", "A");
- put("\u00C2", "A");
- put("\u00C3", "A");
- put("\u00C4", "Ae");
- put("\u00C5", "Aa");
- put("\u00C6", "Ae");
- put("\u00C7", "C");
- put("\u00C8", "E");
- put("\u00C9", "E");
- put("\u00CA", "E");
- put("\u00CB", "E");
- put("\u00CC", "I");
- put("\u00CD", "I");
- put("\u00CE", "I");
- put("\u00CF", "I");
- put("\u00D0", "D");
- put("\u00D1", "N");
- put("\u00D2", "O");
- put("\u00D3", "O");
- put("\u00D4", "O");
- put("\u00D5", "O");
- put("\u00D6", "Oe");
- put("\u00D8", "Oe");
- put("\u00D9", "U");
- put("\u00DA", "U");
- put("\u00DB", "U");
- put("\u00DC", "Ue"); // U umlaut ..
- put("\u00DD", "Y");
- put("\u00DF", "ss");
- put("\u00E0", "a");
- put("\u00E1", "a");
- put("\u00E2", "a");
- put("\u00E3", "a");
- put("\u00E4", "ae");
- put("\u00E5", "aa");
- put("\u00E6", "ae");
- put("\u00E7", "c");
- put("\u00E8", "e");
- put("\u00E9", "e");
- put("\u00EA", "e");
- put("\u00EB", "e");
- put("\u00EC", "i");
- put("\u00ED", "i");
- put("\u00EE", "i");
- put("\u00EF", "i");
- put("\u00F0", "o");
- put("\u00F1", "n");
- put("\u00F2", "o");
- put("\u00F3", "o");
- put("\u00F4", "o");
- put("\u00F5", "o");
- put("\u00F6", "oe");
- put("\u00F8", "oe");
- put("\u00F9", "u");
- put("\u00FA", "u");
- put("\u00FB", "u");
- put("\u00FC", "ue"); // u umlaut...
- put("\u00FD", "y");
- put("\u00FF", "y");
- put("\u0100", "A");
- put("\u0101", "a");
- put("\u0102", "A");
- put("\u0103", "a");
- put("\u0104", "A");
- put("\u0105", "a");
- put("\u0106", "C");
- put("\u0107", "c");
- put("\u0108", "C");
- put("\u0109", "c");
- put("\u010A", "C");
- put("\u010B", "c");
- put("\u010C", "C");
- put("\u010D", "c");
- put("\u010E", "D");
- put("\u010F", "d");
- put("\u0110", "D");
- put("\u0111", "d");
- put("\u0112", "E");
- put("\u0113", "e");
- put("\u0114", "E");
- put("\u0115", "e");
- put("\u0116", "E");
- put("\u0117", "e");
- put("\u0118", "E");
- put("\u0119", "e");
- put("\u011A", "E");
- put("\u011B", "e");
- put("\u011C", "G");
- put("\u011D", "g");
- put("\u011E", "G");
- put("\u011F", "g");
- put("\u0120", "G");
- put("\u0121", "g");
- put("\u0122", "G");
- put("\u0123", "g");
- put("\u0124", "H");
- put("\u0125", "h");
- put("\u0127", "h");
- put("\u0128", "I");
- put("\u0129", "i");
- put("\u012A", "I");
- put("\u012B", "i");
- put("\u012C", "I");
- put("\u012D", "i");
- put("\u012E", "I");
- put("\u012F", "i");
- put("\u0130", "I");
- put("\u0131", "i");
- put("\u0132", "IJ");
- put("\u0133", "ij");
- put("\u0134", "J");
- put("\u0135", "j");
- put("\u0136", "K");
- put("\u0137", "k");
- put("\u0138", "k");
- put("\u0139", "L");
- put("\u013A", "l");
- put("\u013B", "L");
- put("\u013C", "l");
- put("\u013D", "L");
- put("\u013E", "l");
- put("\u013F", "L");
- put("\u0140", "l");
- put("\u0141", "L");
- put("\u0142", "l");
- put("\u0143", "N");
- put("\u0144", "n");
- put("\u0145", "N");
- put("\u0146", "n");
- put("\u0147", "N");
- put("\u0148", "n");
- put("\u0149", "n");
- put("\u014A", "N");
- put("\u014B", "n");
- put("\u014C", "O");
- put("\u014D", "o");
- put("\u014E", "O");
- put("\u014F", "o");
- put("\u0150", "Oe");
- put("\u0151", "oe");
- put("\u0152", "OE");
- put("\u0153", "oe");
- put("\u0154", "R");
- put("\u0155", "r");
- put("\u0156", "R");
- put("\u0157", "r");
- put("\u0158", "R");
- put("\u0159", "r");
- put("\u015A", "S");
- put("\u015B", "s");
- put("\u015C", "S");
- put("\u015D", "s");
- put("\u015E", "S");
- put("\u015F", "s");
- put("\u0160", "S");
- put("\u0161", "s");
- put("\u0162", "T");
- put("\u0163", "t");
- put("\u0164", "T");
- put("\u0165", "t");
- put("\u0166", "T");
- put("\u0167", "t");
- put("\u0168", "U");
- put("\u0169", "u");
- put("\u016A", "U");
- put("\u016B", "u");
- put("\u016C", "U");
- put("\u016D", "u");
- put("\u016E", "UU");
- put("\u016F", "uu");
- put("\u0170", "Ue");
- put("\u0171", "ue");
- put("\u0172", "U");
- put("\u0173", "u");
- put("\u0174", "W");
- put("\u0175", "w");
- put("\u0176", "Y");
- put("\u0177", "y");
- put("\u0178", "Y");
- put("\u0179", "Z");
- put("\u017A", "z");
- put("\u017B", "Z");
- put("\u017C", "z");
- put("\u017D", "Z");
- put("\u017E", "z");
- put("\u1EBC", "E");
- put("\u1EBD", "e");
- put("\u1EF8", "Y");
- put("\u1EF9", "y");
- put("\u01CD", "A");
- put("\u01CE", "a");
- put("\u01CF", "I");
- put("\u01D0", "i");
- put("\u01D1", "O");
- put("\u01D2", "o");
- put("\u01D3", "U");
- put("\u01D4", "u");
- put("\u0232", "Y");
- put("\u0233", "y");
- put("\u01EA", "O");
- put("\u01EB", "o");
- put("\u1E0C", "D");
- put("\u1E0D", "d");
- put("\u1E24", "H");
- put("\u1E25", "h");
- put("\u1E36", "L");
- put("\u1E37", "l");
- put("\u1E38", "L");
- put("\u1E39", "l");
- put("\u1E42", "M");
- put("\u1E43", "m");
- put("\u1E46", "N");
- put("\u1E47", "n");
- put("\u1E5A", "R");
- put("\u1E5B", "r");
- put("\u1E5C", "R");
- put("\u1E5D", "r");
- put("\u1E62", "S");
- put("\u1E63", "s");
- put("\u1E6C", "T");
- put("\u1E6D", "t");
- put("\u00CF", "I");
-
- put("\u008C", "AE"); // doesn't work?
- put("\u016E", "U");
- put("\u016F", "u");
-
- put("\u0178", "Y");
- put("\u00FE", ""); // thorn character
-
- // UNICODE_CHARS.put("\u0100", "");
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/logic/xmp/XMPPreferences.java b/src/main/java/net/sf/jabref/logic/xmp/XMPPreferences.java
index 9647545..bb9fc10 100644
--- a/src/main/java/net/sf/jabref/logic/xmp/XMPPreferences.java
+++ b/src/main/java/net/sf/jabref/logic/xmp/XMPPreferences.java
@@ -2,27 +2,19 @@ package net.sf.jabref.logic.xmp;
import java.util.List;
-import net.sf.jabref.preferences.JabRefPreferences;
-
public class XMPPreferences {
private final boolean useXMPPrivacyFilter;
private final List<String> xmpPrivacyFilter;
- private final String keywordSeparator;
+ private final Character keywordSeparator;
- public XMPPreferences(boolean useXMPPrivacyFilter, List<String> xmpPrivacyFilter, String keywordSeparator) {
+ public XMPPreferences(boolean useXMPPrivacyFilter, List<String> xmpPrivacyFilter, Character keywordSeparator) {
this.useXMPPrivacyFilter = useXMPPrivacyFilter;
this.xmpPrivacyFilter = xmpPrivacyFilter;
this.keywordSeparator = keywordSeparator;
}
- public static XMPPreferences fromPreferences(JabRefPreferences jabrefPreferences) {
- return new XMPPreferences(jabrefPreferences.getBoolean(JabRefPreferences.USE_XMP_PRIVACY_FILTER),
- jabrefPreferences.getStringList(JabRefPreferences.XMP_PRIVACY_FILTERS),
- jabrefPreferences.get(JabRefPreferences.KEYWORD_SEPARATOR));
- }
-
public boolean isUseXMPPrivacyFilter() {
return useXMPPrivacyFilter;
}
@@ -31,7 +23,7 @@ public class XMPPreferences {
return xmpPrivacyFilter;
}
- public String getKeywordSeparator() {
+ public Character getKeywordSeparator() {
return keywordSeparator;
}
}
diff --git a/src/main/java/net/sf/jabref/logic/xmp/XMPSchemaBibtex.java b/src/main/java/net/sf/jabref/logic/xmp/XMPSchemaBibtex.java
index 5fb7a49..75eafae 100644
--- a/src/main/java/net/sf/jabref/logic/xmp/XMPSchemaBibtex.java
+++ b/src/main/java/net/sf/jabref/logic/xmp/XMPSchemaBibtex.java
@@ -9,12 +9,14 @@ import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
+import javax.xml.transform.TransformerException;
+
import net.sf.jabref.model.database.BibDatabase;
import net.sf.jabref.model.entry.Author;
import net.sf.jabref.model.entry.AuthorList;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.FieldName;
-import net.sf.jabref.model.entry.FieldProperties;
+import net.sf.jabref.model.entry.FieldProperty;
import net.sf.jabref.model.entry.IdGenerator;
import net.sf.jabref.model.entry.InternalBibtexFields;
@@ -57,8 +59,10 @@ public class XMPSchemaBibtex extends XMPSchema {
*
* @param e
* The existing XML element.
+ * @param namespace
+ * The name space considered. Must currently be there for compatibility reasons despite being unused.
*/
- public XMPSchemaBibtex(Element e, String namespace) {
+ public XMPSchemaBibtex(Element e, @SuppressWarnings("unused") String namespace) {
super(e, XMPSchemaBibtex.KEY);
}
@@ -273,29 +277,29 @@ public class XMPSchemaBibtex extends XMPSchema {
// Set all the values including key and entryType
Set<String> fields = entry.getFieldNames();
- if (xmpPreferences != null && xmpPreferences.isUseXMPPrivacyFilter()) {
+ if ((xmpPreferences != null) && xmpPreferences.isUseXMPPrivacyFilter()) {
Set<String> filters = new TreeSet<>(xmpPreferences.getXmpPrivacyFilter());
fields.removeAll(filters);
}
for (String field : fields) {
- String value = BibDatabase.getResolvedField(field, entry, database).orElse("");
- if (InternalBibtexFields.getFieldExtras(field).contains(FieldProperties.PERSON_NAMES)) {
+ String value = entry.getResolvedFieldOrAlias(field, database).orElse("");
+ if (InternalBibtexFields.getFieldProperties(field).contains(FieldProperty.PERSON_NAMES)) {
setPersonList(field, value);
} else {
setTextProperty(field, value);
}
}
- setTextProperty("entrytype", entry.getType());
+ setTextProperty(BibEntry.TYPE_HEADER, entry.getType());
}
public BibEntry getBibtexEntry() {
- String type = getTextProperty("entrytype");
+ String type = getTextProperty(BibEntry.TYPE_HEADER);
BibEntry e = new BibEntry(IdGenerator.next(), type);
// Get Text Properties
Map<String, String> text = XMPSchemaBibtex.getAllProperties(this, "bibtex");
- text.remove("entrytype");
+ text.remove(BibEntry.TYPE_HEADER);
e.setField(text);
return e;
}
diff --git a/src/main/java/net/sf/jabref/logic/xmp/XMPUtil.java b/src/main/java/net/sf/jabref/logic/xmp/XMPUtil.java
index 6b5feef..33f45c1 100644
--- a/src/main/java/net/sf/jabref/logic/xmp/XMPUtil.java
+++ b/src/main/java/net/sf/jabref/logic/xmp/XMPUtil.java
@@ -30,9 +30,9 @@ import net.sf.jabref.model.database.BibDatabaseMode;
import net.sf.jabref.model.entry.Author;
import net.sf.jabref.model.entry.AuthorList;
import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.model.entry.EntryUtil;
import net.sf.jabref.model.entry.FieldName;
import net.sf.jabref.model.entry.MonthUtil;
+import net.sf.jabref.model.strings.StringUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -123,10 +123,6 @@ public class XMPUtil {
return result;
}
- public static PDDocument loadWithAutomaticDecryption(Path filePath) throws IOException {
- return loadWithAutomaticDecryption(new FileInputStream(filePath.toFile()));
- }
-
public static PDDocument loadWithAutomaticDecryption(InputStream inputStream) throws IOException {
PDDocument doc = PDDocument.load(inputStream);
@@ -264,7 +260,7 @@ public class XMPUtil {
if (key.startsWith("bibtex/")) {
String value = dict.getString(key);
key = key.substring("bibtex/".length());
- if ("entrytype".equals(key)) {
+ if (BibEntry.TYPE_HEADER.equals(key)) {
entry.setType(value);
} else {
entry.setField(key, value);
@@ -993,7 +989,7 @@ public class XMPUtil {
di.setCustomMetadataValue("bibtex/" + fieldName, fieldContent);
}
}
- di.setCustomMetadataValue("bibtex/entrytype", EntryUtil.capitalizeFirst(resolvedEntry.getType()));
+ di.setCustomMetadataValue("bibtex/entrytype", StringUtil.capitalizeFirst(resolvedEntry.getType()));
}
/**
diff --git a/src/main/java/net/sf/jabref/migrations/FileLinksUpgradeWarning.java b/src/main/java/net/sf/jabref/migrations/FileLinksUpgradeWarning.java
index 11af25c..529b405 100644
--- a/src/main/java/net/sf/jabref/migrations/FileLinksUpgradeWarning.java
+++ b/src/main/java/net/sf/jabref/migrations/FileLinksUpgradeWarning.java
@@ -1,6 +1,5 @@
package net.sf.jabref.migrations;
-import java.util.Arrays;
import java.util.List;
import javax.swing.JButton;
@@ -20,11 +19,11 @@ import net.sf.jabref.gui.undo.UndoableFieldChange;
import net.sf.jabref.logic.cleanup.UpgradePdfPsToFileCleanup;
import net.sf.jabref.logic.importer.ParserResult;
import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.logic.layout.format.FileLinkPreferences;
import net.sf.jabref.model.FieldChange;
import net.sf.jabref.model.database.BibDatabase;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.FieldName;
+import net.sf.jabref.model.metadata.FileDirectoryPreferences;
import net.sf.jabref.preferences.JabRefPreferences;
import com.jgoodies.forms.builder.FormBuilder;
@@ -41,7 +40,7 @@ import com.jgoodies.forms.layout.FormLayout;
*/
public class FileLinksUpgradeWarning implements PostOpenAction {
- private static final String[] FIELDS_TO_LOOK_FOR = new String[] {FieldName.PDF, FieldName.PS, "evastar_pdf"};
+ private static final String[] FIELDS_TO_LOOK_FOR = new String[] {FieldName.PDF, FieldName.PS};
private boolean offerChangeSettings;
@@ -64,8 +63,9 @@ public class FileLinksUpgradeWarning implements PostOpenAction {
// Only offer to upgrade links if the pdf/ps fields are used:
offerChangeDatabase = linksFound(pr.getDatabase(), FileLinksUpgradeWarning.FIELDS_TO_LOOK_FOR);
// If the "file" directory is not set, offer to migrate pdf/ps dir:
- offerSetFileDir = !Globals.prefs.hasKey(FieldName.FILE + FileLinkPreferences.DIR_SUFFIX)
- && (Globals.prefs.hasKey("pdfDirectory") || Globals.prefs.hasKey("psDirectory"));
+ offerSetFileDir = !Globals.prefs.hasKey(FieldName.FILE + FileDirectoryPreferences.DIR_SUFFIX)
+ && (Globals.prefs.hasKey(FieldName.PDF + FileDirectoryPreferences.DIR_SUFFIX)
+ || Globals.prefs.hasKey(FieldName.PS + FileDirectoryPreferences.DIR_SUFFIX));
// First check if this warning is disabled:
return Globals.prefs.getBoolean(JabRefPreferences.SHOW_FILE_LINKS_UPGRADE_WARNING) && isThereSomethingToBeDone();
@@ -114,10 +114,10 @@ public class FileLinksUpgradeWarning implements PostOpenAction {
formBuilder.add(changeDatabase).xy(1, row);
}
if (offerSetFileDir) {
- if (Globals.prefs.hasKey("pdfDirectory")) {
- fileDir.setText(Globals.prefs.get("pdfDirectory"));
+ if (Globals.prefs.hasKey(FieldName.PDF + FileDirectoryPreferences.DIR_SUFFIX)) {
+ fileDir.setText(Globals.prefs.get(FieldName.PDF + FileDirectoryPreferences.DIR_SUFFIX));
} else {
- fileDir.setText(Globals.prefs.get("psDirectory"));
+ fileDir.setText(Globals.prefs.get(FieldName.PS + FileDirectoryPreferences.DIR_SUFFIX));
}
JPanel builderPanel = new JPanel();
builderPanel.add(setFileDir);
@@ -183,13 +183,13 @@ public class FileLinksUpgradeWarning implements PostOpenAction {
if (upgradeDatabase) {
// Update file links links in the database:
- NamedCompound ce = upgradePdfPsToFile(pr.getDatabase(), FileLinksUpgradeWarning.FIELDS_TO_LOOK_FOR);
+ NamedCompound ce = upgradePdfPsToFile(pr.getDatabase());
panel.getUndoManager().addEdit(ce);
panel.markBaseChanged();
}
if (fileDir != null) {
- Globals.prefs.put(FieldName.FILE + FileLinkPreferences.DIR_SUFFIX, fileDir);
+ Globals.prefs.put(FieldName.FILE + FileDirectoryPreferences.DIR_SUFFIX, fileDir);
}
if (upgradePrefs) {
@@ -207,7 +207,6 @@ public class FileLinksUpgradeWarning implements PostOpenAction {
sb.append(FieldName.FILE);
Globals.prefs.put(JabRefPreferences.CUSTOM_TAB_FIELDS + "0", sb.toString());
Globals.prefs.updateEntryEditorTabList();
- panel.frame().removeCachedEntryEditors();
}
panel.frame().setupAllTables();
}
@@ -236,10 +235,10 @@ public class FileLinksUpgradeWarning implements PostOpenAction {
* @param fields The fields to find links in.
* @return A CompoundEdit specifying the undo operation for the whole operation.
*/
- private static NamedCompound upgradePdfPsToFile(BibDatabase database, String[] fields) {
+ private static NamedCompound upgradePdfPsToFile(BibDatabase database) {
NamedCompound ce = new NamedCompound(Localization.lang("Move external links to 'file' field"));
- UpgradePdfPsToFileCleanup cleanupJob = new UpgradePdfPsToFileCleanup(Arrays.asList(fields));
+ UpgradePdfPsToFileCleanup cleanupJob = new UpgradePdfPsToFileCleanup();
for (BibEntry entry : database.getEntries()) {
List<FieldChange> changes = cleanupJob.cleanup(entry);
diff --git a/src/main/java/net/sf/jabref/migrations/PreferencesMigrations.java b/src/main/java/net/sf/jabref/migrations/PreferencesMigrations.java
index 4e421ef..49d10f2 100644
--- a/src/main/java/net/sf/jabref/migrations/PreferencesMigrations.java
+++ b/src/main/java/net/sf/jabref/migrations/PreferencesMigrations.java
@@ -7,7 +7,6 @@ import java.util.prefs.Preferences;
import net.sf.jabref.Globals;
import net.sf.jabref.JabRefMain;
-import net.sf.jabref.model.bibtexkeypattern.AbstractBibtexKeyPattern;
import net.sf.jabref.model.bibtexkeypattern.GlobalBibtexKeyPattern;
import net.sf.jabref.model.entry.FieldName;
import net.sf.jabref.preferences.JabRefPreferences;
@@ -131,8 +130,9 @@ public class PreferencesMigrations {
throws BackingStoreException {
LOGGER.info("Found old Bibtex Key patterns which will be migrated to new version.");
- GlobalBibtexKeyPattern keyPattern = new GlobalBibtexKeyPattern(AbstractBibtexKeyPattern
- .split(prefs.get(JabRefPreferences.DEFAULT_BIBTEX_KEY_PATTERN)));
+ GlobalBibtexKeyPattern keyPattern = GlobalBibtexKeyPattern.fromPattern(
+ prefs.get(JabRefPreferences.DEFAULT_BIBTEX_KEY_PATTERN)
+ );
for (String key : oldPatternPrefs.keys()) {
keyPattern.addBibtexKeyPattern(key, oldPatternPrefs.get(key, null));
}
diff --git a/src/main/java/net/sf/jabref/model/ChainNode.java b/src/main/java/net/sf/jabref/model/ChainNode.java
new file mode 100644
index 0000000..9afb351
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/ChainNode.java
@@ -0,0 +1,154 @@
+package net.sf.jabref.model;
+
+import java.util.Objects;
+import java.util.Optional;
+
+/**
+ * Represents a node in a chain.
+ * We view a chain as a vertical hierarchy and thus refer to the previous node as parent and the next node is a child.
+ * <p>
+ * In usual implementations, nodes function as wrappers around a data object. Thus normally they have a value property
+ * which allows access to the value stored in the node.
+ * In contrast to this approach, the ChainNode<T> class is designed to be used as a base class which provides the
+ * tree traversing functionality via inheritance.
+ * <p>
+ * Example usage:
+ * private class BasicChainNode extends ChainNode<BasicChainNode> {
+ * public BasicChainNode() {
+ * super(BasicChainNode.class);
+ * }
+ * }
+ *
+ * @param <T> the type of the class
+ */
+ at SuppressWarnings("unchecked") // We use some explicit casts of the form "(T) this". The constructor ensures that this cast is valid.
+public abstract class ChainNode<T extends ChainNode<T>> {
+
+ /**
+ * This node's parent, or null if this node has no parent
+ */
+ private T parent;
+ /**
+ * This node's child, or null if this node has no child
+ */
+ private T child;
+
+ /**
+ * Constructs a chain node without parent and no child.
+ *
+ * @param derivingClass class deriving from TreeNode<T>. It should always be "T.class".
+ * We need this parameter since it is hard to get this information by other means.
+ */
+ public ChainNode(Class<T> derivingClass) {
+ parent = null;
+ child = null;
+
+ if (!derivingClass.isInstance(this)) {
+ throw new UnsupportedOperationException("The class extending ChainNode<T> has to derive from T");
+ }
+ }
+
+ /**
+ * Returns this node's parent or an empty Optional if this node has no parent.
+ *
+ * @return this node's parent T, or an empty Optional if this node has no parent
+ */
+ public Optional<T> getParent() {
+ return Optional.ofNullable(parent);
+ }
+
+ /**
+ * Returns this node's child or an empty Optional if this node has no child.
+ *
+ * @return this node's child T, or an empty Optional if this node has no child
+ */
+ public Optional<T> getChild() {
+ return Optional.ofNullable(child);
+ }
+
+ /**
+ * Removes this node from its parent and makes it a child of the specified node.
+ * In this way the whole subchain based at this node is moved to the given node.
+ *
+ * @param target the new parent
+ * @throws NullPointerException if target is null
+ * @throws UnsupportedOperationException if target is an descendant of this node
+ */
+ public void moveTo(T target) {
+ Objects.requireNonNull(target);
+
+ // Check that the target node is not an ancestor of this node, because this would create loops in the tree
+ if (this.isAncestorOf(target)) {
+ throw new UnsupportedOperationException("the target cannot be a descendant of this node");
+ }
+
+ // Remove from previous parent
+ getParent().ifPresent(oldParent -> oldParent.removeChild());
+
+ // Add as child
+ target.setChild((T) this);
+ }
+
+ /**
+ * Adds the node as the child. Also sets the parent of the given node to this node.
+ * The given node is not allowed to already be in a tree (i.e. it has to have no parent).
+ *
+ * @param child the node to add as child
+ * @return the child node
+ * @throws UnsupportedOperationException if the given node has already a parent
+ */
+ public T setChild(T child) {
+ Objects.requireNonNull(child);
+ if (child.getParent().isPresent()) {
+ throw new UnsupportedOperationException("Cannot add a node which already has a parent, use moveTo instead");
+ }
+
+ child.setParent((T) this);
+ this.child = child;
+
+ return child;
+ }
+
+ /**
+ * Sets the parent node of this node.
+ * <p>
+ * This method does not set this node as the child of the new parent nor does it remove this node
+ * from the old parent. You should probably call {@link #moveTo(ChainNode)} to change the chain.
+ *
+ * @param parent the new parent
+ */
+ protected void setParent(T parent) {
+ this.parent = Objects.requireNonNull(parent);
+ }
+
+ /**
+ * Removes the child from this node's child list, giving it an empty parent.
+ *
+ */
+ public void removeChild() {
+ if (child != null) {
+ // NPE if this is ever called
+ child.setParent(null);
+ }
+ child = null;
+ }
+
+ /**
+ * Returns true if this node is an ancestor of the given node.
+ * <p>
+ * A node is considered an ancestor of itself.
+ *
+ * @param anotherNode node to test
+ * @return true if anotherNode is a descendant of this node
+ * @throws NullPointerException if anotherNode is null
+ */
+ public boolean isAncestorOf(T anotherNode) {
+ Objects.requireNonNull(anotherNode);
+
+ if (anotherNode == this) {
+ return true;
+ } else {
+ return child.isAncestorOf(anotherNode);
+ }
+ }
+}
diff --git a/src/main/java/net/sf/jabref/model/Defaults.java b/src/main/java/net/sf/jabref/model/Defaults.java
new file mode 100644
index 0000000..213b277
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/Defaults.java
@@ -0,0 +1,17 @@
+package net.sf.jabref.model;
+
+import net.sf.jabref.model.database.BibDatabaseMode;
+
+public class Defaults {
+
+ public final BibDatabaseMode mode;
+
+ public Defaults() {
+ this.mode = BibDatabaseMode.BIBTEX;
+ }
+
+ public Defaults(BibDatabaseMode mode) {
+ this.mode = mode;
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/model/DuplicateCheck.java b/src/main/java/net/sf/jabref/model/DuplicateCheck.java
index 87c26ec..056920d 100644
--- a/src/main/java/net/sf/jabref/model/DuplicateCheck.java
+++ b/src/main/java/net/sf/jabref/model/DuplicateCheck.java
@@ -13,7 +13,7 @@ import net.sf.jabref.model.entry.AuthorList;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.EntryType;
import net.sf.jabref.model.entry.FieldName;
-import net.sf.jabref.model.entry.FieldProperties;
+import net.sf.jabref.model.entry.FieldProperty;
import net.sf.jabref.model.entry.InternalBibtexFields;
import org.apache.commons.logging.Log;
@@ -118,8 +118,8 @@ public class DuplicateCheck {
}
private static int compareSingleField(String field, BibEntry one, BibEntry two) {
- Optional<String> optionalStringOne = one.getFieldOptional(field);
- Optional<String> optionalStringTwo = two.getFieldOptional(field);
+ Optional<String> optionalStringOne = one.getField(field);
+ Optional<String> optionalStringTwo = two.getField(field);
if (!optionalStringOne.isPresent()) {
if (!optionalStringTwo.isPresent()) {
return EMPTY_IN_BOTH;
@@ -133,7 +133,7 @@ public class DuplicateCheck {
String stringOne = optionalStringOne.get();
String stringTwo = optionalStringTwo.get();
- if (InternalBibtexFields.getFieldExtras(field).contains(FieldProperties.PERSON_NAMES)) {
+ if (InternalBibtexFields.getFieldProperties(field).contains(FieldProperty.PERSON_NAMES)) {
// Specific for name fields.
// Harmonise case:
String authorOne = AuthorList.fixAuthorLastNameOnlyCommas(stringOne, false).replace(" and ", " ").toLowerCase();
@@ -182,8 +182,8 @@ public class DuplicateCheck {
int score = 0;
for (String field : allFields) {
- Optional<String> stringOne = one.getFieldOptional(field);
- Optional<String> stringTwo = two.getFieldOptional(field);
+ Optional<String> stringOne = one.getField(field);
+ Optional<String> stringTwo = two.getField(field);
if (stringOne.equals(stringTwo)) {
score++;
}
diff --git a/src/main/java/net/sf/jabref/model/EntryTypes.java b/src/main/java/net/sf/jabref/model/EntryTypes.java
index ec4cd43..f7a73a7 100644
--- a/src/main/java/net/sf/jabref/model/EntryTypes.java
+++ b/src/main/java/net/sf/jabref/model/EntryTypes.java
@@ -1,5 +1,6 @@
package net.sf.jabref.model;
+import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
@@ -26,8 +27,10 @@ public class EntryTypes {
private final Map<String, EntryType> STANDARD_TYPES;
private final EntryType defaultType;
- public InternalEntryTypes(EntryType defaultType, List<EntryType>... entryTypes) {
+
+ public InternalEntryTypes(EntryType defaultType, List<List<EntryType>> entryTypes) {
this.defaultType = defaultType;
+
for (List<EntryType> list : entryTypes) {
for (EntryType type : list) {
ALL_TYPES.put(type.getName().toLowerCase(), type);
@@ -95,8 +98,11 @@ public class EntryTypes {
}
- public static final InternalEntryTypes BIBTEX = new InternalEntryTypes(BibtexEntryTypes.MISC, BibtexEntryTypes.ALL, IEEETranEntryTypes.ALL);
- public static final InternalEntryTypes BIBLATEX = new InternalEntryTypes(BibLatexEntryTypes.MISC, BibLatexEntryTypes.ALL);
+
+ public static final InternalEntryTypes BIBTEX = new InternalEntryTypes(BibtexEntryTypes.MISC,
+ Arrays.asList(BibtexEntryTypes.ALL, IEEETranEntryTypes.ALL));
+ public static final InternalEntryTypes BIBLATEX = new InternalEntryTypes(BibLatexEntryTypes.MISC,
+ Arrays.asList(BibLatexEntryTypes.ALL));
/**
* This method returns the BibtexEntryType for the name of a type,
diff --git a/src/main/java/net/sf/jabref/model/bibtexkeypattern/AbstractBibtexKeyPattern.java b/src/main/java/net/sf/jabref/model/bibtexkeypattern/AbstractBibtexKeyPattern.java
index a8c8bcf..9dbdd26 100644
--- a/src/main/java/net/sf/jabref/model/bibtexkeypattern/AbstractBibtexKeyPattern.java
+++ b/src/main/java/net/sf/jabref/model/bibtexkeypattern/AbstractBibtexKeyPattern.java
@@ -7,6 +7,7 @@ import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.StringTokenizer;
+import java.util.stream.Collectors;
/**
* A small table, where an entry type is associated with a Bibtex key pattern (an
@@ -14,7 +15,7 @@ import java.util.StringTokenizer;
*/
public abstract class AbstractBibtexKeyPattern {
- protected List<String> defaultPattern;
+ protected List<String> defaultPattern = new ArrayList<>();
protected Map<String, List<String>> data = new HashMap<>();
@@ -76,7 +77,7 @@ public abstract class AbstractBibtexKeyPattern {
if (result == null) {
// check default value
result = getDefaultValue();
- if (result == null) {
+ if (result == null || result.isEmpty()) {
// we are the "last" to ask
// we don't have anything left
return getLastLevelBibtexKeyPattern(key);
@@ -131,6 +132,7 @@ public abstract class AbstractBibtexKeyPattern {
* @param bibtexKeyPattern the pattern to store
*/
public void setDefaultValue(String bibtexKeyPattern) {
+ Objects.requireNonNull(bibtexKeyPattern);
this.defaultPattern = AbstractBibtexKeyPattern.split(bibtexKeyPattern);
}
@@ -138,5 +140,10 @@ public abstract class AbstractBibtexKeyPattern {
return data.keySet();
}
+ public Map<String, List<String>> getPatterns() {
+ return data.entrySet().stream().collect(
+ Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
+ }
+
public abstract List<String> getLastLevelBibtexKeyPattern(String key);
}
diff --git a/src/main/java/net/sf/jabref/model/bibtexkeypattern/GlobalBibtexKeyPattern.java b/src/main/java/net/sf/jabref/model/bibtexkeypattern/GlobalBibtexKeyPattern.java
index 7eb0da3..5c1d4d1 100644
--- a/src/main/java/net/sf/jabref/model/bibtexkeypattern/GlobalBibtexKeyPattern.java
+++ b/src/main/java/net/sf/jabref/model/bibtexkeypattern/GlobalBibtexKeyPattern.java
@@ -10,6 +10,10 @@ public class GlobalBibtexKeyPattern extends AbstractBibtexKeyPattern {
defaultBibtexKeyPattern = bibtexKeyPattern;
}
+ public static GlobalBibtexKeyPattern fromPattern(String pattern) {
+ return new GlobalBibtexKeyPattern(split(pattern));
+ }
+
@Override
public List<String> getLastLevelBibtexKeyPattern(String key) {
return defaultBibtexKeyPattern;
diff --git a/src/main/java/net/sf/jabref/model/cleanup/CleanupJob.java b/src/main/java/net/sf/jabref/model/cleanup/CleanupJob.java
new file mode 100644
index 0000000..17c29fc
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/cleanup/CleanupJob.java
@@ -0,0 +1,16 @@
+package net.sf.jabref.model.cleanup;
+
+import java.util.List;
+
+import net.sf.jabref.model.FieldChange;
+import net.sf.jabref.model.entry.BibEntry;
+
+ at FunctionalInterface
+public interface CleanupJob {
+
+ /**
+ * Cleanup the entry.
+ */
+ List<FieldChange> cleanup(BibEntry entry);
+
+}
diff --git a/src/main/java/net/sf/jabref/model/cleanup/FieldFormatterCleanup.java b/src/main/java/net/sf/jabref/model/cleanup/FieldFormatterCleanup.java
new file mode 100644
index 0000000..2b459d6
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/cleanup/FieldFormatterCleanup.java
@@ -0,0 +1,120 @@
+package net.sf.jabref.model.cleanup;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+import net.sf.jabref.model.FieldChange;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldName;
+import net.sf.jabref.model.entry.event.EntryEventSource;
+
+/**
+ * Formats a given entry field with the specified formatter.
+ */
+public class FieldFormatterCleanup implements CleanupJob {
+
+ private final String field;
+ private final Formatter formatter;
+
+ public FieldFormatterCleanup(String field, Formatter formatter) {
+ this.field = field;
+ this.formatter = formatter;
+ }
+
+ @Override
+ public List<FieldChange> cleanup(BibEntry entry) {
+ if (FieldName.INTERNAL_ALL_FIELD.equalsIgnoreCase(field)) {
+ return cleanupAllFields(entry);
+ } else if (FieldName.INTERNAL_ALL_TEXT_FIELDS_FIELD.equalsIgnoreCase(field)) {
+ return cleanupAllTextFields(entry);
+ } else {
+ return cleanupSingleField(field, entry);
+ }
+ }
+
+ /**
+ * Runs the formatter on the specified field in the given entry.
+ *
+ * If the formatter returns an empty string, then the field is removed.
+ * @param fieldKey the field on which to run the formatter
+ * @param entry the entry to be cleaned up
+ * @return a list of changes of the entry
+ */
+ private List<FieldChange> cleanupSingleField(String fieldKey, BibEntry entry) {
+ if (!entry.hasField(fieldKey)) {
+ // Not set -> nothing to do
+ return new ArrayList<>();
+ }
+ String oldValue = entry.getField(fieldKey).orElse(null);
+
+ // Run formatter
+ String newValue = formatter.format(oldValue);
+
+ if (oldValue.equals(newValue)) {
+ return new ArrayList<>();
+ } else {
+ if(newValue.isEmpty()) {
+ entry.clearField(fieldKey);
+ newValue = null;
+ } else {
+ entry.setField(fieldKey, newValue, EntryEventSource.SAVE_ACTION);
+ }
+ FieldChange change = new FieldChange(entry, fieldKey, oldValue, newValue);
+ return Collections.singletonList(change);
+ }
+ }
+
+ private List<FieldChange> cleanupAllFields(BibEntry entry) {
+ List<FieldChange> fieldChanges = new ArrayList<>();
+
+ for (String fieldKey : entry.getFieldNames()) {
+ fieldChanges.addAll(cleanupSingleField(fieldKey, entry));
+ }
+
+ return fieldChanges;
+ }
+
+ private List<FieldChange> cleanupAllTextFields(BibEntry entry) {
+ List<FieldChange> fieldChanges = new ArrayList<>();
+ Set<String> fields = entry.getFieldNames();
+ fields.removeAll(FieldName.getNotTextFieldNames());
+ for (String fieldKey : fields) {
+ fieldChanges.addAll(cleanupSingleField(fieldKey, entry));
+ }
+
+ return fieldChanges;
+ }
+
+ public String getField() {
+ return field;
+ }
+
+ public Formatter getFormatter() {
+ return formatter;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o instanceof FieldFormatterCleanup) {
+ FieldFormatterCleanup that = (FieldFormatterCleanup) o;
+ return Objects.equals(field, that.field) && Objects.equals(formatter, that.formatter);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(field, formatter);
+ }
+
+ @Override
+ public String toString() {
+ return field + ": " + formatter.getName();
+ }
+}
diff --git a/src/main/java/net/sf/jabref/model/cleanup/FieldFormatterCleanups.java b/src/main/java/net/sf/jabref/model/cleanup/FieldFormatterCleanups.java
new file mode 100644
index 0000000..2961f6f
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/cleanup/FieldFormatterCleanups.java
@@ -0,0 +1,122 @@
+package net.sf.jabref.model.cleanup;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.StringJoiner;
+
+import net.sf.jabref.model.FieldChange;
+import net.sf.jabref.model.entry.BibEntry;
+
+public class FieldFormatterCleanups {
+
+ public static final String ENABLED = "enabled";
+ public static final String DISABLED = "disabled";
+
+ private final List<FieldFormatterCleanup> actions;
+
+ private final boolean enabled;
+
+ public FieldFormatterCleanups(boolean enabled, List<FieldFormatterCleanup> actions) {
+ this.enabled = enabled;
+ this.actions = Objects.requireNonNull(actions);
+ }
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public List<FieldFormatterCleanup> getConfiguredActions() {
+ return Collections.unmodifiableList(actions);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if ((o == null) || (getClass() != o.getClass())) {
+ return false;
+ }
+
+ FieldFormatterCleanups that = (FieldFormatterCleanups) o;
+
+ if (enabled != that.enabled) {
+ return false;
+ }
+ return actions.equals(that.actions);
+
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(actions, enabled);
+ }
+
+ public List<FieldChange> applySaveActions(BibEntry entry) {
+ if (enabled) {
+ return applyAllActions(entry);
+ } else {
+ return new ArrayList<>();
+ }
+ }
+
+ private List<FieldChange> applyAllActions(BibEntry entry) {
+ List<FieldChange> result = new ArrayList<>();
+
+ for (FieldFormatterCleanup action : actions) {
+ result.addAll(action.cleanup(entry));
+ }
+
+ return result;
+ }
+
+ public List<String> getAsStringList(String newline) {
+ List<String> stringRepresentation = new ArrayList<>();
+
+ if (enabled) {
+ stringRepresentation.add(ENABLED);
+ } else {
+ stringRepresentation.add(DISABLED);
+ }
+
+ String formatterString = getMetaDataString(actions, newline);
+ stringRepresentation.add(formatterString);
+ return stringRepresentation;
+ }
+
+ private static String getMetaDataString(List<FieldFormatterCleanup> actionList, String newline) {
+ //first, group all formatters by the field for which they apply
+ Map<String, List<String>> groupedByField = new HashMap<>();
+ for (FieldFormatterCleanup cleanup : actionList) {
+ String key = cleanup.getField();
+
+ // add new list into the hashmap if needed
+ if (!groupedByField.containsKey(key)) {
+ groupedByField.put(key, new ArrayList<>());
+ }
+
+ //add the formatter to the map if it is not already there
+ List<String> formattersForKey = groupedByField.get(key);
+ if (!formattersForKey.contains(cleanup.getFormatter().getKey())) {
+ formattersForKey.add(cleanup.getFormatter().getKey());
+ }
+ }
+
+ // convert the contents of the hashmap into the correct serialization
+ StringBuilder result = new StringBuilder();
+ for (Map.Entry<String, List<String>> entry : groupedByField.entrySet()) {
+ result.append(entry.getKey());
+
+ StringJoiner joiner = new StringJoiner(",", "[", "]" + newline);
+ entry.getValue().forEach(joiner::add);
+ result.append(joiner.toString());
+ }
+
+ return result.toString();
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/model/cleanup/Formatter.java b/src/main/java/net/sf/jabref/model/cleanup/Formatter.java
new file mode 100644
index 0000000..95f6607
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/cleanup/Formatter.java
@@ -0,0 +1,74 @@
+package net.sf.jabref.model.cleanup;
+
+/**
+ * The Formatter is used for a Filter design-pattern. Implementing classes have to accept a String and returned a
+ * formatted version of it.
+ *
+ * Example:
+ *
+ * "John von Neumann" => "von Neumann, John"
+ *
+ */
+public interface Formatter {
+ /**
+ * Returns a human readable name of the formatter usable for e.g. in the GUI
+ *
+ * @return the name of the formatter, always not null
+ */
+ String getName();
+
+
+ /**
+ * Returns a unique key for the formatter that can be used for its identification
+ * @return the key of the formatter, always not null
+ */
+ String getKey();
+
+ /**
+ * Formats a field value by with a particular formatter transformation.
+ *
+ * Calling this method with a null argument results in a NullPointerException.
+ *
+ * @param value the input String
+ * @return the formatted output String
+ */
+ String format(String value);
+
+ /**
+ * Returns a description of the formatter.
+ *
+ * @return the description string, always non empty
+ */
+ String getDescription();
+
+ /**
+ * Returns an example input string of the formatter.
+ * This example is used as input to the formatter to demonstrate its functionality
+ *
+ * @return the example input string, always non empty
+ */
+ String getExampleInput();
+
+ /**
+ * Returns a default hashcode of the formatter based on its key.
+ *
+ * @return the hash of the key of the formatter
+ */
+ default int defaultHashCode() {
+ return getKey().hashCode();
+ }
+
+ /**
+ * Indicates whether some other object is the same formatter as this one based on the key.
+ *
+ * @param obj the object to compare the formatter to
+ * @return true if the object is a formatter with the same key
+ */
+ default boolean defaultEquals(Object obj) {
+ if(obj instanceof Formatter) {
+ return getKey().equals(((Formatter)obj).getKey());
+ } else {
+ return false;
+ }
+ }
+}
diff --git a/src/main/java/net/sf/jabref/model/database/BibDatabase.java b/src/main/java/net/sf/jabref/model/database/BibDatabase.java
index b67273a..87ca8a7 100644
--- a/src/main/java/net/sf/jabref/model/database/BibDatabase.java
+++ b/src/main/java/net/sf/jabref/model/database/BibDatabase.java
@@ -1,5 +1,7 @@
package net.sf.jabref.model.database;
+import java.math.BigInteger;
+import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -13,20 +15,19 @@ import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;
+import java.util.stream.Collectors;
-import net.sf.jabref.event.source.EntryEventSource;
-import net.sf.jabref.model.EntryTypes;
+import net.sf.jabref.model.database.event.EntryAddedEvent;
+import net.sf.jabref.model.database.event.EntryRemovedEvent;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.BibtexString;
-import net.sf.jabref.model.entry.EntryType;
-import net.sf.jabref.model.entry.EntryUtil;
import net.sf.jabref.model.entry.FieldName;
import net.sf.jabref.model.entry.InternalBibtexFields;
import net.sf.jabref.model.entry.MonthUtil;
-import net.sf.jabref.model.event.EntryAddedEvent;
-import net.sf.jabref.model.event.EntryChangedEvent;
-import net.sf.jabref.model.event.EntryRemovedEvent;
-import net.sf.jabref.model.event.FieldChangedEvent;
+import net.sf.jabref.model.entry.event.EntryChangedEvent;
+import net.sf.jabref.model.entry.event.EntryEventSource;
+import net.sf.jabref.model.entry.event.FieldChangedEvent;
+import net.sf.jabref.model.strings.StringUtil;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
@@ -60,11 +61,13 @@ public class BibDatabase {
*/
private final Set<String> internalIDs = new HashSet<>();
-
private final EventBus eventBus = new EventBus();
+ private String sharedDatabaseID;
+
public BibDatabase() {
+ this.eventBus.register(duplicationChecker);
this.registerListener(new KeyChangeListener(this));
}
@@ -101,22 +104,19 @@ public class BibDatabase {
return Collections.unmodifiableList(entries);
}
+ /**
+ * Returns a set of Strings, that contains all field names that are visible. This means that the fields
+ * are not internal fields. Internal fields are fields, that are starting with "_".
+ *
+ * @return set of fieldnames, that are visible
+ */
public Set<String> getAllVisibleFields() {
Set<String> allFields = new TreeSet<>();
for (BibEntry e : getEntries()) {
allFields.addAll(e.getFieldNames());
}
- Set<String> toberemoved = new TreeSet<>();
- for (String field : allFields) {
- if (InternalBibtexFields.isInternalField(field)) {
- toberemoved.add(field);
- }
- }
-
- for (String field : toberemoved) {
- allFields.remove(field);
- }
- return allFields;
+ return allFields.stream().filter(field -> !InternalBibtexFields.isInternalField(field))
+ .collect(Collectors.toSet());
}
/**
@@ -131,6 +131,13 @@ public class BibDatabase {
return Optional.empty();
}
+ /**
+ * Collects entries having the specified BibTeX key and returns these entries as list.
+ * The order of the entries is the order they appear in the database.
+ *
+ * @param key
+ * @return list of entries that contains the given key
+ */
public synchronized List<BibEntry> getEntriesByKey(String key) {
List<BibEntry> result = new ArrayList<>();
@@ -164,8 +171,7 @@ public class BibDatabase {
* @param eventSource Source the event is sent from
* @return false if the insert was done without a duplicate warning
*/
- public synchronized boolean insertEntry(BibEntry entry, EntryEventSource eventSource)
- throws KeyCollisionException {
+ public synchronized boolean insertEntry(BibEntry entry, EntryEventSource eventSource) throws KeyCollisionException {
Objects.requireNonNull(entry);
String id = entry.getId();
@@ -178,7 +184,7 @@ public class BibDatabase {
entry.registerListener(this);
eventBus.post(new EntryAddedEvent(entry, eventSource));
- return duplicationChecker.checkForDuplicateKeyAndAdd(null, entry.getCiteKeyOptional().orElse(null));
+ return duplicationChecker.isDuplicateCiteKeyExisting(entry);
}
/**
@@ -193,34 +199,20 @@ public class BibDatabase {
/**
* Removes the given entry.
* The Entry is removed based on the id {@link BibEntry#id}
+ *
* @param toBeDeleted Entry to delete
* @param eventSource Source the event is sent from
*/
public synchronized void removeEntry(BibEntry toBeDeleted, EntryEventSource eventSource) {
Objects.requireNonNull(toBeDeleted);
- boolean anyRemoved = entries.removeIf(entry -> entry.getId().equals(toBeDeleted.getId()));
+ boolean anyRemoved = entries.removeIf(entry -> entry.getId().equals(toBeDeleted.getId()));
if (anyRemoved) {
internalIDs.remove(toBeDeleted.getId());
- toBeDeleted.getCiteKeyOptional().ifPresent(duplicationChecker::removeKeyFromSet);
eventBus.post(new EntryRemovedEvent(toBeDeleted, eventSource));
}
}
- public int getNumberOfKeyOccurrences(String key) {
- return duplicationChecker.getNumberOfKeyOccurrences(key);
- }
-
- public synchronized boolean setCiteKeyForEntry(BibEntry entry, String key) {
- String oldKey = entry.getCiteKeyOptional().orElse(null);
- if (key == null) {
- entry.clearField(BibEntry.KEY_FIELD);
- } else {
- entry.setCiteKey(key);
- }
- return duplicationChecker.checkForDuplicateKeyAndAdd(oldKey, key);
- }
-
/**
* Sets the database's preamble.
*/
@@ -230,22 +222,26 @@ public class BibDatabase {
/**
* Returns the database's preamble.
+ * If the preamble text consists only of whitespace, then also an empty optional is returned.
*/
- public synchronized String getPreamble() {
- return preamble;
+ public synchronized Optional<String> getPreamble() {
+ if (StringUtil.isBlank(preamble)) {
+ return Optional.empty();
+ } else {
+ return Optional.of(preamble);
+ }
}
/**
* Inserts a Bibtex String.
*/
- public synchronized void addString(BibtexString string)
- throws KeyCollisionException {
+ public synchronized void addString(BibtexString string) throws KeyCollisionException {
if (hasStringLabel(string.getName())) {
throw new KeyCollisionException("A string with that label already exists");
}
if (bibtexStrings.containsKey(string.getId())) {
- throw new KeyCollisionException("Duplicate BibTeXString id.");
+ throw new KeyCollisionException("Duplicate BibTeX string id.");
}
bibtexStrings.put(string.getId(), string);
@@ -301,7 +297,7 @@ public class BibDatabase {
* @param database another BibDatabase
*/
public void copyPreamble(BibDatabase database) {
- setPreamble(database.getPreamble());
+ setPreamble(database.getPreamble().orElse(""));
}
/**
@@ -429,8 +425,10 @@ public class BibDatabase {
}
}
+
private static final Pattern RESOLVE_CONTENT_PATTERN = Pattern.compile(".*#[^#]+#.*");
+
private String resolveContent(String result, Set<String> usedIds) {
String res = result;
if (RESOLVE_CONTENT_PATTERN.matcher(res).matches()) {
@@ -479,68 +477,16 @@ public class BibDatabase {
return res;
}
-
-
/**
- * Returns the text stored in the given field of the given bibtex entry
- * which belongs to the given database.
- * <p>
- * If a database is given, this function will try to resolve any string
- * references in the field-value.
- * Also, if a database is given, this function will try to find values for
- * unset fields in the entry linked by the "crossref" field, if any.
+ * @deprecated use {@link BibDatabase#resolveForStrings(String)}
*
- * @param field The field to return the value of.
- * @param entry The bibtex entry which contains the field.
- * @param database maybenull
- * The database of the bibtex entry.
- * @return The resolved field value or null if not found.
- */
- public static Optional<String> getResolvedField(String field, BibEntry entry, BibDatabase database) {
- Objects.requireNonNull(entry, "entry cannot be null");
-
- if (BibEntry.TYPE_HEADER.equals(field) || BibEntry.OBSOLETE_TYPE_HEADER.equals(field)) {
- Optional<EntryType> entryType = EntryTypes.getType(entry.getType(), BibDatabaseMode.BIBLATEX);
- if (entryType.isPresent()) {
- return Optional.of(entryType.get().getName());
- } else {
- return Optional.of(EntryUtil.capitalizeFirst(entry.getType()));
- }
- }
-
- if (BibEntry.KEY_FIELD.equals(field)) {
- return entry.getCiteKeyOptional();
- }
-
- // TODO: Changed this to also consider alias fields, which is the expected
- // behavior for the preview layout and for the check whatever all fields are present.
- // But there might be unwanted side-effects?!
- Optional<String> result = entry.getFieldOrAlias(field);
-
- // If this field is not set, and the entry has a crossref, try to look up the
- // field in the referred entry: Do not do this for the bibtex key.
- if (!result.isPresent() && (database != null)) {
- Optional<String> crossrefKey = entry.getFieldOptional(FieldName.CROSSREF);
- if (crossrefKey.isPresent() && !crossrefKey.get().isEmpty()) {
- Optional<BibEntry> referred = database.getEntryByKey(crossrefKey.get());
- if (referred.isPresent()) {
- // Ok, we found the referred entry. Get the field value from that
- // entry. If it is unset there, too, stop looking:
- result = referred.get().getFieldOrAlias(field);
- }
- }
- }
-
- return result.map(resultText -> BibDatabase.getText(resultText, database));
- }
-
- /**
* Returns a text with references resolved according to an optionally given database.
*
* @param toResolve maybenull The text to resolve.
* @param database maybenull The database to use for resolving the text.
* @return The resolved text or the original text if either the text or the database are null
*/
+ @Deprecated
public static String getText(String toResolve, BibDatabase database) {
if ((toResolve != null) && (database != null)) {
return database.resolveForStrings(toResolve);
@@ -582,4 +528,38 @@ public class BibDatabase {
private void relayEntryChangeEvent(FieldChangedEvent event) {
eventBus.post(event);
}
+
+ public Optional<BibEntry> getReferencedEntry(BibEntry entry) {
+ return entry.getField(FieldName.CROSSREF).flatMap(this::getEntryByKey);
+ }
+
+ public Optional<String> getSharedDatabaseID() {
+ return Optional.ofNullable(this.sharedDatabaseID);
+ }
+
+ public boolean isShared() {
+ return getSharedDatabaseID().isPresent();
+ }
+
+ public void setSharedDatabaseID(String sharedDatabaseID) {
+ this.sharedDatabaseID = sharedDatabaseID;
+ }
+
+ public void clearSharedDatabaseID() {
+ this.sharedDatabaseID = null;
+ }
+
+ /**
+ * Generates and sets a random ID which is globally unique.
+ *
+ * @return The generated sharedDatabaseID
+ */
+ public String generateSharedDatabaseID() {
+ this.sharedDatabaseID = new BigInteger(128, new SecureRandom()).toString(32);
+ return this.sharedDatabaseID;
+ }
+
+ public DuplicationChecker getDuplicationChecker() {
+ return duplicationChecker;
+ }
}
diff --git a/src/main/java/net/sf/jabref/model/database/BibDatabaseContext.java b/src/main/java/net/sf/jabref/model/database/BibDatabaseContext.java
new file mode 100644
index 0000000..01603fc
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/database/BibDatabaseContext.java
@@ -0,0 +1,262 @@
+package net.sf.jabref.model.database;
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+import net.sf.jabref.model.Defaults;
+import net.sf.jabref.model.bibtexkeypattern.GlobalBibtexKeyPattern;
+import net.sf.jabref.model.entry.FieldName;
+import net.sf.jabref.model.metadata.FileDirectoryPreferences;
+import net.sf.jabref.model.metadata.MetaData;
+import net.sf.jabref.shared.DBMSSynchronizer;
+
+/**
+ * Represents everything related to a BIB file.
+ * <p>
+ * The entries are stored in BibDatabase, the other data in MetaData and the options relevant for this file in Defaults.
+ */
+public class BibDatabaseContext {
+
+ private final BibDatabase database;
+ private MetaData metaData;
+ private final Defaults defaults;
+ /** The file where this database was last saved to. */
+ private File file;
+ private DBMSSynchronizer dbmsSynchronizer;
+ private DatabaseLocation location;
+
+ public BibDatabaseContext() {
+ this(new Defaults());
+ }
+
+ public BibDatabaseContext(Defaults defaults) {
+ this(new BibDatabase(), defaults);
+ }
+
+ public BibDatabaseContext(BibDatabase database) {
+ this(database, new Defaults());
+ }
+
+ public BibDatabaseContext(BibDatabase database, Defaults defaults) {
+ this(database, new MetaData(), defaults);
+ }
+
+ public BibDatabaseContext(BibDatabase database, MetaData metaData, Defaults defaults) {
+ this.defaults = Objects.requireNonNull(defaults);
+ this.database = Objects.requireNonNull(database);
+ this.metaData = Objects.requireNonNull(metaData);
+ this.location = DatabaseLocation.LOCAL;
+ }
+
+ public BibDatabaseContext(BibDatabase database, MetaData metaData) {
+ this(database, metaData, new Defaults());
+ }
+
+ public BibDatabaseContext(BibDatabase database, MetaData metaData, File file, Defaults defaults,
+ DatabaseLocation location) {
+ this(database, metaData, defaults);
+ Objects.requireNonNull(location);
+ this.setDatabaseFile(file);
+
+ if (location == DatabaseLocation.LOCAL) {
+ convertToLocalDatabase();
+ }
+ }
+
+ public BibDatabaseContext(BibDatabase database, MetaData metaData, File file, Defaults defaults) {
+ this(database, metaData, file, defaults, DatabaseLocation.LOCAL);
+ }
+
+ public BibDatabaseContext(BibDatabase database, MetaData metaData, File file) {
+ this(database, metaData, file, new Defaults());
+ }
+
+ public BibDatabaseContext(Defaults defaults, DatabaseLocation location, Character keywordSeparator,
+ GlobalBibtexKeyPattern globalCiteKeyPattern) {
+ this(new BibDatabase(), new MetaData(), defaults);
+ if (location == DatabaseLocation.SHARED) {
+ convertToSharedDatabase(keywordSeparator, globalCiteKeyPattern);
+ }
+ }
+
+ public BibDatabaseMode getMode() {
+ Optional<BibDatabaseMode> mode = metaData.getMode();
+
+ if (!mode.isPresent()) {
+ BibDatabaseMode inferredMode = BibDatabaseModeDetection.inferMode(database);
+ BibDatabaseMode newMode = BibDatabaseMode.BIBTEX;
+ if ((defaults.mode == BibDatabaseMode.BIBLATEX) || (inferredMode == BibDatabaseMode.BIBLATEX)) {
+ newMode = BibDatabaseMode.BIBLATEX;
+ }
+ this.setMode(newMode);
+ return newMode;
+ }
+ return mode.get();
+ }
+
+ public void setMode(BibDatabaseMode bibDatabaseMode) {
+ metaData.setMode(bibDatabaseMode);
+ }
+
+ /**
+ * Get the file where this database was last saved to or loaded from, if any.
+ *
+ * @return Optional of the relevant File, or Optional.empty() if none is defined.
+ * @deprecated use {@link #getDatabasePath()} instead
+ */
+ @Deprecated
+ public Optional<File> getDatabaseFile() {
+ return Optional.ofNullable(file);
+ }
+
+ public Optional<Path> getDatabasePath() {
+ return Optional.ofNullable(file).map(File::toPath);
+ }
+
+ public void setDatabaseFile(File file) {
+ this.file = file;
+ }
+
+ public void clearDatabaseFile() {
+ this.file = null;
+ }
+
+ public BibDatabase getDatabase() {
+ return database;
+ }
+
+ public MetaData getMetaData() {
+ return metaData;
+ }
+
+ public void setMetaData(MetaData metaData) {
+ this.metaData = Objects.requireNonNull(metaData);
+ }
+
+ public boolean isBiblatexMode() {
+ return getMode() == BibDatabaseMode.BIBLATEX;
+ }
+
+ public List<String> getFileDirectories(FileDirectoryPreferences preferences) {
+ return getFileDirectories(FieldName.FILE, preferences);
+ }
+
+ /**
+ * Returns the first existing file directory from {@link #getFileDirectories(FileDirectoryPreferences)}
+ * @param preferences The FileDirectoryPreferences
+ * @return Optional of Path
+ */
+ public Optional<Path> getFirstExistingFileDir(FileDirectoryPreferences preferences) {
+ return getFileDirectories(preferences).stream().filter(s -> !s.isEmpty()).map(p -> Paths.get(p))
+ .filter(Files::exists).findFirst();
+ //Filter for empty string, as this would be expanded to the jar-directory with Paths.get()
+ }
+
+ /**
+ * Look up the directories set up for the given field type for this database.
+ * If no directory is set up, return that defined in global preferences.
+ * There can be up to three directory definitions for these files:
+ * the database's metadata can specify a general directory and/or a user-specific directory
+ * or the preferences can specify one.
+ * <p>
+ * The settings are prioritized in the following order and the first defined setting is used:
+ * 1. metadata user-specific directory
+ * 2. metadata general directory
+ * 3. preferences directory
+ * 4. BIB file directory
+ *
+ * @param
+ * @param fieldName The field type
+ * @return The default directory for this field type.
+ */
+ public List<String> getFileDirectories(String fieldName, FileDirectoryPreferences preferences) {
+ List<String> fileDirs = new ArrayList<>();
+
+ // 1. metadata user-specific directory
+ Optional<String> userFileDirectory = metaData.getUserFileDirectory(preferences.getUser());
+ if (userFileDirectory.isPresent()) {
+ fileDirs.add(getFileDirectoryPath(userFileDirectory.get()));
+ }
+
+ // 2. metadata general directory
+ Optional<String> metaDataDirectory = metaData.getDefaultFileDirectory();
+ if (metaDataDirectory.isPresent()) {
+ fileDirs.add(getFileDirectoryPath(metaDataDirectory.get()));
+ }
+
+ // 3. preferences directory
+ preferences.getFileDirectory(fieldName).ifPresent(path ->
+ fileDirs.add(path.toAbsolutePath().toString())
+ );
+
+ // 4. BIB file directory
+ getDatabasePath().ifPresent(dbPath -> {
+ String parentDir = dbPath.getParent().toAbsolutePath().toString();
+ // Check if we should add it as primary file dir (first in the list) or not:
+ if (preferences.isBibLocationAsPrimary()) {
+ fileDirs.add(0, parentDir);
+ } else {
+ fileDirs.add(parentDir);
+ }
+ });
+
+ return fileDirs;
+ }
+
+ private String getFileDirectoryPath(String directoryName) {
+ String dir = directoryName;
+ // If this directory is relative, we try to interpret it as relative to
+ // the file path of this BIB file:
+ Optional<File> databaseFile = getDatabaseFile();
+ if (!new File(dir).isAbsolute() && databaseFile.isPresent()) {
+ String relDir;
+ if (".".equals(dir)) {
+ // if dir is only "current" directory, just use its parent (== real current directory) as path
+ relDir = databaseFile.get().getParent();
+ } else {
+ relDir = databaseFile.get().getParent() + File.separator + dir;
+ }
+ // If this directory actually exists, it is very likely that the
+ // user wants us to use it:
+ if (new File(relDir).exists()) {
+ dir = relDir;
+ }
+ }
+ return dir;
+ }
+
+ public DBMSSynchronizer getDBMSSynchronizer() {
+ return this.dbmsSynchronizer;
+ }
+
+ public void clearDBMSSynchronizer() {
+ this.dbmsSynchronizer = null;
+ }
+
+ public DatabaseLocation getLocation() {
+ return this.location;
+ }
+
+ public void convertToSharedDatabase(Character keywordSeparator, GlobalBibtexKeyPattern globalCiteKeyPattern) {
+ this.dbmsSynchronizer = new DBMSSynchronizer(this, keywordSeparator, globalCiteKeyPattern);
+ this.database.registerListener(dbmsSynchronizer);
+ this.metaData.registerListener(dbmsSynchronizer);
+
+ this.location = DatabaseLocation.SHARED;
+ }
+
+ public void convertToLocalDatabase() {
+ if (Objects.nonNull(dbmsSynchronizer) && (location == DatabaseLocation.SHARED)) {
+ this.database.unregisterListener(dbmsSynchronizer);
+ this.metaData.unregisterListener(dbmsSynchronizer);
+ }
+
+ this.location = DatabaseLocation.LOCAL;
+ }
+}
diff --git a/src/main/java/net/sf/jabref/model/database/BibDatabaseMode.java b/src/main/java/net/sf/jabref/model/database/BibDatabaseMode.java
index 54b402d..a2b40d7 100644
--- a/src/main/java/net/sf/jabref/model/database/BibDatabaseMode.java
+++ b/src/main/java/net/sf/jabref/model/database/BibDatabaseMode.java
@@ -2,34 +2,66 @@ package net.sf.jabref.model.database;
import java.util.Locale;
+/**
+ * An enum which contains the possible {@link BibDatabase} Modes.
+ * Possible are BibTeX and BibLaTeX.
+ */
public enum BibDatabaseMode {
BIBTEX,
BIBLATEX;
+ /**
+ * @return the name of the current mode as String
+ */
public String getFormattedName() {
- if(this == BIBTEX) {
+ if (this == BIBTEX) {
return "BibTeX";
} else {
return "BibLaTeX";
}
}
+ /**
+ * Returns the opposite mode of the current mode as {@link BibDatabaseMode}.
+ *
+ * @return BibLaTeX if the current mode is BIBTEX, BibTeX else
+ */
public BibDatabaseMode getOppositeMode() {
- if(this == BIBTEX) {
+ if (this == BIBTEX) {
return BIBLATEX;
} else {
return BIBTEX;
}
}
+ /**
+ * Returns the {@link BibDatabaseMode} from a given boolean.
+ *
+ * @return BIBLATEX if isBibLatex is true, else BIBTEX
+ */
public static BibDatabaseMode fromPreference(boolean isBibLatex) {
- return isBibLatex ? BIBLATEX : BIBTEX;
+ if (isBibLatex) {
+ return BIBLATEX;
+ } else {
+ return BIBTEX;
+ }
}
+ /**
+ * Returns the {@link BibDatabaseMode} that equals the given string. The use of capital and small letters
+ * in the string doesn't matter.If neither "bibtex" nor "biblatex" is the given string, then an
+ * {@link IllegalArgumentException} will be thrown.
+ *
+ * @return BIBTEX, if the string is bibtex<br>
+ * BIBLATEX, if the string is biblatex<br>
+ */
public static BibDatabaseMode parse(String data) {
return BibDatabaseMode.valueOf(data.toUpperCase(Locale.ENGLISH));
}
+ /**
+ * @return The current mode as String in lowercase
+ */
public String getAsString() {
return getFormattedName().toLowerCase(Locale.ENGLISH);
}
diff --git a/src/main/java/net/sf/jabref/model/database/BibDatabaseModeDetection.java b/src/main/java/net/sf/jabref/model/database/BibDatabaseModeDetection.java
index 992b6d3..43aafbe 100644
--- a/src/main/java/net/sf/jabref/model/database/BibDatabaseModeDetection.java
+++ b/src/main/java/net/sf/jabref/model/database/BibDatabaseModeDetection.java
@@ -1,6 +1,7 @@
package net.sf.jabref.model.database;
import java.util.List;
+import java.util.Locale;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -11,9 +12,10 @@ import net.sf.jabref.model.entry.BibtexEntryTypes;
import net.sf.jabref.model.entry.EntryType;
public class BibDatabaseModeDetection {
- private static final List<EntryType> bibtex = BibtexEntryTypes.ALL;
- private static final List<EntryType> biblatex = BibLatexEntryTypes.ALL;
- private static final List<String> exclusiveBiblatex = filterEntryTypesNames(biblatex, isNotIncludedIn(bibtex));
+
+ private static final List<EntryType> BIBTEX = BibtexEntryTypes.ALL;
+ private static final List<EntryType> BIBLATEX = BibLatexEntryTypes.ALL;
+ private static final List<String> EXCLUSIVE_BIBLATEX = filterEntryTypesNames(BIBLATEX, isNotIncludedIn(BIBTEX));
/**
* Tries to infer the database type by examining a BibDatabase database.
@@ -32,7 +34,7 @@ public class BibDatabaseModeDetection {
final Stream<String> entryTypes = database.getEntries().stream().map(BibEntry::getType);
// type-based check
- if (entryTypes.anyMatch(type -> exclusiveBiblatex.contains(type.toLowerCase()))) {
+ if (entryTypes.anyMatch(type -> EXCLUSIVE_BIBLATEX.contains(type.toLowerCase(Locale.ENGLISH)))) {
return BibDatabaseMode.BIBLATEX;
} else {
// field-based check
diff --git a/src/main/java/net/sf/jabref/model/database/BibDatabases.java b/src/main/java/net/sf/jabref/model/database/BibDatabases.java
index 4318f60..badc1a8 100644
--- a/src/main/java/net/sf/jabref/model/database/BibDatabases.java
+++ b/src/main/java/net/sf/jabref/model/database/BibDatabases.java
@@ -9,6 +9,13 @@ import net.sf.jabref.model.entry.IdGenerator;
public class BibDatabases {
+ /**
+ * Gets a collection of bibentries and sets an ID for every entry. After that
+ * all entries will be inserted into a new BibDatabase.
+ *
+ * @param bibentries a collection that contains {@link BibEntry}
+ * @return BibDatabase that contains the entries
+ */
public static BibDatabase createDatabase(Collection<BibEntry> bibentries) {
BibDatabase database = new BibDatabase();
diff --git a/src/main/java/net/sf/jabref/model/database/DatabaseLocation.java b/src/main/java/net/sf/jabref/model/database/DatabaseLocation.java
index 0c0fa85..e93a72f 100644
--- a/src/main/java/net/sf/jabref/model/database/DatabaseLocation.java
+++ b/src/main/java/net/sf/jabref/model/database/DatabaseLocation.java
@@ -1,7 +1,5 @@
package net.sf.jabref.model.database;
-import net.sf.jabref.BibDatabaseContext;
-
/**
* This enum represents the location for {@link BibDatabaseContext}.
*/
diff --git a/src/main/java/net/sf/jabref/model/database/DuplicationChecker.java b/src/main/java/net/sf/jabref/model/database/DuplicationChecker.java
index b21ebce..a7f429d 100644
--- a/src/main/java/net/sf/jabref/model/database/DuplicationChecker.java
+++ b/src/main/java/net/sf/jabref/model/database/DuplicationChecker.java
@@ -2,101 +2,109 @@ package net.sf.jabref.model.database;
import java.util.HashMap;
import java.util.Map;
+import java.util.Optional;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
+import net.sf.jabref.model.database.event.EntryAddedEvent;
+import net.sf.jabref.model.database.event.EntryRemovedEvent;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.event.FieldChangedEvent;
+
+import com.google.common.eventbus.Subscribe;
/**
- * Determines which bibtex cite keys are duplicates in a single {@link BibDatabase}
+ * Determines which bibtex cite keys are duplicates in a single {@link BibDatabase}.
*/
-class DuplicationChecker {
-
- private static final Log LOGGER = LogFactory.getLog(DuplicationChecker.class);
+public class DuplicationChecker {
- // use a map instead of a set since i need to know how many of each key is in there
+ /** use a map instead of a set since I need to know how many of each key is in there */
private final Map<String, Integer> allKeys = new HashMap<>();
- //##########################################
- // usage:
- // isDuplicate=checkForDuplicateKeyAndAdd( null, b.getKey() , issueDuplicateWarning);
- //############################################
- // if the newkey already exists and is not the same as oldkey it will give a warning
- // else it will add the newkey to the to set and remove the oldkey
- public boolean checkForDuplicateKeyAndAdd(String oldKey, String newKey) {
- // LOGGER.debug(" checkForDuplicateKeyAndAdd [oldKey = " + oldKey + "] [newKey = " + newKey + "]");
-
- boolean duplicate;
- if (oldKey == null) {// this is a new entry so don't bother removing oldKey
- duplicate = addKeyToSet(newKey);
- } else {
- if (oldKey.equals(newKey)) {// were OK because the user did not change keys
- duplicate = false;
- } else {// user changed the key
-
- // removed the oldkey
- // But what if more than two have the same key?
- // this means that user can add another key and would not get a warning!
- // consider this: i add a key xxx, then i add another key xxx . I get a warning. I delete the key xxx. JBM
- // removes this key from the allKey. then I add another key xxx. I don't get a warning!
- // i need a way to count the number of keys of each type
- // hashmap=>int (increment each time)
-
- removeKeyFromSet(oldKey);
- duplicate = addKeyToSet(newKey);
- }
- }
- if (duplicate) {
- LOGGER.warn("Warning there is a duplicate key: " + newKey);
- }
- return duplicate;
+
+ /**
+ * Checks if there is more than one occurrence of this key
+ */
+ public boolean isDuplicateCiteKeyExisting(String citeKey) {
+ return getNumberOfKeyOccurrences(citeKey) > 1;
+ }
+
+ /**
+ * Checks if there is more than one occurrence of the cite key
+ */
+ public boolean isDuplicateCiteKeyExisting(BibEntry entry) {
+ return isDuplicateCiteKeyExisting(entry.getCiteKeyOptional().orElse(null));
}
/**
* Returns the number of occurrences of the given key in this database.
*/
- public int getNumberOfKeyOccurrences(String key) {
- Integer numberOfOccurrences = allKeys.get(key);
- if (numberOfOccurrences == null) {
- return 0;
- } else {
- return numberOfOccurrences;
+ public int getNumberOfKeyOccurrences(String citeKey) {
+ return allKeys.getOrDefault(citeKey, 0);
+ }
+
+ /**
+ * Helper function for counting the number of the key usages.
+ * Adds the given key to the internal keyset together with the count of it.
+ * The counter is increased if the key already exists, otherwise set to 1.
+ * <br>
+ * Special case: If a null or empty key is passed, it is not counted and thus not added.
+ *
+ * Reasoning:
+ * Consider this: I add a key xxx, then I add another key xxx. I get a warning. I delete the key xxx.
+ * Consider JabRef simply removing this key from a set of allKeys.
+ * Then I add another key xxx. I don't get a warning!
+ * Thus, I need a way to count the number of keys of each type.
+ * Solution: hashmap=>int (increment each time at add and decrement each time at remove)
+ */
+ private void addKeyToSet(String key) {
+ if (key == null || key.isEmpty()) {
+ return;
}
+ allKeys.put(key, getNumberOfKeyOccurrences(key) + 1);
}
- //========================================================
- // keep track of all the keys to warn if there are duplicates
- //========================================================
- public boolean addKeyToSet(String key) {
- if ((key == null) || key.isEmpty()) {
- return false;//don't put empty key
+ /**
+ * Helper function for counting the number of the key usages.
+ * Removes the given key from the internal keyset together with the count of it, if the key is set to 1.
+ * If it is not set to 1, the counter will be decreased.
+ * <br>
+ * Special case: If a null or empty key is passed, it is not counted and thus not removed.
+ */
+ private void removeKeyFromSet(String key) {
+ if (key == null || key.isEmpty()) {
+ return;
}
- boolean exists = false;
- if (allKeys.containsKey(key)) {
- // warning
- exists = true;
- allKeys.put(key, allKeys.get(key) + 1);// incrementInteger( allKeys.get(key)));
+
+ int numberOfKeyOccurrences = getNumberOfKeyOccurrences(key);
+ if (numberOfKeyOccurrences > 1) {
+ allKeys.put(key, numberOfKeyOccurrences - 1);
} else {
- allKeys.put(key, 1);
+ allKeys.remove(key);
}
- return exists;
}
- //========================================================
- // reduce the number of keys by 1. if this number goes to zero then remove from the set
- // note: there is a good reason why we should not use a hashset but use hashmap instead
- //========================================================
- public void removeKeyFromSet(String key) {
- if ((key == null) || key.isEmpty()) {
- return;
+ @Subscribe
+ public void listen(FieldChangedEvent fieldChangedEvent) {
+ if (fieldChangedEvent.getFieldName().equals(BibEntry.KEY_FIELD)) {
+ removeKeyFromSet(fieldChangedEvent.getOldValue());
+ addKeyToSet(fieldChangedEvent.getNewValue());
}
- if (allKeys.containsKey(key)) {
- Integer tI = allKeys.get(key); // if(allKeys.get(key) instanceof Integer)
- if (tI == 1) {
- allKeys.remove(key);
- } else {
- allKeys.put(key, tI - 1);//decrementInteger( tI ));
- }
+ }
+
+ @Subscribe
+ public void listen(EntryRemovedEvent entryRemovedEvent) {
+ Optional<String> citeKey = entryRemovedEvent.getBibEntry().getCiteKeyOptional();
+ if (citeKey.isPresent()) {
+ removeKeyFromSet(citeKey.get());
}
}
+
+ @Subscribe
+ public void listen(EntryAddedEvent entryAddedEvent) {
+ Optional<String> citekey = entryAddedEvent.getBibEntry().getCiteKeyOptional();
+ if (citekey.isPresent()) {
+ addKeyToSet(citekey.get());
+ }
+ }
+
}
diff --git a/src/main/java/net/sf/jabref/model/database/EntrySorter.java b/src/main/java/net/sf/jabref/model/database/EntrySorter.java
index a335734..0db4a3a 100644
--- a/src/main/java/net/sf/jabref/model/database/EntrySorter.java
+++ b/src/main/java/net/sf/jabref/model/database/EntrySorter.java
@@ -9,7 +9,6 @@ import net.sf.jabref.model.entry.BibEntry;
public class EntrySorter {
- // guarded by itself
private final List<BibEntry> entries;
public EntrySorter(List<BibEntry> entries, Comparator<BibEntry> comparator) {
diff --git a/src/main/java/net/sf/jabref/model/database/KeyChangeListener.java b/src/main/java/net/sf/jabref/model/database/KeyChangeListener.java
index a8ee325..ba2c5d4 100644
--- a/src/main/java/net/sf/jabref/model/database/KeyChangeListener.java
+++ b/src/main/java/net/sf/jabref/model/database/KeyChangeListener.java
@@ -4,11 +4,11 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import net.sf.jabref.model.database.event.EntryRemovedEvent;
import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.model.entry.FieldProperties;
+import net.sf.jabref.model.entry.FieldProperty;
import net.sf.jabref.model.entry.InternalBibtexFields;
-import net.sf.jabref.model.event.EntryRemovedEvent;
-import net.sf.jabref.model.event.FieldChangedEvent;
+import net.sf.jabref.model.entry.event.FieldChangedEvent;
import com.google.common.eventbus.Subscribe;
@@ -25,8 +25,8 @@ public class KeyChangeListener {
// Look for fields with FieldProperies.SINGLE_ENTRY_LINK or FieldProperties.MULTIPLE_ENTRY_LINK to speed up the search later
for (String fieldName : InternalBibtexFields.getAllPublicFieldNames()) {
- if (InternalBibtexFields.getFieldExtras(fieldName).contains(FieldProperties.SINGLE_ENTRY_LINK)
- || InternalBibtexFields.getFieldExtras(fieldName).contains(FieldProperties.MULTIPLE_ENTRY_LINK)) {
+ if (InternalBibtexFields.getFieldProperties(fieldName).contains(FieldProperty.SINGLE_ENTRY_LINK)
+ || InternalBibtexFields.getFieldProperties(fieldName).contains(FieldProperty.MULTIPLE_ENTRY_LINK)) {
keyFields.add(fieldName);
}
}
@@ -49,8 +49,8 @@ public class KeyChangeListener {
private void updateEntryLinks(String newKey, String oldKey) {
for (BibEntry entry : database.getEntries()) {
for (String field : keyFields) {
- entry.getFieldOptional(field).ifPresent(fieldContent -> {
- if (InternalBibtexFields.getFieldExtras(field).contains(FieldProperties.SINGLE_ENTRY_LINK)) {
+ entry.getField(field).ifPresent(fieldContent -> {
+ if (InternalBibtexFields.getFieldProperties(field).contains(FieldProperty.SINGLE_ENTRY_LINK)) {
replaceSingleKeyInField(newKey, oldKey, entry, field, fieldContent);
} else { // MULTIPLE_ENTRY_LINK
replaceKeyInMultiplesKeyField(newKey, oldKey, entry, field, fieldContent);
diff --git a/src/main/java/net/sf/jabref/model/database/event/AutosaveEvent.java b/src/main/java/net/sf/jabref/model/database/event/AutosaveEvent.java
new file mode 100644
index 0000000..9b8152d
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/database/event/AutosaveEvent.java
@@ -0,0 +1,8 @@
+package net.sf.jabref.model.database.event;
+
+/**
+ * This Event is fired from {@link net.sf.jabref.logic.autosaveandbackup.AutosaveManager} in case that a save task is pending.
+ */
+public class AutosaveEvent {
+ // no data
+}
diff --git a/src/main/java/net/sf/jabref/model/database/event/BibDatabaseContextChangedEvent.java b/src/main/java/net/sf/jabref/model/database/event/BibDatabaseContextChangedEvent.java
new file mode 100644
index 0000000..92da1de
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/database/event/BibDatabaseContextChangedEvent.java
@@ -0,0 +1,10 @@
+package net.sf.jabref.model.database.event;
+
+import net.sf.jabref.model.metadata.event.MetaDataChangedEvent;
+
+/**
+ * This Event is automatically fired at the same time as {@link EntryEvent}, {@link GroupUpdatedEvent} or {@link MetaDataChangedEvent}.
+ */
+public class BibDatabaseContextChangedEvent {
+ // no data
+}
diff --git a/src/main/java/net/sf/jabref/model/database/event/ChangePropagation.java b/src/main/java/net/sf/jabref/model/database/event/ChangePropagation.java
new file mode 100644
index 0000000..aaf7b9d
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/database/event/ChangePropagation.java
@@ -0,0 +1,6 @@
+package net.sf.jabref.model.database.event;
+
+
+public enum ChangePropagation {
+ POST_EVENT, DO_NOT_POST_EVENT
+}
diff --git a/src/main/java/net/sf/jabref/model/database/event/EntryAddedEvent.java b/src/main/java/net/sf/jabref/model/database/event/EntryAddedEvent.java
new file mode 100644
index 0000000..83c8ae7
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/database/event/EntryAddedEvent.java
@@ -0,0 +1,27 @@
+package net.sf.jabref.model.database.event;
+
+import net.sf.jabref.model.database.BibDatabase;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.event.EntryEvent;
+import net.sf.jabref.model.entry.event.EntryEventSource;
+
+/**
+ * {@link EntryAddedEvent} is fired when a new {@link BibEntry} was added to the {@link BibDatabase}.
+ */
+public class EntryAddedEvent extends EntryEvent {
+
+ /**
+ * @param bibEntry the entry which has been added
+ */
+ public EntryAddedEvent(BibEntry bibEntry) {
+ super(bibEntry);
+ }
+
+ /**
+ * @param bibEntry <code>BibEntry</code> object which has been added.
+ * @param location Location affected by this event
+ */
+ public EntryAddedEvent(BibEntry bibEntry, EntryEventSource location) {
+ super(bibEntry, location);
+ }
+}
diff --git a/src/main/java/net/sf/jabref/model/database/event/EntryRemovedEvent.java b/src/main/java/net/sf/jabref/model/database/event/EntryRemovedEvent.java
new file mode 100644
index 0000000..7d83a87
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/database/event/EntryRemovedEvent.java
@@ -0,0 +1,29 @@
+package net.sf.jabref.model.database.event;
+
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.event.EntryEvent;
+import net.sf.jabref.model.entry.event.EntryEventSource;
+
+/**
+ * <code>RemovedEntryEvent</code> is fired when a <code>BibEntry</code> was removed
+ * from the database.
+ */
+
+public class EntryRemovedEvent extends EntryEvent {
+
+ /**
+ * @param bibEntry <code>BibEntry</code> object which has been removed.
+ */
+ public EntryRemovedEvent(BibEntry bibEntry) {
+ super(bibEntry);
+ }
+
+ /**
+ * @param bibEntry <code>BibEntry</code> object which has been removed.
+ * @param location Location affected by this event
+ */
+ public EntryRemovedEvent(BibEntry bibEntry, EntryEventSource location) {
+ super(bibEntry, location);
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/model/entry/Author.java b/src/main/java/net/sf/jabref/model/entry/Author.java
index 94e1cac..8ed93c4 100644
--- a/src/main/java/net/sf/jabref/model/entry/Author.java
+++ b/src/main/java/net/sf/jabref/model/entry/Author.java
@@ -258,8 +258,8 @@ public class Author {
* @return abbreviated first name of the author (may consist of several
* tokens)
*/
- public String getFirstAbbr() {
- return firstAbbr;
+ public Optional<String> getFirstAbbr() {
+ return Optional.ofNullable(firstAbbr);
}
/**
@@ -301,7 +301,7 @@ public class Author {
*/
public String getLastOnly() {
if (vonPart == null) {
- return lastPart == null ? "" : lastPart;
+ return getLast().orElse("");
} else {
return lastPart == null ? vonPart : vonPart + ' ' + lastPart;
}
@@ -318,17 +318,11 @@ public class Author {
*/
public String getLastFirst(boolean abbr) {
StringBuilder res = new StringBuilder(getLastOnly());
- if (jrPart != null) {
- res.append(", ").append(jrPart);
- }
+ getJr().ifPresent(jr -> res.append(", ").append(jr));
if (abbr) {
- if (firstAbbr != null) {
- res.append(", ").append(firstAbbr);
- }
+ getFirstAbbr().ifPresent(firstA -> res.append(", ").append(firstA));
} else {
- if (firstPart != null) {
- res.append(", ").append(firstPart);
- }
+ getFirst().ifPresent(first -> res.append(", ").append(first));
}
return res.toString();
}
@@ -345,13 +339,12 @@ public class Author {
public String getFirstLast(boolean abbr) {
StringBuilder res = new StringBuilder();
if (abbr) {
- res.append(firstAbbr == null ? "" : firstAbbr + ' ').append(getLastOnly());
+ getFirstAbbr().map(firstA -> firstA + ' ').ifPresent(res::append);
} else {
- res.append(firstPart == null ? "" : firstPart + ' ').append(getLastOnly());
- }
- if (jrPart != null) {
- res.append(", ").append(jrPart);
+ getFirst().map(first -> first + ' ').ifPresent(res::append);
}
+ res.append(getLastOnly());
+ getJr().ifPresent(jr -> res.append(", ").append(jr));
return res.toString();
}
@@ -376,17 +369,9 @@ public class Author {
*/
public String getNameForAlphabetization() {
StringBuilder res = new StringBuilder();
- if (lastPart != null) {
- res.append(lastPart);
- }
- if (jrPart != null) {
- res.append(", ");
- res.append(jrPart);
- }
- if (firstAbbr != null) {
- res.append(", ");
- res.append(firstAbbr);
- }
+ getLast().ifPresent(res::append);
+ getJr().ifPresent(jr -> res.append(", ").append(jr));
+ getFirstAbbr().ifPresent(firstA -> res.append(", ").append(firstA));
while ((res.length() > 0) && (res.charAt(0) == '{')) {
res.deleteCharAt(0);
}
diff --git a/src/main/java/net/sf/jabref/model/entry/AuthorList.java b/src/main/java/net/sf/jabref/model/entry/AuthorList.java
index 6282bd5..6f205db 100644
--- a/src/main/java/net/sf/jabref/model/entry/AuthorList.java
+++ b/src/main/java/net/sf/jabref/model/entry/AuthorList.java
@@ -1,7 +1,11 @@
package net.sf.jabref.model.entry;
+import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
+import java.util.Locale;
import java.util.Objects;
import java.util.WeakHashMap;
import java.util.stream.Collectors;
@@ -130,6 +134,9 @@ public class AuthorList {
private static final WeakHashMap<String, AuthorList> AUTHOR_CACHE = new WeakHashMap<>();
+ // Avoid partition where these values are contained
+ private final static Collection<String> avoidTermsInLowerCase = Arrays.asList("jr", "sr", "jnr", "snr", "von", "zu", "van", "der");
+
/**
* Creates a new list of authors.
* <p>
@@ -157,6 +164,46 @@ public class AuthorList {
public static AuthorList parse(String authors) {
Objects.requireNonNull(authors);
+ // Handle case names in order lastname, firstname and separated by ","
+ // E.g., Ali Babar, M., Dingsøyr, T., Lago, P., van der Vliet, H.
+ if (!authors.toUpperCase(Locale.ENGLISH).contains(" AND ") && !authors.contains("{") && !authors.contains(";")) {
+ List<String> arrayNameList = Arrays.asList(authors.split(","));
+
+ // Delete spaces for correct case identification
+ arrayNameList.replaceAll(String::trim);
+
+ // Looking for space between pre- and lastname
+ boolean spaceInAllParts = arrayNameList.stream().filter(name -> name.contains(" ")).collect(Collectors
+ .toList()).size() == arrayNameList.size();
+
+ // We hit the comma name separator case
+ // Usually the getAsLastFirstNamesWithAnd method would separate them if pre- and lastname are separated with "and"
+ // If not, we check if spaces separate pre- and lastname
+ if (spaceInAllParts) {
+ authors = authors.replaceAll(",", " and");
+ } else {
+ // Looking for name affixes to avoid
+ // arrayNameList needs to reduce by the count off avoiding terms
+ // valuePartsCount holds the count of name parts without the avoided terms
+
+ int valuePartsCount = arrayNameList.size();
+ // Holds the index of each term which needs to be avoided
+ Collection<Integer> avoidIndex = new HashSet<>();
+
+ for (int i = 0; i < arrayNameList.size(); i++) {
+ if (avoidTermsInLowerCase.contains(arrayNameList.get(i).toLowerCase())) {
+ avoidIndex.add(i);
+ valuePartsCount--;
+ }
+ }
+
+ if ((valuePartsCount % 2) == 0) {
+ // We hit the described special case with name affix like Jr
+ authors = buildWithAffix(avoidIndex, arrayNameList).toString();
+ }
+ }
+ }
+
AuthorList authorList = AUTHOR_CACHE.get(authors);
if (authorList == null) {
AuthorListParser parser = new AuthorListParser();
@@ -577,4 +624,34 @@ public class AuthorList {
return authorsAlph;
}
+ /**
+ * Builds a new array of strings with stringbuilder.
+ * Regarding to the name affixes.
+ * @return New string with correct seperation
+ */
+ private static StringBuilder buildWithAffix(Collection<Integer> indexArray, List<String> nameList) {
+ StringBuilder stringBuilder = new StringBuilder();
+ // avoidedTimes needs to be increased by the count of avoided terms for correct odd/even calculation
+ int avoidedTimes = 0;
+ for (int i = 0; i < nameList.size(); i++) {
+ if (indexArray.contains(i)) {
+ // We hit a name affix
+ stringBuilder.append(nameList.get(i));
+ stringBuilder.append(',');
+ avoidedTimes++;
+ } else {
+ stringBuilder.append(nameList.get(i));
+ if (((i + avoidedTimes) % 2) == 0) {
+ // Hit separation between last name and firstname --> comma has to be kept
+ stringBuilder.append(',');
+ } else {
+ // Hit separation between full names (e.g., Ali Babar, M. and Dingsøyr, T.) --> semicolon has to be used
+ // Will be treated correctly by AuthorList.parse(authors);
+ stringBuilder.append(';');
+ }
+ }
+ }
+ return stringBuilder;
+ }
+
}
diff --git a/src/main/java/net/sf/jabref/model/entry/BibEntry.java b/src/main/java/net/sf/jabref/model/entry/BibEntry.java
index 76e5046..4c0bc05 100644
--- a/src/main/java/net/sf/jabref/model/entry/BibEntry.java
+++ b/src/main/java/net/sf/jabref/model/entry/BibEntry.java
@@ -21,10 +21,14 @@ import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;
-import net.sf.jabref.event.source.EntryEventSource;
+import net.sf.jabref.model.EntryTypes;
import net.sf.jabref.model.FieldChange;
import net.sf.jabref.model.database.BibDatabase;
-import net.sf.jabref.model.event.FieldChangedEvent;
+import net.sf.jabref.model.database.BibDatabaseMode;
+import net.sf.jabref.model.entry.event.EntryEventSource;
+import net.sf.jabref.model.entry.event.FieldChangedEvent;
+import net.sf.jabref.model.strings.LatexToUnicode;
+import net.sf.jabref.model.strings.StringUtil;
import com.google.common.base.Strings;
import com.google.common.eventbus.EventBus;
@@ -49,11 +53,22 @@ public class BibEntry implements Cloneable {
private String type;
private Map<String, String> fields = new ConcurrentHashMap<>();
- /*
+
+ /**
* Map to store the words in every field
*/
private final Map<String, Set<String>> fieldsAsWords = new HashMap<>();
+ /**
+ * Cache that stores latex free versions of fields.
+ */
+ private final Map<String, String> latexFreeFields = new ConcurrentHashMap<>();
+
+ /**
+ * Used to cleanse field values for internal LaTeX-free storage
+ */
+ private LatexToUnicode unicodeConverter = new LatexToUnicode();
+
// Search and grouping status is stored in boolean fields for quick reference:
private boolean searchHit;
private boolean groupHit;
@@ -62,7 +77,7 @@ public class BibEntry implements Cloneable {
private String commentsBeforeEntry = "";
- /*
+ /**
* Marks whether the complete serialization, which was read from file, should be used.
*
* Is set to false, if parts of the entry change. This causes the entry to be serialized based on the internal state (and not based on the old serialization)
@@ -92,7 +107,7 @@ public class BibEntry implements Cloneable {
/**
* Constructs a new BibEntry with the given ID and given type
*
- * @param id The ID to be used
+ * @param id The ID to be used
* @param type The type to set. May be null or empty. In that case, DEFAULT_TYPE is used.
*/
public BibEntry(String id, String type) {
@@ -103,6 +118,55 @@ public class BibEntry implements Cloneable {
this.sharedBibEntryData = new SharedBibEntryData();
}
+ public Optional<FieldChange> replaceKeywords(KeywordList keywordsToReplace, Optional<Keyword> newValue,
+ Character keywordDelimiter) {
+ KeywordList keywordList = getKeywords(keywordDelimiter);
+ keywordList.replaceKeywords(keywordsToReplace, newValue);
+
+ return putKeywords(keywordList, keywordDelimiter);
+ }
+
+ /**
+ * Returns the text stored in the given field of the given bibtex entry
+ * which belongs to the given database.
+ * <p>
+ * If a database is given, this function will try to resolve any string
+ * references in the field-value.
+ * Also, if a database is given, this function will try to find values for
+ * unset fields in the entry linked by the "crossref" field, if any.
+ *
+ * @param field The field to return the value of.
+ * @param database maybenull
+ * The database of the bibtex entry.
+ * @return The resolved field value or null if not found.
+ */
+ public Optional<String> getResolvedFieldOrAlias(String field, BibDatabase database) {
+ Objects.requireNonNull(this, "entry cannot be null");
+
+ if (TYPE_HEADER.equals(field) || OBSOLETE_TYPE_HEADER.equals(field)) {
+ Optional<EntryType> entryType = EntryTypes.getType(getType(), BibDatabaseMode.BIBLATEX);
+ if (entryType.isPresent()) {
+ return Optional.of(entryType.get().getName());
+ } else {
+ return Optional.of(StringUtil.capitalizeFirst(getType()));
+ }
+ }
+
+ if (KEY_FIELD.equals(field)) {
+ return getCiteKeyOptional();
+ }
+
+ Optional<String> result = getFieldOrAlias(field);
+
+ // If this field is not set, and the entry has a crossref, try to look up the
+ // field in the referred entry: Do not do this for the bibtex key.
+ if (!result.isPresent() && (database != null)) {
+ Optional<BibEntry> referred = database.getReferencedEntry(this);
+ result = referred.flatMap(entry -> entry.getFieldOrAlias(field));
+ }
+ return result.map(resultText -> BibDatabase.getText(resultText, database));
+ }
+
/**
* Sets this entry's ID, provided the database containing it
* doesn't veto the change.
@@ -128,10 +192,9 @@ public class BibEntry implements Cloneable {
/**
* Sets the cite key AKA citation key AKA BibTeX key.
- *
* Note: This is <emph>not</emph> the internal Id of this entry. The internal Id is always present, whereas the BibTeX key might not be present.
*
- * @param newCiteKey The cite key to set. Must not be null, may be empty to remove it.
+ * @param newCiteKey The cite key to set. Must not be null; use {@link #clearCiteKey()} to remove the cite key.
*/
public void setCiteKey(String newCiteKey) {
setField(KEY_FIELD, newCiteKey);
@@ -139,7 +202,6 @@ public class BibEntry implements Cloneable {
/**
* Returns the cite key AKA citation key AKA BibTeX key, or null if it is not set.
- *
* Note: this is <emph>not</emph> the internal Id of this entry. The internal Id is always present, whereas the BibTeX key might not be present.
*/
@Deprecated
@@ -172,7 +234,7 @@ public class BibEntry implements Cloneable {
} else {
newType = type;
}
- String oldType = getFieldOptional(TYPE_HEADER).orElse(null);
+ String oldType = getField(TYPE_HEADER).orElse(null);
// We set the type before throwing the changeEvent, to enable
// the change listener to access the new value if the change
@@ -207,17 +269,9 @@ public class BibEntry implements Cloneable {
}
/**
- * Use {@link #getFieldOptional} instead
- */
- @Deprecated
- public String getField(String name) {
- return fields.get(toLowerCase(name));
- }
-
- /**
* Returns the contents of the given field as an Optional.
*/
- public Optional<String> getFieldOptional(String name) {
+ public Optional<String> getField(String name) {
return Optional.ofNullable(fields.get(toLowerCase(name)));
}
@@ -235,28 +289,17 @@ public class BibEntry implements Cloneable {
}
/**
- * Returns the contents of the given field or its alias as an Optional
- * <p>
- * The following aliases are considered (old bibtex <-> new biblatex) based
- * on the BibLatex documentation, chapter 2.2.5:<br>
- * address <-> location <br>
- * annote <-> annotation <br>
- * archiveprefix <-> eprinttype <br>
- * journal <-> journaltitle <br>
- * key <-> sortkey <br>
- * pdf <-> file <br
- * primaryclass <-> eprintclass <br>
- * school <-> institution <br>
- * These work bidirectional. <br>
- * <p>
- * Special attention is paid to dates: (see the BibLatex documentation,
- * chapter 2.3.8)
- * The fields 'year' and 'month' are used if the 'date'
- * field is empty. Conversely, getFieldOrAlias("year") also tries to
- * extract the year from the 'date' field (analogously for 'month').
+ * Internal method used to get the content of a field (or its alias)
+ *
+ * Used by {@link #getFieldOrAlias(String)} and {@link #getFieldOrAliasLatexFree(String)}
+ *
+ * @param name name of the field
+ * @param getFieldInterface
+ *
+ * @return determined field value
*/
- public Optional<String> getFieldOrAlias(String name) {
- Optional<String> fieldValue = getFieldOptional(toLowerCase(name));
+ private Optional<String> genericGetFieldOrAlias(String name, GetFieldInterface getFieldInterface) {
+ Optional<String> fieldValue = getFieldInterface.getValueForField(toLowerCase(name));
if (fieldValue.isPresent() && !fieldValue.get().isEmpty()) {
return fieldValue;
@@ -266,14 +309,14 @@ public class BibEntry implements Cloneable {
String aliasForField = EntryConverter.FIELD_ALIASES.get(name);
if (aliasForField != null) {
- return getFieldOptional(aliasForField);
+ return getFieldInterface.getValueForField(aliasForField);
}
// Finally, handle dates
if (FieldName.DATE.equals(name)) {
- Optional<String> year = getFieldOptional(FieldName.YEAR);
+ Optional<String> year = getFieldInterface.getValueForField(FieldName.YEAR);
if (year.isPresent()) {
- MonthUtil.Month month = MonthUtil.getMonth(getFieldOptional(FieldName.MONTH).orElse(""));
+ MonthUtil.Month month = MonthUtil.getMonth(getFieldInterface.getValueForField(FieldName.MONTH).orElse(""));
if (month.isValid()) {
return Optional.of(year.get() + '-' + month.twoDigitNumber);
} else {
@@ -282,7 +325,7 @@ public class BibEntry implements Cloneable {
}
}
if (FieldName.YEAR.equals(name) || FieldName.MONTH.equals(name)) {
- Optional<String> date = getFieldOptional(FieldName.DATE);
+ Optional<String> date = getFieldInterface.getValueForField(FieldName.DATE);
if (!date.isPresent()) {
return Optional.empty();
}
@@ -340,6 +383,47 @@ public class BibEntry implements Cloneable {
return Optional.empty();
}
+ private interface GetFieldInterface {
+ Optional<String> getValueForField(String fieldName);
+ }
+
+ /**
+ * Return the LaTeX-free contents of the given field or its alias an an Optional
+ *
+ * For details see also {@link #getFieldOrAlias(String)}
+ *
+ * @param name the name of the field
+ * @return the stored latex-free content of the field (or its alias)
+ */
+ public Optional<String> getFieldOrAliasLatexFree(String name) {
+ return genericGetFieldOrAlias(name, this::getLatexFreeField);
+ }
+
+ /**
+ * Returns the contents of the given field or its alias as an Optional
+ * <p>
+ * The following aliases are considered (old bibtex <-> new biblatex) based
+ * on the BibLatex documentation, chapter 2.2.5:<br>
+ * address <-> location <br>
+ * annote <-> annotation <br>
+ * archiveprefix <-> eprinttype <br>
+ * journal <-> journaltitle <br>
+ * key <-> sortkey <br>
+ * pdf <-> file <br
+ * primaryclass <-> eprintclass <br>
+ * school <-> institution <br>
+ * These work bidirectional. <br>
+ * <p>
+ * Special attention is paid to dates: (see the BibLatex documentation,
+ * chapter 2.3.8)
+ * The fields 'year' and 'month' are used if the 'date'
+ * field is empty. Conversely, getFieldOrAlias("year") also tries to
+ * extract the year from the 'date' field (analogously for 'month').
+ */
+ public Optional<String> getFieldOrAlias(String name) {
+ return genericGetFieldOrAlias(name, this::getField);
+ }
+
/**
* Sets a number of fields simultaneously. The given HashMap contains field
* names as keys, each mapped to the value to set.
@@ -352,8 +436,9 @@ public class BibEntry implements Cloneable {
/**
* Set a field, and notify listeners about the change.
- * @param name The field to set
- * @param value The value to set
+ *
+ * @param name The field to set
+ * @param value The value to set
* @param eventSource Source the event is sent from
*/
public Optional<FieldChange> setField(String name, String value, EntryEventSource eventSource) {
@@ -366,7 +451,7 @@ public class BibEntry implements Cloneable {
return clearField(fieldName);
}
- String oldValue = getFieldOptional(fieldName).orElse(null);
+ String oldValue = getField(fieldName).orElse(null);
if (value.equals(oldValue)) {
return Optional.empty();
}
@@ -377,8 +462,8 @@ public class BibEntry implements Cloneable {
changed = true;
- fields.put(fieldName, value);
- fieldsAsWords.remove(fieldName);
+ fields.put(fieldName, value.intern());
+ invalidateFieldCache(fieldName);
FieldChange change = new FieldChange(this, fieldName, oldValue, value);
eventBus.post(new FieldChangedEvent(change, eventSource));
@@ -416,7 +501,7 @@ public class BibEntry implements Cloneable {
* Remove the mapping for the field name, and notify listeners about
* the change including the {@link EntryEventSource}.
*
- * @param name The field to clear.
+ * @param name The field to clear.
* @param eventSource the source a new {@link FieldChangedEvent} should be posten from.
*/
public Optional<FieldChange> clearField(String name, EntryEventSource eventSource) {
@@ -426,7 +511,7 @@ public class BibEntry implements Cloneable {
throw new IllegalArgumentException("The field name '" + name + "' is reserved");
}
- Optional<String> oldValue = getFieldOptional(fieldName);
+ Optional<String> oldValue = getField(fieldName);
if (!oldValue.isPresent()) {
return Optional.empty();
}
@@ -434,7 +519,8 @@ public class BibEntry implements Cloneable {
changed = true;
fields.remove(fieldName);
- fieldsAsWords.remove(fieldName);
+ invalidateFieldCache(fieldName);
+
FieldChange change = new FieldChange(this, fieldName, oldValue.get(), null);
eventBus.post(new FieldChangedEvent(change, eventSource));
return Optional.of(change);
@@ -462,7 +548,7 @@ public class BibEntry implements Cloneable {
return false;
}
} else {
- if (!BibDatabase.getResolvedField(fieldName, this, database).isPresent()) {
+ if (!this.getResolvedFieldOrAlias(fieldName, database).isPresent()) {
return false;
}
}
@@ -474,7 +560,7 @@ public class BibEntry implements Cloneable {
for (String field : fieldsToCheck) {
String fieldName = toLowerCase(field);
- Optional<String> value = BibDatabase.getResolvedField(fieldName, this, database);
+ Optional<String> value = this.getResolvedFieldOrAlias(fieldName, database);
if ((value.isPresent()) && !value.get().isEmpty()) {
return true;
}
@@ -526,8 +612,8 @@ public class BibEntry implements Cloneable {
* Author1, Author2: Title (Year)
*/
public String getAuthorTitleYear(int maxCharacters) {
- String[] s = new String[] {getFieldOptional(FieldName.AUTHOR).orElse("N/A"),
- getFieldOptional(FieldName.TITLE).orElse("N/A"), getFieldOptional(FieldName.YEAR).orElse("N/A")};
+ String[] s = new String[]{getField(FieldName.AUTHOR).orElse("N/A"), getField(FieldName.TITLE).orElse("N/A"),
+ getField(FieldName.YEAR).orElse("N/A")};
String text = s[0] + ": \"" + s[1] + "\" (" + s[2] + ')';
if ((maxCharacters <= 0) || (text.length() <= maxCharacters)) {
@@ -546,9 +632,9 @@ public class BibEntry implements Cloneable {
return Optional.empty();
}
- Optional<String> year = getFieldOptional(FieldName.YEAR);
+ Optional<String> year = getField(FieldName.YEAR);
- Optional<String> monthString = getFieldOptional(FieldName.MONTH);
+ Optional<String> monthString = getField(FieldName.MONTH);
if (monthString.isPresent()) {
MonthUtil.Month month = MonthUtil.getMonth(monthString.get());
if (month.isValid()) {
@@ -579,9 +665,14 @@ public class BibEntry implements Cloneable {
this.changed = changed;
}
- public Optional<FieldChange> putKeywords(Collection<String> keywords, String separator) {
+ public Optional<FieldChange> putKeywords(List<String> keywords, Character delimiter) {
+ Objects.requireNonNull(delimiter);
+ return putKeywords(new KeywordList(keywords), delimiter);
+ }
+
+ public Optional<FieldChange> putKeywords(KeywordList keywords, Character delimiter) {
Objects.requireNonNull(keywords);
- Optional<String> oldValue = this.getFieldOptional(FieldName.KEYWORDS);
+ Optional<String> oldValue = this.getField(FieldName.KEYWORDS);
if (keywords.isEmpty()) {
// Clear keyword field
@@ -593,7 +684,7 @@ public class BibEntry implements Cloneable {
}
// Set new keyword field
- String newValue = String.join(separator, keywords);
+ String newValue = keywords.getAsString(delimiter);
return this.setField(FieldName.KEYWORDS, newValue);
}
@@ -602,16 +693,20 @@ public class BibEntry implements Cloneable {
*
* @param keyword Keyword to add
*/
- public void addKeyword(String keyword, String separator) {
+ public void addKeyword(String keyword, Character delimiter) {
Objects.requireNonNull(keyword, "keyword must not be null");
if (keyword.isEmpty()) {
return;
}
- Set<String> keywords = this.getKeywords();
+ addKeyword(new Keyword(keyword), delimiter);
+ }
+
+ public void addKeyword(Keyword keyword, Character delimiter) {
+ KeywordList keywords = this.getKeywords(delimiter);
keywords.add(keyword);
- this.putKeywords(keywords, separator);
+ this.putKeywords(keywords, delimiter);
}
/**
@@ -619,16 +714,18 @@ public class BibEntry implements Cloneable {
*
* @param keywords Keywords to add
*/
- public void addKeywords(Collection<String> keywords, String separator) {
+ public void addKeywords(Collection<String> keywords, Character delimiter) {
Objects.requireNonNull(keywords);
-
- for (String keyword : keywords) {
- this.addKeyword(keyword, separator);
- }
+ keywords.forEach(keyword -> addKeyword(keyword, delimiter));
}
- public Set<String> getKeywords() {
- return net.sf.jabref.model.entry.EntryUtil.getSeparatedKeywords(this);
+ public KeywordList getKeywords(Character delimiter) {
+ Optional<String> keywordsContent = getField(FieldName.KEYWORDS);
+ if (keywordsContent.isPresent()) {
+ return KeywordList.parse(keywordsContent.get(), delimiter);
+ } else {
+ return new KeywordList();
+ }
}
public Collection<String> getFieldValues() {
@@ -681,6 +778,15 @@ public class BibEntry implements Cloneable {
return REMOVE_TRAILING_WHITESPACE.matcher(commentsBeforeEntry).replaceFirst("");
}
+ public List<ParsedEntryLink> getEntryLinkList(String fieldName, BibDatabase database) {
+ return getField(fieldName).map(fieldValue -> EntryLinkList.parse(fieldValue, database))
+ .orElse(Collections.emptyList());
+ }
+
+ public Optional<FieldChange> setEntryLinkList(String fieldName, List<ParsedEntryLink> list) {
+ return setField(fieldName, EntryLinkList.serialize(list));
+ }
+
public Set<String> getFieldAsWords(String field) {
String fieldName = toLowerCase(field);
Set<String> storedList = fieldsAsWords.get(fieldName);
@@ -691,10 +797,31 @@ public class BibEntry implements Cloneable {
if (fieldValue == null) {
return Collections.emptySet();
} else {
- HashSet<String> words = new HashSet<>(EntryUtil.getStringAsWords(fieldValue));
+ HashSet<String> words = new HashSet<>(StringUtil.getStringAsWords(fieldValue));
fieldsAsWords.put(fieldName, words);
return words;
}
}
}
+
+ public Optional<FieldChange> clearCiteKey() {
+ return clearField(KEY_FIELD);
+ }
+
+ private void invalidateFieldCache(String fieldName) {
+ latexFreeFields.remove(fieldName);
+ fieldsAsWords.remove(fieldName);
+ }
+
+ public Optional<String> getLatexFreeField(String name) {
+ if (!hasField(name)) {
+ return Optional.empty();
+ } else if (latexFreeFields.containsKey(name)) {
+ return Optional.ofNullable(latexFreeFields.get(toLowerCase(name)));
+ } else {
+ String latexFreeField = unicodeConverter.format(getField(name).get()).intern();
+ latexFreeFields.put(name, latexFreeField);
+ return Optional.of(latexFreeField);
+ }
+ }
}
diff --git a/src/main/java/net/sf/jabref/model/entry/BibLatexEntryTypes.java b/src/main/java/net/sf/jabref/model/entry/BibLatexEntryTypes.java
index ca5235b..9c0c5b2 100644
--- a/src/main/java/net/sf/jabref/model/entry/BibLatexEntryTypes.java
+++ b/src/main/java/net/sf/jabref/model/entry/BibLatexEntryTypes.java
@@ -13,20 +13,24 @@ public class BibLatexEntryTypes {
public static final BibLatexEntryType ARTICLE = new BibLatexEntryType() {
- private final List<String> primaryOptionalFields = Collections.unmodifiableList(
- Arrays.asList(FieldName.SUBTITLE, FieldName.EDITOR, FieldName.SERIES, FieldName.VOLUME, FieldName.NUMBER, FieldName.EID, FieldName.ISSUE, FieldName.PAGES,
- FieldName.NOTE, FieldName.ISSN, FieldName.DOI, FieldName.EPRINT, FieldName.EPRINTCLASS, FieldName.EPRINTTYPE,
- FieldName.URL, FieldName.URLDATE));
+ private final List<String> primaryOptionalFields = Collections.unmodifiableList(Arrays.asList(
+ FieldName.SUBTITLE, FieldName.EDITOR, FieldName.SERIES, FieldName.VOLUME, FieldName.NUMBER,
+ FieldName.EID, FieldName.ISSUE, FieldName.PAGES, FieldName.NOTE, FieldName.ISSN, FieldName.DOI,
+ FieldName.EPRINT, FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE));
{
- addAllRequired(FieldName.AUTHOR, FieldName.TITLE, FieldName.JOURNALTITLE, FieldName.orFields(FieldName.YEAR, FieldName.DATE));
- addAllOptional(FieldName.TRANSLATOR, "annotator", "commentator", FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.EDITOR, "editora",
- "editorb", "editorc", FieldName.JOURNALSUBTITLE, "issuetitle", "issuesubtitle", FieldName.LANGUAGE, FieldName.ORIGLANGUAGE,
- FieldName.SERIES, FieldName.VOLUME, FieldName.NUMBER, FieldName.EID, FieldName.ISSUE, FieldName.MONTH, FieldName.PAGES, FieldName.VERSION, FieldName.NOTE, FieldName.ISSN,
- "addendum", FieldName.PUBSTATE, FieldName.DOI, FieldName.EPRINT, FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL,
- FieldName.URLDATE);
+ addAllRequired(FieldName.AUTHOR, FieldName.TITLE, FieldName.JOURNALTITLE,
+ FieldName.orFields(FieldName.YEAR, FieldName.DATE));
+ addAllOptional(FieldName.TRANSLATOR, FieldName.ANNOTATOR, FieldName.COMMENTATOR, FieldName.SUBTITLE,
+ FieldName.TITLEADDON, FieldName.EDITOR, FieldName.EDITORA, FieldName.EDITORB, FieldName.EDITORC,
+ FieldName.JOURNALSUBTITLE, FieldName.ISSUETITLE, FieldName.ISSUESUBTITLE, FieldName.LANGUAGE,
+ FieldName.ORIGLANGUAGE, FieldName.SERIES, FieldName.VOLUME, FieldName.NUMBER, FieldName.EID,
+ FieldName.ISSUE, FieldName.MONTH, FieldName.PAGES, FieldName.VERSION, FieldName.NOTE,
+ FieldName.ISSN, FieldName.ADDENDUM, FieldName.PUBSTATE, FieldName.DOI, FieldName.EPRINT,
+ FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE);
}
+
@Override
public String getName() {
return "Article";
@@ -40,23 +44,26 @@ public class BibLatexEntryTypes {
public static final BibLatexEntryType BOOK = new BibLatexEntryType() {
- private final List<String> primaryOptionalFields = Collections
- .unmodifiableList(Arrays.asList(FieldName.EDITOR, FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.MAINTITLE,
- FieldName.MAINSUBTITLE, FieldName.MAINTITLEADDON, FieldName.VOLUME, FieldName.EDITION, FieldName.PUBLISHER, FieldName.ISBN, FieldName.CHAPTER, FieldName.PAGES,
- FieldName.PAGETOTAL, FieldName.DOI, FieldName.EPRINT, FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL,
- FieldName.URLDATE));
-
+ private final List<String> primaryOptionalFields = Collections.unmodifiableList(Arrays.asList(FieldName.EDITOR,
+ FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.MAINTITLE, FieldName.MAINSUBTITLE,
+ FieldName.MAINTITLEADDON, FieldName.VOLUME, FieldName.EDITION, FieldName.PUBLISHER, FieldName.ISBN,
+ FieldName.CHAPTER, FieldName.PAGES, FieldName.PAGETOTAL, FieldName.DOI, FieldName.EPRINT,
+ FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE));
{
addAllRequired(FieldName.AUTHOR, FieldName.TITLE, FieldName.orFields(FieldName.YEAR, FieldName.DATE));
- addAllOptional(FieldName.EDITOR, "editora", "editorb", "editorc", FieldName.TRANSLATOR, "annotator", "commentator",
- "introduction", "foreword", "afterword", FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.MAINTITLE, FieldName.MAINSUBTITLE,
- FieldName.MAINTITLEADDON, FieldName.LANGUAGE, FieldName.ORIGLANGUAGE, FieldName.VOLUME, FieldName.PART, FieldName.EDITION, FieldName.VOLUMES, FieldName.SERIES,
- FieldName.NUMBER, FieldName.NOTE, FieldName.PUBLISHER, FieldName.LOCATION, FieldName.ISBN, FieldName.CHAPTER, FieldName.PAGES, FieldName.PAGETOTAL,
- "addendum", FieldName.PUBSTATE, FieldName.DOI, FieldName.EPRINT, FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL,
- FieldName.URLDATE);
+ addAllOptional(FieldName.EDITOR, FieldName.EDITORA, FieldName.EDITORB, FieldName.EDITORC,
+ FieldName.TRANSLATOR, FieldName.ANNOTATOR, FieldName.COMMENTATOR, FieldName.INTRODUCTION,
+ FieldName.FOREWORD, FieldName.AFTERWORD, FieldName.SUBTITLE, FieldName.TITLEADDON,
+ FieldName.MAINTITLE, FieldName.MAINSUBTITLE, FieldName.MAINTITLEADDON, FieldName.LANGUAGE,
+ FieldName.ORIGLANGUAGE, FieldName.VOLUME, FieldName.PART, FieldName.EDITION, FieldName.VOLUMES,
+ FieldName.SERIES, FieldName.NUMBER, FieldName.NOTE, FieldName.PUBLISHER, FieldName.LOCATION,
+ FieldName.ISBN, FieldName.CHAPTER, FieldName.PAGES, FieldName.PAGETOTAL, FieldName.ADDENDUM,
+ FieldName.PUBSTATE, FieldName.DOI, FieldName.EPRINT, FieldName.EPRINTCLASS, FieldName.EPRINTTYPE,
+ FieldName.URL, FieldName.URLDATE);
}
+
@Override
public String getName() {
return "Book";
@@ -70,19 +77,23 @@ public class BibLatexEntryTypes {
public static final BibLatexEntryType MVBOOK = new BibLatexEntryType() {
- private final List<String> primaryOptionalFields = Collections
- .unmodifiableList(Arrays.asList(FieldName.EDITOR, FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.EDITION, FieldName.PUBLISHER, FieldName.ISBN, FieldName.PAGETOTAL,
- FieldName.DOI, FieldName.EPRINT, FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE));
+ private final List<String> primaryOptionalFields = Collections.unmodifiableList(
+ Arrays.asList(FieldName.EDITOR, FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.EDITION,
+ FieldName.PUBLISHER, FieldName.ISBN, FieldName.PAGETOTAL, FieldName.DOI, FieldName.EPRINT,
+ FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE));
{
addAllRequired(FieldName.AUTHOR, FieldName.TITLE, FieldName.orFields(FieldName.YEAR, FieldName.DATE));
- addAllOptional(FieldName.EDITOR, "editora", "editorb", "editorc", FieldName.TRANSLATOR, "annotator", "commentator",
- "introduction", "foreword", "afterword", FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.LANGUAGE, FieldName.ORIGLANGUAGE,
- FieldName.EDITION, FieldName.VOLUMES, FieldName.SERIES, FieldName.NUMBER, FieldName.NOTE, FieldName.PUBLISHER, FieldName.LOCATION, FieldName.ISBN, FieldName.PAGETOTAL,
- "addendum", FieldName.PUBSTATE, FieldName.DOI, FieldName.EPRINT, FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL,
- FieldName.URLDATE);
+ addAllOptional(FieldName.EDITOR, FieldName.EDITORA, FieldName.EDITORB, FieldName.EDITORC,
+ FieldName.TRANSLATOR, FieldName.ANNOTATOR, FieldName.COMMENTATOR, FieldName.INTRODUCTION,
+ FieldName.FOREWORD, FieldName.AFTERWORD, FieldName.SUBTITLE, FieldName.TITLEADDON,
+ FieldName.LANGUAGE, FieldName.ORIGLANGUAGE, FieldName.EDITION, FieldName.VOLUMES, FieldName.SERIES,
+ FieldName.NUMBER, FieldName.NOTE, FieldName.PUBLISHER, FieldName.LOCATION, FieldName.ISBN,
+ FieldName.PAGETOTAL, FieldName.ADDENDUM, FieldName.PUBSTATE, FieldName.DOI, FieldName.EPRINT,
+ FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE);
}
+
@Override
public String getName() {
return "MvBook";
@@ -96,24 +107,28 @@ public class BibLatexEntryTypes {
public static final BibLatexEntryType INBOOK = new BibLatexEntryType() {
- private final List<String> primaryOptionalFields = Collections.unmodifiableList(Arrays
- .asList(FieldName.BOOKAUTHOR, FieldName.EDITOR, FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.MAINTITLE, FieldName.MAINSUBTITLE,
- FieldName.MAINTITLEADDON, FieldName.BOOKSUBTITLE, FieldName.BOOKTITLEADDON, FieldName.VOLUME, FieldName.EDITION, FieldName.PUBLISHER, FieldName.ISBN,
- FieldName.CHAPTER, FieldName.PAGES, FieldName.DOI, FieldName.EPRINT, FieldName.EPRINTCLASS, FieldName.EPRINTTYPE,
- FieldName.URL, FieldName.URLDATE));
-
+ private final List<String> primaryOptionalFields = Collections.unmodifiableList(
+ Arrays.asList(FieldName.BOOKAUTHOR, FieldName.EDITOR, FieldName.SUBTITLE, FieldName.TITLEADDON,
+ FieldName.MAINTITLE, FieldName.MAINSUBTITLE, FieldName.MAINTITLEADDON, FieldName.BOOKSUBTITLE,
+ FieldName.BOOKTITLEADDON, FieldName.VOLUME, FieldName.EDITION, FieldName.PUBLISHER,
+ FieldName.ISBN, FieldName.CHAPTER, FieldName.PAGES, FieldName.DOI, FieldName.EPRINT,
+ FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE));
{
- addAllRequired(FieldName.AUTHOR, FieldName.TITLE, FieldName.BOOKTITLE, FieldName.orFields(FieldName.YEAR, FieldName.DATE));
- addAllOptional(FieldName.BOOKAUTHOR, FieldName.EDITOR, "editora", "editorb", "editorc", FieldName.TRANSLATOR, "annotator",
- "commentator", "introduction", "foreword", "afterword", FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.MAINTITLE,
- FieldName.MAINSUBTITLE, FieldName.MAINTITLEADDON, FieldName.BOOKSUBTITLE, FieldName.BOOKTITLEADDON, FieldName.LANGUAGE, FieldName.ORIGLANGUAGE,
- FieldName.VOLUME, FieldName.PART, FieldName.EDITION, FieldName.VOLUMES, FieldName.SERIES, FieldName.NUMBER, FieldName.NOTE, FieldName.PUBLISHER, FieldName.LOCATION, FieldName.ISBN,
- FieldName.CHAPTER, FieldName.PAGES, "addendum", FieldName.PUBSTATE, FieldName.DOI, FieldName.EPRINT, FieldName.EPRINTCLASS,
- FieldName.EPRINTTYPE, FieldName.URL,
- FieldName.URLDATE);
+ addAllRequired(FieldName.AUTHOR, FieldName.TITLE, FieldName.BOOKTITLE,
+ FieldName.orFields(FieldName.YEAR, FieldName.DATE));
+ addAllOptional(FieldName.BOOKAUTHOR, FieldName.EDITOR, FieldName.EDITORA, FieldName.EDITORB,
+ FieldName.EDITORC, FieldName.TRANSLATOR, FieldName.ANNOTATOR, FieldName.COMMENTATOR,
+ FieldName.INTRODUCTION, FieldName.FOREWORD, FieldName.AFTERWORD, FieldName.SUBTITLE,
+ FieldName.TITLEADDON, FieldName.MAINTITLE, FieldName.MAINSUBTITLE, FieldName.MAINTITLEADDON,
+ FieldName.BOOKSUBTITLE, FieldName.BOOKTITLEADDON, FieldName.LANGUAGE, FieldName.ORIGLANGUAGE,
+ FieldName.VOLUME, FieldName.PART, FieldName.EDITION, FieldName.VOLUMES, FieldName.SERIES,
+ FieldName.NUMBER, FieldName.NOTE, FieldName.PUBLISHER, FieldName.LOCATION, FieldName.ISBN,
+ FieldName.CHAPTER, FieldName.PAGES, FieldName.ADDENDUM, FieldName.PUBSTATE, FieldName.DOI,
+ FieldName.EPRINT, FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE);
}
+
@Override
public String getName() {
return "InBook";
@@ -176,18 +191,20 @@ public class BibLatexEntryTypes {
public static final BibLatexEntryType BOOKLET = new BibLatexEntryType() {
private final List<String> primaryOptionalFields = Collections
- .unmodifiableList(Arrays.asList(FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.HOWPUBLISHED, FieldName.CHAPTER,
- FieldName.PAGES, FieldName.DOI, FieldName.EPRINT, FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL,
- FieldName.URLDATE));
+ .unmodifiableList(Arrays.asList(FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.HOWPUBLISHED,
+ FieldName.CHAPTER, FieldName.PAGES, FieldName.DOI, FieldName.EPRINT, FieldName.EPRINTCLASS,
+ FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE));
{
- addAllRequired(FieldName.orFields(FieldName.AUTHOR, FieldName.EDITOR), FieldName.TITLE, FieldName.orFields(FieldName.YEAR, FieldName.DATE));
- addAllOptional(FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.LANGUAGE, FieldName.HOWPUBLISHED, FieldName.TYPE, FieldName.NOTE, FieldName.LOCATION, FieldName.CHAPTER,
- FieldName.PAGES, FieldName.PAGETOTAL, "addendum", FieldName.PUBSTATE, FieldName.DOI, FieldName.EPRINT,
- FieldName.EPRINTCLASS, FieldName.EPRINTTYPE,
- FieldName.URL, FieldName.URLDATE);
+ addAllRequired(FieldName.orFields(FieldName.AUTHOR, FieldName.EDITOR), FieldName.TITLE,
+ FieldName.orFields(FieldName.YEAR, FieldName.DATE));
+ addAllOptional(FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.LANGUAGE, FieldName.HOWPUBLISHED,
+ FieldName.TYPE, FieldName.NOTE, FieldName.LOCATION, FieldName.CHAPTER, FieldName.PAGES,
+ FieldName.PAGETOTAL, FieldName.ADDENDUM, FieldName.PUBSTATE, FieldName.DOI, FieldName.EPRINT,
+ FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE);
}
+
@Override
public String getName() {
return "Booklet";
@@ -201,21 +218,26 @@ public class BibLatexEntryTypes {
public static final BibLatexEntryType COLLECTION = new BibLatexEntryType() {
- private final List<String> primaryOptionalFields = Collections
- .unmodifiableList(Arrays.asList(FieldName.TRANSLATOR, FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.MAINTITLE,
- FieldName.MAINSUBTITLE, FieldName.MAINTITLEADDON, FieldName.VOLUME, FieldName.EDITION, FieldName.PUBLISHER, FieldName.ISBN, FieldName.CHAPTER, FieldName.PAGES,
- FieldName.DOI, FieldName.EPRINT, FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE));
-
+ private final List<String> primaryOptionalFields = Collections.unmodifiableList(Arrays.asList(
+ FieldName.TRANSLATOR, FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.MAINTITLE,
+ FieldName.MAINSUBTITLE, FieldName.MAINTITLEADDON, FieldName.VOLUME, FieldName.EDITION,
+ FieldName.PUBLISHER, FieldName.ISBN, FieldName.CHAPTER, FieldName.PAGES, FieldName.DOI,
+ FieldName.EPRINT, FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE));
{
addAllRequired(FieldName.EDITOR, FieldName.TITLE, FieldName.orFields(FieldName.YEAR, FieldName.DATE));
- addAllOptional("editora", "editorb", "editorc", FieldName.TRANSLATOR, "annotator", "commentator", "introduction",
- "foreword", "afterword", FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.MAINTITLE, FieldName.MAINSUBTITLE, FieldName.MAINTITLEADDON,
- FieldName.LANGUAGE, FieldName.ORIGLANGUAGE, FieldName.VOLUME, FieldName.PART, FieldName.EDITION, FieldName.VOLUMES, FieldName.SERIES, FieldName.NUMBER, FieldName.NOTE,
- FieldName.PUBLISHER, FieldName.LOCATION, FieldName.ISBN, FieldName.CHAPTER, FieldName.PAGES, FieldName.PAGETOTAL, "addendum", FieldName.PUBSTATE, FieldName.DOI,
- FieldName.EPRINT, FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE);
+ addAllOptional(FieldName.EDITORA, FieldName.EDITORB, FieldName.EDITORC, FieldName.TRANSLATOR,
+ FieldName.ANNOTATOR, FieldName.COMMENTATOR, FieldName.INTRODUCTION, FieldName.FOREWORD,
+ FieldName.AFTERWORD, FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.MAINTITLE,
+ FieldName.MAINSUBTITLE, FieldName.MAINTITLEADDON, FieldName.LANGUAGE, FieldName.ORIGLANGUAGE,
+ FieldName.VOLUME, FieldName.PART, FieldName.EDITION, FieldName.VOLUMES, FieldName.SERIES,
+ FieldName.NUMBER, FieldName.NOTE, FieldName.PUBLISHER, FieldName.LOCATION, FieldName.ISBN,
+ FieldName.CHAPTER, FieldName.PAGES, FieldName.PAGETOTAL, FieldName.ADDENDUM, FieldName.PUBSTATE,
+ FieldName.DOI, FieldName.EPRINT, FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL,
+ FieldName.URLDATE);
}
+
@Override
public String getName() {
return "Collection";
@@ -230,18 +252,22 @@ public class BibLatexEntryTypes {
public static final BibLatexEntryType MVCOLLECTION = new BibLatexEntryType() {
private final List<String> primaryOptionalFields = Collections
- .unmodifiableList(Arrays.asList(FieldName.TRANSLATOR, FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.EDITION, FieldName.PUBLISHER, FieldName.ISBN,
- FieldName.DOI, FieldName.EPRINT, FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE));
-
+ .unmodifiableList(Arrays.asList(FieldName.TRANSLATOR, FieldName.SUBTITLE, FieldName.TITLEADDON,
+ FieldName.EDITION, FieldName.PUBLISHER, FieldName.ISBN, FieldName.DOI, FieldName.EPRINT,
+ FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE));
{
addAllRequired(FieldName.EDITOR, FieldName.TITLE, FieldName.orFields(FieldName.YEAR, FieldName.DATE));
- addAllOptional("editora", "editorb", "editorc", FieldName.TRANSLATOR, "annotator", "commentator", "introduction",
- "foreword", "afterword", FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.LANGUAGE, FieldName.ORIGLANGUAGE, FieldName.EDITION, FieldName.VOLUMES, FieldName.SERIES, FieldName.NUMBER, FieldName.NOTE,
- FieldName.PUBLISHER, FieldName.LOCATION, FieldName.ISBN, FieldName.PAGETOTAL, "addendum", FieldName.PUBSTATE, FieldName.DOI,
- FieldName.EPRINT, FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE);
+ addAllOptional(FieldName.EDITORA, FieldName.EDITORB, FieldName.EDITORC, FieldName.TRANSLATOR,
+ FieldName.ANNOTATOR, FieldName.COMMENTATOR, FieldName.INTRODUCTION, FieldName.FOREWORD,
+ FieldName.AFTERWORD, FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.LANGUAGE,
+ FieldName.ORIGLANGUAGE, FieldName.EDITION, FieldName.VOLUMES, FieldName.SERIES, FieldName.NUMBER,
+ FieldName.NOTE, FieldName.PUBLISHER, FieldName.LOCATION, FieldName.ISBN, FieldName.PAGETOTAL,
+ FieldName.ADDENDUM, FieldName.PUBSTATE, FieldName.DOI, FieldName.EPRINT, FieldName.EPRINTCLASS,
+ FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE);
}
+
@Override
public String getName() {
return "MvCollection";
@@ -255,23 +281,28 @@ public class BibLatexEntryTypes {
public static final BibLatexEntryType INCOLLECTION = new BibLatexEntryType() {
- private final List<String> primaryOptionalFields = Collections.unmodifiableList(
- Arrays.asList(FieldName.TRANSLATOR, FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.MAINTITLE, FieldName.MAINSUBTITLE,
- FieldName.MAINTITLEADDON, FieldName.BOOKSUBTITLE, FieldName.BOOKTITLEADDON, FieldName.VOLUME, FieldName.EDITION, FieldName.PUBLISHER, FieldName.ISBN,
- FieldName.CHAPTER, FieldName.PAGES, FieldName.DOI, FieldName.EPRINT, FieldName.EPRINTCLASS, FieldName.EPRINTTYPE,
- FieldName.URL, FieldName.URLDATE));
-
+ private final List<String> primaryOptionalFields = Collections
+ .unmodifiableList(Arrays.asList(FieldName.TRANSLATOR, FieldName.SUBTITLE, FieldName.TITLEADDON,
+ FieldName.MAINTITLE, FieldName.MAINSUBTITLE, FieldName.MAINTITLEADDON, FieldName.BOOKSUBTITLE,
+ FieldName.BOOKTITLEADDON, FieldName.VOLUME, FieldName.EDITION, FieldName.PUBLISHER,
+ FieldName.ISBN, FieldName.CHAPTER, FieldName.PAGES, FieldName.DOI, FieldName.EPRINT,
+ FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE));
{
- addAllRequired(FieldName.AUTHOR, FieldName.TITLE, FieldName.BOOKTITLE, FieldName.orFields(FieldName.YEAR, FieldName.DATE));
- addAllOptional(FieldName.EDITOR, "editora", "editorb", "editorc", FieldName.TRANSLATOR, "annotator", "commentator", "introduction",
- "foreword", "afterword", FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.MAINTITLE, FieldName.MAINSUBTITLE, FieldName.MAINTITLEADDON,
- FieldName.BOOKSUBTITLE, FieldName.BOOKTITLEADDON, FieldName.LANGUAGE, FieldName.ORIGLANGUAGE, FieldName.VOLUME, FieldName.PART, FieldName.EDITION,
- FieldName.VOLUMES, FieldName.SERIES, FieldName.NUMBER, FieldName.NOTE, FieldName.PUBLISHER, FieldName.LOCATION, FieldName.ISBN, FieldName.CHAPTER, FieldName.PAGES,
- "addendum", FieldName.PUBSTATE, FieldName.DOI, FieldName.EPRINT, FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL,
- FieldName.URLDATE);
+ addAllRequired(FieldName.AUTHOR, FieldName.TITLE, FieldName.BOOKTITLE,
+ FieldName.orFields(FieldName.YEAR, FieldName.DATE));
+ addAllOptional(FieldName.EDITOR, FieldName.EDITORA, FieldName.EDITORB, FieldName.EDITORC,
+ FieldName.TRANSLATOR, FieldName.ANNOTATOR, FieldName.COMMENTATOR, FieldName.INTRODUCTION,
+ FieldName.FOREWORD, FieldName.AFTERWORD, FieldName.SUBTITLE, FieldName.TITLEADDON,
+ FieldName.MAINTITLE, FieldName.MAINSUBTITLE, FieldName.MAINTITLEADDON, FieldName.BOOKSUBTITLE,
+ FieldName.BOOKTITLEADDON, FieldName.LANGUAGE, FieldName.ORIGLANGUAGE, FieldName.VOLUME,
+ FieldName.PART, FieldName.EDITION, FieldName.VOLUMES, FieldName.SERIES, FieldName.NUMBER,
+ FieldName.NOTE, FieldName.PUBLISHER, FieldName.LOCATION, FieldName.ISBN, FieldName.CHAPTER,
+ FieldName.PAGES, FieldName.ADDENDUM, FieldName.PUBSTATE, FieldName.DOI, FieldName.EPRINT,
+ FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE);
}
+
@Override
public String getName() {
return "InCollection";
@@ -309,20 +340,22 @@ public class BibLatexEntryTypes {
public static final BibLatexEntryType MANUAL = new BibLatexEntryType() {
- private final List<String> primaryOptionalFields = Collections
- .unmodifiableList(Arrays.asList(FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.EDITION, FieldName.PUBLISHER, FieldName.ISBN,
- FieldName.CHAPTER, FieldName.PAGES, FieldName.DOI, FieldName.EPRINT, FieldName.EPRINTCLASS,
- FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE));
-
+ private final List<String> primaryOptionalFields = Collections.unmodifiableList(
+ Arrays.asList(FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.EDITION, FieldName.PUBLISHER,
+ FieldName.ISBN, FieldName.CHAPTER, FieldName.PAGES, FieldName.DOI, FieldName.EPRINT,
+ FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE));
{
- addAllRequired(FieldName.orFields(FieldName.AUTHOR, FieldName.EDITOR), FieldName.TITLE, FieldName.orFields(FieldName.YEAR, FieldName.DATE));
- addAllOptional(FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.LANGUAGE, FieldName.EDITION, FieldName.TYPE, FieldName.SERIES, FieldName.NUMBER, FieldName.VERSION,
- FieldName.NOTE, FieldName.ORGANIZATION, FieldName.PUBLISHER, FieldName.LOCATION, FieldName.ISBN, FieldName.CHAPTER, FieldName.PAGES, FieldName.PAGETOTAL,
- "addendum", FieldName.PUBSTATE, FieldName.DOI, FieldName.EPRINT, FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL,
- FieldName.URLDATE);
+ addAllRequired(FieldName.orFields(FieldName.AUTHOR, FieldName.EDITOR), FieldName.TITLE,
+ FieldName.orFields(FieldName.YEAR, FieldName.DATE));
+ addAllOptional(FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.LANGUAGE, FieldName.EDITION,
+ FieldName.TYPE, FieldName.SERIES, FieldName.NUMBER, FieldName.VERSION, FieldName.NOTE,
+ FieldName.ORGANIZATION, FieldName.PUBLISHER, FieldName.LOCATION, FieldName.ISBN, FieldName.CHAPTER,
+ FieldName.PAGES, FieldName.PAGETOTAL, FieldName.ADDENDUM, FieldName.PUBSTATE, FieldName.DOI,
+ FieldName.EPRINT, FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE);
}
+
@Override
public String getName() {
return "Manual";
@@ -336,19 +369,20 @@ public class BibLatexEntryTypes {
public static final BibLatexEntryType MISC = new BibLatexEntryType() {
- private final List<String> primaryOptionalFields = Collections
- .unmodifiableList(Arrays.asList(FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.HOWPUBLISHED, FieldName.LOCATION,
- FieldName.DOI, FieldName.EPRINT, FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE));
-
+ private final List<String> primaryOptionalFields = Collections.unmodifiableList(Arrays.asList(
+ FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.HOWPUBLISHED, FieldName.LOCATION, FieldName.DOI,
+ FieldName.EPRINT, FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE));
{
- addAllRequired(FieldName.orFields(FieldName.AUTHOR, FieldName.EDITOR), FieldName.TITLE, FieldName.orFields(FieldName.YEAR, FieldName.DATE));
- addAllOptional(FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.LANGUAGE, FieldName.HOWPUBLISHED, FieldName.TYPE, FieldName.VERSION, FieldName.NOTE,
- FieldName.ORGANIZATION, FieldName.LOCATION, FieldName.MONTH, "addendum", FieldName.PUBSTATE, FieldName.DOI,
- FieldName.EPRINT, FieldName.EPRINTCLASS,
- FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE);
+ addAllRequired(FieldName.orFields(FieldName.AUTHOR, FieldName.EDITOR), FieldName.TITLE,
+ FieldName.orFields(FieldName.YEAR, FieldName.DATE));
+ addAllOptional(FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.LANGUAGE, FieldName.HOWPUBLISHED,
+ FieldName.TYPE, FieldName.VERSION, FieldName.NOTE, FieldName.ORGANIZATION, FieldName.LOCATION,
+ FieldName.MONTH, FieldName.ADDENDUM, FieldName.PUBSTATE, FieldName.DOI, FieldName.EPRINT,
+ FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE);
}
+
@Override
public String getName() {
return "Misc";
@@ -362,15 +396,18 @@ public class BibLatexEntryTypes {
public static final BibLatexEntryType ONLINE = new BibLatexEntryType() {
- private final List<String> primaryOptionalFields = Collections.unmodifiableList(
- Arrays.asList(FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.NOTE, FieldName.ORGANIZATION, FieldName.URLDATE));
-
+ private final List<String> primaryOptionalFields = Collections.unmodifiableList(Arrays.asList(
+ FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.NOTE, FieldName.ORGANIZATION, FieldName.URLDATE));
{
- addAllRequired(FieldName.orFields(FieldName.AUTHOR, FieldName.EDITOR), FieldName.TITLE, FieldName.orFields(FieldName.YEAR, FieldName.DATE), FieldName.URL);
- addAllOptional(FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.LANGUAGE, FieldName.VERSION, FieldName.NOTE, FieldName.ORGANIZATION, FieldName.MONTH, "addendum", FieldName.PUBSTATE, FieldName.URLDATE);
+ addAllRequired(FieldName.orFields(FieldName.AUTHOR, FieldName.EDITOR), FieldName.TITLE,
+ FieldName.orFields(FieldName.YEAR, FieldName.DATE), FieldName.URL);
+ addAllOptional(FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.LANGUAGE, FieldName.VERSION,
+ FieldName.NOTE, FieldName.ORGANIZATION, FieldName.MONTH, FieldName.ADDENDUM, FieldName.PUBSTATE,
+ FieldName.URLDATE);
}
+
@Override
public String getName() {
return "Online";
@@ -384,18 +421,20 @@ public class BibLatexEntryTypes {
public static final BibLatexEntryType PATENT = new BibLatexEntryType() {
- private final List<String> primaryOptionalFields = Collections.unmodifiableList(Arrays.asList("holder",
- FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.DOI, FieldName.EPRINT, FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL,
- FieldName.URLDATE));
-
+ private final List<String> primaryOptionalFields = Collections.unmodifiableList(Arrays.asList(FieldName.HOLDER,
+ FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.DOI, FieldName.EPRINT, FieldName.EPRINTCLASS,
+ FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE));
{
- addAllRequired(FieldName.AUTHOR, FieldName.TITLE, FieldName.NUMBER, FieldName.orFields(FieldName.YEAR, FieldName.DATE));
- addAllOptional("holder", FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.TYPE, FieldName.VERSION, FieldName.LOCATION, FieldName.NOTE, FieldName.MONTH,
- "addendum", FieldName.PUBSTATE, FieldName.DOI, FieldName.EPRINT, FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL,
- FieldName.URLDATE);
+ addAllRequired(FieldName.AUTHOR, FieldName.TITLE, FieldName.NUMBER,
+ FieldName.orFields(FieldName.YEAR, FieldName.DATE));
+ addAllOptional(FieldName.HOLDER, FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.TYPE,
+ FieldName.VERSION, FieldName.LOCATION, FieldName.NOTE, FieldName.MONTH, FieldName.ADDENDUM,
+ FieldName.PUBSTATE, FieldName.DOI, FieldName.EPRINT, FieldName.EPRINTCLASS, FieldName.EPRINTTYPE,
+ FieldName.URL, FieldName.URLDATE);
}
+
@Override
public String getName() {
return "Patent";
@@ -409,18 +448,20 @@ public class BibLatexEntryTypes {
public static final BibLatexEntryType PERIODICAL = new BibLatexEntryType() {
- private final List<String> primaryOptionalFields = Collections
- .unmodifiableList(Arrays.asList(FieldName.SUBTITLE, "issuetitle", "issuesubtitle", FieldName.ISSN, FieldName.DOI,
- FieldName.EPRINT, FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE));
-
+ private final List<String> primaryOptionalFields = Collections.unmodifiableList(Arrays.asList(
+ FieldName.SUBTITLE, FieldName.ISSUETITLE, FieldName.ISSUESUBTITLE, FieldName.ISSN, FieldName.DOI,
+ FieldName.EPRINT, FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE));
{
addAllRequired(FieldName.EDITOR, FieldName.TITLE, FieldName.orFields(FieldName.YEAR, FieldName.DATE));
- addAllOptional("editora", "editorb", "editorc", FieldName.SUBTITLE, "issuetitle", "issuesubtitle", FieldName.LANGUAGE,
- FieldName.SERIES, FieldName.VOLUME, FieldName.NUMBER, FieldName.ISSUE, FieldName.MONTH, FieldName.NOTE, FieldName.ISSN, "addendum", FieldName.PUBSTATE,
- FieldName.DOI, FieldName.EPRINT, FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE);
+ addAllOptional(FieldName.EDITORA, FieldName.EDITORB, FieldName.EDITORC, FieldName.SUBTITLE,
+ FieldName.ISSUETITLE, FieldName.ISSUESUBTITLE, FieldName.LANGUAGE, FieldName.SERIES,
+ FieldName.VOLUME, FieldName.NUMBER, FieldName.ISSUE, FieldName.MONTH, FieldName.NOTE,
+ FieldName.ISSN, FieldName.ADDENDUM, FieldName.PUBSTATE, FieldName.DOI, FieldName.EPRINT,
+ FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE);
}
+
@Override
public String getName() {
return "Periodical";
@@ -458,21 +499,25 @@ public class BibLatexEntryTypes {
public static final BibLatexEntryType PROCEEDINGS = new BibLatexEntryType() {
- private final List<String> primaryOptionalFields = Collections
- .unmodifiableList(Arrays.asList(FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.MAINTITLE, FieldName.MAINSUBTITLE,
- FieldName.MAINTITLEADDON, "eventtitle", FieldName.VOLUME, FieldName.PUBLISHER, FieldName.ISBN, FieldName.CHAPTER, FieldName.PAGES, FieldName.PAGETOTAL,
- FieldName.DOI, FieldName.EPRINT, FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE));
-
+ private final List<String> primaryOptionalFields = Collections.unmodifiableList(Arrays.asList(
+ FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.MAINTITLE, FieldName.MAINSUBTITLE,
+ FieldName.MAINTITLEADDON, FieldName.EVENTTITLE, FieldName.VOLUME, FieldName.PUBLISHER, FieldName.ISBN,
+ FieldName.CHAPTER, FieldName.PAGES, FieldName.PAGETOTAL, FieldName.DOI, FieldName.EPRINT,
+ FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE));
{
addAllRequired(FieldName.TITLE, FieldName.orFields(FieldName.YEAR, FieldName.DATE));
- addAllOptional(FieldName.EDITOR, FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.MAINTITLE, FieldName.MAINSUBTITLE, FieldName.MAINTITLEADDON, "eventtitle",
- "eventtitleaddon", "eventdate", "venue", FieldName.LANGUAGE, FieldName.VOLUME, FieldName.PART, FieldName.VOLUMES, FieldName.SERIES, FieldName.NUMBER, FieldName.NOTE,
- FieldName.ORGANIZATION, FieldName.PUBLISHER, FieldName.LOCATION, FieldName.MONTH, FieldName.YEAR, FieldName.ISBN, FieldName.CHAPTER, FieldName.PAGES, FieldName.PAGETOTAL,
- "addendum", FieldName.PUBSTATE, FieldName.DOI, FieldName.EPRINT, FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL,
+ addAllOptional(FieldName.EDITOR, FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.MAINTITLE,
+ FieldName.MAINSUBTITLE, FieldName.MAINTITLEADDON, FieldName.EVENTTITLE, FieldName.EVENTTITLEADDON,
+ FieldName.EVENTDATE, FieldName.VENUE, FieldName.LANGUAGE, FieldName.VOLUME, FieldName.PART,
+ FieldName.VOLUMES, FieldName.SERIES, FieldName.NUMBER, FieldName.NOTE, FieldName.ORGANIZATION,
+ FieldName.PUBLISHER, FieldName.LOCATION, FieldName.MONTH, FieldName.YEAR, FieldName.ISBN,
+ FieldName.CHAPTER, FieldName.PAGES, FieldName.PAGETOTAL, FieldName.ADDENDUM, FieldName.PUBSTATE,
+ FieldName.DOI, FieldName.EPRINT, FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL,
FieldName.URLDATE);
}
+
@Override
public String getName() {
return "Proceedings";
@@ -486,21 +531,24 @@ public class BibLatexEntryTypes {
public static final BibLatexEntryType MVPROCEEDINGS = new BibLatexEntryType() {
- private final List<String> primaryOptionalFields = Collections
- .unmodifiableList(Arrays.asList(FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.MAINTITLE, FieldName.MAINSUBTITLE,
- FieldName.MAINTITLEADDON, "eventtitle", FieldName.VOLUME, FieldName.PUBLISHER, FieldName.ISBN, FieldName.CHAPTER, FieldName.PAGES, FieldName.PAGETOTAL,
- FieldName.DOI, FieldName.EPRINT, FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE));
-
+ private final List<String> primaryOptionalFields = Collections.unmodifiableList(Arrays.asList(
+ FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.MAINTITLE, FieldName.MAINSUBTITLE,
+ FieldName.MAINTITLEADDON, FieldName.EVENTTITLE, FieldName.VOLUME, FieldName.PUBLISHER, FieldName.ISBN,
+ FieldName.CHAPTER, FieldName.PAGES, FieldName.PAGETOTAL, FieldName.DOI, FieldName.EPRINT,
+ FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE));
{
addAllRequired(FieldName.TITLE, FieldName.orFields(FieldName.YEAR, FieldName.DATE));
- addAllOptional(FieldName.EDITOR, FieldName.SUBTITLE, FieldName.TITLEADDON, "eventtitle",
- "eventtitleaddon", "eventdate", "venue", FieldName.LANGUAGE, FieldName.VOLUMES, FieldName.SERIES, FieldName.NUMBER, FieldName.NOTE,
- FieldName.ORGANIZATION, FieldName.PUBLISHER, FieldName.LOCATION, FieldName.MONTH, FieldName.ISBN, FieldName.PAGETOTAL,
- "addendum", FieldName.PUBSTATE, FieldName.DOI, FieldName.EPRINT, FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL,
+ addAllOptional(FieldName.EDITOR, FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.EVENTTITLE,
+ FieldName.EVENTTITLEADDON, FieldName.EVENTDATE, FieldName.VENUE, FieldName.LANGUAGE,
+ FieldName.VOLUMES, FieldName.SERIES, FieldName.NUMBER, FieldName.NOTE, FieldName.ORGANIZATION,
+ FieldName.PUBLISHER, FieldName.LOCATION, FieldName.MONTH, FieldName.ISBN, FieldName.PAGETOTAL,
+ FieldName.ADDENDUM, FieldName.PUBSTATE, FieldName.DOI, FieldName.EPRINT, FieldName.EPRINTCLASS,
+ FieldName.EPRINTTYPE, FieldName.URL,
FieldName.URLDATE);
}
+
@Override
public String getName() {
return "MvProceedings";
@@ -515,22 +563,26 @@ public class BibLatexEntryTypes {
public static final BibLatexEntryType INPROCEEDINGS = new BibLatexEntryType() {
private final List<String> primaryOptionalFields = Collections
- .unmodifiableList(Arrays.asList(FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.MAINTITLE, FieldName.MAINSUBTITLE,
- FieldName.MAINTITLEADDON, FieldName.BOOKSUBTITLE, FieldName.BOOKTITLEADDON, "eventtitle", FieldName.VOLUME, FieldName.PUBLISHER, FieldName.ISBN,
- FieldName.CHAPTER, FieldName.PAGES, FieldName.DOI, FieldName.EPRINT, FieldName.EPRINTCLASS, FieldName.EPRINTTYPE,
- FieldName.URL, FieldName.URLDATE));
-
+ .unmodifiableList(Arrays.asList(FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.MAINTITLE,
+ FieldName.MAINSUBTITLE, FieldName.MAINTITLEADDON, FieldName.BOOKSUBTITLE,
+ FieldName.BOOKTITLEADDON, FieldName.EVENTTITLE, FieldName.VOLUME, FieldName.PUBLISHER,
+ FieldName.ISBN, FieldName.CHAPTER, FieldName.PAGES, FieldName.DOI, FieldName.EPRINT,
+ FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE));
{
- addAllRequired(FieldName.AUTHOR, FieldName.TITLE, FieldName.BOOKTITLE, FieldName.orFields(FieldName.YEAR, FieldName.DATE));
- addAllOptional(FieldName.EDITOR, FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.MAINTITLE, FieldName.MAINSUBTITLE, FieldName.MAINTITLEADDON, FieldName.BOOKSUBTITLE,
- FieldName.BOOKTITLEADDON, "eventtitle", "eventtitleaddon", "eventdate", "venue", FieldName.LANGUAGE, FieldName.VOLUME, FieldName.PART, FieldName.VOLUMES,
- FieldName.SERIES, FieldName.NUMBER, FieldName.NOTE, FieldName.ORGANIZATION, FieldName.PUBLISHER, FieldName.LOCATION, FieldName.MONTH, FieldName.ISBN,
- FieldName.CHAPTER, FieldName.PAGES, "addendum", FieldName.PUBSTATE, FieldName.DOI, FieldName.EPRINT, FieldName.EPRINTCLASS,
- FieldName.EPRINTTYPE, FieldName.URL,
- FieldName.URLDATE);
+ addAllRequired(FieldName.AUTHOR, FieldName.TITLE, FieldName.BOOKTITLE,
+ FieldName.orFields(FieldName.YEAR, FieldName.DATE));
+ addAllOptional(FieldName.EDITOR, FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.MAINTITLE,
+ FieldName.MAINSUBTITLE, FieldName.MAINTITLEADDON, FieldName.BOOKSUBTITLE, FieldName.BOOKTITLEADDON,
+ FieldName.EVENTTITLE, FieldName.EVENTTITLEADDON, FieldName.EVENTDATE, FieldName.VENUE,
+ FieldName.LANGUAGE, FieldName.VOLUME, FieldName.PART, FieldName.VOLUMES, FieldName.SERIES,
+ FieldName.NUMBER, FieldName.NOTE, FieldName.ORGANIZATION, FieldName.PUBLISHER, FieldName.LOCATION,
+ FieldName.MONTH, FieldName.ISBN, FieldName.CHAPTER, FieldName.PAGES, FieldName.ADDENDUM,
+ FieldName.PUBSTATE, FieldName.DOI, FieldName.EPRINT, FieldName.EPRINTCLASS, FieldName.EPRINTTYPE,
+ FieldName.URL, FieldName.URLDATE);
}
+
@Override
public String getName() {
return "InProceedings";
@@ -616,20 +668,22 @@ public class BibLatexEntryTypes {
public static final BibLatexEntryType REPORT = new BibLatexEntryType() {
- private final List<String> primaryOptionalFields = Collections
- .unmodifiableList(Arrays.asList(FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.NUMBER, FieldName.ISRN, FieldName.CHAPTER,
- FieldName.PAGES, FieldName.PAGETOTAL, FieldName.DOI, FieldName.EPRINT, FieldName.EPRINTCLASS, FieldName.EPRINTTYPE,
- FieldName.URL, FieldName.URLDATE));
-
+ private final List<String> primaryOptionalFields = Collections.unmodifiableList(
+ Arrays.asList(FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.NUMBER, FieldName.ISRN,
+ FieldName.CHAPTER, FieldName.PAGES, FieldName.PAGETOTAL, FieldName.DOI, FieldName.EPRINT,
+ FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE));
{
- addAllRequired(FieldName.AUTHOR, FieldName.TITLE, FieldName.TYPE, FieldName.INSTITUTION, FieldName.orFields(FieldName.YEAR, FieldName.DATE));
- addAllOptional(FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.LANGUAGE, FieldName.NUMBER, FieldName.VERSION, FieldName.NOTE, FieldName.LOCATION, FieldName.MONTH,
- FieldName.ISRN, FieldName.CHAPTER, FieldName.PAGES, FieldName.PAGETOTAL, "addendum", FieldName.PUBSTATE, FieldName.DOI,
- FieldName.EPRINT,
- FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE);
+ addAllRequired(FieldName.AUTHOR, FieldName.TITLE, FieldName.TYPE, FieldName.INSTITUTION,
+ FieldName.orFields(FieldName.YEAR, FieldName.DATE));
+ addAllOptional(FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.LANGUAGE, FieldName.NUMBER,
+ FieldName.VERSION, FieldName.NOTE, FieldName.LOCATION, FieldName.MONTH, FieldName.ISRN,
+ FieldName.CHAPTER, FieldName.PAGES, FieldName.PAGETOTAL, FieldName.ADDENDUM, FieldName.PUBSTATE,
+ FieldName.DOI, FieldName.EPRINT, FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL,
+ FieldName.URLDATE);
}
+
@Override
public String getName() {
return "Report";
@@ -642,10 +696,12 @@ public class BibLatexEntryTypes {
};
public static final BibLatexEntryType SET = new BibLatexEntryType() {
+
{
addAllRequired(FieldName.ENTRYSET, FieldName.CROSSREF);
}
+
@Override
public String getName() {
return "Set";
@@ -655,18 +711,20 @@ public class BibLatexEntryTypes {
public static final BibLatexEntryType THESIS = new BibLatexEntryType() {
private final List<String> primaryOptionalFields = Collections
- .unmodifiableList(Arrays.asList(FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.CHAPTER, FieldName.PAGES, FieldName.PAGETOTAL,
- FieldName.DOI, FieldName.EPRINT, FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE));
-
+ .unmodifiableList(Arrays.asList(FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.CHAPTER,
+ FieldName.PAGES, FieldName.PAGETOTAL, FieldName.DOI, FieldName.EPRINT, FieldName.EPRINTCLASS,
+ FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE));
{
- addAllRequired(FieldName.AUTHOR, FieldName.TITLE, FieldName.TYPE, FieldName.INSTITUTION, FieldName.orFields(FieldName.YEAR, FieldName.DATE));
- addAllOptional(FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.LANGUAGE, FieldName.NOTE, FieldName.LOCATION, FieldName.MONTH, FieldName.ISBN, FieldName.CHAPTER,
- FieldName.PAGES, FieldName.PAGETOTAL, "addendum", FieldName.PUBSTATE, FieldName.DOI, FieldName.EPRINT,
- FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL,
- FieldName.URLDATE);
+ addAllRequired(FieldName.AUTHOR, FieldName.TITLE, FieldName.TYPE, FieldName.INSTITUTION,
+ FieldName.orFields(FieldName.YEAR, FieldName.DATE));
+ addAllOptional(FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.LANGUAGE, FieldName.NOTE,
+ FieldName.LOCATION, FieldName.MONTH, FieldName.ISBN, FieldName.CHAPTER, FieldName.PAGES,
+ FieldName.PAGETOTAL, FieldName.ADDENDUM, FieldName.PUBSTATE, FieldName.DOI, FieldName.EPRINT,
+ FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE);
}
+
@Override
public String getName() {
return "Thesis";
@@ -680,16 +738,18 @@ public class BibLatexEntryTypes {
public static final BibLatexEntryType UNPUBLISHED = new BibLatexEntryType() {
- private final List<String> primaryOptionalFields = Collections.unmodifiableList(
- Arrays.asList(FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.HOWPUBLISHED, FieldName.PUBSTATE, FieldName.URL, FieldName.URLDATE));
-
+ private final List<String> primaryOptionalFields = Collections
+ .unmodifiableList(Arrays.asList(FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.HOWPUBLISHED,
+ FieldName.PUBSTATE, FieldName.URL, FieldName.URLDATE));
{
addAllRequired(FieldName.AUTHOR, FieldName.TITLE, FieldName.orFields(FieldName.YEAR, FieldName.DATE));
- addAllOptional(FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.LANGUAGE, FieldName.HOWPUBLISHED, FieldName.NOTE, FieldName.LOCATION, FieldName.MONTH,
- "addendum", FieldName.PUBSTATE, FieldName.URL, FieldName.URLDATE);
+ addAllOptional(FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.LANGUAGE, FieldName.HOWPUBLISHED,
+ FieldName.NOTE, FieldName.LOCATION, FieldName.MONTH, FieldName.ADDENDUM, FieldName.PUBSTATE,
+ FieldName.URL, FieldName.URLDATE);
}
+
@Override
public String getName() {
return "Unpublished";
@@ -754,20 +814,21 @@ public class BibLatexEntryTypes {
public static final BibLatexEntryType MASTERSTHESIS = new BibLatexEntryType() {
private final List<String> primaryOptionalFields = Collections
- .unmodifiableList(Arrays.asList(FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.TYPE, FieldName.CHAPTER, FieldName.PAGES,
- FieldName.PAGETOTAL, FieldName.DOI, FieldName.EPRINT, FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL,
- FieldName.URLDATE));
-
+ .unmodifiableList(Arrays.asList(FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.TYPE,
+ FieldName.CHAPTER, FieldName.PAGES, FieldName.PAGETOTAL, FieldName.DOI, FieldName.EPRINT,
+ FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE));
{
// Treated as alias of "THESIS", except FieldName.TYPE field is optional
- addAllRequired(FieldName.AUTHOR, FieldName.TITLE, FieldName.INSTITUTION, FieldName.orFields(FieldName.YEAR, FieldName.DATE));
- addAllOptional(FieldName.TYPE, FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.LANGUAGE, FieldName.NOTE, FieldName.LOCATION, FieldName.MONTH, FieldName.ISBN, FieldName.CHAPTER,
- FieldName.PAGES, FieldName.PAGETOTAL, "addendum", FieldName.PUBSTATE, FieldName.DOI, FieldName.EPRINT,
- FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL,
- FieldName.URLDATE);
+ addAllRequired(FieldName.AUTHOR, FieldName.TITLE, FieldName.INSTITUTION,
+ FieldName.orFields(FieldName.YEAR, FieldName.DATE));
+ addAllOptional(FieldName.TYPE, FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.LANGUAGE, FieldName.NOTE,
+ FieldName.LOCATION, FieldName.MONTH, FieldName.ISBN, FieldName.CHAPTER, FieldName.PAGES,
+ FieldName.PAGETOTAL, FieldName.ADDENDUM, FieldName.PUBSTATE, FieldName.DOI, FieldName.EPRINT,
+ FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE);
}
+
@Override
public String getName() {
return "MastersThesis";
@@ -782,20 +843,21 @@ public class BibLatexEntryTypes {
public static final BibLatexEntryType PHDTHESIS = new BibLatexEntryType() {
private final List<String> primaryOptionalFields = Collections
- .unmodifiableList(Arrays.asList(FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.TYPE, FieldName.CHAPTER, FieldName.PAGES,
- FieldName.PAGETOTAL, FieldName.DOI, FieldName.EPRINT, FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL,
- FieldName.URLDATE));
-
+ .unmodifiableList(Arrays.asList(FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.TYPE,
+ FieldName.CHAPTER, FieldName.PAGES, FieldName.PAGETOTAL, FieldName.DOI, FieldName.EPRINT,
+ FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE));
{
// Treated as alias of "THESIS", except FieldName.TYPE field is optional
- addAllRequired(FieldName.AUTHOR, FieldName.TITLE, FieldName.INSTITUTION, FieldName.orFields(FieldName.YEAR, FieldName.DATE));
- addAllOptional(FieldName.TYPE, FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.LANGUAGE, FieldName.NOTE, FieldName.LOCATION, FieldName.MONTH, FieldName.ISBN, FieldName.CHAPTER,
- FieldName.PAGES, FieldName.PAGETOTAL, "addendum", FieldName.PUBSTATE, FieldName.DOI, FieldName.EPRINT,
- FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL,
- FieldName.URLDATE);
+ addAllRequired(FieldName.AUTHOR, FieldName.TITLE, FieldName.INSTITUTION,
+ FieldName.orFields(FieldName.YEAR, FieldName.DATE));
+ addAllOptional(FieldName.TYPE, FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.LANGUAGE, FieldName.NOTE,
+ FieldName.LOCATION, FieldName.MONTH, FieldName.ISBN, FieldName.CHAPTER, FieldName.PAGES,
+ FieldName.PAGETOTAL, FieldName.ADDENDUM, FieldName.PUBSTATE, FieldName.DOI, FieldName.EPRINT,
+ FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE);
}
+
@Override
public String getName() {
return "PhdThesis";
@@ -809,20 +871,23 @@ public class BibLatexEntryTypes {
public static final BibLatexEntryType TECHREPORT = new BibLatexEntryType() {
- private final List<String> primaryOptionalFields = Collections.unmodifiableList(
- Arrays.asList(FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.TYPE, FieldName.NUMBER, FieldName.ISRN, FieldName.CHAPTER, FieldName.PAGES,
- FieldName.PAGETOTAL, FieldName.DOI, FieldName.EPRINT, FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL,
- FieldName.URLDATE));
-
+ private final List<String> primaryOptionalFields = Collections.unmodifiableList(Arrays.asList(
+ FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.TYPE, FieldName.NUMBER, FieldName.ISRN,
+ FieldName.CHAPTER, FieldName.PAGES, FieldName.PAGETOTAL, FieldName.DOI, FieldName.EPRINT,
+ FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE));
{
// Treated as alias of "REPORT", except FieldName.TYPE field is optional
- addAllRequired(FieldName.AUTHOR, FieldName.TITLE, FieldName.INSTITUTION, FieldName.orFields(FieldName.YEAR, FieldName.DATE));
- addAllOptional(FieldName.TYPE, FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.LANGUAGE, FieldName.NUMBER, FieldName.VERSION, FieldName.NOTE, FieldName.LOCATION, FieldName.MONTH,
- FieldName.ISRN, FieldName.CHAPTER, FieldName.PAGES, FieldName.PAGETOTAL, "addendum", FieldName.PUBSTATE, FieldName.DOI,
- FieldName.EPRINT, FieldName.EPRINTCLASS, FieldName.EPRINTTYPE, FieldName.URL, FieldName.URLDATE);
+ addAllRequired(FieldName.AUTHOR, FieldName.TITLE, FieldName.INSTITUTION,
+ FieldName.orFields(FieldName.YEAR, FieldName.DATE));
+ addAllOptional(FieldName.TYPE, FieldName.SUBTITLE, FieldName.TITLEADDON, FieldName.LANGUAGE,
+ FieldName.NUMBER, FieldName.VERSION, FieldName.NOTE, FieldName.LOCATION, FieldName.MONTH,
+ FieldName.ISRN, FieldName.CHAPTER, FieldName.PAGES, FieldName.PAGETOTAL, FieldName.ADDENDUM,
+ FieldName.PUBSTATE, FieldName.DOI, FieldName.EPRINT, FieldName.EPRINTCLASS, FieldName.EPRINTTYPE,
+ FieldName.URL, FieldName.URLDATE);
}
+
@Override
public String getName() {
return "TechReport";
@@ -865,11 +930,13 @@ public class BibLatexEntryTypes {
public static final BibLatexEntryType IEEETRANBSTCTL = new BibLatexEntryType() {
{
- addAllOptional("ctluse_article_number", "ctluse_paper", "ctluse_forced_etal", "ctluse_url",
- "ctlmax_names_forced_etal", "ctlnames_show_etal", "ctluse_alt_spacing", "ctlalt_stretch_factor",
- "ctldash_repeated_names", "ctlname_format_string", "ctlname_latex_cmd", "ctlname_url_prefix");
+ addAllOptional(FieldName.CTLUSE_ARTICLE_NUMBER, FieldName.CTLUSE_PAPER, FieldName.CTLUSE_FORCED_ETAL,
+ FieldName.CTLUSE_URL, FieldName.CTLMAX_NAMES_FORCED_ETAL, FieldName.CTLNAMES_SHOW_ETAL,
+ FieldName.CTLUSE_ALT_SPACING, FieldName.CTLALT_STRETCH_FACTOR, FieldName.CTLDASH_REPEATED_NAMES,
+ FieldName.CTLNAME_FORMAT_STRING, FieldName.CTLNAME_LATEX_CMD, FieldName.CTLNAME_URL_PREFIX);
}
+
@Override
public String getName() {
return "IEEEtranBSTCTL";
@@ -881,6 +948,7 @@ public class BibLatexEntryTypes {
SUPPPERIODICAL, PROCEEDINGS, MVPROCEEDINGS, INPROCEEDINGS, REFERENCE, MVREFERENCE, INREFERENCE, REPORT, SET,
THESIS, UNPUBLISHED, CONFERENCE, ELECTRONIC, MASTERSTHESIS, PHDTHESIS, TECHREPORT, WWW, IEEETRANBSTCTL);
+
public static Optional<EntryType> getType(String name) {
return ALL.stream().filter(e -> e.getName().equalsIgnoreCase(name)).findFirst();
}
diff --git a/src/main/java/net/sf/jabref/model/entry/BibtexSingleField.java b/src/main/java/net/sf/jabref/model/entry/BibtexSingleField.java
index 5100bbd..f9a4050 100644
--- a/src/main/java/net/sf/jabref/model/entry/BibtexSingleField.java
+++ b/src/main/java/net/sf/jabref/model/entry/BibtexSingleField.java
@@ -4,12 +4,9 @@ import java.util.EnumSet;
import java.util.Set;
/**
- *
* Class for keeping properties of a single BibTeX/BibLatex field
- *
*/
public class BibtexSingleField {
-
// some field constants
public static final double DEFAULT_FIELD_WEIGHT = 1;
public static final double MAX_FIELD_WEIGHT = 2;
@@ -20,7 +17,6 @@ public class BibtexSingleField {
public static final int DEFAULT_FIELD_LENGTH = 100;
-
private enum Flag {
STANDARD,
PRIVATE,
@@ -28,7 +24,6 @@ public class BibtexSingleField {
WRITEABLE
}
-
// the field name
private String name;
@@ -39,10 +34,9 @@ public class BibtexSingleField {
private int length = DEFAULT_FIELD_LENGTH;
private double weight = DEFAULT_FIELD_WEIGHT;
- // the extras data
- // fieldExtras contains mappings to tell the EntryEditor to add a specific
- // function to this field, for instance a "browse" button for the "pdf" field.
- private Set<FieldProperties> extras = EnumSet.noneOf(FieldProperties.class);
+ // properties contains a set of FieldProperty to e.g. tell the EntryEditor to add a specific
+ // function to this field, to format names, or to control the integrity checks.
+ private Set<FieldProperty> properties = EnumSet.noneOf(FieldProperty.class);
// a comma separated list of alternative bibtex-fieldnames, e.g.
// "LCCN" is the same like "lib-congress"
@@ -119,14 +113,14 @@ public class BibtexSingleField {
return flags.contains(Flag.WRITEABLE);
}
- public void setExtras(Set<FieldProperties> pExtras) {
- extras = pExtras;
+ public void setExtras(Set<FieldProperty> pExtras) {
+ properties = pExtras;
}
// fieldExtras contains mappings to tell the EntryEditor to add a specific
// function to this field, for instance a "browse" button for the "pdf" field.
- public Set<FieldProperties> getExtras() {
- return extras;
+ public Set<FieldProperty> getFieldProperties() {
+ return properties;
}
public void setWeight(double value) {
@@ -157,15 +151,15 @@ public class BibtexSingleField {
*/
public BibtexSingleField setNumeric(boolean numeric) {
if (numeric) {
- extras.add(FieldProperties.NUMERIC);
+ properties.add(FieldProperty.NUMERIC);
} else {
- extras.remove(FieldProperties.NUMERIC);
+ properties.remove(FieldProperty.NUMERIC);
}
return this;
}
public boolean isNumeric() {
- return extras.contains(FieldProperties.NUMERIC);
+ return properties.contains(FieldProperty.NUMERIC);
}
public void setName(String fieldName) {
diff --git a/src/main/java/net/sf/jabref/model/entry/BibtexString.java b/src/main/java/net/sf/jabref/model/entry/BibtexString.java
index 8d9844e..6f51390 100644
--- a/src/main/java/net/sf/jabref/model/entry/BibtexString.java
+++ b/src/main/java/net/sf/jabref/model/entry/BibtexString.java
@@ -107,6 +107,9 @@ public class BibtexString implements Cloneable {
type = Type.get(name);
}
+ /*
+ * Never returns null
+ */
public String getContent() {
return content == null ? "" : content;
}
diff --git a/src/main/java/net/sf/jabref/model/entry/CustomEntryType.java b/src/main/java/net/sf/jabref/model/entry/CustomEntryType.java
index 8b1624d..95daa90 100644
--- a/src/main/java/net/sf/jabref/model/entry/CustomEntryType.java
+++ b/src/main/java/net/sf/jabref/model/entry/CustomEntryType.java
@@ -9,6 +9,8 @@ import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
+import net.sf.jabref.model.strings.StringUtil;
+
/**
* This class is used to represent customized entry types.
*/
@@ -21,14 +23,14 @@ public class CustomEntryType implements EntryType {
private final List<String> primaryOptional;
public CustomEntryType(String name, List<String> required, List<String> primaryOptional, List<String> secondaryOptional) {
- this.name = EntryUtil.capitalizeFirst(name);
+ this.name = StringUtil.capitalizeFirst(name);
this.primaryOptional = primaryOptional;
this.required = required;
this.optional = Stream.concat(primaryOptional.stream(), secondaryOptional.stream()).collect(Collectors.toList());
}
public CustomEntryType(String name, List<String> required, List<String> optional) {
- this.name = EntryUtil.capitalizeFirst(name);
+ this.name = StringUtil.capitalizeFirst(name);
this.required = required;
this.optional = optional;
this.primaryOptional = optional;
diff --git a/src/main/java/net/sf/jabref/model/entry/EntryLinkList.java b/src/main/java/net/sf/jabref/model/entry/EntryLinkList.java
new file mode 100644
index 0000000..c0b414c
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/entry/EntryLinkList.java
@@ -0,0 +1,29 @@
+package net.sf.jabref.model.entry;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import net.sf.jabref.model.database.BibDatabase;
+
+public class EntryLinkList {
+
+ private static String SEPARATOR = ",";
+
+
+ public static List<ParsedEntryLink> parse(String fieldValue, BibDatabase database) {
+ List<ParsedEntryLink> result = new ArrayList<>();
+ if ((fieldValue != null) && !fieldValue.isEmpty()) {
+ String[] entries = fieldValue.split(SEPARATOR);
+
+ for (String entry : entries) {
+ result.add(new ParsedEntryLink(entry, database));
+ }
+ }
+ return result;
+ }
+
+ public static String serialize(List<ParsedEntryLink> list) {
+ return String.join(SEPARATOR, list.stream().map(link -> link.getKey()).collect(Collectors.toList()));
+ }
+}
diff --git a/src/main/java/net/sf/jabref/model/entry/EntryUtil.java b/src/main/java/net/sf/jabref/model/entry/EntryUtil.java
deleted file mode 100644
index eaa96e4..0000000
--- a/src/main/java/net/sf/jabref/model/entry/EntryUtil.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package net.sf.jabref.model.entry;
-
-import java.util.Arrays;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.StringTokenizer;
-
-public class EntryUtil {
-
- public static final String SEPARATING_CHARS_NOSPACE = ";,\n";
-
-
- /**
- * Make first character of String uppercase, and the
- * rest lowercase.
- */
- public static String capitalizeFirst(String toCapitalize) {
- if (toCapitalize.length() > 1) {
- return toCapitalize.substring(0, 1).toUpperCase()
- + toCapitalize.substring(1, toCapitalize.length()).toLowerCase();
- } else {
- return toCapitalize.toUpperCase();
- }
-
- }
-
- /**
- * @param keywordString a String of keywords
- * @return an List containing the keywords. An empty list if keywords are null or empty
- */
- public static Set<String> getSeparatedKeywords(String keywordString) {
- LinkedHashSet<String> keywords = new LinkedHashSet<>();
- if (keywordString == null) {
- return keywords;
- }
- // _NOSPACE is a hack to support keywords such as "choreography transactions"
- // a more intelligent algorithm would check for the separator chosen (SEPARATING_CHARS_NOSPACE)
- // if nothing is found, " " is likely to be the separating char.
- // solution by RisKeywords.java: s.split(",[ ]*")
- StringTokenizer tok = new StringTokenizer(keywordString, SEPARATING_CHARS_NOSPACE);
- while (tok.hasMoreTokens()) {
- String word = tok.nextToken().trim();
- keywords.add(word);
- }
- return keywords;
- }
-
- /**
- * @param entry a BibEntry
- * @return an List containing the keywords of the entry. An empty list if keywords are null or empty
- */
- public static Set<String> getSeparatedKeywords(BibEntry entry) {
- return getSeparatedKeywords(entry.getFieldOptional(FieldName.KEYWORDS).orElse(null));
- }
-
- /**
- * Returns a list of words contained in the given text.
- * Whitespace, comma and semicolon are considered as separator between words.
- *
- * @param text the input
- * @return a list of words
- */
- public static List<String> getStringAsWords(String text) {
- return Arrays.asList(text.split("[\\s,;]+"));
- }
-}
diff --git a/src/main/java/net/sf/jabref/model/entry/FieldName.java b/src/main/java/net/sf/jabref/model/entry/FieldName.java
index cb5708a..e5f8908 100644
--- a/src/main/java/net/sf/jabref/model/entry/FieldName.java
+++ b/src/main/java/net/sf/jabref/model/entry/FieldName.java
@@ -1,52 +1,81 @@
package net.sf.jabref.model.entry;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
+import net.sf.jabref.model.strings.StringUtil;
+
/**
* String constants for BibTeX entry field names
*
*/
public class FieldName {
-
// Character separating field names that are to be used in sequence as
// fallbacks for a single column (e.g. "author/editor" to use editor where
// author is not set):
public static final String FIELD_SEPARATOR = "/";
+ public static final String INTERNAL_ALL_FIELD = "all";
+ public static final String INTERNAL_ALL_TEXT_FIELDS_FIELD = "all-text-fields";
+
// Field name constants
public static final String ABSTRACT = "abstract";
+ public static final String ADDENDUM = "addendum";
public static final String ADDRESS = "address";
+ public static final String AFTERWORD = "afterword";
public static final String ANNOTE = "annote";
public static final String ANNOTATION = "annotation";
+ public static final String ANNOTATOR = "annotator";
+ public static final String ASSIGNEE = "assignee";
public static final String AUTHOR = "author";
public static final String BOOKAUTHOR = "bookauthor";
+ public static final String BOOKPAGINATION = "bookpagination";
public static final String BOOKSUBTITLE = "booksubtitle";
public static final String BOOKTITLE = "booktitle";
public static final String BOOKTITLEADDON = "booktitleaddon";
public static final String CHAPTER = "chapter";
+ public static final String COMMENTATOR = "commentator";
public static final String COMMENTS = "comments";
public static final String CROSSREF = "crossref";
public static final String DATE = "date";
+ public static final String DAY = "day";
+ public static final String DAYFILED = "dayfiled";
public static final String DOI = "doi";
public static final String EDITION = "edition";
public static final String EDITOR = "editor";
+ public static final String EDITORA = "editora";
+ public static final String EDITORB = "editorb";
+ public static final String EDITORC = "editorc";
+ public static final String EDITORTYPE = "editortype";
+ public static final String EDITORATYPE = "editoratype";
+ public static final String EDITORBTYPE = "editorbtype";
+ public static final String EDITORCTYPE = "editorctype";
public static final String EID = "eid";
public static final String ENTRYSET = "entryset";
public static final String EPRINT = "eprint";
public static final String EPRINTCLASS = "eprintclass";
public static final String EPRINTTYPE = "eprinttype";
+ public static final String EVENTDATE = "eventdate";
+ public static final String EVENTTITLE = "eventtitle";
+ public static final String EVENTTITLEADDON = "eventtitleaddon";
public static final String FILE = "file";
+ public static final String FOREWORD = "foreword";
public static final String FOLDER = "folder";
public static final String GENDER = "gender";
+ public static final String HOLDER = "holder";
public static final String HOWPUBLISHED = "howpublished";
public static final String INSTITUTION = "institution";
+ public static final String INTRODUCTION = "introduction";
public static final String ISBN = "isbn";
public static final String ISRN = "isrn";
public static final String ISSN = "issn";
public static final String ISSUE = "issue";
+ public static final String ISSUETITLE = "issuetitle";
+ public static final String ISSUESUBTITLE = "issuesubtitle";
public static final String JOURNAL = "journal";
public static final String JOURNALSUBTITLE = "journalsubtitle";
public static final String JOURNALTITLE = "journaltitle";
@@ -58,22 +87,32 @@ public class FieldName {
public static final String MAINTITLE = "maintitle";
public static final String MAINTITLEADDON = "maintitleaddon";
public static final String MONTH = "month";
+ public static final String MONTHFILED = "monthfiled";
+ public static final String NAMEADDON = "nameaddon";
+ public static final String NATIONALITY = "nationality";
public static final String NOTE = "note";
public static final String NUMBER = "number";
public static final String ORGANIZATION = "organization";
+ public static final String ORIGDATE = "origdate";
public static final String ORIGLANGUAGE = "origlanguage";
public static final String PAGES = "pages";
public static final String PAGETOTAL = "pagetotal";
+ public static final String PAGINATION = "pagination";
public static final String PART = "part";
public static final String PDF = "pdf";
+ public static final String PMID = "pmid";
public static final String PS = "ps";
public static final String PUBLISHER = "publisher";
public static final String PUBSTATE = "pubstate";
public static final String RELATED = "related";
public static final String REPORTNO = "reportno";
public static final String REVIEW = "review";
+ public static final String REVISION = "revision";
public static final String SCHOOL = "school";
public static final String SERIES = "series";
+ public static final String SHORTAUTHOR = "shortauthor";
+ public static final String SHORTEDITOR = "shorteditor";
+ public static final String SORTNAME = "sortname";
public static final String SUBTITLE = "subtitle";
public static final String TITLE = "title";
public static final String TITLEADDON = "titleaddon";
@@ -82,12 +121,27 @@ public class FieldName {
public static final String URI = "uri";
public static final String URL = "url";
public static final String URLDATE = "urldate";
+ public static final String VENUE = "venue";
public static final String VERSION = "version";
public static final String VOLUME = "volume";
public static final String VOLUMES = "volumes";
public static final String YEAR = "year";
public static final String YEARFILED = "yearfiled";
+ // IEEE BSTctl fields
+ public static final String CTLALT_STRETCH_FACTOR = "ctlalt_stretch_factor";
+ public static final String CTLDASH_REPEATED_NAMES = "ctldash_repeated_names";
+ public static final String CTLMAX_NAMES_FORCED_ETAL = "ctlmax_names_forced_etal";
+ public static final String CTLNAME_FORMAT_STRING = "ctlname_format_string";
+ public static final String CTLNAME_LATEX_CMD = "ctlname_latex_cmd";
+ public static final String CTLNAME_URL_PREFIX = "ctlname_url_prefix";
+ public static final String CTLNAMES_SHOW_ETAL = "ctlnames_show_etal";
+ public static final String CTLUSE_ALT_SPACING = "ctluse_alt_spacing";
+ public static final String CTLUSE_ARTICLE_NUMBER = "ctluse_article_number";
+ public static final String CTLUSE_FORCED_ETAL = "ctluse_forced_etal";
+ public static final String CTLUSE_PAPER = "ctluse_paper";
+ public static final String CTLUSE_URL = "ctluse_url";
+
// JabRef internal field names
public static final String OWNER = "owner";
public static final String TIMESTAMP = "timestamp"; // Not the actual field name, but the default value
@@ -100,7 +154,6 @@ public class FieldName {
// Map to hold alternative display names
private static final Map<String, String> displayNames = new HashMap<>();
-
public static String orFields(String... fields) {
return String.join(FieldName.FIELD_SEPARATOR, fields);
}
@@ -114,13 +167,13 @@ public class FieldName {
displayNames.put(FieldName.ISBN, "ISBN");
displayNames.put(FieldName.ISRN, "ISRN");
displayNames.put(FieldName.ISSN, "ISSN");
+ displayNames.put(FieldName.PMID, "PMID");
displayNames.put(FieldName.PS, "PS");
displayNames.put(FieldName.PDF, "PDF");
displayNames.put(FieldName.URI, "URI");
displayNames.put(FieldName.URL, "URL");
}
-
/**
* @param field - field to get the display version for
* @return A version of the field name more suitable for display
@@ -131,6 +184,13 @@ public class FieldName {
if (displayNames.containsKey(lowercaseField)) {
return displayNames.get(lowercaseField);
}
- return EntryUtil.capitalizeFirst(field);
+ return StringUtil.capitalizeFirst(field);
+ }
+
+ public static ArrayList getNotTextFieldNames() {
+ ArrayList<String> notTextFieldNames = new ArrayList<>();
+ notTextFieldNames.addAll(Arrays.asList(FieldName.DOI, FieldName.FILE, FieldName.URL, FieldName.URI, FieldName.ISBN, FieldName.ISSN, FieldName.MONTH, FieldName.DATE, FieldName.YEAR));
+ return notTextFieldNames;
}
+
}
diff --git a/src/main/java/net/sf/jabref/model/entry/FieldProperties.java b/src/main/java/net/sf/jabref/model/entry/FieldProperties.java
deleted file mode 100644
index 95949fe..0000000
--- a/src/main/java/net/sf/jabref/model/entry/FieldProperties.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package net.sf.jabref.model.entry;
-
-import java.util.EnumSet;
-import java.util.Set;
-
-public enum FieldProperties {
- YES_NO,
- DATE,
- JOURNAL_NAME,
- EXTERNAL,
- OWNER,
- MONTH,
- FILE_EDITOR,
- NUMERIC,
- PERSON_NAMES,
- INTEGER,
- GENDER,
- LANGUAGE,
- DOI,
- EDITOR_TYPE,
- PAGINATION,
- TYPE,
- CROSSREF,
- ISO_DATE,
- ISBN,
- EPRINT,
- BOOK_NAME,
- SINGLE_ENTRY_LINK,
- MULTIPLE_ENTRY_LINK,
- PUBLICATION_STATE,
- VERBATIM;
-
- public static final Set<FieldProperties> ALL_OPTS = EnumSet.allOf(FieldProperties.class);
-
-}
diff --git a/src/main/java/net/sf/jabref/model/entry/FieldProperty.java b/src/main/java/net/sf/jabref/model/entry/FieldProperty.java
new file mode 100644
index 0000000..fad8f29
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/entry/FieldProperty.java
@@ -0,0 +1,35 @@
+package net.sf.jabref.model.entry;
+
+import java.util.EnumSet;
+import java.util.Set;
+
+public enum FieldProperty {
+ YES_NO,
+ DATE,
+ JOURNAL_NAME,
+ EXTERNAL,
+ OWNER,
+ MONTH,
+ FILE_EDITOR,
+ NUMERIC,
+ PERSON_NAMES,
+ INTEGER,
+ GENDER,
+ LANGUAGE,
+ DOI,
+ EDITOR_TYPE,
+ PAGINATION,
+ TYPE,
+ CROSSREF,
+ ISO_DATE,
+ ISBN,
+ EPRINT,
+ BOOK_NAME,
+ SINGLE_ENTRY_LINK,
+ MULTIPLE_ENTRY_LINK,
+ PUBLICATION_STATE,
+ VERBATIM;
+
+ public static final Set<FieldProperty> ALL_OPTS = EnumSet.allOf(FieldProperty.class);
+
+}
diff --git a/src/main/java/net/sf/jabref/model/entry/IEEETranEntryTypes.java b/src/main/java/net/sf/jabref/model/entry/IEEETranEntryTypes.java
index e063546..70b1d21 100644
--- a/src/main/java/net/sf/jabref/model/entry/IEEETranEntryTypes.java
+++ b/src/main/java/net/sf/jabref/model/entry/IEEETranEntryTypes.java
@@ -20,9 +20,8 @@ public class IEEETranEntryTypes {
public static final EntryType ELECTRONIC = new BibtexEntryType() {
{
- addAllOptional(FieldName.AUTHOR, FieldName.MONTH, FieldName.YEAR, FieldName.TITLE, FieldName.LANGUAGE, FieldName.HOWPUBLISHED, FieldName.ORGANIZATION, FieldName.ADDRESS,
- FieldName.NOTE, FieldName.URL);
-
+ addAllOptional(FieldName.AUTHOR, FieldName.MONTH, FieldName.YEAR, FieldName.TITLE, FieldName.LANGUAGE,
+ FieldName.HOWPUBLISHED, FieldName.ORGANIZATION, FieldName.ADDRESS, FieldName.NOTE, FieldName.URL);
}
@Override
@@ -37,9 +36,10 @@ public class IEEETranEntryTypes {
public static final EntryType IEEETRANBSTCTL = new BibtexEntryType() {
{
- addAllOptional("ctluse_article_number", "ctluse_paper", "ctluse_forced_etal", "ctluse_url",
- "ctlmax_names_forced_etal", "ctlnames_show_etal", "ctluse_alt_spacing", "ctlalt_stretch_factor",
- "ctldash_repeated_names", "ctlname_format_string", "ctlname_latex_cmd", "ctlname_url_prefix");
+ addAllOptional(FieldName.CTLUSE_ARTICLE_NUMBER, FieldName.CTLUSE_PAPER, FieldName.CTLUSE_FORCED_ETAL,
+ FieldName.CTLUSE_URL, FieldName.CTLMAX_NAMES_FORCED_ETAL, FieldName.CTLNAMES_SHOW_ETAL,
+ FieldName.CTLUSE_ALT_SPACING, FieldName.CTLALT_STRETCH_FACTOR, FieldName.CTLDASH_REPEATED_NAMES,
+ FieldName.CTLNAME_FORMAT_STRING, FieldName.CTLNAME_LATEX_CMD, FieldName.CTLNAME_URL_PREFIX);
}
@Override
@@ -59,7 +59,8 @@ public class IEEETranEntryTypes {
{
addAllRequired(FieldName.TITLE, FieldName.YEAR);
- addAllOptional(FieldName.EDITOR, FieldName.LANGUAGE, FieldName.SERIES, FieldName.VOLUME, FieldName.NUMBER, FieldName.ORGANIZATION, FieldName.MONTH, FieldName.NOTE, FieldName.URL);
+ addAllOptional(FieldName.EDITOR, FieldName.LANGUAGE, FieldName.SERIES, FieldName.VOLUME, FieldName.NUMBER,
+ FieldName.ORGANIZATION, FieldName.MONTH, FieldName.NOTE, FieldName.URL);
}
@Override
@@ -77,9 +78,11 @@ public class IEEETranEntryTypes {
public static final EntryType PATENT = new BibtexEntryType() {
{
- addAllRequired("nationality", FieldName.NUMBER, FieldName.orFields(FieldName.YEAR, FieldName.YEARFILED));
- addAllOptional(FieldName.AUTHOR, FieldName.TITLE, FieldName.LANGUAGE, "assignee", FieldName.ADDRESS, FieldName.TYPE, FieldName.NUMBER, "day", "dayfiled",
- FieldName.MONTH, "monthfiled", FieldName.NOTE, FieldName.URL);
+ addAllRequired(FieldName.NATIONALITY, FieldName.NUMBER,
+ FieldName.orFields(FieldName.YEAR, FieldName.YEARFILED));
+ addAllOptional(FieldName.AUTHOR, FieldName.TITLE, FieldName.LANGUAGE, FieldName.ASSIGNEE, FieldName.ADDRESS,
+ FieldName.TYPE, FieldName.NUMBER, FieldName.DAY, FieldName.DAYFILED, FieldName.MONTH,
+ FieldName.MONTHFILED, FieldName.NOTE, FieldName.URL);
}
@Override
@@ -98,8 +101,9 @@ public class IEEETranEntryTypes {
{
addAllRequired(FieldName.TITLE, FieldName.orFields(FieldName.ORGANIZATION, FieldName.INSTITUTION));
- addAllOptional(FieldName.AUTHOR, FieldName.LANGUAGE, FieldName.HOWPUBLISHED, FieldName.TYPE, FieldName.NUMBER, "revision", FieldName.ADDRESS, FieldName.MONTH,
- FieldName.YEAR, FieldName.NOTE, FieldName.URL);
+ addAllOptional(FieldName.AUTHOR, FieldName.LANGUAGE, FieldName.HOWPUBLISHED, FieldName.TYPE,
+ FieldName.NUMBER, FieldName.REVISION, FieldName.ADDRESS, FieldName.MONTH, FieldName.YEAR,
+ FieldName.NOTE, FieldName.URL);
}
@Override
diff --git a/src/main/java/net/sf/jabref/model/entry/InternalBibtexFields.java b/src/main/java/net/sf/jabref/model/entry/InternalBibtexFields.java
index 648eee6..d322830 100644
--- a/src/main/java/net/sf/jabref/model/entry/InternalBibtexFields.java
+++ b/src/main/java/net/sf/jabref/model/entry/InternalBibtexFields.java
@@ -13,6 +13,8 @@ import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
+import net.sf.jabref.model.entry.specialfields.SpecialField;
+
/**
* Handling of bibtex fields.
* All bibtex-field related stuff should be placed here!
@@ -34,41 +36,53 @@ public class InternalBibtexFields {
private String timeStampField;
// Lists of fields with special properties
- public static final List<String> INTEGER_FIELDS = Arrays.asList("ctlmax_names_forced_etal", "ctlnames_show_etal",
- "ctlalt_stretch_factor", FieldName.VOLUMES);
- public static final List<String> IEEETRANBSTCTL_YES_NO_FIELDS = Arrays.asList("ctluse_article_number",
- "ctluse_paper", "ctluse_url", "ctluse_forced_etal", "ctluse_alt_spacing", "ctldash_repeated_names");
- public static final List<String> BIBLATEX_DATE_FIELDS = Arrays.asList(FieldName.DATE, "eventdate", "origdate",
- FieldName.URLDATE);
- public static final List<String> BIBLATEX_PERSON_NAME_FIELDS = Arrays.asList(FieldName.AUTHOR, FieldName.EDITOR,
- "editora", "editorb", "editorc", FieldName.TRANSLATOR, "annotator", "commentator", "introduction", "foreword",
- "afterword", FieldName.BOOKAUTHOR, "holder", "shortauthor", "shorteditor", "sortname", "nameaddon");
- public static final List<String> BIBLATEX_EDITOR_TYPE_FIELDS = Arrays.asList("editortype", "editoratype",
- "editorbtype", "editorctype");
- public static final List<String> BIBLATEX_PAGINATION_FIELDS = Arrays.asList("pagination", "bookpagination");
-
- public static final List<String> BIBLATEX_JOURNAL_NAME_FIELDS = Arrays.asList(FieldName.JOURNAL,
+ private static final List<String> INTEGER_FIELDS = Arrays.asList(FieldName.CTLMAX_NAMES_FORCED_ETAL,
+ FieldName.CTLNAMES_SHOW_ETAL, FieldName.CTLALT_STRETCH_FACTOR, FieldName.VOLUMES, FieldName.PMID);
+
+ private static final List<String> IEEETRANBSTCTL_YES_NO_FIELDS = Arrays.asList(FieldName.CTLUSE_ARTICLE_NUMBER,
+ FieldName.CTLUSE_PAPER, FieldName.CTLUSE_URL, FieldName.CTLUSE_FORCED_ETAL, FieldName.CTLUSE_ALT_SPACING,
+ FieldName.CTLDASH_REPEATED_NAMES);
+
+ private static final List<String> BIBLATEX_DATE_FIELDS = Arrays.asList(FieldName.DATE, FieldName.EVENTDATE,
+ FieldName.ORIGDATE, FieldName.URLDATE);
+
+ private static final List<String> BIBLATEX_PERSON_NAME_FIELDS = Arrays.asList(FieldName.AUTHOR, FieldName.EDITOR,
+ FieldName.EDITORA, FieldName.EDITORB, FieldName.EDITORC, FieldName.TRANSLATOR, FieldName.ANNOTATOR,
+ FieldName.COMMENTATOR, FieldName.INTRODUCTION, FieldName.FOREWORD, FieldName.AFTERWORD,
+ FieldName.BOOKAUTHOR, FieldName.HOLDER, FieldName.SHORTAUTHOR, FieldName.SHORTEDITOR, FieldName.SORTNAME,
+ FieldName.NAMEADDON, FieldName.ASSIGNEE);
+
+ private static final List<String> BIBLATEX_EDITOR_TYPE_FIELDS = Arrays.asList(FieldName.EDITORTYPE,
+ FieldName.EDITORATYPE, FieldName.EDITORBTYPE, FieldName.EDITORCTYPE);
+
+ private static final List<String> BIBLATEX_PAGINATION_FIELDS = Arrays.asList(FieldName.PAGINATION,
+ FieldName.BOOKPAGINATION);
+
+ private static final List<String> BIBLATEX_JOURNAL_NAME_FIELDS = Arrays.asList(FieldName.JOURNAL,
FieldName.JOURNALTITLE, FieldName.JOURNALSUBTITLE);
- public static final List<String> BIBLATEX_BOOK_NAME_FIELDS = Arrays.asList(FieldName.BOOKTITLE, FieldName.MAINTITLE,
- FieldName.MAINSUBTITLE, FieldName.MAINTITLEADDON, FieldName.BOOKSUBTITLE, FieldName.BOOKTITLEADDON);
+ private static final List<String> BIBLATEX_BOOK_NAME_FIELDS = Arrays.asList(FieldName.BOOKTITLE,
+ FieldName.MAINTITLE, FieldName.MAINSUBTITLE, FieldName.MAINTITLEADDON, FieldName.BOOKSUBTITLE,
+ FieldName.BOOKTITLEADDON);
- public static final List<String> BIBLATEX_LANGUAGE_FIELDS = Arrays.asList(FieldName.LANGUAGE,
+ private static final List<String> BIBLATEX_LANGUAGE_FIELDS = Arrays.asList(FieldName.LANGUAGE,
FieldName.ORIGLANGUAGE);
- public static final List<String> BIBLATEX_MULTI_KEY_FIELDS = Arrays.asList(FieldName.RELATED, FieldName.ENTRYSET);
+ private static final List<String> BIBLATEX_MULTI_KEY_FIELDS = Arrays.asList(FieldName.RELATED, FieldName.ENTRYSET);
- public static final List<String> SPECIAL_FIELDS = Arrays.asList(SpecialFields.FIELDNAME_PRINTED,
- SpecialFields.FIELDNAME_PRIORITY, SpecialFields.FIELDNAME_QUALITY,
- SpecialFields.FIELDNAME_RANKING, SpecialFields.FIELDNAME_READ,
- SpecialFields.FIELDNAME_RELEVANCE);
+ private static final List<String> VERBATIM_FIELDS = Arrays.asList(FieldName.URL, FieldName.FILE,
+ FieldName.CTLNAME_FORMAT_STRING, FieldName.CTLNAME_LATEX_CMD, FieldName.CTLNAME_URL_PREFIX);
+
+ private static final List<String> SPECIAL_FIELDS = Arrays.asList(SpecialField.PRINTED.getFieldName(),
+ SpecialField.PRIORITY.getFieldName(), SpecialField.QUALITY.getFieldName(),
+ SpecialField.RANKING.getFieldName(), SpecialField.READ_STATUS.getFieldName(),
+ SpecialField.RELEVANCE.getFieldName());
// singleton instance
- private static InternalBibtexFields RUNTIME = new InternalBibtexFields(
- SpecialFields.PREF_SERIALIZESPECIALFIELDS_DEFAULT, FieldName.TIMESTAMP);
+ private static InternalBibtexFields RUNTIME = new InternalBibtexFields(FieldName.TIMESTAMP);
- private InternalBibtexFields(boolean serializeSpecialFields, String timeStampFieldName) {
+ private InternalBibtexFields(String timeStampFieldName) {
fieldSet = new HashMap<>();
BibtexSingleField dummy;
@@ -83,31 +97,33 @@ public class InternalBibtexFields {
add(new BibtexSingleField(FieldName.AUTHOR, true, BibtexSingleField.MEDIUM_W, 280));
add(new BibtexSingleField(FieldName.BOOKTITLE, true, 175));
add(new BibtexSingleField(FieldName.CHAPTER, true, BibtexSingleField.SMALL_W));
- dummy = new BibtexSingleField(FieldName.CROSSREF, true, BibtexSingleField.SMALL_W);
- dummy.setExtras(EnumSet.of(FieldProperties.CROSSREF, FieldProperties.SINGLE_ENTRY_LINK));
+ dummy = new BibtexSingleField(FieldName.CROSSREF, true, BibtexSingleField.LARGE_W);
+ dummy.setExtras(EnumSet.of(FieldProperty.CROSSREF, FieldProperty.SINGLE_ENTRY_LINK));
add(dummy);
add(new BibtexSingleField(FieldName.EDITION, true, BibtexSingleField.SMALL_W));
add(new BibtexSingleField(FieldName.EDITOR, true, BibtexSingleField.MEDIUM_W, 280));
dummy = new BibtexSingleField(FieldName.EPRINT, true, BibtexSingleField.SMALL_W);
- dummy.setExtras(EnumSet.of(FieldProperties.EPRINT));
+ dummy.setExtras(EnumSet.of(FieldProperty.EPRINT));
add(dummy);
add(new BibtexSingleField(FieldName.HOWPUBLISHED, true, BibtexSingleField.MEDIUM_W));
add(new BibtexSingleField(FieldName.INSTITUTION, true, BibtexSingleField.MEDIUM_W));
dummy = new BibtexSingleField(FieldName.ISBN, true, BibtexSingleField.SMALL_W);
- dummy.setExtras(EnumSet.of(FieldProperties.ISBN));
+ dummy.setExtras(EnumSet.of(FieldProperty.ISBN));
add(dummy);
+ add(new BibtexSingleField(FieldName.ISSN, true, BibtexSingleField.SMALL_W));
+
dummy = new BibtexSingleField(FieldName.JOURNAL, true, BibtexSingleField.SMALL_W);
- dummy.setExtras(EnumSet.of(FieldProperties.JOURNAL_NAME));
+ dummy.setExtras(EnumSet.of(FieldProperty.JOURNAL_NAME));
add(dummy);
dummy = new BibtexSingleField(FieldName.JOURNALTITLE, true, BibtexSingleField.SMALL_W);
- dummy.setExtras(EnumSet.of(FieldProperties.JOURNAL_NAME));
+ dummy.setExtras(EnumSet.of(FieldProperty.JOURNAL_NAME));
add(dummy);
add(new BibtexSingleField(FieldName.KEY, true));
dummy = new BibtexSingleField(FieldName.MONTH, true, BibtexSingleField.SMALL_W);
- dummy.setExtras(EnumSet.of(FieldProperties.MONTH));
+ dummy.setExtras(EnumSet.of(FieldProperty.MONTH));
add(dummy);
add(new BibtexSingleField(FieldName.NOTE, true, BibtexSingleField.MEDIUM_W));
add(new BibtexSingleField(FieldName.NUMBER, true, BibtexSingleField.SMALL_W, 60).setNumeric(true));
@@ -118,7 +134,7 @@ public class InternalBibtexFields {
add(new BibtexSingleField(FieldName.SERIES, true, BibtexSingleField.SMALL_W));
add(new BibtexSingleField(FieldName.TITLE, true, 400));
dummy = new BibtexSingleField(FieldName.TYPE, true, BibtexSingleField.SMALL_W);
- dummy.getExtras().add(FieldProperties.TYPE);
+ dummy.getFieldProperties().add(FieldProperty.TYPE);
add(dummy);
add(new BibtexSingleField(FieldName.LANGUAGE, true, BibtexSingleField.SMALL_W));
add(new BibtexSingleField(FieldName.VOLUME, true, BibtexSingleField.SMALL_W, 60).setNumeric(true));
@@ -127,11 +143,11 @@ public class InternalBibtexFields {
// custom fields not displayed at editor, but as columns in the UI
for (String fieldName : SPECIAL_FIELDS) {
dummy = new BibtexSingleField(fieldName, false);
- if (!serializeSpecialFields) {
- dummy.setPrivate();
- dummy.setWriteable(false);
- dummy.setDisplayable(false);
- }
+
+ dummy.setPrivate();
+ dummy.setWriteable(false);
+ dummy.setDisplayable(false);
+
add(dummy);
}
@@ -141,41 +157,42 @@ public class InternalBibtexFields {
add(dummy);
dummy = new BibtexSingleField(FieldName.DOI, true, BibtexSingleField.SMALL_W);
- dummy.setExtras(EnumSet.of(FieldProperties.DOI));
+ dummy.setExtras(EnumSet.of(FieldProperty.DOI));
add(dummy);
add(new BibtexSingleField(FieldName.EID, true, BibtexSingleField.SMALL_W));
dummy = new BibtexSingleField(FieldName.DATE, true);
- dummy.setExtras(EnumSet.of(FieldProperties.DATE));
- dummy.setPrivate(); // TODO: Why private?
+ dummy.setExtras(EnumSet.of(FieldProperty.DATE));
add(dummy);
- add(new BibtexSingleField("pmid", false, BibtexSingleField.SMALL_W, 60).setNumeric(true));
+ add(new BibtexSingleField(FieldName.PMID, false, BibtexSingleField.SMALL_W, 60).setNumeric(true));
// additional fields ------------------------------------------------------
add(new BibtexSingleField(FieldName.LOCATION, false));
add(new BibtexSingleField(FieldName.ABSTRACT, false, BibtexSingleField.LARGE_W, 400));
dummy = new BibtexSingleField(FieldName.URL, false, BibtexSingleField.SMALL_W);
- dummy.setExtras(EnumSet.of(FieldProperties.EXTERNAL, FieldProperties.VERBATIM));
+ dummy.setExtras(EnumSet.of(FieldProperty.EXTERNAL, FieldProperty.VERBATIM));
add(dummy);
add(new BibtexSingleField("comment", false, BibtexSingleField.MEDIUM_W));
add(new BibtexSingleField(FieldName.KEYWORDS, false, BibtexSingleField.SMALL_W));
dummy = new BibtexSingleField(FieldName.FILE, false);
- dummy.setExtras(EnumSet.of(FieldProperties.FILE_EDITOR, FieldProperties.VERBATIM));
+ dummy.setExtras(EnumSet.of(FieldProperty.FILE_EDITOR, FieldProperty.VERBATIM));
add(dummy);
- add(new BibtexSingleField("search", false, 75));
+ dummy = new BibtexSingleField(FieldName.RELATED, false);
+ dummy.setExtras(EnumSet.of(FieldProperty.MULTIPLE_ENTRY_LINK));
+ add(dummy);
// some BibLatex fields
dummy = new BibtexSingleField(FieldName.GENDER, true, BibtexSingleField.SMALL_W);
- dummy.getExtras().add(FieldProperties.GENDER);
+ dummy.getFieldProperties().add(FieldProperty.GENDER);
add(dummy);
dummy = new BibtexSingleField(FieldName.PUBSTATE, true, BibtexSingleField.SMALL_W);
- dummy.getExtras().add(FieldProperties.PUBLICATION_STATE);
+ dummy.getFieldProperties().add(FieldProperty.PUBLICATION_STATE);
add(dummy);
// some internal fields ----------------------------------------------
@@ -186,14 +203,13 @@ public class InternalBibtexFields {
add(dummy);
dummy = new BibtexSingleField(FieldName.OWNER, false, BibtexSingleField.SMALL_W);
- dummy.setExtras(EnumSet.of(FieldProperties.OWNER));
+ dummy.setExtras(EnumSet.of(FieldProperty.OWNER));
dummy.setPrivate();
add(dummy);
- dummy = new BibtexSingleField(timeStampFieldName, false, BibtexSingleField.SMALL_W);
timeStampField = timeStampFieldName;
-
- dummy.setExtras(EnumSet.of(FieldProperties.DATE));
+ dummy = new BibtexSingleField(timeStampFieldName, false, BibtexSingleField.SMALL_W);
+ dummy.setExtras(EnumSet.of(FieldProperty.DATE));
dummy.setPrivate();
add(dummy);
@@ -222,15 +238,28 @@ public class InternalBibtexFields {
// IEEEtranBSTCTL fields that should be "yes" or "no"
for (String yesNoField : IEEETRANBSTCTL_YES_NO_FIELDS) {
dummy = new BibtexSingleField(yesNoField, false);
- dummy.setExtras(EnumSet.of(FieldProperties.YES_NO));
+ dummy.setExtras(EnumSet.of(FieldProperty.YES_NO));
add(dummy);
}
// Fields that should be an integer value
for (String numericField : INTEGER_FIELDS) {
- dummy = new BibtexSingleField(numericField, false).setNumeric(true);
- dummy.getExtras().add(FieldProperties.INTEGER);
- add(dummy);
+ BibtexSingleField field = fieldSet.get(numericField);
+ if (field == null) {
+ field = new BibtexSingleField(numericField, true, BibtexSingleField.SMALL_W).setNumeric(true);
+ }
+ field.getFieldProperties().add(FieldProperty.INTEGER);
+ add(field);
+ }
+
+ // Fields that should be treated as verbatim, so no formatting requirements
+ for (String fieldText : VERBATIM_FIELDS) {
+ BibtexSingleField field = fieldSet.get(fieldText);
+ if (field == null) {
+ field = new BibtexSingleField(fieldText, true, BibtexSingleField.SMALL_W);
+ }
+ field.getFieldProperties().add(FieldProperty.VERBATIM);
+ add(field);
}
// Set all fields with person names
@@ -239,7 +268,7 @@ public class InternalBibtexFields {
if (field == null) {
field = new BibtexSingleField(fieldText, true, BibtexSingleField.SMALL_W);
}
- field.getExtras().add(FieldProperties.PERSON_NAMES);
+ field.getFieldProperties().add(FieldProperty.PERSON_NAMES);
add(field);
}
@@ -249,7 +278,7 @@ public class InternalBibtexFields {
if (field == null) {
field = new BibtexSingleField(fieldText, true, BibtexSingleField.SMALL_W);
}
- field.getExtras().add(FieldProperties.EDITOR_TYPE);
+ field.getFieldProperties().add(FieldProperty.EDITOR_TYPE);
add(field);
}
@@ -259,7 +288,7 @@ public class InternalBibtexFields {
if (field == null) {
field = new BibtexSingleField(fieldText, true, BibtexSingleField.SMALL_W);
}
- field.getExtras().add(FieldProperties.PAGINATION);
+ field.getFieldProperties().add(FieldProperty.PAGINATION);
add(field);
}
@@ -269,8 +298,8 @@ public class InternalBibtexFields {
if (field == null) {
field = new BibtexSingleField(fieldText, true, BibtexSingleField.SMALL_W);
}
- field.getExtras().add(FieldProperties.DATE);
- field.getExtras().add(FieldProperties.ISO_DATE);
+ field.getFieldProperties().add(FieldProperty.DATE);
+ field.getFieldProperties().add(FieldProperty.ISO_DATE);
add(field);
}
@@ -280,7 +309,7 @@ public class InternalBibtexFields {
if (field == null) {
field = new BibtexSingleField(fieldText, true, BibtexSingleField.SMALL_W);
}
- field.getExtras().add(FieldProperties.JOURNAL_NAME);
+ field.getFieldProperties().add(FieldProperty.JOURNAL_NAME);
add(field);
}
@@ -290,7 +319,7 @@ public class InternalBibtexFields {
if (field == null) {
field = new BibtexSingleField(fieldText, true, BibtexSingleField.SMALL_W);
}
- field.getExtras().add(FieldProperties.BOOK_NAME);
+ field.getFieldProperties().add(FieldProperty.BOOK_NAME);
add(field);
}
@@ -300,7 +329,7 @@ public class InternalBibtexFields {
if (field == null) {
field = new BibtexSingleField(fieldText, true, BibtexSingleField.SMALL_W);
}
- field.getExtras().add(FieldProperties.LANGUAGE);
+ field.getFieldProperties().add(FieldProperty.LANGUAGE);
add(field);
}
@@ -310,7 +339,7 @@ public class InternalBibtexFields {
if (field == null) {
field = new BibtexSingleField(fieldText, true, BibtexSingleField.SMALL_W);
}
- field.getExtras().add(FieldProperties.MULTIPLE_ENTRY_LINK);
+ field.getFieldProperties().add(FieldProperty.MULTIPLE_ENTRY_LINK);
add(field);
}
}
@@ -386,12 +415,12 @@ public class InternalBibtexFields {
return Optional.empty();
}
- public static Set<FieldProperties> getFieldExtras(String name) {
+ public static Set<FieldProperty> getFieldProperties(String name) {
Optional<BibtexSingleField> sField = InternalBibtexFields.getField(name);
if (sField.isPresent()) {
- return sField.get().getExtras();
+ return sField.get().getFieldProperties();
}
- return EnumSet.noneOf(FieldProperties.class);
+ return EnumSet.noneOf(FieldProperty.class);
}
public static double getFieldWeight(String name) {
@@ -468,35 +497,41 @@ public class InternalBibtexFields {
}
/**
- * returns a List with only private fieldnames
+ * returns a List with all fieldnames incl. internal fieldnames
*/
- public static List<String> getAllPrivateFieldNames() {
- List<String> pFields = new ArrayList<>();
- for (BibtexSingleField sField : InternalBibtexFields.RUNTIME.fieldSet.values()) {
- if (sField.isPrivate()) {
- pFields.add(sField.getFieldName());
- }
- }
- return pFields;
+ public static List<String> getAllPublicAndInteralFieldNames() {
+ //add the internal field names to public fields
+ List<String> publicAndInternalFields = new ArrayList<>();
+ publicAndInternalFields.addAll(InternalBibtexFields.getAllPublicFieldNames());
+ publicAndInternalFields.add(FieldName.INTERNAL_ALL_FIELD);
+ publicAndInternalFields.add(FieldName.INTERNAL_ALL_TEXT_FIELDS_FIELD);
+ // sort the entries
+ Collections.sort(publicAndInternalFields);
+
+ return publicAndInternalFields;
}
public static List<String> getJournalNameFields() {
return InternalBibtexFields.getAllPublicFieldNames().stream().filter(
- fieldName -> InternalBibtexFields.getFieldExtras(fieldName).contains(FieldProperties.JOURNAL_NAME))
+ fieldName -> InternalBibtexFields.getFieldProperties(fieldName).contains(FieldProperty.JOURNAL_NAME))
.collect(Collectors.toList());
}
public static List<String> getBookNameFields() {
return InternalBibtexFields.getAllPublicFieldNames().stream()
- .filter(fieldName -> InternalBibtexFields.getFieldExtras(fieldName).contains(FieldProperties.BOOK_NAME))
+ .filter(fieldName -> InternalBibtexFields.getFieldProperties(fieldName).contains(FieldProperty.BOOK_NAME))
.collect(Collectors.toList());
}
public static List<String> getPersonNameFields() {
return InternalBibtexFields.getAllPublicFieldNames().stream().filter(
- fieldName -> InternalBibtexFields.getFieldExtras(fieldName).contains(FieldProperties.PERSON_NAMES))
+ fieldName -> InternalBibtexFields.getFieldProperties(fieldName).contains(FieldProperty.PERSON_NAMES))
.collect(Collectors.toList());
}
+ public static List<String> getIEEETranBSTctlYesNoFields() {
+ return IEEETRANBSTCTL_YES_NO_FIELDS;
+ }
+
}
diff --git a/src/main/java/net/sf/jabref/model/entry/Keyword.java b/src/main/java/net/sf/jabref/model/entry/Keyword.java
new file mode 100644
index 0000000..ff51f7d
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/entry/Keyword.java
@@ -0,0 +1,45 @@
+package net.sf.jabref.model.entry;
+
+import java.util.Objects;
+
+import net.sf.jabref.model.ChainNode;
+
+/**
+ * Represents a keyword in a chain of keywords.
+ * For example, "JabRef" in "Bibliographic manager > Awesome ones > JabRef"
+ */
+public class Keyword extends ChainNode<Keyword> implements Comparable<Keyword> {
+
+ private final String keyword;
+
+ public Keyword(String keyword) {
+ super(Keyword.class);
+ this.keyword = Objects.requireNonNull(keyword);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ return Objects.equals(keyword, ((Keyword) o).keyword);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(keyword);
+ }
+
+ @Override
+ public String toString() {
+ return keyword;
+ }
+
+ @Override
+ public int compareTo(Keyword o) {
+ return keyword.compareTo(o.keyword);
+ }
+}
diff --git a/src/main/java/net/sf/jabref/model/entry/KeywordList.java b/src/main/java/net/sf/jabref/model/entry/KeywordList.java
new file mode 100644
index 0000000..36b58c2
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/entry/KeywordList.java
@@ -0,0 +1,181 @@
+package net.sf.jabref.model.entry;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.StringTokenizer;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import net.sf.jabref.model.strings.StringUtil;
+
+/**
+ * Represents a list of keyword chains.
+ * For example, "Type > A, Type > B, Something else".
+ */
+public class KeywordList implements Iterable<Keyword> {
+
+ private final List<Keyword> keywords;
+
+ public KeywordList() {
+ keywords = new ArrayList<>();
+ }
+
+ public KeywordList(Collection<Keyword> keywords) {
+ this.keywords = new ArrayList<>();
+ keywords.forEach(this::add);
+ }
+
+ public KeywordList(List<String> keywords) {
+ this(keywords.stream().map(Keyword::new).collect(Collectors.toList()));
+ }
+
+ public KeywordList(String... keywords) {
+ this(Arrays.stream(keywords).map(Keyword::new).collect(Collectors.toList()));
+ }
+
+ /**
+ * @param keywordString a String of keywords
+ * @return an parsed list containing the keywords
+ */
+ public static KeywordList parse(String keywordString, Character delimiter) {
+ if (StringUtil.isBlank(keywordString)) {
+ return new KeywordList();
+ }
+
+ List<String> keywords = new ArrayList<>();
+
+ StringTokenizer tok = new StringTokenizer(keywordString, delimiter.toString());
+ while (tok.hasMoreTokens()) {
+ String word = tok.nextToken().trim();
+ keywords.add(word);
+ }
+ return new KeywordList(keywords);
+ }
+
+ public KeywordList createClone() {
+ return new KeywordList(this.keywords);
+ }
+
+ public void replaceAll(KeywordList keywordsToReplace, Keyword newValue) {
+ Objects.requireNonNull(newValue);
+
+ // Remove keywords which should be replaced
+ int foundPosition = -1; // remember position of the last found keyword
+ for (Keyword specialFieldKeyword : keywordsToReplace) {
+ int pos = keywords.indexOf(specialFieldKeyword);
+ if (pos >= 0) {
+ foundPosition = pos;
+ keywords.remove(pos);
+ }
+ }
+
+ // Add new keyword at right position
+ if (foundPosition == -1) {
+ add(newValue);
+ } else {
+ keywords.add(foundPosition, newValue);
+ }
+ }
+
+ public void removeAll(KeywordList keywordsToRemove) {
+ keywords.removeAll(keywordsToRemove.keywords);
+ }
+
+ /**
+ * @deprecated use {@link #replaceAll(KeywordList, Keyword)} or {@link #removeAll(KeywordList)}
+ */
+ @Deprecated
+ public void replaceKeywords(KeywordList keywordsToReplace, Optional<Keyword> newValue) {
+ if (newValue.isPresent()) {
+ replaceAll(keywordsToReplace, newValue.get());
+ } else {
+ removeAll(keywordsToReplace);
+ }
+ }
+
+ public boolean add(Keyword keyword) {
+ if (contains(keyword)) {
+ return false; // Don't add duplicate keywords
+ }
+ return keywords.add(keyword);
+ }
+
+ /**
+ * Keywords are separated by the given delimiter and an additional space, i.e. "one, two".
+ */
+ public String getAsString(Character delimiter) {
+ return keywords.stream().map(Keyword::toString).collect(Collectors.joining(delimiter + " "));
+ }
+
+ public void add(String keywordsString) {
+ add(new Keyword(keywordsString));
+ }
+
+ @Override
+ public Iterator<Keyword> iterator() {
+ return keywords.iterator();
+ }
+
+ public int size() {
+ return keywords.size();
+ }
+
+ public boolean isEmpty() {
+ return keywords.isEmpty();
+ }
+
+ public boolean contains(Object o) {
+ return keywords.contains(o);
+ }
+
+ public boolean remove(Object o) {
+ return keywords.remove(o);
+ }
+
+ public void addAll(KeywordList keywordsToAdd) {
+ keywords.addAll(keywordsToAdd.keywords);
+ }
+
+ public void retainAll(KeywordList keywordToRetain) {
+ keywords.retainAll(keywordToRetain.keywords);
+ }
+
+ public void clear() {
+ keywords.clear();
+ }
+
+ public Keyword get(int index) {
+ return keywords.get(index);
+ }
+
+ public Stream<Keyword> stream() {
+ return keywords.stream();
+ }
+
+ @Override
+ public String toString() {
+ return getAsString(',');
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if ((o == null) || (getClass() != o.getClass())) {
+ return false;
+ }
+ KeywordList keywords1 = (KeywordList) o;
+ return Objects.equals(keywords, keywords1.keywords);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(keywords);
+ }
+}
diff --git a/src/main/java/net/sf/jabref/model/entry/ParsedEntryLink.java b/src/main/java/net/sf/jabref/model/entry/ParsedEntryLink.java
new file mode 100644
index 0000000..0527dbf
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/entry/ParsedEntryLink.java
@@ -0,0 +1,59 @@
+package net.sf.jabref.model.entry;
+
+import java.util.Objects;
+import java.util.Optional;
+
+import net.sf.jabref.model.database.BibDatabase;
+
+public class ParsedEntryLink {
+
+ private String key;
+ private Optional<BibEntry> linkedEntry;
+ private BibDatabase dataBase;
+
+ public ParsedEntryLink(String key, BibDatabase dataBase) {
+ this.key = key;
+ this.linkedEntry = dataBase.getEntryByKey(this.key);
+ this.dataBase = dataBase;
+ }
+
+ public ParsedEntryLink(BibEntry bibEntry) {
+ this.key = bibEntry.getCiteKeyOptional().orElse("");
+ this.linkedEntry = Optional.of(bibEntry);
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public Optional<BibEntry> getLinkedEntry() {
+ return linkedEntry;
+ }
+
+ public void setKey(String newKey) {
+ this.key = newKey;
+ this.linkedEntry = getDataBase().getEntryByKey(this.key);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(key, linkedEntry);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof ParsedEntryLink)) {
+ return false;
+ }
+ ParsedEntryLink other = (ParsedEntryLink) obj;
+ return Objects.equals(key, other.key) && Objects.equals(linkedEntry, other.linkedEntry);
+ }
+
+ public BibDatabase getDataBase() {
+ return dataBase;
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/model/entry/SpecialFields.java b/src/main/java/net/sf/jabref/model/entry/SpecialFields.java
deleted file mode 100644
index 80c3c10..0000000
--- a/src/main/java/net/sf/jabref/model/entry/SpecialFields.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package net.sf.jabref.model.entry;
-
-
-public class SpecialFields {
-
- public static final String FIELDNAME_PRINTED = "printed";
- public static final String FIELDNAME_PRIORITY = "priority";
- public static final String FIELDNAME_QUALITY = "qualityassured";
- public static final String FIELDNAME_RANKING = "ranking";
- public static final String FIELDNAME_READ = "readstatus";
- public static final String FIELDNAME_RELEVANCE = "relevance";
-
- public static final Boolean PREF_SPECIALFIELDSENABLED_DEFAULT = Boolean.TRUE;
-
- public static final Boolean PREF_SHOWCOLUMN_PRINTED_DEFAULT = Boolean.FALSE;
-
- public static final Boolean PREF_SHOWCOLUMN_PRIORITY_DEFAULT = Boolean.FALSE;
-
- public static final Boolean PREF_SHOWCOLUMN_QUALITY_DEFAULT = Boolean.FALSE;
-
- public static final Boolean PREF_SHOWCOLUMN_RANKING_DEFAULT = Boolean.TRUE;
-
- public static final Boolean PREF_SHOWCOLUMN_READ_DEFAULT = Boolean.FALSE;
-
- public static final Boolean PREF_SHOWCOLUMN_RELEVANCE_DEFAULT = Boolean.FALSE;
-
- public static final Boolean PREF_AUTOSYNCSPECIALFIELDSTOKEYWORDS_DEFAULT = Boolean.TRUE;
-
- public static final Boolean PREF_SERIALIZESPECIALFIELDS_DEFAULT = Boolean.FALSE;
-
-}
diff --git a/src/main/java/net/sf/jabref/model/entry/event/EntryChangedEvent.java b/src/main/java/net/sf/jabref/model/entry/event/EntryChangedEvent.java
new file mode 100644
index 0000000..25694de
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/entry/event/EntryChangedEvent.java
@@ -0,0 +1,26 @@
+package net.sf.jabref.model.entry.event;
+
+import net.sf.jabref.model.entry.BibEntry;
+
+/**
+ * <code>EntryChangedEvent</code> is fired when a <code>BibEntry</code> has been changed.
+ */
+
+public class EntryChangedEvent extends EntryEvent {
+
+ /**
+ * @param bibEntry <code>BibEntry</code> object the changes were applied on.
+ */
+ public EntryChangedEvent(BibEntry bibEntry) {
+ super(bibEntry);
+ }
+
+ /**
+ * @param bibEntry <code>BibEntry</code> object the changes were applied on.
+ * @param location Location affected by this event
+ */
+ public EntryChangedEvent(BibEntry bibEntry, EntryEventSource location) {
+ super(bibEntry, location);
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/model/entry/event/EntryEvent.java b/src/main/java/net/sf/jabref/model/entry/event/EntryEvent.java
new file mode 100644
index 0000000..f0252b9
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/entry/event/EntryEvent.java
@@ -0,0 +1,41 @@
+package net.sf.jabref.model.entry.event;
+
+import java.util.Objects;
+
+import net.sf.jabref.model.database.event.BibDatabaseContextChangedEvent;
+import net.sf.jabref.model.entry.BibEntry;
+
+/**
+ * This abstract class pretends a minimal set of attributes and methods
+ * which an entry event should have.
+ */
+public abstract class EntryEvent extends BibDatabaseContextChangedEvent {
+
+ private final BibEntry bibEntry;
+ private final EntryEventSource location;
+
+
+ /**
+ * @param bibEntry BibEntry object which is involved in this event
+ */
+ public EntryEvent(BibEntry bibEntry) {
+ this(bibEntry, EntryEventSource.LOCAL);
+ }
+
+ /**
+ * @param bibEntry BibEntry object which is involved in this event
+ * @param location Location affected by this event
+ */
+ public EntryEvent(BibEntry bibEntry, EntryEventSource location) {
+ this.bibEntry = Objects.requireNonNull(bibEntry);
+ this.location = Objects.requireNonNull(location);
+ }
+
+ public BibEntry getBibEntry() {
+ return this.bibEntry;
+ }
+
+ public EntryEventSource getEntryEventSource() {
+ return this.location;
+ }
+}
diff --git a/src/main/java/net/sf/jabref/model/entry/event/EntryEventSource.java b/src/main/java/net/sf/jabref/model/entry/event/EntryEventSource.java
new file mode 100644
index 0000000..ca1051f
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/entry/event/EntryEventSource.java
@@ -0,0 +1,11 @@
+package net.sf.jabref.model.entry.event;
+
+/**
+ * This enum represents the context EntryEvents were sent from.
+ */
+public enum EntryEventSource {
+ LOCAL,
+ SHARED,
+ UNDO,
+ SAVE_ACTION
+}
diff --git a/src/main/java/net/sf/jabref/model/entry/event/FieldChangedEvent.java b/src/main/java/net/sf/jabref/model/entry/event/FieldChangedEvent.java
new file mode 100644
index 0000000..778a1ef
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/entry/event/FieldChangedEvent.java
@@ -0,0 +1,72 @@
+package net.sf.jabref.model.entry.event;
+
+import net.sf.jabref.model.FieldChange;
+import net.sf.jabref.model.entry.BibEntry;
+
+/**
+ * <code>FieldChangedEvent</code> is fired when a field of <code>BibEntry</code> has been modified, removed or added.
+ */
+public class FieldChangedEvent extends EntryChangedEvent {
+
+ private final String fieldName;
+ private final String newValue;
+ private final String oldValue;
+
+
+ /**
+ * @param bibEntry Affected BibEntry object
+ * @param fieldName Name of field which has been changed
+ * @param newValue new field value
+ * @param newValue old field value
+ * @param location location Location affected by this event
+ */
+ public FieldChangedEvent(BibEntry bibEntry, String fieldName, String newValue, String oldValue,
+ EntryEventSource location) {
+ super(bibEntry, location);
+ this.fieldName = fieldName;
+ this.newValue = newValue;
+ this.oldValue = oldValue;
+ }
+
+ /**
+ * @param bibEntry Affected BibEntry object
+ * @param fieldName Name of field which has been changed
+ * @param newValue new field value
+ */
+ public FieldChangedEvent(BibEntry bibEntry, String fieldName, String newValue, String oldValue) {
+ super(bibEntry);
+ this.fieldName = fieldName;
+ this.newValue = newValue;
+ this.oldValue = oldValue;
+ }
+
+ /**
+ * @param bibEntry Affected BibEntry object
+ * @param fieldName Name of field which has been changed
+ * @param newValue new field value
+ * @param location location Location affected by this event
+ */
+ public FieldChangedEvent(FieldChange fieldChange, EntryEventSource location) {
+ super(fieldChange.getEntry(), location);
+ this.fieldName = fieldChange.getField();
+ this.newValue = fieldChange.getNewValue();
+ this.oldValue = fieldChange.getOldValue();
+ }
+
+ public FieldChangedEvent(FieldChange fieldChange) {
+ this(fieldChange, EntryEventSource.LOCAL);
+ }
+
+ public String getFieldName() {
+ return fieldName;
+ }
+
+ public String getNewValue() {
+ return newValue;
+ }
+
+ public String getOldValue() {
+ return oldValue;
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/model/entry/specialfields/SpecialField.java b/src/main/java/net/sf/jabref/model/entry/specialfields/SpecialField.java
new file mode 100644
index 0000000..e4a6dc3
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/entry/specialfields/SpecialField.java
@@ -0,0 +1,111 @@
+package net.sf.jabref.model.entry.specialfields;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Optional;
+
+import net.sf.jabref.model.entry.KeywordList;
+
+public enum SpecialField {
+
+ PRINTED("printed",
+ SpecialFieldValue.PRINTED
+ ),
+
+ PRIORITY("priority",
+ SpecialFieldValue.CLEAR_PRIORITY,
+ SpecialFieldValue.PRIORITY_HIGH,
+ SpecialFieldValue.PRIORITY_MEDIUM,
+ SpecialFieldValue.PRIORITY_LOW
+ ),
+
+ QUALITY("qualityassured",
+ SpecialFieldValue.QUALITY_ASSURED
+ ),
+
+ RANKING("ranking",
+ SpecialFieldValue.CLEAR_RANK,
+ SpecialFieldValue.RANK_1,
+ SpecialFieldValue.RANK_2,
+ SpecialFieldValue.RANK_3,
+ SpecialFieldValue.RANK_4,
+ SpecialFieldValue.RANK_5
+ ),
+
+ READ_STATUS("readstatus",
+ SpecialFieldValue.CLEAR_READ_STATUS,
+ SpecialFieldValue.READ,
+ SpecialFieldValue.SKIMMED
+ ),
+
+ RELEVANCE("relevance",
+ SpecialFieldValue.RELEVANT
+ );
+
+ private List<SpecialFieldValue> values;
+ private KeywordList keywords;
+ private HashMap<String, SpecialFieldValue> map;
+ private String fieldName;
+
+ SpecialField(String fieldName, SpecialFieldValue... values) {
+ this.fieldName = fieldName;
+ this.values = new ArrayList<>();
+ this.keywords = new KeywordList();
+ this.map = new HashMap<>();
+ for (SpecialFieldValue value : values) {
+ this.values.add(value);
+ value.getKeyword().ifPresent(keywords::add);
+ value.getFieldValue().ifPresent(fieldValue -> map.put(fieldValue, value));
+ }
+ }
+
+ public List<SpecialFieldValue> getValues() {
+ return this.values;
+ }
+
+ public KeywordList getKeyWords() {
+ return this.keywords;
+ }
+
+ public Optional<SpecialFieldValue> parse(String value) {
+ return Optional.ofNullable(map.get(value));
+ }
+
+ public String getFieldName() {
+ return fieldName;
+ }
+
+ public boolean isSingleValueField() {
+ return this.values.size() == 1;
+ }
+
+ public static Optional<SpecialField> getSpecialFieldInstanceFromFieldName(String fieldName) {
+ switch (fieldName) {
+ case "priority":
+ return Optional.of(SpecialField.PRIORITY);
+ case "qualityassured":
+ return Optional.of(SpecialField.QUALITY);
+ case "ranking":
+ return Optional.of(SpecialField.RANKING);
+ case "readstatus":
+ return Optional.of(SpecialField.RELEVANCE);
+ case "relevance":
+ return Optional.of(SpecialField.READ_STATUS);
+ case "printed":
+ return Optional.of(SpecialField.PRINTED);
+ default:
+ return Optional.empty();
+ }
+ }
+
+
+ /**
+ * @param fieldName the name of the field to check
+ * @return true if given field is a special field, false otherwise
+ */
+ public static boolean isSpecialField(String fieldName) {
+ return SpecialField.getSpecialFieldInstanceFromFieldName(fieldName).isPresent();
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/model/entry/specialfields/SpecialFieldValue.java b/src/main/java/net/sf/jabref/model/entry/specialfields/SpecialFieldValue.java
new file mode 100644
index 0000000..a701851
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/entry/specialfields/SpecialFieldValue.java
@@ -0,0 +1,45 @@
+package net.sf.jabref.model.entry.specialfields;
+
+import java.util.Optional;
+
+import net.sf.jabref.model.entry.Keyword;
+
+public enum SpecialFieldValue {
+
+ PRINTED("printed"),
+ CLEAR_PRIORITY(null),
+ PRIORITY_HIGH("prio1"),
+ PRIORITY_MEDIUM("prio2"),
+ PRIORITY_LOW("prio3"),
+ QUALITY_ASSURED("qualityAssured"),
+ CLEAR_RANK(null),
+ RANK_1("rank1"),
+ RANK_2("rank2"),
+ RANK_3("rank3"),
+ RANK_4("rank4"),
+ RANK_5("rank5"),
+ CLEAR_READ_STATUS(null),
+ READ("read"),
+ SKIMMED("skimmed"),
+ RELEVANT("relevant");
+
+ // keyword used at keyword field
+ private final Optional<Keyword> keyword;
+
+ /**
+ *
+ * @param keyword - The keyword to be used at BibTex's keyword field. May be "null" if no keyword is to be set
+ */
+ SpecialFieldValue(String keyword) {
+ this.keyword = Optional.ofNullable(keyword).map(Keyword::new);
+ }
+
+ public Optional<Keyword> getKeyword() {
+ return keyword;
+ }
+
+ public Optional<String> getFieldValue() {
+ return keyword.map(Keyword::toString);
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/model/event/EntryAddedEvent.java b/src/main/java/net/sf/jabref/model/event/EntryAddedEvent.java
deleted file mode 100644
index 2953f3d..0000000
--- a/src/main/java/net/sf/jabref/model/event/EntryAddedEvent.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package net.sf.jabref.model.event;
-
-import net.sf.jabref.event.source.EntryEventSource;
-import net.sf.jabref.model.database.BibDatabase;
-import net.sf.jabref.model.entry.BibEntry;
-
-/**
- * {@link EntryAddedEvent} is fired when a new {@link BibEntry} was added to the {@link BibDatabase}.
- */
-public class EntryAddedEvent extends EntryEvent {
-
- /**
- * @param bibEntry the entry which has been added
- */
- public EntryAddedEvent(BibEntry bibEntry) {
- super(bibEntry);
- }
-
- /**
- * @param bibEntry <code>BibEntry</code> object which has been added.
- * @param location Location affected by this event
- */
- public EntryAddedEvent(BibEntry bibEntry, EntryEventSource location) {
- super(bibEntry, location);
- }
-}
diff --git a/src/main/java/net/sf/jabref/model/event/EntryChangedEvent.java b/src/main/java/net/sf/jabref/model/event/EntryChangedEvent.java
deleted file mode 100644
index 885d737..0000000
--- a/src/main/java/net/sf/jabref/model/event/EntryChangedEvent.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package net.sf.jabref.model.event;
-
-import net.sf.jabref.event.source.EntryEventSource;
-import net.sf.jabref.model.entry.BibEntry;
-
-/**
- * <code>EntryChangedEvent</code> is fired when a <code>BibEntry</code> has been changed.
- */
-
-public class EntryChangedEvent extends EntryEvent {
-
- /**
- * @param bibEntry <code>BibEntry</code> object the changes were applied on.
- */
- public EntryChangedEvent(BibEntry bibEntry) {
- super(bibEntry);
- }
-
- /**
- * @param bibEntry <code>BibEntry</code> object the changes were applied on.
- * @param location Location affected by this event
- */
- public EntryChangedEvent(BibEntry bibEntry, EntryEventSource location) {
- super(bibEntry, location);
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/model/event/EntryEvent.java b/src/main/java/net/sf/jabref/model/event/EntryEvent.java
deleted file mode 100644
index 89776da..0000000
--- a/src/main/java/net/sf/jabref/model/event/EntryEvent.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package net.sf.jabref.model.event;
-
-import net.sf.jabref.event.source.EntryEventSource;
-import net.sf.jabref.model.entry.BibEntry;
-
-/**
- * This abstract class pretends a minimal set of attributes and methods
- * which an entry event should have.
- */
-public abstract class EntryEvent {
-
- private final BibEntry bibEntry;
- private final EntryEventSource location;
-
-
- /**
- * @param bibEntry BibEntry object which is involved in this event
- */
- public EntryEvent(BibEntry bibEntry) {
- this(bibEntry, EntryEventSource.LOCAL);
- }
-
- /**
- * @param bibEntry BibEntry object which is involved in this event
- * @param location Location affected by this event
- */
- public EntryEvent(BibEntry bibEntry, EntryEventSource location) {
- this.bibEntry = bibEntry;
- this.location = location;
- }
-
- public BibEntry getBibEntry() {
- return this.bibEntry;
- }
-
- public EntryEventSource getEntryEventSource() {
- return this.location;
- }
-}
diff --git a/src/main/java/net/sf/jabref/model/event/EntryRemovedEvent.java b/src/main/java/net/sf/jabref/model/event/EntryRemovedEvent.java
deleted file mode 100644
index 1a0e9d9..0000000
--- a/src/main/java/net/sf/jabref/model/event/EntryRemovedEvent.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package net.sf.jabref.model.event;
-
-import net.sf.jabref.event.source.EntryEventSource;
-import net.sf.jabref.model.entry.BibEntry;
-
-/**
- * <code>RemovedEntryEvent</code> is fired when a <code>BibEntry</code> was removed
- * from the database.
- */
-
-public class EntryRemovedEvent extends EntryEvent {
-
- /**
- * @param bibEntry <code>BibEntry</code> object which has been removed.
- */
- public EntryRemovedEvent(BibEntry bibEntry) {
- super(bibEntry);
- }
-
- /**
- * @param bibEntry <code>BibEntry</code> object which has been removed.
- * @param location Location affected by this event
- */
- public EntryRemovedEvent(BibEntry bibEntry, EntryEventSource location) {
- super(bibEntry, location);
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/model/event/FieldChangedEvent.java b/src/main/java/net/sf/jabref/model/event/FieldChangedEvent.java
deleted file mode 100644
index 136ba5d..0000000
--- a/src/main/java/net/sf/jabref/model/event/FieldChangedEvent.java
+++ /dev/null
@@ -1,73 +0,0 @@
-package net.sf.jabref.model.event;
-
-import net.sf.jabref.event.source.EntryEventSource;
-import net.sf.jabref.model.FieldChange;
-import net.sf.jabref.model.entry.BibEntry;
-
-/**
- * <code>FieldChangedEvent</code> is fired when a field of <code>BibEntry</code> has been modified, removed or added.
- */
-public class FieldChangedEvent extends EntryChangedEvent {
-
- private final String fieldName;
- private final String newValue;
- private final String oldValue;
-
-
- /**
- * @param bibEntry Affected BibEntry object
- * @param fieldName Name of field which has been changed
- * @param newValue new field value
- * @param newValue old field value
- * @param location location Location affected by this event
- */
- public FieldChangedEvent(BibEntry bibEntry, String fieldName, String newValue, String oldValue,
- EntryEventSource location) {
- super(bibEntry, location);
- this.fieldName = fieldName;
- this.newValue = newValue;
- this.oldValue = oldValue;
- }
-
- /**
- * @param bibEntry Affected BibEntry object
- * @param fieldName Name of field which has been changed
- * @param newValue new field value
- */
- public FieldChangedEvent(BibEntry bibEntry, String fieldName, String newValue, String oldValue) {
- super(bibEntry);
- this.fieldName = fieldName;
- this.newValue = newValue;
- this.oldValue = oldValue;
- }
-
- /**
- * @param bibEntry Affected BibEntry object
- * @param fieldName Name of field which has been changed
- * @param newValue new field value
- * @param location location Location affected by this event
- */
- public FieldChangedEvent(FieldChange fieldChange, EntryEventSource location) {
- super(fieldChange.getEntry(), location);
- this.fieldName = fieldChange.getField();
- this.newValue = fieldChange.getNewValue();
- this.oldValue = fieldChange.getOldValue();
- }
-
- public FieldChangedEvent(FieldChange fieldChange) {
- this(fieldChange, EntryEventSource.LOCAL);
- }
-
- public String getFieldName() {
- return fieldName;
- }
-
- public String getNewValue() {
- return newValue;
- }
-
- public String getOldValue() {
- return oldValue;
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/model/groups/AbstractGroup.java b/src/main/java/net/sf/jabref/model/groups/AbstractGroup.java
new file mode 100644
index 0000000..cf01f32
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/groups/AbstractGroup.java
@@ -0,0 +1,180 @@
+package net.sf.jabref.model.groups;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+import net.sf.jabref.model.database.BibDatabase;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.search.SearchMatcher;
+
+/**
+ * A group of BibtexEntries.
+ */
+public abstract class AbstractGroup implements SearchMatcher {
+
+ /**
+ * Character used for quoting in the string representation.
+ */
+ public static final char QUOTE_CHAR = '\\';
+ /**
+ * For separating units (e.g. name, which every group has) in the string
+ * representation
+ */
+ public static final String SEPARATOR = ";";
+ /**
+ * The group's name (every type of group has one).
+ */
+ private String name;
+ /**
+ * The hierarchical context of the group (INDEPENDENT, REFINING, or
+ * INCLUDING). Defaults to INDEPENDENT, which will be used if and
+ * only if the context specified in the constructor is invalid.
+ */
+ private GroupHierarchyType context = GroupHierarchyType.INDEPENDENT;
+
+
+ protected AbstractGroup(String name, GroupHierarchyType context) {
+ this.name = name;
+ setHierarchicalContext(context);
+ }
+
+ public GroupHierarchyType getContext() {
+ return context;
+ }
+
+ public abstract String getTypeId();
+
+ /**
+ * Returns this group's name, e.g. for display in a list/tree.
+ */
+ public final String getName() {
+ return name;
+ }
+
+ /**
+ * Sets the group's name.
+ */
+ public final void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * @return true if this type of group supports the explicit adding of
+ * entries.
+ */
+ public abstract boolean supportsAdd();
+
+ /**
+ * @return true if this type of group supports the explicit removal of
+ * entries.
+ */
+ public abstract boolean supportsRemove();
+
+ /**
+ * Adds the specified entries to this group.
+ *
+ * @return If this group or one or more entries was/were modified as a
+ * result of this operation, an object is returned that allows to
+ * undo this change. null is returned otherwise.
+ */
+ public abstract Optional<EntriesGroupChange> add(List<BibEntry> entriesToAdd);
+
+ public Optional<EntriesGroupChange> add(BibEntry entryToAdd) {
+ return add(Collections.singletonList(entryToAdd));
+ }
+
+ /**
+ * Removes the specified entries from this group.
+ *
+ * @return If this group or one or more entries was/were modified as a
+ * result of this operation, an object is returned that allows to
+ * undo this change. null is returned otherwise.
+ */
+ public abstract Optional<EntriesGroupChange> remove(List<BibEntry> entriesToRemove);
+
+ /**
+ * @return true if this group contains the specified entry, false otherwise.
+ */
+ public abstract boolean contains(BibEntry entry);
+
+ @Override
+ public boolean isMatch(BibEntry entry) {
+ return contains(entry);
+ }
+
+ /**
+ * @return true if this group contains any of the specified entries, false
+ * otherwise.
+ */
+ public boolean containsAny(List<BibEntry> entries) {
+ for (BibEntry entry : entries) {
+ if (contains(entry)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @return true if this group contains all of the specified entries, false
+ * otherwise.
+ */
+ public boolean containsAll(List<BibEntry> entries) {
+ for (BibEntry entry : entries) {
+ if (!contains(entry)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Returns true if this group is dynamic, i.e. uses a search definition or
+ * equiv. that might match new entries, or false if this group contains a
+ * fixed set of entries and thus will never match a new entry that was not
+ * explicitly added to it.
+ */
+ public abstract boolean isDynamic();
+
+ /**
+ * Returns the group's hierarchical context.
+ */
+ public GroupHierarchyType getHierarchicalContext() {
+ return context;
+ }
+
+ /**
+ * Sets the groups's hierarchical context. If context is not a valid
+ * value, the call is ignored.
+ */
+ public void setHierarchicalContext(GroupHierarchyType context) {
+ if (context == null) {
+ return;
+ }
+ this.context = context;
+ }
+
+ /**
+ * @return A deep copy of this object.
+ */
+ public abstract AbstractGroup deepCopy();
+
+ // by general AbstractGroup contract, toString() must return
+ // something from which this object can be reconstructed
+ // using fromString(String).
+
+ // by general AbstractGroup contract, equals() must be implemented
+
+ /**
+ * Update the group, if necessary, to handle the situation where the group
+ * is applied to a different BibDatabase than it was created for. This
+ * is for instance used when updating the group tree due to an external change.
+ *
+ * @param db The database to refresh for.
+ */
+ public void refreshForNewDatabase(BibDatabase db) {
+ // Default is to do nothing. Group types that are affected by a change
+ // of database must override this method.
+ }
+}
diff --git a/src/main/java/net/sf/jabref/model/groups/AllEntriesGroup.java b/src/main/java/net/sf/jabref/model/groups/AllEntriesGroup.java
new file mode 100644
index 0000000..063079d
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/groups/AllEntriesGroup.java
@@ -0,0 +1,78 @@
+package net.sf.jabref.model.groups;
+
+import java.util.List;
+import java.util.Optional;
+
+import net.sf.jabref.model.entry.BibEntry;
+
+/**
+ * This group contains all entries. Always. At any time!
+ */
+public class AllEntriesGroup extends AbstractGroup {
+
+ public static final String ID = "AllEntriesGroup:";
+
+
+ public AllEntriesGroup(String name) {
+ super(name, GroupHierarchyType.INDEPENDENT);
+ }
+
+ @Override
+ public boolean supportsAdd() {
+ return false;
+ }
+
+ @Override
+ public boolean supportsRemove() {
+ return false;
+ }
+
+ @Override
+ public Optional<EntriesGroupChange> add(List<BibEntry> entriesToAdd) {
+ // not supported -> ignore
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional<EntriesGroupChange> remove(List<BibEntry> entriesToRemove) {
+ // not supported -> ignore
+ return Optional.empty();
+ }
+
+ @Override
+ public AbstractGroup deepCopy() {
+ return new AllEntriesGroup(getName());
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return o instanceof AllEntriesGroup;
+ }
+
+ @Override
+ public String toString() {
+ return AllEntriesGroup.ID;
+ }
+
+ @Override
+ public boolean contains(BibEntry entry) {
+ return true;
+ }
+
+ @Override
+ public boolean isDynamic() {
+ // this is actually a special case; I define it as non-dynamic
+ return false;
+ }
+
+ @Override
+ public String getTypeId() {
+ return AllEntriesGroup.ID;
+ }
+
+ @Override
+ public int hashCode() {
+ // TODO Auto-generated method stub
+ return super.hashCode();
+ }
+}
diff --git a/src/main/java/net/sf/jabref/model/groups/EntriesGroupChange.java b/src/main/java/net/sf/jabref/model/groups/EntriesGroupChange.java
new file mode 100644
index 0000000..7dfdf82
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/groups/EntriesGroupChange.java
@@ -0,0 +1,43 @@
+package net.sf.jabref.model.groups;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import net.sf.jabref.model.FieldChange;
+import net.sf.jabref.model.entry.BibEntry;
+
+public class EntriesGroupChange {
+
+ private Set<BibEntry> oldEntries;
+ private Set<BibEntry> newEntries;
+ private List<FieldChange> entryChanges;
+
+ public EntriesGroupChange(Set<BibEntry> oldEntries, Set<BibEntry> newEntries) {
+ this(oldEntries, newEntries, Collections.emptyList());
+ }
+
+ public EntriesGroupChange(List<FieldChange> entryChanges) {
+ this(Collections.emptySet(), Collections.emptySet(), entryChanges);
+ }
+
+ public EntriesGroupChange(Set<BibEntry> oldEntries, Set<BibEntry> newEntries,
+ List<FieldChange> entryChanges) {
+ this.oldEntries = oldEntries;
+ this.newEntries = newEntries;
+ this.entryChanges = entryChanges;
+ }
+
+ public Set<BibEntry> getOldEntries() {
+ return oldEntries;
+ }
+
+ public Set<BibEntry> getNewEntries() {
+ return newEntries;
+ }
+
+ public Iterable<FieldChange> getEntryChanges() {
+ return entryChanges;
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/model/groups/ExplicitGroup.java b/src/main/java/net/sf/jabref/model/groups/ExplicitGroup.java
new file mode 100644
index 0000000..b4cbfe5
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/groups/ExplicitGroup.java
@@ -0,0 +1,103 @@
+package net.sf.jabref.model.groups;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.TreeSet;
+
+import net.sf.jabref.model.entry.FieldName;
+import net.sf.jabref.model.strings.StringUtil;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Select explicit bibtex entries. It is also known as static group.
+ *
+ * @author jzieren
+ */
+public class ExplicitGroup extends KeywordGroup {
+
+ public static final String ID = "ExplicitGroup:";
+
+ private final List<String> legacyEntryKeys = new ArrayList<>();
+
+ private static final Log LOGGER = LogFactory.getLog(ExplicitGroup.class);
+
+
+ public ExplicitGroup(String name, GroupHierarchyType context, Character keywordSeparator) {
+ super(name, FieldName.GROUPS, name, true, false, context, keywordSeparator);
+ }
+
+ public void addLegacyEntryKey(String key) {
+ this.legacyEntryKeys.add(key);
+ }
+
+ @Override
+ public AbstractGroup deepCopy() {
+ ExplicitGroup copy = new ExplicitGroup(getName(), getContext(), keywordSeparator);
+ copy.legacyEntryKeys.addAll(legacyEntryKeys);
+ return copy;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof ExplicitGroup)) {
+ return false;
+ }
+ ExplicitGroup other = (ExplicitGroup) o;
+ return Objects.equals(getName(), other.getName()) && Objects.equals(getHierarchicalContext(),
+ other.getHierarchicalContext()) && Objects.equals(getLegacyEntryKeys(), other.getLegacyEntryKeys());
+ }
+
+ /**
+ * Returns a String representation of this group and its entries.
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(ExplicitGroup.ID).append(
+ StringUtil.quote(getName(), AbstractGroup.SEPARATOR, AbstractGroup.QUOTE_CHAR)).
+ append(AbstractGroup.SEPARATOR).append(getContext().ordinal()).append(AbstractGroup.SEPARATOR);
+
+ // write legacy entry keys in well-defined order for CVS compatibility
+ Set<String> sortedKeys = new TreeSet<>();
+ sortedKeys.addAll(legacyEntryKeys);
+
+ for (String sortedKey : sortedKeys) {
+ sb.append(StringUtil.quote(sortedKey, AbstractGroup.SEPARATOR, AbstractGroup.QUOTE_CHAR)).append(
+ AbstractGroup.SEPARATOR);
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Remove all stored cite keys, resulting in an empty group.
+ */
+ public void clearLegacyEntryKeys() {
+ legacyEntryKeys.clear();
+ }
+
+ public List<String> getLegacyEntryKeys() {
+ return legacyEntryKeys;
+ }
+
+ @Override
+ public String getTypeId() {
+ return ExplicitGroup.ID;
+ }
+
+ @Override
+ public int hashCode() {
+ return super.hashCode();
+ }
+
+ @Override
+ public boolean isDynamic() {
+ return false;
+ }
+}
diff --git a/src/main/java/net/sf/jabref/model/groups/GroupHierarchyType.java b/src/main/java/net/sf/jabref/model/groups/GroupHierarchyType.java
new file mode 100644
index 0000000..352f358
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/groups/GroupHierarchyType.java
@@ -0,0 +1,28 @@
+package net.sf.jabref.model.groups;
+
+public enum GroupHierarchyType {
+
+ /** Group's contents are independent of its hierarchical position. */
+ INDEPENDENT,
+
+ /**
+ * Group's content is the intersection of its own content with its
+ * supergroup's content.
+ */
+ REFINING, // INTERSECTION
+
+ /**
+ * Group's content is the union of its own content with its subgroups'
+ * content.
+ */
+ INCLUDING; // UNION
+
+ public static GroupHierarchyType getByNumber(int type) {
+ GroupHierarchyType[] types = values();
+ if(type >= 0 && type < types.length) {
+ return types[type];
+ } else {
+ return null;
+ }
+ }
+}
diff --git a/src/main/java/net/sf/jabref/model/groups/GroupTreeNode.java b/src/main/java/net/sf/jabref/model/groups/GroupTreeNode.java
new file mode 100644
index 0000000..299d21f
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/groups/GroupTreeNode.java
@@ -0,0 +1,250 @@
+package net.sf.jabref.model.groups;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import net.sf.jabref.model.database.BibDatabase;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.search.SearchMatcher;
+import net.sf.jabref.model.search.matchers.MatcherSet;
+import net.sf.jabref.model.search.matchers.MatcherSets;
+
+/**
+ * A node in the groups tree that holds exactly one AbstractGroup.
+ */
+public class GroupTreeNode extends TreeNode<GroupTreeNode> {
+
+ private AbstractGroup group;
+
+ /**
+ * Creates this node and associates the specified group with it.
+ *
+ * @param group the group underlying this node
+ */
+ public GroupTreeNode(AbstractGroup group) {
+ super(GroupTreeNode.class);
+ setGroup(group);
+ }
+
+ public static GroupTreeNode fromGroup(AbstractGroup group) {
+ return new GroupTreeNode(group);
+ }
+
+ /**
+ * Returns the group underlying this node.
+ *
+ * @return the group associated with this node
+ */
+ public AbstractGroup getGroup() {
+ return group;
+ }
+
+ /**
+ * Associates the specified group with this node.
+ *
+ * @param newGroup the new group (has to be non-null)
+ */
+ @Deprecated // use other overload
+ public void setGroup(AbstractGroup newGroup) {
+ this.group = Objects.requireNonNull(newGroup);
+ }
+
+ /**
+ * Associates the specified group with this node while also providing the possibility to modify previous matched
+ * entries so that they are now matched by the new group.
+ *
+ * @param newGroup the new group (has to be non-null)
+ * @param shouldKeepPreviousAssignments specifies whether previous matched entries should be carried over
+ * @param entriesInDatabase list of entries in the database
+ */
+ public Optional<EntriesGroupChange> setGroup(AbstractGroup newGroup, boolean shouldKeepPreviousAssignments,
+ List<BibEntry> entriesInDatabase) {
+ AbstractGroup oldGroup = getGroup();
+ setGroup(newGroup);
+
+ // Keep assignments from previous group
+ if (shouldKeepPreviousAssignments && newGroup.supportsAdd()) {
+ List<BibEntry> entriesMatchedByOldGroup = entriesInDatabase.stream().filter(oldGroup::isMatch)
+ .collect(Collectors.toList());
+ if ((oldGroup instanceof ExplicitGroup) && (newGroup instanceof ExplicitGroup)) {
+ // Rename of explicit group, so remove old group assignment
+ oldGroup.remove(entriesMatchedByOldGroup);
+ }
+ return newGroup.add(entriesMatchedByOldGroup);
+ }
+ return Optional.empty();
+ }
+
+ /**
+ * Returns a textual representation of this node and its children. This
+ * representation contains both the tree structure and the textual
+ * representations of the group associated with each node.
+ * Every node is one entry in the list of strings.
+ *
+ * @return a representation of the tree based at this node as a list of strings
+ */
+ public List<String> getTreeAsString() {
+
+ List<String> representation = new ArrayList<>();
+
+ // Append myself
+ representation.add(this.toString());
+
+ // Append children
+ for(GroupTreeNode child : getChildren()) {
+ representation.addAll(child.getTreeAsString());
+ }
+
+ return representation;
+ }
+
+ /**
+ * Update all groups, if necessary, to handle the situation where the group
+ * tree is applied to a different BibDatabase than it was created for. This
+ * is for instance used when updating the group tree due to an external change.
+ *
+ * @param db The database to refresh for.
+ * @deprecated This method shouldn't be necessary anymore once explicit group memberships are saved directly in the entry.
+ * TODO: Remove this method.
+ */
+ @Deprecated
+ public void refreshGroupsForNewDatabase(BibDatabase db) {
+ for (GroupTreeNode node : getChildren()) {
+ node.group.refreshForNewDatabase(db);
+ node.refreshGroupsForNewDatabase(db);
+ }
+ }
+
+ /**
+ * Creates a SearchRule that finds elements contained in this nodes group,
+ * or the union of those elements in its own group and its
+ * children's groups (recursively), or the intersection of the elements in
+ * its own group and its parent's group (depending on the hierarchical settings stored in the involved groups)
+ *
+ * @return a SearchRule that finds the desired elements
+ */
+ public SearchMatcher getSearchRule() {
+ return getSearchRule(group.getHierarchicalContext());
+ }
+
+ private SearchMatcher getSearchRule(GroupHierarchyType originalContext) {
+ final GroupHierarchyType context = group.getHierarchicalContext();
+ if (context == GroupHierarchyType.INDEPENDENT) {
+ return group;
+ }
+ MatcherSet searchRule = MatcherSets.build(
+ context == GroupHierarchyType.REFINING ? MatcherSets.MatcherType.AND : MatcherSets.MatcherType.OR);
+ searchRule.addRule(group);
+ if ((context == GroupHierarchyType.INCLUDING) && (originalContext != GroupHierarchyType.REFINING)) {
+ for (GroupTreeNode child : getChildren()) {
+ searchRule.addRule(child.getSearchRule(originalContext));
+ }
+ } else if ((context == GroupHierarchyType.REFINING) && !isRoot() && (originalContext
+ != GroupHierarchyType.INCLUDING)) {
+ searchRule.addRule(getParent().get().getSearchRule(originalContext));
+ }
+ return searchRule;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if ((o == null) || (getClass() != o.getClass())) {
+ return false;
+ }
+ GroupTreeNode that = (GroupTreeNode) o;
+ return Objects.equals(group, that.group);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(group);
+ }
+
+ public List<GroupTreeNode> getContainingGroups(List<BibEntry> entries, boolean requireAll) {
+ List<GroupTreeNode> groups = new ArrayList<>();
+
+ // Add myself if I contain the entries
+ if(requireAll) {
+ if(this.group.containsAll(entries)) {
+ groups.add(this);
+ }
+ } else {
+ if(this.group.containsAny(entries)) {
+ groups.add(this);
+ }
+ }
+
+ // Traverse children
+ for(GroupTreeNode child : getChildren()) {
+ groups.addAll(child.getContainingGroups(entries, requireAll));
+ }
+
+ return groups;
+ }
+
+ public List<GroupTreeNode> getMatchingGroups(List<BibEntry> entries) {
+ List<GroupTreeNode> groups = new ArrayList<>();
+
+ // Add myself if I contain the entries
+ SearchMatcher matcher = getSearchRule();
+ for (BibEntry entry : entries) {
+ if (matcher.isMatch(entry)) {
+ groups.add(this);
+ break;
+ }
+ }
+
+ // Traverse children
+ for(GroupTreeNode child : getChildren()) {
+ groups.addAll(child.getMatchingGroups(entries));
+ }
+
+ return groups;
+ }
+
+ public boolean supportsAddingEntries() {
+ return group.supportsAdd();
+ }
+
+ public String getName() {
+ return group.getName();
+ }
+
+ public GroupTreeNode addSubgroup(AbstractGroup subgroup) {
+ GroupTreeNode child = GroupTreeNode.fromGroup(subgroup);
+ addChild(child);
+ return child;
+ }
+
+ @Override
+ public String toString() {
+ return String.valueOf(this.getLevel()) + ' ' + group.toString();
+ }
+
+ @Override
+ public GroupTreeNode copyNode() {
+ return GroupTreeNode.fromGroup(group);
+ }
+
+ /**
+ * Determines the number of entries in the specified list which are matched by this group.
+ * @param entries list of entries to be searched
+ * @return number of hits
+ */
+ public int numberOfHits(List<BibEntry> entries) {
+ int hits = 0;
+ SearchMatcher matcher = getSearchRule();
+ for (BibEntry entry : entries) {
+ if (matcher.isMatch(entry)) {
+ hits++;
+ }
+ }
+ return hits;
+ }
+}
diff --git a/src/main/java/net/sf/jabref/model/groups/GroupsUtil.java b/src/main/java/net/sf/jabref/model/groups/GroupsUtil.java
new file mode 100644
index 0000000..69276a0
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/groups/GroupsUtil.java
@@ -0,0 +1,80 @@
+package net.sf.jabref.model.groups;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.TreeSet;
+import java.util.stream.Collectors;
+
+import net.sf.jabref.model.database.BibDatabase;
+import net.sf.jabref.model.entry.Author;
+import net.sf.jabref.model.entry.AuthorList;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.strings.StringUtil;
+
+public class GroupsUtil {
+
+ public static Set<String> findDeliminatedWordsInField(BibDatabase db, String field, String deliminator) {
+ Set<String> res = new TreeSet<>();
+
+ for (BibEntry be : db.getEntries()) {
+ be.getField(field).ifPresent(fieldValue -> {
+ StringTokenizer tok = new StringTokenizer(fieldValue.trim(), deliminator);
+ while (tok.hasMoreTokens()) {
+ res.add(StringUtil.capitalizeFirst(tok.nextToken().trim()));
+ }
+ });
+ }
+ return res;
+ }
+
+ /**
+ * Returns a Set containing all words used in the database in the given field type. Characters in
+ * <code>remove</code> are not included.
+ *
+ * @param db a <code>BibDatabase</code> value
+ * @param field a <code>String</code> value
+ * @param remove a <code>String</code> value
+ * @return a <code>Set</code> value
+ */
+ public static Set<String> findAllWordsInField(BibDatabase db, String field, String remove) {
+ Set<String> res = new TreeSet<>();
+ for (BibEntry be : db.getEntries()) {
+ be.getField(field).ifPresent(o -> {
+ StringTokenizer tok = new StringTokenizer(o, remove, false);
+ while (tok.hasMoreTokens()) {
+ res.add(StringUtil.capitalizeFirst(tok.nextToken().trim()));
+ }
+ });
+ }
+ return res;
+ }
+
+ /**
+ * Finds all authors' last names in all the given fields for the given database.
+ *
+ * @param db The database.
+ * @param fields The fields to look in.
+ * @return a set containing the names.
+ */
+ public static Set<String> findAuthorLastNames(BibDatabase db, List<String> fields) {
+ Set<String> res = new TreeSet<>();
+ for (BibEntry be : db.getEntries()) {
+ for (String field : fields) {
+ be.getField(field).ifPresent(val -> {
+ if (!val.isEmpty()) {
+ AuthorList al = AuthorList.parse(val);
+ res.addAll(al.getAuthors().stream().map(Author::getLast).filter(Optional::isPresent)
+ .map(Optional::get).filter(lastName -> !lastName.isEmpty())
+ .collect(Collectors.toList()));
+ }
+ });
+ }
+ }
+
+ return res;
+ }
+
+
+}
diff --git a/src/main/java/net/sf/jabref/model/groups/KeywordGroup.java b/src/main/java/net/sf/jabref/model/groups/KeywordGroup.java
new file mode 100644
index 0000000..5e824d2
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/groups/KeywordGroup.java
@@ -0,0 +1,298 @@
+package net.sf.jabref.model.groups;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+import net.sf.jabref.model.FieldChange;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.KeywordList;
+import net.sf.jabref.model.strings.StringUtil;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * @author jzieren
+ */
+public class KeywordGroup extends AbstractGroup {
+
+ public static final String ID = "KeywordGroup:";
+
+ private final String searchField;
+ private final String searchExpression;
+ private final boolean caseSensitive;
+ private final boolean regExp;
+ private Pattern pattern;
+ private final List<String> searchWords;
+ protected final Character keywordSeparator;
+
+ private static final Log LOGGER = LogFactory.getLog(KeywordGroup.class);
+
+
+ /**
+ * Creates a KeywordGroup with the specified properties.
+ */
+ public KeywordGroup(String name, String searchField,
+ String searchExpression, boolean caseSensitive, boolean regExp,
+ GroupHierarchyType context, Character keywordSeparator) {
+ super(name, context);
+ this.searchField = searchField;
+ this.searchExpression = searchExpression;
+ this.caseSensitive = caseSensitive;
+ this.regExp = regExp;
+ if (this.regExp) {
+ compilePattern();
+ }
+ this.keywordSeparator = keywordSeparator;
+ this.searchWords = StringUtil.getStringAsWords(searchExpression);
+ }
+
+ private void compilePattern() throws IllegalArgumentException {
+ try {
+ pattern = caseSensitive ? Pattern.compile("\\b" + searchExpression + "\\b") : Pattern.compile(
+ "\\b" + searchExpression + "\\b", Pattern.CASE_INSENSITIVE);
+ } catch (PatternSyntaxException exception) {
+ throw new IllegalArgumentException("Syntax error in regular-expression pattern: " + searchExpression);
+ }
+ }
+
+ /**
+ * Returns a String representation of this object that can be used to
+ * reconstruct it.
+ */
+ @Override
+ public String toString() {
+ return KeywordGroup.ID + StringUtil.quote(getName(), AbstractGroup.SEPARATOR, AbstractGroup.QUOTE_CHAR) +
+ AbstractGroup.SEPARATOR
+ + getContext().ordinal() + AbstractGroup.SEPARATOR
+ + StringUtil.quote(searchField, AbstractGroup.SEPARATOR, AbstractGroup.QUOTE_CHAR) + AbstractGroup.SEPARATOR
+ + StringUtil.quote(searchExpression, AbstractGroup.SEPARATOR, AbstractGroup.QUOTE_CHAR)
+ + AbstractGroup.SEPARATOR + StringUtil.booleanToBinaryString(caseSensitive) + AbstractGroup.SEPARATOR
+ + StringUtil.booleanToBinaryString(regExp) + AbstractGroup.SEPARATOR;
+ }
+
+ @Override
+ public boolean supportsAdd() {
+ return !regExp;
+ }
+
+ @Override
+ public boolean supportsRemove() {
+ return !regExp;
+ }
+
+ @Override
+ public Optional<EntriesGroupChange> add(List<BibEntry> entriesToAdd) {
+ if (!supportsAdd()) {
+ return Optional.empty();
+ }
+ if ((entriesToAdd != null) && !(entriesToAdd.isEmpty())) {
+ List<FieldChange> changes = new ArrayList<>();
+ boolean modified = false;
+ for (BibEntry entry : entriesToAdd) {
+ if (!contains(entry)) {
+ String oldContent = entry.getField(searchField).orElse(null);
+ KeywordList wordlist = KeywordList.parse(oldContent, keywordSeparator);
+ wordlist.add(searchExpression);
+ String newContent = wordlist.getAsString(keywordSeparator);
+ entry.setField(searchField, newContent);
+
+ // Store change information.
+ changes.add(new FieldChange(entry, searchField, oldContent, newContent));
+ modified = true;
+ }
+ }
+
+ return modified ? Optional.of(new EntriesGroupChange(changes)) : Optional.empty();
+ }
+
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional<EntriesGroupChange> remove(List<BibEntry> entriesToRemove) {
+ if (!supportsRemove()) {
+ return Optional.empty();
+ }
+
+ if ((entriesToRemove != null) && (!entriesToRemove.isEmpty())) {
+ List<FieldChange> changes = new ArrayList<>();
+ boolean modified = false;
+ for (BibEntry entry : entriesToRemove) {
+ if (contains(entry)) {
+ String oldContent = entry.getField(searchField).orElse(null);
+ removeMatches(entry);
+
+ // Store change information.
+ changes.add(new FieldChange(entry, searchField, oldContent,
+ entry.getField(searchField).orElse(null)));
+ modified = true;
+ }
+ }
+
+ return modified ? Optional.of(new EntriesGroupChange(changes)) : Optional.empty();
+ }
+
+ return Optional.empty();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof KeywordGroup)) {
+ return false;
+ }
+ KeywordGroup other = (KeywordGroup) o;
+ return getName().equals(other.getName())
+ && searchField.equals(other.searchField)
+ && searchExpression.equals(other.searchExpression)
+ && (caseSensitive == other.caseSensitive)
+ && (regExp == other.regExp)
+ && (getHierarchicalContext() == other.getHierarchicalContext());
+ }
+
+ @Override
+ public boolean contains(BibEntry entry) {
+ if (regExp) {
+ Optional<String> content = entry.getField(searchField);
+ return content.map(value -> pattern.matcher(value).find()).orElse(false);
+ }
+
+ Set<String> words = entry.getFieldAsWords(searchField);
+ if (words.isEmpty()) {
+ return false;
+ }
+
+ if (caseSensitive) {
+ return words.containsAll(searchWords);
+ }
+ return containsCaseInsensitive(searchWords, words);
+ }
+
+ private boolean containsCaseInsensitive(List<String> searchText, Set<String> words) {
+ for (String searchWord : searchText) {
+ if (!containsCaseInsensitive(searchWord, words)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private boolean containsCaseInsensitive(String text, Set<String> words) {
+ for (String word : words) {
+ if (word.equalsIgnoreCase(text)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Look for the given non-regexp string in another string, but check whether a
+ * match concerns a complete word, not part of a word.
+ *
+ * @param word The word to look for.
+ * @param text The string to look in.
+ * @return true if the word was found, false otherwise.
+ */
+ public static boolean containsWord(String word, String text) {
+ int piv = 0;
+ while (piv < text.length()) {
+ int index = text.indexOf(word, piv);
+ if (index < 0) {
+ return false;
+ }
+ // Found a match. See if it is a complete word:
+ if (((index == 0) || !Character.isLetterOrDigit(text.charAt(index - 1))) &&
+ (((index + word.length()) == text.length())
+ || !Character.isLetterOrDigit(text.charAt(index + word.length())))) {
+ return true;
+ } else {
+ piv = index + 1;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Removes matches of searchString in the entry's field. This is only
+ * possible if the search expression is not a regExp.
+ */
+ private void removeMatches(BibEntry entry) {
+ entry.getField(searchField).ifPresent(content -> {
+ StringBuffer sbOrig = new StringBuffer(content);
+ StringBuffer sbLower = new StringBuffer(content.toLowerCase());
+ StringBuffer haystack = caseSensitive ? sbOrig : sbLower;
+ String needle = caseSensitive ? searchExpression : searchExpression.toLowerCase();
+ int i;
+ int j;
+ int k;
+ while ((i = haystack.indexOf(needle)) >= 0) {
+ sbOrig.replace(i, i + needle.length(), "");
+ sbLower.replace(i, i + needle.length(), "");
+ // reduce spaces at i to 1
+ j = i;
+ k = i;
+ while (((j - 1) >= 0) && (keywordSeparator.toString().indexOf(haystack.charAt(j - 1)) >= 0)) {
+ --j;
+ }
+ while ((k < haystack.length()) && (keywordSeparator.toString().indexOf(haystack.charAt(k)) >= 0)) {
+ ++k;
+ }
+ sbOrig.replace(j, k, (j >= 0) && (k < sbOrig.length()) ? keywordSeparator.toString() : "");
+ sbLower.replace(j, k, (j >= 0) && (k < sbOrig.length()) ? keywordSeparator.toString() : "");
+ }
+
+ String result = sbOrig.toString().trim();
+ if (result.isEmpty()) {
+ entry.clearField(searchField);
+ } else {
+ entry.setField(searchField, result);
+ }
+ });
+ }
+
+ @Override
+ public AbstractGroup deepCopy() {
+ return new KeywordGroup(getName(), searchField, searchExpression,
+ caseSensitive, regExp, getContext(), keywordSeparator);
+ }
+
+ public boolean isCaseSensitive() {
+ return caseSensitive;
+ }
+
+ public boolean isRegExp() {
+ return regExp;
+ }
+
+ public String getSearchExpression() {
+ return searchExpression;
+ }
+
+ public String getSearchField() {
+ return searchField;
+ }
+
+ @Override
+ public boolean isDynamic() {
+ return true;
+ }
+
+ @Override
+ public String getTypeId() {
+ return KeywordGroup.ID;
+ }
+
+ @Override
+ public int hashCode() {
+ // TODO Auto-generated method stub
+ return super.hashCode();
+ }
+}
diff --git a/src/main/java/net/sf/jabref/model/groups/MoveGroupChange.java b/src/main/java/net/sf/jabref/model/groups/MoveGroupChange.java
new file mode 100644
index 0000000..9e326a6
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/groups/MoveGroupChange.java
@@ -0,0 +1,39 @@
+package net.sf.jabref.model.groups;
+
+public class MoveGroupChange {
+
+ private GroupTreeNode oldParent;
+ private int oldChildIndex;
+ private GroupTreeNode newParent;
+ private int newChildIndex;
+
+ /**
+ * @param oldParent
+ * @param oldChildIndex
+ * @param newParent The new parent node to which the node will be moved.
+ * @param newChildIndex The child index at newParent to which the node will be moved.
+ */
+ public MoveGroupChange(GroupTreeNode oldParent, int oldChildIndex, GroupTreeNode newParent, int newChildIndex) {
+ this.oldParent = oldParent;
+ this.oldChildIndex = oldChildIndex;
+ this.newParent = newParent;
+ this.newChildIndex = newChildIndex;
+ }
+
+ public GroupTreeNode getOldParent() {
+ return oldParent;
+ }
+
+ public int getOldChildIndex() {
+ return oldChildIndex;
+ }
+
+ public GroupTreeNode getNewParent() {
+ return newParent;
+ }
+
+ public int getNewChildIndex() {
+ return newChildIndex;
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/model/groups/SearchGroup.java b/src/main/java/net/sf/jabref/model/groups/SearchGroup.java
new file mode 100644
index 0000000..9bb30fe
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/groups/SearchGroup.java
@@ -0,0 +1,145 @@
+package net.sf.jabref.model.groups;
+
+import java.util.List;
+import java.util.Optional;
+
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.search.GroupSearchQuery;
+import net.sf.jabref.model.search.rules.SearchRule;
+import net.sf.jabref.model.strings.StringUtil;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Internally, it consists of a search pattern.
+ *
+ * @author jzieren
+ */
+public class SearchGroup extends AbstractGroup {
+
+ public static final String ID = "SearchGroup:";
+
+ private final GroupSearchQuery query;
+
+ private static final Log LOGGER = LogFactory.getLog(SearchGroup.class);
+
+ private final String searchExpression;
+ private final boolean caseSensitive;
+ private final boolean regExp;
+
+
+ /**
+ * Creates a SearchGroup with the specified properties.
+ */
+ public SearchGroup(String name, String searchExpression, boolean caseSensitive, boolean regExp,
+ GroupHierarchyType context) {
+ super(name, context);
+
+ this.searchExpression = searchExpression;
+ this.caseSensitive = caseSensitive;
+ this.regExp = regExp;
+ this.query = new GroupSearchQuery(searchExpression, caseSensitive, regExp);
+ }
+
+ @Override
+ public String getTypeId() {
+ return SearchGroup.ID;
+ }
+
+ /**
+ * Returns a String representation of this object that can be used to
+ * reconstruct it.
+ */
+ @Override
+ public String toString() {
+ return SearchGroup.ID + StringUtil.quote(getName(), AbstractGroup.SEPARATOR, AbstractGroup.QUOTE_CHAR)
+ + AbstractGroup.SEPARATOR + getContext().ordinal() + AbstractGroup.SEPARATOR
+ + StringUtil.quote(getSearchExpression(), AbstractGroup.SEPARATOR, AbstractGroup.QUOTE_CHAR)
+ + AbstractGroup.SEPARATOR + StringUtil.booleanToBinaryString(isCaseSensitive())
+ + AbstractGroup.SEPARATOR + StringUtil.booleanToBinaryString(isRegExp()) + AbstractGroup.SEPARATOR;
+ }
+
+ public String getSearchExpression() {
+ return searchExpression;
+ }
+
+ @Override
+ public boolean supportsAdd() {
+ return false;
+ }
+
+ @Override
+ public boolean supportsRemove() {
+ return false;
+ }
+
+ @Override
+ public Optional<EntriesGroupChange> add(List<BibEntry> entriesToAdd) {
+ throw new UnsupportedOperationException("Search group does not support adding entries.");
+ }
+
+ @Override
+ public Optional<EntriesGroupChange> remove(List<BibEntry> entriesToRemove) {
+ throw new UnsupportedOperationException("Search group does not support removing entries.");
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof SearchGroup)) {
+ return false;
+ }
+ SearchGroup other = (SearchGroup) o;
+ return getName().equals(other.getName())
+ && this.getSearchExpression().equals(other.getSearchExpression())
+ && (this.isCaseSensitive() == other.isCaseSensitive())
+ && (isRegExp() == other.isRegExp())
+ && (getHierarchicalContext() == other.getHierarchicalContext());
+ }
+
+ @Override
+ public boolean contains(BibEntry entry) {
+ return this.query.isMatch(entry);
+ }
+
+ @Override
+ public AbstractGroup deepCopy() {
+ try {
+ return new SearchGroup(getName(), getSearchExpression(), isCaseSensitive(),
+ isRegExp(), getHierarchicalContext());
+ } catch (Throwable t) {
+ // this should never happen, because the constructor obviously
+ // succeeded in creating _this_ instance!
+ LOGGER.error("Internal error in SearchGroup.deepCopy(). "
+ + "Please report this on https://github.com/JabRef/jabref/issues", t);
+ return null;
+ }
+ }
+
+ public boolean isCaseSensitive() {
+ return caseSensitive;
+ }
+
+ public boolean isRegExp() {
+ return regExp;
+ }
+
+ @Override
+ public boolean isDynamic() {
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ // TODO Auto-generated method stub
+ return super.hashCode();
+ }
+
+ public SearchRule getSearchRule() {
+ return query.getRule();
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/model/groups/TreeNode.java b/src/main/java/net/sf/jabref/model/groups/TreeNode.java
new file mode 100644
index 0000000..9defd7e
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/groups/TreeNode.java
@@ -0,0 +1,606 @@
+package net.sf.jabref.model.groups;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.function.Consumer;
+
+/**
+ * Represents a node in a tree.
+ * <p>
+ * Usually, tree nodes have a value property which allows access to the value stored in the node.
+ * In contrast to this approach, the TreeNode<T> class is designed to be used as a base class which provides the
+ * tree traversing functionality via inheritance.
+ * <p>
+ * Example usage:
+ * private class BasicTreeNode extends TreeNode<BasicTreeNode> {
+ * public BasicTreeNode() {
+ * super(BasicTreeNode.class);
+ * }
+ * }
+ * <p>
+ * This class started out as a copy of javax.swing.tree.DefaultMutableTreeNode.
+ *
+ * @param <T> the type of the class
+ */
+// We use some explicit casts of the form "(T) this". The constructor ensures that this cast is valid.
+ at SuppressWarnings("unchecked") public abstract class TreeNode<T extends TreeNode<T>> {
+
+ /**
+ * This node's parent, or null if this node has no parent
+ */
+ private T parent;
+ /**
+ * Array of children, may be empty if this node has no children (but never null)
+ */
+ private final List<T> children;
+
+ /**
+ * Constructs a tree node without parent and no children.
+ *
+ * @param derivingClass class deriving from TreeNode<T>. It should always be "T.class".
+ * We need this parameter since it is hard to get this information by other means.
+ */
+ public TreeNode(Class<T> derivingClass) {
+ parent = null;
+ children = new ArrayList<>();
+
+ if (!derivingClass.isInstance(this)) {
+ throw new UnsupportedOperationException("The class extending TreeNode<T> has to derive from T");
+ }
+ }
+
+ /**
+ * Get the path from the root node to this node.
+ * <p>
+ * The elements in the returned list represent the child index of each node in the path, starting at the root.
+ * If this node is the root node, the returned list has zero elements.
+ *
+ * @return a list of numbers which represent an indexed path from the root node to this node
+ */
+ public List<Integer> getIndexedPathFromRoot() {
+ if (parent == null) {
+ return new ArrayList<>();
+ }
+
+ List<Integer> path = parent.getIndexedPathFromRoot();
+ path.add(getPositionInParent());
+ return path;
+ }
+
+ /**
+ * Get the descendant of this node as indicated by the indexedPath.
+ * <p>
+ * If the path could not be traversed completely (i.e. one of the child indices did not exist),
+ * an empty Optional will be returned.
+ *
+ * @param indexedPath sequence of child indices that describe a path from this node to one of its descendants.
+ * Be aware that if indexedPath was obtained by getIndexedPathFromRoot(), this node should
+ * usually be the root node.
+ * @return descendant found by evaluating indexedPath
+ */
+ public Optional<T> getDescendant(List<Integer> indexedPath) {
+ T cursor = (T) this;
+ for (int index : indexedPath) {
+ Optional<T> child = cursor.getChildAt(index);
+ if (child.isPresent()) {
+ cursor = child.get();
+ } else {
+ return Optional.empty();
+ }
+ }
+ return Optional.of(cursor);
+ }
+
+ /**
+ * Get the child index of this node in its parent.
+ * <p>
+ * If this node is a root, then an UnsupportedOperationException is thrown.
+ * Use the isRoot method to check for this case.
+ *
+ * @return the child index of this node in its parent
+ */
+ public int getPositionInParent() {
+ return getParent().orElseThrow(() -> new UnsupportedOperationException("Roots have no position in parent"))
+ .getIndexOfChild((T) this).get();
+ }
+
+ /**
+ * Gets the index of the specified child in this node's child list.
+ * <p>
+ * If the specified node is not a child of this node, returns an empty Optional.
+ * This method performs a linear search and is O(n) where n is the number of children.
+ *
+ * @param childNode the node to search for among this node's children
+ * @return an integer giving the index of the node in this node's child list
+ * or an empty Optional if the specified node is a not a child of this node
+ * @throws NullPointerException if childNode is null
+ */
+ public Optional<Integer> getIndexOfChild(T childNode) {
+ Objects.requireNonNull(childNode);
+ int index = children.indexOf(childNode);
+ if (index == -1) {
+ return Optional.empty();
+ } else {
+ return Optional.of(index);
+ }
+ }
+
+ /**
+ * Gets the number of levels above this node, i.e. the distance from the root to this node.
+ * <p>
+ * If this node is the root, returns 0.
+ *
+ * @return an int giving the number of levels above this node
+ */
+ public int getLevel() {
+ if (parent == null) {
+ return 0;
+ }
+ return parent.getLevel() + 1;
+ }
+
+ /**
+ * Returns the number of children of this node.
+ *
+ * @return an int giving the number of children of this node
+ */
+ public int getNumberOfChildren() {
+ return children.size();
+ }
+
+ /**
+ * Removes this node from its parent and makes it a child of the specified node
+ * by adding it to the end of children list.
+ * In this way the whole subtree based at this node is moved to the given node.
+ *
+ * @param target the new parent
+ * @throws NullPointerException if target is null
+ * @throws ArrayIndexOutOfBoundsException if targetIndex is out of bounds
+ * @throws UnsupportedOperationException if target is an descendant of this node
+ */
+ public void moveTo(T target) {
+ Objects.requireNonNull(target);
+
+ Optional<T> oldParent = getParent();
+ if (oldParent.isPresent() && (oldParent.get() == target)) {
+ this.moveTo(target, target.getNumberOfChildren() - 1);
+ } else {
+ this.moveTo(target, target.getNumberOfChildren());
+ }
+ }
+
+ /**
+ * Returns the path from the root, to get to this node. The last element in the path is this node.
+ *
+ * @return a list of nodes giving the path, where the first element in the path is the root
+ * and the last element is this node.
+ */
+ public List<T> getPathFromRoot() {
+ if (parent == null) {
+ List<T> pathToMe = new ArrayList<>();
+ pathToMe.add((T) this);
+ return pathToMe;
+ }
+
+ List<T> path = parent.getPathFromRoot();
+ path.add((T) this);
+ return path;
+ }
+
+ /**
+ * Returns the next sibling of this node in the parent's children list.
+ * Returns an empty Optional if this node has no parent or if it is the parent's last child.
+ * <p>
+ * This method performs a linear search that is O(n) where n is the number of children.
+ * To traverse the entire children collection, use the parent's getChildren() instead.
+ *
+ * @return the sibling of this node that immediately follows this node
+ * @see #getChildren
+ */
+ public Optional<T> getNextSibling() {
+ return getRelativeSibling(+1);
+ }
+
+ /**
+ * Returns the previous sibling of this node in the parent's children list.
+ * Returns an empty Optional if this node has no parent or is the parent's first child.
+ * <p>
+ * This method performs a linear search that is O(n) where n is the number of children.
+ *
+ * @return the sibling of this node that immediately precedes this node
+ * @see #getChildren
+ */
+ public Optional<T> getPreviousSibling() {
+ return getRelativeSibling(-1);
+ }
+
+ /**
+ * Returns the sibling which is shiftIndex away from this node.
+ */
+ private Optional<T> getRelativeSibling(int shiftIndex) {
+ if (parent == null) {
+ return Optional.empty();
+ } else {
+ int indexInParent = getPositionInParent();
+ int indexTarget = indexInParent + shiftIndex;
+ if (parent.childIndexExists(indexTarget)) {
+ return parent.getChildAt(indexTarget);
+ } else {
+ return Optional.empty();
+ }
+ }
+ }
+
+ /**
+ * Returns this node's parent or an empty Optional if this node has no parent.
+ *
+ * @return this node's parent T, or an empty Optional if this node has no parent
+ */
+ public Optional<T> getParent() {
+ return Optional.ofNullable(parent);
+ }
+
+ /**
+ * Sets the parent node of this node.
+ * <p>
+ * This method does not add this node to the children collection of the new parent nor does it remove this node
+ * from the old parent. You should probably call moveTo or remove to change the tree.
+ *
+ * @param parent the new parent
+ */
+ protected void setParent(T parent) {
+ this.parent = parent;
+ }
+
+ /**
+ * Returns the child at the specified index in this node's children collection.
+ *
+ * @param index an index into this node's children collection
+ * @return the node in this node's children collection at the specified index,
+ * or an empty Optional if the index does not point to a child
+ */
+ public Optional<T> getChildAt(int index) {
+ return childIndexExists(index) ? Optional.of(children.get(index)) : Optional.empty();
+ }
+
+ /**
+ * Returns whether the specified index is a valid index for a child.
+ *
+ * @param index the index to be tested
+ * @return returns true when index is at least 0 and less then the count of children
+ */
+ protected boolean childIndexExists(int index) {
+ return (index >= 0) && (index < children.size());
+ }
+
+ /**
+ * Returns true if this node is the root of the tree.
+ * The root is the only node in the tree with an empty parent; every tree has exactly one root.
+ *
+ * @return true if this node is the root of its tree
+ */
+ public boolean isRoot() {
+ return parent == null;
+ }
+
+ /**
+ * Returns true if this node is an ancestor of the given node.
+ * <p>
+ * A node is considered an ancestor of itself.
+ *
+ * @param anotherNode node to test
+ * @return true if anotherNode is a descendant of this node
+ * @throws NullPointerException if anotherNode is null
+ * @see #isNodeDescendant
+ */
+ public boolean isAncestorOf(T anotherNode) {
+ Objects.requireNonNull(anotherNode);
+
+ if (anotherNode == this) {
+ return true;
+ } else {
+ for (T child : children) {
+ if (child.isAncestorOf(anotherNode)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Returns the root of the tree that contains this node. The root is the ancestor with an empty parent.
+ * Thus a node without a parent is considered its own root.
+ *
+ * @return the root of the tree that contains this node
+ */
+ public T getRoot() {
+ if (parent == null) {
+ return (T) this;
+ } else {
+ return parent.getRoot();
+ }
+ }
+
+ /**
+ * Returns true if this node has no children.
+ *
+ * @return true if this node has no children
+ */
+ public boolean isLeaf() {
+ return (getNumberOfChildren() == 0);
+ }
+
+ /**
+ * Removes the subtree rooted at this node from the tree, giving this node an empty parent.
+ * Does nothing if this node is the root of it tree.
+ */
+ public void removeFromParent() {
+ if (parent != null) {
+ parent.removeChild((T) this);
+ }
+ }
+
+ /**
+ * Removes all of this node's children, setting their parents to empty.
+ * If this node has no children, this method does nothing.
+ */
+ public void removeAllChildren() {
+ while (getNumberOfChildren() > 0) {
+ removeChild(0);
+ }
+ }
+
+ /**
+ * Returns this node's first child if it exists (otherwise returns an empty Optional).
+ *
+ * @return the first child of this node
+ */
+ public Optional<T> getFirstChild() {
+ return getChildAt(0);
+ }
+
+ /**
+ * Returns this node's last child if it exists (otherwise returns an empty Optional).
+ *
+ * @return the last child of this node
+ */
+ public Optional<T> getLastChild() {
+ return getChildAt(children.size() - 1);
+ }
+
+ /**
+ * Returns true if anotherNode is a descendant of this node
+ * -- if it is this node, one of this node's children, or a descendant of one of this node's children.
+ * Note that a node is considered a descendant of itself.
+ * <p>
+ * If anotherNode is null, an exception is thrown.
+ *
+ * @param anotherNode node to test as descendant of this node
+ * @return true if this node is an ancestor of anotherNode
+ * @see #isAncestorOf
+ */
+ public boolean isNodeDescendant(T anotherNode) {
+ Objects.requireNonNull(anotherNode);
+
+ return this.isAncestorOf(anotherNode);
+ }
+
+ /**
+ * Gets a forward-order list of this node's children.
+ * <p>
+ * The returned list is unmodifiable - use the add and remove methods to modify the nodes children.
+ * However, changing the nodes children (for example by calling moveTo) is reflected in a change of
+ * the list returned by getChildren. In other words, getChildren provides a read-only view on the children but
+ * not a copy.
+ *
+ * @return a list of this node's children
+ */
+ public List<T> getChildren() {
+ return Collections.unmodifiableList(children);
+ }
+
+ /**
+ * Removes the given child from this node's child list, giving it an empty parent.
+ *
+ * @param child a child of this node to remove
+ */
+ public void removeChild(T child) {
+ Objects.requireNonNull(child);
+
+ children.remove(child);
+ child.setParent(null);
+
+ notifyAboutDescendantChange((T)this);
+ }
+
+ /**
+ * Removes the child at the specified index from this node's children and sets that node's parent to empty.
+ * <p>
+ * Does nothing if the index does not point to a child.
+ *
+ * @param childIndex the index in this node's child array of the child to remove
+ */
+ public void removeChild(int childIndex) {
+ Optional<T> child = getChildAt(childIndex);
+ if (child.isPresent()) {
+ children.remove(childIndex);
+ child.get().setParent(null);
+ }
+
+ notifyAboutDescendantChange((T)this);
+ }
+
+ /**
+ * Adds the node at the end the children collection. Also sets the parent of the given node to this node.
+ * The given node is not allowed to already be in a tree (i.e. it has to have no parent).
+ *
+ * @param child the node to add
+ * @return the child node
+ */
+ public T addChild(T child) {
+ return addChild(child, children.size());
+ }
+
+ /**
+ * Adds the node at the given position in the children collection. Also sets the parent of the given node to this node.
+ * The given node is not allowed to already be in a tree (i.e. it has to have no parent).
+ *
+ * @param child the node to add
+ * @param index the position where the node should be added
+ * @return the child node
+ * @throws IndexOutOfBoundsException if the index is out of range
+ */
+ public T addChild(T child, int index) {
+ Objects.requireNonNull(child);
+ if (child.getParent().isPresent()) {
+ throw new UnsupportedOperationException("Cannot add a node which already has a parent, use moveTo instead");
+ }
+
+ child.setParent((T) this);
+ children.add(index, child);
+
+ notifyAboutDescendantChange((T)this);
+
+ return child;
+ }
+
+ /**
+ * Removes all children from this node and makes them a child of the specified node
+ * by adding it to the specified position in the children list.
+ *
+ * @param target the new parent
+ * @param targetIndex the position where the children should be inserted
+ * @throws NullPointerException if target is null
+ * @throws ArrayIndexOutOfBoundsException if targetIndex is out of bounds
+ * @throws UnsupportedOperationException if target is an descendant of one of the children of this node
+ */
+ public void moveAllChildrenTo(T target, int targetIndex) {
+ while (getNumberOfChildren() > 0) {
+ getLastChild().get().moveTo(target, targetIndex);
+ }
+ }
+
+ /**
+ * Sorts the list of children according to the order induced by the specified {@link Comparator}.
+ * <p>
+ * All children must be mutually comparable using the specified comparator
+ * (that is, {@code c.compare(e1, e2)} must not throw a {@code ClassCastException}
+ * for any children {@code e1} and {@code e2} in the list).
+ *
+ * @param comparator the comparator used to compare the child nodes
+ * @param recursive if true the whole subtree is sorted
+ * @throws NullPointerException if the comparator is null
+ */
+ public void sortChildren(Comparator<? super T> comparator, boolean recursive) {
+ Objects.requireNonNull(comparator);
+
+ if (this.isLeaf()) {
+ return; // nothing to sort
+ }
+
+ int j = getNumberOfChildren() - 1;
+ int lastModified;
+ while (j > 0) {
+ lastModified = j + 1;
+ j = -1;
+ for (int i = 1; i < lastModified; ++i) {
+ T child1 = getChildAt(i - 1).get();
+ T child2 = getChildAt(i).get();
+ if (comparator.compare(child1, child2) > 0) {
+ child1.moveTo((T) this, i);
+ j = i;
+ }
+ }
+ }
+ if (recursive) {
+ for (T child : getChildren()) {
+ child.sortChildren(comparator, true);
+ }
+ }
+ }
+
+ /**
+ * Removes this node from its parent and makes it a child of the specified node
+ * by adding it to the specified position in the children list.
+ * In this way the whole subtree based at this node is moved to the given node.
+ *
+ * @param target the new parent
+ * @param targetIndex the position where the children should be inserted
+ * @throws NullPointerException if target is null
+ * @throws ArrayIndexOutOfBoundsException if targetIndex is out of bounds
+ * @throws UnsupportedOperationException if target is an descendant of this node
+ */
+ public void moveTo(T target, int targetIndex) {
+ Objects.requireNonNull(target);
+
+ // Check that the target node is not an ancestor of this node, because this would create loops in the tree
+ if (this.isAncestorOf(target)) {
+ throw new UnsupportedOperationException("the target cannot be a descendant of this node");
+ }
+
+ // Remove from previous parent
+ Optional<T> oldParent = getParent();
+ if (oldParent.isPresent()) {
+ oldParent.get().removeChild((T) this);
+ }
+
+ // Add as child
+ target.addChild((T) this, targetIndex);
+ }
+
+ /**
+ * Creates a deep copy of this node and all of its children.
+ *
+ * @return a deep copy of the subtree
+ */
+ public T copySubtree() {
+ T copy = copyNode();
+ for (T child : getChildren()) {
+ child.copySubtree().moveTo(copy);
+ }
+ return copy;
+ }
+
+ /**
+ * Creates a copy of this node, completely separated from the tree (i.e. no children and no parent)
+ *
+ * @return a deep copy of this node
+ */
+ public abstract T copyNode();
+
+ /**
+ * The function which is invoked when something changed in the subtree.
+ */
+ private Consumer<T> onDescendantChanged = t -> {
+ /* Do nothing */ };
+
+ /**
+ * Adds the given function to the list of subscribers which are notified when something changes in the subtree.
+ *
+ * The following events are supported (the text in parentheses specifies which node is passed as the source):
+ * - addChild (new parent)
+ * - removeChild (old parent)
+ * - move (old parent and new parent)
+ * @param subscriber function to be invoked upon a change
+ */
+ public void subscribeToDescendantChanged(Consumer<T> subscriber) {
+ onDescendantChanged = onDescendantChanged.andThen(subscriber);
+ }
+
+ /**
+ * Helper method which notifies all subscribers about a change in the subtree and bubbles the event to all parents.
+ * @param source the node which changed
+ */
+ protected void notifyAboutDescendantChange(T source) {
+ onDescendantChanged.accept(source);
+
+ if( !isRoot()) {
+ parent.notifyAboutDescendantChange(source);
+ }
+ }
+}
diff --git a/src/main/java/net/sf/jabref/model/groups/event/GroupUpdatedEvent.java b/src/main/java/net/sf/jabref/model/groups/event/GroupUpdatedEvent.java
new file mode 100644
index 0000000..26f838d
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/groups/event/GroupUpdatedEvent.java
@@ -0,0 +1,20 @@
+package net.sf.jabref.model.groups.event;
+
+import net.sf.jabref.model.database.event.BibDatabaseContextChangedEvent;
+import net.sf.jabref.model.metadata.MetaData;
+
+public class GroupUpdatedEvent extends BibDatabaseContextChangedEvent {
+
+ private final MetaData metaData;
+
+ /**
+ * @param metaData Affected instance
+ */
+ public GroupUpdatedEvent(MetaData metaData) {
+ this.metaData = metaData;
+ }
+
+ public MetaData getMetaData() {
+ return this.metaData;
+ }
+}
diff --git a/src/main/java/net/sf/jabref/model/metadata/FileDirectoryPreferences.java b/src/main/java/net/sf/jabref/model/metadata/FileDirectoryPreferences.java
new file mode 100644
index 0000000..1016911
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/metadata/FileDirectoryPreferences.java
@@ -0,0 +1,49 @@
+package net.sf.jabref.model.metadata;
+
+import java.nio.file.InvalidPathException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Map;
+import java.util.Optional;
+
+import net.sf.jabref.model.entry.FieldName;
+
+public class FileDirectoryPreferences {
+ public static final String DIR_SUFFIX = "Directory";
+
+ private final String user;
+ private final Map<String, String> fieldFileDirectories;
+ private final boolean bibLocationAsPrimary;
+
+ public FileDirectoryPreferences(String user, Map<String, String> fieldFileDirectories, boolean bibLocationAsPrimary) {
+ this.user = user;
+ this.fieldFileDirectories = fieldFileDirectories;
+ this.bibLocationAsPrimary = bibLocationAsPrimary;
+ }
+
+ public String getUser() {
+ return user;
+ }
+
+ public Optional<Path> getFileDirectory(String field) {
+ try {
+ String value = fieldFileDirectories.get(field);
+ // filter empty paths
+ if (value != null && !value.isEmpty()) {
+ Path path = Paths.get(value);
+ return Optional.of(path);
+ }
+ return Optional.empty();
+ } catch(InvalidPathException ex) {
+ return Optional.empty();
+ }
+ }
+
+ public Optional<Path> getFileDirectory() {
+ return getFileDirectory(FieldName.FILE);
+ }
+
+ public boolean isBibLocationAsPrimary() {
+ return bibLocationAsPrimary;
+ }
+}
diff --git a/src/main/java/net/sf/jabref/model/metadata/MetaData.java b/src/main/java/net/sf/jabref/model/metadata/MetaData.java
new file mode 100644
index 0000000..bfe3261
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/metadata/MetaData.java
@@ -0,0 +1,268 @@
+package net.sf.jabref.model.metadata;
+
+import java.nio.charset.Charset;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+
+import net.sf.jabref.model.bibtexkeypattern.AbstractBibtexKeyPattern;
+import net.sf.jabref.model.bibtexkeypattern.DatabaseBibtexKeyPattern;
+import net.sf.jabref.model.bibtexkeypattern.GlobalBibtexKeyPattern;
+import net.sf.jabref.model.cleanup.FieldFormatterCleanups;
+import net.sf.jabref.model.database.BibDatabaseMode;
+import net.sf.jabref.model.database.event.ChangePropagation;
+import net.sf.jabref.model.entry.FieldName;
+import net.sf.jabref.model.groups.GroupTreeNode;
+import net.sf.jabref.model.groups.event.GroupUpdatedEvent;
+import net.sf.jabref.model.metadata.event.MetaDataChangedEvent;
+
+import com.google.common.eventbus.EventBus;
+
+public class MetaData {
+ public static final String META_FLAG = "jabref-meta: ";
+ public static final String SAVE_ORDER_CONFIG = "saveOrderConfig";
+ public static final String SAVE_ACTIONS = "saveActions";
+ public static final String PREFIX_KEYPATTERN = "keypattern_";
+ public static final String KEYPATTERNDEFAULT = "keypatterndefault";
+ public static final String DATABASE_TYPE = "databaseType";
+ public static final String GROUPSTREE = "groupstree";
+ public static final String FILE_DIRECTORY = FieldName.FILE + FileDirectoryPreferences.DIR_SUFFIX;
+ public static final String PROTECTED_FLAG_META = "protectedFlag";
+
+ public static final char ESCAPE_CHARACTER = '\\';
+ public static final char SEPARATOR_CHARACTER = ';';
+ public static final String SEPARATOR_STRING = String.valueOf(SEPARATOR_CHARACTER);
+
+ private final EventBus eventBus = new EventBus();
+ private GroupTreeNode groupsRoot;
+ private Charset encoding;
+ private SaveOrderConfig saveOrderConfig;
+ private Map<String, String> citeKeyPatterns = new HashMap<>(); // <BibType, Pattern>
+ private Map<String, String> userFileDirectory = new HashMap<>(); // <User, FilePath>
+ private String defaultCiteKeyPattern;
+ private FieldFormatterCleanups saveActions;
+ private BibDatabaseMode mode;
+ private boolean isProtected;
+ private String defaultFileDirectory;
+
+ /**
+ * Constructs an empty metadata.
+ */
+ public MetaData() {
+ // Do nothing
+ }
+
+ public Optional<SaveOrderConfig> getSaveOrderConfig() {
+ return Optional.ofNullable(saveOrderConfig);
+ }
+
+ public void setSaveOrderConfig(SaveOrderConfig saveOrderConfig) {
+ this.saveOrderConfig = saveOrderConfig;
+ postChange();
+ }
+
+ public Optional<GroupTreeNode> getGroups() {
+ return Optional.ofNullable(groupsRoot);
+ }
+
+ /**
+ * Sets a new group root node. <b>WARNING </b>: This invalidates everything
+ * returned by getGroups() so far!!!
+ */
+ public void setGroups(GroupTreeNode root) {
+ groupsRoot = Objects.requireNonNull(root);
+ groupsRoot.subscribeToDescendantChanged(groupTreeNode -> eventBus.post(new GroupUpdatedEvent(this)));
+ eventBus.post(new GroupUpdatedEvent(this));
+ }
+
+ /**
+ * @return the stored label patterns
+ */
+ public AbstractBibtexKeyPattern getCiteKeyPattern(GlobalBibtexKeyPattern globalPattern) {
+ Objects.requireNonNull(globalPattern);
+ AbstractBibtexKeyPattern bibtexKeyPattern = new DatabaseBibtexKeyPattern(globalPattern);
+
+ // Add stored key patterns
+ citeKeyPatterns.forEach(bibtexKeyPattern::addBibtexKeyPattern);
+ getDefaultCiteKeyPattern().ifPresent(bibtexKeyPattern::setDefaultValue);
+
+ return bibtexKeyPattern;
+ }
+
+ /**
+ * Updates the stored key patterns to the given key patterns.
+ *
+ * @param bibtexKeyPattern the key patterns to update to. <br />
+ * A reference to this object is stored internally and is returned at getCiteKeyPattern();
+ */
+ public void setCiteKeyPattern(AbstractBibtexKeyPattern bibtexKeyPattern) {
+ Objects.requireNonNull(bibtexKeyPattern);
+
+ List<String> defaultValue = bibtexKeyPattern.getDefaultValue();
+ Map<String, List<String>> nonDefaultPatterns = bibtexKeyPattern.getPatterns();
+ setCiteKeyPattern(defaultValue, nonDefaultPatterns);
+ }
+
+ public void setCiteKeyPattern(List<String> defaultValue, Map<String, List<String>> nonDefaultPatterns) {
+ // Remove all patterns from metadata
+ citeKeyPatterns.clear();
+
+ // Set new value if it is not a default value
+ for (Map.Entry<String, List<String>> pattern : nonDefaultPatterns.entrySet()) {
+ citeKeyPatterns.put(pattern.getKey(), pattern.getValue().get(0));
+ }
+
+ // Store default pattern
+ if (defaultValue.isEmpty()) {
+ defaultCiteKeyPattern = null;
+ } else {
+ defaultCiteKeyPattern = defaultValue.get(0);
+ }
+
+ postChange();
+ }
+
+ public Optional<FieldFormatterCleanups> getSaveActions() {
+ return Optional.ofNullable(saveActions);
+ }
+
+ public void setSaveActions(FieldFormatterCleanups saveActions) {
+ this.saveActions = Objects.requireNonNull(saveActions);
+ postChange();
+ }
+
+ public Optional<BibDatabaseMode> getMode() {
+ return Optional.ofNullable(mode);
+ }
+
+ public void setMode(BibDatabaseMode mode) {
+ this.mode = Objects.requireNonNull(mode);
+ postChange();
+ }
+
+ public boolean isProtected() {
+ return isProtected;
+ }
+
+ public Optional<String> getDefaultFileDirectory() {
+ return Optional.ofNullable(defaultFileDirectory);
+ }
+
+ public void setDefaultFileDirectory(String path) {
+ defaultFileDirectory = Objects.requireNonNull(path).trim();
+ postChange();
+ }
+
+ public Optional<String> getUserFileDirectory(String user) {
+ return Optional.ofNullable(userFileDirectory.get(user));
+ }
+
+ public void markAsProtected() {
+ isProtected = true;
+ postChange();
+ }
+
+ public void clearDefaultFileDirectory() {
+ defaultFileDirectory = null;
+ postChange();
+ }
+
+ public void setUserFileDirectory(String user, String path) {
+ userFileDirectory.put(Objects.requireNonNull(user), Objects.requireNonNull(path));
+ postChange();
+ }
+
+ public void clearUserFileDirectory(String user) {
+ userFileDirectory.remove(user);
+ postChange();
+ }
+
+ public void markAsNotProtected() {
+ isProtected = false;
+ postChange();
+ }
+
+ public void clearSaveActions() {
+ saveActions = null;
+ postChange();
+ }
+
+ public void clearSaveOrderConfig() {
+ saveOrderConfig = null;
+ postChange();
+ }
+
+ /**
+ * Posts a new {@link MetaDataChangedEvent} on the {@link EventBus}.
+ */
+ private void postChange() {
+ eventBus.post(new MetaDataChangedEvent(this));
+ }
+
+ /**
+ * Returns the encoding used during parsing.
+ */
+ public Optional<Charset> getEncoding() {
+ return Optional.ofNullable(encoding);
+ }
+
+ public void setEncoding(Charset encoding) {
+ setEncoding(encoding, ChangePropagation.POST_EVENT);
+ }
+
+ /**
+ * This Method (with additional parameter) has been introduced to avoid event loops while saving a database.
+ */
+ public void setEncoding(Charset encoding, ChangePropagation postChanges) {
+ this.encoding = Objects.requireNonNull(encoding);
+ if (postChanges == ChangePropagation.POST_EVENT) {
+ postChange();
+ }
+ }
+
+ public void registerListener(Object listener) {
+ this.eventBus.register(listener);
+ }
+
+ public void unregisterListener(Object listener) {
+ this.eventBus.unregister(listener);
+ }
+
+ private Optional<String> getDefaultCiteKeyPattern() {
+ return Optional.ofNullable(defaultCiteKeyPattern);
+ }
+
+ public boolean isEmpty() {
+ return this.equals(new MetaData());
+ }
+
+ public Map<String, String> getUserFileDirectories() {
+ return Collections.unmodifiableMap(userFileDirectory);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ MetaData metaData = (MetaData) o;
+ return isProtected == metaData.isProtected && Objects.equals(groupsRoot, metaData.groupsRoot) && Objects.equals(
+ encoding, metaData.encoding) && Objects.equals(saveOrderConfig, metaData.saveOrderConfig) && Objects
+ .equals(citeKeyPatterns, metaData.citeKeyPatterns) && Objects.equals(userFileDirectory,
+ metaData.userFileDirectory) && Objects.equals(defaultCiteKeyPattern, metaData.defaultCiteKeyPattern)
+ && Objects.equals(saveActions, metaData.saveActions) && mode == metaData.mode && Objects.equals(
+ defaultFileDirectory, metaData.defaultFileDirectory);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(groupsRoot, encoding, saveOrderConfig, citeKeyPatterns, userFileDirectory,
+ defaultCiteKeyPattern, saveActions, mode, isProtected, defaultFileDirectory);
+ }
+}
diff --git a/src/main/java/net/sf/jabref/model/metadata/SaveOrderConfig.java b/src/main/java/net/sf/jabref/model/metadata/SaveOrderConfig.java
new file mode 100644
index 0000000..9c025d0
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/metadata/SaveOrderConfig.java
@@ -0,0 +1,186 @@
+package net.sf.jabref.model.metadata;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Stores the save order config from MetaData
+ * <p>
+ * Format: <choice>, pair of field + ascending (boolean)
+ */
+public class SaveOrderConfig {
+
+ private static final String ORIGINAL = "original";
+ private static final String SPECIFIED = "specified";
+
+ public boolean saveInOriginalOrder;
+
+ // quick hack for outside modifications
+ public final SortCriterion[] sortCriteria = new SortCriterion[3];
+
+ public static SaveOrderConfig parse(List<String> orderedData) {
+ return new SaveOrderConfig(orderedData);
+ }
+
+ public static class SortCriterion {
+
+ public String field;
+ public boolean descending;
+
+
+ public SortCriterion() {
+ this.field = "";
+ }
+
+ public SortCriterion(String field, String descending) {
+ this.field = field;
+ this.descending = Boolean.parseBoolean(descending);
+ }
+
+ public SortCriterion(String field, boolean descending) {
+ this.field = field;
+ this.descending = descending;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder("SortCriterion{");
+ sb.append("field='").append(field).append('\'');
+ sb.append(", descending=").append(descending);
+ sb.append('}');
+ return sb.toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if ((o == null) || (getClass() != o.getClass())) {
+ return false;
+ }
+ SortCriterion that = (SortCriterion) o;
+ return Objects.equals(descending, that.descending) &&
+ Objects.equals(field, that.field);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(field, descending);
+ }
+ }
+
+ public SaveOrderConfig(boolean saveInOriginalOrder, SortCriterion first, SortCriterion second,
+ SortCriterion third) {
+ this.saveInOriginalOrder = saveInOriginalOrder;
+ sortCriteria[0] = first;
+ sortCriteria[1] = second;
+ sortCriteria[2] = third;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o instanceof SaveOrderConfig) {
+ SaveOrderConfig that = (SaveOrderConfig) o;
+ boolean sortCriteriaEquals = sortCriteria[0].equals(that.sortCriteria[0])
+ && sortCriteria[1].equals(that.sortCriteria[1]) && sortCriteria[2].equals(that.sortCriteria[2]);
+
+ return Objects.equals(saveInOriginalOrder, that.saveInOriginalOrder) && sortCriteriaEquals;
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(saveInOriginalOrder, Arrays.hashCode(sortCriteria));
+ }
+
+ public SaveOrderConfig() {
+ // fill default values
+ setSaveInOriginalOrder();
+ sortCriteria[0] = new SortCriterion();
+ sortCriteria[1] = new SortCriterion();
+ sortCriteria[2] = new SortCriterion();
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder("SaveOrderConfig{");
+ sb.append("saveInOriginalOrder=").append(saveInOriginalOrder);
+ sb.append(", sortCriteria=").append(Arrays.toString(sortCriteria));
+ sb.append('}');
+ return sb.toString();
+ }
+
+ private SaveOrderConfig(List<String> data) {
+ Objects.requireNonNull(data);
+
+ if (data.isEmpty()) {
+ throw new IllegalArgumentException();
+ }
+
+ String choice = data.get(0);
+ if (ORIGINAL.equals(choice)) {
+ setSaveInOriginalOrder();
+ } else {
+ setSaveInSpecifiedOrder();
+ }
+
+ if (data.size() >= 3) {
+ sortCriteria[0] = new SortCriterion(data.get(1), data.get(2));
+ } else {
+ sortCriteria[0] = new SortCriterion();
+ }
+ if (data.size() >= 5) {
+ sortCriteria[1] = new SortCriterion(data.get(3), data.get(4));
+ } else {
+ sortCriteria[1] = new SortCriterion();
+ }
+ if (data.size() >= 7) {
+ sortCriteria[2] = new SortCriterion(data.get(5), data.get(6));
+ } else {
+ sortCriteria[2] = new SortCriterion();
+ }
+ }
+
+ public void setSaveInOriginalOrder() {
+ this.saveInOriginalOrder = true;
+ }
+
+ public void setSaveInSpecifiedOrder() {
+ this.saveInOriginalOrder = false;
+ }
+
+ /**
+ * Outputs the current configuration to be consumed later by the constructor
+ */
+ public List<String> getAsStringList() {
+ List<String> res = new ArrayList<>(7);
+ if (saveInOriginalOrder) {
+ res.add(ORIGINAL);
+ } else {
+ res.add(SPECIFIED);
+ }
+
+ res.add(sortCriteria[0].field);
+ res.add(Boolean.toString(sortCriteria[0].descending));
+ res.add(sortCriteria[1].field);
+ res.add(Boolean.toString(sortCriteria[1].descending));
+ res.add(sortCriteria[2].field);
+ res.add(Boolean.toString(sortCriteria[2].descending));
+
+ return res;
+ }
+
+ public static SaveOrderConfig getDefaultSaveOrder() {
+ SaveOrderConfig standard = new SaveOrderConfig();
+ standard.setSaveInOriginalOrder();
+ return standard;
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/model/metadata/event/MetaDataChangedEvent.java b/src/main/java/net/sf/jabref/model/metadata/event/MetaDataChangedEvent.java
new file mode 100644
index 0000000..e3a25b5
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/metadata/event/MetaDataChangedEvent.java
@@ -0,0 +1,23 @@
+package net.sf.jabref.model.metadata.event;
+
+import net.sf.jabref.model.database.event.BibDatabaseContextChangedEvent;
+import net.sf.jabref.model.metadata.MetaData;
+
+/**
+ * {@link MetaDataChangedEvent} is fired when a tuple of meta data has been put or removed.
+ */
+public class MetaDataChangedEvent extends BibDatabaseContextChangedEvent {
+
+ private final MetaData metaData;
+
+ /**
+ * @param metaData Affected instance
+ */
+ public MetaDataChangedEvent(MetaData metaData) {
+ this.metaData = metaData;
+ }
+
+ public MetaData getMetaData() {
+ return this.metaData;
+ }
+}
diff --git a/src/main/java/net/sf/jabref/model/search/GroupSearchQuery.java b/src/main/java/net/sf/jabref/model/search/GroupSearchQuery.java
new file mode 100644
index 0000000..a91dc38
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/search/GroupSearchQuery.java
@@ -0,0 +1,57 @@
+package net.sf.jabref.model.search;
+
+import java.util.Objects;
+
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.search.rules.SearchRule;
+import net.sf.jabref.model.search.rules.SearchRules;
+
+public class GroupSearchQuery implements SearchMatcher {
+
+ private final String query;
+ private final boolean caseSensitive;
+ private final boolean regularExpression;
+ private final SearchRule rule;
+
+ public GroupSearchQuery(String query, boolean caseSensitive, boolean regularExpression) {
+ this.query = Objects.requireNonNull(query);
+ this.caseSensitive = caseSensitive;
+ this.regularExpression = regularExpression;
+ this.rule = Objects.requireNonNull(getSearchRule());
+ }
+
+ @Override
+ public String toString() {
+ return String.format("\"%s\" (%s, %s)", query, getCaseSensitiveDescription(),
+ getRegularExpressionDescription());
+ }
+
+ @Override
+ public boolean isMatch(BibEntry entry) {
+ return this.getRule().applyRule(query, entry);
+ }
+
+ private SearchRule getSearchRule() {
+ return SearchRules.getSearchRuleByQuery(query, caseSensitive, regularExpression);
+ }
+
+ private String getCaseSensitiveDescription() {
+ if (caseSensitive) {
+ return "case sensitive";
+ } else {
+ return "case insensitive";
+ }
+ }
+
+ private String getRegularExpressionDescription() {
+ if (regularExpression) {
+ return "regular expression";
+ } else {
+ return "plain text";
+ }
+ }
+
+ public SearchRule getRule() {
+ return rule;
+ }
+}
diff --git a/src/main/java/net/sf/jabref/model/search/SearchMatcher.java b/src/main/java/net/sf/jabref/model/search/SearchMatcher.java
new file mode 100644
index 0000000..978e1bb
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/search/SearchMatcher.java
@@ -0,0 +1,10 @@
+package net.sf.jabref.model.search;
+
+import net.sf.jabref.model.entry.BibEntry;
+
+ at FunctionalInterface
+public interface SearchMatcher {
+
+ boolean isMatch(BibEntry entry);
+
+}
diff --git a/src/main/java/net/sf/jabref/model/search/matchers/AndMatcher.java b/src/main/java/net/sf/jabref/model/search/matchers/AndMatcher.java
new file mode 100644
index 0000000..2e00583
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/search/matchers/AndMatcher.java
@@ -0,0 +1,26 @@
+package net.sf.jabref.model.search.matchers;
+
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.search.SearchMatcher;
+
+/**
+ * Subclass of MatcherSet that ANDs or ORs between its rules, returning 0 or
+ * 1.
+ */
+public class AndMatcher extends MatcherSet {
+
+ @Override
+ public boolean isMatch(BibEntry bibEntry) {
+ int score = 0;
+
+ // We let each rule add a maximum of 1 to the score.
+ for (SearchMatcher rule : matchers) {
+ if(rule.isMatch(bibEntry)) {
+ score++;
+ }
+ }
+
+ // Then an AND rule demands that score == number of rules
+ return score == matchers.size();
+ }
+}
diff --git a/src/main/java/net/sf/jabref/model/search/matchers/MatcherSet.java b/src/main/java/net/sf/jabref/model/search/matchers/MatcherSet.java
new file mode 100644
index 0000000..fe6856a
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/search/matchers/MatcherSet.java
@@ -0,0 +1,45 @@
+package net.sf.jabref.model.search.matchers;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.Vector;
+
+import net.sf.jabref.model.search.SearchMatcher;
+
+public abstract class MatcherSet implements SearchMatcher {
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ MatcherSet that = (MatcherSet) o;
+
+ return matchers.equals(that.matchers);
+
+ }
+
+ @Override
+ public int hashCode() {
+ return matchers.hashCode();
+ }
+
+ protected final List<SearchMatcher> matchers = new Vector<>();
+
+ public void addRule(SearchMatcher newRule) {
+ matchers.add(Objects.requireNonNull(newRule));
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder("MatcherSet{");
+ sb.append("matchers=").append(matchers);
+ sb.append('}');
+ return sb.toString();
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/model/search/matchers/MatcherSets.java b/src/main/java/net/sf/jabref/model/search/matchers/MatcherSets.java
new file mode 100644
index 0000000..fb52838
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/search/matchers/MatcherSets.java
@@ -0,0 +1,19 @@
+package net.sf.jabref.model.search.matchers;
+
+
+public class MatcherSets {
+
+ public enum MatcherType {
+ AND,
+ OR
+ }
+
+ public static MatcherSet build(MatcherType ruleSet) {
+ if (ruleSet == MatcherType.AND) {
+ return new AndMatcher();
+ } else {
+ return new OrMatcher();
+ }
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/model/search/matchers/NotMatcher.java b/src/main/java/net/sf/jabref/model/search/matchers/NotMatcher.java
new file mode 100644
index 0000000..ac0d606
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/search/matchers/NotMatcher.java
@@ -0,0 +1,27 @@
+package net.sf.jabref.model.search.matchers;
+
+import java.util.Objects;
+
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.search.SearchMatcher;
+
+/**
+ * Inverts the search result.
+ * <p>
+ * Example:
+ * false --> true
+ * true --> false
+ */
+public class NotMatcher implements SearchMatcher {
+
+ private final SearchMatcher otherMatcher;
+
+ public NotMatcher(SearchMatcher otherMatcher) {
+ this.otherMatcher = Objects.requireNonNull(otherMatcher);
+ }
+
+ @Override
+ public boolean isMatch(BibEntry entry) {
+ return !otherMatcher.isMatch(entry);
+ }
+}
diff --git a/src/main/java/net/sf/jabref/model/search/matchers/OrMatcher.java b/src/main/java/net/sf/jabref/model/search/matchers/OrMatcher.java
new file mode 100644
index 0000000..c356566
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/search/matchers/OrMatcher.java
@@ -0,0 +1,26 @@
+package net.sf.jabref.model.search.matchers;
+
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.search.SearchMatcher;
+
+/**
+ * Subclass of MatcherSet that ANDs or ORs between its rules, returning 0 or
+ * 1.
+ */
+public class OrMatcher extends MatcherSet {
+
+ @Override
+ public boolean isMatch(BibEntry bibEntry) {
+ int score = 0;
+
+ // We let each rule add a maximum of 1 to the score.
+ for (SearchMatcher rule : matchers) {
+ if(rule.isMatch(bibEntry)) {
+ score++;
+ }
+ }
+
+ // OR rule demands score > 0.
+ return score > 0;
+ }
+}
diff --git a/src/main/java/net/sf/jabref/model/search/rules/ContainBasedSearchRule.java b/src/main/java/net/sf/jabref/model/search/rules/ContainBasedSearchRule.java
new file mode 100644
index 0000000..22b0f80
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/search/rules/ContainBasedSearchRule.java
@@ -0,0 +1,60 @@
+package net.sf.jabref.model.search.rules;
+
+import java.util.Iterator;
+import java.util.List;
+
+import net.sf.jabref.model.entry.BibEntry;
+
+/**
+ * Search rule for contain-based search.
+ */
+public class ContainBasedSearchRule implements SearchRule {
+
+ private final boolean caseSensitive;
+
+ public ContainBasedSearchRule(boolean caseSensitive) {
+ this.caseSensitive = caseSensitive;
+ }
+
+ public boolean isCaseSensitive() {
+ return caseSensitive;
+ }
+
+ @Override
+ public boolean validateSearchStrings(String query) {
+ return true;
+ }
+
+ @Override
+ public boolean applyRule(String query, BibEntry bibEntry) {
+
+ String searchString = query;
+ if (!caseSensitive) {
+ searchString = searchString.toLowerCase();
+ }
+
+ List<String> unmatchedWords = new SentenceAnalyzer(searchString).getWords();
+
+ for (String fieldKey : bibEntry.getFieldNames()) {
+ String formattedFieldContent = bibEntry.getLatexFreeField(fieldKey).get();
+ if (!caseSensitive) {
+ formattedFieldContent = formattedFieldContent.toLowerCase();
+ }
+
+ Iterator<String> unmatchedWordsIterator = unmatchedWords.iterator();
+ while (unmatchedWordsIterator.hasNext()) {
+ String word = unmatchedWordsIterator.next();
+ if(formattedFieldContent.contains(word)) {
+ unmatchedWordsIterator.remove();
+ }
+ }
+
+ if(unmatchedWords.isEmpty()) {
+ return true;
+ }
+ }
+
+ return false; // Didn't match all words.
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/model/search/rules/GrammarBasedSearchRule.java b/src/main/java/net/sf/jabref/model/search/rules/GrammarBasedSearchRule.java
new file mode 100644
index 0000000..449d859
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/search/rules/GrammarBasedSearchRule.java
@@ -0,0 +1,257 @@
+package net.sf.jabref.model.search.rules;
+
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.Predicate;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.Keyword;
+import net.sf.jabref.search.SearchBaseVisitor;
+import net.sf.jabref.search.SearchLexer;
+import net.sf.jabref.search.SearchParser;
+
+import org.antlr.v4.runtime.ANTLRInputStream;
+import org.antlr.v4.runtime.BailErrorStrategy;
+import org.antlr.v4.runtime.BaseErrorListener;
+import org.antlr.v4.runtime.CommonTokenStream;
+import org.antlr.v4.runtime.RecognitionException;
+import org.antlr.v4.runtime.Recognizer;
+import org.antlr.v4.runtime.misc.ParseCancellationException;
+import org.antlr.v4.runtime.tree.ParseTree;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * The search query must be specified in an expression that is acceptable by the Search.g4 grammar.
+ */
+public class GrammarBasedSearchRule implements SearchRule {
+
+ private static final Log LOGGER = LogFactory.getLog(GrammarBasedSearchRule.class);
+
+ private final boolean caseSensitiveSearch;
+ private final boolean regExpSearch;
+
+ private ParseTree tree;
+ private String query;
+
+
+ public static class ThrowingErrorListener extends BaseErrorListener {
+
+ public static final ThrowingErrorListener INSTANCE = new ThrowingErrorListener();
+
+ @Override
+ public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol,
+ int line, int charPositionInLine, String msg, RecognitionException e)
+ throws ParseCancellationException {
+ throw new ParseCancellationException("line " + line + ":" + charPositionInLine + " " + msg);
+ }
+ }
+
+ public GrammarBasedSearchRule(boolean caseSensitiveSearch, boolean regExpSearch) throws RecognitionException {
+ this.caseSensitiveSearch = caseSensitiveSearch;
+ this.regExpSearch = regExpSearch;
+ }
+
+ public static boolean isValid(boolean caseSensitive, boolean regExp, String query) {
+ return new GrammarBasedSearchRule(caseSensitive, regExp).validateSearchStrings(query);
+ }
+
+ public boolean isCaseSensitiveSearch() {
+ return this.caseSensitiveSearch;
+ }
+
+ public boolean isRegExpSearch() {
+ return this.regExpSearch;
+ }
+
+ public ParseTree getTree() {
+ return this.tree;
+ }
+
+ public String getQuery() {
+ return this.query;
+ }
+
+ private void init(String query) throws ParseCancellationException {
+ if (Objects.equals(this.query, query)) {
+ return;
+ }
+
+ SearchLexer lexer = new SearchLexer(new ANTLRInputStream(query));
+ lexer.removeErrorListeners(); // no infos on file system
+ lexer.addErrorListener(ThrowingErrorListener.INSTANCE);
+ SearchParser parser = new SearchParser(new CommonTokenStream(lexer));
+ parser.removeErrorListeners(); // no infos on file system
+ parser.addErrorListener(ThrowingErrorListener.INSTANCE);
+ parser.setErrorHandler(new BailErrorStrategy()); // ParseCancelationException on parse errors
+ tree = parser.start();
+ this.query = query;
+ }
+
+ @Override
+ public boolean applyRule(String query, BibEntry bibEntry) {
+ try {
+ return new BibtexSearchVisitor(caseSensitiveSearch, regExpSearch, bibEntry).visit(tree);
+ } catch (Exception e) {
+ LOGGER.debug("Search failed", e);
+ return false;
+ }
+ }
+
+ @Override
+ public boolean validateSearchStrings(String query) {
+ try {
+ init(query);
+ return true;
+ } catch (ParseCancellationException e) {
+ LOGGER.debug("Search query invalid", e);
+ return false;
+ }
+ }
+
+ public enum ComparisonOperator {
+ EXACT, CONTAINS, DOES_NOT_CONTAIN;
+
+ public static ComparisonOperator build(String value) {
+ if ("CONTAINS".equalsIgnoreCase(value) || "=".equals(value)) {
+ return CONTAINS;
+ } else if ("MATCHES".equalsIgnoreCase(value) || "==".equals(value)) {
+ return EXACT;
+ } else {
+ return DOES_NOT_CONTAIN;
+ }
+ }
+ }
+
+ public static class Comparator {
+
+ private final ComparisonOperator operator;
+ private final Pattern fieldPattern;
+ private final Pattern valuePattern;
+
+ public Comparator(String field, String value, ComparisonOperator operator, boolean caseSensitive, boolean regex) {
+ this.operator = operator;
+
+ int option = caseSensitive ? 0 : Pattern.CASE_INSENSITIVE;
+ this.fieldPattern = Pattern.compile(regex ? field : "\\Q" + field + "\\E", option);
+ this.valuePattern = Pattern.compile(regex ? value : "\\Q" + value + "\\E", option);
+ }
+
+ public boolean compare(BibEntry entry) {
+ // special case for searching for entrytype=phdthesis
+ if (fieldPattern.matcher(BibEntry.TYPE_HEADER).matches()) {
+ return matchFieldValue(entry.getType());
+ }
+
+ // special case for searching a single keyword
+ if (fieldPattern.matcher("anykeyword").matches()) {
+ return entry.getKeywords(',').stream().map(Keyword::toString).anyMatch(this::matchFieldValue);
+ }
+
+ // specification of fieldsKeys to search is done in the search expression itself
+ Set<String> fieldsKeys = entry.getFieldNames();
+
+ // special case for searching allfields=cat and title=dog
+ if (!fieldPattern.matcher("anyfield").matches()) {
+ // Filter out the requested fields
+ fieldsKeys = fieldsKeys.stream().filter(matchFieldKey()).collect(Collectors.toSet());
+ }
+
+ for (String field : fieldsKeys) {
+ Optional<String> fieldValue = entry.getLatexFreeField(field);
+ if (fieldValue.isPresent()) {
+ if (matchFieldValue(fieldValue.get())) {
+ return true;
+ }
+ }
+ }
+
+ // special case of asdf!=whatever and entry does not contain asdf
+ return fieldsKeys.isEmpty() && (operator == ComparisonOperator.DOES_NOT_CONTAIN);
+ }
+
+ private Predicate<String> matchFieldKey() {
+ return s -> fieldPattern.matcher(s).matches();
+ }
+
+ public boolean matchFieldValue(String content) {
+ Matcher matcher = valuePattern.matcher(content);
+ if (operator == ComparisonOperator.CONTAINS) {
+ return matcher.find();
+ } else if (operator == ComparisonOperator.EXACT) {
+ return matcher.matches();
+ } else if (operator == ComparisonOperator.DOES_NOT_CONTAIN) {
+ return !matcher.find();
+ } else {
+ throw new IllegalStateException("MUST NOT HAPPEN");
+ }
+ }
+
+ }
+
+ /**
+ * Search results in boolean. It may be later on converted to an int.
+ */
+ static class BibtexSearchVisitor extends SearchBaseVisitor<Boolean> {
+
+ private final boolean caseSensitive;
+ private final boolean regex;
+
+ private final BibEntry entry;
+
+ public BibtexSearchVisitor(boolean caseSensitive, boolean regex, BibEntry bibEntry) {
+ this.caseSensitive = caseSensitive;
+ this.regex = regex;
+ this.entry = bibEntry;
+ }
+
+ public boolean comparison(String field, ComparisonOperator operator, String value) {
+ return new Comparator(field, value, operator, caseSensitive, regex).compare(entry);
+ }
+
+ @Override
+ public Boolean visitStart(SearchParser.StartContext ctx) {
+ return visit(ctx.expression());
+ }
+
+ @Override
+ public Boolean visitComparison(SearchParser.ComparisonContext context) {
+ // remove possible enclosing " symbols
+ String right = context.right.getText();
+ if(right.startsWith("\"") && right.endsWith("\"")) {
+ right = right.substring(1, right.length() - 1);
+ }
+
+ Optional<SearchParser.NameContext> fieldDescriptor = Optional.ofNullable(context.left);
+ if (fieldDescriptor.isPresent()) {
+ return comparison(fieldDescriptor.get().getText(), ComparisonOperator.build(context.operator.getText()), right);
+ } else {
+ return new ContainBasedSearchRule(caseSensitive).applyRule(right, entry);
+ }
+ }
+
+ @Override
+ public Boolean visitUnaryExpression(SearchParser.UnaryExpressionContext ctx) {
+ return !visit(ctx.expression()); // negate
+ }
+
+ @Override
+ public Boolean visitParenExpression(SearchParser.ParenExpressionContext ctx) {
+ return visit(ctx.expression()); // ignore parenthesis
+ }
+
+ @Override
+ public Boolean visitBinaryExpression(SearchParser.BinaryExpressionContext ctx) {
+ if ("AND".equalsIgnoreCase(ctx.operator.getText())) {
+ return visit(ctx.left) && visit(ctx.right); // and
+ } else {
+ return visit(ctx.left) || visit(ctx.right); // or
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/model/search/rules/RegexBasedSearchRule.java b/src/main/java/net/sf/jabref/model/search/rules/RegexBasedSearchRule.java
new file mode 100644
index 0000000..e89c394
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/search/rules/RegexBasedSearchRule.java
@@ -0,0 +1,64 @@
+package net.sf.jabref.model.search.rules;
+
+import java.util.Optional;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+import net.sf.jabref.model.entry.BibEntry;
+
+/**
+ * Search rule for regex-based search.
+ */
+public class RegexBasedSearchRule implements SearchRule {
+
+ private final boolean caseSensitive;
+
+ public RegexBasedSearchRule(boolean caseSensitive) {
+ this.caseSensitive = caseSensitive;
+ }
+
+ public boolean isCaseSensitive() {
+ return caseSensitive;
+ }
+
+ @Override
+ public boolean validateSearchStrings(String query) {
+ String searchString = query;
+ if (!caseSensitive) {
+ searchString = searchString.toLowerCase();
+ }
+
+ try {
+ Pattern.compile(searchString, caseSensitive ? 0 : Pattern.CASE_INSENSITIVE);
+ } catch (PatternSyntaxException ex) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public boolean applyRule(String query, BibEntry bibEntry) {
+ Pattern pattern;
+
+ try {
+ pattern = Pattern.compile(query, caseSensitive ? 0 : Pattern.CASE_INSENSITIVE);
+ } catch (PatternSyntaxException ex) {
+ return false;
+ }
+
+ for (String field : bibEntry.getFieldNames()) {
+ Optional<String> fieldOptional = bibEntry.getField(field);
+ if (fieldOptional.isPresent()) {
+ String fieldContentNoBrackets = bibEntry.getLatexFreeField(field).get();
+ Matcher m = pattern.matcher(fieldContentNoBrackets);
+ if (m.find()) {
+ return true;
+ }
+ }
+
+ }
+ return false;
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/model/search/rules/SearchRule.java b/src/main/java/net/sf/jabref/model/search/rules/SearchRule.java
new file mode 100644
index 0000000..ec077bb
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/search/rules/SearchRule.java
@@ -0,0 +1,10 @@
+package net.sf.jabref.model.search.rules;
+
+import net.sf.jabref.model.entry.BibEntry;
+
+public interface SearchRule {
+
+ boolean applyRule(String query, BibEntry bibEntry);
+
+ boolean validateSearchStrings(String query);
+}
diff --git a/src/main/java/net/sf/jabref/model/search/rules/SearchRules.java b/src/main/java/net/sf/jabref/model/search/rules/SearchRules.java
new file mode 100644
index 0000000..55636c7
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/search/rules/SearchRules.java
@@ -0,0 +1,33 @@
+package net.sf.jabref.model.search.rules;
+
+import net.sf.jabref.model.strings.StringUtil;
+
+public class SearchRules {
+
+ /**
+ * Returns the appropriate search rule that fits best to the given parameter.
+ */
+ public static SearchRule getSearchRuleByQuery(String query, boolean caseSensitive, boolean regex) {
+ if (StringUtil.isBlank(query)) {
+ return new ContainBasedSearchRule(caseSensitive);
+ }
+
+ // this searches specified fields if specified,
+ // and all fields otherwise
+ SearchRule searchExpression = new GrammarBasedSearchRule(caseSensitive, regex);
+ if (searchExpression.validateSearchStrings(query)) {
+ return searchExpression;
+ } else {
+ return getSearchRule(caseSensitive, regex);
+ }
+ }
+
+ private static SearchRule getSearchRule(boolean caseSensitive, boolean regex) {
+ if (regex) {
+ return new RegexBasedSearchRule(caseSensitive);
+ } else {
+ return new ContainBasedSearchRule(caseSensitive);
+ }
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/model/search/rules/SentenceAnalyzer.java b/src/main/java/net/sf/jabref/model/search/rules/SentenceAnalyzer.java
new file mode 100644
index 0000000..6ac5f85
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/search/rules/SentenceAnalyzer.java
@@ -0,0 +1,57 @@
+package net.sf.jabref.model.search.rules;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class SentenceAnalyzer {
+
+ public static final char ESCAPE_CHAR = '\\';
+ public static final char QUOTE_CHAR = '"';
+
+ private final String query;
+
+ public SentenceAnalyzer(String query) {
+ this.query = query;
+ }
+
+ public List<String> getWords() {
+ List<String> result = new ArrayList<>();
+
+ StringBuilder stringBuilder = new StringBuilder();
+ boolean escaped = false;
+ boolean quoted = false;
+ for(char c : query.toCharArray()) {
+ // Check if we are entering an escape sequence:
+ if (!escaped && c == ESCAPE_CHAR) {
+ escaped = true;
+ } else {
+ // See if we have reached the end of a word:
+ if (!escaped && !quoted && Character.isWhitespace(c)) {
+ if (stringBuilder.length() > 0) {
+ result.add(stringBuilder.toString());
+ stringBuilder = new StringBuilder();
+ }
+ } else if (c == QUOTE_CHAR) {
+ // Whether it is a start or end quote, store the current
+ // word if any:
+ if (stringBuilder.length() > 0) {
+ result.add(stringBuilder.toString());
+ stringBuilder = new StringBuilder();
+ }
+ quoted = !quoted;
+ } else {
+ // All other possibilities exhausted, we add the char to
+ // the current word:
+ stringBuilder.append(c);
+ }
+ escaped = false;
+ }
+ }
+ // Finished with the loop. If we have a current word, add it:
+ if (stringBuilder.length() > 0) {
+ result.add(stringBuilder.toString());
+ }
+
+ return result;
+ }
+}
diff --git a/src/main/java/net/sf/jabref/model/strings/HTMLUnicodeConversionMaps.java b/src/main/java/net/sf/jabref/model/strings/HTMLUnicodeConversionMaps.java
new file mode 100644
index 0000000..837ded8
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/strings/HTMLUnicodeConversionMaps.java
@@ -0,0 +1,904 @@
+package net.sf.jabref.model.strings;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class HTMLUnicodeConversionMaps {
+
+ /* Portions © International Organization for Standardization 1986:
+ Permission to copy in any form is granted for use with
+ conforming SGML systems and applications as defined in
+ ISO 8879, provided this notice is included in all copies.
+ */
+
+ // most of the LaTeX commands can be read at http://en.wikibooks.org/wiki/LaTeX/Accents
+ // The symbols can be seen at http://www.fileformat.info/info/unicode/char/a4/index.htm. Replace "a4" with the U+ number
+ // http://detexify.kirelabs.org/classify.html and http://www.ctan.org/tex-archive/info/symbols/comprehensive/ might help to find the right LaTeX command
+ // http://llg.cubic.org/docs/ent2latex.html and http://www.w3.org/TR/xml-entity-names/byalpha.html are also useful
+ // as well as http://www.w3.org/Math/characters/unicode.xml
+
+ // An array of arrays of strings in the format:
+ // {"decimal number of HTML entity", "text HTML entity", "corresponding LaTeX command"}
+ // Leaving a field empty is OK as it then will not be included
+ private static final String[][] CONVERSION_LIST = new String[][] {{"160", "nbsp", "{~}"}, // no-break space = non-breaking space,
+ // U+00A0 ISOnum
+ {"161", "iexcl", "{\\textexclamdown}"}, // inverted exclamation mark, U+00A1 ISOnum
+ {"162", "cent", "{\\textcent}"}, // cent sign, U+00A2 ISOnum
+ {"163", "pound", "{\\pounds}"}, // pound sign, U+00A3 ISOnum
+ {"164", "curren", "{\\textcurrency}"}, // currency sign, U+00A4 ISOnum
+ {"165", "yen", "{\\textyen}"}, // yen sign = yuan sign, U+00A5 ISOnum
+ {"166", "brvbar", "{\\textbrokenbar}"}, // broken bar = broken vertical bar,
+ // U+00A6 ISOnum
+ {"167", "sect", "{{\\S}}"}, // section sign, U+00A7 ISOnum
+ {"168", "uml", "{\\\"{}}"}, // diaeresis = spacing diaeresis,
+ // U+00A8 ISOdia
+ {"169", "copy", "{\\copyright}"}, // copyright sign, U+00A9 ISOnum
+ {"170", "ordf", "{\\textordfeminine}"}, // feminine ordinal indicator, U+00AA ISOnum
+ {"171", "laquo", "{\\guillemotleft}"}, // left-pointing double angle quotation mark
+ // = left pointing guillemet, U+00AB ISOnum
+ {"172", "not", "$\\neg$"}, // not sign, U+00AC ISOnum
+ {"173", "shy", "\\-"}, // soft hyphen = discretionary hyphen,
+ // U+00AD ISOnum
+ {"174", "reg", "{\\textregistered}"}, // registered sign = registered trade mark sign,
+ // U+00AE ISOnum
+ {"175", "macr", "{\\={}}"}, // macron = spacing macron = overline
+ // = APL overbar, U+00AF ISOdia
+ {"176", "deg", "{$^{\\circ}$}"}, // degree sign, U+00B0 ISOnum
+ {"177", "plusmn", "$\\pm$"}, // plus-minus sign = plus-or-minus sign,
+ // U+00B1 ISOnum
+ {"178", "sup2", "\\textsuperscript{2}"}, // superscript two = superscript digit two
+ // = squared, U+00B2 ISOnum
+ {"179", "sup3", "\\textsuperscript{3}"}, // superscript three = superscript digit three
+ // = cubed, U+00B3 ISOnum
+ {"180", "acute", "{\\'{}}"}, // acute accent = spacing acute,
+ // U+00B4 ISOdia
+ {"181", "micro", "$\\mu$"}, // micro sign, U+00B5 ISOnum
+ {"", "mu", "$\\mu$"}, // micro sign, U+00B5 ISOnum
+ {"182", "para", "{{\\P}}"}, // pilcrow sign = paragraph sign,
+ // U+00B6 ISOnum
+ {"183", "middot", "$\\cdot$"}, // middle dot = Georgian comma
+ // = Greek middle dot, U+00B7 ISOnum
+ {"184", "cedil", "{\\c{}}"}, // cedilla = spacing cedilla, U+00B8 ISOdia
+ {"185", "sup1", "\\textsuperscript{1}"}, // superscript one = superscript digit one,
+ // U+00B9 ISOnum
+ {"186", "ordm", "{\\textordmasculine}"}, // masculine ordinal indicator,
+ // U+00BA ISOnum
+ {"187", "raquo", "{\\guillemotright}"}, // right-pointing double angle quotation mark
+ // = right pointing guillemet, U+00BB ISOnum
+ {"188", "frac14", "$\\sfrac{1}{4}$"}, // vulgar fraction one quarter
+ // = fraction one quarter, U+00BC ISOnum
+ {"189", "frac12", "$\\sfrac{1}{2}$"}, // vulgar fraction one half
+ // = fraction one half, U+00BD ISOnum
+ {"190", "frac34", "$\\sfrac{3}{4}$"}, // vulgar fraction three quarters
+ // = fraction three quarters, U+00BE ISOnum
+ {"191", "iquest", "{\\textquestiondown}"}, // inverted question mark
+ // = turned question mark, U+00BF ISOnum
+ {"192", "Agrave", "{{\\`{A}}}"}, // latin capital letter A with grave
+ // = latin capital letter A grave,
+ // U+00C0 ISOlat1
+ {"193", "Aacute", "{{\\'{A}}}"}, // latin capital letter A with acute,
+ // U+00C1 ISOlat1
+ {"194", "Acirc", "{{\\^{A}}}"}, // latin capital letter A with circumflex,
+ // U+00C2 ISOlat1
+ {"195", "Atilde", "{{\\~{A}}}"}, // latin capital letter A with tilde,
+ // U+00C3 ISOlat1
+ {"196", "Auml", "{{\\\"{A}}}"}, // latin capital letter A with diaeresis,
+ // U+00C4 ISOlat1
+ {"197", "Aring", "{{\\AA}}"}, // latin capital letter A with ring above
+ // = latin capital letter A ring,
+ // U+00C5 ISOlat1
+ {"198", "AElig", "{{\\AE}}"}, // latin capital letter AE
+ // = latin capital ligature AE,
+ // U+00C6 ISOlat1
+ {"199", "Ccedil", "{{\\c{C}}}"}, // latin capital letter C with cedilla,
+ // U+00C7 ISOlat1
+ {"200", "Egrave", "{{\\`{E}}}"}, // latin capital letter E with grave,
+ // U+00C8 ISOlat1
+ {"201", "Eacute", "{{\\'{E}}}"}, // latin capital letter E with acute,
+ // U+00C9 ISOlat1
+ {"202", "Ecirc", "{{\\^{E}}}"}, // latin capital letter E with circumflex,
+ // U+00CA ISOlat1
+ {"203", "Euml", "{{\\\"{E}}}"}, // latin capital letter E with diaeresis,
+ // U+00CB ISOlat1
+ {"204", "Igrave", "{{\\`{I}}}"}, // latin capital letter I with grave,
+ // U+00CC ISOlat1
+ {"205", "Iacute", "{{\\'{I}}}"}, // latin capital letter I with acute,
+ // U+00CD ISOlat1
+ {"206", "Icirc", "{{\\^{I}}}"}, // latin capital letter I with circumflex,
+ // U+00CE ISOlat1
+ {"207", "Iuml", "{{\\\"{I}}}"}, // latin capital letter I with diaeresis,
+ // U+00CF ISOlat1
+ {"208", "ETH", "{{\\DH}}"}, // latin capital letter ETH, U+00D0 ISOlat1
+ {"209", "Ntilde", "{{\\~{N}}}"}, // latin capital letter N with tilde,
+ // U+00D1 ISOlat1
+ {"210", "Ograve", "{{\\`{O}}}"}, // latin capital letter O with grave,
+ // U+00D2 ISOlat1
+ {"211", "Oacute", "{{\\'{O}}}"}, // latin capital letter O with acute,
+ // U+00D3 ISOlat1
+ {"212", "Ocirc", "{{\\^{O}}}"}, // latin capital letter O with circumflex,
+ // U+00D4 ISOlat1
+ {"213", "Otilde", "{{\\~{O}}}"}, // latin capital letter O with tilde,
+ // U+00D5 ISOlat1
+ {"214", "Ouml", "{{\\\"{O}}}"}, // latin capital letter O with diaeresis,
+ // U+00D6 ISOlat1
+ {"215", "times", "$\\times$"}, // multiplication sign, U+00D7 ISOnum
+ {"216", "Oslash", "{{\\O}}"}, // latin capital letter O with stroke
+ // = latin capital letter O slash,
+ // U+00D8 ISOlat1
+ {"217", "Ugrave", "{{\\`{U}}}"}, // latin capital letter U with grave,
+ // U+00D9 ISOlat1
+ {"218", "Uacute", "{{\\'{U}}}"}, // latin capital letter U with acute,
+ // U+00DA ISOlat1
+ {"219", "Ucirc", "{{\\^{U}}}"}, // latin capital letter U with circumflex,
+ // U+00DB ISOlat1
+ {"220", "Uuml", "{{\\\"{U}}}"}, // latin capital letter U with diaeresis,
+ // U+00DC ISOlat1
+ {"221", "Yacute", "{{\\'{Y}}}"}, // latin capital letter Y with acute,
+ // U+00DD ISOlat1
+ {"222", "THORN", "{{\\TH}}"}, // latin capital letter THORN,
+ // U+00DE ISOlat1
+ {"223", "szlig", "{\\ss}"}, // latin small letter sharp s = ess-zed,
+ // U+00DF ISOlat1
+ {"224", "agrave", "{\\`{a}}"}, // latin small letter a with grave
+ // = latin small letter a grave,
+ // U+00E0 ISOlat1
+ {"225", "aacute", "{\\'{a}}"}, // latin small letter a with acute,
+ // U+00E1 ISOlat1
+ {"226", "acirc", "{\\^{a}}"}, // latin small letter a with circumflex,
+ // U+00E2 ISOlat1
+ {"227", "atilde", "{\\~{a}}"}, // latin small letter a with tilde,
+ // U+00E3 ISOlat1
+ {"228", "auml", "{\\\"{a}}"}, // latin small letter a with diaeresis,
+ // U+00E4 ISOlat1
+ {"229", "aring", "{{\\aa}}"}, // latin small letter a with ring above
+ // = latin small letter a ring,
+ // U+00E5 ISOlat1
+ {"230", "aelig", "{\\ae}"}, // latin small letter ae
+ // = latin small ligature ae, U+00E6 ISOlat1
+ {"231", "ccedil", "{\\c{c}}"}, // latin small letter c with cedilla,
+ // U+00E7 ISOlat1
+ {"232", "egrave", "{\\`{e}}"}, // latin small letter e with grave,
+ // U+00E8 ISOlat1
+ {"233", "eacute", "{\\'{e}}"}, // latin small letter e with acute,
+ // U+00E9 ISOlat1
+ {"234", "ecirc", "{\\^{e}}"}, // latin small letter e with circumflex,
+ // U+00EA ISOlat1
+ {"235", "euml", "{\\\"{e}}"}, // latin small letter e with diaeresis,
+ // U+00EB ISOlat1
+ {"236", "igrave", "{\\`{i}}"}, // latin small letter i with grave,
+ // U+00EC ISOlat1
+ {"237", "iacute", "{\\'{i}}"}, // latin small letter i with acute,
+ // U+00ED ISOlat1
+ {"238", "icirc", "{\\^{i}}"}, // latin small letter i with circumflex,
+ // U+00EE ISOlat1
+ {"239", "iuml", "{\\\"{i}}"}, // latin small letter i with diaeresis,
+ // U+00EF ISOlat1
+ {"240", "eth", "{\\dh}"}, // latin small letter eth, U+00F0 ISOlat1
+ {"241", "ntilde", "{\\~{n}}"}, // latin small letter n with tilde,
+ // U+00F1 ISOlat1
+ {"242", "ograve", "{\\`{o}}"}, // latin small letter o with grave,
+ // U+00F2 ISOlat1
+ {"243", "oacute", "{\\'{o}}"}, // latin small letter o with acute,
+ // U+00F3 ISOlat1
+ {"244", "ocirc", "{\\^{o}}"}, // latin small letter o with circumflex,
+ // U+00F4 ISOlat1
+ {"245", "otilde", "{\\~{o}}"}, // latin small letter o with tilde,
+ // U+00F5 ISOlat1
+ {"246", "ouml", "{\\\"{o}}"}, // latin small letter o with diaeresis,
+ // U+00F6 ISOlat1
+ {"247", "divide", "$\\div$"}, // division sign, U+00F7 ISOnum
+ {"248", "oslash", "{\\o}"}, // latin small letter o with stroke,
+ // = latin small letter o slash,
+ // U+00F8 ISOlat1
+ {"249", "ugrave", "{\\`{u}}"}, // latin small letter u with grave,
+ // U+00F9 ISOlat1
+ {"250", "uacute", "{\\'{u}}"}, // latin small letter u with acute,
+ // U+00FA ISOlat1
+ {"251", "ucirc", "{\\^{u}}"}, // latin small letter u with circumflex,
+ // U+00FB ISOlat1
+ {"252", "uuml", "{\\\"{u}}"}, // latin small letter u with diaeresis,
+ // U+00FC ISOlat1
+ {"253", "yacute", "{\\'{y}}"}, // latin small letter y with acute,
+ // U+00FD ISOlat1
+ {"254", "thorn", "{\\th}"}, // latin small letter thorn,
+ // U+00FE ISOlat1
+ {"255", "yuml", "{\\\"{y}}"}, // latin small letter y with diaeresis,
+ // U+00FF ISOlat1
+
+ /* Greek */
+ {"913", "Alpha", "{{$\\Alpha$}}"}, // greek capital letter alpha, U+0391
+ {"914", "Beta", "{{$\\Beta$}}"}, // greek capital letter beta, U+0392
+ {"915", "Gamma", "{{$\\Gamma$}}"}, // greek capital letter gamma,
+ // U+0393 ISOgrk3
+ {"916", "Delta", "{{$\\Delta$}}"}, // greek capital letter delta,
+ // U+0394 ISOgrk3
+ {"917", "Epsilon", "{{$\\Epsilon$}}"}, // greek capital letter epsilon, U+0395
+ {"918", "Zeta", "{{$\\Zeta$}}"}, // greek capital letter zeta, U+0396
+ {"919", "Eta", "{{$\\Eta$}}"}, // greek capital letter eta, U+0397
+ {"920", "Theta", "{{$\\Theta$}}"}, // greek capital letter theta,
+ // U+0398 ISOgrk3
+ {"921", "Iota", "{{$\\Iota$}}"}, // greek capital letter iota, U+0399
+ {"922", "Kappa", "{{$\\Kappa$}}"}, // greek capital letter kappa, U+039A
+ {"923", "Lambda", "{{$\\Lambda$}}"}, // greek capital letter lambda,
+ // U+039B ISOgrk3
+ {"924", "Mu", "{{$\\Mu$}}"}, // greek capital letter mu, U+039C
+ {"925", "Nu", "{{$\\Nu$}}"}, // greek capital letter nu, U+039D
+ {"926", "Xi", "{{$\\Xi$}}"}, // greek capital letter xi, U+039E ISOgrk3
+ {"927", "Omicron", "{{$\\Omicron$}}"}, // greek capital letter omicron, U+039F
+ {"928", "Pi", "{{$\\Pi$}}"}, // greek capital letter pi, U+03A0 ISOgrk3
+ {"929", "Rho", "{{$\\Rho$}}"}, // greek capital letter rho, U+03A1
+ /* there is no Sigmaf, and no U+03A2 character either */
+ {"931", "Sigma", "{{$\\Sigma$}}"}, // greek capital letter sigma,
+ // U+03A3 ISOgrk3
+ {"932", "Tau", "{{$\\Tau$}}"}, // greek capital letter tau, U+03A4
+ {"933", "Upsilon", "{{$\\Upsilon$}}"}, // greek capital letter upsilon,
+ // U+03A5 ISOgrk3
+ {"934", "Phi", "{{$\\Phi$}}"}, // greek capital letter phi,
+ // U+03A6 ISOgrk3
+ {"935", "Chi", "{{$\\Chi$}}"}, // greek capital letter chi, U+03A7
+ {"936", "Psi", "{{$\\Psi$}}"}, // greek capital letter psi,
+ // U+03A8 ISOgrk3
+ {"937", "Omega", "{{$\\Omega$}}"}, // greek capital letter omega,
+ // U+03A9 ISOgrk3
+
+ {"945", "alpha", "$\\alpha$"}, // greek small letter alpha,
+ // U+03B1 ISOgrk3
+ {"946", "beta", "$\\beta$"}, // greek small letter beta, U+03B2 ISOgrk3
+ {"947", "gamma", "$\\gamma$"}, // greek small letter gamma,
+ // U+03B3 ISOgrk3
+ {"948", "delta", "$\\delta$"}, // greek small letter delta,
+ // U+03B4 ISOgrk3
+ {"949", "epsilon", "$\\epsilon$"}, // greek small letter epsilon,
+ // U+03B5 ISOgrk3
+ {"950", "zeta", "$\\zeta$"}, // greek small letter zeta, U+03B6 ISOgrk3
+ {"951", "eta", "$\\eta$"}, // greek small letter eta, U+03B7 ISOgrk3
+ {"952", "theta", "$\\theta$"}, // greek small letter theta,
+ // U+03B8 ISOgrk3
+ {"953", "iota", "$\\iota$"}, // greek small letter iota, U+03B9 ISOgrk3
+ {"954", "kappa", "$\\kappa$"}, // greek small letter kappa,
+ // U+03BA ISOgrk3
+ {"955", "lambda", "$\\lambda$"}, // greek small letter lambda,
+ // U+03BB ISOgrk3
+ {"956", "mu", "$\\mu$"}, // greek small letter mu, U+03BC ISOgrk3
+ {"957", "nu", "$\\nu$"}, // greek small letter nu, U+03BD ISOgrk3
+ {"958", "xi", "$\\xi$"}, // greek small letter xi, U+03BE ISOgrk3
+ {"959", "omicron", "$\\omicron$"}, // greek small letter omicron, U+03BF NEW
+ {"960", "pi", "$\\phi$"}, // greek small letter pi, U+03C0 ISOgrk3
+ {"961", "rho", "$\\rho$"}, // greek small letter rho, U+03C1 ISOgrk3
+ {"962", "sigmaf", "$\\varsigma$"}, // greek small letter final sigma,
+ // U+03C2 ISOgrk3
+ {"963", "sigma", "$\\sigma$"}, // greek small letter sigma,
+ // U+03C3 ISOgrk3
+ {"964", "tau", "$\\tau$"}, // greek small letter tau, U+03C4 ISOgrk3
+ {"965", "upsilon", "$\\upsilon$"}, // greek small letter upsilon,
+ {"", "upsi", "$\\upsilon$"}, // alias
+ // U+03C5 ISOgrk3
+ {"966", "phi", "$\\phi$"}, // greek small letter phi, U+03C6 ISOgrk3
+ {"967", "chi", "$\\chi$"}, // greek small letter chi, U+03C7 ISOgrk3
+ {"968", "psi", "$\\psi$"}, // greek small letter psi, U+03C8 ISOgrk3
+ {"969", "omega", "$\\omega$"}, // greek small letter omega,
+ // U+03C9 ISOgrk3
+ {"977", "thetasym", "$\\vartheta$"}, // greek small letter theta symbol,
+ {"", "thetav", "$\\vartheta$"}, // greek small letter theta symbol,
+ {"", "vartheta", "$\\vartheta$"}, // greek small letter theta symbol,
+ // U+03D1 NEW
+ {"978", "upsih", "{{$\\Upsilon$}}"}, // greek upsilon with hook symbol,
+ // U+03D2 NEW
+ {"982", "piv", "$\\varphi$"}, // greek pi symbol, U+03D6 ISOgrk3
+
+ /* General Punctuation */
+ {"8226", "bull", "$\\bullet$"}, // bullet = black small circle,
+ // U+2022 ISOpub
+ /* bullet is NOT the same as bullet operator, U+2219 */
+ {"8230", "hellip", "{\\ldots}"}, // horizontal ellipsis = three dot leader,
+ // U+2026 ISOpub
+ {"8242", "prime", "$\\prime$"}, // prime = minutes = feet, U+2032 ISOtech
+ {"8243", "Prime", "$\\prime\\prime$"}, // double prime = seconds = inches,
+ // U+2033 ISOtech
+ {"8254", "oline", "{\\={}}"}, // overline = spacing overscore,
+ // U+203E NEW
+ {"8260", "frasl", "/"}, // fraction slash, U+2044 NEW
+
+ /* Letterlike Symbols */
+ {"8472", "weierp", "$\\wp$"}, // script capital P = power set
+ // = Weierstrass p, U+2118 ISOamso
+ {"8465", "image", "{{$\\Im$}}"}, // blackletter capital I = imaginary part,
+ // U+2111 ISOamso
+ {"8476", "real", "{{$\\Re$}}"}, // blackletter capital R = real part symbol,
+ // U+211C ISOamso
+ {"8482", "trade", "{\\texttrademark}"}, // trade mark sign, U+2122 ISOnum
+ {"8501", "alefsym", "$\\aleph$"}, // alef symbol = first transfinite cardinal,
+ // U+2135 NEW
+ /* alef symbol is NOT the same as hebrew letter alef,
+ U+05D0 although the same glyph could be used to depict both characters */
+ /* Arrows */
+ {"8592", "larr", "$\\leftarrow$"}, // leftwards arrow, U+2190 ISOnum
+ {"8593", "uarr", "$\\uparrow$"}, // upwards arrow, U+2191 ISOnum
+ {"8594", "rarr", "$\\rightarrow$"}, // rightwards arrow, U+2192 ISOnum
+ {"8595", "darr", "$\\downarrow$"}, // downwards arrow, U+2193 ISOnum
+ {"8596", "harr", "$\\leftrightarrow$"}, // left right arrow, U+2194 ISOamsa
+ {"8629", "crarr", "$\\dlsh$"}, // downwards arrow with corner leftwards
+ // = carriage return, U+21B5 NEW - require mathabx
+ {"8656", "lArr", "{{$\\Leftarrow$}}"}, // leftwards double arrow, U+21D0 ISOtech
+ /* ISO 10646 does not say that lArr is the same as the 'is implied by' arrow
+ but also does not have any other character for that function. So ? lArr can
+ be used for 'is implied by' as ISOtech suggests */
+ {"8657", "uArr", "{{$\\Uparrow$}}"}, // upwards double arrow, U+21D1 ISOamsa
+ {"8658", "rArr", "{{$\\Rightarrow$}}"}, // rightwards double arrow,
+ // U+21D2 ISOtech
+ /* ISO 10646 does not say this is the 'implies' character but does not have
+ another character with this function so ?
+ rArr can be used for 'implies' as ISOtech suggests */
+ {"8659", "dArr", "{{$\\Downarrow$}}"}, // downwards double arrow, U+21D3 ISOamsa
+ {"8660", "hArr", "{{$\\Leftrightarrow$}}"}, // left right double arrow,
+ // U+21D4 ISOamsa
+
+ /* Mathematical Operators */
+ {"8704", "forall", "$\\forall$"}, // for all, U+2200 ISOtech
+ {"8706", "part", "$\\partial$"}, // partial differential, U+2202 ISOtech
+ {"8707", "exist", "$\\exists$"}, // there exists, U+2203 ISOtech
+ {"8709", "empty", "$\\emptyset$"}, // empty set = null set = diameter,
+ // U+2205 ISOamso
+ {"8711", "nabla", "$\\nabla$"}, // nabla = backward difference,
+ // U+2207 ISOtech
+ {"8712", "isin", "$\\in$"}, // element of, U+2208 ISOtech
+ {"8713", "notin", "$\\notin$"}, // not an element of, U+2209 ISOtech
+ {"8715", "ni", "$\\ni$"}, // contains as member, U+220B ISOtech
+ /* should there be a more memorable name than 'ni'? */
+ {"8719", "prod", "$\\prod$"}, // n-ary product = product sign,
+ // U+220F ISOamsb
+ /* prod is NOT the same character as U+03A0 'greek capital letter pi' though
+ the same glyph might be used for both */
+ {"8721", "sum", "$\\sum$"}, // n-ary sumation, U+2211 ISOamsb
+ /* sum is NOT the same character as U+03A3 'greek capital letter sigma'
+ though the same glyph might be used for both */
+ {"8722", "minus", "$-$"}, // minus sign, U+2212 ISOtech
+ {"8727", "lowast", "$\\ast$"}, // asterisk operator, U+2217 ISOtech
+ {"8730", "radic", "$\\sqrt{}$"}, // square root = radical sign,
+ // U+221A ISOtech
+ {"8733", "prop", "$\\propto$"}, // proportional to, U+221D ISOtech
+ {"8734", "infin", "$\\infty$"}, // infinity, U+221E ISOtech
+ {"8736", "ang", "$\\angle$"}, // angle, U+2220 ISOamso
+ {"8743", "and", "$\\land$"}, // logical and = wedge, U+2227 ISOtech
+ {"8744", "or", "$\\lor$"}, // logical or = vee, U+2228 ISOtech
+ {"8745", "cap", "$\\cap$"}, // intersection = cap, U+2229 ISOtech
+ {"8746", "cup", "$\\cup$"}, // union = cup, U+222A ISOtech
+ {"8747", "int", "$\\int$"}, // integral, U+222B ISOtech
+ {"8756", "there4", "$\\therefore$"}, // therefore, U+2234 ISOtech; AMSSymb
+ {"8764", "sim", "$\\sim$"}, // tilde operator = varies with = similar to,
+ // U+223C ISOtech
+ /* tilde operator is NOT the same character as the tilde, U+007E,
+ although the same glyph might be used to represent both */
+ {"8773", "cong", "$\\cong$"}, // approximately equal to, U+2245 ISOtech
+ {"8776", "asymp", "$\\approx$"}, // almost equal to = asymptotic to,
+ // U+2248 ISOamsr
+ {"8800", "ne", "$\\neq$"}, // not equal to, U+2260 ISOtech
+ {"8801", "equiv", "$\\equiv$"}, // identical to, U+2261 ISOtech
+ {"8804", "le", "$\\leq$"}, // less-than or equal to, U+2264 ISOtech
+ {"8805", "ge", "$\\geq$"}, // greater-than or equal to,
+ // U+2265 ISOtech
+ {"8834", "sub", "$\\subset$"}, // subset of, U+2282 ISOtech
+ {"8835", "sup", "$\\supset$"}, // superset of, U+2283 ISOtech
+ /* note that nsup, 'not a superset of, U+2283' is not covered by the Symbol
+ font encoding and is not included. Should it be, for symmetry?
+ It is in ISOamsn */
+ {"8836", "nsub", "$\\not\\subset$"}, // not a subset of, U+2284 ISOamsn
+ {"8838", "sube", "$\\subseteq$"}, // subset of or equal to, U+2286 ISOtech
+ {"8839", "supe", "$\\supseteq$"}, // superset of or equal to,
+ // U+2287 ISOtech
+ {"8853", "oplus", "$\\oplus$"}, // circled plus = direct sum,
+ // U+2295 ISOamsb
+ {"8855", "otimes", "$\\otimes$"}, // circled times = vector product,
+ // U+2297 ISOamsb
+ {"8869", "perp", "$\\perp$"}, // up tack = orthogonal to = perpendicular,
+ // U+22A5 ISOtech
+ {"8901", "sdot", "$\\cdot$"}, // dot operator, U+22C5 ISOamsb
+ /* dot operator is NOT the same character as U+00B7 middle dot */
+ {"8968", "lceil", "$\\lceil$"}, // left ceiling = apl upstile,
+ // U+2308 ISOamsc
+ {"8969", "rceil", "$\\rceil$"}, // right ceiling, U+2309 ISOamsc
+ {"8970", "lfloor", "$\\lfloor$"}, // left floor = apl downstile,
+ // U+230A ISOamsc
+ {"8971", "rfloor", "$\\rfloor$"}, // right floor, U+230B ISOamsc
+
+ /* Miscellaneous Technical */
+ {"9001", "lang", "$\\langle$"}, // left-pointing angle bracket = bra,
+ // U+2329 ISOtech
+ /* lang is NOT the same character as U+003C 'less than'
+ or U+2039 'single left-pointing angle quotation mark' */
+ {"9002", "rang", "$\\rangle$"}, // right-pointing angle bracket = ket,
+ // U+232A ISOtech
+ /* rang is NOT the same character as U+003E 'greater than'
+ or U+203A 'single right-pointing angle quotation mark' */
+ /* Geometric Shapes */
+ {"9674", "loz", "$\\lozenge$"}, // lozenge, U+25CA ISOpub
+
+ /* Miscellaneous Symbols */
+ {"9824", "spades", "$\\spadesuit$"}, // black spade suit, U+2660 ISOpub
+ /* black here seems to mean filled as opposed to hollow */
+ {"9827", "clubs", "$\\clubsuit$"}, // black club suit = shamrock,
+ // U+2663 ISOpub
+ {"9829", "hearts", "$\\heartsuit$"}, // black heart suit = valentine,
+ // U+2665 ISOpub
+ {"9830", "diams", "$\\diamondsuit$"}, // black diamond suit, U+2666 ISOpub
+ {"34", "quot", "\""}, // quotation mark = APL quote,
+ // U+0022 ISOnum
+ {"38", "amp", "\\&"}, // ampersand, U+0026 ISOnum
+ {"60", "lt", "$<$"}, // less-than sign, U+003C ISOnum
+ {"62", "gt", "$>$"}, // greater-than sign, U+003E ISOnum
+
+
+ /* General Punctuation */
+ {"8194", "ensp", "\\hspace{0.5em}"}, // en space, U+2002 ISOpub
+ {"8195", "emsp", "\\hspace{1em}"}, // em space, U+2003 ISOpub
+ {"8201", "thinsp", "\\hspace{0.167em}"}, // thin space, U+2009 ISOpub
+ {"8202", "", "\\hspace{0.1em}"}, // hair space, U+2010 ISOpub
+ {"8204", "zwnj", "\\/{}"}, // zero width non-joiner,
+ // U+200C NEW RFC 2070
+ {"8205", "zwj", ""}, // zero width joiner, U+200D NEW RFC 2070
+ {"8206", "lrm", ""}, // left-to-right mark, U+200E NEW RFC 2070
+ {"8207", "rlm", ""}, // right-to-left mark, U+200F NEW RFC 2070
+ {"8211", "ndash", "--"}, // en dash, U+2013 ISOpub
+ {"8212", "mdash", "---"}, // em dash, U+2014 ISOpub
+ {"8216", "lsquo", "{\\textquoteleft}"}, // left single quotation mark,
+ // U+2018 ISOnum
+ {"8217", "rsquo", "{\\textquoteright}"}, // right single quotation mark,
+ // U+2019 ISOnum
+ {"8218", "sbquo", "{\\quotesinglbase}"}, // single low-9 quotation mark, U+201A NEW
+ {"8220", "ldquo", "{\\textquotedblleft}"}, // left double quotation mark,
+ // U+201C ISOnum
+ {"8221", "rdquo", "{\\textquotedblright}"}, // right double quotation mark,
+ // U+201D ISOnum
+ {"8222", "bdquo", "{\\quotedblbase}"}, // double low-9 quotation mark, U+201E NEW
+ {"8224", "dagger", "{\\dag}"}, // dagger, U+2020 ISOpub
+ {"8225", "Dagger", "{\\ddag}"}, // double dagger, U+2021 ISOpub
+ {"8240", "permil", "{\\textperthousand}"}, // per mille sign, U+2030 ISOtech
+ {"8249", "lsaquo", "{\\guilsinglleft}"}, // single left-pointing angle quotation mark,
+ // U+2039 ISO proposed
+ /* lsaquo is proposed but not yet ISO standardized */
+ {"8250", "rsaquo", "{\\guilsinglright}"}, // single right-pointing angle quotation mark,
+ // U+203A ISO proposed
+ /* rsaquo is proposed but not yet ISO standardized */
+ {"8364", "euro", "{\\texteuro}"}, // euro sign, U+20AC NEW
+
+ /* Manually added */
+ {"35", "", "\\#"}, // Hash
+ {"36", "dollar", "\\$"}, // Dollar
+ {"37", "percnt", "\\%"}, // Percent
+ {"39", "apos", "'"}, // Apostrophe
+ {"40", "lpar", "("}, // Left bracket
+ {"41", "rpar", ")"}, // Right bracket
+ {"42", "", "*"}, // Asterisk
+ {"43", "plus", "+"}, // Plus
+ {"44", "comma", ","}, // Comma
+ {"45", "hyphen", "-"}, // Hyphen
+ {"46", "period", "."}, // Period
+ {"47", "slash", "/"}, // Slash (solidus)
+ {"58", "colon", ":"}, // Colon
+ {"59", "semi", ";"}, // Semi colon
+ {"61", "equals", "="}, // Equals to
+ {"91", "lsqb", "["}, // Left square bracket
+ {"92", "bsol", "{\\textbackslash}"}, // Backslash
+ {"93", "rsqb", "]"}, // Right square bracket
+ {"94", "Hat", "{\\^{}}"}, // Circumflex
+ {"95", "lowbar", "\\_"}, // Underscore
+ {"96", "grave", "{\\`{}}"}, // Grave
+ {"123", "lbrace", "\\{"}, // Left curly bracket
+ {"", "lcub", "\\{"}, // Left curly bracket
+ {"124", "vert", "|"}, // Vertical bar
+ {"", "verbar", "|"}, // Vertical bar
+ {"", "VerticalLine", "|"}, // Vertical bar
+ {"125", "rbrace", "\\}"}, // Right curly bracket
+ {"", "rcub", "\\}"}, // Right curly bracket
+ // {"138", "", "{{\\v{S}}}"}, // Line tabulation set
+ // {"141", "", ""}, // Reverse line feed
+ {"145", "", "`"}, // Apostrophe
+ {"146", "", "'"}, // Apostrophe
+ {"147", "", "``"}, // Quotation mark
+ {"148", "", "''"}, // Quotation mark
+ {"150", "", "--"}, // En dash
+ // {"154", "", "{\\v{s}}"}, // Single character introducer
+ {"256", "", "{{\\={A}}}"}, // capital A with macron
+ {"257", "", "{\\={a}}"}, // small a with macron
+ {"258", "", "{{\\u{A}}}"}, // capital A with breve
+ {"259", "", "{\\u{a}}"}, // small a with breve
+ {"260", "Aogon", "{{\\k{A}}}"}, // capital A with ogonek
+ {"261", "aogon", "{\\k{a}}"}, // small a with ogonek
+ {"262", "Cacute", "{{\\'{C}}}"}, // capital C with acute
+ {"263", "cacute", "{\\'{c}}"}, // small C with acute
+ {"264", "Ccirc", "{{\\^{C}}}"}, // capital C with circumflex
+ {"265", "ccirc", "{\\^{c}}"}, // small C with circumflex
+ {"266", "Cdot", "{{\\.{C}}}"}, // capital C with dot above
+ {"267", "cdot", "{\\.{c}}"}, // small C with dot above
+ {"268", "Ccaron", "{{\\v{C}}}"}, // capital C with caron
+ {"269", "ccaron", "{\\v{c}}"}, // small C with caron
+ {"270", "", "{{\\v{D}}}"}, // capital D with caron
+ {"271", "", "{\\v{d}}"}, // small d with caron
+ {"272", "Dstrok", "{{\\DJ}}"}, // capital D with stroke
+ {"273", "dstrok", "{{\\dj}}"}, // small d with stroke
+ {"274", "", "{{\\={E}}}"}, // capital E with macron
+ {"275", "", "{\\={e}}"}, // small e with macron
+ {"276", "", "{{\\u{E}}}"}, // capital E with breve
+ {"277", "", "{\\u{e}}"}, // small e with breve
+ {"278", "", "{{\\.{E}}}"}, // capital E with dot above
+ {"279", "", "{\\.{e}}"}, // small e with dot above
+ {"280", "Eogon", "{{\\k{E}}}"}, // capital E with ogonek
+ {"281", "eogon", "{\\k{e}}"}, // small e with ogonek
+ {"282", "", "{{\\v{E}}}"}, // capital E with caron
+ {"283", "", "{\\v{e}}"}, // small e with caron
+ {"284", "", "{{\\^{G}}}"}, // capital G with circumflex
+ {"285", "", "{\\^{g}}"}, // small g with circumflex
+ {"286", "", "{{\\u{G}}}"}, // capital G with breve
+ {"287", "", "{\\u{g}}"}, // small g with breve
+ {"288", "", "{{\\.{G}}}"}, // capital G with dot above
+ {"289", "", "{\\.{g}}"}, // small g with dot above
+ {"290", "", "{{\\c{G}}}"}, // capital G with cedilla
+ {"291", "", "{\\c{g}}"}, // small g with cedilla
+ {"292", "", "{{\\^{H}}}"}, // capital H with circumflex
+ {"293", "", "{\\^{h}}"}, // small h with circumflex
+ {"294", "", "{{\\B{H}}}"}, // capital H with stroke
+ {"295", "", "{\\B{h}}"}, // small h with stroke
+ {"296", "", "{{\\~{I}}}"}, // capital I with tilde
+ {"297", "", "{\\~{\\i}}"}, // small i with tilde
+ {"298", "Imacr", "{{\\={I}}}"}, // capital I with macron
+ {"299", "imacr", "{\\={\\i}}"}, // small i with macron
+ {"300", "", "{{\\u{I}}}"}, // capital I with breve
+ {"301", "", "{\\u{\\i}}"}, // small i with breve
+ {"302", "Iogon", "{{\\k{I}}}"}, // capital I with ogonek
+ {"303", "iogon", "{\\k{i}}"}, // small i with ogonek
+ {"304", "Idot", "{{\\.{I}}}"}, // capital I with dot above
+ {"305", "inodot", "{\\i}"}, // Small i without the dot
+ {"", "imath", "{\\i}"}, // Small i without the dot
+ {"306", "", "{{\\IJ}}"}, // Dutch di-graph IJ
+ {"307", "", "{{\\ij}}"}, // Dutch di-graph ij
+ {"308", "", "{{\\^{J}}}"}, // capital J with circumflex
+ {"309", "", "{\\^{\\j}}"}, // small j with circumflex
+ {"310", "", "{{\\c{K}}}"}, // capital K with cedilla
+ {"311", "", "{\\c{k}}"}, // small k with cedilla
+ {"312", "", "{\\textkra}"}, // Letter kra
+ {"313", "", "{{\\'{L}}}"}, // capital L with acute
+ {"314", "", "{\\'{l}}"}, // small l with acute
+ {"315", "", "{{\\c{L}}}"}, // capital L with cedilla
+ {"316", "", "{\\c{l}}"}, // small l with cedilla
+ {"317", "", "{{\\v{L}}}"}, // capital L with caron
+ {"318", "", "{\\v{l}}"}, // small l with caron
+ //{"319", "Lmidot", "{\\Lmidot}"}, // upper case L with mid dot
+ //{"320", "lmidot", "{\\lmidot}"}, // lower case l with mid dot
+ {"321", "Lstrok", "{{\\L}}"}, // upper case L with stroke
+ {"322", "lstrok", "{{\\l}}"}, // lower case l with stroke
+ {"323", "Nacute", "{{\\'{N}}}"}, // upper case N with acute
+ {"324", "nacute", "{{\\'{n}}}"}, // lower case n with acute
+ {"325", "", "{{\\c{N}}}"}, // capital N with cedilla
+ {"326", "", "{\\c{n}}"}, // small n with cedilla
+ {"327", "", "{{\\v{N}}}"}, // capital N with caron
+ {"328", "", "{\\v{n}}"}, // small n with caron
+ {"329", "", "{'n}"}, // small n preceded with apostroph
+ {"330", "", "{{\\NG}}"}, // upper case letter Eng
+ {"331", "", "{{\\ng}}"}, // lower case letter Eng
+ {"332", "Omacro", "{{\\={O}}}"}, // the capital letter O with macron
+ {"333", "omacro", "{\\={o}}"}, // the small letter o with macron
+ {"334", "", "{{\\u{O}}}"}, // the capital letter O with breve
+ {"335", "", "{\\u{o}}"}, // the small letter o with breve
+ {"336", "", "{{\\H{O}}}"}, // the capital letter O with double acute
+ {"337", "", "{\\H{o}}"}, // the small letter o with double acute
+ {"338", "OElig", "{{\\OE}}"}, // OE-ligature
+ {"339", "oelig", "{{\\oe}}"}, // oe-ligature
+ {"340", "", "{{\\'{R}}}"}, // upper case R with acute
+ {"341", "", "{{\\'{r}}}"}, // lower case r with acute
+ {"342", "", "{{\\c{R}}}"}, // upper case R with cedilla
+ {"343", "", "{{\\c{r}}}"}, // lower case r with cedilla
+ {"344", "", "{{\\v{R}}}"}, // upper case R with caron
+ {"345", "", "{{\\v{r}}}"}, // lower case r with caron
+ {"346", "", "{{\\'{S}}}"}, // upper case S with acute
+ {"347", "", "{{\\'{s}}}"}, // lower case s with acute
+ {"348", "Scirc", "{{\\^{S}}}"}, // upper case S with circumflex
+ {"349", "scirc", "{\\^{s}}"}, // lower case s with circumflex
+ {"350", "Scedil", "{{\\c{S}}}"}, // upper case S with cedilla
+ {"351", "scedil", "{\\c{s}}"}, // lower case s with cedilla
+ {"352", "Scaron", "{{\\v{S}}}"}, // latin capital letter S with caron,
+ {"353", "scaron", "{\\v{s}}"}, // latin small letter s with caron,
+ {"354", "", "{{\\c{T}}}"}, // upper case T with cedilla
+ {"355", "", "{{\\c{T}}}"}, // lower case t with cedilla
+ {"356", "", "{{\\v{T}}}"}, // latin capital letter T with caron,
+ {"357", "", "{\\v{t}}"}, // latin small letter t with caron,
+ {"358", "", "{{\\B{T}}}"}, // latin capital letter T with stroke,
+ {"359", "", "{\\B{t}}"}, // latin small letter t with stroke,
+ {"360", "", "{{\\~{U}}}"}, // capital U with tilde
+ {"361", "", "{\\~{u}}"}, // small u with tilde
+ {"362", "", "{{\\={U}}}"}, // capital U with macron
+ {"363", "", "{\\={u}}"}, // small u with macron
+ {"364", "", "{{\\u{U}}}"}, // capital U with breve
+ {"365", "", "{\\u{u}}"}, // small u with breve
+ {"366", "", "{{\\r{U}}}"}, // capital U with ring
+ {"367", "", "{\\r{u}}"}, // small u with ring
+ {"368", "", "{{\\={U}}}"}, // capital U with double acute
+ {"369", "", "{\\={u}}"}, // small u with double acute
+ {"370", "Uogon", "{{\\k{U}}}"}, // capital U with ogonek
+ {"371", "uogon", "{\\k{u}}"}, // small u with ogonek
+ {"372", "", "{{\\^{W}}}"}, // capital W with circumflex
+ {"373", "", "{\\^{w}}"}, // small w with circumflex
+ {"374", "", "{{\\^{Y}}}"}, // capital Y with circumflex
+ {"375", "", "{\\^{y}}"}, // small y with circumflex
+ {"376", "Yuml", "{{\\\"{Y}}}"}, // latin capital letter Y with diaeresis,
+ {"377", "", "{{\\'{Z}}}"}, // capital Z with acute
+ {"378", "", "{\\'{z}}"}, // small z with acute
+ {"379", "", "{{\\.{Z}}}"}, // capital Z with dot above
+ {"380", "", "{\\.{z}}"}, // small z with dot above
+ {"381", "Zcaron", "{{\\v{Z}}}"}, // capital Z with caron
+ {"382", "zcaron", "{\\v{z}}"}, // small z with caron
+ // {"383", "", ""}, // long s
+ {"384", "", "{\\B{b}}"}, // small b with stroke
+
+ {"402", "fnof", "\\textit{f}"}, // latin small f with hook = function
+
+ {"405", "", "{{\\hv}}"}, // small letter Hv
+
+ {"416", "", "{{\\OHORN}}"}, // capital O with horn
+ {"417", "", "{{\\ohorn}}"}, // small o with horn
+
+ {"431", "", "{{\\UHORN}}"}, // capital U with horn
+ {"432", "", "{{\\uhorn}}"}, // small u with horn
+
+ {"490", "Oogon", "{{\\k{O}}}"}, // capital letter O with ogonek
+ {"491", "oogon", "{\\k{o}}"}, // small letter o with ogonek
+ {"492", "", "{{\\k{\\={O}}}}"}, // capital letter O with ogonek and macron
+ {"493", "", "{\\k{\\={o}}}"}, // small letter o with ogonek and macron
+
+ {"536", "", "{{\\cb{S}}}"}, // capital letter S with comma below, require combelow
+ {"537", "", "{\\cb{s}}"}, // small letter S with comma below, require combelow
+ {"538", "", "{{\\cb{T}}}"}, // capital letter T with comma below, require combelow
+ {"539", "", "{\\cb{t}}"}, // small letter T with comma below, require combelow
+ {"710", "circ", "{\\^{}}"}, // modifier letter circumflex accent,
+ {"726", "", "+"}, // Modifier plus sign
+ {"727", "", "-"}, // Modifier minus sign
+ {"728", "breve", "{\\u{}}"}, // Breve
+ {"", "Breve", "{\\u{}}"}, // Breve
+ {"729", "dot", "{\\.{}}"}, // Dot above
+ {"730", "ring", "{\\r{}}"}, // Ring above
+ {"731", "ogon", "{\\k{}}"}, // Ogonek
+ {"732", "tilde", "\\~{}"}, // Small tilde
+ {"733", "dblac", "{{\\H{}}}"}, // Double acute
+ {"949", "epsi", "$\\epsilon$"}, // Epsilon - double check
+ {"1013", "epsiv", "$\\varepsilonup$"}, // lunate epsilon, requires txfonts
+ //{"1055", "", "{{\\cyrchar\\CYRP}}"}, // Cyrillic capital Pe
+ //{"1082", "", "{\\cyrchar\\cyrk}"}, // Cyrillic small Ka
+ // {"2013", "", ""}, // NKO letter FA -- Maybe en dash = 0x2013?
+ // {"2014", "", ""}, // NKO letter FA -- Maybe em dash = 0x2014?
+ {"8192", "", "\\hspace{0.5em}"}, // en quad
+ {"8193", "", "\\hspace{1em}"}, // em quad
+ {"8196", "", "\\hspace{0.333em}"}, // Three-Per-Em Space
+ {"8197", "", "\\hspace{0.25em}"}, // Four-Per-Em Space
+ {"8198", "", "\\hspace{0.167em}"}, // Six-Per-Em Space
+ {"8208", "hyphen", "-"}, // Hyphen
+ {"8229", "nldr", "\\.{}\\.{}"}, // Double dots - en leader
+ {"8241", "", "{\\textpertenthousand}"}, // per ten thousands sign
+ {"8244", "", "{$\\prime\\prime\\prime$}"}, // triple prime
+ {"8251", "", "{\\textreferencemark}"}, {"8253", "", "{\\textinterrobang}"},
+ {"8320", "", "$_{0}$"}, // sub-script 0
+ {"8321", "", "$_{1}$"}, // sub-script 1
+ {"8322", "", "$_{2}$"}, // sub-script 2
+ {"8323", "", "$_{3}$"}, // sub-script 3
+ {"8324", "", "$_{4}$"}, // sub-script 4
+ {"8325", "", "$_{5}$"}, // sub-script 5
+ {"8326", "", "$_{6}$"}, // sub-script 6
+ {"8327", "", "$_{7}$"}, // sub-script 7
+ {"8328", "", "$_{8}$"}, // sub-script 8
+ {"8329", "", "$_{9}$"}, // sub-script 9
+ {"8330", "", "$_{+}$"}, // sub-script +
+ {"8331", "", "$_{-}$"}, // sub-script -
+ {"8332", "", "$_{-}$"}, // sub-script =
+ {"8333", "", "$_{(}$"}, // sub-script (
+ {"8334", "", "$_{)}$"}, // sub-script )
+ {"8450", "complexes", "$\\mathbb{C}$"}, // double struck capital C -- requires e.g. amsfonts
+ {"8451", "", "{\\textcelsius}"}, // Degree Celsius
+ {"8459", "Hscr", "{{$\\mathcal{H}$}}"}, // script capital H -- possibly use \mathscr
+ {"8460", "Hfr", "{{$\\mathbb{H}$}}"}, // black letter capital H -- requires e.g. amsfonts
+ {"8466", "Lscr", "{{$\\mathcal{L}$}}"}, // script capital L -- possibly use \mathscr
+ {"8467", "ell", "{$\\ell$}"}, // script small l
+ {"8469", "naturals", "{{$\\mathbb{N}$}}"}, // double struck capital N -- requires e.g. amsfonts
+ {"8474", "Qopf", "{{$\\mathbb{Q}$}}"}, // double struck capital Q -- requires e.g. amsfonts
+ {"8477", "reals", "{{$\\mathbb{R}$}}"}, // double struck capital R -- requires e.g. amsfonts
+ {"8486", "", "${{\\Omega}}$"}, // Omega
+ {"8491", "angst", "{{\\AA}}"}, // Angstrom
+ {"8496", "Escr", "{{$\\mathcal{E}$}}"}, // script capital E
+ {"8531", "frac13", "$\\sfrac{1}{3}$"}, // Vulgar fraction one third
+ {"8532", "frac23", "$\\sfrac{2}{3}$"}, // Vulgar fraction two thirds
+ {"8533", "frac15", "$\\sfrac{1}{5}$"}, // Vulgar fraction one fifth
+ {"8534", "frac25", "$\\sfrac{2}{5}$"}, // Vulgar fraction two fifths
+ {"8535", "frac35", "$\\sfrac{3}{5}$"}, // Vulgar fraction three fifths
+ {"8536", "frac45", "$\\sfrac{4}{5}$"}, // Vulgar fraction four fifths
+ {"8537", "frac16", "$\\sfrac{1}{6}$"}, // Vulgar fraction one sixth
+ {"8538", "frac56", "$\\sfrac{5}{6}$"}, // Vulgar fraction five sixths
+ {"8539", "frac18", "$\\sfrac{1}{8}$"}, // Vulgar fraction one eighth
+ {"8540", "frac38", "$\\sfrac{3}{8}$"}, // Vulgar fraction three eighths
+ {"8541", "frac58", "$\\sfrac{5}{8}$"}, // Vulgar fraction five eighths
+ {"8542", "frac78", "$\\sfrac{7}{8}$"}, // Vulgar fraction seven eighths
+ {"8710", "", "$\\triangle$"}, // Increment - could use a more appropriate symbol
+ {"8714", "", "$\\in$"}, // Small element in
+ {"8723", "mp", "$\\mp$"}, // Minus-plus
+ {"8729", "bullet", "$\\bullet$"}, // Bullet operator
+ {"8741", "", "$\\parallel$"}, // Parallel to
+ {"8758", "ratio", ":"}, // Colon/ratio
+ {"8771", "sime", "$\\simeq$"}, // almost equal to = asymptotic to,
+ {"8776", "ap", "$\\approx$"}, // almost equal to = asymptotic to,
+ {"8810", "ll", "$\\ll$"}, // Much less than
+ {"", "Lt", "$\\ll$"}, // Much less than
+ {"8811", "gg", "$\\gg$"}, // Much greater than
+ {"", "Gt", "$\\gg$"}, // Much greater than
+ {"8818", "lsim", "$\\lesssim$"}, // Less than or equivalent to
+ {"8819", "gsim", "$\\gtrsim$"}, // Greater than or equivalent to
+ {"8862", "boxplus", "$\\boxplus$"}, // Boxed plus -- requires amssymb
+ {"8863", "boxminus", "$\\boxminus$"}, // Boxed minus -- requires amssymb
+ {"8864", "boxtimes", "$\\boxtimes$"}, // Boxed times -- requires amssymb
+ {"8882", "vltri", "$\\triangleleft$"}, // Left triangle
+ {"8883", "vrtri", "$\\triangleright$"}, // Right triangle
+ {"8896", "xwedge", "$\\bigwedge$"}, // Big wedge
+ {"8897", "xvee", "$\\bigvee$"}, // Big vee
+ {"8942", "vdots", "$\\vdots$"}, // vertical ellipsis U+22EE
+ {"8943", "cdots", "$\\cdots$"}, // midline horizontal ellipsis U+22EF
+ /*{"8944", "", "$\\ddots$"}, // up right diagonal ellipsis U+22F0 */
+ {"8945", "ddots", "$\\ddots$"}, // down right diagonal ellipsis U+22F1
+
+ {"9426", "circledc", "{\\copyright}"}, // circled small letter C
+ {"9633", "square", "$\\square$"}, // White square
+ {"9651", "xutri", "$\\bigtriangleup$"}, // White up-pointing big triangle
+ {"9653", "utri", "$\\triangle$"}, // White up-pointing small triangle -- \vartriangle probably
+ // better but requires amssymb
+ {"10877", "les", "$\\leqslant$"}, // Less than slanted equal -- requires amssymb
+ {"10878", "ges", "$\\geqslant$"}, // Less than slanted equal -- requires amssymb
+ {"64256", "", "ff"}, // ff ligature (which LaTeX solves by itself)
+ {"64257", "", "fi"}, // fi ligature (which LaTeX solves by itself)
+ {"64258", "", "fl"}, // fl ligature (which LaTeX solves by itself)
+ {"64259", "", "ffi"}, // ffi ligature (which LaTeX solves by itself)
+ {"64260", "", "ffl"}, // ffl ligature (which LaTeX solves by itself)
+ {"119978", "Oscr", "$\\mathcal{O}$"}, // script capital O -- possibly use \mathscr
+ {"119984", "Uscr", "$\\mathcal{U}$"} // script capital U -- possibly use \mathscr
+
+ };
+ // List of combining accents
+ private static final String[][] ACCENT_LIST = new String[][] {{"768", "`"}, // Grave
+ {"769", "'"}, // Acute
+ {"770", "^"}, // Circumflex
+ {"771", "~"}, // Tilde
+ {"772", "="}, // Macron
+ {"773", "="}, // Overline - not completely correct
+ {"774", "u"}, // Breve
+ {"775", "."}, // Dot above
+ {"776", "\""}, // Diaeresis
+ {"777", "h"}, // Hook above
+ {"778", "r"}, // Ring
+ {"779", "H"}, // Double acute
+ {"780", "v"}, // Caron
+ {"781", "|"}, // Vertical line above
+ {"782", "U"}, // Double vertical line above
+ {"783", "G"}, // Double grave
+ {"784", "textdotbreve"}, // Candrabindu
+ {"785", "t"}, // Inverted breve
+ // {"786", ""}, // Turned comma above
+ // {"787", ""}, // Comma above
+ {"788", "textrevcommaabove"}, // Reversed comma above
+ {"789", "textcommaabover"}, // Comma above right
+ {"790", "textsubgrave"}, // Grave accent below -requires tipa
+ {"791", "textsubacute"}, // Acute accent below - requires tipa
+ {"792", "textadvancing"}, // Left tack below - requires tipa
+ {"793", "textretracting"}, // Right tack below - requires tipa
+ {"794", "textlangleabove"}, // Left angle above
+ {"795", "textrighthorn"}, // Horn
+ {"796", "textsublhalfring"}, // Left half ring below - requires tipa
+ {"797", "textraising"}, // Up tack below - requires tipa
+ {"798", "textlowering"}, // Down tack below - requires tipa
+ {"799", "textsubplus"}, // Plus sign below - requires tipa
+ {"800", "textsubbar"}, // Minus sign below
+ {"801", "textpalhookbelow"}, // Palatalized hook below
+ {"802", "M"}, // Retroflex hook below - textrethookbelow?
+ {"803", "d"}, // Dot below
+ {"804", "textsubumlaut"}, // Diaeresis below - requires tipa
+ {"805", "textsubring"}, // Ring below - requires tipa
+ {"806", "cb"}, // Comma below - requires combelow
+ {"807", "c"}, // Cedilla
+ {"808", "k"}, // Ogonek
+ {"809", "textsyllabic"}, // Vertical line below - requires tipa
+ {"810", "textsubbridge"}, // Bridge below - requires tipa
+ {"811", "textsubw"}, // Inverted double arch below - requires tipa
+ {"812", "textsubwedge"}, // Caron below
+ {"813", "textsubcircum"}, // Circumflex accent below - requires tipa
+ {"814", "textsubbreve"}, // Breve below
+ {"815", "textsubarch"}, // Inverted breve below - requires tipa
+ {"816", "textsubtilde"}, // Tilde below - requires tipa
+ {"817", "b"}, // Macron below - not completely correct
+ {"818", "b"}, // Underline
+ {"819", "subdoublebar"}, // Double low line -- requires extraipa
+ {"820", "textsuperimposetilde"}, // Tilde overlay - requires tipa
+ {"821", "B"}, // Short stroke overlay - textsstrokethru?
+ {"822", "textlstrokethru"}, // Long stroke overlay
+ {"823", "textsstrikethru"}, // Short solidus overlay
+ {"824", "textlstrikethru"}, // Long solidus overlay
+ {"825", "textsubrhalfring"}, // Right half ring below - requires tipa
+ {"826", "textinvsubbridge"}, // inverted bridge below - requires tipa
+ {"827", "textsubsquare"}, // Square below - requires tipa
+ {"828", "textseagull"}, // Seagull below - requires tipa
+ {"829", "textovercross"}, // X above - requires tipa
+ // {"830", ""}, // Vertical tilde
+ // {"831", ""}, // Double overline
+ // {"832", ""}, // Grave tone mark
+ // {"833", ""}, // Acute tone mark
+ // {"834", ""}, // Greek perispomeni
+ // {"835", ""}, // Greek koronis
+ // {"836", ""}, // Greek dialytika tonos
+ // {"837", ""}, // Greek ypogegrammeni
+ {"838", "overbridge"}, // Bridge above - requires extraipa
+ {"839", "subdoublebar"}, // Equals sign below - requires extraipa
+ {"840", "subdoublevert"}, // Double vertical line below - requires extraipa
+ {"841", "subcorner"}, // Left angle below - requires extraipa
+ {"842", "crtilde"}, // Not tilde above - requires extraipa
+ {"843", "dottedtilde"}, // Homothetic above - requires extraipa
+ {"844", "doubletilde"}, // Almost equal to above - requires extraipa
+ {"845", "spreadlips"}, // Left right arrow below - requires extraipa
+ {"846", "whistle"}, // Upwards arrow below - requires extraipa
+ {"861", "textdoublebreve"}, // Double breve
+ {"862", "textdoublemacron"}, // Double macron
+ {"863", "textdoublemacronbelow"}, // Double macron below
+ {"864", "textdoubletilde"}, // Double tilde
+ {"865", "texttoptiebar"}, // Double inverted breve
+ {"866", "sliding"}, // Double rightwards arrow below - requires extraipa
+ };
+
+ public static final Map<String, String> HTML_LATEX_CONVERSION_MAP = new HashMap<>();
+ public static final Map<Integer, String> ESCAPED_ACCENTS = new HashMap<>();
+ public static final Map<String, String> UNICODE_ESCAPED_ACCENTS = new HashMap<>();
+ public static final Map<Integer, String> NUMERICAL_LATEX_CONVERSION_MAP = new HashMap<>();
+ public static final Map<String, String> UNICODE_LATEX_CONVERSION_MAP = new HashMap<>();
+ public static final Map<String, String> LATEX_HTML_CONVERSION_MAP = new HashMap<>();
+ public static final Map<String, String> LATEX_UNICODE_CONVERSION_MAP = new HashMap<>();
+
+
+ static {
+ for (String[] aConversionList : CONVERSION_LIST) {
+ if (!(aConversionList[2].isEmpty())) {
+ String strippedLaTeX = cleanLaTeX(aConversionList[2]);
+ if (!(aConversionList[1].isEmpty())) {
+ HTML_LATEX_CONVERSION_MAP.put("&" + aConversionList[1] + ";", aConversionList[2]);
+ if (!strippedLaTeX.isEmpty()) {
+ LATEX_HTML_CONVERSION_MAP.put(strippedLaTeX, "&" + aConversionList[1] + ";");
+ }
+ } else if (!(aConversionList[0].isEmpty()) && !strippedLaTeX.isEmpty()) {
+ LATEX_HTML_CONVERSION_MAP.put(strippedLaTeX, "&#" + aConversionList[0] + ";");
+ }
+ if (!(aConversionList[0].isEmpty())) {
+ NUMERICAL_LATEX_CONVERSION_MAP.put(Integer.decode(aConversionList[0]), aConversionList[2]);
+ if (Integer.decode(aConversionList[0]) > 128) {
+ String unicodeSymbol = String.valueOf(Character.toChars(Integer.decode(aConversionList[0])));
+ UNICODE_LATEX_CONVERSION_MAP.put(unicodeSymbol, aConversionList[2]);
+ if (!strippedLaTeX.isEmpty()) {
+ LATEX_UNICODE_CONVERSION_MAP.put(strippedLaTeX, unicodeSymbol);
+ }
+ }
+ }
+ }
+ }
+ for (String[] anAccentList : ACCENT_LIST) {
+ ESCAPED_ACCENTS.put(Integer.decode(anAccentList[0]), anAccentList[1]);
+ UNICODE_ESCAPED_ACCENTS.put(anAccentList[1],
+ String.valueOf(Character.toChars(Integer.decode(anAccentList[0]))));
+ }
+ // Manually added values which are killed by cleanLaTeX
+ LATEX_HTML_CONVERSION_MAP.put("$", "$");
+ LATEX_UNICODE_CONVERSION_MAP.put("$", "$");
+
+ // Manual corrections
+ LATEX_HTML_CONVERSION_MAP.put("AA", "Å"); // Overwritten by Å which is less supported
+ LATEX_UNICODE_CONVERSION_MAP.put("AA", "Å"); // Overwritten by Ångstrom symbol
+
+ // Manual additions
+ // Support relax to the extent that it is simply removed
+ LATEX_HTML_CONVERSION_MAP.put("relax", "");
+ LATEX_UNICODE_CONVERSION_MAP.put("relax", "");
+
+ }
+
+ private static String cleanLaTeX(String escapedString) {
+ // Get rid of \{}$ from the LaTeX-string
+ return escapedString.replaceAll("[\\\\\\{\\}\\$]", "");
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/model/strings/LatexToUnicode.java b/src/main/java/net/sf/jabref/model/strings/LatexToUnicode.java
new file mode 100644
index 0000000..a0d5d37
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/strings/LatexToUnicode.java
@@ -0,0 +1,209 @@
+package net.sf.jabref.model.strings;
+
+import java.util.Map;
+import java.util.regex.Pattern;
+
+public class LatexToUnicode {
+
+ private static final Map<String, String> CHARS = HTMLUnicodeConversionMaps.LATEX_UNICODE_CONVERSION_MAP;
+ private static final Map<String, String> ACCENTS = HTMLUnicodeConversionMaps.UNICODE_ESCAPED_ACCENTS;
+
+ private static final Pattern AMP_LATEX = Pattern.compile("&|\\\\&");
+ private static final Pattern P_LATEX = Pattern.compile("[\\n]{1,}");
+ private static final Pattern DOLLAR_LATEX = Pattern.compile("\\\\\\$");
+ private static final Pattern DOLLARS_LATEX = Pattern.compile("\\$([^\\$]*)\\$");
+
+ private static final Pattern AMP = Pattern.compile("\\&");
+ private static final Pattern P = Pattern.compile("<p>");
+ private static final Pattern DOLLAR = Pattern.compile("\\$");
+ private static final Pattern TILDE = Pattern.compile("~");
+
+ public String format(String inField) {
+ if (inField.isEmpty()) {
+ return "";
+ }
+ int i;
+ // TODO: document what does this do
+ String field = AMP_LATEX.matcher(inField).replaceAll("&");
+ field = P_LATEX.matcher(field).replaceAll("<p>");
+ field = DOLLAR_LATEX.matcher(field).replaceAll("$");
+ field = DOLLARS_LATEX.matcher(field).replaceAll("\\{$1\\}");
+
+ StringBuilder sb = new StringBuilder();
+ StringBuilder currentCommand = null;
+
+ char c;
+ boolean escaped = false;
+ boolean incommand = false;
+
+ for (i = 0; i < field.length(); i++) {
+ c = field.charAt(i);
+ if (escaped && (c == '\\')) {
+ sb.append('\\');
+ escaped = false;
+ } else if (c == '\\') {
+ if (incommand) {
+ /* Close Command */
+ String command = currentCommand.toString();
+ String result = CHARS.get(command);
+ if (result == null) {
+ sb.append(command);
+ } else {
+ sb.append(result);
+ }
+
+ }
+ escaped = true;
+ incommand = true;
+ currentCommand = new StringBuilder();
+ } else if (!incommand && ((c == '{') || (c == '}'))) {
+ // Swallow the brace.
+ } else if (Character.isLetter(c) || (c == '%')
+ || StringUtil.SPECIAL_COMMAND_CHARS.contains(String.valueOf(c))) {
+ escaped = false;
+
+ if (!incommand) {
+ sb.append(c);
+ } else {
+ currentCommand.append(c);
+ if ((currentCommand.length() == 1)
+ && StringUtil.SPECIAL_COMMAND_CHARS.contains(currentCommand.toString())
+ && !(i >= (field.length() - 1))) {
+ // This indicates that we are in a command of the type
+ // \^o or \~{n}
+
+ String command = currentCommand.toString();
+ i++;
+ c = field.charAt(i);
+ String commandBody;
+ if (c == '{') {
+ String part = StringUtil.getPart(field, i, false);
+ i += part.length();
+ commandBody = part;
+ } else {
+ commandBody = field.substring(i, i + 1);
+ }
+ String result = CHARS.get(command + commandBody);
+
+ if (result == null) {
+ // Use combining accents if argument is single character or empty
+ if (commandBody.length() <= 1) {
+ String accent = ACCENTS.get(command);
+ if (accent == null) {
+ // Shouldn't happen
+ sb.append(commandBody);
+ } else {
+ sb.append(commandBody).append(accent);
+ }
+ }
+ } else {
+ sb.append(result);
+ }
+
+ incommand = false;
+ escaped = false;
+ } else {
+ // Are we already at the end of the string?
+ if ((i + 1) == field.length()) {
+ String command = currentCommand.toString();
+ String result = CHARS.get(command);
+ /* If found, then use translated version. If not,
+ * then keep
+ * the text of the parameter intact.
+ */
+ if (result == null) {
+ sb.append(command);
+ } else {
+ sb.append(result);
+ }
+
+ }
+ }
+ }
+ } else {
+ if (!incommand) {
+ sb.append(c);
+ } else if (Character.isWhitespace(c) || (c == '{') || (c == '}')) {
+ // First test if we are already at the end of the string.
+ // if (i >= field.length()-1)
+ // break testContent;
+
+ String command = currentCommand.toString();
+
+ if (c == '{') {
+ String argument = StringUtil.getPart(field, i, true);
+ i += argument.length();
+ // handle common case of general latex command
+ String result = CHARS.get(command + argument);
+
+ // If found, then use translated version. If not, then keep
+ // the
+ // text of the parameter intact.
+ if (result == null) {
+ // Use combining accents if argument is single character or empty
+ if (argument.length() <= 1) {
+ String accent = ACCENTS.get(command);
+ if (accent == null) {
+ if (argument.isEmpty()) {
+ // Empty argument, may be used as separator as in \LaTeX{}, so keep the command
+ sb.append(command);
+ } else {
+ sb.append(argument);
+ }
+ } else {
+ sb.append(argument).append(accent);
+ }
+ } else {
+ sb.append(argument);
+ }
+ } else {
+ sb.append(result);
+ }
+ } else if (c == '}') {
+ // This end brace terminates a command. This can be the case in
+ // constructs like {\aa}. The correct behaviour should be to
+ // substitute the evaluated command and swallow the brace:
+ String result = CHARS.get(command);
+
+ if (result == null) {
+ // If the command is unknown, just print it:
+ sb.append(command);
+ } else {
+ sb.append(result);
+ }
+
+ } else {
+ String result = CHARS.get(command);
+
+ if (result == null) {
+ sb.append(command);
+ } else {
+ sb.append(result);
+ }
+ sb.append(' ');
+ }
+ } else {
+ /*
+ * TODO: this point is reached, apparently, if a command is
+ * terminated in a strange way, such as with "$\omega$".
+ * Also, the command "\&" causes us to get here. The former
+ * issue is maybe a little difficult to address, since it
+ * involves the LaTeX math mode. We don't have a complete
+ * LaTeX parser, so maybe it's better to ignore these
+ * commands?
+ */
+ }
+
+ incommand = false;
+ escaped = false;
+ }
+ }
+
+ String result = AMP.matcher(sb.toString()).replaceAll("&");
+ result = P.matcher(result).replaceAll("\n");
+ result = DOLLAR.matcher(result).replaceAll("\\$");
+ result = TILDE.matcher(result).replaceAll("\u00A0");
+ return result;
+
+ }
+}
diff --git a/src/main/java/net/sf/jabref/model/strings/StringUtil.java b/src/main/java/net/sf/jabref/model/strings/StringUtil.java
new file mode 100644
index 0000000..0087d24
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/strings/StringUtil.java
@@ -0,0 +1,708 @@
+package net.sf.jabref.model.strings;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.StringTokenizer;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import com.google.common.base.CharMatcher;
+import org.apache.commons.lang3.StringUtils;
+
+public class StringUtil {
+
+ // Non-letters which are used to denote accents in LaTeX-commands, e.g., in {\"{a}}
+ public static final String SPECIAL_COMMAND_CHARS = "\"`^~'=.|";
+ // contains all possible line breaks, not omitting any break such as "\\n"
+ private static final Pattern LINE_BREAKS = Pattern.compile("\\r\\n|\\r|\\n");
+ private static final Pattern BRACED_TITLE_CAPITAL_PATTERN = Pattern.compile("\\{[A-Z]+\\}");
+ private static final UnicodeToReadableCharMap UNICODE_CHAR_MAP = new UnicodeToReadableCharMap();
+
+ public static String booleanToBinaryString(boolean expression) {
+ return expression ? "1" : "0";
+ }
+
+ /**
+ * Quote special characters.
+ *
+ * @param toQuote The String which may contain special characters.
+ * @param specials A String containing all special characters except the quoting
+ * character itself, which is automatically quoted.
+ * @param quoteChar The quoting character.
+ * @return A String with every special character (including the quoting
+ * character itself) quoted.
+ */
+ public static String quote(String toQuote, String specials, char quoteChar) {
+ if (toQuote == null) {
+ return "";
+ }
+
+ StringBuilder result = new StringBuilder();
+ char c;
+ boolean isSpecial;
+ for (int i = 0; i < toQuote.length(); ++i) {
+ c = toQuote.charAt(i);
+
+ isSpecial = (c == quoteChar);
+ // If non-null specials performs logic-or with specials.indexOf(c) >= 0
+ isSpecial |= ((specials != null) && (specials.indexOf(c) >= 0));
+
+ if (isSpecial) {
+ result.append(quoteChar);
+ }
+ result.append(c);
+ }
+ return result.toString();
+ }
+
+ /**
+ * Creates a substring from a text
+ *
+ * @param text
+ * @param startIndex
+ * @param terminateOnEndBraceOnly
+ * @return
+ */
+ public static String getPart(String text, int startIndex, boolean terminateOnEndBraceOnly) {
+ char c;
+ int count = 0;
+
+ StringBuilder part = new StringBuilder();
+
+ // advance to first char and skip whitespace
+ int index = startIndex + 1;
+ while ((index < text.length()) && Character.isWhitespace(text.charAt(index))) {
+ index++;
+ }
+
+ // then grab whatever is the first token (counting braces)
+ while (index < text.length()) {
+ c = text.charAt(index);
+ if (!terminateOnEndBraceOnly && (count == 0) && Character.isWhitespace(c)) {
+ // end argument and leave whitespace for further processing
+ break;
+ }
+ if ((c == '}') && (--count < 0)) {
+ break;
+ } else if (c == '{') {
+ count++;
+ }
+ part.append(c);
+ index++;
+ }
+ return part.toString();
+ }
+
+ /**
+ * Returns the string, after shaving off whitespace at the beginning and end,
+ * and removing (at most) one pair of braces or " surrounding it.
+ *
+ * @param toShave
+ * @return
+ */
+
+ public static String shaveString(String toShave) {
+ if ((toShave == null) || (toShave.isEmpty())) {
+ return "";
+ }
+ String shaved = toShave.trim();
+ if (isInCurlyBrackets(shaved) || isInCitationMarks(shaved)) {
+ return shaved.substring(1, shaved.length() - 1);
+ }
+ return shaved;
+ }
+
+ /**
+ * Concatenate all strings in the array from index 'from' to 'to' (excluding
+ * to) with the given separator.
+ * <p>
+ * Example:
+ * <p>
+ * String[] s = "ab/cd/ed".split("/"); join(s, "\\", 0, s.length) ->
+ * "ab\\cd\\ed"
+ *
+ * @param strings
+ * @param separator
+ * @param from
+ * @param to Excluding strings[to]
+ * @return
+ */
+ public static String join(String[] strings, String separator, int from, int to) {
+ if ((strings.length == 0) || (from >= to)) {
+ return "";
+ }
+
+ int updatedFrom = Math.max(from, 0);
+ int updatedTo = Math.min(strings.length, to);
+
+ StringBuilder stringBuilder = new StringBuilder();
+ for (int i = updatedFrom; i < (updatedTo - 1); i++) {
+ stringBuilder.append(strings[i]).append(separator);
+ }
+ return stringBuilder.append(strings[updatedTo - 1]).toString();
+ }
+
+ /**
+ * Removes optional square brackets from the string s
+ *
+ * @param toStrip
+ * @return
+ */
+ public static String stripBrackets(String toStrip) {
+ if (isInSquareBrackets(toStrip)) {
+ return toStrip.substring(1, toStrip.length() - 1);
+ }
+ return toStrip;
+ }
+
+ /**
+ * extends the filename with a default Extension, if no Extension '.x' could
+ * be found
+ */
+ public static String getCorrectFileName(String orgName, String defaultExtension) {
+ if (orgName == null) {
+ return "";
+ }
+
+
+ if (orgName.toLowerCase().endsWith("." + defaultExtension.toLowerCase())) {
+ return orgName;
+ }
+
+ int hiddenChar = orgName.indexOf('.', 1); // hidden files Linux/Unix (?)
+ if (hiddenChar < 1) {
+ return orgName + "." + defaultExtension;
+ }
+
+ return orgName;
+ }
+
+ /**
+ * Formats field contents for output. Must be "symmetric" with the parse method above,
+ * so stored and reloaded fields are not mangled.
+ *
+ * @param in
+ * @param wrapAmount
+ * @param newline
+ * @return the wrapped String.
+ */
+ public static String wrap(String in, int wrapAmount, String newline) {
+
+ String[] lines = in.split("\n");
+ StringBuilder result = new StringBuilder();
+ // remove all whitespace at the end of the string, this especially includes \r created when the field content has \r\n as line separator
+ addWrappedLine(result, CharMatcher.WHITESPACE.trimTrailingFrom(lines[0]), wrapAmount, newline); // See
+ for (int i = 1; i < lines.length; i++) {
+
+ if (lines[i].trim().isEmpty()) {
+ result.append(newline);
+ result.append('\t');
+ } else {
+ result.append(newline);
+ result.append('\t');
+ result.append(newline);
+ result.append('\t');
+ // remove all whitespace at the end of the string, this especially includes \r created when the field content has \r\n as line separator
+ String line = CharMatcher.WHITESPACE.trimTrailingFrom(lines[i]);
+ addWrappedLine(result, line, wrapAmount, newline);
+ }
+ }
+ return result.toString();
+ }
+
+ private static void addWrappedLine(StringBuilder result, String line, int wrapAmount, String newline) {
+ // Set our pointer to the beginning of the new line in the StringBuffer:
+ int length = result.length();
+ // Add the line, unmodified:
+ result.append(line);
+
+ while (length < result.length()) {
+ int current = result.indexOf(" ", length + wrapAmount);
+ if ((current < 0) || (current >= result.length())) {
+ break;
+ }
+
+ result.deleteCharAt(current);
+ result.insert(current, newline + "\t");
+ length = current + newline.length();
+
+ }
+ }
+
+ /**
+ * Quotes each and every character, e.g. '!' as !. Used for verbatim
+ * display of arbitrary strings that may contain HTML entities.
+ */
+ public static String quoteForHTML(String toQuote) {
+ StringBuilder result = new StringBuilder();
+ for (int i = 0; i < toQuote.length(); ++i) {
+ result.append("&#").append((int) toQuote.charAt(i)).append(';');
+ }
+ return result.toString();
+ }
+
+ /**
+ * Decodes an encoded double String array back into array form. The array
+ * is assumed to be square, and delimited by the characters ';' (first dim) and
+ * ':' (second dim).
+ * @param value The encoded String to be decoded.
+ * @return The decoded String array.
+ */
+ public static String[][] decodeStringDoubleArray(String value) {
+ List<List<String>> newList = new ArrayList<>();
+ StringBuilder sb = new StringBuilder();
+ List<String> thisEntry = new ArrayList<>();
+ boolean escaped = false;
+ for (int i = 0; i < value.length(); i++) {
+ char c = value.charAt(i);
+ if (!escaped && (c == '\\')) {
+ escaped = true;
+ continue;
+ } else if (!escaped && (c == ':')) {
+ thisEntry.add(sb.toString());
+ sb = new StringBuilder();
+ } else if (!escaped && (c == ';')) {
+ thisEntry.add(sb.toString());
+ sb = new StringBuilder();
+ newList.add(thisEntry);
+ thisEntry = new ArrayList<>();
+ } else {
+ sb.append(c);
+ }
+ escaped = false;
+ }
+ if (sb.length() > 0) {
+ thisEntry.add(sb.toString());
+ }
+ if (!thisEntry.isEmpty()) {
+ newList.add(thisEntry);
+ }
+
+ // Convert to String[][]:
+ String[][] res = new String[newList.size()][];
+ for (int i = 0; i < res.length; i++) {
+ res[i] = new String[newList.get(i).size()];
+ for (int j = 0; j < res[i].length; j++) {
+ res[i][j] = newList.get(i).get(j);
+ }
+ }
+ return res;
+ }
+
+ /**
+ * Wrap all uppercase letters, or sequences of uppercase letters, in curly
+ * braces. Ignore letters within a pair of # character, as these are part of
+ * a string label that should not be modified.
+ *
+ * @param s
+ * The string to modify.
+ * @return The resulting string after wrapping capitals.
+ */
+ public static String putBracesAroundCapitals(String s) {
+
+ boolean inString = false;
+ boolean isBracing = false;
+ boolean escaped = false;
+ int inBrace = 0;
+ StringBuilder buf = new StringBuilder();
+ for (int i = 0; i < s.length(); i++) {
+ // Update variables based on special characters:
+ int c = s.charAt(i);
+ if (c == '{') {
+ inBrace++;
+ } else if (c == '}') {
+ inBrace--;
+ } else if (!escaped && (c == '#')) {
+ inString = !inString;
+ }
+
+ // See if we should start bracing:
+ if ((inBrace == 0) && !isBracing && !inString && Character.isLetter((char) c)
+ && Character.isUpperCase((char) c)) {
+
+ buf.append('{');
+ isBracing = true;
+ }
+
+ // See if we should close a brace set:
+ if (isBracing && !(Character.isLetter((char) c) && Character.isUpperCase((char) c))) {
+
+ buf.append('}');
+ isBracing = false;
+ }
+
+ // Add the current character:
+ buf.append((char) c);
+
+ // Check if we are entering an escape sequence:
+ escaped = (c == '\\') && !escaped;
+
+ }
+ // Check if we have an unclosed brace:
+ if (isBracing) {
+ buf.append('}');
+ }
+
+ return buf.toString();
+ }
+
+ /**
+ * This method looks for occurrences of capital letters enclosed in an
+ * arbitrary number of pairs of braces, e.g. "{AB}" or "{{T}}". All of these
+ * pairs of braces are removed.
+ *
+ * @param s
+ * The String to analyze.
+ * @return A new String with braces removed.
+ */
+ public static String removeBracesAroundCapitals(String s) {
+ String current = s;
+ String previous = s;
+ while ((current = removeSingleBracesAroundCapitals(current)).length() < previous.length()) {
+ previous = current;
+ }
+ return current;
+ }
+
+ /**
+ * This method looks for occurrences of capital letters enclosed in one pair
+ * of braces, e.g. "{AB}". All these are replaced by only the capitals in
+ * between the braces.
+ *
+ * @param s
+ * The String to analyze.
+ * @return A new String with braces removed.
+ */
+ private static String removeSingleBracesAroundCapitals(String s) {
+
+ Matcher mcr = BRACED_TITLE_CAPITAL_PATTERN.matcher(s);
+ StringBuffer buf = new StringBuffer();
+ while (mcr.find()) {
+ String replaceStr = mcr.group();
+ mcr.appendReplacement(buf, replaceStr.substring(1, replaceStr.length() - 1));
+ }
+ mcr.appendTail(buf);
+ return buf.toString();
+ }
+
+ /**
+ * Replaces all platform-dependent line breaks by OS.NEWLINE line breaks.
+ *
+ * We do NOT use UNIX line breaks as the user explicitly configures its linebreaks and this method is used in bibtex field writing
+ *
+ * <example>
+ * Legacy Macintosh \r -> OS.NEWLINE
+ * Windows \r\n -> OS.NEWLINE
+ * </example>
+ *
+ * @return a String with only OS.NEWLINE as line breaks
+ */
+ public static String unifyLineBreaks(String s, String newline) {
+ return LINE_BREAKS.matcher(s).replaceAll(newline);
+ }
+
+ /**
+ * Checks if the given String has exactly one pair of surrounding curly braces <br>
+ * Strings with escaped characters in curly braces at the beginning and end are respected, too
+ * @param toCheck The string to check
+ * @return True, if the check was succesful. False otherwise.
+ */
+ public static boolean isInCurlyBrackets(String toCheck) {
+ int count = 0;
+ int brackets = 0;
+ if ((toCheck == null) || toCheck.isEmpty()) {
+ return false;
+ } else {
+ if ((toCheck.charAt(0) == '{') && (toCheck.charAt(toCheck.length() - 1) == '}')) {
+ for (char c : toCheck.toCharArray()) {
+ if (c == '{') {
+ if (brackets == 0) {
+ count++;
+ }
+ brackets++;
+ } else if (c == '}') {
+ brackets--;
+ }
+ }
+
+ return count == 1;
+ }
+ return false;
+ }
+
+ }
+
+ public static boolean isInSquareBrackets(String toCheck) {
+ if ((toCheck == null) || toCheck.isEmpty()) {
+ return false; // In case of null or empty string
+ } else {
+ return (toCheck.charAt(0) == '[') && (toCheck.charAt(toCheck.length() - 1) == ']');
+ }
+ }
+
+ public static boolean isInCitationMarks(String toCheck) {
+ if ((toCheck == null) || (toCheck.length() <= 1)) {
+ return false; // In case of null, empty string, or a single citation mark
+ } else {
+ return (toCheck.charAt(0) == '"') && (toCheck.charAt(toCheck.length() - 1) == '"');
+ }
+ }
+
+ /**
+ * Optimized method for converting a String into an Integer
+ *
+ * From http://stackoverflow.com/questions/1030479/most-efficient-way-of-converting-string-to-integer-in-java
+ *
+ * @param str the String holding an Integer value
+ * @throws NumberFormatException if str cannot be parsed to an int
+ * @return the int value of str
+ */
+ public static int intValueOf(String str) {
+ int idx = 0;
+ int end;
+ boolean sign = false;
+ char ch;
+
+ if ((str == null) || ((end = str.length()) == 0) || ((((ch = str.charAt(0)) < '0') || (ch > '9')) && (!(sign = ch == '-') || (++idx == end) || ((ch = str.charAt(idx)) < '0') || (ch > '9')))) {
+ throw new NumberFormatException(str);
+ }
+
+ int ival = 0;
+ for (;; ival *= 10) {
+ ival += '0' - ch;
+ if (++idx == end) {
+ return sign ? ival : -ival;
+ }
+ if (((ch = str.charAt(idx)) < '0') || (ch > '9')) {
+ throw new NumberFormatException(str);
+ }
+ }
+ }
+
+ /**
+ * Optimized method for converting a String into an Integer
+ *
+ * From http://stackoverflow.com/questions/1030479/most-efficient-way-of-converting-string-to-integer-in-java
+ *
+ * @param str the String holding an Integer value
+ * @return the int value of str or Optional.empty() if not possible
+ */
+ public static Optional<Integer> intValueOfOptional(String str) {
+ int idx = 0;
+ int end;
+ boolean sign = false;
+ char ch;
+
+ if ((str == null) || ((end = str.length()) == 0) || ((((ch = str.charAt(0)) < '0') || (ch > '9')) && (!(sign = ch == '-') || (++idx == end) || ((ch = str.charAt(idx)) < '0') || (ch > '9')))) {
+ return Optional.empty();
+ }
+
+ int ival = 0;
+ for (;; ival *= 10) {
+ ival += '0' - ch;
+ if (++idx == end) {
+ return Optional.of(sign ? ival : -ival);
+ }
+ if (((ch = str.charAt(idx)) < '0') || (ch > '9')) {
+ return Optional.empty();
+ }
+ }
+ }
+
+ /**
+ * This method ensures that the output String has only
+ * valid XML unicode characters as specified by the
+ * XML 1.0 standard. For reference, please see
+ * <a href="http://www.w3.org/TR/2000/REC-xml-20001006#NT-Char">the
+ * standard</a>. This method will return an empty
+ * String if the input is null or empty.
+ * <p>
+ * URL: http://cse-mjmcl.cse.bris.ac.uk/blog/2007/02/14/1171465494443.html
+ *
+ * @param in The String whose non-valid characters we want to remove.
+ * @return The in String, stripped of non-valid characters.
+ */
+ public static String stripNonValidXMLCharacters(String in) {
+ if ((in == null) || in.isEmpty()) {
+ return ""; // vacancy test.
+ }
+ StringBuilder out = new StringBuilder(); // Used to hold the output.
+ char current; // Used to reference the current character.
+
+ for (int i = 0; i < in.length(); i++) {
+ current = in.charAt(i); // NOTE: No IndexOutOfBoundsException caught here; it should not happen.
+ if ((current == 0x9) || (current == 0xA) || (current == 0xD) || ((current >= 0x20) && (current <= 0xD7FF))
+ || ((current >= 0xE000) && (current <= 0xFFFD))) {
+ out.append(current);
+ }
+ }
+ return out.toString();
+ }
+
+ /*
+ * @param buf String to be tokenized
+ * @param delimstr Delimiter string
+ * @return list {@link java.util.List} of <tt>String</tt>
+ */
+ public static List<String> tokenizeToList(String buf, String delimstr) {
+ List<String> list = new ArrayList<>();
+ String buffer = buf + '\n';
+
+ StringTokenizer st = new StringTokenizer(buffer, delimstr);
+
+ while (st.hasMoreTokens()) {
+ list.add(st.nextToken());
+ }
+
+ return list;
+ }
+
+ public static String limitStringLength(String s, int maxLength) {
+ if (s == null) {
+ return "";
+ }
+
+ if (s.length() <= maxLength) {
+ return s;
+ }
+
+ return s.substring(0, maxLength - 3) + "...";
+ }
+
+ /**
+ * Replace non-English characters like umlauts etc. with a sensible letter or letter combination that bibtex can
+ * accept. The basis for replacement is the HashMap UnicodeToReadableCharMap.
+ */
+ public static String replaceSpecialCharacters(String s) {
+ String result = s;
+ for (Map.Entry<String, String> chrAndReplace : UNICODE_CHAR_MAP.entrySet()) {
+ result = result.replace(chrAndReplace.getKey(), chrAndReplace.getValue());
+ }
+ return result;
+ }
+
+ /**
+ * Return a String with n spaces
+ *
+ * @param n Number of spaces
+ * @return String with n spaces
+ */
+ public static String repeatSpaces(int n) {
+ return repeat(n, ' ');
+ }
+
+ /**
+ * Return a String with n copies of the char c
+ *
+ * @param n Number of copies
+ * @param c char to copy
+ * @return String with n copies of c
+ */
+ public static String repeat(int n, char c) {
+ StringBuilder resultSB = new StringBuilder(n);
+
+ for (int i = 0; i < n; i++) {
+ resultSB.append(c);
+ }
+
+ return resultSB.toString();
+
+ }
+
+ public static boolean isNullOrEmpty(String toTest) {
+ return ((toTest == null) || toTest.isEmpty());
+ }
+
+ public static boolean isBlank(String string) {
+ return !isNotBlank(string);
+ }
+
+ public static boolean isBlank(Optional<String> string) {
+ return !isNotBlank(string);
+ }
+
+ public static boolean isNotBlank(String string) {
+ return StringUtils.isNotBlank(string);
+ }
+
+ public static boolean isNotBlank(Optional<String> string) {
+ return string.isPresent() && isNotBlank(string.get());
+ }
+
+ /**
+ * Return string enclosed in HTML bold tags
+ */
+ public static String boldHTML(String input) {
+ return "<b>" + input + "</b>";
+ }
+
+ /**
+ * Return string enclosed in HTML bold tags if not null, otherwise return alternative text in HTML bold tags
+ */
+ public static String boldHTML(String input, String alternative) {
+
+ if (input == null) {
+ return "<b>" + alternative + "</b>";
+ }
+ return "<b>" + input + "</b>";
+ }
+
+ /**
+ * Unquote special characters.
+ *
+ * @param toUnquote The String which may contain quoted special characters.
+ * @param quoteChar The quoting character.
+ * @return A String with all quoted characters unquoted.
+ */
+ public static String unquote(String toUnquote, char quoteChar) {
+ StringBuilder result = new StringBuilder();
+ char c;
+ boolean quoted = false;
+ for (int i = 0; i < toUnquote.length(); ++i) {
+ c = toUnquote.charAt(i);
+ if (quoted) { // append literally...
+ if (c != '\n') {
+ result.append(c);
+ }
+ quoted = false;
+ } else if (c == quoteChar) {
+ // quote char
+ quoted = true;
+ } else {
+ result.append(c);
+ }
+ }
+ return result.toString();
+ }
+ public static String stripAccents(String searchQuery) {
+ return StringUtils.stripAccents(searchQuery);
+ }
+
+ /**
+ * Make first character of String uppercase, and the
+ * rest lowercase.
+ */
+ public static String capitalizeFirst(String toCapitalize) {
+ if (toCapitalize.length() > 1) {
+ return toCapitalize.substring(0, 1).toUpperCase()
+ + toCapitalize.substring(1, toCapitalize.length()).toLowerCase();
+ } else {
+ return toCapitalize.toUpperCase();
+ }
+
+ }
+
+ /**
+ * Returns a list of words contained in the given text.
+ * Whitespace, comma and semicolon are considered as separator between words.
+ *
+ * @param text the input
+ * @return a list of words
+ */
+ public static List<String> getStringAsWords(String text) {
+ return Arrays.asList(text.split("[\\s,;]+"));
+ }
+}
diff --git a/src/main/java/net/sf/jabref/model/strings/UnicodeToReadableCharMap.java b/src/main/java/net/sf/jabref/model/strings/UnicodeToReadableCharMap.java
new file mode 100644
index 0000000..166865d
--- /dev/null
+++ b/src/main/java/net/sf/jabref/model/strings/UnicodeToReadableCharMap.java
@@ -0,0 +1,241 @@
+package net.sf.jabref.model.strings;
+
+import java.util.HashMap;
+
+public class UnicodeToReadableCharMap extends HashMap<String, String> {
+ public UnicodeToReadableCharMap() {
+ put("\u00C0", "A");
+ put("\u00C1", "A");
+ put("\u00C2", "A");
+ put("\u00C3", "A");
+ put("\u00C4", "Ae");
+ put("\u00C5", "Aa");
+ put("\u00C6", "Ae");
+ put("\u00C7", "C");
+ put("\u00C8", "E");
+ put("\u00C9", "E");
+ put("\u00CA", "E");
+ put("\u00CB", "E");
+ put("\u00CC", "I");
+ put("\u00CD", "I");
+ put("\u00CE", "I");
+ put("\u00CF", "I");
+ put("\u00D0", "D");
+ put("\u00D1", "N");
+ put("\u00D2", "O");
+ put("\u00D3", "O");
+ put("\u00D4", "O");
+ put("\u00D5", "O");
+ put("\u00D6", "Oe");
+ put("\u00D8", "Oe");
+ put("\u00D9", "U");
+ put("\u00DA", "U");
+ put("\u00DB", "U");
+ put("\u00DC", "Ue"); // U umlaut ..
+ put("\u00DD", "Y");
+ put("\u00DF", "ss");
+ put("\u00E0", "a");
+ put("\u00E1", "a");
+ put("\u00E2", "a");
+ put("\u00E3", "a");
+ put("\u00E4", "ae");
+ put("\u00E5", "aa");
+ put("\u00E6", "ae");
+ put("\u00E7", "c");
+ put("\u00E8", "e");
+ put("\u00E9", "e");
+ put("\u00EA", "e");
+ put("\u00EB", "e");
+ put("\u00EC", "i");
+ put("\u00ED", "i");
+ put("\u00EE", "i");
+ put("\u00EF", "i");
+ put("\u00F0", "o");
+ put("\u00F1", "n");
+ put("\u00F2", "o");
+ put("\u00F3", "o");
+ put("\u00F4", "o");
+ put("\u00F5", "o");
+ put("\u00F6", "oe");
+ put("\u00F8", "oe");
+ put("\u00F9", "u");
+ put("\u00FA", "u");
+ put("\u00FB", "u");
+ put("\u00FC", "ue"); // u umlaut...
+ put("\u00FD", "y");
+ put("\u00FF", "y");
+ put("\u0100", "A");
+ put("\u0101", "a");
+ put("\u0102", "A");
+ put("\u0103", "a");
+ put("\u0104", "A");
+ put("\u0105", "a");
+ put("\u0106", "C");
+ put("\u0107", "c");
+ put("\u0108", "C");
+ put("\u0109", "c");
+ put("\u010A", "C");
+ put("\u010B", "c");
+ put("\u010C", "C");
+ put("\u010D", "c");
+ put("\u010E", "D");
+ put("\u010F", "d");
+ put("\u0110", "D");
+ put("\u0111", "d");
+ put("\u0112", "E");
+ put("\u0113", "e");
+ put("\u0114", "E");
+ put("\u0115", "e");
+ put("\u0116", "E");
+ put("\u0117", "e");
+ put("\u0118", "E");
+ put("\u0119", "e");
+ put("\u011A", "E");
+ put("\u011B", "e");
+ put("\u011C", "G");
+ put("\u011D", "g");
+ put("\u011E", "G");
+ put("\u011F", "g");
+ put("\u0120", "G");
+ put("\u0121", "g");
+ put("\u0122", "G");
+ put("\u0123", "g");
+ put("\u0124", "H");
+ put("\u0125", "h");
+ put("\u0127", "h");
+ put("\u0128", "I");
+ put("\u0129", "i");
+ put("\u012A", "I");
+ put("\u012B", "i");
+ put("\u012C", "I");
+ put("\u012D", "i");
+ put("\u012E", "I");
+ put("\u012F", "i");
+ put("\u0130", "I");
+ put("\u0131", "i");
+ put("\u0132", "IJ");
+ put("\u0133", "ij");
+ put("\u0134", "J");
+ put("\u0135", "j");
+ put("\u0136", "K");
+ put("\u0137", "k");
+ put("\u0138", "k");
+ put("\u0139", "L");
+ put("\u013A", "l");
+ put("\u013B", "L");
+ put("\u013C", "l");
+ put("\u013D", "L");
+ put("\u013E", "l");
+ put("\u013F", "L");
+ put("\u0140", "l");
+ put("\u0141", "L");
+ put("\u0142", "l");
+ put("\u0143", "N");
+ put("\u0144", "n");
+ put("\u0145", "N");
+ put("\u0146", "n");
+ put("\u0147", "N");
+ put("\u0148", "n");
+ put("\u0149", "n");
+ put("\u014A", "N");
+ put("\u014B", "n");
+ put("\u014C", "O");
+ put("\u014D", "o");
+ put("\u014E", "O");
+ put("\u014F", "o");
+ put("\u0150", "Oe");
+ put("\u0151", "oe");
+ put("\u0152", "OE");
+ put("\u0153", "oe");
+ put("\u0154", "R");
+ put("\u0155", "r");
+ put("\u0156", "R");
+ put("\u0157", "r");
+ put("\u0158", "R");
+ put("\u0159", "r");
+ put("\u015A", "S");
+ put("\u015B", "s");
+ put("\u015C", "S");
+ put("\u015D", "s");
+ put("\u015E", "S");
+ put("\u015F", "s");
+ put("\u0160", "S");
+ put("\u0161", "s");
+ put("\u0162", "T");
+ put("\u0163", "t");
+ put("\u0164", "T");
+ put("\u0165", "t");
+ put("\u0166", "T");
+ put("\u0167", "t");
+ put("\u0168", "U");
+ put("\u0169", "u");
+ put("\u016A", "U");
+ put("\u016B", "u");
+ put("\u016C", "U");
+ put("\u016D", "u");
+ put("\u016E", "UU");
+ put("\u016F", "uu");
+ put("\u0170", "Ue");
+ put("\u0171", "ue");
+ put("\u0172", "U");
+ put("\u0173", "u");
+ put("\u0174", "W");
+ put("\u0175", "w");
+ put("\u0176", "Y");
+ put("\u0177", "y");
+ put("\u0178", "Y");
+ put("\u0179", "Z");
+ put("\u017A", "z");
+ put("\u017B", "Z");
+ put("\u017C", "z");
+ put("\u017D", "Z");
+ put("\u017E", "z");
+ put("\u1EBC", "E");
+ put("\u1EBD", "e");
+ put("\u1EF8", "Y");
+ put("\u1EF9", "y");
+ put("\u01CD", "A");
+ put("\u01CE", "a");
+ put("\u01CF", "I");
+ put("\u01D0", "i");
+ put("\u01D1", "O");
+ put("\u01D2", "o");
+ put("\u01D3", "U");
+ put("\u01D4", "u");
+ put("\u0232", "Y");
+ put("\u0233", "y");
+ put("\u01EA", "O");
+ put("\u01EB", "o");
+ put("\u1E0C", "D");
+ put("\u1E0D", "d");
+ put("\u1E24", "H");
+ put("\u1E25", "h");
+ put("\u1E36", "L");
+ put("\u1E37", "l");
+ put("\u1E38", "L");
+ put("\u1E39", "l");
+ put("\u1E42", "M");
+ put("\u1E43", "m");
+ put("\u1E46", "N");
+ put("\u1E47", "n");
+ put("\u1E5A", "R");
+ put("\u1E5B", "r");
+ put("\u1E5C", "R");
+ put("\u1E5D", "r");
+ put("\u1E62", "S");
+ put("\u1E63", "s");
+ put("\u1E6C", "T");
+ put("\u1E6D", "t");
+ put("\u00CF", "I");
+
+ put("\u008C", "AE"); // doesn't work?
+ put("\u016E", "U");
+ put("\u016F", "u");
+
+ put("\u0178", "Y");
+ put("\u00FE", ""); // thorn character
+
+ // UNICODE_CHARS.put("\u0100", "");
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/pdfimport/ImportDialog.java b/src/main/java/net/sf/jabref/pdfimport/ImportDialog.java
index f3ee32c..9a025a1 100644
--- a/src/main/java/net/sf/jabref/pdfimport/ImportDialog.java
+++ b/src/main/java/net/sf/jabref/pdfimport/ImportDialog.java
@@ -8,8 +8,12 @@ import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
import javax.swing.BorderFactory;
+import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JCheckBox;
@@ -19,12 +23,15 @@ import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
+import javax.swing.JTextArea;
import javax.swing.KeyStroke;
import javax.swing.WindowConstants;
import net.sf.jabref.Globals;
import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.logic.util.strings.StringUtil;
+import net.sf.jabref.logic.xmp.XMPUtil;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.strings.StringUtil;
import net.sf.jabref.preferences.JabRefPreferences;
import com.jgoodies.forms.builder.ButtonBarBuilder;
@@ -80,6 +87,15 @@ public class ImportDialog extends JDialog {
checkBoxDoNotShowAgain = new JCheckBox(Localization.lang("Do not show this box again for this import"));
useDefaultPDFImportStyle = new JCheckBox(Localization.lang("Always use this PDF import style (and do not ask for each import)"));
DefaultFormBuilder b = new DefaultFormBuilder(new FormLayout("left:pref, 5dlu, left:pref:grow", ""));
+ List<BibEntry> foundEntries = getEntriesFromXMP(fileName);
+ JPanel entriesPanel = new JPanel();
+ entriesPanel.setLayout(new BoxLayout(entriesPanel, BoxLayout.Y_AXIS));
+ foundEntries.forEach(entry -> {
+ JTextArea entryArea = new JTextArea(entry.toString());
+ entryArea.setEditable(false);
+ entriesPanel.add(entryArea);
+ });
+
b.appendSeparator(Localization.lang("Create new entry"));
b.append(radioButtonNoMeta, 3);
b.append(radioButtonXmp, 3);
@@ -89,6 +105,10 @@ public class ImportDialog extends JDialog {
b.nextLine();
b.append(checkBoxDoNotShowAgain);
b.append(useDefaultPDFImportStyle);
+ if (!foundEntries.isEmpty()) {
+ b.appendSeparator(Localization.lang("XMP-metadata"));
+ b.append(entriesPanel, 3);
+ }
b.getPanel().setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
ButtonBarBuilder bb = new ButtonBarBuilder();
bb.addGlue();
@@ -155,6 +175,16 @@ public class ImportDialog extends JDialog {
this.setSize(555, 371);
}
+ private List<BibEntry> getEntriesFromXMP(String fileName) {
+ List<BibEntry> foundEntries = new ArrayList<>();
+ try {
+ foundEntries = XMPUtil.readXMP(fileName, Globals.prefs.getXMPPreferences());
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return foundEntries;
+ }
+
private void onOK() {
this.result = JOptionPane.OK_OPTION;
Globals.prefs.putInt(JabRefPreferences.IMPORT_DEFAULT_PDF_IMPORT_STYLE, this.getChoice());
diff --git a/src/main/java/net/sf/jabref/pdfimport/PdfFileFilter.java b/src/main/java/net/sf/jabref/pdfimport/PdfFileFilter.java
index 6c8f888..c2879a5 100644
--- a/src/main/java/net/sf/jabref/pdfimport/PdfFileFilter.java
+++ b/src/main/java/net/sf/jabref/pdfimport/PdfFileFilter.java
@@ -5,8 +5,6 @@ import java.io.FileFilter;
public class PdfFileFilter implements FileFilter {
- public static final PdfFileFilter INSTANCE = new PdfFileFilter();
-
@Override
public boolean accept(File file) {
String path = file.getPath();
@@ -14,7 +12,7 @@ public class PdfFileFilter implements FileFilter {
return isMatchingFileFilter(path);
}
- public boolean accept(String path) {
+ public static boolean accept(String path) {
if ((path == null) || path.isEmpty() || !path.contains(".")) {
return false;
}
diff --git a/src/main/java/net/sf/jabref/pdfimport/PdfImporter.java b/src/main/java/net/sf/jabref/pdfimport/PdfImporter.java
index b828236..e53cfb9 100644
--- a/src/main/java/net/sf/jabref/pdfimport/PdfImporter.java
+++ b/src/main/java/net/sf/jabref/pdfimport/PdfImporter.java
@@ -12,27 +12,24 @@ import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import net.sf.jabref.Globals;
-import net.sf.jabref.external.DroppedFileHandler;
-import net.sf.jabref.external.ExternalFileTypes;
import net.sf.jabref.gui.BasePanel;
import net.sf.jabref.gui.BasePanelMode;
import net.sf.jabref.gui.EntryTypeDialog;
-import net.sf.jabref.gui.FileListEntry;
-import net.sf.jabref.gui.FileListTableModel;
import net.sf.jabref.gui.JabRefFrame;
import net.sf.jabref.gui.entryeditor.EntryEditor;
+import net.sf.jabref.gui.externalfiles.DroppedFileHandler;
+import net.sf.jabref.gui.externalfiletype.ExternalFileTypes;
+import net.sf.jabref.gui.filelist.FileListEntry;
+import net.sf.jabref.gui.filelist.FileListTableModel;
import net.sf.jabref.gui.maintable.MainTable;
import net.sf.jabref.gui.undo.UndoableInsertEntry;
-import net.sf.jabref.logic.bibtexkeypattern.BibtexKeyPatternPreferences;
import net.sf.jabref.logic.bibtexkeypattern.BibtexKeyPatternUtil;
-import net.sf.jabref.logic.importer.ImportFormatPreferences;
import net.sf.jabref.logic.importer.ParserResult;
import net.sf.jabref.logic.importer.fileformat.PdfContentImporter;
import net.sf.jabref.logic.importer.fileformat.PdfXmpImporter;
import net.sf.jabref.logic.l10n.Localization;
import net.sf.jabref.logic.util.UpdateField;
import net.sf.jabref.logic.util.io.FileUtil;
-import net.sf.jabref.logic.xmp.XMPPreferences;
import net.sf.jabref.logic.xmp.XMPUtil;
import net.sf.jabref.model.database.KeyCollisionException;
import net.sf.jabref.model.entry.BibEntry;
@@ -105,9 +102,8 @@ public class PdfImporter {
// other files: variable noPdfFiles
List<String> files = new ArrayList<>(fileNames);
List<String> noPdfFiles = new ArrayList<>();
- PdfFileFilter pdfFilter = PdfFileFilter.INSTANCE;
for (String file : files) {
- if (!pdfFilter.accept(file)) {
+ if (!PdfFileFilter.accept(file)) {
noPdfFiles.add(file);
}
}
@@ -139,7 +135,7 @@ public class PdfImporter {
for (String fileName : fileNames) {
if (!neverShow && !doNotShowAgain) {
importDialog = new ImportDialog(dropRow >= 0, fileName);
- if (!XMPUtil.hasMetadata(Paths.get(fileName), XMPPreferences.fromPreferences(Globals.prefs))) {
+ if (!XMPUtil.hasMetadata(Paths.get(fileName), Globals.prefs.getXMPPreferences())) {
importDialog.disableXMPChoice();
}
importDialog.setLocationRelativeTo(frame);
@@ -174,7 +170,7 @@ public class PdfImporter {
private void doXMPImport(String fileName, List<BibEntry> res) {
List<BibEntry> localRes = new ArrayList<>();
- PdfXmpImporter importer = new PdfXmpImporter(XMPPreferences.fromPreferences(Globals.prefs));
+ PdfXmpImporter importer = new PdfXmpImporter(Globals.prefs.getXMPPreferences());
Path filePath = Paths.get(fileName);
ParserResult result = importer.importDatabase(filePath, Globals.prefs.getDefaultEncoding());
if (result.hasWarnings()) {
@@ -199,7 +195,8 @@ public class PdfImporter {
FileListTableModel tm = new FileListTableModel();
File toLink = new File(fileName);
// Get a list of file directories:
- List<String> dirsS = panel.getBibDatabaseContext().getFileDirectory();
+ List<String> dirsS = panel.getBibDatabaseContext()
+ .getFileDirectories(Globals.prefs.getFileDirectoryPreferences());
tm.addEntry(0, new FileListEntry(toLink.getName(), FileUtil.shortenFileName(toLink, dirsS).getPath(),
ExternalFileTypes.getInstance().getExternalFileTypeByName("PDF")));
@@ -220,7 +217,7 @@ public class PdfImporter {
private void doContentImport(String fileName, List<BibEntry> res) {
PdfContentImporter contentImporter = new PdfContentImporter(
- ImportFormatPreferences.fromPreferences(Globals.prefs));
+ Globals.prefs.getImportFormatPreferences());
Path filePath = Paths.get(fileName);
ParserResult result = contentImporter.importDatabase(filePath, Globals.prefs.getDefaultEncoding());
if (result.hasWarnings()) {
@@ -239,15 +236,15 @@ public class PdfImporter {
// insert entry to database and link file
panel.getDatabase().insertEntry(entry);
panel.markBaseChanged();
- BibtexKeyPatternUtil.makeLabel(panel.getBibDatabaseContext().getMetaData(), panel.getDatabase(), entry,
- BibtexKeyPatternPreferences.fromPreferences(Globals.prefs));
+ BibtexKeyPatternUtil.makeAndSetLabel(panel.getBibDatabaseContext().getMetaData()
+ .getCiteKeyPattern(Globals.prefs.getBibtexKeyPatternPreferences().getKeyPattern()), panel.getDatabase(), entry,
+ Globals.prefs.getBibtexKeyPatternPreferences());
DroppedFileHandler dfh = new DroppedFileHandler(frame, panel);
dfh.linkPdfToEntry(fileName, entry);
panel.highlightEntry(entry);
if (Globals.prefs.getBoolean(JabRefPreferences.AUTO_OPEN_FORM)) {
EntryEditor editor = panel.getEntryEditor(entry);
panel.showEntryEditor(editor);
- panel.adjustSplitter();
}
res.add(entry);
}
diff --git a/src/main/java/net/sf/jabref/preferences/CustomImportList.java b/src/main/java/net/sf/jabref/preferences/CustomImportList.java
index 9368691..c41129a 100644
--- a/src/main/java/net/sf/jabref/preferences/CustomImportList.java
+++ b/src/main/java/net/sf/jabref/preferences/CustomImportList.java
@@ -4,8 +4,8 @@ import java.util.List;
import java.util.TreeSet;
import net.sf.jabref.Globals;
+import net.sf.jabref.logic.importer.Importer;
import net.sf.jabref.logic.importer.fileformat.CustomImporter;
-import net.sf.jabref.logic.importer.fileformat.ImportFormat;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -14,7 +14,7 @@ import org.apache.commons.logging.LogFactory;
* Collection of user defined custom import formats.
*
* <p>The collection can be stored and retrieved from Preferences. It is sorted by the default
- * order of {@link ImportFormat}.</p>
+ * order of {@link Importer}.</p>
*/
public class CustomImportList extends TreeSet<CustomImporter> {
@@ -34,7 +34,13 @@ public class CustomImportList extends TreeSet<CustomImporter> {
List<String> s;
while (!((s = prefs.getStringList(JabRefPreferences.CUSTOM_IMPORT_FORMAT + i)).isEmpty())) {
try {
- super.add(new CustomImporter(s));
+ if (s.size() == 2) {
+ // New format: basePath, className
+ super.add(new CustomImporter(s.get(0), s.get(1)));
+ } else {
+ // Old format: name, cliId, className, basePath
+ super.add(new CustomImporter(s.get(3), s.get(2)));
+ }
} catch (Exception e) {
LOGGER.warn("Could not load " + s.get(0) + " from preferences. Will ignore.", e);
}
diff --git a/src/main/java/net/sf/jabref/preferences/JabRefPreferences.java b/src/main/java/net/sf/jabref/preferences/JabRefPreferences.java
index 06a9fd2..c85dc1d 100644
--- a/src/main/java/net/sf/jabref/preferences/JabRefPreferences.java
+++ b/src/main/java/net/sf/jabref/preferences/JabRefPreferences.java
@@ -16,11 +16,13 @@ import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.prefs.BackingStoreException;
@@ -37,34 +39,41 @@ import net.sf.jabref.gui.desktop.JabRefDesktop;
import net.sf.jabref.gui.entryeditor.EntryEditorTabList;
import net.sf.jabref.gui.preftabs.ImportSettingsTab;
import net.sf.jabref.logic.autocompleter.AutoCompletePreferences;
+import net.sf.jabref.logic.bibtex.FieldContentParserPreferences;
+import net.sf.jabref.logic.bibtex.LatexFieldFormatterPreferences;
+import net.sf.jabref.logic.bibtexkeypattern.BibtexKeyPatternPreferences;
+import net.sf.jabref.logic.cleanup.CleanupPreferences;
import net.sf.jabref.logic.cleanup.CleanupPreset;
-import net.sf.jabref.logic.cleanup.FieldFormatterCleanup;
+import net.sf.jabref.logic.cleanup.Cleanups;
import net.sf.jabref.logic.exporter.CustomExportList;
import net.sf.jabref.logic.exporter.ExportComparator;
-import net.sf.jabref.logic.exporter.FieldFormatterCleanups;
-import net.sf.jabref.logic.formatter.bibtexfields.HtmlToLatexFormatter;
-import net.sf.jabref.logic.formatter.bibtexfields.LatexCleanupFormatter;
-import net.sf.jabref.logic.formatter.bibtexfields.NormalizeDateFormatter;
-import net.sf.jabref.logic.formatter.bibtexfields.NormalizeMonthFormatter;
-import net.sf.jabref.logic.formatter.bibtexfields.NormalizePagesFormatter;
-import net.sf.jabref.logic.formatter.bibtexfields.UnitsToLatexFormatter;
-import net.sf.jabref.logic.formatter.casechanger.ProtectTermsFormatter;
+import net.sf.jabref.logic.importer.ImportFormatPreferences;
+import net.sf.jabref.logic.journals.JournalAbbreviationLoader;
+import net.sf.jabref.logic.journals.JournalAbbreviationPreferences;
import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.logic.layout.LayoutFormatterPreferences;
+import net.sf.jabref.logic.layout.format.FileLinkPreferences;
+import net.sf.jabref.logic.layout.format.NameFormatterPreferences;
+import net.sf.jabref.logic.net.ProxyPreferences;
import net.sf.jabref.logic.openoffice.OpenOfficePreferences;
import net.sf.jabref.logic.openoffice.StyleLoader;
+import net.sf.jabref.logic.protectedterms.ProtectedTermsList;
import net.sf.jabref.logic.protectedterms.ProtectedTermsLoader;
+import net.sf.jabref.logic.protectedterms.ProtectedTermsPreferences;
+import net.sf.jabref.logic.remote.RemotePreferences;
import net.sf.jabref.logic.util.OS;
import net.sf.jabref.logic.util.UpdateFieldPreferences;
+import net.sf.jabref.logic.util.Version;
import net.sf.jabref.logic.util.io.FileHistory;
-import net.sf.jabref.logic.util.strings.StringUtil;
-import net.sf.jabref.model.bibtexkeypattern.AbstractBibtexKeyPattern;
+import net.sf.jabref.logic.xmp.XMPPreferences;
import net.sf.jabref.model.bibtexkeypattern.GlobalBibtexKeyPattern;
import net.sf.jabref.model.database.BibDatabaseMode;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.CustomEntryType;
-import net.sf.jabref.model.entry.EntryUtil;
import net.sf.jabref.model.entry.FieldName;
-import net.sf.jabref.model.entry.SpecialFields;
+import net.sf.jabref.model.metadata.FileDirectoryPreferences;
+import net.sf.jabref.model.metadata.SaveOrderConfig;
+import net.sf.jabref.model.strings.StringUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -85,7 +94,6 @@ public class JabRefPreferences {
// Push to application preferences
public static final String EMACS_PATH = "emacsPath";
public static final String EMACS_ADDITIONAL_PARAMETERS = "emacsParameters";
- public static final String EMACS_23 = "emacsUseV23InsertString";
public static final String LATEX_EDITOR_PATH = "latexEditorPath";
public static final String TEXSTUDIO_PATH = "TeXstudioPath";
public static final String WIN_EDT_PATH = "winEdtPath";
@@ -105,7 +113,6 @@ public class JabRefPreferences {
public static final String BIBLATEX_DEFAULT_MODE = "biblatexMode";
public static final String NAMES_AS_IS = "namesAsIs";
public static final String ENTRY_EDITOR_HEIGHT = "entryEditorHeight";
- public static final String PREVIEW_PANEL_HEIGHT = "previewPanelHeight";
public static final String AUTO_RESIZE_MODE = "autoResizeMode";
public static final String WINDOW_MAXIMISED = "windowMaximised";
public static final String USE_DEFAULT_LOOK_AND_FEEL = "useDefaultLookAndFeel";
@@ -137,8 +144,7 @@ public class JabRefPreferences {
public static final String SIDE_PANE_COMPONENT_NAMES = "sidePaneComponentNames";
public static final String XMP_PRIVACY_FILTERS = "xmpPrivacyFilters";
public static final String USE_XMP_PRIVACY_FILTER = "useXmpPrivacyFilter";
- public static final String SEARCH_MODE_FILTER = "searchModeFilter";
- public static final String SEARCH_CASE_SENSITIVE = "caseSensitiveSearch";
+ public static final String DEFAULT_AUTO_SORT = "defaultAutoSort";
public static final String DEFAULT_SHOW_SOURCE = "defaultShowSource";
// Window sizes
@@ -175,14 +181,14 @@ public class JabRefPreferences {
public static final String OPEN_LAST_EDITED = "openLastEdited";
public static final String LAST_FOCUSED = "lastFocused";
public static final String BACKUP = "backup";
+
public static final String AUTO_OPEN_FORM = "autoOpenForm";
- public static final String FILE_WORKING_DIRECTORY = "fileWorkingDirectory";
public static final String IMPORT_WORKING_DIRECTORY = "importWorkingDirectory";
public static final String EXPORT_WORKING_DIRECTORY = "exportWorkingDirectory";
+ public static final String PREFS_EXPORT_PATH = "prefsExportPath";
public static final String WORKING_DIRECTORY = "workingDirectory";
public static final String NUMBER_COL_WIDTH = "numberColWidth";
public static final String AUTO_COMPLETE = "autoComplete";
- public static final String SEARCH_REG_EXP = "regExpSearch";
public static final String EDITOR_EMACS_KEYBINDINGS = "editorEMACSkeyBindings";
public static final String EDITOR_EMACS_KEYBINDINGS_REBIND_CA = "editorEMACSkeyBindingsRebindCA";
public static final String EDITOR_EMACS_KEYBINDINGS_REBIND_CF = "editorEMACSkeyBindingsRebindCF";
@@ -237,7 +243,7 @@ public class JabRefPreferences {
public static final String OVERRIDE_DEFAULT_FONTS = "overrideDefaultFonts";
public static final String FONT_SIZE = "fontSize";
public static final String FONT_STYLE = "fontStyle";
- public static final String RECENT_FILES = "recentFiles";
+ public static final String RECENT_DATABASES = "recentDatabases";
public static final String RENAME_ON_MOVE_FILE_TO_FILE_DIR = "renameOnMoveFileToFileDir";
public static final String MEMORY_STICK_MODE = "memoryStickMode";
public static final String DEFAULT_OWNER = "defaultOwner";
@@ -256,10 +262,6 @@ public class JabRefPreferences {
public static final String NON_WRAPPABLE_FIELDS = "nonWrappableFields";
public static final String RESOLVE_STRINGS_ALL_FIELDS = "resolveStringsAllFields";
public static final String DO_NOT_RESOLVE_STRINGS_FOR = "doNotResolveStringsFor";
- public static final String PREVIEW_1 = "preview1";
- public static final String PREVIEW_0 = "preview0";
- public static final String ACTIVE_PREVIEW = "activePreview";
- public static final String PREVIEW_ENABLED = "previewEnabled";
public static final String MERGE_ENTRIES_DIFF_MODE = "mergeEntriesDiffMode";
public static final String CUSTOM_EXPORT_FORMAT = "customExportFormat";
@@ -273,10 +275,9 @@ public class JabRefPreferences {
public static final String USE_DEFAULT_CONSOLE_APPLICATION = "useDefaultConsoleApplication";
// Currently, it is not possible to specify defaults for specific entry types
- // When this should be made possible, the code to inspect is net.sf.jabref.gui.preftabs.BibtexKeyPatternPrefTab.storeSettings() -> LabelPattern keypatterns = getBibtexKeyPattern(); etc
+ // When this should be made possible, the code to inspect is net.sf.jabref.gui.preftabs.BibtexKeyPatternPrefTab.storeSettings() -> LabelPattern keypatterns = getCiteKeyPattern(); etc
public static final String DEFAULT_BIBTEX_KEY_PATTERN = "defaultBibtexKeyPattern";
- public static final String SEARCH_MODE_FLOAT = "floatSearch";
public static final String GRAY_OUT_NON_HITS = "grayOutNonHits";
public static final String CONFIRM_DELETE = "confirmDelete";
public static final String WARN_BEFORE_OVERWRITING_KEY = "warnBeforeOverwritingKey";
@@ -297,20 +298,19 @@ public class JabRefPreferences {
public static final String KEY_GEN_ALWAYS_ADD_LETTER = "keyGenAlwaysAddLetter";
public static final String KEY_GEN_FIRST_LETTER_A = "keyGenFirstLetterA";
public static final String ENFORCE_LEGAL_BIBTEX_KEY = "enforceLegalBibtexKey";
- public static final String PROMPT_BEFORE_USING_AUTOSAVE = "promptBeforeUsingAutosave";
- public static final String AUTO_SAVE_INTERVAL = "autoSaveInterval";
- public static final String AUTO_SAVE = "autoSave";
+ public static final String LOCAL_AUTO_SAVE = "localAutoSave";
public static final String RUN_AUTOMATIC_FILE_SEARCH = "runAutomaticFileSearch";
public static final String NUMERIC_FIELDS = "numericFields";
public static final String REG_EXP_SEARCH_EXPRESSION_KEY = "regExpSearchExpression";
public static final String AUTOLINK_USE_REG_EXP_SEARCH_KEY = "useRegExpSearch";
- public static final String DB_CONNECT_USERNAME = "dbConnectUsername";
- public static final String DB_CONNECT_DATABASE = "dbConnectDatabase";
- public static final String DB_CONNECT_HOSTNAME = "dbConnectHostname";
- public static final String DB_CONNECT_SERVER_TYPE = "dbConnectServerType";
+ private static final String DB_CONNECT_USERNAME = "dbConnectUsername";
+ private static final String DB_CONNECT_DATABASE = "dbConnectDatabase";
+ private static final String DB_CONNECT_HOSTNAME = "dbConnectHostname";
+ private static final String DB_CONNECT_SERVER_TYPE = "dbConnectServerType";
public static final String BIB_LOC_AS_PRIMARY_DIR = "bibLocAsPrimaryDir";
public static final String SELECTED_FETCHER_INDEX = "selectedFetcherIndex";
public static final String WEB_SEARCH_VISIBLE = "webSearchVisible";
+ public static final String GROUP_SIDEPANE_VISIBLE = "groupSidepaneVisible";
public static final String ALLOW_FILE_AUTO_OPEN_BROWSE = "allowFileAutoOpenBrowse";
public static final String CUSTOM_TAB_NAME = "customTabName_";
public static final String CUSTOM_TAB_FIELDS = "customTabFields_";
@@ -318,10 +318,10 @@ public class JabRefPreferences {
public static final String USE_CASE_KEEPER_ON_SEARCH = "useCaseKeeperOnSearch";
public static final String USE_IEEE_ABRV = "useIEEEAbrv";
- public static final String PROTECTED_TERMS_ENABLED_EXTERNAL = "protectedTermsEnabledExternal";
- public static final String PROTECTED_TERMS_DISABLED_EXTERNAL = "protectedTermsDisabledExternal";
- public static final String PROTECTED_TERMS_ENABLED_INTERNAL = "protectedTermsEnabledInternal";
- public static final String PROTECTED_TERMS_DISABLED_INTERNAL = "protectedTermsDisabledInternal";
+ private static final String PROTECTED_TERMS_ENABLED_EXTERNAL = "protectedTermsEnabledExternal";
+ private static final String PROTECTED_TERMS_DISABLED_EXTERNAL = "protectedTermsDisabledExternal";
+ private static final String PROTECTED_TERMS_ENABLED_INTERNAL = "protectedTermsEnabledInternal";
+ private static final String PROTECTED_TERMS_DISABLED_INTERNAL = "protectedTermsDisabledInternal";
public static final String ASK_AUTO_NAMING_PDFS_AGAIN = "AskAutoNamingPDFsAgain";
public static final String CLEANUP_DOI = "CleanUpDOI";
@@ -334,29 +334,14 @@ public class JabRefPreferences {
public static final String CLEANUP_CONVERT_TO_BIBLATEX = "CleanUpConvertToBiblatex";
public static final String CLEANUP_FIX_FILE_LINKS = "CleanUpFixFileLinks";
public static final String CLEANUP_FORMATTERS = "CleanUpFormatters";
- public static final CleanupPreset CLEANUP_DEFAULT_PRESET;
- static {
- EnumSet<CleanupPreset.CleanupStep> deactivedJobs = EnumSet.of(
- CleanupPreset.CleanupStep.CLEAN_UP_UPGRADE_EXTERNAL_LINKS,
- CleanupPreset.CleanupStep.RENAME_PDF_ONLY_RELATIVE_PATHS,
- CleanupPreset.CleanupStep.CONVERT_TO_BIBLATEX);
-
- List<FieldFormatterCleanup> activeFormatterCleanups = new ArrayList<>();
- activeFormatterCleanups.add(new FieldFormatterCleanup(FieldName.PAGES, new NormalizePagesFormatter()));
- activeFormatterCleanups.add(new FieldFormatterCleanup(FieldName.DATE, new NormalizeDateFormatter()));
- activeFormatterCleanups.add(new FieldFormatterCleanup(FieldName.MONTH, new NormalizeMonthFormatter()));
- activeFormatterCleanups.add(new FieldFormatterCleanup(FieldName.TITLE, new ProtectTermsFormatter()));
- activeFormatterCleanups.add(new FieldFormatterCleanup(FieldName.TITLE, new UnitsToLatexFormatter()));
- activeFormatterCleanups.add(new FieldFormatterCleanup(FieldName.TITLE, new LatexCleanupFormatter()));
- activeFormatterCleanups.add(new FieldFormatterCleanup(FieldName.TITLE, new HtmlToLatexFormatter()));
- FieldFormatterCleanups formatterCleanups = new FieldFormatterCleanups(true, activeFormatterCleanups);
- CLEANUP_DEFAULT_PRESET = new CleanupPreset(EnumSet.complementOf(deactivedJobs), formatterCleanups);
- }
public static final String IMPORT_DEFAULT_PDF_IMPORT_STYLE = "importDefaultPDFimportStyle";
public static final String IMPORT_ALWAYSUSE = "importAlwaysUsePDFImportStyle";
public static final String IMPORT_FILENAMEPATTERN = "importFileNamePattern";
+ public static final String IMPORT_FILEDIRPATTERN = "importFileDirPattern";
+ public static final String NAME_FORMATTER_VALUE = "nameFormatterFormats";
+ public static final String NAME_FORMATER_KEY = "nameFormatterNames";
public static final String PUSH_TO_APPLICATION = "pushToApplication";
@@ -421,6 +406,13 @@ public class JabRefPreferences {
public static final String USE_REMOTE_SERVER = "useRemoteServer";
public static final String REMOTE_SERVER_PORT = "remoteServerPort";
+ // Preview
+ private static final String CYCLE_PREVIEW_POS = "cyclePreviewPos";
+ private static final String CYCLE_PREVIEW = "cyclePreview";
+ private static final String PREVIEW_PANEL_HEIGHT = "previewPanelHeight";
+ private static final String PREVIEW_STYLE = "previewStyle";
+ private static final String PREVIEW_ENABLED = "previewEnabled";
+
public final String MARKING_WITH_NUMBER_PATTERN;
private final Preferences prefs;
@@ -434,7 +426,7 @@ public class JabRefPreferences {
private static final String USER_HOME = System.getProperty("user.home");
/**
- * Set with all custom {@link net.sf.jabref.logic.importer.fileformat.ImportFormat}s
+ * Set with all custom {@link Importer}s
*/
public final CustomImportList customImports;
@@ -472,39 +464,34 @@ public class JabRefPreferences {
// load user preferences
prefs = Preferences.userNodeForPackage(JabRefMain.class);
+ SearchPreferences.putDefaults(defaults);
+
defaults.put(TEXMAKER_PATH, JabRefDesktop.getNativeDesktop().detectProgramPath("texmaker", "Texmaker"));
defaults.put(WIN_EDT_PATH, JabRefDesktop.getNativeDesktop().detectProgramPath("WinEdt", "WinEdt Team\\WinEdt"));
defaults.put(LATEX_EDITOR_PATH, JabRefDesktop.getNativeDesktop().detectProgramPath("LEd", "LEd"));
defaults.put(TEXSTUDIO_PATH, JabRefDesktop.getNativeDesktop().detectProgramPath("texstudio", "TeXstudio"));
- defaults.put(BIBLATEX_DEFAULT_MODE, false);
+ defaults.put(BIBLATEX_DEFAULT_MODE, Boolean.FALSE);
if (OS.OS_X) {
- defaults.put(EMACS_PATH, "emacsclient");
- defaults.put(EMACS_23, true);
- defaults.put(EMACS_ADDITIONAL_PARAMETERS, "-n -e");
defaults.put(FONT_FAMILY, "SansSerif");
defaults.put(WIN_LOOK_AND_FEEL, UIManager.getSystemLookAndFeelClassName());
-
+ defaults.put(EMACS_PATH, "emacsclient");
} else if (OS.WINDOWS) {
+ defaults.put(FONT_FAMILY, "Arial");
defaults.put(WIN_LOOK_AND_FEEL, "com.jgoodies.looks.windows.WindowsLookAndFeel");
defaults.put(EMACS_PATH, "emacsclient.exe");
- defaults.put(EMACS_23, true);
- defaults.put(EMACS_ADDITIONAL_PARAMETERS, "-n -e");
- defaults.put(FONT_FAMILY, "Arial");
-
} else {
// Linux
- defaults.put(WIN_LOOK_AND_FEEL, "com.jgoodies.plaf.plastic.Plastic3DLookAndFeel");
defaults.put(FONT_FAMILY, "SansSerif");
-
- defaults.put(EMACS_PATH, "gnuclient");
- defaults.put(EMACS_23, false);
- defaults.put(EMACS_ADDITIONAL_PARAMETERS, "-batch -eval");
+ defaults.put(WIN_LOOK_AND_FEEL, "com.jgoodies.plaf.plastic.Plastic3DLookAndFeel");
+ defaults.put(EMACS_PATH, "emacsclient");
}
+ defaults.put(EMACS_ADDITIONAL_PARAMETERS, "-n -e");
+
defaults.put(PUSH_TO_APPLICATION, "TeXstudio");
- defaults.put(RECENT_FILES, "");
+ defaults.put(RECENT_DATABASES, "");
defaults.put(EXTERNAL_FILE_TYPES, "");
defaults.put(KEY_PATTERN_REGEX, "");
defaults.put(KEY_PATTERN_REPLACEMENT, "");
@@ -527,7 +514,6 @@ public class JabRefPreferences {
defaults.put(SIZE_Y, 768);
defaults.put(WINDOW_MAXIMISED, Boolean.FALSE);
defaults.put(AUTO_RESIZE_MODE, JTable.AUTO_RESIZE_ALL_COLUMNS);
- defaults.put(PREVIEW_PANEL_HEIGHT, 200);
defaults.put(ENTRY_EDITOR_HEIGHT, 400);
defaults.put(TABLE_COLOR_CODES_ON, Boolean.FALSE);
defaults.put(TABLE_RESOLVED_COLOR_CODES_ON, Boolean.FALSE);
@@ -575,7 +561,7 @@ public class JabRefPreferences {
defaults.put(EXPORT_WORKING_DIRECTORY, USER_HOME);
// Remembers working directory of last import
defaults.put(IMPORT_WORKING_DIRECTORY, USER_HOME);
- defaults.put(FILE_WORKING_DIRECTORY, USER_HOME);
+ defaults.put(PREFS_EXPORT_PATH, WORKING_DIRECTORY);
defaults.put(AUTO_OPEN_FORM, Boolean.TRUE);
defaults.put(BACKUP, Boolean.TRUE);
defaults.put(OPEN_LAST_EDITED, Boolean.TRUE);
@@ -602,17 +588,15 @@ public class JabRefPreferences {
defaults.put(TERMS_SIZE_X, 500);
defaults.put(TERMS_SIZE_Y, 500);
defaults.put(DEFAULT_SHOW_SOURCE, Boolean.FALSE);
- defaults.put(SEARCH_CASE_SENSITIVE, Boolean.FALSE);
- defaults.put(SEARCH_MODE_FILTER, Boolean.TRUE);
- defaults.put(SEARCH_REG_EXP, Boolean.FALSE);
+ defaults.put(DEFAULT_AUTO_SORT, Boolean.FALSE);
defaults.put(MERGE_ENTRIES_DIFF_MODE, 2);
defaults.put(EDITOR_EMACS_KEYBINDINGS, Boolean.FALSE);
defaults.put(EDITOR_EMACS_KEYBINDINGS_REBIND_CA, Boolean.TRUE);
defaults.put(EDITOR_EMACS_KEYBINDINGS_REBIND_CF, Boolean.TRUE);
- defaults.put(AUTO_COMPLETE, Boolean.TRUE);
+ defaults.put(AUTO_COMPLETE, Boolean.FALSE);
AutoCompletePreferences.putDefaults(defaults);
defaults.put(GROUP_FLOAT_SELECTIONS, Boolean.TRUE);
defaults.put(GROUP_INTERSECT_SELECTIONS, Boolean.TRUE);
@@ -687,34 +671,32 @@ public class JabRefPreferences {
defaults.put(OO_PATH, OpenOfficePreferences.DEFAULT_OSX_PATH);
defaults.put(OO_EXECUTABLE_PATH, OpenOfficePreferences.DEFAULT_OSX_PATH
+ OpenOfficePreferences.OSX_EXECUTABLE_SUBPATH + OpenOfficePreferences.OSX_EXECUTABLE);
- defaults.put(OO_JARS_PATH,
- OpenOfficePreferences.DEFAULT_OSX_PATH + OpenOfficePreferences.OSX_JARS_SUBPATH);
+ defaults.put(OO_JARS_PATH, OpenOfficePreferences.DEFAULT_OSX_PATH + OpenOfficePreferences.OSX_JARS_SUBPATH);
} else { // Linux
defaults.put(OO_PATH, "/opt/openoffice.org3");
defaults.put(OO_EXECUTABLE_PATH, "/usr/lib/openoffice/program/soffice");
defaults.put(OO_JARS_PATH, "/opt/openoffice.org/basis3.0");
}
- defaults.put(OO_SYNC_WHEN_CITING, false);
- defaults.put(OO_SHOW_PANEL, false);
- defaults.put(OO_USE_ALL_OPEN_BASES, true);
- defaults.put(OO_BIBLIOGRAPHY_STYLE_FILE,
- StyleLoader.DEFAULT_AUTHORYEAR_STYLE_PATH);
+ defaults.put(OO_SYNC_WHEN_CITING, Boolean.FALSE);
+ defaults.put(OO_SHOW_PANEL, Boolean.FALSE);
+ defaults.put(OO_USE_ALL_OPEN_BASES, Boolean.TRUE);
+ defaults.put(OO_BIBLIOGRAPHY_STYLE_FILE, StyleLoader.DEFAULT_AUTHORYEAR_STYLE_PATH);
defaults.put(OO_EXTERNAL_STYLE_FILES, "");
defaults.put(STYLES_POS_X, 0);
defaults.put(STYLES_POS_Y, 0);
defaults.put(STYLES_SIZE_X, 600);
defaults.put(STYLES_SIZE_Y, 400);
- defaults.put(SPECIALFIELDSENABLED, SpecialFields.PREF_SPECIALFIELDSENABLED_DEFAULT);
- defaults.put(SHOWCOLUMN_PRIORITY, SpecialFields.PREF_SHOWCOLUMN_PRIORITY_DEFAULT);
- defaults.put(SHOWCOLUMN_QUALITY, SpecialFields.PREF_SHOWCOLUMN_QUALITY_DEFAULT);
- defaults.put(SHOWCOLUMN_RANKING, SpecialFields.PREF_SHOWCOLUMN_RANKING_DEFAULT);
- defaults.put(SHOWCOLUMN_RELEVANCE, SpecialFields.PREF_SHOWCOLUMN_RELEVANCE_DEFAULT);
- defaults.put(SHOWCOLUMN_PRINTED, SpecialFields.PREF_SHOWCOLUMN_PRINTED_DEFAULT);
- defaults.put(SHOWCOLUMN_READ, SpecialFields.PREF_SHOWCOLUMN_READ_DEFAULT);
- defaults.put(AUTOSYNCSPECIALFIELDSTOKEYWORDS, SpecialFields.PREF_AUTOSYNCSPECIALFIELDSTOKEYWORDS_DEFAULT);
- defaults.put(SERIALIZESPECIALFIELDS, SpecialFields.PREF_SERIALIZESPECIALFIELDS_DEFAULT);
+ defaults.put(SPECIALFIELDSENABLED, Boolean.TRUE);
+ defaults.put(SHOWCOLUMN_PRIORITY, Boolean.FALSE);
+ defaults.put(SHOWCOLUMN_QUALITY, Boolean.FALSE);
+ defaults.put(SHOWCOLUMN_RANKING, Boolean.TRUE);
+ defaults.put(SHOWCOLUMN_RELEVANCE, Boolean.FALSE);
+ defaults.put(SHOWCOLUMN_PRINTED, Boolean.FALSE);
+ defaults.put(SHOWCOLUMN_READ, Boolean.FALSE);
+ defaults.put(AUTOSYNCSPECIALFIELDSTOKEYWORDS, Boolean.TRUE);
+ defaults.put(SERIALIZESPECIALFIELDS, Boolean.FALSE);
defaults.put(USE_OWNER, Boolean.FALSE);
defaults.put(OVERWRITE_OWNER, Boolean.FALSE);
@@ -722,49 +704,7 @@ public class JabRefPreferences {
defaults.put(WARN_BEFORE_OVERWRITING_KEY, Boolean.TRUE);
defaults.put(CONFIRM_DELETE, Boolean.TRUE);
defaults.put(GRAY_OUT_NON_HITS, Boolean.TRUE);
- defaults.put(SEARCH_MODE_FLOAT, Boolean.FALSE);
defaults.put(DEFAULT_BIBTEX_KEY_PATTERN, "[auth][year]");
- defaults.put(PREVIEW_ENABLED, Boolean.TRUE);
- defaults.put(ACTIVE_PREVIEW, 0);
- defaults.put(PREVIEW_0,
- "<font face=\"sans-serif\">"
- + "<b><i>\\format[EntryTypeFormatter]{\\entrytype}</i><a name=\"\\bibtexkey\">\\begin{bibtexkey} (\\bibtexkey)</a>"
- + "\\end{bibtexkey}</b><br>__NEWLINE__"
- + "\\begin{author} \\format[Authors(LastFirst,Initials,Semicolon,Amp),HTMLChars]{\\author}<BR>\\end{author}__NEWLINE__"
- + "\\begin{editor} \\format[Authors(LastFirst,Initials,Semicolon,Amp),HTMLChars]{\\editor} "
- + "<i>(\\format[IfPlural(Eds.,Ed.)]{\\editor})</i><BR>\\end{editor}__NEWLINE__"
- + "\\begin{title} \\format[HTMLChars]{\\title} \\end{title}<BR>__NEWLINE__"
- + "\\begin{chapter} \\format[HTMLChars]{\\chapter}<BR>\\end{chapter}__NEWLINE__"
- + "\\begin{journal} <em>\\format[HTMLChars]{\\journal}, </em>\\end{journal}__NEWLINE__"
- // Include the booktitle field for @inproceedings, @proceedings, etc.
- + "\\begin{booktitle} <em>\\format[HTMLChars]{\\booktitle}, </em>\\end{booktitle}__NEWLINE__"
- + "\\begin{school} <em>\\format[HTMLChars]{\\school}, </em>\\end{school}__NEWLINE__"
- + "\\begin{institution} <em>\\format[HTMLChars]{\\institution}, </em>\\end{institution}__NEWLINE__"
- + "\\begin{publisher} <em>\\format[HTMLChars]{\\publisher}, </em>\\end{publisher}__NEWLINE__"
- + "\\begin{year}<b>\\year</b>\\end{year}\\begin{volume}<i>, \\volume</i>\\end{volume}"
- + "\\begin{pages}, \\format[FormatPagesForHTML]{\\pages} \\end{pages}__NEWLINE__"
- + "\\begin{abstract}<BR><BR><b>Abstract: </b> \\format[HTMLChars]{\\abstract} \\end{abstract}__NEWLINE__"
- + "\\begin{review}<BR><BR><b>Review: </b> \\format[HTMLChars]{\\review} \\end{review}"
- + "</dd>__NEWLINE__<p></p></font>");
- defaults.put(PREVIEW_1,
- "<font face=\"sans-serif\">"
- + "<b><i>\\format[EntryTypeFormatter]{\\entrytype}</i><a name=\"\\bibtexkey\">\\begin{bibtexkey} (\\bibtexkey)</a>"
- + "\\end{bibtexkey}</b><br>__NEWLINE__"
- + "\\begin{author} \\format[Authors(LastFirst,Initials,Semicolon,Amp),HTMLChars]{\\author}<BR>\\end{author}__NEWLINE__"
- + "\\begin{editor} \\format[Authors(LastFirst,Initials,Semicolon,Amp),HTMLChars]{\\editor} "
- + "<i>(\\format[IfPlural(Eds.,Ed.)]{\\editor})</i><BR>\\end{editor}__NEWLINE__"
- + "\\begin{title} \\format[HTMLChars]{\\title} \\end{title}<BR>__NEWLINE__"
- + "\\begin{chapter} \\format[HTMLChars]{\\chapter}<BR>\\end{chapter}__NEWLINE__"
- + "\\begin{journal} <em>\\format[HTMLChars]{\\journal}, </em>\\end{journal}__NEWLINE__"
- // Include the booktitle field for @inproceedings, @proceedings, etc.
- + "\\begin{booktitle} <em>\\format[HTMLChars]{\\booktitle}, </em>\\end{booktitle}__NEWLINE__"
- + "\\begin{school} <em>\\format[HTMLChars]{\\school}, </em>\\end{school}__NEWLINE__"
- + "\\begin{institution} <em>\\format[HTMLChars]{\\institution}, </em>\\end{institution}__NEWLINE__"
- + "\\begin{publisher} <em>\\format[HTMLChars]{\\publisher}, </em>\\end{publisher}__NEWLINE__"
- + "\\begin{year}<b>\\year</b>\\end{year}\\begin{volume}<i>, \\volume</i>\\end{volume}"
- + "\\begin{pages}, \\format[FormatPagesForHTML]{\\pages} \\end{pages}"
- + "</dd>__NEWLINE__<p></p></font>");
-
defaults.put(DO_NOT_RESOLVE_STRINGS_FOR, FieldName.URL);
defaults.put(RESOLVE_STRINGS_ALL_FIELDS, Boolean.FALSE);
defaults.put(NON_WRAPPABLE_FIELDS, "pdf;ps;url;doi;file;isbn;issn");
@@ -796,15 +736,11 @@ public class JabRefPreferences {
defaults.put(IMPORT_INSPECTION_DIALOG_WIDTH, 650);
defaults.put(IMPORT_INSPECTION_DIALOG_HEIGHT, 650);
- defaults.put(SEARCH_DIALOG_WIDTH, 650);
- defaults.put(SEARCH_DIALOG_HEIGHT, 500);
defaults.put(SHOW_FILE_LINKS_UPGRADE_WARNING, Boolean.TRUE);
defaults.put(AUTOLINK_EXACT_KEY_ONLY, Boolean.FALSE);
defaults.put(NUMERIC_FIELDS, "mittnum;author");
defaults.put(RUN_AUTOMATIC_FILE_SEARCH, Boolean.FALSE);
- defaults.put(AUTO_SAVE, Boolean.TRUE);
- defaults.put(AUTO_SAVE_INTERVAL, 5);
- defaults.put(PROMPT_BEFORE_USING_AUTOSAVE, Boolean.TRUE);
+ defaults.put(LOCAL_AUTO_SAVE, Boolean.FALSE);
defaults.put(ENFORCE_LEGAL_BIBTEX_KEY, Boolean.TRUE);
// Curly brackets ({}) are the default delimiters, not quotes (") as these cause trouble when they appear within the field value:
// Currently, JabRef does not escape them
@@ -814,6 +750,7 @@ public class JabRefPreferences {
defaults.put(OPEN_FOLDERS_OF_ATTACHED_FILES, Boolean.FALSE);
defaults.put(ALLOW_FILE_AUTO_OPEN_BROWSE, Boolean.TRUE);
defaults.put(WEB_SEARCH_VISIBLE, Boolean.FALSE);
+ defaults.put(GROUP_SIDEPANE_VISIBLE, Boolean.FALSE);
defaults.put(SELECTED_FETCHER_INDEX, 0);
defaults.put(BIB_LOC_AS_PRIMARY_DIR, Boolean.FALSE);
defaults.put(DB_CONNECT_SERVER_TYPE, "MySQL");
@@ -822,7 +759,7 @@ public class JabRefPreferences {
defaults.put(DB_CONNECT_USERNAME, "root");
defaults.put(ASK_AUTO_NAMING_PDFS_AGAIN, Boolean.TRUE);
- insertCleanupPreset(defaults, CLEANUP_DEFAULT_PRESET);
+ insertDefaultCleanupPreset(defaults);
// defaults for DroppedFileHandler UI
defaults.put(DROPPEDFILEHANDLER_LEAVE, Boolean.FALSE);
@@ -835,6 +772,8 @@ public class JabRefPreferences {
// use BibTeX key appended with filename as default pattern
defaults.put(IMPORT_FILENAMEPATTERN, ImportSettingsTab.DEFAULT_FILENAMEPATTERNS[1]);
+ //Default empty String to be backwards compatible
+ defaults.put(IMPORT_FILEDIRPATTERN, "");
customExports = new CustomExportList(new ExportComparator());
customImports = new CustomImportList(this);
@@ -857,6 +796,32 @@ public class JabRefPreferences {
//versioncheck defaults
defaults.put(VERSION_IGNORED_UPDATE, "");
+
+ // preview
+ defaults.put(CYCLE_PREVIEW, "Preview");
+ defaults.put(CYCLE_PREVIEW_POS, 0);
+ defaults.put(PREVIEW_PANEL_HEIGHT, 200);
+ defaults.put(PREVIEW_ENABLED, Boolean.TRUE);
+ defaults.put(PREVIEW_STYLE,
+ "<font face=\"sans-serif\">"
+ + "<b><i>\\bibtextype</i><a name=\"\\bibtexkey\">\\begin{bibtexkey} (\\bibtexkey)</a>"
+ + "\\end{bibtexkey}</b><br>__NEWLINE__"
+ + "\\begin{author} \\format[Authors(LastFirst,Initials,Semicolon,Amp),HTMLChars]{\\author}<BR>\\end{author}__NEWLINE__"
+ + "\\begin{editor} \\format[Authors(LastFirst,Initials,Semicolon,Amp),HTMLChars]{\\editor} "
+ + "<i>(\\format[IfPlural(Eds.,Ed.)]{\\editor})</i><BR>\\end{editor}__NEWLINE__"
+ + "\\begin{title} \\format[HTMLChars]{\\title} \\end{title}<BR>__NEWLINE__"
+ + "\\begin{chapter} \\format[HTMLChars]{\\chapter}<BR>\\end{chapter}__NEWLINE__"
+ + "\\begin{journal} <em>\\format[HTMLChars]{\\journal}, </em>\\end{journal}__NEWLINE__"
+ // Include the booktitle field for @inproceedings, @proceedings, etc.
+ + "\\begin{booktitle} <em>\\format[HTMLChars]{\\booktitle}, </em>\\end{booktitle}__NEWLINE__"
+ + "\\begin{school} <em>\\format[HTMLChars]{\\school}, </em>\\end{school}__NEWLINE__"
+ + "\\begin{institution} <em>\\format[HTMLChars]{\\institution}, </em>\\end{institution}__NEWLINE__"
+ + "\\begin{publisher} <em>\\format[HTMLChars]{\\publisher}, </em>\\end{publisher}__NEWLINE__"
+ + "\\begin{year}<b>\\year</b>\\end{year}\\begin{volume}<i>, \\volume</i>\\end{volume}"
+ + "\\begin{pages}, \\format[FormatPagesForHTML]{\\pages} \\end{pages}__NEWLINE__"
+ + "\\begin{abstract}<BR><BR><b>Abstract: </b> \\format[HTMLChars]{\\abstract} \\end{abstract}__NEWLINE__"
+ + "\\begin{review}<BR><BR><b>Review: </b> \\format[HTMLChars]{\\review} \\end{review}"
+ + "</dd>__NEWLINE__<p></p></font>");
}
public String getUser() {
@@ -872,11 +837,11 @@ public class JabRefPreferences {
List<String> customFields = new ArrayList<>();
int defNumber = 0;
- while(true) {
+ while (true) {
// saved as CUSTOMTABNAME_def{number} and ; separated
String fields = (String) defaults.get(CUSTOM_TAB_FIELDS + "_def" + defNumber);
- if((fields == null) || fields.isEmpty()) {
+ if ((fields == null) || fields.isEmpty()) {
break;
}
@@ -889,8 +854,7 @@ public class JabRefPreferences {
public void setLanguageDependentDefaultValues() {
// Entry editor tab 0:
defaults.put(CUSTOM_TAB_NAME + "_def0", Localization.lang("General"));
- defaults.put(CUSTOM_TAB_FIELDS + "_def0", "crossref;keywords;file;doi;url;"
- + "comment;owner;timestamp");
+ defaults.put(CUSTOM_TAB_FIELDS + "_def0", "crossref;keywords;file;doi;url;" + "comment;owner;timestamp");
// Entry editor tab 1:
defaults.put(CUSTOM_TAB_FIELDS + "_def1", FieldName.ABSTRACT);
@@ -1113,8 +1077,7 @@ public class JabRefPreferences {
* @return LabelPattern containing all keys. Returned LabelPattern has no parent
*/
public GlobalBibtexKeyPattern getKeyPattern() {
- keyPattern = new GlobalBibtexKeyPattern(
- AbstractBibtexKeyPattern.split(JabRefPreferences.getInstance().get(DEFAULT_BIBTEX_KEY_PATTERN)));
+ keyPattern = GlobalBibtexKeyPattern.fromPattern(get(DEFAULT_BIBTEX_KEY_PATTERN));
Preferences pre = Preferences.userNodeForPackage(JabRefMain.class).node(BIBTEX_KEY_PATTERNS_NODE);
try {
String[] keys = pre.keys();
@@ -1157,16 +1120,16 @@ public class JabRefPreferences {
}
public Map<String, Object> getPreferences() {
- Map<String, Object> prefs = new HashMap<>();
+ Map<String, Object> result = new HashMap<>();
try {
- for(String key : this.prefs.keys()){
+ for (String key : this.prefs.keys()) {
Object value = getObject(key);
- prefs.put(key, value);
+ result.put(key, value);
}
} catch (BackingStoreException e) {
LOGGER.info("could not retrieve preference keys", e);
}
- return prefs;
+ return result;
}
private Object getObject(String key) {
@@ -1181,7 +1144,6 @@ public class JabRefPreferences {
}
}
-
private static Optional<String> getNextUnit(Reader data) throws IOException {
// character last read
// -1 if end of stream
@@ -1252,16 +1214,15 @@ public class JabRefPreferences {
List<String> opt = getStringList(CUSTOM_TYPE_OPT + nr);
List<String> priOpt = getStringList(CUSTOM_TYPE_PRIOPT + nr);
if (priOpt.isEmpty()) {
- return Optional.of(new CustomEntryType(EntryUtil.capitalizeFirst(name), req, opt));
+ return Optional.of(new CustomEntryType(StringUtil.capitalizeFirst(name), req, opt));
}
List<String> secondary = new ArrayList<>(opt);
secondary.removeAll(priOpt);
- return Optional.of(new CustomEntryType(EntryUtil.capitalizeFirst(name), req, priOpt, secondary));
+ return Optional.of(new CustomEntryType(StringUtil.capitalizeFirst(name), req, priOpt, secondary));
}
-
/**
* Removes all information about custom entry types with tags of
*
@@ -1308,7 +1269,8 @@ public class JabRefPreferences {
try (OutputStream os = new FileOutputStream(f)) {
prefs.exportSubtree(os);
} catch (BackingStoreException | IOException ex) {
- throw new JabRefException("Could not export preferences", Localization.lang("Could not export preferences"), ex);
+ throw new JabRefException("Could not export preferences", Localization.lang("Could not export preferences"),
+ ex);
}
}
@@ -1352,7 +1314,14 @@ public class JabRefPreferences {
put(DEFAULT_ENCODING, encoding.name());
}
- private static void insertCleanupPreset(Map<String, Object> storage, CleanupPreset preset) {
+ private static void insertDefaultCleanupPreset(Map<String, Object> storage) {
+ EnumSet<CleanupPreset.CleanupStep> deactivedJobs = EnumSet.of(
+ CleanupPreset.CleanupStep.CLEAN_UP_UPGRADE_EXTERNAL_LINKS,
+ CleanupPreset.CleanupStep.RENAME_PDF_ONLY_RELATIVE_PATHS,
+ CleanupPreset.CleanupStep.CONVERT_TO_BIBLATEX);
+
+ CleanupPreset preset = new CleanupPreset(EnumSet.complementOf(deactivedJobs), Cleanups.DEFAULT_SAVE_ACTIONS);
+
storage.put(CLEANUP_DOI, preset.isCleanUpDOI());
storage.put(CLEANUP_ISSN, preset.isCleanUpISSN());
storage.put(CLEANUP_MOVE_PDF, preset.isMovePDF());
@@ -1362,23 +1331,219 @@ public class JabRefPreferences {
storage.put(CLEANUP_UPGRADE_EXTERNAL_LINKS, preset.isCleanUpUpgradeExternalLinks());
storage.put(CLEANUP_CONVERT_TO_BIBLATEX, preset.isConvertToBiblatex());
storage.put(CLEANUP_FIX_FILE_LINKS, preset.isFixFileLinks());
- storage.put(CLEANUP_FORMATTERS, convertListToString(preset.getFormatterCleanups().getAsStringList()));
+ storage.put(CLEANUP_FORMATTERS, convertListToString(preset.getFormatterCleanups().getAsStringList(OS.NEWLINE)));
}
public FileHistory getFileHistory() {
- return new FileHistory(getStringList(RECENT_FILES));
+ return new FileHistory(getStringList(RECENT_DATABASES));
}
public void storeFileHistory(FileHistory history) {
if (!history.isEmpty()) {
- putStringList(RECENT_FILES, history.getHistory());
+ putStringList(RECENT_DATABASES, history.getHistory());
}
}
+ public FileDirectoryPreferences getFileDirectoryPreferences() {
+ List<String> fields = Arrays.asList(FieldName.FILE, FieldName.PDF, FieldName.PS);
+ Map<String, String> fieldDirectories = new HashMap<>();
+ fields.stream().forEach(
+ fieldName -> fieldDirectories.put(fieldName, get(fieldName + FileDirectoryPreferences.DIR_SUFFIX)));
+ return new FileDirectoryPreferences(getUser(), fieldDirectories,
+ getBoolean(JabRefPreferences.BIB_LOC_AS_PRIMARY_DIR));
+ }
+
public UpdateFieldPreferences getUpdateFieldPreferences() {
return new UpdateFieldPreferences(getBoolean(USE_OWNER), getBoolean(OVERWRITE_OWNER), get(DEFAULT_OWNER),
getBoolean(USE_TIME_STAMP), getBoolean(OVERWRITE_TIME_STAMP), get(TIME_STAMP_FIELD),
get(TIME_STAMP_FORMAT));
}
+ public LatexFieldFormatterPreferences getLatexFieldFormatterPreferences() {
+ return new LatexFieldFormatterPreferences(getBoolean(RESOLVE_STRINGS_ALL_FIELDS),
+ getStringList(DO_NOT_RESOLVE_STRINGS_FOR), getFieldContentParserPreferences());
+ }
+
+ public FieldContentParserPreferences getFieldContentParserPreferences() {
+ return new FieldContentParserPreferences(getStringList(NON_WRAPPABLE_FIELDS));
+ }
+
+ public boolean isKeywordSyncEnabled() {
+ return getBoolean(JabRefPreferences.SPECIALFIELDSENABLED)
+ && getBoolean(JabRefPreferences.AUTOSYNCSPECIALFIELDSTOKEYWORDS);
+ }
+
+ public ImportFormatPreferences getImportFormatPreferences() {
+ return new ImportFormatPreferences(customImports, getDefaultEncoding(), getKeywordDelimiter(),
+ getBibtexKeyPatternPreferences(), getFieldContentParserPreferences(),
+ isKeywordSyncEnabled());
+ }
+
+ public BibtexKeyPatternPreferences getBibtexKeyPatternPreferences() {
+ return new BibtexKeyPatternPreferences(get(KEY_PATTERN_REGEX),
+ get(KEY_PATTERN_REPLACEMENT), getBoolean(KEY_GEN_ALWAYS_ADD_LETTER), getBoolean(KEY_GEN_FIRST_LETTER_A),
+ getBoolean(ENFORCE_LEGAL_BIBTEX_KEY), getKeyPattern(), getKeywordDelimiter());
+ }
+
+ public LayoutFormatterPreferences getLayoutFormatterPreferences(
+ JournalAbbreviationLoader journalAbbreviationLoader) {
+ Objects.requireNonNull(journalAbbreviationLoader);
+ return new LayoutFormatterPreferences(getNameFormatterPreferences(), getJournalAbbreviationPreferences(),
+ getFileLinkPreferences(), journalAbbreviationLoader);
+ }
+
+ public XMPPreferences getXMPPreferences() {
+ return new XMPPreferences(getBoolean(USE_XMP_PRIVACY_FILTER), getStringList(XMP_PRIVACY_FILTERS),
+ getKeywordDelimiter());
+ }
+
+ private NameFormatterPreferences getNameFormatterPreferences() {
+ return new NameFormatterPreferences(getStringList(NAME_FORMATER_KEY), getStringList(NAME_FORMATTER_VALUE));
+ }
+
+ public FileLinkPreferences getFileLinkPreferences() {
+ return new FileLinkPreferences(
+ Collections.singletonList(get(FieldName.FILE + FileDirectoryPreferences.DIR_SUFFIX)),
+ fileDirForDatabase);
+ }
+
+ public JabRefPreferences storeVersionPreferences(VersionPreferences versionPreferences) {
+ put(VERSION_IGNORED_UPDATE, versionPreferences.getIgnoredVersion().toString());
+ return this;
+ }
+
+ public VersionPreferences getVersionPreferences() {
+ Version ignoredVersion = Version.parse(get(VERSION_IGNORED_UPDATE));
+ return new VersionPreferences(ignoredVersion);
+ }
+
+ public JabRefPreferences storePreviewPreferences(PreviewPreferences previewPreferences) {
+ putInt(CYCLE_PREVIEW_POS, previewPreferences.getPreviewCyclePosition());
+ putStringList(CYCLE_PREVIEW, previewPreferences.getPreviewCycle());
+ putInt(PREVIEW_PANEL_HEIGHT, previewPreferences.getPreviewPanelHeight());
+ put(PREVIEW_STYLE, previewPreferences.getPreviewStyle());
+ putBoolean(PREVIEW_ENABLED, previewPreferences.isPreviewPanelEnabled());
+ return this;
+ }
+
+ public PreviewPreferences getPreviewPreferences(){
+ int cyclePos = getInt(CYCLE_PREVIEW_POS);
+ List<String> cycle = getStringList(CYCLE_PREVIEW);
+ int panelHeight = getInt(PREVIEW_PANEL_HEIGHT);
+ String style = get(PREVIEW_STYLE);
+ String styleDefault = (String) defaults.get(PREVIEW_STYLE);
+ boolean enabled = getBoolean(PREVIEW_ENABLED);
+ return new PreviewPreferences(cycle, cyclePos, panelHeight, enabled, style, styleDefault);
+ }
+
+ public void storeProxyPreferences(ProxyPreferences proxyPreferences) {
+ putBoolean(PROXY_USE, proxyPreferences.isUseProxy());
+ put(PROXY_HOSTNAME, proxyPreferences.getHostname());
+ put(PROXY_PORT, proxyPreferences.getPort());
+ putBoolean(PROXY_USE_AUTHENTICATION, proxyPreferences.isUseAuthentication());
+ put(PROXY_USERNAME, proxyPreferences.getUsername());
+ put(PROXY_PASSWORD, proxyPreferences.getPassword());
+ }
+
+ public ProxyPreferences getProxyPreferences() {
+ Boolean useProxy = getBoolean(PROXY_USE);
+ String hostname = get(PROXY_HOSTNAME);
+ String port = get(PROXY_PORT);
+ Boolean useAuthentication = getBoolean(PROXY_USE_AUTHENTICATION);
+ String username = get(PROXY_USERNAME);
+ String password = get(PROXY_PASSWORD);
+ return new ProxyPreferences(useProxy, hostname, port, useAuthentication, username, password);
+ }
+
+ public ProtectedTermsPreferences getProtectedTermsPreferences() {
+ return new ProtectedTermsPreferences(getStringList(PROTECTED_TERMS_ENABLED_INTERNAL),
+ getStringList(PROTECTED_TERMS_ENABLED_EXTERNAL), getStringList(PROTECTED_TERMS_DISABLED_INTERNAL),
+ getStringList(PROTECTED_TERMS_DISABLED_EXTERNAL));
+ }
+
+ public JournalAbbreviationPreferences getJournalAbbreviationPreferences() {
+ return new JournalAbbreviationPreferences(getStringList(EXTERNAL_JOURNAL_LISTS), get(PERSONAL_JOURNAL_LIST),
+ getBoolean(USE_IEEE_ABRV), getDefaultEncoding());
+ }
+
+ public void setProtectedTermsPreferences(ProtectedTermsLoader loader) {
+ List<String> enabledExternalList = new ArrayList<>();
+ List<String> disabledExternalList = new ArrayList<>();
+ List<String> enabledInternalList = new ArrayList<>();
+ List<String> disabledInternalList = new ArrayList<>();
+
+ for (ProtectedTermsList list : loader.getProtectedTermsLists()) {
+ if (list.isInternalList()) {
+ if (list.isEnabled()) {
+ enabledInternalList.add(list.getLocation());
+ } else {
+ disabledInternalList.add(list.getLocation());
+ }
+ } else {
+ if (list.isEnabled()) {
+ enabledExternalList.add(list.getLocation());
+ } else {
+ disabledExternalList.add(list.getLocation());
+ }
+ }
+ }
+
+ putStringList(PROTECTED_TERMS_ENABLED_EXTERNAL, enabledExternalList);
+ putStringList(PROTECTED_TERMS_DISABLED_EXTERNAL, disabledExternalList);
+ putStringList(PROTECTED_TERMS_ENABLED_INTERNAL, enabledInternalList);
+ putStringList(PROTECTED_TERMS_DISABLED_INTERNAL, disabledInternalList);
+
+ }
+
+ public CleanupPreferences getCleanupPreferences(JournalAbbreviationLoader journalAbbreviationLoader) {
+ return new CleanupPreferences(get(IMPORT_FILENAMEPATTERN), get(IMPORT_FILEDIRPATTERN),
+ getLayoutFormatterPreferences(journalAbbreviationLoader), getFileDirectoryPreferences());
+ }
+
+ public RemotePreferences getRemotePreferences() {
+ return new RemotePreferences(getInt(REMOTE_SERVER_PORT), getBoolean(USE_REMOTE_SERVER));
+ }
+
+ public void setRemotePreferences(RemotePreferences remotePreferences) {
+ putInt(REMOTE_SERVER_PORT, remotePreferences.getPort());
+ putBoolean(USE_REMOTE_SERVER, remotePreferences.useRemoteServer());
+ }
+
+ public void storeExportSaveOrder(SaveOrderConfig config) {
+ putBoolean(EXPORT_PRIMARY_SORT_DESCENDING, config.sortCriteria[0].descending);
+ putBoolean(EXPORT_SECONDARY_SORT_DESCENDING, config.sortCriteria[1].descending);
+ putBoolean(EXPORT_TERTIARY_SORT_DESCENDING, config.sortCriteria[2].descending);
+
+ put(EXPORT_PRIMARY_SORT_FIELD, config.sortCriteria[0].field);
+ put(EXPORT_SECONDARY_SORT_FIELD, config.sortCriteria[1].field);
+ put(EXPORT_TERTIARY_SORT_FIELD, config.sortCriteria[2].field);
+ }
+
+ public SaveOrderConfig loadTableSaveOrder() {
+ SaveOrderConfig config = new SaveOrderConfig();
+ config.sortCriteria[0].field = get(TABLE_PRIMARY_SORT_FIELD);
+ config.sortCriteria[0].descending = getBoolean(TABLE_PRIMARY_SORT_DESCENDING);
+ config.sortCriteria[1].field = get(TABLE_SECONDARY_SORT_FIELD);
+ config.sortCriteria[1].descending = getBoolean(TABLE_SECONDARY_SORT_DESCENDING);
+ config.sortCriteria[2].field = get(TABLE_TERTIARY_SORT_FIELD);
+ config.sortCriteria[2].descending = getBoolean(TABLE_TERTIARY_SORT_DESCENDING);
+
+ return config;
+ }
+
+ public SaveOrderConfig loadExportSaveOrder() {
+ SaveOrderConfig config = new SaveOrderConfig();
+ config.sortCriteria[0].field = get(EXPORT_PRIMARY_SORT_FIELD);
+ config.sortCriteria[0].descending = getBoolean(EXPORT_PRIMARY_SORT_DESCENDING);
+ config.sortCriteria[1].field = get(EXPORT_SECONDARY_SORT_FIELD);
+ config.sortCriteria[1].descending = getBoolean(EXPORT_SECONDARY_SORT_DESCENDING);
+ config.sortCriteria[2].field = get(EXPORT_TERTIARY_SORT_FIELD);
+ config.sortCriteria[2].descending = getBoolean(EXPORT_TERTIARY_SORT_DESCENDING);
+
+ return config;
+ }
+
+ public Character getKeywordDelimiter() {
+ return get(KEYWORD_SEPARATOR).charAt(0);
+ }
}
diff --git a/src/main/java/net/sf/jabref/preferences/PreviewPreferences.java b/src/main/java/net/sf/jabref/preferences/PreviewPreferences.java
new file mode 100644
index 0000000..086c6ee
--- /dev/null
+++ b/src/main/java/net/sf/jabref/preferences/PreviewPreferences.java
@@ -0,0 +1,106 @@
+package net.sf.jabref.preferences;
+
+import java.util.List;
+
+
+public class PreviewPreferences {
+
+ private final List<String> previewCycle;
+ private final int previewCyclePosition;
+ private final int previewPanelHeight;
+ private final boolean previewPanelEnabled;
+ private final String previewStyle;
+ private final String previewStyleDefault;
+
+
+ public PreviewPreferences(List<String> previewCycle, int previeCyclePosition, int previewPanelHeight, boolean previewPanelEnabled, String previewStyle, String previewStyleDefault) {
+ this.previewCycle = previewCycle;
+ this.previewCyclePosition = previeCyclePosition;
+ this.previewPanelHeight = previewPanelHeight;
+ this.previewPanelEnabled = previewPanelEnabled;
+ this.previewStyle = previewStyle;
+ this.previewStyleDefault = previewStyleDefault;
+ }
+
+ public List<String> getPreviewCycle() {
+ return previewCycle;
+ }
+
+ public int getPreviewCyclePosition() {
+ return previewCyclePosition;
+ }
+
+ public int getPreviewPanelHeight() {
+ return previewPanelHeight;
+ }
+
+ public boolean isPreviewPanelEnabled() {
+ return previewPanelEnabled;
+ }
+
+ public String getPreviewStyle() {
+ return previewStyle;
+ }
+
+ public String getPreviewStyleDefault() {
+ return previewStyleDefault;
+ }
+
+ public Builder getBuilder() {
+ return new Builder(this);
+ }
+
+
+ public static class Builder {
+ private List<String> previewCycle;
+ private int previeCyclePosition;
+ private int previewPanelHeight;
+ private boolean previewPanelEnabled;
+ private String previewStyle;
+ private final String previewStyleDefault;
+
+
+ public Builder(PreviewPreferences previewPreferences) {
+ this.previewCycle = previewPreferences.getPreviewCycle();
+ this.previeCyclePosition = previewPreferences.getPreviewCyclePosition();
+ this.previewPanelHeight = previewPreferences.getPreviewPanelHeight();
+ this.previewPanelEnabled = previewPreferences.isPreviewPanelEnabled();
+ this.previewStyle = previewPreferences.getPreviewStyle();
+ this.previewStyleDefault = previewPreferences.getPreviewStyleDefault();
+ }
+
+ public Builder withPreviewCycle(List<String> previewCycle) {
+ this.previewCycle = previewCycle;
+ return withPreviewCyclePosition(previeCyclePosition);
+ }
+
+ public Builder withPreviewCyclePosition(int position) {
+ previeCyclePosition = position;
+ while (previeCyclePosition < 0) {
+ previeCyclePosition += previewCycle.size();
+ }
+ previeCyclePosition %= previewCycle.size();
+ return this;
+ }
+
+ public Builder withPreviewPanelHeight(int previewPanelHeight) {
+ this.previewPanelHeight = previewPanelHeight;
+ return this;
+ }
+
+ public Builder withPreviewPanelEnabled(boolean previewPanelEnabled) {
+ this.previewPanelEnabled = previewPanelEnabled;
+ return this;
+ }
+
+ public Builder withPreviewStyle(String previewStyle) {
+ this.previewStyle = previewStyle;
+ return this;
+ }
+
+ public PreviewPreferences build() {
+ return new PreviewPreferences(previewCycle, previeCyclePosition, previewPanelHeight, previewPanelEnabled, previewStyle, previewStyleDefault);
+ }
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/preferences/SearchPreferences.java b/src/main/java/net/sf/jabref/preferences/SearchPreferences.java
new file mode 100644
index 0000000..1a4dbfa
--- /dev/null
+++ b/src/main/java/net/sf/jabref/preferences/SearchPreferences.java
@@ -0,0 +1,117 @@
+package net.sf.jabref.preferences;
+
+import java.util.Map;
+import java.util.Objects;
+
+import net.sf.jabref.gui.search.SearchDisplayMode;
+
+
+public class SearchPreferences {
+
+ private static final String SEARCH_GLOBAL = "searchGlobal";
+ private static final String SEARCH_DISPLAY_MODE = "searchDisplayMode";
+ private static final String SEARCH_CASE_SENSITIVE = "caseSensitiveSearch";
+ private static final String SEARCH_REG_EXP = "regExpSearch";
+
+ private static final String SEARCH_DIALOG_HEIGHT = "searchDialogHeight";
+ private static final String SEARCH_DIALOG_WIDTH = "searchDialogWidth";
+ private static final String SEARCH_DIALOG_POS_X = "searchDialogPosX";
+ private static final String SEARCH_DIALOG_POS_Y = "searchDialogPosY";
+
+ private final JabRefPreferences preferences;
+
+
+ public SearchPreferences(JabRefPreferences preferences) {
+ this.preferences = Objects.requireNonNull(preferences);
+ }
+
+ public static void putDefaults(Map<String, Object> defaults) {
+ defaults.put(SEARCH_GLOBAL, Boolean.FALSE);
+ defaults.put(SEARCH_DISPLAY_MODE, SearchDisplayMode.FILTER.toString());
+ defaults.put(SEARCH_CASE_SENSITIVE, Boolean.FALSE);
+ defaults.put(SEARCH_REG_EXP, Boolean.FALSE);
+
+ defaults.put(SEARCH_DIALOG_WIDTH, 650);
+ defaults.put(SEARCH_DIALOG_HEIGHT, 500);
+ defaults.put(SEARCH_DIALOG_POS_X, 0);
+ defaults.put(SEARCH_DIALOG_POS_Y, 0);
+ }
+
+ public boolean isGlobalSearch() {
+ return preferences.getBoolean(SEARCH_GLOBAL);
+ }
+
+ public SearchPreferences setGlobalSearch(boolean isGlobalSearch) {
+ preferences.putBoolean(SEARCH_GLOBAL, isGlobalSearch);
+ return this;
+ }
+
+ public SearchDisplayMode getSearchMode() {
+ try {
+ return SearchDisplayMode.valueOf(preferences.get(SEARCH_DISPLAY_MODE));
+ } catch (IllegalArgumentException ex) {
+ // Should only occur when the searchmode is set directly via preferences.put and the enum was not used
+ return SearchDisplayMode.valueOf((String) preferences.defaults.get(SEARCH_DISPLAY_MODE));
+ }
+ }
+
+ public SearchPreferences setSearchMode(SearchDisplayMode searchDisplayMode) {
+ preferences.put(SEARCH_DISPLAY_MODE, Objects.requireNonNull(searchDisplayMode).toString());
+ return this;
+ }
+
+ public boolean isCaseSensitive() {
+ return preferences.getBoolean(SEARCH_CASE_SENSITIVE);
+ }
+
+ public SearchPreferences setCaseSensitive(boolean isCaseSensitive) {
+ preferences.putBoolean(SEARCH_CASE_SENSITIVE, isCaseSensitive);
+ return this;
+ }
+
+ public boolean isRegularExpression() {
+ return preferences.getBoolean(SEARCH_REG_EXP);
+ }
+
+ public SearchPreferences setRegularExpression(boolean isRegularExpression) {
+ preferences.putBoolean(SEARCH_REG_EXP, isRegularExpression);
+ return this;
+ }
+
+ public int getSeachDialogWidth() {
+ return preferences.getInt(SEARCH_DIALOG_WIDTH);
+ }
+
+ public SearchPreferences setSearchDialogWidth(int width) {
+ preferences.putInt(SEARCH_DIALOG_WIDTH, width);
+ return this;
+ }
+
+ public int getSeachDialogHeight() {
+ return preferences.getInt(SEARCH_DIALOG_HEIGHT);
+ }
+
+ public SearchPreferences setSearchDialogHeight(int height) {
+ preferences.putInt(SEARCH_DIALOG_HEIGHT, height);
+ return this;
+ }
+
+ public int getSearchDialogPosX() {
+ return preferences.getInt(SEARCH_DIALOG_POS_X);
+ }
+
+ public SearchPreferences setSearchDialogPosX(int x) {
+ preferences.putInt(SEARCH_DIALOG_POS_X, x);
+ return this;
+ }
+
+ public int getSearchDialogPosY() {
+ return preferences.getInt(SEARCH_DIALOG_POS_Y);
+ }
+
+ public SearchPreferences setSearchDialogPosY(int y) {
+ preferences.putInt(SEARCH_DIALOG_POS_Y, y);
+ return this;
+ }
+
+}
diff --git a/src/main/java/net/sf/jabref/preferences/VersionPreferences.java b/src/main/java/net/sf/jabref/preferences/VersionPreferences.java
index ec7f77e..f3758d1 100644
--- a/src/main/java/net/sf/jabref/preferences/VersionPreferences.java
+++ b/src/main/java/net/sf/jabref/preferences/VersionPreferences.java
@@ -2,22 +2,17 @@ package net.sf.jabref.preferences;
import net.sf.jabref.logic.util.Version;
-
public class VersionPreferences {
- private final JabRefPreferences preferences;
-
+ private final Version ignoredVersion;
- public VersionPreferences(JabRefPreferences preferences) {
- this.preferences = preferences;
- }
- public void setAsIgnoredVersion(Version version) {
- preferences.put(JabRefPreferences.VERSION_IGNORED_UPDATE, version.toString());
+ public VersionPreferences(Version ignoredVersion) {
+ this.ignoredVersion = ignoredVersion;
}
public Version getIgnoredVersion() {
- return new Version(preferences.get(JabRefPreferences.VERSION_IGNORED_UPDATE));
+ return ignoredVersion;
}
}
diff --git a/src/main/java/net/sf/jabref/shared/DBMSConnection.java b/src/main/java/net/sf/jabref/shared/DBMSConnection.java
new file mode 100644
index 0000000..f212ef4
--- /dev/null
+++ b/src/main/java/net/sf/jabref/shared/DBMSConnection.java
@@ -0,0 +1,73 @@
+package net.sf.jabref.shared;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.util.HashSet;
+import java.util.Set;
+
+import net.sf.jabref.logic.l10n.Localization;
+import net.sf.jabref.shared.exception.InvalidDBMSConnectionPropertiesException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class DBMSConnection {
+
+ private static final Log LOGGER = LogFactory.getLog(DBMSConnection.class);
+
+ private final Connection connection;
+ private final DBMSConnectionProperties properties;
+
+
+ public DBMSConnection(DBMSConnectionProperties properties) throws SQLException, InvalidDBMSConnectionPropertiesException {
+
+ if (!properties.isValid()) {
+ throw new InvalidDBMSConnectionPropertiesException();
+ }
+ this.properties = properties;
+
+ try {
+ DriverManager.setLoginTimeout(3);
+ // ensure that all SQL drivers are loaded - source: http://stackoverflow.com/a/22384826/873282
+ // we use the side effect of getAvailableDBMSTypes() - it loads all available drivers
+ DBMSConnection.getAvailableDBMSTypes();
+
+ this.connection = DriverManager.getConnection(
+ properties.getType().getUrl(properties.getHost(), properties.getPort(), properties.getDatabase()),
+ properties.getUser(), properties.getPassword());
+ } catch (SQLException e) {
+ // Some systems like PostgreSQL retrieves 0 to every exception.
+ // Therefore a stable error determination is not possible.
+ LOGGER.error("Could not connect to database: " + e.getMessage() + " - Error code: " + e.getErrorCode());
+
+ throw e;
+ }
+ }
+
+ public Connection getConnection() {
+ return this.connection;
+ }
+
+ public DBMSConnectionProperties getProperties() {
+ return this.properties;
+ }
+
+ /**
+ * Returns a Set of {@link DBMSType} which is supported by available drivers.
+ */
+ public static Set<DBMSType> getAvailableDBMSTypes() {
+ Set<DBMSType> dbmsTypes = new HashSet<>();
+
+ for (DBMSType dbms : DBMSType.values()) {
+ try {
+ Class.forName(dbms.getDriverClassPath());
+ dbmsTypes.add(dbms);
+ } catch (ClassNotFoundException e) {
+ // In case that the driver is not available do not perform tests for this system.
+ LOGGER.info(Localization.lang("%0 driver not available.", dbms.toString()));
+ }
+ }
+ return dbmsTypes;
+ }
+}
diff --git a/src/main/java/net/sf/jabref/shared/DBMSConnectionProperties.java b/src/main/java/net/sf/jabref/shared/DBMSConnectionProperties.java
index d85283c..720160f 100644
--- a/src/main/java/net/sf/jabref/shared/DBMSConnectionProperties.java
+++ b/src/main/java/net/sf/jabref/shared/DBMSConnectionProperties.java
@@ -1,10 +1,23 @@
package net.sf.jabref.shared;
+import java.io.UnsupportedEncodingException;
+import java.security.GeneralSecurityException;
+import java.util.Objects;
+import java.util.Optional;
+
+import net.sf.jabref.shared.prefs.SharedDatabasePreferences;
+import net.sf.jabref.shared.security.Password;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
/**
- * Keeps all essential data for establishing a new connection to a DBMS using {@link DBMSConnector}.
+ * Keeps all essential data for establishing a new connection to a DBMS using {@link DBMSConnection}.
*/
public class DBMSConnectionProperties {
+ private static final Log LOGGER = LogFactory.getLog(DBMSConnectionProperties.class);
+
private DBMSType type;
private String host;
private int port;
@@ -17,6 +30,10 @@ public class DBMSConnectionProperties {
// no data
}
+ public DBMSConnectionProperties(SharedDatabasePreferences prefs) {
+ setFromPreferences(prefs);
+ }
+
public DBMSConnectionProperties(DBMSType type, String host, int port, String database, String user,
String password) {
this.type = type;
@@ -75,4 +92,55 @@ public class DBMSConnectionProperties {
this.password = password;
}
+ /**
+ * Compares all properties except the password.
+ */
+ public boolean equals(DBMSConnectionProperties properties) {
+ return this.type.equals(properties.getType())
+ && this.host.equalsIgnoreCase(properties.getHost())
+ && this.port == properties.getPort()
+ && this.database.equals(properties.getDatabase())
+ && this.user.equals(properties.getUser());
+ }
+
+ /**
+ * Gets all required data from {@link SharedDatabasePreferences} and sets them if present.
+ */
+ private void setFromPreferences(SharedDatabasePreferences prefs) {
+ if (prefs.getType().isPresent()) {
+ Optional<DBMSType> dbmsType = DBMSType.fromString(prefs.getType().get());
+ if (dbmsType.isPresent()) {
+ this.type = dbmsType.get();
+ }
+ }
+
+ prefs.getHost().ifPresent(theHost -> this.host = theHost);
+ prefs.getPort().ifPresent(thePort -> this.port = Integer.parseInt(thePort));
+ prefs.getName().ifPresent(theDatabase -> this.database = theDatabase);
+
+ if (prefs.getUser().isPresent()) {
+ this.user = prefs.getUser().get();
+ if (prefs.getPassword().isPresent()) {
+ try {
+ this.password = new Password(prefs.getPassword().get().toCharArray(), prefs.getUser().get()).decrypt();
+ } catch (UnsupportedEncodingException | GeneralSecurityException e) {
+ LOGGER.error("Could not decrypt password", e);
+ }
+ }
+ }
+
+ if (!prefs.getPassword().isPresent()) {
+ // Some DBMS require a non-null value as a password (in case of using an empty string).
+ this.password = "";
+ }
+ }
+
+ public boolean isValid() {
+ return Objects.nonNull(type)
+ && Objects.nonNull(host)
+ && Objects.nonNull(port)
+ && Objects.nonNull(database)
+ && Objects.nonNull(user)
+ && Objects.nonNull(password);
+ }
}
diff --git a/src/main/java/net/sf/jabref/shared/DBMSConnector.java b/src/main/java/net/sf/jabref/shared/DBMSConnector.java
deleted file mode 100644
index db3a829..0000000
--- a/src/main/java/net/sf/jabref/shared/DBMSConnector.java
+++ /dev/null
@@ -1,69 +0,0 @@
-package net.sf.jabref.shared;
-
-import java.sql.Connection;
-import java.sql.DriverManager;
-import java.sql.SQLException;
-import java.util.HashSet;
-import java.util.Set;
-
-import net.sf.jabref.logic.l10n.Localization;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * Used to establish connections between JabRef and database systems like MySQL, PostgreSQL and Oracle.
- */
-public class DBMSConnector {
-
- private static final Log LOGGER = LogFactory.getLog(DBMSConnector.class);
-
-
- /**
- * Determines the suitable driver and retrieves a working SQL Connection in normal case.
- *
- * @param dbmsType Enum entry of {@link DBMSType} which determines the driver
- * @param host Hostname, Domain or IP address
- * @param port Port number the server is listening on
- * @param database An already existent database name.
- * @param user Username
- * @param password Password
- * @return
- * @throws ClassNotFoundException Thrown if no suitable drivers were found
- * @throws SQLException Thrown if connection has failed
- */
- public static Connection getNewConnection(DBMSConnectionProperties properties)
- throws ClassNotFoundException, SQLException {
-
- try {
- DriverManager.setLoginTimeout(3);
- return DriverManager.getConnection(
- properties.getType().getUrl(properties.getHost(), properties.getPort(), properties.getDatabase()),
- properties.getUser(), properties.getPassword());
- } catch (SQLException e) {
- // Some systems like PostgreSQL retrieves 0 to every exception.
- // Therefore a stable error determination is not possible.
- LOGGER.error("Could not connect to database: " + e.getMessage() + " - Error code: " + e.getErrorCode());
-
- throw e;
- }
- }
-
- /**
- * Returns a Set of {@link DBMSType} which is supported by available drivers.
- */
- public static Set<DBMSType> getAvailableDBMSTypes() {
- Set<DBMSType> dbmsTypes = new HashSet<>();
-
- for (DBMSType dbms : DBMSType.values()) {
- try {
- Class.forName(dbms.getDriverClassPath());
- dbmsTypes.add(dbms);
- } catch (ClassNotFoundException e) {
- // In case that the driver is not available do not perform tests for this system.
- LOGGER.info(Localization.lang("%0 driver not available.", dbms.toString()));
- }
- }
- return dbmsTypes;
- }
-}
diff --git a/src/main/java/net/sf/jabref/shared/DBMSProcessor.java b/src/main/java/net/sf/jabref/shared/DBMSProcessor.java
index 1b1fbd4..86595a7 100644
--- a/src/main/java/net/sf/jabref/shared/DBMSProcessor.java
+++ b/src/main/java/net/sf/jabref/shared/DBMSProcessor.java
@@ -13,11 +13,11 @@ import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
+import java.util.UUID;
-import net.sf.jabref.event.source.EntryEventSource;
import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.event.EntryEventSource;
import net.sf.jabref.shared.exception.OfflineLockException;
-import net.sf.jabref.shared.exception.SharedEntryNotPresentException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -27,16 +27,19 @@ import org.apache.commons.logging.LogFactory;
*/
public abstract class DBMSProcessor {
- protected static final Log LOGGER = LogFactory.getLog(DBMSConnector.class);
+ protected static final Log LOGGER = LogFactory.getLog(DBMSProcessor.class);
+
protected final Connection connection;
- /**
- * @param connection Working SQL connection
- * @param dbmsType Instance of {@link DBMSType}
- */
- public DBMSProcessor(Connection connection) {
- this.connection = connection;
+ protected DBMSConnectionProperties connectionProperties;
+
+ public static final String PROCESSOR_ID = UUID.randomUUID().toString();
+
+
+ protected DBMSProcessor(DBMSConnection dbmsConnection) {
+ this.connection = dbmsConnection.getConnection();
+ this.connectionProperties = dbmsConnection.getProperties();
}
/**
@@ -114,10 +117,12 @@ public abstract class DBMSProcessor {
* Escapes parts of SQL expressions like table or field name to match the conventions
* of the database system using the current dbmsType.
*
+ * This method is package private, because of DBMSProcessorTest
+ *
* @param expression Table or field name
* @return Correctly escaped expression
*/
- public abstract String escape(String expression);
+ abstract String escape(String expression);
/**
@@ -126,8 +131,50 @@ public abstract class DBMSProcessor {
* @param bibEntry {@link BibEntry} to be inserted
*/
public void insertEntry(BibEntry bibEntry) {
+ if (!checkForBibEntryExistence(bibEntry)) {
+ insertIntoEntryTable(bibEntry);
+ insertIntoFieldTable(bibEntry);
+ }
+ }
+ /**
+ * Inserts the given bibEntry into ENTRY table.
+ *
+ * @param bibEntry {@link BibEntry} to be inserted
+ */
+ protected void insertIntoEntryTable(BibEntry bibEntry) {
+ // Inserting into ENTRY table
+ StringBuilder insertIntoEntryQuery = new StringBuilder()
+ .append("INSERT INTO ")
+ .append(escape("ENTRY"))
+ .append("(")
+ .append(escape("TYPE"))
+ .append(") VALUES(?)");
+
+ // This is the only method to get generated keys which is accepted by MySQL, PostgreSQL and Oracle.
+ try (PreparedStatement preparedEntryStatement = connection.prepareStatement(insertIntoEntryQuery.toString(),
+ new String[] {"SHARED_ID"})) {
+
+ preparedEntryStatement.setString(1, bibEntry.getType());
+ preparedEntryStatement.executeUpdate();
+
+ try (ResultSet generatedKeys = preparedEntryStatement.getGeneratedKeys()) {
+ if (generatedKeys.next()) {
+ bibEntry.getSharedBibEntryData().setSharedID(generatedKeys.getInt(1)); // set generated ID locally
+ }
+ }
+ } catch (SQLException e) {
+ LOGGER.error("SQL Error: ", e);
+ }
+ }
+
+ /**
+ * Checks whether the given bibEntry already exists on shared database.
+ * @param bibEntry {@link BibEntry} to be checked
+ * @return <code>true</code> if existent, else <code>false</code>
+ */
+ private boolean checkForBibEntryExistence(BibEntry bibEntry) {
try {
// Check if already exists
int sharedID = bibEntry.getSharedBibEntryData().getSharedID();
@@ -143,53 +190,43 @@ public abstract class DBMSProcessor {
preparedSelectStatement.setInt(1, sharedID);
try (ResultSet resultSet = preparedSelectStatement.executeQuery()) {
if (resultSet.next()) {
- return;
+ return true;
}
}
}
}
+ } catch (SQLException e) {
+ LOGGER.error("SQL Error: ", e);
+ }
+ return false;
+ }
- // Inserting into ENTRY table
- StringBuilder insertIntoEntryQuery = new StringBuilder()
- .append("INSERT INTO ")
- .append(escape("ENTRY"))
- .append("(")
- .append(escape("TYPE"))
- .append(") VALUES(?)");
-
- // This is the only method to get generated keys which is accepted by MySQL, PostgreSQL and Oracle.
- try (PreparedStatement preparedEntryStatement = connection.prepareStatement(insertIntoEntryQuery.toString(),
- new String[] {"SHARED_ID"})) {
-
- preparedEntryStatement.setString(1, bibEntry.getType());
- preparedEntryStatement.executeUpdate();
-
- try (ResultSet generatedKeys = preparedEntryStatement.getGeneratedKeys()) {
- if (generatedKeys.next()) {
- bibEntry.getSharedBibEntryData().setSharedID(generatedKeys.getInt(1)); // set generated ID locally
- }
- }
-
- // Inserting into FIELD table
- for (String fieldName : bibEntry.getFieldNames()) {
- StringBuilder insertFieldQuery = new StringBuilder()
- .append("INSERT INTO ")
- .append(escape("FIELD"))
- .append("(")
- .append(escape("ENTRY_SHARED_ID"))
- .append(", ")
- .append(escape("NAME"))
- .append(", ")
- .append(escape("VALUE"))
- .append(") VALUES(?, ?, ?)");
-
- try (PreparedStatement preparedFieldStatement = connection.prepareStatement(insertFieldQuery.toString())) {
- // columnIndex starts with 1
- preparedFieldStatement.setInt(1, bibEntry.getSharedBibEntryData().getSharedID());
- preparedFieldStatement.setString(2, fieldName);
- preparedFieldStatement.setString(3, bibEntry.getFieldOptional(fieldName).get());
- preparedFieldStatement.executeUpdate();
- }
+ /**
+ * Inserts the given bibEntry into FIELD table.
+ *
+ * @param bibEntry {@link BibEntry} to be inserted
+ */
+ private void insertIntoFieldTable(BibEntry bibEntry) {
+ try {
+ // Inserting into FIELD table
+ for (String fieldName : bibEntry.getFieldNames()) {
+ StringBuilder insertFieldQuery = new StringBuilder()
+ .append("INSERT INTO ")
+ .append(escape("FIELD"))
+ .append("(")
+ .append(escape("ENTRY_SHARED_ID"))
+ .append(", ")
+ .append(escape("NAME"))
+ .append(", ")
+ .append(escape("VALUE"))
+ .append(") VALUES(?, ?, ?)");
+
+ try (PreparedStatement preparedFieldStatement = connection.prepareStatement(insertFieldQuery.toString())) {
+ // columnIndex starts with 1
+ preparedFieldStatement.setInt(1, bibEntry.getSharedBibEntryData().getSharedID());
+ preparedFieldStatement.setString(2, fieldName);
+ preparedFieldStatement.setString(3, bibEntry.getField(fieldName).get());
+ preparedFieldStatement.executeUpdate();
}
}
} catch (SQLException e) {
@@ -203,14 +240,14 @@ public abstract class DBMSProcessor {
* @param localBibEntry {@link BibEntry} affected by changes
* @throws SQLException
*/
- public void updateEntry(BibEntry localBibEntry) throws OfflineLockException, SharedEntryNotPresentException, SQLException {
+ public void updateEntry(BibEntry localBibEntry) throws OfflineLockException, SQLException {
connection.setAutoCommit(false); // disable auto commit due to transaction
try {
Optional<BibEntry> sharedEntryOptional = getSharedEntry(localBibEntry.getSharedBibEntryData().getSharedID());
if (!sharedEntryOptional.isPresent()) {
- throw new SharedEntryNotPresentException(localBibEntry);
+ return;
}
BibEntry sharedBibEntry = sharedEntryOptional.get();
@@ -288,7 +325,7 @@ public abstract class DBMSProcessor {
private void insertOrUpdateFields(BibEntry localBibEntry) throws SQLException {
for (String fieldName : localBibEntry.getFieldNames()) {
// avoiding to use deprecated BibEntry.getField() method. null values are accepted by PreparedStatement!
- Optional<String> valueOptional = localBibEntry.getFieldOptional(fieldName);
+ Optional<String> valueOptional = localBibEntry.getField(fieldName);
String value = null;
if (valueOptional.isPresent()) {
value = valueOptional.get();
@@ -487,8 +524,7 @@ public abstract class DBMSProcessor {
/**
* Clears and sets all shared meta data.
*
- * @param metaData JabRef meta data.
- * @throws SQLException
+ * @param data JabRef meta data as map
*/
public void setSharedMetaData(Map<String, String> data) throws SQLException {
connection.createStatement().executeUpdate("TRUNCATE TABLE " + escape("METADATA")); // delete data all data from table
@@ -517,7 +553,8 @@ public abstract class DBMSProcessor {
/**
* Returns a new instance of the abstract type {@link DBMSProcessor}
*/
- public static DBMSProcessor getProcessorInstance(Connection connection, DBMSType type) {
+ public static DBMSProcessor getProcessorInstance(DBMSConnection connection) {
+ DBMSType type = connection.getProperties().getType();
if (type == DBMSType.MYSQL) {
return new MySQLProcessor(connection);
} else if (type == DBMSType.POSTGRESQL) {
@@ -528,4 +565,33 @@ public abstract class DBMSProcessor {
return null; // can never happen except new types were added without updating this method.
}
+ public DBMSConnectionProperties getDBMSConnectionProperties() {
+ return this.connectionProperties;
+ }
+
+ /**
+ * Listens for notifications from DBMS.
+ * Needs to be implemented if LiveUpdate is supported by the DBMS
+ *
+ * @param dbmsSynchronizer {@link DBMSSynchronizer} which handles the notification.
+ */
+ public void startNotificationListener(@SuppressWarnings("unused") DBMSSynchronizer dbmsSynchronizer) {
+ // nothing to do
+ }
+
+ /**
+ * Terminates the notification listener.
+ * Needs to be implemented if LiveUpdate is supported by the DBMS
+ */
+ public void stopNotificationListener() {
+ // nothing to do
+ }
+
+ /**
+ * Notifies all clients ({@link DBMSSynchronizer}) which are connected to the same DBMS.
+ * Needs to be implemented if LiveUpdate is supported by the DBMS
+ */
+ public void notifyClients() {
+ // nothing to do
+ }
}
diff --git a/src/main/java/net/sf/jabref/shared/DBMSSynchronizer.java b/src/main/java/net/sf/jabref/shared/DBMSSynchronizer.java
index 122648e..aeafa76 100644
--- a/src/main/java/net/sf/jabref/shared/DBMSSynchronizer.java
+++ b/src/main/java/net/sf/jabref/shared/DBMSSynchronizer.java
@@ -4,27 +4,31 @@ import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Optional;
import java.util.Set;
-import net.sf.jabref.BibDatabaseContext;
-import net.sf.jabref.MetaData;
-import net.sf.jabref.event.MetaDataChangedEvent;
-import net.sf.jabref.event.source.EntryEventSource;
import net.sf.jabref.logic.exporter.BibDatabaseWriter;
-import net.sf.jabref.logic.importer.util.ParseException;
+import net.sf.jabref.logic.exporter.MetaDataSerializer;
+import net.sf.jabref.logic.importer.ParseException;
+import net.sf.jabref.logic.importer.util.MetaDataParser;
+import net.sf.jabref.model.bibtexkeypattern.GlobalBibtexKeyPattern;
import net.sf.jabref.model.database.BibDatabase;
+import net.sf.jabref.model.database.BibDatabaseContext;
+import net.sf.jabref.model.database.event.EntryAddedEvent;
+import net.sf.jabref.model.database.event.EntryRemovedEvent;
import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.model.event.EntryAddedEvent;
-import net.sf.jabref.model.event.EntryEvent;
-import net.sf.jabref.model.event.EntryRemovedEvent;
-import net.sf.jabref.model.event.FieldChangedEvent;
+import net.sf.jabref.model.entry.event.EntryEvent;
+import net.sf.jabref.model.entry.event.EntryEventSource;
+import net.sf.jabref.model.entry.event.FieldChangedEvent;
+import net.sf.jabref.model.metadata.MetaData;
+import net.sf.jabref.model.metadata.event.MetaDataChangedEvent;
import net.sf.jabref.shared.event.ConnectionLostEvent;
import net.sf.jabref.shared.event.SharedEntryNotPresentEvent;
import net.sf.jabref.shared.event.UpdateRefusedEvent;
import net.sf.jabref.shared.exception.DatabaseNotSupportedException;
+import net.sf.jabref.shared.exception.InvalidDBMSConnectionPropertiesException;
import net.sf.jabref.shared.exception.OfflineLockException;
-import net.sf.jabref.shared.exception.SharedEntryNotPresentException;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
@@ -37,7 +41,7 @@ import org.apache.commons.logging.LogFactory;
*/
public class DBMSSynchronizer {
- private static final Log LOGGER = LogFactory.getLog(DBMSConnector.class);
+ private static final Log LOGGER = LogFactory.getLog(DBMSSynchronizer.class);
private DBMSProcessor dbmsProcessor;
private DBMSType dbmsType;
@@ -47,13 +51,17 @@ public class DBMSSynchronizer {
private final BibDatabase bibDatabase;
private final EventBus eventBus;
private Connection currentConnection;
+ private final Character keywordSeparator;
+ private GlobalBibtexKeyPattern globalCiteKeyPattern;
-
- public DBMSSynchronizer(BibDatabaseContext bibDatabaseContext) {
- this.bibDatabaseContext = bibDatabaseContext;
+ public DBMSSynchronizer(BibDatabaseContext bibDatabaseContext, Character keywordSeparator,
+ GlobalBibtexKeyPattern globalCiteKeyPattern) {
+ this.bibDatabaseContext = Objects.requireNonNull(bibDatabaseContext);
this.bibDatabase = bibDatabaseContext.getDatabase();
this.metaData = bibDatabaseContext.getMetaData();
this.eventBus = new EventBus();
+ this.keywordSeparator = keywordSeparator;
+ this.globalCiteKeyPattern = Objects.requireNonNull(globalCiteKeyPattern);
}
/**
@@ -113,9 +121,17 @@ public class DBMSSynchronizer {
@Subscribe
public void listen(MetaDataChangedEvent event) {
if (checkCurrentConnection()) {
- synchronizeSharedMetaData(event.getMetaData());
+ synchronizeSharedMetaData(event.getMetaData(), globalCiteKeyPattern);
synchronizeLocalDatabase();
applyMetaData();
+ dbmsProcessor.notifyClients();
+ }
+ }
+
+ @Subscribe
+ public void listen(EntryEvent event) {
+ if (isEventSourceAccepted(event)) {
+ dbmsProcessor.notifyClients();
}
}
@@ -123,7 +139,6 @@ public class DBMSSynchronizer {
* Sets the table structure of shared database if needed and pulls all shared entries
* to the new local database.
*
- * @param bibDatabase Local {@link BibDatabase}
* @throws DatabaseNotSupportedException if the version of shared database does not match
* the version of current shared database support ({@link DBMSProcessor}).
*/
@@ -139,6 +154,7 @@ public class DBMSSynchronizer {
}
}
+ dbmsProcessor.startNotificationListener(this);
synchronizeLocalMetaData();
synchronizeLocalDatabase();
}
@@ -172,7 +188,7 @@ public class DBMSSynchronizer {
localEntry.getSharedBibEntryData()
.setVersion(sharedEntry.get().getSharedBibEntryData().getVersion());
for (String field : sharedEntry.get().getFieldNames()) {
- localEntry.setField(field, sharedEntry.get().getFieldOptional(field), EntryEventSource.SHARED);
+ localEntry.setField(field, sharedEntry.get().getField(field), EntryEventSource.SHARED);
}
Set<String> redundantLocalEntryFields = localEntry.getFieldNames();
@@ -212,6 +228,7 @@ public class DBMSSynchronizer {
}
}
if (!match) {
+ eventBus.post(new SharedEntryNotPresentEvent(localEntry));
bibDatabase.removeEntry(localEntry, EntryEventSource.SHARED); // Should not reach the listeners above.
i--; // due to index shift on localEntries
}
@@ -230,8 +247,6 @@ public class DBMSSynchronizer {
dbmsProcessor.updateEntry(bibEntry);
} catch (OfflineLockException exception) {
eventBus.post(new UpdateRefusedEvent(bibDatabaseContext, exception.getLocalBibEntry(), exception.getSharedBibEntry()));
- } catch (SharedEntryNotPresentException exception) {
- eventBus.post(new SharedEntryNotPresentEvent(exception.getNonPresentBibEntry()));
} catch (SQLException e) {
LOGGER.error("SQL Error: ", e);
}
@@ -246,7 +261,7 @@ public class DBMSSynchronizer {
}
try {
- metaData.setData(dbmsProcessor.getSharedMetaData());
+ MetaDataParser.parse(metaData, dbmsProcessor.getSharedMetaData(), keywordSeparator);
} catch (ParseException e) {
LOGGER.error("Parse error", e);
}
@@ -255,12 +270,12 @@ public class DBMSSynchronizer {
/**
* Synchronizes all shared meta data.
*/
- public void synchronizeSharedMetaData(MetaData data) {
+ private void synchronizeSharedMetaData(MetaData data, GlobalBibtexKeyPattern globalCiteKeyPattern) {
if (!checkCurrentConnection()) {
return;
}
try {
- dbmsProcessor.setSharedMetaData(data.getAsStringMap());
+ dbmsProcessor.setSharedMetaData(MetaDataSerializer.getSerializedStringMap(data, globalCiteKeyPattern));
} catch (SQLException e) {
LOGGER.error("SQL Error: ", e);
}
@@ -280,8 +295,6 @@ public class DBMSSynchronizer {
dbmsProcessor.updateEntry(bibEntry);
} catch (OfflineLockException exception) {
eventBus.post(new UpdateRefusedEvent(bibDatabaseContext, exception.getLocalBibEntry(), exception.getSharedBibEntry()));
- } catch (SharedEntryNotPresentException exception) {
- eventBus.post(new SharedEntryNotPresentEvent(exception.getNonPresentBibEntry()));
} catch (SQLException e) {
LOGGER.error("SQL Error: ", e);
}
@@ -332,16 +345,26 @@ public class DBMSSynchronizer {
return ((eventSource == EntryEventSource.LOCAL) || (eventSource == EntryEventSource.UNDO));
}
- public void openSharedDatabase(Connection connection, DBMSType type, String name) throws DatabaseNotSupportedException, SQLException {
- this.dbmsType = type;
- this.dbName = name;
- this.currentConnection = connection;
- this.dbmsProcessor = DBMSProcessor.getProcessorInstance(connection, type);
+ public void openSharedDatabase(DBMSConnection connection) throws DatabaseNotSupportedException, SQLException {
+ this.dbmsType = connection.getProperties().getType();
+ this.dbName = connection.getProperties().getDatabase();
+ this.currentConnection = connection.getConnection();
+ this.dbmsProcessor = DBMSProcessor.getProcessorInstance(connection);
initializeDatabases();
}
- public void openSharedDatabase(DBMSConnectionProperties properties) throws ClassNotFoundException, SQLException, DatabaseNotSupportedException {
- openSharedDatabase(DBMSConnector.getNewConnection(properties), properties.getType(), properties.getDatabase());
+ public void openSharedDatabase(DBMSConnectionProperties properties)
+ throws SQLException, DatabaseNotSupportedException, InvalidDBMSConnectionPropertiesException {
+ openSharedDatabase(new DBMSConnection(properties));
+ }
+
+ public void closeSharedDatabase() {
+ try {
+ dbmsProcessor.stopNotificationListener();
+ currentConnection.close();
+ } catch (SQLException e) {
+ LOGGER.error("SQL Error:", e);
+ }
}
private boolean isPresentLocalBibEntry(BibEntry bibEntry) {
diff --git a/src/main/java/net/sf/jabref/shared/MySQLProcessor.java b/src/main/java/net/sf/jabref/shared/MySQLProcessor.java
index 7e66919..baaed26 100644
--- a/src/main/java/net/sf/jabref/shared/MySQLProcessor.java
+++ b/src/main/java/net/sf/jabref/shared/MySQLProcessor.java
@@ -1,6 +1,5 @@
package net.sf.jabref.shared;
-import java.sql.Connection;
import java.sql.SQLException;
/**
@@ -8,11 +7,7 @@ import java.sql.SQLException;
*/
public class MySQLProcessor extends DBMSProcessor {
- /**
- * @param connection Working SQL connection
- * @param dbmsType Instance of {@link DBMSType}
- */
- public MySQLProcessor(Connection connection) {
+ public MySQLProcessor(DBMSConnection connection) {
super(connection);
}
@@ -43,7 +38,7 @@ public class MySQLProcessor extends DBMSProcessor {
}
@Override
- public String escape(String expression) {
+ String escape(String expression) {
return "`" + expression + "`";
}
}
diff --git a/src/main/java/net/sf/jabref/shared/OracleProcessor.java b/src/main/java/net/sf/jabref/shared/OracleProcessor.java
index 24425a1..280a9d1 100644
--- a/src/main/java/net/sf/jabref/shared/OracleProcessor.java
+++ b/src/main/java/net/sf/jabref/shared/OracleProcessor.java
@@ -1,18 +1,28 @@
package net.sf.jabref.shared;
-import java.sql.Connection;
import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Properties;
+
+import net.sf.jabref.shared.listener.OracleNotificationListener;
+
+import oracle.jdbc.OracleConnection;
+import oracle.jdbc.OracleStatement;
+import oracle.jdbc.dcn.DatabaseChangeRegistration;
/**
* Processes all incoming or outgoing bib data to Oracle database and manages its structure.
*/
public class OracleProcessor extends DBMSProcessor {
- /**
- * @param connection Working SQL connection
- * @param dbmsType Instance of {@link DBMSType}
- */
- public OracleProcessor(Connection connection) {
+ private OracleConnection oracleConnection;
+
+ private OracleNotificationListener listener;
+
+ private DatabaseChangeRegistration databaseChangeRegistration;
+
+
+ public OracleProcessor(DBMSConnection connection) {
super(connection);
}
@@ -50,7 +60,54 @@ public class OracleProcessor extends DBMSProcessor {
}
@Override
- public String escape(String expression) {
+ String escape(String expression) {
return "\"" + expression + "\"";
}
+
+ @Override
+ public void startNotificationListener(DBMSSynchronizer dbmsSynchronizer) {
+
+ this.listener = new OracleNotificationListener(dbmsSynchronizer);
+
+ try {
+ oracleConnection = (OracleConnection) connection;
+
+ Properties properties = new Properties();
+ properties.setProperty(OracleConnection.DCN_NOTIFY_ROWIDS, "true");
+ properties.setProperty(OracleConnection.DCN_QUERY_CHANGE_NOTIFICATION, "true");
+
+ databaseChangeRegistration = oracleConnection.registerDatabaseChangeNotification(properties);
+ databaseChangeRegistration.addListener(listener);
+
+ try (Statement statement = oracleConnection.createStatement()) {
+ ((OracleStatement) statement).setDatabaseChangeRegistration(databaseChangeRegistration);
+ StringBuilder selectQuery = new StringBuilder()
+ .append("SELECT 1 FROM ")
+ .append(escape("ENTRY"))
+ .append(", ")
+ .append(escape("METADATA"));
+ // this execution registers all tables mentioned in selectQuery
+ statement.executeQuery(selectQuery.toString());
+ }
+
+ } catch (SQLException e) {
+ LOGGER.error("SQL Error: ", e);
+ }
+
+ }
+
+ @Override
+ public void stopNotificationListener() {
+ try {
+ oracleConnection.unregisterDatabaseChangeNotification(databaseChangeRegistration);
+ oracleConnection.close();
+ } catch (SQLException e) {
+ LOGGER.error("SQL Error: ", e);
+ }
+ }
+
+ @Override
+ public void notifyClients() {
+ // Do nothing because Oracle triggers notifications automatically.
+ }
}
diff --git a/src/main/java/net/sf/jabref/shared/PostgreSQLProcessor.java b/src/main/java/net/sf/jabref/shared/PostgreSQLProcessor.java
index afe4a1e..1191eb2 100644
--- a/src/main/java/net/sf/jabref/shared/PostgreSQLProcessor.java
+++ b/src/main/java/net/sf/jabref/shared/PostgreSQLProcessor.java
@@ -1,18 +1,21 @@
package net.sf.jabref.shared;
import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import net.sf.jabref.model.entry.BibEntry;
/**
* Processes all incoming or outgoing bib data to PostgreSQL database and manages its structure.
*/
public class PostgreSQLProcessor extends DBMSProcessor {
- /**
- * @param connection Working SQL connection
- * @param dbmsType Instance of {@link DBMSType}
- */
- public PostgreSQLProcessor(Connection connection) {
+ public PostgreSQLProcessor(DBMSConnection connection) {
super(connection);
}
@@ -42,7 +45,35 @@ public class PostgreSQLProcessor extends DBMSProcessor {
}
@Override
- public String escape(String expression) {
+ protected void insertIntoEntryTable(BibEntry bibEntry) {
+ // Inserting into ENTRY table
+ StringBuilder insertIntoEntryQuery = new StringBuilder()
+ .append("INSERT INTO ")
+ .append(escape("ENTRY"))
+ .append("(")
+ .append(escape("TYPE"))
+ .append(") VALUES(?)");
+
+ // This is the only method to get generated keys which is accepted by MySQL, PostgreSQL and Oracle.
+ try (PreparedStatement preparedEntryStatement = connection.prepareStatement(insertIntoEntryQuery.toString(),
+ Statement.RETURN_GENERATED_KEYS)) {
+
+ preparedEntryStatement.setString(1, bibEntry.getType());
+ preparedEntryStatement.executeUpdate();
+
+ try (ResultSet generatedKeys = preparedEntryStatement.getGeneratedKeys()) {
+ if (generatedKeys.next()) {
+ bibEntry.getSharedBibEntryData().setSharedID(generatedKeys.getInt(1)); // set generated ID locally
+ }
+ }
+ } catch (SQLException e) {
+ LOGGER.error("SQL Error: ", e);
+ }
+ }
+
+ @Override
+ String escape(String expression) {
return "\"" + expression + "\"";
}
+
}
diff --git a/src/main/java/net/sf/jabref/shared/event/ConnectionLostEvent.java b/src/main/java/net/sf/jabref/shared/event/ConnectionLostEvent.java
index 798d19c..7e784dd 100644
--- a/src/main/java/net/sf/jabref/shared/event/ConnectionLostEvent.java
+++ b/src/main/java/net/sf/jabref/shared/event/ConnectionLostEvent.java
@@ -1,6 +1,6 @@
package net.sf.jabref.shared.event;
-import net.sf.jabref.BibDatabaseContext;
+import net.sf.jabref.model.database.BibDatabaseContext;
/**
* A new {@link ConnectionLostEvent} is fired, when the connection to the shared database gets lost.
diff --git a/src/main/java/net/sf/jabref/shared/event/UpdateRefusedEvent.java b/src/main/java/net/sf/jabref/shared/event/UpdateRefusedEvent.java
index 1170f19..e50bb95 100644
--- a/src/main/java/net/sf/jabref/shared/event/UpdateRefusedEvent.java
+++ b/src/main/java/net/sf/jabref/shared/event/UpdateRefusedEvent.java
@@ -1,6 +1,6 @@
package net.sf.jabref.shared.event;
-import net.sf.jabref.BibDatabaseContext;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.entry.BibEntry;
/**
diff --git a/src/main/java/net/sf/jabref/shared/exception/InvalidDBMSConnectionPropertiesException.java b/src/main/java/net/sf/jabref/shared/exception/InvalidDBMSConnectionPropertiesException.java
new file mode 100644
index 0000000..900bd09
--- /dev/null
+++ b/src/main/java/net/sf/jabref/shared/exception/InvalidDBMSConnectionPropertiesException.java
@@ -0,0 +1,11 @@
+package net.sf.jabref.shared.exception;
+
+/**
+ * This exception is thrown in case that {@link DBMSConnectionProperties} does not provide all data needed for a connection.
+ */
+public class InvalidDBMSConnectionPropertiesException extends Exception {
+
+ public InvalidDBMSConnectionPropertiesException() {
+ super("Required connection details not present.");
+ }
+}
diff --git a/src/main/java/net/sf/jabref/shared/exception/NotASharedDatabaseException.java b/src/main/java/net/sf/jabref/shared/exception/NotASharedDatabaseException.java
new file mode 100644
index 0000000..9c2aa0e
--- /dev/null
+++ b/src/main/java/net/sf/jabref/shared/exception/NotASharedDatabaseException.java
@@ -0,0 +1,12 @@
+package net.sf.jabref.shared.exception;
+
+
+/**
+ * This exception is thrown when a shared database is required, but it actually isn't one.
+ */
+public class NotASharedDatabaseException extends Exception {
+
+ public NotASharedDatabaseException() {
+ super("Required database is not shared.");
+ }
+}
diff --git a/src/main/java/net/sf/jabref/shared/listener/OracleNotificationListener.java b/src/main/java/net/sf/jabref/shared/listener/OracleNotificationListener.java
new file mode 100644
index 0000000..a083c8e
--- /dev/null
+++ b/src/main/java/net/sf/jabref/shared/listener/OracleNotificationListener.java
@@ -0,0 +1,24 @@
+package net.sf.jabref.shared.listener;
+
+import net.sf.jabref.shared.DBMSSynchronizer;
+
+import oracle.jdbc.dcn.DatabaseChangeEvent;
+import oracle.jdbc.dcn.DatabaseChangeListener;
+
+/**
+ * A listener for Oracle database notifications.
+ */
+public class OracleNotificationListener implements DatabaseChangeListener {
+
+ private final DBMSSynchronizer dbmsSynchronizer;
+
+
+ public OracleNotificationListener(DBMSSynchronizer dbmsSynchronizer) {
+ this.dbmsSynchronizer = dbmsSynchronizer;
+ }
+
+ @Override
+ public void onDatabaseChangeNotification(DatabaseChangeEvent event) {
+ dbmsSynchronizer.pullChanges();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/net/sf/jabref/shared/prefs/SharedDatabasePreferences.java b/src/main/java/net/sf/jabref/shared/prefs/SharedDatabasePreferences.java
new file mode 100644
index 0000000..8fd42df
--- /dev/null
+++ b/src/main/java/net/sf/jabref/shared/prefs/SharedDatabasePreferences.java
@@ -0,0 +1,134 @@
+package net.sf.jabref.shared.prefs;
+
+import java.io.UnsupportedEncodingException;
+import java.security.GeneralSecurityException;
+import java.util.Optional;
+import java.util.prefs.BackingStoreException;
+import java.util.prefs.Preferences;
+
+import net.sf.jabref.JabRefMain;
+import net.sf.jabref.gui.shared.ConnectToSharedDatabaseDialog;
+import net.sf.jabref.shared.DBMSConnectionProperties;
+import net.sf.jabref.shared.security.Password;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Stores and reads persistent data for {@link ConnectToSharedDatabaseDialog}.
+ */
+public class SharedDatabasePreferences {
+
+ private static final Log LOGGER = LogFactory.getLog(SharedDatabasePreferences.class);
+
+ private static final String DEFAULT_NODE = "default";
+ private static final String PARENT_NODE = "jabref-shared";
+
+ private static final String SHARED_DATABASE_TYPE = "sharedDatabaseType";
+ private static final String SHARED_DATABASE_HOST = "sharedDatabaseHost";
+ private static final String SHARED_DATABASE_PORT = "sharedDatabasePort";
+ private static final String SHARED_DATABASE_NAME = "sharedDatabaseName";
+ private static final String SHARED_DATABASE_USER = "sharedDatabaseUser";
+ private static final String SHARED_DATABASE_PASSWORD = "sharedDatabasePassword";
+ private static final String SHARED_DATABASE_REMEMBER_PASSWORD = "sharedDatabaseRememberPassword";
+
+ // This {@link Preferences} is used only for things which should not appear in real JabRefPreferences due to security reasons.
+ private final Preferences internalPrefs;
+
+
+ public SharedDatabasePreferences() {
+ this(DEFAULT_NODE);
+ }
+
+ public SharedDatabasePreferences(String sharedDatabaseID) {
+ internalPrefs = Preferences.userNodeForPackage(JabRefMain.class).parent().node(PARENT_NODE).node(sharedDatabaseID);
+ }
+
+ public Optional<String> getType() {
+ return getOptionalValue(SHARED_DATABASE_TYPE);
+ }
+
+ public Optional<String> getHost() {
+ return getOptionalValue(SHARED_DATABASE_HOST);
+ }
+
+ public Optional<String> getPort() {
+ return getOptionalValue(SHARED_DATABASE_PORT);
+ }
+
+ public Optional<String> getName() {
+ return getOptionalValue(SHARED_DATABASE_NAME);
+ }
+
+ public Optional<String> getUser() {
+ return getOptionalValue(SHARED_DATABASE_USER);
+ }
+
+ public Optional<String> getPassword() {
+ return getOptionalValue(SHARED_DATABASE_PASSWORD);
+ }
+
+ public boolean getRememberPassword() {
+ return internalPrefs.getBoolean(SHARED_DATABASE_REMEMBER_PASSWORD, false);
+ }
+
+ public void setType(String type) {
+ internalPrefs.put(SHARED_DATABASE_TYPE, type);
+ }
+
+ public void setHost(String host) {
+ internalPrefs.put(SHARED_DATABASE_HOST, host);
+ }
+
+ public void setPort(String port) {
+ internalPrefs.put(SHARED_DATABASE_PORT, port);
+ }
+
+ public void setName(String name) {
+ internalPrefs.put(SHARED_DATABASE_NAME, name);
+ }
+
+ public void setUser(String user) {
+ internalPrefs.put(SHARED_DATABASE_USER, user);
+ }
+
+ public void setPassword(String password) {
+ internalPrefs.put(SHARED_DATABASE_PASSWORD, password);
+ }
+
+ public void setRememberPassword(boolean rememberPassword) {
+ internalPrefs.putBoolean(SHARED_DATABASE_REMEMBER_PASSWORD, rememberPassword);
+ }
+
+ public void clearPassword() {
+ internalPrefs.remove(SHARED_DATABASE_PASSWORD);
+ }
+
+ public void clear() throws BackingStoreException {
+ internalPrefs.clear();
+ }
+
+ private Optional<String> getOptionalValue(String key) {
+ return Optional.ofNullable(internalPrefs.get(key, null));
+ }
+
+ public static void clearAll() throws BackingStoreException {
+ Preferences.userNodeForPackage(JabRefMain.class).parent().node(PARENT_NODE).clear();
+ }
+
+ public void putAllDBMSConnectionProperties(DBMSConnectionProperties properties) {
+ assert (properties.isValid());
+
+ setType(properties.getType().toString());
+ setHost(properties.getHost());
+ setPort(String.valueOf(properties.getPort()));
+ setName(properties.getDatabase());
+ setUser(properties.getUser());
+
+ try {
+ setPassword(new Password(properties.getPassword().toCharArray(), properties.getUser()).encrypt());
+ } catch (GeneralSecurityException | UnsupportedEncodingException e) {
+ LOGGER.error("Could not store the password due to encryption problems.", e);
+ }
+ }
+}
diff --git a/src/main/java/net/sf/jabref/shared/security/Password.java b/src/main/java/net/sf/jabref/shared/security/Password.java
new file mode 100644
index 0000000..6e2b185
--- /dev/null
+++ b/src/main/java/net/sf/jabref/shared/security/Password.java
@@ -0,0 +1,65 @@
+package net.sf.jabref.shared.security;
+
+import java.io.UnsupportedEncodingException;
+import java.security.GeneralSecurityException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+import java.util.Base64;
+
+import javax.crypto.Cipher;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * {@link Password} contains methods which are useful to encrypt and decrypt passwords using symetric algorithms.
+ */
+public class Password {
+
+ private final byte[] phrase;
+ private final Cipher cipher;
+ private final SecretKeySpec secretKey;
+ private final IvParameterSpec ivSpec;
+
+
+ /**
+ * @param phrase Phrase which should be encrypted or decrypted
+ * @param key Key which is used to improve symmetric encryption
+ */
+ public Password(char[] phrase, String key) throws NoSuchAlgorithmException, NoSuchPaddingException {
+ this.phrase = new String(phrase).getBytes();
+ this.cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
+ this.secretKey = new SecretKeySpec(get128BitHash(key.getBytes()), "AES");
+ this.ivSpec = new IvParameterSpec("ThisIsA128BitKey".getBytes());
+ }
+
+ /**
+ * Encrypts the set phrase/password with a symmetric encryption algorithm.
+ *
+ * @return Encrypted phrase/password
+ */
+ public String encrypt() throws GeneralSecurityException, UnsupportedEncodingException {
+ cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);
+ return new String(Base64.getEncoder().encode(cipher.doFinal(phrase)), "UTF-8");
+ }
+
+ /**
+ * Decrypts the set phrase/password which was encrypted via {@link Password#encrypt()}.
+ *
+ * @return Decrypted phrase/password
+ */
+ public String decrypt() throws GeneralSecurityException, UnsupportedEncodingException {
+ cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec);
+ return new String(cipher.doFinal(Base64.getDecoder().decode(phrase)), "UTF-8");
+ }
+
+ /**
+ * Returns a 128 bit hash using SHA-256.
+ */
+ private byte[] get128BitHash(byte[] byteArrayToHash) throws NoSuchAlgorithmException {
+ MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
+ messageDigest.update(byteArrayToHash);
+ return Arrays.copyOf(messageDigest.digest(), 16); // return 128 bit
+ }
+}
diff --git a/src/main/java/net/sf/jabref/specialfields/Printed.java b/src/main/java/net/sf/jabref/specialfields/Printed.java
deleted file mode 100644
index 86c7840..0000000
--- a/src/main/java/net/sf/jabref/specialfields/Printed.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package net.sf.jabref.specialfields;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.swing.Icon;
-
-import net.sf.jabref.gui.IconTheme;
-import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.model.entry.SpecialFields;
-
-public class Printed extends SpecialField {
-
- private static Printed INSTANCE;
-
-
- private Printed() {
- List<SpecialFieldValue> values = new ArrayList<>();
- // DO NOT TRANSLATE "printed" as this makes the produced .bib files non portable
- values.add(new SpecialFieldValue(this, "printed", "togglePrinted", Localization.lang("Toggle print status"), IconTheme.JabRefIcon.PRINTED.getSmallIcon(),
- Localization.lang("Toggle print status")));
- this.setValues(values);
- }
-
- @Override
- public String getFieldName() {
- return SpecialFields.FIELDNAME_PRINTED;
- }
-
- @Override
- public String getLocalizedFieldName() {
- return Localization.lang("Printed");
- }
-
- public static Printed getInstance() {
- if (Printed.INSTANCE == null) {
- Printed.INSTANCE = new Printed();
- }
- return Printed.INSTANCE;
- }
-
- @Override
- public Icon getRepresentingIcon() {
- return this.getValues().get(0).getIcon();
- }
-
- @Override
- public boolean isSingleValueField() {
- return true;
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/specialfields/Priority.java b/src/main/java/net/sf/jabref/specialfields/Priority.java
deleted file mode 100644
index 27e6b23..0000000
--- a/src/main/java/net/sf/jabref/specialfields/Priority.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package net.sf.jabref.specialfields;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.swing.Icon;
-
-import net.sf.jabref.gui.IconTheme;
-import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.model.entry.SpecialFields;
-
-public class Priority extends SpecialField {
-
- private static Priority INSTANCE;
-
- private final Icon icon = IconTheme.JabRefIcon.PRIORITY.getSmallIcon();
-
-
- private Priority() {
- List<SpecialFieldValue> values = new ArrayList<>();
- values.add(new SpecialFieldValue(this, null, "clearPriority", Localization.lang("Clear priority"), null,
- Localization.lang("No priority information")));
- Icon tmpicon;
- tmpicon = IconTheme.JabRefIcon.PRIORITY_HIGH.getSmallIcon();
- // DO NOT TRANSLATE "prio1" etc. as this makes the .bib files non portable
- values.add(new SpecialFieldValue(this, "prio1", "setPriority1", Localization.lang("Set priority to high"),
- tmpicon, Localization.lang("Priority high")));
- tmpicon = IconTheme.JabRefIcon.PRIORITY_MEDIUM.getSmallIcon();
- values.add(new SpecialFieldValue(this, "prio2", "setPriority2", Localization.lang("Set priority to medium"),
- tmpicon, Localization.lang("Priority medium")));
- tmpicon = IconTheme.JabRefIcon.PRIORITY_LOW.getSmallIcon();
- values.add(new SpecialFieldValue(this, "prio3", "setPriority3", Localization.lang("Set priority to low"),
- tmpicon, Localization.lang("Priority low")));
- this.setValues(values);
- }
-
- public static Priority getInstance() {
- if (Priority.INSTANCE == null) {
- Priority.INSTANCE = new Priority();
- }
- return Priority.INSTANCE;
- }
-
- @Override
- public String getFieldName() {
- return SpecialFields.FIELDNAME_PRIORITY;
- }
-
- @Override public String getLocalizedFieldName() {
- return Localization.lang("Priority");
- }
-
- @Override
- public Icon getRepresentingIcon() {
- return this.icon;
- }
-}
diff --git a/src/main/java/net/sf/jabref/specialfields/Quality.java b/src/main/java/net/sf/jabref/specialfields/Quality.java
deleted file mode 100644
index 2437afb..0000000
--- a/src/main/java/net/sf/jabref/specialfields/Quality.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package net.sf.jabref.specialfields;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.swing.Icon;
-
-import net.sf.jabref.gui.IconTheme;
-import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.model.entry.SpecialFields;
-
-public class Quality extends SpecialField {
-
- private static Quality INSTANCE;
-
-
- private Quality() {
- List<SpecialFieldValue> values = new ArrayList<>();
- // DO NOT TRANSLATE "qualityAssured" as this makes the produced .bib files non portable
- values.add(new SpecialFieldValue(this, "qualityAssured", "toggleQualityAssured",
- Localization.lang("Toggle quality assured"), IconTheme.JabRefIcon.QUALITY_ASSURED.getSmallIcon(),
- Localization.lang("Toggle quality assured")));
- this.setValues(values);
- }
-
- @Override
- public String getFieldName() {
- return SpecialFields.FIELDNAME_QUALITY;
- }
-
- @Override
- public String getLocalizedFieldName() {
- return Localization.lang("Quality");
- }
-
- public static Quality getInstance() {
- if (Quality.INSTANCE == null) {
- Quality.INSTANCE = new Quality();
- }
- return Quality.INSTANCE;
- }
-
- @Override
- public Icon getRepresentingIcon() {
- return IconTheme.JabRefIcon.QUALITY.getSmallIcon();
- }
-
- @Override
- public boolean isSingleValueField() {
- return true;
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/specialfields/Rank.java b/src/main/java/net/sf/jabref/specialfields/Rank.java
deleted file mode 100644
index 87df8fc..0000000
--- a/src/main/java/net/sf/jabref/specialfields/Rank.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package net.sf.jabref.specialfields;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.swing.Icon;
-
-import net.sf.jabref.gui.IconTheme;
-import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.model.entry.SpecialFields;
-
-public class Rank extends SpecialField {
-
- private static Rank INSTANCE;
-
- private Rank() {
- List<SpecialFieldValue> values = new ArrayList<>();
- // lab.setName("i");
- values.add(new SpecialFieldValue(this, null, "clearRank", Localization.lang("Clear rank"), null,
- Localization.lang("No rank information")));
- // DO NOT TRANSLATE "rank1" etc. as this makes the .bib files non portable
- values.add(new SpecialFieldValue(this, "rank1", "setRank1", "", IconTheme.JabRefIcon.RANK1.getSmallIcon(), Localization.lang("One star")));
- values.add(new SpecialFieldValue(this, "rank2", "setRank2", "", IconTheme.JabRefIcon.RANK2.getSmallIcon(), Localization.lang("Two stars")));
- values.add(new SpecialFieldValue(this, "rank3", "setRank3", "", IconTheme.JabRefIcon.RANK3.getSmallIcon(), Localization.lang("Three stars")));
- values.add(new SpecialFieldValue(this, "rank4", "setRank4", "", IconTheme.JabRefIcon.RANK4.getSmallIcon(), Localization.lang("Four stars")));
- values.add(new SpecialFieldValue(this, "rank5", "setRank5", "", IconTheme.JabRefIcon.RANK5.getSmallIcon(), Localization.lang("Five stars")));
- this.setValues(values);
- }
-
- public static Rank getInstance() {
- if (Rank.INSTANCE == null) {
- Rank.INSTANCE = new Rank();
- }
- return Rank.INSTANCE;
- }
-
- @Override
- public Icon getRepresentingIcon() {
- return IconTheme.JabRefIcon.RANKING.getIcon();
- }
-
- @Override
- public String getFieldName() {
- return SpecialFields.FIELDNAME_RANKING;
- }
-
- @Override public String getLocalizedFieldName() {
- return Localization.lang("Rank");
- }
-}
diff --git a/src/main/java/net/sf/jabref/specialfields/ReadStatus.java b/src/main/java/net/sf/jabref/specialfields/ReadStatus.java
deleted file mode 100644
index bd5fde8..0000000
--- a/src/main/java/net/sf/jabref/specialfields/ReadStatus.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package net.sf.jabref.specialfields;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.swing.Icon;
-
-import net.sf.jabref.gui.IconTheme;
-import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.model.entry.SpecialFields;
-
-public class ReadStatus extends SpecialField {
-
- private static ReadStatus INSTANCE;
-
- private final Icon icon = IconTheme.JabRefIcon.READ_STATUS.getSmallIcon();
-
-
- private ReadStatus() {
- List<SpecialFieldValue> values = new ArrayList<>();
- values.add(new SpecialFieldValue(this, null, "clearReadStatus", Localization.lang("Clear read status"), null,
- Localization.lang("No read status information")));
- Icon tmpicon;
- tmpicon = IconTheme.JabRefIcon.READ_STATUS_READ.getSmallIcon();
- // DO NOT TRANSLATE "read" as this makes the produced .bib files non portable
- values.add(new SpecialFieldValue(this, "read", "setReadStatusToRead",
- Localization.lang("Set read status to read"), tmpicon,
- Localization.lang("Read status read")));
- tmpicon = IconTheme.JabRefIcon.READ_STATUS_SKIMMED.getSmallIcon();
- values.add(new SpecialFieldValue(this, "skimmed", "setReadStatusToSkimmed",
- Localization.lang("Set read status to skimmed"), tmpicon,
- Localization.lang("Read status skimmed")));
- this.setValues(values);
- }
-
- public static ReadStatus getInstance() {
- if (ReadStatus.INSTANCE == null) {
- ReadStatus.INSTANCE = new ReadStatus();
- }
- return ReadStatus.INSTANCE;
- }
-
- @Override
- public String getFieldName() {
- return SpecialFields.FIELDNAME_READ;
- }
-
- @Override
- public String getLocalizedFieldName() {
- return Localization.lang("Read status");
- }
-
- @Override
- public Icon getRepresentingIcon() {
- return this.icon;
- }
-}
diff --git a/src/main/java/net/sf/jabref/specialfields/Relevance.java b/src/main/java/net/sf/jabref/specialfields/Relevance.java
deleted file mode 100644
index 42ced48..0000000
--- a/src/main/java/net/sf/jabref/specialfields/Relevance.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package net.sf.jabref.specialfields;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.swing.Icon;
-
-import net.sf.jabref.gui.IconTheme;
-import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.model.entry.SpecialFields;
-
-public class Relevance extends SpecialField {
-
- private static Relevance INSTANCE;
-
-
- private Relevance() {
- List<SpecialFieldValue> values = new ArrayList<>();
- // action directly set by JabRefFrame
- // DO NOT TRANSLATE "relevant" as this makes the produced .bib files non portable
- values.add(new SpecialFieldValue(this, "relevant", "toggleRelevance", Localization.lang("Toggle relevance"), IconTheme.JabRefIcon.RELEVANCE.getSmallIcon(),
- Localization.lang("Toggle relevance")));
- this.setValues(values);
- }
-
- @Override
- public String getFieldName() {
- return SpecialFields.FIELDNAME_RELEVANCE;
- }
-
- @Override
- public String getLocalizedFieldName() {
- return Localization.lang("Relevance");
- }
-
- public static Relevance getInstance() {
- if (Relevance.INSTANCE == null) {
- Relevance.INSTANCE = new Relevance();
- }
- return Relevance.INSTANCE;
- }
-
- @Override
- public Icon getRepresentingIcon() {
- return this.getValues().get(0).getIcon();
- }
-
- @Override
- public boolean isSingleValueField() {
- return true;
- }
-}
diff --git a/src/main/java/net/sf/jabref/specialfields/SpecialField.java b/src/main/java/net/sf/jabref/specialfields/SpecialField.java
deleted file mode 100644
index 0f18b8d..0000000
--- a/src/main/java/net/sf/jabref/specialfields/SpecialField.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package net.sf.jabref.specialfields;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Objects;
-import java.util.Optional;
-
-import javax.swing.Icon;
-
-import net.sf.jabref.logic.l10n.Localization;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-public abstract class SpecialField {
-
- private static final Log LOGGER = LogFactory.getLog(SpecialField.class);
-
- // currently, menuString is used for undo string
- // public static String TEXT_UNDO;
-
- private List<SpecialFieldValue> values;
- private List<String> keywords;
- private HashMap<String, SpecialFieldValue> map;
-
-
- protected void setValues(List<SpecialFieldValue> values) {
- this.values = values;
- this.keywords = new ArrayList<>();
- this.map = new HashMap<>();
- for (SpecialFieldValue v : values) {
- v.getKeyword().ifPresent(keywords::add);
- v.getFieldValue().ifPresent(fieldValue -> map.put(fieldValue, v));
- }
- }
-
- public List<SpecialFieldValue> getValues() {
- return this.values;
- }
-
- public List<String> getKeyWords() {
- return this.keywords;
- }
-
- public Optional<SpecialFieldValue> parse(String s) {
- return Optional.ofNullable(map.get(s));
- }
-
- public abstract String getFieldName();
-
- public abstract String getLocalizedFieldName();
-
- public abstract Icon getRepresentingIcon();
-
- public String getMenuString() {
- return getLocalizedFieldName();
- }
-
- public String getToolTip() {
- return getLocalizedFieldName();
- }
-
- public String getTextDone(String... params) {
- Objects.requireNonNull(params);
-
- if (isSingleValueField() && (params.length == 1) && (params[0] != null)) {
- // Single value fields can be toggled only
- return Localization.lang("Toggled '%0' for %1 entries", getLocalizedFieldName(), params[0]);
- } else if (!isSingleValueField() && (params.length == 2) && (params[0] != null) && (params[1] != null)) {
- // setting a multi value special field - the setted value is displayed, too
- String[] allParams = {getLocalizedFieldName(), params[0], params[1]};
- return Localization.lang("Set '%0' to '%1' for %2 entries", allParams);
- } else if (!isSingleValueField() && (params.length == 1) && (params[0] != null)) {
- // clearing a multi value specialfield
- return Localization.lang("Cleared '%0' for %1 entries", getLocalizedFieldName(), params[0]);
- } else {
- // invalid usage
- LOGGER.info("Creation of special field status change message failed: illegal argument combination.");
- return "";
- }
- }
-
- public boolean isSingleValueField() {
- return false;
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/specialfields/SpecialFieldAction.java b/src/main/java/net/sf/jabref/specialfields/SpecialFieldAction.java
deleted file mode 100644
index 4375a2b..0000000
--- a/src/main/java/net/sf/jabref/specialfields/SpecialFieldAction.java
+++ /dev/null
@@ -1,74 +0,0 @@
-package net.sf.jabref.specialfields;
-
-import java.util.List;
-
-import net.sf.jabref.gui.JabRefFrame;
-import net.sf.jabref.gui.actions.BaseAction;
-import net.sf.jabref.gui.undo.NamedCompound;
-import net.sf.jabref.model.entry.BibEntry;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-public class SpecialFieldAction implements BaseAction {
-
- private final JabRefFrame frame;
- private final SpecialField specialField;
- private final String value;
- private final boolean nullFieldIfValueIsTheSame;
- private final String undoText;
-
- private static final Log LOGGER = LogFactory.getLog(SpecialFieldAction.class);
-
-
- /**
- *
- * @param nullFieldIfValueIsTheSame - false also causes that doneTextPattern has two place holders %0 for the value and %1 for the sum of entries
- */
- public SpecialFieldAction(
- JabRefFrame frame,
- SpecialField specialField,
- String value,
- boolean nullFieldIfValueIsTheSame,
- String undoText) {
- this.frame = frame;
- this.specialField = specialField;
- this.value = value;
- this.nullFieldIfValueIsTheSame = nullFieldIfValueIsTheSame;
- this.undoText = undoText;
- }
-
- @Override
- public void action() {
- try {
- List<BibEntry> bes = frame.getCurrentBasePanel().getSelectedEntries();
- if ((bes == null) || bes.isEmpty()) {
- return;
- }
- NamedCompound ce = new NamedCompound(undoText);
- for (BibEntry be : bes) {
- // if (value==null) and then call nullField has been omitted as updatefield also handles value==null
- SpecialFieldsUtils.updateField(specialField, value, be, ce, nullFieldIfValueIsTheSame);
- }
- ce.end();
- if (ce.hasEdits()) {
- frame.getCurrentBasePanel().getUndoManager().addEdit(ce);
- frame.getCurrentBasePanel().markBaseChanged();
- frame.getCurrentBasePanel().updateEntryEditorIfShowing();
- String outText;
- if (nullFieldIfValueIsTheSame || value==null) {
- outText = specialField.getTextDone(Integer.toString(bes.size()));
- } else {
- outText = specialField.getTextDone(value, Integer.toString(bes.size()));
- }
- frame.output(outText);
- } else {
- // if user does not change anything with his action, we do not do anything either
- // even no output message
- }
- } catch (Throwable ex) {
- LOGGER.error("Problem setting special fields", ex);
- }
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/specialfields/SpecialFieldDatabaseChangeListener.java b/src/main/java/net/sf/jabref/specialfields/SpecialFieldDatabaseChangeListener.java
deleted file mode 100644
index ebc47cb..0000000
--- a/src/main/java/net/sf/jabref/specialfields/SpecialFieldDatabaseChangeListener.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package net.sf.jabref.specialfields;
-
-import net.sf.jabref.gui.undo.NamedCompound;
-import net.sf.jabref.logic.l10n.Localization;
-import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.model.event.EntryAddedEvent;
-
-import com.google.common.eventbus.Subscribe;
-
-public class SpecialFieldDatabaseChangeListener {
-
- private static SpecialFieldDatabaseChangeListener INSTANCE;
-
- public static SpecialFieldDatabaseChangeListener getInstance() {
- if (SpecialFieldDatabaseChangeListener.INSTANCE == null) {
- SpecialFieldDatabaseChangeListener.INSTANCE = new SpecialFieldDatabaseChangeListener();
- }
- return SpecialFieldDatabaseChangeListener.INSTANCE;
- }
-
- @Subscribe
- public void listen(EntryAddedEvent event) {
- if (SpecialFieldsUtils.keywordSyncEnabled()) {
- final BibEntry entry = event.getBibEntry();
- // NamedCompount code similar to SpecialFieldUpdateListener
- NamedCompound nc = new NamedCompound(Localization.lang("Synchronized special fields based on keywords"));
- SpecialFieldsUtils.syncSpecialFieldsFromKeywords(entry, nc);
- // Don't insert the compound into the undoManager,
- // it would be added before the component which undoes the insertion of the entry and creates heavy problems
- // (which prohibits the undo the deleting multiple entries)
- }
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/specialfields/SpecialFieldDropDown.java b/src/main/java/net/sf/jabref/specialfields/SpecialFieldDropDown.java
deleted file mode 100644
index 08c49bf..0000000
--- a/src/main/java/net/sf/jabref/specialfields/SpecialFieldDropDown.java
+++ /dev/null
@@ -1,97 +0,0 @@
-package net.sf.jabref.specialfields;
-
-import java.awt.Dimension;
-import java.awt.Insets;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-
-import javax.swing.JButton;
-import javax.swing.JMenuItem;
-import javax.swing.JPopupMenu;
-
-import net.sf.jabref.gui.BasePanel;
-import net.sf.jabref.gui.JabRefFrame;
-import net.sf.jabref.logic.util.OS;
-
-import com.jgoodies.looks.HeaderStyle;
-import com.jgoodies.looks.Options;
-
-public class SpecialFieldDropDown {
-
- public static JButton generateSpecialFieldButtonWithDropDown(SpecialField field, JabRefFrame frame) {
- Dimension buttonDim = new Dimension(23, 23);
- JButton button = new JButton(field.getRepresentingIcon());
- button.setToolTipText(field.getToolTip());
- button.setPreferredSize(buttonDim);
- if (!OS.OS_X) {
- button.setMargin(new Insets(1, 0, 2, 0));
- }
- button.setBorder(null);
- button.setBorderPainted(false);
- button.setRolloverEnabled(true);
- button.setOpaque(false);
- button.setBounds(0, 0, buttonDim.width, buttonDim.height);
- button.setSize(buttonDim);
- button.setMinimumSize(buttonDim);
- button.setMaximumSize(buttonDim);
- button.putClientProperty(Options.HEADER_STYLE_KEY, HeaderStyle.BOTH);
- button.addActionListener(new MenuButtonActionListener(field, frame, button, buttonDim));
- return button;
- }
-
-
- private static class MenuButtonActionListener implements ActionListener {
-
- private JPopupMenu popup;
- private final Dimension dim;
- private final JabRefFrame frame;
- private final SpecialField field;
- private final JButton button;
-
-
- public MenuButtonActionListener(SpecialField field, JabRefFrame frame, JButton button, Dimension dim) {
- this.field = field;
- this.dim = dim;
- this.frame = frame;
- this.button = button;
- }
-
- @Override
- public void actionPerformed(ActionEvent e) {
- if (popup == null) {
- popup = new JPopupMenu();
- for (SpecialFieldValue val : field.getValues()) {
- JMenuItem item = new JMenuItem(val.getIcon());
- item.setText(val.getMenuString());
- item.setToolTipText(val.getToolTipText());
- item.addActionListener(new PopupitemActionListener(frame.getCurrentBasePanel(), val.getActionName()));
- item.setMargin(new Insets(0, 0, 0, 0));
- popup.add(item);
- }
- }
- popup.show(button, 0, dim.height);
- }
-
-
- private class PopupitemActionListener implements ActionListener {
-
- private final BasePanel panel;
- private final String actionName;
-
-
- public PopupitemActionListener(BasePanel panel, String actionName) {
- this.panel = panel;
- this.actionName = actionName;
- }
-
- @Override
- public void actionPerformed(ActionEvent e) {
- panel.runCommand(actionName);
- popup.setVisible(false);
- }
-
- }
-
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/specialfields/SpecialFieldMenuAction.java b/src/main/java/net/sf/jabref/specialfields/SpecialFieldMenuAction.java
deleted file mode 100644
index 5e75032..0000000
--- a/src/main/java/net/sf/jabref/specialfields/SpecialFieldMenuAction.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package net.sf.jabref.specialfields;
-
-import java.awt.event.ActionEvent;
-
-import javax.swing.AbstractAction;
-
-import net.sf.jabref.gui.JabRefFrame;
-
-public class SpecialFieldMenuAction extends AbstractAction {
-
- private final JabRefFrame frame;
- private final String actionName;
-
-
- public SpecialFieldMenuAction(SpecialFieldValue val, JabRefFrame frame) {
- super(val.getMenuString(), val.getIcon());
- this.frame = frame;
- this.actionName = val.getActionName();
- }
-
- @Override
- public void actionPerformed(ActionEvent evt) {
- if (frame.getCurrentBasePanel() != null) {
- frame.getCurrentBasePanel().runCommand(actionName);
- }
- }
-}
diff --git a/src/main/java/net/sf/jabref/specialfields/SpecialFieldUpdateListener.java b/src/main/java/net/sf/jabref/specialfields/SpecialFieldUpdateListener.java
deleted file mode 100644
index dbbbd3f..0000000
--- a/src/main/java/net/sf/jabref/specialfields/SpecialFieldUpdateListener.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package net.sf.jabref.specialfields;
-
-import javax.swing.SwingUtilities;
-
-import net.sf.jabref.JabRefGUI;
-import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.model.entry.FieldName;
-import net.sf.jabref.model.event.FieldChangedEvent;
-
-import com.google.common.eventbus.Subscribe;
-
-/**
- * Listener triggering
- * * an update of keywords if special field has been updated
- * * an update of special fields if keywords have been updated
- */
-public class SpecialFieldUpdateListener {
-
- private static SpecialFieldUpdateListener INSTANCE;
-
- @Subscribe
- public void listen(FieldChangedEvent fieldChangedEvent) {
- final BibEntry entry = fieldChangedEvent.getBibEntry();
- final String fieldName = fieldChangedEvent.getFieldName();
- // Source editor cycles through all entries
- // if we immediately updated the fields, the entry editor would detect a subsequent change as a user change
- // and re-fire this event
- // e.g., "keyword = {prio1}, priority = {prio2}" and a change at keyword to prio3 would not succeed.
- SwingUtilities.invokeLater(() -> {
- if (FieldName.KEYWORDS.equals(fieldName)) {
- SpecialFieldsUtils.syncSpecialFieldsFromKeywords(entry);
- SwingUtilities
- .invokeLater(() -> JabRefGUI.getMainFrame().getCurrentBasePanel().updateEntryEditorIfShowing());
- } else {
- if (SpecialFieldsUtils.isSpecialField(fieldName)) {
- SpecialFieldsUtils.syncKeywordsFromSpecialFields(entry);
- SwingUtilities.invokeLater(
- () -> JabRefGUI.getMainFrame().getCurrentBasePanel().updateEntryEditorIfShowing());
- }
- }
- });
- }
-
- public static SpecialFieldUpdateListener getInstance() {
- if (SpecialFieldUpdateListener.INSTANCE == null) {
- SpecialFieldUpdateListener.INSTANCE = new SpecialFieldUpdateListener();
- }
- return SpecialFieldUpdateListener.INSTANCE;
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/specialfields/SpecialFieldValue.java b/src/main/java/net/sf/jabref/specialfields/SpecialFieldValue.java
deleted file mode 100644
index a81adba..0000000
--- a/src/main/java/net/sf/jabref/specialfields/SpecialFieldValue.java
+++ /dev/null
@@ -1,107 +0,0 @@
-package net.sf.jabref.specialfields;
-
-import java.util.Optional;
-
-import javax.swing.Icon;
-import javax.swing.JLabel;
-
-import net.sf.jabref.gui.JabRefFrame;
-
-public class SpecialFieldValue {
-
- private final SpecialField field;
-
- // keyword used at keyword field
- private final String keyword;
-
- // action belonging to this value
- private final String actionName;
-
- // localized menu string used at menu / button
- private final String menuString;
-
- private SpecialFieldAction action;
-
- private SpecialFieldMenuAction menuAction;
-
- private final Icon icon;
-
- private final String toolTipText;
-
-
- // value when used in a separate vield
- //private String fieldValue;
-
- /**
- *
- * @param field The special field this value is a value of
- * @param keyword - The keyword to be used at BibTex's keyword field. May be "null" if no keyword is to be set
- * @param actionName - the action to call
- * @param menuString - the string to display at a menu
- * @param icon - the icon of this value
- * @param toolTipText - the tool tip text
- */
- public SpecialFieldValue(
- SpecialField field,
- String keyword,
- String actionName,
- String menuString,
- Icon icon,
- String toolTipText) {
- this.field = field;
- this.keyword = keyword;
- this.actionName = actionName;
- this.menuString = menuString;
- this.icon = icon;
- this.toolTipText = toolTipText;
- }
-
- public Optional<String> getKeyword() {
- return Optional.ofNullable(this.keyword);
- }
-
- public String getActionName() {
- return this.actionName;
- }
-
- public String getMenuString() {
- return this.menuString;
- }
-
- public JLabel createLabel() {
- JLabel label = new JLabel(this.icon);
- label.setToolTipText(this.toolTipText);
- return label;
- }
-
- public Optional<String> getFieldValue() {
- return Optional.ofNullable(this.keyword);
- }
-
- public Icon getIcon() {
- return this.icon;
- }
-
- public String getToolTipText() {
- return this.toolTipText;
- }
-
- public SpecialFieldAction getAction(JabRefFrame frame) {
- if (this.action == null) {
- action = new SpecialFieldAction(frame, this.field, this.getFieldValue().orElse(null),
- // if field contains only one value, it has to be nulled
- // otherwise, another setting does not empty the field
- this.field.getValues().size() == 1,
- this.getMenuString());
- }
- return action;
- }
-
- public SpecialFieldMenuAction getMenuAction(JabRefFrame frame) {
- if (this.menuAction == null) {
- this.menuAction = new SpecialFieldMenuAction(this, frame);
- }
- return this.menuAction;
- }
-
-}
diff --git a/src/main/java/net/sf/jabref/specialfields/SpecialFieldsUtils.java b/src/main/java/net/sf/jabref/specialfields/SpecialFieldsUtils.java
deleted file mode 100644
index 2dbcc78..0000000
--- a/src/main/java/net/sf/jabref/specialfields/SpecialFieldsUtils.java
+++ /dev/null
@@ -1,174 +0,0 @@
-package net.sf.jabref.specialfields;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Optional;
-import java.util.Set;
-
-import net.sf.jabref.Globals;
-import net.sf.jabref.gui.undo.NamedCompound;
-import net.sf.jabref.gui.undo.UndoableFieldChange;
-import net.sf.jabref.logic.util.UpdateField;
-import net.sf.jabref.model.FieldChange;
-import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.model.entry.EntryUtil;
-import net.sf.jabref.model.entry.FieldName;
-import net.sf.jabref.model.entry.SpecialFields;
-import net.sf.jabref.preferences.JabRefPreferences;
-
-
-public class SpecialFieldsUtils {
-
-
- /****************************************************/
- /** generic treatment **/
- /** no special treatment any more, thanks to enums **/
- /****************************************************/
-
- /**
- * @param e - Field to be handled
- * @param value - may be null to state that field should be emptied
- * @param be - BibTeXEntry to be handled
- * @param ce - Filled with undo info (if necessary)
- * @param nullFieldIfValueIsTheSame - true: field is nulled if value is the same than the current value in be
- */
- public static void updateField(SpecialField e, String value, BibEntry be, NamedCompound ce, boolean nullFieldIfValueIsTheSame) {
- UpdateField.updateField(be, e.getFieldName(), value, nullFieldIfValueIsTheSame)
- .ifPresent(fieldChange -> ce.addEdit(new UndoableFieldChange(fieldChange)));
- // we cannot use "value" here as updateField has side effects: "nullFieldIfValueIsTheSame" nulls the field if value is the same
- SpecialFieldsUtils.exportFieldToKeywords(e, be.getFieldOptional(e.getFieldName()).orElse(null), be, ce);
- }
-
- private static void exportFieldToKeywords(SpecialField e, BibEntry be, NamedCompound ce) {
- SpecialFieldsUtils.exportFieldToKeywords(e, be.getFieldOptional(e.getFieldName()).orElse(null), be, ce);
- }
-
- private static void exportFieldToKeywords(SpecialField e, String newValue, BibEntry entry,
- NamedCompound ce) {
- if (!SpecialFieldsUtils.keywordSyncEnabled()) {
- return;
- }
- List<String> keywordList = new ArrayList<>(entry.getKeywords());
- List<String> specialFieldsKeywords = e.getKeyWords();
-
- int foundPos = -1;
-
- // cleanup keywords
- for (Object value : specialFieldsKeywords) {
- int pos = keywordList.indexOf(value);
- if (pos >= 0) {
- foundPos = pos;
- keywordList.remove(pos);
- }
- }
-
- if (newValue != null) {
- if (foundPos == -1) {
- keywordList.add(newValue);
- } else {
- keywordList.add(foundPos, newValue);
- }
- }
-
-
- Optional<FieldChange> change = entry.putKeywords(keywordList,
- Globals.prefs.get(JabRefPreferences.KEYWORD_SEPARATOR));
- if (ce != null){
- change.ifPresent(changeValue -> ce.addEdit(new UndoableFieldChange(changeValue)));
- }
- }
-
- public static void syncKeywordsFromSpecialFields(BibEntry be) {
- syncKeywordsFromSpecialFields(be, null);
- }
-
- /**
- * Update keywords according to values of special fields
- *
- * @param nc indicates the undo named compound. May be null
- */
- public static void syncKeywordsFromSpecialFields(BibEntry be, NamedCompound nc) {
- SpecialFieldsUtils.exportFieldToKeywords(Priority.getInstance(), be, nc);
- SpecialFieldsUtils.exportFieldToKeywords(Rank.getInstance(), be, nc);
- SpecialFieldsUtils.exportFieldToKeywords(Relevance.getInstance(), be, nc);
- SpecialFieldsUtils.exportFieldToKeywords(Quality.getInstance(), be, nc);
- SpecialFieldsUtils.exportFieldToKeywords(ReadStatus.getInstance(), be, nc);
- SpecialFieldsUtils.exportFieldToKeywords(Printed.getInstance(), be, nc);
- }
-
- private static void importKeywordsForField(Set<String> keywordList, SpecialField c, BibEntry be,
- NamedCompound nc) {
- List<String> values = c.getKeyWords();
- String newValue = null;
- for (String val : values) {
- if (keywordList.contains(val)) {
- newValue = val;
- break;
- }
- }
- UpdateField.updateNonDisplayableField(be, c.getFieldName(), newValue)
- .ifPresent(fieldChange -> {
- if (nc != null) {
- nc.addEdit(new UndoableFieldChange(fieldChange));
- }
- });
- }
-
- public static void syncSpecialFieldsFromKeywords(BibEntry be) {
- syncSpecialFieldsFromKeywords(be, null);
- }
-
- /**
- * updates field values according to keywords
- *
- * @param ce indicates the undo named compound. May be null
- */
- public static void syncSpecialFieldsFromKeywords(BibEntry be, NamedCompound ce) {
- if (!be.hasField(FieldName.KEYWORDS)) {
- return;
- }
- Set<String> keywordList = EntryUtil.getSeparatedKeywords(be);
- SpecialFieldsUtils.importKeywordsForField(keywordList, Priority.getInstance(), be, ce);
- SpecialFieldsUtils.importKeywordsForField(keywordList, Rank.getInstance(), be, ce);
- SpecialFieldsUtils.importKeywordsForField(keywordList, Quality.getInstance(), be, ce);
- SpecialFieldsUtils.importKeywordsForField(keywordList, Relevance.getInstance(), be, ce);
- SpecialFieldsUtils.importKeywordsForField(keywordList, ReadStatus.getInstance(), be, ce);
- SpecialFieldsUtils.importKeywordsForField(keywordList, Printed.getInstance(), be, ce);
- }
-
- /**
- * @param fieldName the fieldName
- * @return an instance of that field. The returned object is a singleton. null is returned if fieldName does not indicate a special field
- */
- public static Optional<SpecialField> getSpecialFieldInstanceFromFieldName(String fieldName) {
- if (fieldName.equals(SpecialFields.FIELDNAME_PRIORITY)) {
- return Optional.of(Priority.getInstance());
- } else if (fieldName.equals(SpecialFields.FIELDNAME_QUALITY)) {
- return Optional.of(Quality.getInstance());
- } else if (fieldName.equals(SpecialFields.FIELDNAME_RANKING)) {
- return Optional.of(Rank.getInstance());
- } else if (fieldName.equals(SpecialFields.FIELDNAME_RELEVANCE)) {
- return Optional.of(Relevance.getInstance());
- } else if (fieldName.equals(SpecialFields.FIELDNAME_READ)) {
- return Optional.of(ReadStatus.getInstance());
- } else if (fieldName.equals(SpecialFields.FIELDNAME_PRINTED)) {
- return Optional.of(Printed.getInstance());
- } else {
- return Optional.empty();
- }
- }
-
- /**
- * @param fieldName the name of the field to check
- * @return true if given field is a special field, false otherwise
- */
- public static boolean isSpecialField(String fieldName) {
- return SpecialFieldsUtils.getSpecialFieldInstanceFromFieldName(fieldName).isPresent();
- }
-
- public static boolean keywordSyncEnabled() {
- return Globals.prefs.getBoolean(JabRefPreferences.SPECIALFIELDSENABLED) &&
- Globals.prefs.getBoolean(JabRefPreferences.AUTOSYNCSPECIALFIELDSTOKEYWORDS);
- }
-
-}
diff --git a/src/main/java/oracle/jdbc/OracleConnection.java b/src/main/java/oracle/jdbc/OracleConnection.java
new file mode 100644
index 0000000..1bd1e64
--- /dev/null
+++ b/src/main/java/oracle/jdbc/OracleConnection.java
@@ -0,0 +1,368 @@
+package oracle.jdbc;
+
+import java.sql.Array;
+import java.sql.Blob;
+import java.sql.CallableStatement;
+import java.sql.Clob;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.NClob;
+import java.sql.PreparedStatement;
+import java.sql.SQLClientInfoException;
+import java.sql.SQLException;
+import java.sql.SQLWarning;
+import java.sql.SQLXML;
+import java.sql.Savepoint;
+import java.sql.Statement;
+import java.sql.Struct;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.Executor;
+
+import oracle.jdbc.dcn.DatabaseChangeRegistration;
+
+/**
+ * A mocking class used as a placeholder for the real Oracle JDBC drivers to prevent build errors.
+ */
+public class OracleConnection implements Connection {
+
+ public static String DCN_NOTIFY_ROWIDS;
+ public static String DCN_QUERY_CHANGE_NOTIFICATION;
+
+
+ @Override
+ public <T> T unwrap(Class<T> iface) throws SQLException {
+ // Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public boolean isWrapperFor(Class<?> iface) throws SQLException {
+ // Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public Statement createStatement() throws SQLException {
+ // Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public PreparedStatement prepareStatement(String sql) throws SQLException {
+ // Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public CallableStatement prepareCall(String sql) throws SQLException {
+ // Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String nativeSQL(String sql) throws SQLException {
+ // Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public void setAutoCommit(boolean autoCommit) throws SQLException {
+ // Auto-generated method stub
+
+ }
+
+ @Override
+ public boolean getAutoCommit() throws SQLException {
+ // Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public void commit() throws SQLException {
+ // Auto-generated method stub
+
+ }
+
+ @Override
+ public void rollback() throws SQLException {
+ // Auto-generated method stub
+
+ }
+
+ @Override
+ public void close() throws SQLException {
+ // Auto-generated method stub
+
+ }
+
+ @Override
+ public boolean isClosed() throws SQLException {
+ // Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public DatabaseMetaData getMetaData() throws SQLException {
+ // Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public void setReadOnly(boolean readOnly) throws SQLException {
+ // Auto-generated method stub
+
+ }
+
+ @Override
+ public boolean isReadOnly() throws SQLException {
+ // Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public void setCatalog(String catalog) throws SQLException {
+ // Auto-generated method stub
+
+ }
+
+ @Override
+ public String getCatalog() throws SQLException {
+ // Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public void setTransactionIsolation(int level) throws SQLException {
+ // Auto-generated method stub
+
+ }
+
+ @Override
+ public int getTransactionIsolation() throws SQLException {
+ // Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public SQLWarning getWarnings() throws SQLException {
+ // Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public void clearWarnings() throws SQLException {
+ // Auto-generated method stub
+
+ }
+
+ @Override
+ public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
+ // Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency)
+ throws SQLException {
+ // Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
+ // Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Map<String, Class<?>> getTypeMap() throws SQLException {
+ // Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
+ // Auto-generated method stub
+
+ }
+
+ @Override
+ public void setHoldability(int holdability) throws SQLException {
+ // Auto-generated method stub
+
+ }
+
+ @Override
+ public int getHoldability() throws SQLException {
+ // Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public Savepoint setSavepoint() throws SQLException {
+ // Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Savepoint setSavepoint(String name) throws SQLException {
+ // Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public void rollback(Savepoint savepoint) throws SQLException {
+ // Auto-generated method stub
+
+ }
+
+ @Override
+ public void releaseSavepoint(Savepoint savepoint) throws SQLException {
+ // Auto-generated method stub
+
+ }
+
+ @Override
+ public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability)
+ throws SQLException {
+ // Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency,
+ int resultSetHoldability) throws SQLException {
+ // Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency,
+ int resultSetHoldability) throws SQLException {
+ // Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
+ // Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
+ // Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
+ // Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Clob createClob() throws SQLException {
+ // Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Blob createBlob() throws SQLException {
+ // Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public NClob createNClob() throws SQLException {
+ // Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public SQLXML createSQLXML() throws SQLException {
+ // Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public boolean isValid(int timeout) throws SQLException {
+ // Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public void setClientInfo(String name, String value) throws SQLClientInfoException {
+ // Auto-generated method stub
+
+ }
+
+ @Override
+ public void setClientInfo(Properties properties) throws SQLClientInfoException {
+ // Auto-generated method stub
+
+ }
+
+ @Override
+ public String getClientInfo(String name) throws SQLException {
+ // Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Properties getClientInfo() throws SQLException {
+ // Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
+ // Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
+ // Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public void setSchema(String schema) throws SQLException {
+ // Auto-generated method stub
+
+ }
+
+ @Override
+ public String getSchema() throws SQLException {
+ // Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public void abort(Executor executor) throws SQLException {
+ // Auto-generated method stub
+
+ }
+
+ @Override
+ public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {
+ // Auto-generated method stub
+
+ }
+
+ @Override
+ public int getNetworkTimeout() throws SQLException {
+ // Auto-generated method stub
+ return 0;
+ }
+
+ public DatabaseChangeRegistration registerDatabaseChangeNotification(@SuppressWarnings("unused") Properties properties) {
+ return new DatabaseChangeRegistration();
+ }
+
+ public void unregisterDatabaseChangeNotification(@SuppressWarnings("unused") DatabaseChangeRegistration databaseChangeRegistration) {
+ // do nothing
+ }
+}
diff --git a/src/main/java/oracle/jdbc/OracleStatement.java b/src/main/java/oracle/jdbc/OracleStatement.java
new file mode 100644
index 0000000..ef24dce
--- /dev/null
+++ b/src/main/java/oracle/jdbc/OracleStatement.java
@@ -0,0 +1,13 @@
+package oracle.jdbc;
+
+import oracle.jdbc.dcn.DatabaseChangeRegistration;
+
+/**
+ * A mocking class used as a placeholder for the real Oracle JDBC drivers to prevent build errors.
+ */
+public class OracleStatement {
+
+ public void setDatabaseChangeRegistration(@SuppressWarnings("unused") DatabaseChangeRegistration registration) {
+ // do nothing
+ }
+}
diff --git a/src/main/java/oracle/jdbc/dcn/DatabaseChangeEvent.java b/src/main/java/oracle/jdbc/dcn/DatabaseChangeEvent.java
new file mode 100644
index 0000000..522c1c4
--- /dev/null
+++ b/src/main/java/oracle/jdbc/dcn/DatabaseChangeEvent.java
@@ -0,0 +1,8 @@
+package oracle.jdbc.dcn;
+
+/**
+ * A mocking class used as a placeholder for the real Oracle JDBC drivers to prevent build errors.
+ */
+public class DatabaseChangeEvent {
+ // no data
+}
diff --git a/src/main/java/oracle/jdbc/dcn/DatabaseChangeListener.java b/src/main/java/oracle/jdbc/dcn/DatabaseChangeListener.java
new file mode 100644
index 0000000..7daae7a
--- /dev/null
+++ b/src/main/java/oracle/jdbc/dcn/DatabaseChangeListener.java
@@ -0,0 +1,9 @@
+package oracle.jdbc.dcn;
+
+/**
+ * A mocking class used as a placeholder for the real Oracle JDBC drivers to prevent build errors.
+ */
+public interface DatabaseChangeListener {
+
+ public void onDatabaseChangeNotification(DatabaseChangeEvent event);
+}
diff --git a/src/main/java/oracle/jdbc/dcn/DatabaseChangeRegistration.java b/src/main/java/oracle/jdbc/dcn/DatabaseChangeRegistration.java
new file mode 100644
index 0000000..a046017
--- /dev/null
+++ b/src/main/java/oracle/jdbc/dcn/DatabaseChangeRegistration.java
@@ -0,0 +1,11 @@
+package oracle.jdbc.dcn;
+
+/**
+ * A mocking class used as a placeholder for the real Oracle JDBC drivers to prevent build errors.
+ */
+public class DatabaseChangeRegistration {
+
+ public void addListener(@SuppressWarnings("unused") DatabaseChangeListener listener) {
+ // do nothing
+ }
+}
diff --git a/src/main/java/oracle/jdbc/driver/OracleDriver.java b/src/main/java/oracle/jdbc/driver/OracleDriver.java
new file mode 100644
index 0000000..7685184
--- /dev/null
+++ b/src/main/java/oracle/jdbc/driver/OracleDriver.java
@@ -0,0 +1,8 @@
+package oracle.jdbc.driver;
+
+/**
+ * A mocking class used as a placeholder for the real Oracle JDBC drivers to prevent build errors.
+ */
+public class OracleDriver {
+ // no data
+}
diff --git a/src/main/java/oracle/jdbc/package-info.java b/src/main/java/oracle/jdbc/package-info.java
new file mode 100644
index 0000000..8683c43
--- /dev/null
+++ b/src/main/java/oracle/jdbc/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * This package contains stubs for oracle.jdbc to prevent build errors if the non-distributable oraclejdbdc6.jar is unavailable in the classpath
+ */
+package oracle.jdbc;
diff --git a/src/main/java/osx/macadapter/MacAdapter.java b/src/main/java/osx/macadapter/MacAdapter.java
index 7983945..419eba8 100644
--- a/src/main/java/osx/macadapter/MacAdapter.java
+++ b/src/main/java/osx/macadapter/MacAdapter.java
@@ -1,18 +1,4 @@
-package osx.macadapter;/* Copyright (C) 2015 JabRef contributors.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-*/
+package osx.macadapter;
import java.io.File;
import java.util.List;
diff --git a/src/main/resources/images/icons/JabRef-icon-mac.svg b/src/main/resources/images/icons/JabRef-icon-mac.svg
index 9269439..39f955f 100644
--- a/src/main/resources/images/icons/JabRef-icon-mac.svg
+++ b/src/main/resources/images/icons/JabRef-icon-mac.svg
@@ -1,6 +1,13 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
-<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://web.resource.org/cc/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="48" height="48" id="svg2" sodipodi:version="0.32" inkscape:version="0.45" sodipodi:docbase="/Us [...]
+<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://web.resource.org/cc/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="48" height="48" id="svg2"
+ sodipodi:version="0.32" inkscape:version="0.45" sodipodi:docbase="/Users/stefan/Desktop"
+ sodipodi:docname="JabRef-icon.svg" inkscape:output_extension="org.inkscape.output.svg.inkscape" version="1.0"
+ sodipodi:modified="TRUE" inkscape:export-filename="/Users/stefan/Desktop/JabRef-icon.png"
+ inkscape:export-xdpi="173.03" inkscape:export-ydpi="173.03">
<defs id="defs4">
<linearGradient id="linearGradient3183">
<stop style="stop-color:#4f5f8f;stop-opacity:1;" offset="0" id="stop3185"/>
@@ -56,4 +63,4 @@
<path style="fill:url(#linearGradient3221);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.05348015px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 23.393566,6.0886773 C 36.731928,6.7477697 46.75263,17.557136 33.602104,24.722605 C 29.911636,27.055511 39.058934,38.657261 42.60508,43.909313 C 33.547329,40.892132 25.628364,31.6634 26.201311,25.390871 C 26.584264,20.852056 33.99263,21.159118 34.298737,18.36607 C 34.604827,15.573203 29.431546,15.86983 23.393 [...]
<path style="opacity:0.71111115;fill:url(#linearGradient3219);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 2.416732,36.468262 C 2.1420683,34.306425 1.8027545,27.329653 1.7829493,20.312407 C 1.7631442,13.294981 0.060980919,7.0555498 3.0662725,3.5749887 C 6.0762591,0.089031076 14.405519,2.018279 22.367854,2.0531764 C 30.330189,2.0882535 38.094615,2.0878938 40.143881,2.2639995 C 42.187661,2.4397454 19.2027 [...]
</g>
-</svg>
\ No newline at end of file
+</svg>
diff --git a/src/main/resources/images/icons/JabRef-icon.svg b/src/main/resources/images/icons/JabRef-icon.svg
index e5988a2..f14f3b4 100644
--- a/src/main/resources/images/icons/JabRef-icon.svg
+++ b/src/main/resources/images/icons/JabRef-icon.svg
@@ -2,21 +2,20 @@
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:xlink="http://www.w3.org/1999/xlink"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="730"
- height="730"
- id="svg2"
- sodipodi:version="0.32"
- inkscape:version="0.91 r13725"
- sodipodi:docname="JabRef-icon.svg"
- version="1.1">
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="730"
+ height="730"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.91 r13725"
+ sodipodi:docname="JabRef-icon.svg"
+ version="1.1">
<defs
id="defs4">
<linearGradient
diff --git a/src/main/resources/l10n/JabRef_da.properties b/src/main/resources/l10n/JabRef_da.properties
index 6829053..73b40eb 100644
--- a/src/main/resources/l10n/JabRef_da.properties
+++ b/src/main/resources/l10n/JabRef_da.properties
@@ -1,804 +1,1377 @@
#!
-#! created/edited by Popeye version 0.55 (https\://github.com/koppor/popeye)
+#! created/edited by Popeye version 0.55 (github.com/JabRef/popeye)
#! encoding:UTF-8
+
%0_contains_the_regular_expression_<b>%1</b>=%0_indeholder_regulærudtrykket_<b>%1</b>
+
%0_contains_the_term_<b>%1</b>=%0_indeholder_udtrykket_<b>%1</b>
+
%0_doesn't_contain_the_regular_expression_<b>%1</b>=%0_indeholder_ikke_regulærudtrykket_<b>%1</b>
+
%0_doesn't_contain_the_term_<b>%1</b>=%0_indeholder_ikke_udtrykket_<b>%1</b>
+
%0_export_successful=%0-eksport_lykkedes
+
%0_matches_the_regular_expression_<b>%1</b>=%0_matcher_regulærudtrykket_<b>%1</b>
+
%0_matches_the_term_<b>%1</b>=%0_matcher_udtrykket_<b>%1</b>
-<field_name>=<feltnavn>
+
<HTML>Could_not_find_file_'%0'<BR>linked_from_entry_'%1'</HTML>=<HTML>Kunne_ikke_finde_filen_'%0'<BR>linket_til_fra_posten_'%1'</HTML>
+
<select>=<vælg>
-<select_word>=<vælg_ord>
+
Abbreviate_journal_names_of_the_selected_entries_(ISO_abbreviation)=Forkort_tidsskriftsnavn_for_de_valgte_poster_(ISO-forkortelse)
Abbreviate_journal_names_of_the_selected_entries_(MEDLINE_abbreviation)=Forkort_tidsskriftsnavn_for_de_valgte_poster_(MEDLINE-forkortelse)
+
Abbreviate_names=Forkort_navn
Abbreviated_%0_journal_names.=Fortkortet_%0_tidsskriftsnavn.
+
Abbreviation=Forkortelse
+
About_JabRef=Om_JabRef
+
Abstract=Sammendrag
+
Accept=Accepter
+
Accept_change=Accepter_ændring
+
Action=Handling
+
Add=Tilføj
-Add_a_(compiled)_custom_ImportFormat_class_from_a_class_path.=Tilføj_en_(kompileret)_egendefineret_ImportFormat-klasse_fra_en_classpath.
+
+Add_a_(compiled)_custom_Importer_class_from_a_class_path.=Tilføj_en_(kompileret)_egendefineret_Importer-klasse_fra_en_classpath.
The_path_need_not_be_on_the_classpath_of_JabRef.=Stien_behøver_ikke_at_være_på_JabRefs_classpath.
-Add_a_(compiled)_custom_ImportFormat_class_from_a_ZIP-archive.=Tilføj_en_kompileret_ImportFormat-klasse_fra_en_ZIP-fil.
+Add_a_(compiled)_custom_Importer_class_from_a_ZIP-archive.=Tilføj_en_kompileret_Importer-klasse_fra_en_ZIP-fil.
The_ZIP-archive_need_not_be_on_the_classpath_of_JabRef.=ZIP-filen_behøver_ikke_at_være_i_din_classpath.
+
Add_entry_selection_to_this_group=Føj_valgte_poster_til_denne_gruppe
+
Add_from_folder=Tilføj_fra_mappe
+
Add_from_JAR=Tilføj_fra_JAR-fil
+
add_group=tilføj_gruppe
+
Add_group=Tilføj_gruppe
+
Add_new=Tilføj_ny
+
Add_subgroup=Tilføj_undergruppe
+
Add_to_group=Tilføj_i_gruppe
+
Added_group_"%0".=Tilføjede_gruppe_"%0".
+
Added_new=Tilføjede_ny
+
Added_string=Tilføjede_streng
+
Additionally,_entries_whose_<b>%0</b>_field_does_not_contain_<b>%1</b>_can_be_assigned_manually_to_this_group_by_selecting_them_then_using_either_drag_and_drop_or_the_context_menu._This_process_adds_the_term_<b>%1</b>_to_each_entry's_<b>%0</b>_field._Entries_can_be_removed_manually_from_this_group_by_selecting_them_then_using_the_context_menu._This_process_removes_the_term_<b>%1</b>_from_each_entry's_<b>%0</b>_field.=Desuden,_poster_hvis_<b>%0</b>-felt_ikke_indeholder_<b>%1</b>_kan_føjes [...]
+
Advanced=Avanceret
All_entries=Alle_poster
All_entries_of_this_type_will_be_declared_typeless._Continue?=Alle_posterne_af_denne_type_vil_blive_klassificeret_som_typeløse._Fortsæt?
+
All_fields=Alle_felter
+
All_subgroups_(recursively)=Alle_undergrupper_(rekursivt)
-An_exception_occurred_while_accessing_'%0'=En_fejl_opstod_ved_læsning_af_'%0'
+
+Always_reformat_BIB_file_on_save_and_export=
+
A_SAX_exception_occurred_while_parsing_'%0'\:=En_SAXException_forekom_ved_læsning_af_'%0'\:
+
and=og
and_the_class_must_be_available_in_your_classpath_next_time_you_start_JabRef.=og_klassen_skal_være_tilgængelig_i_CLASSPATH_næste_gang,_du_starter_JabRef.
+
any_field_that_matches_the_regular_expression_<b>%0</b>=ethvert_felt_som_matcher_regulærudtrykket_<b>%0</b>
+
Appearance=Udseende
+
Append=Tilføj
Append_contents_from_a_BibTeX_database_into_the_currently_viewed_database=Tilføj_indhold_fra_en_BibTeX-database_i_den_åbne_database
+
Append_database=Føj_til_database
+
Append_the_selected_text_to_BibTeX_field=Tilføj_den_valgte_tekst_til_BibTeX-nøglen
Application=Applikation
+
Apply=Udfør
+
Arguments_passed_on_to_running_JabRef_instance._Shutting_down.=Argumenterne_sendt_til_allerede_aktiv_JabRef-instans._Afslutter.
+
Assign_entry_selection_exclusively_to_this_group=Føj_valgte_poster_eksklusivt_til_denne_gruppe
+
Assign_new_file=Tildel_ny_fil
+
Assign_the_original_group's_entries_to_this_group?=Føj_den_oprindelige_gruppes_poster_til_denne_gruppe?
+
Assigned_%0_entries_to_group_"%1".=Tilføjede_%0_poster_til_gruppen_"%1".
+
Assigned_1_entry_to_group_"%0".=Tilføjede_1_post_til_gruppen_"%0".
+
Attach_URL=Tilføj_URL
+
Attempt_to_automatically_set_file_links_for_your_entries._Automatically_setting_works_if_a_file_in_your_file_directory<BR>or_a_subdirectory_is_named_identically_to_an_entry's_BibTeX_key,_plus_extension.=Forsøg_at_sætte_fil-link_automatisk_for_dine_poster._Dette_virker,_hvis_en_fil_i_dit_fil-bibliotek_eller_et_underbibliotek<BR>har_navn_lignende_en_posts_BibTeX-nøgle,_plus_efternavn.
+
Auto=Auto
+
Autodetect_format=Autodetekter_format
+
Autogenerate_BibTeX_keys=Autogenerer_BibTeX-nøgler
Autolink_files_with_names_starting_with_the_BibTeX_key=Autolink_filer_med_navn_som_starter_med_BibTeX-nøglen
+
Autolink_only_files_that_match_the_BibTeX_key=Autolink_kun_filer_med_navn_som_svarer_til_BibTeX-nøglen
+
Automatically_create_groups=Generer_grupper_automatisk
+
Automatically_create_groups_for_database.=Generer_grupper_for_databasen.
+
Automatically_created_groups=Genererede_grupper_automatisk
+
Automatically_remove_exact_duplicates=Fjern_eksakte_dubletter_automatisk
+
Allow_overwriting_existing_links.=Tillad_overskrivning_af_eksisterende_links.
+
Do_not_overwrite_existing_links.=Overskriv_ikke_eksisterende_links.
+
AUX_file_import=AUX-fil_import
+
Available_export_formats=Tilgængelige_eksportformater
+
Available_BibTeX_fields=Tilgængelige_felter
+
Available_import_formats=Tilgængelige_importformater
+
Background_color_for_optional_fields=Baggrundsfarve_for_valgfrie_felter
+
Background_color_for_required_fields=Baggrundsfarve_for_obligatoriske_felter
+
Backup_old_file_when_saving=Lav_sikkerhedskopi_ved_gemning
+
BibTeX_key_is_unique.=BibTeX-nøglen_er_unik
-BibTeX_source=BibTeX-kilde
+
+%0_source=%0-kilde
+
Broken_link=Ugyldigt_link
+
Browse=Gennemse
+
by=med
+
Cancel=Annuller
+
Cannot_add_entries_to_group_without_generating_keys._Generate_keys_now?=Kan_ikke_føje_poster_til_en_gruppe_uden_at_generere_nøgler._Vil_du_generere_nøgler_nu?
+
Cannot_merge_this_change=Kan_ikke_inkorporere_denne_ændring
+
Cannot_move_group_"%0"_down.=Kan_ikke_flytte_gruppen_"%0"_ned.
+
Cannot_move_group_"%0"_left.=Kan_ikke_flytte_gruppen_"%0"_til_venstre.
+
Cannot_move_group_"%0"_right.=Kan_ikke_flytte_gruppen_"%0"_til_højre.
+
Cannot_move_group_"%0"_up.=Kan_ikke_flytte_gruppen_"%0"_op.
+
case_insensitive=skelner_ikke_mellem_store_og_små_bogstaver
+
case_sensitive=skelner_mellem_store_og_små_bogstaver
+
Case_sensitive=Skeln_mellem_store_og_små_bogstaver
+
change_assignment_of_entries=ændre_tildeling_af_poster
+
Change_case=Ændre_store/små_bogstaver
-Change_entry_type=Ændre_posttype
+Change_entry_type=Ændre_posttype
Change_file_type=Ændre_filtype
+
+
Change_of_Grouping_Method=Ændre_grupperingsmetode
+
change_preamble=Ændre_præambel
+
Change_table_column_and_General_fields_settings_to_use_the_new_feature=Ændre_opsætning_for_tabelkollonner_og_generelle_felter_for_anvende_den_nye_funktion
+
Changed_font_settings=ændrede_skrifttypeindstillinger
+
Changed_language_settings=Ændrede_sprogindstillinger
+
Changed_look_and_feel_settings=Ændrede_brugerfladeindstillinger
+
Changed_preamble=Ændrede_præambel
+
Characters_to_ignore=Ignorer_følgende_tegn
+
Check_existing_file_links=Tjek_eksisterende_fil-links
+
Check_links=Tjek_eksterne_links
+
+Choose_the_URL_to_download.=
Cite_command=Citations-kommando
+
Class_name=Klassenavn
+
Clear=Ryd
+
Clear_fields=Ryd_felter
+
Close=Luk
Close_others=
Close_all=
+
Close_dialog=Luk_dialog
+
Close_the_current_database=Luk_denne_database
+
Close_window=Luk_vindue
+
Closed_database=Lukkede_database
+
Collapse_subtree=Luk_forgrening
+
Color_codes_for_required_and_optional_fields=Farvekoder_for_nødvendige_og_valgfrie_felter
+
Color_for_marking_incomplete_entries=Farve_til_markering_af_ufuldstændige_poster
+
Column_width=Kolonnebredde
+
Command_line_id=Kommandolinje-id
-Connect=Tilslut
+
+
Contained_in=Indeholdt_i
+
Content=Indhold
+
Copied=Kopierede
+
Copied_cell_contents=Kopierede_indhold_af_cellen
+
Copied_key=Kopierede_nøgle
+
Copied_keys=Kopierede_nøgler
+
Copy=Kopier
+
Copy_BibTeX_key=Kopier_BibTeX-nøgle
Copy_file_to_file_directory=Kopier_fil_til_filbibliotek
Copy_to_clipboard=Kopier_til_udklipsholder
+
Could_not_call_executable=Kunne_ikke_kalde_programfilen
Could_not_connect_to_Vim_server._Make_sure_that_Vim_is_running<BR>with_correct_server_name.=Kunne_ikke_forbinde_til_Vim-server._Tjek_at_Vim_kjører<BR>med_korrekt_servernavn.
+
Could_not_export_file=Kunne_ikke_eksportere
+
Could_not_export_preferences=Kunne_ikke_eksportere_indstillinger
-# I have reformulated the following lines, because the 1st person form is not suitable\:
-Could_not_find_a_suitable_import_format.=Fandt_ikke_noget_passende_importformat.
+Could_not_find_a_suitable_import_format.=Fandt_ikke_noget_passende_importformat.
Could_not_import_preferences=Kunne_ikke_importere_indstillinger
+
Could_not_instantiate_%0=Kunne_ikke_instantiere_%0
Could_not_instantiate_%0_%1=Kunne_ikke_instantiere_%0_%1
-
Could_not_instantiate_%0._Have_you_chosen_the_correct_package_path?=Kunne_ikke_instantiere_%0._Har_du_valgt_korrekt_pakke-sti?
-
Could_not_open_link=Kunne_ikke_åbne_link
+
Could_not_print_preview=Kunne_ikke_printe_forhåndsvisning
+
Could_not_run_the_'vim'_program.=Kunne_ikke_køre_'vim'-programmet
+
Could_not_save_file.=Kunne_ikke_gemme_fil.
Character_encoding_'%0'_is_not_supported.=Tegnkodingen_'%0'_er_ikke_understøttet.
+
Created_groups.=Oprettede_grupper.
crossreferenced_entries_included=refererede_poster_inkluderet
+
Current_content=Nuværende_indhold
+
Current_value=Nuværende_værdi
+
Custom_entry_types=Brugerdefinerede_posttyper
+
Custom_entry_types_found_in_file=Fandt_brugerdefinerede_posttyper_i_filen
+
Customize_entry_types=Tilpas_posttyper
+
Customize_key_bindings=Opsætning_af_genvejstaster
+
Cut=Klip
+
cut_entries=klippede_poster
+
cut_entry=klip_post
+
+
Database_encoding=Tegnkoding_for_database
+
Database_properties=Databaseegenskaber
Database_type=
+
Date_format=Datoformat
+
Default=Standard
+
Default_encoding=Standard_kodning
+
Default_grouping_field=Standardfelt_for_gruppering
+
Default_look_and_feel=Standard-udseende
+
Default_pattern=Standardmønster
+
Default_sort_criteria=Standard_sorteringskriterier
Define_'%0'=Definer_'%0'
+
Delete=Slet
+
Delete_custom_format=Slet_brugerdefineret_type
+
delete_entries=slet_poster
+
Delete_entry=Slet_post
+
delete_entry=slet_post
+
Delete_multiple_entries=Slet_flere_poster
+
Delete_rows=Slet_rækker
+
Delete_strings=Slet_strenge
+
Deleted=Slettet
+
+Delete_local_file=
+
Delimit_fields_with_semicolon,_ex.=Afgræns_felter_med_semikolon,_f.eks.
+
Descending=Faldende
+
Description=Beskrivelse
+
Deselect_all=Vælg_ingen
Deselect_all_duplicates=Fravælg_alle_dubletter
+
Disable_this_confirmation_dialog=Deaktiver_denne_kontroldialog
+
Display_all_entries_belonging_to_one_or_more_of_the_selected_groups.=Vis_alle_poster_indeholdt_i_mindst_en_af_de_valgte_grupper.
+
Display_all_error_messages=Vis_alle_fejlmeddelelser
+
Display_help_on_command_line_options=Vis_kommandolinjehjælp
-Display_only_entries_belonging_to_all_selected_groups.=Vis_kun_poster_indeholdt_i_alle_valgte_grupper.
+Display_only_entries_belonging_to_all_selected_groups.=Vis_kun_poster_indeholdt_i_alle_valgte_grupper.
Display_version=Vis_versionsnummer
+
Displaying_no_groups=Viser_ingen_grupper
+
Do_not_abbreviate_names=Forkort_ikke_navn
+
Do_not_automatically_set=Sæt_ikke_links_automatisk
+
Do_not_import_entry=Importer_ikke_post
+
Do_not_open_any_files_at_startup=Åbn_ingen_filer_ved_opstart
+
Do_not_overwrite_existing_keys=Overskriv_ikke_eksisterende_nøgler
Do_not_show_these_options_in_the_future=Vis_ikke_disse_valg_igen
+
Do_not_wrap_the_following_fields_when_saving=Introducer_ikke_linjeskift_i_følgende_felter_ved_gemning
Do_not_write_the_following_fields_to_XMP_Metadata\:=Skriv_ikke_følgende_felter_til_XMP-metadata\:
Do_you_want_JabRef_to_do_the_following_operations?=Skal_JabRef_udføre_de_følgende_operationer?
+
+Donate_to_JabRef=
+
Down=Ned
+
Download=Download
+
Download_file=Download_fil
-Downloading...=Downloader...
+Downloading...=Downloader...
Drop_%0=Slip_%0
+
duplicate_removal=fjernelse_af_dubletter
+
Duplicate_string_name=Ikke-unikt_navn_på_streng
+
Duplicates_found=Dubletter_fundet
+
Dynamic_groups=Dynamiske_grupper
+
Dynamically_group_entries_by_a_free-form_search_expression=Grupper_poster_dynamisk_ved_hjælp_af_et_standard_søgeudtryk
+
Dynamically_group_entries_by_searching_a_field_for_a_keyword=Grupper_poster_dynamisk_ved_at_søge_efter_nøgleord_i_et_felt
+
Each_line_must_be_on_the_following_form=Hver_linje_skal_være_på_følgende_form
+
Edit=Rediger
+
Edit_custom_export=Rediger_eksternt_eksportfilter
Edit_entry=Rediger_post
Save_file=Rediger_link
Edit_file_type=Rediger_filtype
+
Edit_group=Rediger_gruppe
+
Edit_journal=Rediger_journal
+
Edit_preamble=Rediger_præambel
Edit_strings=Rediger_tekststrenge
Editor_options=Alternativer_for_redigering
+
Empty_BibTeX_key=tom_BibTeX-nøgle
+
Grouping_may_not_work_for_this_entry.=Gruppering_kan_fejle_for_denne_post.
+
empty_database=tom_database
Enable_word/name_autocompletion=Aktiver_autokomplettering_af_navn/ord
+
Enter_URL=Skriv_URL
+
Enter_URL_to_download=Skriv_URL_som_skal_hentes
+
entries=poster
+
Entries_cannot_be_manually_assigned_to_or_removed_from_this_group.=Poster_kan_ikke_manuelt_tilføjes_eller_fjernes_fra_denne_gruppe.
+
Entries_exported_to_clipboard=Poster_eksporteret_til_udklipsholder
+
+
entry=post
+
Entry_editor=Postredigering
Entry_preview=Forhåndsvisning
+
Entry_table=Hovedtabel
+
Entry_table_columns=Tabelkolonner
+
Entry_type=Posttype
+
Entry_type_names_are_not_allowed_to_contain_white_space_or_the_following_characters=Navn_på_typer_kan_ikke_indeholde_mellemrum_eller_nogle_af_følgende_tegn
+
Entry_types=Posttyper
+
Error=Fejl
Error_exporting_to_clipboard=Fejl_ved_eksport_til_udklipsholder
+
Error_occurred_when_parsing_entry=En_fejl_opstod_ved_læsning_af_post
+
Error_opening_file=Fejl_ved_åbning_af_fil
+
Error_setting_field=Problem_med_at_sætte_felt
Error_while_writing=En_fejl_opstod_ved_skrivning
-
Error_writing_to_%0_file(s).=Fejl_ved_skrivning_til_%0_fil(er).
+
Exceptions=Fejlinformation
+
Existing_file=Eksisterende_fil
+
'%0'_exists._Overwrite_file?='%0'_eksisterer._Erstat_filen?
Overwrite_file?=Erstat_filen?
+
Expand_subtree=Åbn_forgrening
+
Export=Eksporter
+
Export_name=Navn_på_filter
+
Export_preferences=Eksporter_indstillinger
+
Export_preferences_to_file=Eksporter_indstillinger_til_fil
+
Export_properties=Egenskaber_for_eksportfilter
+
Export_to_clipboard=Eksporter_til_udklipsholder
+
Exporting=Eksporterer
Extension=Efternavn
+
External_changes=Eksterne_ændringer
External_file_links=Eksterne_links
+
External_files=Eksterne_filer
+
External_programs=Eksterne_programmer
+
External_viewer_called=Eksternt_program_kaldt
+
Fetch=Hent
+
Field=Felt
+
field=felt
-# Integrity check is a process that checks for indications of wrongly filled out BibTeX fields. "Scan" is the button that starts the check.
+
Field_name=Feltnavn
Field_names_are_not_allowed_to_contain_white_space_or_the_following_characters=Feltnavn_kan_ikke_indeholde_mellemrum_eller_følgende_tegn
Field_to_filter=Felt_som_skal_filtreres
+
Field_to_group_by=Grupperingsfelt
+
File=Fil
-file=fil
+file=fil
File_'%0'_is_already_open.=Filen_'%0'_er_allerede_åben.
+
File_'%0'_not_found=Filen_'%0'_ikke_fundet
+
File_changed=Fil_ændret
File_directory_is_'%0'\:=Filbiblioteket_er_'%0'\:
File_directory_is_not_set_or_does_not_exist\!=Filbiblioteket_er_ikke_sat_eller_eksisterer_ikke\!
-
File_exists=Filen_eksisterer
File_has_been_updated_externally._What_do_you_want_to_do?=Filen_er_blevet_ændret_eksternt._Hvad_vil_du_gøre?
+
File_not_found=Fil_ikke_fundet
File_type=Filtype
+
File_updated_externally=Filen_er_blevet_ændret_eksternt
+
filename=filnavn
+
Files_opened=Filer_åbnet
Filter=Filter
Finished_automatically_setting_external_links.=Fuldførte_automatisk_udfyldning_af_eksterne_links.
+
Finished_synchronizing_file_links._Entries_changed\:_%0.=Fuldførte_synkronisering_af_fil-links._Poster_ændret\:_%0.
Finished_writing_XMP-metadata._Wrote_to_%0_file(s).=Fuldførte_skrivning_af_XMP-metadata._Skrev_til_%0_fil(er).
Finished_writing_XMP_for_%0_file_(%1_skipped,_%2_errors).=Fuldførte_skrivning_af_XMP_for_%0-fil_(sprang_over_%1,_%2_fejl).
+
First_select_the_entries_you_want_keys_to_be_generated_for.=Vælg_først_hvilke_poster_du_vil_generere_nøgler_for.
+
Fit_table_horizontally_on_screen=Tilpas_tabelbredden_horisontalt
+
Float=Flyt
Float_marked_entries=Sorter_mærkede_poster_øverst
+
Font_family=Skrifttype-familie
+
Font_preview=Skrifttype-forhåndsvisning
+
Font_size=Skriftstørrelse
+
Font_style=Skrifttype-stil
+
Font_selection=Skrifttypevælger
+
for=for
+
Format_of_author_and_editor_names=Formattering_af_forfatter-_og_redaktørnavn
Format_string=Formatstreng
+
Format_used=Format_brugt
Formatter_name=Navn_på_formatering
+
found_in_AUX_file=fundet_i_AUX-fil
+
Full_name=Fuldt_navn
+
General=Generelt
+
General_fields=Generelle_felter
+
Generate=Generer
+
Generate_BibTeX_key=Generer_BibTeX-nøgle
+
Generate_keys=Generer_nøgler
-Generate_keys_before_saving_(for_entries_without_a_key)=Generer_nøgler_før_gemning_(for_poster_uden_nøgle)
+Generate_keys_before_saving_(for_entries_without_a_key)=Generer_nøgler_før_gemning_(for_poster_uden_nøgle)
Generate_keys_for_imported_entries=Generer_automatisk_nøgler_for_importerede_poster
+
Generate_now=Generer_nu
+
Generated_BibTeX_key_for=Genererede_BibTeX-nøgle_for
+
Generating_BibTeX_key_for=Genererer_BibTeX-nøgle_for
+Get_fulltext=
Grab=Fang_genvejstast
+
Gray_out_entries_not_in_group_selection=Skraver_poster_udenfor_valgte_grupper
+
Gray_out_non-hits=Skraver_ikke-træffere
+
Groups=Gruppering
+
Have_you_chosen_the_correct_package_path?=Har_du_valgt_korrekt_pakke-sti?
+
Help=Hjælp
Help_on_groups=Hjælp_om_grupper
+
Help_on_key_patterns=Hjælp_om_nøglegenerering
Help_on_regular_expression_search=Hjælp_om_søgning_med_regulære_udtryk
+
Hide_non-hits=Skjul_ikke-træffere
Hierarchical_context=Gruppehierarki
+
Highlight=Fremhæv
Highlight_groups_matching_all_selected_entries=Fremhæv_grupper_som_indeholder_alle_valgte_poster
Highlight_groups_matching_any_selected_entry=Fremhæv_grupper_som_indeholder_mindst_en_af_de_valgte_poster
+Disable_highlight_groups_matching_entries=
+
Highlight_overlapping_groups=Fremhæv_overlappende_grupper
+
Hint\:_To_search_specific_fields_only,_enter_for_example\:<p><tt>author\=smith_and_title\=electrical</tt>=Hint\:_For_kun_at_søge_i_specifikke_felter,_skriv_f.eks.\:<p><tt>author\=smith_and_title\=electrical</tt>
HTML_table=HTML-tabel
HTML_table_(with_Abstract_&_BibTeX)=HTML-tabell_(med_Abstract_&_BibTeX)
Icon=Ikon
+
Ignore=Ignorer
+
Immediate_subgroups=Nærmeste_undergrupper
+
Import=Importer
+
Import_and_keep_old_entry=Importer_og_behold_den_gamle_post
+
Import_and_remove_old_entry=Importer_og_fjern_den_gamle_post
+
Import_entries=Importer_poster
+
Import_failed=Import_mislykkedes
+
Import_file=Importer_fil
+
Import_group_definitions=Importer_gruppedefinitioner
+
Import_name=Navn_på_import
+
Import_preferences=Importer_indstillinger
+
Import_preferences_from_file=Importer_indstillinger_fra_fil
+
Import_strings=Importer_strenge
+
Import_to_open_tab=Importer_til_åbent_faneblad
-Import_word_selector_definitions=Importer_definitioner_for_hurtigvælgere
+
Imported_entries=Importerede_poster
+
Imported_from_database=Importerede_fra_databasen
-ImportFormat_class=ImportFormat-klasse
+
+Importer_class=Importer-klasse
+
Importing=Importerer
+
Importing_in_unknown_format=Importerer_ukendt_format
+
Include_abstracts=Inkluder_abstracts
Include_entries=Inkluder_poster
+
Include_subgroups\:_When_selected,_view_entries_contained_in_this_group_or_its_subgroups=Inkluder_undergrupper\:_Vis_poster_indeholdt_i_denne_gruppe_eller_en_undergruppe
+
Independent_group\:_When_selected,_view_only_this_group's_entries=Uafhængig_gruppe\:_Vis_kun_denne_gruppes_poster
+
Initially_show_groups_tree_expanded=Vis_gruppetræet_ekspanderet_som_udgangspunkt
+
Work_options=
-Input_error=Inputfejl
+
Insert=Tilføj
+
Insert_rows=Tilføj_rækker
Intersection=Fællesmænge
+
Invalid_BibTeX_key=Ugyldig_BibTeX-nøgle
+
Invalid_date_format=Ugyldigt_datoformat
+
Invalid_URL=Ugyldig_URL
+
Inverted=Inverteret
+
ISO_abbreviation=ISO-forkortelse
+
Online_help=
+
JabRef_preferences=JabRef-indstillinger
+
Journal_abbreviations=Tidsskriftsforkortelser
+
Journal_list_preview=Forhåndsvisning_af_tidsskriftsliste
+
Journal_name=Tidsskriftsnavn
+
Keep=Behold
+
Keep_both=Behold_begge
+
Key_bindings=Genvejstaster
+
Key_bindings_changed=Genvejstaster_ændret
+
Key_generator_settings=Indstillinger_for_nøglegenerering
+
Key_pattern=Mønster
+
keys_in_database=nøgler_i_databasen
+
Keyword=Nøgleord
+
Label=Navn
+
Language=Sprog
+
Last_modified=Sidst_ændret
+
LaTeX_AUX_file=LaTeX_AUX-fil
Leave_file_in_its_current_directory=Lad_filen_ligge_i_biblioteket,_den_ligger_i_nu
Left=Venstre
Level=
+
Limit_to_fields=Begræns_til_følgende_felter
+
Limit_to_selected_entries=Begræns_til_valgte_poster
Link=Link
Link_local_file=Link_til_lokal_fil
-
Link_to_file_%0=Link_til_filen_%0
+
Listen_for_remote_operation_on_port=Lyt_efter_fjernoperationer_på_port
Load_and_Save_preferences_from/to_jabref.xml_on_start-up_(memory_stick_mode)=Hent_og_gem_indstillinger_fra/til_jabref.xml_ved_opstart_(memory_stick-tilstand)
+
Look_and_feel=Udseende
Main_file_directory=Hovedbibliotek
Main_layout_file=Hoved-layoutfil
-Manage=Opsæt
+
Manage_custom_exports=Opsæt_eksterne_eksportfiltre
+
Manage_custom_imports=Opsæt_eksterne_importfiltre
Manage_external_file_types=Opsæt_eksterne_filtyper
+
Manage_journal_abbreviations=Opsæt_tidsskriftsforkortelser
+
Mark_entries=Mærk_poster
+
Mark_entry=Mærk_post
+
Mark_new_entries_with_addition_date=Mærk_nye_poster_med_dato
+
Mark_new_entries_with_owner_name=Mærk_nye_poster_med_navn_på_ejer
+
Memory_stick_mode=Memory_Stick-tilstand
+
Menu_and_label_font_size=Størrelse_på_menuskrifttyper
+
Merged_external_changes=Inkorporerede_eksterne_ændringer
+
Messages=Meddelelser
+
Modification_of_field=Ændring_af_felt
+
Modified_group_"%0".=ændrede_gruppen_"%0".
+
Modified_groups=ændrede_grupper
+
Modified_string=ændrede_streng
+
Modify=Ændre
+
modify_group=ændre_gruppe
+
Move=Flyt
+
Move_down=Flyt_ned
+
Move_entries_in_group_selection_to_the_top=Flyt_poster_i_valgte_grupper_til_toppen
Move_external_links_to_'file'_field=Flyt_eksterne_links_til_'file'-feltet
+
move_group=flyt_gruppe
+
Move_up=Flyt_op
+
Moved_group_"%0".=Flyttede_gruppen_"%0".
+
Name=Navn
Name_formatter=Navneformatering
+
Natbib_style=Natbib-stil
nested_AUX_files='nestede'_AUX-filer
+
New=Ny
+
new=ny
+
New_BibTeX_entry=Ny_BibTeX-post
+
New_BibTeX_subdatabase=Ny_BibTeX-deldatabase
+
New_content=Nyt_indhold
+
New_database_created.=Opprettede_ny_database.
+New_%0_database=
New_field_value=Ny_værdi
+
New_file=Ny_fil
New_file_link_(INSERT)=Nyt_link_(INSERT)
+
New_group=Ny_gruppe
+
New_string=Ny_streng
+
Next_entry=Næste_post
+
No_actual_changes_found.=Ingen_reelle_ændringer_fundet.
+
no_base-BibTeX-file_specified=ingen_basis-BibTeXfil_specificeret
+
no_database_generated=ingen_database_genereret
+
No_entries_found._Please_make_sure_you_are_using_the_correct_import_filter.=Ingen_poster_fundet._Kontroller_at_du_bruger_korrekt_importfilter.
+
+
No_entries_found_for_the_search_string_'%0'=Fandt_ingen_poster_for_søgeteksten_'%0'
+
No_entries_imported.=Ingen_poster_importeret.
+
No_exceptions_have_occurred.=Der_er_ikke_sket_nogen_undtagelser.
No_files_found.=Ingen_filer_fundet.
+
No_GUI._Only_process_command_line_options.=Ingen_GUI._Processer_kun_kommandolinjevalg.
+
No_journal_names_could_be_abbreviated.=Ingen_tidsskriftsnavne_kunne_forkortes.
-No_journal_names_could_be_unabbreviated.=Ingen_tidsskriftsnavne_kunne_ekspanderes.
+No_journal_names_could_be_unabbreviated.=Ingen_tidsskriftsnavne_kunne_ekspanderes.
No_PDF_linked=Ingen_PDF_linket
-No_references_found=Ingen_referencer_fundet
+
No_URL_defined=Ingen_URL_er_defineret
not=ikke
+
not_found=ikke_fundet
+
Note_that_you_must_specify_the_fully_qualified_class_name_for_the_look_and_feel,=Bemærk_at_du_skal_specificere_det_fuldstændige_klassenavn_for_udseendet,
+
Nothing_to_redo=Ingenting_at_gentage
+
Nothing_to_undo=Ingenting_at_fortryde
-# The next is used like in "References found\: 1 Number of references to fetch?"
-Number_of_references_to_fetch?=Antal_referencer_som_skal_hentes?
+
occurrences=forekomster
+
OK=OK
One_or_more_file_links_are_of_the_type_'%0',_which_is_undefined._What_do_you_want_to_do?=Et_eller_flere_links_er_af_typen_'%0',_som_er_udefineret._Hvad_vil_du_gøre?
+
One_or_more_keys_will_be_overwritten._Continue?=En_eller_flere_nøgler_vil_blive_overskrevet._Fortsæt?
+
Open=Åbn
+
Open_BibTeX_database=Åbn_BibTeX-database
+
Open_database=Åbn_database
+
Open_editor_when_a_new_entry_is_created=Start_redigering_når_en_ny_post_oprettes
+
Open_file=Åbn_fil
+
Open_last_edited_databases_at_startup=Åbn_sidst_viste_databaser_ved_opstart
-Open_shared_database=
+
+Connect_to_shared_database=
+
Open_terminal_here=
+
Open_URL_or_DOI=Åbn_URL_eller_DOI
+
Opened_database=Åbnede_database
+
Opening=Åbner
+
Opening_preferences...=Åbner_indstillinger...
Operation_canceled.=Operationen_afbrudt.
Operation_not_supported=Operation_ikke_understøttet
+
Optional_fields=Valgfri_felter
+
Options=Valg
+
or=eller
+
Output=Output
+
Output_or_export_file=Gem_eller_eksporter_fil
+
Override=Tilsidesæt
+
Override_default_file_directories=Tilsidesæt_standard_fil-biblioteker
Override_default_font_settings=Tilsidesæt_standardskrifttyper
+
Override_the_BibTeX_field_by_the_selected_text=Tilsidesæt_BibTeX-nøglen_til_fordel_for_den_valgte_nøgle
+
+
Overwrite=Overskriv
Overwrite_existing_field_values=Overskriv_eksisterende_værdier
+
Overwrite_keys=Overskriv_nøgler
+
pairs_processed=par_revideret
Password=Kodeord
+
Paste=Indsæt
+
paste_entries=indsæt_poster
+
paste_entry=indsæt_post
Paste_from_clipboard=Indsæt_fra_udklipsholder
+
Pasted=Indsat
Path_to_%0_not_defined=Sti_til_%0_ikke_defineret
+
Path_to_LyX_pipe=Sti_til_LyX-pipe
PDF_does_not_exist=PDF-filen_findes_ikke
+
Personal_journal_list=Personlig_tidsskriftsliste
+
Plain_text_import=Import_fra_ren_tekst
+
Please_enter_a_name_for_the_group.=Skriv_et_navn_til_gruppen.
+
Please_enter_a_search_term._For_example,_to_search_all_fields_for_<b>Smith</b>,_enter\:<p><tt>smith</tt><p>To_search_the_field_<b>Author</b>_for_<b>Smith</b>_and_the_field_<b>Title</b>_for_<b>electrical</b>,_enter\:<p><tt>author\=smith_and_title\=electrical</tt>=Skriv_et_søgeudtryk._For_eksempel,_for_at_søge_i_alle_felter_efter_<b>Olsen</b>,_skriv\:<p><tt>olsen</tt><p>For_at_søge_i_<b>Author</b>-feltet_efter_<b>Olsen</b>_og_i_<b>Title</b>-feltet_efter_<b>electrical</b>,_skriv\:<p><tt>aut [...]
+
Please_enter_the_field_to_search_(e.g._<b>keywords</b>)_and_the_keyword_to_search_it_for_(e.g._<b>electrical</b>).=Skriv_venligsts_feltet_som_skal_søges_i_(f.eks._<b>keywords</b>)_og_nøgleordet_at_søge_efter_(f.eks._<b>electrical</b>).
+
Please_enter_the_string's_label=Skriv_et_navn_for_strengen
+
Please_select_an_importer.=Vælg_venligst_et_importfilter.
+
Please_select_exactly_one_group_to_move.=Vælg_præcis_én_gruppe_til_flytning.
+
Possible_duplicate_entries=Mulige_dubletter
+
Possible_duplicate_of_existing_entry._Click_to_resolve.=Mulig_dublet_af_eksisterende_post._Klik_for_at_løse_problemet.
+
Preamble=Præambel
+
Preferences=Indstillinger
+
Preferences_recorded.=Indstillinger_gemt.
+
Preview=Forhåndsvisning
+Citation_Style=
+Current_Preview=
+Cannot_generate_preview_based_on_selected_citation_style.=
+Bad_character_inside_entry=
+Error_while_generating_citation_style=
+Preview_style_changed_to\:_%0=
+Next_preview_layout=
+Previous_preview_layout=
+
Previous_entry=Forrige_post
+
Primary_sort_criterion=Primært_sorteringskriterium
Problem_with_parsing_entry=Problem_med_at_læse_post
-
Processing_%0=Arbejder_%0
Program_output=Output_fra_program
Pull_changes_from_shared_database=
+
Pushed_citations_to_%0=Referencer_sendt_til_%0
+
Quit_JabRef=Afslut_JabRef
+
Quit_synchronization=Afslut_synkronisering
+
Raw_source=Kilde
+
Rearrange_tabs_alphabetically_by_title=Omarranger_faneblade_alfabetisk_efter_titel
+
Redo=Gentag
+
Reference_database=Referencedatabase
-# The next two lines are used like in "References found\: 1 Number of references to fetch?"
-References_found=Referencer_fundet
+
+%0_references_found._Number_of_references_to_fetch?=Referencer_fundet\:_%0._Antal_referencer_som_skal_hentes?
+
Refine_supergroup\:_When_selected,_view_entries_contained_in_both_this_group_and_its_supergroup=Undergruppe\:_Vis_poster_indeholdt_både_i_denne_gruppe_og_gruppe_over
+
regular_expression=Regulærudtryk
+
Remember_these_entry_types?=Husk_disse_posttyper?
+
Remote_operation=Fjernstyring
+
Remote_server_port=Port_til_fjernstyring
+
Remove=Fjern
+
Remove_subgroups=Fjern_undergrupper
+
Remove_all_subgroups_of_"%0"?=Fjern_alle_undergrupper_af_"%0"?
+
Remove_entry_from_import=Fjern_post_fra_import
+
Remove_entry_selection_from_this_group=Fjern_valgte_poster_fra_denne_gruppe
+
Remove_entry_type=Slet_posttype
Remove_file_link_(DELETE)=Slet_link_(DELETE)
+
Remove_from_group=Fjern_fra_gruppe
+
Remove_group=Fjern_gruppe
+
Remove_group,_keep_subgroups=Fjern_gruppe,_behold_undergrupper
+
Remove_group_"%0"?=Fjern_gruppen_"%0"?
+
Remove_group_"%0"_and_its_subgroups?=Fjern_gruppen_"%0"_og_dens_undergrupper?
+
remove_group_(keep_subgroups)=fjern_gruppe_(behold_undergrupper)
+
remove_group_and_subgroups=fjern_gruppe_og_undergrupper
+
Remove_group_and_subgroups=Fjern_gruppe_og_undergrupper
+
Remove_link=Slet_link
+
Remove_old_entry=Fjern_gammel_post
+
Remove_selected_strings=Slet_valgte_strenge
+
Removed_group_"%0".=Fjernede_gruppen_"%0"
+
Removed_group_"%0"_and_its_subgroups.=Fjernede_gruppen_"%0"_og_dens_undergrupper
+
Removed_string=Streng_fjernet
Renamed_string=ændrede_navn_på_streng
+
Replace_(regular_expression)=Erstat_(regulærudtryk)
+
Replace_string=Erstat_streng
+
Replace_with=Erstat_med
+
Replaced=Erstattet
+
Required_fields=Obligatoriske_felter
+
Reset_all=Nulstil_alle
+
Resolve_strings_for_all_fields_except=Slå_strenge_op_for_alle_felter_undtagen
Resolve_strings_for_standard_BibTeX_fields_only=Slå_kun_strenge_op_for_standard_BibTeX-felter
+
resolved=løst
+
Revert_to_original_source=Ret_tilbage_til_oprindelig_kildekode
+
Review=Kommentarer
+
Review_changes=Gennemse_ændringer
+
Right=Højre
+
Save=Gem
Save_all_finished.=Alle_databaser_gemt
Save_all_open_databases=Gem_alle_åbne_databaser
+
Save_before_closing=Gem_før_databasen_lukkes
+
Save_database=Gem_database
Save_database_as...=Gem_database_som_...
+
Save_entries_in_their_original_order=Gem_poster_i_oprindelig_rækkefølge
+
Save_failed=Gemning_mislykkedes
+
Save_failed_during_backup_creation=Gemning_mislykkedes_ved_oprettelse_af_sikkerhedskopi
-Save_failed_while_committing_changes\:_%0=Gemning_mislykkedes_ved_inddatering_af_ændringer\:_%0
+
Save_selected_as...=Gem_valgte_som_...
+
Saved_database=Database_gemt
+
Saved_selected_to_'%0'.=Gemte_valgte_i_'%0'.
+
Saving=Gemmer
Saving_all_databases...=Gemmer_alle_databaser...
+
Saving_database=Gemmer_database
-# Integrity check is a process that checks for indications of wrongly filled out BibTeX fields. "Scan" is the button that starts the check.
+
Search=Søg
+
Search_expression=Søgeudtryk
+
Search_for=Søg_efter
+
Searching_for_duplicates...=Søger_efter_dubletter...
Searching_for_files=Søger_efter_filer
+
Secondary_sort_criterion=Sekundært_sorteringskriterium
+
Select=Vælg
+
+
Select_all=Vælg_alle
+
Select_encoding=Vælg_tegnkodning
+
Select_entry_type=Vælg_posttype
Select_external_application=Vælg_ekstern_applikation
+
Select_file_from_ZIP-archive=Vælg_fil_fra_ZIP-fil
+
Select_the_tree_nodes_to_view_and_accept_or_reject_changes=Vælg_forgreningerne_for_at_inspicere_og_acceptere_eller_forkaste_ændringer
Selected_entries=Valgte_poster
-
Set_field=Sæt_felt
Set_fields=Sæt_felter
+
Set_general_fields=Tilpas_generelle_felter
Set_main_external_file_directory=Sæt_hovedbibliotek_for_eksterne_links
+
Set_table_font=Vælg_tabelskrifttype
+
Settings=Indstillinger
+
Shortcut=Genvej
-Show/edit_BibTeX_source=Vis/rediger_BibTeX-kilde
+
+Show/edit_%0_source=Vis/rediger_%0-kilde
+
Show_'Firstname_Lastname'=Vis_'Fornavn_Efternavn'
+
Show_'Lastname,_Firstname'=Vis_'Efternavn,_Fornavn'
+
Show_BibTeX_source_by_default=Vis_BibTeX-kode_som_standard
+
Show_confirmation_dialog_when_deleting_entries=Vis_dialog_for_at_bekræfte_sletning_af_poster
+
Show_description=Vis_beskrivelse
+
Show_dynamic_groups_in_<i>italics</i>=Vis_dynamiske_grupper_i_<i>kursiv</i>
+
Show_entries_<b>not</b>_in_group_selection=Vis_poster_<b>udenfor</b>_valgte_grupper
Show_file_column=Vis_'file'-kolonne
+
Show_icons_for_groups=Vis_ikoner_for_grupper
Show_last_names_only=Vis_kun_efternavn
+
Show_names_unchanged=Vis_navn_uændret
+
Show_optional_fields=Vis_valgfrie_felter
+
Show_required_fields=Vis_obligatoriske_felter
+
Show_URL/DOI_column=Vis_URL/DOI-kolonne
+
Simple_HTML=Simpel_HTML
+
Size=Størrelse
+
Skipped_-_No_PDF_linked=Sprang_over_-_ingen_PDF-fil_linket
Skipped_-_PDF_does_not_exist=Sprang_over_-_PDF-filen_findes_ikke
Skipped_entry.=Sprang_over_post.
+
Sort_alphabetically=Sorter_alfabetisk
sort_subgroups=sorter_undergrupper
+
Sorted_all_subgroups_recursively.=Sorterede_alle_undergrupper_rekursivt.
+
Sorted_immediate_subgroups.=Sorterede_nærmeste_undergrupper.
+
source_edit=redigering_af_kilde
Special_name_formatters=Specielle_navneformateringer
+
Special_table_columns=Specielle_kolonner
+
Starting_import=Starter_import
+
Statically_group_entries_by_manual_assignment=Grupper_poster_statisk_ved_manuel_tildeling
+
Status=Status
+
Stop=Stop
+
Store_journal_abbreviations=Gem_tidsskriftsforkortelser
+
Stored_entry=Post_gemt
+
Strings=Strenge
+
Strings_for_database=Strenge_for_database
+
Subdatabase_from_AUX=Deldatabase_fra_AUX-fil
+
Switches_between_full_and_abbreviated_journal_name_if_the_journal_name_is_known.=Skifter_mellem_fuldt_og_forkortet_tidsskriftsnavn_hvis_navnet_er_kendt.
+
Synchronize_file_links=Synkroniser_eksterne_links
+
Synchronizing_file_links...=Synkroniserer_eksterne_links...
+
Table_appearance=Tabelopsætning
+
Table_background_color=Baggrundsfarve_for_tabel
+
Table_grid_color=Farve_på_linjer_i_tabel
+
Table_text_color=Tekstfarve_i_tabel
+
Tabname=Navn_på_faneblad
Target_file_cannot_be_a_directory.=Angivet_fil_kan_ikke_være_et_bibliotek.
+
Tertiary_sort_criterion=Tertiært_sorteringskriterium
+
Test=Test
+
paste_text_here=Indtastningsfelt
-#The_application_'%0'_associated_with_the_file_type_'%1'_could_not_be_called.=Applikationen_'%0'_associeret_med_filtypen_'%1'_kunne_ikke_startes.
+
The_chosen_date_format_for_new_entries_is_not_valid=Det_valgte_datoformat_er_ugyldigt
The_chosen_encoding_'%0'_could_not_encode_the_following_characters\:=Den_valgte_tegnkodning_'%0'_kunne_ikke_kode_de_følgende_tegn\:
+
+
the_field_<b>%0</b>=feltet_<b>%0</b>
+
The_file<BR>'%0'<BR>has_been_modified<BR>externally\!=Filen<BR>'%0'<BR>er_blevet_ændret<BR>eksternt\!
+
The_group_"%0"_already_contains_the_selection.=Gruppen_"%0"_indeholder_allerede_de_valgte_poster.
+
The_label_of_the_string_cannot_be_a_number.=Navnet_på_strengen_kan_ikke_være_et_tal.
+
The_label_of_the_string_cannot_contain_spaces.=Navnet_på_strengen_kan_ikke_indeholde_mellemrum.
+
The_label_of_the_string_cannot_contain_the_'\#'_character.=Navnet_på_strengen_kan_ikke_indeholde_tegnet_'\#'.
+
The_output_option_depends_on_a_valid_import_option.=Output-indstillingen_er_afhængig_af_en_gyldig_import-indstilling.
The_PDF_contains_one_or_several_BibTeX-records.=PDF-filen_indeholder_en_eller_flere_BibTeX-poster.
Do_you_want_to_import_these_as_new_entries_into_the_current_database?=Vil_du_importere_disse_som_nye_poster_i_den_åbne_database?
+
The_regular_expression_<b>%0</b>_is_invalid\:=Regulærudtrykket_<b>%0</b>_er_ugyldigt\:
+
The_search_is_case_insensitive.=Søgningen_skelner_ikke_mellem_store_og_små_bogstaver.
+
The_search_is_case_sensitive.=Søgningen_skelner_mellem_store_og_små_bogstaver.
+
The_string_has_been_removed_locally=Strengen_er_blevet_slettet_lokalt
+
There_are_possible_duplicates_(marked_with_an_icon)_that_haven't_been_resolved._Continue?=Der_findes_mulige_dubletter_(mærket_med_et_ikon)_som_ikke_er_blevet_håndteret._Fortsæt?
+
This_entry_has_no_BibTeX_key._Generate_key_now?=Denne_post_har_ingen_BibTeX-nøgle._Generer_nøgle_nu?
+
This_entry_is_incomplete=Denne_post_er_ufuldstændig
+
This_entry_type_cannot_be_removed.=Denne_posttype_kan_ikke_slettes.
+
This_external_link_is_of_the_type_'%0',_which_is_undefined._What_do_you_want_to_do?=Dette_eksterne_link_er_af_typen_'%0',_som_er_udefineret._Hvad_vil_du_gøre?
+
This_group_contains_entries_based_on_manual_assignment._Entries_can_be_assigned_to_this_group_by_selecting_them_then_using_either_drag_and_drop_or_the_context_menu._Entries_can_be_removed_from_this_group_by_selecting_them_then_using_the_context_menu.=Denne_gruppe_indeholder_poster_baseret_på_manuel_tildeling._Poster_kan_tildeles_til_denne_gruppe_ved_at_vælge_dem_og_derefter_trække_dem_over_til_gruppen,_eller_ved_hjælp_af_højreklikmenuen.
+
This_group_contains_entries_whose_<b>%0</b>_field_contains_the_keyword_<b>%1</b>=Denne_gruppe_indeholder_poster_hvis_<b>%0</b>-felt_indeholder_nøgleordet_<b>%1</b>
-This_group_contains_entries_whose_<b>%0</b>_field_contains_the_regular_expression_<b>%1</b>=Denne_gruppe_indeholder_poster,_hvis_<b>%0</b>-felt_stemmer_med_regulærudtrykket_<b>%1</b>
+This_group_contains_entries_whose_<b>%0</b>_field_contains_the_regular_expression_<b>%1</b>=Denne_gruppe_indeholder_poster,_hvis_<b>%0</b>-felt_stemmer_med_regulærudtrykket_<b>%1</b>
This_makes_JabRef_look_up_each_file_link_and_check_if_the_file_exists._If_not,_you_will_be_given_options<BR>to_resolve_the_problem.=Dette_får_JabRef_til_at_slå_hvert_fil-link_op_og_tjekke,_om_filen_eksisterer._Hvis_ikke_vil_du_få_mulighed_for_at<br>løse_problemet.
-#This_makes_JabRef_look_up_each_%0_link_and_check_if_the_file_exists._If_not,_you_will_be_given_options<BR>to_resolve_the_problem.=Dette_får_JabRef_til_at_undersøge_hvert_%0-link_og_tjekke,_om_filen_eksisterer._Hvis_ikke_vil_du_få_mulighed<BR>for_at_løse_problemet.
+
This_operation_requires_all_selected_entries_to_have_BibTeX_keys_defined.=Denne_operation_kræver,_at_alle_valgte_poster_har_definerede_BibTeX-nøgler.
+
This_operation_requires_one_or_more_entries_to_be_selected.=Denne_operation_kræver,_at_en_eller_flere_poster_er_valgt.
+
Toggle_abbreviation=Forkort/ekspander
Toggle_entry_preview=Vis/skjul_forhåndsvisning
Toggle_groups_interface=Vis/skjul_grupperingspanel
Try_different_encoding=Prøv_en_anden_tegnkodning
+
Unabbreviate_journal_names_of_the_selected_entries=Ekspander_tidsskriftsnavn_for_de_valgte_poster
Unabbreviated_%0_journal_names.=Ekspanderede_%0_tidsskriftsnavn.
+
Unable_to_open_file.=Kan_ikke_åbne_fil.
Unable_to_open_link._The_application_'%0'_associated_with_the_file_type_'%1'_could_not_be_called.=Kan_ikke_åbne_link._Applikationen_'%0'_associeret_med_filtypen_'%1'_kunne_ikke_kaldes.
unable_to_write_to=kunne_ikke_skrive_til
Undefined_file_type=Udefineret_filtype
+
Undo=Fortryd
+
Union=Foreningsmængde
+
Unknown_BibTeX_entries=Ukendte_BibTeX-poster
+
unknown_edit=ukendt_ændring
+
Unknown_export_format=Ukendt_eksportformat
+
Unmark_all=Fjern_mærkning_fra_alle
+
Unmark_entries=Fjern_mærkning
+
Unmark_entry=Fjern_mærkning
-Unsupported_version_of_class_%0\:_%1=Ikke-understøttet_version_af_klassen_%0\:_%1
+
untitled=uden_navn
+
Up=Op
+
Update_to_current_column_widths=Brug_nuværende_kolonnebredder
+
Updated_group_selection=Gruppevalg_opdateret
Upgrade_external_PDF/PS_links_to_use_the_'%0'_field.=Opgrader_eksterne_PDF-_og_PS-links_til_at_bruge_'%0'-feltet.
Upgrade_file=Opgrader_fil
Upgrade_old_external_file_links_to_use_the_new_feature=Opgrader_gamle_eksterne_links_for_at_bruge_den_nye_funktion
+
usage=brug
Use_autocompletion_for_the_following_fields=Brug_autoudfyldning_for_følgende_felter
+
Use_other_look_and_feel=Brug_andet_udseende
Use_regular_expression_search=Brug_søgning_med_regulærudtryk
+
Username=Brugernavn
+
Value_cleared_externally=Værdi_slettet_eksternt
+
Value_set_externally=Værdi_sat_eksternt
+
verify_that_LyX_is_running_and_that_the_lyxpipe_is_valid=kontroller_at_LyX_kører,_og_at_den_angivne_lyxpipe_stemmer
+
View=Vis
Vim_server_name=Navn_på_Vim-server
+
Waiting_for_ArXiv...=Venter_på_ArXiv
+
Warn_about_unresolved_duplicates_when_closing_inspection_window=Advar_om_dubletter_som_ikke_er_blevet_håndteret,_når_inspektionsvinduet_lukkes
+
Warn_before_overwriting_existing_keys=Advar_før_eksisterende_nøgler_overskrives
+
Warning=Advarsel
+
Warnings=Advarsler
+
web_link=link
What_do_you_want_to_do?=Hvad_vil_du_gøre?
+
When_adding/removing_keywords,_separate_them_by=Når_nøgleord_tilføjes_eller_fjernes,_adskil_dem_med
Will_write_XMP-metadata_to_the_PDFs_linked_from_selected_entries.=Skriver_XMP-metadata_til_PDF-filerne_linket_fra_de_valgte_poster.
+
with=med
+
Write_BibTeXEntry_as_XMP-metadata_to_PDF.=Skriv_BibTeX-posten_som_XMP-metadata_til_PDF.
+
Write_XMP=Skriv_XMP
Write_XMP-metadata=Skriv_XMP-metadata
Write_XMP-metadata_for_all_PDFs_in_current_database?=Skriv_XMP-metadata_for_alle_PDFer_i_denne_database?
-
Writing_XMP-metadata...=Skriver_XMP-metadata...
Writing_XMP-metadata_for_selected_entries...=Skriver_XMP-metadata_for_de_valgte_poster...
+
Wrote_XMP-metadata=Skrev_XMP-metadata
XMP-annotated_PDF=XMP-annoteret_PDF
@@ -807,12 +1380,17 @@ XMP-metadata=XMP-metadata
XMP-metadata_found_in_PDF\:_%0=XMP-metadata_fundet_i_PDF\:_%0
You_must_restart_JabRef_for_this_to_come_into_effect.=Du_skal_genstarte_JabRef_for,_at_dette_skal_træde_i_kraft.
You_have_changed_the_language_setting.=Du_har_valgt_et_nyt_sprog.
+
You_have_changed_the_look_and_feel_setting.=Du_har_ændret_indstillingen_for_udseende.
You_have_entered_an_invalid_search_'%0'.=Ugyldigt_søgeudtryk_'%0'.
+
You_must_choose_a_filename_to_store_journal_abbreviations=Du_skal_vælge_et_filnavn_for_at_gemme_tidsskriftsforkortelser
+
You_must_restart_JabRef_for_the_new_key_bindings_to_work_properly.=Du_skal_genstarte_JabRef_for,_at_de_nye_genvejstaster_skal_fungere.
+
Your_new_key_bindings_have_been_stored.=Dine_nye_genvejstaster_er_blevet_gemt.
+
The_following_fetchers_are_available\:=Følgende_henteværktøjer_er_tilgængelige\:
Could_not_find_fetcher_'%0'=Kunne_ikke_finde_henteværktøjet_'%0'
Running_query_'%0'_with_fetcher_'%1'.=Kører_forespørgsel_'%0'_med_henteværktøjet_'%1'.
@@ -826,16 +1404,13 @@ Number_of_entries_successfully_imported=Antal_poster_korrekt_importeret
Import_canceled_by_user=Import_afbrudt_af_bruger
Progress\:_%0_of_%1=Fremskridt\:_%0_af_%1
Error_while_fetching_from_%0=Fejl_under_hentning_fra_%0
-Fetching_Medline_by_id...=Henter_fra_Medline_via_ID...
-Fetching_Medline_by_term...=Henter_fra_Medline_via_udtryk...
-%0_import_canceled=%0-import_afbrudt
-Please_enter_a_valid_number=Indtast_venligst_et_gyldigt_tal
-Please_enter_a_comma_separated_list_of_Medline_IDs_(numbers)_or_search_terms.=Indtast_venligst_en_kommasepareret_liste_af_Medline_IDer_(numre)_eller_søgeudtryk.
+Please_enter_a_valid_number=Indtast_venligst_et_gyldigt_tal
Show_search_results_in_a_window=Vis_søgeresultater_i_et_vindue
+Show_global_search_results_in_a_window=
+Search_in_all_open_databases=
Move_file_to_file_directory?=Flyt_fil_til_filbibliotek?
Rename_to_'%0'=Omdøb_til_'%0'
-
You_have_changed_the_menu_and_label_font_size.=Du_har_ændret_menu-_og_tekst-skriftstørrelsen.
Database_is_protected._Cannot_save_until_external_changes_have_been_reviewed.=Databasen_er_beskyttet._Kan_ikke_gemme_før_eksterne_ændringer_er_gennemset.
@@ -843,13 +1418,13 @@ Protected_database=Beskyttet_database
Refuse_to_save_the_database_before_external_changes_have_been_reviewed.=Nægt_at_gemme_database_før_eksterne_ændringer_er_gennemset.
Database_protection=Database-beskyttelse
Unable_to_save_database=Kan_ikke_gemme_database
+
BibTeX_key_generator=BibTeX-nøglegenerator
Unable_to_open_link.=Kan_ikke_åbne_link.
Move_the_keyboard_focus_to_the_entry_table=Flyt_tastatur-fokus_til_hovedtabellen
MIME_type=MIME-type
This_feature_lets_new_files_be_opened_or_imported_into_an_already_running_instance_of_JabRef<BR>instead_of_opening_a_new_instance._For_instance,_this_is_useful_when_you_open_a_file_in_JabRef<br>from_your_web_browser.<BR>Note_that_this_will_prevent_you_from_running_more_than_one_instance_of_JabRef_at_a_time.=Denne_funktion_tillader,_at_flere_filer_kan_åbnes_eller_importeres_i_en_allerede_kørende_JabRef<BR>i_stedet_for_at_åbne_programmet_påny._For_eksempel_er_dette_praktisk,_når_du_åbner_f [...]
-
Run_fetcher,_e.g._"--fetch\=Medline\:cancer"=Kør_henteværktøj,_f.eks._"--fetch\=Medline\:cancer"
The_ACM_Digital_Library=ACM_Digital_Library
@@ -857,9 +1432,9 @@ Reset=Nulstil
Use_IEEE_LaTeX_abbreviations=Brug_IEEE-LaTeX-forkortelser
The_Guide_to_Computing_Literature=The_Guide_to_Computing_Literature
+
When_opening_file_link,_search_for_matching_file_if_no_link_is_defined=Søg_efter_en_matchende_fil,_når_der_åbnes_et_fil-link,_der_ikke_er_defineret
Settings_for_%0=Indstillinger_for_%0
-
Mark_entries_imported_into_an_existing_database=Mærk_poster_som_importeres_til_en_eksisterende_database
Unmark_all_entries_before_importing_new_entries_into_an_existing_database=Fjern_mærkning_fra_alle_poster_før_import_af_nye_poster_til_en_eksisterende_database
@@ -869,34 +1444,34 @@ Sort_the_following_fields_as_numeric_fields=Sorter_følgende_felter_som_numerisk
Line_%0\:_Found_corrupted_BibTeX_key.=Linje_%0\:_Fandt_ødelagt_BibTeX-nøgle.
Line_%0\:_Found_corrupted_BibTeX_key_(contains_whitespaces).=Linje_%0\:_Fandt_ødelagt_BibTeX-nøgle_(indeholder_blanktegn).
Line_%0\:_Found_corrupted_BibTeX_key_(comma_missing).=Linje_%0\:_Fandt_ødelagt_BibTeX-nøgle_(manglende_komma).
-Finished_downloading_full_text_document=Download_af_fuldtekst-dokument_afsluttet
Full_text_document_download_failed=Download_af_fuldtekst-dokument_mislykkedes
Update_to_current_column_order=Brug_nuværende_kolonnerækkefølge
-
+Download_from_URL=
Rename_field=Omdøb_felt
Set/clear/rename_fields=Sæt/ryd/omdøb_felter
Rename_field_to=Omdøb_felt_til
Move_contents_of_a_field_into_a_field_with_a_different_name=Flyt_indhold_af_et_felt_til_et_felt_med_et_andet_navn
You_can_only_rename_one_field_at_a_time=Du_kan_kun_omdøbe_et_felt_ad_gangen
+
Remove_all_broken_links=Fjern_alle_ødelagte_links
Cannot_use_port_%0_for_remote_operation;_another_application_may_be_using_it._Try_specifying_another_port.=Kan_ikke_bruge_port_%0_til_fjernstyring;_et_andet_program_bruger_den_måske._Prøv_en_anden_port.
Looking_for_full_text_document...=Søger_efter_tekstdokument...
Autosave=Automatisk_sikkerhedskopi
-Prompt_before_recovering_a_database_from_an_autosave_file=Spørg_før_en_database_genskabes_fra_en_automatisk_sikkerhedskopi.
-Autosave_interval_(minutes)=Automatisk_sikkerhedskopi-interval
-Do_you_want_to_recover_the_database_from_the_autosave_file?=Vil_du_genskabe_databasen_fra_sikkerhedskopien?
-Recover_from_autosave=Genskab_fra_sikkerhedskopi
+A_local_copy_will_be_opened.=
+Autosave_local_databases=
+Automatically_save_the_database_to=
+Please_enter_a_valid_file_path.=
+
Export_in_current_table_sort_order=Eksporter_med_nuværende_tabel-sortering
Export_entries_in_their_original_order=Eksporter_poster_med_den_oprindelige_sortering
Error_opening_file_'%0'.=Fejl_ved_åbning_af_filen_'%0'.
-Autosave_of_file_'%0'=Sikkerhedskopi_af_filen_'%0'
-Error_opening_autosave_of_'%0'._Trying_to_load_'%0'_instead.=Fejl_ved_åbning_af_sikkerhedskopi_af_'%0'._Forsøger_at_åbne_'%0'_i_stedet.
Formatter_not_found\:_%0=Formatering_ikke_fundet\:_%0
Clear_inputarea=Ryd_inputområde
+
Automatically_set_file_links_for_this_entry=Sæt_automatisk_fil-links_for_denne_post
Could_not_save,_file_locked_by_another_JabRef_instance.=Kunne_ikke_gemme,_filen_er_låst_af_en_anden_kørende_JabRef.
File_is_locked_by_another_JabRef_instance.=Filen_er_låst_af_en_anden_kørende_JabRef.
@@ -923,9 +1498,6 @@ includes_subgroups=inkluderer_undergrupper
contains=indeholder
search_expression=søge-udtry
-
-
-%0_mode=%0-tilstand
Optional_fields_2=Valgfri_felter_2
Waiting_for_save_operation_to_finish=Venter_på_gemme-operation
Resolving_duplicate_BibTeX_keys...=Udreder_dublerede_BibTeX-nøgler...
@@ -956,15 +1528,12 @@ Highlight_groups_that_contain_entries_contained_in_any_currently_selected_group=
You_must_enter_an_integer_value_in_the_interval_1025-65535_in_the_text_field_for=Der_skal_indtastes_et_heltal_i_intervallet_1025-65535_i_tekstfeltet_til
Automatically_open_browse_dialog_when_creating_new_file_link=Åbn_automatisk_fildialog_når_nyt_link_oprettes
-
-# Mr. dLib strings\:
Import_metadata_from\:=Importer_metadata_fra\:
Choose_the_source_for_the_metadata_import=Vælg_kilde_for_import_af_metadata
Create_entry_based_on_XMP_data=Opret_post_baseret_på_XMP-data
Create_blank_entry_linking_the_PDF=Opret_tom_post_med_link_til_PDF-filen
Only_attach_PDF=Tilføj_kun_PDF
Title=Titel
-No_internet_connection.=Ingen_Internetforbindelse.
Create_new_entry=Opret_ny_post
Update_existing_entry=Opdater_eksisterende_post
Autocomplete_names_in_'Firstname_Lastname'_format_only=Autofuldfør_kun_navne_i_formatet_'Fornavn_Efternavn'
@@ -1040,14 +1609,11 @@ Select_document=Vælg_dokument
Edit_group_membership=Rediger_gruppemedlemsskab
HTML_list=HTML-liste
Click_group_to_toggle_membership_of_selected_entries=Klik_på_gruppe_for_at_ændre_medlemsskab_for_de_valgte_poster
-Use_EMACS_23_insertion_string=Brug_EMACS_23-indsætningstekststreng
If_possible,_normalize_this_list_of_names_to_conform_to_standard_BibTeX_name_formatting=Om_muligt,_normaliser_denne_navneliste_til_standard_BibTeX-navneformatering
Could_not_open_%0=Kunne_ikke_åbne_%0
Unknown_import_format=Ukendt_importformat
Web_search=Websøgning
-
Style_selection=Valg_af_stil
-
No_valid_style_file_defined=Ingen_gyldig_stilfil_defineret
Choose_pattern=Vælg_mønster
Use_the_BIB_file_location_as_primary_file_directory=Brug_placeringen_af_BIB-filen_som_standard_filbibliotek
@@ -1059,13 +1625,14 @@ JabRef_includes_a_built-in_list_of_journal_abbreviations.=JabRef_har_en_indbygge
You_must_select_either_a_valid_style_file,_or_use_one_of_the_default_styles.=Du_skal_enten_vælge_en_gyldig_stilfil_eller_bruge_en_af_standardstilene.
This_is_a_simple_copy_and_paste_dialog._First_load_or_paste_some_text_into_the_text_input_area.<br>After_that,_you_can_mark_text_and_assign_it_to_a_BibTeX_field.=Dette_er_et_enkelt_klip-og-indsæt-vindue._Indlæs_eller_indsæt_først_tekst_i_tekstfeltet.<br>Derefter_kan_du_markere_tekst_og_tildele_den_til_BibTeX-felter.
-
This_feature_generates_a_new_database_based_on_which_entries_are_needed_in_an_existing_LaTeX_document.=Denne_funktion_genererer_en_ny_database_baseret_på,_hvilke_poster_der_er_brugt_i_et_eksisterende_LaTeX-dokument.
You_need_to_select_one_of_your_open_databases_from_which_to_choose_entries,_as_well_as_the_AUX_file_produced_by_LaTeX_when_compiling_your_document.=Du_skal_vælge_en_af_de_åbne_databaser,_hvor_enheder_skal_hentes_fra,_udover_AUX-filen_genereret_af_LaTeX_når_dokumentet_kompileres.
+
First_select_entries_to_clean_up.=
Cleanup_entry=
Autogenerate_PDF_Names=
Auto-generating_PDF-Names_does_not_support_undo._Continue?=
+
Use_full_firstname_whenever_possible=
Use_abbreviated_firstname_whenever_possible=
Use_abbreviated_and_full_firstname=
@@ -1075,6 +1642,7 @@ Name_format_used_for_autocompletion=
Treatment_of_first_names=
Cleanup_entries=
Automatically_assign_new_entry_to_selected_groups=Tildel_automatisk_nye_poster_til_valgte_grupper
+%0_mode=%0-tilstand
Move_DOIs_from_note_and_URL_field_to_DOI_field_and_remove_http_prefix=
Make_paths_of_linked_files_relative_(if_possible)=
Rename_PDFs_to_given_filename_format_pattern=
@@ -1087,11 +1655,11 @@ One_entry_needed_a_clean_up=
Error_downloading_file_'%0'=Feil_ved_hentning_af_filen_'%0'
Download_failed=Hentning_mislykkedes
+
Remove_selected=Fjern_valgte
Group_tree_could_not_be_parsed._If_you_save_the_BibTeX_database,_all_groups_will_be_lost.=
Attach_file=
-
Setting_all_preferences_to_default_values.=
Resetting_preference_key_'%0'=
Unknown_preference_key_'%0'=
@@ -1134,7 +1702,6 @@ Five_stars=
Four_stars=
Help_on_special_fields=
Keywords_of_selected_entries=
-Manage_content_selectors=
Manage_keywords=
No_priority_information=
No_rank_information=
@@ -1162,10 +1729,10 @@ Two_stars=
Update_keywords=
Write_values_of_special_fields_as_separate_fields_to_BibTeX=
You_have_changed_settings_for_special_fields.=
-
%0_entries_found._To_reduce_server_load,_only_%1_will_be_downloaded.=
A_string_with_that_label_already_exists=Der_findes_allerede_en_streng_med_dette_navn
Connection_to_OpenOffice/LibreOffice_has_been_lost._Please_make_sure_OpenOffice/LibreOffice_is_running,_and_try_to_reconnect.=
+
Correct_the_entry,_and_reopen_editor_to_display/edit_source.=
Could_not_connect_to_a_running_gnuserv_process._Make_sure_that_Emacs_or_XEmacs_is_running,<BR>and_that_the_server_has_been_started_(by_running_the_command_'server-start'/'gnuserv-start').=
Could_not_connect_to_running_OpenOffice/LibreOffice.=
@@ -1187,19 +1754,14 @@ Your_style_file_specifies_the_paragraph_format_'%0',_which_is_undefined_in_your_
Searching...=
You_have_selected_more_than_%0_entries_for_download._Some_web_sites_might_block_you_if_you_make_too_many_rapid_downloads._Do_you_want_to_continue?=
Confirm_selection=
-Unknown_DOI\:_'%0'.=
Add_{}_to_specified_title_words_on_search_to_keep_the_correct_case=
Import_conversions=
Please_enter_a_search_string=
Please_open_or_start_a_new_database_before_searching=
-An_error_occurred_while_fetching_from_ADS_(%0)\:=
-An_error_occurred_while_parsing_abstract=
-Unknown_DiVA_entry\:_'%0'.=
-Get_BibTeX_entry_from_DiVA=
Log=
-
Canceled_merging_entries=
+
Format_units_by_adding_non-breaking_separators_and_keeping_the_correct_case_on_search=
Merge_entries=
Merged_entries=
@@ -1213,29 +1775,35 @@ Use_Emacs_key_bindings=
You_have_to_choose_exactly_two_entries_to_merge.=
Update_timestamp_on_modification=
-
All_key_bindings_will_be_reset_to_their_defaults.=
+
Automatically_set_file_links=
Continue?=
Resetting_all_key_bindings=
-
Hostname=
Invalid_setting=
Network=
Please_specify_both_hostname_and_port=
+Please_specify_both_username_and_password=
+
Use_custom_proxy_configuration=
+Proxy_requires_authentication=
+Attention\:_Password_is_stored_in_plain_text\!=
Clear_connection_settings=
Cleared_connection_settings.=
+
Rebind_C-a,_too=
+Rebind_C-f,_too=
Show_number_of_elements_contained_in_each_group=
Open_folder=
Searches_for_unlinked_PDF_files_on_the_file_system=
-
Export_entries_ordered_as_specified=
Export_sort_order=
+Export_sorting=
Newline_separator=
+
Save_entries_ordered_as_specified=
Save_sort_order=
Show_extra_columns=
@@ -1246,7 +1814,6 @@ Move_to_group=
Clear_read_status=
Convert_to_BibLatex_format_(for_example,_move_the_value_of_the_'journal'_field_to_'journaltitle')=
-Could_not_apply_changes.=
Deprecated_fields=
Hide/show_toolbar=
No_read_status_information=
@@ -1258,121 +1825,109 @@ Save_selected_as_plain_BibTeX...=
Set_read_status_to_read=
Set_read_status_to_skimmed=
Show_deprecated_BibTeX_fields=
+
Show_gridlines=
Show_printed_status=
Show_read_status=
Table_row_height_padding=
-Marked_all_%0_selected_entries=
Marked_selected_entry=
-Toggle_print_status=
-Unmarked_all_%0_selected_entries=
+Marked_all_%0_selected_entries=
Unmarked_selected_entry=
+Unmarked_all_%0_selected_entries=
+Toggle_print_status=
+
Unmarked_all_entries=
Unable_to_find_the_requested_look_and_feel_and_thus_the_default_one_is_used.=
-Could_not_open_browser.=
Opens_JabRef's_GitHub_page=
-Rebind_C-f,_too=
-This_group_contains_all_entries._It_cannot_be_edited_or_removed.=
+Could_not_open_browser.=
+Please_open_%0_manually.=
+The_link_has_been_copied_to_the_clipboard.=
Open_%0_file=
Cannot_delete_file=
-Convert=
-Delete_local_file=
File_permission_error=
-Help_on_Name_Formatting=
-Normalize_to_BibTeX_name_format=
-Path_to_%0=Sti_til_%0
Push_to_%0=Send_til_%0
+Path_to_%0=Sti_til_%0
+Convert=
+Normalize_to_BibTeX_name_format=
+Help_on_Name_Formatting=
Add_new_file_type=
-Follow_DOI_or_URL_link_and_try_to_locate_PDF_full_text_document=
+
Left_entry=
-No_information_added=
+Right_entry=
+Use=
Original_entry=
Replace_original_entry=
-Right_entry=
+No_information_added=
Select_at_least_one_entry_to_manage_keywords.=
-Use=
-Changed_type_to_'%0'_for=Ændrede_type_til_'%0'_for
-Database_'%0'_has_changed.=
-Copy_\\cite{BibTeX_key}=Kopier_\\cite{BibTeX-nøgler}
-Copy_BibTeX_key_and_title=
-File_rename_failed_for_%0_entries.=
-To_set_up,_go_to=For_at_sætte_op,_gå_til
-Search_%0=Søg_i_%0
-Invalid_DOI\:_'%0'.=Ugyldig_DOI\:_'%0'.
-Could_not_connect_to_%0=Kunne_ikke_forbinde_til_%0
-
+OpenDocument_text=
+OpenDocument_spreadsheet=
+OpenDocument_presentation=
%0_image=
-%0_problem(s)_found=
-'%0'_is_not_a_valid_ADS_bibcode.=
-Accepting_the_change_replaces_the_complete_groups_tree_with_the_externally_modified_groups_tree.=
Added_entry=
-Added_new_'%0'_entry.=
-Choose_the_URL_to_download.=
-Deleted_entry=
-Discard_changes=
-Donate_to_JabRef=
-Export_with_selected_format=
-Field_is_missing=
-Filled=
-From_import=
-Keep_left=
-Keep_merged_entry_only=
-Keep_right=
-Merged_BibTeX_source_code=
Modified_entry=
+Deleted_entry=
Modified_groups_tree=
-Multiple_entries_selected._Do_you_want_to_change_the_type_of_all_these_to_'%0'?=
-No_problems_found.=
-Old_entry=
-OpenDocument_presentation=
-OpenDocument_spreadsheet=
-OpenDocument_text=
-Please_move_the_file_manually_and_link_in_place.=
-Print_entry_preview=
-Really_delete_the_%0_selected_entries?=
-Really_delete_the_selected_entry?=
Removed_all_groups=
-Return_to_JabRef=
-Save_changes=
+Accepting_the_change_replaces_the_complete_groups_tree_with_the_externally_modified_groups_tree.=
Select_export_format=
+Return_to_JabRef=
+Please_move_the_file_manually_and_link_in_place.=
+Could_not_connect_to_%0=Kunne_ikke_forbinde_til_%0
Warning\:_%0_out_of_%1_entries_have_undefined_BibTeX_key.=
-large_capitals_are_not_masked_using_curly_brackets_{}=
occurrence=
-should_contain_a_four_digit_number=
-should_contain_a_valid_page_number_range=
-should_end_with_a_name=
+Added_new_'%0'_entry.=
+Multiple_entries_selected._Do_you_want_to_change_the_type_of_all_these_to_'%0'?=
+Changed_type_to_'%0'_for=Ændrede_type_til_'%0'_for
+Really_delete_the_selected_entry?=
+Really_delete_the_%0_selected_entries?=
+Keep_merged_entry_only=
+Keep_left=
+Keep_right=
+Old_entry=
+From_import=
+No_problems_found.=
+%0_problem(s)_found=
+Save_changes=
+Discard_changes=
+Database_'%0'_has_changed.=
+Print_entry_preview=
+Copy_\\cite{BibTeX_key}=Kopier_\\cite{BibTeX-nøgler}
+Copy_BibTeX_key_and_title=
+File_rename_failed_for_%0_entries.=
+To_set_up,_go_to=For_at_sætte_op,_gå_til
+Merged_BibTeX_source_code=
+Invalid_DOI\:_'%0'.=Ugyldig_DOI\:_'%0'.
should_start_with_a_name=
+should_end_with_a_name=
unexpected_closing_curly_bracket=
unexpected_opening_curly_bracket=
+capital_letters_are_not_masked_using_curly_brackets_{}=
+should_contain_a_four_digit_number=
+should_contain_a_valid_page_number_range=
+Filled=
+Field_is_missing=
+Search_%0=Søg_i_%0
-Advanced_search_active.=
-Found_%0_results.=
-No_results_found.=
-Normal_search_active.=
-Search_globally=
-Search_in_all_open_databases=
Search_results_in_all_databases_for_%0=
Search_results_in_database_%0_for_%1=
-This_search_contains_entries_in_which=
+Search_globally=
+No_results_found.=
+Found_%0_results.=
+Advanced_search_active.=
+Normal_search_active.=
+plain_text=
This_search_contains_entries_in_which_any_field_contains_the_regular_expression_<b>%0</b>=
This_search_contains_entries_in_which_any_field_contains_the_term_<b>%0</b>=
-plain_text=
-
-Attention\:_Password_is_stored_in_plain_text\!=
-Please_specify_both_username_and_password=
-Proxy_requires_authentication=
+This_search_contains_entries_in_which=
-An_autosave_file_was_found_for_this_database._This_could_indicate_that_JabRef_did_not_shut_down_cleanly_last_time_the_file_was_used.=
-Note\:_A_full_text_search_is_currently_not_supported_for_%0=
Unable_to_autodetect_OpenOffice/LibreOffice_installation._Please_choose_the_installation_directory_manually.=
-
JabRef_no_longer_supports_'ps'_or_'pdf'_fields.<br>File_links_are_now_stored_in_the_'file'_field_and_files_are_stored_in_an_external_file_directory.<br>To_make_use_of_this_feature,_JabRef_needs_to_upgrade_file_links.<br><br>=
This_database_uses_outdated_file_links.=
@@ -1411,52 +1966,32 @@ Resolve_duplicate_BibTeX_keys=
Save_all=
String_dialog,_add_string=
String_dialog,_remove_string=
-Switch_preview_layout=
Synchronize_files=
Unabbreviate=
-
-
should_contain_a_protocol=
-
Copy_preview=
-
Automatically_setting_file_links=
Regenerating_BibTeX_keys_according_to_metadata=
No_meta_data_present_in_BIB_file._Cannot_regenerate_BibTeX_keys=
-
Regenerate_all_keys_for_the_entries_in_a_BibTeX_file=
-
Show_debug_level_messages=
-
-Export_sorting=
-
-New_%0_database=
-
-New_%0_database_created.=
-
-No_entry_found_for_ISBN_%0_at_www.ebook.de=
-
-
-Save_actions=
-Enable_save_actions=
-Always_reformat_BIB_file_on_save_and_export=
Default_bibliography_mode=
-
+New_%0_database_created.=
Show_only_preferences_deviating_from_their_default_value=
default=
key=
type=
value=
-
Show_preferences=
+Save_actions=
+Enable_save_actions=
Other_fields=
Show_remaining_fields=
-link_should_refer_to_a_correct_file_path=
+link_should_refer_to_a_correct_file_path=
abbreviation_detected=
wrong_entry_type_as_proceedings_has_page_numbers=
-
Abbreviate_journal_names=
Abbreviating...=
Adding_fetched_entries=
@@ -1468,28 +2003,22 @@ Unabbreviate_journal_names=
Unabbreviating...=
Usage=
+
+Adds_{}_brackets_around_acronyms,_month_names_and_countries_to_preserve_their_case.=
Are_you_sure_you_want_to_reset_all_settings_to_default_values?=
Reset_preferences=
-
Ill-formed_entrytype_comment_in_BIB_file=
+
+Move_linked_files_to_default_file_directory_%0=
+
Clipboard=
Could_not_paste_entry_as_text\:=
Do_you_still_want_to_continue?=
This_action_will_modify_the_following_field(s)_in_at_least_one_entry_each\:=
This_could_cause_undesired_changes_to_your_entries.=
-
-Disable_highlight_groups_matching_entries=
Run_field_formatter\:=
-
-Adds_{}_brackets_around_acronyms,_month_names_and_countries_to_preserve_their_case.=
-Converts_units_to_LaTeX_formatting.=
-Does_nothing.=
-
-
Table_font_size_is_%0=
-
-Move_linked_files_to_default_file_directory_%0=
-
+%0_import_canceled=%0-import_afbrudt
Internal_style=
Add_style_file=
Are_you_sure_you_want_to_remove_the_style?=
@@ -1497,7 +2026,6 @@ Current_style_is_'%0'=
Remove_style=
Select_one_of_the_available_styles_or_add_a_style_file_from_disk.=
You_must_select_a_valid_style_file.=
-
Reload=
Capitalize=
@@ -1508,9 +2036,11 @@ Changes_all_letters_to_upper_case.=
Changes_the_first_letter_of_all_words_to_capital_case_and_the_remaining_letters_to_lower_case.=
Cleans_up_LaTeX_code.=
Converts_HTML_code_to_LaTeX_code.=
+Converts_HTML_code_to_Unicode.=
Converts_LaTeX_encoding_to_Unicode_characters.=
Converts_Unicode_characters_to_LaTeX_encoding.=
Converts_ordinals_to_LaTeX_superscripts.=
+Converts_units_to_LaTeX_formatting.=
HTML_to_LaTeX=
LaTeX_cleanup=
LaTeX_to_Unicode=
@@ -1534,16 +2064,13 @@ Title_case=
Unicode_to_LaTeX=
Units_to_LaTeX=
Upper_case=
+Does_nothing.=
Identity=
-
Clears_the_field_completely.=
Directory_not_found=
Main_file_directory_not_set\!=
-
This_operation_requires_exactly_one_item_to_be_selected.=
-
Importing_in_%0_format=
-
Female_name=
Female_names=
Male_name=
@@ -1588,38 +2115,29 @@ U.S._patent=
U.S._patent_request=
Verse=
-
change_entries_of_group=
odd_number_of_unescaped_'\#'=
+
Plain_text=
Show_diff=
character=
word=
-
Show_symmetric_diff=
HTML_encoded_character_found=
-
booktitle_ends_with_'conference_on'=
+
All_external_files=
OpenOffice/LibreOffice_integration=
incorrect_control_digit=
incorrect_format=
-
-Expected_"%0"_to_contain_whitespace=
-Syntax_error_in_regular-expression_pattern=
-
Copy_version_to_clipboard=
Copied_version_to_clipboard=
+
BibTeX_key=
Message=
-
-Get_fulltext=
-
-Download_from_URL=
-
Decryption_not_supported.=
Cleared_'%0'_for_%1_entries=
@@ -1638,16 +2156,11 @@ To_see_what_is_new_view_the_changelog.=
A_new_version_of_JabRef_has_been_released.=
JabRef_is_up-to-date.=
Latest_version=
-
-Please_open_%0_manually.=
-
-The_link_has_been_copied_to_the_clipboard.=
-
Online_help_forum=
-
Custom=
-Converts_HTML_code_to_Unicode.=
+Export_cited=
+Unable_to_generate_new_database=
Open_console=
Use_default_terminal_emulator=
@@ -1655,30 +2168,22 @@ Execute_command=
Note\:_Use_the_placeholder_%0_for_the_location_of_the_opened_database_file.=
Executing_command_\"%0\"...=
Error_occured_while_executing_the_command_\"%0\".=
-
Reformat_ISSN=
-Unable_to_generate_new_database=
-
-Export_cited=
Countries_and_territories_in_English=
Electrical_engineering_terms=
Enabled=
Internal_list=
+Manage_protected_terms_files=
Months_and_weekdays_in_English=
The_text_after_the_last_line_starting_with_\#_will_be_used=
Add_protected_terms_file=
Are_you_sure_you_want_to_remove_the_protected_terms_file?=
Remove_protected_terms_file=
-
-Manage_protected_terms_files=
-
Add_selected_text_to_list=
Add_{}_around_selected_text=
Format_field=
New_protected_terms_file=
-
-
change_field_%0_of_entry_%1_from_%2_to_%3=
change_key_from_%0_to_%1=
change_string_content_%0_to_%1=
@@ -1688,39 +2193,29 @@ insert_entry_%0=
insert_string_%0=
remove_entry_%0=
remove_string_%0=
-
undefined=
-
-
Cannot_get_info_based_on_given_%0\:_%1=
-
Get_BibTeX_data_from_%0=
No_%0_found=Ingen_%0_fundet
-
Entry_from_%0=Post_fra_%0
-
Merge_entry_with_%0_information=
Updated_entry_with_info_from_%0=
Connection=
+Connecting...=
Host=
Port=
Database=
User=
+Connect=Tilslut
Connection_error=
-Driver_error=
Connection_to_%0_server_established.=
Required_field_"%0"_is_empty.=
-
%0_driver_not_available.=
-
The_connection_to_the_server_has_been_terminated.=
-
Connection_lost.=
Reconnect=
Work_offline=
-
Working_offline.=
-
Update_refused.=
Update_refused=
Local_entry=
@@ -1731,9 +2226,13 @@ Local_version\:_%0=
Shared_version\:_%0=
Please_merge_the_shared_entry_with_yours_and_press_"Merge_entries"_to_resolve_this_problem.=
Canceling_this_operation_will_leave_your_changes_unsynchronized._Cancel_anyway?=
-The_BibEntry_you_currently_work_on_has_been_deleted_on_the_shared_side._Hit_"Keep"_to_recover_the_entry.=
-Cannot_cite_entries_without_BibTeX_keys._Generate_keys_now?=
+Shared_entry_is_no_longer_present=
+The_BibEntry_you_currently_work_on_has_been_deleted_on_the_shared_side.=
+You_can_restore_the_entry_using_the_"Undo"_operation.=
+Remember_password?=
+You_are_already_connected_to_a_database_using_entered_connection_details.=
+Cannot_cite_entries_without_BibTeX_keys._Generate_keys_now?=
New_technical_report=
%0_file=
@@ -1742,12 +2241,8 @@ Protected_terms_file=
Style_file=
Open_OpenOffice/LibreOffice_connection=
-
You_must_enter_at_least_one_field_name=
-
-
Non-ASCII_encoded_character_found=
-
Toggle_web_search_interface=
Background_color_for_resolved_fields=
Color_code_for_resolved_fields=
@@ -1761,13 +2256,59 @@ There_were_%0_files_which_could_not_be_imported.=
Migration_help_information=
Entered_database_has_obsolete_structure_and_is_no_longer_supported.=
However,_a_new_database_was_created_alongside_the_pre-3.6_one.=
-
Click_here_to_learn_about_the_migration_of_pre-3.6_databases.=
-
-Connecting...=
Opens_JabRef's_Facebook_page=
Opens_JabRef's_blog=
Opens_JabRef's_website=
-
Opens_a_link_where_the_current_development_version_can_be_downloaded=
See_what_has_been_changed_in_the_JabRef_versions=
+Referenced_BibTeX_key_does_not_exist=
+Finished_downloading_full_text_document_for_entry_%0.=
+Full_text_document_download_failed_for_entry_%0.=
+Look_up_full_text_documents=
+You_are_about_to_look_up_full_text_documents_for_%0_entries.=
+last_four_nonpunctuation_characters_should_be_numerals=
+shared=
+should_contain_an_integer_or_a_literal=
+should_have_the_first_letter_capitalized=
+
+ID=
+ID_type=
+ID-based_entry_generator=
+Fetcher_'%0'_did_not_find_an_entry_for_id_'%1'.=
+
+Select_first_entry=
+Select_last_entry=
+
+Invalid_ISBN\:_'%0'.=
+should_be_an_integer_or_normalized=
+should_be_normalized=
+
+Empty_search_ID=
+The_given_search_ID_was_empty.=
+Copy_BibTeX_key_and_link=
+empty_BibTeX_key=
+BibLaTeX_field_only=
+
+Error_while_generating_fetch_URL=
+Error_while_parsing_ID_list=
+Unable_to_get_PubMed_IDs=
+Backup_found=
+A_backup_file_for_'%0'_was_found.=
+This_could_indicate_that_JabRef_did_not_shut_down_cleanly_last_time_the_file_was_used.=
+Do_you_want_to_recover_the_database_from_the_backup_file?=
+Firstname_Lastname=
+
+Recommended_for_%0=
+This_might_be_caused_by_reaching_the_traffic_limitation_of_Google_Scholar_(see_'Help'_for_details).=
+
+Problem_downloading_from_%1=
+
+File_directory_pattern=
+Update_with_bibliographic_information_from_the_web=
+
+Could_not_find_any_bibliographic_information.=
+BibTeX_key_%0_deviates_from_generated_key_%1=
+DOI_%0_is_invalid=
+
+Jump_to_entry=
diff --git a/src/main/resources/l10n/JabRef_de.properties b/src/main/resources/l10n/JabRef_de.properties
index ef7e9f9..fb08a9d 100644
--- a/src/main/resources/l10n/JabRef_de.properties
+++ b/src/main/resources/l10n/JabRef_de.properties
@@ -1,5 +1,5 @@
#!
-#! created/edited by Popeye version 0.55 (popeye.sourceforge.net)
+#! created/edited by Popeye version 0.55 (github.com/JabRef/popeye)
#! encoding:UTF-8
%0_contains_the_regular_expression_<b>%1</b>=%0_den_regulären_Ausdruck_<b>%1</b>_enthält
@@ -12,18 +12,14 @@
%0_export_successful=%0-Export_erfolgreich
-
%0_matches_the_regular_expression_<b>%1</b>=%0_exakt_dem_regulären_Ausdruck_<b>%1</b>_entspricht
%0_matches_the_term_<b>%1</b>=%0_exakt_dem_Ausdruck_<b>%1</b>_entspricht
-<field_name>=<Feldname>
<HTML>Could_not_find_file_'%0'<BR>linked_from_entry_'%1'</HTML>=<HTML>Die_Datei_'%0',_die_vom_Eintrag<BR>'%1'_verlinkt_wird,_wurde_nicht_gefunden</HTML>
-
<select>=<auswählen>
-<select_word>=<Wort_auswählen>
Abbreviate_journal_names_of_the_selected_entries_(ISO_abbreviation)=Zeitschriftentitel_der_ausgewählten_Einträge_abkürzen_(ISO-Abkürzung)
Abbreviate_journal_names_of_the_selected_entries_(MEDLINE_abbreviation)=Zeitschriftentitel_der_ausgewählten_Einträge_abkürzen_(MEDLINE-Abkürzung)
@@ -44,13 +40,12 @@ Action=Aktion
Add=Hinzufügen
-Add_a_(compiled)_custom_ImportFormat_class_from_a_class_path.=Füge_eine_(kompilierte)_externe_ImportFormat_Klasse_aus_einem_Verzeichnis_hinzu.
+Add_a_(compiled)_custom_Importer_class_from_a_class_path.=Füge_eine_(kompilierte)_externe_Importer_Klasse_aus_einem_Verzeichnis_hinzu.
The_path_need_not_be_on_the_classpath_of_JabRef.=Das_Verzeichnis_muss_nicht_im_Klassenpfad_von_JabRef_enthalten_sein.
-Add_a_(compiled)_custom_ImportFormat_class_from_a_ZIP-archive.=Füge_eine_(kompilierte)_externe_ImportFormat_Klasse_aus_Verzeichnis_hinzu.
+Add_a_(compiled)_custom_Importer_class_from_a_ZIP-archive.=Füge_eine_(kompilierte)_externe_Importer_Klasse_aus_Verzeichnis_hinzu.
The_ZIP-archive_need_not_be_on_the_classpath_of_JabRef.=Das_Verzeichnis_muss_nicht_im_Klassenpfad_von_JabRef_enthalten_sein.
-
Add_entry_selection_to_this_group=Ausgewählte_Einträge_zu_dieser_Gruppe_hinzufügen
Add_from_folder=Aus_Klassenpfad_hinzufügen
@@ -76,8 +71,6 @@ Added_string=String_hinzugefügt
Additionally,_entries_whose_<b>%0</b>_field_does_not_contain_<b>%1</b>_can_be_assigned_manually_to_this_group_by_selecting_them_then_using_either_drag_and_drop_or_the_context_menu._This_process_adds_the_term_<b>%1</b>_to_each_entry's_<b>%0</b>_field._Entries_can_be_removed_manually_from_this_group_by_selecting_them_then_using_the_context_menu._This_process_removes_the_term_<b>%1</b>_from_each_entry's_<b>%0</b>_field.=Zusätzlich_können_Einträge,_deren_Feld_<b>%0</b>_nicht_<b>%1</b>_enthäl [...]
Advanced=Erweitert
-
-
All_entries=Alle_Einträge
All_entries_of_this_type_will_be_declared_typeless._Continue?=Alle_Einträge_dieses_Typs_werden_als_'ohne_Typ'_angesehen._Fortfahren?
@@ -85,11 +78,11 @@ All_fields=Alle_Felder
All_subgroups_(recursively)=Alle_Untergruppen_(rekursiv)
-An_exception_occurred_while_accessing_'%0'=Fehler_beim_Zugriff_auf_'%0'
+Always_reformat_BIB_file_on_save_and_export=Formatiere_BIB_Datei_immer_neu_beim_Exportieren
+
A_SAX_exception_occurred_while_parsing_'%0'\:=Beim_Parsen_von_'%0'_ist_eine_SAX-Exception_aufgetreten\:
and=und
-
and_the_class_must_be_available_in_your_classpath_next_time_you_start_JabRef.=Außerdem_muss_die_Klasse_beim_nächsten_Start_von_JabRef_durch_den_"Classpath"_erreichbar_sein.
any_field_that_matches_the_regular_expression_<b>%0</b>=ein_beliebiges_Feld,_auf_das_der_reguläre_Ausdruck_<b>%0</b>_passt,
@@ -97,9 +90,9 @@ any_field_that_matches_the_regular_expression_<b>%0</b>=ein_beliebiges_Feld,_auf
Appearance=Erscheinungsbild
Append=anfügen
-Append_contents_from_a_BibTeX_database_into_the_currently_viewed_database=Inhalt_einer_BibTeX-Datei_an_die_aktuelle_Datei_anhängen
+Append_contents_from_a_BibTeX_database_into_the_currently_viewed_database=Inhalt_einer_BibTeX-Datenbank_an_die_aktuelle_Datenbank_anhängen
-Append_database=Datei_anhängen
+Append_database=Datenbank_anhängen
Append_the_selected_text_to_BibTeX_field=Ausgewählten_Text_an_BibTeX-Key_anhängen
Application=Anwendung
@@ -128,21 +121,18 @@ Autodetect_format=Format_automatisch_erkennen
Autogenerate_BibTeX_keys=BibTeX-Keys_automatisch_generieren
-
-
-
Autolink_files_with_names_starting_with_the_BibTeX_key=Dateien,_deren_Namen_mit_dem_BibTeX-Key_beginnen,_automatisch_verlinken
+
Autolink_only_files_that_match_the_BibTeX_key=Nur_Dateien_verlinken,_deren_Namen_dem_BibTeX-Key_entsprechen
Automatically_create_groups=Gruppen_automatisch_erstellen
-Automatically_create_groups_for_database.=Automatisch_Gruppen_für_die_Datei_anlegen.
+Automatically_create_groups_for_database.=Automatisch_Gruppen_für_die_Datenbank_anlegen.
Automatically_created_groups=Automatisch_erzeugte_Gruppen
Automatically_remove_exact_duplicates=Exakte_Duplikate_automatisch_löschen
-
Allow_overwriting_existing_links.=Vorhandene_Links_überschreiben.
Do_not_overwrite_existing_links.=Vorhandene_Links_nicht_überschreiben.
@@ -163,9 +153,7 @@ Backup_old_file_when_saving=Beim_Speichern_ein_Backup_der_alten_Datei_anlegen
BibTeX_key_is_unique.=Der_BibTeX-Key_ist_eindeutig.
-
-BibTeX_source=BibTeX-Quelltext
-
+%0_source=%0-Quelltext
Broken_link=Ungültiger_Link
@@ -195,12 +183,9 @@ Case_sensitive=Groß-/Kleinschreibung
change_assignment_of_entries=Änderung_der_zugewiesenen_Einträge
-# The following are for case change in right-click menu in entry editor. The last four
-# illustrate the four variations of capitalization
Change_case=Groß-_und_Kleinschreibung
Change_entry_type=Eintragstyp_ändern
-
Change_file_type=Dateityp_ändern
@@ -208,10 +193,8 @@ Change_of_Grouping_Method=Ändern_der_Gruppierungsmethode
change_preamble=Präambel_ändern
-
Change_table_column_and_General_fields_settings_to_use_the_new_feature=Tabellenspalte_und_Einstellungen_der_Allgemeinen_Felder_ändern,_um_die_neue_Funktion_zu_nutzen
-
Changed_font_settings=Schrifteinstellungen_geändert
Changed_language_settings=Spracheinstellungen_geändert
@@ -226,27 +209,26 @@ Check_existing_file_links=Existierende_Datei-Links_überprüfen
Check_links=Links_überprüfen
+Choose_the_URL_to_download.=Wählen_Sie_die_Download-URL
Cite_command=Cite-Befehl
Class_name=Klassenname
Clear=Zurücksetzen
-
Clear_fields=Felder_löschen
-
Close=Schließen
Close_others=Andere_schließen
Close_all=Alle_schließen
-Close_dialog=Dialog_schließen
-Close_the_current_database=Aktuelle_Datei_schließen
+Close_dialog=Dialog_schließen
+Close_the_current_database=Aktuelle_Datenbank_schließen
Close_window=Fenster_schließen
-Closed_database=Datei_geschlossen
+Closed_database=Datenbank_geschlossen
Collapse_subtree=Unterbaum_zuklappen
@@ -258,6 +240,7 @@ Column_width=Spaltenbreite
Command_line_id=Kommandozeilen_ID
+
Contained_in=Enthalten_in
Content=Inhalt
@@ -284,17 +267,16 @@ Could_not_export_file=Konnte_Datei_nicht_exportieren
Could_not_export_preferences=Einstellungen_konnten_nicht_exportiert_werden
-Could_not_find_a_suitable_import_format.=Kein_passendes_Importformat_gefunden.
+Could_not_find_a_suitable_import_format.=Kein_passendes_Importer_gefunden.
Could_not_import_preferences=Einstellungen_konnten_nicht_importiert_werden
Could_not_instantiate_%0=Konnte_Importer_nicht_erzeugen_%0
Could_not_instantiate_%0_%1=Konnte_Importer_nicht_erzeugen_%0_%1
-
Could_not_instantiate_%0._Have_you_chosen_the_correct_package_path?=Konnte_%0_nicht_realisieren._Haben_Sie_den_richtigen_Paket-Pfad_angegeben?
-
Could_not_open_link=Link_konnte_nicht_geöffnet_werden
Could_not_print_preview=Druckvorschau_fehlgeschlagen
+
Could_not_run_the_'vim'_program.=Das_Programm_'vim'_konnte_nicht_gestartet_werden.
Could_not_save_file.=Datei_konnte_nicht_gespeichert_werden.
@@ -323,9 +305,9 @@ cut_entries=Einträge_ausschneiden
cut_entry=Eintrag_ausschneiden
-Database_encoding=Zeichenkodierung_der_Datei
+Database_encoding=Zeichenkodierung_der_Datenbank
-Database_properties=Eigenschaften_der_Datei
+Database_properties=Eigenschaften_der_Datenbank
Database_type=Typ der Datenbank
@@ -348,8 +330,6 @@ Delete=Löschen
Delete_custom_format=Format_des_Eintragstyps_löschen
-# I have reformulated the following lines, because the 1st person form is not suitable\:
-# (Folgende_URL_konnte_nicht_analysiert_werden)
delete_entries=Einträge_löschen
Delete_entry=Eintrag_löschen
@@ -364,6 +344,8 @@ Delete_strings=Strings_löschen
Deleted=Gelöscht
+Delete_local_file=Lösche_lokale_Datei
+
Delimit_fields_with_semicolon,_ex.=Felder_mit_Semikolon_abgrenzen,_z.B.
Descending=Absteigend
@@ -373,8 +355,6 @@ Description=Beschreibung
Deselect_all=Auswahl_aufheben
Deselect_all_duplicates=Auswahl_der_Duplikate_aufheben
-
-
Disable_this_confirmation_dialog=Diesen_Bestätigungsdialog_deaktivieren
Display_all_entries_belonging_to_one_or_more_of_the_selected_groups.=Alle_Einträge_anzeigen,_die_zu_einer_oder_mehreren_der_ausgewählten_Gruppen_gehören.
@@ -384,7 +364,6 @@ Display_all_error_messages=Zeige_alle_Fehlermeldugen
Display_help_on_command_line_options=Zeige_Kommandozeilenhilfe
Display_only_entries_belonging_to_all_selected_groups.=Nur_Einträge_anzeigen,_die_zu_allen_ausgewählten_Gruppen_gehören.
-
Display_version=Version_anzeigen
Displaying_no_groups=Keine_Gruppen_anzeigen
@@ -405,6 +384,7 @@ Do_not_write_the_following_fields_to_XMP_Metadata\:=Folgende_Felder_nicht_in_die
Do_you_want_JabRef_to_do_the_following_operations?=Soll_JabRef_die_folgenden_Vorgänge_durchführen?
+Donate_to_JabRef=An_JabRef_spenden
Down=Abwärts
@@ -416,14 +396,12 @@ Downloading...=Download_läuft
Drop_%0=%0_streichen
-
duplicate_removal=Duplikate_entfernen
Duplicate_string_name=Doppelter_String-Name
Duplicates_found=Doppelte_Einträge_gefunden
-
Dynamic_groups=Dynamische_Gruppen
Dynamically_group_entries_by_a_free-form_search_expression=Dynamisches_Gruppieren_der_Einträge_anhand_eines_beliebigen_Suchausdrucks
@@ -454,7 +432,6 @@ Grouping_may_not_work_for_this_entry.=Es_kann_sein,_dass_die_Gruppierung_für_di
empty_database=leere_Datenbank
Enable_word/name_autocompletion=Autovervollständigung_aktivieren
-
Enter_URL=URL_eingeben
Enter_URL_to_download=URL_für_den_Download_eingeben
@@ -466,7 +443,6 @@ Entries_cannot_be_manually_assigned_to_or_removed_from_this_group.=Ein_manuelles
Entries_exported_to_clipboard=Einträge_in_die_Zwischenablage_kopiert
-
entry=Eintrag
Entry_editor=Eintragseditor
@@ -486,7 +462,6 @@ Entry_types=Eintragstypen
Error=Fehler
Error_exporting_to_clipboard=Fehler_beim_Exportieren_in_die_Zwischenablage
-##Error\:_check_your_External_viewer_settings_in_Preferences=Fehler\:_überprüfen_Sie_Ihre_Einstellungen_zu_Externen_Programmen
Error_occurred_when_parsing_entry=Fehler_beim_Analysieren_des_Eintrags
Error_opening_file=Fehler_beim_Öffnen_der_Datei
@@ -494,7 +469,6 @@ Error_opening_file=Fehler_beim_Öffnen_der_Datei
Error_setting_field=Fehler_beim_Erstellen_des_Feldes
Error_while_writing=Fehler_beim_Schreiben
-
Error_writing_to_%0_file(s).=Fehler_beim_Schreiben_in_%0_Datei(en).
@@ -532,19 +506,15 @@ External_programs=Externe_Programme
External_viewer_called=Externer_Betrachter_aufgerufen
-
Fetch=Abrufen
Field=Feld
field=Feld
-# Integrity check is a process that checks for indications of wrongly filled out BibTeX fields. "Scan" is the button that starts the check.
-
Field_name=Feldname
Field_names_are_not_allowed_to_contain_white_space_or_the_following_characters=Feldbezeichnungen_dürfen_keine_Leerzeichen_enthalten_und_keine_der_folgenden_Zeichen
-
Field_to_filter=Feld_für_Filter
Field_to_group_by=Sortierfeld
@@ -552,7 +522,6 @@ Field_to_group_by=Sortierfeld
File=Datei
file=Datei
-
File_'%0'_is_already_open.=Datei_'%0'_ist_bereits_geöffnet.
File_'%0'_not_found=Datei_'%0'_nicht_gefunden
@@ -564,7 +533,6 @@ File_directory_is_not_set_or_does_not_exist\!=Dateiverzeichnis_ist_nicht_gesetzt
File_exists=Datei_ist_vorhanden
-
File_has_been_updated_externally._What_do_you_want_to_do?=Die_Datei_wurde_extern_aktualisiert._Was_wollen_Sie_tun?
File_not_found=Datei_nicht_gefunden
@@ -589,7 +557,6 @@ First_select_the_entries_you_want_keys_to_be_generated_for.=Wählen_Sie_zuerst_d
Fit_table_horizontally_on_screen=Tabelle_horizontal_dem_Bildschirm_anpassen
Float=Oben_einsortieren
-
Float_marked_entries=Markierte_Einträge_zuoberst_anzeigen
Font_family=Schriftart
@@ -625,8 +592,6 @@ Generate_BibTeX_key=BibTeX-Key_generieren
Generate_keys=Erstelle_Key
Generate_keys_before_saving_(for_entries_without_a_key)=Keys_vor_dem_Speichern_erstellen_(für_Einräge_ohne_Key)
-
-
Generate_keys_for_imported_entries=Keys_für_importierte_Einträge_generieren
Generate_now=Jetzt_generieren
@@ -634,22 +599,19 @@ Generate_now=Jetzt_generieren
Generated_BibTeX_key_for=BibTeX-Key_erzeugt_für
Generating_BibTeX_key_for=Erzeuge_BibTeX-Key_für
-
+Get_fulltext=Hole_Volltext
Grab=Tastenkürzel_holen
Gray_out_entries_not_in_group_selection=Einträge_ausblenden,_die_nicht_in_der_Gruppenauswahl_sind
Gray_out_non-hits=Nicht-Treffer_grau_einfärben
-
Groups=Gruppen
-
Have_you_chosen_the_correct_package_path?=Habe_Sie_den_richtigen_Klassenpfad_gewählt?
Help=Hilfe
-
Help_on_groups=Hilfe_zu_Gruppen
Help_on_key_patterns=Hilfe_zu_BibTeX-Key-Mustern
@@ -657,20 +619,18 @@ Help_on_regular_expression_search=Hilfe_zur_Suche_mit_regulärem_Ausdruck
Hide_non-hits=Nicht-Treffer_ausblenden
-
Hierarchical_context=Hierarchischer_Kontext
Highlight=Markieren
Highlight_groups_matching_all_selected_entries=Gruppen_hervorheben,_die_alle_ausgewählten_Einträge_enthalten
Highlight_groups_matching_any_selected_entry=Gruppen_hervorheben,_die_einen_der_ausgewählten_Einträge_enthalten
+Disable_highlight_groups_matching_entries=Keine_Gruppen_hervorheben
Highlight_overlapping_groups=Sich_überschneidende_Gruppen_markieren
Hint\:_To_search_specific_fields_only,_enter_for_example\:<p><tt>author\=smith_and_title\=electrical</tt>=Hinweis\:_Um_ausschließlich_bestimmte_Felder_zu_durchsuchen,_geben_Sie_z.B._ein\:<p><tt>author\=smith_and_title\=electrical</tt>
-
HTML_table=HTML-Tabelle
-
HTML_table_(with_Abstract_&_BibTeX)=HTML-Tabelle_(mit_Abstract_&_BibTeX)
Icon=Icon
@@ -688,7 +648,7 @@ Import_entries=Einträge_importieren
Import_failed=Import_fehlgeschlagen
-Import_file=Importiere_Datei
+Import_file=Datei_importieren
Import_group_definitions=Gruppendefinitionen_importieren
@@ -696,50 +656,37 @@ Import_name=Name_des_Importfilters
Import_preferences=Einstellungen_importieren
-Import_preferences_from_file=Importiere_Einstellungen_aus_Datei
+Import_preferences_from_file=Einstellungen_aus_Datei_importieren
Import_strings=Strings_importieren
Import_to_open_tab=In_geöffnetes_Tab_importieren
-Import_word_selector_definitions=Wortauswahldefinitionen_importieren
-
-
Imported_entries=Einträge_importiert
-Imported_from_database=Importiert_aus_Datei
+Imported_from_database=Importiert_aus_Datenbank
-ImportFormat_class=ImportFormat_Klasse
+Importer_class=Importer_Klasse
-Importing=Importiere
-
-Importing_in_unknown_format=Importiere_ein_unbekanntes_Format
+Importing=Importieren
+Importing_in_unknown_format=Ein_unbekanntes_Format_importieren
Include_abstracts=Abstracts_berücksichtigen
Include_entries=Einträge_einschließen
Include_subgroups\:_When_selected,_view_entries_contained_in_this_group_or_its_subgroups=Untergruppen_berücksichtigen\:_Einträge_dieser_Gruppe_und_ihrer_Untergruppen_anzeigen
-
-
-
Independent_group\:_When_selected,_view_only_this_group's_entries=Unabhängige_Gruppen\:_Nur_die_Einträge_dieser_Gruppe_anzeigen
Initially_show_groups_tree_expanded=Baumansicht_der_Gruppen_standardmäßig_aufklappen
Work_options=Bearbeitungsoptionen
-Input_error=Eingabefehler
-
Insert=einfügen
Insert_rows=Zeilen_einfügen
-
-
-
-# Integrity check is a process that checks for indications of wrongly filled out BibTeX fields. "Scan" is the button that starts the check.
Intersection=Schnittmenge
Invalid_BibTeX_key=Ungültiger_BibTeX-Key
@@ -790,7 +737,6 @@ Leave_file_in_its_current_directory=Datei_im_aktuellen_Verzeichnis_lassen
Left=Links
Level=Ebene
-
Limit_to_fields=Auf_folgende_Felder_begrenzen
Limit_to_selected_entries=Auf_ausgewählte_Einträge_begrenzen
@@ -802,15 +748,11 @@ Link_to_file_%0=Link_zur_Datei_%0
Listen_for_remote_operation_on_port=Port_nach_externem_Zugriff_abhören
Load_and_Save_preferences_from/to_jabref.xml_on_start-up_(memory_stick_mode)=Einstellungen_beim_Start_laden_von/speichern_in_jabref.xml_(Memory_Stick-Modus)
-
-
Look_and_feel=Aussehen
Main_file_directory=Standard-Verzeichnis_für_Dateien
Main_layout_file=Haupt-Layoutdatei
-Manage=Verwalten
-
Manage_custom_exports=Verwalte_externe_Exportfilter
Manage_custom_imports=Verwalte_externe_Importfilter
@@ -826,7 +768,6 @@ Mark_new_entries_with_addition_date=Neue_Einträge_mit_Datum_versehen
Mark_new_entries_with_owner_name=Neue_Einträge_mit_Namen_des_Besitzers_versehen
-# These are status line messages when marking/unmarking entries\:
Memory_stick_mode=Memory_Stick-Modus
Menu_and_label_font_size=Schriftgröße_in_Menüs
@@ -847,7 +788,6 @@ Modify=Bearbeiten
modify_group=Gruppe_bearbeiten
-
Move=Verschieben
Move_down=Nach_unten
@@ -872,14 +812,14 @@ New=Neu
new=neu
-
New_BibTeX_entry=Neuer_BibTeX-Eintrag
-New_BibTeX_subdatabase=Neue_BibTeX-Teildatei
+New_BibTeX_subdatabase=Neue_BibTeX-Teildatenbank
New_content=Neuer_Inhalt
-New_database_created.=Neue_Datei_angelegt.
+New_database_created.=Neue_Datenbank_angelegt.
+New_%0_database=Neue_%0_Datenbank
New_field_value=Neuer_Feldwert
New_file=Neue_Datei
@@ -891,7 +831,6 @@ New_string=Neuer_String
Next_entry=Nächster_Eintrag
-
No_actual_changes_found.=Keine_aktuellen_Änderungen_gefunden.
no_base-BibTeX-file_specified=keine_BibTeX-Datei_angegeben
@@ -900,11 +839,11 @@ no_database_generated=keine_Datenbank_erstellt_und_geschrieben
No_entries_found._Please_make_sure_you_are_using_the_correct_import_filter.=Keine_Einträge_gefunden._Bitte_vergewissern_Sie_sich,_dass_Sie_den_richtigen_Importfilter_benutzen.
+
No_entries_found_for_the_search_string_'%0'=Für_den_Suchausdruck_'%0'_wurden_keine_Einträge_gefunden
No_entries_imported.=Keine_Einträge_importiert.
-
No_exceptions_have_occurred.=Es_sind_keine_Ausnahmen_aufgetreten.
No_files_found.=Keine_Dateien_gefunden.
@@ -913,31 +852,22 @@ No_GUI._Only_process_command_line_options.=Kein_GUI._Nur_Kommandozeilenbefehle_a
No_journal_names_could_be_abbreviated.=Es_konnten_keine_Zeitschriftentitel_abgekürzt_werden.
No_journal_names_could_be_unabbreviated.=Das_Aufheben_der_Abkürzung_konnte_bei_keiner_Zeitschrift_durchgeführt_werden.
-
No_PDF_linked=Kein_PDF_verlinkt
-No_references_found=Keine_Literaturangaben_gefunden
-
-
No_URL_defined=Keine_URL_angegeben
not=nicht
not_found=davon_nicht_gefunden
-
Note_that_you_must_specify_the_fully_qualified_class_name_for_the_look_and_feel,=Es_muss_der_volle_Klassenname_für_das_zu_verwendende_"look_and_feel"_angegeben_werden.
Nothing_to_redo=Wiederholen_nicht_möglich
Nothing_to_undo=Rückgängig_nicht_möglich
-# The next is used like in "References found\: 1 Number of references to fetch?"
-Number_of_references_to_fetch?=Anzahl_der_abzurufenden_Literaturangaben?
-
occurrences=Vorkommen
OK=OK
-
One_or_more_file_links_are_of_the_type_'%0',_which_is_undefined._What_do_you_want_to_do?=Mindestens_ein_Dateilink_ist_vom_Typ_'%0',_der_nicht_definiert_ist._Was_wollen_Sie_tun?
One_or_more_keys_will_be_overwritten._Continue?=Einer_oder_mehrere_Keys_werden_überschrieben._Fortsetzen?
@@ -945,24 +875,23 @@ One_or_more_keys_will_be_overwritten._Continue?=Einer_oder_mehrere_Keys_werden_
Open=Öffnen
-Open_BibTeX_database=BibTeX-Datei_öffnen
+Open_BibTeX_database=BibTeX-Datenbank_öffnen
-Open_database=Datei_öffnen
+Open_database=Datenbank_öffnen
Open_editor_when_a_new_entry_is_created=Eintragseditor_öffnen,_wenn_ein_neuer_Eintrag_angelegt_wird
Open_file=Datei_öffnen
-Open_last_edited_databases_at_startup=Beim_Starten_von_JabRef_die_letzten_bearbeiteten_Dateien_öffnen
-
-Open_shared_database=Öffne entfernte Datenbank
+Open_last_edited_databases_at_startup=Beim_Starten_von_JabRef_die_letzten_bearbeiteten_Datenbanken_öffnen
+Connect_to_shared_database=Geteilte_Datenbank_öffnen
Open_terminal_here=Konsole_hier_öffnen
Open_URL_or_DOI=URL_oder_DOI_öffnen
-Opened_database=Datei_geöffnet
+Opened_database=Datenbank_geöffnet
Opening=Öffne
@@ -977,7 +906,6 @@ Options=Optionen
or=oder
-
Output=Ausgabe
Output_or_export_file=Speichere_oder_exportiere_Datei
@@ -990,6 +918,7 @@ Override_default_font_settings=Standardschrifteinstellungen_überschreiben
Override_the_BibTeX_field_by_the_selected_text=BibTeX-Key_mit_ausgewähltem_Text_überschreiben
+
Overwrite=Überschreiben
Overwrite_existing_field_values=Bestehende_Feldwerte_überschreiben
@@ -1006,6 +935,7 @@ paste_entry=Eintrag_einfügen
Paste_from_clipboard=Aus_der_Zwischenablage_einfügen
Pasted=Eingefügt
+
Path_to_%0_not_defined=Pfad_zu_%0_nicht_definiert
Path_to_LyX_pipe=Pfad_zur_LyX-pipe
@@ -1039,18 +969,22 @@ Preferences=Einstellungen
Preferences_recorded.=Einstellungen_gespeichert.
Preview=Vorschau
+Citation_Style=Zitierstil
+Current_Preview=Aktuelle_Vorschau
+Cannot_generate_preview_based_on_selected_citation_style.=Vorschau_für_gewählten_Zitierstil_kann_nicht_generiert_werden.
+Bad_character_inside_entry=Eintrag_enthält_fehlerhaftes_Zeichen
+Error_while_generating_citation_style=Fehler_beim_Generieren_des_Zitierstils
+Preview_style_changed_to\:_%0=Vorschaustil_geändert_zu:_%0
+Next_preview_layout=Nächster_Vorschaustil
+Previous_preview_layout=Voriger_Vorschaustil
Previous_entry=Vorheriger_Eintrag
Primary_sort_criterion=Primäres_Sortierkriterium
-
Problem_with_parsing_entry=Problem_beim_Analysieren_des_Eintrags
-
Processing_%0=Bearbeite_%0
-
Program_output=Programmausgabe
-
-Pull_changes_from_shared_database=Datenbank-Änderungen_beziehen
+Pull_changes_from_shared_database=Änderungen_der_geteilten_Datenbank_beziehen
Pushed_citations_to_%0=Einträge_in_%0_eingefügt
@@ -1060,19 +994,16 @@ Quit_synchronization=Synchronisation_beenden
Raw_source=Importtext
-
Rearrange_tabs_alphabetically_by_title=Tabs_alphabetisch_nach_Titel_sortieren
Redo=Wiederholen
Reference_database=Referenz-Datenbank
-# The next two lines are used like in "References found\: 1 Number of references to fetch?"
-References_found=Literaturangaben_gefunden
+%0_references_found._Number_of_references_to_fetch?=%0_Literaturangaben_gefunden._Anzahl_der_abzurufenden_Literaturangaben?
Refine_supergroup\:_When_selected,_view_entries_contained_in_both_this_group_and_its_supergroup=Obergruppe_einbeziehen\:_Einträge_aus_dieser_Gruppe_und_ihrer_übergeordneten_Gruppe_anzeigen
-
regular_expression=Regulärer_Ausdruck
Remember_these_entry_types?=Diese_Eintragstypen_behalten?
@@ -1083,13 +1014,10 @@ Remote_server_port=Externer_Server-Port
Remove=Löschen
-
Remove_subgroups=Untergruppen_entfernen
Remove_all_subgroups_of_"%0"?=Alle_Untergruppen_von_"%0"_entfernen?
-
-
Remove_entry_from_import=Eintrag_von_Importierung_entfernen
Remove_entry_selection_from_this_group=Ausgewählte_Einträge_aus_dieser_Gruppe_entfernen
@@ -1097,7 +1025,6 @@ Remove_entry_selection_from_this_group=Ausgewählte_Einträge_aus_dieser_Gruppe_
Remove_entry_type=Eintragstyp_löschen
Remove_file_link_(DELETE)=Dateilink_entfernen_(DELETE)
-
Remove_from_group=Aus_Gruppe_entfernen
Remove_group=Gruppe_löschen
@@ -1120,7 +1047,6 @@ Remove_old_entry=Alten_Eintrag_entfernen
Remove_selected_strings=Ausgewählte_Strings_entfernen
-
Removed_group_"%0".=Gruppe_"%0"_gelöscht.
Removed_group_"%0"_and_its_subgroups.=Gruppe_"%0"_inklusive_Untergruppen_gelöscht.
@@ -1146,7 +1072,6 @@ Resolve_strings_for_standard_BibTeX_fields_only=Strings_nur_für_Standard-BibTeX
resolved=davon_aufgelöst
-
Revert_to_original_source=Original_wiederherstellen
Review=Überprüfung
@@ -1158,12 +1083,12 @@ Right=Rechts
Save=Speichern
Save_all_finished.=Speichern_aller_Dateien_beendet
-Save_all_open_databases=Alle_geöffneten_Dateien_speichern
+Save_all_open_databases=Alle_geöffneten_Datenbanken_speichern
Save_before_closing=Speichern_vor_dem_Beenden
-Save_database=Datei_speichern
-Save_database_as...=Datei_speichern_unter_...
+Save_database=Datenbank_speichern
+Save_database_as...=Datenbank_speichern_unter_...
Save_entries_in_their_original_order=Einträge_in_ursprünglicher_Reihenfolge_abspeichern
@@ -1171,36 +1096,23 @@ Save_failed=Fehler_beim_Speichern
Save_failed_during_backup_creation=Während_der_Erstellung_des_Backups_ist_das_Speichern_fehlgeschlagen
-Save_failed_while_committing_changes\:_%0=Während_die_Änderungen_übermittelt_wurden,_ist_das_Speichern_fehlgeschlagen\:_%0
-
Save_selected_as...=Auswahl_speichern_unter_...
-Saved_database=Datei_gespeichert
+Saved_database=Datenbank_gespeichert
Saved_selected_to_'%0'.=Auswahl_gespeichert_unter_'%0'.
-
Saving=Speichere
-Saving_all_databases...=Alle_Dateien_werden_gespeichert...
-
-Saving_database=Speichere_Datei
+Saving_all_databases...=Alle_Datenbanken_werden_gespeichert...
+Saving_database=Speichere_Datenbank
Search=Suchen
-
-
Search_expression=Suchausdruck
Search_for=Suchen_nach
-
-
-
-
-
-
-
Searching_for_duplicates...=Suche_nach_doppelten_Einträgen...
Searching_for_files=Suche_nach_Dateien
@@ -1211,24 +1123,17 @@ Select=Auswählen
-
Select_all=Alle_auswählen
-
Select_encoding=Kodierung_wählen
-
Select_entry_type=Eintragstyp_auswählen
Select_external_application=Externe_Anwendung_auswählen
Select_file_from_ZIP-archive=Eintrag_aus_der_ZIP-Archiv_auswählen
-
-
-
Select_the_tree_nodes_to_view_and_accept_or_reject_changes=Wählen_Sie_die_Verzweigungen_aus,_um_die_Änderungen_zu_sehen_und_anzunehmen_oder_zu_verwerfen
Selected_entries=Ausgewählte_Einträge
-
Set_field=Setze_Feld
Set_fields=Felder_setzen
@@ -1239,11 +1144,9 @@ Set_table_font=Tabellenschriftart_auswählen
Settings=Einstellungen
-
-
Shortcut=Tastenkürzel
-Show/edit_BibTeX_source=BibTeX-Quelltextpanel_anzeigen
+Show/edit_%0_source=%0-Quelltext_anzeigen/editieren
Show_'Firstname_Lastname'='Vorname_Nachname'_anzeigen
@@ -1251,7 +1154,6 @@ Show_'Lastname,_Firstname'='Nachname,_Vorname'_anzeigen
Show_BibTeX_source_by_default=Quelltextpanel_standardmäßig_anzeigen
-
Show_confirmation_dialog_when_deleting_entries=Dialog_zum_Löschen_von_Einträgen_anzeigen
Show_description=Beschreibung_anzeigen
@@ -1267,17 +1169,12 @@ Show_last_names_only=Zeige_nur_Nachnamen
Show_names_unchanged=Namen_unverändert_anzeigen
-
-
Show_optional_fields=Optionale_Felder_anzeigen
-
Show_required_fields=Benötigte_Felder_anzeigen
Show_URL/DOI_column=URL/DOI-Spalte_anzeigen
-
-
Simple_HTML=Einfaches_HTML
Size=Größe
@@ -1289,8 +1186,6 @@ Skipped_entry.=Eintrag_übersprungen.
Sort_alphabetically=Alphabetisch_sortieren
-
-
sort_subgroups=Untergruppen_sortieren
Sorted_all_subgroups_recursively.=Alle_Untergruppen_rekursiv_sortiert.
@@ -1302,8 +1197,6 @@ Special_name_formatters=Spezielle_Namens-Formatierer
Special_table_columns=Spezielle_Spalten
-
-
Starting_import=Starte_Import
Statically_group_entries_by_manual_assignment=Statisches_Gruppieren_der_Einträge_durch_manuelle_Zuweisung
@@ -1314,17 +1207,14 @@ Stop=Stop
Store_journal_abbreviations=Abkürzungen_der_Zeitschriften_speichern
-
Stored_entry=Eintrag_gespeichert
Strings=Ersetzen
-Strings_for_database=Strings_für_die_Datei
+Strings_for_database=Strings_für_die_Datenbank
Subdatabase_from_AUX=Teildatenbank_aus_AUX-Datei
-
-##\## These lines were changed\:
Switches_between_full_and_abbreviated_journal_name_if_the_journal_name_is_known.=Wechselt_zwischen_vollem_und_abgekürztem_Zeitschriftentitel_falls_bekannt.
Synchronize_file_links=Links_zu_Dateien_synchronisieren
@@ -1367,7 +1257,7 @@ The_label_of_the_string_cannot_contain_the_'\#'_character.=Der_Name_des_Strings_
The_output_option_depends_on_a_valid_import_option.=Die_Ausgabe-Option_beruht_auf_einer_gültigen_Import-Option.
The_PDF_contains_one_or_several_BibTeX-records.=Die_PDF-Datei_enthält_mindestens_einen_BibTeX-Datensatz.
-Do_you_want_to_import_these_as_new_entries_into_the_current_database?=Wollen_Sie_diese(n)_als_neue_Einträge_in_die_aktuelle_Datei_importieren?
+Do_you_want_to_import_these_as_new_entries_into_the_current_database?=Wollen_Sie_diese(n)_als_neue_Einträge_in_die_aktuelle_Datenbank_importieren?
The_regular_expression_<b>%0</b>_is_invalid\:=Der_reguläre_Ausdruck_<b>%0</b>_ist_ungültig\:
@@ -1378,18 +1268,17 @@ The_search_is_case_sensitive.=Groß-/Kleinschreibung_wird_unterschieden.
The_string_has_been_removed_locally=Der_String_wurde_lokal_entfernt
There_are_possible_duplicates_(marked_with_an_icon)_that_haven't_been_resolved._Continue?=Es_gibt_mögliche_Duplikate_(markiert_mit_einem_Icon),_die_nicht_geklärt_werden_konnten._Fortfahren?
+
This_entry_has_no_BibTeX_key._Generate_key_now?=Dieser_Eintrag_hat_keinen_BibTeX-Key._Soll_jetzt_einer_erstellt_werden?
This_entry_is_incomplete=Dieser_Eintrag_ist_unvollständig
This_entry_type_cannot_be_removed.=Dieser_Eintragstyp_kann_nicht_entfernt_werden.
+
This_external_link_is_of_the_type_'%0',_which_is_undefined._What_do_you_want_to_do?=Dies_ist_ein_externer_Link_des_Typs_'%0',_der_nicht_definiert_ist._Was_wollen_Sie_tun?
This_group_contains_entries_based_on_manual_assignment._Entries_can_be_assigned_to_this_group_by_selecting_them_then_using_either_drag_and_drop_or_the_context_menu._Entries_can_be_removed_from_this_group_by_selecting_them_then_using_the_context_menu.=Diese_Gruppe_enthält_manuell_zugewiesene_Einträge._Einträge_können_dieser_Gruppe_zugewiesen_werden,_indem_Sie_sie_selektieren_und_dann_entweder_Drag&Drop_oder_das_Kontextmenü_benutzen._Einträge_können_aus_dieser_Gruppe_entfernt_werden,_indem [...]
-
-
-
This_group_contains_entries_whose_<b>%0</b>_field_contains_the_keyword_<b>%1</b>=Diese_Gruppe_enthält_Eintrage,_deren_Feld_<b>%0</b>_das_Stichwort_<b>%1</b>_enthält
This_group_contains_entries_whose_<b>%0</b>_field_contains_the_regular_expression_<b>%1</b>=Diese_Gruppe_enthält_Eintrage,_deren_Feld_<b>%0</b>_den_regulären_Ausdruck_<b>%1</b>_enthält
@@ -1399,17 +1288,13 @@ This_operation_requires_all_selected_entries_to_have_BibTeX_keys_defined.=Für_d
This_operation_requires_one_or_more_entries_to_be_selected.=Für_diesen_Vorgang_muss_mindestens_ein_Eintrag_ausgewählt_sein.
-
Toggle_abbreviation=Abkürzung_an-/abschalten
Toggle_entry_preview=Eintragsvorschau_ein-/ausblenden
Toggle_groups_interface=Gruppenansicht_ein-/ausblenden
-
Try_different_encoding=Versuchen_Sie_es_mit_einer_anderen_Kodierung
Unabbreviate_journal_names_of_the_selected_entries=Abkürzung_der_Zeitschriftentitel_der_ausgewählten_Einträge_aufheben
Unabbreviated_%0_journal_names.=Bei_%0_Zeitschriftentiteln_wurde_die_Abkürzung_aufgehoben.
-Unabbreviate_journal_names=Abkürzung_der_Zeitschriftentitel_aufheben
-
Unable_to_open_file.=Datei_kann_nicht_geöffnet_werden.
Unable_to_open_link._The_application_'%0'_associated_with_the_file_type_'%1'_could_not_be_called.=Öffnen_des_Links_nicht_möglich._Die_Anwendung_'%0',_die_dem_Dateityp_'%1'_zugeordnet_ist,_konnte_nicht_aufgerufen_werden.
@@ -1424,7 +1309,6 @@ Unknown_BibTeX_entries=Unbekannte_BibTeX_Einträge
unknown_edit=unbekannter_Bearbeitungsschritt
-
Unknown_export_format=Unbekanntes_Export-Format
Unmark_all=Sämtliche_Markierungen_aufheben
@@ -1433,10 +1317,6 @@ Unmark_entries=Markierung_aufheben
Unmark_entry=Markierung_aufheben
-
-
-Unsupported_version_of_class_%0\:_%1=Nicht_unterstützte_Version_der_Klasse_%0\:_%1
-
untitled=ohne_Titel
Up=Hoch
@@ -1451,7 +1331,6 @@ Upgrade_old_external_file_links_to_use_the_new_feature=Alte_Links_zu_externen_Da
usage=Benutzung
Use_autocompletion_for_the_following_fields=Autovervollständigung_für_folgende_Felder_benutzen
-
Use_other_look_and_feel=anderes_"look_and_feel"_benutzen
Use_regular_expression_search=Suche_mit_regulärem_Ausdruck_benutzen
@@ -1486,10 +1365,10 @@ Will_write_XMP-metadata_to_the_PDFs_linked_from_selected_entries.=Schreibe_XMP-M
with=mit
Write_BibTeXEntry_as_XMP-metadata_to_PDF.=BibTeX-Eintrag_als_XMP-Metadaten_ins_PDF_schreiben.
+
Write_XMP=XMP_schreiben
Write_XMP-metadata=Schreibe_XMP-Metadaten
-Write_XMP-metadata_for_all_PDFs_in_current_database?=XMP-Metadaten_für_alle_PDFs_der_aktuellen_Datei_schreiben?
-
+Write_XMP-metadata_for_all_PDFs_in_current_database?=XMP-Metadaten_für_alle_PDFs_der_aktuellen_Datenbank_schreiben?
Writing_XMP-metadata...=XMP-Metadaten_werden_geschrieben...
Writing_XMP-metadata_for_selected_entries...=XMP-Metadaten_für_ausgewählte_Einträge_werden_geschrieben...
@@ -1497,14 +1376,12 @@ Wrote_XMP-metadata=XMP-Metadaten_geschrieben
XMP-annotated_PDF=PDF_mit_XMP-Anmerkungen
XMP_export_privacy_settings=Sicherheitseinstellungen_für_den_XMP-Export
-
XMP-metadata=XMP-Metadaten
XMP-metadata_found_in_PDF\:_%0=XMP-Metadaten_gefunden_im_PDF\:_%0
-
You_must_restart_JabRef_for_this_to_come_into_effect.=Sie_müssen_JabRef_neu_starten,_damit_diese_Änderungen_in_Kraft_treten.
You_have_changed_the_language_setting.=Sie_haben_die_Spracheinstellung_geändert.
-You_have_changed_the_look_and_feel_setting.=Sie_haben_die_Einstellungen_des_Erscheinungsbildes_('look_and_feel')_geändert.
+You_have_changed_the_look_and_feel_setting.=Sie_haben_die_Einstellungen_des_Erscheinungsbildes_('look_and_feel')_geändert.
You_have_entered_an_invalid_search_'%0'.=Sie_haben_eine_ungültige_Suche_'%0'_eingegeben.
@@ -1512,7 +1389,6 @@ You_must_choose_a_filename_to_store_journal_abbreviations=Sie_müssen_einen_Date
You_must_restart_JabRef_for_the_new_key_bindings_to_work_properly.=Sie_müssen_JabRef_neu_starten,_damit_die_Tastenkürzel_funktionieren.
-
Your_new_key_bindings_have_been_stored.=Ihre_neuen_Tastenkürzel_wurden_gespeichert.
The_following_fetchers_are_available\:=Folgende_Recherchetools_stehen_zur_Verfügung\:
@@ -1529,32 +1405,26 @@ Import_canceled_by_user=Import_durch_Benutzer_abgebrochen
Progress\:_%0_of_%1=Fortschritt\:_%0_von_%1
Error_while_fetching_from_%0=Fehler_beim_Abrufen_von_%0
-Fetching_Medline_by_id...=Rufe_Medline_mittels_ID_ab...
-
-Fetching_Medline_by_term...=Rufe_Medline_mittels_Suchbegriff_ab...
-%0_import_canceled=%0-Import_abgebrochen
Please_enter_a_valid_number=Bitte_geben_Sie_eine_gültige_Zahl_ein
-Please_enter_a_comma_separated_list_of_Medline_IDs_(numbers)_or_search_terms.=Bitte_geben_Sie_eine_durch_Kommas_unterteilte_Liste_von_Medline-IDs_(Zahlen)_oder_Suchausdrücken_ein.
-
Show_search_results_in_a_window=Suchergebnisse_in_einem_Fenster_anzeigen
+Show_global_search_results_in_a_window=Globale_Suchergebnisse_in_einem_Fenster_anzeigen
+Search_in_all_open_databases=Suche_in_allen_offenen_Datenbanken
Move_file_to_file_directory?=Datei_in_Dateiverzeichnis_verschieben?
Rename_to_'%0'=Umbenennen_in_'%0'
-
You_have_changed_the_menu_and_label_font_size.=Sie_haben_die_Schriftgröße_für_Menüs_und_Label_geändert.
-Database_is_protected._Cannot_save_until_external_changes_have_been_reviewed.=Die_Datei_ist_geschützt._Speichern_nicht_möglich,_bis_externe_Änderungen_geprüft_wurden.
-Protected_database=Geschützte_Datei
-Refuse_to_save_the_database_before_external_changes_have_been_reviewed.=Die_Datei_kann_nicht_gespeichert_werden,_bis_externe_Änderungen_geprüft_wurden.
+Database_is_protected._Cannot_save_until_external_changes_have_been_reviewed.=Die_Datenbank_ist_geschützt._Speichern_nicht_möglich,_bis_externe_Änderungen_geprüft_wurden.
+Protected_database=Geschützte_Datenbank
+Refuse_to_save_the_database_before_external_changes_have_been_reviewed.=Die_Datenbank_kann_nicht_gespeichert_werden,_bis_externe_Änderungen_geprüft_wurden.
+Database_protection=Datenbankschutz
+Unable_to_save_database=Speichern_der_Datenbank_nicht_möglich
-Database_protection=Dateischutz
-Unable_to_save_database=Speichern_der_Datei_nicht_möglich
BibTeX_key_generator=BibTeX-Key-Generator
Unable_to_open_link.=Öffnen_des_Links_nicht_möglich
Move_the_keyboard_focus_to_the_entry_table=Tastatur-Fokus_auf_die_Tabelle_setzen
MIME_type=MIME-Typ
This_feature_lets_new_files_be_opened_or_imported_into_an_already_running_instance_of_JabRef<BR>instead_of_opening_a_new_instance._For_instance,_this_is_useful_when_you_open_a_file_in_JabRef<br>from_your_web_browser.<BR>Note_that_this_will_prevent_you_from_running_more_than_one_instance_of_JabRef_at_a_time.=Diese_Funktion_öffnet_neue_oder_importierte_Dateien_in_einer_bereits_laufenden_Instanz_von_JabRef<BR>und_nicht_in_einem_neuen_Fenster._Das_ist_beispielsweise_nützlich,<BR>wenn_Sie_Jab [...]
-
Run_fetcher,_e.g._"--fetch\=Medline\:cancer"=Recherche_starten,_z.B._"--fetch=Medline\:cancer"
The_ACM_Digital_Library=ACM_Digital_Library
@@ -1562,11 +1432,11 @@ Reset=Zurücksetzen
Use_IEEE_LaTeX_abbreviations=Benutze_IEEE-LaTeX-Abkürzungen
The_Guide_to_Computing_Literature=The_Guide_to_Computing_Literature
+
When_opening_file_link,_search_for_matching_file_if_no_link_is_defined=Beim_Öffnen_des_Dateilinks_die_passende_Datei_suchen,_falls_keine_verlinkt_ist
Settings_for_%0=Einstellungen_für_%0
-
-Mark_entries_imported_into_an_existing_database=Einträge,_die_in_eine_Tabelle_importiert_werden,_markieren
-Unmark_all_entries_before_importing_new_entries_into_an_existing_database=Markierung_aller_Einträge_aufheben,_bevor_neue_Einträge_importiert_werden
+Mark_entries_imported_into_an_existing_database=Markiere_Einträge,_die_in_eine_bestehende_Datenbank_importiert_werden
+Unmark_all_entries_before_importing_new_entries_into_an_existing_database=Markierung_aller_Einträge_aufheben,_bevor_neue_Einträge_in_eine_bestehende_Datenbank_importiert_werden
Forward=Vor
Back=Zurück
@@ -1574,31 +1444,30 @@ Sort_the_following_fields_as_numeric_fields=Sortiere_folgende_Felder_als_numeris
Line_%0\:_Found_corrupted_BibTeX_key.=Zeile_%0\:_Beschädigter_BibTeX-Key_gefunden.
Line_%0\:_Found_corrupted_BibTeX_key_(contains_whitespaces).=Zeile_%0\:_Beschädigter_BibTeX-Key_gefunden_(enthält_Leerzeichen).
Line_%0\:_Found_corrupted_BibTeX_key_(comma_missing).=Zeile_%0\:_Beschädigter_BibTeX-Key_gefunden_(Komma_fehlt).
-Finished_downloading_full_text_document=Herunterladen_des_Volltext-Dokuments_abgeschlossen
Full_text_document_download_failed=Herunterladen_des_Volltext-Beitrags_fehlgeschlagen
Update_to_current_column_order=Aktuelle_Spaltenanordnung_verwenden
-
+Download_from_URL=Download_von_URL
Rename_field=Feld_umbenennen
Set/clear/rename_fields=Felder_setzen/löschen/umbenennen
Rename_field_to=Feld_umbenennen
Move_contents_of_a_field_into_a_field_with_a_different_name=Inhalt_eines_Felds_in_ein_Feld_mit_anderem_Namen_verschieben
-
You_can_only_rename_one_field_at_a_time=Sie_können_nur_eine_Datei_auf_einmal_umbenennen
+
Remove_all_broken_links=Alle_ungültigen_Links_löschen
+
Cannot_use_port_%0_for_remote_operation;_another_application_may_be_using_it._Try_specifying_another_port.=Port_%0_konnte_nicht_für_externen_Zugriff_genutzt_werden;_er_wird_möglicherweise_von_einer_anderen_Anwendung_benutzt._Versuchen_Sie_einen_anderen_Port.
Looking_for_full_text_document...=Suche_Volltext-Dokument...
-Autosave=Automatische_Sicherung
-Prompt_before_recovering_a_database_from_an_autosave_file=Bestätigen,_wenn_eine_Datei_aus_einer_automatischen_Sicherung_wiederhergestellt_werden_soll
-Autosave_interval_(minutes)=Intervall_für_automatische_Sicherung_(Minuten)
-Do_you_want_to_recover_the_database_from_the_autosave_file?=Wollen_Sie_die_Datei_aus_der_automatischen_Sicherung_wiederherstellen?
-Recover_from_autosave=Wiederherstellen_aus_automatischer_Sicherung
+Autosave=Automatische_Speicherung
+A_local_copy_will_be_opened.=Eine_lokale_Kopie_wird_geöffnet.
+Autosave_local_databases=Automatische_Abspeicherung_für_lokale_Datenbanken
+Automatically_save_the_database_to=Speichere_die_Datenbank_automatisch_nach
+Please_enter_a_valid_file_path.=Bitte_geben_Sie_einen_korrekten_Dateipfad_ein.
+
+
Export_in_current_table_sort_order=Exportieren_sortiert_nach_der_aktuellen_Tabelle
Export_entries_in_their_original_order=Einträge_in_ursprünglicher_Reihenfolge_exportieren
-
Error_opening_file_'%0'.=Fehler_beim_Öffnen_der_Datei_'%0'.
-Autosave_of_file_'%0'=Automatische_Sicherung_der_Datei_'%0'
-Error_opening_autosave_of_'%0'._Trying_to_load_'%0'_instead.=Fehler_beim_Öffnen_der_automatischen_Sicherung_von_'%0'._Stattdessen_wird_versucht,_'%0'_zu_öffnen.
Formatter_not_found\:_%0=Formatierer_nicht_gefunden\:_%0
Clear_inputarea=Eingabefeld_löschen
@@ -1629,28 +1498,26 @@ includes_subgroups=berücksichtigt_Untergruppen
contains=enthält
search_expression=Suchausdruck
-
-
-%0_mode=%0-Modus
Optional_fields_2=Optionale_Felder_2
Waiting_for_save_operation_to_finish=Das_Ende_des_Speichervorgangs_wird_abgewartet
Resolving_duplicate_BibTeX_keys...=Beseitige_doppelte_BibTeX-Keys...
Finished_resolving_duplicate_BibTeX_keys._%0_entries_modified.=Beseitigen_doppelter_BibTeX-Keys_abgeschlossen._%0_Einträge_geändert.
-This_database_contains_one_or_more_duplicated_BibTeX_keys.=Diese_Datei_enthält_einen_oder_mehrere_doppelte_BibTeX-Keys.
+This_database_contains_one_or_more_duplicated_BibTeX_keys.=Diese_Datenbank_enthält_einen_oder_mehrere_doppelte_BibTeX-Keys.
Do_you_want_to_resolve_duplicate_keys_now?=Wollen_Sie_die_doppelten_Einträge_jetzt_beseitigen?
Find_and_remove_duplicate_BibTeX_keys=Finde_und_entferne_doppelte_BibTeX-Keys
Expected_syntax_for_--fetch\='<name_of_fetcher>\:<query>'=Erwartete_Syntax_für_--fetch='<Name_des_Fetchers>\:<Anfrage>'
Duplicate_BibTeX_key=Doppelter_BibTeX-Key
-
Import_marking_color=Farbe_zum_Markieren_von_importierten_Einträgen
Always_add_letter_(a,_b,_...)_to_generated_keys=Immer_einen_Buchstaben_(a,_b,_...)_zum_BibTeX-Key_hinzufügen
+
Ensure_unique_keys_using_letters_(a,_b,_...)=Eindeutige_Keys_mit_Buchstaben_(a,_b,_...)_sicherstellen
Ensure_unique_keys_using_letters_(b,_c,_...)=Eindeutige_Keys_mit_Buchstaben_(b,_c,_...)_sicherstellen
Entry_editor_active_background_color=Aktive_Hintergrundfarbe_des_Eintragseditors
Entry_editor_background_color=Hintergrundfarbe_des_Eintragseditors
Entry_editor_font_color=Schriftfarbe_des_Eintragseditors
Entry_editor_invalid_field_color=Farbe_für_ungülte_Felder_im_Eintragseditor
+
Table_and_entry_editor_colors=Tabellen-_und_Eintragseditor-Farben
General_file_directory=Standard-Dateiverzeichnis
@@ -1667,7 +1534,6 @@ Create_entry_based_on_XMP_data=Eintrag_aus_XMP-Daten_erstellen
Create_blank_entry_linking_the_PDF=Leeren_Eintrag_erstellen_mit_Link_zum_PDF
Only_attach_PDF=Nur_PDF_anhängen
Title=Titel
-No_internet_connection.=Keine_Internetverbindung.
Create_new_entry=Neuen_Eintrag_erstellen
Update_existing_entry=Bestehenden_Eintrag_aktualisieren
Autocomplete_names_in_'Firstname_Lastname'_format_only=Automatische_Vervollständigung_von_Namen_nur_im_Format_'Vorname_Nachname'
@@ -1717,7 +1583,7 @@ Connected_to_document=Verbindung_zum_Dokument_hergestellt
Insert_a_citation_without_text_(the_entry_will_appear_in_the_reference_list)=Literaturverweis_ohne_Text_einfügen_(der_Eintrag_wird_in_der_Literaturliste_erscheinen)
Cite_selected_entries_with_extra_information=Ausgewählte_Einträge_mit_Zusatzinformation_zitieren
Ensure_that_the_bibliography_is_up-to-date=Sicherstellen,_dass_die_Bibliographie_aktuell_ist
-Your_OpenOffice/LibreOffice_document_references_the_BibTeX_key_'%0',_which_could_not_be_found_in_your_current_database.=Ihr_OpenOffice/LibreOffice-Dokument_verweist_auf_den_BibTeX-Key_'0%',_der_in_der_aktuellen_Datei_nicht_gefunden_wurde.
+Your_OpenOffice/LibreOffice_document_references_the_BibTeX_key_'%0',_which_could_not_be_found_in_your_current_database.=Ihr_OpenOffice/LibreOffice-Dokument_verweist_auf_den_BibTeX-Key_'0%',_der_in_der_aktuellen_Datenbank_nicht_gefunden_wurde.
Unable_to_synchronize_bibliography=Synchronisieren_der_Bibliographie_fehlgeschlagen
Combine_pairs_of_citations_that_are_separated_by_spaces_only=Verbinde_Paare_von_Literaturverweisen,_die_nur_durch_Leerzeichen_voneinander_getrennt_sind
Autodetection_failed=Automatische_Erkennung_fehlgeschlagen
@@ -1732,7 +1598,7 @@ The_paragraph_format_is_controlled_by_the_property_'ReferenceParagraphFormat'_or
The_character_format_is_controlled_by_the_citation_property_'CitationCharacterFormat'_in_the_style_file.=Das_Zeichenformat_wird_von_der_Eigenschaft_'CitationCharacterFormat'_in_der_Stildatei_bestimmt.
Automatically_sync_bibliography_when_inserting_citations=Bibliographie_beim_Einfügen_von_Literaturverweisen_automatisch_synchronisieren
Look_up_BibTeX_entries_in_the_active_tab_only=BibTeX-Einträge_nur_im_aktiven_Tab_suchen
-Look_up_BibTeX_entries_in_all_open_databases=BibTeX-Einträge_in_allen_geöffneten_Dateien_suchen
+Look_up_BibTeX_entries_in_all_open_databases=BibTeX-Einträge_in_allen_geöffneten_Datenbanken_suchen
Autodetecting_paths...=Automatische_Erkennung_der_Pfade...
Could_not_find_OpenOffice/LibreOffice_installation=Die_OpenOffice/LibreOffice-Installation_konnte_nicht_gefunden_werden
Directories=Ordner
@@ -1743,14 +1609,11 @@ Select_document=Datei_wählen
Edit_group_membership=Gruppenzugehörigkeit_bearbeiten
HTML_list=HTML-Liste
Click_group_to_toggle_membership_of_selected_entries=Gruppe_anklicken,_um_die_Zugehörigkeit_der_ausgewählten_Einträge_zu_ändern
-Use_EMACS_23_insertion_string=EMACS_23_Einfügungs-Ausdruck_benutzen
If_possible,_normalize_this_list_of_names_to_conform_to_standard_BibTeX_name_formatting=Diese_Namensliste_soll_nach_Möglichkeit_so_normalisiert_werden,_dass_sie_sich_nach_der_üblichen_BibTeX-Namensformatierung_richtet
Could_not_open_%0=%0_konnte_nicht_geöffnet_werden
Unknown_import_format=Unbekanntes_Import-Format
Web_search=Internetrecherche
-
Style_selection=Stil-Auswahl
-
No_valid_style_file_defined=Keine_gültige_Stildatei_angegeben
Choose_pattern=Muster_wählen
Use_the_BIB_file_location_as_primary_file_directory=Pfad_der_BIB-Datei_als_primäres_Dateiverzeichnis_verwenden
@@ -1762,13 +1625,14 @@ JabRef_includes_a_built-in_list_of_journal_abbreviations.=JabRef_verfügt_über_
You_must_select_either_a_valid_style_file,_or_use_one_of_the_default_styles.=Sie_müssen_entweder_eine_gültige_Stildatei_auswählen_oder_einen_der_Standard-Stile_benutzen.
This_is_a_simple_copy_and_paste_dialog._First_load_or_paste_some_text_into_the_text_input_area.<br>After_that,_you_can_mark_text_and_assign_it_to_a_BibTeX_field.=Dieser_Dialog_ermöglicht_das_schnelle_Einfügen_von_Einträgen_aus_normalen_Text._Die_gewünschten_Textstellen<br>werden_markiert_und_z.B._durch_Doppelklick_einem_selektierten_BibTeX_Eintrag_zugeordnet.
+This_feature_generates_a_new_database_based_on_which_entries_are_needed_in_an_existing_LaTeX_document.=Diese_Funktion_erstellt_eine_neue_Datenbank_basierend_auf_den_Einträgen,_die_von_einem_bestehenden_LaTeX-Dokument_benötigt_werden.
+You_need_to_select_one_of_your_open_databases_from_which_to_choose_entries,_as_well_as_the_AUX_file_produced_by_LaTeX_when_compiling_your_document.=Sie_müssen_eine_Ihrer_geöffneten_Datenbanken,_von_denen_Einträge_genommen_werden_sollen,_sowie_die_AUX-Datei,_die_von_LaTeX_beim_Kompilieren_Ihres_Dokuments_erstellt_wird,_auswählen.
-This_feature_generates_a_new_database_based_on_which_entries_are_needed_in_an_existing_LaTeX_document.=Diese_Funktion_erstellt_eine_neue_Datei_basierend_auf_den_Einträgen,_die_von_einem_bestehenden_LaTeX-Dokument_benötigt_werden.
-You_need_to_select_one_of_your_open_databases_from_which_to_choose_entries,_as_well_as_the_AUX_file_produced_by_LaTeX_when_compiling_your_document.=Sie_müssen_eine_Ihrer_geöffneten_Dateien,_von_denen_Einträge_genommen_werden_sollen,_sowie_die_AUX-Datei,_die_von_LaTeX_beim_Kompilieren_Ihres_Dokuments_erstellt_wird,_auswählen.
First_select_entries_to_clean_up.=Wählen_Sie_zuerst_die_Einträge_aus,_für_die_ein_Cleanup_durchgeführt_werden_soll.
Cleanup_entry=Eintrag_aufräumen
Autogenerate_PDF_Names=Automatische_PDF_Umbenennung
Auto-generating_PDF-Names_does_not_support_undo._Continue?=Automatische_PDF_Umbenennung_kann_nicht_rückgängig_gemacht_werden._Fortfahren?
+
Use_full_firstname_whenever_possible=Den_ganzen_Vornamen_nutzen,_wenn_möglich
Use_abbreviated_firstname_whenever_possible=Den_abgekürzten_Vornamen_benutzen,_wenn_möglich
Use_abbreviated_and_full_firstname=Abgekürzte_und_ganze_Vornamen_verwenden
@@ -1778,6 +1642,7 @@ Name_format_used_for_autocompletion=Namensformat_für_die_Autovervollständigung
Treatment_of_first_names=Behandlung_von_Vornamen
Cleanup_entries=Einträge_aufräumen
Automatically_assign_new_entry_to_selected_groups=Neuen_Eintrag_automatisch_den_ausgewählten_Gruppen_zuordnen
+%0_mode=%0-Modus
Move_DOIs_from_note_and_URL_field_to_DOI_field_and_remove_http_prefix=DOIs_von_den_Feldern_note_und_URL_ins_DOI-Feld_verschieben_und_das_http-Präfix_löschen
Make_paths_of_linked_files_relative_(if_possible)=Pfade_verlinkter_Dateien_zu_relativen_Pfaden_ändern_(falls_möglich)
Rename_PDFs_to_given_filename_format_pattern=PDFs_entsprechend_dem_vorgegebenen_Namensformat_umbenennen
@@ -1792,9 +1657,9 @@ Error_downloading_file_'%0'=Fehler_beim_Herunterladen_der_Datei_'%0'
Download_failed=Download_fehlgeschlagen
Remove_selected=Ausgewählte_löschen
-Group_tree_could_not_be_parsed._If_you_save_the_BibTeX_database,_all_groups_will_be_lost.=Der_Gruppenbaum_konnte_nicht_geparsed_werden._Wenn_Sie_die_BibTeX-Datei_speichern,_gehen_alle_Gruppen_verloren.
-Attach_file=Datei_anhängen
+Group_tree_could_not_be_parsed._If_you_save_the_BibTeX_database,_all_groups_will_be_lost.=Der_Gruppenbaum_konnte_nicht_geparsed_werden._Wenn_Sie_die_BibTeX-Datenbank_speichern,_gehen_alle_Gruppen_verloren.
+Attach_file=Datei_anhängen
Setting_all_preferences_to_default_values.=Setze_alle_Einstellungen_auf_die_Standardwerte.
Resetting_preference_key_'%0'=Setze_Einstellung_'0%'_zurück
Unknown_preference_key_'%0'=Unbekannte_Einstellung_'0%'
@@ -1817,7 +1682,7 @@ Select_file_type\:=Dateityp_wählen\:
These_files_are_not_linked_in_the_active_database.=Diese_Dateien_sind_in_der_aktiven_Datenbank_nicht_verlinkt.
Entry_type_to_be_created\:=Eintragstyp,_der_erstellt_werden_soll\:
Searching_file_system...=Dateisystem_wird_durchsucht...
-Importing_into_Database...=Importieren_in_die_Datei...
+Importing_into_Database...=In_die_Datenbank_importieren...
Select_directory=Verzeichnis_wählen
Select_files=Dateien_wählen
BibTeX_entry_creation=Erstellung_eines_BibTeX-Eintrags
@@ -1828,7 +1693,6 @@ The_current_BibTeX_key_will_be_overwritten._Continue?=Der_aktuelle_BibTeX-Key_wi
Overwrite_key=Key_überschreiben
Not_overwriting_existing_key._To_change_this_setting,_open_Options_->_Prefererences_->_BibTeX_key_generator=Der_existierende_Key_wird_nicht_überschrieben._Um_diese_Einstellung_zu_ändern,_öffnen_Sie_Optionen_->_Einstellungen_->_BibTeX-Key-Generator
How_would_you_like_to_link_to_'%0'?=Wie_möchten_Sie_zu_'%0'_verlinken?
-
BibTeX_key_patterns=BibTeX-Key-Muster
Changed_special_field_settings=Einstellungen_für_spezielle_Felder_geändert
Clear_priority=Priorität_aufheben
@@ -1838,7 +1702,6 @@ Five_stars=Fünf_Sterne
Four_stars=Vier_Sterne
Help_on_special_fields=Hilfe_zu_speziellen_Feldern
Keywords_of_selected_entries=Stichworte_der_ausgewählten_Einträge
-Manage_content_selectors=Inhaltsauswahl_verwalten
Manage_keywords=Stichworte_verwalten
No_priority_information=Keine_Informationen_zur_Priorität
No_rank_information=Keine_Informationen_zum_Rang
@@ -1866,10 +1729,10 @@ Two_stars=Zwei_Sterne
Update_keywords=Stichworte_aktualisieren
Write_values_of_special_fields_as_separate_fields_to_BibTeX=Werte_spezieller_Felder_separat_in_die_BibTeX-Datei_schreiben
You_have_changed_settings_for_special_fields.=Sie_haben_die_Einstellungen_für_spezielle_Felder_geändert.
-
%0_entries_found._To_reduce_server_load,_only_%1_will_be_downloaded.=%0_Einträge_gefunden._Um_die_Serverlast_zu_reduzieren,_werden_nur_%1_heruntergeladen.
A_string_with_that_label_already_exists=Ein_String_mit_diesem_Label_ist_bereits_vorhanden
Connection_to_OpenOffice/LibreOffice_has_been_lost._Please_make_sure_OpenOffice/LibreOffice_is_running,_and_try_to_reconnect.=Verbindung_zu_OpenOffice/LibreOffice_verloren._Bitte_stellen_Sie_sicher,_dass_OpenOffice/LibreOffice_läuft,_und_versuchen_Sie,_erneut_zu_verbinden.
+
Correct_the_entry,_and_reopen_editor_to_display/edit_source.=Eintrag_korrigieren_und_Editor_erneut_öffnen,_um_den_Quelltext_anzuzeigen/zu_bearbeiten.
Could_not_connect_to_a_running_gnuserv_process._Make_sure_that_Emacs_or_XEmacs_is_running,<BR>and_that_the_server_has_been_started_(by_running_the_command_'server-start'/'gnuserv-start').=Keine_Verbindung_zu_einem_laufenden_gnuserv-Prozess_möglich._Vergewissern_Sie_sich,_dass_Emacs_oder_XEmacs_läuft<BR>und_dass_der_Server_gestartet_wurde_(mit_dem_Befehl_'server-start'/'gnuserv-start').
Could_not_connect_to_running_OpenOffice/LibreOffice.=Verbindung_zu_OpenOffice/LibreOffice_fehlgeschlagen.
@@ -1891,19 +1754,14 @@ Your_style_file_specifies_the_paragraph_format_'%0',_which_is_undefined_in_your_
Searching...=Suche_läuft...
You_have_selected_more_than_%0_entries_for_download._Some_web_sites_might_block_you_if_you_make_too_many_rapid_downloads._Do_you_want_to_continue?=Sie_haben_mehr_als_%0_Einträge_zum_Download_ausgewählt._Einige_Webseiten_könnten_zu_viele_Downloads_blockieren._Möchten_Sie_fortfahren?
Confirm_selection=Auswahl_bestätigen
-Unknown_DOI\:_'%0'.=Unbekannte_DOI\:_'0%'.
Add_{}_to_specified_title_words_on_search_to_keep_the_correct_case=Nach_der_Suche_{}_zu_festgesetzten_Titelworten_hinzufügen,_um_Groß-/Kleinschreibung_beizubehalten
Import_conversions=Konvertierungen_importieren
Please_enter_a_search_string=Bitte_geben_Sie_eine_Suchphrase_ein
-Please_open_or_start_a_new_database_before_searching=Bitte_öffnen_Sie_eine_Datei_oder_legen_Sie_eine_neue_an,_bevor_Sie_suchen
-An_error_occurred_while_fetching_from_ADS_(%0)\:=Beim_Abrufen_von_ADS_ist_ein_Fehler_aufgetreten_(%0)\:
-An_error_occurred_while_parsing_abstract=Beim_Parsen_der_Zusammenfassung_ist_ein_Fehler_aufgetreten
-Unknown_DiVA_entry\:_'%0'.=Unbekannter_DiVA-Eintrag\:_'0%'.
-Get_BibTeX_entry_from_DiVA=BibTeX-Eintrag_aus_DiVA_erstellen
+Please_open_or_start_a_new_database_before_searching=Bitte_öffnen_Sie_eine_Datenbank_oder_legen_Sie_eine_neue_an,_bevor_Sie_suchen
Log=Protokoll
-
Canceled_merging_entries=Zusammenführen_der_Einträge_abgebrochen
+
Format_units_by_adding_non-breaking_separators_and_keeping_the_correct_case_on_search=Einheiten_formatieren\:_nicht-umbrechende_Trennzeichen_hinzufügen_und_bei_der_Suche_Groß-/Kleinschreibung_beibehalten
Merge_entries=Einträge_zusammenführen
Merged_entries=Die_Einträge_wurden_zusammengeführt
@@ -1917,29 +1775,35 @@ Use_Emacs_key_bindings=Emacs-Tastaturkürzel_benutzen
You_have_to_choose_exactly_two_entries_to_merge.=Sie_müssen_genau_zwei_Einträge_auswählen,_die_zusammengeführt_werden_sollen.
Update_timestamp_on_modification=Zeitstempel_bei_Änderung_aktualisieren
-
All_key_bindings_will_be_reset_to_their_defaults.=Alle_Tastaturkürzel_werden_auf_den_Standard_zurückgesetzt.
+
Automatically_set_file_links=Dateilinks_automatisch_setzen
Continue?=Fortfahren?
Resetting_all_key_bindings=Alle_Tastaturkürzel_werden_zurückgesetzt
-
Hostname=Host
Invalid_setting=Ungültige_Einstellung
Network=Netzwerk
Please_specify_both_hostname_and_port=Bitte_geben_Sie_den_Namen_des_Hosts_und_den_Port_an
+Please_specify_both_username_and_password=Bitte_geben_Sie_Benutzernamen_und_Passwort_an
+
Use_custom_proxy_configuration=Benutzerdefinierte_Proxy-Konfiguration_verwenden
+Proxy_requires_authentication=Proxy_erfordert_Authentifizierung
+Attention\:_Password_is_stored_in_plain_text\!=Achtung\:_Das_Passwort_wird_im_Klartext_gespeichert\!
Clear_connection_settings=Verbindungseinstellungen_zurücksetzen
Cleared_connection_settings.=Verbindungseinstellungen_wurden_zurückgesetzt.
+
Rebind_C-a,_too=C-a_ebenfalls_neu_zuweisen
+Rebind_C-f,_too=C-f_ebenfalls_neu_zuweisen
Show_number_of_elements_contained_in_each_group=Anzahl_der_Elemente_jeder_Gruppe_anzeigen
Open_folder=Ordner_öffnen
Searches_for_unlinked_PDF_files_on_the_file_system=Sucht_nach_nicht_verlinkten_PDF-Dateien_im_Dateisystem
-
Export_entries_ordered_as_specified=Einträge_in_der_angegebenen_Reihenfolge_exportieren
Export_sort_order=Sortierreihenfolge_exportieren
+Export_sorting=Exportiere_Sortierung
Newline_separator=Zeichen_für_Zeilenumbruch
+
Save_entries_ordered_as_specified=Einträge_in_angegebener_Reihenfolge_speichern
Save_sort_order=Sortierreihenfolge_speichern
Show_extra_columns=Extraspalten_anzeigen
@@ -1950,7 +1814,6 @@ Move_to_group=Verschieben_in_Gruppe
Clear_read_status=Lesestatus_leeren
Convert_to_BibLatex_format_(for_example,_move_the_value_of_the_'journal'_field_to_'journaltitle')=Ins_biblatex-Format_konvertieren_(verschiebe_beispielsweise_den_Wert_des_Felds_'journal'_in_das_Feld_'journaltitle')
-Could_not_apply_changes.=Die_Änderungen_konnten_nicht_übernommen_werden.
Deprecated_fields=Abgelehnte_Felder
Hide/show_toolbar=Toolbar_zeigen/verbergen
No_read_status_information=Keine_Informationen_zum_Lesestatus
@@ -1962,126 +1825,109 @@ Save_selected_as_plain_BibTeX...=Ausgewählte_Einträge_als_reines_BibTeX_speich
Set_read_status_to_read=Lesestatus_auf_'gelesen'_gesetzt
Set_read_status_to_skimmed=Lesestatus_auf_'überflogen'_gesetzt
Show_deprecated_BibTeX_fields=Abgelehnte_BibTeX-Felder_zeigen
+
Show_gridlines=Gitternetzlinien_anzeigen
Show_printed_status=Druckstatus_anzeigen
Show_read_status=Lesestatus_anzeigen
Table_row_height_padding=Zeilenabstand
-Marked_all_%0_selected_entries=Alle_%0_Einträge_markiert
Marked_selected_entry=Ausgewählten_Eintrag_markiert
-Toggle_print_status=Druckstatus_umschalten
-Unmarked_all_%0_selected_entries=Markierung_für_alle_%0_ausgewählten_Einträge_aufgehoben
+Marked_all_%0_selected_entries=Alle_%0_Einträge_markiert
Unmarked_selected_entry=Markierung_für_ausgewählten_Eintrag_aufgehoben
+Unmarked_all_%0_selected_entries=Markierung_für_alle_%0_ausgewählten_Einträge_aufgehoben
+Toggle_print_status=Druckstatus_umschalten
+
Unmarked_all_entries=Markierung_für_alle_Einträge_aufgehoben
Unable_to_find_the_requested_look_and_feel_and_thus_the_default_one_is_used.=Look_and_feel_konnte_nicht_gefunden_werden,_stattdessen_wird_der_Standard_verwendet.
-Could_not_open_browser.=Konnte_Browser_nicht_öffnen.
Opens_JabRef's_GitHub_page=Öffnet_JabRefs_GitHub-Seite
-Rebind_C-f,_too=C-f_ebenfalls_neu_zuweisen
-
-This_group_contains_all_entries._It_cannot_be_edited_or_removed.=Diese_Gruppe_enthält_alle_Einträge._Sie_kann_nicht_gelöscht_werden.
+Could_not_open_browser.=Konnte_Browser_nicht_öffnen.
+Please_open_%0_manually.=Bitte_öffnen_Sie_%0_manuell.
+The_link_has_been_copied_to_the_clipboard.=Der_Link_wurde_in_die_Zwischenablage_kopiert.
Open_%0_file=%0_Datei_öffnen
Cannot_delete_file=Datei_kann_nicht_gelöscht_werden.
-Convert=Konvertiere
-Delete_local_file=Lösche_lokale_Datei
File_permission_error=Fehler_beim_Dateizugriff.
-Help_on_Name_Formatting=Hilfe_zur_Namensformatierung
-Normalize_to_BibTeX_name_format=Normalisiere_ins_BibTeX-Namensformat
-Path_to_%0=Pfad_zu_%0
Push_to_%0=In_%0_einfügen
+Path_to_%0=Pfad_zu_%0
+Convert=Konvertiere
+Normalize_to_BibTeX_name_format=Normalisiere_ins_BibTeX-Namensformat
+Help_on_Name_Formatting=Hilfe_zur_Namensformatierung
Add_new_file_type=Füge_neuen_Dateityp_hinzu
-Follow_DOI_or_URL_link_and_try_to_locate_PDF_full_text_document=Folge_DOI/URL-Link_um_ein_PDF-Volltextdokument_zu_finden
+
Left_entry=Linker_Eintrag
-No_information_added=Keine_Informationen_hinzugefügt
+Right_entry=Rechter_Eintrag
+Use=Benutze
Original_entry=Originaleintrag
Replace_original_entry=Ersetze_Originaleintrag
-Right_entry=Rechter_Eintrag
+No_information_added=Keine_Informationen_hinzugefügt
Select_at_least_one_entry_to_manage_keywords.=Es_muss_mindestens_ein_Eintrag_ausgewählt_sein_um_Stichworte_verwalten_zu_können.
-Use=Benutze
-Changed_type_to_'%0'_for=Typ_geändert_zu_'%0'_für
-Database_'%0'_has_changed.=Die_Datenbank_'%0'_wurde_geändert.
-Copy_\\cite{BibTeX_key}=\\cite{BibTeX_key}_kopieren
-Copy_BibTeX_key_and_title=BibTeX-Key_und_Titel_kopieren
-File_rename_failed_for_%0_entries.=Dateiumbennung_schlug_ür_%0_Einträge_fehl.
-To_set_up,_go_to=Einstellungen_unter
-Search_%0=%0_durchsuchen
-Invalid_DOI\:_'%0'.=Ungültiger_DOI\:_'%0'.
-Could_not_connect_to_%0=Verbindung_zu_%0_fehlgeschlagen
-
+OpenDocument_text=OpenDocument-Text
+OpenDocument_spreadsheet=OpenDocument-Tabelle
+OpenDocument_presentation=OpenDocument-Präsentation
%0_image=%0-Bild
-%0_problem(s)_found=%0_Problem(e)_gefunden
-'%0'_is_not_a_valid_ADS_bibcode.='%0'_ist_kein_gültiger_ADS-Bibcode
-Accepting_the_change_replaces_the_complete_groups_tree_with_the_externally_modified_groups_tree.=Akzeptieren_der_Änderungen_führt_dazu,_dass_die_komplette_Gruppenstruktur_durch_die_externen_Änderungen_erstetzt_wird.
Added_entry=Eintrag_hinzugefügt
-Added_new_'%0'_entry.=Neuer_'%0'_Eintrag_hinzugefügt.
-Choose_the_URL_to_download.=Wählen_Sie_die_Download-URL
-Deleted_entry=Eintrag_gelöscht
-Discard_changes=Änderungen_verwerfen
-
-Donate_to_JabRef=An_JabRef_spenden
-Export_with_selected_format=Exportiere_im_gewählten_Format
-Field_is_missing=Feld_fehlt
-Filled=Befüllt
-From_import=Aus_im_Import
-Keep_left=Links_beibehalten
-Keep_merged_entry_only=Nur_den_zusammengeführten_Eintrag_beibehalten
-Keep_right=Rechts_beibehalten
-Merged_BibTeX_source_code=BibTeX-Quelltext_zusammengeführt
Modified_entry=Eintrag_ bearbeitet
+Deleted_entry=Eintrag_gelöscht
Modified_groups_tree=Gruppenstruktur_bearbeitet
-Multiple_entries_selected._Do_you_want_to_change_the_type_of_all_these_to_'%0'?=Mehrere_Einträge_ausgewählt._Wollen_Sie_den_Typ_aller_Einträge_zu_'%0'_ändern?
-No_problems_found.=Keine_Probleme_gefunden.
-Old_entry=Alter_Eintrag
-OpenDocument_presentation=OpenDocument-Präsentation
-OpenDocument_spreadsheet=OpenDocument-Tabelle
-OpenDocument_text=OpenDocument-Text
-Please_move_the_file_manually_and_link_in_place.=Bitte_die_Datei_manuell_verschieben_und_verlinken.
-Print_entry_preview=Eintragsvorschau_drucken
-Really_delete_the_%0_selected_entries?=Wirklich_alle_%0_ausgewählten_Einträge_löschen?
-Really_delete_the_selected_entry?=Ausgewählten_Eintrag_wirklich_löschen?
Removed_all_groups=Alle_Gruppen_entfernt
-Return_to_JabRef=Zurück_zu_JabRef
-Save_changes=Änderungen_speichern
+Accepting_the_change_replaces_the_complete_groups_tree_with_the_externally_modified_groups_tree.=Akzeptieren_der_Änderungen_führt_dazu,_dass_die_komplette_Gruppenstruktur_durch_die_externen_Änderungen_erstetzt_wird.
Select_export_format=Export-Format_wählen
+Return_to_JabRef=Zurück_zu_JabRef
+Please_move_the_file_manually_and_link_in_place.=Bitte_die_Datei_manuell_verschieben_und_verlinken.
+Could_not_connect_to_%0=Verbindung_zu_%0_fehlgeschlagen
Warning\:_%0_out_of_%1_entries_have_undefined_BibTeX_key.=Warnung\:_%0_von_%1_Einträgen_haben_keinen_BibTeX-Key.
-large_capitals_are_not_masked_using_curly_brackets_{}=Großbuchstaben_sind_nicht_in_geschweiften_Klammern_{}_gesetzt
occurrence=Vorkommen
-should_contain_a_four_digit_number=sollte_eine_vierstellige_Zahl_enthalten
-should_contain_a_valid_page_number_range=sollte_einen_gültigen_Seitenbereich_enthalten
-should_end_with_a_name=sollte_mit_einem_Name_enden
+Added_new_'%0'_entry.=Neuer_'%0'_Eintrag_hinzugefügt.
+Multiple_entries_selected._Do_you_want_to_change_the_type_of_all_these_to_'%0'?=Mehrere_Einträge_ausgewählt._Wollen_Sie_den_Typ_aller_Einträge_zu_'%0'_ändern?
+Changed_type_to_'%0'_for=Typ_geändert_zu_'%0'_für
+Really_delete_the_selected_entry?=Ausgewählten_Eintrag_wirklich_löschen?
+Really_delete_the_%0_selected_entries?=Wirklich_alle_%0_ausgewählten_Einträge_löschen?
+Keep_merged_entry_only=Nur_den_zusammengeführten_Eintrag_beibehalten
+Keep_left=Links_beibehalten
+Keep_right=Rechts_beibehalten
+Old_entry=Alter_Eintrag
+From_import=Aus_im_Import
+No_problems_found.=Keine_Probleme_gefunden.
+%0_problem(s)_found=%0_Problem(e)_gefunden
+Save_changes=Änderungen_speichern
+Discard_changes=Änderungen_verwerfen
+Database_'%0'_has_changed.=Die_Datenbank_'%0'_wurde_geändert.
+Print_entry_preview=Eintragsvorschau_drucken
+Copy_\\cite{BibTeX_key}=\\cite{BibTeX_key}_kopieren
+Copy_BibTeX_key_and_title=BibTeX-Key_und_Titel_kopieren
+File_rename_failed_for_%0_entries.=Dateiumbennung_schlug_ür_%0_Einträge_fehl.
+To_set_up,_go_to=Einstellungen_unter
+Merged_BibTeX_source_code=BibTeX-Quelltext_zusammengeführt
+Invalid_DOI\:_'%0'.=Ungültiger_DOI\:_'%0'.
should_start_with_a_name=sollte_mit_einem_Name_beginnen
-should_contain_a_protocol=sollte_ein_Protokoll_beinhalten
-
+should_end_with_a_name=sollte_mit_einem_Name_enden
unexpected_closing_curly_bracket=unerwartete_schließende_geschweifte_Klammer
unexpected_opening_curly_bracket=unerwartete_öffnende_geschweifte_Klammer
+capital_letters_are_not_masked_using_curly_brackets_{}=Großbuchstaben_sind_nicht_in_geschweiften_Klammern_{}_gesetzt
+should_contain_a_four_digit_number=sollte_eine_vierstellige_Zahl_enthalten
+should_contain_a_valid_page_number_range=sollte_einen_gültigen_Seitenbereich_enthalten
+Filled=Befüllt
+Field_is_missing=Feld_fehlt
+Search_%0=%0_durchsuchen
-Advanced_search_active.=Erweiterte_Suche_aktiv.
-Found_%0_results.=%0_Ergebnisse_gefunden.
-No_results_found.=Keine_Ergebnisse_gefunden.
-Normal_search_active.=Normale_Suche_aktiv.
-Search_globally=Global_suchen
-Search_in_all_open_databases=Suche_in_allen_offenen_Datenbanken
Search_results_in_all_databases_for_%0=Suchergebnisse_in_allen_Datenbanken_für_%0
Search_results_in_database_%0_for_%1=Suchergebnisse_in_Datenbank_%0_für_%1
-This_search_contains_entries_in_which=Diese_Suche_enthält_Einträge,_in_denen
+Search_globally=Global_suchen
+No_results_found.=Keine_Ergebnisse_gefunden.
+Found_%0_results.=%0_Ergebnisse_gefunden.
+Advanced_search_active.=Erweiterte_Suche_aktiv.
+Normal_search_active.=Normale_Suche_aktiv.
+plain_text=Klartext
This_search_contains_entries_in_which_any_field_contains_the_regular_expression_<b>%0</b>=Diese_Suche_enthält_Einträge,_die_in_einem_beliebigen_Feld_den_regulären_Ausdruck_<b>%0</b>_enthalten
This_search_contains_entries_in_which_any_field_contains_the_term_<b>%0</b>=Diese_Suche_enthält_Einträge,_die_in_einem_beliebigen_Feld_den_Begriff_<b>%0</b>_enthalten
-plain_text=Klartext
-Attention\:_Password_is_stored_in_plain_text\!=Achtung\:_Das_Passwort_wird_im_Klartext_gespeichert\!
-
-Please_specify_both_username_and_password=Bitte_geben_Sie_Benutzernamen_und_Passwort_an
-Proxy_requires_authentication=Proxy_erfordert_Authentifizierung
-
+This_search_contains_entries_in_which=Diese_Suche_enthält_Einträge,_in_denen
-An_autosave_file_was_found_for_this_database._This_could_indicate_that_JabRef_did_not_shut_down_cleanly_last_time_the_file_was_used.=Es_wurde_eine_Sicherungsdatei_für_diese_Datenbank_gefunden._Dies_deutet_darauf_hin,_dass_JabRef_das_letzte_mal_nicht_korrekt_beende_wurde,_als_diese_Datei_benutzt_wurde.
-Note\:_A_full_text_search_is_currently_not_supported_for_%0=Beachten_Sie\:_Eine_Volltextsuche_für_%0_wird_zurzeit_nicht_unterstützt
Unable_to_autodetect_OpenOffice/LibreOffice_installation._Please_choose_the_installation_directory_manually.=Konnte_Openoffice/LibreOffice_Installationspfad_nicht_atuomatisch_bestimmen._Bitte_wählen_Sie_das_Installationsverzeichnis_manuell_aus.
-
JabRef_no_longer_supports_'ps'_or_'pdf'_fields.<br>File_links_are_now_stored_in_the_'file'_field_and_files_are_stored_in_an_external_file_directory.<br>To_make_use_of_this_feature,_JabRef_needs_to_upgrade_file_links.<br><br>=JabRef_unterstützt_nicht_länger_'ps'_oder_'pdf'_Felder.<br>Dateilinks_werden_ab_jetzt_im_'Datei'_Feld_gespeichert_und_Dateien_werden_in_einem_externen_Dateiverzeichnis_gespeichert.<br>Um_diese_neue_Funktion_zu_nutzen_muss_JabRef_die_Dateilinks_aktualisieren.
This_database_uses_outdated_file_links.=Diese_Datenbank_benutzt_veraltete_Dateilinks.
@@ -2099,8 +1945,8 @@ Entry_editor,_store_field=Eintragseditor,_Feld_speichern
File_list_editor,_move_entry_down=Dateilisteneditor,_verschiebe_Eintrag_nach_unten
File_list_editor,_move_entry_up=Dateilisteneditor,_verschiebe_Eintrag_nach_oben
Focus_entry_table=Eintragstabelle_fokussieren
-Import_into_current_database=Importiere_in_aktuelle_Datenbank
-Import_into_new_database=Importiere_in_neue_Datenbank
+Import_into_current_database=Importieren_in_aktuelle_Datenbank
+Import_into_new_database=Importieren_in_neue_Datenbank
Increase_table_font_size=Vergrößere_Tabellenschriftgröße
New_article=Neuer_Artikel
New_book=Neues_Buch
@@ -2120,52 +1966,32 @@ Resolve_duplicate_BibTeX_keys=Doppelte_BibTeX-Keys_auflösen
Save_all=Alle_speichern
String_dialog,_add_string=Stringdialog,_String_hinzufügen
String_dialog,_remove_string=Stringdialog,_String_entfernen
-Switch_preview_layout=Wechsele_Vorschau_Layout
Synchronize_files=Sychronisiere_Dateien
Unabbreviate=Abkürzung_aufheben
-
-
-
+should_contain_a_protocol=sollte_ein_Protokoll_beinhalten
Copy_preview=Kopiere_Vorschau
-
Automatically_setting_file_links=Dateilinks_werden_automatisch_gesetzt
Regenerating_BibTeX_keys_according_to_metadata=Regeneriere_BibTeX-Keys_anhand_ihrer_Metadaten
No_meta_data_present_in_BIB_file._Cannot_regenerate_BibTeX_keys=Keine_Metadaten_in_Bibdatei_vorhanden. Kann_keine_BibTeX-Keys_regenerieren
-
Regenerate_all_keys_for_the_entries_in_a_BibTeX_file=Regeneriere_alle_BibTeX-Keys_für_Einträge_in_einer_BibTeX_Datei
-
Show_debug_level_messages=Zeige_Debug_Level_Meldungen
-
-Export_sorting=Exportiere_Sortierung
-
-New_%0_database=Neue_%0_Datenbank
-
-New_%0_database_created.=Neue_%0_Datenbank_erstellt.
-
-No_entry_found_for_ISBN_%0_at_www.ebook.de=Kein_Eintrag_für_ISBN_%0_bei_www.ebook.de_gefunden
-
-
-Save_actions=Speicheraktionen
-Enable_save_actions=Speicheraktionen_aktivieren
-Always_reformat_BIB_file_on_save_and_export=Formatiere_BIB_Datei_immer_neu_beim_Exportieren
Default_bibliography_mode=Standard_Bibliographiemodus
-
+New_%0_database_created.=Neue_%0_Datenbank_erstellt.
Show_only_preferences_deviating_from_their_default_value=Zeige_nur_Einstellungen,_die_vom_Standardwert_abweichen
default=Standard
key=Schlüssel
type=Typ
value=Wert
-
Show_preferences=Zeige_Einstellungen
-
+Save_actions=Speicheraktionen
+Enable_save_actions=Speicheraktionen_aktivieren
Other_fields=Andere_Felder
Show_remaining_fields=Zeige_übrige_Felder
link_should_refer_to_a_correct_file_path=Link_sollte_einen_korrekten_Dateipfad_referenzieren
-
abbreviation_detected=Abkürzung_erkannt
-
+wrong_entry_type_as_proceedings_has_page_numbers=falscher_Eintragstyp,_weil_'Konferenzbericht'_Feld_mit_Seitenzahlen_hat
Abbreviate_journal_names=Kürze_Zeitschriftentitel_ab
Abbreviating...=Kürze_ab...
Adding_fetched_entries=Füge_abgerufene_Einträge_hinzu
@@ -2173,31 +1999,26 @@ Display_keywords_appearing_in_ALL_entries=Zeige_Schlüsselwörter_die_in_ALLEN_E
Display_keywords_appearing_in_ANY_entry=Zeige_Schlüsselwörter_die_in_mind._EINEM_Eintrag_vorkommen
Fetching_entries_from_Inspire=Rufe_Einträge_von_Inspire_ab
None_of_the_selected_entries_have_BibTeX_keys.=Keiner_der_selektieren_Einträge_besitzt_BibTeX-Keys.
-
+Unabbreviate_journal_names=Abkürzung_der_Zeitschriftentitel_aufheben
Unabbreviating...=Hebe_Abkürzungen_auf...
Usage=Bedienung
+
+Adds_{}_brackets_around_acronyms,_month_names_and_countries_to_preserve_their_case.=Fügt_{}-Klammern_um_Akronyme,_Monatsnamen_und_Ländernamen_ein,_um_Groß-/Kleinschreibung_beizubehalten.
Are_you_sure_you_want_to_reset_all_settings_to_default_values?=Wollen_sie_wirklich_alle_Einstellungen_auf_Standardwerte_zurücksetzen?
Reset_preferences=Einstellungen_zurücksetzen
-
Ill-formed_entrytype_comment_in_BIB_file=Fehlerhafter_Eintragstypkommentar_in_BIB_Datei
+
+Move_linked_files_to_default_file_directory_%0=Verknüpfte_Dateien_in_das_Standardverzeichnis_%0_verschieben
+
Clipboard=Zwischenablage
Could_not_paste_entry_as_text\:=Konnte_Einträge_nicht_als_Text_parsen\:
Do_you_still_want_to_continue?=Wollen_Sie_wirklich_fortfahren?
This_action_will_modify_the_following_field(s)_in_at_least_one_entry_each\:=Diese_Aktion_wird_jeweils_das/die_folgenden_Feld(er)_in_mindestens_einem_Eintrag_ändern\:
This_could_cause_undesired_changes_to_your_entries.=Dies_könnte_ungewollte_Änderungen_an_Ihren_Einträgen_hervorrufen.
-
-
-Disable_highlight_groups_matching_entries=Keine_Gruppen_hervorheben
Run_field_formatter\:=Führe_Feldformatierer_aus\:
-
-Adds_{}_brackets_around_acronyms,_month_names_and_countries_to_preserve_their_case.=Fügt_{}-Klammern_um_Akronyme,_Monatsnamen_und_Ländernamen_ein,_um_Groß-/Kleinschreibung_beizubehalten.
-Converts_units_to_LaTeX_formatting.=Konvertiert_Einheiten_in_LaTeX-Code.
-Does_nothing.=Macht_nichts.
-
Table_font_size_is_%0=Tabellenschriftgröße_ist_%0%
-
-
+%0_import_canceled=%0-Import_abgebrochen
Internal_style=Interner_Stil
Add_style_file=Füge_Stildatei_hinzu
Are_you_sure_you_want_to_remove_the_style?=Wollen_Sie_wirklich_den_Stil_entfernen?
@@ -2205,7 +2026,6 @@ Current_style_is_'%0'=Aktueller_Stil_ist_%0
Remove_style=Style_entfernen
Select_one_of_the_available_styles_or_add_a_style_file_from_disk.=Wählen_Sie_einen_der_verfügbaren_Stile_aus_oder_fügen_Sie_eine_Stildatei_von_der_Festplatte_hinzu.
You_must_select_a_valid_style_file.=Sie_müssen_eine_valide_Stildatei_auswählen.
-
Reload=Neu_laden
Capitalize=Großschreiben
@@ -2215,12 +2035,12 @@ Changes_all_letters_to_lower_case.=Ändere_alle_Buchstaben_in_Kleinschreibung.
Changes_all_letters_to_upper_case.=Ändere_alle_Buchstaben_in_Großschreibung.
Changes_the_first_letter_of_all_words_to_capital_case_and_the_remaining_letters_to_lower_case.=Schreibt_den_ersten_Buchstaben_eines_jeden_Wortes_groß_und_schreibt_alle_anderen_Wörter_klein.
Cleans_up_LaTeX_code.=Räumt_LaTeX-Code_auf.
-
Converts_HTML_code_to_LaTeX_code.=Konvertiere_HTML-Code_in_LaTeX-Code.
Converts_HTML_code_to_Unicode.=Konvertiere_HTML-Code_in_Unicode.
Converts_LaTeX_encoding_to_Unicode_characters.=Konvertiere_LaTeX_Kodierung_in_Unicode_Zeichen.
Converts_Unicode_characters_to_LaTeX_encoding.=Konvertiere_Unicode_Zeichen_in_LaTeX_Kodierung.
Converts_ordinals_to_LaTeX_superscripts.=Konvertiere_Ordinalzahlen_in_LaTeX_Hochstellung.
+Converts_units_to_LaTeX_formatting.=Konvertiert_Einheiten_in_LaTeX-Code.
HTML_to_LaTeX=HTML_zu_LaTeX
LaTeX_cleanup=LaTeX_Aufräumen
LaTeX_to_Unicode=LaTeX_zu_Unicode
@@ -2244,22 +2064,13 @@ Title_case=Groß-/Kleinschreibung_von_Titeln
Unicode_to_LaTeX=Unicode_zu_LaTeX
Units_to_LaTeX=Einheiten_zu_LaTeX
Upper_case=Großschreibung
+Does_nothing.=Macht_nichts.
Identity=Identität
-
-
Clears_the_field_completely.=Löscht_das_Feld_komplett
-
-
+Directory_not_found=Verzeichnis_nicht_gefunden
Main_file_directory_not_set\!=Hauptverzeichnis_nicht_gesetzt\!
-
This_operation_requires_exactly_one_item_to_be_selected.=Für_diesen_Vorgang_muss_genau_ein_Eintrag_ausgewählt_sein
-
-Directory_not_found=Verzeichnis_nicht_gefunden
-
-Move_linked_files_to_default_file_directory_%0=Verknüpfte_Dateien_in_das_Standardverzeichnis_%0_verschieben
-wrong_entry_type_as_proceedings_has_page_numbers=falscher_Eintragstyp,_weil_'Konferenzbericht'_Feld_mit_Seitenzahlen_hat
-
-Importing_in_%0_format=Importiere_im_Format_%0
+Importing_in_%0_format=Importieren_im_Format_%0
Female_name=weiblicher_Name
Female_names=weibliche_Namen
Male_name=männlicher_Name
@@ -2306,34 +2117,27 @@ Verse=Vers
change_entries_of_group=Ändere_Einträge_der_Gruppe
odd_number_of_unescaped_'\#'=Ungerade_Anzahl_an_'\#'_Maskierungszeichen
+
Plain_text=Klartext
Show_diff=Zeige_Änderungen
character=Zeichen
word=Wort
-
Show_symmetric_diff=Zeige_Änderungen_symmetisch
HTML_encoded_character_found=HTML_kodiertes_Zeichen_gefunden
-
booktitle_ends_with_'conference_on'=Buchtitel_endet_mit_'Konferenzbericht'
+
All_external_files=Alle_externen_Dateien
OpenOffice/LibreOffice_integration=OpenOffice/LibreOffice-Integration
incorrect_control_digit=Falsche_Prüfziffer
incorrect_format=Falsches_Format
-
-Expected_"%0"_to_contain_whitespace=Erwartete_Leerzeichen_in_"%0"
-Syntax_error_in_regular-expression_pattern=Syntaxfehler_in_Regulärem_Ausdruck
Copy_version_to_clipboard=Kopiere_Version_in_die_Zwischenablage
Copied_version_to_clipboard=Version_in_die_Zwischenablage_kopiert
+
BibTeX_key=BibTeX-Key
Message=Nachricht
-
-Get_fulltext=Hole_Volltext
-
-Download_from_URL=Download_von_URL
-
Decryption_not_supported.=Entschlüsselung_wird_nicht_unterstützt.
Cleared_'%0'_for_%1_entries='%0'_für_%1_Einträge_entfernt
@@ -2352,14 +2156,12 @@ To_see_what_is_new_view_the_changelog.=Für_Neuerungen/Änderungen_Changelog_ans
A_new_version_of_JabRef_has_been_released.=Eine_neue_JabRef_Version_wurde_veröffentlicht.
JabRef_is_up-to-date.=JabRef_ist_auf_dem_aktuellsten_Stand.
Latest_version=Neueste_Version
-
-Please_open_%0_manually.=Bitte_öffnen_Sie_%0_manuell.
-
-The_link_has_been_copied_to_the_clipboard.=Der_Link_wurde_in_die_Zwischenablage_kopiert.
Online_help_forum=Online-Hilfeforum
-
Custom=Benutzerdefiniert
+Export_cited=Exportiere_zitierte_Einträge
+Unable_to_generate_new_database=Kann_keine_neue_Datenbank_generieren
+
Open_console=Terminal_öffnen
Use_default_terminal_emulator=Standard_Terminal-Emulator_verwenden
Execute_command=Befehl_ausführen
@@ -2368,26 +2170,20 @@ Executing_command_\"%0\"...=Ausführung_des_Kommandos_\"%0\"...
Error_occured_while_executing_the_command_\"%0\".=Während_der_Ausführung_des_Befehls_\"%0\"_ist_ein_Fehler_aufgetreten.
Reformat_ISSN=Formatiere_ISSN
-Unable_to_generate_new_database=Kann_keine_neue_Datenbank_generieren
-
-Export_cited=Exportiere_zitierte_Einträge
Countries_and_territories_in_English=Länder_und_Territorien_in_Englisch
Electrical_engineering_terms=Begriffe_aus_der_Elektrotechnik
Enabled=Aktiviert
Internal_list=Interne_Liste
+Manage_protected_terms_files=Verwalte_geschützte_Begriffsdatei
Months_and_weekdays_in_English=Monate_und_Wochentage_in_Englisch
The_text_after_the_last_line_starting_with_\#_will_be_used=Der_Text_nach_der_letzten_Zeile_die,_mit_\#_beginnt,_wird_benutzt
Add_protected_terms_file=Füge_geschützte_Begriffsdatei_hinzu
Are_you_sure_you_want_to_remove_the_protected_terms_file?=Sind_Sie_sicher,_dass_Sie_die_geschützte_Begriffsdatei_löschen_wollen?
Remove_protected_terms_file=Lösche_geschützte_Begriffsdatei
-
-Manage_protected_terms_files=Verwalte_geschützte_Begriffsdatei
-
Add_selected_text_to_list=Markierten_Text_zur_Liste_hinzufügen
Add_{}_around_selected_text={}_um_markierten_Text_einfügen
Format_field=Formatfeld
New_protected_terms_file=Neue_geschützte_Begriffsdatei
-
change_field_%0_of_entry_%1_from_%2_to_%3=Ändere_Feld_%0_von_Eintrag_%1_von_%2_auf_%3
change_key_from_%0_to_%1=Ändere_Key_von_%0_auf_%1
change_string_content_%0_to_%1=Ändere_Stringinhalt_von_%0_auf_%1
@@ -2397,40 +2193,29 @@ insert_entry_%0=Füge_Eintrag_%0_hinzu
insert_string_%0=Füge_String_%0_hinzu
remove_entry_%0=Entferne_Eintrag_%0
remove_string_%0=Entferne_String_%0
-
undefined=unbekannt
-
Cannot_get_info_based_on_given_%0\:_%1=Informationen_können_für_den_angegebenen_%0_'%1'_nicht_ermittelt_werden.
-
Get_BibTeX_data_from_%0=Hole_BibTeX-Daten_durch_%0
No_%0_found=Keine_%0_gefunden
-
Entry_from_%0=Eintrag_basierend_auf_%0
-
Merge_entry_with_%0_information=Eintrag_mit_%0-Informationen_zusammenführen
Updated_entry_with_info_from_%0=Eintrag_wurde_mit_%0-Information_aktualisiert.
-
Connection=Verbindung
+Connecting...=Verbinde...
Host=Host
Port=Port
Database=Datenbank
User=Benutzer
Connect=Verbinden
Connection_error=Verbindungsfehler
-Driver_error=Treiberfehler
Connection_to_%0_server_established.=Verbindung_zum_%0_Server hergestellt.
Required_field_"%0"_is_empty.=Erforederliches_Feld_"%0"_ist_leer.
-
%0_driver_not_available.=%0-Treiber_nicht_verfügbar.
-
The_connection_to_the_server_has_been_terminated.=Verbindung_zum_Server_wurde_abgebrochen.
-
Connection_lost.=Verbindung_verloren.
Reconnect=Neu_verbinden.
Work_offline=Offline_arbeiten.
-
Working_offline.=Arbeite_offline.
-
Update_refused.=Aktualisierung_verweigert.
Update_refused=Aktualisierung_verweigert
Local_entry=Lokaler_Eintrag
@@ -2441,7 +2226,12 @@ Local_version\:_%0=Lokale_Version\:_%0
Shared_version\:_%0=Geteilte_genutzte_Version\:_%0
Please_merge_the_shared_entry_with_yours_and_press_"Merge_entries"_to_resolve_this_problem.=Bitte_führen_Sie_den_gemeinsam_genutzten_Eintrag_mit_Ihrem_zusammen_und_klicken_Sie_auf_"Einträge_zuammenführen",_um_das_Problem_zu_beheben.
Canceling_this_operation_will_leave_your_changes_unsynchronized._Cancel_anyway?=Durch_einen_Abbruch_dieser_Operation_werden_die_Änderungen_nicht_synchronisiert._Trotzdem_abbrechen?
-The_BibEntry_you_currently_work_on_has_been_deleted_on_the_shared_side._Hit_"Keep"_to_recover_the_entry.=Der_Eintrag,_welchen_Sie_zur_Zeit_bearbeiten,_ist_auf_der_gemeinsam_genutzen_Datenbank_nicht_mehr_vorhanden._Klicken_Sie_auf_"Behalten",_um_den_Eintrag_wiederherzustellen.
+Shared_entry_is_no_longer_present=Geteilter_Eintrag_ist_nicht_mehr_vorhanden
+The_BibEntry_you_currently_work_on_has_been_deleted_on_the_shared_side.=Der_Eintrag,_welchen_Sie_zur_Zeit_bearbeiten,_ist_auf_der_geteilten_Datenbank_nicht_mehr_vorhanden.
+You_can_restore_the_entry_using_the_"Undo"_operation.=Unter_Benutzung_der_"Rückgängig"-Funktion_kann_der_Eintrag_wiederhergestellt_werden.
+Remember_password?=Passwort_merken?
+You_are_already_connected_to_a_database_using_entered_connection_details.=Eine_Datenbankverbindung_mit_den_eingegebenen_Verbindungsinformationen_besteht_bereits.
+
Cannot_cite_entries_without_BibTeX_keys._Generate_keys_now?=Kann_keine_Einträge_ohne_BibTeX-Key_zitieren._Keys_jetzt_generieren?
New_technical_report=Neuer_technischer_Bericht
@@ -2451,16 +2241,11 @@ Protected_terms_file=Geschützte_Begriffsdatei
Style_file=Stildatei
Open_OpenOffice/LibreOffice_connection=Öffne_OpenOffice/LibreOffice_Verbindung
-
You_must_enter_at_least_one_field_name=Sie_müssen_mindestens_einen_Feldnamen_angeben
-
-
Non-ASCII_encoded_character_found=Nicht_ASCII-kodiertes_Zeichen_gefunden
-
Toggle_web_search_interface=Websuche_ein-/ausschalten
Background_color_for_resolved_fields=Hintergrundfarbe_für_referenzierte_Felder
Color_code_for_resolved_fields=Farbanzeige_für_referenzierte_Felder
-
%0_files_found=%0_Dateien_gefunden
%0_of_%1=%0_von_%1
One_file_found=Eine_Datei_gefunden
@@ -2471,14 +2256,59 @@ There_were_%0_files_which_could_not_be_imported.=%0_Dateien_konnten_nicht_import
Migration_help_information=Hilfe_zur_Migration
Entered_database_has_obsolete_structure_and_is_no_longer_supported.=Die_gewählte_Datenbank_nutzt_eine_veraltete,_nicht_mehr_unterstützte_Struktur.
However,_a_new_database_was_created_alongside_the_pre-3.6_one.=Dennoch_wurde_eine_neue_Datenbank_neben_der_alten_Datenbank_erzeugt.
-
Click_here_to_learn_about_the_migration_of_pre-3.6_databases.=Klicken_um_Informationen_zur_Migration_von_vor-3.6-Datenbanken_zu_erhalten.
-
-Connecting...=Verbinde...
-
Opens_JabRef's_Facebook_page=Öffnet_JabRefs_Facebookseite
Opens_JabRef's_blog=Öffnet_JabRefs_Blog
Opens_JabRef's_website=Öffnet_JabRefs_Webseite
-
Opens_a_link_where_the_current_development_version_can_be_downloaded=Öffnet_eine_Seite_auf_der_die_aktuellste_Entwicklungsversion_heruntergeladen_werden_kann
See_what_has_been_changed_in_the_JabRef_versions=Beschreibt_was_in_den_verschiedenen_JabRef-Versionen_geändert_wurde
+Referenced_BibTeX_key_does_not_exist=Referenzierter_BibTeX-Key_existiert_nicht
+Finished_downloading_full_text_document_for_entry_%0.=Download des Volltextdokuments für Eintrag %0 komplett
+Full_text_document_download_failed_for_entry_%0.=Download des Volltextdokuments für Eintrag %0 fehlgeschlagen
+Look_up_full_text_documents=Volltextdokumente suchen
+You_are_about_to_look_up_full_text_documents_for_%0_entries.=Sie werden gleich Volltextdokumente für %0 Einträge suchen
+last_four_nonpunctuation_characters_should_be_numerals=Die letzten vier Nichtinterpunktionszeichen sollten Numerale sein
+shared=geteilt
+should_contain_an_integer_or_a_literal=Sollte_einen_Integer_oder_einen_Literal_enthalten
+should_have_the_first_letter_capitalized=Sollte_den_ersten_Buchstaben_großgeschrieben_haben
+
+ID=ID
+ID_type=ID-Typ
+ID-based_entry_generator=ID-basierter_Eintragsgenerator
+Fetcher_'%0'_did_not_find_an_entry_for_id_'%1'.=Der_%0-Fetcher_hat_keinen_Eintrag_für_die_ID_'%1'_gefunden.
+
+Select_first_entry=Ersten_Eintrag_auswählen
+Select_last_entry=Letzten_Eintrag_auswählen
+
+Invalid_ISBN\:_'%0'.=Ungültige_ISBN\:_'%0'.
+should_be_an_integer_or_normalized=Sollte_ein_Integer_oder_normalisiert_sein
+should_be_normalized=Sollte_normalisiert_sein
+
+Empty_search_ID=Leere_Such-ID
+The_given_search_ID_was_empty.=Die_übergebene_Such-ID_ist_leer.
+Copy_BibTeX_key_and_link=BibTeX-Key_und_Link_kopieren
+empty_BibTeX_key=Leerer_BibTeX-Key
+BibLaTeX_field_only=Nur_ein_BibLaTeX-Feld
+
+Error_while_generating_fetch_URL=Fehler_beim_generieren_der_Abruf_URL
+Error_while_parsing_ID_list=Fehler_beim_parsen_der_ID-Liste
+Unable_to_get_PubMed_IDs=Es_ist_nicht_möglich_die_PubMed_ID's_zu_bekommen
+Backup_found=Backup_gefunden
+A_backup_file_for_'%0'_was_found.=Es_wurde_eine_Backup-Datei_für_'%0'_gefunden.
+This_could_indicate_that_JabRef_did_not_shut_down_cleanly_last_time_the_file_was_used.=Dies_kann_bedeuten,_dass_JabRef_bei_der_letzten_Benutzung_nicht_korrekt_beendet_wurde.
+Do_you_want_to_recover_the_database_from_the_backup_file?=Möchten_Sie_die_Datenbank_mit_Hilfe_der_Backup-Datei_wiederherstellen?
+Firstname_Lastname=Vorname_Nachname
+
+Recommended_for_%0=Empfohlen_für_%0
+This_might_be_caused_by_reaching_the_traffic_limitation_of_Google_Scholar_(see_'Help'_for_details).=Dies_kann_durch_eine_Downloadbeschränkung_von_Google_Scholar_ausgelöst_werden_(mehr_Details_in_der_'Hilfe').
+
+Problem_downloading_from_%1=
+
+File_directory_pattern=
+Update_with_bibliographic_information_from_the_web=
+
+Could_not_find_any_bibliographic_information.=
+BibTeX_key_%0_deviates_from_generated_key_%1=
+DOI_%0_is_invalid=
+
+Jump_to_entry=Springe_zu_Eintrag
diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties
index 34c9b97..edaaa54 100644
--- a/src/main/resources/l10n/JabRef_en.properties
+++ b/src/main/resources/l10n/JabRef_en.properties
@@ -1,6 +1,6 @@
#!
-#! created/edited by Popeye version 0.55 (popeye.sourceforge.net)
-#! encoding:ISO-8859-1
+#! created/edited by Popeye version 0.55 (github.com/JabRef/popeye)
+#! encoding:UTF-8
%0_contains_the_regular_expression_<b>%1</b>=%0_contains_the_regular_expression_<b>%1</b>
@@ -16,12 +16,10 @@
%0_matches_the_term_<b>%1</b>=%0_matches_the_term_<b>%1</b>
-<field_name>=<field_name>
<HTML>Could_not_find_file_'%0'<BR>linked_from_entry_'%1'</HTML>=<HTML>Could_not_find_file_'%0'<BR>linked_from_entry_'%1'</HTML>
<select>=<select>
-<select_word>=<select_word>
Abbreviate_journal_names_of_the_selected_entries_(ISO_abbreviation)=Abbreviate_journal_names_of_the_selected_entries_(ISO_abbreviation)
Abbreviate_journal_names_of_the_selected_entries_(MEDLINE_abbreviation)=Abbreviate_journal_names_of_the_selected_entries_(MEDLINE_abbreviation)
@@ -42,10 +40,10 @@ Action=Action
Add=Add
-Add_a_(compiled)_custom_ImportFormat_class_from_a_class_path.=Add_a_(compiled)_custom_ImportFormat_class_from_a_class_path.
+Add_a_(compiled)_custom_Importer_class_from_a_class_path.=Add_a_(compiled)_custom_Importer_class_from_a_class_path.
The_path_need_not_be_on_the_classpath_of_JabRef.=The_path_need_not_be_on_the_classpath_of_JabRef.
-Add_a_(compiled)_custom_ImportFormat_class_from_a_ZIP-archive.=Add_a_(compiled)_custom_ImportFormat_class_from_a_ZIP-archive.
+Add_a_(compiled)_custom_Importer_class_from_a_ZIP-archive.=Add_a_(compiled)_custom_Importer_class_from_a_ZIP-archive.
The_ZIP-archive_need_not_be_on_the_classpath_of_JabRef.=The_ZIP-archive_need_not_be_on_the_classpath_of_JabRef.
Add_entry_selection_to_this_group=Add_entry_selection_to_this_group
@@ -82,7 +80,6 @@ All_subgroups_(recursively)=All_subgroups_(recursively)
Always_reformat_BIB_file_on_save_and_export=Always_reformat_BIB_file_on_save_and_export
-An_exception_occurred_while_accessing_'%0'=An_exception_occurred_while_accessing_'%0'
A_SAX_exception_occurred_while_parsing_'%0'\:=A_SAX_exception_occurred_while_parsing_'%0'\:
and=and
@@ -156,7 +153,7 @@ Backup_old_file_when_saving=Backup_old_file_when_saving
BibTeX_key_is_unique.=BibTeX_key_is_unique.
-BibTeX_source=BibTeX_source
+%0_source=%0_source
Broken_link=Broken_link
@@ -465,7 +462,6 @@ Entry_types=Entry_types
Error=Error
Error_exporting_to_clipboard=Error_exporting_to_clipboard
-##Error\:_check_your_External_viewer_settings_in_Preferences=Error\:_check_your_External_viewer_settings_in_Preferences
Error_occurred_when_parsing_entry=Error_occurred_when_parsing_entry
Error_opening_file=Error_opening_file
@@ -485,7 +481,6 @@ Overwrite_file?=Overwrite_file?
Expand_subtree=Expand_subtree
-#previousentrynottranslated.Toviewit,openGroupinterfaceandclickonthe"newgroup"button
Export=Export
Export_name=Export_name
@@ -517,8 +512,6 @@ Field=Field
field=field
-#IntegritycheckisaprocessthatchecksforindicationsofwronglyfilledoutBibTeXfields."Scan"isthebuttonthatstartsthecheck.
-
Field_name=Field_name
Field_names_are_not_allowed_to_contain_white_space_or_the_following_characters=Field_names_are_not_allowed_to_contain_white_space_or_the_following_characters
@@ -669,13 +662,11 @@ Import_strings=Import_strings
Import_to_open_tab=Import_to_open_tab
-Import_word_selector_definitions=Import_word_selector_definitions
-
Imported_entries=Imported_entries
Imported_from_database=Imported_from_database
-ImportFormat_class=ImportFormat_class
+Importer_class=Importer_class
Importing=Importing
@@ -692,15 +683,10 @@ Initially_show_groups_tree_expanded=Initially_show_groups_tree_expanded
Work_options=Work_options
-Input_error=Input_error
-
Insert=Insert
Insert_rows=Insert_rows
-
-
-#IntegritycheckisaprocessthatchecksforindicationsofwronglyfilledoutBibTeXfields."Scan"isthebuttonthatstartsthecheck.
Intersection=Intersection
Invalid_BibTeX_key=Invalid_BibTeX_key
@@ -737,7 +723,6 @@ Key_pattern=Key_pattern
keys_in_database=keys_in_database
-#nottranslated.Toviewit,usemenu"Tools|NewBibTeXfilefromAUxfile",andlaunchtheactiononanon-existantAUXfile.
Keyword=Keyword
Label=Label
@@ -768,8 +753,6 @@ Main_file_directory=Main_file_directory
Main_layout_file=Main_layout_file
-Manage=Manage
-
Manage_custom_exports=Manage_custom_exports
Manage_custom_imports=Manage_custom_imports
@@ -871,8 +854,6 @@ No_journal_names_could_be_abbreviated.=No_journal_names_could_be_abbreviated.
No_journal_names_could_be_unabbreviated.=No_journal_names_could_be_unabbreviated.
No_PDF_linked=No_PDF_linked
-No_references_found=No_references_found
-
No_URL_defined=No_URL_defined
not=not
@@ -884,9 +865,6 @@ Nothing_to_redo=Nothing_to_redo
Nothing_to_undo=Nothing_to_undo
-#Thenextisusedlikein"Referencesfound\:1Numberofreferencestofetch?"
-Number_of_references_to_fetch?=Number_of_references_to_fetch?
-
occurrences=occurrences
OK=OK
@@ -907,7 +885,7 @@ Open_file=Open_file
Open_last_edited_databases_at_startup=Open_last_edited_databases_at_startup
-Open_shared_database=Open_shared_database
+Connect_to_shared_database=Connect_to_shared_database
Open_terminal_here=Open_terminal_here
@@ -991,6 +969,14 @@ Preferences=Preferences
Preferences_recorded.=Preferences_recorded.
Preview=Preview
+Citation_Style=Citation_Style
+Current_Preview=Current_Preview
+Cannot_generate_preview_based_on_selected_citation_style.=Cannot_generate_preview_based_on_selected_citation_style.
+Bad_character_inside_entry=Bad_character_inside_entry
+Error_while_generating_citation_style=Error_while_generating_citation_style
+Preview_style_changed_to\:_%0=Preview_style_changed_to\:_%0
+Next_preview_layout=Next_preview_layout
+Previous_preview_layout=Previous_preview_layout
Previous_entry=Previous_entry
@@ -1014,8 +1000,7 @@ Redo=Redo
Reference_database=Reference_database
-#Thenexttwolinesareusedlikein"Referencesfound\:1Numberofreferencestofetch?"
-References_found=References_found
+%0_references_found._Number_of_references_to_fetch?=%0_references_found._Number_of_references_to_fetch?
Refine_supergroup\:_When_selected,_view_entries_contained_in_both_this_group_and_its_supergroup=Refine_supergroup\:_When_selected,_view_entries_contained_in_both_this_group_and_its_supergroup
@@ -1111,8 +1096,6 @@ Save_failed=Save_failed
Save_failed_during_backup_creation=Save_failed_during_backup_creation
-Save_failed_while_committing_changes\:_%0=Save_failed_while_committing_changes\:_%0
-
Save_selected_as...=Save_selected_as...
Saved_database=Saved_database
@@ -1163,7 +1146,7 @@ Settings=Settings
Shortcut=Shortcut
-Show/edit_BibTeX_source=Show/edit_BibTeX_source
+Show/edit_%0_source=Show/edit_%0_source
Show_'Firstname_Lastname'=Show_'Firstname_Lastname'
@@ -1185,7 +1168,7 @@ Show_icons_for_groups=Show_icons_for_groups
Show_last_names_only=Show_last_names_only
Show_names_unchanged=Show_names_unchanged
-
+
Show_optional_fields=Show_optional_fields
Show_required_fields=Show_required_fields
@@ -1334,8 +1317,6 @@ Unmark_entries=Unmark_entries
Unmark_entry=Unmark_entry
-Unsupported_version_of_class_%0\:_%1=Unsupported_version_of_class_%0\:_%1
-
untitled=untitled
Up=Up
@@ -1424,12 +1405,10 @@ Import_canceled_by_user=Import_canceled_by_user
Progress\:_%0_of_%1=Progress\:_%0_of_%1
Error_while_fetching_from_%0=Error_while_fetching_from_%0
-Fetching_Medline_by_id...=Fetching_Medline_by_id...
-
-Fetching_Medline_by_term...=Fetching_Medline_by_term...
Please_enter_a_valid_number=Please_enter_a_valid_number
-Please_enter_a_comma_separated_list_of_Medline_IDs_(numbers)_or_search_terms.=Please_enter_a_comma_separated_list_of_Medline_IDs_(numbers)_or_search_terms.
Show_search_results_in_a_window=Show_search_results_in_a_window
+Show_global_search_results_in_a_window=Show_global_search_results_in_a_window
+Search_in_all_open_databases=Search_in_all_open_databases
Move_file_to_file_directory?=Move_file_to_file_directory?
Rename_to_'%0'=Rename_to_'%0'
You_have_changed_the_menu_and_label_font_size.=You_have_changed_the_menu_and_label_font_size.
@@ -1465,7 +1444,6 @@ Sort_the_following_fields_as_numeric_fields=Sort_the_following_fields_as_numeric
Line_%0\:_Found_corrupted_BibTeX_key.=Line_%0\:_Found_corrupted_BibTeX_key.
Line_%0\:_Found_corrupted_BibTeX_key_(contains_whitespaces).=Line_%0\:_Found_corrupted_BibTeX_key_(contains_whitespaces).
Line_%0\:_Found_corrupted_BibTeX_key_(comma_missing).=Line_%0\:_Found_corrupted_BibTeX_key_(comma_missing).
-Finished_downloading_full_text_document=Finished_downloading_full_text_document
Full_text_document_download_failed=Full_text_document_download_failed
Update_to_current_column_order=Update_to_current_column_order
Download_from_URL=Download_from_URL
@@ -1481,16 +1459,15 @@ Cannot_use_port_%0_for_remote_operation;_another_application_may_be_using_it._Tr
Looking_for_full_text_document...=Looking_for_full_text_document...
Autosave=Autosave
-Prompt_before_recovering_a_database_from_an_autosave_file=Prompt_before_recovering_a_database_from_an_autosave_file
-Autosave_interval_(minutes)=Autosave_interval_(minutes)
-Do_you_want_to_recover_the_database_from_the_autosave_file?=Do_you_want_to_recover_the_database_from_the_autosave_file?
-Recover_from_autosave=Recover_from_autosave
+A_local_copy_will_be_opened.=A_local_copy_will_be_opened.
+Autosave_local_databases=Autosave_local_databases
+Automatically_save_the_database_to=Automatically_save_the_database_to
+Please_enter_a_valid_file_path.=Please_enter_a_valid_file_path.
+
Export_in_current_table_sort_order=Export_in_current_table_sort_order
Export_entries_in_their_original_order=Export_entries_in_their_original_order
Error_opening_file_'%0'.=Error_opening_file_'%0'.
-Autosave_of_file_'%0'=Autosave_of_file_'%0'
-Error_opening_autosave_of_'%0'._Trying_to_load_'%0'_instead.=Error_opening_autosave_of_'%0'._Trying_to_load_'%0'_instead.
Formatter_not_found\:_%0=Formatter_not_found\:_%0
Clear_inputarea=Clear_inputarea
@@ -1557,7 +1534,6 @@ Create_entry_based_on_XMP_data=Create_entry_based_on_XMP_data
Create_blank_entry_linking_the_PDF=Create_blank_entry_linking_the_PDF
Only_attach_PDF=Only_attach_PDF
Title=Title
-No_internet_connection.=No_internet_connection.
Create_new_entry=Create_new_entry
Update_existing_entry=Update_existing_entry
Autocomplete_names_in_'Firstname_Lastname'_format_only=Autocomplete_names_in_'Firstname_Lastname'_format_only
@@ -1633,7 +1609,6 @@ Select_document=Select_document
Edit_group_membership=Edit_group_membership
HTML_list=HTML_list
Click_group_to_toggle_membership_of_selected_entries=Click_group_to_toggle_membership_of_selected_entries
-Use_EMACS_23_insertion_string=Use_EMACS_23_insertion_string
If_possible,_normalize_this_list_of_names_to_conform_to_standard_BibTeX_name_formatting=If_possible,_normalize_this_list_of_names_to_conform_to_standard_BibTeX_name_formatting
Could_not_open_%0=Could_not_open_%0
Unknown_import_format=Unknown_import_format
@@ -1727,7 +1702,6 @@ Five_stars=Five_stars
Four_stars=Four_stars
Help_on_special_fields=Help_on_special_fields
Keywords_of_selected_entries=Keywords_of_selected_entries
-Manage_content_selectors=Manage_content_selectors
Manage_keywords=Manage_keywords
No_priority_information=No_priority_information
No_rank_information=No_rank_information
@@ -1780,15 +1754,10 @@ Your_style_file_specifies_the_paragraph_format_'%0',_which_is_undefined_in_your_
Searching...=Searching...
You_have_selected_more_than_%0_entries_for_download._Some_web_sites_might_block_you_if_you_make_too_many_rapid_downloads._Do_you_want_to_continue?=You_have_selected_more_than_%0_entries_for_download._Some_web_sites_might_block_you_if_you_make_too_many_rapid_downloads._Do_you_want_to_continue?
Confirm_selection=Confirm_selection
-Unknown_DOI\:_'%0'.=Unknown_DOI\:_'%0'.
Add_{}_to_specified_title_words_on_search_to_keep_the_correct_case=Add_{}_to_specified_title_words_on_search_to_keep_the_correct_case
Import_conversions=Import_conversions
Please_enter_a_search_string=Please_enter_a_search_string
Please_open_or_start_a_new_database_before_searching=Please_open_or_start_a_new_database_before_searching
-An_error_occurred_while_fetching_from_ADS_(%0)\:=An_error_occurred_while_fetching_from_ADS_(%0)\:
-An_error_occurred_while_parsing_abstract=An_error_occurred_while_parsing_abstract
-Unknown_DiVA_entry\:_'%0'.=Unknown_DiVA_entry\:_'%0'.
-Get_BibTeX_entry_from_DiVA=Get_BibTeX_entry_from_DiVA
Log=Log
Canceled_merging_entries=Canceled_merging_entries
@@ -1845,7 +1814,6 @@ Move_to_group=Move_to_group
Clear_read_status=Clear_read_status
Convert_to_BibLatex_format_(for_example,_move_the_value_of_the_'journal'_field_to_'journaltitle')=Convert_to_BibLatex_format_(for_example,_move_the_value_of_the_'journal'_field_to_'journaltitle')
-Could_not_apply_changes.=Could_not_apply_changes.
Deprecated_fields=Deprecated_fields
Hide/show_toolbar=Hide/show_toolbar
No_read_status_information=No_read_status_information
@@ -1879,9 +1847,6 @@ Could_not_open_browser.=Could_not_open_browser.
Please_open_%0_manually.=Please_open_%0_manually.
The_link_has_been_copied_to_the_clipboard.=The_link_has_been_copied_to_the_clipboard.
-This_group_contains_all_entries._It_cannot_be_edited_or_removed.=This_group_contains_all_entries._It_cannot_be_edited_or_removed.
-
-No_entry_found_for_ISBN_%0_at_www.ebook.de=No_entry_found_for_ISBN_%0_at_www.ebook.de
Open_%0_file=Open_%0_file
Cannot_delete_file=Cannot_delete_file
@@ -1893,7 +1858,6 @@ Normalize_to_BibTeX_name_format=Normalize_to_BibTeX_name_format
Help_on_Name_Formatting=Help_on_Name_Formatting
Add_new_file_type=Add_new_file_type
-Follow_DOI_or_URL_link_and_try_to_locate_PDF_full_text_document=Follow_DOI_or_URL_link_and_try_to_locate_PDF_full_text_document
Left_entry=Left_entry
Right_entry=Right_entry
@@ -1913,7 +1877,6 @@ Modified_groups_tree=Modified_groups_tree
Removed_all_groups=Removed_all_groups
Accepting_the_change_replaces_the_complete_groups_tree_with_the_externally_modified_groups_tree.=Accepting_the_change_replaces_the_complete_groups_tree_with_the_externally_modified_groups_tree.
Select_export_format=Select_export_format
-Export_with_selected_format=Export_with_selected_format
Return_to_JabRef=Return_to_JabRef
Please_move_the_file_manually_and_link_in_place.=Please_move_the_file_manually_and_link_in_place.
Could_not_connect_to_%0=Could_not_connect_to_%0
@@ -1940,13 +1903,12 @@ Copy_BibTeX_key_and_title=Copy_BibTeX_key_and_title
File_rename_failed_for_%0_entries.=File_rename_failed_for_%0_entries.
To_set_up,_go_to=To_set_up,_go_to
Merged_BibTeX_source_code=Merged_BibTeX_source_code
-'%0'_is_not_a_valid_ADS_bibcode.='%0'_is_not_a_valid_ADS_bibcode.
Invalid_DOI\:_'%0'.=Invalid_DOI\:_'%0'.
should_start_with_a_name=should_start_with_a_name
should_end_with_a_name=should_end_with_a_name
unexpected_closing_curly_bracket=unexpected_closing_curly_bracket
unexpected_opening_curly_bracket=unexpected_opening_curly_bracket
-large_capitals_are_not_masked_using_curly_brackets_{}=large_capitals_are_not_masked_using_curly_brackets_{}
+capital_letters_are_not_masked_using_curly_brackets_{}=capital_letters_are_not_masked_using_curly_brackets_{}
should_contain_a_four_digit_number=should_contain_a_four_digit_number
should_contain_a_valid_page_number_range=should_contain_a_valid_page_number_range
Filled=Filled
@@ -1956,7 +1918,6 @@ Search_%0=Search_%0
Search_results_in_all_databases_for_%0=Search_results_in_all_databases_for_%0
Search_results_in_database_%0_for_%1=Search_results_in_database_%0_for_%1
Search_globally=Search_globally
-Search_in_all_open_databases=Search_in_all_open_databases
No_results_found.=No_results_found.
Found_%0_results.=Found_%0_results.
Advanced_search_active.=Advanced_search_active.
@@ -1966,8 +1927,6 @@ This_search_contains_entries_in_which_any_field_contains_the_regular_expression_
This_search_contains_entries_in_which_any_field_contains_the_term_<b>%0</b>=This_search_contains_entries_in_which_any_field_contains_the_term_<b>%0</b>
This_search_contains_entries_in_which=This_search_contains_entries_in_which
-An_autosave_file_was_found_for_this_database._This_could_indicate_that_JabRef_did_not_shut_down_cleanly_last_time_the_file_was_used.=An_autosave_file_was_found_for_this_database._This_could_indicate_that_JabRef_did_not_shut_down_cleanly_last_time_the_file_was_used.
-Note\:_A_full_text_search_is_currently_not_supported_for_%0=Note\:_A_full_text_search_is_currently_not_supported_for_%0
Unable_to_autodetect_OpenOffice/LibreOffice_installation._Please_choose_the_installation_directory_manually.=Unable_to_autodetect_OpenOffice/LibreOffice_installation._Please_choose_the_installation_directory_manually.
JabRef_no_longer_supports_'ps'_or_'pdf'_fields.<br>File_links_are_now_stored_in_the_'file'_field_and_files_are_stored_in_an_external_file_directory.<br>To_make_use_of_this_feature,_JabRef_needs_to_upgrade_file_links.<br><br>=JabRef_no_longer_supports_'ps'_or_'pdf'_fields.<br>File_links_are_now_stored_in_the_'file'_field_and_files_are_stored_in_an_external_file_directory.<br>To_make_use_of_this_feature,_JabRef_needs_to_upgrade_file_links.<br><br>
This_database_uses_outdated_file_links.=This_database_uses_outdated_file_links.
@@ -2007,7 +1966,6 @@ Resolve_duplicate_BibTeX_keys=Resolve_duplicate_BibTeX_keys
Save_all=Save_all
String_dialog,_add_string=String_dialog,_add_string
String_dialog,_remove_string=String_dialog,_remove_string
-Switch_preview_layout=Switch_preview_layout
Synchronize_files=Synchronize_files
Unabbreviate=Unabbreviate
should_contain_a_protocol=should_contain_a_protocol
@@ -2175,14 +2133,11 @@ OpenOffice/LibreOffice_integration=OpenOffice/LibreOffice_integration
incorrect_control_digit=incorrect_control_digit
incorrect_format=incorrect_format
-Expected_"%0"_to_contain_whitespace=Expected_"%0"_to_contain_whitespace
-Syntax_error_in_regular-expression_pattern=Syntax_error_in_regular-expression_pattern
Copy_version_to_clipboard=Copy_version_to_clipboard
Copied_version_to_clipboard=Copied_version_to_clipboard
BibTeX_key=BibTeX_key
Message=Message
-
Decryption_not_supported.=Decryption_not_supported.
Cleared_'%0'_for_%1_entries=Cleared_'%0'_for_%1_entries
@@ -2253,7 +2208,6 @@ Database=Database
User=User
Connect=Connect
Connection_error=Connection_error
-Driver_error=Driver_error
Connection_to_%0_server_established.=Connection_to_%0_server_established.
Required_field_"%0"_is_empty.=Required_field_"%0"_is_empty.
%0_driver_not_available.=%0_driver_not_available.
@@ -2272,7 +2226,12 @@ Local_version\:_%0=Local_version\:_%0
Shared_version\:_%0=Shared_version\:_%0
Please_merge_the_shared_entry_with_yours_and_press_"Merge_entries"_to_resolve_this_problem.=Please_merge_the_shared_entry_with_yours_and_press_"Merge_entries"_to_resolve_this_problem.
Canceling_this_operation_will_leave_your_changes_unsynchronized._Cancel_anyway?=Canceling_this_operation_will_leave_your_changes_unsynchronized._Cancel_anyway?
-The_BibEntry_you_currently_work_on_has_been_deleted_on_the_shared_side._Hit_"Keep"_to_recover_the_entry.=The_BibEntry_you_currently_work_on_has_been_deleted_on_the_shared_side._Hit_"Keep"_to_recover_the_entry.
+Shared_entry_is_no_longer_present=Shared_entry_is_no_longer_present
+The_BibEntry_you_currently_work_on_has_been_deleted_on_the_shared_side.=The_BibEntry_you_currently_work_on_has_been_deleted_on_the_shared_side.
+You_can_restore_the_entry_using_the_"Undo"_operation.=You_can_restore_the_entry_using_the_"Undo"_operation.
+Remember_password?=Remember_password?
+You_are_already_connected_to_a_database_using_entered_connection_details.=You_are_already_connected_to_a_database_using_entered_connection_details.
+
Cannot_cite_entries_without_BibTeX_keys._Generate_keys_now?=Cannot_cite_entries_without_BibTeX_keys._Generate_keys_now?
New_technical_report=New_technical_report
@@ -2303,3 +2262,53 @@ Opens_JabRef's_blog=Opens_JabRef's_blog
Opens_JabRef's_website=Opens_JabRef's_website
Opens_a_link_where_the_current_development_version_can_be_downloaded=Opens_a_link_where_the_current_development_version_can_be_downloaded
See_what_has_been_changed_in_the_JabRef_versions=See_what_has_been_changed_in_the_JabRef_versions
+Referenced_BibTeX_key_does_not_exist=Referenced_BibTeX_key_does_not_exist
+Finished_downloading_full_text_document_for_entry_%0.=Finished_downloading_full_text_document_for_entry_%0.
+Full_text_document_download_failed_for_entry_%0.=Full_text_document_download_failed_for_entry_%0.
+Look_up_full_text_documents=Look_up_full_text_documents
+You_are_about_to_look_up_full_text_documents_for_%0_entries.=You_are_about_to_look_up_full_text_documents_for_%0_entries.
+last_four_nonpunctuation_characters_should_be_numerals=last_four_nonpunctuation_characters_should_be_numerals
+shared=shared
+should_contain_an_integer_or_a_literal=should_contain_an_integer_or_a_literal
+should_have_the_first_letter_capitalized=should_have_the_first_letter_capitalized
+
+ID=ID
+ID_type=ID_type
+ID-based_entry_generator=ID-based_entry_generator
+Fetcher_'%0'_did_not_find_an_entry_for_id_'%1'.=Fetcher_'%0'_did_not_find_an_entry_for_id_'%1'.
+
+Select_first_entry=Select_first_entry
+Select_last_entry=Select_last_entry
+
+Invalid_ISBN\:_'%0'.=Invalid_ISBN\:_'%0'.
+should_be_an_integer_or_normalized=should_be_an_integer_or_normalized
+should_be_normalized=should_be_normalized
+
+Empty_search_ID=Empty_search_ID
+The_given_search_ID_was_empty.=The_given_search_ID_was_empty.
+Copy_BibTeX_key_and_link=Copy_BibTeX_key_and_link
+empty_BibTeX_key=empty_BibTeX_key
+BibLaTeX_field_only=BibLaTeX_field_only
+
+Error_while_generating_fetch_URL=Error_while_generating_fetch_URL
+Error_while_parsing_ID_list=Error_while_parsing_ID_list
+Unable_to_get_PubMed_IDs=Unable_to_get_PubMed_IDs
+Backup_found=Backup_found
+A_backup_file_for_'%0'_was_found.=A_backup_file_for_'%0'_was_found.
+This_could_indicate_that_JabRef_did_not_shut_down_cleanly_last_time_the_file_was_used.=This_could_indicate_that_JabRef_did_not_shut_down_cleanly_last_time_the_file_was_used.
+Do_you_want_to_recover_the_database_from_the_backup_file?=Do_you_want_to_recover_the_database_from_the_backup_file?
+Firstname_Lastname=Firstname_Lastname
+
+Recommended_for_%0=Recommended_for_%0
+This_might_be_caused_by_reaching_the_traffic_limitation_of_Google_Scholar_(see_'Help'_for_details).=This_might_be_caused_by_reaching_the_traffic_limitation_of_Google_Scholar_(see_'Help'_for_details).
+
+Problem_downloading_from_%1=Problem_downloading_from_%1
+
+File_directory_pattern=File_directory_pattern
+Update_with_bibliographic_information_from_the_web=Update_with_bibliographic_information_from_the_web
+
+Could_not_find_any_bibliographic_information.=Could_not_find_any_bibliographic_information.
+BibTeX_key_%0_deviates_from_generated_key_%1=BibTeX_key_%0_deviates_from_generated_key_%1
+DOI_%0_is_invalid=DOI_%0_is_invalid
+
+Jump_to_entry=Jump_to_entry
diff --git a/src/main/resources/l10n/JabRef_es.properties b/src/main/resources/l10n/JabRef_es.properties
index c54b603..e872020 100644
--- a/src/main/resources/l10n/JabRef_es.properties
+++ b/src/main/resources/l10n/JabRef_es.properties
@@ -1,763 +1,1396 @@
#!
-#!_created/edited_by_Popeye_version_0.55_(https\://github.com/koppor/popeye)
-#!_encoding:UTF-8
+#! created/edited by Popeye version 0.55 (github.com/JabRef/popeye)
+#! encoding:UTF-8
+
%0_contains_the_regular_expression_<b>%1</b>=%0_contiene_la_expresión_regular_<b>%1</b>
+
%0_contains_the_term_<b>%1</b>=%0%nbsp;contiene_el_término_<b>%1</b>
+
%0_doesn't_contain_the_regular_expression_<b>%1</b>=%0_no_contiene_la_Expresión_Regular_<b>&1</b>
+
%0_doesn't_contain_the_term_<b>%1</b>=%0_no_contiene_el_término_<b>%1</b>
+
%0_export_successful=%0_exportado_con_éxito
+
%0_matches_the_regular_expression_<b>%1</b>=%0_coincidencias_con_la_Expresión_Regular_<b>%1</b>
+
%0_matches_the_term_<b>%1</b>=%0_coincidencias_con_el_término_<b>%1</b>
-<field_name>=<nombre_del_campo>
+
<HTML>Could_not_find_file_'%0'<BR>linked_from_entry_'%1'</HTML>=<HTML>No_se_encuentra_el_archivo_'%0'<BR>enlazado_desde_la_entrada_'%1'</HTML>
+
<select>=<seleccionar>
-<select_word>=<seleccionar_palabra>
+
Abbreviate_journal_names_of_the_selected_entries_(ISO_abbreviation)=Abreviar_nombres_de_revistas_de_las_entradas_seleccionadas_(Abreviatura_ISO)
Abbreviate_journal_names_of_the_selected_entries_(MEDLINE_abbreviation)=Abreviar_nombres_de_revistas_de_las_entradas_seleccionadas_(Abreviatura_MEDLINE)
+
Abbreviate_names=Abreviar_nombres
Abbreviated_%0_journal_names.=Se_han_abreviado_%0_nombres_de_revistas
+
Abbreviation=Abreviatura
+
About_JabRef=Acerca_de_JabRef
+
Abstract=Resumen
+
Accept=Aceptar
+
Accept_change=Aceptar_cambio
+
Action=Acción
+
Add=Añadir
-Add_a_(compiled)_custom_ImportFormat_class_from_a_class_path.=Añadir_una_clase_personalizada_(compilada)_ImportFormat_desde_una_classpath.
+
+Add_a_(compiled)_custom_Importer_class_from_a_class_path.=Añadir_una_clase_personalizada_(compilada)_Importer_desde_una_classpath.
The_path_need_not_be_on_the_classpath_of_JabRef.=La_ruta_no_debe_estar_en_la_classpath_de_JabRef.
-Add_a_(compiled)_custom_ImportFormat_class_from_a_ZIP-archive.=Añadir_una_clase_personalizada_(compilada)_ImportFormat_desde_un_archivo_ZIP.
+
+Add_a_(compiled)_custom_Importer_class_from_a_ZIP-archive.=Añadir_una_clase_personalizada_(compilada)_Importer_desde_un_archivo_ZIP.
The_ZIP-archive_need_not_be_on_the_classpath_of_JabRef.=El_archivo_ZIP_no_tiene_por_qué_estar_en_la_classpath_de_JabRef.
+
Add_entry_selection_to_this_group=Añadir_selección_de_entrada_al_grupo
+
Add_from_folder=Añadir_desde_carpeta
+
Add_from_JAR=Añadir_desde_JAR
+
add_group=añadir_grupo
+
Add_group=Añadir_grupo
+
Add_new=Añadir_nuevo
+
Add_subgroup=Añadir_subgrupo
+
Add_to_group=Añadir_a_grupo
+
Added_group_"%0".=Grupo_"%0"_añadido
+
Added_new=Nuevo_añadido
+
Added_string=Cadena_añadida
+
Additionally,_entries_whose_<b>%0</b>_field_does_not_contain_<b>%1</b>_can_be_assigned_manually_to_this_group_by_selecting_them_then_using_either_drag_and_drop_or_the_context_menu._This_process_adds_the_term_<b>%1</b>_to_each_entry's_<b>%0</b>_field._Entries_can_be_removed_manually_from_this_group_by_selecting_them_then_using_the_context_menu._This_process_removes_the_term_<b>%1</b>_from_each_entry's_<b>%0</b>_field.=Adicionalmente,_entradas_cuyo_campo_<b>%0</b>_no_contenga_<b>%1</b>_pue [...]
+
Advanced=Avanzado
All_entries=Todas_las_entradas
All_entries_of_this_type_will_be_declared_typeless._Continue?=Todas_las_entradas_de_este_tipo_serán_declaradas_Sin_Tipo._¿Continuar?
+
All_fields=Todos_los_campos
+
All_subgroups_(recursively)=Todos_los_subgrupos(Recursivamente)
-An_exception_occurred_while_accessing_'%0'=Ocurrió_una_Excepción_mientras_se_accedía_a_'%0'
+
+Always_reformat_BIB_file_on_save_and_export=Siempre_reformatear_el_fichero_BIB_al_guardar_y_exportar
+
A_SAX_exception_occurred_while_parsing_'%0'\:=Ocurrió_una_Excepción_SAX_mientras_se_analizaba_la_sintaxis_de_'%0'\:
+
and=y
and_the_class_must_be_available_in_your_classpath_next_time_you_start_JabRef.=y_la_clase_debe_estar_disponible_en_su_classpath_la_próxima_vez_que_inicie_JabRef.
+
any_field_that_matches_the_regular_expression_<b>%0</b>=cualquier_campo_que_satisfaga_la_Expresión_Regular_<b>%0</b>
+
Appearance=Aspecto
+
Append=Añadir
Append_contents_from_a_BibTeX_database_into_the_currently_viewed_database=Agregar_contenidos_desde_una_base_de_datos_BibTeX_a_la_base_de_datos_actual
+
Append_database=Agregar_base_de_datos
+
Append_the_selected_text_to_BibTeX_field=Agregar_el_texto_seleccionado_a_la_clave_BibTeX
Application=Aplicación
+
Apply=Aplicar
+
Arguments_passed_on_to_running_JabRef_instance._Shutting_down.=Argumentos_pasados_a_una_instancia_JabRef_en_ejecución._Cerrando_el_programa.
+
Assign_entry_selection_exclusively_to_this_group=Asignar_la_seleccion_de_entradas_exclusivamente_a_este_grupo
+
Assign_new_file=Asignar_nuevo_archivo
+
Assign_the_original_group's_entries_to_this_group?=¿Asignar_las_entradas_del_grupo_original_a_este_grupo?
+
Assigned_%0_entries_to_group_"%1".=Se_han_asignado_%0_entradas_al_grupo_"%1"
+
Assigned_1_entry_to_group_"%0".=Asignada_una_entrada_al_grupo_"%0".
+
Attach_URL=Adjuntar_URL
+
Attempt_to_automatically_set_file_links_for_your_entries._Automatically_setting_works_if_a_file_in_your_file_directory<BR>or_a_subdirectory_is_named_identically_to_an_entry's_BibTeX_key,_plus_extension.=Intentar_establecer_automáticamente_archivo_enlaces_para_sus_entradas._El_establecimiento_automático_funciona_si_un_archivo_en_la_carpeta_archivo_o_un_subdirectrio_<BR>_tiene_nombre_idéntico_a_una_entrada_BibTeX_más_la_extensión.
+
Auto=Auto
+
Autodetect_format=Autodetectar_formato
+
Autogenerate_BibTeX_keys=Autogenerar_claves_BibTeX
+
Autolink_files_with_names_starting_with_the_BibTeX_key=Autoenlazar_con_nombres_comenzando_por_la_clave_BibTeX
+
Autolink_only_files_that_match_the_BibTeX_key=Autoenlazar_sólo_archivos_cuyo_nombre_coincida_con_la_clave_BibTeX
+
Automatically_create_groups=Crear_grupos_automáticamente
+
Automatically_create_groups_for_database.=Crear_grupos_para_base_de_datos_automáticamente
+
Automatically_created_groups=Grupos_automáticamente_creados
+
Automatically_remove_exact_duplicates=Eliminar_automáticamente_duplicados_exactos
+
Allow_overwriting_existing_links.=Permitir_sobreescribir_enlaces_existentes.
+
Do_not_overwrite_existing_links.=No_sobreescribir_enlaces_existentes.
+
AUX_file_import=Importar_archivo_AUX
+
Available_export_formats=Formatos_para_exportación_disponibles
+
Available_BibTeX_fields=Campos_Disponibles
+
Available_import_formats=Formatos_disponibles_para_importar
+
Background_color_for_optional_fields=Color_de_fondo_campos_opcionales
+
Background_color_for_required_fields=Color_de_fondo_campos_requeridos
+
Backup_old_file_when_saving=Hacer_copia_de_respaldo_del_archivo_antiguo_al_grabar
+
BibTeX_key_is_unique.=La_clave_BibTeX_es_única
-BibTeX_source=Origen_BibTeX
+
+%0_source=Origen_%0
+
Broken_link=Enlace_roto
+
Browse=Explorar
+
by=por
+
Cancel=Cancelar
+
Cannot_add_entries_to_group_without_generating_keys._Generate_keys_now?=No_se_pueden_añadir_entradas_a_un_grupo_sin_generar_claves._¿Generar_claves_ahora?
+
Cannot_merge_this_change=No_se_puede_incorporar_este_cambio
+
Cannot_move_group_"%0"_down.=No_se_puede_mover_el_grupo_"%0"_hacia_abajo.
+
Cannot_move_group_"%0"_left.=No_se_puede_mover_el_grupo_"%0"_hacia_la_izquierda
+
Cannot_move_group_"%0"_right.=No_se_puede_mover_el_grupo_"%0"_hacia_la_derecha.
+
Cannot_move_group_"%0"_up.=No_se_puede_mover_el_grupo_"%0"_hacia_arriba.
+
case_insensitive=insensible_al_uso_de_mayúsculas/minúsculas
+
case_sensitive=sensible_al_uso_de_mayúsculas/minúsculas
+
Case_sensitive=Sensible_al_uso_de_mayúsculas/minúsculas
+
change_assignment_of_entries=Cambiar_asignación_de_entradas
+
Change_case=Cambiar_mayúsculas/minúsculas
+
Change_entry_type=Cambiar_tipo_de_entrada
Change_file_type=Cambiar_tipo_de_archivo
+
+
Change_of_Grouping_Method=Cambiar_método_de_agrupamiento
+
change_preamble=cambiar_preámbulo
+
Change_table_column_and_General_fields_settings_to_use_the_new_feature=Cambiar_los_ajustes_de_columna_de_tabla_y_campos_generales_para_usar_la_nueva_caraterística
+
Changed_font_settings=Ajustes_de_tipo_de_letra_cambiados
+
Changed_language_settings=Ajustes_de_lenguaje_cambiados
+
Changed_look_and_feel_settings=Ajustes_de_aspecto_cambiados
+
Changed_preamble=Preámbulo_cambiado
+
Characters_to_ignore=Caracteres_a_ignorar
+
Check_existing_file_links=Comprobar_archivo_enlaces_existentes
+
Check_links=Comprobar_enlaces
+
Choose_the_URL_to_download.=Seleccionar_URL_a_descargar.
Cite_command=Comando_Citar
+
Class_name=Nombre_de_clase
+
Clear=Limpiar
+
Clear_fields=Limpiar_campos
+
Close=Cerrar
Close_others=Cerrar_otros
Close_all=Cerrar_todos
+
Close_dialog=Cerrar_diálogo
+
Close_the_current_database=Cerrar_la_base_de_datos_actual
+
Close_window=Cerrar_ventana
+
Closed_database=Base_de_datos_cerrada
+
Collapse_subtree=Colapsar_subárbol
+
Color_codes_for_required_and_optional_fields=Códigos_de_color_para_campos_requeridos_y_opcionales
+
Color_for_marking_incomplete_entries=Color_para_marcar_entradas_incompletas
+
Column_width=Ancho_de_columna
+
Command_line_id=Id_de_línea_de_comando
-Connect=Conectar
+
+
Contained_in=Contenido_en
+
Content=Contenido
+
Copied=Copiado
+
Copied_cell_contents=Contenido_de_celda_copiado
+
Copied_key=Clave_copiada
+
Copied_keys=Claves_copiadas
+
Copy=Copiar
+
Copy_BibTeX_key=Copiar_clave_BibTeXt
Copy_file_to_file_directory=Copiar_archivos_a_carpeta
+
Copy_to_clipboard=Copiar_al_portapapeles
+
Could_not_call_executable=No_se_puede_llamar_al_ejecutable
Could_not_connect_to_Vim_server._Make_sure_that_Vim_is_running<BR>with_correct_server_name.=No_se_puede_conectar_con_el_servidor_Vim._Asegúrese_de_que_Vim_está_corriendo<BR>_con_el_nombre_de_servidor_correcto.
+
Could_not_export_file=No_se_puede_exportar_el_archivo
+
Could_not_export_preferences=No_se_pueden_exportar_las_preferencias
+
Could_not_find_a_suitable_import_format.=No_se_encuentra_un_formato_de_importación_apropiado.
Could_not_import_preferences=No_se_pueden_importar_las_preferencias
+
Could_not_instantiate_%0=No_se_puede_instanciar_%0
Could_not_instantiate_%0_%1=No_se_puede_instanciar_%0_%1
Could_not_instantiate_%0._Have_you_chosen_the_correct_package_path?=No_se_puede_instanciar_%0._¿Ha_escogido_la_ruta_del_paquete_correctamente?
Could_not_open_link=No_se_puede_abrir_el_enlace
+
Could_not_print_preview=No_se_puede_imprimir_la_vista_previa
+
Could_not_run_the_'vim'_program.=No_se_puede_ejecutar_Vim
+
Could_not_save_file.=No_se_puede_guardar_el_archivo.
Character_encoding_'%0'_is_not_supported.=La_codificaciónd_de_caracteres_'%0'_no_está_soportada.
+
Created_groups.=Grupos_creados.
+
crossreferenced_entries_included=entradas_de_referencia_cruzada_incluídas
+
Current_content=Contenido_actual
+
Current_value=Valor_actual
+
Custom_entry_types=Tipos_de_entrada_personalizados
+
Custom_entry_types_found_in_file=Se_han_encontrado_tipos_de_entrada_personalizados_en_el_archivo
+
Customize_entry_types=Tipos_de_entrada_personalizados
+
Customize_key_bindings=Pesonalizar_combinaciones_de_tecla
+
Cut=Cortar
+
cut_entries=Cortar_entradas
+
cut_entry=Cortar_entrada
+
+
Database_encoding=Codificación_de_la_Base_de_Datos
+
Database_properties=Propiedades_de_la_Base_de_Datos
Database_type=
+
Date_format=Formato_de_fecha
+
Default=Por_defecto
+
Default_encoding=Codificación_por_defecto
+
Default_grouping_field=Campo_de_agrupación_por_defecto
+
Default_look_and_feel=Aspecto_por_defecto
+
Default_pattern=Patrón_por_defecto
+
Default_sort_criteria=Criterio_de_ordenación_por_defecto
Define_'%0'=Definir_'%0'
+
Delete=Borrar
+
Delete_custom_format=Borrar_formato_por_defecto
+
delete_entries=borrar_entradas
+
Delete_entry=Borrar_entrada
+
delete_entry=borrar_entrada
+
Delete_multiple_entries=Borrar_entradas_múltiples
+
Delete_rows=Borrar_filas
+
Delete_strings=Borrar_cadenas
+
Deleted=Borrado
+
+Delete_local_file=Eliminar_archivo_local
+
Delimit_fields_with_semicolon,_ex.=Delimitar_campos_con_punto_y_coma
+
Descending=Descendiente
+
Description=Descripción
+
Deselect_all=Deseleccionar_todos
Deselect_all_duplicates=Deseleccionar_todos_los_duplicados
+
Disable_this_confirmation_dialog=Deshabilitar_este_diálogo_de_confirmación
+
Display_all_entries_belonging_to_one_or_more_of_the_selected_groups.=Mostrar_todas_las_entradas_pertenecientes_a_uno_o_más_de_los_grupos_seleccionados.
+
Display_all_error_messages=Mostrar_todos_los_mensajes_de_error
+
Display_help_on_command_line_options=Mosrar_ayuda_en_las_opciones_de_línea_de_comando
+
Display_only_entries_belonging_to_all_selected_groups.=Mostrar_sólo_entradas_pertenecientes_a_todos_los_grupos_seleccionados.
Display_version=Mostrar_versión
+
Displaying_no_groups=No_se_muestran_grupos
+
Do_not_abbreviate_names=No_abreviar_nombres
+
Do_not_automatically_set=No_establecer_automáticamente
+
Do_not_import_entry=No_importar_entrada
+
Do_not_open_any_files_at_startup=No_abrir_ningún_archivo_al_arrancar
+
Do_not_overwrite_existing_keys=No_sobreescribir_claves_existentes
Do_not_show_these_options_in_the_future=No_mostrar_estas_ospciones_en_el_futuro
+
Do_not_wrap_the_following_fields_when_saving=No_envolver_los_siguientes_campos_al_guardar
Do_not_write_the_following_fields_to_XMP_Metadata\:=No_escribir_los_campos_a_continuación_a_los_metadatos_XMP
+
Do_you_want_JabRef_to_do_the_following_operations?=¿Quiere_que_JabRef_efectúe_las_siguientes_operaciones?
+
+Donate_to_JabRef=Donar_a_JabRef
+
Down=Abajo
+
Download=Descargar
+
Download_file=Descargar_archivo
+
Downloading...=Descargando...
Drop_%0=Soltar_%0
+
duplicate_removal=eliminación_de_duplicados
+
Duplicate_string_name=Nombre_de_cadena_duplicado
+
Duplicates_found=Se_han_encontrado_duplicados
+
Dynamic_groups=Grupos_dinámicos
+
Dynamically_group_entries_by_a_free-form_search_expression=Agrupar_entradas_dinámicamente_por_una_expresión_de_búsqueda_libre
+
Dynamically_group_entries_by_searching_a_field_for_a_keyword=Agrupar_entradas_dinámicamente_buscando_palabra_clave_en_campo
+
Each_line_must_be_on_the_following_form=Cada_línea_debe_tener_la_siguiente_forma
+
Edit=Editar
+
Edit_custom_export=Editar_exportación_personalizada
Edit_entry=Editar_entrada
Save_file=Editar_enlace_a_archivo
Edit_file_type=Editar_tipo_de_archivo
+
Edit_group=Editar_grupo
+
Edit_journal=Editar_revista
+
Edit_preamble=Editar_preámbulo
Edit_strings=Editar_cadenas
Editor_options=Opciones_del_editor
+
Empty_BibTeX_key=Clave_BibTeXt_vacía
+
Grouping_may_not_work_for_this_entry.=El_agrupamiento_puede_no_funcionar_para_esta_entrada.
+
empty_database=base_de_datos_vacía
Enable_word/name_autocompletion=Permitir_autocompletado_de_palabra/nombre
+
Enter_URL=Introducir_URL
+
Enter_URL_to_download=Introducir_URL_a_descargar
+
entries=entradas
+
Entries_cannot_be_manually_assigned_to_or_removed_from_this_group.=Las_entradas_no_se_pueden_asignar_o_eliminar_manualmente_de_este_grupo.
+
Entries_exported_to_clipboard=Entradas_exportadas_a_portapapeles
+
+
entry=entrada
+
Entry_editor=Editor_de_entrada
+
Entry_preview=Vista_previa_de_la_entrada
+
Entry_table=Tabla_de_entrada
+
Entry_table_columns=Columnas_de_la_tabla_de_entrada
+
Entry_type=Tipo_de_entrada
+
Entry_type_names_are_not_allowed_to_contain_white_space_or_the_following_characters=No_se_permiten_espacios_ni_los_caracteres_siguientes_en_el_nombre_de_tipo_de_entrada
+
Entry_types=Tipos_de_entrada
+
Error=Error
Error_exporting_to_clipboard=Error_exportando_al_portapapeles
+
Error_occurred_when_parsing_entry=Ocurrió_un_error_al_analizar_la_entrada
+
Error_opening_file=Error_al_abrir_el_archivo
+
Error_setting_field=Error_estableciendo_el_campo
Error_while_writing=Error_al_escribir
Error_writing_to_%0_file(s).=Error_escribiendo_%0_archivo(s).
+
+
Exceptions=Excepciones
+
Existing_file=Fichero_existente
+
'%0'_exists._Overwrite_file?='%0'_existe._¿Sobreescribir?
Overwrite_file?=¿Sobreescribir?
+
Expand_subtree=Expandir_subárbol
+
Export=Exportar
+
Export_name=Exportar_nombre
+
Export_preferences=Exportar_preferencias
+
Export_preferences_to_file=Exportar_preferencias_a_archivo
+
Export_properties=Exportar_propiedades
+
Export_to_clipboard=Exportar_al_portapapeles
+
Exporting=Exportando
Extension=Extensión
+
External_changes=Cambios_externos
+
External_file_links=Enlaces_a_archivos_externos
+
External_files=Archivos_externos
+
External_programs=Programas_externos
+
External_viewer_called=Se_ha_lanzado_el_visor_externo
+
Fetch=Recuperar
+
Field=Campo
+
field=campo
+
Field_name=Nombre_del_campo
Field_names_are_not_allowed_to_contain_white_space_or_the_following_characters=No_se_permiten_los_espacios_o_los_siguientes_caracteres_en_los_nombres_de_campo
+
Field_to_filter=Filtro_a_partir_de_campo
+
Field_to_group_by=Agrupar_a_partir_de_campo
+
File=Archivo
+
file=archivo
File_'%0'_is_already_open.=El_archivo_'%0'_ya_está_abierto.
+
File_'%0'_not_found=No_se_encuentra_el_archivo_'%'
+
File_changed=Fichero_cambiado
File_directory_is_'%0'\:=La_carpeta_de_archivos_es_'%0'\:
+
File_directory_is_not_set_or_does_not_exist\!=¡La_carpeta_de_archivos_no_etá_establecida_o_no_existe\!
File_exists=El_archivo_ya_existe
+
File_has_been_updated_externally._What_do_you_want_to_do?=El_archivo_ha_sido_editado
+
File_not_found=No_se_ha_encontrado_el_archivo
File_type=Tipo_de_archivo
+
File_updated_externally=Archivo_actualizado_externamente
+
filename=nombre_de_archivo
+
Files_opened=Archivos_abiertos
+
Filter=Filtro
+
Finished_automatically_setting_external_links.=Se_ha_finalizado_la_configuración_automática_de_enlaces_esternos.
+
Finished_synchronizing_file_links._Entries_changed\:_%0.=Se_ha_finalizado_la_sincronización_de_archivo_enlaces._Se_cambiaron_\:_%0_entradas.
Finished_writing_XMP-metadata._Wrote_to_%0_file(s).=Se_ha_finalizado_la_escritura_de_los_metadtos_XMP._Se_escribió_en_%0_archivo(s).
Finished_writing_XMP_for_%0_file_(%1_skipped,_%2_errors).=Se_finalizó_la_escritura_XMP_en_archivo_%0_(%1_evitados,_%2_errores).
+
First_select_the_entries_you_want_keys_to_be_generated_for.=En_primer_lugar,_seleccione_las_entradas_para_las_que_desea_generar_claves
+
Fit_table_horizontally_on_screen=Ajustar_la_tabla_al_ancho_de_pantalla
+
Float=Flotar
Float_marked_entries=Flotar_entradas_marcadas
+
Font_family=Tipo_de_letra
+
Font_preview=Vista_previa_del_tipo_de_letra
+
Font_size=Tamaño_de_tipo_de_letra
+
Font_style=Estilo_de_tipo_de_letra
+
Font_selection=Selector_tipo_de_letra
+
for=para
+
Format_of_author_and_editor_names=Formato_de_los_nombres_de_autor_y_editor
Format_string=Formatear_cadena
+
Format_used=Formato_usado
Formatter_name=Nombre_del_formateador
+
found_in_AUX_file=encontrado_en_archivo_AUX
+
Full_name=Nombre_completo
+
General=General
+
General_fields=Generar_campos
+
Generate=Generar
+
Generate_BibTeX_key=Generar_clave_BibTeX
+
Generate_keys=Generar_claves
+
Generate_keys_before_saving_(for_entries_without_a_key)=Generar_claves_antes_de_guardar_(para_entradas_sin_clave)
Generate_keys_for_imported_entries=Generar_claves_para_claves_importadas
+
Generate_now=Generar_ahora
+
Generated_BibTeX_key_for=Generar_clabe_BibTeX_para
+
Generating_BibTeX_key_for=Generarando_clave_BibTeX_para
+Get_fulltext=
Grab=Coger
+
Gray_out_entries_not_in_group_selection=Poner_en_gris_entradas_que_no_estén_en_el_grupo_de_selección
+
Gray_out_non-hits=Poner_en_gris_los_no_encontrados
+
Groups=Grupos
+
Have_you_chosen_the_correct_package_path?=¿Ha_escogido_la_ruta_de_paquetes_correcta?
+
Help=Ayuda
+
Help_on_groups=Ayuda_sobre_grupos
+
Help_on_key_patterns=Ayuda_sobre_patrones_de_teclas
Help_on_regular_expression_search=Ayuda_sobre_búsqueda_mediante_expresión_regular
+
Hide_non-hits=Esconder_los_no-aciertos
+
Hierarchical_context=Contexto_jerárquico
+
Highlight=Resaltar
Highlight_groups_matching_all_selected_entries=Resaltar_grupos_donde_coincidan_todas_las_entradas_seleccionadas
Highlight_groups_matching_any_selected_entry=Resaltar_grupos_donde_coincida_cualquier_entrada_seccionada
+Disable_highlight_groups_matching_entries=Deshabilitar_el_resaltado_de_grupos_en_que_coincidad_entradas
+
Highlight_overlapping_groups=Resaltar_grupos_solapados
+
Hint\:_To_search_specific_fields_only,_enter_for_example\:<p><tt>author\=smith_and_title\=electrical</tt>=Pista_\:_Para_buscar_sólo_campos_específicos,_introduzca,_por_ejemplo,_\:_<p><tt>author\=smith_and_title\=electrical</tt>
+
HTML_table=Tabla_HTML
HTML_table_(with_Abstract_&_BibTeX)=Tabla_HTML_(con_Abstract_BibTeX)
Icon=Icono
+
Ignore=Ignorar
+
Immediate_subgroups=Subgrupos_inmediatos
+
Import=Importar
+
Import_and_keep_old_entry=Importar_y_conservar_entrada_antigua
+
Import_and_remove_old_entry=Importar_y_eliminar_antigua_entrada
+
Import_entries=Importar_entradas
+
Import_failed=Falló_la_importación
+
Import_file=Importar_archivo
+
Import_group_definitions=Importar_definiciones_de_grupo
+
Import_name=Importar_nombre
+
Import_preferences=Importar_preferencias
+
Import_preferences_from_file=Importar_preferencias_desde_archivo
+
Import_strings=Importar_cadenas
+
Import_to_open_tab=Importar_en_pestaña_abierta
-Import_word_selector_definitions=Importar_definiciones_de_selector_de_palabras
+
Imported_entries=Importar_entradas
+
Imported_from_database=Importado_desde_base_de_datos
-ImportFormat_class=Importar_formato_de_clase
+
+Importer_class=Importar_formato_de_clase
+
Importing=Importando
+
Importing_in_unknown_format=Importando_en_formato_desconocido
+
Include_abstracts=Incluir_abstracts
Include_entries=Incluir_entradas
+
Include_subgroups\:_When_selected,_view_entries_contained_in_this_group_or_its_subgroups=Incluir_subgrupos\:_Ver_entradas_contenidas_es_este_grupo_o_sus_subgrupos_cuando_estén_seleccionadas.
+
Independent_group\:_When_selected,_view_only_this_group's_entries=Grupo_independiente\:_ver_sólo_las_entradas_de_este_grupo_cuando_esté_seleccionado.
+
Initially_show_groups_tree_expanded=Mostrar_inicialmente_árbol_de_grupos_extendido
+
Work_options=Opciones_de_trabajo
-Input_error=Error_de_entrada
+
Insert=Insertar
+
Insert_rows=Insertar_filas
Intersection=Intersección
+
Invalid_BibTeX_key=Clave_BibTeX_inválida
+
Invalid_date_format=Formato_de_fecha_no_válido
+
Invalid_URL=URL_no_válida
+
Inverted=Invertido
+
ISO_abbreviation=Abreviatura_ISO
+
Online_help=
+
JabRef_preferences=Preferencias_de_JabRef
+
Journal_abbreviations=Abreviaturas_de_publicaciones
+
Journal_list_preview=Vista_previa_de_la_lista_de_publicaciones
+
Journal_name=Nombre_de_la_revista
+
Keep=Mantener
+
Keep_both=Mantener_ambos
+
Key_bindings=Combinaciones_de_teclas
+
Key_bindings_changed=Combinaciones_de_teclas_cambiadas
+
Key_generator_settings=Ajustes_del_generador_de_claves
+
Key_pattern=Patrón_de_clave
+
keys_in_database=claves_en_la_base_de_datos
+
Keyword=Palabra_clave
+
Label=Etiqueta
+
Language=Idioma
+
Last_modified=Modificado_por_última_vez
+
LaTeX_AUX_file=Archivo_LaTeX_AUX
Leave_file_in_its_current_directory=Dejar_el_archivo_en_su_directorio_actual
+
Left=Dejar
Level=
+
Limit_to_fields=Limitar_a_los_campos
+
Limit_to_selected_entries=Limitar_a_las_entradas_seleccionadas
+
Link=Enlace
Link_local_file=Enlazar_archivo_local
Link_to_file_%0=Enlazar_al_archivo_%0
+
Listen_for_remote_operation_on_port=Escuchar_para_operación_remota_en_el_puerto
Load_and_Save_preferences_from/to_jabref.xml_on_start-up_(memory_stick_mode)=Cargar_y_guardar_preferencias_desde/a_jabref.xml_al_arrancar_(modo_lápiz_de_memoria)
+
Look_and_feel=Aspecto
Main_file_directory=Carpeta_del_archivo_principal
+
Main_layout_file=Archivo_de_configuración_principal
-Manage=Administrar
+
Manage_custom_exports=Administrar_esportaciones_personalizadas
+
Manage_custom_imports=Administrar_importaciones_personalizadas
Manage_external_file_types=Administrar_tipos_de_archivo_externos
+
Manage_journal_abbreviations=Administrar_abreviaturas_de_revistas
+
Mark_entries=Marcar_entradas
+
Mark_entry=Marcar_entrada
+
Mark_new_entries_with_addition_date=Marcar_nuevas_entradas_con_fecha_de_incorporación
+
Mark_new_entries_with_owner_name=Marcar_nuevas_entradas_con_nombre_de_propietario
+
Memory_stick_mode=Modo_lápiz_de_memoria
+
Menu_and_label_font_size=Tamaño_de_tipo_de_letra_para_menú_y_etiquetas
+
Merged_external_changes=Cambios_externos_incorporados
+
Messages=Mensajes
+
Modification_of_field=Modificación_de_campo
+
Modified_group_"%0".=Se_ha_modificado_el_grupo_"%0".
+
Modified_groups=Grupos_modificados
+
Modified_string=Cadena_modificada
+
Modify=Modificar
+
modify_group=Modificar_grupo
+
Move=Mover
+
Move_down=Mover_hacia_abajo
+
Move_entries_in_group_selection_to_the_top=Mover_entradas_en_el_grupo_seleccionado_al_inicio
Move_external_links_to_'file'_field=Mover_enlaces_externos_al_campo_'archivo'
+
move_group=Mover_grupo
+
Move_up=Mover_hacia_arriba
+
Moved_group_"%0".=Se_ha_movido_el_grupo_"%0".
+
Name=Nombre
Name_formatter=Formateador_de_nombre
+
Natbib_style=Estilo_Natbib
+
nested_AUX_files=Archivos_AUX_anidados
+
New=Nuevo
+
new=new
+
New_BibTeX_entry=Nueva_entrada_BibTeX
+
New_BibTeX_subdatabase=Nueva_base_de_datos_secundaria_BibTeX
+
New_content=Nuevo_contenido
+
New_database_created.=Nueva_base_de_datos_creada.
+New_%0_database=Nueva_base_de_datos_%0
New_field_value=Nuevo_valor_de_campo
+
New_file=Nuevo_archivo
New_file_link_(INSERT)=Nuevo_enlace_a_archivo_(INSERTAR)
+
New_group=Nuevo_grupo
+
New_string=Nueva_cadena
+
Next_entry=Entrada_siguiente
+
No_actual_changes_found.=No_se_han_encontrado_cambios_actuales.
+
no_base-BibTeX-file_specified=no_se_ha_especificado_archiv_base_BibTeX
+
no_database_generated=No_se_generó_base_de_datos
+
No_entries_found._Please_make_sure_you_are_using_the_correct_import_filter.=No_se_han_encontrado_entradas._Asegúrese_de_que_está_usando_el_filtro_de_importación_correcto.
+
+
No_entries_found_for_the_search_string_'%0'=No_se_han_encontrado_entdas_para_la_cadena_de_búsqueda_'%0'
+
No_entries_imported.=No_se_han_importado_entradas.
+
No_exceptions_have_occurred.=No_han_ocurrido_excepciones.
No_files_found.=No_se_han_encontrado_archivos.
+
No_GUI._Only_process_command_line_options.=Sin_GUI._Procesar_sólo_opciones_de_la_línea_de_comandos.
+
No_journal_names_could_be_abbreviated.=No_se_pudieron_abreviar_nombres_de_revistas.
+
No_journal_names_could_be_unabbreviated.=No_se_pudieron_expandir_nombres_de_revistas.
No_PDF_linked=Ningún_PDF_enlazado
-No_references_found=No_se_han_encontrado_referencias
+
No_URL_defined=Ninguna_URL_definida
not=no
+
not_found=no_encontrado
+
Note_that_you_must_specify_the_fully_qualified_class_name_for_the_look_and_feel,=Tenga_en_cuenta_que_debe_especificar_el_nombre_completo_de_clase_para_la_apariencia.
+
Nothing_to_redo=Nada_que_rehacer
+
Nothing_to_undo=Nada_que_deshacer
-Number_of_references_to_fetch?=¿Número_de_apariciones_a_recuperar?
+
occurrences=apariciones
+
OK=Ok
One_or_more_file_links_are_of_the_type_'%0',_which_is_undefined._What_do_you_want_to_do?=Uno_o_más_archivos_son_del_tipo_'%0',_que_no_está_definido._¿Qué_desea_hacer?
+
One_or_more_keys_will_be_overwritten._Continue?=Una_o_claves_se_sobreescribirán._¿Continuar?
+
Open=Abrir
+
Open_BibTeX_database=Abrir_base_de_datos_BIbTeX
+
Open_database=Abrir_base_de_datos
+
Open_editor_when_a_new_entry_is_created=Abrir_editor_al_crear_nueva_entrada
+
Open_file=Abrir_archivo
+
Open_last_edited_databases_at_startup=Abrir_las_últimas_bases_de_datos_editadas_al_arrancar
-Open_shared_database=
+
+Connect_to_shared_database=
+
Open_terminal_here=Open_terminal_here
+
Open_URL_or_DOI=Abril_URL_o_DOI
+
Opened_database=Base_de_datos_abierta
+
Opening=Abriendo
+
Opening_preferences...=Preferencias_de_apertura
+
Operation_canceled.=Operación_cancelada.
Operation_not_supported=Operación_no_soportada
+
Optional_fields=Campos_opcionales
+
Options=Opciones
+
or=o
+
Output=Salida
+
Output_or_export_file=Sacar_o_exportar_archivo,
+
Override=Ignorar
+
Override_default_file_directories=Ignorar_carpetas_de_archivo_por_defecto
+
Override_default_font_settings=Ignorar_ajustes_de_tipo_de_letra_por_defecto
+
Override_the_BibTeX_field_by_the_selected_text=Ignorar_la_clave_BibTeX_por_el_texto_seleccionado
+
+
Overwrite=Sobreescribir
Overwrite_existing_field_values=Sobreescribir_valores_de_campo_existentes
+
Overwrite_keys=Sobreescribir_claves
+
pairs_processed=pares_procesados
Password=Contraseña
+
Paste=Pegar
+
paste_entries=pegar_entradas
+
paste_entry=pegar_entrada
Paste_from_clipboard=Pegar_desde_el_portapapeles
+
Pasted=Pegado
+
Path_to_%0_not_defined=Ruta_hasta_%0_sin_definir
+
Path_to_LyX_pipe=Ruta_hasta_el_pipe_LyX
+
PDF_does_not_exist=No_existe_el_PDF
+
Personal_journal_list=Lista_personal_de_revistas
+
Plain_text_import=Importar_texto_plano
+
Please_enter_a_name_for_the_group.=Introduzca_un_nombre_para_el_grupo.
+
Please_enter_a_search_term._For_example,_to_search_all_fields_for_<b>Smith</b>,_enter\:<p><tt>smith</tt><p>To_search_the_field_<b>Author</b>_for_<b>Smith</b>_and_the_field_<b>Title</b>_for_<b>electrical</b>,_enter\:<p><tt>author\=smith_and_title\=electrical</tt>=Introduzca_un_término_de_búsqueda._Por_ejemplo,_para_buscar_en_todos_los_campos_<b>García</b>,_introduzca\:<p><tt>garcía</tt><p>_Para_buscar_<b>García</b>_dentro_del_campo_<b>Author</b>_y_<b>eléctrico</b>_en_el_campo_<b>Title</b> [...]
+
Please_enter_the_field_to_search_(e.g._<b>keywords</b>)_and_the_keyword_to_search_it_for_(e.g._<b>electrical</b>).=Introduzca_el_campo_en_que_buscar_(p.e._<b>keywords</b>)_y_la_palabra_clave_a_buscar_(p.e._<b>eléctrico</b>).
+
Please_enter_the_string's_label=Introduzca_la_etiqueta_de_la_cadena
+
Please_select_an_importer.=Seleccionar_un_importador.
+
Please_select_exactly_one_group_to_move.=Seleccione_exactamente_un_grupo_para_mover.
+
Possible_duplicate_entries=Posibles_entradas_duplicadas
+
Possible_duplicate_of_existing_entry._Click_to_resolve.=Posible_duplicado_de_entrada_existente._Clique_para_resolver.
+
Preamble=Preámbulo
+
Preferences=Preferencias
+
Preferences_recorded.=Preferencias_guardadas.
+
Preview=Vista_previa
+Citation_Style=
+Current_Preview=
+Cannot_generate_preview_based_on_selected_citation_style.=
+Bad_character_inside_entry=
+Error_while_generating_citation_style=
+Preview_style_changed_to\:_%0=
+Next_preview_layout=
+Previous_preview_layout=
+
Previous_entry=Entrada_anterior
+
Primary_sort_criterion=Criterio_de_ordenación_primario
Problem_with_parsing_entry=Problemas_analizando_entradas
-
Processing_%0=Procesando_%0
Program_output=Salida_del_programa
Pull_changes_from_shared_database=
+
Pushed_citations_to_%0=Se_han_enviado_las_citas_a_%0
+
Quit_JabRef=Salir_de_JabRef
+
Quit_synchronization=Dejar_de_sincronizar
+
Raw_source=Furente_de_datos_en_bruto
+
Rearrange_tabs_alphabetically_by_title=Disponer_las_pestañas_alfabéticamente_por_título
+
Redo=Rehacer
+
Reference_database=Base_de_datos_de_referencia
-References_found=Referencias_encontradas
+
+%0_references_found._Number_of_references_to_fetch?=Referencias_encontradas\:_%0._¿Número_de_apariciones_a_recuperar?
+
Refine_supergroup\:_When_selected,_view_entries_contained_in_both_this_group_and_its_supergroup=Refinar_supergrupo\:_Ver_entradas_contenidas_en_este_grupo_y_sus_subgrupos_cuando_estén_seleccionadas
+
regular_expression=Expresión_Regular
+
Remember_these_entry_types?=¿Recordar_estos_tipos_de_entrada?
+
Remote_operation=Operación_remota
+
Remote_server_port=Puerto_remoto_del_servidor
+
Remove=Eliminar
+
Remove_subgroups=Eliminar_subgrupos
+
Remove_all_subgroups_of_"%0"?=¿Eliminar_todos_los_subrgrupos_de_"%0"?
+
Remove_entry_from_import=Eliminar_entrada_importada
+
Remove_entry_selection_from_this_group=Eliminar_selección_de_entradas_de_este_grupo
+
Remove_entry_type=Eliminar_tipo_de_entrada
Remove_file_link_(DELETE)=Eliminar_enlace_a_archivo_(BORRAR)
+
Remove_from_group=Eliminar_del_grupo
+
Remove_group=Eliminar_grupo
+
Remove_group,_keep_subgroups=Eliminar_grupo,_mantener_subgrupos
+
Remove_group_"%0"?=¿Eliminar_el_grupo_"%0%?
+
Remove_group_"%0"_and_its_subgroups?=¿Ena_grupo_250"_y_sus_subgrupos?
+
remove_group_(keep_subgroups)=eliminar_grupo_(mantener_subgrupos)
+
remove_group_and_subgroups=eliminar_grupo_y_subgrupos
+
Remove_group_and_subgroups=Eliminar_grupo_y_subgrupos
+
Remove_link=Eliminar_enlace
+
Remove_old_entry=Eliminar_vieja_entrada
+
Remove_selected_strings=Eliminar_cadenas_seleccionadas
+
Removed_group_"%0".=el_grupo_"%0"_se_ha_eliminado.
+
Removed_group_"%0"_and_its_subgroups.=Se_ha_eliminado_el_grupo_"%0"_y_sus_subgrupos.
+
Removed_string=Cadena_eliminada
+
Renamed_string=Cadena_renombrada
+
Replace_(regular_expression)=Reemplazar_(Expresión_regular)
+
Replace_string=Reemplazar_cadena
+
Replace_with=Reemplazar_con
+
Replaced=Reemplazado
+
Required_fields=Campos_requeridos
+
Reset_all=Restablecer_todos
+
Resolve_strings_for_all_fields_except=Resolver_cadenas_para_todos_los_campos_excepto
Resolve_strings_for_standard_BibTeX_fields_only=Resolver_cadenas_únicamente_para_los_campos_BibTeX_estándar
+
resolved=resuelto
+
Revert_to_original_source=Volver_a_la_fuente_original
+
Review=Revisar
+
Review_changes=Revisar_cambios
+
Right=Derecha
+
Save=Guardar
Save_all_finished.=Guardar_todos_los_finalizados
+
Save_all_open_databases=Guardar_todas_las_bases_de_datos_abiertas
+
Save_before_closing=Guardar_antres_de_cerrar
+
Save_database=Guardar_base_de_datos
Save_database_as...=Guardar_base_de_datos_como...
+
Save_entries_in_their_original_order=Guardar_entradas_en_el_orden_original
+
Save_failed=Fallón_el_guardado
+
Save_failed_during_backup_creation=Error_durante_el_guardado_mientras_se_creaba_la_copia_de_seguridad
-Save_failed_while_committing_changes\:_%0=Error_mientras_se_efectuaban_los_cambios\:_%0
+
Save_selected_as...=Guardar_seleccionado_como...
+
Saved_database=Base_de_datos_guardada
+
Saved_selected_to_'%0'.=Guardar_seleccionados_a_'%0'.
+
Saving=Guardando
Saving_all_databases...=Guardando_todas_las_bases_de_datos...
+
Saving_database=Guardando_base_de_datos
+
Search=Buscar
+
Search_expression=Buscar_expresión
+
Search_for=Buscar
+
Searching_for_duplicates...=Buscando_duplicados...
+
Searching_for_files=Buscando_archivos
+
Secondary_sort_criterion=Criterio_secundario_de_ordenación
+
Select=Seleccionar
+
+
Select_all=Seleccionar_todo
+
Select_encoding=Seleccionar_codificación
+
Select_entry_type=Seleccionar_tipo_de_entrada
Select_external_application=Seleccionar_aplicación_externa
+
Select_file_from_ZIP-archive=Seleccionar_archivo_desde_archivo_ZIP
+
Select_the_tree_nodes_to_view_and_accept_or_reject_changes=Seleccionar_nodos_de_árbol_para_ver_y_aceptar_o_rechazar_los_cambios.
Selected_entries=Entradas_seleccionadas
Set_field=Establecer_campo
Set_fields=Establecer_campos
+
Set_general_fields=Establecer_campos_generales
Set_main_external_file_directory=Establecer_carpeta_de_archivo_externo_principal
+
Set_table_font=Establecer_tipo_dera_para_las_tablas
+
Settings=Ajustes
+
Shortcut=Atajo
-Show/edit_BibTeX_source=Mostrar/editar_fuente_BibTeX
+
+Show/edit_%0_source=Mostrar/editar_fuente_%0
+
Show_'Firstname_Lastname'=Mostrar_'Nombre_Apellido'
+
Show_'Lastname,_Firstname'=Mostrar_'Apellido,_Nombre'
+
Show_BibTeX_source_by_default=Mostrar_fuente_BibTeX_por_defecto
+
Show_confirmation_dialog_when_deleting_entries=Mostra_diálogo_de_confirmación_al_borrar_entradas
+
Show_description=Mostrar_descripción
+
Show_dynamic_groups_in_<i>italics</i>=Mostrar_grupos_dinámicos_en_<i>cursiva</i>
+
Show_entries_<b>not</b>_in_group_selection=Mostrar_entradas_que_NO_estén_en_la_selección_de_grupo
+
Show_file_column=Mostrar_columna_de_archivo
+
Show_icons_for_groups=Mostrar_iconos_para_grupos
Show_last_names_only=Mostrar_sólo_apellidos
+
Show_names_unchanged=Mostrar_nombres_sin_cambios
+
Show_optional_fields=Mostrar_campos_opcionales
+
Show_required_fields=Mostrar_campos_requeridos
+
Show_URL/DOI_column=Mostrar_columna_URL/DOI
+
Simple_HTML=HTML_sencillo
+
Size=Tamaño
+
Skipped_-_No_PDF_linked=Omitido_-_No_se_enlazó_PDF
Skipped_-_PDF_does_not_exist=Omitido_-_No_existe_el_PDF
+
Skipped_entry.=Entrada_omitida.
+
Sort_alphabetically=Ordenar_alfabéticamente
+
sort_subgroups=ordenar_subgrupos
+
Sorted_all_subgroups_recursively.=Ordenar_todos_los_subgrupos_recursivamente.
+
Sorted_immediate_subgroups.=Subgrupos_inmediatos_ordenados.
+
source_edit=editar_fuente
Special_name_formatters=Formateadores_con_nombre_especial
+
Special_table_columns=Columna_de_tabla_especiales
+
Starting_import=Comenzando_a_importar
+
Statically_group_entries_by_manual_assignment=Agrupar_entradas_estadísticamente_mediante_asgnación_manual
+
Status=Estado
+
Stop=Parar
+
Store_journal_abbreviations=Almacenar_abreviaturas_de_revista
+
Stored_entry=Entrada_almacenada
+
Strings=Cadenas
+
Strings_for_database=Cadenas_para_base_de_datos
+
Subdatabase_from_AUX=Base_de_datos_secundaria_desde_AUX
+
Switches_between_full_and_abbreviated_journal_name_if_the_journal_name_is_known.=Cambia_entre_nombre_completo_y_abreviatura_de_la_revista_si_se_conoce_en_nombe_de_la_revista.
+
Synchronize_file_links=Sincronizar_enlaces_de_archivo
+
Synchronizing_file_links...=Sincronizando_archivo_enlaces...
+
Table_appearance=Aspecto_de_la_tabla
+
Table_background_color=Color_de_fondo_de_la_tabla
+
Table_grid_color=Color_de_las_líneas_de_la_tabla
+
Table_text_color=Color_del_texto_de_la_tabla
+
Tabname=Nombre_de_pestaña
Target_file_cannot_be_a_directory.=El_archivo_de_destino_no_puede_ser_una_carpeta.
+
Tertiary_sort_criterion=Criterio_de_ordenación_terciario
+
Test=Prueba
+
paste_text_here=Área_de_entrada_de_texto
+
The_chosen_date_format_for_new_entries_is_not_valid=El_forma-to_de_fecha_escogido_para_nuevas_entradas_no_es_correcto
+
The_chosen_encoding_'%0'_could_not_encode_the_following_characters\:=La_codificación_de_caracteres_'%'_no_puede_codificar_los_siguientes_caracteres\:
+
+
the_field_<b>%0</b>=el_campo_<b>%0</b>
+
The_file<BR>'%0'<BR>has_been_modified<BR>externally\!=¡El_archivo<BR>'%0'<BR>ha_sido_modificado<BR>_externamente\!
+
The_group_"%0"_already_contains_the_selection.=El_grupo_"%0"_ya_contiene_la_selección.
+
The_label_of_the_string_cannot_be_a_number.=La_etiqueta_de_la_cadena_no_puede_ser_un_número.
+
The_label_of_the_string_cannot_contain_spaces.=La_etiqueta_de_la_cadena_no_puede_contener_espacios.
+
The_label_of_the_string_cannot_contain_the_'\#'_character.=La_etiqueta_de_la_cadena_no_puede_contener_el_caracter_'\#'.
+
The_output_option_depends_on_a_valid_import_option.=La_opción_de_salida_depende_de_una_opción_de_importación_válida.
The_PDF_contains_one_or_several_BibTeX-records.=El_PDF_contiene_uno_o_más_registros_BibTeX.
Do_you_want_to_import_these_as_new_entries_into_the_current_database?=¿Desea_importarlos_como_nuevas_entradas_en_la_base_de_datos_actual?
+
The_regular_expression_<b>%0</b>_is_invalid\:=La_expresión_regular_<b>%0</b>_no_es_válida\:
+
The_search_is_case_insensitive.=La_búsqueda_no_distingue_mayúsculas/minúsculas
+
The_search_is_case_sensitive.=La_búsqueda_distingue_mayúsculas/minúsculas
+
The_string_has_been_removed_locally=La_cadena_ha_sido_eliminada_localmente
+
There_are_possible_duplicates_(marked_with_an_icon)_that_haven't_been_resolved._Continue?=Hay_posibles_duplicados_(marcados_con_el_icono)_que_no_han_sido_resueltos._¿Continuar?
+
This_entry_has_no_BibTeX_key._Generate_key_now?=Esta_entrada_no_tiene_clave_BibTeX._¿Generar_ahora?
+
This_entry_is_incomplete=Esta_entrada_está_incompleta¡u+
+
This_entry_type_cannot_be_removed.=Este_tipo_de_entrada_no_puede_ser_eliminada.
+
This_external_link_is_of_the_type_'%0',_which_is_undefined._What_do_you_want_to_do?=El_enlace_externo_es_del_tipo_'%0',_que_no_está_definido._¿Qué_desea_hacer?
+
This_group_contains_entries_based_on_manual_assignment._Entries_can_be_assigned_to_this_group_by_selecting_them_then_using_either_drag_and_drop_or_the_context_menu._Entries_can_be_removed_from_this_group_by_selecting_them_then_using_the_context_menu.=Este_grupo_contiene_entradas_basadas_en_asignación_manual._Las_entradas_pueden_ser_asignadas_a_este_grupo_seleccionándolas_usando_el_menú_contextual_o_bien_mediante_arrastrar-soltar._Las_entradas_pueden_ser_eliminadas_de_este_grupo_seleccion [...]
+
This_group_contains_entries_whose_<b>%0</b>_field_contains_the_keyword_<b>%1</b>=Este_grupo_contiene_entradas_cuyo_campo_<b>%0</b>_contiene_la_palabra_clave_<b>%1</b>_
+
This_group_contains_entries_whose_<b>%0</b>_field_contains_the_regular_expression_<b>%1</b>=Este_grupo_contiene_entradas_cuyo_campo_<b>%0</b>_contiene_la<_expresión_regular_<b>%1</b>_
This_makes_JabRef_look_up_each_file_link_and_check_if_the_file_exists._If_not,_you_will_be_given_options<BR>to_resolve_the_problem.=JabRef_inspeccionará_cada_enlace_archivo_y_comprobará_si_el_archivo_existe._En_caso_contrario,_se_le_ofrecerán_opciones_<BR>_para_solucionar_el_problema.
+
This_operation_requires_all_selected_entries_to_have_BibTeX_keys_defined.=Esta_operación_requiere_que_todas_las_entradas_seleccionadas_tengan_claves_BibTeX_definidas.
+
This_operation_requires_one_or_more_entries_to_be_selected.=Esta_operación_requiere_seleccionar_una_o_más_entradas.
+
Toggle_abbreviation=Usar_abreviatura_si/no
Toggle_entry_preview=Usar_vista_previa_de_la_entrada_si/no
Toggle_groups_interface=Usar_interfaz_de_grupos_si/no
Try_different_encoding=Probar_una_codificación_diferente
+
Unabbreviate_journal_names_of_the_selected_entries=Desabreviar_nombre_de_revista_de_las_entradas_seleccionadas
Unabbreviated_%0_journal_names.=%0_nombres_de_revista_desabreviados
+
Unable_to_open_file.=No_se_puede_abrir_el_archivo
Unable_to_open_link._The_application_'%0'_associated_with_the_file_type_'%1'_could_not_be_called.=No_se_puede_abrir_el_enlace._La_aplicación_'%'_asociada_con_el_tipo_de_archivo_'%1'_no_puede_ser_lanzada.
unable_to_write_to=no_se_puede_escribir_en
Undefined_file_type=Tipo_de_archivo_no_definido
+
Undo=Deshacer
+
Union=Unión
+
Unknown_BibTeX_entries=Entradas_BibTeX_desconocidas
+
unknown_edit=edición_desconocida
+
Unknown_export_format=Formato_de_exportación_desconocido
+
Unmark_all=Desmarcar_todos
+
Unmark_entries=Desmarcar_entradas
+
Unmark_entry=Desmarcar_entrada
-Unsupported_version_of_class_%0\:_%1=La_versión_%1_de_la_clase_%0_no_está_soportada
+
untitled=sin_título
+
Up=Arriba
+
Update_to_current_column_widths=Actualizar_a_anchos_de_columna_actuales
+
Updated_group_selection=Actualizar_selección_de_grupo
Upgrade_external_PDF/PS_links_to_use_the_'%0'_field.=Actualizar_enlaces_a_PDF/PS_externos_para_usar_el_campo_'%0'.
Upgrade_file=Actualizar_archivo
Upgrade_old_external_file_links_to_use_the_new_feature=Actualizar_enlaces_a_archivos_externos_para_usar_la_nueva_característica.
+
usage=Uso
Use_autocompletion_for_the_following_fields=Usar_autocompletar_para_los_siguientes_campos
+
Use_other_look_and_feel=Usar_otro_aspecto
Use_regular_expression_search=Usar_búsqueda_de_expresión_regular
+
Username=Nombre_de_usuario
+
Value_cleared_externally=Valor_limpiado_externamente
+
Value_set_externally=Valor_establecido_externamente
+
verify_that_LyX_is_running_and_that_the_lyxpipe_is_valid=virificar_que_LyX_está_funcionando_y_que_lyxpipe_es_válido
+
View=Ver
Vim_server_name=Nombre_de_servidor_Vim
+
Waiting_for_ArXiv...=Esperando_a_ArXiv
+
Warn_about_unresolved_duplicates_when_closing_inspection_window=Advertir_sobre_duplicados_sin_resolver_cuando_al_cerrar_la_ventana_de_inspección
+
Warn_before_overwriting_existing_keys=Advertir_antes_de_sobreescribir_claves_existentes
+
Warning=Advertencia
+
Warnings=Advertencias
+
web_link=enlace_a_web
+
What_do_you_want_to_do?=¿Qué_desea_hacer?
+
When_adding/removing_keywords,_separate_them_by=Cuando_se_eliminen/añadan_palabras_clave,_separar_por
Will_write_XMP-metadata_to_the_PDFs_linked_from_selected_entries.=Escribirá_metadatos_XMP_a_los_PDF's_enlazados_desde_las_entradas_seleccionadas.
+
with=con
+
Write_BibTeXEntry_as_XMP-metadata_to_PDF.=Escribir_entrada_BibTeX_como_metadatos_XMP_al_PDF.
+
Write_XMP=Escribir_XMP
Write_XMP-metadata=Escribir_metadatos_XMP
Write_XMP-metadata_for_all_PDFs_in_current_database?=¿Escribir_metadatos_XMP_para_todos_los_PDF_en_la_base_de_datos_actual?
Writing_XMP-metadata...=Escribiendo_metadatos_XMP
Writing_XMP-metadata_for_selected_entries...=Escribiendo_metadatos_XMP_para_las_entradas_seleccionadas...
+
Wrote_XMP-metadata=Se_han_escrito_los_metadatos_XMP
+
XMP-annotated_PDF=PDF_con_anotaciones_XMP
XMP_export_privacy_settings=Ajustes_de_privacidad_en_exportación_XMP
XMP-metadata=Metadatos_XMP
XMP-metadata_found_in_PDF\:_%0=Metadatos_XMP_encontrados_en_PDF\:_'%0'
You_must_restart_JabRef_for_this_to_come_into_effect.=Debe_reiniciar_JabRef_para_que_los_cambios_surtan_efecto.
You_have_changed_the_language_setting.=Ha_cambiado_el_ajuste_de_lenguaje.
+
You_have_changed_the_look_and_feel_setting.=Ha_cambiado_el_ajuste_de_aspecto.
+
You_have_entered_an_invalid_search_'%0'.=Ha_introducido_una_búsqueda_inválida_'%0'
+
You_must_choose_a_filename_to_store_journal_abbreviations=Debe_escoger_un_nombre_de_archivo_para_almacenar_abreviaturas_de_revistas.
+
You_must_restart_JabRef_for_the_new_key_bindings_to_work_properly.=Debe_reiniciar_JabRef_para_que_las_nuevas_combinaciones_de_teclas_funcionen_correctamente.
+
Your_new_key_bindings_have_been_stored.=Sus_nuevas_combinaciones_de_teclas_han_sido_almacenadas.
+
The_following_fetchers_are_available\:=Están_disponibles_los_siguientes_recuperadores_de_datos\:
Could_not_find_fetcher_'%0'=No_se_puede_encontrar_el_recuperador_de_datos_'%0'
Running_query_'%0'_with_fetcher_'%1'.=Ejecutando_consulta_'%0'_con_recuperador_'%1'
@@ -771,63 +1404,74 @@ Number_of_entries_successfully_imported=Número_de_entradas_importadas_con_éxit
Import_canceled_by_user=Importación_cancelada_por_el_usuario
Progress\:_%0_of_%1=Progreso\:_%0_de_%1
Error_while_fetching_from_%0=Error_al_recuperar_desde_%0
-Fetching_Medline_by_id...=Recuperando_desde_Medline_por_id...
-Fetching_Medline_by_term...=Recuperando_desde_Medline_por_término...
-%0_import_canceled=Importación_desde_%0_cancelada
+
Please_enter_a_valid_number=Por_favor,_introduzca_un_número_válido
-Please_enter_a_comma_separated_list_of_Medline_IDs_(numbers)_or_search_terms.=Por_favor,_introduzca_una_lista_de_valores_separados_por_coma_de_IDs_de_Medline_(números)_o_términos_de_búsqueda.
Show_search_results_in_a_window=Mostrar_los_resultados_de_la_búsqueda_en_una_ventana
+Show_global_search_results_in_a_window=
+Search_in_all_open_databases=
Move_file_to_file_directory?=¿Mover_archivo_a_la_carpeta_de_archivos?
Rename_to_'%0'=Renombrar_a_'%0'
You_have_changed_the_menu_and_label_font_size.=Ha_cambiado_el_tamaño_de_tipo_de_letra_para_el_menu_y_etiqueta.
+
Database_is_protected._Cannot_save_until_external_changes_have_been_reviewed.=La_base_de_datos_está_protegida._No_se_puede_guardar_hasta_que_los_cambios_externos_hayan_sido_revisados.
Protected_database=Base_de_datos_protegida
Refuse_to_save_the_database_before_external_changes_have_been_reviewed.=Rechazar_guadar_la_base_de_datos_antes_qde_que_los_cambios_externos_hayan_sido_revisado.
Database_protection=Proteccion_de_la_base_de_datos
Unable_to_save_database=No_es_posible_guardar_la_base_de_datos
+
BibTeX_key_generator=Generador_de_claves_BibTeX
Unable_to_open_link.=No_es_posible_abrir_el_enlace.
Move_the_keyboard_focus_to_the_entry_table=Mover_el_foco_del_teclado_a_la_tabla_de_entradas
MIME_type=Tipo_MIME
+
This_feature_lets_new_files_be_opened_or_imported_into_an_already_running_instance_of_JabRef<BR>instead_of_opening_a_new_instance._For_instance,_this_is_useful_when_you_open_a_file_in_JabRef<br>from_your_web_browser.<BR>Note_that_this_will_prevent_you_from_running_more_than_one_instance_of_JabRef_at_a_time.=Esta_función_permite_que_nuevos_archivos_seasn_abiertos_o_importados_en_una_instancia_de_JabRef_que_ya_se_esté_ejecutando,<BR>en_lugar_de_abrir_una_nueva_instancia._Esto_es_útil,_por_ [...]
Run_fetcher,_e.g._"--fetch\=Medline\:cancer"=Ejecutar_recuperador,_por_ejemplo_"--fetch=Medline\:cancer"
+
The_ACM_Digital_Library=La_Biblioteca_Digital_ACM
Reset=Restablecer
+
Use_IEEE_LaTeX_abbreviations=Usar_abreviaturas_LaTeX_IEEE
The_Guide_to_Computing_Literature=The_Guide_to_Computing_Literature
+
When_opening_file_link,_search_for_matching_file_if_no_link_is_defined=Al_abrir_el_enlace_al_archivo,_buscar_por_archivo_coincidente_si_no_hay_enlace_definido
Settings_for_%0=Ajustes_para_%0
Mark_entries_imported_into_an_existing_database=Marcar_entradas_importadas_en_una_base_de_datos_existente
Unmark_all_entries_before_importing_new_entries_into_an_existing_database=Desmarcar_todas_las_entradas_antes_de_importar_nuevas_entradas_en_una_base_de_datos_existente
+
Forward=Adelante
Back=Atrás
Sort_the_following_fields_as_numeric_fields=Ordenar_los_siguientes_campos_como_campos_numéricos
Line_%0\:_Found_corrupted_BibTeX_key.=Línea_%0\:_Se_ha_encontrado_una_clave_BibTeX_corrupta.
Line_%0\:_Found_corrupted_BibTeX_key_(contains_whitespaces).=Línea_%0\:_Se_ha_encontrado_una_clave_BibTeX_corrupta_(contiene_espacios_en_blanco)
Line_%0\:_Found_corrupted_BibTeX_key_(comma_missing).=Línea_%0\:_Se_ha_encontrado_clave_BibTeX_corrupta_(falta_coma).
-Finished_downloading_full_text_document=Se_ha_finalizado_la_descarga_del_texto_completo_del_documento
Full_text_document_download_failed=Falló_la_descarga_del_texto_completo_del_artículo
Update_to_current_column_order=Actualizar_al_orden_de_columnas_actual
+Download_from_URL=
Rename_field=Renombrar_campo
Set/clear/rename_fields=Establecer/limpiar/renombrar_campos
Rename_field_to=Renombrar_campo_a
Move_contents_of_a_field_into_a_field_with_a_different_name=Mover_contenidos_de_un_campo_en_un_campo_con_nombre_diferente
You_can_only_rename_one_field_at_a_time=Sólo_puede_renombrar_un_campo_a_la_vez
+
Remove_all_broken_links=Eliminar_todos_los_enlaces_rotos
+
Cannot_use_port_%0_for_remote_operation;_another_application_may_be_using_it._Try_specifying_another_port.=No_se_puede_usar_el_puerto_%0_para_operación_remota\:_Puede_estar_en_uso_por_otra_aplicación._Pruebe_a_especificar_otro_puerto.
+
Looking_for_full_text_document...=Buscando_texto_completo_de_documento...
Autosave=Autoguardado
-Prompt_before_recovering_a_database_from_an_autosave_file=Preguntar_antes_de_recuperar_una_base_de_datos_desde_un_archivo_autoguardado
-Autosave_interval_(minutes)=Intervalo_de_autoguardado_(minutos)
-Do_you_want_to_recover_the_database_from_the_autosave_file?=¿Quiere_recuperar_la_base_de_datos_desde_el_archivo_autoguardado?
-Recover_from_autosave=Recuperar_desde_archivo_autoguardado
+A_local_copy_will_be_opened.=
+Autosave_local_databases=
+Automatically_save_the_database_to=
+Please_enter_a_valid_file_path.=
+
+
Export_in_current_table_sort_order=Exportar_con_el_criterio_de_ordenación_actual
Export_entries_in_their_original_order=Exportar_entradas_en_su_orden_original
Error_opening_file_'%0'.=Error_abriendo_el_archivo_'%0'.
-Autosave_of_file_'%0'=Autoguardado_del_archivo_'%0'
-Error_opening_autosave_of_'%0'._Trying_to_load_'%0'_instead.=Error_abriendo_el_archivo_autoguardado_de_'%0'._Intentando_cargar_'%0'_en_su_lugar.
+
Formatter_not_found\:_%0=Formateador_no_encontrado\:_%0
Clear_inputarea=Limpiar_área_de_entrada
+
Automatically_set_file_links_for_this_entry=Ajustar_enlaces_de_archivo_automáticamente_para_esta_entrada
Could_not_save,_file_locked_by_another_JabRef_instance.=No_se_puede_guardar._Fichero_bloqueado_por_otra_instancia_JabRef.
File_is_locked_by_another_JabRef_instance.=El_archivo_está_bloqueado_por_otra_instancia_de_JabRef.
@@ -836,10 +1480,12 @@ File_locked=Archivo_bloqueado
Current_tmp_value=Valor_temporal_actual
Metadata_change=Cambio_de_metadatos
Changes_have_been_made_to_the_following_metadata_elements=Se_han_efectuado_los_cambios_a_los_siguientes_elementos_de_los_metadatos
+
Generate_groups_for_author_last_names=Generar_grupos_para_apellidos_de_autor
Generate_groups_for_editor_last_names=Generar_grupos_para_apellidos_de_editor
Generate_groups_from_keywords_in_a_BibTeX_field=Generar_grupos_desde_palabras_claves_de_un_campo_BibTeX
Enforce_legal_characters_in_BibTeX_keys=Uso_obligado_de_caracteres_legales_en_claves_BibTeX
+
Save_without_backup?=¿Guardar_sin_copia_de_seguridad?
Unable_to_create_backup=No_es_posible_crear_la_copia_de_seguridad
Move_file_to_file_directory=Mover_archivo_al_directorio_de_archivos
@@ -850,31 +1496,36 @@ dynamic_group=grupo_dinámico
refines_supergroup=afina_supergrupo
includes_subgroups=incluye_subgrupos
contains=contiene
-%0_mode=modo_%0
search_expression=expresión_de_búsqueda
+
Optional_fields_2=Campos_opcionales_2
Waiting_for_save_operation_to_finish=Esperando_a_que_acabe_la_operación_de_guardado
Resolving_duplicate_BibTeX_keys...=Resolviendo_claves_BibTeX_duplicadas...
Finished_resolving_duplicate_BibTeX_keys._%0_entries_modified.=Resolución_de_claves_BibTeX_duplicadas_finalizada._%0_entradas_modificadas.
This_database_contains_one_or_more_duplicated_BibTeX_keys.=Esta_base_de_datos_contiene_una_o_más_claves_BibTeX_duplicadas.
Do_you_want_to_resolve_duplicate_keys_now?=¿Quiere_resolver_las_claves_duplicadas_ahora?
+
Find_and_remove_duplicate_BibTeX_keys=Encontrar_y_eliminar_entradas_BibTeX_duplicadas
Expected_syntax_for_--fetch\='<name_of_fetcher>\:<query>'=Sintaxis_esperada_para_--fetch='<nombre_del_recuperador>\:<consulta>'
Duplicate_BibTeX_key=Clave_BibTeX_duplicada
Import_marking_color=Importar_color_para_marcas
Always_add_letter_(a,_b,_...)_to_generated_keys=Siempre_añadir_letra_(a,b,_...)_a_las_claves_generadas
+
Ensure_unique_keys_using_letters_(a,_b,_...)=Asegurar_unicidad_de_claves_usando_letras_(a,b,_...)
Ensure_unique_keys_using_letters_(b,_c,_...)=Asegurar_unicidad_de_claves_usando_letras_(b,c,_...)
Entry_editor_active_background_color=Color_de_fondo_del_editor_de_entradas_para_celdas_activas
Entry_editor_background_color=Color_de_fondo_del_editor_de_entradas
Entry_editor_font_color=Color_de_tipo_de_letra_del_editor_de_entradas
Entry_editor_invalid_field_color=Color_de_campo_inválido_del_editor_de_entradas
+
Table_and_entry_editor_colors=Colores_de_tabla_y_editor_de_entradas
+
General_file_directory=Carpeta_general_de_archivos.
User-specific_file_directory=Carpeta_de_archivos_de_usuario
Search_failed\:_illegal_search_expression=La_búsqueda_ha_fallado._Expresión_de_búsqueda_ilegal
Show_ArXiv_column=Mostrar_columna_ArXiv
Highlight_groups_that_contain_entries_contained_in_any_currently_selected_group=Resaltar_grupos_con_entradas_contenidas_en_cualquier_grupo_seleccionado_actualmente.
+
You_must_enter_an_integer_value_in_the_interval_1025-65535_in_the_text_field_for=Es_preciso_introducir_un_valor_entero_comprendido_entre_1025_y_65535_en_el_campo_de_texto_para
Automatically_open_browse_dialog_when_creating_new_file_link=Abrir_automáticamente_el_diálogo_de_exploración_al_crear_nuevo_enlace_a_archivo
Import_metadata_from\:=Importar_metadatos_desde\:
@@ -883,7 +1534,6 @@ Create_entry_based_on_XMP_data=Crear_entradas_a_partir_de_datos_XMP
Create_blank_entry_linking_the_PDF=Crear_entrada_en_blanco_enlazando_el_PDF
Only_attach_PDF=Sólo_adjnntar_PDF
Title=Título
-No_internet_connection.=_Sin_conexión_a_Internet.
Create_new_entry=Crear_nueva_entrada
Update_existing_entry=Actualizar_entrada_existente
Autocomplete_names_in_'Firstname_Lastname'_format_only=Autocompletar_nombres_sólo_en_el_formato_'Nombre_Apellidos'
@@ -959,7 +1609,6 @@ Select_document=Seleccionar_documento
Edit_group_membership=Editar_pertenecia_a_grupo
HTML_list=Listado_HTML
Click_group_to_toggle_membership_of_selected_entries=Haga_click_sobre_el_grupo_para_cambiar_el_grupo_al_que_pertenecen_las_entradas_seleccionadas
-Use_EMACS_23_insertion_string=Usar_la_cadena_de_inserción_EMACS_23
If_possible,_normalize_this_list_of_names_to_conform_to_standard_BibTeX_name_formatting=Normalizar_esta_lista_de_nombres_para_cumplir_con_el_formato_de_nombre_BibTeX_estándar
Could_not_open_%0=No_se_puede_abrir_%0
Unknown_import_format=Formato_de_importación_desconocido
@@ -974,13 +1623,16 @@ OpenOffice/LibreOffice_connection=Conexión_OpenOffice/LibreOffice
You_can_add_additional_journal_names_by_setting_up_a_personal_journal_list,<br>as_well_as_linking_to_external_journal_lists.=Puede_añadir_nombres_de_revista_adicionales_estabeciendo_una_lista_de_publicaciones_personal,<br>así_como_enlazando_con_una_lista_externa.
JabRef_includes_a_built-in_list_of_journal_abbreviations.=JabRef_incluye_una_lista_de_abreviaturas_preincluida
You_must_select_either_a_valid_style_file,_or_use_one_of_the_default_styles.=Debe_seleccionar_un_archivo_de_estilo_válido_o_usar_uno_de_los_estilos_por_defecto.
+
This_is_a_simple_copy_and_paste_dialog._First_load_or_paste_some_text_into_the_text_input_area.<br>After_that,_you_can_mark_text_and_assign_it_to_a_BibTeX_field.=Este_es_un_diálogo_de_copia-pega_simple._Primero,_cargue_o_pegue_algo_de_texto_en_el_área_de_entrada_de_texto.<br>Posteriormente,_puede_marcar_texto_y_asignarlo_a_un_campo_BibTeX.
This_feature_generates_a_new_database_based_on_which_entries_are_needed_in_an_existing_LaTeX_document.=Esta_funcionalidad_genera_una_nueva_base_de_datos_basada_en_las_entradas_que_se_necesitan_en_un_documento_LaTeX_existente.
You_need_to_select_one_of_your_open_databases_from_which_to_choose_entries,_as_well_as_the_AUX_file_produced_by_LaTeX_when_compiling_your_document.=Necesita_seleccionar_una_de_sus_bases_de_datos_abiertas_desde_la_que_se_escogerán_entradas,_así_como_el_archivo_AUX_generado_por_LaTeX_al_compilar_su_documento.
+
First_select_entries_to_clean_up.=Seleccione_las_entradas_a_limpiar_en_primer_lugar.
Cleanup_entry=Limpiar_entradas
Autogenerate_PDF_Names=Autogenerar_nombres_de_PDF
Auto-generating_PDF-Names_does_not_support_undo._Continue?=La_autogeneración_de_nombres_de_PDF_no_se_puede_deshacer._¿Continuar?
+
Use_full_firstname_whenever_possible=Usar_nombre_de_pila_completo_cuando_sea_posible
Use_abbreviated_firstname_whenever_possible=Usar_nombre_de_pila_abreviado_cuando_sea_posible
Use_abbreviated_and_full_firstname=Usar_apellido_completo_y_abreviado
@@ -990,6 +1642,7 @@ Name_format_used_for_autocompletion=Formato_de_nombre_usado_para_autocompletar
Treatment_of_first_names=Tratamiento_de_nombres_de_pila
Cleanup_entries=Limpiar_entradas
Automatically_assign_new_entry_to_selected_groups=Asignar_automáticamente_nueva_entrada_a_los_grupos_seleccionados
+%0_mode=modo_%0
Move_DOIs_from_note_and_URL_field_to_DOI_field_and_remove_http_prefix=Mover_DOIs_desde_los_campos_nota_y_URL_al_campo_DOI_y_eliminar_el_prefijo_http
Make_paths_of_linked_files_relative_(if_possible)=Hacer_rutas_de_los_ficheros_enlazados_relativas_(si_es_posible)
Rename_PDFs_to_given_filename_format_pattern=Renombrar_PDFs_al_patron_de_formato_de_nombre_archivo_proporcionado
@@ -999,15 +1652,19 @@ Doing_a_cleanup_for_%0_entries...=Haciendo_la_limpieza_de_%0_entradas
No_entry_needed_a_clean_up=Ninguna_entrada_necesitó_de_limpieza
One_entry_needed_a_clean_up=Sólo_una_entrada_necesitó_limpieza
%0_entries_needed_a_clean_up=%0_entradas_necesitarion_limpieza
+
Error_downloading_file_'%0'=Error_descargando_el_archivo_'%0'
Download_failed=Falló_la_descarga
+
Remove_selected=Eliminar_seleccionados
+
Group_tree_could_not_be_parsed._If_you_save_the_BibTeX_database,_all_groups_will_be_lost.=El_arbol_de_grupo_no_puede_ser_examinado._Si_guarda_la_base_de_datos_BibTeX,_todos_los_grupos_se_perderán.
Attach_file=Adjuntar_archivo
Setting_all_preferences_to_default_values.=Estableciendo_todas_las_preferencias_a_los_valores_por_defecto.
Resetting_preference_key_'%0'=Reestableciendo_la_preferencia_con_clave_'%0'
Unknown_preference_key_'%0'=Clave_de_preferencia_desconocida_'%0'
Unable_to_clear_preferences.=No_es_posible_limpiar_preferencias.
+
Reset_preferences_(key1,key2,..._or_'all')=Restablecer_preferencias_(key1,key2,..._or_'todas')
Find_unlinked_files=Buscar_archivos_desenlazados
Unselect_all=Deseleccionar_todo
@@ -1045,7 +1702,6 @@ Five_stars=Cinco_estrellas
Four_stars=Cuatro_estrellas
Help_on_special_fields=Ayuda_sobre_campos_especiales
Keywords_of_selected_entries=Palabras_clave_de_las_entradas_seleccionadas
-Manage_content_selectors=Getionar_selectores_de_contenido
Manage_keywords=Administrar_palabras_clave
No_priority_information=Sin_información_de_prioridad
No_rank_information=Sin_información_de_rango
@@ -1076,6 +1732,7 @@ You_have_changed_settings_for_special_fields.=Ha_cambiado_los_ajustes_para_campo
%0_entries_found._To_reduce_server_load,_only_%1_will_be_downloaded.=%0_entradas_encontradas._Para_reducir_la_carga_del_servidor,_sólo_%1_será(n)_descargada(s).
A_string_with_that_label_already_exists=Una_cadena_con_esa_etiqueta_ya_existe
Connection_to_OpenOffice/LibreOffice_has_been_lost._Please_make_sure_OpenOffice/LibreOffice_is_running,_and_try_to_reconnect.=La_conexión_con_OpenOffice/LibreOffice_se_ha_perdido._Asegúrese_de_que_OpenOffice/LibreOffice_está_ejecutándose_e_intente_reconectar.
+
Correct_the_entry,_and_reopen_editor_to_display/edit_source.=Corregir_la_entrada_y_reabrir_el_editor_para_mostrar/editar_fuente.
Could_not_connect_to_a_running_gnuserv_process._Make_sure_that_Emacs_or_XEmacs_is_running,<BR>and_that_the_server_has_been_started_(by_running_the_command_'server-start'/'gnuserv-start').=No_se_puede_conectar_con_un_proceso_gnuserv_ejecutándose._Asegúrese_de_que_Emacs_o_XEmacs_está_ejecutándose,<BR>y_que_el_servidor_se_ha_arrancado_(ejecutando_el_comando_'server-start'/'gnuserv-start').
Could_not_connect_to_running_OpenOffice/LibreOffice.=No_se_puede_conectar_a_un_OpenOffice/LibreOffice_en_ejecución.
@@ -1093,20 +1750,18 @@ Use_the_following_delimiter_character(s)\:=Usar_como_caracter(es)_delimitador(es
When_downloading_files,_or_moving_linked_files_to_the_file_directory,_prefer_the_BIB_file_location_rather_than_the_file_directory_set_above=Al_descargar_archivos_o_mover_archivos_enlazados_a_la_carpeta_de_archivos,_preferir_la_ubicación_del_archivo_BIB_antes_que_el_directorio_de_archivos_establecido_arriba.
Your_style_file_specifies_the_character_format_'%0',_which_is_undefined_in_your_current_OpenOffice/LibreOffice_document.=Su_archivo_de_estilo_especifica_el_formato_de_carácter_'%0',_que_no_está_definido_en_su_documento_OpenOffice/LibreOffice_actual.
Your_style_file_specifies_the_paragraph_format_'%0',_which_is_undefined_in_your_current_OpenOffice/LibreOffice_document.=Su_archivo_de_estilo_especifica_el_formato_de_párrafo_'%0',_que_no_está_definido_en_su_documento_OpenOffice/LibreOffice.
+
Searching...=Buscando...
You_have_selected_more_than_%0_entries_for_download._Some_web_sites_might_block_you_if_you_make_too_many_rapid_downloads._Do_you_want_to_continue?=Ha_seleccionado_más_de_%0_entradas_para_descargar._Algunos_sitios_web_podrían_bloquearle_si_hace_demasiadas_descargas._¿Desea_continuar?
Confirm_selection=Confirmar_selección
-Unknown_DOI\:_'%0'.=DOI_desconocido\:_'%0'.
Add_{}_to_specified_title_words_on_search_to_keep_the_correct_case=Añadir_{}_para_especificar_las_palabras_del_título_para_mantener_mayúsculas/minúsculas_correctamente
Import_conversions=Importar_conversiones
Please_enter_a_search_string=Introduzca_una_cadena_de_búsqueda,_por_favor
Please_open_or_start_a_new_database_before_searching=Abra_o_cree_una_nueva_base_de_datos_antes_de_buscar,_por_favor
-An_error_occurred_while_fetching_from_ADS_(%0)\:=Ocurrió_un_error_al_recuperar_desde_ADS_(%0)\:
-An_error_occurred_while_parsing_abstract=Ocurrió_un_error_mientras_se_analizaba_el_resumen
-Unknown_DiVA_entry\:_'%0'.=Entrada_DiVA_desconocida\:_'%0'.
-Get_BibTeX_entry_from_DiVA=Obtener_entrada_BibTeX_desde_DiVA
Log=Registro
+
Canceled_merging_entries=Cancelar_fusionado_de_entradas
+
Format_units_by_adding_non-breaking_separators_and_keeping_the_correct_case_on_search=Formatear_unidades_añadiendo_separadores_no_divisores_y_manteniendo_mayúsculas/minúsculas_correctamente_en_la_búsqueda
Merge_entries=Fusionar_entradas
Merged_entries=Fusionar_entradas_en_una_nueva_y_mantener_la_antigua
@@ -1118,8 +1773,10 @@ Show_DOI_first=Mostrar_DOI_en_primer_lugar
Show_URL_first=Mostrar_URL_en_primer_lugar
Use_Emacs_key_bindings=Usar_combinaciones_de_teclas_de_Emacs
You_have_to_choose_exactly_two_entries_to_merge.=Tiene_que_escoger_exactamente_dos_entradas_para_fusionar.
+
Update_timestamp_on_modification=Actualizar_marca_de_tiempo_al_modificar
All_key_bindings_will_be_reset_to_their_defaults.=Todas_las_combinaciones_de_teclas_serán_restablecidas_a_su_configuración_por_defecto
+
Automatically_set_file_links=Establecer_enlaces_de_archivo_automáticamente
Continue?=¿Continuar?
Resetting_all_key_bindings=Reestableciendo_todas_las_combinaciones_de_teclas
@@ -1127,29 +1784,36 @@ Hostname=Host
Invalid_setting=Ajuste_inválido
Network=Red
Please_specify_both_hostname_and_port=Especifique_tanto_nombre_de_host_como_puerto
-Port=Puerto
+Please_specify_both_username_and_password=Por_favor,_especifique_nombre_de_usuario_y_contraseña
+
Use_custom_proxy_configuration=Usar_configuración_de_proxy_personalizada
+Proxy_requires_authentication=El_proxi_requiere_autenticación
+Attention\:_Password_is_stored_in_plain_text\!=Atención\:_¡La_contraseña_está_almacenada_como_texto_plano!
Clear_connection_settings=Limpiar_ajustes_de_conexión
Cleared_connection_settings.=Ajustes_de_conexión_limpiados
+
Rebind_C-a,_too=Volver_a_combinar_C-a_también
+Rebind_C-f,_too=Recombinar_C-f,_también
+
Show_number_of_elements_contained_in_each_group=Mostrar_número_de_elementos_contenidos_en_cada_grupo
Open_folder=Abrir_carpeta
Searches_for_unlinked_PDF_files_on_the_file_system=Busca_archivos_PDF_sin_enlazar_en_el_sistema_de_archivos
-
Export_entries_ordered_as_specified=Exportar_entradas_según_el_orden_especificado
Export_sort_order=Criterio_de_ordenación_para_exportación
+Export_sorting=Exportar_ordenación
Newline_separator=Separador_de_nueva_línea
+
Save_entries_ordered_as_specified=Guardar_entradas_según_el_orden_especificado
Save_sort_order=Criterio_de_ordenación_para_guardar
Show_extra_columns=Mostrar_columnas_extra
Parsing_error=Error_analizando
illegal_backslash_expression=Expresión_de_barra_inclinada_ilegal
+
Move_to_group=Mover_al_grupo
Clear_read_status=Borrar_status_de_lectura
Convert_to_BibLatex_format_(for_example,_move_the_value_of_the_'journal'_field_to_'journaltitle')=Convertir_a_formato_BibLatex_(por_ejemplo,_mover_el_valor_del_campo_'journal'_a_'journaltitle')
-Could_not_apply_changes.=No_se_pudieron_aplicar_los_cambios
Deprecated_fields=Campos_obsoletos
Hide/show_toolbar=Mostrar/ocultar_barra_de_herramientas
No_read_status_information=No_hay_información_sobre_status_de_lectura
@@ -1161,119 +1825,108 @@ Save_selected_as_plain_BibTeX...=Guardar_seleccionados_como_BibTeX_plano...
Set_read_status_to_read=Establecer_estatus_de_lectura_a_Leído
Set_read_status_to_skimmed=Establecer_estatus_de_lectura_a_Vistazo
Show_deprecated_BibTeX_fields=Mostrar_campos_BibTeX_obsoletos
+
Show_gridlines=Mostrar_líneas_de_rejilla
Show_printed_status=Mostrar_estatus_de_impresion
Show_read_status=Mostrar_estatus_de_lectura
Table_row_height_padding=Relleno_de_altura_de_fila
-Marked_all_%0_selected_entries=Marcadas_todas_las_%0_entradas_seleccionadas
Marked_selected_entry=Entrada_marcada_seleccionadas
-Toggle_print_status=Cambiar_estatus_de_impresion
-Unmarked_all_%0_selected_entries=Desmarcadas_todas_las_%0_entradas_seleccionadas
+Marked_all_%0_selected_entries=Marcadas_todas_las_%0_entradas_seleccionadas
Unmarked_selected_entry=Entrada_seleccionada_desmarcada
+Unmarked_all_%0_selected_entries=Desmarcadas_todas_las_%0_entradas_seleccionadas
+Toggle_print_status=Cambiar_estatus_de_impresion
+
Unmarked_all_entries=Desmarcar_todas_las_entradas
Unable_to_find_the_requested_look_and_feel_and_thus_the_default_one_is_used.=No_se_puede_encontrar_el_aspecto_solicitado,_por_lo_que_se_usará_el_aspecto_por_defecto
-Could_not_open_browser.=No_se_puede_abrir_el_explorador.
Opens_JabRef's_GitHub_page=Abrir_la_página_de_JabRef_en_GitHub
-
-Rebind_C-f,_too=Recombinar_C-f,_también
-This_group_contains_all_entries._It_cannot_be_edited_or_removed.=Este_grupo_contiene_todas_las_entradas._No_puede_ser_eliminado_o_editado.
+Could_not_open_browser.=No_se_puede_abrir_el_explorador.
+Please_open_%0_manually.=
+The_link_has_been_copied_to_the_clipboard.=
Open_%0_file=Abrir_archivo_%0
Cannot_delete_file=No_se_puede_borrar_el_archivo
-Convert=Convertirº
-Delete_local_file=Eliminar_archivo_local
File_permission_error=Error_de_permisos_de_archivo
-Help_on_Name_Formatting=Ayuda_en_Formateo_de_Nombres
-Normalize_to_BibTeX_name_format=Normalizar_a_formato_de_nombre_BibTeX
Push_to_%0=Enviar_entradas_a_%0
+Path_to_%0=Ruta_hasta_%0
+Convert=Convertirº
+Normalize_to_BibTeX_name_format=Normalizar_a_formato_de_nombre_BibTeX
+Help_on_Name_Formatting=Ayuda_en_Formateo_de_Nombres
Add_new_file_type=Añadir_un_nuevo_tipo_de_archivo
-Follow_DOI_or_URL_link_and_try_to_locate_PDF_full_text_document=Seguir_DOI_o_URL_e_intentar_encontrar_PDF_de_texto_completo
+
Left_entry=Entrada_izquierda
-No_information_added=No_se_ha_añadido_información
+Right_entry=Entrada_derecha
+Use=Usar
Original_entry=Entrada_original
Replace_original_entry=Reemplazar_entrada_original
-Right_entry=Entrada_derecha
+No_information_added=No_se_ha_añadido_información
Select_at_least_one_entry_to_manage_keywords.=Seleccionar_al_menos_una_entrada_para_gestionar_palabras_clave.
-Use=Usar
-Changed_type_to_'%0'_for=Tipo_cambiado_a_'%0'_para
-Database_'%0'_has_changed.=La_base_de_datos_'%0'_ha_cambiado.
-Copy_\\cite{BibTeX_key}=Copiar_\\cite{clave_BibTeX}
-Copy_BibTeX_key_and_title=Copiar_clave_y_título_BibTeX
-File_rename_failed_for_%0_entries.=Ha_fallado_el_renombrado_para_%0_entradas.
-To_set_up,_go_to=Para_configurar,_vaya_a
-Search_%0=Buscar_en_%0
-Invalid_DOI\:_'%0'.=DOI_no_válida\:_'%0'.
-Could_not_connect_to_%0=No_se_puede_conectar_a_%0
-Path_to_%0=Ruta_hasta_%0
-
+OpenDocument_text=Texto_OpenDocument
+OpenDocument_spreadsheet=Hoja_de_cálculo_OpenDocument
+OpenDocument_presentation=Presentación_OpenDocument
%0_image=imagen_%0
-%0_problem(s)_found=%0_problema(s)_encontrado(s)
-'%0'_is_not_a_valid_ADS_bibcode.='%0'_no_es_un_bibcode_ADS_válido
-Accepting_the_change_replaces_the_complete_groups_tree_with_the_externally_modified_groups_tree.=Aceptar_el_cambio_reemplaza_el_árbol_completo_de_grupos_por_el_árbol_de_grupos_modificado_externamente
Added_entry=Entrada_añadida
-Added_new_'%0'_entry.=Añadida_la_nueva_entrada_'%0'
-Deleted_entry=Entrada_eliminada
-Discard_changes=Descartar_cambios
-Donate_to_JabRef=Donar_a_JabRef
-Export_with_selected_format=Exportar_con_el_formato_seleccionado
-Field_is_missing=No_se_encuentra_el_campo
-Filled=Relleno
-From_import=Entrada_importada
-Keep_left=mantener_izquierdo
-Keep_merged_entry_only=Mantener_sólo_la_entrada_fusionada
-Keep_right=Mantener_derecho
-Merged_BibTeX_source_code=Código_fuente_BibTex_fusionado
Modified_entry=Entrada_modificada
+Deleted_entry=Entrada_eliminada
Modified_groups_tree=Árbol_de_grupos_modificado
-Multiple_entries_selected._Do_you_want_to_change_the_type_of_all_these_to_'%0'?=Múltiples_entradas_seleccionadas._¿Desea_cambiar_el_tipo_de_todas_ellas_a_'%0'?
-No_problems_found.=No_se_encontraron_problemas.
-Old_entry=Entrada_antigua
-OpenDocument_presentation=Presentación_OpenDocument
-OpenDocument_spreadsheet=Hoja_de_cálculo_OpenDocument
-OpenDocument_text=Texto_OpenDocument
-Please_move_the_file_manually_and_link_in_place.=Por_favor,_mueva_el_fichero_manualmente_y_enlance_en_el_destino
-Print_entry_preview=Imprimir_vista_previa_de_la_entrada
-Really_delete_the_%0_selected_entries?=¿Realmente_desea_eliminar_%0_entradas?
-Really_delete_the_selected_entry?=¿Borrar_realmente_la_entrada_seleccionada?
Removed_all_groups=Se_eliminaron_todos_los_grupos
-Return_to_JabRef=Volver_a_JabRef
-Save_changes=Guardar_cambios
+Accepting_the_change_replaces_the_complete_groups_tree_with_the_externally_modified_groups_tree.=Aceptar_el_cambio_reemplaza_el_árbol_completo_de_grupos_por_el_árbol_de_grupos_modificado_externamente
Select_export_format=Seleccionar_formato_para_exportar
+Return_to_JabRef=Volver_a_JabRef
+Please_move_the_file_manually_and_link_in_place.=Por_favor,_mueva_el_fichero_manualmente_y_enlance_en_el_destino
+Could_not_connect_to_%0=No_se_puede_conectar_a_%0
Warning\:_%0_out_of_%1_entries_have_undefined_BibTeX_key.=Atención:_%0_de_un_total_de_%1_entradas_tienen_clave_BibTex_indefinida.
-large_capitals_are_not_masked_using_curly_brackets_{}=la_máscara_no_afecta_a_las_mayúsculas_al_usar_llaves_{}
occurrence=incidencia
-should_contain_a_four_digit_number=debería_contener_un_número_de_cuatro_dígitos
-should_contain_a_valid_page_number_range=debería_contener_un_número_de_página_válido
-should_end_with_a_name=debería_acabar_por_un_nombre
+Added_new_'%0'_entry.=Añadida_la_nueva_entrada_'%0'
+Multiple_entries_selected._Do_you_want_to_change_the_type_of_all_these_to_'%0'?=Múltiples_entradas_seleccionadas._¿Desea_cambiar_el_tipo_de_todas_ellas_a_'%0'?
+Changed_type_to_'%0'_for=Tipo_cambiado_a_'%0'_para
+Really_delete_the_selected_entry?=¿Borrar_realmente_la_entrada_seleccionada?
+Really_delete_the_%0_selected_entries?=¿Realmente_desea_eliminar_%0_entradas?
+Keep_merged_entry_only=Mantener_sólo_la_entrada_fusionada
+Keep_left=mantener_izquierdo
+Keep_right=Mantener_derecho
+Old_entry=Entrada_antigua
+From_import=Entrada_importada
+No_problems_found.=No_se_encontraron_problemas.
+%0_problem(s)_found=%0_problema(s)_encontrado(s)
+Save_changes=Guardar_cambios
+Discard_changes=Descartar_cambios
+Database_'%0'_has_changed.=La_base_de_datos_'%0'_ha_cambiado.
+Print_entry_preview=Imprimir_vista_previa_de_la_entrada
+Copy_\\cite{BibTeX_key}=Copiar_\\cite{clave_BibTeX}
+Copy_BibTeX_key_and_title=Copiar_clave_y_título_BibTeX
+File_rename_failed_for_%0_entries.=Ha_fallado_el_renombrado_para_%0_entradas.
+To_set_up,_go_to=Para_configurar,_vaya_a
+Merged_BibTeX_source_code=Código_fuente_BibTex_fusionado
+Invalid_DOI\:_'%0'.=DOI_no_válida\:_'%0'.
should_start_with_a_name=debería_comenzar_por_un_nombre
+should_end_with_a_name=debería_acabar_por_un_nombre
unexpected_closing_curly_bracket=Llave_de_cierre_inesperada
unexpected_opening_curly_bracket=Llave_de_apertura_inesperada
+capital_letters_are_not_masked_using_curly_brackets_{}=la_máscara_no_afecta_a_las_mayúsculas_al_usar_llaves_{}
+should_contain_a_four_digit_number=debería_contener_un_número_de_cuatro_dígitos
+should_contain_a_valid_page_number_range=debería_contener_un_número_de_página_válido
+Filled=Relleno
+Field_is_missing=No_se_encuentra_el_campo
+Search_%0=Buscar_en_%0
-Advanced_search_active.=Búsqueda_avanzada_activa.
-Found_%0_results.=Se_encontraron_%0_resultados.
-No_results_found.=No_se_encontraron_resultados.
-Normal_search_active.=Búsqueda_normal_activa.
-Search_globally=Buscar_globalmente.
-Search_in_all_open_databases=Buscar_en_todas_las_bases_de_datos_abiertas.
Search_results_in_all_databases_for_%0=Resultados_para_%0_en_todas_las_bases_de_datos
Search_results_in_database_%0_for_%1=Resultados_para_%1_en_la_base_de_datos_&0
-This_search_contains_entries_in_which=Esta_búsqueda_contiene_entradas_en_las_cuales
+Search_globally=Buscar_globalmente.
+No_results_found.=No_se_encontraron_resultados.
+Found_%0_results.=Se_encontraron_%0_resultados.
+Advanced_search_active.=Búsqueda_avanzada_activa.
+Normal_search_active.=Búsqueda_normal_activa.
+plain_text=texto_plano
This_search_contains_entries_in_which_any_field_contains_the_regular_expression_<b>%0</b>=Esta_búsqueda_contiene_entradas_en_las_cuales_cualquier_campo_contiene_la_expresión_regular_<b>%0</b>
This_search_contains_entries_in_which_any_field_contains_the_term_<b>%0</b>=Esta_búsqueda_contiene_entradas_en_las_cuales_cualquier_campo_contiene_el_término_<b>%0</b>
-plain_text=texto_plano
-
-Attention\:_Password_is_stored_in_plain_text\!=Atención\:_¡La_contraseña_está_almacenada_como_texto_plano!
-Please_specify_both_username_and_password=Por_favor,_especifique_nombre_de_usuario_y_contraseña
-Proxy_requires_authentication=El_proxi_requiere_autenticación
+This_search_contains_entries_in_which=Esta_búsqueda_contiene_entradas_en_las_cuales
-An_autosave_file_was_found_for_this_database._This_could_indicate_that_JabRef_did_not_shut_down_cleanly_last_time_the_file_was_used.=_Se_ha_encontrado_un_fichero_de_autoguardado_de_esta_base_de_datos._Esto_podría_indicar_que_JabRef_no_se_cerró_correctamente_la_última_vez_que_se_usó_el_archivo.
-Note\:_A_full_text_search_is_currently_not_supported_for_%0=Nota\:_Por_el_momento_no_se_soporta_la_búsqueda_de_texto_completo_para_%0
Unable_to_autodetect_OpenOffice/LibreOffice_installation._Please_choose_the_installation_directory_manually.=No_se_puede_autodetectar_OpenOffice/LibreOffice._Por_favor,_escoja_el_directorio_de_instalación_manualmente.
JabRef_no_longer_supports_'ps'_or_'pdf'_fields.<br>File_links_are_now_stored_in_the_'file'_field_and_files_are_stored_in_an_external_file_directory.<br>To_make_use_of_this_feature,_JabRef_needs_to_upgrade_file_links.<br><br>=Jabref_ya_no_soporta_los_campos_'ps'_o_'pdf'.<br>Ahora_los_enlaces_a_archivo_se_guardan_en_el_campo_'archivo'_y_los_archivos_se_guardan_en_un_directorio_externo.<br>Para_hacer_uso_de_esta_característica,_JabRef_necesita_actualizar_los_enlaces.<br><br>
This_database_uses_outdated_file_links.=Esta_base_de_datos_usa_enlaces_obsoletos
@@ -1313,53 +1966,32 @@ Resolve_duplicate_BibTeX_keys=Resolver_claves_BibTeX_duplicadas
Save_all=Guardar_todo
String_dialog,_add_string=Diálogo_de_cadena,_añadir_cadena
String_dialog,_remove_string=Diálogo_de_cadena,_eliminar_cadena
-Switch_preview_layout=Cambiar_esquema_de_previsualización
Synchronize_files=Sincronizar_archivos
Unabbreviate=Eliminar_abreviatura
-
should_contain_a_protocol=Debería_contener_un_protocolo
Copy_preview=Copiar_vista_previa
-
Automatically_setting_file_links=Estableciendo_automáticamente_enlaces_de_archivo
Regenerating_BibTeX_keys_according_to_metadata=Regenerando_claves_BibTeX_de_acuerdo_a_los_metadatos
No_meta_data_present_in_BIB_file._Cannot_regenerate_BibTeX_keys=No_hay_metadatos_en_el_BIB_file._No_se_pueden_regenerar_las_claves_BibTex
-
Regenerate_all_keys_for_the_entries_in_a_BibTeX_file=Regenerar_todas_las_claves_para_las_entradas_de_un_archivo_BibTeX
-
Show_debug_level_messages=Mostrar_mensajes_de_nivel_de_depuración
-
-Export_sorting=Exportar_ordenación
-
-New_%0_database=Nueva_base_de_datos_%0
-
-New_%0_database_created.=Creada_la_nueva_base_de_datos_%0
-
-No_entry_found_for_ISBN_%0_at_www.ebook.de=No_se_encontró_entrada_para_el_ISBN_%0_en_www.ebook.de
-
-Save_actions=Guardar_acciones
-Enable_save_actions=Habilitar_guardado_de_acciones
-Always_reformat_BIB_file_on_save_and_export=Siempre_reformatear_el_fichero_BIB_al_guardar_y_exportar
Default_bibliography_mode=Modo_de_bibliografía_por_defecto
-
-
+New_%0_database_created.=Creada_la_nueva_base_de_datos_%0
Show_only_preferences_deviating_from_their_default_value=Mostrar_sólo_preferencias_derivadas_de_su_valor_por_defecto
default=defecto
key=clave
type=tipo
value=valor
-
Show_preferences=Mostrar_preferencias
-
-
+Save_actions=Guardar_acciones
+Enable_save_actions=Habilitar_guardado_de_acciones
Other_fields=Otros_campos
Show_remaining_fields=Mostrar_campos_restantes
link_should_refer_to_a_correct_file_path=el_enlace_debería_referirse_a_una_ruta_de_acceso_correcta
-
abbreviation_detected=abreviatura_detectada
wrong_entry_type_as_proceedings_has_page_numbers=tipo_de_entrada_incorrecto,_ya_que_proceedings_tiene_números_de_página
-
Abbreviate_journal_names=Abreviar_nombres_de_publicación
Abbreviating...=Abreviando...
Adding_fetched_entries=Añadiendo_las_entradas_recuperadas
@@ -1371,28 +2003,22 @@ Unabbreviate_journal_names=Eliminar_abreviatura_de_nombres_de_publicación
Unabbreviating...=Eliminando_abreviaturas...
Usage=Uso
+
+Adds_{}_brackets_around_acronyms,_month_names_and_countries_to_preserve_their_case.=Añade_llaves_alrededor_de_los_acrónimos,_nombres_de_mes_y_países_para_preservar_las_mayúsculas
Are_you_sure_you_want_to_reset_all_settings_to_default_values?=¿Está_seguro_de_querer_reiniciar_todos_los_ajustes_a_sus_valores_por_defecto?
Reset_preferences=Preferencias
-
Ill-formed_entrytype_comment_in_BIB_file=Comentario_de_tipo_de_entrada_mal_formado_en_fichero_bib
+
+Move_linked_files_to_default_file_directory_%0=Mover_archivos_enlazados_a_la_carpeta_de_archivos_por_defecto
+
Clipboard=Portapapeles
Could_not_paste_entry_as_text\:=No_se_puede_pegar_la_entrada_como_texto\:
Do_you_still_want_to_continue?=¿Aún_desea_continuar?
This_action_will_modify_the_following_field(s)_in_at_least_one_entry_each\:=Esta_acción_modificará_los_siguientes_campos_en_al_menos_una_entrad_por_cada_uno\:
This_could_cause_undesired_changes_to_your_entries.=Esto_podría_causar_cambios_indeseados_a_sus_entradas.
-
-Disable_highlight_groups_matching_entries=Deshabilitar_el_resaltado_de_grupos_en_que_coincidad_entradas
Run_field_formatter\:=Ejecutar_formateador_de_campo\:
-
-Adds_{}_brackets_around_acronyms,_month_names_and_countries_to_preserve_their_case.=Añade_llaves_alrededor_de_los_acrónimos,_nombres_de_mes_y_países_para_preservar_las_mayúsculas
-Converts_units_to_LaTeX_formatting.=Convierte_unidades_a_formato_LaTeX
-Does_nothing.=No_hace_nada
-
-
Table_font_size_is_%0=El_tamaño_de_tipo_de_letra_es_%0
-
-Move_linked_files_to_default_file_directory_%0=Mover_archivos_enlazados_a_la_carpeta_de_archivos_por_defecto
-
+%0_import_canceled=Importación_desde_%0_cancelada
Internal_style=Estilo_interno
Add_style_file=Añadir_archivo_de_estilo
Are_you_sure_you_want_to_remove_the_style?=¿Está_seguro_de_querer_eliminar_el_archivo?
@@ -1400,7 +2026,6 @@ Current_style_is_'%0'=El_estilo_actual_es_'%0'
Remove_style=Eliminar_estilo
Select_one_of_the_available_styles_or_add_a_style_file_from_disk.=Seleccion_uno_de_los_estilos_disponibles_o_añada_un_archivo_de_estilo_desde_el_disco
You_must_select_a_valid_style_file.=Debe_seleccionar_un_fichero_de_estilo_válidoº
-
Reload=Recargar
Capitalize=Capitalizar
@@ -1411,9 +2036,11 @@ Changes_all_letters_to_upper_case.=Cambia_todas_las_letras_a_mayúscula
Changes_the_first_letter_of_all_words_to_capital_case_and_the_remaining_letters_to_lower_case.=Cambia_la_primera_letra_de_todas_las_palabras_a_mayúscula_y_el_resto_a_minúscula
Cleans_up_LaTeX_code.=Limpia_el_código_LaTeX
Converts_HTML_code_to_LaTeX_code.=Convierte_código_HTML_a_código_LaTeX
+Converts_HTML_code_to_Unicode.=
Converts_LaTeX_encoding_to_Unicode_characters.=Convierte_codificación_LaTeX_a_caracteres_Unicode
Converts_Unicode_characters_to_LaTeX_encoding.=Conviert_caracteres_Unicode_a_codificación_LaTeX
Converts_ordinals_to_LaTeX_superscripts.=Convierte_ordinales_LaTeX_a_superíndices
+Converts_units_to_LaTeX_formatting.=Convierte_unidades_a_formato_LaTeX
HTML_to_LaTeX=HTML_a_LaTeX
LaTeX_cleanup=Limpieza_LaTeX
LaTeX_to_Unicode=LaTeX_a_Unicode
@@ -1437,16 +2064,13 @@ Title_case=Mayúsculas/minúsculas_del_título
Unicode_to_LaTeX=Unicode_a_LaTeX
Units_to_LaTeX=Unidades_a_LaTeX
Upper_case=Mayúsculas
+Does_nothing.=No_hace_nada
Identity=Identidad
-
Clears_the_field_completely.=Limpia_el_campo_completamente.
Directory_not_found=Directorio_no_encontrado
Main_file_directory_not_set\!=¡El_directorio_de_archivos_principal_no_está_establecido!
-
This_operation_requires_exactly_one_item_to_be_selected.=Esta_operación_requiere_seleccionar_exactamente_un_elemento.
-
Importing_in_%0_format=Importando_en_formato_%0
-
Female_name=Nombre_femenino
Female_names=Nombres_femeninos
Male_name=Nombre_masculino
@@ -1455,220 +2079,236 @@ Mixed_names=Nombres_mixtos
Neuter_name=Nombre_neutro
Neuter_names=Nombres_neutros
+Lookup_DOI=Buscar_DOI
-Lookup_DOI=
-
-Audio_CD=
-British_patent=
-British_patent_request=
+Audio_CD=Audio_CD
+British_patent=Patente_británica
+British_patent_request=Solicitud_de_patente_británica
Candidate_thesis=
-Collaborator=
-Column=
-Compiler=
-Continuator=
-Data_CD=
-Editor=
-European_patent=
-European_patent_request=
-Founder=
-French_patent=
-French_patent_request=
-German_patent=
-German_patent_request=
-Line=
-Master's_thesis=
-Page=
-Paragraph=
-Patent=
-Patent_request=
-PhD_thesis=
-Redactor=
-Research_report=
-Reviser=
-Section=
-Software=
-Technical_report=
-U.S._patent=
-U.S._patent_request=
-Verse=
-
-change_entries_of_group=
-odd_number_of_unescaped_'\#'=
-
-Plain_text=
-Show_diff=
-character=
-word=
-
-Show_symmetric_diff=
-
-HTML_encoded_character_found=
-
-booktitle_ends_with_'conference_on'=
-All_external_files=
-
-OpenOffice/LibreOffice_integration=
-
-incorrect_control_digit=
-incorrect_format=
-
-Expected_"%0"_to_contain_whitespace=
-Syntax_error_in_regular-expression_pattern=
-
-Copy_version_to_clipboard=
-Copied_version_to_clipboard=
-BibTeX_key=
-Message=
-
-Get_fulltext=
-
-Download_from_URL=
-
-Decryption_not_supported.=
-
-Cleared_'%0'_for_%1_entries=Ajustes_de_'%0'_para_%1_entradas
+Collaborator=Colaborador
+Column=Columna
+Compiler=Compilador
+Continuator=Continuador
+Data_CD=C_de_datos
+Editor=Editor
+European_patent=Patente_Europea
+European_patent_request=Solicitud_de_patente_europea
+Founder=Fundador
+French_patent=Patente_francesa
+French_patent_request=Solicitud_de_patente_francesa
+German_patent=Patente_alemana
+German_patent_request=Solicitud_de_patente_alemana
+Line=Línea
+Master's_thesis=Tesis de máster
+Page=Página
+Paragraph=Párrafo
+Patent=Patente
+Patent_request=Solicitud_de_patente
+PhD_thesis=Tesis_doctoral
+Redactor=Redactor
+Research_report=Informe_de_investigación
+Reviser=Revisor
+Section=Sección
+Software=Software
+Technical_report=Informe_técnico
+U.S._patent=Patente_estadounidense
+U.S._patent_request=Solicitud_de_patente_estadounidense
+Verse=Verso
+
+change_entries_of_group=cambiar_entradas_del_grupo
+odd_number_of_unescaped_'\#'=número_impar_de_'\#'_sin_escapar
+
+Plain_text=Texto_plano
+Show_diff=Mostrar_diff
+character=carácter
+word=palabra
+Show_symmetric_diff=Mostrar_diff_simétrico
+
+HTML_encoded_character_found=Se_han_encontrado_caracteres_codificados_HTML
+booktitle_ends_with_'conference_on'=El_título_del_libro_acaba_con_'conference_on'
+
+All_external_files=Todos_los_ficheros_externos
+
+OpenOffice/LibreOffice_integration=Integración_con_OpenOffice/LibreOffice
+
+incorrect_control_digit=dígito_de_control_incorrecto
+incorrect_format=formato_incorrecto
+Copy_version_to_clipboard=Copiar_versión_al_portapapeles
+Copied_version_to_clipboard=Version_copiada_al_portapapeles
+
+BibTeX_key=Clave_BibTeX
+Message=Mensaje
+Decryption_not_supported.=Desencriptación_no_soportada
+
+Cleared_'%0'_for_%1_entries=Limpieza_de_'%0'_para_%1_entradas
Set_'%0'_to_'%1'_for_%2_entries=Establecer_'%0'_a_'%1'_para_%2_entradas
-Toggled_'%0'_for_%1_entries=Cambiada_'%0'_para_%1_entradas
-
-Check_for_updates=
-Download_update=
-New_version_available=
-Installed_version=
-Remind_me_later=
-Ignore_this_update=
-Could_not_connect_to_the_update_server.=
-Please_try_again_later_and/or_check_your_network_connection.=
-To_see_what_is_new_view_the_changelog.=
-A_new_version_of_JabRef_has_been_released.=
-JabRef_is_up-to-date.=
-Latest_version=
-
-Please_open_%0_manually.=
-
-The_link_has_been_copied_to_the_clipboard.=
-
-Online_help_forum=
-
-Custom=
-
-Converts_HTML_code_to_Unicode.=
-
-Open_console=
-Use_default_terminal_emulator=
-Execute_command=
-Note\:_Use_the_placeholder_%0_for_the_location_of_the_opened_database_file.=
-Executing_command_\"%0\"...=
-Error_occured_while_executing_the_command_\"%0\".=
-
-Reformat_ISSN=
-
-Unable_to_generate_new_database=
-
-Export_cited=
-Countries_and_territories_in_English=
-Electrical_engineering_terms=
-Enabled=
-Internal_list=
-Months_and_weekdays_in_English=
-The_text_after_the_last_line_starting_with_\#_will_be_used=
-
-Add_protected_terms_file=
-Are_you_sure_you_want_to_remove_the_protected_terms_file?=
-Remove_protected_terms_file=
-
-Manage_protected_terms_files=
-
-Add_selected_text_to_list=
-Add_{}_around_selected_text=
-Format_field=
-New_protected_terms_file=
-
-
-change_field_%0_of_entry_%1_from_%2_to_%3=
-change_key_from_%0_to_%1=
-change_string_content_%0_to_%1=
-change_string_name_%0_to_%1=
-change_type_of_entry_%0_from_%1_to_%2=
-insert_entry_%0=
-insert_string_%0=
-remove_entry_%0=
-remove_string_%0=
-
-undefined=
-Cannot_get_info_based_on_given_%0\:_%1=No_se_encuentra_información_basada_en_el_%0_%1
-
+Toggled_'%0'_for_%1_entries=Cambio_de_'%0'_para_%1_entradas
+
+Check_for_updates=Comprobar_actualizaciones
+Download_update=Descargar_actualización
+New_version_available=Nueva_versión_disponible
+Installed_version=Versión_instalada
+Remind_me_later=Recordármelo_después
+Ignore_this_update=Ignorar_esta_actualización
+Could_not_connect_to_the_update_server.=No_se_puede_conectar_al_servidor_de_actualizaciones
+Please_try_again_later_and/or_check_your_network_connection.=Por_favor,_inténtelo_de_nuevo_más_tarde_o_compruebe_su_conexión_a_la_red.
+To_see_what_is_new_view_the_changelog.=Para_ver_qué_hay_de_nuevo,_vea_el_resgistro_de_cambios.
+A_new_version_of_JabRef_has_been_released.=Se_ha_lanzado_una_nueva_versión_de_JabRef
+JabRef_is_up-to-date.=JabRef_está_actualizado.
+Latest_version=Última_versión
+Online_help_forum=Foro_de_ayuda_online
+Custom=Personalizado
+
+Export_cited=Exportar_citados
+Unable_to_generate_new_database=No_se_puede_generar_la_nueva_base_de_datos
+
+Open_console=Abrir_consola
+Use_default_terminal_emulator=Usar_emulador_de_consola_por_defecto
+Execute_command=Ejecutar_comando
+Note\:_Use_the_placeholder_%0_for_the_location_of_the_opened_database_file.=Nota\:usar_el_marcador_%0_para_la_ubicación_de_la_base_de_datos_abierta
+Executing_command_\"%0\"...=Ejecutando_el_comando_\"%0"\...
+Error_occured_while_executing_the_command_\"%0\".=Error_durante_la_ejecución_del_comando_\"%0"\.
+Reformat_ISSN=Reformatear_ISSN
+
+Countries_and_territories_in_English=Países_y_territorios_en_inglés.
+Electrical_engineering_terms=Términos_de_ingeniería_electrónica
+Enabled=Habilitado
+Internal_list=Lista_interna
+Manage_protected_terms_files=Gestionar_ficheros_detérminos_protegidos
+Months_and_weekdays_in_English=Meses_y_días_de_la_semana_en_inglés
+The_text_after_the_last_line_starting_with_\#_will_be_used=Se_usará_el_texto_después_de_la_última_línea_con_\#
+Add_protected_terms_file=Añadir_archivo_de_términos_protegidos
+Are_you_sure_you_want_to_remove_the_protected_terms_file?=¿Está_seguro_de_querer_eliminar_el_archivo_de_términos_protegidos?
+Remove_protected_terms_file=Eliminar_el_archivo_de_términos_protegidos
+Add_selected_text_to_list=Añadir_texto_seleccionado_a_la_lista
+Add_{}_around_selected_text=Añadir_{}_alrededor_del_texto_seleccionado
+Format_field=Formatear_campo
+New_protected_terms_file=Nuevo_archivo_de_términos_protegidos
+change_field_%0_of_entry_%1_from_%2_to_%3=Cambiar_campo_%0_de_la_entrada_%1_de_%2_a_%3
+change_key_from_%0_to_%1=cambiar_clave_de_%0_a_%1
+change_string_content_%0_to_%1=cambiar_contenido_de_la_cadena_%0_a_%1
+change_string_name_%0_to_%1=cambiar_el_nombre_%0_a_%1
+change_type_of_entry_%0_from_%1_to_%2=cambiar_el_tipo_de_la_entrada_%0_de_%1_a_%2
+insert_entry_%0=insertar_entrada_%0
+insert_string_%0=insertar_cadena_%0
+remove_entry_%0=eliminar_entrada_%0
+remove_string_%0=eliminar_cadena_%0
+undefined=No_definido
+Cannot_get_info_based_on_given_%0\:_%1=No_se_encuentra_información_basada_en_%0
Get_BibTeX_data_from_%0=Obtener_datos_BibTeX_desde_%0
-No_%0_found=
-
+No_%0_found=No_se_encontró_%0
Entry_from_%0=Entrada_desde_%0
-
Merge_entry_with_%0_information=Fusionar_entrada_con_informaciçon_%0
Updated_entry_with_info_from_%0=Entrada_actualizada_con_información_del_%0
-Connection=
-Host=
-Database=
-User=
-Connection_error=
-Driver_error=
-Connection_to_%0_server_established.=
-Required_field_"%0"_is_empty.=
-
-%0_driver_not_available.=
-
-The_connection_to_the_server_has_been_terminated.=
-
-Connection_lost.=
-Reconnect=
-Work_offline=
-
-Working_offline.=
-
-Update_refused.=
-Update_refused=
-Local_entry=
-Shared_entry=
-Update_could_not_be_performed_due_to_existing_change_conflicts.=
-You_are_not_working_on_the_newest_version_of_BibEntry.=
-Local_version\:_%0=
-Shared_version\:_%0=
-Please_merge_the_shared_entry_with_yours_and_press_"Merge_entries"_to_resolve_this_problem.=
-Canceling_this_operation_will_leave_your_changes_unsynchronized._Cancel_anyway?=
-The_BibEntry_you_currently_work_on_has_been_deleted_on_the_shared_side._Hit_"Keep"_to_recover_the_entry.=
-Cannot_cite_entries_without_BibTeX_keys._Generate_keys_now?=
-New_technical_report=
-
-%0_file=
-Custom_layout_file=
-Protected_terms_file=
-Style_file=
-
-Open_OpenOffice/LibreOffice_connection=
-
-You_must_enter_at_least_one_field_name=
-
-
-Non-ASCII_encoded_character_found=
-
-Toggle_web_search_interface=
-Background_color_for_resolved_fields=
-Color_code_for_resolved_fields=
-%0_files_found=
-%0_of_%1=
-One_file_found=
-The_import_finished_with_warnings\:=
-There_was_one_file_that_could_not_be_imported.=
-There_were_%0_files_which_could_not_be_imported.=
-
-Migration_help_information=
-Entered_database_has_obsolete_structure_and_is_no_longer_supported.=
-However,_a_new_database_was_created_alongside_the_pre-3.6_one.=
-
-Click_here_to_learn_about_the_migration_of_pre-3.6_databases.=
-
-Connecting...=
-Opens_JabRef's_Facebook_page=
-Opens_JabRef's_blog=
-Opens_JabRef's_website=
-
-Opens_a_link_where_the_current_development_version_can_be_downloaded=
-See_what_has_been_changed_in_the_JabRef_versions=
+Connection=Conexión
+Connecting...=Conectando...
+Host=Host
+Port=Puerto
+Database=Base_de_datos
+User=Usuario
+Connect=Conectar
+Connection_error=Error_de_conexión
+Connection_to_%0_server_established.=Se_ha_establecido_conexión_con_el_servidor_%0.
+Required_field_"%0"_is_empty.=El_campo_%0_requerido_está_vacío
+%0_driver_not_available.=El_driver_%0_no_está_disponible.
+The_connection_to_the_server_has_been_terminated.=Se_ha_finalizado_la_conexión_con_el_servidor_%0.
+Connection_lost.=Conexión_perdida.
+Reconnect=Reconectar
+Work_offline=Trabajar_sin_conexión
+Working_offline.=Trabajando_sin_conexión
+Update_refused.=Actualización_rechazada.
+Update_refused=Actualización_rechazada
+Local_entry=Entrada_local
+Shared_entry=Entrada_compartida
+Update_could_not_be_performed_due_to_existing_change_conflicts.=No_se_pudo_actualizar_debido_a_los_conflictos_de_cambio_existentes.
+You_are_not_working_on_the_newest_version_of_BibEntry.=No_está_trabajando_con_la_versión_más_reciente_de_BibEntry.
+Local_version\:_%0=Versión_local\:_%0
+Shared_version\:_%0=Versión_compartida\:_%0
+Please_merge_the_shared_entry_with_yours_and_press_"Merge_entries"_to_resolve_this_problem.=Por_favor,_fusione_la_entrada_compartida_con_la_suya_y_presione_"Fusionar_entradas"_para_resolver_el_problema.
+Canceling_this_operation_will_leave_your_changes_unsynchronized._Cancel_anyway?=Cancelar_la_operación_dejará_sus_cambios_sin_sincronizar._¿Cancelar_de_todos_modos?
+Shared_entry_is_no_longer_present=La_entrada_compartida_ya_no_está_presente.
+The_BibEntry_you_currently_work_on_has_been_deleted_on_the_shared_side.=La_BibEntry_en_la_que_trabaja_actualmente_ha_sido_eliminada_en_la_parte_compartida.
+You_can_restore_the_entry_using_the_"Undo"_operation.=Puede_restaurar_la_entrada_mediante_la_operación_"Deshacer"
+Remember_password?=¿Recordar_contraseña?
+You_are_already_connected_to_a_database_using_entered_connection_details.=Ya_esa_conectado_a_una_vase_de_datos_usando_los_detalles_de_la_conexión_introducidos.
+
+Cannot_cite_entries_without_BibTeX_keys._Generate_keys_now?=No_se_puede_citar_entradas_sin_las_claves_BibTeX._¿Generar_ahora?
+New_technical_report=Nuevo_informe_técnico
+
+%0_file=Archvo_%0
+Custom_layout_file=Archivo_de_diseño_personalizado
+Protected_terms_file=Archivo_de_términos_protegidos
+Style_file=Archivo_de_estilo
+
+Open_OpenOffice/LibreOffice_connection=Conexión_OpenOffice/LibreOffice
+You_must_enter_at_least_one_field_name=Debe_introducir,_al_menos,_un_nombre_de_campo
+Non-ASCII_encoded_character_found=Se_han_encontrado_caracteres_con_codificación_no-ASCII
+Toggle_web_search_interface=Cambiar_interfaz_de_búsqueda_web
+Background_color_for_resolved_fields=Color_de_fondo_para_campos_resueltos
+Color_code_for_resolved_fields=Código_de_color_para_campos_resueltos
+%0_files_found=Se_encontraron_%0_archivos
+%0_of_%1=%0_de_%1
+One_file_found=Se_encontró_un_archivo
+The_import_finished_with_warnings\:=La_importación_finalizó_con_las_siguientes_alertas\:
+There_was_one_file_that_could_not_be_imported.=No_se_pudo_importar_un_archivo.
+There_were_%0_files_which_could_not_be_imported.=No_se_pudieron_importar_%0_archivos.
+
+Migration_help_information=Información_de_ayuda_para_la_migración
+Entered_database_has_obsolete_structure_and_is_no_longer_supported.=La_base_de_datos_introducida_tiene_una_estructura_obsoleta_y_no_se_soporta.
+However,_a_new_database_was_created_alongside_the_pre-3.6_one.=En_todo_caso,_una_nueva_base_de_datos_ha_sido_creada_junto_a_la_previa_a_la_versión_3.6.
+Click_here_to_learn_about_the_migration_of_pre-3.6_databases.=Haga_click_aquí_para_aprender_sobre_la_migración_de_bases_de_datos_de_versiones_previas_a_la_3.6
+Opens_JabRef's_Facebook_page=Abrir_Facebook_de_JabRef
+Opens_JabRef's_blog=Abrir_el_blog_de_JabRef
+Opens_JabRef's_website=Abrir_el_sitio_web_de_JabRef
+Opens_a_link_where_the_current_development_version_can_be_downloaded=Abre_un_enlace_donde_descarga_la_versión_de_desarrollo
+See_what_has_been_changed_in_the_JabRef_versions=Vea_lo_que_se_ha_cambiado_en_las_versiones_de_JabRef
+Referenced_BibTeX_key_does_not_exist=La_clave_BibTex_referenciada_no_existe
+Finished_downloading_full_text_document_for_entry_%0.=Se_ha_completado_la_descarga_del_texto_completo_para_la_entrada_%0.
+Full_text_document_download_failed_for_entry_%0.=Falló_la_descarga_del_texto_completo_para_la_entrada_%0.
+Look_up_full_text_documents=Buscar_textos_completos
+You_are_about_to_look_up_full_text_documents_for_%0_entries.=Está_a_punto_de_buscar_textos_completos_para_%0_entradas
+last_four_nonpunctuation_characters_should_be_numerals=los_últimos_caracteres_de_no-puntuación_deberían_ser_números.
+shared=compartido
+should_contain_an_integer_or_a_literal=debería_contener_un_entero_o_un_literal
+should_have_the_first_letter_capitalized=debería_tener_la_primera_letra_mayúscula
+
+ID=ID
+ID_type=Tipo_de_ID
+ID-based_entry_generator=Generador_de_entradas_basado_en_ID
+Fetcher_'%0'_did_not_find_an_entry_for_id_'%1'.=El_recolector_'%0'_no_encontró_entradas_para_la_id_'%1'.
+
+Select_first_entry=Seleccionar_primera_entrada
+Select_last_entry=Seleccionar_última_entrada
+
+Invalid_ISBN\:_'%0'.=El_ISBN_'%0'_no_es_válido.
+should_be_an_integer_or_normalized=debería_ser_normalizado_o_entero
+should_be_normalized=debería_ser_normalizado
+
+Empty_search_ID=Vaciar_ID_de_búsqueda
+The_given_search_ID_was_empty.=La_ID_de_búsqueda_está_vacía.
+Copy_BibTeX_key_and_link=Copiar_clave_BibTeX_y_enlace
+empty_BibTeX_key=vaciar_clave_BibTeX
+BibLaTeX_field_only=Sólo_campo_BibLaTeX
+
+Error_while_generating_fetch_URL=Error_al_generar_la_URL_de_recolección
+Error_while_parsing_ID_list=Error_al_analizar_la_lista_de_ID
+Unable_to_get_PubMed_IDs=No_se_pudieron_obtener_las_ID_PubMed
+Backup_found=Encontrada_copia_de_seguridad
+A_backup_file_for_'%0'_was_found.=Una_copia_de_seguridad_para_'%0'_ha_sido_encontrada.
+This_could_indicate_that_JabRef_did_not_shut_down_cleanly_last_time_the_file_was_used.=Esto_puede_indicar_que_JabRef_no_se_cerró_correctamente_la_última_vez_que_se_usó_ese_archivo.
+Do_you_want_to_recover_the_database_from_the_backup_file?=¿Quiere_recuperar_la_base_de_datos_desde_la_copia_de_seguridad?
+Firstname_Lastname=Nombre_Apellido
+
+Recommended_for_%0=Recomendado_para_%0
+This_might_be_caused_by_reaching_the_traffic_limitation_of_Google_Scholar_(see_'Help'_for_details).=Esto_puede_ser_debido_a_alcanzar_el_límite_de_tráfico_de_GoogleScholar_(vea_la_'Ayuda'_para_más_detalles)
+
+Problem_downloading_from_%1=
+
+File_directory_pattern=
+Update_with_bibliographic_information_from_the_web=
+
+Could_not_find_any_bibliographic_information.=
+BibTeX_key_%0_deviates_from_generated_key_%1=
+DOI_%0_is_invalid=
+
+Jump_to_entry=
diff --git a/src/main/resources/l10n/JabRef_fa.properties b/src/main/resources/l10n/JabRef_fa.properties
index 86b6115..0110e5a 100644
--- a/src/main/resources/l10n/JabRef_fa.properties
+++ b/src/main/resources/l10n/JabRef_fa.properties
@@ -1,6 +1,6 @@
#!
-#! created/edited by Popeye version 0.55 (https\://github.com/JabRef/popeye)
-#! encoding:ISO-8859-1
+#! created/edited by Popeye version 0.55 (github.com/JabRef/popeye)
+#! encoding:UTF-8
%0_contains_the_regular_expression_<b>%1</b>=
@@ -12,18 +12,14 @@
%0_export_successful=
-
%0_matches_the_regular_expression_<b>%1</b>=
%0_matches_the_term_<b>%1</b>=
-<field_name>=
<HTML>Could_not_find_file_'%0'<BR>linked_from_entry_'%1'</HTML>=
-
<select>=
-<select_word>=
Abbreviate_journal_names_of_the_selected_entries_(ISO_abbreviation)=
Abbreviate_journal_names_of_the_selected_entries_(MEDLINE_abbreviation)=
@@ -44,13 +40,12 @@ Action=
Add=
-Add_a_(compiled)_custom_ImportFormat_class_from_a_class_path.=
+Add_a_(compiled)_custom_Importer_class_from_a_class_path.=
The_path_need_not_be_on_the_classpath_of_JabRef.=
-Add_a_(compiled)_custom_ImportFormat_class_from_a_ZIP-archive.=
+Add_a_(compiled)_custom_Importer_class_from_a_ZIP-archive.=
The_ZIP-archive_need_not_be_on_the_classpath_of_JabRef.=
-
Add_entry_selection_to_this_group=
Add_from_folder=
@@ -76,8 +71,6 @@ Added_string=
Additionally,_entries_whose_<b>%0</b>_field_does_not_contain_<b>%1</b>_can_be_assigned_manually_to_this_group_by_selecting_them_then_using_either_drag_and_drop_or_the_context_menu._This_process_adds_the_term_<b>%1</b>_to_each_entry's_<b>%0</b>_field._Entries_can_be_removed_manually_from_this_group_by_selecting_them_then_using_the_context_menu._This_process_removes_the_term_<b>%1</b>_from_each_entry's_<b>%0</b>_field.=
Advanced=
-
-
All_entries=
All_entries_of_this_type_will_be_declared_typeless._Continue?=
@@ -85,11 +78,11 @@ All_fields=
All_subgroups_(recursively)=
-An_exception_occurred_while_accessing_'%0'=
+Always_reformat_BIB_file_on_save_and_export=
+
A_SAX_exception_occurred_while_parsing_'%0'\:=
and=
-
and_the_class_must_be_available_in_your_classpath_next_time_you_start_JabRef.=
any_field_that_matches_the_regular_expression_<b>%0</b>=
@@ -120,6 +113,7 @@ Assigned_1_entry_to_group_"%0".=
Attach_URL=
+Attempt_to_automatically_set_file_links_for_your_entries._Automatically_setting_works_if_a_file_in_your_file_directory<BR>or_a_subdirectory_is_named_identically_to_an_entry's_BibTeX_key,_plus_extension.=
Auto=
@@ -127,7 +121,6 @@ Autodetect_format=
Autogenerate_BibTeX_keys=
-
Autolink_files_with_names_starting_with_the_BibTeX_key=
Autolink_only_files_that_match_the_BibTeX_key=
@@ -140,6 +133,10 @@ Automatically_created_groups=
Automatically_remove_exact_duplicates=
+Allow_overwriting_existing_links.=
+
+Do_not_overwrite_existing_links.=
+
AUX_file_import=
Available_export_formats=
@@ -156,9 +153,7 @@ Backup_old_file_when_saving=
BibTeX_key_is_unique.=
-
-BibTeX_source=
-
+%0_source=
Broken_link=
@@ -198,18 +193,19 @@ Change_of_Grouping_Method=
change_preamble=
-
Change_table_column_and_General_fields_settings_to_use_the_new_feature=
-
Changed_font_settings=
Changed_language_settings=
+Changed_look_and_feel_settings=
+
Changed_preamble=
Characters_to_ignore=
+Check_existing_file_links=
Check_links=
@@ -220,10 +216,8 @@ Class_name=
Clear=
-
Clear_fields=
-
Close=
Close_others=
Close_all=
@@ -232,7 +226,6 @@ Close_dialog=
Close_the_current_database=
-
Close_window=
Closed_database=
@@ -351,6 +344,8 @@ Delete_strings=
Deleted=
+Delete_local_file=
+
Delimit_fields_with_semicolon,_ex.=
Descending=
@@ -360,8 +355,6 @@ Description=
Deselect_all=
Deselect_all_duplicates=
-
-
Disable_this_confirmation_dialog=
Display_all_entries_belonging_to_one_or_more_of_the_selected_groups.=
@@ -391,6 +384,7 @@ Do_not_write_the_following_fields_to_XMP_Metadata\:=
Do_you_want_JabRef_to_do_the_following_operations?=
+Donate_to_JabRef=
Down=
@@ -402,15 +396,12 @@ Downloading...=
Drop_%0=
-
-
duplicate_removal=
Duplicate_string_name=
Duplicates_found=
-
Dynamic_groups=
Dynamically_group_entries_by_a_free-form_search_expression=
@@ -441,7 +432,6 @@ Grouping_may_not_work_for_this_entry.=
empty_database=
Enable_word/name_autocompletion=
-
Enter_URL=
Enter_URL_to_download=
@@ -453,7 +443,6 @@ Entries_cannot_be_manually_assigned_to_or_removed_from_this_group.=
Entries_exported_to_clipboard=
-
entry=
Entry_editor=
@@ -473,7 +462,6 @@ Entry_types=
Error=
Error_exporting_to_clipboard=
-##Error\:_check_your_External_viewer_settings_in_Preferences=
Error_occurred_when_parsing_entry=
Error_opening_file=
@@ -493,7 +481,6 @@ Overwrite_file?=
Expand_subtree=
-#previousentrynottranslated.Toviewit,openGroupinterfaceandclickonthe"newgroup"button
Export=
Export_name=
@@ -519,15 +506,12 @@ External_programs=
External_viewer_called=
-
Fetch=
Field=
field=
-#IntegritycheckisaprocessthatchecksforindicationsofwronglyfilledoutBibTeXfields."Scan"isthebuttonthatstartsthecheck.
-
Field_name=
Field_names_are_not_allowed_to_contain_white_space_or_the_following_characters=
@@ -538,7 +522,6 @@ Field_to_group_by=
File=
file=
-
File_'%0'_is_already_open.=
File_'%0'_not_found=
@@ -565,6 +548,7 @@ Filter=
Finished_automatically_setting_external_links.=
+Finished_synchronizing_file_links._Entries_changed\:_%0.=
Finished_writing_XMP-metadata._Wrote_to_%0_file(s).=
Finished_writing_XMP_for_%0_file_(%1_skipped,_%2_errors).=
@@ -615,22 +599,19 @@ Generate_now=
Generated_BibTeX_key_for=
Generating_BibTeX_key_for=
-
+Get_fulltext=
Grab=
Gray_out_entries_not_in_group_selection=
Gray_out_non-hits=
-
Groups=
-
Have_you_chosen_the_correct_package_path?=
Help=
-
Help_on_groups=
Help_on_key_patterns=
@@ -638,12 +619,12 @@ Help_on_regular_expression_search=
Hide_non-hits=
-
Hierarchical_context=
Highlight=
Highlight_groups_matching_all_selected_entries=
Highlight_groups_matching_any_selected_entry=
+Disable_highlight_groups_matching_entries=
Highlight_overlapping_groups=
@@ -681,52 +662,49 @@ Import_strings=
Import_to_open_tab=
-Import_word_selector_definitions=
-
-
Imported_entries=
Imported_from_database=
-ImportFormat_class=
+Importer_class=
Importing=
Importing_in_unknown_format=
-
Include_abstracts=
Include_entries=
Include_subgroups\:_When_selected,_view_entries_contained_in_this_group_or_its_subgroups=
-
-
-
Independent_group\:_When_selected,_view_only_this_group's_entries=
Initially_show_groups_tree_expanded=
Work_options=
-Input_error=
-
Insert=
Insert_rows=
+Intersection=
+Invalid_BibTeX_key=
-
-#IntegritycheckisaprocessthatchecksforindicationsofwronglyfilledoutBibTeXfields."Scan"isthebuttonthatstartsthecheck.
Invalid_date_format=
Invalid_URL=
+Inverted=
+
ISO_abbreviation=
+Online_help=
+
JabRef_preferences=
+Journal_abbreviations=
+
Journal_list_preview=
Journal_name=
@@ -745,7 +723,6 @@ Key_pattern=
keys_in_database=
-#nottranslated.Toviewit,usemenu"Tools|NewBibTeXfilefromAUxfile",andlaunchtheactiononanon-existantAUXfile.
Keyword=
Label=
@@ -765,18 +742,17 @@ Limit_to_fields=
Limit_to_selected_entries=
Link=
+Link_local_file=
Link_to_file_%0=
+Listen_for_remote_operation_on_port=
Load_and_Save_preferences_from/to_jabref.xml_on_start-up_(memory_stick_mode)=
-
-
+Look_and_feel=
Main_file_directory=
Main_layout_file=
-Manage=
-
Manage_custom_exports=
Manage_custom_imports=
@@ -812,7 +788,6 @@ Modify=
modify_group=
-
Move=
Move_down=
@@ -837,7 +812,6 @@ New=
new=
-
New_BibTeX_entry=
New_BibTeX_subdatabase=
@@ -845,6 +819,7 @@ New_BibTeX_subdatabase=
New_content=
New_database_created.=
+New_%0_database=
New_field_value=
New_file=
@@ -856,7 +831,6 @@ New_string=
Next_entry=
-
No_actual_changes_found.=
no_base-BibTeX-file_specified=
@@ -870,7 +844,6 @@ No_entries_found_for_the_search_string_'%0'=
No_entries_imported.=
-
No_exceptions_have_occurred.=
No_files_found.=
@@ -881,24 +854,17 @@ No_journal_names_could_be_abbreviated.=
No_journal_names_could_be_unabbreviated.=
No_PDF_linked=
-No_references_found=
-
-
No_URL_defined=
not=
not_found=
-
Note_that_you_must_specify_the_fully_qualified_class_name_for_the_look_and_feel,=
Nothing_to_redo=
Nothing_to_undo=
-#Thenextisusedlikein"Referencesfound\:1Numberofreferencestofetch?"
-Number_of_references_to_fetch?=
-
occurrences=
OK=
@@ -919,8 +885,7 @@ Open_file=
Open_last_edited_databases_at_startup=
-Open_shared_database=
-
+Connect_to_shared_database=
Open_terminal_here=
@@ -995,6 +960,8 @@ Please_select_exactly_one_group_to_move.=
Possible_duplicate_entries=
+Possible_duplicate_of_existing_entry._Click_to_resolve.=
+
Preamble=
Preferences=
@@ -1002,17 +969,23 @@ Preferences=
Preferences_recorded.=
Preview=
+Citation_Style=
+Current_Preview=
+Cannot_generate_preview_based_on_selected_citation_style.=
+Bad_character_inside_entry=
+Error_while_generating_citation_style=
+Preview_style_changed_to\:_%0=
+Next_preview_layout=
+Previous_preview_layout=
Previous_entry=
Primary_sort_criterion=
-
Problem_with_parsing_entry=
Processing_%0=
Program_output=
Pull_changes_from_shared_database=
-
Pushed_citations_to_%0=
Quit_JabRef=
@@ -1021,19 +994,16 @@ Quit_synchronization=
Raw_source=
-
Rearrange_tabs_alphabetically_by_title=
Redo=
Reference_database=
-#Thenexttwolinesareusedlikein"Referencesfound\:1Numberofreferencestofetch?"
-References_found=
+%0_references_found._Number_of_references_to_fetch?=
Refine_supergroup\:_When_selected,_view_entries_contained_in_both_this_group_and_its_supergroup=
-
regular_expression=
Remember_these_entry_types?=
@@ -1044,13 +1014,10 @@ Remote_server_port=
Remove=
-
Remove_subgroups=
Remove_all_subgroups_of_"%0"?=
-
-
Remove_entry_from_import=
Remove_entry_selection_from_this_group=
@@ -1058,7 +1025,6 @@ Remove_entry_selection_from_this_group=
Remove_entry_type=
Remove_file_link_(DELETE)=
-
Remove_from_group=
Remove_group=
@@ -1081,7 +1047,6 @@ Remove_old_entry=
Remove_selected_strings=
-
Removed_group_"%0".=
Removed_group_"%0"_and_its_subgroups.=
@@ -1107,7 +1072,6 @@ Resolve_strings_for_standard_BibTeX_fields_only=
resolved=
-
Revert_to_original_source=
Review=
@@ -1132,36 +1096,23 @@ Save_failed=
Save_failed_during_backup_creation=
-Save_failed_while_committing_changes\:_%0=
-
Save_selected_as...=
Saved_database=
Saved_selected_to_'%0'.=
-
Saving=
Saving_all_databases...=
Saving_database=
-
Search=
-
-
Search_expression=
Search_for=
-
-
-
-
-
-
-
Searching_for_duplicates...=
Searching_for_files=
@@ -1172,21 +1123,15 @@ Select=
-
Select_all=
-
Select_encoding=
-
Select_entry_type=
Select_external_application=
Select_file_from_ZIP-archive=
-
-
-
Select_the_tree_nodes_to_view_and_accept_or_reject_changes=
Selected_entries=
Set_field=
@@ -1199,11 +1144,9 @@ Set_table_font=
Settings=
-
-
Shortcut=
-Show/edit_BibTeX_source=
+Show/edit_%0_source=
Show_'Firstname_Lastname'=
@@ -1211,7 +1154,6 @@ Show_'Lastname,_Firstname'=
Show_BibTeX_source_by_default=
-
Show_confirmation_dialog_when_deleting_entries=
Show_description=
@@ -1227,17 +1169,12 @@ Show_last_names_only=
Show_names_unchanged=
-
-
Show_optional_fields=
-
Show_required_fields=
Show_URL/DOI_column=
-
-
Simple_HTML=
Size=
@@ -1249,8 +1186,6 @@ Skipped_entry.=
Sort_alphabetically=
-
-
sort_subgroups=
Sorted_all_subgroups_recursively.=
@@ -1262,7 +1197,6 @@ Special_name_formatters=
Special_table_columns=
-
Starting_import=
Statically_group_entries_by_manual_assignment=
@@ -1273,7 +1207,6 @@ Stop=
Store_journal_abbreviations=
-
Stored_entry=
Strings=
@@ -1282,9 +1215,11 @@ Strings_for_database=
Subdatabase_from_AUX=
+Switches_between_full_and_abbreviated_journal_name_if_the_journal_name_is_known.=
Synchronize_file_links=
+Synchronizing_file_links...=
Table_appearance=
@@ -1308,7 +1243,6 @@ The_chosen_date_format_for_new_entries_is_not_valid=
The_chosen_encoding_'%0'_could_not_encode_the_following_characters\:=
-
the_field_<b>%0</b>=
The_file<BR>'%0'<BR>has_been_modified<BR>externally\!=
@@ -1345,21 +1279,18 @@ This_external_link_is_of_the_type_'%0',_which_is_undefined._What_do_you_want_to_
This_group_contains_entries_based_on_manual_assignment._Entries_can_be_assigned_to_this_group_by_selecting_them_then_using_either_drag_and_drop_or_the_context_menu._Entries_can_be_removed_from_this_group_by_selecting_them_then_using_the_context_menu.=
-
-
-
This_group_contains_entries_whose_<b>%0</b>_field_contains_the_keyword_<b>%1</b>=
This_group_contains_entries_whose_<b>%0</b>_field_contains_the_regular_expression_<b>%1</b>=
+This_makes_JabRef_look_up_each_file_link_and_check_if_the_file_exists._If_not,_you_will_be_given_options<BR>to_resolve_the_problem.=
+
This_operation_requires_all_selected_entries_to_have_BibTeX_keys_defined.=
This_operation_requires_one_or_more_entries_to_be_selected.=
-
Toggle_abbreviation=
Toggle_entry_preview=
Toggle_groups_interface=
-
Try_different_encoding=
Unabbreviate_journal_names_of_the_selected_entries=
@@ -1378,7 +1309,6 @@ Unknown_BibTeX_entries=
unknown_edit=
-
Unknown_export_format=
Unmark_all=
@@ -1387,10 +1317,6 @@ Unmark_entries=
Unmark_entry=
-
-
-Unsupported_version_of_class_%0\:_%1=
-
untitled=
Up=
@@ -1405,7 +1331,6 @@ Upgrade_old_external_file_links_to_use_the_new_feature=
usage=
Use_autocompletion_for_the_following_fields=
-
Use_other_look_and_feel=
Use_regular_expression_search=
@@ -1447,7 +1372,6 @@ Write_XMP-metadata_for_all_PDFs_in_current_database?=
Writing_XMP-metadata...=
Writing_XMP-metadata_for_selected_entries...=
-
Wrote_XMP-metadata=
XMP-annotated_PDF=
@@ -1459,17 +1383,14 @@ You_have_changed_the_language_setting.=
You_have_changed_the_look_and_feel_setting.=
-
You_have_entered_an_invalid_search_'%0'.=
You_must_choose_a_filename_to_store_journal_abbreviations=
You_must_restart_JabRef_for_the_new_key_bindings_to_work_properly.=
-
Your_new_key_bindings_have_been_stored.=
-
The_following_fetchers_are_available\:=
Could_not_find_fetcher_'%0'=
Running_query_'%0'_with_fetcher_'%1'.=
@@ -1484,14 +1405,10 @@ Import_canceled_by_user=
Progress\:_%0_of_%1=
Error_while_fetching_from_%0=
-Fetching_Medline_by_id...=
-
-Fetching_Medline_by_term...=
-%0_import_canceled=
Please_enter_a_valid_number=
-Please_enter_a_comma_separated_list_of_Medline_IDs_(numbers)_or_search_terms.=
-
Show_search_results_in_a_window=
+Show_global_search_results_in_a_window=
+Search_in_all_open_databases=
Move_file_to_file_directory?=
Rename_to_'%0'=
You_have_changed_the_menu_and_label_font_size.=
@@ -1518,21 +1435,18 @@ The_Guide_to_Computing_Literature=
When_opening_file_link,_search_for_matching_file_if_no_link_is_defined=
Settings_for_%0=
-
-
-
Mark_entries_imported_into_an_existing_database=
Unmark_all_entries_before_importing_new_entries_into_an_existing_database=
Forward=
Back=
Sort_the_following_fields_as_numeric_fields=
+Line_%0\:_Found_corrupted_BibTeX_key.=
Line_%0\:_Found_corrupted_BibTeX_key_(contains_whitespaces).=
Line_%0\:_Found_corrupted_BibTeX_key_(comma_missing).=
-Finished_downloading_full_text_document=
Full_text_document_download_failed=
Update_to_current_column_order=
-
+Download_from_URL=
Rename_field=
Set/clear/rename_fields=
Rename_field_to=
@@ -1545,16 +1459,15 @@ Cannot_use_port_%0_for_remote_operation;_another_application_may_be_using_it._Tr
Looking_for_full_text_document...=
Autosave=
-Prompt_before_recovering_a_database_from_an_autosave_file=
-Autosave_interval_(minutes)=
-Do_you_want_to_recover_the_database_from_the_autosave_file?=
-Recover_from_autosave=
+A_local_copy_will_be_opened.=
+Autosave_local_databases=
+Automatically_save_the_database_to=
+Please_enter_a_valid_file_path.=
+
Export_in_current_table_sort_order=
Export_entries_in_their_original_order=
Error_opening_file_'%0'.=
-Autosave_of_file_'%0'=
-Error_opening_autosave_of_'%0'._Trying_to_load_'%0'_instead.=
Formatter_not_found\:_%0=
Clear_inputarea=
@@ -1585,13 +1498,13 @@ includes_subgroups=
contains=
search_expression=
-
-
Optional_fields_2=
Waiting_for_save_operation_to_finish=
Resolving_duplicate_BibTeX_keys...=
+Finished_resolving_duplicate_BibTeX_keys._%0_entries_modified.=
This_database_contains_one_or_more_duplicated_BibTeX_keys.=
Do_you_want_to_resolve_duplicate_keys_now?=
+
Find_and_remove_duplicate_BibTeX_keys=
Expected_syntax_for_--fetch\='<name_of_fetcher>\:<query>'=
Duplicate_BibTeX_key=
@@ -1621,7 +1534,6 @@ Create_entry_based_on_XMP_data=
Create_blank_entry_linking_the_PDF=
Only_attach_PDF=
Title=
-No_internet_connection.=
Create_new_entry=
Update_existing_entry=
Autocomplete_names_in_'Firstname_Lastname'_format_only=
@@ -1686,17 +1598,17 @@ The_paragraph_format_is_controlled_by_the_property_'ReferenceParagraphFormat'_or
The_character_format_is_controlled_by_the_citation_property_'CitationCharacterFormat'_in_the_style_file.=
Automatically_sync_bibliography_when_inserting_citations=
Look_up_BibTeX_entries_in_the_active_tab_only=
+Look_up_BibTeX_entries_in_all_open_databases=
Autodetecting_paths...=
Could_not_find_OpenOffice/LibreOffice_installation=
Directories=
Found_more_than_one_OpenOffice/LibreOffice_executable.=
Please_choose_which_one_to_connect_to\:=
+Choose_OpenOffice/LibreOffice_executable=
Select_document=
Edit_group_membership=
-
HTML_list=
Click_group_to_toggle_membership_of_selected_entries=
-Use_EMACS_23_insertion_string=
If_possible,_normalize_this_list_of_names_to_conform_to_standard_BibTeX_name_formatting=
Could_not_open_%0=
Unknown_import_format=
@@ -1790,7 +1702,6 @@ Five_stars=
Four_stars=
Help_on_special_fields=
Keywords_of_selected_entries=
-Manage_content_selectors=
Manage_keywords=
No_priority_information=
No_rank_information=
@@ -1843,15 +1754,10 @@ Your_style_file_specifies_the_paragraph_format_'%0',_which_is_undefined_in_your_
Searching...=
You_have_selected_more_than_%0_entries_for_download._Some_web_sites_might_block_you_if_you_make_too_many_rapid_downloads._Do_you_want_to_continue?=
Confirm_selection=
-Unknown_DOI\:_'%0'.=
Add_{}_to_specified_title_words_on_search_to_keep_the_correct_case=
Import_conversions=
Please_enter_a_search_string=
Please_open_or_start_a_new_database_before_searching=
-An_error_occurred_while_fetching_from_ADS_(%0)\:=
-An_error_occurred_while_parsing_abstract=
-Unknown_DiVA_entry\:_'%0'.=
-Get_BibTeX_entry_from_DiVA=
Log=
Canceled_merging_entries=
@@ -1878,8 +1784,11 @@ Hostname=
Invalid_setting=
Network=
Please_specify_both_hostname_and_port=
+Please_specify_both_username_and_password=
Use_custom_proxy_configuration=
+Proxy_requires_authentication=
+Attention\:_Password_is_stored_in_plain_text\!=
Clear_connection_settings=
Cleared_connection_settings.=
@@ -1892,6 +1801,7 @@ Open_folder=
Searches_for_unlinked_PDF_files_on_the_file_system=
Export_entries_ordered_as_specified=
Export_sort_order=
+Export_sorting=
Newline_separator=
Save_entries_ordered_as_specified=
@@ -1902,7 +1812,8 @@ illegal_backslash_expression=
Move_to_group=
-Could_not_apply_changes.=
+Clear_read_status=
+Convert_to_BibLatex_format_(for_example,_move_the_value_of_the_'journal'_field_to_'journaltitle')=
Deprecated_fields=
Hide/show_toolbar=
No_read_status_information=
@@ -1933,120 +1844,90 @@ Unable_to_find_the_requested_look_and_feel_and_thus_the_default_one_is_used.=
Opens_JabRef's_GitHub_page=
Could_not_open_browser.=
-
-This_group_contains_all_entries._It_cannot_be_edited_or_removed.=
+Please_open_%0_manually.=
+The_link_has_been_copied_to_the_clipboard.=
Open_%0_file=
Cannot_delete_file=
-Convert=
-Delete_local_file=
File_permission_error=
-Help_on_Name_Formatting=
-Normalize_to_BibTeX_name_format=
Push_to_%0=
+Path_to_%0=
+Convert=
+Normalize_to_BibTeX_name_format=
+Help_on_Name_Formatting=
Add_new_file_type=
-Follow_DOI_or_URL_link_and_try_to_locate_PDF_full_text_document=
+
Left_entry=
-No_information_added=
+Right_entry=
+Use=
Original_entry=
Replace_original_entry=
-Right_entry=
+No_information_added=
Select_at_least_one_entry_to_manage_keywords.=
-Use=
-Changed_type_to_'%0'_for=
-Database_'%0'_has_changed.=
-Copy_\\cite{BibTeX_key}=
-Copy_BibTeX_key_and_title=
-File_rename_failed_for_%0_entries.=
-Could_not_connect_to_%0=
-
+OpenDocument_text=
+OpenDocument_spreadsheet=
+OpenDocument_presentation=
%0_image=
-%0_problem(s)_found=
-'%0'_is_not_a_valid_ADS_bibcode.=
-Accepting_the_change_replaces_the_complete_groups_tree_with_the_externally_modified_groups_tree.=
Added_entry=
-Added_new_'%0'_entry.=
-Changed_look_and_feel_settings=
-Clear_read_status=
-Convert_to_BibLatex_format_(for_example,_move_the_value_of_the_'journal'_field_to_'journaltitle')=
-Deleted_entry=
-Discard_changes=
-Donate_to_JabRef=
-Export_with_selected_format=
-Field_is_missing=
-Filled=
-Finished_resolving_duplicate_BibTeX_keys._%0_entries_modified.=
-From_import=
-Intersection=
-Invalid_BibTeX_key=
-Invalid_DOI\:_'%0'.=
-Inverted=
-Online_help=
-Journal_abbreviations=
-Keep_left=
-Keep_merged_entry_only=
-Keep_right=
-Line_%0\:_Found_corrupted_BibTeX_key.=
-Link_local_file=
-Listen_for_remote_operation_on_port=
-Look_and_feel=
-Look_up_BibTeX_entries_in_all_open_databases=
-Merged_BibTeX_source_code=
Modified_entry=
+Deleted_entry=
Modified_groups_tree=
-Multiple_entries_selected._Do_you_want_to_change_the_type_of_all_these_to_'%0'?=
-No_problems_found.=
-Old_entry=
-OpenDocument_presentation=
-OpenDocument_spreadsheet=
-OpenDocument_text=
-Path_to_%0=
-Please_move_the_file_manually_and_link_in_place.=
-Possible_duplicate_of_existing_entry._Click_to_resolve.=
-Print_entry_preview=
-Really_delete_the_%0_selected_entries?=
-Really_delete_the_selected_entry?=
Removed_all_groups=
-Return_to_JabRef=
-Save_changes=
-Search_%0=
+Accepting_the_change_replaces_the_complete_groups_tree_with_the_externally_modified_groups_tree.=
Select_export_format=
-Switches_between_full_and_abbreviated_journal_name_if_the_journal_name_is_known.=
-To_set_up,_go_to=
+Return_to_JabRef=
+Please_move_the_file_manually_and_link_in_place.=
+Could_not_connect_to_%0=
Warning\:_%0_out_of_%1_entries_have_undefined_BibTeX_key.=
-large_capitals_are_not_masked_using_curly_brackets_{}=
occurrence=
-should_contain_a_four_digit_number=
-should_contain_a_valid_page_number_range=
-should_end_with_a_name=
+Added_new_'%0'_entry.=
+Multiple_entries_selected._Do_you_want_to_change_the_type_of_all_these_to_'%0'?=
+Changed_type_to_'%0'_for=
+Really_delete_the_selected_entry?=
+Really_delete_the_%0_selected_entries?=
+Keep_merged_entry_only=
+Keep_left=
+Keep_right=
+Old_entry=
+From_import=
+No_problems_found.=
+%0_problem(s)_found=
+Save_changes=
+Discard_changes=
+Database_'%0'_has_changed.=
+Print_entry_preview=
+Copy_\\cite{BibTeX_key}=
+Copy_BibTeX_key_and_title=
+File_rename_failed_for_%0_entries.=
+To_set_up,_go_to=
+Merged_BibTeX_source_code=
+Invalid_DOI\:_'%0'.=
should_start_with_a_name=
+should_end_with_a_name=
unexpected_closing_curly_bracket=
unexpected_opening_curly_bracket=
+capital_letters_are_not_masked_using_curly_brackets_{}=
+should_contain_a_four_digit_number=
+should_contain_a_valid_page_number_range=
+Filled=
+Field_is_missing=
+Search_%0=
-Advanced_search_active.=
-Choose_OpenOffice/LibreOffice_executable=
-Found_%0_results.=
-No_results_found.=
-Normal_search_active.=
-Search_globally=
-Search_in_all_open_databases=
Search_results_in_all_databases_for_%0=
Search_results_in_database_%0_for_%1=
-This_search_contains_entries_in_which=
+Search_globally=
+No_results_found.=
+Found_%0_results.=
+Advanced_search_active.=
+Normal_search_active.=
+plain_text=
This_search_contains_entries_in_which_any_field_contains_the_regular_expression_<b>%0</b>=
This_search_contains_entries_in_which_any_field_contains_the_term_<b>%0</b>=
-plain_text=
-
-Attention\:_Password_is_stored_in_plain_text\!=
-Please_specify_both_username_and_password=
-Proxy_requires_authentication=
+This_search_contains_entries_in_which=
-An_autosave_file_was_found_for_this_database._This_could_indicate_that_JabRef_did_not_shut_down_cleanly_last_time_the_file_was_used.=
-Note\:_A_full_text_search_is_currently_not_supported_for_%0=
Unable_to_autodetect_OpenOffice/LibreOffice_installation._Please_choose_the_installation_directory_manually.=
-
JabRef_no_longer_supports_'ps'_or_'pdf'_fields.<br>File_links_are_now_stored_in_the_'file'_field_and_files_are_stored_in_an_external_file_directory.<br>To_make_use_of_this_feature,_JabRef_needs_to_upgrade_file_links.<br><br>=
This_database_uses_outdated_file_links.=
@@ -2085,53 +1966,32 @@ Resolve_duplicate_BibTeX_keys=
Save_all=
String_dialog,_add_string=
String_dialog,_remove_string=
-Switch_preview_layout=
Synchronize_files=
Unabbreviate=
-
should_contain_a_protocol=
Copy_preview=
-
Automatically_setting_file_links=
Regenerating_BibTeX_keys_according_to_metadata=
No_meta_data_present_in_BIB_file._Cannot_regenerate_BibTeX_keys=
-
Regenerate_all_keys_for_the_entries_in_a_BibTeX_file=
-
Show_debug_level_messages=
-
-Export_sorting=
-
-New_%0_database=
-
-New_%0_database_created.=
-
-No_entry_found_for_ISBN_%0_at_www.ebook.de=
-
-Save_actions=
-Enable_save_actions=
-Always_reformat_BIB_file_on_save_and_export=
Default_bibliography_mode=
-
-
+New_%0_database_created.=
Show_only_preferences_deviating_from_their_default_value=
default=
key=
type=
value=
-
Show_preferences=
-
-
+Save_actions=
+Enable_save_actions=
Other_fields=
Show_remaining_fields=
link_should_refer_to_a_correct_file_path=
-
abbreviation_detected=
wrong_entry_type_as_proceedings_has_page_numbers=
-
Abbreviate_journal_names=
Abbreviating...=
Adding_fetched_entries=
@@ -2143,35 +2003,22 @@ Unabbreviate_journal_names=
Unabbreviating...=
Usage=
+
+Adds_{}_brackets_around_acronyms,_month_names_and_countries_to_preserve_their_case.=
Are_you_sure_you_want_to_reset_all_settings_to_default_values?=
Reset_preferences=
-
Ill-formed_entrytype_comment_in_BIB_file=
+
+Move_linked_files_to_default_file_directory_%0=
+
Clipboard=
Could_not_paste_entry_as_text\:=
Do_you_still_want_to_continue?=
This_action_will_modify_the_following_field(s)_in_at_least_one_entry_each\:=
This_could_cause_undesired_changes_to_your_entries.=
-
-Disable_highlight_groups_matching_entries=
Run_field_formatter\:=
-
-Adds_{}_brackets_around_acronyms,_month_names_and_countries_to_preserve_their_case.=
-Converts_units_to_LaTeX_formatting.=
-Does_nothing.=
-
-
Table_font_size_is_%0=
-Attempt_to_automatically_set_file_links_for_your_entries._Automatically_setting_works_if_a_file_in_your_file_directory<BR>or_a_subdirectory_is_named_identically_to_an_entry's_BibTeX_key,_plus_extension.=
-Allow_overwriting_existing_links.=
-Do_not_overwrite_existing_links.=
-Check_existing_file_links=
-Finished_synchronizing_file_links._Entries_changed\:_%0.=
-Synchronizing_file_links...=
-This_makes_JabRef_look_up_each_file_link_and_check_if_the_file_exists._If_not,_you_will_be_given_options<BR>to_resolve_the_problem.=
-
-Move_linked_files_to_default_file_directory_%0=
-
+%0_import_canceled=
Internal_style=
Add_style_file=
Are_you_sure_you_want_to_remove_the_style?=
@@ -2179,7 +2026,6 @@ Current_style_is_'%0'=
Remove_style=
Select_one_of_the_available_styles_or_add_a_style_file_from_disk.=
You_must_select_a_valid_style_file.=
-
Reload=
Capitalize=
@@ -2190,9 +2036,11 @@ Changes_all_letters_to_upper_case.=
Changes_the_first_letter_of_all_words_to_capital_case_and_the_remaining_letters_to_lower_case.=
Cleans_up_LaTeX_code.=
Converts_HTML_code_to_LaTeX_code.=
+Converts_HTML_code_to_Unicode.=
Converts_LaTeX_encoding_to_Unicode_characters.=
Converts_Unicode_characters_to_LaTeX_encoding.=
Converts_ordinals_to_LaTeX_superscripts.=
+Converts_units_to_LaTeX_formatting.=
HTML_to_LaTeX=
LaTeX_cleanup=
LaTeX_to_Unicode=
@@ -2216,16 +2064,13 @@ Title_case=
Unicode_to_LaTeX=
Units_to_LaTeX=
Upper_case=
+Does_nothing.=
Identity=
-
Clears_the_field_completely.=
Directory_not_found=
Main_file_directory_not_set\!=
-
This_operation_requires_exactly_one_item_to_be_selected.=
-
Importing_in_%0_format=
-
Female_name=
Female_names=
Male_name=
@@ -2234,7 +2079,6 @@ Mixed_names=
Neuter_name=
Neuter_names=
-
Lookup_DOI=
Audio_CD=
@@ -2273,35 +2117,27 @@ Verse=
change_entries_of_group=
odd_number_of_unescaped_'\#'=
+
Plain_text=
Show_diff=
character=
word=
-
Show_symmetric_diff=
HTML_encoded_character_found=
-
booktitle_ends_with_'conference_on'=
+
All_external_files=
OpenOffice/LibreOffice_integration=
incorrect_control_digit=
incorrect_format=
-
-Expected_"%0"_to_contain_whitespace=
-Syntax_error_in_regular-expression_pattern=
-
Copy_version_to_clipboard=
Copied_version_to_clipboard=
+
BibTeX_key=
Message=
-
-Get_fulltext=
-
-Download_from_URL=
-
Decryption_not_supported.=
Cleared_'%0'_for_%1_entries=
@@ -2320,16 +2156,11 @@ To_see_what_is_new_view_the_changelog.=
A_new_version_of_JabRef_has_been_released.=
JabRef_is_up-to-date.=
Latest_version=
-
-Please_open_%0_manually.=
-
-The_link_has_been_copied_to_the_clipboard.=
-
Online_help_forum=
-
Custom=
-Converts_HTML_code_to_Unicode.=
+Export_cited=
+Unable_to_generate_new_database=
Open_console=
Use_default_terminal_emulator=
@@ -2337,31 +2168,22 @@ Execute_command=
Note\:_Use_the_placeholder_%0_for_the_location_of_the_opened_database_file.=
Executing_command_\"%0\"...=
Error_occured_while_executing_the_command_\"%0\".=
-
Reformat_ISSN=
-Unable_to_generate_new_database=
-
-Export_cited=
Countries_and_territories_in_English=
Electrical_engineering_terms=
Enabled=
Internal_list=
+Manage_protected_terms_files=
Months_and_weekdays_in_English=
The_text_after_the_last_line_starting_with_\#_will_be_used=
-
Add_protected_terms_file=
Are_you_sure_you_want_to_remove_the_protected_terms_file?=
Remove_protected_terms_file=
-
-Manage_protected_terms_files=
-
Add_selected_text_to_list=
Add_{}_around_selected_text=
Format_field=
New_protected_terms_file=
-
-
change_field_%0_of_entry_%1_from_%2_to_%3=
change_key_from_%0_to_%1=
change_string_content_%0_to_%1=
@@ -2371,38 +2193,29 @@ insert_entry_%0=
insert_string_%0=
remove_entry_%0=
remove_string_%0=
-
undefined=
Cannot_get_info_based_on_given_%0\:_%1=
-
+Get_BibTeX_data_from_%0=
+No_%0_found=
Entry_from_%0=
-
Merge_entry_with_%0_information=
Updated_entry_with_info_from_%0=
-
-Get_BibTeX_data_from_%0=
-No_%0_found=
Connection=
+Connecting...=
Host=
Port=
Database=
User=
Connect=
Connection_error=
-Driver_error=
Connection_to_%0_server_established.=
Required_field_"%0"_is_empty.=
-
%0_driver_not_available.=
-
The_connection_to_the_server_has_been_terminated.=
-
Connection_lost.=
Reconnect=
Work_offline=
-
Working_offline.=
-
Update_refused.=
Update_refused=
Local_entry=
@@ -2413,7 +2226,12 @@ Local_version\:_%0=
Shared_version\:_%0=
Please_merge_the_shared_entry_with_yours_and_press_"Merge_entries"_to_resolve_this_problem.=
Canceling_this_operation_will_leave_your_changes_unsynchronized._Cancel_anyway?=
-The_BibEntry_you_currently_work_on_has_been_deleted_on_the_shared_side._Hit_"Keep"_to_recover_the_entry.=
+Shared_entry_is_no_longer_present=
+The_BibEntry_you_currently_work_on_has_been_deleted_on_the_shared_side.=
+You_can_restore_the_entry_using_the_"Undo"_operation.=
+Remember_password?=
+You_are_already_connected_to_a_database_using_entered_connection_details.=
+
Cannot_cite_entries_without_BibTeX_keys._Generate_keys_now?=
New_technical_report=
@@ -2423,12 +2241,8 @@ Protected_terms_file=
Style_file=
Open_OpenOffice/LibreOffice_connection=
-
You_must_enter_at_least_one_field_name=
-
-
Non-ASCII_encoded_character_found=
-
Toggle_web_search_interface=
Background_color_for_resolved_fields=
Color_code_for_resolved_fields=
@@ -2442,13 +2256,59 @@ There_were_%0_files_which_could_not_be_imported.=
Migration_help_information=
Entered_database_has_obsolete_structure_and_is_no_longer_supported.=
However,_a_new_database_was_created_alongside_the_pre-3.6_one.=
-
Click_here_to_learn_about_the_migration_of_pre-3.6_databases.=
-
-Connecting...=
Opens_JabRef's_Facebook_page=
Opens_JabRef's_blog=
Opens_JabRef's_website=
-
Opens_a_link_where_the_current_development_version_can_be_downloaded=
See_what_has_been_changed_in_the_JabRef_versions=
+Referenced_BibTeX_key_does_not_exist=
+Finished_downloading_full_text_document_for_entry_%0.=
+Full_text_document_download_failed_for_entry_%0.=
+Look_up_full_text_documents=
+You_are_about_to_look_up_full_text_documents_for_%0_entries.=
+last_four_nonpunctuation_characters_should_be_numerals=
+shared=
+should_contain_an_integer_or_a_literal=
+should_have_the_first_letter_capitalized=
+
+ID=
+ID_type=
+ID-based_entry_generator=
+Fetcher_'%0'_did_not_find_an_entry_for_id_'%1'.=
+
+Select_first_entry=
+Select_last_entry=
+
+Invalid_ISBN\:_'%0'.=
+should_be_an_integer_or_normalized=
+should_be_normalized=
+
+Empty_search_ID=
+The_given_search_ID_was_empty.=
+Copy_BibTeX_key_and_link=
+empty_BibTeX_key=
+BibLaTeX_field_only=
+
+Error_while_generating_fetch_URL=
+Error_while_parsing_ID_list=
+Unable_to_get_PubMed_IDs=
+Backup_found=
+A_backup_file_for_'%0'_was_found.=
+This_could_indicate_that_JabRef_did_not_shut_down_cleanly_last_time_the_file_was_used.=
+Do_you_want_to_recover_the_database_from_the_backup_file?=
+Firstname_Lastname=
+
+Recommended_for_%0=
+This_might_be_caused_by_reaching_the_traffic_limitation_of_Google_Scholar_(see_'Help'_for_details).=
+
+Problem_downloading_from_%1=
+
+File_directory_pattern=
+Update_with_bibliographic_information_from_the_web=
+
+Could_not_find_any_bibliographic_information.=
+BibTeX_key_%0_deviates_from_generated_key_%1=
+DOI_%0_is_invalid=
+
+Jump_to_entry=
diff --git a/src/main/resources/l10n/JabRef_fr.properties b/src/main/resources/l10n/JabRef_fr.properties
index 1f9f433..010d1dc 100644
--- a/src/main/resources/l10n/JabRef_fr.properties
+++ b/src/main/resources/l10n/JabRef_fr.properties
@@ -1,763 +1,1396 @@
#!
-#! created/edited by Popeye version 0.55 (https\://github.com/koppor/popeye)
-#! encoding:ISO-8859-1
+#! created/edited by Popeye version 0.55 (github.com/JabRef/popeye)
+#! encoding:UTF-8
+
%0_contains_the_regular_expression_<b>%1</b>=%0_contient_l'expression_régulière_<b>%1</b>
+
%0_contains_the_term_<b>%1</b>=%0_contient_le_terme_<b>%1</b>
+
%0_doesn't_contain_the_regular_expression_<b>%1</b>=%0_ne_contient_pas_l'expression_régulière_<b>%1</b>
+
%0_doesn't_contain_the_term_<b>%1</b>=%0_ne_contient_pas_le_terme_<b>%1</b>
+
%0_export_successful=%0_\:_Exportation_réussie
+
%0_matches_the_regular_expression_<b>%1</b>=%0_correspond_à_l'expression_régulière_<b>%1</b>
+
%0_matches_the_term_<b>%1</b>=%0_correspond_au_terme_<b>%1</b>
-<field_name>=<nom_de_champ>
+
<HTML>Could_not_find_file_'%0'<BR>linked_from_entry_'%1'</HTML>=<HTML>Le_fichier_'%0'_n'a_pas_pu_être_trouvé_<BR>à_partir_du_lien_de_l'entrée_'%1'</HTML>
+
<select>=<sélectionner>
-<select_word>=<entrer_le_mot-clef>
+
Abbreviate_journal_names_of_the_selected_entries_(ISO_abbreviation)=Abréger_les_noms_de_journaux_des_entrées_sélectionnées_(abréviations_ISO)
Abbreviate_journal_names_of_the_selected_entries_(MEDLINE_abbreviation)=Abréger_les_noms_de_journaux_des_entrées_sélectionnées_(abréviations_MEDLINE)
+
Abbreviate_names=Abréger_les_noms
Abbreviated_%0_journal_names.=%0_noms_de_journaux_abrégés.
+
Abbreviation=Abréviation
+
About_JabRef=A_propos_de_JabRef
+
Abstract=Résumé
+
Accept=Valider
+
Accept_change=Accepter_la_modification
+
Action=Action
+
Add=Ajouter
-Add_a_(compiled)_custom_ImportFormat_class_from_a_class_path.=Ajouter_une_classe_ImportFormat_personnalisée_(compilée)_à_partir_d'un_chemin_de_classe.
+
+Add_a_(compiled)_custom_Importer_class_from_a_class_path.=Ajouter_une_classe_Importer_personnalisée_(compilée)_à_partir_d'un_chemin_de_classe.
The_path_need_not_be_on_the_classpath_of_JabRef.=Le_chemin_n'a_pas_besoin_d'être_dans_le_chemin_de_classe_de_JabRef.
-Add_a_(compiled)_custom_ImportFormat_class_from_a_ZIP-archive.=Ajouter_une_classe_ImportFormat_personnalisée_(compilée)_à_partir_d'une_archive_ZIP.
+
+Add_a_(compiled)_custom_Importer_class_from_a_ZIP-archive.=Ajouter_une_classe_Importer_personnalisée_(compilée)_à_partir_d'une_archive_ZIP.
The_ZIP-archive_need_not_be_on_the_classpath_of_JabRef.=L'archive_ZIP_n'a_pas_besoin_d'être_dans_le_chemin_de_classe_de_JabRef.
+
Add_entry_selection_to_this_group=Ajouter_les_entrées_sélectionnées_à_ce_groupe
+
Add_from_folder=Ajouter_à_partir_du_répertoire
+
Add_from_JAR=Ajouter_à_partir_de_JAR
+
add_group=ajouter_un_groupe
+
Add_group=Ajouter_un_groupe
+
Add_new=Ajouter_nouvelle
+
Add_subgroup=Ajouter_un_sous-groupe
+
Add_to_group=Ajouter_au_groupe
+
Added_group_"%0".=Groupe_"%0"_ajouté.
+
Added_new=Nouvel_ajout
+
Added_string=Chaîne_ajoutée
+
Additionally,_entries_whose_<b>%0</b>_field_does_not_contain_<b>%1</b>_can_be_assigned_manually_to_this_group_by_selecting_them_then_using_either_drag_and_drop_or_the_context_menu._This_process_adds_the_term_<b>%1</b>_to_each_entry's_<b>%0</b>_field._Entries_can_be_removed_manually_from_this_group_by_selecting_them_then_using_the_context_menu._This_process_removes_the_term_<b>%1</b>_from_each_entry's_<b>%0</b>_field.=De_plus,_des_entrées_dont_le_champ_<b>%0</b>_ne_contient_pas_<b>%1</b>_ [...]
+
Advanced=Avancé
All_entries=Toutes_les_entrées
All_entries_of_this_type_will_be_declared_typeless._Continue?=Toutes_les_entrées_de_ce_type_seront_déclarées_'sans_type'._Continuer_?
+
All_fields=Tous_les_champs
+
All_subgroups_(recursively)=Tous_les_sous-groupes_(récursivement)
-An_exception_occurred_while_accessing_'%0'=Une_exception_est_survenue_lors_de_l'accès_à_'%0'
+
+Always_reformat_BIB_file_on_save_and_export=Toujours_remettre_en_forme_les_fichiers_BIB_lors_de_l'enregistrement_et_de_l'exportation
+
A_SAX_exception_occurred_while_parsing_'%0'\:=Une_exception_SAX_est_survenue_pendant_le_traitement_de_'%0'_\:
+
and=et
and_the_class_must_be_available_in_your_classpath_next_time_you_start_JabRef.=et_la_classe_doit_être_disponible_dans_votre_chemin_de_classe_la_prochaine_fois_que_vous_démarrez_JabRef.
+
any_field_that_matches_the_regular_expression_<b>%0</b>=tout_champ_qui_correspond_à_l'expression_régulière_<b>%0</b>
+
Appearance=Aspect
+
Append=Ajouter
Append_contents_from_a_BibTeX_database_into_the_currently_viewed_database=Ajouter_le_contenu_d'une_base_BibTeX_à_la_base_actuelle
+
Append_database=Joindre_à_la_base
+
Append_the_selected_text_to_BibTeX_field=Ajouter_le_texte_sélectionné_à_la_clef_BibTeX
Application=Application
+
Apply=Appliquer
+
Arguments_passed_on_to_running_JabRef_instance._Shutting_down.=Arguments_transmis_à_l'instance_JabRef_active._Arrêt.
+
Assign_entry_selection_exclusively_to_this_group=Assigner_les_entrées_sélectionnées_uniquement_à_ce_groupe
+
Assign_new_file=Assigner_un_nouveau_fichier
+
Assign_the_original_group's_entries_to_this_group?=Assigner_les_entrées_originales_du_groupe_à_ce_groupe_?
+
Assigned_%0_entries_to_group_"%1".=%0_entrées_ajoutées_au_groupe_"%1".
+
Assigned_1_entry_to_group_"%0".=Une_entrée_ajoutée_au_groupe_"%0".
+
Attach_URL=Attacher_l'URL
+
Attempt_to_automatically_set_file_links_for_your_entries._Automatically_setting_works_if_a_file_in_your_file_directory<BR>or_a_subdirectory_is_named_identically_to_an_entry's_BibTeX_key,_plus_extension.=Cela_tente_de_définir_automatiquement_les_liens_fichier_de_vos_entrées.<BR>La_définition_automatique_fonctionne_si_un_fichier_dans_votre_répertoire_fichier<BR>ou_dans_un_sous-répertoire_porte_le_même_nom_que_la_clef_d'une_entrée_BibTeX,<BR>_l'extension_en_plus.
+
Auto=Auto
+
Autodetect_format=Détection_automatique_du_format
+
Autogenerate_BibTeX_keys=Création_automatique_des_clefs_BibTeX
+
Autolink_files_with_names_starting_with_the_BibTeX_key=Lier_automatiquement_les_fichiers_commençant_par_la_clef_BibTeX
+
Autolink_only_files_that_match_the_BibTeX_key=Lier_automatiquement_les_fichiers_correspondant_exactement_à_la_clef_BibTeX
+
Automatically_create_groups=Créer_automatiquement_des_groupes
+
Automatically_create_groups_for_database.=Créer_automatiquement_des_groupes_pour_la_base.
+
Automatically_created_groups=Groupes_créés_automatiquement
+
Automatically_remove_exact_duplicates=Supprimer_automatiquement_les_doublons_identiques
+
Allow_overwriting_existing_links.=Ecraser_les_liens_existants.
+
Do_not_overwrite_existing_links.=Ne_pas_écraser_les_liens_existants.
+
AUX_file_import=Importation_de_fichier_AUX
+
Available_export_formats=Formats_d'exportation_disponibles
+
Available_BibTeX_fields=Champs_BibTeX_disponibles
+
Available_import_formats=Formats_d'importation_disponibles
+
Background_color_for_optional_fields=Couleur_d'arrière-plan_pour_les_champs_optionnels
+
Background_color_for_required_fields=Couleur_d'arrière-plan_pour_les_champs_requis
+
Backup_old_file_when_saving=Créer_une_copie_de_sauvegarde_lors_de_l'enregistrement
+
BibTeX_key_is_unique.=La_clef_BibTeX_est_unique.
-BibTeX_source=Source_BibTeX
+
+%0_source=Source_%0
+
Broken_link=Lien_invalide
+
Browse=Explorer
+
by=par
+
Cancel=Annuler
+
Cannot_add_entries_to_group_without_generating_keys._Generate_keys_now?=Les_entrées_ne_peuvent_pas_être_ajoutées_au_groupe_sans_générer_des_clefs._Voulez-vous_générer_des_clefs_maintenant_?
+
Cannot_merge_this_change=Cette_modification_ne_peut_pas_être_fusionnée
+
Cannot_move_group_"%0"_down.=Le_groupe_"%0"_ne_peut_pas_être_déplacé_vers_le_bas.
+
Cannot_move_group_"%0"_left.=Le_groupe_"%0"_ne_peut_pas_être_déplacé_vers_la_gauche.
+
Cannot_move_group_"%0"_right.=Le_groupe_"%0"_ne_peut_pas_être_déplacé_vers_la_droite.
+
Cannot_move_group_"%0"_up.=Le_groupe_"%0"_ne_peut_pas_être_déplacé_vers_le_haut
+
case_insensitive=insensible_à_la_casse
+
case_sensitive=sensible_à_la_casse
+
Case_sensitive=Sensible_à_la_casse
+
change_assignment_of_entries=changer_l'assignation_des_entrées
+
Change_case=Changer_la_casse
+
Change_entry_type=Changer_le_type_d'entrée
Change_file_type=Changer_le_type_de_fichier
+
+
Change_of_Grouping_Method=Changement_de_la_Méthode_de_Groupement
+
change_preamble=changer_le_préambule
+
Change_table_column_and_General_fields_settings_to_use_the_new_feature=Modifier_les_colonnes_de_la_table_et_les_paramètres_des_champs_généraux_pour_utiliser_cette_nouvelle_fonction
+
Changed_font_settings=Paramètres_de_police_modifiés
+
Changed_language_settings=Paramètres_linguistiques_modifiés
+
Changed_look_and_feel_settings=Changer_les_paramètres_d'apparence
+
Changed_preamble=Préambule_modifié
+
Characters_to_ignore=Caractères_à_ignorer
+
Check_existing_file_links=Vérifier_les_liens_fichier_existants
+
Check_links=Vérifier_les_liens
+
Choose_the_URL_to_download.=Choisir_l'URL_de_téléchargement.
Cite_command=Commande_Cite
+
Class_name=Nom_de_classe
+
Clear=Vider
+
Clear_fields=Vider_les_champs
+
Close=Fermer
Close_others=Fermer_les_autres
Close_all=Fermer_toutes
+
Close_dialog=Fermer_la_fenêtre
+
Close_the_current_database=Fermer_la_base_courante
+
Close_window=Fermer_la_fenêtre
+
Closed_database=Base_fermée
+
Collapse_subtree=Masquer_le_sous-arbre
+
Color_codes_for_required_and_optional_fields=Codes_de_couleurs_pour_les_champs_requis_et_optionnels
+
Color_for_marking_incomplete_entries=Couleur_pour_marquer_les_entrées_incomplètes
+
Column_width=Largeur_de_colonne
+
Command_line_id=Identifiant_de_la_ligne_de_commande
-Connect=Connexion_automatique
+
+
Contained_in=Contenu_dans
+
Content=Contenu
+
Copied=Copié
+
Copied_cell_contents=Contenu_des_cellules_copié
+
Copied_key=Clef_copiée
+
Copied_keys=Clefs_copiées
+
Copy=Copier
+
Copy_BibTeX_key=Copier_la_clef_BibTeX
Copy_file_to_file_directory=Copier_le_fichier_vers_le_répertoire_de_fichiers
+
Copy_to_clipboard=Copier_dans_le_presse-papier
+
Could_not_call_executable=L'exécutable_n'a_pas_pu_être_lancé
Could_not_connect_to_Vim_server._Make_sure_that_Vim_is_running<BR>with_correct_server_name.=La_connexion_au_serveur_Vim_a_échoué._Assurez-vous_que_Vim_tourne<BR>avec_le_bon_nom_de_serveur.
+
Could_not_export_file=Le_fichier_n'a_pas_pu_être_exporté
+
Could_not_export_preferences=L'exportation_des_préférences_a_échoué
+
Could_not_find_a_suitable_import_format.=Un_format_d'importation_convenable_n'a_pas_pu_être_trouvé
Could_not_import_preferences=L'importation_des_préférences_a_échoué
+
Could_not_instantiate_%0=N'a_pas_pu_initialiser_%0
Could_not_instantiate_%0_%1=N'a_pas_pu_initialiser_%0_%1
Could_not_instantiate_%0._Have_you_chosen_the_correct_package_path?=%0_a_échoué._Avez-vous_choisi_le_chemin_de_paquetage_correct_?
Could_not_open_link=Le_lien_n'a_pas_pu_être_ouvert
+
Could_not_print_preview=Echec_de_l'impression_de_l'aperçu
+
Could_not_run_the_'vim'_program.=Le_programme_'vim'_n'a_pas_pu_être_lancé.
+
Could_not_save_file.=Le_fichier_n'a_pas_pu_être_enregistré_.
Character_encoding_'%0'_is_not_supported.=L'encodage_de_caractères_'%0'_n'est_pas_supporté.
+
Created_groups.=Groupes_créés.
+
crossreferenced_entries_included=Entrées_avec_références_croisées_incluses
+
Current_content=Contenu_actuel
+
Current_value=Valeur_actuelle
+
Custom_entry_types=Types_d'entrées_personnalisées
+
Custom_entry_types_found_in_file=Types_d'entrées_personnalisées_trouvées_dans_le_fichier
+
Customize_entry_types=Personnaliser_les_types_d'entrées
+
Customize_key_bindings=Personnaliser_les_affectations_de_touches
+
Cut=Couper
+
cut_entries=Couper_les_entrées
+
cut_entry=supprimer_l'entrée
+
+
Database_encoding=Encodage_de_la_base_de_données
+
Database_properties=Propriétés_de_la_base_de_données
Database_type=Type_de_base_de_données
+
Date_format=Format_de_date
+
Default=Défaut
+
Default_encoding=Encodage_par_défaut
+
Default_grouping_field=Champ_par_défaut_pour_les_groupes
+
Default_look_and_feel=Apparence_par_défaut
+
Default_pattern=Modèle_par_défaut
+
Default_sort_criteria=Critère_de_tri_par_défaut
Define_'%0'=Définir_'%0'
+
Delete=Supprimer
+
Delete_custom_format=Supprimer_le_format_personnalisé
+
delete_entries=effacer_les_entrées
+
Delete_entry=Supprimer_l'entrée
+
delete_entry=effacer_l'entrée
+
Delete_multiple_entries=Effacer_plusieurs_entrées
+
Delete_rows=Supprimer_des_lignes
+
Delete_strings=Supprimer_les_chaînes
+
Deleted=Supprimé
+
+Delete_local_file=Supprimer_le_fichier_local
+
Delimit_fields_with_semicolon,_ex.=Délimiter_les_champs_par_des_points-virgules,_ex.
+
Descending=Descendant
+
Description=Description
+
Deselect_all=Tout_désélectionner
Deselect_all_duplicates=Désélectionner_tous_les_doublons
+
Disable_this_confirmation_dialog=Désactiver_cette_demande_de_confirmation
+
Display_all_entries_belonging_to_one_or_more_of_the_selected_groups.=Afficher_toutes_les_entrées_appartenant_à_au_moins_un_des_groupes_sélectionnés.
+
Display_all_error_messages=Afficher_tous_les_messages_d'erreur
+
Display_help_on_command_line_options=Afficher_l'aide_sur_les_options_de_la_ligne_de_commande
+
Display_only_entries_belonging_to_all_selected_groups.=Afficher_uniquement_les_entrées_appartenant_à_tous_les_groupes_sélectionnés.
Display_version=Afficher_la_version
+
Displaying_no_groups=Pas_de_groupes_à_afficher
+
Do_not_abbreviate_names=Ne_pas_abréger_les_noms
+
Do_not_automatically_set=Ne_pas_définir_automatiquement.
+
Do_not_import_entry=Ne_pas_importer_l'entrée
+
Do_not_open_any_files_at_startup=N'ouvrir_aucun_fichier_au_démarrage
+
Do_not_overwrite_existing_keys=Ne_pas_écraser_de_clefs_existantes
Do_not_show_these_options_in_the_future=Ne_pas_afficher_ces_options_à_l'avenir
+
Do_not_wrap_the_following_fields_when_saving=Ne_pas_renvoyer_à_la_ligne_les_champs_suivants_lors_de_l'enregistrement
Do_not_write_the_following_fields_to_XMP_Metadata\:=Ne_pas_écrire_les_champs_suivants_dans_les_métadonnées_XMP_\:
+
Do_you_want_JabRef_to_do_the_following_operations?=Voulez-vous_que_JabRef_fasse_les_opérations_suivantes_?
+
+Donate_to_JabRef=Faire_un_don_à_JabRef
+
Down=Bas
+
Download=Télécharger
+
Download_file=Télécharger_le_fichier
+
Downloading...=Téléchargement...
Drop_%0=Déposer_%0
+
duplicate_removal=Suppression_des_doublons
+
Duplicate_string_name=Dupliquer_le_nom_de_chaîne
+
Duplicates_found=Doublons_trouvés
+
Dynamic_groups=Groupes_dynamiques
+
Dynamically_group_entries_by_a_free-form_search_expression=Grouper_dynamiquement_les_entrées_en_utilisant_une_expression_de_recherche_de_forme_libre
+
Dynamically_group_entries_by_searching_a_field_for_a_keyword=Grouper_dynamiquement_les_entrées_en_cherchant_un_mot-clef_dans_un_champ
+
Each_line_must_be_on_the_following_form=Chaque_ligne_doit_ê_de_la_forme_suivante
+
Edit=Editer
+
Edit_custom_export=Editer_l'exportation_personnalisée
Edit_entry=Editer_l'entrée
Save_file=Editer_le_lien_de_fichier
Edit_file_type=Editer_le_type_de_fichier
+
Edit_group=Editer_le_groupe
+
Edit_journal=Editer_le_journal
+
Edit_preamble=Editer_le_préambule
Edit_strings=Editer_les_chaînes
Editor_options=Options_d'éditeur
+
Empty_BibTeX_key=Clef_BibTeX_vide
+
Grouping_may_not_work_for_this_entry.=La_gestion_des_groupes_pourrait_ne_plus_fonctionner_pour_cette_entrée.
+
empty_database=base_vide
Enable_word/name_autocompletion=Autoriser_l'auto-génération_des_mots/noms
+
Enter_URL=Entrer_l'URL
+
Enter_URL_to_download=Entrer_l'URL_de_téléchargement
+
entries=entrées
+
Entries_cannot_be_manually_assigned_to_or_removed_from_this_group.=Des_entrées_ne_peuvent_pas_être_ajoutées_ou_supprimées_manuellement_de_ce_groupe.
+
Entries_exported_to_clipboard=Entrées_exportées_vers_le_presse-papiers
+
+
entry=entrée
+
Entry_editor=Editeur_d'entrée
+
Entry_preview=Aperçu_de_l'entrée
+
Entry_table=Table_des_entrées
+
Entry_table_columns=Colonnes_de_la_table_des_entrées
+
Entry_type=Type_d'entrée
+
Entry_type_names_are_not_allowed_to_contain_white_space_or_the_following_characters=Les_noms_de_type_d'entrée_ne_peuvent_pas_contenir_d'espace_et_les_caractères_suivants
+
Entry_types=Types_d'entrées
+
Error=Erreur
Error_exporting_to_clipboard=Erreur_lors_de_l'exportation_vers_le_presse-papiers
+
Error_occurred_when_parsing_entry=Une_erreur_est_survenue_pendant_le_traitement_de_l'entrée
+
Error_opening_file=Erreur_lors_de_l'ouverture_du_fichier
+
Error_setting_field=Erreur_de_configuration_du_champ
Error_while_writing=Erreur_lors_de_l'écriture
Error_writing_to_%0_file(s).=Erreur_lors_de_l'écriture_de_%0_fichier(s).
+
+
Exceptions=Exceptions
+
Existing_file=Fichier_existant
+
'%0'_exists._Overwrite_file?='%0'_existe._Ecraser_le_fichier_?
Overwrite_file?=Ecraser_le_fichier_?
+
Expand_subtree=Développer_le_sous-arbre
+
Export=Exporter
+
Export_name=Nom_de_l'exportation
+
Export_preferences=Exporter_les_préférences
+
Export_preferences_to_file=Exporter_les_préférences_vers_un_fichier
+
Export_properties=Propriétés_de_l'exportation
+
Export_to_clipboard=Exporter_vers_le_presse-papiers
+
Exporting=Exportation_en_cours
Extension=Extension
+
External_changes=Modifications_externes
+
External_file_links=Liens_vers_les_fichiers_externes
+
External_files=Fichiers_externes
+
External_programs=Programmes_externes
+
External_viewer_called=Afficheur_externe_lancé
+
Fetch=Rechercher
+
Field=Champ
+
field=Champ
+
Field_name=Nom_du_champ
Field_names_are_not_allowed_to_contain_white_space_or_the_following_characters=Les_noms_de_champs_ne_peuvent_pas_contenir_d'espace_ou_l'un_des_caractères_suivants
+
Field_to_filter=Champ_vers_filtre
+
Field_to_group_by=Champ_à_grouper_par
+
File=Fichier
+
file=fichier
File_'%0'_is_already_open.=Le_fichier_'%0'_est_déjà_ouvert.
+
File_'%0'_not_found=Fichier_'%0'_non_trouvé
+
File_changed=Fichier_changé
File_directory_is_'%0'\:=Le_répertoire_de_fichier_est_'%0'_\:
+
File_directory_is_not_set_or_does_not_exist\!=Le_répertoire_de_fichiers_n'est_pas_configuré_ou_n'existe_pas_\!
File_exists=Le_fichier_existe
+
File_has_been_updated_externally._What_do_you_want_to_do?=Le_fichier_a_été_mis_à_jour_externalement._Que_voulez-vous_faire_?
+
File_not_found=Fichier_non_trouvé
File_type=Type_de_fichier
+
File_updated_externally=Fichier_mis_à_jour_externalement
+
filename=nom_de_fichier
+
Files_opened=Fichiers_ouverts
+
Filter=Filtre
+
Finished_automatically_setting_external_links.=La_définition_automatique_des_liens_externes_est_terminée.
+
Finished_synchronizing_file_links._Entries_changed\:_%0.=Synchronisation_des_liens_fichier_terminée._Entrées_modifiées\:_%0.
Finished_writing_XMP-metadata._Wrote_to_%0_file(s).=Ecriture_des_méta-données_XMP_terminée._Ecriture_de_%0_fichier(s).
Finished_writing_XMP_for_%0_file_(%1_skipped,_%2_errors).=Fin_de_l'écriture_des_XMP_pour_%0_fichiers_(%1_passés,_%2_erreurs).
+
First_select_the_entries_you_want_keys_to_be_generated_for.=Commencez_par_sélectionner_les_entrées_pour_lesquelles_vous_voulez_que_des_clefs_soient_générées.
+
Fit_table_horizontally_on_screen=Ajuster_horizontalement_la_table_à_l'écran
+
Float=Flottante
Float_marked_entries=Entrées_marquées_flottantes
+
Font_family=Famille_de_police
+
Font_preview=Prévisualisation_de_la_police
+
Font_size=Taille_de_police
+
Font_style=Style_de_police
+
Font_selection=Sélecteur_de_police
+
for=pour
+
Format_of_author_and_editor_names=Format_des_noms_d'auteurs_et_d'éditeurs
Format_string=Chaîne_de_format
+
Format_used=Format_utilisé
Formatter_name=Nom_de_formateur
+
found_in_AUX_file=trouvées_dans_le_fichier_AUX
+
Full_name=Nom_complet
+
General=Général
+
General_fields=Champs_généraux
+
Generate=Créer
+
Generate_BibTeX_key=Créer_la_clef_BibTeX
+
Generate_keys=Générer_les_clefs
+
Generate_keys_before_saving_(for_entries_without_a_key)=Générer_les_clefs_avant_d'enregistrer_(pour_les_entrées_sans_clef)
Generate_keys_for_imported_entries=Générer_les_clefs_pour_les_entrées_importées
+
Generate_now=Générer_maintenant
+
Generated_BibTeX_key_for=Création_terminée_de_la_clef_BibTeX_pour
+
Generating_BibTeX_key_for=Création_en_cours_d'une_clef_BibTeX_pour
+Get_fulltext=Obtenir_le_document
Grab=Rechercher
+
Gray_out_entries_not_in_group_selection=Griser_les_entrées_hors_de_la_sélection
+
Gray_out_non-hits=Griser_les_entrées_non_correspondantes
+
Groups=Groupes
+
Have_you_chosen_the_correct_package_path?=Avez-vous_choisi_le_bon_chemin_pour_le_paquetage_?
+
Help=Aide
+
Help_on_groups=Aide_sur_les_groupes
+
Help_on_key_patterns=Aide_sur_le_paramétrage_des_clefs
Help_on_regular_expression_search=Aide_sur_la_recherche_d'une_expression_régulière
+
Hide_non-hits=Masquer_les_entrées_non_correspondantes
+
Hierarchical_context=Type_de_hiérarchie
+
Highlight=Surlignée
Highlight_groups_matching_all_selected_entries=Surligner_les_groupes_correspondant_à_toutes_les_entrées_sélectionnées
Highlight_groups_matching_any_selected_entry=Surligner_les_groupes_correspondant_à_au_moins_une_des_entrées_sélectionnées
+Disable_highlight_groups_matching_entries=Désactiver_le_surlignement_des_groupes_correspondant_à_des_entrées
+
Highlight_overlapping_groups=Surligner_les_groupes_se_chevauchant
+
Hint\:_To_search_specific_fields_only,_enter_for_example\:<p><tt>author\=smith_and_title\=electrical</tt>=Astuce\:_Pour_chercher_uniquement_dans_des_champs_spécifiques,_entrez_par_exemple\:<p><tt>author\=smith_and_title\=électrique</tt>
+
HTML_table=Tableau_HTML
HTML_table_(with_Abstract_&_BibTeX)=Tableau_HTML_(avec_Résumé_&_BibTeX)
Icon=Icône
+
Ignore=Ignorer
+
Immediate_subgroups=Uniquement_les_sous-groupes_directs
+
Import=Importer
+
Import_and_keep_old_entry=Importer_et_conserver_l'ancienne_entrée
+
Import_and_remove_old_entry=Importer_et_supprimer_l'ancienne_entrée
+
Import_entries=Importer_les_entrées
+
Import_failed=L'importation_a_échouée
+
Import_file=Fichier_à_importer
+
Import_group_definitions=Importer_les_définitions_de_groupe
+
Import_name=nom_Import
+
Import_preferences=Importer_les_préférences
+
Import_preferences_from_file=Importer_les_préférences_depuis_un_fichier
+
Import_strings=Importer_les_chaînes
+
Import_to_open_tab=Importer_dans_l'onglet_ouvert
-Import_word_selector_definitions=Importer_les_définitions_des_sélecteurs_de_mots
+
Imported_entries=Entrées_importées
+
Imported_from_database=Importé_à_partir_de_la_base_de_données
-ImportFormat_class=Classe_ImportFormat
+
+Importer_class=Classe_Importer
+
Importing=Importation_en_cours
+
Importing_in_unknown_format=Importation_dans_un_format_inconnu
+
Include_abstracts=Inclure_les_résumés
Include_entries=Entrées_affectées
+
Include_subgroups\:_When_selected,_view_entries_contained_in_this_group_or_its_subgroups=Inclut_les_sous-groupes_\:_Quand_sélectionné,_afficher_les_entrées_contenues_dans_ce_groupe_ou_ses_sous-groupes
+
Independent_group\:_When_selected,_view_only_this_group's_entries=Groupe_indépendant_\:_Quand_sélectionné,_afficher_uniquement_les_entrées_de_ce_groupe
+
Initially_show_groups_tree_expanded=Afficher_au_départ_l'arbre_des_groupes_développé
+
Work_options=Attribution_des_champs
-Input_error=Entrée_erronée
+
Insert=Insérer
+
Insert_rows=Insérer_des_lignes
Intersection=Intersection
+
Invalid_BibTeX_key=Clef_BibTeX_invalide
+
Invalid_date_format=Format_de_date_invalide
+
Invalid_URL=URL_invalide
+
Inverted=Complémentaire
+
ISO_abbreviation=Abréviation_ISO
+
Online_help=Aide_en_ligne
+
JabRef_preferences=Préférences_pour_JabRef
+
Journal_abbreviations=Abréviations_de_journaux
+
Journal_list_preview=Prévisualisation_de_la_liste_des_journaux
+
Journal_name=Nom_du_journal
+
Keep=Garder
+
Keep_both=Garder_les_deux
+
Key_bindings=Affectations_des_touches
+
Key_bindings_changed=Affectations_des_touches_modifiées
+
Key_generator_settings=Paramétrage_du_générateur_de_clef
+
Key_pattern=Paramétrage_des_clefs
+
keys_in_database=clefs_dans_la_base_de_données
+
Keyword=Mot-clef
+
Label=Nom_du_champ
+
Language=Langue
+
Last_modified=Dernier_modifié
+
LaTeX_AUX_file=Fichier_LaTeX_AUX
Leave_file_in_its_current_directory=Laisser_le_fichier_dans_son_répertoire_courant
+
Left=Gauche
Level=Niveau
+
Limit_to_fields=Restreindre_aux_champs
+
Limit_to_selected_entries=Restreindre_aux_seules_entrées_sélectionnées
+
Link=Lien
Link_local_file=Lier_le_fichier_local
Link_to_file_%0=Lien_vers_le_fichier_%0
+
Listen_for_remote_operation_on_port=Ecouter_le_port_pour_des_opérations_à_distance
Load_and_Save_preferences_from/to_jabref.xml_on_start-up_(memory_stick_mode)=Charger_et_enregistrer_les_préférences_de/vers_jabref.xml_au_démarrage_(mode_clef_mémoire)
+
Look_and_feel=Apparence
Main_file_directory=Répertoire_de_fichiers_principal
+
Main_layout_file=Principal_fichier_de_mise_en_page
-Manage=Gérer
+
Manage_custom_exports=Gérer_les_exportations_personnalisées
+
Manage_custom_imports=Gérer_les_importations_personnalisées
Manage_external_file_types=Gérer_les_types_de_fichiers_externes
+
Manage_journal_abbreviations=Gérer_les_abréviations_de_journaux
+
Mark_entries=Etiqueter_ces_entrées
+
Mark_entry=Etiqueter_l'entrée
+
Mark_new_entries_with_addition_date=Enregistrer_la_date_d'ajout_pour_les_nouvelles_entrées
+
Mark_new_entries_with_owner_name=Nouvelles_entrées_attribuées_au_propriétaire
+
Memory_stick_mode=Mode_clef_mémoire
+
Menu_and_label_font_size=Taille_de_police_pour_les_menus_et_les_champs
+
Merged_external_changes=Fusionner_les_modifications_externes
+
Messages=Messages
+
Modification_of_field=Modification_du_champ
+
Modified_group_"%0".=Groupe_"%0"_modifié.
+
Modified_groups=Groupes_modifiés
+
Modified_string=Chaîne_modifiée
+
Modify=Modifier
+
modify_group=Modifier_le_groupe
+
Move=Déplacer
+
Move_down=Déplacer_vers_le_bas
+
Move_entries_in_group_selection_to_the_top=Déplacer_les_entrées_sélectionnées_en_haut
Move_external_links_to_'file'_field=Déplacer_les_liens_externes_vers_le_champ_'fichier'
+
move_group=déplacer_le_groupe
+
Move_up=Déplacer_vers_le_haut
+
Moved_group_"%0".=Groupe_"%0"_déplacé.
+
Name=Nom
Name_formatter=Formateur_de_nom
+
Natbib_style=Style_Natbib
+
nested_AUX_files=fichiers_AUX_imbriqués
+
New=Nouveau
+
new=nouveau
+
New_BibTeX_entry=Nouvelle_entrée_BibTeX
+
New_BibTeX_subdatabase=Nouveau_fichier_BibTeX
+
New_content=Nouveau_contenu
+
New_database_created.=Nouvelle_base_créée.
+New_%0_database=Nouvelle_base_%0
New_field_value=Nouvelle_valeur_du_champ
+
New_file=Nouveau_fichier
New_file_link_(INSERT)=Nouveau_lien_de_fichier_(INSERT)
+
New_group=Nouveau_groupe
+
New_string=Nouvelle_chaîne
+
Next_entry=Entrée_suivante
+
No_actual_changes_found.=Pas_de_changements_trouvés.
+
no_base-BibTeX-file_specified=fichier_BibTeX_non_spécifié
+
no_database_generated=pas_de_base_créée
+
No_entries_found._Please_make_sure_you_are_using_the_correct_import_filter.=Pas_d'entrées_trouvées._Assurez-vous,_SVP,_que_vous_utilisez_le_filtre_d'importation_approprié.
+
+
No_entries_found_for_the_search_string_'%0'=Pas_d'entrée_pour_la_chaîne_de_recherche_'%0'
+
No_entries_imported.=Pas_d'entrées_importées.
+
No_exceptions_have_occurred.=Aucune_exception_n'est_survenue.
No_files_found.=Fichiers_non_trouvés.
+
No_GUI._Only_process_command_line_options.=Pas_d'interface_utilisateur._Traitement_limité_aux_options_de_la_ligne_de_commande.
+
No_journal_names_could_be_abbreviated.=Aucun_nom_de_journal_n'a_pu_être_abrégé.
+
No_journal_names_could_be_unabbreviated.=Aucun_nom_de_journal_n'a_pu_être_développé.
No_PDF_linked=Pas_de_PDF_lié
-No_references_found=Aucune_référence_trouvée
+
No_URL_defined=Pas_d'URL_définie
not=non
+
not_found=non_trouvé
+
Note_that_you_must_specify_the_fully_qualified_class_name_for_the_look_and_feel,=Notez_que_vous_devez_spécifier_le_nom_de_classe_complet_pour_l'apparence,
+
Nothing_to_redo=Rien_à_répéter
+
Nothing_to_undo=Rien_à_annuler
-Number_of_references_to_fetch?=Nombre_de_références_à_récupérer_?
+
occurrences=occurrences
+
OK=Ok
One_or_more_file_links_are_of_the_type_'%0',_which_is_undefined._What_do_you_want_to_do?=Un_ou_plusieurs_liens_de_fichier_sont_du_type_'%0',_qui_est_indéfini._Que_voulez-vous_faire_?
+
One_or_more_keys_will_be_overwritten._Continue?=Une_ou_plusieurs_clefs_seront_écrasées._Continuer_?
+
Open=Ouvrir
+
Open_BibTeX_database=Ouvrir_une_base_BibTeX
+
Open_database=Ouvrir_une_base
+
Open_editor_when_a_new_entry_is_created=Ouvrir_l'éditeur_quand_une_nouvelle_entrée_est_créée
+
Open_file=Ouvrir_le_fichier
+
Open_last_edited_databases_at_startup=Ouvrir_les_fichiers_de_la_dernière_session_au_démarrage
-Open_shared_database=Ouvrir_une_base_de_données_partagée
+
+Connect_to_shared_database=Ouvrir_une_base_de_données_partagée
+
Open_terminal_here=Ouvrir_un_terminal_ici
+
Open_URL_or_DOI=Ouvrir_URL_ou_DOI
+
Opened_database=Base_ouverte
+
Opening=Ouverture_en_cours
+
Opening_preferences...=Ouverture_des_préférences_en_cours...
+
Operation_canceled.=Opération_annulée.
Operation_not_supported=Opération_non_supportée
+
Optional_fields=Champs_optionnels
+
Options=Options
+
or=ou
+
Output=Sortie
+
Output_or_export_file=Fichier_de_sortie_ou_d'exportation
+
Override=Remplacer
+
Override_default_file_directories=Remplacer_les_répertoires_de_fichier_par_défaut
+
Override_default_font_settings=Se_substituer_aux_paramètres_de_police_par_défaut
+
Override_the_BibTeX_field_by_the_selected_text=Remplacer_la_clef_BibTeX_par_le_texte_sélectionné
+
+
Overwrite=Ecraser
Overwrite_existing_field_values=Ecraser_les_valeurs_existantes_du_champ
+
Overwrite_keys=Ecraser_les_clefs
+
pairs_processed=paires_traitées
Password=Mot_de_passe
+
Paste=Coller
+
paste_entries=Coller_les_entrées
+
paste_entry=Coller_l'entrée
Paste_from_clipboard=Coller_depuis_le_presse-papiers
+
Pasted=Collé
+
Path_to_%0_not_defined=Chemin_vers_%0_non_défini
+
Path_to_LyX_pipe=Chemin_du_canal_de_transmission_LyX
+
PDF_does_not_exist=Le_PDF_n'existe_pas
+
Personal_journal_list=Liste_personnelle_de_journaux
+
Plain_text_import=Importation_de_texte_brut
+
Please_enter_a_name_for_the_group.=SVP,_entrez_un_nom_pour_le_groupe.
+
Please_enter_a_search_term._For_example,_to_search_all_fields_for_<b>Smith</b>,_enter\:<p><tt>smith</tt><p>To_search_the_field_<b>Author</b>_for_<b>Smith</b>_and_the_field_<b>Title</b>_for_<b>electrical</b>,_enter\:<p><tt>author\=smith_and_title\=electrical</tt>=SVP,_entrez_un_terme_à_recherche._Par_exemple,_pour_rechercher_<b>Smith</b>_dans_tout_les_champs,_entrez_\:<p><tt>smith</tt><p>Pour_rechercher_<b>Smith</b>_dans_le_champ_<b>Author</b>_et_<b>électrique</b>_dans_le_champ_<b>Title</ [...]
+
Please_enter_the_field_to_search_(e.g._<b>keywords</b>)_and_the_keyword_to_search_it_for_(e.g._<b>electrical</b>).=SVP,_entrez_le_champ_de_recherche_(par_ex._<b>keywords</b>)_et_le_mot-clef_à_rechercher_(par_ex._<b>électrique</b>).
+
Please_enter_the_string's_label=SVP,_entrez_le_nom_de_la_chaîne
+
Please_select_an_importer.=Sélectionner_un_filtre_d'importation,_SVP.
+
Please_select_exactly_one_group_to_move.=SVP,_sélectionnez_uniquement_un_groupe_à_déplacer.
+
Possible_duplicate_entries=Entrées_potentiellement_dupliquées
+
Possible_duplicate_of_existing_entry._Click_to_resolve.=Duplication_possible_d'une_entrée_existante._Cliquer_pour_vérifier.
+
Preamble=Préambule
+
Preferences=Préférences
+
Preferences_recorded.=Préférences_enregistrées.
+
Preview=Aperçu
+Citation_Style=Style_de_citation
+Current_Preview=Aperçu_actuel
+Cannot_generate_preview_based_on_selected_citation_style.=La_prévisualisation_ne_peut_pas_être_générée_à_partir_du_style_de_citation_sélectionné.
+Bad_character_inside_entry=Caractère_érroné_dans_l'entrée
+Error_while_generating_citation_style=Erreur_lors_de_la_génération_du_style_de_citation
+Preview_style_changed_to\:_%0=Style_d'aperçu_modifié_en_:_%0
+Next_preview_layout=Mode_d'aperçu_suivant
+Previous_preview_layout=Mode_d'aperçu_précédent
+
Previous_entry=Entrée_précédente
+
Primary_sort_criterion=Critère_de_tri_principal
Problem_with_parsing_entry=Problème_de_traitement_d'une_entrée
-
Processing_%0=Traitement_de_%0
Program_output=Sortie_du_programme
Pull_changes_from_shared_database=Récupérer_les_modification_depuis_la_base_de_données_partagée
+
Pushed_citations_to_%0=Envoyer_les_citations_vers_%0
+
Quit_JabRef=Quitter_JabRef
+
Quit_synchronization=Quitter_la_synchronisation
+
Raw_source=Texte_brut
+
Rearrange_tabs_alphabetically_by_title=Classer_les_onglets_par_ordre_alphabétique
+
Redo=Répéter
+
Reference_database=Base_de_référence
-References_found=Références_trouvées
+
+%0_references_found._Number_of_references_to_fetch?=Références_trouvées\:_%0._Nombre_de_références_à_récupérer_?
+
Refine_supergroup\:_When_selected,_view_entries_contained_in_both_this_group_and_its_supergroup=Raffine_le_super-groupe_\:_Quand_sélectionné,_afficher_les_entrées_contenues_à_la_fois_dans_ce_groupe_et_son_super-groupe
+
regular_expression=Expression_régulière
+
Remember_these_entry_types?=Se_souvenir_de_ces_types_d'entrées_?
+
Remote_operation=Accès_à_distance
+
Remote_server_port=Port_du_serveur_d'accès_à_distance
+
Remove=Supprimer
+
Remove_subgroups=Supprimer_les_sous-groupes
+
Remove_all_subgroups_of_"%0"?=Supprimer_tous_les_sous-groupes_de_"%0"_?
+
Remove_entry_from_import=Supprimer_l'entrée_de_l'importation
+
Remove_entry_selection_from_this_group=Supprimer_les_entrées_sélectionnées_de_ce_groupe
+
Remove_entry_type=Supprimer_le_type_d'entrée
Remove_file_link_(DELETE)=Supprimer_le_lien_de_fichier_(DELETE)
+
Remove_from_group=Supprimer_du_groupe
+
Remove_group=Supprimer_le_groupe
+
Remove_group,_keep_subgroups=Supprimer_le_groupe,_garder_les_sous-groupes
+
Remove_group_"%0"?=Supprimer_le_groupe_"%0"_?
+
Remove_group_"%0"_and_its_subgroups?=Supprimer_le_groupe_"%0"_et_ses_sous-groupes_?
+
remove_group_(keep_subgroups)=supprimer_le_groupe_(garder_les_sous-groupes)
+
remove_group_and_subgroups=supprimer_le_groupe_et_les_sous-groupes
+
Remove_group_and_subgroups=Supprimer_le_groupe_et_les_sous-groupes
+
Remove_link=Supprimer_le_lien
+
Remove_old_entry=Supprimer_l'ancienne_entrée
+
Remove_selected_strings=Supprimer_les_chaînes_sélectionnées
+
Removed_group_"%0".=Groupe_"%0"_supprimé.
+
Removed_group_"%0"_and_its_subgroups.=Groupe_"%0"_et_ses_sous-groupes_supprimés.
+
Removed_string=Chaîne_supprimée
+
Renamed_string=Chaîne_renommée
+
Replace_(regular_expression)=Remplacer_(expression_régulière)
+
Replace_string=Remplacer_la_chaîne
+
Replace_with=Remplacer_par
+
Replaced=Remplacé
+
Required_fields=Champs_requis
+
Reset_all=Rétablir_les_options_précédentes
+
Resolve_strings_for_all_fields_except=Traiter_les_chaînes_pour_tous_les_champs_sauf
Resolve_strings_for_standard_BibTeX_fields_only=Traiter_les_chaînes_pour_les_champs_BibTeX_standard_uniquement
+
resolved=résolu
+
Revert_to_original_source=Rétablir_le_contenu_initial
+
Review=Remarques
+
Review_changes=Revoir_les_changements
+
Right=Droite
+
Save=Enregistrer
Save_all_finished.=Enregistrement_de_tout_terminée.
+
Save_all_open_databases=Enregistrement_toutes_les_bases_ouvertes
+
Save_before_closing=Enregistrement_avant_fermeture
+
Save_database=Enregistrement_la_base
Save_database_as...=Enregistrement_la_base_sous...
+
Save_entries_in_their_original_order=Enregistrement_les_entrées_dans_leur_ordre_original
+
Save_failed=Echec_de_l'enregistrement
+
Save_failed_during_backup_creation=L'enregistrement_a_échoué_durant_la_création_de_la_copie_de_secours
-Save_failed_while_committing_changes\:_%0=L'enregistrement_a_échoué_lors_de_la_soumission_des_changements\:_%0
+
Save_selected_as...=Enregistrer_la_sélection_sous...
+
Saved_database=Base_enregistrée
+
Saved_selected_to_'%0'.=Sélection_enregistrée_dans_'%0'.
+
Saving=Enregistrement_en_cours
Saving_all_databases...=Enregistrement_de_toutes_les_bases...
+
Saving_database=Enregistrement_de_la_base_en_cours
+
Search=Recherche
+
Search_expression=Expression_à_rechercher
+
Search_for=Rechercher
+
Searching_for_duplicates...=Recherche_des_doublons_en_cours...
+
Searching_for_files=Recherche_de_fichiers...
+
Secondary_sort_criterion=Critère_secondaire_de_tri
+
Select=Sélectionner
+
+
Select_all=Tout_sélectionner
+
Select_encoding=Sélectionner_l'encodage
+
Select_entry_type=Sélectionner_un_type_d'entrée
Select_external_application=Sélectionner_une_application_externe
+
Select_file_from_ZIP-archive=Sélectionner_un_fichier_depuis_une_archive_ZIP
+
Select_the_tree_nodes_to_view_and_accept_or_reject_changes=Sélectionner_les_noeuds_de_l'arborescence_pour_voir,_et_accepter_ou_rejeter,_les_modifications
Selected_entries=Les_entrées_sélectionnées
Set_field=Configurer_le_champ
Set_fields=Configurer_les_champs
+
Set_general_fields=Définir_les_champs_généraux
Set_main_external_file_directory=Définir_le_répertoire_principal_des_fichiers_externes
+
Set_table_font=Définir_la_police_de_la_table
+
Settings=Paramètres
+
Shortcut=Raccourci
-Show/edit_BibTeX_source=Montrer/éditer_le_source_BibTeX
+
+Show/edit_%0_source=Montrer/éditer_le_source_%0
+
Show_'Firstname_Lastname'=Ordre_d'affichage_'Prénom_Nom'
+
Show_'Lastname,_Firstname'=Ordre_d'affichage_'Nom,_Prénom'
+
Show_BibTeX_source_by_default=Par_défaut,_afficher_l'onglet_Source_BibTeX
+
Show_confirmation_dialog_when_deleting_entries=Demander_une_confirmation_lors_de_la_suppression_d'entrées
+
Show_description=Montrer_la_description
+
Show_dynamic_groups_in_<i>italics</i>=Afficher_les_groupes_dynamiques_en_<i>italique</i>
+
Show_entries_<b>not</b>_in_group_selection=Montrer_les_entrées_<b>non</b>_sélectionnées
+
Show_file_column=Afficher_la_colonne_Fichier
+
Show_icons_for_groups=Afficher_les_icônes_pour_les_groupes
Show_last_names_only=Afficher_uniquement_les_noms_propres
+
Show_names_unchanged=Ordre_des_noms_inchangé
+
Show_optional_fields=Montrer_les_champs_optionnels
+
Show_required_fields=Montrer_les_champs_requis
+
Show_URL/DOI_column=Afficher_la_colonne_URL/DOI
+
Simple_HTML=HTML_(simple)
+
Size=Taille
+
Skipped_-_No_PDF_linked=Sauté_-_Pas_de_PDF_lié
Skipped_-_PDF_does_not_exist=Omis_-_Le_PDF_n'existe_pas
+
Skipped_entry.=Entrée_omise
+
Sort_alphabetically=Classer_alphabétiquement
+
sort_subgroups=trier_les_sous-groupes
+
Sorted_all_subgroups_recursively.=Tous_les_sous-groupes_récursivement_triés.
+
Sorted_immediate_subgroups.=Sous-groupes_directs_triés.
+
source_edit=édition_du_source
Special_name_formatters=Formateurs_de_nom_spéciaux
+
Special_table_columns=Colonnes_de_tableau_particulières
+
Starting_import=Début_d'importation
+
Statically_group_entries_by_manual_assignment=Grouper_manuellement_les_entrées
+
Status=Etat
+
Stop=Arrêt
+
Store_journal_abbreviations=Stocker_les_abréviations_de_journaux
+
Stored_entry=Entrée_enregistrée
+
Strings=Chaîne
+
Strings_for_database=Chaînes_pour_la_base
+
Subdatabase_from_AUX=BibTeX_à_partir_de_LaTeX_AUX
+
Switches_between_full_and_abbreviated_journal_name_if_the_journal_name_is_known.=Basculer_entre_les_noms_de_journaux_développés_et_abrégés_si_le_nom_de_journal_est_connu.
+
Synchronize_file_links=Synchroniser_les_liens_vers_les_fichiers
+
Synchronizing_file_links...=Synchronisation_des_liens_fichier...
+
Table_appearance=Apparence_de_la_table
+
Table_background_color=Couleur_d'arrière-plan_de_la_table
+
Table_grid_color=Couleur_de_la_grille_de_la_table
+
Table_text_color=Couleur_du_texte_de_la_table
+
Tabname=Nom_d'onglet
Target_file_cannot_be_a_directory.=Le_fichier_cible_ne_peut_pas_être_un_répertoire.
+
Tertiary_sort_criterion=Critère_tertiaire_de_tri
+
Test=Test
+
paste_text_here=Zone_de_saisie_du_texte
+
The_chosen_date_format_for_new_entries_is_not_valid=Le_format_de_date_choisi_pour_les_nouvelles_entrées_n'est_pas_valide
+
The_chosen_encoding_'%0'_could_not_encode_the_following_characters\:=L'encodage_'%0'_choisi_ne_peut_pas_encoder_les_caractères_suivants_\:
+
+
the_field_<b>%0</b>=le_champ_<b>%0</b>
+
The_file<BR>'%0'<BR>has_been_modified<BR>externally\!=Le_fichier<BR>'%0'<BR>a_été_modifié_<BR>externalement_\!
+
The_group_"%0"_already_contains_the_selection.=Le_groupe_"%0"_contient_déjà_la_sélection.
+
The_label_of_the_string_cannot_be_a_number.=L'intitulé_de_la_chaîne_ne_peut_être_un_nombre.
+
The_label_of_the_string_cannot_contain_spaces.=Un_nom_de_chaîne_ne_peut_pas_contenir_d'espaces.
+
The_label_of_the_string_cannot_contain_the_'\#'_character.=Le_nom_de_la_chaîne_ne_peut_pas_contenir_le_caractère_'\#'.
+
The_output_option_depends_on_a_valid_import_option.=L'option_de_sortie_dépend_d'une_option_d'importation_valide.
The_PDF_contains_one_or_several_BibTeX-records.=Le_PDF_contient_un_ou_plusieurs_enregistrements_BibTeX.
Do_you_want_to_import_these_as_new_entries_into_the_current_database?=Voulez-vous_les_importer_comme_de_nouvelles_entrées_dans_la_base_de_données_actuelle_?
+
The_regular_expression_<b>%0</b>_is_invalid\:=L'expression_régulière_<b>%0</b>_est_invalide\:
+
The_search_is_case_insensitive.=La_recherche_n'est_pas_sensible_à_la_casse.
+
The_search_is_case_sensitive.=La_recherche_est_sensible_à_la_casse.
+
The_string_has_been_removed_locally=La_chaîne_a_été_supprimée_localement
+
There_are_possible_duplicates_(marked_with_an_icon)_that_haven't_been_resolved._Continue?=Il_y_a_des_doublons_potentiels_(marqué_avec_un_icône)_qui_n'ont_pas_été_traités._Continuer_?
+
This_entry_has_no_BibTeX_key._Generate_key_now?=Cette_entrée_n'a_pas_de_clef_BibTeX._En_générer_une_maintenant_?
+
This_entry_is_incomplete=Cette_entrée_est_incomplète
+
This_entry_type_cannot_be_removed.=Ce_type_d'entrée_ne_peut_pas_être_supprimé.
+
This_external_link_is_of_the_type_'%0',_which_is_undefined._What_do_you_want_to_do?=Ce_lien_externe_est_du_type_'%0',_qui_est_indéfini._Que_voulez-vous_faire_?
+
This_group_contains_entries_based_on_manual_assignment._Entries_can_be_assigned_to_this_group_by_selecting_them_then_using_either_drag_and_drop_or_the_context_menu._Entries_can_be_removed_from_this_group_by_selecting_them_then_using_the_context_menu.=Ce_groupe_contient_des_entrées_basées_sur_un_ajout_manuel._Des_entrées_peuvent_être_ajoutées_à_ce_groupe_en_les_sélectionnant_puis_en_utilisant_un_glisser-déplacer_ou_le_menu_contextuel._Des_entrées_peuvent_être_supprimées_de_ce_groupe_en_le [...]
+
This_group_contains_entries_whose_<b>%0</b>_field_contains_the_keyword_<b>%1</b>=Ce_groupe_contient_des_entrées_dont_le_champ_<b>%0</b>_contient_le_mot-clef_<b>%1</b>_
+
This_group_contains_entries_whose_<b>%0</b>_field_contains_the_regular_expression_<b>%1</b>=Ce_groupe_contient_des_entrées_dont_le_champ_<b>%0</b>_contient_l'expression_régulière_<b>%1</b>_
This_makes_JabRef_look_up_each_file_link_and_check_if_the_file_exists._If_not,_you_will_be_given_options<BR>to_resolve_the_problem.=JabRef_cherche_chaque_fichier_lien_et_vérifie_si_le_fichier_existe._Si_non,_des_options_vous_seront_proposées<BR>pour_résoudre_le_problème.
+
This_operation_requires_all_selected_entries_to_have_BibTeX_keys_defined.=Cette_opération_nécessite_que_toutes_les_entrées_sélectionnées_aient_des_clefs_BibTeX_définies
+
This_operation_requires_one_or_more_entries_to_be_selected.=Cette_opération_nécessite_qu'une_ou_plusieurs_entrées_soient_sélectionnées.
+
Toggle_abbreviation=Afficher/Masquer_l'abréviation
Toggle_entry_preview=Afficher/Masquer_l'aperçu
Toggle_groups_interface=Afficher/Masquer_l'interface_des_groupes
Try_different_encoding=Essayer_un_encodage_différent
+
Unabbreviate_journal_names_of_the_selected_entries=Développer_les_noms_de_journaux_des_entrées_sélectionnées
Unabbreviated_%0_journal_names.=%0_noms_de_journaux_développés.
+
Unable_to_open_file.=Impossible_d'ouvrir_le_fichier
Unable_to_open_link._The_application_'%0'_associated_with_the_file_type_'%1'_could_not_be_called.=Impossible_d'ouvrir_un_lien._L'application_'%0'_associée_avec_le_type_de_fichier_'%1'_n'a_pu_être_appelée.
unable_to_write_to=Impossible_d'écrire_sur
Undefined_file_type=Type_de_fichier_indéfini
+
Undo=Annuler
+
Union=Union
+
Unknown_BibTeX_entries=Entrées_BibTeX_inconnues
+
unknown_edit=édition_inconnue
+
Unknown_export_format=Format_d'exportation_inconnu
+
Unmark_all=Tout_désétiqueter
+
Unmark_entries=Désétiqueter_ces_entrées
+
Unmark_entry=Désétiqueter_l'entrée
-Unsupported_version_of_class_%0\:_%1=Version_non_supportée_de_la_classe_%0_\:_%1
+
untitled=sans_titre
+
Up=Haut
+
Update_to_current_column_widths=Figer_les_largeurs_actuelles_des_colonnes
+
Updated_group_selection=Sélection_de_groupe_mise_à_jour
Upgrade_external_PDF/PS_links_to_use_the_'%0'_field.=Mettre_à_jour_les_liens_externes_PDF/PS_pour_utiliser_le_champ_'%0'.
Upgrade_file=Mettre_à_jour_le_fichier
Upgrade_old_external_file_links_to_use_the_new_feature=Mettre_à_jour_les_anciens_liens_vers_les_fichiers_externes_pour_utiliser_cette_nouvelle_fonction
+
usage=usage
Use_autocompletion_for_the_following_fields=Utiliser_l'auto-génération_pour_les_champs_suivants
+
Use_other_look_and_feel=Utiliser_une_autre_apparence
Use_regular_expression_search=Utiliser_l'expression_régulière_pour_la_recherche
+
Username=Nom_d'utilisateur
+
Value_cleared_externally=Valeur_supprimée_externalement
+
Value_set_externally=Valeur_paramétrée_externalement
+
verify_that_LyX_is_running_and_that_the_lyxpipe_is_valid=vérifier_que_LyX_tourne_et_que_le_canal_de_transmission_LyX_est_valide
+
View=Aperçu
Vim_server_name=Nom_du_serveur_Vim
+
Waiting_for_ArXiv...=Attente_de_ArXiv...
+
Warn_about_unresolved_duplicates_when_closing_inspection_window=Avertir_des_doublons_non_résolus_lors_de_la_fermeture_de_la_fenêtre_d'inspection
+
Warn_before_overwriting_existing_keys=Avertir_avant_d'écraser_des_clefs_existantes
+
Warning=Avertissement
+
Warnings=Messages_d'avertissement
+
web_link=Lien_internet
+
What_do_you_want_to_do?=Que_voulez-vous_faire_?
+
When_adding/removing_keywords,_separate_them_by=Lors_de_l'ajout/suppression_de_mots-clef,_les_séparer_avec
Will_write_XMP-metadata_to_the_PDFs_linked_from_selected_entries.=Ecrit_les_métadonnées_XMP_dans_les_PDFs_liés_aux_entrées_sélectionnées
+
with=avec
+
Write_BibTeXEntry_as_XMP-metadata_to_PDF.=Ecrire_l'entrée_BibTeX_comme_des_métadonnées_XMP_dans_un_PDF
+
Write_XMP=Ecrire_XMP
Write_XMP-metadata=Ecrire_les_métadonnées_XMP
Write_XMP-metadata_for_all_PDFs_in_current_database?=Ecrire_les_métadonnées_XMP_pour_tous_les_PDFs_dans_la_base_courante_?
Writing_XMP-metadata...=Ecriture_des_métadonnées_XMP
Writing_XMP-metadata_for_selected_entries...=Ecriture_des_métadonnées_XMP_pour_les_entrées_sélectionnées
+
Wrote_XMP-metadata=Méta-données_XMP_écrites
+
XMP-annotated_PDF=PDF_avec_annotations_XMP
XMP_export_privacy_settings=Paramètres_de_confidentialité_pour_l'exportation_XMP
XMP-metadata=Métadonnées_XMP
XMP-metadata_found_in_PDF\:_%0=Métadonnées_XMP_trouvées_dans_le_PDF\:_%0
You_must_restart_JabRef_for_this_to_come_into_effect.=Vous_devez_redémarrer_JabRef_pour_que_ce_changement_prenne_effet.
You_have_changed_the_language_setting.=Vous_avez_modifié_la_langue.
+
You_have_changed_the_look_and_feel_setting.=Vous_avez_changé_les_paramètres_d'apparence.
+
You_have_entered_an_invalid_search_'%0'.=Vous_avez_entré_une_recherche_invalide_'%0'.
+
You_must_choose_a_filename_to_store_journal_abbreviations=Vous_devez_choisir_un_nom_de_fichier_pour_stocker_les_abréviations_de_journaux
+
You_must_restart_JabRef_for_the_new_key_bindings_to_work_properly.=Vous_devez_relancer_JabRef_pour_que_les_nouvelles_affectations_des_touches_soient_activées
+
Your_new_key_bindings_have_been_stored.=Votre_nouvelle_affectation_de_touche_a_été_enregistrée
+
The_following_fetchers_are_available\:=Les_outils_de_recherche_suivants_sont_disponible_\:
Could_not_find_fetcher_'%0'=L'outil_de_recherche_'%0'_n'a_pas_pu_être_trouvé
Running_query_'%0'_with_fetcher_'%1'.=Execution_de_la_requête_'%0'_avec_l'outil_de_recherche_'%1'.
@@ -771,33 +1404,37 @@ Number_of_entries_successfully_imported=Nombre_d'entrées_importées_avec_succè
Import_canceled_by_user=Importation_interrompue_par_l'utilisateur
Progress\:_%0_of_%1=Progrès_\:_%0_de_%1
Error_while_fetching_from_%0=Erreur_au_cours_de_la_recherche_%0
-Fetching_Medline_by_id...=Recherche_sur_Medline_par_id...
-Fetching_Medline_by_term...=Recherche_sur_Medline_par_terme...
-%0_import_canceled=Importation_%0_annulée
+
Please_enter_a_valid_number=SVP,_entrez_un_nombre_valide
-Please_enter_a_comma_separated_list_of_Medline_IDs_(numbers)_or_search_terms.=SVP,_entrez_une_liste_séparée_par_des_virgules_d'ID_Medline_(nombres)_ou_de_termes_de_recherche.
Show_search_results_in_a_window=Afficher_les_résultats_de_recherche_dans_une_fenêtre
+Show_global_search_results_in_a_window=Afficher_les_résultats_de_recherche_globale_dans_une_fenêtre
+Search_in_all_open_databases=Rechercher_sur_toutes_les_bases_ouvertes
Move_file_to_file_directory?=Déplacer_le_fichier_vers_le_répertoire_de_fichiers_?
Rename_to_'%0'=Renommer_vers_'%0'
You_have_changed_the_menu_and_label_font_size.=Vous_avez_modifié_la_taille_de_police_des_menus_et_des_étiquettes.
+
Database_is_protected._Cannot_save_until_external_changes_have_been_reviewed.=La_base_est_protégée._L'enregistrement_ne_peut_être_effectué_tant_que_les_changements_externes_n'auront_pas_été_vérifiés.
Protected_database=Base_protégée
Refuse_to_save_the_database_before_external_changes_have_been_reviewed.=Refuser_d'enregistrer_la_base_tant_que_les_changements_externes_ne_sont_pas_vérifiés.
Database_protection=Protection_de_la_base
Unable_to_save_database=Impossible_d'enregistrer_la_base
+
BibTeX_key_generator=Générateur_de_clefs_BibTeX
Unable_to_open_link.=Impossible_d'ouvrir_un_lien.
Move_the_keyboard_focus_to_the_entry_table=Déplacer_le_curseur_vers_la_table_des_entrées
MIME_type=Type_MIME
+
This_feature_lets_new_files_be_opened_or_imported_into_an_already_running_instance_of_JabRef<BR>instead_of_opening_a_new_instance._For_instance,_this_is_useful_when_you_open_a_file_in_JabRef<br>from_your_web_browser.<BR>Note_that_this_will_prevent_you_from_running_more_than_one_instance_of_JabRef_at_a_time.=Cette_fonction_permet_aux_nouveaux_fichiers_d'être_ouverts_ou_importés_dans_une_fenêtre_JabRef_déjà_active<BR>au_lieu_d'ouvrir_une_nouvelle_fenêtre._Par_exemple,_c'est_utile_quand_vou [...]
Run_fetcher,_e.g._"--fetch\=Medline\:cancer"=Lance_une_recherche,_par._ex._"--fetch=Medline\:cancer"
+
The_ACM_Digital_Library=La_Bibliothèque_Numérique_ACM
Reset=Réinitialiser
+
Use_IEEE_LaTeX_abbreviations=Utiliser_les_abbréviations_LaTeX_IEEE
The_Guide_to_Computing_Literature=Le_Guide_de_la_Littérature_Informatique
+
When_opening_file_link,_search_for_matching_file_if_no_link_is_defined=A_l'ouverture_d'un_lien_de_fichier,_rechercher_un_fichier_correspondant_si_aucun_lien_n'est_défini
Settings_for_%0=Paramètres_pour_%0
-
Mark_entries_imported_into_an_existing_database=Etiqueter_les_entrées_importées_dans_une_base_existante
Unmark_all_entries_before_importing_new_entries_into_an_existing_database=Désétiqueter_toutes_les_entrées_avant_d'importer_de_nouvelles_entrées_dans_une_base_existante
@@ -807,31 +1444,31 @@ Sort_the_following_fields_as_numeric_fields=Trier_les_champs_suivants_comme_des_
Line_%0\:_Found_corrupted_BibTeX_key.=Ligne_%0_\:_Clef_BibTeX_corrompue_trouvée.
Line_%0\:_Found_corrupted_BibTeX_key_(contains_whitespaces).=Ligne_%0_\:_Clef_BibTeX_corrompue_trouvée_(contient_des_espaces).
Line_%0\:_Found_corrupted_BibTeX_key_(comma_missing).=Ligne_%0_\:_Clef_BibTeX_corrompue_trouvée_(virgule_manquante).
-Finished_downloading_full_text_document=Téléchargement_du_document_cité_terminé
Full_text_document_download_failed=Echec_du_téléchargement_du_document_cité
Update_to_current_column_order=Enregistrer_l'ordre_actuel_des_colonnes
-
+Download_from_URL=Télécharger_depuis_l'URL
Rename_field=Renommer_le_champ
Set/clear/rename_fields=Définir/vider/renommer_les_champs
Rename_field_to=Renommer_le_champ_en
Move_contents_of_a_field_into_a_field_with_a_different_name=Déplacer_le_contenu_d'un_champ_vers_un_champ_d'un_nom_différent
-
You_can_only_rename_one_field_at_a_time=Vou_pouvez_supprimer_uniquement_un_champ_à_la_fois
+
Remove_all_broken_links=Supprimer_tous_les_liens_invalides
+
Cannot_use_port_%0_for_remote_operation;_another_application_may_be_using_it._Try_specifying_another_port.=Le_port_%0_ne_peut_pas_être_utilisé_pour_une_opération_à_distance_;_une_autre_application_pourrait_être_en_train_de_l'utiliser._Essayer_de_spécifier_un_autre_port.
Looking_for_full_text_document...=Téléchargement_du_document_cité
Autosave=Sauvegarde_automatique
-Prompt_before_recovering_a_database_from_an_autosave_file=Demander_avant_la_récupération_d'une_base_de_données_à_partir_d'une_sauvegarde_automatique
-Autosave_interval_(minutes)=Intervalle_de_sauvegarde_automatique_(minutes)
-Do_you_want_to_recover_the_database_from_the_autosave_file?=Voulez-vous_récupérer_une_base_de_données_à_partir_de_la_sauvegarde_automatique_?
-Recover_from_autosave=Récupération_à_partir_d'une_sauvegarde_automatique
+A_local_copy_will_be_opened.=Une_copie_locale_sera_ouverte.
+Autosave_local_databases=Sauvegarder_automatiquement_les_bases_de_données_locales
+Automatically_save_the_database_to=Sauvegarder_automatiquement_les_bases_de_données_dans
+Please_enter_a_valid_file_path.=Entrez_un_chemin_de_fichier_valide,_SVP.
+
Export_in_current_table_sort_order=Exporter_dans_l'ordre_de_tri_actuel_de_la_table
Export_entries_in_their_original_order=Exporter_les_entrées_dans_leur_ordre_original
Error_opening_file_'%0'.=Erreur_lors_de_l'ouverture_du_fichier_'%0'.
-Autosave_of_file_'%0'=Sauvegarde_automatique_du_fichier_'%0'
-Error_opening_autosave_of_'%0'._Trying_to_load_'%0'_instead.=Erreur_lors_de_la_sauvegarde_automatique_de_'%0'._A_la_place,_essai_d'ouverture_de_'%0'.
+
Formatter_not_found\:_%0=Formateur_non_trouvé_\:_%0
Clear_inputarea=Vider_la_zone_de_saisie
@@ -861,8 +1498,6 @@ includes_subgroups=incluant_les_sous-groupes
contains=contient
search_expression=expression_de_recherche
-
-
Optional_fields_2=Champs_optionnels_2
Waiting_for_save_operation_to_finish=Attente_de_la_fin_de_l'opération_de_sauvegarde
Resolving_duplicate_BibTeX_keys...=Traitement_des_clefs_BibTeX_dupliquées...
@@ -889,27 +1524,22 @@ General_file_directory=Répertoire_général
User-specific_file_directory=Répertoire_spécifique_à_l'utilisateur
Search_failed\:_illegal_search_expression=Echec_de_la_recherche_\:_Expression_de_recherche_illégale
Show_ArXiv_column=Montrer_la_colonne_ArXiv
-
Highlight_groups_that_contain_entries_contained_in_any_currently_selected_group=Surligner_les_groupes_qui_contiennent_des_entrées_contenues_dans_un_des_groupes_sélectionnés
-
You_must_enter_an_integer_value_in_the_interval_1025-65535_in_the_text_field_for=Vous_devez_entrer_dans_le_champ_texte_une_valeur_entière_comprise_entre_1025_et_65535_pour
Automatically_open_browse_dialog_when_creating_new_file_link=Ouvrir_automatiquement_la_fenêtre_de_navigation_lors_de_la_création_d'un_nouveau_lien_de_fichier
-
Import_metadata_from\:=Importer_les_métadonnées_depuis\:
Choose_the_source_for_the_metadata_import=Choisir_la_source_pour_l'importation_des_métadonnées
Create_entry_based_on_XMP_data=Créer_une_entrée_basée_sur_les_données_XMP
Create_blank_entry_linking_the_PDF=Créer_une_entrée_vide_liée_au_PDF
Only_attach_PDF=Lier_uniquement_le_PDF
Title=Titre
-No_internet_connection.=_Pas_de_connexion_internet.
Create_new_entry=Créer_une_nouvelle_entrée
Update_existing_entry=Mettre_à_jour_une_entrée_existante
Autocomplete_names_in_'Firstname_Lastname'_format_only=Complétion_automatique_des_noms_uniquement_dans_le_format_'Prénom_Nom'
Autocomplete_names_in_'Lastname,_Firstname'_format_only=Complétion_automatique_des_noms_uniquement_dans_le_format_'Nom,_Prénom'
Autocomplete_names_in_both_formats=Complétion_automatique_des_noms_dans_les_2_formats
Marking_color_%0=Marquage_de_la_couleur_%0
-
The_name_'comment'_cannot_be_used_as_an_entry_type_name.=Le_nom_'comment'_ne_peut_pas_être_utilisé_comme_nom_de_type_d'entrée.
You_must_enter_an_integer_value_in_the_text_field_for=Vous_devez_entrer_une_valeur_entière_dans_le_champ_texte_pour
Send_as_email=Expédier_par_courriel
@@ -979,13 +1609,11 @@ Select_document=Sélectionner_un_document
Edit_group_membership=Editer_l'appartenance_aux_groupes
HTML_list=Liste_HTML
Click_group_to_toggle_membership_of_selected_entries=Cliquer_sur_un_groupe_pour_inverser_l'appartenance_des_entrées_sélectionnées
-Use_EMACS_23_insertion_string=Utiliser_la_chaîne_d'insertion_d'EMACS_23
If_possible,_normalize_this_list_of_names_to_conform_to_standard_BibTeX_name_formatting=Si_possible,_normaliser_cette_liste_de_noms_afin_de_correspondre_au_formatage_des_noms_au_standard_BibTeX
Could_not_open_%0=%0_n'a_pas_pu_être_ouvert
Unknown_import_format=Format_d'importation_inconnu
Web_search=Recherche_web
Style_selection=Sélection_du_style
-
No_valid_style_file_defined=Aucun_style_de_fichier_valide_n'est_défini
Choose_pattern=Choisissez_un_modèle
Use_the_BIB_file_location_as_primary_file_directory=Utiliser_le_répertoire_du_fichier_BIB_comme_répertoire_principal_de_fichiers
@@ -996,15 +1624,15 @@ You_can_add_additional_journal_names_by_setting_up_a_personal_journal_list,<br>a
JabRef_includes_a_built-in_list_of_journal_abbreviations.=JabRef_intègre_une_liste_d'abréviations_de_journaux.
You_must_select_either_a_valid_style_file,_or_use_one_of_the_default_styles.=Vous_devez_sélectionner_soit_un_style_de_fichier_valide,_soit_utiliser_un_des_styles_par_défaut.
-
This_is_a_simple_copy_and_paste_dialog._First_load_or_paste_some_text_into_the_text_input_area.<br>After_that,_you_can_mark_text_and_assign_it_to_a_BibTeX_field.=Ceci_est_simplement_une_fenêtre_de_copier-coller._Commencez_par_charger_ou_coller_du_texte_dans_la_zone_de_saisie_de_texte.<br>Ensuite,_vous_pouvez_sélectionner_des_portions_de_texte_et_les_attribuer_à_des_champs_BibTeX.
-
This_feature_generates_a_new_database_based_on_which_entries_are_needed_in_an_existing_LaTeX_document.=Cette_fonction_génère_une_nouvelle_base_de_données_basées_sur_les_entrées_requises_par_un_document_LaTeX_existant.
You_need_to_select_one_of_your_open_databases_from_which_to_choose_entries,_as_well_as_the_AUX_file_produced_by_LaTeX_when_compiling_your_document.=Vous_devez_sélectionnner_une_de_vos_bases_de_données_ouvertes_à_partir_de_laquelle_choisir_vos_entreées,_ainsi_que_le_fichier_AUX_produit_par_LaTeX_lors_de_la_compilation_du_document.
+
First_select_entries_to_clean_up.=Commencez_par_sélectionner_les_entrées_à_nettoyer
Cleanup_entry=Nettoyage_des_entrées
Autogenerate_PDF_Names=Génération_automatique_des_noms_des_PDF
Auto-generating_PDF-Names_does_not_support_undo._Continue?=La_génération_automatique_des_noms_des_PDF_ne_peut_pas_être_annulée._Continuer?
+
Use_full_firstname_whenever_possible=Utiliser_le_prénom_en_entier_quand_c'est_possible
Use_abbreviated_firstname_whenever_possible=Utiliser_le_prénom_abrégé_quand_c'est_possible
Use_abbreviated_and_full_firstname=Utiliser_le_prénom_abrégé_et_entier
@@ -1014,6 +1642,7 @@ Name_format_used_for_autocompletion=Format_de_nom_utilisé_pour_la_complétion_a
Treatment_of_first_names=Traitement_des_prénoms
Cleanup_entries=Nettoyage_des_entrées
Automatically_assign_new_entry_to_selected_groups=Assigner_automatiquement_les_nouvelles_entrées_aux_groupes_sélectionnés
+%0_mode=Mode_%0
Move_DOIs_from_note_and_URL_field_to_DOI_field_and_remove_http_prefix=Déplacer_les_DOIs_des_champs_note_et_URL_vers_le_champ_DOI,_et_supprimer_le_prefix_http
Make_paths_of_linked_files_relative_(if_possible)=Rendre_relatifs_les_chemins_des_fichiers_liés_(si_possible)
Rename_PDFs_to_given_filename_format_pattern=Renommer_les_PDF_selon_le_modèle_donné_de_format_de_nom_de_fichier
@@ -1023,7 +1652,6 @@ Doing_a_cleanup_for_%0_entries...=Nettoyage_en_cours_pour_%0_entrées...
No_entry_needed_a_clean_up=Aucune_entrée_ne_nécessitait_un_nettoyage
One_entry_needed_a_clean_up=Une_entrée_nécessitait_un_nettoyage
%0_entries_needed_a_clean_up=%0_entrées_nécessitaient_un_nettoyage
-%0_mode=Mode_%0
Error_downloading_file_'%0'=Erreur_lors_du_téléchargement_du_fichier_'%0'
Download_failed=Echec_du_téléchargement
@@ -1032,7 +1660,6 @@ Remove_selected=Supprimer_la_sélection
Group_tree_could_not_be_parsed._If_you_save_the_BibTeX_database,_all_groups_will_be_lost.=L'arbre_des_groupes_n'a_pu_être_analysé._Si_vous_sauvez_la_base_BibTeX,_tous_les_groupes_seront_perdus.
Attach_file=Attacher_un_fichier
-
Setting_all_preferences_to_default_values.=Initialiser_la_configuration_aux_valeurs_par_défaut.
Resetting_preference_key_'%0'=Réinitialiser_la_clef_de_configuration_'%0'
Unknown_preference_key_'%0'=Clef_de_configuration_'%0'_inconnue
@@ -1075,7 +1702,6 @@ Five_stars=Cinq_étoiles
Four_stars=Quatre_étoiles
Help_on_special_fields=Aide_sur_les_champs_spéciaux
Keywords_of_selected_entries=Mots-clefs_des_entrées_sélectionnés
-Manage_content_selectors=Gérer_les_sélecteurs_de_contenu
Manage_keywords=Gérer_les_mots-clefs
No_priority_information=Pas_d'information_sur_la_priorité
No_rank_information=Pas_d'information_sur_le_rang
@@ -1103,10 +1729,10 @@ Two_stars=Deux_étoiles
Update_keywords=Mettre_à_jour_les_mots-clefs
Write_values_of_special_fields_as_separate_fields_to_BibTeX=Ecrire_les_valeurs_des_champs_spéciaux_dans_des_champs_BibTeX_séparés
You_have_changed_settings_for_special_fields.=Vous_avez_modifié_les_paramètres_pour_les_champs_spéciaux.
-
%0_entries_found._To_reduce_server_load,_only_%1_will_be_downloaded.=%0_entrées_trouvées._Pour_réduire_la_charge_du_serveur,_seulement_%1_seront_téléchargées.
A_string_with_that_label_already_exists=Une_chaine_avec_cette_étiquette_existe_déja
Connection_to_OpenOffice/LibreOffice_has_been_lost._Please_make_sure_OpenOffice/LibreOffice_is_running,_and_try_to_reconnect.=La_connexion_à_OpenOffice/LibreOffice_a_été_perdue._S'il_vous_plait,_assurez-vous_qu'OpenOffice/LibreOffice_soit_lancé,_et_essayez_de_vous_reconnecter.
+
Correct_the_entry,_and_reopen_editor_to_display/edit_source.=Corrigez_l'entrée_et_ré-ouvrez_l'éditeur_pour_afficher/éditer_la_source.
Could_not_connect_to_a_running_gnuserv_process._Make_sure_that_Emacs_or_XEmacs_is_running,<BR>and_that_the_server_has_been_started_(by_running_the_command_'server-start'/'gnuserv-start').=La_connexion_à_un_processus_gnuserv_actif_a_échoué._Assurez-vous_que_Emacs_ou_XEmacs_soit_lancé,<BR>et_que_le_serveur_a_été_démarré_(en_lançant_la_commande_'server-start'/'gnuserv-start').
Could_not_connect_to_running_OpenOffice/LibreOffice.=La_connexion_à_OpenOffice/LibreOffice_n'a_pas_pu_être_lancée.
@@ -1128,24 +1754,19 @@ Your_style_file_specifies_the_paragraph_format_'%0',_which_is_undefined_in_your_
Searching...=Recherche...
You_have_selected_more_than_%0_entries_for_download._Some_web_sites_might_block_you_if_you_make_too_many_rapid_downloads._Do_you_want_to_continue?=Vous_avez_sélectionné_plus_de_%0_entrées_à_télécharger._Certains_sites_web_pourraient_vous_bloquer_si_vous_effectuez_de_trop_nombreux_et_rapides_téléchargements._Voulez-vous_continuer?
Confirm_selection=Confirmez_la_sélection
-Unknown_DOI\:_'%0'.=DOI_inconnu_\:_'%0'.
Add_{}_to_specified_title_words_on_search_to_keep_the_correct_case=Ajouter_{}_aux_mots_du_titre_spécifiés_lors_d'une_recherche_pour_préserver_la_casse_correcte
Import_conversions=Importer_les_conversions
Please_enter_a_search_string=Entrez_s'il_vous_plait_une_chaine_de_recherche
Please_open_or_start_a_new_database_before_searching=S'il_vous_plait,_ouvrez_ou_créer_une_nouvelle_base_avant_la_recherche
-An_error_occurred_while_fetching_from_ADS_(%0)\:=Une_erreur_est_survenue_lors_de_la_recherche_ADS_(%0)_\:
-An_error_occurred_while_parsing_abstract=Une_erreur_est_survenue_pendant_le_traitement_du_résumé
-Unknown_DiVA_entry\:_'%0'.=Entrée_DiVA_inconnue\:_'%0'.
-Get_BibTeX_entry_from_DiVA=Obtenir_l'entrée_BibTeX_à_partir_de_DiVA
Log=Message
-
Canceled_merging_entries=Fusion_des_entrées_interrompues
+
Format_units_by_adding_non-breaking_separators_and_keeping_the_correct_case_on_search=Formatter_les_unités_en_ajouter_des_séparateurs_non_interruptibles_et_conserver_la_casse_correcte_pour_la_recherche
Merge_entries=Fusionner_les_entrées
Merged_entries=Entrées_fusionnées_dans_une_nouvelle_et_anciennes_conservées
Merged_entry=Entrée_fusionnée
-None=Aucune
+None=Effacer
Parse=Analyser
Result=Résultat
Show_DOI_first=Montrer_le_DOI_en_premier
@@ -1154,29 +1775,35 @@ Use_Emacs_key_bindings=Utiliser_les_raccourcis_clavier_d'Emacs
You_have_to_choose_exactly_two_entries_to_merge.=Vous_devez_choisir_exactement_deux_entrées_à_fusionner.
Update_timestamp_on_modification=Mettre_à_jour_l'horodatage_en_cas_de_modification
-
All_key_bindings_will_be_reset_to_their_defaults.=Tous_les_raccourcis_clavier_seront_réinitialisés_à_leurs_valeurs_par_défaut.
+
Automatically_set_file_links=Configurer_automatiquement_les_liens_de_fichier
Continue?=Continuer_?
Resetting_all_key_bindings=Réinitialisation_de_tous_les_raccourcis_clavier
-
Hostname=Ordinateur_hôte
Invalid_setting=Paramétrage_invalide
Network=Réseau
Please_specify_both_hostname_and_port=Entrez_à_la_fois_le_nom_de_l'ordinateur_hôte_et_le_port,_s'il_vous_plait
+Please_specify_both_username_and_password=Préciser_à_la_fois_le_nom_d'utilisateur_et_le_mot_de_passe,_SVP
+
Use_custom_proxy_configuration=Utiliser_une_configuration_de_proxy_personnalisée
+Proxy_requires_authentication=Le_proxy_demande_une_authentification
+Attention\:_Password_is_stored_in_plain_text\!=Attention\:_Le_mot_de_passe_est_stocké_en_clair_dans_du_texte_brut.
Clear_connection_settings=Réinitialiser_les_paramètres_de_connexion
Cleared_connection_settings.=Paramètres_de_connexion_réinitialisés.
+
Rebind_C-a,_too=Ré-associer_aussi_C-a
+Rebind_C-f,_too=Ré-associer_aussi_C-f
Show_number_of_elements_contained_in_each_group=Afficher_le_nombre_d'éléments_contenus_dans_chaque_groupe
Open_folder=Ouvrir_le_répertoire
Searches_for_unlinked_PDF_files_on_the_file_system=Rechercher_les_fichiers_PDF_non_liés_dans_le_système_de_fichiers
-
Export_entries_ordered_as_specified=Exporter_les_entrées_dans_l'ordre_spécifié
Export_sort_order=Exporter_l'ordre_de_tri
+Export_sorting=Exportation_du_tri
Newline_separator=Séparateur_de_ligne
+
Save_entries_ordered_as_specified=Enregistrer_les_entrées_dans_l'ordre_spécifié
Save_sort_order=Enregistrer_l'ordre_de_tri
Show_extra_columns=Montrer_les_colonnes_supplémentaires
@@ -1187,7 +1814,6 @@ Move_to_group=Déplacer_vers_le_groupe
Clear_read_status=Effacer_le_statut_de_lecture
Convert_to_BibLatex_format_(for_example,_move_the_value_of_the_'journal'_field_to_'journaltitle')=Convertir_au_format_BibLaTeX_(par_exemple,_transformer_la_valeur_du_champ_'journal'_en_'journaltitle')
-Could_not_apply_changes.=Les_changements_n'ont_pas_pu_être_effectués.
Deprecated_fields=Champs_obsolètes
Hide/show_toolbar=Masquer/afficher_la_barre_d'outils
No_read_status_information=Pas_d'information_sur_le_statut_de_lecture
@@ -1199,122 +1825,109 @@ Save_selected_as_plain_BibTeX...=Enregistrer_la_sélection_en_BibTeX_basique...
Set_read_status_to_read=Mettre_le_statut_de_lecture_à_lu
Set_read_status_to_skimmed=Mettre_le_statut_de_lecture_à_parcouru
Show_deprecated_BibTeX_fields=Montrer_les_champs_BibTeX_obsolètes
+
Show_gridlines=Afficher_la_grille
Show_printed_status=Afficher_le_statut_d'impression
Show_read_status=Afficher_le_statut_de_lecture
Table_row_height_padding=Espacement_en_hauteur_des_rangées_de_tableau
-Marked_all_%0_selected_entries=%0_entrées_sélectionnées_étiquetées
Marked_selected_entry=Entrées_sélectionnées_étiquetées
-
-Toggle_print_status=Changer_le_statut_d'impression
-Unmarked_all_%0_selected_entries=%O_entrées_sélectionnées_désétiquetées
+Marked_all_%0_selected_entries=%0_entrées_sélectionnées_étiquetées
Unmarked_selected_entry=Entrées_sélectionnées_désétiquetées
+Unmarked_all_%0_selected_entries=%O_entrées_sélectionnées_désétiquetées
+Toggle_print_status=Changer_le_statut_d'impression
+
Unmarked_all_entries=Toutes_les_entrées_désétiquetées
Unable_to_find_the_requested_look_and_feel_and_thus_the_default_one_is_used.=Impossible_de_trouver_l'apparence_demandée._Aussi,_celle_par_défaut_est_utilisée.
-Could_not_open_browser.=Le_navigateur_n'a_pas_pu_être_lancé.
Opens_JabRef's_GitHub_page=Ouvre_la_page_GitHub_de_JabRef
-
-Rebind_C-f,_too=Ré-associer_aussi_C-f
-This_group_contains_all_entries._It_cannot_be_edited_or_removed.=Ce_groupe_contient_toutes_les_entrées._Il_ne_peut_pas_être_modifié_ou_supprimé.
+Could_not_open_browser.=Le_navigateur_n'a_pas_pu_être_lancé.
+Please_open_%0_manually.=Ouvrez_%0_manuellement,_SVP.
+The_link_has_been_copied_to_the_clipboard.=Le_lien_a_été_copié_dans_le_presse-papiers.
Open_%0_file=Ouvrir_le_fichier_%0
Cannot_delete_file=Le_fichier_ne_peut_pas_être_supprimé
-Convert=Convertir
-Delete_local_file=Supprimer_le_fichier_local
File_permission_error=Erreur_due_aux_permissions_du_fichier
-Help_on_Name_Formatting=Aide_sur_le_formatage_des_noms
-Normalize_to_BibTeX_name_format=Normaliser_au_format_de_nom_BibTeX
-Path_to_%0=Chemin_vers_%0
Push_to_%0=Envoyer_vers_%0
+Path_to_%0=Chemin_vers_%0
+Convert=Convertir
+Normalize_to_BibTeX_name_format=Normaliser_au_format_de_nom_BibTeX
+Help_on_Name_Formatting=Aide_sur_le_formatage_des_noms
Add_new_file_type=Ajouter_un_nouveau_type_de_fichier
-Follow_DOI_or_URL_link_and_try_to_locate_PDF_full_text_document=Suivre_le_DOI_ou_le_lien_URL,_et_essayer_de_trouver_le_document_complet_en_PDF
+
Left_entry=Entrée_de_gauche
-No_information_added=Aucune_information_ajoutée
+Right_entry=Entrée_de_droite
+Use=Utilisation
Original_entry=Entrée_d'origine
Replace_original_entry=Remplacer_l'entrée_d'origine
-Right_entry=Entrée_de_droite
+No_information_added=Aucune_information_ajoutée
Select_at_least_one_entry_to_manage_keywords.=Sélectionner_au_moins_une_entrée_pour_gérer_les_mots-clefs.
-Use=Utilisation
-Changed_type_to_'%0'_for=Type_modifié_en_'%0'_pour
-Database_'%0'_has_changed.=La_base_de_données_'%0'_a_été_modifiée.
-Copy_\\cite{BibTeX_key}=Copier_\\cite{clé_BibTeX}
-Copy_BibTeX_key_and_title=Copier_la_clef_BibTeX_et_le_titre
-File_rename_failed_for_%0_entries.=Le_renommage_des_fichiers_a_échoué_pour_%0_entrées.
-To_set_up,_go_to=Pour_configurer,_voir
-Search_%0=Recherche_%0
-Invalid_DOI\:_'%0'.=DOI_invalide\:_'%0'.
-Could_not_connect_to_%0=La_connexion_à_%0_n'a_pas_pu_être_établie
+OpenDocument_text=Texte_OpenDocument
+OpenDocument_spreadsheet=Tableau_OpenDocument
+OpenDocument_presentation=Présentation_OpenDocument
%0_image=%0_image
-%0_problem(s)_found=%0_problème(s)_trouvé(s).
-'%0'_is_not_a_valid_ADS_bibcode.='%0'n'est_pas_un_bibcode_ADS_valide.
-Accepting_the_change_replaces_the_complete_groups_tree_with_the_externally_modified_groups_tree.=Acceptation_que_l'arbre_des_groupes_entier_soit_remplacé_par_l'arbre_des_groupes_modifiés_externalement.
Added_entry=Entrée_ajoutée
-Added_new_'%0'_entry.=Nouvelle_entrée_'%0'_ajoutée
-Deleted_entry=Entrée_supprimée
-Discard_changes=Abandonner_les_modifications
-Donate_to_JabRef=Faire_un_don_à_JabRef
-Export_with_selected_format=Exporter_avec_le_format_sélectionné
-Field_is_missing=Un_champ_est_manquant
-Filled=Rempli
-From_import=A_partir_de_l'importation
-Keep_left=Conserver_le_gauche
-Keep_merged_entry_only=Ne_conserver_que_les_entrées_fusionnées
-Keep_right=Conserver_le_droit
-Merged_BibTeX_source_code=Code_source_BibTeX_fusionné
Modified_entry=Entrée_modifiée
+Deleted_entry=Entrée_supprimée
Modified_groups_tree=Arbre_des_groupes_modifié
-Multiple_entries_selected._Do_you_want_to_change_the_type_of_all_these_to_'%0'?=Plusieurs_entrées_sont_sélectionnées.Voulez-vous_changer_le_type_de_toutes_en_'%0'_?
-No_problems_found.=Aucun_problème_rencontré
-Old_entry=Ancienne_entrée
-OpenDocument_presentation=Présentation_OpenDocument
-OpenDocument_spreadsheet=Tableau_OpenDocument
-OpenDocument_text=Texte_OpenDocument
-Please_move_the_file_manually_and_link_in_place.=Déplacez_le_fichier_manuellement_et_liez-le,_SVP.
-Print_entry_preview=Imprimer_la_prévisualisation_de_l'entrée
-Really_delete_the_%0_selected_entries?=Voulez-vous_vraiment_supprimer_les_%0_entrées_sélectionnées_?
-Really_delete_the_selected_entry?=Voulez-vous_vraiment_supprimer_l'entrée_sélectionnée_?
Removed_all_groups=Supprimer_tous_les_groupes
-Return_to_JabRef=Revenir_à_JabRef
-Save_changes=Enregistrer_les_modifications
+Accepting_the_change_replaces_the_complete_groups_tree_with_the_externally_modified_groups_tree.=Acceptation_que_l'arbre_des_groupes_entier_soit_remplacé_par_l'arbre_des_groupes_modifiés_externalement.
Select_export_format=Sélectionner_un_format_d'exportation
+Return_to_JabRef=Revenir_à_JabRef
+Please_move_the_file_manually_and_link_in_place.=Déplacez_le_fichier_manuellement_et_liez-le,_SVP.
+Could_not_connect_to_%0=La_connexion_à_%0_n'a_pas_pu_être_établie
Warning\:_%0_out_of_%1_entries_have_undefined_BibTeX_key.=Attention$nbsp\:_%0_des_%1_entrées_n'ont_pas_de_clef_BibTeX.
-large_capitals_are_not_masked_using_curly_brackets_{}=Des_grandes_capitales_ne_sont_pas_incluses_entre_accolades_{}
occurrence=occurrence
-should_contain_a_four_digit_number=devrait_contenir_un_nombre_à_quatre_chiffres
-should_contain_a_valid_page_number_range=devrait_contenir_une_gamme_de_pages_valide
-should_end_with_a_name=devrait_se_terminer_par_un_nom
+Added_new_'%0'_entry.=Nouvelle_entrée_'%0'_ajoutée
+Multiple_entries_selected._Do_you_want_to_change_the_type_of_all_these_to_'%0'?=Plusieurs_entrées_sont_sélectionnées.Voulez-vous_changer_le_type_de_toutes_en_'%0'_?
+Changed_type_to_'%0'_for=Type_modifié_en_'%0'_pour
+Really_delete_the_selected_entry?=Voulez-vous_vraiment_supprimer_l'entrée_sélectionnée_?
+Really_delete_the_%0_selected_entries?=Voulez-vous_vraiment_supprimer_les_%0_entrées_sélectionnées_?
+Keep_merged_entry_only=Ne_conserver_que_les_entrées_fusionnées
+Keep_left=Conserver_le_gauche
+Keep_right=Conserver_le_droit
+Old_entry=Ancienne_entrée
+From_import=A_partir_de_l'importation
+No_problems_found.=Aucun_problème_rencontré
+%0_problem(s)_found=%0_problème(s)_trouvé(s).
+Save_changes=Enregistrer_les_modifications
+Discard_changes=Abandonner_les_modifications
+Database_'%0'_has_changed.=La_base_de_données_'%0'_a_été_modifiée.
+Print_entry_preview=Imprimer_la_prévisualisation_de_l'entrée
+Copy_\\cite{BibTeX_key}=Copier_\\cite{clé_BibTeX}
+Copy_BibTeX_key_and_title=Copier_la_clef_BibTeX_et_le_titre
+File_rename_failed_for_%0_entries.=Le_renommage_des_fichiers_a_échoué_pour_%0_entrées.
+To_set_up,_go_to=Pour_configurer,_voir
+Merged_BibTeX_source_code=Code_source_BibTeX_fusionné
+Invalid_DOI\:_'%0'.=DOI_invalide\:_'%0'.
should_start_with_a_name=devrait_débuter_par_un_nom
+should_end_with_a_name=devrait_se_terminer_par_un_nom
unexpected_closing_curly_bracket=accolade_fermante_incongrue
unexpected_opening_curly_bracket=accolade_ouvrante_incongrue
+capital_letters_are_not_masked_using_curly_brackets_{}=Des_majuscules_ne_sont_pas_incluses_entre_accolades_{}
+should_contain_a_four_digit_number=devrait_contenir_un_nombre_à_quatre_chiffres
+should_contain_a_valid_page_number_range=devrait_contenir_une_gamme_de_pages_valide
+Filled=Rempli
+Field_is_missing=Un_champ_est_manquant
+Search_%0=Recherche_%0
-Advanced_search_active.=Recherche_avancée_active.
-Found_%0_results.=%0_résultats_trouvés.
-No_results_found.=Aucun_résultat_trouvé.
-Normal_search_active.=Recherche_normale_active.
-Search_globally=Rechercher_globalement
-Search_in_all_open_databases=Rechercher_dans_toutes_les_bases_ouvertes
Search_results_in_all_databases_for_%0=Résultats_de_recherche_dans_toutes_les_bases_pour_%0
Search_results_in_database_%0_for_%1=Résultats_de_recherche_dans_la_base_%0_pour_%1
-This_search_contains_entries_in_which=Cette_recherche_contient_des_entrées_pour_lequelles
+Search_globally=Rechercher_globalement
+No_results_found.=Aucun_résultat_trouvé.
+Found_%0_results.=%0_résultats_trouvés.
+Advanced_search_active.=Recherche_avancée_active.
+Normal_search_active.=Recherche_normale_active.
+plain_text=texte_brut
This_search_contains_entries_in_which_any_field_contains_the_regular_expression_<b>%0</b>=Cette_recherche_contient_des_entrées_pour_lesquelles_au_moins_un_champ_contient_l'expression_régulière_<b>%0</b>
This_search_contains_entries_in_which_any_field_contains_the_term_<b>%0</b>=Cette_recherche_contient_des_entrées_pour_lesquelles_au_moins_un_champ_contient_le_terme_<b>%0</b>
+This_search_contains_entries_in_which=Cette_recherche_contient_des_entrées_pour_lequelles
-plain_text=texte_brut
-
-Attention\:_Password_is_stored_in_plain_text\!=Attention\:_Le_mot_de_passe_est_stocké_en_clair_dans_du_texte_brut.
-Please_specify_both_username_and_password=Préciser_à_la_fois_le_nom_d'utilisateur_et_le_mot_de_passe,_SVP
-Proxy_requires_authentication=Le_proxy_demande_une_authentification
-
-An_autosave_file_was_found_for_this_database._This_could_indicate_that_JabRef_did_not_shut_down_cleanly_last_time_the_file_was_used.=Un_fichier_de_sauvegarde_automatique_a_été_trouvé_pour_cette_base_de_données._Cela_pourrait_indiquer_que_JabRef_ne_s'est_pas_fermé_proprement_la_dernière_fois_que_ce_fichier_a_été_utilisé.
-Note\:_A_full_text_search_is_currently_not_supported_for_%0=Note_\:_La_recherche_sur_le_texte_complet_n'est_actuellement_pas_disponible_pour_%0
Unable_to_autodetect_OpenOffice/LibreOffice_installation._Please_choose_the_installation_directory_manually.=La_détection_automatique_de_OpenOffice/LibreOffice_a_échouée._S'il_voul_plait,_sélectionnez_manuellement_le_répertoire_d'installation.
-
JabRef_no_longer_supports_'ps'_or_'pdf'_fields.<br>File_links_are_now_stored_in_the_'file'_field_and_files_are_stored_in_an_external_file_directory.<br>To_make_use_of_this_feature,_JabRef_needs_to_upgrade_file_links.<br><br>=JabRef_ne_gère_plus_les_champs_'ps'_et_'pdf'.<br>Les_liens_vers_les_fichiers_sont_maintenant_enregistrés_dans_le_champ_'file'_et_les_fichiers_sont_enregistrés_dans_un_répertoire_externe.<br>Pour_utiliser_cette_fonctionnalité,_JabRef_a_besoin_de_mettre_à_jour_les_lien [...]
This_database_uses_outdated_file_links.=Cette_base_de_données_utilise_des_liens_de_fichier_périmés
@@ -1353,64 +1966,32 @@ Resolve_duplicate_BibTeX_keys=Solutionner_les_clefs_BibTeX_dupliquées
Save_all=Enregistrer_tout
String_dialog,_add_string=Chaine_de_dialogue,_ajouter_une_chaine
String_dialog,_remove_string=Chaine_de_dialogue,_supprimer_une_chaine
-Switch_preview_layout=Basculer_la_prévisualisation
Synchronize_files=Synchroniser_les_fichiers
Unabbreviate=Dés-abréger
-
-
should_contain_a_protocol=doit_contenir_un_protocole
Copy_preview=Copier_la_prévisualisation
-
Automatically_setting_file_links=Définition_automatique_des_liens_de_fichier
Regenerating_BibTeX_keys_according_to_metadata=Régénération_des_clefs_BibTeX_à_partir_des_métadonnées
No_meta_data_present_in_BIB_file._Cannot_regenerate_BibTeX_keys=Aucune_métadonnée_dans_le_fichier_BibTeX._Les_clefs_n'ont_pas_pu_être_régénérées
-
Regenerate_all_keys_for_the_entries_in_a_BibTeX_file=Régénére_toutes_les_clefs_pour_les_entrées_d'un_fichier_BibTeX
-
Show_debug_level_messages=Afficher_les_messages_de_débogage
-
-Export_sorting=Exportation_du_tri
-
-New_%0_database=Nouvelle_base_%0
-
-New_%0_database_created.=Nouvelle_base_%0_créée.
-
-No_entry_found_for_ISBN_%0_at_www.ebook.de=Aucune_entrée_trouvée_pour_l'ISBN_%0_depuis_www.ebook.de
-
-Run_field_formatter\:=Lancer_le_formatage_des_champs_:
-
-Adds_{}_brackets_around_acronyms,_month_names_and_countries_to_preserve_their_case.=Ajoute_des_accolades_{}_autour_des_acronymes,_des_noms_de_mois_et_des_pays_afin_de_préserver_leur_casse.
-Converts_units_to_LaTeX_formatting.=Convertit_les_unités_en_code_LaTeX.
-Does_nothing.=Ne_fait_rien.
-
-
-Table_font_size_is_%0=La_taille_de_police_de_la_table_est_%0
-
-Move_linked_files_to_default_file_directory_%0=Déplacer_les_fichiers_liés_vers_le_répertoire_par_défaut_%0
-Save_actions=Enregistrer_les_actions
-Enable_save_actions=Autoriser_l'enregistrement_des_actions
-Always_reformat_BIB_file_on_save_and_export=Toujours_remettre_en_forme_les_fichiers_BIB_lors_de_l'enregistrement_et_de_l'exportation
-
Default_bibliography_mode=Mode_bibliographique_par_défaut
-
-
+New_%0_database_created.=Nouvelle_base_%0_créée.
Show_only_preferences_deviating_from_their_default_value=Afficher_uniquement_les_préférences_différentes_de_leur_valeur_par_défaut
default=par_défaut
key=clef
type=type
value=valeur
-
Show_preferences=Afficher_les_préférences
-
+Save_actions=Enregistrer_les_actions
+Enable_save_actions=Autoriser_l'enregistrement_des_actions
Other_fields=Autres_champs
Show_remaining_fields=Afficher_les_champs_restants
link_should_refer_to_a_correct_file_path=Le_lien_doit_correspondre_à_un_chemin_de_fichier_valide
-
abbreviation_detected=Abréviation_détectée
wrong_entry_type_as_proceedings_has_page_numbers=Mauvais_type_d'entrée_car_le_proceedings_a_des_numéros_de_page
-
Abbreviate_journal_names=Abrégez_les_noms_de_journaux
Abbreviating...=Abrègement_en_cours
Adding_fetched_entries=Ajout_des_entrées_récupérées
@@ -1422,20 +2003,22 @@ Unabbreviate_journal_names=Dés-abréger_des_noms_de_journaux
Unabbreviating...=Dés-abrègement...
Usage=Usage
+
+Adds_{}_brackets_around_acronyms,_month_names_and_countries_to_preserve_their_case.=Ajoute_des_accolades_{}_autour_des_acronymes,_des_noms_de_mois_et_des_pays_afin_de_préserver_leur_casse.
Are_you_sure_you_want_to_reset_all_settings_to_default_values?=Etes-vous_sûr_de_vouloir_rétablir_toutes_les_valeurs_par_défaut_du_paramétrage_?
Reset_preferences=Rétablir_les_préférences
-
Ill-formed_entrytype_comment_in_BIB_file=Commentaire_de_type_d'entrées_mal_construit_dans_un_fichier_BIB
+
+Move_linked_files_to_default_file_directory_%0=Déplacer_les_fichiers_liés_vers_le_répertoire_par_défaut_%0
+
Clipboard=Presse-papiers
Could_not_paste_entry_as_text\:=L'entrée_n'a_pas_pu_être_collée_comme_du_texte_:
Do_you_still_want_to_continue?=Voulez-vous_continuer_?
This_action_will_modify_the_following_field(s)_in_at_least_one_entry_each\:=Cette_action_modifiera_le(s)_champ(s)_suivant(s)_dans_au_moins_une_entrée_chacune_:
This_could_cause_undesired_changes_to_your_entries.=Cela_pourrai_causer_des_changements_non_souhaités_dans_vos_entrées.
-
-Disable_highlight_groups_matching_entries=Désactiver_le_surlignement_des_groupes_correspondant_à_des_entrées
-
-
-
+Run_field_formatter\:=Lancer_le_formatage_des_champs_:
+Table_font_size_is_%0=La_taille_de_police_de_la_table_est_%0
+%0_import_canceled=Importation_%0_annulée
Internal_style=Style_interne
Add_style_file=Ajouter_un_fichier_de_style
Are_you_sure_you_want_to_remove_the_style?=Êtes-vous_sûr_de_vouloir_supprimer_le_style_?
@@ -1443,7 +2026,6 @@ Current_style_is_'%0'=Le_style_actuel_est_'%0'
Remove_style=Supprimer_le_style
Select_one_of_the_available_styles_or_add_a_style_file_from_disk.=Sélectionner_l'un_des_styles_disponibles_ou_ajouter_un_fichier_de_style_depuis_le_disque.
You_must_select_a_valid_style_file.=Vous_devez_sélectionner_un_fichier_de_style_valide.
-
Reload=Recharger
Capitalize=Convertir_en_majuscules
@@ -1454,9 +2036,11 @@ Changes_all_letters_to_upper_case.=Convertit_toutes_les_lettres_en_majuscules.
Changes_the_first_letter_of_all_words_to_capital_case_and_the_remaining_letters_to_lower_case.=Convertit_en_majuscules_la_première_lettre_de_tous_les_mots,_et_les_autres_lettres_en_minuscules.
Cleans_up_LaTeX_code.=Nettoyer_le_code_LaTeX.
Converts_HTML_code_to_LaTeX_code.=Convertit_le_code_HTML_en_code_LaTeX.
+Converts_HTML_code_to_Unicode.=Convertit_du_code_HTML_en_Unicode.
Converts_LaTeX_encoding_to_Unicode_characters.=Convertit_l'encodage_LaTeX_en_caractères_Unicode.
Converts_Unicode_characters_to_LaTeX_encoding.=Convertit_les_caractères_Unicode_en_encodage_LaTeX.
Converts_ordinals_to_LaTeX_superscripts.=Convertit_les_numéros_ordinaux_en_exposants_LaTeX.
+Converts_units_to_LaTeX_formatting.=Convertit_les_unités_en_code_LaTeX.
HTML_to_LaTeX=HTML_vers_LaTeX
LaTeX_cleanup=Nettoyage_LaTeX
LaTeX_to_Unicode=LaTeX_vers_Unicode
@@ -1480,16 +2064,12 @@ Title_case=Casse_du_titre
Unicode_to_LaTeX=Unicode_vers_LaTeX
Units_to_LaTeX=Unités_vers_LaTeX
Upper_case=Majuscule
+Does_nothing.=Ne_fait_rien.
Identity=Identité
-
Clears_the_field_completely.=Vide_entièrement_le_champ.
-
+Directory_not_found=Répertoire_non_trouvé
Main_file_directory_not_set\!=Répertoire_de_fichiers_principal_non_défini_!
-
This_operation_requires_exactly_one_item_to_be_selected.=Cette_opération_nécessite_qu'un_unique_élément_soit_sélectionné.
-
-Directory_not_found=Répertoire_non_trouvé
-
Importing_in_%0_format=Importation_au_format_%0
Female_name=Nom_féminin
Female_names=Noms_féminins
@@ -1537,14 +2117,15 @@ Verse=Verset
change_entries_of_group=Changer_des_entrées_du_groupe
odd_number_of_unescaped_'\#'=Nombre_impair_de_'\#'_non_échappé
+
Plain_text=Texte_brut
Show_diff=Montrer_les_différences
character=caractère
word=mot
-
Show_symmetric_diff=Montre_les_différences_symétriques
HTML_encoded_character_found=Caractère_encodé_en_HTML_trouvé
+booktitle_ends_with_'conference_on'=le_titre_d'ouvrage_se_termine_par_'conference_on'
All_external_files=Tous_les_fichiers_externes
@@ -1552,21 +2133,11 @@ OpenOffice/LibreOffice_integration=Intégration_OpenOffice/LibreOffice
incorrect_control_digit=chiffre_de_contrôle_incorrect
incorrect_format=format_incorrect
-
-Expected_"%0"_to_contain_whitespace="%0"_devrait_contenir_une_espace
-Syntax_error_in_regular-expression_pattern=Erreur_de_syntaxe_dans_le_format_d'une_expression_régulière
-
Copy_version_to_clipboard=Copier_la_version_dans_le_presse-papiers
Copied_version_to_clipboard=Version_copiée_dans_le_presse-papiers
-booktitle_ends_with_'conference_on'=le_titre_d'ouvrage_se_termine_par_'conference_on'
BibTeX_key=Clef_BibTeX
Message=Message
-
-Get_fulltext=Obtenir_le_document
-
-Download_from_URL=Télécharger_depuis_l'URL
-
Decryption_not_supported.=Déchiffrement_non_supporté.
Cleared_'%0'_for_%1_entries=Réinitialisés_'%0'_pour_%1_entrées
@@ -1580,21 +2151,16 @@ Installed_version=Version_installée
Remind_me_later=Me_le_rappeler_plus_tard
Ignore_this_update=Ignorer_cette_mise_à_jour
Could_not_connect_to_the_update_server.=La_connexion_au_serveur_de_mise_à_jour_a_échoué.
-Please_try_again_later_and/or_check_your_network_connection.=Essayez_plus_tard_ou_vérifier_votre_connection_réseau.
+Please_try_again_later_and/or_check_your_network_connection.=Essayez_plus_tard_ou_vérifier_votre_connexion_réseau.
To_see_what_is_new_view_the_changelog.=Pour_voir_les_nouveautés,_affichez_le_journal_des_modifications.
A_new_version_of_JabRef_has_been_released.=Une_nouvelle_version_de_JabRef_a_été_publiée.
JabRef_is_up-to-date.=JabRef_est_à_jour.
Latest_version=Version_la_plus_récente
-
-Please_open_%0_manually.=Ouvrez_%0_manuellement,_SVP.
-
-The_link_has_been_copied_to_the_clipboard.=Le_lien_a_été_copié_dans_le_presse-papiers.
-
Online_help_forum=Forum_d'aide_en_ligne
-
Custom=Personnalisé
-Converts_HTML_code_to_Unicode.=Convertit_du_code_HTML_en_Unicode.
+Export_cited=Exporter_les_citées
+Unable_to_generate_new_database=Impossible_de_générer_une_nouvelle_base_de_données
Open_console=Ouvrir_la_console
Use_default_terminal_emulator=Utilise_l'émulateur_de_terminal_par_défaut
@@ -1603,26 +2169,21 @@ Note\:_Use_the_placeholder_%0_for_the_location_of_the_opened_database_file.=Note
Executing_command_\"%0\"...=Exécution_de_la_commande_\"%0\"...
Error_occured_while_executing_the_command_\"%0\".=Une_erreur_est_survenue_lors_de_l'exécution_de_la_commande_\"%0\".
Reformat_ISSN=Reformater_l'ISSN
-Unable_to_generate_new_database=Impossible_de_générer_une_nouvelle_base_de_données
-Export_cited=Exporter_les_citées
Countries_and_territories_in_English=Pays_et_territoires_en_anglais
Electrical_engineering_terms=Termes_du_génie_électrique
Enabled=Activé
Internal_list=List_interne
+Manage_protected_terms_files=Gérer_les_fichiers_des_termes_protégés
Months_and_weekdays_in_English=Mois_et_jours_de_la_semaine_en_anglais
The_text_after_the_last_line_starting_with_\#_will_be_used=Le_texte_après_la_dernière_ligne_commençant_par_\#_sera_utilisé
-
Add_protected_terms_file=Ajouter_le_fichier_des_termes_protégés
Are_you_sure_you_want_to_remove_the_protected_terms_file?=Etes-vous_sûr_de_vouloir_supprimer_le_fichier_des_termes_protégés_?
Remove_protected_terms_file=Supprimer_le_fichier_des_termes_protégés
-Manage_protected_terms_files=Gérer_les_fichiers_des_termes_protégés
-
Add_selected_text_to_list=Ajouter_le_texte_sélectionné_à_la_liste
Add_{}_around_selected_text=Ajouter_{}_autour_du_texte_sélectionné
Format_field=Formatter_le_champ
New_protected_terms_file=Nouveau_fichier_de_termes_protégés
-
change_field_%0_of_entry_%1_from_%2_to_%3=modifier_le_champ_%0_de_l'entrée_%1_de_%2_en_%3
change_key_from_%0_to_%1=modifier_la_clef_de_%0_en_%1
change_string_content_%0_to_%1=modifier_le_contenu_de_la_chaine_de_%0_en_%1
@@ -1632,38 +2193,29 @@ insert_entry_%0=insèrer_l'entrée_%0
insert_string_%0=insèrer_la_chaine_%0
remove_entry_%0=supprimer_l'entrée_%0
remove_string_%0=supprimer_la_chaine_%0
-
undefined=indéfini
-
Cannot_get_info_based_on_given_%0\:_%1=Aucune_information_disponible_à_partir_de_ce_%0_:_%1
-
Get_BibTeX_data_from_%0=Récupérer_les_données_BibTEX_à_partir_du_%0
No_%0_found=%0_non_trouvé
-
Entry_from_%0=Entrée_à_partir_du_%0
-
Merge_entry_with_%0_information=Fusionner_l'entrée_sur_la_base_des_informations_du_%0
Updated_entry_with_info_from_%0=Entrée_mise_à_jour_à_partir_des_informations_du_%0
Connection=Connection
+Connecting...=Connexion_en_cours...
Host=Hôte
Port=Port
Database=Base_de_données
User=Utilisateur
+Connect=Connexion_automatique
Connection_error=Erreur_de_connexion
-Driver_error=Erreur_de_pilote
Connection_to_%0_server_established.=Connexion_au_serveur_%0_établie
Required_field_"%0"_is_empty.=Le_champ_requis_"%0"_est_vide;
-
%0_driver_not_available.=Pilote_%0_non_disponible.
-
The_connection_to_the_server_has_been_terminated.=La_connexion_au_serveur_a_été_interrompue.
-
Connection_lost.=Connexion_perdue.
Reconnect=Reconnexion
Work_offline=Travail_hors-ligne
-
Working_offline.=Travail_hors-ligne.
-
Update_refused.=Mise_à_jour_refusée;
Update_refused=Mise_à_jour_refusée
Local_entry=Entrée_locale
@@ -1673,12 +2225,12 @@ You_are_not_working_on_the_newest_version_of_BibEntry.=Vous_ne_travaillez_pas_su
Local_version\:_%0=Version_locale\:_%0
Shared_version\:_%0=Version_partagée\:_%0
Please_merge_the_shared_entry_with_yours_and_press_"Merge_entries"_to_resolve_this_problem.=SVP,_fusionnez_l'entrée_partagée_avec_la_vôtre_et_cliquez_sur_"Fusionner_les_entr\u00e9es"_pour_résoudre_ce_problème.
-
-
Canceling_this_operation_will_leave_your_changes_unsynchronized._Cancel_anyway?=Annuler_cette_operation_laissera_vos_changements_désynchronisés._Annuler_quand_même_?
-
-The_BibEntry_you_currently_work_on_has_been_deleted_on_the_shared_side._Hit_"Keep"_to_recover_the_entry.=L'entrée_sur_laquelle_vous_travaillez_actuellement_a_été_supprimée_de_la_base_partagée._Cliquez_sur_"Garder"_pour_réintégrer_l'entrée.
-
+Shared_entry_is_no_longer_present=L'entrée_partagée_n'est_plus_présente
+The_BibEntry_you_currently_work_on_has_been_deleted_on_the_shared_side.=L'entrée_sur_laquelle_vous_travaillez_actuellement_a_été_supprimée_de_la_base_partagée.
+You_can_restore_the_entry_using_the_"Undo"_operation.=Vous_pouvez_restaurer_l'entrée_en_utilisant_l'opération_"Annuler".
+Remember_password?=Mémoriser_le_mot_de_passe_?
+You_are_already_connected_to_a_database_using_entered_connection_details.=Vous_êtes_déjà_connecté_à_une_base_de_données_en_utilisant_les_informations_de_connexion_entrées.
Cannot_cite_entries_without_BibTeX_keys._Generate_keys_now?=Citation_impossible_sans_clef_BibTeX._Générer_les_clefs_maintenant?
New_technical_report=Nouveau_rapport_technique
@@ -1689,34 +2241,74 @@ Protected_terms_file=Fichier_des_termes_protégés
Style_file=Fichier_de_style
Open_OpenOffice/LibreOffice_connection=Ouvrir_une_connexion_OpenOffice/LibreOffice
-
You_must_enter_at_least_one_field_name=Vous_devez_entrer_au_moins_un_nom_de_champ
-
-
Non-ASCII_encoded_character_found=Caractère_ayant_un_encodage_non-ASCII_trouvé
-
Toggle_web_search_interface=Afficher/Masquer_l'interface_de_recherche_internet
-
Background_color_for_resolved_fields=Couleur_de_fond_pour_les_champs_traités
Color_code_for_resolved_fields=Code_couleur_pour_les_champs_traités
-
%0_files_found=%0_fichiers_trouvés
%0_of_%1=%0_de_%1
One_file_found=Un_fichier_trouvé
The_import_finished_with_warnings\:=L'importation_s'est_terminée_avec_des_messages_d'avertissement\:
There_was_one_file_that_could_not_be_imported.=Un_fichier_n'a_pas_pu_être_importé.
There_were_%0_files_which_could_not_be_imported.=%0_fichiers_n'ont_pas_pu_être_importés.
+
Migration_help_information=Aide_sur_la_migration
Entered_database_has_obsolete_structure_and_is_no_longer_supported.=Cette_base_de_données_a_une_structure_obsolète_qui_n'est_plus_gérée.
However,_a_new_database_was_created_alongside_the_pre-3.6_one.=Ainsi,_une_nouvelle_base_a_été_créée_en_parallèle_de_celle_antérieure_à_la_version_3.6.
-
Click_here_to_learn_about_the_migration_of_pre-3.6_databases.=Cliquer_ici_pour_plus_de_détails_sur_la_migration_des_bases_antérieures_à_la_version_3.6.
-
-Connecting...=Connexion_en_cours...
-
Opens_JabRef's_Facebook_page=Ouvre_la_page_Facebook_de_JabRef
Opens_JabRef's_blog=Ouvre_le_blog_de_JabRef
Opens_JabRef's_website=Ouvre_le_site_Internet_de_JabRef
-
Opens_a_link_where_the_current_development_version_can_be_downloaded=Ouvre_un_lien_d'où-la_version_de_développement_actuelle_peut_être_téléchargée
See_what_has_been_changed_in_the_JabRef_versions=Afficher_les_changements_dans_les_versions_de_JabRef
+Referenced_BibTeX_key_does_not_exist=La_clef_BibTeX_référencée_n'existe_pas
+Finished_downloading_full_text_document_for_entry_%0.=Téléchargement_terminé_pour_le_texte_intégral_de_l'entrée_%0.
+Full_text_document_download_failed_for_entry_%0.=Echec_du_téléchargement_pour_le_texte_intégral_de_l'entrée_%0.
+Look_up_full_text_documents=Recherche_des_textes_intégraux
+You_are_about_to_look_up_full_text_documents_for_%0_entries.=Vous_allez_rechercher_les_textes_intégraux_pour_%0_entrées.
+last_four_nonpunctuation_characters_should_be_numerals=Les_4_derniers_caractères_devraient_être_des_chiffres
+shared=partagé
+should_contain_an_integer_or_a_literal=doit_contenir_un_nombre_entier_ou_en_toutes_lettres
+should_have_the_first_letter_capitalized=doit_avoir_une_première_lettre_en_majuscule
+
+ID=Identifiant
+ID_type=Type_d'identifiant
+ID-based_entry_generator=Générateur_d'entrée_basé_sur_l'identifiant
+Fetcher_'%0'_did_not_find_an_entry_for_id_'%1'.=L'outil_de_recherche_%0_n'a_pas_trouvé_d'entrée_pour_l'identifiant_%1
+
+Select_first_entry=Sélectionner_la_première_entrée
+Select_last_entry=Sélectionner_la_dernière_entrée
+
+Invalid_ISBN\:_'%0'.=ISBN_invalide_:_%0.
+should_be_an_integer_or_normalized=devrait_être_un_entier_ou_une_abréviation_standard
+should_be_normalized=devrait_être_une_abréviation_standard
+
+Empty_search_ID=Identifiant_de_recherche_vide
+The_given_search_ID_was_empty.=L'Identifiant_de_recherche_entré_était_vide.
+Copy_BibTeX_key_and_link=Copier_la_clef_BibTeX_et_le_lien
+empty_BibTeX_key=Clef_BibTeX_vide
+BibLaTeX_field_only=Champ_BibLaTeX_uniquement
+
+Error_while_generating_fetch_URL=Erreur_lors_de_la_créatio_de_l'URL_de_recherche
+Error_while_parsing_ID_list=Erreur_lors_du_traitement_de_la_liste_des_identifiants
+Unable_to_get_PubMed_IDs=Impossible_d'obtenir_les_identifiants_PubMed
+Backup_found=Sauvegarde_trouvée
+A_backup_file_for_'%0'_was_found.=Un_fichier_de_sauvegarde_a_été_trouvé_pour_'%0'.
+This_could_indicate_that_JabRef_did_not_shut_down_cleanly_last_time_the_file_was_used.=Cela_pourrait_indiquer_que_JabRef_ne_s'est_pas_fermé_proprement_lors_de_la_dernière_utilisation_du_fichier.
+Do_you_want_to_recover_the_database_from_the_backup_file?=Voulez-vous_récupérer_la_base_de_données_à_partir_du_fichier_de_sauvegarde_?
+Firstname_Lastname=Prénom_Nom
+
+Recommended_for_%0=Recommandé_pour_%0
+This_might_be_caused_by_reaching_the_traffic_limitation_of_Google_Scholar_(see_'Help'_for_details).=La_limitation_de_trafic_de_Google_Scholar_pourrait_avoir_été_atteinte_(voir_l'aide_pour_plus_de_détails).
+
+Problem_downloading_from_%1=
+
+File_directory_pattern=
+Update_with_bibliographic_information_from_the_web=
+
+Could_not_find_any_bibliographic_information.=
+BibTeX_key_%0_deviates_from_generated_key_%1=
+DOI_%0_is_invalid=
+
+Jump_to_entry=
diff --git a/src/main/resources/l10n/JabRef_in.properties b/src/main/resources/l10n/JabRef_in.properties
index e3147ca..262fdc4 100644
--- a/src/main/resources/l10n/JabRef_in.properties
+++ b/src/main/resources/l10n/JabRef_in.properties
@@ -1,762 +1,1396 @@
#!
-#! created/edited by Popeye version 0.55 (https\://github.com/koppor/popeye)
-#! encoding:ISO-8859-1
+#! created/edited by Popeye version 0.55 (github.com/JabRef/popeye)
+#! encoding:UTF-8
+
%0_contains_the_regular_expression_<b>%1</b>=%0_mengandung_Ekspresi_Reguler_<b>%1</b>
+
%0_contains_the_term_<b>%1</b>=%_mengandung_istilah_<b>%1</b>
+
%0_doesn't_contain_the_regular_expression_<b>%1</b>=%0_tidak_mengandung_Ekspresi_Reguler_<b>%1</b>
+
%0_doesn't_contain_the_term_<b>%1</b>=%0_tidak_mengandung_istilah_<b>%1</b>
+
%0_export_successful=%0_ekspor_berhasil
+
%0_matches_the_regular_expression_<b>%1</b>=%0_sesuai_dengan_Ekspresi_Reguler_<b>%1</b>
+
%0_matches_the_term_<b>%1</b>=%0_sesuai_dengan_istilah_<b>%1</b>
-<field_name>=<nama_bidang>
+
<HTML>Could_not_find_file_'%0'<BR>linked_from_entry_'%1'</HTML>=<HTML>tidak_bisa_menemukan_berkas_'%0'<BR>tautan_dari_entri_'%1'</HTML>
+
<select>=<pilih>
-<select_word>=<pilih_kata>
+
Abbreviate_journal_names_of_the_selected_entries_(ISO_abbreviation)=Singkat_nama_jurnal_dari_entri_pilihan_(Singkatan_ISO)
Abbreviate_journal_names_of_the_selected_entries_(MEDLINE_abbreviation)=Singkat_nama_jurnal_dari_entri_pilihan_(Singkatan_MEDLINE)
+
Abbreviate_names=Singkat_nama
Abbreviated_%0_journal_names.=Singkatan_%0_nama_jurnal.
+
Abbreviation=Singkatan
+
About_JabRef=Tentang_JabRef
+
Abstract=Abstrak
+
Accept=Terima
+
Accept_change=Terima_perubahan
+
Action=Aksi
+
Add=Tambah
-Add_a_(compiled)_custom_ImportFormat_class_from_a_class_path.=Tambah_kelas_ImportFormat_dari_lokasi_class.
+
+Add_a_(compiled)_custom_Importer_class_from_a_class_path.=Tambah_kelas_Importer_dari_lokasi_class.
The_path_need_not_be_on_the_classpath_of_JabRef.=Lokasi_tidak_harus_pada_lokasi_kelas_JabRef.
-Add_a_(compiled)_custom_ImportFormat_class_from_a_ZIP-archive.=Tambah_suaian_kelas_ImportFormat_dari_arsip_ZIP.
+
+Add_a_(compiled)_custom_Importer_class_from_a_ZIP-archive.=Tambah_suaian_kelas_Importer_dari_arsip_ZIP.
The_ZIP-archive_need_not_be_on_the_classpath_of_JabRef.=Lokasi_arsip_ZIP_tidak_harus_dalam_lokasi_kelas_JabRef.
+
Add_entry_selection_to_this_group=Tambah_entri_pilihan_ke_grup_ini
+
Add_from_folder=Tambah_dari_folder
+
Add_from_JAR=Tambah_dari_JAR
+
add_group=tambah_grup
+
Add_group=Tambah_Grup
+
Add_new=Tambah_baru
+
Add_subgroup=Tambah_Anak_Grup
+
Add_to_group=Tambah_ke_grup
+
Added_group_"%0".=Grup_ditambahkan_"%0".
+
Added_new=Ditambahkan_baru
+
Added_string=Ditambahkan_string
+
Additionally,_entries_whose_<b>%0</b>_field_does_not_contain_<b>%1</b>_can_be_assigned_manually_to_this_group_by_selecting_them_then_using_either_drag_and_drop_or_the_context_menu._This_process_adds_the_term_<b>%1</b>_to_each_entry's_<b>%0</b>_field._Entries_can_be_removed_manually_from_this_group_by_selecting_them_then_using_the_context_menu._This_process_removes_the_term_<b>%1</b>_from_each_entry's_<b>%0</b>_field.=Tambahan,_entri_bidang_<b>%0</b>_yang_tidak_mengandung<b>%1</b>_dapat_d [...]
+
Advanced=Tingkat_lanjut
All_entries=Semua_entri
All_entries_of_this_type_will_be_declared_typeless._Continue?=Semua_entri_tipe_ini_akan_dinyatakan_sebagai_tanpa_tipe._Teruskan?
+
All_fields=Semua_bidang
+
All_subgroups_(recursively)=Semua_anak_grup_(rekursif)
-An_exception_occurred_while_accessing_'%0'=Kesalahan_terjadi_ketika_mengakses_'%0'
+
+Always_reformat_BIB_file_on_save_and_export=
+
A_SAX_exception_occurred_while_parsing_'%0'\:=SAXException_terjadi_ketika_mengurai_'%0'\:
+
and=dan
and_the_class_must_be_available_in_your_classpath_next_time_you_start_JabRef.=dan_kelas_tersebut_harus_dinyatakan_di_lokasi_kelas_waktu_menjalankan_JabRef.
+
any_field_that_matches_the_regular_expression_<b>%0</b>=bidang_yang_sesuai_dengan_ekspresi_reguler_<b>%0</b>
+
Appearance=Penampilan
+
Append=Menambah
Append_contents_from_a_BibTeX_database_into_the_currently_viewed_database=Menambah_isi_dari_basisdata_BibTeX_ke_basisdata_yang_sedang_dilihat_sekarang
+
Append_database=Menambah_basisdata
+
Append_the_selected_text_to_BibTeX_field=Menambah_teks_pilihan_ke_kunci_BibTeX
Application=Aplikasi
+
Apply=Terapkan
+
Arguments_passed_on_to_running_JabRef_instance._Shutting_down.=Argumen_dimasukkan_pada_JabRef_yang_sedang_dibuka._Dimatikan.
+
Assign_entry_selection_exclusively_to_this_group=Terapkan_pilihan_entri_hanya_ke_grup_ini
+
Assign_new_file=Terapkan_ke_berkas_baru
+
Assign_the_original_group's_entries_to_this_group?=Terapkan_entri_grup_asli_ke_grup_ini?
+
Assigned_%0_entries_to_group_"%1".=Diterapkan_%0_entri_ke_grup_"%1".
+
Assigned_1_entry_to_group_"%0".=Diterapkan_1_entri_ke_grup_"%0".
+
Attach_URL=Lampirkan_URL
+
Attempt_to_automatically_set_file_links_for_your_entries._Automatically_setting_works_if_a_file_in_your_file_directory<BR>or_a_subdirectory_is_named_identically_to_an_entry's_BibTeX_key,_plus_extension.=Mencoba_atur_otomatis_berkas_tautan_untuk_entri_anda._Pengaturan_otomatis_berfungsi_jika_berkas_di_folder_berkas_atau_subfolder<BR>diberi_nama_sama_dengan_kunci_BibTeX,_tambah_ekstensi.
+
Auto=Otomatis
+
Autodetect_format=Deteksi_format_otomatis
+
Autogenerate_BibTeX_keys=Kunci_BibTeX_dibuat_otomatis
+
Autolink_files_with_names_starting_with_the_BibTeX_key=Tautan_otomatis_berkas_dgn_nama_yang_sama_kunci_BibTeX
+
Autolink_only_files_that_match_the_BibTeX_key=Tautan_otomatis_hanya_pada_berkas_sesuai_dgn_kunci_BibTeX
+
Automatically_create_groups=Otomatis_membuat_grup
+
Automatically_create_groups_for_database.=Otomatis_membuat_grup_untuk_basisdata.
+
Automatically_created_groups=Grup_yang_dibuat_otomatis
+
Automatically_remove_exact_duplicates=Otomatis_menghapus_yang_sama
+
Allow_overwriting_existing_links.=Mengijinkan_menindih_tautan_yang_ada.
+
Do_not_overwrite_existing_links.=Tidak_boleh_menindih_tautan_yang_ada.
+
AUX_file_import=Impor_berkas_AUX
+
Available_export_formats=Format_ekspor_yang_dikenal
+
Available_BibTeX_fields=Bidang_tersedia
+
Available_import_formats=Format_impor_yang_dikenal
+
Background_color_for_optional_fields=Latar_bidang_tambahan
+
Background_color_for_required_fields=Latar_bidang_utama
+
Backup_old_file_when_saving=Cadangan_berkas_lama_ketika_menyimpan
+
BibTeX_key_is_unique.=Kunci_BibTeX_tidak_boleh_sama.
-BibTeX_source=Sumber_BibTeX
+
+%0_source=
+
Broken_link=Tautan_rusak
+
Browse=Jelajah
+
by=oleh
+
Cancel=Batal
+
Cannot_add_entries_to_group_without_generating_keys._Generate_keys_now?=Tidak_bisa_menambah_entri_ke_grup_tanpa_membuat_kunci._Membuat_kunci_sekarang?
+
Cannot_merge_this_change=Tidak_bisa_menggabung_perubahan_ini
+
Cannot_move_group_"%0"_down.=Tidak_bisa_meggeser_grup_"%0"_kebawah.
+
Cannot_move_group_"%0"_left.=Tidak_bisa_meggeser_grup_"%0"_kekiri.
+
Cannot_move_group_"%0"_right.=Tidak_bisa_meggeser_grup_"%0"_kekanan.
+
Cannot_move_group_"%0"_up.=Tidak_bisa_meggeser_grup_"%0"_keatas.
+
case_insensitive=huruf_besar_kecil_tidak_penting
+
case_sensitive=memperhitungkan_huruf_besar_kecil
+
Case_sensitive=Huruf_besar_kecil_tidak_penting
+
change_assignment_of_entries=merubah_penugasan_entri
+
Change_case=Merubah_huruf_besar/kecil
+
Change_entry_type=Merubah_tipe_entri
Change_file_type=Merubah_tipe_berkas
+
+
Change_of_Grouping_Method=Metubah_Metode_Grup
+
change_preamble=merubah_preamble
+
Change_table_column_and_General_fields_settings_to_use_the_new_feature=Merubah_kolom_tabel_dan_pengaturan_umum_bidang_dengan_menerapkan_fitur_baru
+
Changed_font_settings=Pengaturan_huruf_berubah
+
Changed_language_settings=Pengaturan_bahasa_berubah
+
Changed_look_and_feel_settings=Pengaturan_penampilan_berubah
+
Changed_preamble=Preamble_berubah
+
Characters_to_ignore=Karakter_diabaikan
+
Check_existing_file_links=Periksa_berkas_tautan_yang_sudah_ada
+
Check_links=Periksa_tautan
+
Choose_the_URL_to_download.=Pilih_URL_untuk_dimuaturun.
Cite_command=Perintah_acuan
+
Class_name=Nama_kelas
+
Clear=Bersihkan
+
Clear_fields=Bersihkan_beberapa_bidang
+
Close=Tutup
Close_others=Tutup_lainnya
Close_all=Tutup_semua
+
Close_dialog=Tutup_dialog
+
Close_the_current_database=Tutup_basisdata_yang_sekarang
+
Close_window=Tutup_jendela
+
Closed_database=Basisdata_ditutup
+
Collapse_subtree=Tutup_cabang_pohon
+
Color_codes_for_required_and_optional_fields=Kode_warna_untuk_bidang_utama_dan_tambahan
+
Color_for_marking_incomplete_entries=Tanda_untuk_entri_kosong
+
Column_width=Lebar_kolom
+
Command_line_id=id_perintah_baris
-Connect=Menghubungi
+
+
Contained_in=Terkandung_di
+
Content=Isi
+
Copied=Disalin
+
Copied_cell_contents=Isi_sel_disalin
+
Copied_key=Kunci_disalin
+
Copied_keys=Kunci_disalin
+
Copy=Salin
+
Copy_BibTeX_key=Salin_kunci_bibTeX
Copy_file_to_file_directory=Salin_berkas_ke_direktori_berkas
+
Copy_to_clipboard=Salin_ke_papan_klip
+
Could_not_call_executable=Tidak_bisa_memanggil_yang_bisa_dijalankan
Could_not_connect_to_Vim_server._Make_sure_that_Vim_is_running<BR>with_correct_server_name.=Tidak_bisa_menghubungi_server_Vim._Pastikan_Vim_sedang_berjalan<BR>dengan_nama_server_yang_sah.
+
Could_not_export_file=Tidak_bisa_ekspor_berkas
+
Could_not_export_preferences=Tidak_bisa_ekspor_preferensi
+
Could_not_find_a_suitable_import_format.=Tidak_bisa_menemukan_format_impor_yang_sesuai.
Could_not_import_preferences=Tidak_bisa_impor_preferensi
+
Could_not_instantiate_%0=Tidak_bisa_instansiasi_%0
Could_not_instantiate_%0_%1=Tidak_bisa_instansiasi_%0_%1
Could_not_instantiate_%0._Have_you_chosen_the_correct_package_path?=Tidak_bisa_instansiasi_%0._Apakah_anda_sudah_memilih_lokasi_paket_yang_benar?
Could_not_open_link=Tidak_bisa_membuka_tautan
+
Could_not_print_preview=Tidak_bisa_mencetak_pratampilan
+
Could_not_run_the_'vim'_program.=Tidak_bisa_menjalankan_program_'vim'.
+
Could_not_save_file.=Tidak_bisa_membuka_berkas.
Character_encoding_'%0'_is_not_supported.=Enkoding_karakter_'%0'_tidak_didukung.
+
Created_groups.=Grup_dibuat.
+
crossreferenced_entries_included=entri_referensi_silang_diikutkan
+
Current_content=Isi_sekarang
+
Current_value=Angka_sekarang
+
Custom_entry_types=Tipe_entri_suaian
+
Custom_entry_types_found_in_file=Tipe_entri_suaian_ditemukan_dalam_berkas
+
Customize_entry_types=Tipe_entri_ubahsuai
+
Customize_key_bindings=Ubahsuai_kunci_gabungan
+
Cut=Potong
+
cut_entries=potong_entri
+
cut_entry=potong_entri
+
+
Database_encoding=Enkoding_basisdata
+
Database_properties=Properti_basisdata
Database_type=
+
Date_format=Format_tanggal
+
Default=Bawaan
+
Default_encoding=Enkoding_bawaan
+
Default_grouping_field=Bidang_grup_bawaan
+
Default_look_and_feel=Penampilan_artistik_bawaan
+
Default_pattern=Pola_bawaan
+
Default_sort_criteria=Kriteria_pengurutan_bawaan
Define_'%0'=Mendefinisi_'%0'
+
Delete=Hapus
+
Delete_custom_format=Menghapus_format_suaian
+
delete_entries=hapus_entri
+
Delete_entry=Hapus_entri
+
delete_entry=hapus_entri
+
Delete_multiple_entries=Hapus_entri_berganda
+
Delete_rows=Hapus_baris
+
Delete_strings=Hapus_string
+
Deleted=Dihapus
+
+Delete_local_file=Hapus_berkas_lokal
+
Delimit_fields_with_semicolon,_ex.=Batas_bidang_dengan_titik_koma,_misal,
+
Descending=Urutan_menurun
+
Description=Deskripsi
+
Deselect_all=Lepas_semua_pilihan
Deselect_all_duplicates=Lepas_semua_pilihan_duplikasi
+
Disable_this_confirmation_dialog=Dialog_konfirmasi_ini_tidak_aktif
+
Display_all_entries_belonging_to_one_or_more_of_the_selected_groups.=Tampilkan_semua_entri_yang_ada_di_grup_pilihan.
+
Display_all_error_messages=Tampilkan_semua_pesan_kesalahan
+
Display_help_on_command_line_options=Tampilkan_bantuan_pada_opsi_perindah_baris
+
Display_only_entries_belonging_to_all_selected_groups.=Tampilkan_entri_hanya_yang_ada_di_grup_pilihan.
Display_version=Tampilkan_versi
+
Displaying_no_groups=Grup_tidak_ditampilkan
+
Do_not_abbreviate_names=Jangan_singkat_nama
+
Do_not_automatically_set=Jangan_pengaturan_otomatis
+
Do_not_import_entry=Jangan_impor_entri
+
Do_not_open_any_files_at_startup=Jangan_buka_berkas_saat_menjalankan
+
Do_not_overwrite_existing_keys=Jangan_menindih_kunci_yang_ada
Do_not_show_these_options_in_the_future=Untuk_selanjutnya_jangan_tampilkan_ini_lagi
+
Do_not_wrap_the_following_fields_when_saving=Jangan_lipat_bidang_berikut_ketika_menyimpan
Do_not_write_the_following_fields_to_XMP_Metadata\:=Jangan_menulis_bidang_dibawah_pada_Metadata_XMP\:
+
Do_you_want_JabRef_to_do_the_following_operations?=Apakah_anda_ingin_JabRef_melakukan_proses_berikut?
+
+Donate_to_JabRef=Sumbang_ke_JabRef
+
Down=Kebawah
+
Download=Muaturun
+
Download_file=Muaturun_berkas
+
Downloading...=Sedang_muaturun...
Drop_%0=Letakkan_%0
+
duplicate_removal=penghapus_yang_sama
+
Duplicate_string_name=Nama_string_sama
+
Duplicates_found=Ditemukan_ada_yang_sama
+
Dynamic_groups=Grup_dinamik
+
Dynamically_group_entries_by_a_free-form_search_expression=Entri_grup_dinamik_dengan_ekspresi_pencarian_bebas
+
Dynamically_group_entries_by_searching_a_field_for_a_keyword=Entri_grup_dinamk_dengan_pencarian_bidang_dari_katakunci
+
Each_line_must_be_on_the_following_form=Setiap_baris_harus_menurut_bentuk_berikut
+
Edit=Sunting
+
Edit_custom_export=Sunting_ekspor_atursendiri
Edit_entry=Sunting_entri
Save_file=Sunting_berkas_tautan
Edit_file_type=Sunting_tipe_berkas
+
Edit_group=Sunting_grup
+
Edit_journal=Sunting_jurnal
+
Edit_preamble=Sunting_preamble
Edit_strings=Sunting_string
Editor_options=Pilihan_Penyunting
+
Empty_BibTeX_key=Kunci_BibTeX_kosong
+
Grouping_may_not_work_for_this_entry.=Grup_tidak_bisa_menggunakan_entri_ini.
+
empty_database=basisdata_kosong
Enable_word/name_autocompletion=Otomatis_melengkapi_kata/nama
+
Enter_URL=Tulis_URL
+
Enter_URL_to_download=Tulis_URL_untuk_muaturun
+
entries=entri
+
Entries_cannot_be_manually_assigned_to_or_removed_from_this_group.=Entri_tidak_bisa_diterapkan_secara_manual_atau_dihapus_dari_grup_ini.
+
Entries_exported_to_clipboard=Entri_diekspor_ke_papan_klip
+
+
entry=entri
+
Entry_editor=Penyunting_entri
+
Entry_preview=Pratampilan_entri
+
Entry_table=Tabel_entri
+
Entry_table_columns=Kolom_tabel_entri
+
Entry_type=Tipe_entri
+
Entry_type_names_are_not_allowed_to_contain_white_space_or_the_following_characters=Entri_tipe_nama_tidak_diijinkan_mengandung_spasi_kosong_atau_karakter_berikut
+
Entry_types=Tipe_entri
+
Error=Kesalahan
Error_exporting_to_clipboard=Kesalahan_mengekspor_ke_papan_klip
+
Error_occurred_when_parsing_entry=Kesalahan_terjadi_ketika_mengurai_entri
+
Error_opening_file=Kesalahan_ketika_membuka_berkas
+
Error_setting_field=Kesalahan_pengaturan_bidang
Error_while_writing=Kesalahan_ketika_menulis
Error_writing_to_%0_file(s).=Kesalahan_menulis_ke_berkas_%0.
+
+
Exceptions=Perkecualian
+
Existing_file=Berkas_yang_ada
+
'%0'_exists._Overwrite_file?='%0'_esudah_ada._Berkas_ditindih?
Overwrite_file?=Berkas_ditindih?
+
Expand_subtree=Paparkan_cabang
+
Export=Ekspor
+
Export_name=Ekspor_nama
+
Export_preferences=Preferensi_Ekspor
+
Export_preferences_to_file=Ekspor_preferensi_ke_berkas
+
Export_properties=Ekspor_properti
+
Export_to_clipboard=Ekspor_ke_papan_klip
+
Exporting=Proses_mengekspor
Extension=Ekstensi
+
External_changes=Perubahan_eksternal
+
External_file_links=Tautan_berkas_eksternal
+
External_files=Berkas_eksternal
+
External_programs=Program_eksternal
+
External_viewer_called=Penampil_eksternal_dijalankan
+
Fetch=Mengambil
+
Field=Bidang
+
field=bidang
+
Field_name=Nama_bidang
Field_names_are_not_allowed_to_contain_white_space_or_the_following_characters=Nama_bidang_tidak_diijinkan_mengandung_spasi_kosong_atau_karakter_berikut
+
Field_to_filter=Bidang_ditapis
+
Field_to_group_by=Bidang_ke_grup_berdasar
+
File=Berkas
+
file=berkas
File_'%0'_is_already_open.=Berkas_'%0'_sudah_dibuka
+
File_'%0'_not_found=Berkas_'%0'_tidak_ditemukan
+
File_changed=Berkas_sudah_diubah
File_directory_is_'%0'\:=Lokasi_berkas_adalah_'%0'\:
+
File_directory_is_not_set_or_does_not_exist\!=Lokasi_berkas_belum_ditentukan_atau_tidak_ada\!
File_exists=Berkas_ada
+
File_has_been_updated_externally._What_do_you_want_to_do?=Berkas_diperbarui_dengan_program_eksternal._Apakah_yang_and_inginkan?
+
File_not_found=Berkas_tidak_ditemukan
File_type=Tipe_berkas
+
File_updated_externally=Berkas_diperbarui_secara_eksternal
+
filename=nama_berkas
+
Files_opened=Berkas_dibuka
+
Filter=Penapis
+
Finished_automatically_setting_external_links.=Selesai_pengaturan_otomatis_tautan_eksternal.
+
Finished_synchronizing_file_links._Entries_changed\:_%0.=Selesai_menyelaraskan_berkas_tautan._Entri_diubah\:_%0.
Finished_writing_XMP-metadata._Wrote_to_%0_file(s).=Selesai_menulis_XMP-metadata._Ditulis_ke_berkas_%0.
Finished_writing_XMP_for_%0_file_(%1_skipped,_%2_errors).=Selesai_menulis_XMP_untuk_berkas_%0_(%1_dilewati,_%2_kesalahan).
+
First_select_the_entries_you_want_keys_to_be_generated_for.=Pertama_pilih_entri_yang_anda_kehendaki_untuk_dibuat_kunci.
+
Fit_table_horizontally_on_screen=Sesuaikan_ukuran_tabel_horisontal_sesuai_layar
+
Float=Ambangan
Float_marked_entries=Ambangan_ditandai_sebagai_entri
+
Font_family=Keluarga_Huruf
+
Font_preview=Pratampilan_Huruf
+
Font_size=Ukuran_Huruf
+
Font_style=Corak_huruf
+
Font_selection=PemilihHuruf
+
for=untuk
+
Format_of_author_and_editor_names=Format_nama_penulis_dan_penyunting
Format_string=Format_string
+
Format_used=Format_digunakan
Formatter_name=Nama_Pemformat
+
found_in_AUX_file=ditemukan_dalam_berkas_AUX
+
Full_name=Nama_lengkap
+
General=Umum
+
General_fields=Bidang_umum
+
Generate=Membuat
+
Generate_BibTeX_key=Membuat_kunci_BibTeX
+
Generate_keys=Membuat_kunci
+
Generate_keys_before_saving_(for_entries_without_a_key)=Buat_kunci_sebelum_menyimpan_(untuk_entri_tanpa_kunci)
Generate_keys_for_imported_entries=Buat_kunci_untuk_entri_impor
+
Generate_now=Membuat_sekarang
+
Generated_BibTeX_key_for=Kunci_BibTeX_dibuat_untuk
+
Generating_BibTeX_key_for=Membuat_kunci_BibTeX_untuk
+Get_fulltext=
Grab=Ambil
+
Gray_out_entries_not_in_group_selection=Kelabukan_entri_yang_tidak_dalam_pilihan_grup
+
Gray_out_non-hits=Kelabukan_non-hits
+
Groups=Grup
+
Have_you_chosen_the_correct_package_path?=Apakah_anda_sudah_memilih_lokasi_paket_yang_tepat?
+
Help=Bantuan
+
Help_on_groups=Bantuan_untuk_grup
+
Help_on_key_patterns=Bantuan_untuk_pola_kunci
Help_on_regular_expression_search=Bantuan_untuk_Pencarian_Ekspresi_Reguler
+
Hide_non-hits=Sembunyikan_non-hits
+
Hierarchical_context=Konteks_berhirarki
+
Highlight=Warnakan
Highlight_groups_matching_all_selected_entries=Warnakan_grup_yang_sesuai_dengan_semua_entri_pilihan
Highlight_groups_matching_any_selected_entry=Warnakan_grup_yang_sesuai_dengan_entri_pilihan
+Disable_highlight_groups_matching_entries=
+
Highlight_overlapping_groups=Warnakan_grup_yang_bertindih
+
Hint\:_To_search_specific_fields_only,_enter_for_example\:<p><tt>author\=smith_and_title\=electrical</tt>=Sarant\:_untuk_mencari_hanya_bidang_tertentu,_misal_tulis\:<p><tt>author\=smith_dan_title\=electrical</tt>
+
HTML_table=Tabel_HTML
HTML_table_(with_Abstract_&_BibTeX)=Tabel_HTML_(dengan_Abstrak_dan_BibTeX)
Icon=Ikon
+
Ignore=Abaikan
+
Immediate_subgroups=sub-grup_seketika
+
Import=Impor
+
Import_and_keep_old_entry=Impor_dan_pertahankan_entri_lama
+
Import_and_remove_old_entry=Impor_dan_hapus_entri_lama
+
Import_entries=Impor_entri
+
Import_failed=Impor_gagal
+
Import_file=Impor_berkas
+
Import_group_definitions=Impor_definisi_grup
+
Import_name=Impor_nama
+
Import_preferences=Preferensi_Impor
+
Import_preferences_from_file=Impor_preferensi_dari_berkas
+
Import_strings=Impor_string
+
Import_to_open_tab=Impor_ke_tab_yang_dibuka
-Import_word_selector_definitions=Impor_definisi_pemilih_kata
+
Imported_entries=entri_diimpor
+
Imported_from_database=diimpor_dari_basisdata
-ImportFormat_class=kelas_ImportFormat
+
+Importer_class=kelas_Importer
+
Importing=Sedang_mengimpor
+
Importing_in_unknown_format=Mengimpor_pada_format_tidak_dikenal
+
Include_abstracts=Termasuk_abstrak
Include_entries=Termasuk_entri
+
Include_subgroups\:_When_selected,_view_entries_contained_in_this_group_or_its_subgroups=Termasuk_sub-grup\:_Ketika_dipilih,_lihat_entri_yang_ada_di_grup_atau_sub-grup_ini.
+
Independent_group\:_When_selected,_view_only_this_group's_entries=Grup_bebas\:_Ketika_dipilih,_lihat_hanya_entri_grup_ini
+
Initially_show_groups_tree_expanded=Awalnya_grup_tampil_dengan_detail_dibuka
-Input_error=Kesalahan_masukan
+
+Work_options=
+
Insert=Sisipkan
+
Insert_rows=Sisipkan_baris
Intersection=Interseksi
+
Invalid_BibTeX_key=Kunci_BibTeX_salah
+
Invalid_date_format=Format_hari_salah
+
Invalid_URL=URL_salah
+
Inverted=Dibalik
+
ISO_abbreviation=Singkatan_ISO
+
Online_help=
+
JabRef_preferences=Preferensi_JabRef
+
Journal_abbreviations=Singkatan_nama_Jurnal
+
Journal_list_preview=Tampilkan_daftar_Jurnal
+
Journal_name=Nama_Jurnal
+
Keep=Tetap
+
Keep_both=Tetap_keduanya
+
Key_bindings=Gabungan_kunci
+
Key_bindings_changed=Gabungan_kunci_berubah
+
Key_generator_settings=Pengaturan_pembuat_kunci
+
Key_pattern=Pola_kunci
+
keys_in_database=daftar_kunci_di_basisdata
+
Keyword=katakunci
+
Label=Label
+
Language=Bahasa
+
Last_modified=Terakhir_diubah
+
LaTeX_AUX_file=berkas_LaTeX_AUX
Leave_file_in_its_current_directory=Tinggalkan_berkas_di_direktori_yg_sekarang
+
Left=Kiri
Level=
+
Limit_to_fields=Batasi_ke_bidang
+
Limit_to_selected_entries=Batasi_ke_entri_pilihan
+
Link=Tautan
Link_local_file=Tautan_berkas_lokal
Link_to_file_%0=Tautan_ke_berkas_%0
+
Listen_for_remote_operation_on_port=Menggunakan_operasi_jarak_jauh_pada_port
Load_and_Save_preferences_from/to_jabref.xml_on_start-up_(memory_stick_mode)=Muat_dan_Simpan_preferensi_dari/ke_jabref.xml_ketika_memulai_(mode_pena_simpan)
+
Look_and_feel=Penampilan_artistik
Main_file_directory=Lokasi_berkas_utama
+
Main_layout_file=Berkas_tataletak_utama
-Manage=Mengatur
+
Manage_custom_exports=Mengatur_ekspor_atursendiri
+
Manage_custom_imports=Mengatur_impor_atursendiri
Manage_external_file_types=Pengaturan_program_eksternal
+
Manage_journal_abbreviations=Pengaturan_singkatan_jurnal
+
Mark_entries=Tandai_entri
+
Mark_entry=Tandai_entri
+
Mark_new_entries_with_addition_date=Tandai_entri_baru_dengan_tambahan_tanggal
+
Mark_new_entries_with_owner_name=Tandai_entri_baru_dengan_nama_pemilik
+
Memory_stick_mode=Mode_Pena_Simpan
+
Menu_and_label_font_size=Ukuran_huruf_menu_dan_label
+
Merged_external_changes=Menggabung_perubahan_eksternal
+
Messages=Pesan
+
Modification_of_field=Modifikasi_bidang
+
Modified_group_"%0".=Grup_dimodifikasi_"%0".
+
Modified_groups=Grup_dimodifikasi
+
Modified_string=String_dimodifikasi
+
Modify=Memodifikasi
+
modify_group=memodifikasi_grup
+
Move=Memindah
+
Move_down=Pindah_kebawah
+
Move_entries_in_group_selection_to_the_top=Pindah_entri_dalam_grup_pilihan_ke_atas
Move_external_links_to_'file'_field=Pindah_tautan_eksternal_ke_bidang_'berkas'
+
move_group=pindah_grup
+
Move_up=Pindah_keatas
+
Moved_group_"%0".=Grup_dipindah_"%0".
+
Name=Nama
Name_formatter=Pemformat_nama
+
Natbib_style=Gaya_Natbib
+
nested_AUX_files=berkas_AUX_bertingkat
+
New=Baru
+
new=baru
+
New_BibTeX_entry=Entri_BibTeX_baru
+
New_BibTeX_subdatabase=Anak_basisdata_BibTeX_baru
+
New_content=Isi_baru
+
New_database_created.=Basisdata_baru_selesai_dibuat.
+New_%0_database=Basisdata_baru_%0
New_field_value=Isi_bidang_baru
+
New_file=Berkas_baru
New_file_link_(INSERT)=Tautan_berkas_baru_(SISIPAN)
+
New_group=Grup_baru
+
New_string=String_baru
+
Next_entry=Entri_berikutnya
+
No_actual_changes_found.=Tidak_ada_perubahan.
+
no_base-BibTeX-file_specified=tidak_ada_berkas_berbasis_BibTeX_dinyatakan
+
no_database_generated=tidak_ada_basisdata_dibuat
+
No_entries_found._Please_make_sure_you_are_using_the_correct_import_filter.=Entri_tidak_ditemukan._Pastikan_anda_menggunakan_penapis_impor_yang_tepat.
+
+
No_entries_found_for_the_search_string_'%0'=Tidak_adan_entri_ditemukan_untuk_pencarian_string_'%0'
+
No_entries_imported.=Tidak_ada_entri_yang_diimpor.
+
No_exceptions_have_occurred.=Tidak_ada_perkecualian_yang_terjadi.
No_files_found.=Berkas_tidak_ditemukan.
+
No_GUI._Only_process_command_line_options.=Tidak_ada_GUI._Hanya_menggunakan_perintah_baris.
+
No_journal_names_could_be_abbreviated.=Tidak_ada_nama_jurnal_yang_bisa_disingkat.
+
No_journal_names_could_be_unabbreviated.=Tidak_ada_ada_nama_jurnal_yang_bisa_dipanjangkan.
No_PDF_linked=Tidak_ada_tautan_PDF
-No_references_found=Referensi_tidak_ditemukan
+
No_URL_defined=Tidak_ada_URL_didefinisikan
not=tidak
+
not_found=tidak_ditemukan
+
Note_that_you_must_specify_the_fully_qualified_class_name_for_the_look_and_feel,=Anda_harus_menyatakan_nama_kelas_spesifik_yang_akan_digunakan
+
Nothing_to_redo=Tidak_ada_yang_dibatalkan
+
Nothing_to_undo=Tidak_ada_yang_dikembalikan
-Number_of_references_to_fetch?=Nomor_referensi_yang_diambil?
+
occurrences=kali
+
OK=Ok
One_or_more_file_links_are_of_the_type_'%0',_which_is_undefined._What_do_you_want_to_do?=Satu_atau_lebih_tautan_berkas_dari_tipe_'%0',_yang_tidak_didefinisikan._Apa_yang_anda_inginkan?
+
One_or_more_keys_will_be_overwritten._Continue?=Satu_atau_lebih_kunci_akan_ditindih._Teruskan?
+
Open=Buka
+
Open_BibTeX_database=Buka_basisdata_BibTeX
+
Open_database=Buka_basisdata
+
Open_editor_when_a_new_entry_is_created=Buka_penyunting_ketika_entri_baru_dibuat
+
Open_file=Buka_berkas
+
Open_last_edited_databases_at_startup=Buka_basisdata_terakhir_ketika_memulai
-Open_shared_database=
+
+Connect_to_shared_database=
+
Open_terminal_here=Buka_terminal_di_sini
+
Open_URL_or_DOI=Buka_URL_atau_DOI
+
Opened_database=Basisdata_dibuka
+
Opening=Membuka
+
Opening_preferences...=Membuka_preferensi...
+
Operation_canceled.=Operasi_dibatalkan.
Operation_not_supported=Operasi_tidak_didukung
+
Optional_fields=Bidang_tambahan
+
Options=Pilihan
+
or=atau
+
Output=Keluaran
+
Output_or_export_file=Keluaran_atau_berkas_ekspor
+
Override=Ganti
+
Override_default_file_directories=Ganti_direktori_berkas_bawaan
+
Override_default_font_settings=Ganti_ukuran_huruf_bawaan
+
Override_the_BibTeX_field_by_the_selected_text=Ganti_kunci_BibTeX_dengan_pilihan_teks
+
+
Overwrite=Tindih
Overwrite_existing_field_values=Tindih_isi_bidang_yang_ada
+
Overwrite_keys=Tindih_kunci
+
pairs_processed=proses_berpasangan
Password=Katalaluan
+
Paste=Tempel
+
paste_entries=tempel_entri
+
paste_entry=tempel_entri
Paste_from_clipboard=Tempel_dari_papan_klip
+
Pasted=Ditempel
+
Path_to_%0_not_defined=Lokasi_%0_tidak_ada
+
Path_to_LyX_pipe=Lokasi_pipa_LyX
+
PDF_does_not_exist=PDF_tidak_ada
+
Personal_journal_list=Daftar_jurnal_pribadi
+
Plain_text_import=Impor_teks_normal
+
Please_enter_a_name_for_the_group.=Tuliskan_nama_untuk_grup.
+
Please_enter_a_search_term._For_example,_to_search_all_fields_for_<b>Smith</b>,_enter\:<p><tt>smith</tt><p>To_search_the_field_<b>Author</b>_for_<b>Smith</b>_and_the_field_<b>Title</b>_for_<b>electrical</b>,_enter\:<p><tt>author\=smith_and_title\=electrical</tt>=Tuliskan_kata_pencarian._Contoh,_untuk_mencari_di_semua_bidang_<b>Smith</b>,_tulis\:<p><tt>smith</tt><p>Untuk_mencari_pada_bidang_<b>Author</b>_untuk_<b>Smith</b>_dan_pada_bidang_<b>Title</b>_untuk_<b>electrical</b>,_tulis\:<p><t [...]
+
Please_enter_the_field_to_search_(e.g._<b>keywords</b>)_and_the_keyword_to_search_it_for_(e.g._<b>electrical</b>).=Tulis_bidang_pencarian_(misal_<b>keywords</b>)_dan_katakunci_untuk_mencari_(misal_<b>electrical</b>).
+
Please_enter_the_string's_label=Tuliskan_label_string
+
Please_select_an_importer.=Silahkan_pilih_pengimpor.
+
Please_select_exactly_one_group_to_move.=Silahkan_pilih_satu_grup_yang_akan_dipindah.
+
Possible_duplicate_entries=Mungkin_entri_sama
+
Possible_duplicate_of_existing_entry._Click_to_resolve.=Mungkin_entri_sama_dengan_lainnya._Klik_untuk_menyelesaikan.
+
Preamble=Preambel
+
Preferences=Preferensi
+
Preferences_recorded.=Preferensi_disimpan.
+
Preview=Pratampilan
+Citation_Style=
+Current_Preview=
+Cannot_generate_preview_based_on_selected_citation_style.=
+Bad_character_inside_entry=
+Error_while_generating_citation_style=
+Preview_style_changed_to\:_%0=
+Next_preview_layout=
+Previous_preview_layout=
+
Previous_entry=Entri_sebelumnya
+
Primary_sort_criterion=Kriteria_pertama
Problem_with_parsing_entry=Permasalahan_dengan_penguraian_entri
-
Processing_%0=Memroses_%0
Program_output=Keluaran_program
Pull_changes_from_shared_database=
+
Pushed_citations_to_%0=Kirim_acuan_ke_%0
+
Quit_JabRef=Keluar_JabRef
+
Quit_synchronization=Keluar_sinkronisasi
+
Raw_source=Sumber_asli
+
Rearrange_tabs_alphabetically_by_title=Mengatur_tab_judul_berdasarkan_alfabet
+
Redo=Mengembalikan
+
Reference_database=Basisdata_acuan
-References_found=Acuan_ditemukan
+
+%0_references_found._Number_of_references_to_fetch?=Acuan_ditemukan\:_%0._Nomor_referensi_yang_diambil?
+
Refine_supergroup\:_When_selected,_view_entries_contained_in_both_this_group_and_its_supergroup=Perbaiki_supergrup\:_Ketika_dipilih,_lihat_entri_yang_ada_di_grup_ini_dan_supergrup
+
regular_expression=Ekspresi_reguler
+
Remember_these_entry_types?=Ingat_tipe_entri_ini?
+
Remote_operation=Penggunaan_jarak_jauh
+
Remote_server_port=Port_server_jauh
+
Remove=Hapus
+
Remove_subgroups=Hapus_semua_sub-grup
+
Remove_all_subgroups_of_"%0"?=Hapus_semua_sub-grup_dari_"%0"?
+
Remove_entry_from_import=Hapus_entri_dari_impor
+
Remove_entry_selection_from_this_group=Hapus_entri_pilihan_dari_grup_ini
+
Remove_entry_type=Hapus_tipe_entri
Remove_file_link_(DELETE)=Hapus_tautan_berkas_(HAPUS)
+
Remove_from_group=Hapus_dari_grup
+
Remove_group=Hapus_grup
+
Remove_group,_keep_subgroups=Hapus_grup,_sub-grup_tetap
+
Remove_group_"%0"?=Hapus_grup_"%0"?
+
Remove_group_"%0"_and_its_subgroups?=Hapus_grup_"%0"_dan_sub-grup_nya?
+
remove_group_(keep_subgroups)=hapus_grup_(pertahankan_sub-grup)
+
remove_group_and_subgroups=hapus_grup_dan_sub-grup
+
Remove_group_and_subgroups=Hapus_grup_dan_sub-grup
+
Remove_link=Hapus_tautan
+
Remove_old_entry=Hapus_entri_lama
+
Remove_selected_strings=Hapus_string_pilihan
+
Removed_group_"%0".=Hapus_grup_"%0".
+
Removed_group_"%0"_and_its_subgroups.=Hapus_grup_"%0"_dan_sub-grup_nya.
+
Removed_string=Hapus_string
+
Renamed_string=Ganti_nama_string
+
Replace_(regular_expression)=Ganti_(ekspresi_reguler)
+
Replace_string=Ganti_string
+
Replace_with=Ganti_dengan
+
Replaced=Diganti
+
Required_fields=Bidang_diperlukan
+
Reset_all=Atur_ulang_semua
+
Resolve_strings_for_all_fields_except=Selesaikan_masalah_string_untuk_semua_bidang_kecuali
Resolve_strings_for_standard_BibTeX_fields_only=Selesaikan_masalah_string_hanya_pada_bidang_BibTeX_standar
+
resolved=sudah_diselesaikan
+
Revert_to_original_source=Kembalikan_ke_sumber_asli
+
Review=Periksa_ulang
+
Review_changes=Periksa_ulang_perubahan
+
Right=Kanan
+
Save=Simpan
Save_all_finished.=Simpan_semua_selesai.
+
Save_all_open_databases=Simpan_semua_basisdata_yang_dibuka
+
Save_before_closing=Simpan_sebelum_menutup
+
Save_database=Simpan_basisdata
Save_database_as...=Simpan_basisdata_sebagai...
+
Save_entries_in_their_original_order=Simpan_entri_pada_urutan_aslinya
+
Save_failed=Gagal_menyimpan
+
Save_failed_during_backup_creation=Gagal_menyimpan_waktu_membuat_cadangan
-Save_failed_while_committing_changes\:_%0=Gagal_menyimpan_waktu_memasukkan_perubahan\:_%0
+
Save_selected_as...=Simpan_pilihan_sebagai...
+
Saved_database=Basisdata_disimpan
+
Saved_selected_to_'%0'.=Simpan_pilihan_ke_'%0'.
+
Saving=Menyimpan
Saving_all_databases...=Menyimpan_semua_basisdata...
+
Saving_database=Menyimpan_basisdata
+
Search=Cari
+
Search_expression=Ekspresi_pencarian
+
Search_for=Mencari
+
Searching_for_duplicates...=pencarian_hal_yang_sama...
+
Searching_for_files=Mencari_berkas
+
Secondary_sort_criterion=Kriteria_kedua
+
Select=Pilih
+
+
Select_all=Pilih_semua
+
Select_encoding=Pilih_enkoding
+
Select_entry_type=Pilih_tipe_entri
Select_external_application=Pilih_aplikasi_eksternal
+
Select_file_from_ZIP-archive=Pilih_berkas_dari_arsip_ZIP
+
Select_the_tree_nodes_to_view_and_accept_or_reject_changes=Pilih_tiga_nodal_untuk_melihat,_menerima_atau_menolak_perubahan
Selected_entries=Entri_pilihan
Set_field=Pilih_bidang
Set_fields=Pilih_beberapa_bidang
+
Set_general_fields=Pilih_bidang_umum
Set_main_external_file_directory=Tetapkan_direktori_utama_berkas_eksternal
+
Set_table_font=Tetapkan_huruf_tabel
+
Settings=Pengaturan
+
Shortcut=Pintasan
-Show/edit_BibTeX_source=Tampil/Sunting_sumber_BibTeX
+
+Show/edit_%0_source=
+
Show_'Firstname_Lastname'=Tampil_'Depan_Belakang'
+
Show_'Lastname,_Firstname'=Tampil_'Belakang_Depan'
+
Show_BibTeX_source_by_default=Tampilkan_sumber_BibTeX_sebagai_bawaan
+
Show_confirmation_dialog_when_deleting_entries=Tampilkan_dialog_konfirmasi_jika_menghapus_entri
+
Show_description=Tampilkan_deskripsi
+
Show_dynamic_groups_in_<i>italics</i>=Tampilkan_grup_dinamik_dengan_huruf_<i>miring</i>
+
Show_entries_<b>not</b>_in_group_selection=Tampilkan_entri_<b>tidak</b>_dalam_pilihan_grup
+
Show_file_column=Tampilkan_kolom_berkas
+
Show_icons_for_groups=Tampilkan_ikon_untuk_grup
Show_last_names_only=Tampil_hanya_nama_belakang
+
Show_names_unchanged=Nama_apa_adanya
+
Show_optional_fields=Tampilkan_bidang_tambahan
+
Show_required_fields=Tampilkan_bidang_utama
+
Show_URL/DOI_column=Tampilkan_kolom_URL/DOI
+
Simple_HTML=HTML_sederhana
+
Size=Ukuran
+
Skipped_-_No_PDF_linked=Dilompati_-_Tanpa_tautan_PDF
Skipped_-_PDF_does_not_exist=Dilompati_-_PDF_tidak_ada
+
Skipped_entry.=Entri_dilompati.
+
Sort_alphabetically=Urut_alfabet
+
sort_subgroups=urut_sub-grup
+
Sorted_all_subgroups_recursively.=Diurutkan_semua_sub-grup_secara_rekursif
+
Sorted_immediate_subgroups.=Diurutkan_sub-grup_seketika.
+
source_edit=sunting_sumber
Special_name_formatters=Pemformat_Nama_Spesial
+
Special_table_columns=Kolom_tabe_khusus
+
Starting_import=Memulai_impor
+
Statically_group_entries_by_manual_assignment=Entri_grup_statik_secara_penerapan_manual
+
Status=Status
+
Stop=Berhenti
+
Store_journal_abbreviations=Simpan_singkatan_jurnal
+
Stored_entry=Entri_yang_disimpan
+
Strings=String
+
Strings_for_database=String_untuk_basisdata
+
Subdatabase_from_AUX=Sub-basisdata_dari_AUX
+
Switches_between_full_and_abbreviated_journal_name_if_the_journal_name_is_known.=Menukar_antara_nama_jurnal_penuh_dan_singkatan_jika_nama_jurnal_diketahui.
+
Synchronize_file_links=Sinkronkan_tautan_berkas
+
Synchronizing_file_links...=Sinkronisasi_berkas_tautan...
+
Table_appearance=Penampilan_tabel
+
Table_background_color=Latar_tabel
+
Table_grid_color=Jejaring
+
Table_text_color=Teks
+
Tabname=Nama_tab
Target_file_cannot_be_a_directory.=Berkas_target_tidak_boleh_nama_folder
+
Tertiary_sort_criterion=Kriteria_ketiga
+
Test=Coba_lihat
+
paste_text_here=Area_Masukan_Teks
+
The_chosen_date_format_for_new_entries_is_not_valid=Format_hari_yang_dipilih_untuk_entri_baru_tidak_sah
+
The_chosen_encoding_'%0'_could_not_encode_the_following_characters\:=Enkoding_yang_dipilih_'%0'_tidak_bisa_digunakan_untuk_karakter_berikut\:
+
+
the_field_<b>%0</b>=bidang_<b>%0</b>
+
The_file<BR>'%0'<BR>has_been_modified<BR>externally\!=Berkas<BR>'%0'<BR>telah_diubah<BR>oleh_program_eksternal\!
+
The_group_"%0"_already_contains_the_selection.=Grup_"%0"_sudah_mengandung_pilihan.
+
The_label_of_the_string_cannot_be_a_number.=Label_untuk_string_tidak_boleh_berupa_angka.
+
The_label_of_the_string_cannot_contain_spaces.=Label_untuk_string_tidak_boleh_ada_spasi.
+
The_label_of_the_string_cannot_contain_the_'\#'_character.=Label_string_tidak_boleh_mengandung_karakter_'\#'.
+
The_output_option_depends_on_a_valid_import_option.=Pilihan_keluaran_tergantung_dari_pilihan_impor_yang_sah.
The_PDF_contains_one_or_several_BibTeX-records.=PDF_mengandung_satu_atau_beberapa_data_BibTeX.
Do_you_want_to_import_these_as_new_entries_into_the_current_database?=Apakah_anda_ingin_impor_sebagai_entri_baru_pada_basisdata_sekarang?
+
The_regular_expression_<b>%0</b>_is_invalid\:=Ekspresi_reguler_<b>%0</b>_tidak_sah\:
+
The_search_is_case_insensitive.=Pencarian_tidak_meperhitungkan_huruf_besar_kecil.
+
The_search_is_case_sensitive.=Pencarian_meperhitungkan_huruf_besar_kecil.
+
The_string_has_been_removed_locally=String_sudah_dihapus_secara_lokal
+
There_are_possible_duplicates_(marked_with_an_icon)_that_haven't_been_resolved._Continue?=Ada_kemungkinan_sama_(ditandai_dengan_ikon)_yang_belum_diselesaikan._Teruskan?
+
This_entry_has_no_BibTeX_key._Generate_key_now?=Entri_ini_belum_mempunyai_kunci_BibTeX._Membuat_kunci_sekarang?
+
This_entry_is_incomplete=Entri_belum_lengkap
+
This_entry_type_cannot_be_removed.=Tipe_entri_tidak_bisa_dihapus.
+
This_external_link_is_of_the_type_'%0',_which_is_undefined._What_do_you_want_to_do?=Tautan_eksternal_dari_tipe_'%0',_yang_belum_didefinisikan._Apa_yang_akan_anda_lakukan?
+
This_group_contains_entries_based_on_manual_assignment._Entries_can_be_assigned_to_this_group_by_selecting_them_then_using_either_drag_and_drop_or_the_context_menu._Entries_can_be_removed_from_this_group_by_selecting_them_then_using_the_context_menu.=Grup_ini_mempunyai_entri_berdasar_dari_pengisian_manual._Entri_dapat_dituliskan_dalam_grup_ini_dengan_cara_memilih_entri_kemudian_menggunakannya_melalui_seret_dan_tempatkan_atau_dari_konteks_menu._Entri_dapat_dihapus_dari_grup_dengan_memilih [...]
+
This_group_contains_entries_whose_<b>%0</b>_field_contains_the_keyword_<b>%1</b>=Grup_ini_memiliki_entri_dimana_bidang_<b>%0</b>_memiliki_katakunci_<b>%1</b>
+
This_group_contains_entries_whose_<b>%0</b>_field_contains_the_regular_expression_<b>%1</b>=Grup_ini_memiliki_entri_dimana_bidang_<b>%0</b>_mempunyai_ekspresi_reguler_<b>%1</b>
This_makes_JabRef_look_up_each_file_link_and_check_if_the_file_exists._If_not,_you_will_be_given_options<BR>to_resolve_the_problem.=Ini_membuat_JabRef_mencari_disemua_tautan_berkas_dan_memeriksa_apakah_ada_berkas._Jika_tidak,_anda_diberi_pilihan_<BR>untuk_mengatasi_masalah.
+
This_operation_requires_all_selected_entries_to_have_BibTeX_keys_defined.=Operasi_ini_memerlukan_semua_entri_mempunyai_kunci_BibTeX.
+
This_operation_requires_one_or_more_entries_to_be_selected.=Operasi_ini_memerlukan_satu_atau_lebih_entri_yang_dipilih.
+
Toggle_abbreviation=Gunakan_singkatan
Toggle_entry_preview=Gunakan_pratampilan_entri
Toggle_groups_interface=Gunakan_antarmuka_grup
Try_different_encoding=Coba_enkoding_lain
+
Unabbreviate_journal_names_of_the_selected_entries=Nama_jurnal_tidak_disingkat_dari_entri_pilihan
Unabbreviated_%0_journal_names.=%0_nama_jurnal_tidak_disingkat.
+
Unable_to_open_file.=Tidak_bisa_membuka_berkas.
Unable_to_open_link._The_application_'%0'_associated_with_the_file_type_'%1'_could_not_be_called.=Tidak_bisa_membuka_tautan._Aplikasi_'%0'_yang_berkaitan_dengan_berkas_tipe_'%0'_tidak_bisa_dimuat.
unable_to_write_to=tidak_bisa_menulis_ke
Undefined_file_type=tipe_berkas_tidak_terdefinisi
+
Undo=Batalkan
+
Union=Menyatu
+
Unknown_BibTeX_entries=Entri_BibTeX_tidak_dikenal
+
unknown_edit=suntingan_tidak_dikenal
+
Unknown_export_format=format_ekspor_tidak_dikenal
+
Unmark_all=Hilangkan_tanda_semua
+
Unmark_entries=Hilangkan_tanda_entri
+
Unmark_entry=Hilangkan_tanda_entri
-Unsupported_version_of_class_%0\:_%1=Versi_kelas_tidak_didukung_%0\:_%1
+
untitled=tanpa_judul
+
Up=Naik
+
Update_to_current_column_widths=Perbarui_sesuai_lebar_kolom_sekarang
+
Updated_group_selection=Pilihan_grup_diperbarui
Upgrade_external_PDF/PS_links_to_use_the_'%0'_field.=Perbarui_tautan_eksternal_PDF/PS_untuk_digunakan_bidang_'%0'.
Upgrade_file=Naiktaraf_berkas
Upgrade_old_external_file_links_to_use_the_new_feature=Naiktaraf_tautan_berkas_eksternal_lama_untuk_digunakan_di_fitur_baru
+
usage=penggunaan
Use_autocompletion_for_the_following_fields=Gunakan_otomatis_melengkapi_pada_bidang_berikut
+
Use_other_look_and_feel=Gunakan_gaya_penampilan_lain
Use_regular_expression_search=Gunakan_ekspresi_pencarian_biasa
+
Username=Nama_pengguna
+
Value_cleared_externally=Isi_dihapus_dari_luar
+
Value_set_externally=Isi_diatur_dari_luar
+
verify_that_LyX_is_running_and_that_the_lyxpipe_is_valid=pastikan_LyX_sedang_dijalankan_dan_pipalyx_nya_benar
+
View=Tampilkan
Vim_server_name=Nama_Server_Vim
+
Waiting_for_ArXiv...=Menunggu_ArXiv...
+
Warn_about_unresolved_duplicates_when_closing_inspection_window=Peringatkan_jika_masih_ada_duplikasi_ketika_menutup_dialog
+
Warn_before_overwriting_existing_keys=Peringatan_sebelum_menindih_kunci
+
Warning=Peringatan
+
Warnings=Peringatan
+
web_link=tautan_web
+
What_do_you_want_to_do?=Apa_yang_anda_inginkan?
+
When_adding/removing_keywords,_separate_them_by=Ketika_menambah/menghapus_katakunci,_pisahkan_dengan_tanda
Will_write_XMP-metadata_to_the_PDFs_linked_from_selected_entries.=Akan_menulis_metadata_XMP_ke_tautan_PDF_dari_entri_pilihan.
+
with=dan
+
Write_BibTeXEntry_as_XMP-metadata_to_PDF.=Menulis_BibTeXEntry_sebagai_XMP-metadata_ke_PDF.
+
Write_XMP=Menulis_XMP
Write_XMP-metadata=Menulis_XMP-metadata
Write_XMP-metadata_for_all_PDFs_in_current_database?=Menulis_XMP-metadata_untuk_semua_PDF_di_basisdata_sekarang?
Writing_XMP-metadata...=Sedang_menulis_XMP_metadata...
Writing_XMP-metadata_for_selected_entries...=Sedang_menulis_XMP_metadata_untuk_entri_pilihan...
+
Wrote_XMP-metadata=XMP-metadata_ditulis
+
XMP-annotated_PDF=XMP-annotated_PDF
XMP_export_privacy_settings=Pengaturan_Info_Ekspor_XMP
XMP-metadata=Metadata_XMP
XMP-metadata_found_in_PDF\:_%0=XMP_metadata_ditemukan_di_PDF\:_%0
You_must_restart_JabRef_for_this_to_come_into_effect.=Anda_harus_menjalankan_ulang_JabRef_agar_berfungsi.
You_have_changed_the_language_setting.=Anda_telah_mengganti_pengaturan_bahasa.
+
You_have_changed_the_look_and_feel_setting.=Pengaturan_penampilan_sudah_anda_ubah.
+
You_have_entered_an_invalid_search_'%0'.=Anda_telah_menulis_pencarian_yang_salah_'%0'.
+
You_must_choose_a_filename_to_store_journal_abbreviations=Anda_harus_memilih_nama_berkas_untuk_menyimpan_singkatan_jurnal
+
You_must_restart_JabRef_for_the_new_key_bindings_to_work_properly.=Anda_harus_menjalankan_ulang_JabRef_agar_gabungan_kunci_dapat_berfungsi.
+
Your_new_key_bindings_have_been_stored.=Gabungan_kunci_anda_sudah_disimpan.
+
The_following_fetchers_are_available\:=Pengambil_berikut_tersedia\:
Could_not_find_fetcher_'%0'=Tidak_bisa_menemukan_pengambil_'%0'
Running_query_'%0'_with_fetcher_'%1'.=Jalankan_Kueri_'%0'_dengan_pengambil_'%1'.
@@ -770,63 +1404,74 @@ Number_of_entries_successfully_imported=Jumlah_entri_yang_berhasil_diimpor
Import_canceled_by_user=Impor_dibatalkan_oleh_pengguna
Progress\:_%0_of_%1=Berlangsung\:_%0_of_%1
Error_while_fetching_from_%0=Kesalahan_ketika_mengambil_dari_%0
-Fetching_Medline_by_id...=mengambil_Medline_berdasar_id...
-Fetching_Medline_by_term...=Mengambil_Medline_berdasar_istilah...
-%0_import_canceled=Impor_%0_dibatalkan
+
Please_enter_a_valid_number=Tuliskan_nomor_yang_benar
-Please_enter_a_comma_separated_list_of_Medline_IDs_(numbers)_or_search_terms.=Gunakan_pemisah_koma_dari_ID_Medline_(angka)_atau_cari_istilah.
Show_search_results_in_a_window=Tampilkan_hasil_pencarian_di_jendela
+Show_global_search_results_in_a_window=
+Search_in_all_open_databases=
Move_file_to_file_directory?=Pindah_berkas_ke_direktori_berkas?
Rename_to_'%0'=Ganti_nama_menjadi_'%0'
You_have_changed_the_menu_and_label_font_size.=Ukuran_huruf_menu_dan_label_sudah_anda_ubah.
+
Database_is_protected._Cannot_save_until_external_changes_have_been_reviewed.=Basisdata_dilindungi._Tidak_bisa_disimpan_sebelum_perubahan_eksternal_diperiksa.
Protected_database=Basisdata_terlindungi
Refuse_to_save_the_database_before_external_changes_have_been_reviewed.=Menolak_menyimpan_basisdata_sebelum_perubahan_eksternal_diperiksa.
Database_protection=Perlindungan_basisdata
Unable_to_save_database=Tidak_bisa_menyimpan_basisdata
+
BibTeX_key_generator=Pembuat_kunci_BibTeX
Unable_to_open_link.=Tidak_bisa_membuka_tautan.
Move_the_keyboard_focus_to_the_entry_table=Pindah_fokus_papanketik_ke_tabel_entri
MIME_type=Tipe_MIME
+
This_feature_lets_new_files_be_opened_or_imported_into_an_already_running_instance_of_JabRef<BR>instead_of_opening_a_new_instance._For_instance,_this_is_useful_when_you_open_a_file_in_JabRef<br>from_your_web_browser.<BR>Note_that_this_will_prevent_you_from_running_more_than_one_instance_of_JabRef_at_a_time.=Fitur_ini_memungkinkan_berkas_baru_atau_impor_ke_jendela_JabRef_yang_aktif<br>bukan_membuat_baru._Hal_ini_berguna_ketika_anda_membuka_berkas_di_JabRef<br>dari_halaman_web.<br>Hal_ini_ [...]
Run_fetcher,_e.g._"--fetch\=Medline\:cancer"=Jalankan_Pengambil,_misal._"--fetch=Medline\:cancer"
+
The_ACM_Digital_Library=Pustaka_ACM_Dijital
Reset=Atur_ulang
+
Use_IEEE_LaTeX_abbreviations=Gunakan_singkatan_IEEE_LaTeX
The_Guide_to_Computing_Literature=Panduan_untuk_Computing_Literature
+
When_opening_file_link,_search_for_matching_file_if_no_link_is_defined=Ketika_membuka_tautan_berkas,_cari_berkas_yang_sesuai
Settings_for_%0=Pengaturan_untuk
Mark_entries_imported_into_an_existing_database=Tandai_entri_impor_di_basisdata_yang_sudah_ada
Unmark_all_entries_before_importing_new_entries_into_an_existing_database=Hilangkan_tanda_semua_entri_sebelum_mengimpor_entri_baru_ke_basisdata
+
Forward=Maju
Back=Kembali
Sort_the_following_fields_as_numeric_fields=Urutkan_bidang_berikut_sepeerti_angka
Line_%0\:_Found_corrupted_BibTeX_key.=Baris_%0\:_Ditemukan_kunci_BibTeX_ada_kesalahan.
Line_%0\:_Found_corrupted_BibTeX_key_(contains_whitespaces).=Baris_%0\:_Ditemukan_kunci_BibTeX_ada_kesalahan_(mengandung_spasi_kosong).
Line_%0\:_Found_corrupted_BibTeX_key_(comma_missing).=Baris_%0\:_Ditemukan_kunci_BibTeX_ada_kesalahan_(tidak_ada_koma).
-Finished_downloading_full_text_document=Selesai_muaturun_dokumen_teks_lengkap
Full_text_document_download_failed=Gagal_muaturun_artikel_teks_lengkap
Update_to_current_column_order=Perbarui_sebuai_urutan_kolom_sekarang
+Download_from_URL=
Rename_field=Ganti_nama_bidang
Set/clear/rename_fields=Pilih/hapus/namai_ulang_bidang
Rename_field_to=Ganti_nama_bidang_menjadi
Move_contents_of_a_field_into_a_field_with_a_different_name=Pindah_isi_dari_bidang_ke_bidang_lain_dengan_nama_lain
You_can_only_rename_one_field_at_a_time=Anda_bisa_mengganti_nama_satu_bidang_dalam_satu_waktu
+
Remove_all_broken_links=Hapus_semua_tautan_rusak?
+
Cannot_use_port_%0_for_remote_operation;_another_application_may_be_using_it._Try_specifying_another_port.=Tidak_bisa_memakai_port_%0_untuk_operasi_jauh;_aplikasi_lain_mungkin_sedang_menggunakan._Coba_port_lain.
+
Looking_for_full_text_document...=Sedang_mencari_dokumen_teks_lengkap...
Autosave=Simpan_otomatis
-Prompt_before_recovering_a_database_from_an_autosave_file=Ingatkan_ketika_ambil_ulang_basisdata_dari_berkas_simpanan_otomatis
-Autosave_interval_(minutes)=Interval_waktu_menyimpan_otomatis_(menit)
-Do_you_want_to_recover_the_database_from_the_autosave_file?=Apakah_anda_ingin_mengembalikan_basisdata_dari_berkas_simpan_otomatis?
-Recover_from_autosave=Mengambil_uland_dari_simpan_otomatis
+A_local_copy_will_be_opened.=
+Autosave_local_databases=
+Automatically_save_the_database_to=
+Please_enter_a_valid_file_path.=
+
+
Export_in_current_table_sort_order=Ekspor_menurut_tabel_urutan_sekarang
Export_entries_in_their_original_order=Ekspor_entri_dengan_urutan_aslinya
Error_opening_file_'%0'.=Kesalahan_ketika_membuka_berkas_'%0'.
-Autosave_of_file_'%0'=Menyimpan_otomatis_berkas_'%0'
-Error_opening_autosave_of_'%0'._Trying_to_load_'%0'_instead.=Kesalahan_ketika_membuka_simpanan_otomatis_'%0'._Gantinya_memuat_'%0'.
+
Formatter_not_found\:_%0=Pemformat_tidak_ditemukan\:_%0
Clear_inputarea=Bersihkan_area_masukan
+
Automatically_set_file_links_for_this_entry=Otomatis_membuat_tautan_berkas_untuk_entri_ini
Could_not_save,_file_locked_by_another_JabRef_instance.=Tidak_bisa_menyimpan,_berkas_dikunci_oleh_JabRef_yang_jalan.
File_is_locked_by_another_JabRef_instance.=Berkas_dikunci_oleh_JabRef_lain.
@@ -835,10 +1480,12 @@ File_locked=Berkas_dikunci
Current_tmp_value=Angka_tmp_sekarang
Metadata_change=Perubahan_Metadata
Changes_have_been_made_to_the_following_metadata_elements=Perubahan_telah_dilakukan_pada_elemen_metadata_berikut
+
Generate_groups_for_author_last_names=Membuat_grup_untuk_nama_belakang_penulis
Generate_groups_for_editor_last_names=Membuat_grup_untuk_nama_belakang_penyunting
Generate_groups_from_keywords_in_a_BibTeX_field=Membuat_grup_dari_katakunci_di_bidang_BibTeX
Enforce_legal_characters_in_BibTeX_keys=Menggunakan_karakter_legal_untuk_kunci_BibTeX
+
Save_without_backup?=Simpan_tanpa_cadangan?
Unable_to_create_backup=Tidak_bisa_membuat_cadangan
Move_file_to_file_directory=Pindah_berkas_ke_direktori_berkas
@@ -850,24 +1497,29 @@ refines_supergroup=memperbaiki_supergrup
includes_subgroups=termasuk_subgrup
contains=kandungan
search_expression=ekspresi_pencarian
+
Optional_fields_2=Bidang_tambahan_2
Waiting_for_save_operation_to_finish=Menunggu_proses_menyimpan_selesai
Resolving_duplicate_BibTeX_keys...=Mengatasi_masalah_kunci_BibTeX_sama...
Finished_resolving_duplicate_BibTeX_keys._%0_entries_modified.=Selesai_mengatasi_masalah_kunci_BibTeX_sama._%0_entri_diubah.
This_database_contains_one_or_more_duplicated_BibTeX_keys.=Basisdata_ini_mempunyai_satu_atau_lebih_kunci_BibTeX_yang_sama.
Do_you_want_to_resolve_duplicate_keys_now?=Apakah_anda_ingin_menyelesaikan_masalah_kunci_sama_sekarang?
+
Find_and_remove_duplicate_BibTeX_keys=Temukan_dan_hapus_kunci_BibTeX_yang_sama
Expected_syntax_for_--fetch\='<name_of_fetcher>\:<query>'=Sintaks_yang_diharapkan_untuk_--fetch='<name_of_fetcher>\:<query>'
Duplicate_BibTeX_key=kunci_BibTeX_sama
Import_marking_color=Tanda_impor
Always_add_letter_(a,_b,_...)_to_generated_keys=Selalu_tambah_huruf_(a,_b,_...)_untuk_kunci
+
Ensure_unique_keys_using_letters_(a,_b,_...)=Pastikan_kunci_unik_dengan_huruf_(a,_b,_...)
Ensure_unique_keys_using_letters_(b,_c,_...)=Pastikan_kunci_unik_dengan_huruf_(b,c,_...)
Entry_editor_active_background_color=Latar_penyunting_entri_aktif
Entry_editor_background_color=Latar_penyunting_entri
Entry_editor_font_color=Huruf_penyunting_entri
Entry_editor_invalid_field_color=Entri_bidang_tidak_valid
+
Table_and_entry_editor_colors=Warna_tabel_dan_penyunting_entri
+
General_file_directory=Direktori_berkas_umum
User-specific_file_directory=Direktori_berkas_khusus_pengguna
Search_failed\:_illegal_search_expression=Pencarian_gagal\:_ekspresi_pencarian_tidak_benar
@@ -876,14 +1528,12 @@ Highlight_groups_that_contain_entries_contained_in_any_currently_selected_group=
You_must_enter_an_integer_value_in_the_interval_1025-65535_in_the_text_field_for=Anda_harus_memasukkan_angka_bulat_antara_1025-65535_di_bidang_teks
Automatically_open_browse_dialog_when_creating_new_file_link=Otomatis_membuka_dialog_jelajah_ketika_membuat_tautan_berkas_baru
-
Import_metadata_from\:=Impor_Metadata_dari\:
Choose_the_source_for_the_metadata_import=Pilih_sumber_untuk_impor_metadata
Create_entry_based_on_XMP_data=Membuat_entri_berasal_data_XMP
Create_blank_entry_linking_the_PDF=Membuat_entri_kosong_tautan_PDF
Only_attach_PDF=Hanya_lampirkan_PDF
Title=Judul
-No_internet_connection.=Konesksi_Internet_Tidak_Ada.
Create_new_entry=membuat_Entri_Baru
Update_existing_entry=Perbarui_Entri_Yang_Sudah_Ada
Autocomplete_names_in_'Firstname_Lastname'_format_only=Nama_isian_otomatis_hanya_untuk_format_'Namadepan_Namaakhir'
@@ -959,14 +1609,11 @@ Select_document=Pilih_dokumen
Edit_group_membership=Sunting_Aggota_Grup
HTML_list=Daftar_HTML
Click_group_to_toggle_membership_of_selected_entries=Klik_grup_untuk_masuk_ke_anggota_dari_entri_pilihan
-Use_EMACS_23_insertion_string=Gunakan_EMACS_23_sisipan_karakter
If_possible,_normalize_this_list_of_names_to_conform_to_standard_BibTeX_name_formatting=Jika_memungkinkan,_sesuaikan_daftar_nama_untuk_mengikuti_format_penamaan_BibTeX
Could_not_open_%0=Tidak_bisa_membuka_%0
Unknown_import_format=Format_impor_tidak_dikenal
Web_search=Pencarian_Web
-
Style_selection=Pilihan_gaya
-
No_valid_style_file_defined=(gaya_yang_sah_tidak_ditemukan)
Choose_pattern=Pilih_pola
Use_the_BIB_file_location_as_primary_file_directory=Gunakan_lokasi_berkas_BIB_sebagai_direktori_berkas_utama
@@ -978,13 +1625,14 @@ JabRef_includes_a_built-in_list_of_journal_abbreviations.=Salah_satu_daftar_sing
You_must_select_either_a_valid_style_file,_or_use_one_of_the_default_styles.=Anda_harus_memilih_berkas_gaya_yang_sah,_atau_menggunakan_salah_satu_gaya_bawaan.
This_is_a_simple_copy_and_paste_dialog._First_load_or_paste_some_text_into_the_text_input_area.<br>After_that,_you_can_mark_text_and_assign_it_to_a_BibTeX_field.=Inilah_dialog_salin-tempel_yang_dasar._Pertama,_memuat_atau_menempel_ke_dalam_area_masukan_teks.<br>Setelah_itu,_anda_bisa_menanda_teks_dan_menulisnya_ke_dalam_bidang_BibTeX.
-
This_feature_generates_a_new_database_based_on_which_entries_are_needed_in_an_existing_LaTeX_document.=Fitur_ini_membuat_basisdata_yang_baru_berdasar_para_entri_yang_dibutuhkan_dalam_dokumen_LaTeX_yang_sudah_ada.
You_need_to_select_one_of_your_open_databases_from_which_to_choose_entries,_as_well_as_the_AUX_file_produced_by_LaTeX_when_compiling_your_document.=Anda_harus_memilih_salah_satu_basisdata_yang_terbuka_dari_mana_entri_akan_dipilih_dan_berkas_AUX_yang_dibuat_oleh_LaTeX_saat_dokumen_disusun.
+
First_select_entries_to_clean_up.=Pilih_entri_untuk_dibersihkan_dulu.
Cleanup_entry=Bersihkan_entri
Autogenerate_PDF_Names=Buat_otomatis_nama_PDF
Auto-generating_PDF-Names_does_not_support_undo._Continue?=Pembuatan_otomatis_nama_PDF_tidak_ada_fungsi_pengembalian._Teruskan?
+
Use_full_firstname_whenever_possible=Gunakan_nama_kecil_penuh_kalau_mungkin
Use_abbreviated_firstname_whenever_possible=Gunakan_singkatan_nama_kecil_kalau_mungkin
Use_abbreviated_and_full_firstname=Gunakan_nama_kecil_yang_penuh_dan_disingkatkan
@@ -994,6 +1642,7 @@ Name_format_used_for_autocompletion=Format_nama_yang_digunakan_untuk_pelengkapan
Treatment_of_first_names=
Cleanup_entries=Bersihkan_entri
Automatically_assign_new_entry_to_selected_groups=Tulis_entri_yang_baru_ke_pilihan_grup_secara_otomatis
+%0_mode=Mode_%0
Move_DOIs_from_note_and_URL_field_to_DOI_field_and_remove_http_prefix=Pindah_DOI_dari_bidang_catatan_dan_URL_ke_bidang_DOI_dan_hapuskan_prefiks_http
Make_paths_of_linked_files_relative_(if_possible)=Menjadikan_lokasi_berkas_yang_ditautkan_relatif_(kalau_mungkin)
Rename_PDFs_to_given_filename_format_pattern=Ganti_nama_PDF_dengan_pola_format_nama_berkas
@@ -1003,14 +1652,14 @@ Doing_a_cleanup_for_%0_entries...=Melakukan_pembersihan_%0_entri...
No_entry_needed_a_clean_up=Tidak_ada_entri_yang_membutuhkan_pembersihan
One_entry_needed_a_clean_up=Sebuah_entri_membutuhkan_pembersihan
%0_entries_needed_a_clean_up=%0_entri_membutuhkan_pembersihan
-%0_mode=Mode_%0
+
Error_downloading_file_'%0'=Kesalahan_ketika_muatturun_berkas_'%0'
Download_failed=Pemuatturunan_gagal
+Remove_selected=Hapuskan_pilihan
Group_tree_could_not_be_parsed._If_you_save_the_BibTeX_database,_all_groups_will_be_lost.=
Attach_file=Lampirkan_berkas
-
Setting_all_preferences_to_default_values.=Tetapkan_semua_pengaturan_menjadi_pengaturan_bawaan.
Resetting_preference_key_'%0'=Kembalikan_kunci_pengaturan_'%0'
Unknown_preference_key_'%0'=Kunci_pengaturan_'%0'_tidak_dikenal
@@ -1053,7 +1702,6 @@ Five_stars=Lima_bintang
Four_stars=Empat_bintang
Help_on_special_fields=Bantuan_bidang_khusus
Keywords_of_selected_entries=Katakunci_entri_pilihan
-Manage_content_selectors=Atur_kata_pemilih_isi
Manage_keywords=Atur_katakunci
No_priority_information=Tidak_ada_informasi_prioritas
No_rank_information=Tidak_ada_informasi_pangkat
@@ -1081,9 +1729,10 @@ Two_stars=Dua_bintang
Update_keywords=Perbarui_katakunci
Write_values_of_special_fields_as_separate_fields_to_BibTeX=Tulis_isi_bidang_khusus_sebagai_bidang_terpisah_ke_BibTeX
You_have_changed_settings_for_special_fields.=Anda_telah_merubah_pengaturan_bidang_khusus.
-
%0_entries_found._To_reduce_server_load,_only_%1_will_be_downloaded.=%0_entri_ditemukan._Untuk_mengurangi_beban_server,_hanya_%1_akan_dimuatturun.
+A_string_with_that_label_already_exists=String_dengan_label_tadi_sudah_ada
Connection_to_OpenOffice/LibreOffice_has_been_lost._Please_make_sure_OpenOffice/LibreOffice_is_running,_and_try_to_reconnect.=Sambungan_ke_OpenOffice/LibreOffice_terlepas._Pastikan_OpenOffice/LibreOffice_dijalankan,_dan_coba_menyambung_sekali_lagi.
+
Correct_the_entry,_and_reopen_editor_to_display/edit_source.=Koreksi_entri_dan_buka_editor_penunjuk/pengedit_sumber_sekali_lagi.
Could_not_connect_to_a_running_gnuserv_process._Make_sure_that_Emacs_or_XEmacs_is_running,<BR>and_that_the_server_has_been_started_(by_running_the_command_'server-start'/'gnuserv-start').=Tidak_bisa_menyambung_ke_proses_gnuserv_yang_sudah_dijalankan._Pastikan_Emacs_atau_XEmacs<br>dan_server_sudah_dijalankan_(dengan_perintah_'server-start'/'gnuserv-start')
Could_not_connect_to_running_OpenOffice/LibreOffice.=Tidak_bisa_menyambung_dengan_OpenOffice/LibreOffice.
@@ -1105,20 +1754,14 @@ Your_style_file_specifies_the_paragraph_format_'%0',_which_is_undefined_in_your_
Searching...=Sedang_mencari...
You_have_selected_more_than_%0_entries_for_download._Some_web_sites_might_block_you_if_you_make_too_many_rapid_downloads._Do_you_want_to_continue?=Anda_memilih_lebih_dari_%0_entri._Sejumlah_situs_web_akan_memblokir_anda_kalau_melakukan_terlalu_banyak_pemuatturunan_dengan_cepat._Apa_mau_teruskan?
Confirm_selection=Mengkonfirmasi_pilihan
-Unknown_DOI\:_'%0'.=DOI_tidak_dikenal\:_'%0'.
Add_{}_to_specified_title_words_on_search_to_keep_the_correct_case=
Import_conversions=Impor_konversi
Please_enter_a_search_string=Tuliskan_string_pencarian
Please_open_or_start_a_new_database_before_searching=Buka_atau_jalankan_basisdata_yang_baru_sebelum_mencari
-An_error_occurred_while_fetching_from_ADS_(%0)\:=Kesalahan_ketika_mengambil_dari_ADS_(%0)\:
-An_error_occurred_while_parsing_abstract=Kesalahan_ketika_mengurai_abstrak
-Unknown_DiVA_entry\:_'%0'.=Entri_DiVA_tidak_dikenal\:_'%0'.
-Get_BibTeX_entry_from_DiVA=Dapatkan_entri_BibTeX_dari_DiVA
Log=Log
-
-
Canceled_merging_entries=Penggabungan_entri_dibatalkan
+
Format_units_by_adding_non-breaking_separators_and_keeping_the_correct_case_on_search=
Merge_entries=Gabung_entri
Merged_entries=
@@ -1132,29 +1775,35 @@ Use_Emacs_key_bindings=
You_have_to_choose_exactly_two_entries_to_merge.=Anda_harus_memilih_dua_entri_untuk_digabung.
Update_timestamp_on_modification=
-
All_key_bindings_will_be_reset_to_their_defaults.=
+
Automatically_set_file_links=Buat_tautan_berkas_secara_otomatis.
Continue?=Teruskan?
Resetting_all_key_bindings=
-
Hostname=Nama_host
Invalid_setting=Pengaturan_tidak_sah
Network=Jaringan
Please_specify_both_hostname_and_port=Silahkan_nyatakan_nama_host_dan_port
+Please_specify_both_username_and_password=Silahkan_menulis_nama_pengguna_dan_kata_sandi
+
Use_custom_proxy_configuration=Gunakan_konfigurasi_proxy_suaian
+Proxy_requires_authentication=Proxy_memerlukan_otentikasi
+Attention\:_Password_is_stored_in_plain_text\!=Perhatian\:_Kata_sandi_disimpan_sebagai_teks_biasa\!
Clear_connection_settings=Bersihkan_pengaturan_koneksi
Cleared_connection_settings.=Pengaturan_koneksi_dibersihkan.
+
Rebind_C-a,_too=
+Rebind_C-f,_too=
Show_number_of_elements_contained_in_each_group=Tampilkan_jumlah_unsur_dalam_setiap_grup
Open_folder=Buka_direktori
Searches_for_unlinked_PDF_files_on_the_file_system=Cari_berkas_PDF_yang_tidak_bertautan_dalam_sistem_berkas
-
Export_entries_ordered_as_specified=
Export_sort_order=Ekspor_urutan_penyortiran
+Export_sorting=Ekspor_penyortiran
Newline_separator=Pembatas_baris_yang_baru
+
Save_entries_ordered_as_specified=
Save_sort_order=Simpan_urutan_penyortiran
Show_extra_columns=Tampilkan_kolom_ekstra
@@ -1165,7 +1814,6 @@ Move_to_group=Pindah_ke_grup
Clear_read_status=Bersihkan_status_pembacaan
Convert_to_BibLatex_format_(for_example,_move_the_value_of_the_'journal'_field_to_'journaltitle')=
-Could_not_apply_changes.=Tidak_bisa_terapkan_perubahan.
Deprecated_fields=
Hide/show_toolbar=Sembunyikan/Tampilkan_toolbar
No_read_status_information=Tidak_ada_informasi_status_pembacaan
@@ -1177,126 +1825,111 @@ Save_selected_as_plain_BibTeX...=Simpan_pilihan_sebagai_BibTeX_teks_biasa
Set_read_status_to_read=Menjadikan_status_pembacaan_dibaca
Set_read_status_to_skimmed=
Show_deprecated_BibTeX_fields=
+
Show_gridlines=Tampilkan_garis_kisi
Show_printed_status=Tampilkan_status_pencetakan
Show_read_status=Tampilkan_status_pembacaan
Table_row_height_padding=Lapisan_tinggi_baris_tabel
-Marked_all_%0_selected_entries=Semua_%0_entri_pilihan_ditandai
Marked_selected_entry=Entri_pilihan_ditandai
-Toggle_print_status=
-Unmarked_all_%0_selected_entries=Tanda_semua_%0_entri_pilihan_dihilangkan
+Marked_all_%0_selected_entries=Semua_%0_entri_pilihan_ditandai
Unmarked_selected_entry=Tanda_entri_pilihan_dihilangkan
+Unmarked_all_%0_selected_entries=Tanda_semua_%0_entri_pilihan_dihilangkan
+Toggle_print_status=
+
Unmarked_all_entries=Tanda_semua_entri_dihilangkan
Unable_to_find_the_requested_look_and_feel_and_thus_the_default_one_is_used.=Penampilan_yang_dimintai_tidak_bisa_ditemukan._Karena_begitu,_penampilan_bawaan_akan_digunakan.
-Could_not_open_browser.=Penjelajah_tidak_bisa_dibuka.
Opens_JabRef's_GitHub_page=Buka_halaman_JabRef_di_GitHub
-
-Rebind_C-f,_too=
-This_group_contains_all_entries._It_cannot_be_edited_or_removed.=Grup_ini_mengandung_semua_entri._Tidak_bisa_disunting_atau_dihapus.
+Could_not_open_browser.=Penjelajah_tidak_bisa_dibuka.
+Please_open_%0_manually.=
+The_link_has_been_copied_to_the_clipboard.=
Open_%0_file=Buka_berkas_%0
Cannot_delete_file=Tidak_bisa_menghapus_berkas
-Convert=
-Delete_local_file=Hapus_berkas_lokal
File_permission_error=Kesalahan_hak_akses_berkas
-Help_on_Name_Formatting=
-Normalize_to_BibTeX_name_format=
Push_to_%0=Kirim_pilihan_ke_%0
+Path_to_%0=Lokasi_%0
+Convert=
+Normalize_to_BibTeX_name_format=
+Help_on_Name_Formatting=
Add_new_file_type=Tambahkan_tipe_berkas_yang_baru
-Follow_DOI_or_URL_link_and_try_to_locate_PDF_full_text_document=Ikut_DOI_atau_URL_dan_coba_melokasikan_dokumen_PDF_teks_penuh
+
Left_entry=
-No_information_added=Tidak_ada_informasi_yang_ditambahkan
+Right_entry=
+Use=
Original_entry=Entri_asli
Replace_original_entry=Ganti_entri_asli
-Right_entry=
+No_information_added=Tidak_ada_informasi_yang_ditambahkan
Select_at_least_one_entry_to_manage_keywords.=Pilih_paling_sedikit_sebuah_entri_untuk_mengatur_katakunci.
-Use=
-Changed_type_to_'%0'_for=Merubah_tipe_ke_'%0'_untuk
-Database_'%0'_has_changed.=Basisdata_%0_telah_berubah.
-Copy_\\cite{BibTeX_key}=Salin_\\cite{kunci_BibTeX}
-To_set_up,_go_to=Untuk_mengatur,_dari
-Search_%0=Pencarian_%0
-Invalid_DOI\:_'%0'.=DOI_salah\:_'%0'.
-Could_not_connect_to_%0=Tidak_bisa_menghubungi_%0
-Path_to_%0=Lokasi_%0
-
+OpenDocument_text=Teks_OpenDocument
+OpenDocument_spreadsheet=Lembatang_lajur_OpenDocument
+OpenDocument_presentation=Presentasi_Open_Document
%0_image=
-%0_problem(s)_found=%0_kesalahan_ditemukan
-'%0'_is_not_a_valid_ADS_bibcode.='%0'_bukan_kode_BIB_ADS_yang_sah.
-Accepting_the_change_replaces_the_complete_groups_tree_with_the_externally_modified_groups_tree.=
Added_entry=Entri_ditambahkan
-Added_new_'%0'_entry.=Entri_yang_baru_'%0'_ditambahkan.
-Copy_BibTeX_key_and_title=Salin_kunci_BibTeX_dan_judul
-Deleted_entry=Entri_dihapus
-Discard_changes=Perubahan_dibuang
-Donate_to_JabRef=Sumbang_ke_JabRef
-Export_with_selected_format=Ekspor_dengan_format_yang_dipilih
-Field_is_missing=Tidak_ada_bidang
-File_rename_failed_for_%0_entries.=Perubahan_nama_berkas_gagal_untuk_%0_entri.
-Filled=Dipenuhi
-From_import=Dari_impor
-Keep_left=
-Keep_merged_entry_only=
-Keep_right=
-Merged_BibTeX_source_code=
Modified_entry=
+Deleted_entry=Entri_dihapus
Modified_groups_tree=
-Multiple_entries_selected._Do_you_want_to_change_the_type_of_all_these_to_'%0'?=
-No_problems_found.=Tidak_menemukan_kesulitan.
-Old_entry=Entri_yang_tua
-OpenDocument_presentation=Presentasi_Open_Document
-OpenDocument_spreadsheet=Lembatang_lajur_OpenDocument
-OpenDocument_text=Teks_OpenDocument
-Please_move_the_file_manually_and_link_in_place.=Silahkan_memindah_berkas_secara_manual_dan_menautkan_tempatnya.
-Print_entry_preview=Cetak_pratinjau_entri
-Really_delete_the_%0_selected_entries?=Apa_benar-benar_mau_menghapus_%0_entri_yang_dipilih?
-Really_delete_the_selected_entry?=Apa_benar-benar_mau_menghapus_entri_pilihan?
Removed_all_groups=Semua_kelompok_dihapus
-Return_to_JabRef=Kembali_ke_JabRef
-Save_changes=Simpan_perubahan
+Accepting_the_change_replaces_the_complete_groups_tree_with_the_externally_modified_groups_tree.=
Select_export_format=Pilih_format_ekspor
+Return_to_JabRef=Kembali_ke_JabRef
+Please_move_the_file_manually_and_link_in_place.=Silahkan_memindah_berkas_secara_manual_dan_menautkan_tempatnya.
+Could_not_connect_to_%0=Tidak_bisa_menghubungi_%0
Warning\:_%0_out_of_%1_entries_have_undefined_BibTeX_key.=Peringatan\:_%0_dari_%1_entri_ada_kunci_BibTeX_yang_tidak_terdefinisi.
-large_capitals_are_not_masked_using_curly_brackets_{}=
occurrence=
-should_contain_a_four_digit_number=harus_berisi_nomor_dengan_empat_angka
-should_contain_a_valid_page_number_range=
-should_end_with_a_name=harus_berakhiran_nama
+Added_new_'%0'_entry.=Entri_yang_baru_'%0'_ditambahkan.
+Multiple_entries_selected._Do_you_want_to_change_the_type_of_all_these_to_'%0'?=
+Changed_type_to_'%0'_for=Merubah_tipe_ke_'%0'_untuk
+Really_delete_the_selected_entry?=Apa_benar-benar_mau_menghapus_entri_pilihan?
+Really_delete_the_%0_selected_entries?=Apa_benar-benar_mau_menghapus_%0_entri_yang_dipilih?
+Keep_merged_entry_only=
+Keep_left=
+Keep_right=
+Old_entry=Entri_yang_tua
+From_import=Dari_impor
+No_problems_found.=Tidak_menemukan_kesulitan.
+%0_problem(s)_found=%0_kesalahan_ditemukan
+Save_changes=Simpan_perubahan
+Discard_changes=Perubahan_dibuang
+Database_'%0'_has_changed.=Basisdata_%0_telah_berubah.
+Print_entry_preview=Cetak_pratinjau_entri
+Copy_\\cite{BibTeX_key}=Salin_\\cite{kunci_BibTeX}
+Copy_BibTeX_key_and_title=Salin_kunci_BibTeX_dan_judul
+File_rename_failed_for_%0_entries.=Perubahan_nama_berkas_gagal_untuk_%0_entri.
+To_set_up,_go_to=Untuk_mengatur,_dari
+Merged_BibTeX_source_code=
+Invalid_DOI\:_'%0'.=DOI_salah\:_'%0'.
should_start_with_a_name=harus_bermula_dengan_nama
+should_end_with_a_name=harus_berakhiran_nama
unexpected_closing_curly_bracket=
unexpected_opening_curly_bracket=
+capital_letters_are_not_masked_using_curly_brackets_{}=
+should_contain_a_four_digit_number=harus_berisi_nomor_dengan_empat_angka
+should_contain_a_valid_page_number_range=
+Filled=Dipenuhi
+Field_is_missing=Tidak_ada_bidang
+Search_%0=Pencarian_%0
-Work_options=
-
-Advanced_search_active.=Pencarian_lanjut_aktif.
-Found_%0_results.=Menemukan_%0_hasil_pencarian.
-No_results_found.=Tidak_menemukan_hasil_pencarian.
-Normal_search_active.=Pencarian_biasa_aktif.
-Search_globally=Cari_secara_global
-Search_in_all_open_databases=Cari_dalam_semua_basisdata_yang_terbuka
Search_results_in_all_databases_for_%0=Hasil_pencarian_untuk_%0_dalam_semua_basisdata
Search_results_in_database_%0_for_%1=Hasil_pencarian_untuk_%0_dalam_basisdata_%1
-This_search_contains_entries_in_which=
+Search_globally=Cari_secara_global
+No_results_found.=Tidak_menemukan_hasil_pencarian.
+Found_%0_results.=Menemukan_%0_hasil_pencarian.
+Advanced_search_active.=Pencarian_lanjut_aktif.
+Normal_search_active.=Pencarian_biasa_aktif.
+plain_text=teks_biasa
This_search_contains_entries_in_which_any_field_contains_the_regular_expression_<b>%0</b>=
This_search_contains_entries_in_which_any_field_contains_the_term_<b>%0</b>=
-plain_text=teks_biasa
-
-Attention\:_Password_is_stored_in_plain_text\!=Perhatian\:_Kata_sandi_disimpan_sebagai_teks_biasa\!
-Please_specify_both_username_and_password=Silahkan_menulis_nama_pengguna_dan_kata_sandi
-Proxy_requires_authentication=Proxy_memerlukan_otentikasi
+This_search_contains_entries_in_which=
-An_autosave_file_was_found_for_this_database._This_could_indicate_that_JabRef_did_not_shut_down_cleanly_last_time_the_file_was_used.=
-Note\:_A_full_text_search_is_currently_not_supported_for_%0=
Unable_to_autodetect_OpenOffice/LibreOffice_installation._Please_choose_the_installation_directory_manually.=
-
JabRef_no_longer_supports_'ps'_or_'pdf'_fields.<br>File_links_are_now_stored_in_the_'file'_field_and_files_are_stored_in_an_external_file_directory.<br>To_make_use_of_this_feature,_JabRef_needs_to_upgrade_file_links.<br><br>=
This_database_uses_outdated_file_links.=
-A_string_with_that_label_already_exists=String_dengan_label_tadi_sudah_ada
Clear_search=Bersihkan_pencarian
Close_database=Tutup_basisdata
@@ -1333,55 +1966,32 @@ Resolve_duplicate_BibTeX_keys=
Save_all=Simpan_semua
String_dialog,_add_string=Dialog_string,_tambah_string
String_dialog,_remove_string=Dialog_string,_hapus_string
-Switch_preview_layout=
Synchronize_files=Sinkronkan_berkas
Unabbreviate=
-
should_contain_a_protocol=
-
Copy_preview=
-
Automatically_setting_file_links=
Regenerating_BibTeX_keys_according_to_metadata=
No_meta_data_present_in_BIB_file._Cannot_regenerate_BibTeX_keys=
-
Regenerate_all_keys_for_the_entries_in_a_BibTeX_file=
-
Show_debug_level_messages=
-
-Export_sorting=Ekspor_penyortiran
-
-New_%0_database=Basisdata_baru_%0
-
-New_%0_database_created.=Basisdata_baru_%0_dibuat.
-
-No_entry_found_for_ISBN_%0_at_www.ebook.de=
-
-Save_actions=
-Enable_save_actions=
-Always_reformat_BIB_file_on_save_and_export=
-
Default_bibliography_mode=Mode_bibliografi_bawaan
-
-
+New_%0_database_created.=Basisdata_baru_%0_dibuat.
Show_only_preferences_deviating_from_their_default_value=
default=bawaan
key=kunci
type=tipe
value=
-
Show_preferences=
-
-
+Save_actions=
+Enable_save_actions=
Other_fields=Bidang_lain
Show_remaining_fields=
link_should_refer_to_a_correct_file_path=
-
abbreviation_detected=
wrong_entry_type_as_proceedings_has_page_numbers=
-
Abbreviate_journal_names=Singkatkan_nama_jurnal
Abbreviating...=Singkatkan...
Adding_fetched_entries=Tambah_entri_ambilan
@@ -1393,28 +2003,22 @@ Unabbreviate_journal_names=
Unabbreviating...=
Usage=Penggunaan
+
+Adds_{}_brackets_around_acronyms,_month_names_and_countries_to_preserve_their_case.=
Are_you_sure_you_want_to_reset_all_settings_to_default_values?=
Reset_preferences=
-
Ill-formed_entrytype_comment_in_BIB_file=
+
+Move_linked_files_to_default_file_directory_%0=
+
Clipboard=
Could_not_paste_entry_as_text\:=Entri_tidak_bisa_dimuat_sebagai_teks\:
Do_you_still_want_to_continue?=Apa_masih_mau_meneruskan?
This_action_will_modify_the_following_field(s)_in_at_least_one_entry_each\:=
This_could_cause_undesired_changes_to_your_entries.=
-
-Disable_highlight_groups_matching_entries=
Run_field_formatter\:=
-
-Adds_{}_brackets_around_acronyms,_month_names_and_countries_to_preserve_their_case.=
-Converts_units_to_LaTeX_formatting.=
-Does_nothing.=
-
-
Table_font_size_is_%0=
-
-Move_linked_files_to_default_file_directory_%0=
-
+%0_import_canceled=Impor_%0_dibatalkan
Internal_style=
Add_style_file=Tambah_berkas_gaya
Are_you_sure_you_want_to_remove_the_style?=
@@ -1422,7 +2026,6 @@ Current_style_is_'%0'=
Remove_style=
Select_one_of_the_available_styles_or_add_a_style_file_from_disk.=
You_must_select_a_valid_style_file.=Anda_harus_memilih_berkas_file_yang_sah.
-
Reload=
Capitalize=
@@ -1433,9 +2036,11 @@ Changes_all_letters_to_upper_case.=
Changes_the_first_letter_of_all_words_to_capital_case_and_the_remaining_letters_to_lower_case.=
Cleans_up_LaTeX_code.=
Converts_HTML_code_to_LaTeX_code.=
+Converts_HTML_code_to_Unicode.=
Converts_LaTeX_encoding_to_Unicode_characters.=
Converts_Unicode_characters_to_LaTeX_encoding.=
Converts_ordinals_to_LaTeX_superscripts.=
+Converts_units_to_LaTeX_formatting.=
HTML_to_LaTeX=HTML_ke_LaTeX
LaTeX_cleanup=Pembersihan_LaTeX
LaTeX_to_Unicode=LaTeX_ke_Unicode
@@ -1459,6 +2064,7 @@ Title_case=
Unicode_to_LaTeX=
Units_to_LaTeX=
Upper_case=
+Does_nothing.=
Identity=
Clears_the_field_completely.=
Directory_not_found=
@@ -1473,7 +2079,6 @@ Mixed_names=
Neuter_name=
Neuter_names=
-Remove_selected=Hapuskan_pilihan
Lookup_DOI=
Audio_CD=
@@ -1517,31 +2122,22 @@ Plain_text=
Show_diff=
character=
word=
-
Show_symmetric_diff=
HTML_encoded_character_found=
-
booktitle_ends_with_'conference_on'=
+
All_external_files=
OpenOffice/LibreOffice_integration=
incorrect_control_digit=
incorrect_format=
-
-Expected_"%0"_to_contain_whitespace=
-Syntax_error_in_regular-expression_pattern=
-
Copy_version_to_clipboard=
Copied_version_to_clipboard=
+
BibTeX_key=
Message=
-
-Get_fulltext=
-
-Download_from_URL=
-
Decryption_not_supported.=
Cleared_'%0'_for_%1_entries=
@@ -1560,16 +2156,11 @@ To_see_what_is_new_view_the_changelog.=
A_new_version_of_JabRef_has_been_released.=
JabRef_is_up-to-date.=
Latest_version=
-
-Please_open_%0_manually.=
-
-The_link_has_been_copied_to_the_clipboard.=
-
Online_help_forum=
-
Custom=
-Converts_HTML_code_to_Unicode.=
+Export_cited=
+Unable_to_generate_new_database=
Open_console=
Use_default_terminal_emulator=
@@ -1577,28 +2168,22 @@ Execute_command=
Note\:_Use_the_placeholder_%0_for_the_location_of_the_opened_database_file.=
Executing_command_\"%0\"...=
Error_occured_while_executing_the_command_\"%0\".=
-
Reformat_ISSN=
-Unable_to_generate_new_database=
-Export_cited=
Countries_and_territories_in_English=
Electrical_engineering_terms=
Enabled=
Internal_list=
+Manage_protected_terms_files=
Months_and_weekdays_in_English=
The_text_after_the_last_line_starting_with_\#_will_be_used=
-
Add_protected_terms_file=
Are_you_sure_you_want_to_remove_the_protected_terms_file?=
Remove_protected_terms_file=
-
-Manage_protected_terms_files=
Add_selected_text_to_list=
Add_{}_around_selected_text=
Format_field=
New_protected_terms_file=
-
change_field_%0_of_entry_%1_from_%2_to_%3=
change_key_from_%0_to_%1=
change_string_content_%0_to_%1=
@@ -1608,37 +2193,29 @@ insert_entry_%0=
insert_string_%0=
remove_entry_%0=
remove_string_%0=
-
undefined=
Cannot_get_info_based_on_given_%0\:_%1=Tidak_bisa_mendapatkan_informasi_berdasar_%0\:_%1
-
Get_BibTeX_data_from_%0=Dapatkan_data_BibTeX_dari_%0
No_%0_found=
-
Entry_from_%0=Entri_dari_%0
-
Merge_entry_with_%0_information=Gabung_entri_dengan_informasi_%0
Updated_entry_with_info_from_%0=Entri_diperbarui_dengan_informasi_dari_%0
Connection=
+Connecting...=
Host=
Port=
Database=
User=
+Connect=Menghubungi
Connection_error=
-Driver_error=
Connection_to_%0_server_established.=
Required_field_"%0"_is_empty.=
-
%0_driver_not_available.=
-
The_connection_to_the_server_has_been_terminated.=
-
Connection_lost.=
Reconnect=
Work_offline=
-
Working_offline.=
-
Update_refused.=
Update_refused=
Local_entry=
@@ -1649,7 +2226,12 @@ Local_version\:_%0=
Shared_version\:_%0=
Please_merge_the_shared_entry_with_yours_and_press_"Merge_entries"_to_resolve_this_problem.=
Canceling_this_operation_will_leave_your_changes_unsynchronized._Cancel_anyway?=
-The_BibEntry_you_currently_work_on_has_been_deleted_on_the_shared_side._Hit_"Keep"_to_recover_the_entry.=
+Shared_entry_is_no_longer_present=
+The_BibEntry_you_currently_work_on_has_been_deleted_on_the_shared_side.=
+You_can_restore_the_entry_using_the_"Undo"_operation.=
+Remember_password?=
+You_are_already_connected_to_a_database_using_entered_connection_details.=
+
Cannot_cite_entries_without_BibTeX_keys._Generate_keys_now?=
New_technical_report=
@@ -1659,12 +2241,8 @@ Protected_terms_file=
Style_file=
Open_OpenOffice/LibreOffice_connection=
-
You_must_enter_at_least_one_field_name=
-
-
Non-ASCII_encoded_character_found=
-
Toggle_web_search_interface=
Background_color_for_resolved_fields=
Color_code_for_resolved_fields=
@@ -1678,13 +2256,59 @@ There_were_%0_files_which_could_not_be_imported.=
Migration_help_information=
Entered_database_has_obsolete_structure_and_is_no_longer_supported.=
However,_a_new_database_was_created_alongside_the_pre-3.6_one.=
-
Click_here_to_learn_about_the_migration_of_pre-3.6_databases.=
-
-Connecting...=
Opens_JabRef's_Facebook_page=
Opens_JabRef's_blog=
Opens_JabRef's_website=
-
Opens_a_link_where_the_current_development_version_can_be_downloaded=
See_what_has_been_changed_in_the_JabRef_versions=
+Referenced_BibTeX_key_does_not_exist=
+Finished_downloading_full_text_document_for_entry_%0.=
+Full_text_document_download_failed_for_entry_%0.=
+Look_up_full_text_documents=
+You_are_about_to_look_up_full_text_documents_for_%0_entries.=
+last_four_nonpunctuation_characters_should_be_numerals=
+shared=
+should_contain_an_integer_or_a_literal=
+should_have_the_first_letter_capitalized=
+
+ID=
+ID_type=
+ID-based_entry_generator=
+Fetcher_'%0'_did_not_find_an_entry_for_id_'%1'.=
+
+Select_first_entry=
+Select_last_entry=
+
+Invalid_ISBN\:_'%0'.=
+should_be_an_integer_or_normalized=
+should_be_normalized=
+
+Empty_search_ID=
+The_given_search_ID_was_empty.=
+Copy_BibTeX_key_and_link=
+empty_BibTeX_key=
+BibLaTeX_field_only=
+
+Error_while_generating_fetch_URL=
+Error_while_parsing_ID_list=
+Unable_to_get_PubMed_IDs=
+Backup_found=
+A_backup_file_for_'%0'_was_found.=
+This_could_indicate_that_JabRef_did_not_shut_down_cleanly_last_time_the_file_was_used.=
+Do_you_want_to_recover_the_database_from_the_backup_file?=
+Firstname_Lastname=
+
+Recommended_for_%0=
+This_might_be_caused_by_reaching_the_traffic_limitation_of_Google_Scholar_(see_'Help'_for_details).=
+
+Problem_downloading_from_%1=
+
+File_directory_pattern=
+Update_with_bibliographic_information_from_the_web=
+
+Could_not_find_any_bibliographic_information.=
+BibTeX_key_%0_deviates_from_generated_key_%1=
+DOI_%0_is_invalid=
+
+Jump_to_entry=
diff --git a/src/main/resources/l10n/JabRef_it.properties b/src/main/resources/l10n/JabRef_it.properties
index 541a675..d830c6c 100644
--- a/src/main/resources/l10n/JabRef_it.properties
+++ b/src/main/resources/l10n/JabRef_it.properties
@@ -1,558 +1,939 @@
#!
-#! created/edited by Popeye version 0.55 (https\://github.com/koppor/popeye)
-#! encoding:ISO-8859-1
-%0_contains_the_regular_expression_<b>%1</b>=%0_contiene_l'Espressione_Regolare_<b>%1</b>
+#! created/edited by Popeye version 0.55 (github.com/JabRef/popeye)
+#! encoding:UTF-8
+
+%0_contains_the_regular_expression_<b>%1</b>=%0_contiene_l'espressione_regolare_<b>%1</b>
+
%0_contains_the_term_<b>%1</b>=%0_contiene_il_termine_<b>%1</b>
-%0_doesn't_contain_the_regular_expression_<b>%1</b>=%0_non_contiene_l'Espressione_Regolare_<b>%1</b>
+
+%0_doesn't_contain_the_regular_expression_<b>%1</b>=%0_non_contiene_l'espressione_regolare_<b>%1</b>
+
%0_doesn't_contain_the_term_<b>%1</b>=%0_non_contiene_il_termine_<b>%1</b>
+
%0_export_successful=%0_esportazioni_riuscite
-%0_matches_the_regular_expression_<b>%1</b>=%0_corrisponde_all'Espressione_Regolare_<b>%1</b>
+
+%0_matches_the_regular_expression_<b>%1</b>=%0_corrisponde_all'espressione_regolare_<b>%1</b>
+
%0_matches_the_term_<b>%1</b>=%0_corrisponde_al_termine_<b>%1</b>
-<field_name>=<nome_del_campo>
-<HTML>Could_not_find_file_'%0'<BR>linked_from_entry_'%1'</HTML>=<HTML>Non_\u00e8_stato_trovato_il_file_'%0'_<BR>collegato_alla_voce_'%1'</HTML>
+
+<HTML>Could_not_find_file_'%0'<BR>linked_from_entry_'%1'</HTML>=<HTML>Non_è_stato_trovato_il_file_'%0'_<BR>collegato_alla_voce_'%1'</HTML>
+
<select>=<seleziona>
-<select_word>=<select_word>
+
Abbreviate_journal_names_of_the_selected_entries_(ISO_abbreviation)=Abbrevia_i_nomi_dei_giornali_delle_voci_selezionate_(abbreviazioni_ISO)
Abbreviate_journal_names_of_the_selected_entries_(MEDLINE_abbreviation)=Abbrevia_i_nomi_dei_giornali_delle_voci_selezionate_(abbreviazioni_MEDLINE)
+
Abbreviate_names=Abbrevia_i_nomi
Abbreviated_%0_journal_names.=%0_nomi_di_riviste_abbreviati.
+
Abbreviation=Abbreviazione
+
About_JabRef=Informazioni_su_JabRef
-Abstract=Riassunto
+
+Abstract=Sommario
+
Accept=Accetta
+
Accept_change=Accetta_la_modifica
+
Action=Azione
+
Add=Aggiungi
-Add_a_(compiled)_custom_ImportFormat_class_from_a_class_path.=Aggiungi_una_classe_ImportFormat_personalizzata_(compilata)_da_un_percorso.
+
+Add_a_(compiled)_custom_Importer_class_from_a_class_path.=Aggiungi_una_classe_Importer_personalizzata_(compilata)_da_un_percorso.
The_path_need_not_be_on_the_classpath_of_JabRef.=Il_percorso_non_deve_necessariamente_essere_nel_classpath_di_JabRef.
-Add_a_(compiled)_custom_ImportFormat_class_from_a_ZIP-archive.=Aggiungi_una_classe_ImportFormat_personalizzata_(compilata)_da_un_archivio_ZIP.
+
+Add_a_(compiled)_custom_Importer_class_from_a_ZIP-archive.=Aggiungi_una_classe_Importer_personalizzata_(compilata)_da_un_archivio_ZIP.
The_ZIP-archive_need_not_be_on_the_classpath_of_JabRef.=L'archivio_ZIP_non_deve_necessariamente_essere_nel_classpath_di_JabRef.
+
Add_entry_selection_to_this_group=Aggiungi_le_voci_selezionate_a_questo_gruppo
+
Add_from_folder=Aggiungi_da_una_cartella
+
Add_from_JAR=Aggiungi_da_un_file_JAR
+
add_group=aggiungi_un_gruppo
+
Add_group=Aggiungi_un_gruppo
+
Add_new=Aggiungi_nuovo
+
Add_subgroup=Aggiungi_un_sottogruppo
+
Add_to_group=Aggiungi_al_gruppo
+
Added_group_"%0".=Aggiunto_gruppo_"%0".
+
Added_new=Aggiunto_nuovo
+
Added_string=Aggiunta_stringa
+
Additionally,_entries_whose_<b>%0</b>_field_does_not_contain_<b>%1</b>_can_be_assigned_manually_to_this_group_by_selecting_them_then_using_either_drag_and_drop_or_the_context_menu._This_process_adds_the_term_<b>%1</b>_to_each_entry's_<b>%0</b>_field._Entries_can_be_removed_manually_from_this_group_by_selecting_them_then_using_the_context_menu._This_process_removes_the_term_<b>%1</b>_from_each_entry's_<b>%0</b>_field.=Inoltre,_le_voci_il_cui_campo_<b>%0</b>_non_contiene_<b>%1</b>_possono_ [...]
+
Advanced=Avanzate
All_entries=Tutte_le_voci
All_entries_of_this_type_will_be_declared_typeless._Continue?=Tutte_le_voci_di_questo_tipo_saranno_definite_'senza_tipo'._Continuare?
+
All_fields=Tutti_i_campi
+
All_subgroups_(recursively)=Tutti_i_sottogruppi_(ricorsivamente)
-An_exception_occurred_while_accessing_'%0'=Eccezione_durante_l'accesso_a_'%0'
-A_SAX_exception_occurred_while_parsing_'%0'\:=Eccezione_SAX_durante_l'elaborazione_di_'%0'\:
+
+Always_reformat_BIB_file_on_save_and_export=Riformatta_sempre_il_file_BIB_quando_salvi_o_esporti
+
+A_SAX_exception_occurred_while_parsing_'%0'\:=Eccezione_SAX_durante_l'analisi_di_'%0'\:
+
and=e
and_the_class_must_be_available_in_your_classpath_next_time_you_start_JabRef.=e_la_classe_deve_essere_nel_tuo_"classpath"_al_successivo_avvio_di_JabRef.
+
any_field_that_matches_the_regular_expression_<b>%0</b>=qualsiasi_campo_che_corrisponda_all'espressione_regolare_<b>%0</b>
+
Appearance=Aspetto
+
Append=Accoda
Append_contents_from_a_BibTeX_database_into_the_currently_viewed_database=Accoda_il_contenuto_di_un_database_BibTeX_al_database_corrente
+
Append_database=Accoda_database
+
Append_the_selected_text_to_BibTeX_field=Accoda_il_testo_selezionato_alla_chiave_BibTeX
Application=Applicazione
+
Apply=Applica
+
Arguments_passed_on_to_running_JabRef_instance._Shutting_down.=Argomenti_passati_all'istanza_attiva_di_JabRef._Chiusura_in_corso.
+
Assign_entry_selection_exclusively_to_this_group=Assegna_le_voci_selezionate_esclusivamente_a_questo_gruppo
+
Assign_new_file=Assegna_un_nuovo_file
+
Assign_the_original_group's_entries_to_this_group?=Assegnare_le_voci_originali_del_gruppo_a_questo_gruppo?
+
Assigned_%0_entries_to_group_"%1".=Assegnate_%0_voci_al_gruppo_"%1".
+
Assigned_1_entry_to_group_"%0".=Una_voce_assegnata_al_gruppo_"%0".
+
Attach_URL=Allega_URL
-Attempt_to_automatically_set_file_links_for_your_entries._Automatically_setting_works_if_a_file_in_your_file_directory<BR>or_a_subdirectory_is_named_identically_to_an_entry's_BibTeX_key,_plus_extension.=Tentativo_di_definire_automaticamente_file_collegamenti_per_le_tue_voci._La_definizione_avviene_automaticamente_se_un_file_nella_cartella_file_o_sottocartella<BR>ha_lo_stesso_nome_della_chiave_di_una_voce_BibTeX,_a_meno_dell'estensione.
+
+Attempt_to_automatically_set_file_links_for_your_entries._Automatically_setting_works_if_a_file_in_your_file_directory<BR>or_a_subdirectory_is_named_identically_to_an_entry's_BibTeX_key,_plus_extension.=Tentativo_di_definire_automaticamente_collegamenti_a_file_per_le_tue_voci._La_definizione_avviene_automaticamente_se_un_file_nella_cartella_file_o_sottocartella<BR>ha_lo_stesso_nome_della_chiave_di_una_voce_BibTeX,_a_meno_dell'estensione.
+
Auto=Auto
+
Autodetect_format=Rivelamento_automatico_del_formato
+
Autogenerate_BibTeX_keys=Generazione_automatica_delle_chiavi_BibTeX
+Autolink_files_with_names_starting_with_the_BibTeX_key=Collegare_automaticamente_i_file_con_nomi_che_iniziano_con_la_chiave_BibTeX
-Autolink_files_with_names_starting_with_the_BibTeX_key=Collegare_automaticamente_i_file_con_nome_che_inizia_con_la_chiave_BibTeX
Autolink_only_files_that_match_the_BibTeX_key=Collegare_automaticamente_solo_i_file_con_nome_corrispondente_alla_chiave_BibTeX
+
Automatically_create_groups=Crea_automaticamente_i_gruppi
+
Automatically_create_groups_for_database.=Crea_automaticamente_i_gruppi_per_il_database
+
Automatically_created_groups=Gruppi_creati_automaticamente
+
Automatically_remove_exact_duplicates=Rimuovi_automaticamente_i_duplicati_esatti
+
Allow_overwriting_existing_links.=Consenti_la_sovrascrittura_dei_collegamenti_esistenti.
+
Do_not_overwrite_existing_links.=Non_consentire_la_sovrascrittura_dei_collegamenti_esistenti.
+
AUX_file_import=Importa_file_AUX
+
Available_export_formats=Formati_di_esportazione_disponibili
+
Available_BibTeX_fields=Campi_BibTeX_disponibili
+
Available_import_formats=Formati_di_importazione_disponibili
+
Background_color_for_optional_fields=Colore_di_sfondo_per_i_campi_facoltativi
+
Background_color_for_required_fields=Colore_di_sfondo_per_i_campi_obbligatori
-Backup_old_file_when_saving=Fare_una_copia_di_backup_del_vecchio_file_quando_viene_salvato
-BibTeX_key_is_unique.=La_chiave_BibTeX_\u00e8_unica.
-BibTeX_source=Sorgente_BibTeX
-# Usually used the english word.
+
+Backup_old_file_when_saving=Fai_una_copia_di_backup_del_vecchio_file_quando_viene_salvato
+
+BibTeX_key_is_unique.=La_chiave_BibTeX_è_unica.
+
+%0_source=Sorgente_%0
+
Broken_link=Collegamento_interrotto
+
Browse=Sfoglia
-# Unsure how to translate out of context
+
by=da
+
Cancel=Annulla
+
Cannot_add_entries_to_group_without_generating_keys._Generate_keys_now?=Le_voci_non_possono_essere_inserite_in_un_gruppo_se_prive_di_chiave._Generare_le_chiavi_ora?
-Cannot_merge_this_change=Questa_modifica_non__pu\u00f2_essere_incorporata
-Cannot_move_group_"%0"_down.=Impossibile_spostare_il_gruppo_"%0"_in_gi\u00f9
+
+Cannot_merge_this_change=Questa_modifica_non__può_essere_incorporata
+
+Cannot_move_group_"%0"_down.=Impossibile_spostare_il_gruppo_"%0"_in_giù
+
Cannot_move_group_"%0"_left.=Impossibile_spostare_il_gruppo_"%0"_a_sinistra
+
Cannot_move_group_"%0"_right.=Impossibile_spostare_il_gruppo_"%0"_a_destra
+
Cannot_move_group_"%0"_up.=Impossibile_spostare_il_gruppo_"%0"_in_su
-case_insensitive=non_distingue__maiuscole_e_minuscole
-case_sensitive=distingue__maiuscole_e_minuscole
-Case_sensitive=Distingue__maiuscole_e_minuscole
+
+case_insensitive=non_distingue_maiuscole_e_minuscole
+
+case_sensitive=distingue_maiuscole_e_minuscole
+
+Case_sensitive=Distingue_maiuscole_e_minuscole
+
change_assignment_of_entries=modifica_l'assegnazione_delle_voci
+
Change_case=Inverti_maiuscolo/minuscolo
-Change_entry_type=Cambia_tipo_di_voce
+Change_entry_type=Cambia_tipo_di_voce
Change_file_type=Cambia_il_tipo_di_file
+
+
Change_of_Grouping_Method=Cambia_Metodo_di_Raggruppamento
+
change_preamble=modifica_il_preambolo
-Change_table_column_and_General_fields_settings_to_use_the_new_feature=Modificare_le_colonne_della_tabella_e_le_impostazioni_dei_campi_generali_per_utilizzare_la_nuova_funzione
+
+Change_table_column_and_General_fields_settings_to_use_the_new_feature=Modifica_le_colonne_della_tabella_e_le_impostazioni_dei_campi_generali_per_utilizzare_la_nuova_funzione
+
Changed_font_settings=Parametri_dei_font_modificati
+
Changed_language_settings=Parametri_della_lingua_modificati
+
Changed_look_and_feel_settings=Parametri_del_"Look-and-Feel"_modificati
+
Changed_preamble=Preambolo_modificato
+
Characters_to_ignore=Caratteri_da_ignorare
-Check_existing_file_links=Verificare_i_file_collegamenti_esistenti
-Check_links=Verificare_i_collegamenti
+
+Check_existing_file_links=Verificare_i_collegamenti_a_file_esistenti
+
+Check_links=Verifica_i_collegamenti
+
Choose_the_URL_to_download.=Scegliere_l'URL_da_scaricare.
Cite_command=Comando_Cite
+
Class_name=Nome_della_classe
+
Clear=Svuota
+
Clear_fields=Annulla_i_campi
-# Unsure the translation below
+
Close=Chiudi
-Close_others=
-Close_all=
+Close_others=Chiudi_gli_altri
+Close_all=Chiudi_tutti
+
Close_dialog=Chiudi_la_finestra_di_dialogo
+
Close_the_current_database=Chiudi_il_database_corrente
+
Close_window=Chiudi_la_finestra
+
Closed_database=Database_chiuso
+
Collapse_subtree=Collassa_il_sotto-albero
+
Color_codes_for_required_and_optional_fields=Codifica_a_colori_per_campi_obbligatori_e_opzionali
+
Color_for_marking_incomplete_entries=Colore_per_contrassegnare_voci_incomplete
+
Column_width=Larghezza_della_colonna
+
Command_line_id=Identificativo_della_riga_di_comando
-# Not sure\: "Registrazione completa" ?
-Connect=Connessione
+
+
Contained_in=Contenuto_in
+
Content=Contenuto
+
Copied=Copiato
+
Copied_cell_contents=Contenuto_delle_celle_copiato
+
Copied_key=Chiave_BibTeX_copiata
+
Copied_keys=Chiavi_BibTeX_copiate
+
Copy=Copia
+
Copy_BibTeX_key=Copia_chiave_BibTeX
Copy_file_to_file_directory=Copia_il_file_nella_cartella_dei_file
+
Copy_to_clipboard=Copia_negli_appunti
-Could_not_call_executable=Non_\u00e8_possibile_effetuare_la_chiamata_dell'eseguibile
+
+Could_not_call_executable=Non_è_possibile_effetuare_la_chiamata_dell'eseguibile
Could_not_connect_to_Vim_server._Make_sure_that_Vim_is_running<BR>with_correct_server_name.=Impossibile_stabilire_la_connessione_al_server_Vim.<BR>Assicurarsi_che_Vim_sia_in_esecuzione_con_il_nome_di_server_corretto.
+
Could_not_export_file=Impossibile_esportare_il_file
+
Could_not_export_preferences=Impossibile_esportare_le_preferenze
+
Could_not_find_a_suitable_import_format.=Impossibile_trovare_un_formato_di_importazione_adeguato
Could_not_import_preferences=Impossibile_importare_le_preferenze
-Could_not_instantiate_%0=Impossibile_inizializzare_%0
-Could_not_instantiate_%0_%1=Impossibile_inizializzare_%0_%1
-Could_not_instantiate_%0._Have_you_chosen_the_correct_package_path?=Impossibile_inizializzare_%0._Verificare_il_"package_path".
-
+Could_not_instantiate_%0=Impossibile_istanziare_%0
+Could_not_instantiate_%0_%1=Impossibile_istanziare_%0_%1
+Could_not_instantiate_%0._Have_you_chosen_the_correct_package_path?=Impossibile_istanziare_%0._Verificare_il_"package_path".
Could_not_open_link=Impossibile_aprire_il_collegamento
+
Could_not_print_preview=Impossibile_visualizzare_l'anteprima_di_stampa
+
Could_not_run_the_'vim'_program.=Impossibile_eseguire_il_programma_'vim'.
+
Could_not_save_file.=Impossibile_salvare_il_file.
-Character_encoding_'%0'_is_not_supported.=La_codifica_dei_caratteri_'%0'_non_\u00e8_supportata.
+Character_encoding_'%0'_is_not_supported.=La_codifica_dei_caratteri_'%0'_non_è_supportata.
+
Created_groups.=Gruppi_creati
+
crossreferenced_entries_included=Incluse_le_voci_con_riferimenti_incrociati
+
Current_content=Contenuto_corrente
+
Current_value=Valore_corrente
+
Custom_entry_types=Tipi_di_voce_personalizzati
+
Custom_entry_types_found_in_file=Tipi_di_voce_personalizzati_trovati_nel_file
+
Customize_entry_types=Personalizza_tipi_di_voce
+
Customize_key_bindings=Personalizza_combinazioni_di_tasti
+
Cut=Taglia
-cut_entries=Taglia_voci
+
+cut_entries=taglia_voci
+
cut_entry=taglia_voce
+
+
Database_encoding=Codifica_database
-Database_properties=Propriet\u00e0_del_database
-Database_type=
+Database_properties=Proprietà_del_database
+
+Database_type=Tipo_di_database
+
Date_format=Formato_data
+
Default=Predefinito
+
Default_encoding=Codifica_predefinita
+
Default_grouping_field=Campo_di_raggruppamento_predefinito
+
Default_look_and_feel="Look-and-Feel"_predefinito
+
Default_pattern=Modello_predefinito
+
Default_sort_criteria=Criterio_di_ordinamento_predefinito
Define_'%0'=Definisci_'%0'
+
Delete=Cancella
+
Delete_custom_format=Cancella_i_formati_personalizzati
-delete_entries=Cancella_le_voci
+
+delete_entries=cancella_le_voci
+
Delete_entry=Cancella_la_voce
+
delete_entry=cancella_la_voce
-Delete_multiple_entries=Cancella_pi\u00f9_voci
+
+Delete_multiple_entries=Cancella_più_voci
+
Delete_rows=Cancella_voci
+
Delete_strings=Cancella_stringhe
+
Deleted=Cancellato
+
+Delete_local_file=Cancella_file_locale
+
Delimit_fields_with_semicolon,_ex.=Campi_delimitati_da_punto_e_virgola,_ex.
+
Descending=Discendente
+
Description=Descrizione
+
Deselect_all=Deseleziona_tutto
Deselect_all_duplicates=Deseleziona_tutti_i_duplicati
+
Disable_this_confirmation_dialog=Disabilita_la_richiesta_di_conferma
-Display_all_entries_belonging_to_one_or_more_of_the_selected_groups.=Mostra_tutte_le_voci_appartenenti_a_uno_o_pi\u00f9_gruppi_tra_quelli_selezionati.
+
+Display_all_entries_belonging_to_one_or_more_of_the_selected_groups.=Mostra_tutte_le_voci_appartenenti_a_uno_o_più_gruppi_tra_quelli_selezionati.
+
Display_all_error_messages=Mostra_tutti_i_messaggi_di_errore
+
Display_help_on_command_line_options=Mostra_l'aiuto_sulle_opzioni_della_riga_di_comando
-Display_only_entries_belonging_to_all_selected_groups.=Mostra_solo_le_voci_appartenenti_a_tutti_i_gruppi_selezionati.
+Display_only_entries_belonging_to_all_selected_groups.=Mostra_solo_le_voci_appartenenti_a_tutti_i_gruppi_selezionati.
Display_version=Versione
+
Displaying_no_groups=Nessun_gruppo_da_visualizzare
+
Do_not_abbreviate_names=Non_abbreviare_i_nomi
+
Do_not_automatically_set=Non_effettuare_definizioni_automatiche
+
Do_not_import_entry=Non_importare_la_voce
+
Do_not_open_any_files_at_startup=Non_aprire_nessun_file_all'avvio
+
Do_not_overwrite_existing_keys=Non_sovrascrivere_chiavi_esistenti
Do_not_show_these_options_in_the_future=Non_mostrare_queste_opzioni_in_futuro
-Do_not_wrap_the_following_fields_when_saving=Non_mandare_a_capo_i_campi_seguenti_salvando_il_file
+Do_not_wrap_the_following_fields_when_saving=Non_mandare_a_capo_i_campi_seguenti_salvando_il_file
Do_not_write_the_following_fields_to_XMP_Metadata\:=Non_scrivere_i_dati_dei_campi_seguenti_nei_metadati_XMP\:
Do_you_want_JabRef_to_do_the_following_operations?=Vuoi_che_JabRef_esegua_le_operazioni_seguenti?
-Down=Gi\u00f9
+
+Donate_to_JabRef=Fai_una_donazione_a_JabRef
+
+Down=Giù
+
Download=Download
+
Download_file=Scarica_il_file
+
Downloading...=Download_in_corso...
-# Check translation below
Drop_%0=Rilascia_%0
+
duplicate_removal=rimozione_di_doppioni
+
Duplicate_string_name=Nome_di_stringa_duplicato
+
Duplicates_found=Trovati_doppioni
+
Dynamic_groups=Gruppi_dinamici
Dynamically_group_entries_by_a_free-form_search_expression=Raggruppa_dinamicamente_le_voci_utilizzando_una_espressione_di_ricerca_in_formato_libero
+
Dynamically_group_entries_by_searching_a_field_for_a_keyword=Raggruppa_dinamicamente_le_voci_ricercando_una_parola_chiave_in_un_campo
+
Each_line_must_be_on_the_following_form=Ciascuna_linea_deve_essere_nel_formato_seguente
+
Edit=Modifica
+
Edit_custom_export=Modifica_l'esportazione_personalizzata
Edit_entry=Modifica_voce
Save_file=Modifica_il_collegamento_al_file
Edit_file_type=Modifica_il_tipo_di_file
+
Edit_group=Modifica_il_gruppo
+
Edit_journal=Modifica_la_rivista
+
Edit_preamble=Modifica_il_preambolo
Edit_strings=Modifica_le_stringhe
Editor_options=Opzioni_dell'editor
+
Empty_BibTeX_key=Chiave_BibTeX_vuota
+
Grouping_may_not_work_for_this_entry.=La_gestione_dei_gruppi_potrebbe_non_funzionare_per_questa_voce.
+
empty_database=database_vuoto
Enable_word/name_autocompletion=Abilita_autocompletamento_di_parole/nomi
+
Enter_URL=Immettere_l'URL
+
Enter_URL_to_download=Immettere_l'URL_da_scaricare
+
entries=voci
+
Entries_cannot_be_manually_assigned_to_or_removed_from_this_group.=Le_voci_non_possono_essere_inserite_o_rimosse_manualmente_da_questo_gruppo.
+
Entries_exported_to_clipboard=Voci_esportate_negli_appunti
+
+
entry=voce
+
Entry_editor=Modifica_voci
Entry_preview=Anteprima_della_voce
+
Entry_table=Tabella_delle_voci
+
Entry_table_columns=Colonne_della_tabella_delle_voci
+
Entry_type=Tipo_di_voce
+
Entry_type_names_are_not_allowed_to_contain_white_space_or_the_following_characters=I_nomi_dei_tipi_di_voce_non_possono_contenere_spazi_o_i_caratteri_seguenti
+
Entry_types=Tipi_di_voce
-Error=Errore
+Error=Errore
Error_exporting_to_clipboard=Errore_durante_l'esportazione_negli_appunti
+
Error_occurred_when_parsing_entry=Errore_durante_l'elaborazione_della_voce
+
Error_opening_file=Errore_all'apertura_del_file
+
Error_setting_field=Errore_nell'impostazione_del_campo
Error_while_writing=Errore_durante_la_scrittura
-
Error_writing_to_%0_file(s).=Errore_di_scrittura_di_%0_file.
+
+
Exceptions=Eccezioni
+
Existing_file=File_esistente
+
'%0'_exists._Overwrite_file?='%0'_esiste._Sovrascrivere_il_file?
Overwrite_file?=Sovrascrivere_il_file?
+
Expand_subtree=Espandere_il_sotto-albero
+
Export=Esporta
+
Export_name=Esporta_nome
+
Export_preferences=Esporta_preferenze
+
Export_preferences_to_file=Esporta_preferenze_in_un_file
-Export_properties=Esporta_propriet\u00e0
+
+Export_properties=Esporta_proprietà
+
Export_to_clipboard=Esporta_negli_appunti
+
Exporting=Esportazione_in_corso
Extension=Estensione
+
External_changes=Modifiche_esterne
External_file_links=Collegamenti_a_file_esterni
+
External_files=File_esterni
+
External_programs=Programmi_esterni
+
External_viewer_called=Chiamata_a_visualizzatore_esterno
+
Fetch=Recupera
+
Field=Campo
+
field=campo
+
Field_name=Nome_del_campo
Field_names_are_not_allowed_to_contain_white_space_or_the_following_characters=I_nomi_dei_campi_non_possono_contenere_spazi_o_i_caratteri_seguenti
Field_to_filter=Campi_da_filtrare
+
Field_to_group_by=Campo_di_raggruppamento
+
File=File
+
file=file
+File_'%0'_is_already_open.=Il_file_'%0'__è_già_aperto.
-File_'%0'_is_already_open.=Il_file_'%0'__\u00e8_gi\u00e0_aperto.
File_'%0'_not_found=File_'%0'_non_trovato
+
File_changed=File_modificato
-File_directory_is_'%0'\:=La_cartella_dei_file_\u00e8_'%0'\:
+File_directory_is_'%0'\:=La_cartella_dei_file_è_'%0'\:
-File_directory_is_not_set_or_does_not_exist\!=La_cartella_dei_file_non_\u00e8_impostata_o_non_esiste\!
+File_directory_is_not_set_or_does_not_exist\!=La_cartella_dei_file_non_è_impostata_o_non_esiste\!
File_exists=Il_file_esiste
-File_has_been_updated_externally._What_do_you_want_to_do?=Il_file_\u00e8_stato_aggiornato_da_un'applicazione_esterna._Cosa_vuoi_fare?
+File_has_been_updated_externally._What_do_you_want_to_do?=Il_file_è_stato_aggiornato_da_un'applicazione_esterna._Cosa_vuoi_fare?
+
File_not_found=File_non_trovato
File_type=Tipo_di_file
+
File_updated_externally=File_aggiornato_esternamente
+
filename=nome_del_file
+
Files_opened=File_aperti
+
Filter=Filtro
Finished_automatically_setting_external_links.=Impostazione_automatica_dei_collegamenti_esterni_terminata.
-Finished_synchronizing_file_links._Entries_changed\:_%0.=Sincronizzazione_di_file_collegamenti:_Voci_cambiate\:_%0.
+Finished_synchronizing_file_links._Entries_changed\:_%0.=Sincronizzazione_di_collegamenti_a_file:_Voci_cambiate\:_%0.
Finished_writing_XMP-metadata._Wrote_to_%0_file(s).=Scrittura_dei_metadati_XMP_terminata._Scrittura_eseguita_su_%0_file.
Finished_writing_XMP_for_%0_file_(%1_skipped,_%2_errors).=Terminata_la_scrittura_di_metadati_XMP_per_%0_file_(%1_saltati,_%2_errori).
+
First_select_the_entries_you_want_keys_to_be_generated_for.=Selezionare_dapprima_le_voci_per_le_quali_si_vogliono_generare_le_chiavi.
+
Fit_table_horizontally_on_screen=Adatta_la_tabella_allo_schermo_orizontalmente
+
Float=Galleggiante
Float_marked_entries=Voci_evidenziate_sempre_in_alto
+
Font_family=Famiglia_di_font
+
Font_preview=Anteprima_font
+
Font_size=Dimensione_font
+
Font_style=Stile_font
+
Font_selection=Selettore_dei_font
+
for=per
+
Format_of_author_and_editor_names=Formato_dei_nomi_di_autori_e_curatori
Format_string=Stringa_di_formattazione
+
Format_used=Formato_utilizzato
Formatter_name=Nome_della_formattazione
+
found_in_AUX_file=trovate_nel_file_AUX
+
Full_name=Nome_completo
+
General=Generale
+
General_fields=Campi_generali
+
Generate=Genera
+
Generate_BibTeX_key=Genera_la_chiave_BibTeX
-Generate_keys=Genera_le_chiavi
-Generate_keys_before_saving_(for_entries_without_a_key)=Genera_le_chiavi_prima_di_salvare_(per_le_voci_senza_chiave)
+Generate_keys=Genera_le_chiavi
+Generate_keys_before_saving_(for_entries_without_a_key)=Genera_le_chiavi_prima_di_salvare_(per_le_voci_senza_chiave)
Generate_keys_for_imported_entries=Genera_chiavi_per_le_voci_importate
+
Generate_now=Genera_ora
+
Generated_BibTeX_key_for=Generata_la_chiave_BibTeX_per
+
Generating_BibTeX_key_for=Generazione_in_corso_della_chiave_BibTeX_per
-## Check below
+Get_fulltext=Prendi_testo_completo
Grab=Assegna
+
Gray_out_entries_not_in_group_selection=Evidenzia_in_grigio_le_voci_fuori_dai_gruppi_selezionati
+
Gray_out_non-hits=Disattiva_le_voci_non_corrispondenti
+
Groups=Gruppi
-Have_you_chosen_the_correct_package_path?=Il_classpath_\u00e8_corretto?
+
+Have_you_chosen_the_correct_package_path?=Il_classpath_è_corretto?
+
Help=Aiuto
Help_on_groups=Aiuto_sui_gruppi
+
Help_on_key_patterns=Aiuto_sulla_composizione_delle_chiavi
Help_on_regular_expression_search=Aiuto_sulla_ricerca_di_un'espressione_regolare
+
Hide_non-hits=Nascondi_le_voci_non_corrispondenti
Hierarchical_context=Contesto_gerarchico
+
Highlight=Evidenzia
Highlight_groups_matching_all_selected_entries=Evidenzia_i_gruppi_corrispondenti_a_tutte_le_voci_selezionate
Highlight_groups_matching_any_selected_entry=Evidenzia_i_gruppi_corrispondenti_almeno_ad_una_delle_voci_selezionate
-Highlight_overlapping_groups=Evidenzia_gruppi_con_voci_in__comune
+Disable_highlight_groups_matching_entries=Disabilita_l'evidenziazione_dei_gruppi_corrispondenti
+
+Highlight_overlapping_groups=Evidenzia_gruppi_con_voci_in_comune
+
Hint\:_To_search_specific_fields_only,_enter_for_example\:<p><tt>author\=smith_and_title\=electrical</tt>=Suggerimento\:_Per_ricercare_in_un_campo_specifico_digitare,_per_esempio\:<p><tt>author\=smith_and_title\=electrical</tt>
HTML_table=Tabella_HTML
-
-HTML_table_(with_Abstract_&_BibTeX)=Tabella_HTML_(con_riassunto_e_BibTeX)
+HTML_table_(with_Abstract_&_BibTeX)=Tabella_HTML_(con_Sommario_e_BibTeX)
Icon=Icona
+
Ignore=Ignora
+
Immediate_subgroups=Sottogruppi_diretti
+
Import=Importa
+
Import_and_keep_old_entry=Importa_e_mantieni_le_vecchie_voci
+
Import_and_remove_old_entry=Importa_e_rimuovi_le_vecchie_voci
+
Import_entries=Importa_voci
+
Import_failed=Importazione_fallita
+
Import_file=Importa_file
+
Import_group_definitions=Importa_definizioni_di_gruppo
+
Import_name=Importa_nome
+
Import_preferences=Importa_preferenze
+
Import_preferences_from_file=Importa_preferenze_da_un_file
+
Import_strings=Importa_stringhe
+
Import_to_open_tab=Importa_nella_scheda_aperta
-Import_word_selector_definitions=Importa_le_definizioni_per_la_selezione_di_parole
+
Imported_entries=Voci_importate
+
Imported_from_database=Importato_dal_database
-ImportFormat_class=Classe_ImportFormat
+
+Importer_class=Classe_Importer
+
Importing=Importazione_in_corso
+
Importing_in_unknown_format=Importazione_in_formato_sconosciuto
-Include_abstracts=Includi_il_riassunto
+
+Include_abstracts=Includi_il_sommario
Include_entries=Includi_voci
+
Include_subgroups\:_When_selected,_view_entries_contained_in_this_group_or_its_subgroups=Includi_i_sottogruppi\:_Quando_selezionato,_mostra_le_voci_contenute_in_questo_gruppo_e_nei_suoi_sottogruppi
+
Independent_group\:_When_selected,_view_only_this_group's_entries=Gruppo_indipendente\:_Quando_selezionato,_mostra_solo_le_voci_di_questo_gruppo
+
Initially_show_groups_tree_expanded=Inizialmente_mostra_l'albero_dei_gruppi_espanso
+
Work_options=Attribuzione_dei_campi
-Input_error=Voce_errata
+
Insert=Inserisci
+
Insert_rows=Inserisci_righe
Intersection=Intersezione
+
Invalid_BibTeX_key=Chiave_BibTeX_non_valida
+
Invalid_date_format=Formato_data_non_valido
+
Invalid_URL=URL_non_valido
-Inverted=Complemantare
+
+Inverted=Complementare
+
ISO_abbreviation=Abbreviazione_ISO
-Online_help=
+
+Online_help=Help_online
+
JabRef_preferences=Preferenze_JabRef
+
Journal_abbreviations=Abbreviazioni_riviste
+
Journal_list_preview=Anteprima_della_lista_delle_riviste
+
Journal_name=Nome_della_rivista
+
Keep=Mantieni
+
Keep_both=Mantieni_entrambi
+
Key_bindings=Combinazioni_di_tasti
+
Key_bindings_changed=Combinazioni_di_tasti_modificate
+
Key_generator_settings=Impostazioni_per_la_generazione_delle_chiavi
+
Key_pattern=Modello_delle_chiavi
+
keys_in_database=Chiavi_in_database
+
Keyword=Parola_Chiave
-##_check\:_Nome_del_campo_(fr)?
+
Label=Etichetta
+
Language=Lingua
+
Last_modified=Ultimo_modificato
+
LaTeX_AUX_file=File_AUX_LaTeX
Leave_file_in_its_current_directory=Lascia_il_file_nella_cartella_corrente
Left=Sinistra
-Level=
+Level=Livello
+
Limit_to_fields=Restrizioni_ai_campi
+
Limit_to_selected_entries=Restrizioni_alle_voci_selezionate
Link=Collegamento
Link_local_file=Collegamento_al_file_locale
Link_to_file_%0=Collegamento_al_file_%0
+
Listen_for_remote_operation_on_port=Porta_in_ascolto_per_operazioni_remote
-Load_and_Save_preferences_from/to_jabref.xml_on_start-up_(memory_stick_mode)=Carica_e_salva_le_preferenze_da/in_jabref.xml_all'avvio_(modalit\u00e0_chiavetta_di_memoria)
+Load_and_Save_preferences_from/to_jabref.xml_on_start-up_(memory_stick_mode)=Carica_e_salva_le_preferenze_da/in_jabref.xml_all'avvio_(modalità_chiavetta_di_memoria)
+
Look_and_feel=Aspetto
Main_file_directory=Cartella_dei_file_principale
Main_layout_file=File_di_layout_principale
-Manage=Gestione
+
Manage_custom_exports=Gestione_delle_esportazioni_personalizzate
+
Manage_custom_imports=Gestione_delle_importazioni_personalizzate
Manage_external_file_types=Gestione_dei_tipi_di_file_esterni
+
Manage_journal_abbreviations=Gestione_delle_abbreviazioni_delle_riviste
+
Mark_entries=Contrassegna_voci
+
Mark_entry=Contrassegna_voce
-Mark_new_entries_with_addition_date=Contrassegna_le_nuove_voci_con_la_data_di_aggiunta
+
+Mark_new_entries_with_addition_date=Contrassegna_le_nuove_voci_con_la_data_di_inserimento
+
Mark_new_entries_with_owner_name=Contrassegna_le_nuove_voci_con_il_nome_del_proprietario
-Memory_stick_mode=Modalit\u00e0_chiavetta_di_memoria
+
+Memory_stick_mode=Modalità_chiavetta_di_memoria
+
Menu_and_label_font_size=Dimensione_del_font_di_menu_ed_etichette
-Merged_external_changes=Incorpora_modifiche_esterne
+
+Merged_external_changes=Modifiche_esterne_incorporate
+
Messages=Messaggi
+
Modification_of_field=Modifica_del_campo
+
Modified_group_"%0".=Gruppo_"%0"_modificato.
+
Modified_groups=Gruppi_modificati
+
Modified_string=Stringa_modificata
+
Modify=Modifica
-modify_group=Modifica_gruppo
+
+modify_group=modifica_gruppo
+
Move=Sposta
-Move_down=Sposta_in_gi\u00f9
+
+Move_down=Sposta_in_giù
+
Move_entries_in_group_selection_to_the_top=Sposta_le_voci_selezionate_in_su
Move_external_links_to_'file'_field=Sposta_i_collegamenti_esterni_nel_campo_'file'
+
move_group=sposta_gruppo
+
Move_up=Sposta_in_su
+
Moved_group_"%0".=Spostato_gruppo_"%0".
+
Name=Nome
Name_formatter=Formattazione_dei_nomi
+
Natbib_style=Stile_Natbib
nested_AUX_files=File_AUX_nidificati
+
New=Nuovo
+
new=nuovo
+
New_BibTeX_entry=Nuova_voce_BibTeX
+
New_BibTeX_subdatabase=Nuovo_subdatabase_BibTeX
+
New_content=Nuovo_contenuto
+
New_database_created.=Nuovo_database_creato
+New_%0_database=Nuovo_database_%0
New_field_value=Nuovo_valore_del_campo
+
New_file=Nuovo_file
New_file_link_(INSERT)=Nuovo_collegamento_a_file_(INSERT)
+
New_group=Nuovo_gruppo
+
New_string=Nuova_stringa
+
Next_entry=Voce_successiva
+
No_actual_changes_found.=Nessun_cambiamento_trovato.
+
no_base-BibTeX-file_specified=nessun_database_BibTeX_specificato
+
no_database_generated=nessun_database_creato
+
No_entries_found._Please_make_sure_you_are_using_the_correct_import_filter.=Nessuna_voce_trovata._Verificare_che_si_stia_utilizzando_il_filtro_di_importazione_appropriato.
+
No_entries_found_for_the_search_string_'%0'=Nessuna_voce_trovata_in_base_alla_stringa_di_ricerca_'%0'
+
No_entries_imported.=Nessuna_voce_importata
-No_exceptions_have_occurred.=Non_si_\u00e8_verificata_nessuna_eccezione
+
+No_exceptions_have_occurred.=Non_si_è_verificata_nessuna_eccezione
No_files_found.=Nessun_file_trovato.
+
No_GUI._Only_process_command_line_options.=Senza_interfaccia_grafica._Elaborate_solo_le_opzioni_della_riga_di_comando.
-No_journal_names_could_be_abbreviated.=Nessun_nome_di_rivista_pu\u00f2_essere_abbreviato.
-No_journal_names_could_be_unabbreviated.=Nessuna_abbreviazione_di_rivista_pu\u00f2_essere_estesa.
+No_journal_names_could_be_abbreviated.=Nessun_nome_di_rivista_può_essere_abbreviato.
+
+No_journal_names_could_be_unabbreviated.=Nessuna_abbreviazione_di_rivista_può_essere_estesa.
No_PDF_linked=Nessun_file_PDF_collegato
-No_references_found=Nessun_riferimento_trovato
+
No_URL_defined=Nessun_URL_trovato
-not=no
+not=non
+
not_found=non_trovato
-Note_that_you_must_specify_the_fully_qualified_class_name_for_the_look_and_feel,=Nota\:_\u00e8_necessario_specificare_il_nome_di_classe_completo_per_il_"Look-and-Feel",
+
+Note_that_you_must_specify_the_fully_qualified_class_name_for_the_look_and_feel,=Nota\:_è_necessario_specificare_il_nome_di_classe_completo_per_il_"Look-and-Feel",
+
Nothing_to_redo=Niente_da_ripetere
+
Nothing_to_undo=Niente_da_annullare
-Number_of_references_to_fetch?=Numero_di_riferimenti_da_recuperare?
+
occurrences=ricorrenze
-OK=Ok
-One_or_more_file_links_are_of_the_type_'%0',_which_is_undefined._What_do_you_want_to_do?=Uno_o_pi\u00f9_collegamenti_a_file_sono_del_tipo_'%0',_non_definito._Come_procedere?
-One_or_more_keys_will_be_overwritten._Continue?=Una_o_pi\u00f9_chiavi_saranno_sovrascritte._Continuare?
+
+OK=OK
+One_or_more_file_links_are_of_the_type_'%0',_which_is_undefined._What_do_you_want_to_do?=Uno_o_più_collegamenti_a_file_sono_del_tipo_'%0',_non_definito._Come_procedere?
+
+One_or_more_keys_will_be_overwritten._Continue?=Una_o_più_chiavi_saranno_sovrascritte._Continuare?
+
Open=Apri
+
Open_BibTeX_database=Apri_database_BibTeX
+
Open_database=Apri_database
+
Open_editor_when_a_new_entry_is_created=Apri_per_modifiche_quando_una_nuova_voce_viene_creata
+
Open_file=Apri_file
+
Open_last_edited_databases_at_startup=All'avvio_apri_i_database_aperti_nella_sessione_precedente
-Open_shared_database=
-Open_terminal_here=
+
+Connect_to_shared_database=Apri_database_condiviso
+
+Open_terminal_here=Apri_un_terminale_qui
+
Open_URL_or_DOI=Apri_URL_o_DOI
+
Opened_database=Database_aperto
+
Opening=Apertura_in_corso
-Opening_preferences...=Apertura_delle_preferenze_in_corso...
+Opening_preferences...=Apertura_delle_preferenze_in_corso...
Operation_canceled.=Operazione_annullata.
Operation_not_supported=Operazione_non_supportata
+
Optional_fields=Campi_opzionali
+
Options=Opzioni
+
or=o
+
Output=Output
+
Output_or_export_file=File_di_salvataggio_o_esportazione
-##_check
+
Override=Sovrascrivi
+
Override_default_file_directories=Alternative_alle_cartelle_di_file_predefinite
+
Override_default_font_settings=Ignora_le_impostazioni_dei_font_predefinite
-##_check
+
Override_the_BibTeX_field_by_the_selected_text=Sovrascrivi_la_chiave_BibTeX_con_il_testo_selezionato
+
+
Overwrite=Sovrascrivi
Overwrite_existing_field_values=Sovrascrivi_i_valori_esistenti_del_campo
-##_check
+
Overwrite_keys=Sovrascrivi_chiavi
+
pairs_processed=coppie_elaborate
Password=Password
+
Paste=Incolla
+
paste_entries=incolla_voci
-paste_entry=incolla_voce
+paste_entry=incolla_voce
Paste_from_clipboard=Incolla_dagli_appunti
+
Pasted=Incollato
Path_to_%0_not_defined=Percorso_per_%0_non_definito
@@ -560,280 +941,460 @@ Path_to_%0_not_defined=Percorso_per_%0_non_definito
Path_to_LyX_pipe=Percorso_per_la_pipe_LyX
PDF_does_not_exist=Il_file_PDF_non_esiste
+
Personal_journal_list=Lista_di_riviste_personale
+
Plain_text_import=Importazione_da_solo_testo
+
Please_enter_a_name_for_the_group.=Immettere_un_nome_per_il_gruppo
+
Please_enter_a_search_term._For_example,_to_search_all_fields_for_<b>Smith</b>,_enter\:<p><tt>smith</tt><p>To_search_the_field_<b>Author</b>_for_<b>Smith</b>_and_the_field_<b>Title</b>_for_<b>electrical</b>,_enter\:<p><tt>author\=smith_and_title\=electrical</tt>=Immettere_un_termine_di_ricerca._Per_esempio,_per_ricercare_in_tutti_i_campi_<b>Smith</b>,_imettere\:<p><tt>smith</tt><p>_Per_ricercare_nel_campo_<b>Author</b>_il_termine_<b>Smith</b>_e_nel_campo_<b>Title</b>_il_termine_<b>electr [...]
+
Please_enter_the_field_to_search_(e.g._<b>keywords</b>)_and_the_keyword_to_search_it_for_(e.g._<b>electrical</b>).=Immettere_il_cmpo_di_ricerca_(es._<b>keywords</b>)_e_la_parola_chiave_da_ricercare_(es._<b>electrical</b>).
+
Please_enter_the_string's_label=Immettere_l'etichetta_della_stringa
+
Please_select_an_importer.=Selezionare_un_filtro_di_importazione.
+
Please_select_exactly_one_group_to_move.=Selezionare_un_solo_gruppo_da_spostare.
+
Possible_duplicate_entries=Voci_potenzialmente_duplicate
+
Possible_duplicate_of_existing_entry._Click_to_resolve.=Possibile_duplicazione_di_una_voce_esistente._Cliccare_per_effettuare_la_verifica.
+
Preamble=Preambolo
+
Preferences=Preferenze
+
Preferences_recorded.=Preferenze_registrate.
+
Preview=Anteprima
+Citation_Style=Stile_delle_citazioni
+Current_Preview=Anteprima_di_stampa_corrente
+Cannot_generate_preview_based_on_selected_citation_style.=Non_posso_generare_un'anteprima_usando_lo_stile_delle_citazioni_scelto.
+Bad_character_inside_entry=Carattere_errato_nella_voce
+Error_while_generating_citation_style=Errore_durante_la_generazione_dello_stile_di_citazione
+Preview_style_changed_to\:_%0=Stile_di_anteprima_modificato_in\:_%0
+Next_preview_layout=Prossimo_layout_di_anteprima
+Previous_preview_layout=Successivo_layout_di_anteprima
+
Previous_entry=Voce_precedente
+
Primary_sort_criterion=Criterio_di_ordinamento_principale
Problem_with_parsing_entry=Problema_di_analisi_di_una_voce
-
Processing_%0=Elaborazione_di_%0
Program_output=Output_del_programma
-Pull_changes_from_shared_database=
+Pull_changes_from_shared_database=Estrai_modifiche_dal_database_condiviso
+
Pushed_citations_to_%0=Citazioni_inviate_a_%0
+
Quit_JabRef=Chiudi_JabRef
+
Quit_synchronization=Chiudi_sincronizzazione
-##check
+
Raw_source=Solo_testo
+
Rearrange_tabs_alphabetically_by_title=Ordina_alfabeticamente_le_schede
+
Redo=Ripeti
+
Reference_database=Database_di_riferimenti
-References_found=Riferimenti_trovati
+
+%0_references_found._Number_of_references_to_fetch?=Riferimenti_trovati\:_%0._Numero_di_riferimenti_da_recuperare?
+
Refine_supergroup\:_When_selected,_view_entries_contained_in_both_this_group_and_its_supergroup=Perfeziona_il_super-gruppo\:_Quando_selezionato,_mostra_le_voci_contenute_sia_in_questo_gruppo_sia_nel_suo_super-gruppo
+
regular_expression=Espressione_regolare
+
Remember_these_entry_types?=Ricordare_questo_tipo_di_voce?
+
Remote_operation=Accesso_remoto
+
Remote_server_port=Porta_del_server_remoto
+
Remove=Rimuovi
-##_check_(tutte?)
+
Remove_subgroups=Rimuovi_tutti_i_sottogruppi
+
Remove_all_subgroups_of_"%0"?=Rimuovere_tutti_i_sottogruppi_di_"%0"?
+
Remove_entry_from_import=Rimuovi_la_voce_dall'importazione
+
Remove_entry_selection_from_this_group=Rimuovi_le_voci_selezionate_da_questo_gruppo
+
Remove_entry_type=Rimuovi_il_tipo_di_voce
Remove_file_link_(DELETE)=Rimuovi_collegamento_a_file_(DELETE)
+
Remove_from_group=Rimuovi_dal_gruppo
+
Remove_group=Rimuovi_gruppo
+
Remove_group,_keep_subgroups=Rimuovi_gruppo,_mantieni_i_sottogruppi
+
Remove_group_"%0"?=Rimuovere_il_gruppo_"%0"?
+
Remove_group_"%0"_and_its_subgroups?=Rimuovere_il_gruppo_"%0"_ed_i_suoi_sottogruppi?
+
remove_group_(keep_subgroups)=rimuovi_gruppo_(mantieni_i_sottogruppi)
+
remove_group_and_subgroups=rimuovi_gruppo_e_sottogruppi
+
Remove_group_and_subgroups=Rimuovi_gruppo_e_sottogruppi
Remove_link=Rimuovere_il_collegamento
+
Remove_old_entry=Rimuovi_vecchia_voce
+
Remove_selected_strings=Rimuovi_le_stringhe_selezionate
+
Removed_group_"%0".=Rimosso_gruppo_"%0".
+
Removed_group_"%0"_and_its_subgroups.=Rimosso_gruppo_"%0"_e_suoi_sottogruppi.
+
Removed_string=Stringa_rimossa
+
Renamed_string=Stringa_rinominata
+
Replace_(regular_expression)=Sostituisci_(espressione_regolare)
+
Replace_string=Sostituisci_stringa
+
Replace_with=Sostituisci_con
+
Replaced=Sostituito
+
Required_fields=Campo_obbligatorio
+
Reset_all=Reimposta_tutto
Resolve_strings_for_all_fields_except=Risolve_le_stringhe_per_tutti_i_campi_tranne
Resolve_strings_for_standard_BibTeX_fields_only=Risolve_le_stringhe_solo_per_i_campi_BibTeX_standard
+
resolved=risolto
+
Revert_to_original_source=Ripristina_il_contenuto_iniziale
-##_check_Rivista?_Verifica?
+
Review=Rivedi
+
Review_changes=Rivedi_le_modifiche
+
Right=Destra
+
Save=Salva
Save_all_finished.=Terminato_il_salvataggio_di_tutti_i_database.
Save_all_open_databases=Salva_tutti_i_database_aperti
+
Save_before_closing=Salva_prima_di_chiudere
+
Save_database=Salva_il_database
Save_database_as...=Salva_il_database_come...
+
Save_entries_in_their_original_order=Salva_le_voci_nel_loro_ordine_originale
+
Save_failed=Salvataggio_fallito
+
Save_failed_during_backup_creation=Salvataggio_fallito_durante_la_creazione_della_copia_di_backup
-Save_failed_while_committing_changes\:_%0=Salvataggio_fallito_nel_rendere_definitivi_i_cambiamenti\:_%0
+
Save_selected_as...=Salva_la_selezione_come...
+
Saved_database=Database_salvato
+
Saved_selected_to_'%0'.=Salvata_la_selezione_in_'%0'.
+
Saving=Salvataggio_in_corso
Saving_all_databases...=Salvataggio_di_tutti_i_database...
+
Saving_database=Salvataggio_del_database_in_corso
-##_check
+
Search=Ricerca
+
Search_expression=Espressione_di_ricerca
+
Search_for=Ricerca
+
Searching_for_duplicates...=Ricerca_di_duplicati_in_corso...
Searching_for_files=Ricerca_dei_file
+
Secondary_sort_criterion=Criterio_di_ordinamento_secondario
+
Select=Seleziona
+
+
Select_all=Seleziona_tutto
+
Select_encoding=Seleziona_la_codifica
+
Select_entry_type=Seleziona_un_tipo_di_voce
Select_external_application=Seleziona_un'applicazione_esterna
+
Select_file_from_ZIP-archive=Seleziona_un_file_da_un_archivio_ZIP
+
Select_the_tree_nodes_to_view_and_accept_or_reject_changes=Selezionare_i_nodi_dell'albero_per_vedere_ed_accettare_o_rifiutare_le_modifiche
Selected_entries=Voci_selezionate
-
Set_field=Imposta_il_campo
Set_fields=Imposta_i_campi
+
Set_general_fields=Definisci_i_campi_generali
Set_main_external_file_directory=Impostare_la_cartella_principale_dei_file_esterni
+
Set_table_font=Definisci_i_font_della_tabella
+
Settings=Parametri
-##_check
+
Shortcut=Scorciatoia
-Show/edit_BibTeX_source=Mostra/Modifica_codice_sorgente_BibTeX
+
+Show/edit_%0_source=Mostra/Modifica_codice_sorgente_%0
+
Show_'Firstname_Lastname'=Mostra_'Nome_Cognome'
+
Show_'Lastname,_Firstname'=Mostra_'Cognome,_Nome'
+
Show_BibTeX_source_by_default=Mostra_il_codice_sorgente_BibTeX_per_impostazione_predefinita
+
Show_confirmation_dialog_when_deleting_entries=Chiedere_conferma_della_cancellazione_di_una_voce
+
Show_description=Mostra_descrizione
+
Show_dynamic_groups_in_<i>italics</i>=Mostra_gruppi_dinamici_in_<i>corsivo</i>
+
Show_entries_<b>not</b>_in_group_selection=Mostra_le_voci_<b>non</b>_comprese_nei_gruppi_selezionati
Show_file_column=Visualizza_la_colonna_File
+
Show_icons_for_groups=Mostra_le_icone_per_i_gruppi
Show_last_names_only=Mostra_solo_i_cognomi
+
Show_names_unchanged=Mostra_i_nomi_immodificati
+
Show_optional_fields=Mostra_i_campi_opzionali
+
Show_required_fields=Mostra_i_campi_obbligatori
+
Show_URL/DOI_column=Mostra_colonna_URL/DOI
+
Simple_HTML=HTML_semplice
+
Size=Dimensione
+
Skipped_-_No_PDF_linked=Saltato_-_Nessun_file_PDF_collegato
Skipped_-_PDF_does_not_exist=Saltato_-_Il_file_PDF_non_esiste
Skipped_entry.=Voce_saltata
+
Sort_alphabetically=Ordina_alfabeticamente
sort_subgroups=ordina_i_sottogruppi
+
Sorted_all_subgroups_recursively.=Ordina_tutti_i_sottogruppi_ricorsivamente.
+
Sorted_immediate_subgroups.=Ordinati_i_sottogruppi_immediati.
+
source_edit=modifica_sorgente
Special_name_formatters=Formattazioni_speciali_dei_nomi
+
Special_table_columns=Colonne_di_tabella_speciali
+
Starting_import=Inizio_importazione
+
Statically_group_entries_by_manual_assignment=Raggruppa_manualmente_le_voci
+
Status=Stato
+
Stop=Arresta
+
Store_journal_abbreviations=Registra_le_abbreviazioni_delle_riviste
+
Stored_entry=Voce_registrata
+
Strings=Stringa
+
Strings_for_database=Stringhe_per_il_database
+
Subdatabase_from_AUX=Subdatabase_da_file_LaTeX_AUX
-Switches_between_full_and_abbreviated_journal_name_if_the_journal_name_is_known.=Alterna_nomi_completi_e_nomi_abbreviati_per_le_riviste_delle_quali_\u00e8_noto_il_nome.
+
+Switches_between_full_and_abbreviated_journal_name_if_the_journal_name_is_known.=Alterna_nomi_completi_e_nomi_abbreviati_per_le_riviste_delle_quali_è_noto_il_nome.
Synchronize_file_links=Sincronizza_il_collegamento_ai_file
+
Synchronizing_file_links...=Sincronizzazione_di_file_collegamenti_in_corso...
+
Table_appearance=Aspetto_della_tabella
+
Table_background_color=Colore_di_sfondo_della_tabella
+
Table_grid_color=Colore_della_griglia_della_tabella
+
Table_text_color=Colore_del_testo_della_tabella
+
Tabname=Nome_della_scheda
Target_file_cannot_be_a_directory.=L'oggetto_deve_essere_un_file,_non_una_cartella.
+
Tertiary_sort_criterion=Criterio_di_ordinamento_terziario
+
Test=Test
+
paste_text_here=Area_di_inserimento_testo
-The_chosen_date_format_for_new_entries_is_not_valid=Il_formato_di_data_scelto_per_le_nuove_voci_non_\u00e8_valido
-The_chosen_encoding_'%0'_could_not_encode_the_following_characters\:=La_codifica_scelta_'%0'_non_pu\u00f2_codificare_i_caratteri_seguenti\:
+The_chosen_date_format_for_new_entries_is_not_valid=Il_formato_di_data_scelto_per_le_nuove_voci_non_è_valido
+
+The_chosen_encoding_'%0'_could_not_encode_the_following_characters\:=La_codifica_scelta_'%0'_non_può_codificare_i_caratteri_seguenti\:
+
the_field_<b>%0</b>=il_campo_<b>%0</b>
-The_file<BR>'%0'<BR>has_been_modified<BR>externally\!=Il_file_<BR>'%0'<BR>_\u00e8_stato_modificato_da_un'applicazione_esterna
-The_group_"%0"_already_contains_the_selection.=Il_gruppo_"%0"_contiene_gi\u00e0_la_selezione.
-The_label_of_the_string_cannot_be_a_number.=L'etichetta_della_stringa_non_pu\u00f2_essere_un_numero.
-The_label_of_the_string_cannot_contain_spaces.=L'etichetta_della_stringa_non_pu\u00f2_contenere_spazi.
-The_label_of_the_string_cannot_contain_the_'\#'_character.=L'etichetta_della_stringa_non_pu\u00f2_contenere_il_carattere_'\#'
+
+The_file<BR>'%0'<BR>has_been_modified<BR>externally\!=Il_file_<BR>'%0'<BR>_è_stato_modificato_da_un'applicazione_esterna
+
+The_group_"%0"_already_contains_the_selection.=Il_gruppo_"%0"_contiene_già_la_selezione.
+
+The_label_of_the_string_cannot_be_a_number.=L'etichetta_della_stringa_non_può_essere_un_numero.
+
+The_label_of_the_string_cannot_contain_spaces.=L'etichetta_della_stringa_non_può_contenere_spazi.
+
+The_label_of_the_string_cannot_contain_the_'\#'_character.=L'etichetta_della_stringa_non_può_contenere_il_carattere_'\#'
+
The_output_option_depends_on_a_valid_import_option.=L'opzione_di_output_dipende_da_una_opzione_di_importazione_valida.
-The_PDF_contains_one_or_several_BibTeX-records.=Il_file_PDF_contiene_uno_o_pi\u00f9_record_BibTeX.
+The_PDF_contains_one_or_several_BibTeX-records.=Il_file_PDF_contiene_uno_o_più_record_BibTeX.
Do_you_want_to_import_these_as_new_entries_into_the_current_database?=Vuoi_importarli_come_nuove_voci_nel_database_corrente?
-The_regular_expression_<b>%0</b>_is_invalid\:=L'espressione_regolare_<b>%0</b>_non_\u00e8_valida\:
+
+The_regular_expression_<b>%0</b>_is_invalid\:=L'espressione_regolare_<b>%0</b>_non_è_valida\:
+
The_search_is_case_insensitive.=La_ricerca_non_distingue_maiuscole_e_minuscole.
+
The_search_is_case_sensitive.=La_ricerca_distingue_maiuscole_e_minuscole.
-The_string_has_been_removed_locally=La_stringa_\u00e8_stata_rimossa_localmente
+
+The_string_has_been_removed_locally=La_stringa_è_stata_rimossa_localmente
+
There_are_possible_duplicates_(marked_with_an_icon)_that_haven't_been_resolved._Continue?=Ci_sono_dei_potenziali_duplicati_(contrassegnati_con_una_icona_'D')_che_non_possono_essere_risolti._Continuare?
-This_entry_has_no_BibTeX_key._Generate_key_now?=Questa_voce_\u00e8_priva_di_una_chiave_BibTeX._Generarla_ora?
-This_entry_is_incomplete=La_voce_\u00e8_incompleta
-This_entry_type_cannot_be_removed.=Questo_tipo_di_voce_non_pu\u00f2_essere_eliminato.
-This_external_link_is_of_the_type_'%0',_which_is_undefined._What_do_you_want_to_do?=Questo_collegamento_\u00e8_di_tipo_'%0',_ancora_indefinito._Cosa_vuoi_fare?
+
+This_entry_has_no_BibTeX_key._Generate_key_now?=Questa_voce_è_priva_di_una_chiave_BibTeX._Generarla_ora?
+
+This_entry_is_incomplete=La_voce_è_incompleta
+
+This_entry_type_cannot_be_removed.=Questo_tipo_di_voce_non_può_essere_eliminato.
+
+This_external_link_is_of_the_type_'%0',_which_is_undefined._What_do_you_want_to_do?=Questo_collegamento_è_di_tipo_'%0',_ancora_indefinito._Cosa_vuoi_fare?
+
This_group_contains_entries_based_on_manual_assignment._Entries_can_be_assigned_to_this_group_by_selecting_them_then_using_either_drag_and_drop_or_the_context_menu._Entries_can_be_removed_from_this_group_by_selecting_them_then_using_the_context_menu.=Questo_gruppo_contiene_voci_assegnate_manualmente._Altre_voci_possono_essere_assegnate_a_questo_gruppo_selezionandole_e_utilizzando_il_menu_contestuale_oppure_trascinandole_nel_gruppo._Le_voci_possono_essere_rimosse_dal_gruppo_selezionandole [...]
+
This_group_contains_entries_whose_<b>%0</b>_field_contains_the_keyword_<b>%1</b>=Questo_gruppo_contiene_voci_in_cui_il_campo_<b>%0</b>__contiene_la_keyword_<b>%1</b>
+
This_group_contains_entries_whose_<b>%0</b>_field_contains_the_regular_expression_<b>%1</b>=Questo_gruppo_contiene_voci_in_cui_il_campo_<b>%0</b>__contiene_l'espressione_regolare_<b>%1</b>
-This_makes_JabRef_look_up_each_file_link_and_check_if_the_file_exists._If_not,_you_will_be_given_options<BR>to_resolve_the_problem.=Per_ciascuno_dei_file_collegamenti,_JabRef_verificher\u00e0_l'esistenza_del_file.<BR>In_caso_negativo_proporr\u00e0_delle_opzioni_per_la_risoluzione_del_problema.
-This_operation_requires_all_selected_entries_to_have_BibTeX_keys_defined.=Per_questa_operazione_\u00e8_necessario_che_tutte_le_voci_selezionate_abbiano_la_chiave_BibTeX_definita
-This_operation_requires_one_or_more_entries_to_be_selected.=Per_questa_operazione_una_o_pi\u00f9_voci_devono_essere_selezionate
+This_makes_JabRef_look_up_each_file_link_and_check_if_the_file_exists._If_not,_you_will_be_given_options<BR>to_resolve_the_problem.=Per_ciascuno_dei_file_collegamenti,_JabRef_verificherà_l'esistenza_del_file.<BR>In_caso_negativo_proporrà_delle_opzioni_per_la_risoluzione_del_problema.
+
+This_operation_requires_all_selected_entries_to_have_BibTeX_keys_defined.=Per_questa_operazione_è_necessario_che_tutte_le_voci_selezionate_abbiano_la_chiave_BibTeX_definita
+
+This_operation_requires_one_or_more_entries_to_be_selected.=Per_questa_operazione_una_o_più_voci_devono_essere_selezionate
+
Toggle_abbreviation=Mostra/Nascondi_l'abbreviazione
Toggle_entry_preview=Mostra/Nascondi_l'anteprima
Toggle_groups_interface=Mostra/Nascondi_l'interfaccia_dei_gruppi
Try_different_encoding=Prova_codifiche_differenti
+
Unabbreviate_journal_names_of_the_selected_entries=Mostra_il_nome_completo_delle_riviste_per_le_voci_selezionate
Unabbreviated_%0_journal_names.=%0_nomi_di_riviste_per_esteso.
+
Unable_to_open_file.=Impossibile_aprire_il_file
-Unable_to_open_link._The_application_'%0'_associated_with_the_file_type_'%1'_could_not_be_called.=Impossibile_aprire_il_collegamento._L'applicazione_'%0'_associata_con_il_tipo_di_file_'%1'_non_pu\u00f2_essere_aperta.
+Unable_to_open_link._The_application_'%0'_associated_with_the_file_type_'%1'_could_not_be_called.=Impossibile_aprire_il_collegamento._L'applicazione_'%0'_associata_con_il_tipo_di_file_'%1'_non_può_essere_aperta.
unable_to_write_to=Impossibile_scrivere_su
Undefined_file_type=Tipo_di_file_non_definito
+
Undo=Annulla
+
Union=Unione
+
Unknown_BibTeX_entries=Voci_BibTeX_sconosciute
-##_check
+
unknown_edit=modifica_sconosciuta
+
Unknown_export_format=Formato_di_esportazione_sconosciuto
+
Unmark_all=Rimuovi_tutti_i_contrassegni
+
Unmark_entries=Rimuovi_i_contrassegni_dalle_voci
+
Unmark_entry=Rimuovi_il_contrassegno_dalla_voce
-Unsupported_version_of_class_%0\:_%1=Versione_non_supportata_della_classe_%0\:_%1
+
untitled=senza_titolo
-##check\:_Alto?
+
Up=Su
+
Update_to_current_column_widths=Aggiorna_la_larghezza_delle_colonne_ai_valori_correnti
+
Updated_group_selection=Selezione_di_gruppo_aggiornata
Upgrade_external_PDF/PS_links_to_use_the_'%0'_field.=Aggiornare_i_collegamenti_esterni_PDF/PS_per_utilizzare_il_campo_'%0'.
Upgrade_file=Aggiornamento_del_file
Upgrade_old_external_file_links_to_use_the_new_feature=Aggiornare_i_vecchi_collegamenti_ai_file_esterni_per_utilizzare_la_nuova_funzione
+
usage=uso
Use_autocompletion_for_the_following_fields=Usa_l'autocompletamento_per_i_seguenti_campi
+
Use_other_look_and_feel=Usa_un_altro_"Look-and-Feel"
Use_regular_expression_search=Ricerca_l'espressione_regolare
+
Username=Username
+
Value_cleared_externally=Valore_cancellato_esternamente
+
Value_set_externally=Valore_impostato_esternamente
+
verify_that_LyX_is_running_and_that_the_lyxpipe_is_valid=verifica_che_LyX_sia_in_esecuzione_e_che_la_lyxpipe_sia_valida
+
View=Visualizza
Vim_server_name=Nome_del_server_Vim
Waiting_for_ArXiv...=In_attesa_di_ArXiv...
+
Warn_about_unresolved_duplicates_when_closing_inspection_window=Avverti_della_presenza_di_doppioni_non_risolti_alla_chiusura_della_finestra_di_ispezione
+
Warn_before_overwriting_existing_keys=Avverti_prima_di_sovrascrivere_chiavi_esistenti
+
Warning=Avvertimento
+
Warnings=Avvertimenti
-web_link=Collegamenti_Internet
+web_link=collegamenti_Internet
What_do_you_want_to_do?=Cosa_vuoi_fare?
+
When_adding/removing_keywords,_separate_them_by=All'aggiunta/rimozione_di_keyword_separarle_con
Will_write_XMP-metadata_to_the_PDFs_linked_from_selected_entries.=Scrive_i_metadati_XMP_nei_file_PDF_collegati_alle_voci_selezionate
+
with=con
+
Write_BibTeXEntry_as_XMP-metadata_to_PDF.=Scrivi_voce_BibTeX_come_metadati_XMP_in_un_file_PDF.
+
Write_XMP=Scrivi_XMP
Write_XMP-metadata=Scrivi_i_metadati_XMP
Write_XMP-metadata_for_all_PDFs_in_current_database?=Scrivere_i_metadati_XMP_per_tutti_i_file_PDF_del_database_corrente?
-
Writing_XMP-metadata...=Scrittura_dei_metadati_XMP...
Writing_XMP-metadata_for_selected_entries...=Scrittura_dei_metadati_XMP_per_le_voci_selezionate
+
Wrote_XMP-metadata=Metadati_XMP_scritti
XMP-annotated_PDF=PDF_con_annotazioni_XMP
XMP_export_privacy_settings=Impostazioni_per_la_riservatezza_dei_dati_XMP_esportati
-
XMP-metadata=Metadati_XMP
XMP-metadata_found_in_PDF\:_%0=Metadati_XMP_trovati_nel_file_PDF\:_%0
You_must_restart_JabRef_for_this_to_come_into_effect.=Riavviare_JabRef_per_rendere_effettiva_la_modifica.
-You_have_changed_the_language_setting.=La_lingua_\u00e8_stata_modificata.
+You_have_changed_the_language_setting.=La_lingua_è_stata_modificata.
+
You_have_changed_the_look_and_feel_setting.=Le_impostazioni_dell'aspetto_dell'applicazione_sono_stati_cambiati.
-You_have_entered_an_invalid_search_'%0'.=\u00c8_stata_inserita_una_ricerca_non_valida_'%0'.
+You_have_entered_an_invalid_search_'%0'.=È_stata_inserita_una_ricerca_non_valida_'%0'.
+
You_must_choose_a_filename_to_store_journal_abbreviations=Scegliere_un_nome_per_il_file_in_cui_registrare_le_abbreviazioni_delle_riviste
+
You_must_restart_JabRef_for_the_new_key_bindings_to_work_properly.=Riavviare_JabRef_per_rendere_operative_le_nuove_assegnazioni_di_tasti.
-Your_new_key_bindings_have_been_stored.=La_nuova_assegnazione_di_tasti_\u00e8_stata_salvata.
-The_following_fetchers_are_available\:=Le_utilit\u00e0_di_ricerca_seguenti_sono_disponibili\:
-Could_not_find_fetcher_'%0'=Impossibile_trovare_l'utilit\u00e0_di_ricerca_'%0'
-Running_query_'%0'_with_fetcher_'%1'.=Esecuzione_della_query_'%0'_con_l'utilit\u00e0_di_ricerca_'%1'.
-Query_'%0'_with_fetcher_'%1'_did_not_return_any_results.=La_query_'%0'_con_l'utilit\u00e0_di_ricerca_'%1'_non_ha_prodotto_alcun_risultato.
+
+Your_new_key_bindings_have_been_stored.=La_nuova_assegnazione_di_tasti_è_stata_salvata.
+
+The_following_fetchers_are_available\:=Le_utilità_di_ricerca_seguenti_sono_disponibili\:
+Could_not_find_fetcher_'%0'=Impossibile_trovare_l'utilità_di_ricerca_'%0'
+Running_query_'%0'_with_fetcher_'%1'.=Esecuzione_della_query_'%0'_con_l'utilità_di_ricerca_'%1'.
+Query_'%0'_with_fetcher_'%1'_did_not_return_any_results.=La_query_'%0'_con_l'utilità_di_ricerca_'%1'_non_ha_prodotto_alcun_risultato.
Move/Rename_file=Sposta/Rinomina_il_file
File_moved=File_spostato
Move_file_failed=Spostamento_del_file_fallito
@@ -843,30 +1404,27 @@ Number_of_entries_successfully_imported=Numero_di_voci_importate_con_successo
Import_canceled_by_user=Importazione_interrotta_dall'utente
Progress\:_%0_of_%1=Stato_d'avanzamento\:_%0_di_%1
Error_while_fetching_from_%0=Errore_durante_la_ricerca_%0
-Fetching_Medline_by_id...=Recupero_da_Medline_per_id...
-Fetching_Medline_by_term...=Recupero_da_Medline_per_termine...
-%0_import_canceled=Importazione_da_%0_annullata
-Please_enter_a_valid_number=Inserire_un_numero_valido
-Please_enter_a_comma_separated_list_of_Medline_IDs_(numbers)_or_search_terms.=Inserire_una_lista_separata_da_virgole_di_ID_Medline_(numeri)_o_termini_di_ricerca.
+Please_enter_a_valid_number=Inserire_un_numero_valido
Show_search_results_in_a_window=Mostra_i_risultati_della_ricerca_in_una_finestra
+Show_global_search_results_in_a_window=Mostra_i_risultati_della_ricerca_globale_in_una_finestra
+Search_in_all_open_databases=Cerca_in_tutti_i_database_aperti
Move_file_to_file_directory?=Spostare_i_file_nella_cartella_dei_file_principale?
Rename_to_'%0'=Rinomina_in_'%0'
-
You_have_changed_the_menu_and_label_font_size.=Sono_state_modificate_le_dimensioni_del_carattere_di_menu_ed_etichette.
-Database_is_protected._Cannot_save_until_external_changes_have_been_reviewed.=Il_database_\u00e8_protetto._Le_modifiche_esterne_devono_evvere_state_riviste_prima_di_poter_salvare.
+Database_is_protected._Cannot_save_until_external_changes_have_been_reviewed.=Il_database_è_protetto._Le_modifiche_esterne_devono_evvere_state_riviste_prima_di_poter_salvare.
Protected_database=Database_protetto
Refuse_to_save_the_database_before_external_changes_have_been_reviewed.=Rifiuta_di_salvare_prima_che_le_modifiche_esterne_siano_state_riviste.
Database_protection=Protezione_del_database
Unable_to_save_database=Impossibile_salvare_il_database
+
BibTeX_key_generator=Generatore_di_chiavi_BibTeX
Unable_to_open_link.=Impossibile_aprire_il_collegamento.
Move_the_keyboard_focus_to_the_entry_table=Sposta_il_cursore_nella_tabella_delle_voci
MIME_type=Tipo_MIME
-This_feature_lets_new_files_be_opened_or_imported_into_an_already_running_instance_of_JabRef<BR>instead_of_opening_a_new_instance._For_instance,_this_is_useful_when_you_open_a_file_in_JabRef<br>from_your_web_browser.<BR>Note_that_this_will_prevent_you_from_running_more_than_one_instance_of_JabRef_at_a_time.=Questa_funzione_permette_l'apertura_o_l'importazione_di_nuovi_file_in_una_istanza_di_JabRef_gi\u00e0_aperta<BR>invece_di_aprirne_una_nuova._Per_esempio,_ci\u00f2_\u00e8_utile_quando_u [...]
-
+This_feature_lets_new_files_be_opened_or_imported_into_an_already_running_instance_of_JabRef<BR>instead_of_opening_a_new_instance._For_instance,_this_is_useful_when_you_open_a_file_in_JabRef<br>from_your_web_browser.<BR>Note_that_this_will_prevent_you_from_running_more_than_one_instance_of_JabRef_at_a_time.=Questa_funzione_permette_l'apertura_o_l'importazione_di_nuovi_file_in_una_istanza_di_JabRef_già_aperta<BR>invece_di_aprirne_una_nuova._Per_esempio,_ciò_è_utile_quando_un_file_viene_ap [...]
Run_fetcher,_e.g._"--fetch\=Medline\:cancer"=Lanciare_una_ricerca,_es._"--fetch=Medline\:cancer"
The_ACM_Digital_Library=ACM_Digital_Library
@@ -874,47 +1432,49 @@ Reset=Reinizializza
Use_IEEE_LaTeX_abbreviations=Usa_le_abbreviazioni_LaTeX_IEEE
The_Guide_to_Computing_Literature=The_Guide_to_Computing_Literature
-When_opening_file_link,_search_for_matching_file_if_no_link_is_defined=All'apertura_di_un_collegamento_ad_un_file,_ricercare_un_file_corrispondente_se_non_ne_\u00e8_definito_uno.
+
+When_opening_file_link,_search_for_matching_file_if_no_link_is_defined=All'apertura_di_un_collegamento_ad_un_file,_ricercare_un_file_corrispondente_se_non_ne_è_definito_uno.
Settings_for_%0=Parametri__per_%0
Mark_entries_imported_into_an_existing_database=Contrassegna_le_voci_importate_in_un_database_preesistente
Unmark_all_entries_before_importing_new_entries_into_an_existing_database=Rimuovi_tutti_i_contrassegni_prima_di_importare_nuove_voci_in_un_database_preesistente
+
Forward=Successivo
Back=Precedente
Sort_the_following_fields_as_numeric_fields=Ordina_i_campi_seguenti_come_campi_numerici
Line_%0\:_Found_corrupted_BibTeX_key.=Riga_%0\:_chiave_BibTeX_corrotta.
Line_%0\:_Found_corrupted_BibTeX_key_(contains_whitespaces).=Riga_%0\:_chiave_BibTeX_corrotta_(contiene_spazi).
Line_%0\:_Found_corrupted_BibTeX_key_(comma_missing).=Riga_%0\:_chiave_BibTeX_corrotta_(virgola_mancante).
-Finished_downloading_full_text_document=Terminato_il_download_del_documento_citato
Full_text_document_download_failed=Fallito_il_download_del_documento_citato
Update_to_current_column_order=Salvare_l'ordine_delle_colonne_attuale
-
+Download_from_URL=Scarica_dall'URL
Rename_field=Rinomina_il_campo
Set/clear/rename_fields=Imposta/svuota/rinomina_i_campi
Rename_field_to=Rinomina_il_campo_in
Move_contents_of_a_field_into_a_field_with_a_different_name=Sposta_il_contenuto_di_un_campo_in_un_campo_con_nome_diverso
+You_can_only_rename_one_field_at_a_time=È_possibile_rinominare_solo_un_campo_per_volta
-You_can_only_rename_one_field_at_a_time=\u00c8_possibile_rinominare_solo_un_campo_per_volta
Remove_all_broken_links=Rimuovere_tutti_i_collegamenti_non_validi
+
Cannot_use_port_%0_for_remote_operation;_another_application_may_be_using_it._Try_specifying_another_port.=Impossibile_utilizzare_la_porta_%0_per_operazioni_remote;_la_porta_potrebbe_essere_in_uso_da_parte_di_un'altra_applicazione._Provare_a_specificare_una_porta_diversa.
Looking_for_full_text_document...=Ricerca_del_documento_citato
Autosave=Salvataggio_automatico
-Prompt_before_recovering_a_database_from_an_autosave_file=Richiedere_conferma_prima_del_recupero_di_un_database_da_un_salvataggio_automatico
-Autosave_interval_(minutes)=Intervallo_di_salvataggio_automatico_(minuti)
-Do_you_want_to_recover_the_database_from_the_autosave_file?=Recuperare_il_database_dal_salvataggio_automatico?
-Recover_from_autosave=Recupero_da_salvataggio_automatico
+A_local_copy_will_be_opened.=Verrà_aperta_una_copia_locale.
+Autosave_local_databases=Salva_automaticamente_i_database_locali
+Automatically_save_the_database_to=Salva_automaticamente_il_database_come
+Please_enter_a_valid_file_path.=Per_favore_inserisci_un_percorso_di_file_valido.
+
Export_in_current_table_sort_order=Esportare_nell'ordine_corrente_della_tabella
Export_entries_in_their_original_order=Esportare_le_voci_nell'ordine_originale
Error_opening_file_'%0'.=Errore_nell'apertura_del_file_'%0'.
-Autosave_of_file_'%0'=Salvataggio_automatico_del_file_'%0'
-Error_opening_autosave_of_'%0'._Trying_to_load_'%0'_instead.=Errore_nell'apertura_del_salvataggio_automatico_di_'%0'._Tentativo_di_apertura_di_'%0'.
+
Formatter_not_found\:_%0=Formattazione_non_trovata\:_%0
Clear_inputarea=Svuota_l'area_di_inserimento
Automatically_set_file_links_for_this_entry=Definire_automaticamente_i_collegamenti_ai_file_per_questa_voce
-Could_not_save,_file_locked_by_another_JabRef_instance.=Impossibile_salvare,_il_file_\u00e8_bloccato_da_un'altra_istanza_di_JabRef.
-File_is_locked_by_another_JabRef_instance.=Il_file_\u00e8_bloccato_da_un'altra_istanza_di_JabRef.
+Could_not_save,_file_locked_by_another_JabRef_instance.=Impossibile_salvare,_il_file_è_bloccato_da_un'altra_istanza_di_JabRef.
+File_is_locked_by_another_JabRef_instance.=Il_file_è_bloccato_da_un'altra_istanza_di_JabRef.
Do_you_want_to_override_the_file_lock?=Vuoi_ignorare_il_blocco_del_file?
File_locked=File_bloccato
Current_tmp_value=Variabile_"tmp"_corrente
@@ -928,36 +1488,31 @@ Enforce_legal_characters_in_BibTeX_keys=Imponi_l'utilizzo_dei_soli_caratteri_con
Save_without_backup?=Salvare_senza_backup?
Unable_to_create_backup=Impossibile_creare_un_backup
-## end note
-
Move_file_to_file_directory=Sposta_il_file_nella_cartella_dei_file
Rename_file_to=Rinomina_il_file_in
-<b>All_Entries</b>_(this_group_cannot_be_edited_or_removed)=<b>Tutte_le_voci</b>_(questo_gruppo_non_pu\u00f2_essere_modificato_o_rimosso)
+<b>All_Entries</b>_(this_group_cannot_be_edited_or_removed)=<b>Tutte_le_voci</b>_(questo_gruppo_non_può_essere_modificato_o_rimosso)
static_group=gruppo_statico
dynamic_group=gruppo_dinamico
refines_supergroup=ridefinisce_il_super-gruppo
includes_subgroups=include_il_super-gruppo
contains=contiene
-search_expression=espressione_di_ricerc
-
-
-
+search_expression=espressione_di_ricerca
Optional_fields_2=Campi_opzionali_2
Waiting_for_save_operation_to_finish=In_attesa_del_termine_del_salvataggio
Resolving_duplicate_BibTeX_keys...=Risoluzione_delle_chiavi_BibTeX_duplicate...
Finished_resolving_duplicate_BibTeX_keys._%0_entries_modified.=Terminata_la_risoluzione_delle_chiavi_BibTeX_duplicate._%0_voci_modificate.
-This_database_contains_one_or_more_duplicated_BibTeX_keys.=Questo_database_contiene_una_o_pi\u00f9_chiavi_BibTeX_duplicate.
+This_database_contains_one_or_more_duplicated_BibTeX_keys.=Questo_database_contiene_una_o_più_chiavi_BibTeX_duplicate.
Do_you_want_to_resolve_duplicate_keys_now?=Vuoi_effettuare_la_risoluzione_delle_chiavi_duplicate_ora?
+
Find_and_remove_duplicate_BibTeX_keys=Trova_e_rimuovi_le_chiavi_BibTeX_duplicate
Expected_syntax_for_--fetch\='<name_of_fetcher>\:<query>'=Sintassi_attesa_per_--fetch='<name_of_fetcher>\:<query>'
Duplicate_BibTeX_key=Chiave_BibTeX_duplicata
Import_marking_color=Colore_per_contrassegnare_le_voci_importate
-
Always_add_letter_(a,_b,_...)_to_generated_keys=Aggiungi_sempre_una_lettera_(a,_b,_...)_alle_chiavi_generate
-Ensure_unique_keys_using_letters_(a,_b,_...)=Assicura_l'unicit\u00e0_delle_chiavi_con_l'uso_di_lettere_(a,_b,_...)
-Ensure_unique_keys_using_letters_(b,_c,_...)=Assicura_l'unicit\u00e0_delle_chiavi_con_l'uso_di_lettere_(b,_c,_...)
+Ensure_unique_keys_using_letters_(a,_b,_...)=Assicura_l'unicità_delle_chiavi_con_l'uso_di_lettere_(a,_b,_...)
+Ensure_unique_keys_using_letters_(b,_c,_...)=Assicura_l'unicità_delle_chiavi_con_l'uso_di_lettere_(b,_c,_...)
Entry_editor_active_background_color=Colore_dello_sfondo_quando_attivo_l'editor_delle_voci
Entry_editor_background_color=Colore_dello_sfondo_dell'editor_delle_voci
Entry_editor_font_color=Colore_del_font_dell'editor_delle_voci
@@ -970,23 +1525,22 @@ User-specific_file_directory=Cartella_dei_file_specifica_dell'utente
Search_failed\:_illegal_search_expression=Ricerca_fallita\:_espressione_di_ricerca_illegale
Show_ArXiv_column=Mostra_la_colonna_ArXiv
Highlight_groups_that_contain_entries_contained_in_any_currently_selected_group=Evidenzia_i_gruppi_contenenti_voci_incluse_in_uno_dei_gruppi_selezionati
-You_must_enter_an_integer_value_in_the_interval_1025-65535_in_the_text_field_for=\u00c8_necessario_inserire_un_intero_nell'intervallo_1025-65535_nel_campo_di_testo_per
-Automatically_open_browse_dialog_when_creating_new_file_link=Apri_automaticamente_la_finestra_di_dialogo_"Sfoglia"_quando_viene_creato_un_nuovo_collegamento_ad_un_file
+You_must_enter_an_integer_value_in_the_interval_1025-65535_in_the_text_field_for=È_necessario_inserire_un_intero_nell'intervallo_1025-65535_nel_campo_di_testo_per
+Automatically_open_browse_dialog_when_creating_new_file_link=Apri_automaticamente_la_finestra_di_dialogo_"Sfoglia"_quando_viene_creato_un_nuovo_collegamento_ad_un_file
Import_metadata_from\:=Importa_i_Metadati_da\:
Choose_the_source_for_the_metadata_import=Scegli_la_sorgente_dei_metadati_da_importare
Create_entry_based_on_XMP_data=Crea_una_nuova_voce_in_base_ai_dati_XMP
Create_blank_entry_linking_the_PDF=Crea_una_voce_vuota_collegata_al_file_PDF
Only_attach_PDF=Allega_solo_il_file_PDF
Title=Titolo
-No_internet_connection.=Nessuna_connessione_a_Internet.
Create_new_entry=Crea_una_nuova_voce
Update_existing_entry=Aggiorna_la_voce_esistente
Autocomplete_names_in_'Firstname_Lastname'_format_only=Autocompletamento_dei_nomi_solo_nel_formato_'Firstname_Lastname'
Autocomplete_names_in_'Lastname,_Firstname'_format_only=Autocompletamento_dei_nomi_solo_nel_formato_'Lastname,_Firstname'
Autocomplete_names_in_both_formats=Autocompletamento_dei_nomi_in_entrambi_i_formati
Marking_color_%0=Colore_di_contrassegno_%0
-The_name_'comment'_cannot_be_used_as_an_entry_type_name.=Il_nome_'comment'_non_pu\u00f2_essere_utilizzato_come_nome_di_tipo_di_voce.
+The_name_'comment'_cannot_be_used_as_an_entry_type_name.=Il_nome_'comment'_non_può_essere_utilizzato_come_nome_di_tipo_di_voce.
You_must_enter_an_integer_value_in_the_text_field_for=Inserire_un_numero_intero_nel_campo_di_testo_per
Send_as_email=Invia_come_email
References=Riferimenti
@@ -995,14 +1549,14 @@ Subject_for_sending_an_email_with_references=Oggetto_per_l'invio_di_email_con_ri
Automatically_open_folders_of_attached_files=Apri_automaticamente_le_cartelle_dei_file_allegati
Create_entry_based_on_content=Crea_una_voce_in_base_al_contenuto
Do_not_show_this_box_again_for_this_import=Non_mostrare_nuovamente_questo_dialogo_per_questa_importazione
-Always_use_this_PDF_import_style_(and_do_not_ask_for_each_import)=Usa_sempre_questa_modalit\u00e0_di_importazione_PDF_(non_chiedere_per_ogni_importazione)
+Always_use_this_PDF_import_style_(and_do_not_ask_for_each_import)=Usa_sempre_questa_modalità_di_importazione_PDF_(non_chiedere_per_ogni_importazione)
Error_creating_email=Errore_nella_creazione_della_email
Entries_added_to_an_email=Voci_aggiunte_ad_un'email
exportFormat=Formato_di_esportazione
Output_file_missing=File_di_output_mancante
No_search_matches.=Nessuna_corrispondenza_per_la_ricerca.
The_output_option_depends_on_a_valid_input_option.=L'opzione_di_output_dipende_da_un'opzione_di_input_valida.
-Default_import_style_for_drag_and_drop_of_PDFs=Modalit\u00e0_di_importazione_predefinita_per_il_drag_and_drop_dei_file_PDF
+Default_import_style_for_drag_and_drop_of_PDFs=Modalità_di_importazione_predefinita_per_il_drag_and_drop_dei_file_PDF
Default_PDF_file_link_action=Azione_predefinita_per_il_collegamento_ai_file_PDF
Filename_format_pattern=Modello_del_formato_dei_nomi_dei_file
Additional_parameters=Parametri_addizionali
@@ -1026,7 +1580,7 @@ Select_Writer_document=Selezionare_il_documento_Writer
Sync_OpenOffice/LibreOffice_bibliography=Sincronizza_la_bibliografia_OpenOffice/LibreOffice
Select_which_open_Writer_document_to_work_on=Selezionare_il_documento_Writer_aperto_su_cui_lavorare
Connected_to_document=Connesso_al_documento
-Insert_a_citation_without_text_(the_entry_will_appear_in_the_reference_list)=Inserire_una_citazione_senza_testo_(la_voce_comparir\u00e0_nella_lista_dei_riferimenti)
+Insert_a_citation_without_text_(the_entry_will_appear_in_the_reference_list)=Inserire_una_citazione_senza_testo_(la_voce_comparirà_nella_lista_dei_riferimenti)
Cite_selected_entries_with_extra_information=Cita_le_voci_selezionate_con_informazioni_aggiuntive
Ensure_that_the_bibliography_is_up-to-date=Assicura_che_la_bibliografia_sia_aggiornata
Your_OpenOffice/LibreOffice_document_references_the_BibTeX_key_'%0',_which_could_not_be_found_in_your_current_database.=Il_tuo_documento_OpenOffice/LibreOffice_fa_riferimento_alla_chiave_BibTeX_'%0',_non_presente_nel_database_corrente.
@@ -1040,47 +1594,45 @@ Path_to_OpenOffice/LibreOffice_directory=Percorso_per_la_cartella_OpenOffice/Lib
Path_to_OpenOffice/LibreOffice_executable=Percorso_per_il_file_eseguibile_OpenOffice/LibreOffice
Path_to_OpenOffice/LibreOffice_library_dir=Percorso_per_la_cartella_della_libreria_OpenOffice/LibreOffice
Connection_lost=Connessione_perduta
-The_paragraph_format_is_controlled_by_the_property_'ReferenceParagraphFormat'_or_'ReferenceHeaderParagraphFormat'_in_the_style_file.=Il_formato_del_paragrafo_\u00e8_controllato_dalle_propriet\u00e0_'ReferenceParagraphFormat'_o_'ReferenceHeaderParagraphFormat'_nel_file_di_stile.
-The_character_format_is_controlled_by_the_citation_property_'CitationCharacterFormat'_in_the_style_file.=Il_formato_del_carattere_\u00e8_controllato_dalla_propriet\u00e0_della_citazione_'CitationCharacterFormat'_nel_file_di_stile.
+The_paragraph_format_is_controlled_by_the_property_'ReferenceParagraphFormat'_or_'ReferenceHeaderParagraphFormat'_in_the_style_file.=Il_formato_del_paragrafo_è_controllato_dalle_proprietà_'ReferenceParagraphFormat'_o_'ReferenceHeaderParagraphFormat'_nel_file_di_stile.
+The_character_format_is_controlled_by_the_citation_property_'CitationCharacterFormat'_in_the_style_file.=Il_formato_del_carattere_è_controllato_dalla_proprietà_della_citazione_'CitationCharacterFormat'_nel_file_di_stile.
Automatically_sync_bibliography_when_inserting_citations=Sincronizza_automaticamente_la_bibliografia_all'inserimento_delle_citazioni
Look_up_BibTeX_entries_in_the_active_tab_only=Ricerca_le_voci_BibTeX_solo_nella_scheda_attiva
Look_up_BibTeX_entries_in_all_open_databases=Ricerca_le_voci_BibTeX_in_tutti_i_database_aperti
Autodetecting_paths...=Autorilevamento_dei_percorsi...
Could_not_find_OpenOffice/LibreOffice_installation=Impossibile_trovare_l'installazione_OpenOffice/LibreOffice
Directories=Cartelle
-Found_more_than_one_OpenOffice/LibreOffice_executable.=Trovati_pi\u00f9_di_un_file_eseguibile_OpenOffice/LibreOffice.
+Found_more_than_one_OpenOffice/LibreOffice_executable.=Trovati_più_di_un_file_eseguibile_OpenOffice/LibreOffice.
Please_choose_which_one_to_connect_to\:=Selezionare_quello_al_quale_connettersi\:
Choose_OpenOffice/LibreOffice_executable=Scegliere_file_eseguibile_OpenOffice/LibreOffice
Select_document=Selezionare_il_documento
Edit_group_membership=Modifica_l'appartenenza_ai_gruppi
HTML_list=Lista_HTML
Click_group_to_toggle_membership_of_selected_entries=Cliccare_sul_gruppo_per_invertire_l'appartenenza_delle_voci_selezionate
-Use_EMACS_23_insertion_string=Usa_la_stringa_di_inserimento_EMACS_23
If_possible,_normalize_this_list_of_names_to_conform_to_standard_BibTeX_name_formatting=Se_possiblile,_normalizzare_questa_lista_di_nomi_in_accordo_con_lo_standard_di_formattazione_dei_nomi_BibTeX
Could_not_open_%0=Impossiblie_aprire_%0
Unknown_import_format=Formato_di_importazione_sconosciuto
Web_search=Ricerca_sul_Web
-
Style_selection=Selezione_dello_stile
-
No_valid_style_file_defined=Nessun_file_di_stile_valido_definito
Choose_pattern=Sceglire_un_modello
Use_the_BIB_file_location_as_primary_file_directory=Utilizza_la_posizione_del_file_BibTeX_come_cartella_dei_file_principale
Could_not_run_the_gnuclient/emacsclient_program._Make_sure_you_have_the_emacsclient/gnuclient_program_installed_and_available_in_the_PATH.=Impossibile_eseguire_il_programma_gnuclient/emacsclient._Assicurarsi_che_il_programma_gnuclient/emacsclient_sia_installato_e_disponibile_nel_PATH.
Built-in_journal_list=Lista_di_riviste_interna
OpenOffice/LibreOffice_connection=Connessione_a_OpenOffice/LibreOffice
-You_can_add_additional_journal_names_by_setting_up_a_personal_journal_list,<br>as_well_as_linking_to_external_journal_lists.=\u00c8_possibile_aggiungere_altri_nomi_di_riviste_creando_una_lista_personale,<BR>oppure_creando_un_collegamento_a_liste_di_riviste_esterne.
+You_can_add_additional_journal_names_by_setting_up_a_personal_journal_list,<br>as_well_as_linking_to_external_journal_lists.=È_possibile_aggiungere_altri_nomi_di_riviste_creando_una_lista_personale,<BR>oppure_creando_un_collegamento_a_liste_di_riviste_esterne.
JabRef_includes_a_built-in_list_of_journal_abbreviations.=JabRef_include_una_lista_interna_di_abbreviazioni_di_nomi_di_riviste.
You_must_select_either_a_valid_style_file,_or_use_one_of_the_default_styles.=Selezionare_un_file_di_stile_valido_oppure_utilizzare_uno_degli_stili_predefiniti.
-This_is_a_simple_copy_and_paste_dialog._First_load_or_paste_some_text_into_the_text_input_area.<br>After_that,_you_can_mark_text_and_assign_it_to_a_BibTeX_field.=Questo_\u00e8_un_semplice_dialogo_di_copia_e_incolla._Prima_carica_o_incolla_il_testo_nell'area_di_inserimento_di_testo.<BR>Quindi_\u00e8_possibile_selezionare_parti_del_testo_e_assegnarle_ai_campi_BibTeX.
+This_is_a_simple_copy_and_paste_dialog._First_load_or_paste_some_text_into_the_text_input_area.<br>After_that,_you_can_mark_text_and_assign_it_to_a_BibTeX_field.=Questo_è_un_semplice_dialogo_di_copia_e_incolla._Prima_carica_o_incolla_il_testo_nell'area_di_inserimento_di_testo.<BR>Quindi_è_possibile_selezionare_parti_del_testo_e_assegnarle_ai_campi_BibTeX.
This_feature_generates_a_new_database_based_on_which_entries_are_needed_in_an_existing_LaTeX_document.=Questa_funzione_genera_un_nuovo_database_basato_sulle_voci_necessarie_in_un_documento_LaTeX_esistente.
-You_need_to_select_one_of_your_open_databases_from_which_to_choose_entries,_as_well_as_the_AUX_file_produced_by_LaTeX_when_compiling_your_document.=\u00c8_necessario_selezionare_uno_dei_database_aperti_da_cui_scegliere_le_voci,_cos\u00ec_come_il_file_AUX_prodotto_da_LaTeX_nel_compilare_il_documento.
+You_need_to_select_one_of_your_open_databases_from_which_to_choose_entries,_as_well_as_the_AUX_file_produced_by_LaTeX_when_compiling_your_document.=È_necessario_selezionare_uno_dei_database_aperti_da_cui_scegliere_le_voci,_così_come_il_file_AUX_prodotto_da_LaTeX_nel_compilare_il_documento.
First_select_entries_to_clean_up.=Selezionare_le_voci_da_ripulire.
Cleanup_entry=Ripulisci_voce
Autogenerate_PDF_Names=Genera_automaticamente_i_nomi_dei_file_PDF
-Auto-generating_PDF-Names_does_not_support_undo._Continue?=La_generazione_automatica_dei_nomi_dei_file_PDF_non_pu\u00f2_essere_annullata._Continuare?
+Auto-generating_PDF-Names_does_not_support_undo._Continue?=La_generazione_automatica_dei_nomi_dei_file_PDF_non_può_essere_annullata._Continuare?
+
Use_full_firstname_whenever_possible=Usa_nome_completo_quando_possibile
Use_abbreviated_firstname_whenever_possible=Usa_nome_abbreviato_quando_possibile
Use_abbreviated_and_full_firstname=Usa_nome_abbreviato_e_completo
@@ -1090,6 +1642,7 @@ Name_format_used_for_autocompletion=Formato_dei_nomi_usato_per_l'autocompletamen
Treatment_of_first_names=Gestione_dei_nomi
Cleanup_entries=Ripulisci_voci
Automatically_assign_new_entry_to_selected_groups=Assegna_automaticamente_la_nuova_voce_ai_gruppi_selezionati
+%0_mode=modalità_%0
Move_DOIs_from_note_and_URL_field_to_DOI_field_and_remove_http_prefix=Sposta_i_DOI_dai_campi_note_e_URL_al_campo_DOI_e_rimuovi_il_prefisso_'http'
Make_paths_of_linked_files_relative_(if_possible)=Rendi_relativi_i_percorsi_dei_file_collegati_(se_possibile)
Rename_PDFs_to_given_filename_format_pattern=Rinomina_i_file_PDF_secondo_il_modello_di_nome_dei_file
@@ -1099,7 +1652,7 @@ Doing_a_cleanup_for_%0_entries...=Ripulitura_per_%0_voci...
No_entry_needed_a_clean_up=Nessuna_voce_necessita_ripulitura
One_entry_needed_a_clean_up=Una_voce_necessita_ripulitura
%0_entries_needed_a_clean_up=%0_voci_necessitano_ripulitura
-%0_mode=modalit\u00e0_%0
+
Error_downloading_file_'%0'=Errore_nel_corso_del_download_del_file_'%0'
Download_failed=Download_fallito
@@ -1107,7 +1660,6 @@ Remove_selected=Rimuovi_la_selezione
Group_tree_could_not_be_parsed._If_you_save_the_BibTeX_database,_all_groups_will_be_lost.=Impossibile_analizzare_l'albero_dei_gruppi._Salvando_il_database_BibTeX_i_gruppi_saranno_persi.
Attach_file=Allega_file
-
Setting_all_preferences_to_default_values.=Imposta_tutte_le_preferenze_ai_valori_predefiniti.
Resetting_preference_key_'%0'=Reimposta_la_chiave_delle_preferenze_'%0'
Unknown_preference_key_'%0'=Chiave_delle_preferenze_sconosciuta_'%0'
@@ -1137,53 +1689,50 @@ BibTeX_entry_creation=Creazione_della_voce_BibTeX
<No_selection>=<Nessuna_selezione>
Unable_to_connect_to_FreeCite_online_service.=Impossibile_connettersi_al_servizio_online_FreeCite.
Parse_with_FreeCite=Analizza_con_FreeCite
-The_current_BibTeX_key_will_be_overwritten._Continue?=La_chiave_BibTeX_corrente_sar\u00e0_sovrascritta._Continuare?
+The_current_BibTeX_key_will_be_overwritten._Continue?=La_chiave_BibTeX_corrente_sarà_sovrascritta._Continuare?
Overwrite_key=Sovrascrivi_chiave
Not_overwriting_existing_key._To_change_this_setting,_open_Options_->_Prefererences_->_BibTeX_key_generator=Le_chiavi_esistenti_non_vengono_sovrascritte._Per_cambiare_questa_impostazione,_aprire_Opzioni_->_Preferenze_->_Generatore_di_chiavi_BibTeX
How_would_you_like_to_link_to_'%0'?=Come_vuoi_collegare_a_'%0'?
BibTeX_key_patterns=Modelli_delle_chiavi_BibTeX
Changed_special_field_settings=Cambiate_le_impostazioni_dei_campi_speciali
-Clear_priority=Azzera_le_priorit\u00e0
-# not sure how to translate 'rank'\: voto, punteggio, valutazione, grado, rango?
+Clear_priority=Azzera_le_priorità
Clear_rank=Azzera_la_valutazione
Enable_special_fields=Abilita_campi_speciali
Five_stars=Cinque_stelle
Four_stars=Quattro_stelle
Help_on_special_fields=Aiuto_sui_campi_speciali
Keywords_of_selected_entries=Parole_chiave_delle_voci_selezionate
-Manage_content_selectors=Gestione_dei_selettori_dei_contenuti
Manage_keywords=Gestione_delle_parole_chiave
-No_priority_information=Nessuna_informazione_di_priorit\u00e0
+No_priority_information=Nessuna_informazione_di_priorità
No_rank_information=Nessuna_informazione_sulla_valutazione
One_star=Una_stella
-Priority=Priorit\u00e0
-Priority_high=Priorit\u00e0_alta
-Priority_low=Priorit\u00e0_bassa
-Priority_medium=Priorit\u00e0_media
-Quality=Qualit\u00e0
+Priority=Priorità
+Priority_high=Priorità_alta
+Priority_low=Priorità_bassa
+Priority_medium=Priorità_media
+Quality=Qualità
Rank=Valutazione
Relevance=Rilevanza
-Set_priority_to_high=Assegna_priorit\u00e0_alta
-Set_priority_to_low=Assegna_priorit\u00e0_bassa
-Set_priority_to_medium=Assegna_priorit\u00e0_media
-Show_priority=Mostra_priorit\u00e0
-Show_quality=Mostra_qualit\u00e0
+Set_priority_to_high=Assegna_priorità_alta
+Set_priority_to_low=Assegna_priorità_bassa
+Set_priority_to_medium=Assegna_priorità_media
+Show_priority=Mostra_priorità
+Show_quality=Mostra_qualità
Show_rank=Mostra_valutazione
Show_relevance=Mostra_rilevanza
Synchronize_with_keywords=Sincronizza_con_le_parole_chiave
Synchronized_special_fields_based_on_keywords=Sincronizzati_i_campi_speciali_in_base_alle_parole_chiave.
Three_stars=Tre_stelle
-# 'toggle' translated as in German translation
Toggle_relevance=Mostra/Nascondi_rilevanza
-Toggle_quality_assured=Mostra/Nascondi_qualit\u00e0
+Toggle_quality_assured=Mostra/Nascondi_qualità
Two_stars=Due_stelle
Update_keywords=Aggiorna_parole_chiave
Write_values_of_special_fields_as_separate_fields_to_BibTeX=Scrivi_i_valori_dei_campi_speciali_come_campi_separati_nelle_voci_BibTeX
You_have_changed_settings_for_special_fields.=Sono_state_modificate_le_impostazioni_per_i_campi_speciali.
-
%0_entries_found._To_reduce_server_load,_only_%1_will_be_downloaded.=Trovate_%0_voci._Per_ridurre_il_carico_sul_server_ne_saranno_scaricate_solo_%1.
-A_string_with_that_label_already_exists=Una_stringa_con_questa_etichetta_esiste_gi\u00e0.
+A_string_with_that_label_already_exists=Una_stringa_con_questa_etichetta_esiste_già.
Connection_to_OpenOffice/LibreOffice_has_been_lost._Please_make_sure_OpenOffice/LibreOffice_is_running,_and_try_to_reconnect.=Perduta_la_connessione_con_OpenOffice/LibreOffice._Assicurarsi_che_OpenOffice/LibreOffice_sia_in_esecuzione_e_provare_a_riconnettersi.
+
Correct_the_entry,_and_reopen_editor_to_display/edit_source.=Correggi_la_voce_e_riapri_l'editor_per_mostrare/modificare_il_codice_sorgente.
Could_not_connect_to_a_running_gnuserv_process._Make_sure_that_Emacs_or_XEmacs_is_running,<BR>and_that_the_server_has_been_started_(by_running_the_command_'server-start'/'gnuserv-start').=Impossibile_la_connessione_a_un_processo_gnuserv_in_esecuzione._Accertarsi_che_Emacs_o_XEmacs_siano_in_esecuzione,<BR>e_che_il_server_sia_stato_avviato_(con_il_comando_'server-start'/'gnuserv-start').
Could_not_connect_to_running_OpenOffice/LibreOffice.=Impossibile_la_connessione_ad_OpenOffice/LibreOffice.
@@ -1191,34 +1740,29 @@ Make_sure_you_have_installed_OpenOffice/LibreOffice_with_Java_support.=Assicurar
If_connecting_manually,_please_verify_program_and_library_paths.=Se_si_effettua_la_connessione_manualmente_verificare_i_percorsi_al_programma_e_alla_libreria.
Error_message\:=Messaggio_di_errore\:
Created_group_"%0".=Creato_il_gruppo_"%0".
-If_a_pasted_or_imported_entry_already_has_the_field_set,_overwrite.=Se_la_voce_incollata_o_importata_ha_il_campo_gi\u00e0_impostato,_sovrascrivere.
+If_a_pasted_or_imported_entry_already_has_the_field_set,_overwrite.=Se_la_voce_incollata_o_importata_ha_il_campo_già_impostato,_sovrascrivere.
Import_metadata_from_PDF=Importa_metadati_dal_file_PDF
Not_connected_to_any_Writer_document._Please_make_sure_a_document_is_open,_and_use_the_'Select_Writer_document'_button_to_connect_to_it.=Non_connesso_ad_alcun_documento_Writer._Assicurarsi_che_un_documento_sia_aperto_e_connetterlo_con_il_bottone_"Selezionare_il_documento_Writer".
Removed_all_subgroups_of_group_"%0".=Eliminati_tutti_i_sottogruppi_del_gruppo_"%0".
-To_disable_the_memory_stick_mode_rename_or_remove_the_jabref.xml_file_in_the_same_folder_as_JabRef.=Per_disabilitare_la_modalit\u00e0_chiavetta_di_memoria_rinominare_o_cancellare_il_file_"jabref.xml"_che_si_trova_nella_cartella_di_installazione_di_JabRef.
-Unable_to_connect._One_possible_reason_is_that_JabRef_and_OpenOffice/LibreOffice_are_not_both_running_in_either_32_bit_mode_or_64_bit_mode.=Impossibile_connettersi._Una_possibile_ragione_\u00e8_il_fatto_che_JabRef_e_OpenOffice/LibreOffice_non_vengono_eseguiti_nella_stessa_modalit\u00e0_a_32_o_64_bit.
+To_disable_the_memory_stick_mode_rename_or_remove_the_jabref.xml_file_in_the_same_folder_as_JabRef.=Per_disabilitare_la_modalità_chiavetta_di_memoria_rinominare_o_cancellare_il_file_"jabref.xml"_che_si_trova_nella_cartella_di_installazione_di_JabRef.
+Unable_to_connect._One_possible_reason_is_that_JabRef_and_OpenOffice/LibreOffice_are_not_both_running_in_either_32_bit_mode_or_64_bit_mode.=Impossibile_connettersi._Una_possibile_ragione_è_il_fatto_che_JabRef_e_OpenOffice/LibreOffice_non_vengono_eseguiti_nella_stessa_modalità_a_32_o_64_bit.
Use_the_following_delimiter_character(s)\:=Usa_i_seguenti_caratteri_di_delimitazione\:
When_downloading_files,_or_moving_linked_files_to_the_file_directory,_prefer_the_BIB_file_location_rather_than_the_file_directory_set_above=Quando_si_scaricano_i_file_o_si_spostano_i_file_collegati,_preferire_la_posizione_del_file_BibTeX_alla_cartella_impostata_sopra.
-Your_style_file_specifies_the_character_format_'%0',_which_is_undefined_in_your_current_OpenOffice/LibreOffice_document.=Il_file_di_stile_specifica_il_formato_di_carattere_"%0"_che_non_\u00e8_tuttavia_definito_nel_documento_OpenOffice/LibreOffice_corrente.
-Your_style_file_specifies_the_paragraph_format_'%0',_which_is_undefined_in_your_current_OpenOffice/LibreOffice_document.=Il_file_di_stile_specifica_il_formato_di_paragrafo_"%0"_che_non_\u00e8_tuttavia_definito_nel_documento_OpenOffice/LibreOffice_corrente.
+Your_style_file_specifies_the_character_format_'%0',_which_is_undefined_in_your_current_OpenOffice/LibreOffice_document.=Il_file_di_stile_specifica_il_formato_di_carattere_"%0"_che_non_è_tuttavia_definito_nel_documento_OpenOffice/LibreOffice_corrente.
+Your_style_file_specifies_the_paragraph_format_'%0',_which_is_undefined_in_your_current_OpenOffice/LibreOffice_document.=Il_file_di_stile_specifica_il_formato_di_paragrafo_"%0"_che_non_è_tuttavia_definito_nel_documento_OpenOffice/LibreOffice_corrente.
Searching...=Ricerca_in_corso...
-You_have_selected_more_than_%0_entries_for_download._Some_web_sites_might_block_you_if_you_make_too_many_rapid_downloads._Do_you_want_to_continue?=Sono_state_selezionate_pi\u00f9_di_%0_voci_da_scaricare._Alcuni_siti_potrebbero_bloccare_la_connessione_se_si_eseguono_scaricamenti_troppo_numerosi_e_rapidi._Continuare?
+You_have_selected_more_than_%0_entries_for_download._Some_web_sites_might_block_you_if_you_make_too_many_rapid_downloads._Do_you_want_to_continue?=Sono_state_selezionate_più_di_%0_voci_da_scaricare._Alcuni_siti_potrebbero_bloccare_la_connessione_se_si_eseguono_scaricamenti_troppo_numerosi_e_rapidi._Continuare?
Confirm_selection=Conferma_la_selezione
-Unknown_DOI\:_'%0'.=DOI_sconosciuto\:_'%0'
Add_{}_to_specified_title_words_on_search_to_keep_the_correct_case=Aggiungere_{}_alle_parole_del_titolo_specificate_per_mantenere_la_corretta_capitalizzazione_nella_ricerca.
Import_conversions=Importare_le_conversioni
Please_enter_a_search_string=Inserire_una_stringa_di_ricerca
Please_open_or_start_a_new_database_before_searching=Aprire_o_creare_un_nuovo_database_prima_di_effettuare_la_ricerca
-An_error_occurred_while_fetching_from_ADS_(%0)\:=Si_\u00e8_verificato_un_errore_durante_il_recupero_da_ADS_(%0)\:
-An_error_occurred_while_parsing_abstract=Si_\u00e8_verificato_un_errore_durante_l'elaborazione_del_riassunto
-Unknown_DiVA_entry\:_'%0'.=Voce_DiVA_sconosciuta\:_'%0'
-Get_BibTeX_entry_from_DiVA=Recupera_la_voce_BibTeX_da_DiVA
Log=Registro
-
Canceled_merging_entries=Accorpamento_delle_voci_cancellato
-Format_units_by_adding_non-breaking_separators_and_keeping_the_correct_case_on_search=Struttura_le_unit\u00e0_aggiungendo_separatori_non_interrompibili_e_conservare_la_corretta_capitalizzazione_per_la_ricerca
+
+Format_units_by_adding_non-breaking_separators_and_keeping_the_correct_case_on_search=Struttura_le_unità_aggiungendo_separatori_non_interrompibili_e_conservare_la_corretta_capitalizzazione_per_la_ricerca
Merge_entries=Accorpa_le_voci
Merged_entries=Accorpate_le_voci_in_una_nuova_e_mantenute_le_vecchie
Merged_entry=Voce_accorpata
@@ -1228,32 +1772,38 @@ Result=Risultato
Show_DOI_first=Mostrare_prima_il_DOI
Show_URL_first=Mostrare_prima_l'URL
Use_Emacs_key_bindings=Utilizza_le_scorciatoie_di_tastiera_di_Emacs
-You_have_to_choose_exactly_two_entries_to_merge.=\u00c8_necessario_selezionare_esattamente_due_voci_da_accorpare.
+You_have_to_choose_exactly_two_entries_to_merge.=È_necessario_selezionare_esattamente_due_voci_da_accorpare.
Update_timestamp_on_modification=Aggiornare_data_e_ora_a_seguito_di_una_modifica
-
All_key_bindings_will_be_reset_to_their_defaults.=Tutte_le_scorciatoie_di_tastiera_saranno_reimpostate_ai_valori_predefiniti.
+
Automatically_set_file_links=Impostazione_automatica_dei_collegamenti_ai_file
Continue?=Continuare?
Resetting_all_key_bindings=Reimpostazione_di_tutte_le_scorciatoie_di_tastiera
-
Hostname=Host
Invalid_setting=Impostazione_non_valida
Network=Rete
Please_specify_both_hostname_and_port=Specificare_sia_il_nome_dell'host_sia_il_numero_della_porta
+Please_specify_both_username_and_password=Specificare_sia_il_nome_utente_che_la_password
+
Use_custom_proxy_configuration=Utilizza_una_configurazione_del_proxy_personalizzata.
+Proxy_requires_authentication=Il_proxy_richiede_un'autenticazione
+Attention\:_Password_is_stored_in_plain_text\!=Attenzione\:_Password_salvata_come_testo_semplice\!
Clear_connection_settings=Reinizializza_i_parametri_di_connessione
Cleared_connection_settings.=Parametri_di_connessione_reinizializzati
+
Rebind_C-a,_too=Riassociare_anche_C-a
+Rebind_C-f,_too=Riassociare_anche_C-f
Show_number_of_elements_contained_in_each_group=Mostra_il_numero_di_elementi_contenuti_in_ciascun_gruppo
Open_folder=Apri_la_cartella
Searches_for_unlinked_PDF_files_on_the_file_system=Cerca_i_file_PDF_non_collegati_nel_filesystem
-
Export_entries_ordered_as_specified=Esporta_le_voci_nell'ordine_specificato
Export_sort_order=Esporta_il_modo_di_ordinamento
+Export_sorting=Esporta_l'ordinamento
Newline_separator=Separatore_di_linea
+
Save_entries_ordered_as_specified=Salva_le_voci_nell'ordine_specificato
Save_sort_order=Salva_il_modo_di_ordinamento
Show_extra_columns=Mostra_le_colonne_supplementari
@@ -1264,7 +1814,6 @@ Move_to_group=Sposta_nel_gruppo
Clear_read_status=Annulla_lo_stato_di_lettura
Convert_to_BibLatex_format_(for_example,_move_the_value_of_the_'journal'_field_to_'journaltitle')=Converti_nel_formato_BibLatex_(per_esempio,_sposta_il_valore_del_campo_'journal'_nel_campo_'journaltitle')
-Could_not_apply_changes.=Impossibile_applicare_le_modifiche.
Deprecated_fields=Campi_obsoleti
Hide/show_toolbar=Mostra/Nascondi_la_barra_degli_strumenti
No_read_status_information=Nessuna_informazione_sullo_stato_di_lettura
@@ -1276,516 +1825,490 @@ Save_selected_as_plain_BibTeX...=Salva_la_selezione_in_formato_BibTeX_base...
Set_read_status_to_read=Imposta_lo_stato_di_lettura_a_'letto'
Set_read_status_to_skimmed=Imposta_lo_stato_di_lettura_a_'scorso'
Show_deprecated_BibTeX_fields=Mostra_i_campi_BibTeX_obsoleti
+
Show_gridlines=Mostra_la_griglia
Show_printed_status=Mostra_lo_stato_di_stampa
Show_read_status=Mostra_lo_stato_di_lettura
Table_row_height_padding=Altezza_delle_righe
-Marked_all_%0_selected_entries=Contrassegnate_tutte_le_'%0'_voci_selezionate
Marked_selected_entry=Contrassegnate_le_voci_selezionate
-Toggle_print_status=Invertito_lo_stato_di_stampa
-Unmarked_all_%0_selected_entries=Rimossi_i_contrassegni_da_tutte_le_'%0'_voci_selezionate
+Marked_all_%0_selected_entries=Contrassegnate_tutte_le_'%0'_voci_selezionate
Unmarked_selected_entry=Rimossi_i_contrassegni_dalle_voci_selezionate
+Unmarked_all_%0_selected_entries=Rimossi_i_contrassegni_da_tutte_le_'%0'_voci_selezionate
+Toggle_print_status=Invertito_lo_stato_di_stampa
+
Unmarked_all_entries=Rimossi_i_contrassegni_da_tutte_voci
Unable_to_find_the_requested_look_and_feel_and_thus_the_default_one_is_used.=Impossibile_trovare_il_'look_and_feel'_richiesto._Viene_utilizzato_quello_predefinito
-Could_not_open_browser.=Impossibile_avviare_il_browser
Opens_JabRef's_GitHub_page=Apri_la_pagina_di_JabRef_su_GitHub
+Could_not_open_browser.=Impossibile_avviare_il_browser
+Please_open_%0_manually.=Per_favore_aprire_%0_manualmente.
+The_link_has_been_copied_to_the_clipboard.=Il_link_è_stato_copiato_negli_appunti.
-Rebind_C-f,_too=Riassociare_anche_C-f
-This_group_contains_all_entries._It_cannot_be_edited_or_removed.=Questo_gruppo_contiene_tutte_le_voci._Non_pu\u00f2_essere_modificato_o_rimosso.
-
-Open_%0_file=
+Open_%0_file=Apri_il_file_%0
-Cannot_delete_file=
-Convert=
-Delete_local_file=
-File_permission_error=
-Help_on_Name_Formatting=
-Normalize_to_BibTeX_name_format=
-Path_to_%0=Percorso_per_%0
+Cannot_delete_file=Non_posso_cancellare_il_file
+File_permission_error=Errore_nei_permessi_del_file
Push_to_%0=Invia_a_%0
-
-Add_new_file_type=
-Follow_DOI_or_URL_link_and_try_to_locate_PDF_full_text_document=
-Left_entry=
-No_information_added=
-Original_entry=
-Replace_original_entry=
-Right_entry=
-Select_at_least_one_entry_to_manage_keywords.=
-Use=
+Path_to_%0=Percorso_per_%0
+Convert=Converti
+Normalize_to_BibTeX_name_format=Normalizza_al_formato_di_nome_di_BibTeX
+Help_on_Name_Formatting=Aiuto_sulla_Formattazione_dei_Nomi
+
+Add_new_file_type=Aggiungi_un_nuovo_tipo_di_file
+
+Left_entry=Voce_di_sinistra
+Right_entry=Voce_di_destra
+Use=Uso
+Original_entry=Voce_originale
+Replace_original_entry=Rimpiazza_il_voce_originale
+No_information_added=Non_è_stata_aggiunta_alcuna_informazione
+Select_at_least_one_entry_to_manage_keywords.=Seleziona_almeno_una_voce_per_gestire_le_parole_chiave
+OpenDocument_text=Testo_di_OpenDocument
+OpenDocument_spreadsheet=Foglio_di_calcolo_di_OpenDocument
+OpenDocument_presentation=Presentazione_di_OpenDocument
+%0_image=immagine_%0
+Added_entry=Voce_aggiunta
+Modified_entry=Voce_modificata
+Deleted_entry=Voce_cancellata
+Modified_groups_tree=Albero_dei_gruppi_modificato
+Removed_all_groups=Cancellati_tutti_i_gruppi
+Accepting_the_change_replaces_the_complete_groups_tree_with_the_externally_modified_groups_tree.=Accettando_le_modifiche_si_sovrascriver_à_l'albero_dei_gruppi_con_quello_modificato_esternamente.
+Select_export_format=Selezionare_il_formato_di_esportazione
+Return_to_JabRef=Ritorna_a_JabRef
+Please_move_the_file_manually_and_link_in_place.=Per_favore_sposta_il_file_manualmente_e_collegalo_al_suo_posto.
+Could_not_connect_to_%0=Impossibile_la_connessione_a_%0
+Warning\:_%0_out_of_%1_entries_have_undefined_BibTeX_key.=Attenzione\:_%0_di_%1_campi_hanno_chiavi_BibTeX_non_definite.
+occurrence=occorrenza
+Added_new_'%0'_entry.=Aggiunta_la_nuova_voce_'%0'.
+Multiple_entries_selected._Do_you_want_to_change_the_type_of_all_these_to_'%0'?=Selezione_multipla._Vuoi_cambiare_il_tipo_di_tutti_questi_in_'%0'?
Changed_type_to_'%0'_for=Tipo_cambiato_in_'%0'_per
-Database_'%0'_has_changed.=Il_database_'%0'_\u00e8_stato_modificato.
+Really_delete_the_selected_entry?=Cancellare_veramente_la_voce_selezionata?
+Really_delete_the_%0_selected_entries?=Cancellare_veramente_le_%0_voci_selezionate?
+Keep_merged_entry_only=Tieni_solo_i_voci_accorpate
+Keep_left=Tieni_quelli_di_sinistra
+Keep_right=Tieni_quelli_di_destra
+Old_entry=Voce_vecchia
+From_import=Dall'importazione
+No_problems_found.=Nessun_problema_trovato.
+%0_problem(s)_found=%0_problemi_trovati
+Save_changes=Salva_le_modifiche
+Discard_changes=Scarta_le_modifiche
+Database_'%0'_has_changed.=Il_database_'%0'_è_stato_modificato.
+Print_entry_preview=Stampa_l'anteprima_della_voce
Copy_\\cite{BibTeX_key}=Copia_\\cite{chiave_BibTeX}
Copy_BibTeX_key_and_title=Copia_la_chiave_BibTeX_ed_il_titolo
File_rename_failed_for_%0_entries.=Rinominazione_dei_file_fallita_per_%0_voci.
To_set_up,_go_to=Per_configurare_vedi
-Search_%0=Ricerca_%0
+Merged_BibTeX_source_code=Codice_sorgente_BibTeX_accorpato
Invalid_DOI\:_'%0'.=DOI_non_valido\:_'%0'.
-Could_not_connect_to_%0=Impossibile_la_connessione_a_%0
+should_start_with_a_name=deve_cominciare_con_un_nome
+should_end_with_a_name=deve_finire_con_un_nome
+unexpected_closing_curly_bracket=parentesi_graffa_chiusa_inaspettata
+unexpected_opening_curly_bracket=parentesi_graffa_aperta_inaspettata
+capital_letters_are_not_masked_using_curly_brackets_{}=le_maiuscole_grandi_non_vengono_nascoste_con_le_parentesi_graffe_{}
+should_contain_a_four_digit_number=deve_contenere_un_numero_di_quattro_cifre
+should_contain_a_valid_page_number_range=deve_contenere_un_intervallo_valido_di_numeri_di_pagina
+Filled=Riempito
+Field_is_missing=Campo_mancante
+Search_%0=Ricerca_%0
-%0_image=
-%0_problem(s)_found=
-'%0'_is_not_a_valid_ADS_bibcode.=
-Accepting_the_change_replaces_the_complete_groups_tree_with_the_externally_modified_groups_tree.=
-Added_entry=
-Added_new_'%0'_entry.=
-Deleted_entry=
-Discard_changes=
-Donate_to_JabRef=
-Export_with_selected_format=
-Field_is_missing=
-Filled=
-From_import=
-Keep_left=
-Keep_merged_entry_only=
-Keep_right=
-Merged_BibTeX_source_code=
-Modified_entry=
-Modified_groups_tree=
-Multiple_entries_selected._Do_you_want_to_change_the_type_of_all_these_to_'%0'?=
-No_problems_found.=
-Old_entry=
-OpenDocument_presentation=
-OpenDocument_spreadsheet=
-OpenDocument_text=
-Please_move_the_file_manually_and_link_in_place.=
-Print_entry_preview=
-Really_delete_the_%0_selected_entries?=
-Really_delete_the_selected_entry?=
-Removed_all_groups=
-Return_to_JabRef=
-Save_changes=
-Select_export_format=
-Warning\:_%0_out_of_%1_entries_have_undefined_BibTeX_key.=
-large_capitals_are_not_masked_using_curly_brackets_{}=
-occurrence=
-should_contain_a_four_digit_number=
-should_contain_a_valid_page_number_range=
-should_end_with_a_name=
-should_start_with_a_name=
-unexpected_closing_curly_bracket=
-unexpected_opening_curly_bracket=
-
-Advanced_search_active.=
-Found_%0_results.=
-No_results_found.=
-Normal_search_active.=
-Search_globally=
-Search_in_all_open_databases=
-Search_results_in_all_databases_for_%0=
-Search_results_in_database_%0_for_%1=
-This_search_contains_entries_in_which=
-This_search_contains_entries_in_which_any_field_contains_the_regular_expression_<b>%0</b>=
-This_search_contains_entries_in_which_any_field_contains_the_term_<b>%0</b>=
-plain_text=
-
-Attention\:_Password_is_stored_in_plain_text\!=
-Please_specify_both_username_and_password=
-Proxy_requires_authentication=
-
-An_autosave_file_was_found_for_this_database._This_could_indicate_that_JabRef_did_not_shut_down_cleanly_last_time_the_file_was_used.=
-Note\:_A_full_text_search_is_currently_not_supported_for_%0=
-Unable_to_autodetect_OpenOffice/LibreOffice_installation._Please_choose_the_installation_directory_manually.=
-
-JabRef_no_longer_supports_'ps'_or_'pdf'_fields.<br>File_links_are_now_stored_in_the_'file'_field_and_files_are_stored_in_an_external_file_directory.<br>To_make_use_of_this_feature,_JabRef_needs_to_upgrade_file_links.<br><br>=
-This_database_uses_outdated_file_links.=
-
-Clear_search=
-Close_database=
-Close_entry_editor=
-Decrease_table_font_size=
-Entry_editor,_next_entry=
-Entry_editor,_next_panel=
-Entry_editor,_next_panel_2=
-Entry_editor,_previous_entry=
-Entry_editor,_previous_panel=
-Entry_editor,_previous_panel_2=
-Entry_editor,_store_field=
-File_list_editor,_move_entry_down=
-File_list_editor,_move_entry_up=
-Focus_entry_table=
-Import_into_current_database=
-Import_into_new_database=
-Increase_table_font_size=
-New_article=
-New_book=
-New_entry=
-New_from_plain_text=
-New_inbook=
-New_mastersthesis=
-New_phdthesis=
-New_proceedings=
-New_unpublished=
-Next_tab=
-Preamble_editor,_store_changes=
-Previous_tab=
-Push_to_application=
-Refresh_OpenOffice/LibreOffice=
-Resolve_duplicate_BibTeX_keys=
-Save_all=
-String_dialog,_add_string=
-String_dialog,_remove_string=
-Switch_preview_layout=
-Synchronize_files=
-Unabbreviate=
-
-should_contain_a_protocol=
-
-Copy_preview=
-
-Automatically_setting_file_links=
-Regenerating_BibTeX_keys_according_to_metadata=
-No_meta_data_present_in_BIB_file._Cannot_regenerate_BibTeX_keys=
-
-Regenerate_all_keys_for_the_entries_in_a_BibTeX_file=
-
-Show_debug_level_messages=
-
-Export_sorting=
-
-New_%0_database=
-
-New_%0_database_created.=
-
-No_entry_found_for_ISBN_%0_at_www.ebook.de=
-
-Save_actions=
-Enable_save_actions=
-Always_reformat_BIB_file_on_save_and_export=
-
-Default_bibliography_mode=
-
-
-Show_only_preferences_deviating_from_their_default_value=
-default=
-key=
-type=
-value=
-
-Show_preferences=
-
-
-Other_fields=
-Show_remaining_fields=
-
-link_should_refer_to_a_correct_file_path=
-
-abbreviation_detected=
-wrong_entry_type_as_proceedings_has_page_numbers=
-
-Abbreviate_journal_names=
-Abbreviating...=
-Adding_fetched_entries=
-Display_keywords_appearing_in_ALL_entries=
-Display_keywords_appearing_in_ANY_entry=
-Fetching_entries_from_Inspire=
-None_of_the_selected_entries_have_BibTeX_keys.=
-Unabbreviate_journal_names=
-Unabbreviating...=
-Usage=
-
-Are_you_sure_you_want_to_reset_all_settings_to_default_values?=
-Reset_preferences=
-
-Ill-formed_entrytype_comment_in_BIB_file=
-Clipboard=
-Could_not_paste_entry_as_text\:=
-Do_you_still_want_to_continue?=
-This_action_will_modify_the_following_field(s)_in_at_least_one_entry_each\:=
-This_could_cause_undesired_changes_to_your_entries.=
-
-Disable_highlight_groups_matching_entries=
-Run_field_formatter\:=
-
-Adds_{}_brackets_around_acronyms,_month_names_and_countries_to_preserve_their_case.=
-Converts_units_to_LaTeX_formatting.=
-Does_nothing.=
-
-
-Table_font_size_is_%0=
-
-Move_linked_files_to_default_file_directory_%0=
-
-Internal_style=
-Add_style_file=
-Are_you_sure_you_want_to_remove_the_style?=
-Current_style_is_'%0'=
-Remove_style=
-Select_one_of_the_available_styles_or_add_a_style_file_from_disk.=
-You_must_select_a_valid_style_file.=
-
-Reload=
-
-Capitalize=
-Capitalize_all_words,_but_converts_articles,_prepositions,_and_conjunctions_to_lower_case.=
-Capitalize_the_first_word,_changes_other_words_to_lower_case.=
-Changes_all_letters_to_lower_case.=
-Changes_all_letters_to_upper_case.=
-Changes_the_first_letter_of_all_words_to_capital_case_and_the_remaining_letters_to_lower_case.=
-Cleans_up_LaTeX_code.=
-Converts_HTML_code_to_LaTeX_code.=
-Converts_LaTeX_encoding_to_Unicode_characters.=
-Converts_Unicode_characters_to_LaTeX_encoding.=
-Converts_ordinals_to_LaTeX_superscripts.=
-HTML_to_LaTeX=
-LaTeX_cleanup=
-LaTeX_to_Unicode=
-Lower_case=
-Minify_list_of_person_names=
-Normalize_date=
-Normalize_month=
-Normalize_month_to_BibTeX_standard_abbreviation.=
-Normalize_names_of_persons=
-Normalize_page_numbers=
-Normalize_pages_to_BibTeX_standard.=
-Normalizes_lists_of_persons_to_the_BibTeX_standard.=
-Normalizes_the_date_to_ISO_date_format.=
-Ordinals_to_LaTeX_superscript=
-Protect_terms=
-Remove_enclosing_braces=
-Removes_braces_encapsulating_the_complete_field_content.=
-Sentence_case=
-Shortens_lists_of_persons_if_there_are_more_than_2_persons_to_"et_al.".=
-Title_case=
-Unicode_to_LaTeX=
-Units_to_LaTeX=
-Upper_case=
-Identity=
-
-Clears_the_field_completely.=
-Directory_not_found=
-Main_file_directory_not_set\!=
-
-This_operation_requires_exactly_one_item_to_be_selected.=
-
-Importing_in_%0_format=
-
-Female_name=
-Female_names=
-Male_name=
-Male_names=
-Mixed_names=
-Neuter_name=
-Neuter_names=
-
-
-
-Lookup_DOI=
-
-Audio_CD=
-British_patent=
-British_patent_request=
-Candidate_thesis=
-Collaborator=
-Column=
-Compiler=
-Continuator=
-Data_CD=
-Editor=
-European_patent=
-European_patent_request=
-Founder=
-French_patent=
-French_patent_request=
-German_patent=
-German_patent_request=
-Line=
-Master's_thesis=
-Page=
-Paragraph=
-Patent=
-Patent_request=
-PhD_thesis=
-Redactor=
-Research_report=
-Reviser=
-Section=
-Software=
-Technical_report=
-U.S._patent=
-U.S._patent_request=
-Verse=
-
-change_entries_of_group=
-odd_number_of_unescaped_'\#'=
-Plain_text=
-Show_diff=
-character=
-word=
-
-Show_symmetric_diff=
-
-HTML_encoded_character_found=
-
-booktitle_ends_with_'conference_on'=
-All_external_files=
-
-OpenOffice/LibreOffice_integration=
-
-incorrect_control_digit=
-incorrect_format=
-
-Expected_"%0"_to_contain_whitespace=
-Syntax_error_in_regular-expression_pattern=
-
-Copy_version_to_clipboard=
-Copied_version_to_clipboard=
-BibTeX_key=
-Message=
-
-Get_fulltext=
-
-Download_from_URL=
-
-Decryption_not_supported.=
+Search_results_in_all_databases_for_%0=Risultati_della_ricerca_di_%0_in_tutti_i_database
+Search_results_in_database_%0_for_%1=Risultati_della_ricerca_di_%1_nel_database_%0
+Search_globally=Ricerca_globale
+No_results_found.=Nessun_risultato_trovato.
+Found_%0_results.=Trovati_%0_risultati.
+Advanced_search_active.=Ricerca_avanzata_attiva.
+Normal_search_active.=Ricerca_normale_attiva.
+plain_text=Testo_semplice
+This_search_contains_entries_in_which_any_field_contains_the_regular_expression_<b>%0</b>=Questa_ricerca_contiene_occorrenze_in_cui_qualsiasi_campo_contiene_l'espressione_regolare_<b>%0</b>
+This_search_contains_entries_in_which_any_field_contains_the_term_<b>%0</b>=Questa_ricerca_contiene_occorrenze_in_cui_qualsiasi_campo_contiene_il_termine_<b>%0</b>
+This_search_contains_entries_in_which=Questa_ricerca_contiene_occorrenze_in_cui
+
+Unable_to_autodetect_OpenOffice/LibreOffice_installation._Please_choose_the_installation_directory_manually.=Non_sono_in_grado_di_rilevare_l'installazione_di_OpenOffice/LibreOffice._Scegliere_la_cartella_di_installazione_manualmente.
+JabRef_no_longer_supports_'ps'_or_'pdf'_fields.<br>File_links_are_now_stored_in_the_'file'_field_and_files_are_stored_in_an_external_file_directory.<br>To_make_use_of_this_feature,_JabRef_needs_to_upgrade_file_links.<br><br>=JabRef_non_supporta_più_campi_'ps'_o_'pdf'.<br>I_link_ai_file_sono_salvati_ora_nei_campi_'file'_e_i_file_sono_salvati_in_una_cartella_esterna.<br>Per_usare_questa_funzione_JabRef_ha_bisogno_di_aggiornare_i_link_ai_file.<br><br>
+This_database_uses_outdated_file_links.=Questo_database_usa_vecchi_link_a_file.
+
+Clear_search=Cancella_la_ricerca
+Close_database=Chiudi_il_database
+Close_entry_editor=Chiudi_l'editor_della_voce
+Decrease_table_font_size=Decrementa_la_grandezza_del_carattere_della_tavola
+Entry_editor,_next_entry=Editor_della_voce,_voce_successiva
+Entry_editor,_next_panel=Editor_della_voce,_pannello_successivo
+Entry_editor,_next_panel_2=Editor_della_voce,_pannello_successivo_2
+Entry_editor,_previous_entry=Editor_della_voce,_voce_precedente
+Entry_editor,_previous_panel=Editor_della_voce,_pannello_precedente
+Entry_editor,_previous_panel_2=Editor_della_voce,_pannello_precedente_2
+Entry_editor,_store_field=Editor_della_voce,_campo_accumulatore
+File_list_editor,_move_entry_down=Editor_di_liste_di_file,_sposta_la_voce_in_giù
+File_list_editor,_move_entry_up=Editor_di_liste_di_file,_sposta_la_voce_in_su
+Focus_entry_table=Sposta_il_fuoco_sulla_tavola_della_voce
+Import_into_current_database=Importa_nel_database_corrente
+Import_into_new_database=Importa_in_un_nuovo_database
+Increase_table_font_size=Incremente_la_grandezza_del_carattere_della_tavola
+New_article=Nuovo_articolo
+New_book=Nuovo_libro
+New_entry=Nuova_voce
+New_from_plain_text=Nuovo_da_testo_libero
+New_inbook=Nuovo_in_libro
+New_mastersthesis=Nuova_tesi_di_master
+New_phdthesis=Nuova_tesi_di_dottorato
+New_proceedings=Nuovi_atti_di_congresso
+New_unpublished=Nuovo_non_pubblicato
+Next_tab=Scheda_successiva
+Preamble_editor,_store_changes=Editor_di_preambolo
+Previous_tab=Scheda_precedente
+Push_to_application=Manda_all'applicazione
+Refresh_OpenOffice/LibreOffice=Ricarica_OpenOffice/LibreOffice
+Resolve_duplicate_BibTeX_keys=Risolvi_duplicazione_chiavi_BibTeX
+Save_all=Salva_tutto
+String_dialog,_add_string=Dialogo_stringhe,_aggiungi_una_stringa
+String_dialog,_remove_string=Dialogo_stringhe,_cancella_una_stringa
+Synchronize_files=Sincronizza_file
+Unabbreviate=Togli_abbreviazioni
+should_contain_a_protocol=deve_contenere_un_protocollo
+Copy_preview=Copia_l'anteprima
+Automatically_setting_file_links=Seleziona_automaticamente_i_collegamenti_ai_file
+Regenerating_BibTeX_keys_according_to_metadata=Rigenera_le_chiavi_BibTeX_secondo_i_metadati
+No_meta_data_present_in_BIB_file._Cannot_regenerate_BibTeX_keys=Non_ci_sono_meta_nel_fil_BIB._Non_posso_rigenerare_le_chiavi_BibTeX
+Regenerate_all_keys_for_the_entries_in_a_BibTeX_file=Rigenera_tutte_le_chiavi_per_i_campi_di_un_file_BibTeX
+Show_debug_level_messages=Mostra_i_messaggi_del_livello_di_debug
+Default_bibliography_mode=Modalità_bibliografica_predefinita
+New_%0_database_created.=Creato_il_nuovo_database_%0.
+Show_only_preferences_deviating_from_their_default_value=Mostra_solo_le_preferenze_diverse_dai_valori_predefiniti
+default=predefinito
+key=chiave
+type=tipo
+value=valore
+Show_preferences=Mostra_preferenze
+Save_actions=Salva_azioni
+Enable_save_actions=Abilita_il_salvataggio_delle_azioni
+
+Other_fields=Altri_campi
+Show_remaining_fields=Mostra_i_campi_rimanenti
+
+link_should_refer_to_a_correct_file_path=il_link_deve_riferirsi_ad_un_percorso_file_corretto
+abbreviation_detected=rilevata_abbreviazione
+wrong_entry_type_as_proceedings_has_page_numbers=tipo_di_voce_sbagliata_perché_ha_numeri_di_pagina
+Abbreviate_journal_names=Nomi_di_rivista_abbreviati
+Abbreviating...=Applico_le_abbreviazioni
+Adding_fetched_entries=Aggiungo_le_voci_estratte
+Display_keywords_appearing_in_ALL_entries=Mostra_le_parole_chiave_che_compaiono_in_TUTTI_le_voci
+Display_keywords_appearing_in_ANY_entry=Mostra_le_parole_chiave_che_compaiono_in_QUALSIASI_voce
+Fetching_entries_from_Inspire=Estrae_le_voci_da_Inspire
+None_of_the_selected_entries_have_BibTeX_keys.=Nessuno_delle_voci_selezionate_ha_chiavi_BibTeX.
+Unabbreviate_journal_names=Nomi_di_rivista_senza_abbreviazione
+Unabbreviating...=Elimino_le_abbreviazioni
+Usage=Uso
+
+
+Adds_{}_brackets_around_acronyms,_month_names_and_countries_to_preserve_their_case.=Aggiungi_parentesi_graffe_{}_intorno_ad_acronimi,_nomi_di_mesi_e_nazioni_per_preservare_maiuscole/minuscole.
+Are_you_sure_you_want_to_reset_all_settings_to_default_values?=Sei_sicuro_di_voler_riportare_tutte_le_preferenze_ai_propri_valori_predefiniti?
+Reset_preferences=Reimposta_le_preferenze
+Ill-formed_entrytype_comment_in_BIB_file=Commento_nel_tipo_di_voce_malformato_nel_file_BIB
+
+Move_linked_files_to_default_file_directory_%0=Sposta_i_collegamenti_ai_file_nella_cartella_predefinita
+
+Clipboard=Appunti
+Could_not_paste_entry_as_text\:=Non_posso_incollare_la_voce_come_testo\:
+Do_you_still_want_to_continue?=Vuoi_ancora_continuare?
+This_action_will_modify_the_following_field(s)_in_at_least_one_entry_each\:=Questa_azione_modificherà_i_seguenti_campi_per_almeno_una_voce_ciascuno\:
+This_could_cause_undesired_changes_to_your_entries.=Questo_potrebbe_causare_modifiche_indesiderate_alle_tue_voci.
+Run_field_formatter\:=Fa_andare_il_formattatore_di_campo\:
+Table_font_size_is_%0=La_grandezza_del_carattere_\e00e8_%0
+%0_import_canceled=Importazione_da_%0_annullata
+Internal_style=Stile_interno
+Add_style_file=Aggiungi_file_di_stile
+Are_you_sure_you_want_to_remove_the_style?=Sei_sicuro_di_voler_rimuovere_lo_stile?
+Current_style_is_'%0'=Lo_stile_corrente_è_'%0'
+Remove_style=Rimuovi_lo_stile
+Select_one_of_the_available_styles_or_add_a_style_file_from_disk.=Seleziona_uno_degli_stili_disponibili_o_aggiungi_uno_stile_dal_disco.
+You_must_select_a_valid_style_file.=Devi_selezionare_un_file_di_stile_valido.
+Reload=Ricarica
+
+Capitalize=Metti_in_maiuscolo_la_prima_lettera
+Capitalize_all_words,_but_converts_articles,_prepositions,_and_conjunctions_to_lower_case.=Metti_in_maiuscolo_la_prima_lettera_di_tutte_le_parole,_ma_converti_articoli_preposizioni_e_congiunzioni_in_minuscolo.
+Capitalize_the_first_word,_changes_other_words_to_lower_case.=Metti_in_maiuscolo_la_prima_lettera_della_prima_parola,_metti_in_minuscolo_tutte_le_altre_parole.
+Changes_all_letters_to_lower_case.=Metti_tutte_le_lettere_in_minuscolo.
+Changes_all_letters_to_upper_case.=Metti_tutte_le_lettere_in_maiuscolo.
+Changes_the_first_letter_of_all_words_to_capital_case_and_the_remaining_letters_to_lower_case.=Metti_in_maiuscolo_la_prima_lettera_di_tutte_le_parole_e_le_altre_in_minuscolo.
+Cleans_up_LaTeX_code.=Pulisci_il_codice_LaTeX.
+Converts_HTML_code_to_LaTeX_code.=Converti_il_codice_HTML_in_LaTeX.
+Converts_HTML_code_to_Unicode.=Converti_il_codice_HTML_in_Unicode.
+Converts_LaTeX_encoding_to_Unicode_characters.=Converti_la_codice_LaTeX_in_caratteri_Unicode.
+Converts_Unicode_characters_to_LaTeX_encoding.=Converti_i_caratteri_Unicode_in_codice_LaTeX.
+Converts_ordinals_to_LaTeX_superscripts.=Converti_gli_ordinali_in_indici_alti_LaTeX.
+Converts_units_to_LaTeX_formatting.=Converti_unità_in_formattazione_LaTeX.
+HTML_to_LaTeX=Da_HTML_a_LaTeX
+LaTeX_cleanup=Pulisci_il_LaTeX
+LaTeX_to_Unicode=Da_LaTeX_a_Unicode
+Lower_case=Minuscolo
+Minify_list_of_person_names=Riduci_la_lista_di_nomi_di_persona
+Normalize_date=Normalizza_la_data
+Normalize_month=Normalizza_il_mese
+Normalize_month_to_BibTeX_standard_abbreviation.=Normalizza_il_mese_secondo_l'abbreviazione_standard_di_BibTeX.
+Normalize_names_of_persons=Normalizza_i_nomi_di_persona
+Normalize_page_numbers=Normalizza_i_numeri_di_pagina
+Normalize_pages_to_BibTeX_standard.=Normalizza_le_pagine_secondo_lo_standard_di_BibTeX.
+Normalizes_lists_of_persons_to_the_BibTeX_standard.=Normalizza_le_liste_di_persone__secondo_lo_standard_di_BibTeX.
+Normalizes_the_date_to_ISO_date_format.=Normalizza_le_date_secondo_il_formato_di_data_ISO
+Ordinals_to_LaTeX_superscript=Da_ordinali_ad_apici_LaTeX
+Protect_terms=Termini_protetti
+Remove_enclosing_braces=Rimuovi_le_parentesi_graffe_interne
+Removes_braces_encapsulating_the_complete_field_content.=Rimuovi_le_parentesi_graffe_che_incapsulano_completamente_il_contenuto_dei_campi.
+Sentence_case=Frase_maiuscola/minuscola
+Shortens_lists_of_persons_if_there_are_more_than_2_persons_to_"et_al.".=Se_ci_sono_più_di_due_persone_in_una_lista,_abbrevia_in_"et_al.".
+Title_case=Titolo_maiuscolo/minuscolo
+Unicode_to_LaTeX=Da_Unicode_a_LaTeX
+Units_to_LaTeX=Da_unità_a_LaTeX
+Upper_case=Maiuscolo
+Does_nothing.=Non_fa_niente.
+Identity=Identità
+Clears_the_field_completely.=Azzera_completamente_il_campo.
+Directory_not_found=Cartella_non_trovata
+Main_file_directory_not_set\!=Cartella_principale_non_selezionata\!
+This_operation_requires_exactly_one_item_to_be_selected.=Per_questa_operazione_devi_selezionare_esattamente_un_elemento.
+Importing_in_%0_format=Importo_nel_formato_%0
+Female_name=Nome_di_donna
+Female_names=Nomi_di_donna
+Male_name=Nome_di_uomo
+Male_names=Nomi_di_uomo
+Mixed_names=Nomi_misti
+Neuter_name=Nome_neutro
+Neuter_names=Nomi_neutri
+
+Lookup_DOI=Cerca_DOI
+
+Audio_CD=CD_Audio
+British_patent=Brevetto_britannico
+British_patent_request=Richiesto_brevetto_britannico
+Candidate_thesis=Tesi_candidata
+Collaborator=Collaboratore
+Column=Colonna
+Compiler=Compilatore
+Continuator=Continuatore
+Data_CD=CD_Dati
+Editor=Editore
+European_patent=Brevetto_europeo
+European_patent_request=Richiesta_di_brevetto_europeo
+Founder=Fondatore
+French_patent=Brevetto_francese
+French_patent_request=Richiesta_di_brevetto_francese
+German_patent=Brevetto_tedesco
+German_patent_request=Richesta_di_brevetto_tedesco
+Line=Riga
+Master's_thesis=Tesi_di_laurea_specialistica
+Page=Pagina
+Paragraph=Paragrafo
+Patent=Brevetto
+Patent_request=Richiesta_di_brevetto
+PhD_thesis=Tesi_di_dottorato
+Redactor=Redattore
+Research_report=Relazione_di_ricerca
+Reviser=Revisore
+Section=Sezione
+Software=Software
+Technical_report=Relazione_tecnica
+U.S._patent=Brevetto_U.S.
+U.S._patent_request=Richiesta_di_brevetto_U.S.
+Verse=Verso
+
+change_entries_of_group=modifica_le_voci_del_gruppo
+odd_number_of_unescaped_'\#'=numero_dispari_di_'\#'_non_marcati
+
+Plain_text=Testo_semplice
+Show_diff=Mostra_differenze
+character=carattere
+word=parola
+Show_symmetric_diff=Mostra_differenze_simmetriche
+
+HTML_encoded_character_found=Trovato_un_carattere_in_codifica_HTML
+booktitle_ends_with_'conference_on'=il_titolo_del_libro_termina_con_'conferenza_su'
+
+All_external_files=Tutti_i_file_esterni
+
+OpenOffice/LibreOffice_integration=integrazione_con_OpenOffice/LibreOffice
+
+incorrect_control_digit=carattere_di_controllo_non_corretto
+incorrect_format=formato_non_corretto
+Copy_version_to_clipboard=Copia_la_versione_negli_appunti
+Copied_version_to_clipboard=Versione_copiata_negli_appunti
+
+BibTeX_key=Chiave_BibTeX
+Message=Messaggio
+Decryption_not_supported.=Decrittografazione_non_supportata.
Cleared_'%0'_for_%1_entries=Reinizializzati_'%0'_per_%1_voce/i
Set_'%0'_to_'%1'_for_%2_entries='%0'_impostata_a_'%1'_per_%2_voce/i
Toggled_'%0'_for_%1_entries=Modificata_la_valutazione_di_'%0'_per_%1_voce/i
-Check_for_updates=
-Download_update=
-New_version_available=
-Installed_version=
-Remind_me_later=
-Ignore_this_update=
-Could_not_connect_to_the_update_server.=
-Please_try_again_later_and/or_check_your_network_connection.=
-To_see_what_is_new_view_the_changelog.=
-A_new_version_of_JabRef_has_been_released.=
-JabRef_is_up-to-date.=
-Latest_version=
-
-Please_open_%0_manually.=
-
-The_link_has_been_copied_to_the_clipboard.=
-
-Online_help_forum=
-
-Custom=
-
-Converts_HTML_code_to_Unicode.=
-
-Open_console=
-Use_default_terminal_emulator=
-Execute_command=
-Note\:_Use_the_placeholder_%0_for_the_location_of_the_opened_database_file.=
-Executing_command_\"%0\"...=
-Error_occured_while_executing_the_command_\"%0\".=
-
-Reformat_ISSN=
-
-Unable_to_generate_new_database=
-
-Export_cited=
-Countries_and_territories_in_English=
-Electrical_engineering_terms=
-Enabled=
-Internal_list=
-Months_and_weekdays_in_English=
-The_text_after_the_last_line_starting_with_\#_will_be_used=
-
-Add_protected_terms_file=
-Are_you_sure_you_want_to_remove_the_protected_terms_file?=
-Remove_protected_terms_file=
-Manage_protected_terms_files=
-
-Add_selected_text_to_list=
-Add_{}_around_selected_text=
-Format_field=
-New_protected_terms_file=
-
-
-change_field_%0_of_entry_%1_from_%2_to_%3=
-change_key_from_%0_to_%1=
-change_string_content_%0_to_%1=
-change_string_name_%0_to_%1=
-change_type_of_entry_%0_from_%1_to_%2=
-insert_entry_%0=
-insert_string_%0=
-remove_entry_%0=
-remove_string_%0=
-
-undefined=
-
-
-Cannot_get_info_based_on_given_%0\:_%1=
-Get_BibTeX_data_from_%0=
-No_%0_found=
-Entry_from_%0=
-
-Merge_entry_with_%0_information=
-Updated_entry_with_info_from_%0=
-Connection=
-Host=
-Port=
-Database=
-User=
-Connection_error=
-Driver_error=
-Connection_to_%0_server_established.=
-Required_field_"%0"_is_empty.=
-
-%0_driver_not_available.=
-
-The_connection_to_the_server_has_been_terminated.=
-
-Connection_lost.=
-Reconnect=
-Work_offline=
-
-Working_offline.=
-
-Update_refused.=
-Update_refused=
-Local_entry=
-Shared_entry=
-Update_could_not_be_performed_due_to_existing_change_conflicts.=
-You_are_not_working_on_the_newest_version_of_BibEntry.=
-Local_version\:_%0=
-Shared_version\:_%0=
-Please_merge_the_shared_entry_with_yours_and_press_"Merge_entries"_to_resolve_this_problem.=
-Canceling_this_operation_will_leave_your_changes_unsynchronized._Cancel_anyway?=
-The_BibEntry_you_currently_work_on_has_been_deleted_on_the_shared_side._Hit_"Keep"_to_recover_the_entry.=
-Cannot_cite_entries_without_BibTeX_keys._Generate_keys_now?=
-New_technical_report=
-
-%0_file=
-Custom_layout_file=
-Protected_terms_file=
-Style_file=
-
-Open_OpenOffice/LibreOffice_connection=
-
-You_must_enter_at_least_one_field_name=
-
-
-Non-ASCII_encoded_character_found=
-
-Toggle_web_search_interface=
-Background_color_for_resolved_fields=
-Color_code_for_resolved_fields=
-%0_files_found=
-%0_of_%1=
-One_file_found=
-The_import_finished_with_warnings\:=
-There_was_one_file_that_could_not_be_imported.=
-There_were_%0_files_which_could_not_be_imported.=
-
-Migration_help_information=
-Entered_database_has_obsolete_structure_and_is_no_longer_supported.=
-However,_a_new_database_was_created_alongside_the_pre-3.6_one.=
-
-Click_here_to_learn_about_the_migration_of_pre-3.6_databases.=
-
-Connecting...=
-Opens_JabRef's_Facebook_page=
-Opens_JabRef's_blog=
-Opens_JabRef's_website=
-
-Opens_a_link_where_the_current_development_version_can_be_downloaded=
-See_what_has_been_changed_in_the_JabRef_versions=
+Check_for_updates=Cerca_degli_aggiornamenti
+Download_update=Scarica_gli_aggiornamenti
+New_version_available=Nuova_versione_disponibile
+Installed_version=Versione_installata
+Remind_me_later=Ricordamelo_dopo
+Ignore_this_update=Ignora_questo_aggiornamento
+Could_not_connect_to_the_update_server.=Non_posso_connettermi_al_server_degli_aggiornamenti.
+Please_try_again_later_and/or_check_your_network_connection.=Prova_più_tardi_e/o_controlla_la_tua_connessione.
+To_see_what_is_new_view_the_changelog.=Per_vedere_cosa_c'è_di_nuovo_controlla_il_changelog
+A_new_version_of_JabRef_has_been_released.=È_stata_rilasciata_una_nuova_versione_di_JabRef.
+JabRef_is_up-to-date.=JabRef_è_aggiornato.
+Latest_version=Ultima_versione
+Online_help_forum=Forum_per_help_online
+Custom=Appopsito
+
+Export_cited=Esporta_citazioni
+Unable_to_generate_new_database=Impossibile_generare_il_nuovo_database
+
+Open_console=Apri_la_console
+Use_default_terminal_emulator=Usa_l'emulatore_di_terminale_predefinito
+Execute_command=Esegui_il_comando
+Note\:_Use_the_placeholder_%0_for_the_location_of_the_opened_database_file.=Nota\:_Usa_il_segnaposto_%0_come_posizione_nel_file_di_database_aperto.
+Executing_command_\"%0\"...=Esegui_il_comando_\"%0\"
+Error_occured_while_executing_the_command_\"%0\".=È_avvenuto_un_errore_eseguendo_il_comando_\"%0\".
+Reformat_ISSN=Riformatta_ISSN
+
+Countries_and_territories_in_English=Paesi_e_territori_in_inglese
+Electrical_engineering_terms=Termini_di_ingegneria_elettrica
+Enabled=Abilitato
+Internal_list=Lista_interna
+Manage_protected_terms_files=Gestisci_file_di_termini_protetti
+Months_and_weekdays_in_English=Mesi_e_giorni_in_inglese
+The_text_after_the_last_line_starting_with_\#_will_be_used=Verrà_usato_il_testo_dopo_l'ultima_riga_che_comincia_con_\#
+Add_protected_terms_file=Aggiungi_un_file_di_termini_protetti
+Are_you_sure_you_want_to_remove_the_protected_terms_file?=Sei_sicuro_di_voler_rimuovere_il_file_di_termini_protetti?
+Remove_protected_terms_file=Rimuovi_il_file_di_termini_protetti
+Add_selected_text_to_list=Aggiungi_il_testo_selezionato_alla_lista
+Add_{}_around_selected_text=Aggiungi_{}_intorno_al_testo_selezionato
+Format_field=Campo_di_formattazione
+New_protected_terms_file=Nuovo_file_di_termini_protetti
+change_field_%0_of_entry_%1_from_%2_to_%3=modifica_il_campo_%0_della_voce_%1_da_%2_a_%3
+change_key_from_%0_to_%1=modifica_la_chiave_da_%0_a_%1
+change_string_content_%0_to_%1=modifica_il_contenuto_della_stringa_da_%0_a_%1
+change_string_name_%0_to_%1=modifica_il_nome_della_stringa_da_%0_a_%1
+change_type_of_entry_%0_from_%1_to_%2=modifica_il_tipo_della_voce_%0_da_%1_a_%2
+insert_entry_%0=inserisci_la_voce_%0
+insert_string_%0=inserisci_la_stringa_%0
+remove_entry_%0=rimuovi_la_voce_%0
+remove_string_%0=rimuovi_la_stringa_%0
+undefined=non_definito
+Cannot_get_info_based_on_given_%0\:_%1=Non_trovo_informazioni_in_base_alla_data_%0\:_%1
+Get_BibTeX_data_from_%0=Preleva_i_dati_BibTeX_da_%0
+No_%0_found=Nessun_%0_trovato
+Entry_from_%0=Voce_da_%0
+Merge_entry_with_%0_information=Accorpa_la_voce_con_l'informazione_%0
+Updated_entry_with_info_from_%0=Aggiornata_la_voce_con_l'informazione_da_%0
+Connection=Connessione
+Connecting...=Connetto...
+Host=Host
+Port=Porta
+Database=Database
+User=Utente
+Connect=Connetto
+Connection_error=Errore_di_connessione
+Connection_to_%0_server_established.=Connessione_al_server_%0_stabilita.
+Required_field_"%0"_is_empty.=Il_campo_obbligatorio_"%0"_è_vuoto.
+%0_driver_not_available.=Driver_%0_non_disponibile.
+The_connection_to_the_server_has_been_terminated.=La_connessione_al_server_è_stata_interrotta.
+Connection_lost.=Connessione_perduta.
+Reconnect=Riconnetto
+Work_offline=Lavora_senza_connessione
+Working_offline.=Senza_connessione.
+Update_refused.=Aggiornamento_rifiutato.
+Update_refused=Aggiornamento_rifiutato
+Local_entry=Voce_locale
+Shared_entry=Voce_condivisa
+Update_could_not_be_performed_due_to_existing_change_conflicts.=L'aggiornamento_non_è_stato_possibile_a_causa_di_un_conflitto_tra_modifiche.
+You_are_not_working_on_the_newest_version_of_BibEntry.=Non_stai_usando_la_versione_più_recente_di_BibEntry.
+Local_version\:_%0=Versione_locale\:_%0
+Shared_version\:_%0=Versione_condivisa\:_%0
+Please_merge_the_shared_entry_with_yours_and_press_"Merge_entries"_to_resolve_this_problem.=Accorpa_la_voce_condivisa_con_la_tua_e_premi_"Accorpa_voci"_per_risolvere_questo_problema.
+Canceling_this_operation_will_leave_your_changes_unsynchronized._Cancel_anyway?=Cancellare_questa_operazione_lascerà_le_modifiche_non_sincronizzate._Cancella_comunque?
+Shared_entry_is_no_longer_present=La_voce_condivisa_non_è_più_presente
+The_BibEntry_you_currently_work_on_has_been_deleted_on_the_shared_side.=La_BibEntry_su_cui_stai_lavorando_è_stata_cancellata_dalla_parte_che_l'ha_condivisa.
+You_can_restore_the_entry_using_the_"Undo"_operation.=Puoi_ripristinare_la_voce_usando_l'"Undo".
+Remember_password?=Devo_ricordare_la_password?
+You_are_already_connected_to_a_database_using_entered_connection_details.=Sei_già_connesso_ad_un_database_con_i_dettagli_di_connessione_specificati.
+
+Cannot_cite_entries_without_BibTeX_keys._Generate_keys_now?=Non_posso_citare_voci_senza_chiavi_BibTeX._Le_genero_ora?
+New_technical_report=Nuovo_rapporto_tecnico
+
+%0_file=file_%0
+Custom_layout_file=File_di_layout_apposito
+Protected_terms_file=File_di_termini_protetti
+Style_file=File_stile
+
+Open_OpenOffice/LibreOffice_connection=Apri_connessione_OpenOffice/LibreOffice
+You_must_enter_at_least_one_field_name=Devi_inserire_almeno_il_nome_di_un_campo
+Non-ASCII_encoded_character_found=Trovato_un_carattere_non_codificato_ASCII
+Toggle_web_search_interface=Inverti_la_selezione_dell'interfaccia_di_ricerca_web
+Background_color_for_resolved_fields=Colore_di_sfondo_per_i_campi_risolti
+Color_code_for_resolved_fields=Codice_di_colore_per_i_campi_risolti
+%0_files_found=Trovati_%0_file
+%0_of_%1=%0_di_%1
+One_file_found=Trovato_un_file
+The_import_finished_with_warnings\:=L'importazione_è_terminata_con_degli_avvisi\:
+There_was_one_file_that_could_not_be_imported.=Un_file_non_è_stato_importato.
+There_were_%0_files_which_could_not_be_imported.=%0_file_non_sono_stati_importati.
+
+Migration_help_information=Informazioni_per_la_migrazione
+Entered_database_has_obsolete_structure_and_is_no_longer_supported.=Il_database_selezionato_ha_una_struttura_obsoleta_e_non_è_più_supportato.
+However,_a_new_database_was_created_alongside_the_pre-3.6_one.=Tuttavia_è_stato_creato_un_nuovo_database_oltre_a_quello_pre-3.6.
+Click_here_to_learn_about_the_migration_of_pre-3.6_databases.=Clicca_qui_per_informazioni_sulla_migrazione_di_database_pre-3.6
+Opens_JabRef's_Facebook_page=Apri_la_pagina_Facebook_di_JabRef
+Opens_JabRef's_blog=Apri_il_blog_di_JabRef
+Opens_JabRef's_website=Apri_il_sito_web_di_JabRef
+Opens_a_link_where_the_current_development_version_can_be_downloaded=Apri_un_collegamento_da_cui_scaricare_la_versione_di_sviluppo
+See_what_has_been_changed_in_the_JabRef_versions=Vedi_cosa_è_cambiato_tra_le_versioni_di_JabRef
+Referenced_BibTeX_key_does_not_exist=La_chiave_BibTeX_a_cui_ci_si_riferisce_non_esiste
+Finished_downloading_full_text_document_for_entry_%0.=Lo_scaricamento_del_testo_completo_del_documento_della_voce_%0_è_terminato.
+Full_text_document_download_failed_for_entry_%0.=Lo_scaricamento_del_testo_completo_del_documento_della_voce_%0_è_fallito
+Look_up_full_text_documents=Cerca_documenti_completi
+You_are_about_to_look_up_full_text_documents_for_%0_entries.=Stai_per_cercare_documenti_completi_per_la_voce_%0.
+last_four_nonpunctuation_characters_should_be_numerals=gli_ultimi_quattro_caratteri_non_di_interpunzione_devono_essere_dei_numerali
+shared=condiviso
+should_contain_an_integer_or_a_literal=deve_contenere_almeno_un_intero_o_una_lettera
+should_have_the_first_letter_capitalized=la_prima_lettera_deve_essere_maiuscola
+
+ID=ID
+ID_type=Tipo_di_ID
+ID-based_entry_generator=Generatore_di_voci_basato_su_ID
+Fetcher_'%0'_did_not_find_an_entry_for_id_'%1'.=Il_collettore_'%0'_non_ha_trovato_una_voce_per_l'id_'%1'
+
+Select_first_entry=Seleziona_la_prima_voce
+Select_last_entry=Seleziona_l'ultima_voce
+
+Invalid_ISBN\:_'%0'.=ISBN_invalido\:'%0'
+should_be_an_integer_or_normalized=dovrebbe_essere_un_intero_o_normalizzato
+should_be_normalized=dovrebbe_essere_normalizzato
+
+Empty_search_ID=ID_della_ricerca_vuoto
+The_given_search_ID_was_empty.=L'ID_della_ricerca_usato_era_vuoto.
+Copy_BibTeX_key_and_link=Copia_la_chiave_e_il_link_BibTeX
+empty_BibTeX_key=chiave_BibTeX_vuota
+BibLaTeX_field_only=campo_solo_BibLaTeX
+
+Error_while_generating_fetch_URL=Errore_generando_l'URL_per_l'estrazione
+Error_while_parsing_ID_list=Errore_analizzando_la_lista_di_ID
+Unable_to_get_PubMed_IDs=Impossibile_prelevare_gli_ID_di_PubMed
+Backup_found=Trovato_il_backup
+A_backup_file_for_'%0'_was_found.=Non_ho_trovato_un_file_di_backup_per_'%0'
+This_could_indicate_that_JabRef_did_not_shut_down_cleanly_last_time_the_file_was_used.=Questo_può_significare_che_HabRef_non_si_è_chiuso_correttamente_l'ultima_volta_che_il_file_è_stato_usato.
+Do_you_want_to_recover_the_database_from_the_backup_file?=Vuoi_recuperare_l'archivio_dal_file_di_backup?
+Firstname_Lastname=Nome_Cognome
+
+Recommended_for_%0=Raccomandato_per_%0
+This_might_be_caused_by_reaching_the_traffic_limitation_of_Google_Scholar_(see_'Help'_for_details).=Questo_può_essere_dovuto_al_raggiungimento_del_limite_di_traffico_di_Google_Scholar_(vedi_'Aiuto'_per_i_dettagli).
+
+Problem_downloading_from_%1=Problema_scaricando_da_%1
+
+File_directory_pattern=
+Update_with_bibliographic_information_from_the_web=Aggiorna_con_informazioni_bibliografiche_dal_web
+
+Could_not_find_any_bibliographic_information.=Non_ho_trovato_informazioni_bibliografiche.
+BibTeX_key_%0_deviates_from_generated_key_%1=Chiave_BibTeX_%0_diversa_dalla_chiave_generata_%1
+DOI_%0_is_invalid=DOI_%0_non_valido
+
+Jump_to_entry=
diff --git a/src/main/resources/l10n/JabRef_ja.properties b/src/main/resources/l10n/JabRef_ja.properties
index 03c8403..370d4a6 100644
--- a/src/main/resources/l10n/JabRef_ja.properties
+++ b/src/main/resources/l10n/JabRef_ja.properties
@@ -1,5 +1,5 @@
#!
-#! created/edited by Popeye version 0.55 (https\://github.com/koppor/popeye)
+#! created/edited by Popeye version 0.55 (github.com/JabRef/popeye)
#! encoding:UTF-8
%0_contains_the_regular_expression_<b>%1</b>=%0には、正規表現<b>%1</b>が含まれています
@@ -12,18 +12,14 @@
%0_export_successful=%0個の書き出しに成功しました
-
%0_matches_the_regular_expression_<b>%1</b>=%0は正規表現<b>%1</b>に一致します
%0_matches_the_term_<b>%1</b>=%0は項目<b>%1</b>に一致します
-<field_name>=<フィールド名>
<HTML>Could_not_find_file_'%0'<BR>linked_from_entry_'%1'</HTML>=<HTML>項目「%1」からリンクされているファイル<BR>「%0」を見つけることができませんでした</HTML>
-
<select>=<選択してください>
-<select_word>=<単語を選択してください>
Abbreviate_journal_names_of_the_selected_entries_(ISO_abbreviation)=選択項目の学術誌名を短縮形にします(ISO式短縮形)
Abbreviate_journal_names_of_the_selected_entries_(MEDLINE_abbreviation)=選択項目の学術誌名を短縮形にします(MEDLINE式短縮形)
@@ -44,13 +40,12 @@ Action=アクション
Add=追加
-Add_a_(compiled)_custom_ImportFormat_class_from_a_class_path.=(コンパイルした)ユーザー定義ImportFormatクラスをクラスパスから追加します。
+Add_a_(compiled)_custom_Importer_class_from_a_class_path.=(コンパイルした)ユーザー定義ImportFormatクラスをクラスパスから追加します。
The_path_need_not_be_on_the_classpath_of_JabRef.=このパスは、JabRefのクラスパスにあるとは限りません。
-Add_a_(compiled)_custom_ImportFormat_class_from_a_ZIP-archive.=(コンパイルした)ユーザー定義ImportFormatクラスをZIP書庫から追加します。
+Add_a_(compiled)_custom_Importer_class_from_a_ZIP-archive.=(コンパイルした)ユーザー定義ImportFormatクラスをZIP書庫から追加します。
The_ZIP-archive_need_not_be_on_the_classpath_of_JabRef.=このZIP書庫は、JabRefのクラスパスにあるとは限りません。
-
Add_entry_selection_to_this_group=選択項目をこのグループに追加
Add_from_folder=フォルダから追加
@@ -76,8 +71,6 @@ Added_string=文字列を追加しました\:
Additionally,_entries_whose_<b>%0</b>_field_does_not_contain_<b>%1</b>_can_be_assigned_manually_to_this_group_by_selecting_them_then_using_either_drag_and_drop_or_the_context_menu._This_process_adds_the_term_<b>%1</b>_to_each_entry's_<b>%0</b>_field._Entries_can_be_removed_manually_from_this_group_by_selecting_them_then_using_the_context_menu._This_process_removes_the_term_<b>%1</b>_from_each_entry's_<b>%0</b>_field.=さらに、<b>%0</b>フィールドに<b>%1</b>が含まれていない項目は、選択してからドラッグアンドドロップをするかコンテクストメニュー [...]
Advanced=詳細設定
-
-
All_entries=全項目
All_entries_of_this_type_will_be_declared_typeless._Continue?=この型の項目はすべて型なしと宣言されます。続けますか?
@@ -85,11 +78,11 @@ All_fields=全フィールド
All_subgroups_(recursively)=全下層グループ(再帰的に)
-An_exception_occurred_while_accessing_'%0'=「%0」にアクセス中に例外エラーが発生しました\:
+Always_reformat_BIB_file_on_save_and_export=保存・書出の際、つねにBIBファイルを再整形する
+
A_SAX_exception_occurred_while_parsing_'%0'\:=「%0」を解析中にSAX例外エラーが発生しました\:
and=および
-
and_the_class_must_be_available_in_your_classpath_next_time_you_start_JabRef.=また、次回JabRefを起動したときに、お使いのクラスパス中でクラスが利用可能になっていなくてはなりません。
any_field_that_matches_the_regular_expression_<b>%0</b>=正規表現<b>%0</b>に一致するフィールドすべて
@@ -128,7 +121,6 @@ Autodetect_format=書式を自動検出
Autogenerate_BibTeX_keys=BibTeX鍵を自動生成
-
Autolink_files_with_names_starting_with_the_BibTeX_key=BibTeX鍵で始まるファイル名を持つファイルを自動リンク
Autolink_only_files_that_match_the_BibTeX_key=BibTeX鍵に一致するファイルのみを自動リンク
@@ -139,7 +131,11 @@ Automatically_create_groups_for_database.=データベースのグループを
Automatically_created_groups=グループを自動生成しました
-Automatically_remove_exact_duplicates=完全な重複を自動的に削除する
+Automatically_remove_exact_duplicates=完全に同一な重複を自動削除
+
+Allow_overwriting_existing_links.=既存リンクの上書きを許可する。
+
+Do_not_overwrite_existing_links.=既存リンクは上書きしない。
AUX_file_import=AUXファイルの読み込み
@@ -157,9 +153,7 @@ Backup_old_file_when_saving=保存時に旧ファイルをバックアップ
BibTeX_key_is_unique.=BibTeX鍵は一意です。
-
-BibTeX_source=BibTeXソース
-
+%0_source=%0ソース
Broken_link=壊れたリンク
@@ -199,10 +193,8 @@ Change_of_Grouping_Method=グループ法を変更
change_preamble=プリアンブルを変更
-
Change_table_column_and_General_fields_settings_to_use_the_new_feature=新しい機能を用いるために、表列と汎用フィールドの設定を変更
-
Changed_font_settings=フォント設定を変更しました
Changed_language_settings=言語設定を変更しました
@@ -216,24 +208,24 @@ Characters_to_ignore=無視する文字
Check_existing_file_links=既存のファイルリンクを確認
Check_links=リンクを確認
+
+Choose_the_URL_to_download.=ダウンロードするURLを選んでください。
Cite_command=Citeコマンド
Class_name=クラス名
Clear=消去
-
Clear_fields=フィールドを消去
-
Close=閉じる
Close_others=他を閉じる
Close_all=すべて閉じる
+
Close_dialog=ダイアログを閉じる
Close_the_current_database=現在のデータベースを閉じる
-
Close_window=ウィンドウを閉じる
Closed_database=データベースを閉じました
@@ -248,7 +240,6 @@ Column_width=列幅
Command_line_id=コマンドラインID
-Connect=接続
Contained_in=所在
@@ -281,11 +272,11 @@ Could_not_import_preferences=設定を読み込めませんでした
Could_not_instantiate_%0=%0にインスタンス化できませんでした
Could_not_instantiate_%0_%1=%0_%1にインスタンス化できませんでした
-
Could_not_instantiate_%0._Have_you_chosen_the_correct_package_path?=%0にインスタンス化できませんでした。正しいパッケージパスを選択しましたか?
Could_not_open_link=リンクを開けませんでした
Could_not_print_preview=プレビューを印刷できませんでした
+
Could_not_run_the_'vim'_program.=「vim」プログラムを実行できませんでした。
Could_not_save_file.=ファイルを保存できませんでした
@@ -303,9 +294,9 @@ Custom_entry_types=ユーザー項目型
Custom_entry_types_found_in_file=ユーザー項目型がファイル中に見つかりました
-Customize_entry_types=項目型を調整
+Customize_entry_types=項目型の調整
-Customize_key_bindings=キー割当を調整
+Customize_key_bindings=キー割当の調整
Cut=切り取り
@@ -318,7 +309,7 @@ Database_encoding=データベースのエンコーディング
Database_properties=データベース特性
-Database_type=
+Database_type=データベース型
Date_format=日付書式
@@ -353,6 +344,8 @@ Delete_strings=文字列を削除
Deleted=削除しました\:
+Delete_local_file=ローカルファイルを削除
+
Delimit_fields_with_semicolon,_ex.=各フィールドをセミコロンで区切ってください。例
Descending=降順
@@ -362,8 +355,6 @@ Description=説明
Deselect_all=すべて選択解除
Deselect_all_duplicates=重複をすべて削除
-
-
Disable_this_confirmation_dialog=この確認ダイアログをもう表示しない
Display_all_entries_belonging_to_one_or_more_of_the_selected_groups.=選択したグループの一つ以上に属する項目をすべて表示する。
@@ -393,6 +384,7 @@ Do_not_write_the_following_fields_to_XMP_Metadata\:=以下のフィールドはX
Do_you_want_JabRef_to_do_the_following_operations?=JabRefに以下の操作をさせますか?
+Donate_to_JabRef=JabRefに寄付する
Down=下
@@ -404,15 +396,12 @@ Downloading...=ダウンロード中です…
Drop_%0=%0をドロップ
-
-
duplicate_removal=重複を削除
Duplicate_string_name=重複した文字列名
Duplicates_found=重複が見つかりました
-
Dynamic_groups=動的グループ
Dynamically_group_entries_by_a_free-form_search_expression=自由型検索表現で動的にグループ化
@@ -443,7 +432,6 @@ Grouping_may_not_work_for_this_entry.=この項目に対するグループ化は
empty_database=データベースは空です
Enable_word/name_autocompletion=単語と名称の自動補完を有効にする
-
Enter_URL=URLを入力してください
Enter_URL_to_download=ダウンロードするURLを入力してください
@@ -455,7 +443,6 @@ Entries_cannot_be_manually_assigned_to_or_removed_from_this_group.=項目を手
Entries_exported_to_clipboard=項目をクリップボードに書き出しました\:
-
entry=項目
Entry_editor=項目エディタ
@@ -475,7 +462,6 @@ Entry_types=項目型
Error=エラー
Error_exporting_to_clipboard=クリップボード書き出し中にエラー発生
-##Error\:_check_your_External_viewer_settings_in_Preferences=Error\:_check_your_External_viewer_settings_in_Preferences
Error_occurred_when_parsing_entry=項目を解析中にエラーが発生
Error_opening_file=ファイルを開く際にエラー発生
@@ -495,7 +481,6 @@ Overwrite_file?=ファイルを上書きしますか?
Expand_subtree=下層ツリーを開く
-#previousentrynottranslated.Toviewit,openGroupinterfaceandclickonthe"newgroup"button
Export=書き出す
Export_name=書出名
@@ -521,15 +506,12 @@ External_programs=外部プログラム
External_viewer_called=外部ビューアが呼び出されました
-
Fetch=取得
Field=フィールド
field=フィールド
-#IntegritycheckisaprocessthatchecksforindicationsofwronglyfilledoutBibTeXfields."Scan"isthebuttonthatstartsthecheck.
-
Field_name=フィールド名
Field_names_are_not_allowed_to_contain_white_space_or_the_following_characters=フィールド名には、スペースや以下の文字を使うことはできません
@@ -540,7 +522,6 @@ Field_to_group_by=グループ化するフィールド
File=ファイル
file=ファイル
-
File_'%0'_is_already_open.=ファイル「%0」は既に開かれています。
File_'%0'_not_found=ファイル「%0」が見つかりませんでした
@@ -618,22 +599,19 @@ Generate_now=いま生成する
Generated_BibTeX_key_for=以下の項目のBibTeX鍵を生成しました\:
Generating_BibTeX_key_for=以下の項目のBibTeX鍵を生成しています\:
-
+Get_fulltext=フルテキストを得る
Grab=入手
Gray_out_entries_not_in_group_selection=グループ選択にない項目を淡色化する
Gray_out_non-hits=合致しないものを淡色化
-
Groups=グループ
-
Have_you_chosen_the_correct_package_path?=正しいパッケージパスを選択しましたか?
Help=ヘルプ
-
Help_on_groups=グループに関するヘルプ
Help_on_key_patterns=キーパターンに関するヘルプ
@@ -641,19 +619,19 @@ Help_on_regular_expression_search=正規表現検索に関するヘルプ
Hide_non-hits=合致しないものを非表示
-
Hierarchical_context=階層コンテクスト
Highlight=着色
Highlight_groups_matching_all_selected_entries=全選択項目に一致するグループを着色
Highlight_groups_matching_any_selected_entry=任意の選択項目に一致するグループを着色
+Disable_highlight_groups_matching_entries=項目に一致するグループの着色を無効化
Highlight_overlapping_groups=重複のあるグループを着色
Hint\:_To_search_specific_fields_only,_enter_for_example\:<p><tt>author\=smith_and_title\=electrical</tt>=ヒント\:_特定のフィールドのみを検索するには、たとえば\:<p><tt>author\=smith_and_title\=electrical</tt>と入力してください
-HTML_table=HTML_table
-HTML_table_(with_Abstract_&_BibTeX)=HTML_table_(with_Abstract_&_BibTeX)
+HTML_table=HTMLテーブル
+HTML_table_(with_Abstract_&_BibTeX)=HTMLテーブル_(Abstract及びBibTeX付き)
Icon=アイコン
Ignore=無視
@@ -684,44 +662,31 @@ Import_strings=文字列を読み込み
Import_to_open_tab=読み込んでタブを開く
-Import_word_selector_definitions=単語選択メニューの定義を読み込み
-
-
Imported_entries=項目を読み込みました\:
Imported_from_database=データベースから読み込みました\:
-ImportFormat_class=ImportFormatクラス
+Importer_class=Importerクラス
Importing=読み込んでいます
Importing_in_unknown_format=未知の書式で読み込んでいます
-
Include_abstracts=概要を取り込む
Include_entries=項目を含める
Include_subgroups\:_When_selected,_view_entries_contained_in_this_group_or_its_subgroups=下層グループの取り込み:このグループやその配下の下層グループに含まれている項目を表示
-
-
-
Independent_group\:_When_selected,_view_only_this_group's_entries=独立グループ:このグループの項目のみを表示
Initially_show_groups_tree_expanded=最初にグループツリーを展開した状態で表示
Work_options=作業オプション
-Input_error=入力エラー
-
Insert=挿入
Insert_rows=行を挿入
-
-
-
-#IntegritycheckisaprocessthatchecksforindicationsofwronglyfilledoutBibTeXfields."Scan"isthebuttonthatstartsthecheck.
Intersection=論理積
Invalid_BibTeX_key=無効なBibTeX鍵です
@@ -746,7 +711,7 @@ Journal_name=学術誌名
Keep=維持
-Keep_both=両者を維持
+Keep_both=両側を維持
Key_bindings=キー割当
@@ -758,7 +723,6 @@ Key_pattern=キーパターン
keys_in_database=データベース中の鍵
-#nottranslated.Toviewit,usemenu"Tools|NewBibTeXfilefromAUxfile",andlaunchtheactiononanon-existantAUXfile.
Keyword=キーワード
Label=ラベル
@@ -770,10 +734,9 @@ Last_modified=最終修正日時
LaTeX_AUX_file=LaTeX_AUXファイル
Leave_file_in_its_current_directory=ファイルを現在のディレクトリに置いておく。
-Left=左
+Left=左側
Level=レベル
-
Limit_to_fields=以下のフィールドに制限
Limit_to_selected_entries=選択項目に制限
@@ -785,15 +748,11 @@ Link_to_file_%0=ファイル%0へのリンク
Listen_for_remote_operation_on_port=以下のポートでリモート操作を待ち受ける
Load_and_Save_preferences_from/to_jabref.xml_on_start-up_(memory_stick_mode)=起動時にjabref.xmlの読み込みと保存を行う(メモリースティックモード)
-
-
Look_and_feel=操作性
Main_file_directory=基本ファイルディレクトリ
Main_layout_file=基本レイアウトファイル
-Manage=管理
-
Manage_custom_exports=ユーザー書出の管理
Manage_custom_imports=ユーザー読込の管理
@@ -829,7 +788,6 @@ Modify=修正
modify_group=グループを修正
-
Move=移動
Move_down=下げる
@@ -854,7 +812,6 @@ New=新規
new=新規
-
New_BibTeX_entry=新規BibTeX項目
New_BibTeX_subdatabase=新規BibTeX副データベース
@@ -862,6 +819,7 @@ New_BibTeX_subdatabase=新規BibTeX副データベース
New_content=新規内容
New_database_created.=新規データベースが作成されました。
+New_%0_database=新規%0データベース
New_field_value=新規フィールド値
New_file=新規ファイル
@@ -873,7 +831,6 @@ New_string=新規文字列
Next_entry=次の項目
-
No_actual_changes_found.=実際に変更されているところは見つかりませんでした。
no_base-BibTeX-file_specified=ベースとなるBibTeXファイルが指定されていません
@@ -887,7 +844,6 @@ No_entries_found_for_the_search_string_'%0'=検索文字列「%0」に一致す
No_entries_imported.=項目は読み込まれませんでした。
-
No_exceptions_have_occurred.=例外エラーは発生しませんでした。
No_files_found.=ファイルがみつかりません。
@@ -898,24 +854,17 @@ No_journal_names_could_be_abbreviated.=学術誌名を短縮形にすること
No_journal_names_could_be_unabbreviated.=学術誌名を非短縮形にすることができませんでした。
No_PDF_linked=PDFはリンクされていません
-No_references_found=参照が見つかりませんでした
-
-
No_URL_defined=URLは定義されていません
not=not
not_found=見つかりません
-
Note_that_you_must_specify_the_fully_qualified_class_name_for_the_look_and_feel,=操作性(look&feel)には、完全に有効なクラス名を指定しなくてはならないことに注意してください。
Nothing_to_redo=繰り返すべきものがありません
Nothing_to_undo=取り消すべきものがありません
-#Thenextisusedlikein"Referencesfound\:1Numberofreferencestofetch?"
-Number_of_references_to_fetch?=取得する参照数?
-
occurrences=個
OK=OK
@@ -936,7 +885,7 @@ Open_file=ファイルを開く
Open_last_edited_databases_at_startup=起動時に最後に編集していたデータベースを開く
-Open_shared_database=
+Connect_to_shared_database=共有データベースを開く
Open_terminal_here=ここで端末を開く
@@ -1009,7 +958,7 @@ Please_select_an_importer.=読込を選択してください。
Please_select_exactly_one_group_to_move.=移動するグループを一つだけ選択してください。
-Possible_duplicate_entries=潜在的な重複項目
+Possible_duplicate_entries=重複の可能性のある項目
Possible_duplicate_of_existing_entry._Click_to_resolve.=既存項目と重複している可能性があります。解消するにはクリックしてください。
@@ -1020,17 +969,22 @@ Preferences=設定
Preferences_recorded.=設定が記録されました。
Preview=プレビュー
+Citation_Style=
+Current_Preview=
+Cannot_generate_preview_based_on_selected_citation_style.=
+Bad_character_inside_entry=
+Error_while_generating_citation_style=
+Preview_style_changed_to\:_%0=
+Next_preview_layout=
+Previous_preview_layout=
Previous_entry=前の項目
Primary_sort_criterion=第一整序基準
-
Problem_with_parsing_entry=項目を解析中に問題が発生しました
-
Processing_%0=以下を処理中です\:_%0
Program_output=プログラム出力
-Pull_changes_from_shared_database=
-
+Pull_changes_from_shared_database=共有データベースから変更点を持ってくる
Pushed_citations_to_%0=引用を%0に送り込みました
@@ -1040,19 +994,16 @@ Quit_synchronization=動機を終了する
Raw_source=元のソース
-
Rearrange_tabs_alphabetically_by_title=タブをタイトルでアルファベット順に整序
Redo=繰り返し
Reference_database=参照データベース
-#Thenexttwolinesareusedlikein"Referencesfound\:1Numberofreferencestofetch?"
-References_found=参照を検出
+%0_references_found._Number_of_references_to_fetch?=参照を検出\:_%0。_取得する参照数?
Refine_supergroup\:_When_selected,_view_entries_contained_in_both_this_group_and_its_supergroup=上層グループの絞り込み:このグループとその上層グループの両方に含まれている項目を表示
-
regular_expression=正規表現
Remember_these_entry_types?=これらの項目型を記憶しますか?
@@ -1063,13 +1014,10 @@ Remote_server_port=リモートサーバーのポート
Remove=削除
-
Remove_subgroups=下層グループを削除
Remove_all_subgroups_of_"%0"?=「%0」の下層グループをすべて削除しますか?
-
-
Remove_entry_from_import=読み込み分から項目を削除
Remove_entry_selection_from_this_group=このグループから選択項目を削除
@@ -1077,7 +1025,6 @@ Remove_entry_selection_from_this_group=このグループから選択項目を
Remove_entry_type=項目型を削除
Remove_file_link_(DELETE)=ファイルリンクを削除(DELETE)
-
Remove_from_group=グループから削除
Remove_group=グループを削除
@@ -1100,7 +1047,6 @@ Remove_old_entry=旧項目を削除
Remove_selected_strings=選択した文字列を削除する
-
Removed_group_"%0".=グループ「%0」を削除しました。
Removed_group_"%0"_and_its_subgroups.=グループ「%0」とその下層グループを削除しました。
@@ -1111,7 +1057,7 @@ Renamed_string=文字列を改名しました
Replace_(regular_expression)=置換対象(正規表現)
-Replace_string=文字列を置換
+Replace_string=文字列の置換
Replace_with=置換文字列
@@ -1126,14 +1072,13 @@ Resolve_strings_for_standard_BibTeX_fields_only=文字列をBibTeX標準フィ
resolved=解消しました
-
Revert_to_original_source=元のソースに復帰する
Review=論評
Review_changes=変更を検査する
-Right=右
+Right=右側
Save=保存
Save_all_finished.=保存がすべて終わりました。
@@ -1151,36 +1096,23 @@ Save_failed=保存に失敗
Save_failed_during_backup_creation=バックアップ作成中に保存に失敗
-Save_failed_while_committing_changes\:_%0=変更をコミット中に保存に失敗\:_%0
-
Save_selected_as...=選択部に名前を付けて保存...
Saved_database=データベースを保存しました
Saved_selected_to_'%0'.=選択部を以下に保存しました\:'%0'
-
Saving=保存しています
Saving_all_databases...=データベースをすべて保存しています...
Saving_database=データベースを保存しています
-
Search=検索
-
-
Search_expression=検索表現
Search_for=検索対象
-
-
-
-
-
-
-
Searching_for_duplicates...=重複を検索しています...
Searching_for_files=ファイルを検索しています
@@ -1191,21 +1123,15 @@ Select=選択
-
Select_all=すべて選択
-
Select_encoding=エンコーディングを選択
-
Select_entry_type=項目型を選択してください
Select_external_application=外部アプリケーションを選択
Select_file_from_ZIP-archive=ZIP書庫からファイルを選択してください
-
-
-
Select_the_tree_nodes_to_view_and_accept_or_reject_changes=ツリーノードを選択して表示させ、変更を受諾ないし拒否してください
Selected_entries=選択した項目
Set_field=フィールドを設定
@@ -1218,11 +1144,9 @@ Set_table_font=表フォントを設定
Settings=設定
-
-
Shortcut=捷径(ショートカット)
-Show/edit_BibTeX_source=BibTeXソースを表示・編集
+Show/edit_%0_source=%0ソースを表示・編集
Show_'Firstname_Lastname'=「名_姓」と表示
@@ -1230,7 +1154,6 @@ Show_'Lastname,_Firstname'=「姓,_名」と表示
Show_BibTeX_source_by_default=既定でBibTeXソースを表示
-
Show_confirmation_dialog_when_deleting_entries=項目を削除する際に確認ダイアログを表示
Show_description=説明を表示
@@ -1246,17 +1169,12 @@ Show_last_names_only=姓のみを表示する
Show_names_unchanged=氏名をそのまま表示
-
-
Show_optional_fields=非必須フィールドを表示
-
Show_required_fields=必須フィールドを表示
Show_URL/DOI_column=URL/DOI列を表示
-
-
Simple_HTML=単純なHTML
Size=サイズ
@@ -1268,8 +1186,6 @@ Skipped_entry.=項目を跳ばしました。
Sort_alphabetically=アルファベット順に整序
-
-
sort_subgroups=下層グループを整序
Sorted_all_subgroups_recursively.=下層グループをすべて再帰的に整序しました。
@@ -1281,7 +1197,6 @@ Special_name_formatters=名前の整形の定義
Special_table_columns=特殊な表列
-
Starting_import=読み込みを開始
Statically_group_entries_by_manual_assignment=手動割り当てによって静的に項目をグループ化
@@ -1292,21 +1207,19 @@ Stop=停止
Store_journal_abbreviations=学術誌名の短縮形を保管
-
Stored_entry=項目を保管
Strings=文字列
Strings_for_database=右のデータベースで用いる文字列
-Subdatabase_from_AUX=AUXから副データベース
-
+Subdatabase_from_AUX=AUXからの部分データベース
Switches_between_full_and_abbreviated_journal_name_if_the_journal_name_is_known.=学術誌名が既知の場合は、完全な学術誌名と短縮形を切り替える。
-Synchronize_file_links=ファイルリンクを同期
+Synchronize_file_links=ファイルリンクの同期
-Synchronizing_file_links...=ファイルリンクを同期...
+Synchronizing_file_links...=ファイルリンクの同期...
Table_appearance=表の外観
@@ -1330,7 +1243,6 @@ The_chosen_date_format_for_new_entries_is_not_valid=新規項目に選択した
The_chosen_encoding_'%0'_could_not_encode_the_following_characters\:=選択したエンコーディング「%0」は、以下の文字をエンコードすることができませんでした\:
-
the_field_<b>%0</b>=フィールド<b>%0</b>
The_file<BR>'%0'<BR>has_been_modified<BR>externally\!=ファイル<BR>'%0'<BR>は外部から<BR>修正されました!
@@ -1367,9 +1279,6 @@ This_external_link_is_of_the_type_'%0',_which_is_undefined._What_do_you_want_to_
This_group_contains_entries_based_on_manual_assignment._Entries_can_be_assigned_to_this_group_by_selecting_them_then_using_either_drag_and_drop_or_the_context_menu._Entries_can_be_removed_from_this_group_by_selecting_them_then_using_the_context_menu.=このグループは、手動割り当てによる項目を含んでいます。項目を選択して、ドラッグアンドドロップを行うかコンテクストメニューを使うかすれば、このグループに項目を割り当てることができます。項目を選択してコンテクストメニューを使えば、項目を削除することができます。
-
-
-
This_group_contains_entries_whose_<b>%0</b>_field_contains_the_keyword_<b>%1</b>=このグループには、<b>%0</b>フィールドにキーワード<b>%1</b>を含んでいる項目があります
This_group_contains_entries_whose_<b>%0</b>_field_contains_the_regular_expression_<b>%1</b>=このグループには、<b>%0</b>フィールドに正規表現<b>%1</b>を含んでいる項目があります
@@ -1379,11 +1288,9 @@ This_operation_requires_all_selected_entries_to_have_BibTeX_keys_defined.=この
This_operation_requires_one_or_more_entries_to_be_selected.=この操作を行うには、1つ以上の項目が選択されている必要があります。
-
Toggle_abbreviation=短縮形/非短縮形の切替
Toggle_entry_preview=項目プレビューを入切
Toggle_groups_interface=グループ制御面を入切
-
Try_different_encoding=別のエンコーディングを試す
Unabbreviate_journal_names_of_the_selected_entries=選択した項目の誌名を非短縮形にする
@@ -1402,7 +1309,6 @@ Unknown_BibTeX_entries=認識されなかったBibTeX項目
unknown_edit=知らない編集
-
Unknown_export_format=知らない書き出し書式です
Unmark_all=すべての標識を解除
@@ -1411,10 +1317,6 @@ Unmark_entries=項目の標識を外す
Unmark_entry=項目の標識を外す
-
-
-Unsupported_version_of_class_%0\:_%1=クラス%0のサポートされていない版\:_%1
-
untitled=タイトルなし
Up=上
@@ -1429,7 +1331,6 @@ Upgrade_old_external_file_links_to_use_the_new_feature=古い外部ファイル
usage=使用法
Use_autocompletion_for_the_following_fields=右記のフィールドで自動補完を使用
-
Use_other_look_and_feel=別の操作性を使用する
Use_regular_expression_search=正規表現検索を使用
@@ -1471,7 +1372,6 @@ Write_XMP-metadata_for_all_PDFs_in_current_database?=現データベースの全
Writing_XMP-metadata...=XMPメタデータを書き込んでいます...
Writing_XMP-metadata_for_selected_entries...=選択した項目にXMPメタデータを書き込んでいます...
-
Wrote_XMP-metadata=XMPメタデータを書き込みました
XMP-annotated_PDF=XMP注釈付きPDF
@@ -1480,8 +1380,8 @@ XMP-metadata=XMPメタデータ
XMP-metadata_found_in_PDF\:_%0=PDF中にXMPメタデータを検出しました\:_%0
You_must_restart_JabRef_for_this_to_come_into_effect.=これを有効にするためにはJabRefを再起動する必要があります。
You_have_changed_the_language_setting.=言語設定が変更されました。
-You_have_changed_the_look_and_feel_setting.=操作性の設定が変更されました。
+You_have_changed_the_look_and_feel_setting.=操作性の設定が変更されました。
You_have_entered_an_invalid_search_'%0'.=無効な検索「%0」を入力しました。
@@ -1489,10 +1389,8 @@ You_must_choose_a_filename_to_store_journal_abbreviations=誌名短縮形を保
You_must_restart_JabRef_for_the_new_key_bindings_to_work_properly.=新しいキー割当が正しく機能するようにするためには、JabRefを再起動しなくてはなりません。
-
Your_new_key_bindings_have_been_stored.=新しいキー割当が保管されました。
-
The_following_fetchers_are_available\:=以下の取得子が使用できます\:
Could_not_find_fetcher_'%0'=取得子「%0」を見つけられませんでした
Running_query_'%0'_with_fetcher_'%1'.=取得子「%1」を使用して、クエリ「%0」を実行しています。
@@ -1507,14 +1405,10 @@ Import_canceled_by_user=読み込みはユーザーによって取り消され
Progress\:_%0_of_%1=進捗状況\:_%1のうち%0
Error_while_fetching_from_%0=%0からの取得中にエラー発生
-Fetching_Medline_by_id...=MedlineからID順で取得中...
-
-Fetching_Medline_by_term...=Medlineからterm順で取得中...
-%0_import_canceled=%0からの読み込みを取り消しました
Please_enter_a_valid_number=有効な数値を入力してください
-Please_enter_a_comma_separated_list_of_Medline_IDs_(numbers)_or_search_terms.=コンマ区切りでMedline_ID_(番号)ないしは検索項目の一覧を入力してください。
-
Show_search_results_in_a_window=検索結果をウィンドウに表示
+Show_global_search_results_in_a_window=
+Search_in_all_open_databases=
Move_file_to_file_directory?=ファイルをファイルディレクトリに移動しますか?
Rename_to_'%0'=「%0」に改名
You_have_changed_the_menu_and_label_font_size.=メニュートラベルのフォント寸法が変更されました。
@@ -1531,7 +1425,6 @@ Move_the_keyboard_focus_to_the_entry_table=キーボードのフォーカスを
MIME_type=MIME型
This_feature_lets_new_files_be_opened_or_imported_into_an_already_running_instance_of_JabRef<BR>instead_of_opening_a_new_instance._For_instance,_this_is_useful_when_you_open_a_file_in_JabRef<br>from_your_web_browser.<BR>Note_that_this_will_prevent_you_from_running_more_than_one_instance_of_JabRef_at_a_time.=この機能は、新規ファイルを、新しいJabRefインスタンスを開かないで、すでに実行されているインスタンスに開いたり<BR>読み込んだりするものです。たとえば、これは、ウェブブラウザからJabRefにファイルを開かせたい時に便利です。<BR>これによって、一度にJabRefのインスタンスを一つしか開けなくなることに注意してください。
-
Run_fetcher,_e.g._"--fetch\=Medline\:cancer"=取得子を実行する。例:「--fetch\=Medline\:cancer」
The_ACM_Digital_Library=ACMデジタルライブラリ
@@ -1542,9 +1435,6 @@ The_Guide_to_Computing_Literature=The_Guide_to_Computing_Literature
When_opening_file_link,_search_for_matching_file_if_no_link_is_defined=ファイルリンクを開く際、リンクが定義されていなければ、一致するファイルを検索する
Settings_for_%0=「%0」の設定
-
-
-
Mark_entries_imported_into_an_existing_database=既存データベースに読み込んだ項目を標識する
Unmark_all_entries_before_importing_new_entries_into_an_existing_database=既存のデータベースに新規項目を読み込む前に全項目のマークを解除する
@@ -1554,10 +1444,9 @@ Sort_the_following_fields_as_numeric_fields=以下のフィールドは数値フ
Line_%0\:_Found_corrupted_BibTeX_key.=%0行め\:_破損したBibTeX鍵を検出しました。
Line_%0\:_Found_corrupted_BibTeX_key_(contains_whitespaces).=%0行め\:_破損したBibTeX鍵を発見しました(空白が入っている)。
Line_%0\:_Found_corrupted_BibTeX_key_(comma_missing).=%0行め\:_破損したBibTeX鍵を発見しました(コンマが欠落)。
-Finished_downloading_full_text_document=文書本体のダウンロードが終了しました
Full_text_document_download_failed=論文本体のダウンロードに失敗しました
Update_to_current_column_order=現在の列順に更新
-
+Download_from_URL=URLからダウンロード
Rename_field=フィールドを改名しました
Set/clear/rename_fields=フィールドを設定/消去/名称変更
Rename_field_to=フィールド名を以下に変更
@@ -1570,16 +1459,15 @@ Cannot_use_port_%0_for_remote_operation;_another_application_may_be_using_it._Tr
Looking_for_full_text_document...=文書本体を探しています...
Autosave=自動保存
-Prompt_before_recovering_a_database_from_an_autosave_file=自動保存ファイルからデータベースを回復する前に確認を促す
-Autosave_interval_(minutes)=自動保存の間隔(分)
-Do_you_want_to_recover_the_database_from_the_autosave_file?=データベースを自動保存ファイルから回復しますか?
-Recover_from_autosave=自動保存から復帰
+A_local_copy_will_be_opened.=
+Autosave_local_databases=
+Automatically_save_the_database_to=
+Please_enter_a_valid_file_path.=
+
Export_in_current_table_sort_order=現在の表での整序順で書き出し
Export_entries_in_their_original_order=項目をオリジナルの順序で書き出し
Error_opening_file_'%0'.=ファイル「%0」を開く際にエラー発生
-Autosave_of_file_'%0'=「%0」ファイルの自動保存
-Error_opening_autosave_of_'%0'._Trying_to_load_'%0'_instead.=「%0」の自動保存中にエラーが発生しました。代わりに「%0」を読み込んでみてください。
Formatter_not_found\:_%0=整形子が見つかりません\:_%0
Clear_inputarea=入力領域を一掃
@@ -1610,39 +1498,35 @@ includes_subgroups=下層グループを含む
contains=contains
search_expression=検索表現\:
-
-
-%0_mode=%0モード
-
Optional_fields_2=非必須フィールド2
Waiting_for_save_operation_to_finish=保存操作が終了するのを待っています
Resolving_duplicate_BibTeX_keys...=重複したBibTeX鍵を解決...
Finished_resolving_duplicate_BibTeX_keys._%0_entries_modified.=重複したBibTeX鍵を解消し終わりました。%0項目を修正しました。
This_database_contains_one_or_more_duplicated_BibTeX_keys.=このデータベースには、1つないし複数の重複したBibTeX鍵があります。
Do_you_want_to_resolve_duplicate_keys_now?=重複した鍵を直ちに解消しますか?
+
Find_and_remove_duplicate_BibTeX_keys=重複BibTeX鍵を検出して削除
Expected_syntax_for_--fetch\='<name_of_fetcher>\:<query>'=--fetch='<取得子名>\:<問い合わせ>'に期待される文法
Duplicate_BibTeX_key=重複したBibTeX鍵
Import_marking_color=読み込み標識の色
Always_add_letter_(a,_b,_...)_to_generated_keys=鍵生成時に常に(a,_,b,_…)などの文字を付加
+
Ensure_unique_keys_using_letters_(a,_b,_...)=(a,_,b,_…)などの文字を使用して鍵が唯一であることを保証
Ensure_unique_keys_using_letters_(b,_c,_...)=(b,_,c,_…)などの文字を使用して鍵が唯一であることを保証
Entry_editor_active_background_color=項目エディタのアクティブ背景色
Entry_editor_background_color=項目エディタの背景色
Entry_editor_font_color=項目エディタのフォント色
Entry_editor_invalid_field_color=項目エディタの無効フィールド色
+
Table_and_entry_editor_colors=表および項目エディタ色
+
General_file_directory=一般ファイルディレクトリ
User-specific_file_directory=ユーザーファイルディレクトリ
Search_failed\:_illegal_search_expression=検索に失敗\:_誤った検索表現です
Show_ArXiv_column=ArXiv列を表示
-
-
Highlight_groups_that_contain_entries_contained_in_any_currently_selected_group=現在選択されているグループに含まれている項目を持つグループを着色
You_must_enter_an_integer_value_in_the_interval_1025-65535_in_the_text_field_for=テキストフィールドに1025〜65535の間の整数値を入力しなくてはなりません:
-
-
Automatically_open_browse_dialog_when_creating_new_file_link=新しくファイルリンクを作成する際、自動的にブラウズダイアログを開く
Import_metadata_from\:=右記からメタデータを読み込み\:
Choose_the_source_for_the_metadata_import=メタデータを読み込むソースを選んでください
@@ -1650,7 +1534,6 @@ Create_entry_based_on_XMP_data=XMPデータに基づいて項目を生成
Create_blank_entry_linking_the_PDF=PDFにリンクした空の項目を生成
Only_attach_PDF=PDFを添付してください
Title=タイトル
-No_internet_connection.=インターネットに接続されていません。
Create_new_entry=新規項目を作成
Update_existing_entry=既存項目を更新
Autocomplete_names_in_'Firstname_Lastname'_format_only=「名_姓」形式の名前のみ自動補完
@@ -1691,7 +1574,7 @@ Journals=学術誌
Cite=引用
Cite_in-text=文中への引用
Insert_empty_citation=空の引用を挿入
-Merge_citations=引用を統合
+Merge_citations=引用の統合
Manual_connect=手動接続
Select_Writer_document=Writer文書を選択
Sync_OpenOffice/LibreOffice_bibliography=OpenOffice/LibreOffice書誌情報を同期
@@ -1726,13 +1609,11 @@ Select_document=文書を選択
Edit_group_membership=グループ参加状態を編集
HTML_list=HTML一覧
Click_group_to_toggle_membership_of_selected_entries=グループをクリックして、選択した項目の所属を入切してください
-Use_EMACS_23_insertion_string=EMACS_23型文字列挿入を行う
-If_possible,_normalize_this_list_of_names_to_conform_to_standard_BibTeX_name_formatting=可能ならば、名称一覧を標準的なBibTeX名書式に合致するように規準化する
+If_possible,_normalize_this_list_of_names_to_conform_to_standard_BibTeX_name_formatting=可能ならば、名称一覧を標準的なBibTeX名書式に合致するように標準化する
Could_not_open_%0=%0を開くことができませんでした
Unknown_import_format=未知の読み込み型です
Web_search=ウェブ検索
Style_selection=様式の選択
-
No_valid_style_file_defined=有効な様式ファイルが定義されていません
Choose_pattern=パターンを選択してください
Use_the_BIB_file_location_as_primary_file_directory=bibファイルの場所を主要ファイルディレクトリとして使用
@@ -1742,14 +1623,16 @@ OpenOffice/LibreOffice_connection=OpenOffice/LibreOffice接続
You_can_add_additional_journal_names_by_setting_up_a_personal_journal_list,<br>as_well_as_linking_to_external_journal_lists.=個人用学術誌一覧を作成、または外部の学術誌一覧にリンクすることで<br>学術誌名を追加することができます。
JabRef_includes_a_built-in_list_of_journal_abbreviations.=JabRefには学術誌短縮名の組み込み一覧があります。
You_must_select_either_a_valid_style_file,_or_use_one_of_the_default_styles.=有効な様式ファイルを選択するか、既定様式のうち一つを用いなくてはなりません。
-This_is_a_simple_copy_and_paste_dialog._First_load_or_paste_some_text_into_the_text_input_area.<br>After_that,_you_can_mark_text_and_assign_it_to_a_BibTeX_field.=これは単純なコピー&ペーストダイアログです。まず入力領域に文章を読み込むか貼り付けてください。<br>その後、文章を標識して、それをBibTeXフィールドに割り当てることができます。
+This_is_a_simple_copy_and_paste_dialog._First_load_or_paste_some_text_into_the_text_input_area.<br>After_that,_you_can_mark_text_and_assign_it_to_a_BibTeX_field.=これは単純なコピー&ペーストダイアログです。まず入力領域に文章を読み込むか貼り付けてください。<br>その後、文章を標識して、それをBibTeXフィールドに割り当てることができます。
This_feature_generates_a_new_database_based_on_which_entries_are_needed_in_an_existing_LaTeX_document.=この機能を使うと、既存のLaTeX文書に必要とされている項目が何であるかを検出して新規データベースが作成されます。
You_need_to_select_one_of_your_open_databases_from_which_to_choose_entries,_as_well_as_the_AUX_file_produced_by_LaTeX_when_compiling_your_document.=項目を選ぶための既に開かれているデータベースと、文書をコンパイルする際にLaTeXが生成したAUXファイルを選択する必要があります。
+
First_select_entries_to_clean_up.=まず消去する項目を選択してください。
-Cleanup_entry=項目を消去
+Cleanup_entry=項目の整理
Autogenerate_PDF_Names=PDF名を自動生成
Auto-generating_PDF-Names_does_not_support_undo._Continue?=PDF名の自動生成は取り消せません。続けますか?
+
Use_full_firstname_whenever_possible=可能な場合は常に完全なファーストネームを使用
Use_abbreviated_firstname_whenever_possible=可能な場合は常に短縮したファーストネームを使用
Use_abbreviated_and_full_firstname=短縮したファーストネームと完全なファーストネームを両方使用
@@ -1757,17 +1640,19 @@ Autocompletion_options=自動補完オプション
Autocomplete_after_following_number_of_characters=右記の文字数以上で自動補完
Name_format_used_for_autocompletion=自動補完に使用される氏名の書式
Treatment_of_first_names=名(first_name)の取り扱い
-Cleanup_entries=項目を消去
+Cleanup_entries=項目の整理
Automatically_assign_new_entry_to_selected_groups=選択したグループに新規項目を自動割り当て
+%0_mode=%0モード
Move_DOIs_from_note_and_URL_field_to_DOI_field_and_remove_http_prefix=DOIをnote及びURLフィールドからDOIフィールドに移動して、http前置句を削除する
Make_paths_of_linked_files_relative_(if_possible)=リンクファイルのパスを(可能な限り)相対パスにする
Rename_PDFs_to_given_filename_format_pattern=PDFを指定したファイル名書式パターンに改名する
Rename_only_PDFs_having_a_relative_path=相対パスを持つPDFのみを改名
What_would_you_like_to_clean_up?=どれを消去しますか?
-Doing_a_cleanup_for_%0_entries...=%0個の項目を消去しています...
+Doing_a_cleanup_for_%0_entries...=%0個の項目を整理しています...
No_entry_needed_a_clean_up=消去の必要がある項目はありませんでした
One_entry_needed_a_clean_up=1つの項目を消去する必要がありました
%0_entries_needed_a_clean_up=%0個の項目を消去する必要がありました
+
Error_downloading_file_'%0'=ファイル「%0」をダウンロードする際にエラー発生
Download_failed=ダウンロードに失敗しました
@@ -1775,20 +1660,19 @@ Remove_selected=選択分を削除
Group_tree_could_not_be_parsed._If_you_save_the_BibTeX_database,_all_groups_will_be_lost.=グループツリーを解析できませんでした。BibTeXデータベースを保存すると、グループはすべて失われます。
Attach_file=ファイルを添付
-
Setting_all_preferences_to_default_values.=すべての設定を既定値にします。
Resetting_preference_key_'%0'=キー「%0」の設定をリセットします
Unknown_preference_key_'%0'=キー「%0」という設定は知りません
Unable_to_clear_preferences.=設定を消去することができませんでした。
Reset_preferences_(key1,key2,..._or_'all')=設定をリセット(キー1・キー2…あるいは「all」)
-Find_unlinked_files=リンクしていないファイルを検索
+Find_unlinked_files=リンクされていないファイルを検索
Unselect_all=すべての選択を解除
Expand_all=すべて展開表示
Collapse_all=すべて畳んで表示
Opens_the_file_browser.=ファイルブラウザを開きます
Scan_directory=ディレクトリを走査
-Searches_the_selected_directory_for_unlinked_files.=選択したディレクトリで非リンクファイルを検索
+Searches_the_selected_directory_for_unlinked_files.=選択したディレクトリでリンクされていないファイルを検索
Starts_the_import_of_BibTeX_entries.=BibTeX項目の読み込みを開始します。
Leave_this_dialog.=このダイアログを閉じます。
Create_directory_based_keywords=ディレクトリに基づいたキーワードを生成
@@ -1818,7 +1702,6 @@ Five_stars=五つ星
Four_stars=四つ星
Help_on_special_fields=特殊フィールドのヘルプ
Keywords_of_selected_entries=選択した項目のキーワード
-Manage_content_selectors=内容選択子を管理
Manage_keywords=キーワードの管理
No_priority_information=優先度の情報がありません
No_rank_information=評価の情報がありません
@@ -1846,10 +1729,10 @@ Two_stars=二つ星
Update_keywords=キーワードを更新
Write_values_of_special_fields_as_separate_fields_to_BibTeX=特殊フィールドの値を独立したフィールドとしてBibTeXに書き込む
You_have_changed_settings_for_special_fields.=特殊フィールドの設定が変更されました。
-
%0_entries_found._To_reduce_server_load,_only_%1_will_be_downloaded.=%0個の項目が検出されました。サーバー負荷を軽減するため、%1個のみがダウンロードされます。
A_string_with_that_label_already_exists=そのラベルを持つ文字列は既に存在しています
Connection_to_OpenOffice/LibreOffice_has_been_lost._Please_make_sure_OpenOffice/LibreOffice_is_running,_and_try_to_reconnect.=OpenOffice/LibreOfficeへの接続が失われました。OpenOffice/LibreOfficeが実行されていることを確認して再接続を試みてください。
+
Correct_the_entry,_and_reopen_editor_to_display/edit_source.=項目を修正してエディタを再度開き、ソースを表示もしくは編集してください。
Could_not_connect_to_a_running_gnuserv_process._Make_sure_that_Emacs_or_XEmacs_is_running,<BR>and_that_the_server_has_been_started_(by_running_the_command_'server-start'/'gnuserv-start').=実行中のgnuservプロセスに接続できませんでした。EmacsあるいはXEmacsが実行中であることを確認し、<BR>(「server-start」または「gnuserv-start」コマンドを実行して)サーバーが起動していることてください。
Could_not_connect_to_running_OpenOffice/LibreOffice.=実行中のOpenOffice/LibreOfficeに接続できませんでした。
@@ -1871,23 +1754,18 @@ Your_style_file_specifies_the_paragraph_format_'%0',_which_is_undefined_in_your_
Searching...=検索中...
You_have_selected_more_than_%0_entries_for_download._Some_web_sites_might_block_you_if_you_make_too_many_rapid_downloads._Do_you_want_to_continue?=ダウンロードする項目を%0個以上選択しました。あまりに多くのダウンロードを急に行うと、其れをブロックするウェブサイトもあります。続けますか?
Confirm_selection=選択範囲を確認
-Unknown_DOI\:_'%0'.=「%0」は既知のDOIではありません
Add_{}_to_specified_title_words_on_search_to_keep_the_correct_case=大小文字を正しく維持するため、検索中に指定したタイトル語に{}を付け加える
Import_conversions=読み込み時変換
Please_enter_a_search_string=検索文字列を入力してください
Please_open_or_start_a_new_database_before_searching=検索前にデータベースを開くか新規データベースを開始してください
-An_error_occurred_while_fetching_from_ADS_(%0)\:=ADSからの取得中にエラーが発生しました(%0)\:
-An_error_occurred_while_parsing_abstract=abstractの解析時にエラー発生
-Unknown_DiVA_entry\:_'%0'.=未知のDiVA項目\:「%0」
-Get_BibTeX_entry_from_DiVA=DiVAからBibTeX項目を取得
Log=ログ
-
Canceled_merging_entries=項目の統合を取り消しました
+
Format_units_by_adding_non-breaking_separators_and_keeping_the_correct_case_on_search=非改行区切りを付して検索で大文字小文字が正しくなるよう単位を整形
-Merge_entries=項目を統合
-Merged_entries=統合項目を新規に追加し旧項目を残しました
-Merged_entry=項目を統合しました
+Merge_entries=項目の統合
+Merged_entries=項目を統合しました
+Merged_entry=統合後の項目
None=なし
Parse=解析
Result=結果
@@ -1898,32 +1776,37 @@ You_have_to_choose_exactly_two_entries_to_merge.=統合する項目を2つ選ば
Update_timestamp_on_modification=修正時にタイムスタンプを更新
All_key_bindings_will_be_reset_to_their_defaults.=すべてのキー割当を既定値に復帰します。
+
Automatically_set_file_links=ファイルリンクを自動設定
Continue?=続けますか?
Resetting_all_key_bindings=キー割当をすべて復帰
-
Hostname=ホスト
Invalid_setting=無効な設定です
Network=ネットワーク
Please_specify_both_hostname_and_port=ホスト名とポートの両方を指定してください
-Port=ポート
+Please_specify_both_username_and_password=ユーザー名とパスワードをともに指定してください
+
Use_custom_proxy_configuration=ユーザー定義のプロキシ設定を用いる
+Proxy_requires_authentication=プロキシには認証が必要
+Attention\:_Password_is_stored_in_plain_text\!=警告:パスワードは平文で保管されます!
Clear_connection_settings=接続設定を消去する
Cleared_connection_settings.=接続設定を消去しました
+
Rebind_C-a,_too=C-aも割り当て直す
+Rebind_C-f,_too=C-fもバインドし直します
Show_number_of_elements_contained_in_each_group=各グループに含まれる項目の数を表示する
Open_folder=フォルダを開く
Searches_for_unlinked_PDF_files_on_the_file_system=ファイルシステム上にあるリンクされていないPDFファイルを検索する
-
Export_entries_ordered_as_specified=項目を指定順に書き出し
Export_sort_order=書き出し整序順
+Export_sorting=整序法を書き出す
Newline_separator=新規行分離子
+
Save_entries_ordered_as_specified=項目を指定順に保存
Save_sort_order=整序順を保存
Show_extra_columns=追加列を表示
-
Parsing_error=解析エラー
illegal_backslash_expression=バックスラッシュ表現が不正です
@@ -1931,7 +1814,6 @@ Move_to_group=グループに移動
Clear_read_status=既読情報を消去
Convert_to_BibLatex_format_(for_example,_move_the_value_of_the_'journal'_field_to_'journaltitle')=BibLatex形式に変換(例:「journal」フィールドの値を「journaltitle」フィールドに移管)
-Could_not_apply_changes.=変更を適用できませんでした。
Deprecated_fields=旧式のフィールドです
Hide/show_toolbar=ツールバーを表示/非表示
No_read_status_information=既読情報がありません
@@ -1943,130 +1825,112 @@ Save_selected_as_plain_BibTeX...=選択部をplain_BibTeXとして保存...
Set_read_status_to_read=既読情報を既読に設定
Set_read_status_to_skimmed=既読情報を斜め読み済に設定
Show_deprecated_BibTeX_fields=旧式のBibTeXフィールドを表示
+
Show_gridlines=グリッド線を表示
Show_printed_status=印刷済情報を表示
Show_read_status=既読情報を表示
Table_row_height_padding=表の行高パディング
-Marked_all_%0_selected_entries=%0個の選択項目全てに標識を付けました
Marked_selected_entry=選択した項目に標識を付けました
-Toggle_print_status=印刷済情報を変更
-Unmarked_all_%0_selected_entries=%0個の選択項目全ての標識を外しました
+Marked_all_%0_selected_entries=%0個の選択項目全てに標識を付けました
Unmarked_selected_entry=選択項目の標識を外しました
+Unmarked_all_%0_selected_entries=%0個の選択項目全ての標識を外しました
+Toggle_print_status=印刷済情報を変更
+
Unmarked_all_entries=全項目の標識を外しました
Unable_to_find_the_requested_look_and_feel_and_thus_the_default_one_is_used.=要求のあった操作性設定を見つけることができなかったので、既定値を使用します。
-Could_not_open_browser.=ブラウザを開くことができませんでした。
Opens_JabRef's_GitHub_page=JabRefのGitHubページを開きます
-
-Rebind_C-f,_too=C-fもバインドし直します
-This_group_contains_all_entries._It_cannot_be_edited_or_removed.=このグループは全項目を含んでいます。編集したり削除したりすることはできません。
+Could_not_open_browser.=ブラウザを開くことができませんでした。
+Please_open_%0_manually.=%0を手動で開いてください.
+The_link_has_been_copied_to_the_clipboard.=リンクがクリップボードにコピーされました.
Open_%0_file=%0個のファイルを開きます
Cannot_delete_file=ファイルを削除することができません
-Convert=変換
-Delete_local_file=ローカルファイルを削除
File_permission_error=ファイルアクセス権のエラー
-Help_on_Name_Formatting=名前の書式に関するヘルプ
-Normalize_to_BibTeX_name_format=BibTeXの名前書式に標準化
-Path_to_%0=%0へのパス
Push_to_%0=%0にプッシュ
+Path_to_%0=%0へのパス
+Convert=変換
+Normalize_to_BibTeX_name_format=BibTeXの名前書式に標準化
+Help_on_Name_Formatting=名前の書式に関するヘルプ
Add_new_file_type=新規ファイル形式を追加
-Follow_DOI_or_URL_link_and_try_to_locate_PDF_full_text_document=DOIまたはURLリンクをたどってPDF文書本体の場所を探してください
-Left_entry=左の項目
-No_information_added=情報は追加されていません
+
+Left_entry=左側の項目
+Right_entry=右側の項目
+Use=採用
Original_entry=元の項目
Replace_original_entry=元の項目を置き換える
-Right_entry=右の項目
+No_information_added=情報は追加されていません
Select_at_least_one_entry_to_manage_keywords.=キーワードを操作するには少なくともひとつの項目を選択してください。
-Use=右記を使用してください:
-Changed_type_to_'%0'_for=右記を「%0」型に変更しました;
-Database_'%0'_has_changed.=データベース「%0」に変更が加えられました。
-Copy_\\cite{BibTeX_key}=\\cite{BibTeX鍵}をコピー
-Copy_BibTeX_key_and_title=BibTeX鍵とタイトルをコピー
-File_rename_failed_for_%0_entries.=%0項目のファイル名変更が失敗しました。
-To_set_up,_go_to=設定するには、
-Search_%0=%0を検索
-Invalid_DOI\:_'%0'.=無効なDOIです\:_'%0'.
-Could_not_connect_to_%0=%0に接続することができませんでした
-
+OpenDocument_text=OpenDocument文書
+OpenDocument_spreadsheet=OpenDocument表計算
+OpenDocument_presentation=OpenDocumentプレゼンテーション
%0_image=%0画像
-%0_problem(s)_found=%0件問題を検出しました
-'%0'_is_not_a_valid_ADS_bibcode.=「%0」は有効なADS bibcodeではありません。
-Accepting_the_change_replaces_the_complete_groups_tree_with_the_externally_modified_groups_tree.=変更を承認すると、外部で修正されたグループツリーで,グループツリー全体を置き換えます。
Added_entry=項目を追加しました
-Added_new_'%0'_entry.=「%0」項目を新規に追加しました。
-Choose_the_URL_to_download.=ダウンロードするURLを選んでください。
-Deleted_entry=項目を削除
-Discard_changes=変更を放棄
-Donate_to_JabRef=JabRefに寄付する
-Export_with_selected_format=選択した形式で書き出し
-Field_is_missing=フィールドがありません
-Filled=書込み済
-From_import=読込より
-Keep_left=左側を維持
-Keep_merged_entry_only=マージした項目のみを維持
-Keep_right=右側を維持
-Merged_BibTeX_source_code=BibTeXソースコードをマージしました
Modified_entry=項目を修正しました
+Deleted_entry=項目を削除
Modified_groups_tree=グループツリーを修正しました
-Multiple_entries_selected._Do_you_want_to_change_the_type_of_all_these_to_'%0'?=複数の項目を選択しています。これらすべての項目の_型を「%0」に変更しますか?
-No_problems_found.=問題は検出されませんでした。
-Old_entry=旧項目
-OpenDocument_presentation=OpenDocumentプレゼンテーション
-OpenDocument_spreadsheet=OpenDocument表計算
-OpenDocument_text=OpenDocument文書
-Please_move_the_file_manually_and_link_in_place.=ファイルを手動で移動して、そこでリンクしてください。
-Print_entry_preview=項目プレビューを印刷
-Really_delete_the_%0_selected_entries?=選択した%0項目を本当に削除しますか?
-Really_delete_the_selected_entry?=選択した項目を本当に削除しますか?
Removed_all_groups=全グループを削除しました
-Return_to_JabRef=JabRefに戻る
-Save_changes=変更点を保存
+Accepting_the_change_replaces_the_complete_groups_tree_with_the_externally_modified_groups_tree.=変更を承認すると、外部で修正されたグループツリーで,グループツリー全体を置き換えます。
Select_export_format=書き出し形式を選んでください
+Return_to_JabRef=JabRefに戻る
+Please_move_the_file_manually_and_link_in_place.=ファイルを手動で移動して、そこでリンクしてください。
+Could_not_connect_to_%0=%0に接続することができませんでした
Warning\:_%0_out_of_%1_entries_have_undefined_BibTeX_key.=警告;%1項目中%0項目に定義されていないBibTeX鍵があります。
-large_capitals_are_not_masked_using_curly_brackets_{}=波かっこ{}では、大文字はマスクされません
occurrence=個
-should_contain_a_four_digit_number=4桁の数字でなくてはなりません
-should_contain_a_valid_page_number_range=有効なページ数範囲でなくてはなりません
-should_end_with_a_name=終わりは名前でなくてはなりません
+Added_new_'%0'_entry.=「%0」項目を新規に追加しました。
+Multiple_entries_selected._Do_you_want_to_change_the_type_of_all_these_to_'%0'?=複数の項目を選択しています。これらすべての項目の_型を「%0」に変更しますか?
+Changed_type_to_'%0'_for=右記を「%0」型に変更しました:
+Really_delete_the_selected_entry?=選択した項目を本当に削除しますか?
+Really_delete_the_%0_selected_entries?=選択した%0項目を本当に削除しますか?
+Keep_merged_entry_only=統合した項目のみを維持
+Keep_left=左側を維持
+Keep_right=右側を維持
+Old_entry=旧項目
+From_import=読込より
+No_problems_found.=問題は検出されませんでした。
+%0_problem(s)_found=%0件問題を検出しました
+Save_changes=変更点を保存
+Discard_changes=変更を放棄
+Database_'%0'_has_changed.=データベース「%0」に変更が加えられました。
+Print_entry_preview=項目プレビューを印刷
+Copy_\\cite{BibTeX_key}=\\cite{BibTeX鍵}をコピー
+Copy_BibTeX_key_and_title=BibTeX鍵とタイトルをコピー
+File_rename_failed_for_%0_entries.=%0項目のファイル名変更が失敗しました。
+To_set_up,_go_to=設定するには、
+Merged_BibTeX_source_code=統合後のBibTeXソースコード
+Invalid_DOI\:_'%0'.=無効なDOIです\:_'%0'.
should_start_with_a_name=始まりは名前でなくてはなりません
+should_end_with_a_name=終わりは名前でなくてはなりません
unexpected_closing_curly_bracket=閉じ波かっこが余分にあります
unexpected_opening_curly_bracket=開き波かっこが余計にあります
+capital_letters_are_not_masked_using_curly_brackets_{}=波かっこ{}では、大文字はマスクされません
+should_contain_a_four_digit_number=4桁の数字でなくてはなりません
+should_contain_a_valid_page_number_range=有効なページ数範囲でなくてはなりません
+Filled=書込み済
+Field_is_missing=フィールドがありません
+Search_%0=%0を検索
-Advanced_search_active.=詳細検索が進行中です。
-Found_%0_results.=%0件検出しました。
-No_results_found.=検出されませんでした。
-Normal_search_active.=通常検索が進行中です。
-Search_globally=大域検索
-Search_in_all_open_databases=開かれているデータベースをすべて検索
Search_results_in_all_databases_for_%0=%0を全データベースで検索した結果
Search_results_in_database_%0_for_%1=%0をデータベース%1で検索した結果
-This_search_contains_entries_in_which=この検索結果は下記のものを表示;
+Search_globally=大域検索
+No_results_found.=検出されませんでした。
+Found_%0_results.=%0件検出しました。
+Advanced_search_active.=詳細検索が進行中です。
+Normal_search_active.=通常検索が進行中です。
+plain_text=平文
This_search_contains_entries_in_which_any_field_contains_the_regular_expression_<b>%0</b>=この検索結果は、フィールドのうちどれかに正規表現<b>%0</b>が含まれている項目を表示します。
This_search_contains_entries_in_which_any_field_contains_the_term_<b>%0</b>=この検索結果は、フィールドのうちどれかに用語<b>%0</b>が含まれている項目を表示します。
-plain_text=平文
-
-Attention\:_Password_is_stored_in_plain_text\!=警告:パスワードは平文で保管されます!
-Please_specify_both_username_and_password=ユーザー名とパスワードをともに指定してください
-Proxy_requires_authentication=プロキシには認証が必要
+This_search_contains_entries_in_which=この検索結果は下記のものを表示;
-Always_reformat_BIB_file_on_save_and_export=保存・書出の際、つねにBIBファイルを再整形する
-Allow_overwriting_existing_links.=既存リンクの上書きを許可する。
-Do_not_overwrite_existing_links.=既存リンクは上書きしない。
-Disable_highlight_groups_matching_entries=項目に一致するグループの着色を無効化
-New_%0_database=新規%0データベース
-Export_sorting=整序法を書き出す
-No_entry_found_for_ISBN_%0_at_www.ebook.de=www.ebook.deにISBN_%0に一致する項目は見つかりませんでした
-An_autosave_file_was_found_for_this_database._This_could_indicate_that_JabRef_did_not_shut_down_cleanly_last_time_the_file_was_used.=このデータベースの自動保存ファイルが見つかりました。このファイルを最後に使用した際、JabRefが正常に終了しなかった可能性があります。
-Note\:_A_full_text_search_is_currently_not_supported_for_%0=註:%0ではフルテキスト検索はまだサポートされていません
Unable_to_autodetect_OpenOffice/LibreOffice_installation._Please_choose_the_installation_directory_manually.=OpenOffice/LibreOfficeが導入済みであることを自動検出できませんでした。導入先ディレクトリを手動で選択してください。
JabRef_no_longer_supports_'ps'_or_'pdf'_fields.<br>File_links_are_now_stored_in_the_'file'_field_and_files_are_stored_in_an_external_file_directory.<br>To_make_use_of_this_feature,_JabRef_needs_to_upgrade_file_links.<br><br>=JabRefは「ps」「pdf」フィールドのサポートを停止しました。<br>現在、ファイルリンクは「file」フィールドに保管され、ファイルは外部のファイルディレクトリに保管されます。<br>この機能を利用するには、JabRefにファイルリンクを更新させる必要があります。<br><br>
This_database_uses_outdated_file_links.=このデータベースは旧式のファイルリンクを使用しています。
+
Clear_search=検索を消去
Close_database=データベースを閉じる
Close_entry_editor=項目エディタを閉じる
@@ -2102,7 +1966,6 @@ Resolve_duplicate_BibTeX_keys=重複BibTeX鍵を解消
Save_all=全て保存
String_dialog,_add_string=文字列ダイアログ・文字列を追加
String_dialog,_remove_string=文字列ダイアログ・文字列を削除
-Switch_preview_layout=プレビューレイアウトを切り替え
Synchronize_files=ファイルを同期
Unabbreviate=非短縮形化
should_contain_a_protocol=プロトコルを含む必要あり
@@ -2122,8 +1985,10 @@ value=値
Show_preferences=設定を表示
Save_actions=アクションを保存
Enable_save_actions=アクションの保存を有効化
+
Other_fields=他のフィールド
Show_remaining_fields=その他のフィールドを表示
+
link_should_refer_to_a_correct_file_path=リンクは正しいファイルパスを参照しなくてはなりません
abbreviation_detected=短縮形を検出しました
wrong_entry_type_as_proceedings_has_page_numbers=項目型の誤り:proceedingsにページ番号があります
@@ -2137,12 +2002,15 @@ None_of_the_selected_entries_have_BibTeX_keys.=選択した項目のいずれに
Unabbreviate_journal_names=学術誌名を非短縮形化
Unabbreviating...=非短縮形化中...
Usage=使用法
+
+
Adds_{}_brackets_around_acronyms,_month_names_and_countries_to_preserve_their_case.=大文字が維持されるように、略語や月名、国名の前後には{}括弧を付してください。
-Converts_units_to_LaTeX_formatting.=単位をLaTeX形式に変換します。
-Does_nothing.=何もしません。
Are_you_sure_you_want_to_reset_all_settings_to_default_values?=本当に全ての設定を既定値に戻しますか?
Reset_preferences=設定をリセット
Ill-formed_entrytype_comment_in_BIB_file=bibファイル中に誤った書式の項目型コメントがあります
+
+Move_linked_files_to_default_file_directory_%0=リンクを張られたファイルを既定ファイルディレクトリ%0に移動します
+
Clipboard=クリップボード
Could_not_paste_entry_as_text\:=項目をテキストとして貼り付けることができませんでした\:
Do_you_still_want_to_continue?=それでも続けますか?
@@ -2150,7 +2018,7 @@ This_action_will_modify_the_following_field(s)_in_at_least_one_entry_each\:=こ
This_could_cause_undesired_changes_to_your_entries.=これはあなたの項目に望ましくない変更を加えるおそれがあります。
Run_field_formatter\:=フィールド整形子を起動します\:
Table_font_size_is_%0=表フォント寸法は%0です
-Move_linked_files_to_default_file_directory_%0=リンクを張られたファイルを既定ファイルディレクトリ%0に移動します
+%0_import_canceled=%0からの読み込みを取り消しました
Internal_style=内部スタイル
Add_style_file=スタイルファイルを追加
Are_you_sure_you_want_to_remove_the_style?=本当にこのスタイルを削除しますか?
@@ -2168,11 +2036,13 @@ Changes_all_letters_to_upper_case.=全文字を大文字に変換します。
Changes_the_first_letter_of_all_words_to_capital_case_and_the_remaining_letters_to_lower_case.=全単語の最初の文字を大文字に変換し、他の文字を小文字に変換します。
Cleans_up_LaTeX_code.=LaTeXコードを一掃します。
Converts_HTML_code_to_LaTeX_code.=HTMLコードをLaTeXコードに変換します。
+Converts_HTML_code_to_Unicode.=HTMLコードをUnicodeに変換します.
Converts_LaTeX_encoding_to_Unicode_characters.=LaTeXエンコーディングをUnicode文字に変換します。
Converts_Unicode_characters_to_LaTeX_encoding.=Unicode文字をLaTeXエンコーディングに変換します。
Converts_ordinals_to_LaTeX_superscripts.=序数をLaTeX上付き文字に変換します。
+Converts_units_to_LaTeX_formatting.=単位をLaTeX形式に変換します。
HTML_to_LaTeX=HTMLからLaTeXへ
-LaTeX_cleanup=LaTeX除去
+LaTeX_cleanup=LaTeXの整理
LaTeX_to_Unicode=LaTeXからUnicodeへ
Lower_case=小文字
Minify_list_of_person_names=人名一覧の圧縮
@@ -2194,16 +2064,13 @@ Title_case=タイトルの大小文字パターン
Unicode_to_LaTeX=UnicodeからLaTeXへ
Units_to_LaTeX=単位からLaTeXへ
Upper_case=大文字
+Does_nothing.=何もしません。
Identity=同一
-
Clears_the_field_completely.=フィールドを完全に消去する。
Directory_not_found=ディレクトリが検出されませんでした
Main_file_directory_not_set\!=主幹ファイルディレクトリが設定されていません!
-
This_operation_requires_exactly_one_item_to_be_selected.=この操作では、1項目のみ選択されている必要があります。
-
Importing_in_%0_format=%0形式で読み込み
-
Female_name=女性名
Female_names=女性名
Male_name=男性名
@@ -2222,7 +2089,6 @@ Collaborator=共著者
Column=列
Compiler=コンパイラ
Continuator=継承者
-
Data_CD=データCD
Editor=編集者
European_patent=欧州特許
@@ -2249,17 +2115,17 @@ U.S._patent=米国特許
U.S._patent_request=米国特許申請
Verse=詩句
-
change_entries_of_group=グループ項目を変更
odd_number_of_unescaped_'\#'=エスケープしていない「\#」の奇数
+
Plain_text=平文
Show_diff=差異を表示
character=文字
word=単語
-
Show_symmetric_diff=差異を対照表示
HTML_encoded_character_found=HTMLエンコードされた文字が見つかりました
+booktitle_ends_with_'conference_on'=「conference_on」で終わるbooktitle
All_external_files=全外部ファイル
@@ -2267,165 +2133,182 @@ OpenOffice/LibreOffice_integration=OpenOffice/LibreOfficeの統合
incorrect_control_digit=誤った制御数字
incorrect_format=誤った書式
-
-Expected_"%0"_to_contain_whitespace=空白を入れる「%0」が期待されます
-Syntax_error_in_regular-expression_pattern=正規表現パターン中の文法エラー
-
Copy_version_to_clipboard=バージョンをクリップボードにコピー
Copied_version_to_clipboard=クリップボードにコピーされたバージョン
-booktitle_ends_with_'conference_on'=「conference_on」で終わるbooktitle
BibTeX_key=BibTeX鍵
Message=メッセージ
-
-Get_fulltext=フルテキストを得る
-
-Download_from_URL=URLからダウンロード
-
-Decryption_not_supported.=
-
-Cleared_'%0'_for_%1_entries=
-Set_'%0'_to_'%1'_for_%2_entries=
-Toggled_'%0'_for_%1_entries=
-
-Check_for_updates=
-Download_update=
-New_version_available=
-Installed_version=
-Remind_me_later=
-Ignore_this_update=
-Could_not_connect_to_the_update_server.=
-Please_try_again_later_and/or_check_your_network_connection.=
-To_see_what_is_new_view_the_changelog.=
-A_new_version_of_JabRef_has_been_released.=
-JabRef_is_up-to-date.=
-Latest_version=
-
-Please_open_%0_manually.=
-
-The_link_has_been_copied_to_the_clipboard.=
-
-Online_help_forum=
-
-Custom=
-
-Converts_HTML_code_to_Unicode.=
-
-Open_console=
-Use_default_terminal_emulator=
-Execute_command=
-Note\:_Use_the_placeholder_%0_for_the_location_of_the_opened_database_file.=
-Executing_command_\"%0\"...=
-Error_occured_while_executing_the_command_\"%0\".=
-
-Reformat_ISSN=
-
-Unable_to_generate_new_database=
-
-Export_cited=
-Countries_and_territories_in_English=
-Electrical_engineering_terms=
-Enabled=
-Internal_list=
-Months_and_weekdays_in_English=
-The_text_after_the_last_line_starting_with_\#_will_be_used=
-Add_protected_terms_file=
-Are_you_sure_you_want_to_remove_the_protected_terms_file?=
-Remove_protected_terms_file=
-
-Manage_protected_terms_files=
-
-Add_selected_text_to_list=
-Add_{}_around_selected_text=
-Format_field=
-New_protected_terms_file=
-
-
-change_field_%0_of_entry_%1_from_%2_to_%3=
-change_key_from_%0_to_%1=
-change_string_content_%0_to_%1=
-change_string_name_%0_to_%1=
-change_type_of_entry_%0_from_%1_to_%2=
-insert_entry_%0=
-insert_string_%0=
-remove_entry_%0=
-remove_string_%0=
-
-undefined=
+Decryption_not_supported.=サポートされていない復号化です.
+
+Cleared_'%0'_for_%1_entries=%1項目から「%0」を消去しました
+Set_'%0'_to_'%1'_for_%2_entries=%2項目の「%0」を「%1」に設定しました
+Toggled_'%0'_for_%1_entries=%1項目の「%0」を切り替えました
+
+Check_for_updates=更新があるかを確認
+Download_update=更新分をダウンロード
+New_version_available=新しい版があります
+Installed_version=インストールされた版
+Remind_me_later=後で通知
+Ignore_this_update=この更新は無視する
+Could_not_connect_to_the_update_server.=更新サーバーに接続できませんでした.
+Please_try_again_later_and/or_check_your_network_connection.=ネットワーク接続を確認した上で,後で再度試みてください.
+To_see_what_is_new_view_the_changelog.=変更履歴を開いて新機能を見る
+A_new_version_of_JabRef_has_been_released.=JabRefの新版がリリースされました.
+JabRef_is_up-to-date.=JabRefは最新です.
+Latest_version=最新版
+Online_help_forum=オンラインヘルプ フォーラム
+Custom=カスタム
+
+Export_cited=引用を書き出す
+Unable_to_generate_new_database=新しいデータベースを生成することができませんでした
+
+Open_console=コンソールを開く
+Use_default_terminal_emulator=既定の擬似端末を使用する
+Execute_command=コマンドを実行
+Note\:_Use_the_placeholder_%0_for_the_location_of_the_opened_database_file.=【註】開かれたデータベースの場所のプレイスホルダーに%0を使用します.
+Executing_command_\"%0\"...=コマンド「%0」を実行…
+Error_occured_while_executing_the_command_\"%0\".=コマンド「%0」を実行中にエラーが発生しました
+Reformat_ISSN=ISSNを再構成
+
+Countries_and_territories_in_English=英語での国名・地域名
+Electrical_engineering_terms=電気工学用語
+Enabled=有効
+Internal_list=内部リスト
+Manage_protected_terms_files=予約語ファイルを管理する
+Months_and_weekdays_in_English=英語での月名と曜日名
+The_text_after_the_last_line_starting_with_\#_will_be_used=\#で始まる最後の行の後の文字列が使用されます
+Add_protected_terms_file=予約語ファイルを追加する
+Are_you_sure_you_want_to_remove_the_protected_terms_file?=本当に予約語ファイルを削除して良いですか?
+Remove_protected_terms_file=予約語ファイルを削除する
+Add_selected_text_to_list=選択した平文をリストに追加する
+Add_{}_around_selected_text=選択した平文の前後に{}を付加する
+Format_field=フィールドを整形する
+New_protected_terms_file=新規予約語ファイル
+change_field_%0_of_entry_%1_from_%2_to_%3=%2から%3までの項目%1のフィールド%0を変更する
+change_key_from_%0_to_%1=%0から%1までの鍵を変更する
+change_string_content_%0_to_%1=文字列の内容%0を%1に変更する
+change_string_name_%0_to_%1=文字列名%0を%1に変更する
+change_type_of_entry_%0_from_%1_to_%2=項目%0の型を%1から%2に変更する
+insert_entry_%0=項目%0を挿入する
+insert_string_%0=文字列%0を挿入する
+remove_entry_%0=項目%0を削除する
+remove_string_%0=文字列%0を削除する
+undefined=未定義
Cannot_get_info_based_on_given_%0\:_%1=提供された%0で情報を得ることができません:%1
-
Get_BibTeX_data_from_%0=%0からBibTeXデータを取得
No_%0_found=%0が見つかりませんでした
-
Entry_from_%0=%0からの項目
-
-Merge_entry_with_%0_information=項目を%0情報とマージ
+Merge_entry_with_%0_information=項目を%0情報と統合
Updated_entry_with_info_from_%0=%0からの情報で項目を更新しました
-Connection=
-Host=
-Database=
-User=
-Connection_error=
-Driver_error=
-Connection_to_%0_server_established.=
-Required_field_"%0"_is_empty.=
-
-%0_driver_not_available.=
-
-The_connection_to_the_server_has_been_terminated.=
-
-Connection_lost.=
-Reconnect=
-Work_offline=
-
-Working_offline.=
-
-Update_refused.=
-Update_refused=
-Local_entry=
-Shared_entry=
-Update_could_not_be_performed_due_to_existing_change_conflicts.=
-You_are_not_working_on_the_newest_version_of_BibEntry.=
-Local_version\:_%0=
-Shared_version\:_%0=
-Please_merge_the_shared_entry_with_yours_and_press_"Merge_entries"_to_resolve_this_problem.=
-Canceling_this_operation_will_leave_your_changes_unsynchronized._Cancel_anyway?=
-The_BibEntry_you_currently_work_on_has_been_deleted_on_the_shared_side._Hit_"Keep"_to_recover_the_entry.=
-Cannot_cite_entries_without_BibTeX_keys._Generate_keys_now?=
-New_technical_report=
-
-%0_file=
-Custom_layout_file=
-Protected_terms_file=
-Style_file=
-
-Open_OpenOffice/LibreOffice_connection=
-
-You_must_enter_at_least_one_field_name=
-
-
-Non-ASCII_encoded_character_found=
-
-Toggle_web_search_interface=
-Background_color_for_resolved_fields=
-Color_code_for_resolved_fields=
-%0_files_found=
-%0_of_%1=
-One_file_found=
-The_import_finished_with_warnings\:=
-There_was_one_file_that_could_not_be_imported.=
-There_were_%0_files_which_could_not_be_imported.=
-
-Migration_help_information=
-Entered_database_has_obsolete_structure_and_is_no_longer_supported.=
-However,_a_new_database_was_created_alongside_the_pre-3.6_one.=
-
-Click_here_to_learn_about_the_migration_of_pre-3.6_databases.=
-
-Connecting...=
-Opens_JabRef's_Facebook_page=
-Opens_JabRef's_blog=
-Opens_JabRef's_website=
-
-Opens_a_link_where_the_current_development_version_can_be_downloaded=
-See_what_has_been_changed_in_the_JabRef_versions=
+Connection=接続
+Connecting...=接続中...
+Host=ホスト
+Port=ポート
+Database=データベース
+User=ユーザー
+Connect=接続
+Connection_error=接続エラー
+Connection_to_%0_server_established.=%0サーバーへの接続が確立されました.
+Required_field_"%0"_is_empty.=必須フィールド「%0」が空です.
+%0_driver_not_available.=%0ドライバが利用できません.
+The_connection_to_the_server_has_been_terminated.=サーバーへの接続が絶たれました.
+Connection_lost.=接続を喪失しました.
+Reconnect=再接続
+Work_offline=オフラインで作業
+Working_offline.=オフラインで作業しています.
+Update_refused.=更新が拒否されました.
+Update_refused=更新拒否
+Local_entry=ローカルの項目
+Shared_entry=共有項目
+Update_could_not_be_performed_due_to_existing_change_conflicts.=既存変更点の衝突により更新は実行できませんでした.
+You_are_not_working_on_the_newest_version_of_BibEntry.=現在,BibEntryの最新版で作業中ではありません.
+Local_version\:_%0=ローカルのバージョン:%0
+Shared_version\:_%0=共有のバージョン:%0
+Please_merge_the_shared_entry_with_yours_and_press_"Merge_entries"_to_resolve_this_problem.=この問題を解決するには,共有項目をローカル項目と統合して「項目を統合」ボタンを押してください.
+Canceling_this_operation_will_leave_your_changes_unsynchronized._Cancel_anyway?=この操作を取り消してしまうと,変更点が同期されないまま残ってしまいます.それでも取り消しますか?
+Shared_entry_is_no_longer_present=
+The_BibEntry_you_currently_work_on_has_been_deleted_on_the_shared_side.=現在作業しているBibEntryが共有側で削除されています.
+You_can_restore_the_entry_using_the_"Undo"_operation.=
+Remember_password?=パスワードを記憶しますか?
+You_are_already_connected_to_a_database_using_entered_connection_details.=
+
+Cannot_cite_entries_without_BibTeX_keys._Generate_keys_now?=BibTeX鍵がないと,項目を引用することができません.ここで鍵を生成しますか?
+New_technical_report=新規technical_report
+
+%0_file=%0ファイル
+Custom_layout_file=カスタムレイアウトファイル
+Protected_terms_file=予約語ファイル
+Style_file=スタイルファイル
+
+Open_OpenOffice/LibreOffice_connection=OpenOffice/LibreOffice接続を開く
+You_must_enter_at_least_one_field_name=少なくとも一つのフィールド名を入力する必要があります
+Non-ASCII_encoded_character_found=ASCIIエンコードでない文字が検出されました
+Toggle_web_search_interface=ウェブ検索インタフェースを入切
+Background_color_for_resolved_fields=解決したフィールドの背景色
+Color_code_for_resolved_fields=解決したフィールドの色コード
+%0_files_found=%0個のファイルが見つかりました
+%0_of_%1=%1のうちの%0
+One_file_found=1個のファイルが見つかりました
+The_import_finished_with_warnings\:=右記の警告とともに読み込みが終了しました:
+There_was_one_file_that_could_not_be_imported.=読み込みのできなかったファイルが一つありました.
+There_were_%0_files_which_could_not_be_imported.=読み込みのできなかったファイルが%0個ありました.
+
+Migration_help_information=移出入ヘルプ情報
+Entered_database_has_obsolete_structure_and_is_no_longer_supported.=入力されたデータベースは旧式の構造を持っていて,もうサポートされていません.
+However,_a_new_database_was_created_alongside_the_pre-3.6_one.=しかしながら,pre-3.6データベースに従って,新しいデータベースが生成されました.
+Click_here_to_learn_about_the_migration_of_pre-3.6_databases.=pre-3.6データベースの移出入について知るには,ここをクリックしてください.
+Opens_JabRef's_Facebook_page=JabRefのFacebookページを開きます
+Opens_JabRef's_blog=JabRefのブログを開きます
+Opens_JabRef's_website=JabRefのウェブサイトを開きます
+Opens_a_link_where_the_current_development_version_can_be_downloaded=現行開発版をダウンロードできる場所へのリンクを開きます
+See_what_has_been_changed_in_the_JabRef_versions=JabRefの各版における変更点を見ます
+Referenced_BibTeX_key_does_not_exist=参照されたBibTeX鍵は存在しません
+Finished_downloading_full_text_document_for_entry_%0.=項目%0の文書本体のダウンロードが終了しました.
+Full_text_document_download_failed_for_entry_%0.=項目%0の文書本体のダウンロードに失敗しました.
+Look_up_full_text_documents=文書本体を見る
+You_are_about_to_look_up_full_text_documents_for_%0_entries.=%0項目の文書本体を見ようとしています.
+last_four_nonpunctuation_characters_should_be_numerals=句読点を含まない最後の4文字は数字でなくてはなりません
+shared=共有中
+should_contain_an_integer_or_a_literal=整数または文字を含んでいなくてはなりません
+should_have_the_first_letter_capitalized=最初の文字を大文字にしなくてはなりません
+
+ID=ID
+ID_type=ID型
+ID-based_entry_generator=ID基準項目生成子
+Fetcher_'%0'_did_not_find_an_entry_for_id_'%1'.=取得子「%0」は,IDが「%1」の項目を見つけられませんでした.
+
+Select_first_entry=最初の項目を選択
+Select_last_entry=最後の項目を選択
+
+Invalid_ISBN\:_'%0'.=ISBN「%0」は無効です.
+should_be_an_integer_or_normalized=標準化されたものか整数でなくてはなりません
+should_be_normalized=標準化されたものでなくてはなりません
+
+Empty_search_ID=検索IDが空
+The_given_search_ID_was_empty.=提示された検索IDが空です.
+Copy_BibTeX_key_and_link=BibTeX鍵とリンクをコピー
+empty_BibTeX_key=空のBibTeX鍵
+BibLaTeX_field_only=BibLaTeXフィールドのみ
+
+Error_while_generating_fetch_URL=
+Error_while_parsing_ID_list=
+Unable_to_get_PubMed_IDs=
+Backup_found=
+A_backup_file_for_'%0'_was_found.=
+This_could_indicate_that_JabRef_did_not_shut_down_cleanly_last_time_the_file_was_used.=
+Do_you_want_to_recover_the_database_from_the_backup_file?=
+Firstname_Lastname=
+
+Recommended_for_%0=
+This_might_be_caused_by_reaching_the_traffic_limitation_of_Google_Scholar_(see_'Help'_for_details).=
+
+Problem_downloading_from_%1=
+
+File_directory_pattern=
+Update_with_bibliographic_information_from_the_web=
+
+Could_not_find_any_bibliographic_information.=
+BibTeX_key_%0_deviates_from_generated_key_%1=
+DOI_%0_is_invalid=
+
+Jump_to_entry=
diff --git a/src/main/resources/l10n/JabRef_nl.properties b/src/main/resources/l10n/JabRef_nl.properties
index 728aaba..e18ae56 100644
--- a/src/main/resources/l10n/JabRef_nl.properties
+++ b/src/main/resources/l10n/JabRef_nl.properties
@@ -1,6 +1,6 @@
#!
-#! created/edited by Popeye version 0.55 (https\://github.com/koppor/popeye)
-#! encoding:ISO-8859-1
+#! created/edited by Popeye version 0.55 (github.com/JabRef/popeye)
+#! encoding:UTF-8
%0_contains_the_regular_expression_<b>%1</b>=%0_bevat_de_regular_expression_<b>%1</b>
@@ -12,18 +12,14 @@
%0_export_successful=
-
%0_matches_the_regular_expression_<b>%1</b>=%0_komt_overeen_met_de_regular_expression_<b>%1</b>
%0_matches_the_term_<b>%1</b>=%0_komt_overeen_met_de_term_<b>%1</b>
-<field_name>=<veldnaam>
<HTML>Could_not_find_file_'%0'<BR>linked_from_entry_'%1'</HTML>=
-
<select>=<selecteer>
-<select_word>=<selecteer_woord>
Abbreviate_journal_names_of_the_selected_entries_(ISO_abbreviation)=Kort_tijdschriftennamen_met_de_geselecteerde_entries_af_(ISO_afkorting)
Abbreviate_journal_names_of_the_selected_entries_(MEDLINE_abbreviation)=Kort_tijdschriftennamen_met_de_geselecteerde_entries_af_(MEDLINE_afkorting)
@@ -44,13 +40,12 @@ Action=Actie
Add=Toevoegen
-Add_a_(compiled)_custom_ImportFormat_class_from_a_class_path.=Voeg_een_(gecompileerde)_externe_ImportFormat_klasse_van_een_class_path_toe.
+Add_a_(compiled)_custom_Importer_class_from_a_class_path.=Voeg_een_(gecompileerde)_externe_Importer_klasse_van_een_class_path_toe.
The_path_need_not_be_on_the_classpath_of_JabRef.=Het_pad_moet_niet_in_het_classpath_van_JabRef_staan.
-Add_a_(compiled)_custom_ImportFormat_class_from_a_ZIP-archive.=Voeg_een_(gecompileerde)_externe_ImportFormat_klasse_van_een_ZIP-archief_toe.
+Add_a_(compiled)_custom_Importer_class_from_a_ZIP-archive.=Voeg_een_(gecompileerde)_externe_Importer_klasse_van_een_ZIP-archief_toe.
The_ZIP-archive_need_not_be_on_the_classpath_of_JabRef.=Het_pad_moet_niet_in_het_classpath_van_JabRef_staan.
-
Add_entry_selection_to_this_group=Voeg_entry_selectie_toe_aan_deze_groep
Add_from_folder=Voeg_toe_uit_map
@@ -76,8 +71,6 @@ Added_string=Toegevoegde_constante
Additionally,_entries_whose_<b>%0</b>_field_does_not_contain_<b>%1</b>_can_be_assigned_manually_to_this_group_by_selecting_them_then_using_either_drag_and_drop_or_the_context_menu._This_process_adds_the_term_<b>%1</b>_to_each_entry's_<b>%0</b>_field._Entries_can_be_removed_manually_from_this_group_by_selecting_them_then_using_the_context_menu._This_process_removes_the_term_<b>%1</b>_from_each_entry's_<b>%0</b>_field.=Bijkomstig,_entries_waarvan_het_<b>%0</b>_veld_niet_<b>%1</b>_bevatten_ [...]
Advanced=Geavanceerd
-
-
All_entries=Alle_entries
All_entries_of_this_type_will_be_declared_typeless._Continue?=
@@ -85,11 +78,11 @@ All_fields=Alle_velden
All_subgroups_(recursively)=Alle_subgroepen_(recursief)
-An_exception_occurred_while_accessing_'%0'=
+Always_reformat_BIB_file_on_save_and_export=
+
A_SAX_exception_occurred_while_parsing_'%0'\:=
and=en
-
and_the_class_must_be_available_in_your_classpath_next_time_you_start_JabRef.=en_de_klasse_moet_beschikbaar_zijn_in_uw_classpath_de_volgende_keer_wanneer_u_JabRef_opstart
any_field_that_matches_the_regular_expression_<b>%0</b>=elk_veld_dat_overeenkomt_met_de_regular_expression_<b>%0</b>
@@ -128,10 +121,8 @@ Autodetect_format=Formaat_automatisch_detecteren
Autogenerate_BibTeX_keys=BibTeX-sleutels_automatisch_genereren
-
-
-
Autolink_files_with_names_starting_with_the_BibTeX_key=
+
Autolink_only_files_that_match_the_BibTeX_key=
Automatically_create_groups=Groepen_automatisch_aanmaken
@@ -162,9 +153,7 @@ Backup_old_file_when_saving=Maak_reservekopie_van_oud_bestand_bij_het_opslaan
BibTeX_key_is_unique.=BibTeX-sleutel_is_uniek
-
-BibTeX_source=BibTeX-broncode
-
+%0_source=%0-broncode
Broken_link=
@@ -194,12 +183,9 @@ Case_sensitive=Hoofdletter_gevoelig
change_assignment_of_entries=verandering_toekenning_van_entries
-# The following are for case change in right-click menu in entry editor. The last four
-# illustrate the four variations of capitalization
Change_case=Verander_geval
Change_entry_type=Wijzig_entry_type
-
Change_file_type=Wijzig_bestandstype
@@ -207,10 +193,8 @@ Change_of_Grouping_Method=Wijzig_groepering_methode
change_preamble=wijzig_inleiding
-
Change_table_column_and_General_fields_settings_to_use_the_new_feature=
-
Changed_font_settings=Gewijzigde_lettertypeinstellingen
Changed_language_settings=Gewijzigde_taal_instellingen
@@ -232,18 +216,16 @@ Class_name=Klassenaam
Clear=Wissen
-
Clear_fields=Velden_wissen
-
Close=Sluiten
Close_others=
Close_all=
+
Close_dialog=Sluit_dialoog
Close_the_current_database=Sluit_de_huidige_database
-
Close_window=Sluit_venster
Closed_database=Sluit_database
@@ -258,7 +240,6 @@ Column_width=Kolombreedte
Command_line_id=Commandoregel_id
-Connect=Verbinden
Contained_in=bevat_in
@@ -291,12 +272,11 @@ Could_not_import_preferences=Kon_instellingen_niet_importeren
Could_not_instantiate_%0=Kon_geen_instantie_van_%0_aanmaken
Could_not_instantiate_%0_%1=Kon_geen_instantie_van_%0_%1_aanmaken
-
Could_not_instantiate_%0._Have_you_chosen_the_correct_package_path?=Kon_geen_instantie_van_%0_aanmaken._Heeft_u_het_correcte_pakket_pad_gekozen?
-
Could_not_open_link=
Could_not_print_preview=
+
Could_not_run_the_'vim'_program.=
Could_not_save_file.=Kon_het_bestand_niet_opslaan.
@@ -350,8 +330,6 @@ Delete=Verwijderen
Delete_custom_format=Verwijder_aangepast_formaat
-# I have reformulated the following lines, because the 1st person form is not suitable\:
-# (Folgende_URL_konnte_nicht_analysiert_werden)
delete_entries=verwijder_entries
Delete_entry=Verwijder_entry
@@ -366,6 +344,8 @@ Delete_strings=Verwijder_constanten
Deleted=Verwijderd
+Delete_local_file=
+
Delimit_fields_with_semicolon,_ex.=Scheid_velden_met_puntkomma,_bv.
Descending=Afdalend
@@ -375,8 +355,6 @@ Description=Beschrijving
Deselect_all=Alle_selecties_ongedaan_maken
Deselect_all_duplicates=
-
-
Disable_this_confirmation_dialog=Maak_deze_bevestigingsdialoog_onbeschikbaar
Display_all_entries_belonging_to_one_or_more_of_the_selected_groups.=Toon_alle_entries_die_bij_een_of_meerdere_van_de_geselecteerde_groepen_behoren.
@@ -386,7 +364,6 @@ Display_all_error_messages=Toon_alle_foutmeldingen
Display_help_on_command_line_options=Toon_help_over_commandline_opties
Display_only_entries_belonging_to_all_selected_groups.=Toon_alleen_entries_die_tot_alle_geselecteerde_groepen_behoren.
-
Display_version=Display_versie
Displaying_no_groups=Geen_groepen_tonend
@@ -407,6 +384,7 @@ Do_not_write_the_following_fields_to_XMP_Metadata\:=
Do_you_want_JabRef_to_do_the_following_operations?=
+Donate_to_JabRef=
Down=Omlaag
@@ -418,15 +396,12 @@ Downloading...=Downloading...
Drop_%0=
-
-
duplicate_removal=dubbels_verwijderen
Duplicate_string_name=Dubbele_constante_naam
Duplicates_found=Dubbels_gevonden
-
Dynamic_groups=Dynamische_groepen
Dynamically_group_entries_by_a_free-form_search_expression=Dynamisch_entries_groeperen_door_een_"free-form"_zoek_expressie
@@ -457,7 +432,6 @@ Grouping_may_not_work_for_this_entry.=Groepering_kan_misschien_niet_werken_voor_
empty_database=lege_database
Enable_word/name_autocompletion=
-
Enter_URL=URL_ingeven
Enter_URL_to_download=Geef_URL_om_te_downloaden_in
@@ -469,7 +443,6 @@ Entries_cannot_be_manually_assigned_to_or_removed_from_this_group.=Entries_kunne
Entries_exported_to_clipboard=Entries_ge\u00ebxporteerd_naar_het_klembord
-
entry=entry
Entry_editor=Entry_editor
@@ -487,10 +460,8 @@ Entry_type_names_are_not_allowed_to_contain_white_space_or_the_following_charact
Entry_types=Entrytypes
Error=Foutmelding
-
Error_exporting_to_clipboard=
-##Error\:_check_your_External_viewer_settings_in_Preferences=Foutmelding\:_controleer_uw_Externe_viewer_instellingen_in_Instellingen
Error_occurred_when_parsing_entry=Foutmelding_bij_het_ontleden_van_de_entry
Error_opening_file=Foutmelding_bij_het_openen_van_het_bestand
@@ -498,7 +469,6 @@ Error_opening_file=Foutmelding_bij_het_openen_van_het_bestand
Error_setting_field=Foutmelding_bij_het_instellen_van_het_veld
Error_while_writing=Foutmelding_bij_het_schrijven
-
Error_writing_to_%0_file(s).=
@@ -536,19 +506,15 @@ External_programs=Externe_programma's
External_viewer_called=Externe_viewer_opgeroepen
-
Fetch=Ophalen
Field=Veld
field=veld
-# Integrity check is a process that checks for indications of wrongly filled out BibTeX fields. "Scan" is the button that starts the check.
-
Field_name=Veldnaam
Field_names_are_not_allowed_to_contain_white_space_or_the_following_characters=
-
Field_to_filter=
Field_to_group_by=Veld_te_groeperen_op
@@ -556,7 +522,6 @@ Field_to_group_by=Veld_te_groeperen_op
File=Bestand
file=bestand
-
File_'%0'_is_already_open.=
File_'%0'_not_found=Bestand_'%0'_niet_gevonden
@@ -568,7 +533,6 @@ File_directory_is_not_set_or_does_not_exist\!=
File_exists=Bestand_bestaat
-
File_has_been_updated_externally._What_do_you_want_to_do?=
File_not_found=Bestand_niet_gevonden
@@ -582,7 +546,6 @@ Files_opened=Bestanden_geopend
Filter=Filter
-
Finished_automatically_setting_external_links.=
Finished_synchronizing_file_links._Entries_changed\:_%0.=Synchroniseren_van_bestand_snelkoppelingen_voltooid._Aantal_veranderde_entries\:_%0.
@@ -594,7 +557,6 @@ First_select_the_entries_you_want_keys_to_be_generated_for.=Selecteer_eerst_de_e
Fit_table_horizontally_on_screen=Pas_tabel_horizontaal_aan_op_het_scherm
Float=Float
-
Float_marked_entries=Gemarkeerde_entries_bovenaan_tonen
Font_family=Lettertype_Type
@@ -630,7 +592,6 @@ Generate_BibTeX_key=Genereer_BibTeX-sleutel
Generate_keys=Genereer_sleutels
Generate_keys_before_saving_(for_entries_without_a_key)=Genereer_sleutels_voor_het_opslaan_(voor_entries_zonder_een_sleutel)
-
Generate_keys_for_imported_entries=
Generate_now=Genereer_nu
@@ -638,22 +599,19 @@ Generate_now=Genereer_nu
Generated_BibTeX_key_for=Gegenereerde_BibTeX-sleutel_voor
Generating_BibTeX_key_for=BibTeX-sleutel_aan_het_genereren_voor
-
+Get_fulltext=
Grab=Neem
Gray_out_entries_not_in_group_selection=Maak_entries_die_niet_in_de_groep_selectie_zitten_grijs
Gray_out_non-hits=Maak_niet_gevonden_items_grijs
-
Groups=Groepen
-
Have_you_chosen_the_correct_package_path?=Heeft_u_het_correcte_pakket_pad_gekozen?
Help=Help
-
Help_on_groups=Help_over_groepen
Help_on_key_patterns=Help_over_sleutelpatronen
@@ -661,20 +619,18 @@ Help_on_regular_expression_search=Help_over_Regular_Expression_Zoekopdracht
Hide_non-hits=Verberg_niet_gevonden_objecten
-
Hierarchical_context=Hi\u00ebrarchische_context
Highlight=Markeren
Highlight_groups_matching_all_selected_entries=Markeer_groepen_die_overeenkomen_met_alle_geselecteerde_entries
Highlight_groups_matching_any_selected_entry=Markeer_groepen_die_overeenkomen_met_elke_geselecteerde_entry
+Disable_highlight_groups_matching_entries=
Highlight_overlapping_groups=Markeer_overlappende_groepen
Hint\:_To_search_specific_fields_only,_enter_for_example\:<p><tt>author\=smith_and_title\=electrical</tt>=Hint\:_Om_specifieke_velden_alleen_te_zoeken,_geef_bijvoorbeeld_in\:<p><tt>auteur\=smith_en_titel\=electrical</tt>
-
HTML_table=HTML_tabel
-
HTML_table_(with_Abstract_&_BibTeX)=HTML_tabel_(met_Abstract_&_BibTeX)
Icon=
@@ -706,42 +662,31 @@ Import_strings=Importeer_constanten
Import_to_open_tab=Importeer_naar_open_tabblad
-Import_word_selector_definitions=Importeer_woordselecteerder_definities
-
-
Imported_entries=Ge\u00efmporteerde_entries
Imported_from_database=Ge\u00efmporteerd_van_database
-ImportFormat_class=ImportFormat_Klasse
+Importer_class=Importer_Klasse
Importing=Aan_het_importeren
Importing_in_unknown_format=Aan_het_Importeren_in_onbekend_formaat
-
Include_abstracts=Abstracts_insluiten
Include_entries=Entries_insluiten
Include_subgroups\:_When_selected,_view_entries_contained_in_this_group_or_its_subgroups=Subgroepen_insluiten\:_Wanneer_geselecteerd,_toon_entries_in_deze_groep_of_in_zijn_subgroepen
-
-
-
Independent_group\:_When_selected,_view_only_this_group's_entries=Onafhankelijke_groep\:_Wanneer_geselecteerd,_toon_enkel_de_entries_van_deze_groep
Initially_show_groups_tree_expanded=Initieel,_toon_alle_bomen_van_de_groepen_uitgeklapt
-Input_error=Invoer_foutmelding
+Work_options=
Insert=Invoegen
Insert_rows=Rijen_invoegen
-
-
-
-# Integrity check is a process that checks for indications of wrongly filled out BibTeX fields. "Scan" is the button that starts the check.
Intersection=Doorsnede
Invalid_BibTeX_key=Ongeldige_BibTeX-sleutel
@@ -803,16 +748,11 @@ Link_to_file_%0=
Listen_for_remote_operation_on_port=Luister_naar_operatie_vanop_afstand_op_poort
Load_and_Save_preferences_from/to_jabref.xml_on_start-up_(memory_stick_mode)=
-
-
Look_and_feel="Look_and_feel"
-
Main_file_directory=
Main_layout_file=Hoofd_layoutbestand
-Manage=Beheren
-
Manage_custom_exports=Beheer_externe_exportfilters
Manage_custom_imports=Beheer_externe_importfilters
@@ -828,7 +768,6 @@ Mark_new_entries_with_addition_date=Markeer_nieuwe_entries_met_datum_van_toevoeg
Mark_new_entries_with_owner_name=Markeer_nieuwe_entries_met_naam_van_eigenaar
-# These are status line messages when marking/unmarking entries\:
Memory_stick_mode=
Menu_and_label_font_size=Menu_en_label_lettertypegrootte
@@ -849,7 +788,6 @@ Modify=Wijzigen
modify_group=wijzig_groep
-
Move=Verplaats
Move_down=Verplaats_naar_beneden
@@ -874,7 +812,6 @@ New=Nieuw
new=nieuw
-
New_BibTeX_entry=Nieuwe_BibTeX-entry
New_BibTeX_subdatabase=Nieuwe_BibTeX_subdatabase
@@ -882,6 +819,7 @@ New_BibTeX_subdatabase=Nieuwe_BibTeX_subdatabase
New_content=Nieuwe_inhoud
New_database_created.=Nieuwe_database_aangemaakt.
+New_%0_database=
New_field_value=Nieuwe_veld_waarde
New_file=Nieuw_bestand
@@ -893,7 +831,6 @@ New_string=Nieuwe_constante
Next_entry=Volgende_entry
-
No_actual_changes_found.=Geen_actuele_veranderingen_gevonden.
no_base-BibTeX-file_specified=Geen_basis_BibTeX-bestand_gespecifieerd
@@ -902,11 +839,11 @@ no_database_generated=Geen_database_gegenereerd
No_entries_found._Please_make_sure_you_are_using_the_correct_import_filter.=Geen_entries_gevonden._Zorg_er_a.u.b._voor_dat_u_de_juiste_importfilter_gebruikt.
+
No_entries_found_for_the_search_string_'%0'=
No_entries_imported.=Geen_entries_ge\u00efmporteerd.
-
No_exceptions_have_occurred.=Geen_uitzonderingen_zijn_voorgekomen.
No_files_found.=
@@ -915,27 +852,19 @@ No_GUI._Only_process_command_line_options.=Geen_GUI._Alleen_proces_commandoregel
No_journal_names_could_be_abbreviated.=Er_konden_geen_tijdschrift_namen_afgekort_worden.
No_journal_names_could_be_unabbreviated.=Geen_afkortingen_van_tijdschrift_namen_konden_ongedaan_gemaakt_worden.
-
No_PDF_linked=
-No_references_found=Geen_referenties_gevonden
-
-
No_URL_defined=Geen_URL_gedefinieerd
not=niet
not_found=niet_gevonden
-
Note_that_you_must_specify_the_fully_qualified_class_name_for_the_look_and_feel,=Merk_op_dat_u_de_volledig_gekwalificeerde_klassenaam_voor_de_"look_and_feel"_moet_specificeren,
Nothing_to_redo=Niets_om_te_herstellen
Nothing_to_undo=Niets_om_ongedaan_te_maken
-# The next is used like in "References found\: 1 Number of references to fetch?"
-Number_of_references_to_fetch?=Aantal_referenties_om_op_te_halen?
-
occurrences=voorkomens
OK=OK
@@ -956,7 +885,8 @@ Open_file=Open_bestand
Open_last_edited_databases_at_startup=Open_laatst_aangepaste_databases_bij_het_opstarten
-Open_shared_database=
+Connect_to_shared_database=
+
Open_terminal_here=
Open_URL_or_DOI=Open_URL_of_DOI
@@ -966,6 +896,7 @@ Opened_database=Geopende_database
Opening=Aan_het_openen
Opening_preferences...=Instellingen_aan_het_openen
+
Operation_canceled.=Operatie_geannuleerd.
Operation_not_supported=
@@ -975,7 +906,6 @@ Options=Opties
or=of
-
Output=Uitvoer
Output_or_export_file=Geef_uitvoer_of_exporteer_bestand
@@ -987,6 +917,8 @@ Override_default_file_directories=Wijzig_standaard_bestandsmappen
Override_default_font_settings=Wijzig_standaard_lettertypeinstellingen
Override_the_BibTeX_field_by_the_selected_text=Wijzig_de_BibTeX-sleutel_door_de_geselecteerde_tekst
+
+
Overwrite=
Overwrite_existing_field_values=Overschrijf_bestaande_veld_waarden
@@ -1037,19 +969,23 @@ Preferences=Instellingen
Preferences_recorded.=Instellingen_opgeslagen.
Preview=Voorbeeld
+Citation_Style=
+Current_Preview=
+Cannot_generate_preview_based_on_selected_citation_style.=
+Bad_character_inside_entry=
+Error_while_generating_citation_style=
+Preview_style_changed_to\:_%0=
+Next_preview_layout=
+Previous_preview_layout=
Previous_entry=Vorige_entry
Primary_sort_criterion=Primair_sorteercriterium
-
Problem_with_parsing_entry=Probleem_met_entry_ontleding
-
Processing_%0=
-
Program_output=Programma_uitvoer
Pull_changes_from_shared_database=
-
Pushed_citations_to_%0=
Quit_JabRef=JabRef_afsluiten
@@ -1058,19 +994,16 @@ Quit_synchronization=Synchronisatie_afsluiten
Raw_source=Ruwe_bron
-
Rearrange_tabs_alphabetically_by_title=Rangschik_tabbladen_alfabetisch_op_titel
Redo=Herstellen
Reference_database=Referentie_database
-# The next two lines are used like in "References found\: 1 Number of references to fetch?"
-References_found=Referenties_gevonden
+%0_references_found._Number_of_references_to_fetch?=Referenties_gevonden\:_%0._Aantal_referenties_om_op_te_halen?
Refine_supergroup\:_When_selected,_view_entries_contained_in_both_this_group_and_its_supergroup=Verfijn_supergroep\:_Wanneer_geselecteerd,_toon_de_entries_die_in_deze_groep_en_zijn_supergroep_zitten
-
regular_expression=Regular_Expression
Remember_these_entry_types?=Deze_entry_types_behouden?
@@ -1081,13 +1014,10 @@ Remote_server_port=Externe_server_poort
Remove=Verwijderen
-
Remove_subgroups=Verwijder_alle_subgroepen
Remove_all_subgroups_of_"%0"?=Alle_subgroepen_van_"%0"_verwijderen?
-
-
Remove_entry_from_import=Verwijder_entry_uit_importering
Remove_entry_selection_from_this_group=Verwijder_entry_selectie_van_deze_groep
@@ -1095,7 +1025,6 @@ Remove_entry_selection_from_this_group=Verwijder_entry_selectie_van_deze_groep
Remove_entry_type=Verwijder_entry_type
Remove_file_link_(DELETE)=
-
Remove_from_group=Verwijder_uit_groep
Remove_group=Verwijder_groep
@@ -1118,7 +1047,6 @@ Remove_old_entry=Verwijder_oude_entry
Remove_selected_strings=Verwijder_geselecteerde_entries
-
Removed_group_"%0".=Groep_"%0"_verwijderd.
Removed_group_"%0"_and_its_subgroups.=Groep_"%0"_en_zijn_subgroepen_verwijderd.
@@ -1144,7 +1072,6 @@ Resolve_strings_for_standard_BibTeX_fields_only=
resolved=opgelost
-
Revert_to_original_source=Herstel_naar_originele_bron
Review=Recensie
@@ -1169,36 +1096,23 @@ Save_failed=Opslaan_mislukt
Save_failed_during_backup_creation=Opslaan_mislukt_tijdens_creatie_van_backup
-Save_failed_while_committing_changes\:_%0=Opslaan_mislukt_bij_het_vastleggen_van_veranderingen\:_%0
-
Save_selected_as...=Sla_geselecteerde_op_als_...
Saved_database=Database_opgeslagen
Saved_selected_to_'%0'.=Geselecteerde_opgeslagen_naar_'%0'.
-
Saving=Aan_het_opslaan
Saving_all_databases...=
Saving_database=Database_aan_het_opslaan
-
Search=Zoeken
-
-
Search_expression=Zoek_expressie
Search_for=Zoek_naar
-
-
-
-
-
-
-
Searching_for_duplicates...=Aan_het_zoeken_naar_dubbels
Searching_for_files=
@@ -1209,24 +1123,17 @@ Select=Selecteer
-
Select_all=Alles_selecteren
-
Select_encoding=Selecteer_encodering
-
Select_entry_type=Selecteer_entry_type
Select_external_application=Selecteer_externe_applicatie
Select_file_from_ZIP-archive=Selecteer_bestand_van_ZIP-archief
-
-
-
Select_the_tree_nodes_to_view_and_accept_or_reject_changes=Selecteer_de_boom_knopen_om_veranderingen_te_tonen_en_te_accepteren_of_afwijzen
Selected_entries=Geselecteerde_entries
-
Set_field=Veld_instellen
Set_fields=Velden_instellen
@@ -1237,11 +1144,9 @@ Set_table_font=Tabel_lettertype_instellen
Settings=Instellingen
-
-
Shortcut=Snelkoppeling
-Show/edit_BibTeX_source=Toon/bewerk_BibTeX-broncode
+Show/edit_%0_source=Toon/bewerk_%0-broncode
Show_'Firstname_Lastname'=Toon_'Voornaam_Familienaam'
@@ -1249,7 +1154,6 @@ Show_'Lastname,_Firstname'=Toon_'Familienaam,_Voornaam'
Show_BibTeX_source_by_default=Toon_standaard_BibTeX-broncode
-
Show_confirmation_dialog_when_deleting_entries=Toon_bevestigingsdialoog_bij_verwijderen_van_entries
Show_description=Toon_beschrijving
@@ -1265,29 +1169,23 @@ Show_last_names_only=Toon_enkel_laatste_namen
Show_names_unchanged=Toon_namen_onveranderd
-
-
Show_optional_fields=Toon_optionele_velden
-
Show_required_fields=Toon_vereiste_velden
Show_URL/DOI_column=Toon_URL/DOI-kolom
-
-
Simple_HTML=Eenvoudige_HTML
Size=Grootte
Skipped_-_No_PDF_linked=Overgeslagen_-_Geen_PDF_gelinkt
Skipped_-_PDF_does_not_exist=Overgeslagen_-_PDF_bestaat_niet
+
Skipped_entry.=Overgeslagen_entry.
Sort_alphabetically=Alphabetisch_sorteren
-
-
sort_subgroups=subgroepen_sorteren
Sorted_all_subgroups_recursively.=Alle_subgroepen_recursief_gesorteerd.
@@ -1299,8 +1197,6 @@ Special_name_formatters=
Special_table_columns=Speciale_tabelkolommen
-
-
Starting_import=Importeren_aan_het_starten
Statically_group_entries_by_manual_assignment=Groepeer_entries_statisch_door_manuele_toekenning
@@ -1311,7 +1207,6 @@ Stop=Stop
Store_journal_abbreviations=Tijdschrift_afkortingen_opslaan
-
Stored_entry=Entry_opgeslagen
Strings=Constanten
@@ -1320,8 +1215,6 @@ Strings_for_database=Constanten_voor_database
Subdatabase_from_AUX=Subdatabase_van_AUX
-
-##\## These lines were changed\:
Switches_between_full_and_abbreviated_journal_name_if_the_journal_name_is_known.=Schakelt_tussen_volledige_en_afgekorte_tijdschriftnaam_als_het_tijdschrift_gekend_is.
Synchronize_file_links=
@@ -1375,33 +1268,29 @@ The_search_is_case_sensitive.=De_zoekopdracht_is_hoofdlettergevoelig.
The_string_has_been_removed_locally=De_constante_werd_lokaal_verwijderd
There_are_possible_duplicates_(marked_with_an_icon)_that_haven't_been_resolved._Continue?=Er_zijn_mogelijke_dubbels_(aangeduid_met_een_icoon)_die_nog_niet_opgelost_werden._Verdergaan?
+
This_entry_has_no_BibTeX_key._Generate_key_now?=
This_entry_is_incomplete=Deze_entry_is_onvolledig
This_entry_type_cannot_be_removed.=Dit_entry_type_kan_niet_verwijderd_worden.
+
This_external_link_is_of_the_type_'%0',_which_is_undefined._What_do_you_want_to_do?=
This_group_contains_entries_based_on_manual_assignment._Entries_can_be_assigned_to_this_group_by_selecting_them_then_using_either_drag_and_drop_or_the_context_menu._Entries_can_be_removed_from_this_group_by_selecting_them_then_using_the_context_menu.=Deze_groep_bevat_entries_gebaseerd_op_manuele_toekenning._Entries_kunnen_aan_deze_groep_toegekend_worden_door_ze_te_selecteren_en_hierna_ofwel_"drag_and_drop"_of_het_contextmenu_te_gebruiken._Entries_kunnen_uit_deze_groep_verwijderd_worden_d [...]
-
-
-
This_group_contains_entries_whose_<b>%0</b>_field_contains_the_keyword_<b>%1</b>=Deze_groep_bevat_entries_waarin_het_<b>%0</b>_veld_het_sleutelwoord_<b>%1</b>_bevat
This_group_contains_entries_whose_<b>%0</b>_field_contains_the_regular_expression_<b>%1</b>=Deze_groep_bevat_entries_waarin_het_<b>%0</b>_veld_de_regular_expression_<b>%1</b>_bevat
-
This_makes_JabRef_look_up_each_file_link_and_check_if_the_file_exists._If_not,_you_will_be_given_options<BR>to_resolve_the_problem.=Dit_zorgt_ervoor_dat_JabRef_elke_bestand_snelkoppeling_op_zoekt_en_controleert_of_het_bestand_bestaat._Indien_dit_niet_het_geval_is,_zullen_u_opties_gegeven_worden<BR>om_het_probleem_op_te_lossen.
This_operation_requires_all_selected_entries_to_have_BibTeX_keys_defined.=Deze_operatie_vereist_dat_alle_geselecteerde_entries_BibTeX-sleutels_gedefinieerd_hebben.
This_operation_requires_one_or_more_entries_to_be_selected.=Deze_operatie_vereist_dat_een_of_meer_entries_geselecteerd_zijn.
-
Toggle_abbreviation=Toon_afkorting
Toggle_entry_preview=Toon_entry_voorbeeld
Toggle_groups_interface=Toon_groepenvenster
-
Try_different_encoding=Probeer_een_andere_encodering
Unabbreviate_journal_names_of_the_selected_entries=Maak_afkortingen_van_tijdschriftnamen_van_geselecteerde_entries_ongedaan
@@ -1420,7 +1309,6 @@ Unknown_BibTeX_entries=Onbekende_BibTeX-entries
unknown_edit=onbekende_aanpassing
-
Unknown_export_format=Onbekend_exporteerformaat
Unmark_all=Alle_markeringen_ongedaan_maken
@@ -1429,10 +1317,6 @@ Unmark_entries=Alle_markeringen_van_entries_ongedaan_maken
Unmark_entry=Markering_van_entry_ongedaan_maken
-
-
-Unsupported_version_of_class_%0\:_%1=Niet_ondersteunde_versie_van_klasse_%0\:_%1
-
untitled=naamloos
Up=Omhoog
@@ -1447,7 +1331,6 @@ Upgrade_old_external_file_links_to_use_the_new_feature=
usage=gebruik
Use_autocompletion_for_the_following_fields=
-
Use_other_look_and_feel=Gebruik_andere_"look_and_feel"
Use_regular_expression_search=Gebruik_Regular_Expression_Zoekopdracht
@@ -1482,10 +1365,10 @@ Will_write_XMP-metadata_to_the_PDFs_linked_from_selected_entries.=Zal_XMP_metada
with=met
Write_BibTeXEntry_as_XMP-metadata_to_PDF.=Schrijf_BibTeX-entry_als_XMP-metadata_naar_PDF.
+
Write_XMP=Schrijf_XMP
Write_XMP-metadata=
Write_XMP-metadata_for_all_PDFs_in_current_database?=
-
Writing_XMP-metadata...=XMP_metadata_aan_het_schrijven...
Writing_XMP-metadata_for_selected_entries...=XMP_metadata_voor_geselecteerde_entries_aan_het_schrijven...
@@ -1493,14 +1376,12 @@ Wrote_XMP-metadata=
XMP-annotated_PDF=XMP_geannoteerde_PDF
XMP_export_privacy_settings=
-
XMP-metadata=XMP_metadata
XMP-metadata_found_in_PDF\:_%0=
-
You_must_restart_JabRef_for_this_to_come_into_effect.=U_moet_JabRef_herstarten_om_dit_toe_te_passen.
You_have_changed_the_language_setting.=U_heeft_de_taalinstelling_veranderd.
-You_have_changed_the_look_and_feel_setting.=
+You_have_changed_the_look_and_feel_setting.=
You_have_entered_an_invalid_search_'%0'.=
@@ -1508,8 +1389,8 @@ You_must_choose_a_filename_to_store_journal_abbreviations=U_moet_een_bestandsnaa
You_must_restart_JabRef_for_the_new_key_bindings_to_work_properly.=U_moet_JabRef_herstarten_zodat_de_nieuwe_sneltoetsen_correct_kunnen_werken.
-
Your_new_key_bindings_have_been_stored.=Uw_nieuwe_sneltoetsen_zijn_opgeslagen.
+
The_following_fetchers_are_available\:=
Could_not_find_fetcher_'%0'=
Running_query_'%0'_with_fetcher_'%1'.=
@@ -1523,16 +1404,13 @@ Number_of_entries_successfully_imported=
Import_canceled_by_user=
Progress\:_%0_of_%1=
Error_while_fetching_from_%0=
-Fetching_Medline_by_id...=
-Fetching_Medline_by_term...=
-%0_import_canceled=
-Please_enter_a_valid_number=
-Please_enter_a_comma_separated_list_of_Medline_IDs_(numbers)_or_search_terms.=
+Please_enter_a_valid_number=
Show_search_results_in_a_window=
+Show_global_search_results_in_a_window=
+Search_in_all_open_databases=
Move_file_to_file_directory?=
Rename_to_'%0'=
-
You_have_changed_the_menu_and_label_font_size.=
Database_is_protected._Cannot_save_until_external_changes_have_been_reviewed.=
@@ -1540,53 +1418,60 @@ Protected_database=
Refuse_to_save_the_database_before_external_changes_have_been_reviewed.=
Database_protection=
Unable_to_save_database=
+
BibTeX_key_generator=
Unable_to_open_link.=
Move_the_keyboard_focus_to_the_entry_table=
MIME_type=
+
This_feature_lets_new_files_be_opened_or_imported_into_an_already_running_instance_of_JabRef<BR>instead_of_opening_a_new_instance._For_instance,_this_is_useful_when_you_open_a_file_in_JabRef<br>from_your_web_browser.<BR>Note_that_this_will_prevent_you_from_running_more_than_one_instance_of_JabRef_at_a_time.=
Run_fetcher,_e.g._"--fetch\=Medline\:cancer"=
+
The_ACM_Digital_Library=
Reset=
+
Use_IEEE_LaTeX_abbreviations=
The_Guide_to_Computing_Literature=
+
When_opening_file_link,_search_for_matching_file_if_no_link_is_defined=
Settings_for_%0=
Mark_entries_imported_into_an_existing_database=
Unmark_all_entries_before_importing_new_entries_into_an_existing_database=
+
Forward=
Back=
Sort_the_following_fields_as_numeric_fields=
Line_%0\:_Found_corrupted_BibTeX_key.=
Line_%0\:_Found_corrupted_BibTeX_key_(contains_whitespaces).=
Line_%0\:_Found_corrupted_BibTeX_key_(comma_missing).=
-Finished_downloading_full_text_document=
Full_text_document_download_failed=
Update_to_current_column_order=
-
+Download_from_URL=
Rename_field=
Set/clear/rename_fields=
Rename_field_to=
Move_contents_of_a_field_into_a_field_with_a_different_name=
-
You_can_only_rename_one_field_at_a_time=
+
Remove_all_broken_links=
+
Cannot_use_port_%0_for_remote_operation;_another_application_may_be_using_it._Try_specifying_another_port.=
Looking_for_full_text_document...=
Autosave=
-Prompt_before_recovering_a_database_from_an_autosave_file=
-Autosave_interval_(minutes)=
-Do_you_want_to_recover_the_database_from_the_autosave_file?=
-Recover_from_autosave=
+A_local_copy_will_be_opened.=
+Autosave_local_databases=
+Automatically_save_the_database_to=
+Please_enter_a_valid_file_path.=
+
Export_in_current_table_sort_order=
Export_entries_in_their_original_order=
Error_opening_file_'%0'.=
-Autosave_of_file_'%0'=
-Error_opening_autosave_of_'%0'._Trying_to_load_'%0'_instead.=
+
Formatter_not_found\:_%0=
Clear_inputarea=
+
Automatically_set_file_links_for_this_entry=
Could_not_save,_file_locked_by_another_JabRef_instance.=
File_is_locked_by_another_JabRef_instance.=
@@ -1613,8 +1498,6 @@ includes_subgroups=
contains=
search_expression=
-
-
Optional_fields_2=
Waiting_for_save_operation_to_finish=
Resolving_duplicate_BibTeX_keys...=
@@ -1645,14 +1528,12 @@ Highlight_groups_that_contain_entries_contained_in_any_currently_selected_group=
You_must_enter_an_integer_value_in_the_interval_1025-65535_in_the_text_field_for=
Automatically_open_browse_dialog_when_creating_new_file_link=
-
Import_metadata_from\:=
Choose_the_source_for_the_metadata_import=
Create_entry_based_on_XMP_data=
Create_blank_entry_linking_the_PDF=
Only_attach_PDF=
Title=
-No_internet_connection.=
Create_new_entry=
Update_existing_entry=
Autocomplete_names_in_'Firstname_Lastname'_format_only=
@@ -1728,13 +1609,11 @@ Select_document=
Edit_group_membership=
HTML_list=
Click_group_to_toggle_membership_of_selected_entries=
-Use_EMACS_23_insertion_string=
If_possible,_normalize_this_list_of_names_to_conform_to_standard_BibTeX_name_formatting=
Could_not_open_%0=
Unknown_import_format=
Web_search=
Style_selection=
-
No_valid_style_file_defined=
Choose_pattern=
Use_the_BIB_file_location_as_primary_file_directory=
@@ -1744,14 +1623,16 @@ OpenOffice/LibreOffice_connection=
You_can_add_additional_journal_names_by_setting_up_a_personal_journal_list,<br>as_well_as_linking_to_external_journal_lists.=
JabRef_includes_a_built-in_list_of_journal_abbreviations.=
You_must_select_either_a_valid_style_file,_or_use_one_of_the_default_styles.=
+
This_is_a_simple_copy_and_paste_dialog._First_load_or_paste_some_text_into_the_text_input_area.<br>After_that,_you_can_mark_text_and_assign_it_to_a_BibTeX_field.=
-%0_mode=
This_feature_generates_a_new_database_based_on_which_entries_are_needed_in_an_existing_LaTeX_document.=
You_need_to_select_one_of_your_open_databases_from_which_to_choose_entries,_as_well_as_the_AUX_file_produced_by_LaTeX_when_compiling_your_document.=
+
First_select_entries_to_clean_up.=
Cleanup_entry=
Autogenerate_PDF_Names=
Auto-generating_PDF-Names_does_not_support_undo._Continue?=
+
Use_full_firstname_whenever_possible=
Use_abbreviated_firstname_whenever_possible=
Use_abbreviated_and_full_firstname=
@@ -1761,6 +1642,7 @@ Name_format_used_for_autocompletion=
Treatment_of_first_names=
Cleanup_entries=
Automatically_assign_new_entry_to_selected_groups=
+%0_mode=
Move_DOIs_from_note_and_URL_field_to_DOI_field_and_remove_http_prefix=
Make_paths_of_linked_files_relative_(if_possible)=
Rename_PDFs_to_given_filename_format_pattern=
@@ -1778,7 +1660,6 @@ Remove_selected=
Group_tree_could_not_be_parsed._If_you_save_the_BibTeX_database,_all_groups_will_be_lost.=
Attach_file=
-
Setting_all_preferences_to_default_values.=
Resetting_preference_key_'%0'=
Unknown_preference_key_'%0'=
@@ -1821,7 +1702,6 @@ Five_stars=
Four_stars=
Help_on_special_fields=
Keywords_of_selected_entries=
-Manage_content_selectors=
Manage_keywords=
No_priority_information=
No_rank_information=
@@ -1849,10 +1729,10 @@ Two_stars=
Update_keywords=
Write_values_of_special_fields_as_separate_fields_to_BibTeX=
You_have_changed_settings_for_special_fields.=
-
%0_entries_found._To_reduce_server_load,_only_%1_will_be_downloaded.=
A_string_with_that_label_already_exists=
Connection_to_OpenOffice/LibreOffice_has_been_lost._Please_make_sure_OpenOffice/LibreOffice_is_running,_and_try_to_reconnect.=
+
Correct_the_entry,_and_reopen_editor_to_display/edit_source.=
Could_not_connect_to_a_running_gnuserv_process._Make_sure_that_Emacs_or_XEmacs_is_running,<BR>and_that_the_server_has_been_started_(by_running_the_command_'server-start'/'gnuserv-start').=
Could_not_connect_to_running_OpenOffice/LibreOffice.=
@@ -1874,19 +1754,14 @@ Your_style_file_specifies_the_paragraph_format_'%0',_which_is_undefined_in_your_
Searching...=
You_have_selected_more_than_%0_entries_for_download._Some_web_sites_might_block_you_if_you_make_too_many_rapid_downloads._Do_you_want_to_continue?=
Confirm_selection=
-Unknown_DOI\:_'%0'.=Unbekende_DOI\:_'%0'.
Add_{}_to_specified_title_words_on_search_to_keep_the_correct_case=
Import_conversions=
Please_enter_a_search_string=
Please_open_or_start_a_new_database_before_searching=
-An_error_occurred_while_fetching_from_ADS_(%0)\:=
-An_error_occurred_while_parsing_abstract=
-Unknown_DiVA_entry\:_'%0'.=
-Get_BibTeX_entry_from_DiVA=
Log=
-
Canceled_merging_entries=
+
Format_units_by_adding_non-breaking_separators_and_keeping_the_correct_case_on_search=
Merge_entries=
Merged_entries=
@@ -1900,30 +1775,35 @@ Use_Emacs_key_bindings=
You_have_to_choose_exactly_two_entries_to_merge.=
Update_timestamp_on_modification=
-
All_key_bindings_will_be_reset_to_their_defaults.=
+
Automatically_set_file_links=
Continue?=
Resetting_all_key_bindings=
-
Hostname=
Invalid_setting=
Network=Netwerk
Please_specify_both_hostname_and_port=
-Port=Poort
+Please_specify_both_username_and_password=
+
Use_custom_proxy_configuration=
+Proxy_requires_authentication=
+Attention\:_Password_is_stored_in_plain_text\!=
Clear_connection_settings=
Cleared_connection_settings.=
+
Rebind_C-a,_too=
+Rebind_C-f,_too=
Show_number_of_elements_contained_in_each_group=
Open_folder=Open_map
Searches_for_unlinked_PDF_files_on_the_file_system=
-
Export_entries_ordered_as_specified=
Export_sort_order=
+Export_sorting=
Newline_separator=
+
Save_entries_ordered_as_specified=
Save_sort_order=
Show_extra_columns=
@@ -1934,7 +1814,6 @@ Move_to_group=
Clear_read_status=
Convert_to_BibLatex_format_(for_example,_move_the_value_of_the_'journal'_field_to_'journaltitle')=
-Could_not_apply_changes.=
Deprecated_fields=
Hide/show_toolbar=
No_read_status_information=
@@ -1946,123 +1825,109 @@ Save_selected_as_plain_BibTeX...=
Set_read_status_to_read=
Set_read_status_to_skimmed=
Show_deprecated_BibTeX_fields=
+
Show_gridlines=
Show_printed_status=
Show_read_status=
Table_row_height_padding=
-Marked_all_%0_selected_entries=
Marked_selected_entry=
-Toggle_print_status=
-Unmarked_all_%0_selected_entries=
+Marked_all_%0_selected_entries=
Unmarked_selected_entry=
+Unmarked_all_%0_selected_entries=
+Toggle_print_status=
+
Unmarked_all_entries=
Unable_to_find_the_requested_look_and_feel_and_thus_the_default_one_is_used.=
-Could_not_open_browser.=
Opens_JabRef's_GitHub_page=
-
-Rebind_C-f,_too=
-This_group_contains_all_entries._It_cannot_be_edited_or_removed.=
+Could_not_open_browser.=
+Please_open_%0_manually.=
+The_link_has_been_copied_to_the_clipboard.=
Open_%0_file=
Cannot_delete_file=
-Convert=
-Delete_local_file=
File_permission_error=
-Help_on_Name_Formatting=
-Normalize_to_BibTeX_name_format=
Push_to_%0=Stuur_selectie_naar_%0
+Path_to_%0=
+Convert=
+Normalize_to_BibTeX_name_format=
+Help_on_Name_Formatting=
Add_new_file_type=
-Follow_DOI_or_URL_link_and_try_to_locate_PDF_full_text_document=
+
Left_entry=
-No_information_added=
+Right_entry=
+Use=
Original_entry=
Replace_original_entry=
-Right_entry=
+No_information_added=
Select_at_least_one_entry_to_manage_keywords.=
-Use=
-Changed_type_to_'%0'_for=Type_gewijzigd_naar_'%0'_voor
-Database_'%0'_has_changed.=
-Copy_\\cite{BibTeX_key}=Kopieer_\\cite{BibTeX-sleutel}
-Copy_BibTeX_key_and_title=Kopieer_BibTeX_sleutel_en_titel
-File_rename_failed_for_%0_entries.=
-To_set_up,_go_to=Om_in_te_stellen,_ga_naar
-Search_%0=Zoek_%0
-Invalid_DOI\:_'%0'.=Ongeldig_DOI\:_'%0'.
-Could_not_connect_to_%0=
-
+OpenDocument_text=
+OpenDocument_spreadsheet=
+OpenDocument_presentation=
%0_image=
-%0_problem(s)_found=
-'%0'_is_not_a_valid_ADS_bibcode.=
-Accepting_the_change_replaces_the_complete_groups_tree_with_the_externally_modified_groups_tree.=
Added_entry=
-Added_new_'%0'_entry.=
-Deleted_entry=
-Discard_changes=
-Donate_to_JabRef=
-Export_with_selected_format=
-Field_is_missing=
-Filled=
-From_import=
-Keep_left=
-Keep_merged_entry_only=
-Keep_right=
-Merged_BibTeX_source_code=
Modified_entry=
+Deleted_entry=
Modified_groups_tree=
-Multiple_entries_selected._Do_you_want_to_change_the_type_of_all_these_to_'%0'?=
-No_problems_found.=
-Old_entry=
-OpenDocument_presentation=
-OpenDocument_spreadsheet=
-OpenDocument_text=
-Path_to_%0=
-Please_move_the_file_manually_and_link_in_place.=
-Print_entry_preview=
-Really_delete_the_%0_selected_entries?=
-Really_delete_the_selected_entry?=
Removed_all_groups=
-Return_to_JabRef=
-Save_changes=
+Accepting_the_change_replaces_the_complete_groups_tree_with_the_externally_modified_groups_tree.=
Select_export_format=
+Return_to_JabRef=
+Please_move_the_file_manually_and_link_in_place.=
+Could_not_connect_to_%0=
Warning\:_%0_out_of_%1_entries_have_undefined_BibTeX_key.=
-large_capitals_are_not_masked_using_curly_brackets_{}=
occurrence=
-should_contain_a_four_digit_number=
-should_contain_a_valid_page_number_range=
-should_end_with_a_name=
+Added_new_'%0'_entry.=
+Multiple_entries_selected._Do_you_want_to_change_the_type_of_all_these_to_'%0'?=
+Changed_type_to_'%0'_for=Type_gewijzigd_naar_'%0'_voor
+Really_delete_the_selected_entry?=
+Really_delete_the_%0_selected_entries?=
+Keep_merged_entry_only=
+Keep_left=
+Keep_right=
+Old_entry=
+From_import=
+No_problems_found.=
+%0_problem(s)_found=
+Save_changes=
+Discard_changes=
+Database_'%0'_has_changed.=
+Print_entry_preview=
+Copy_\\cite{BibTeX_key}=Kopieer_\\cite{BibTeX-sleutel}
+Copy_BibTeX_key_and_title=Kopieer_BibTeX_sleutel_en_titel
+File_rename_failed_for_%0_entries.=
+To_set_up,_go_to=Om_in_te_stellen,_ga_naar
+Merged_BibTeX_source_code=
+Invalid_DOI\:_'%0'.=Ongeldig_DOI\:_'%0'.
should_start_with_a_name=
+should_end_with_a_name=
unexpected_closing_curly_bracket=
unexpected_opening_curly_bracket=
+capital_letters_are_not_masked_using_curly_brackets_{}=
+should_contain_a_four_digit_number=
+should_contain_a_valid_page_number_range=
+Filled=
+Field_is_missing=
+Search_%0=Zoek_%0
-Work_options=
-
-Advanced_search_active.=
-Found_%0_results.=
-No_results_found.=
-Normal_search_active.=
-Search_globally=
-Search_in_all_open_databases=
Search_results_in_all_databases_for_%0=
Search_results_in_database_%0_for_%1=
-This_search_contains_entries_in_which=
+Search_globally=
+No_results_found.=
+Found_%0_results.=
+Advanced_search_active.=
+Normal_search_active.=
+plain_text=
This_search_contains_entries_in_which_any_field_contains_the_regular_expression_<b>%0</b>=
This_search_contains_entries_in_which_any_field_contains_the_term_<b>%0</b>=
-plain_text=
-
-Attention\:_Password_is_stored_in_plain_text\!=
-Please_specify_both_username_and_password=
-Proxy_requires_authentication=
+This_search_contains_entries_in_which=
-An_autosave_file_was_found_for_this_database._This_could_indicate_that_JabRef_did_not_shut_down_cleanly_last_time_the_file_was_used.=
-Note\:_A_full_text_search_is_currently_not_supported_for_%0=
Unable_to_autodetect_OpenOffice/LibreOffice_installation._Please_choose_the_installation_directory_manually.=
-
JabRef_no_longer_supports_'ps'_or_'pdf'_fields.<br>File_links_are_now_stored_in_the_'file'_field_and_files_are_stored_in_an_external_file_directory.<br>To_make_use_of_this_feature,_JabRef_needs_to_upgrade_file_links.<br><br>=
This_database_uses_outdated_file_links.=
@@ -2101,55 +1966,32 @@ Resolve_duplicate_BibTeX_keys=
Save_all=
String_dialog,_add_string=
String_dialog,_remove_string=
-Switch_preview_layout=
Synchronize_files=
Unabbreviate=
-
should_contain_a_protocol=
Copy_preview=
-
Automatically_setting_file_links=
Regenerating_BibTeX_keys_according_to_metadata=
No_meta_data_present_in_BIB_file._Cannot_regenerate_BibTeX_keys=
-
Regenerate_all_keys_for_the_entries_in_a_BibTeX_file=
-
Show_debug_level_messages=
-
-Export_sorting=
-
-New_%0_database=
-
-New_%0_database_created.=
-
-No_entry_found_for_ISBN_%0_at_www.ebook.de=
-
-Save_actions=
-Enable_save_actions=
-Always_reformat_BIB_file_on_save_and_export=
Default_bibliography_mode=
-
-
+New_%0_database_created.=
Show_only_preferences_deviating_from_their_default_value=
default=
key=
type=
value=
-
Show_preferences=
-
-
+Save_actions=
+Enable_save_actions=
Other_fields=
Show_remaining_fields=
link_should_refer_to_a_correct_file_path=
-
abbreviation_detected=
wrong_entry_type_as_proceedings_has_page_numbers=
-
-Run_field_formatter\:=
-
Abbreviate_journal_names=
Abbreviating...=
Adding_fetched_entries=
@@ -2161,27 +2003,22 @@ Unabbreviate_journal_names=
Unabbreviating...=
Usage=
-Adds_{}_brackets_around_acronyms,_month_names_and_countries_to_preserve_their_case.=
-Converts_units_to_LaTeX_formatting.=
-Does_nothing.=
+Adds_{}_brackets_around_acronyms,_month_names_and_countries_to_preserve_their_case.=
Are_you_sure_you_want_to_reset_all_settings_to_default_values?=
Reset_preferences=
-
Ill-formed_entrytype_comment_in_BIB_file=
+
+Move_linked_files_to_default_file_directory_%0=
+
Clipboard=
Could_not_paste_entry_as_text\:=
Do_you_still_want_to_continue?=
This_action_will_modify_the_following_field(s)_in_at_least_one_entry_each\:=
This_could_cause_undesired_changes_to_your_entries.=
-
-Disable_highlight_groups_matching_entries=
-
-
+Run_field_formatter\:=
Table_font_size_is_%0=
-
-Move_linked_files_to_default_file_directory_%0=
-
+%0_import_canceled=
Internal_style=
Add_style_file=
Are_you_sure_you_want_to_remove_the_style?=
@@ -2189,7 +2026,6 @@ Current_style_is_'%0'=
Remove_style=
Select_one_of_the_available_styles_or_add_a_style_file_from_disk.=
You_must_select_a_valid_style_file.=
-
Reload=
Capitalize=
@@ -2200,9 +2036,11 @@ Changes_all_letters_to_upper_case.=
Changes_the_first_letter_of_all_words_to_capital_case_and_the_remaining_letters_to_lower_case.=
Cleans_up_LaTeX_code.=
Converts_HTML_code_to_LaTeX_code.=
+Converts_HTML_code_to_Unicode.=
Converts_LaTeX_encoding_to_Unicode_characters.=
Converts_Unicode_characters_to_LaTeX_encoding.=
Converts_ordinals_to_LaTeX_superscripts.=
+Converts_units_to_LaTeX_formatting.=
HTML_to_LaTeX=
LaTeX_cleanup=
LaTeX_to_Unicode=
@@ -2226,16 +2064,13 @@ Title_case=
Unicode_to_LaTeX=
Units_to_LaTeX=
Upper_case=
+Does_nothing.=
Identity=
-
Clears_the_field_completely.=
Directory_not_found=
Main_file_directory_not_set\!=
-
This_operation_requires_exactly_one_item_to_be_selected.=
-
Importing_in_%0_format=
-
Female_name=
Female_names=
Male_name=
@@ -2244,8 +2079,6 @@ Mixed_names=
Neuter_name=
Neuter_names=
-
-
Lookup_DOI=
Audio_CD=
@@ -2282,38 +2115,29 @@ U.S._patent=
U.S._patent_request=
Verse=
-
change_entries_of_group=
odd_number_of_unescaped_'\#'=
+
Plain_text=
Show_diff=
character=
word=
-
Show_symmetric_diff=
HTML_encoded_character_found=
-
booktitle_ends_with_'conference_on'=
+
All_external_files=
OpenOffice/LibreOffice_integration=
incorrect_control_digit=
incorrect_format=
-
-Expected_"%0"_to_contain_whitespace=
-Syntax_error_in_regular-expression_pattern=
-
Copy_version_to_clipboard=
Copied_version_to_clipboard=
+
BibTeX_key=
Message=
-
-Get_fulltext=
-
-Download_from_URL=
-
Decryption_not_supported.=
Cleared_'%0'_for_%1_entries=
@@ -2332,16 +2156,11 @@ To_see_what_is_new_view_the_changelog.=
A_new_version_of_JabRef_has_been_released.=
JabRef_is_up-to-date.=
Latest_version=
-
-Please_open_%0_manually.=
-
-The_link_has_been_copied_to_the_clipboard.=
-
Online_help_forum=
-
Custom=
-Converts_HTML_code_to_Unicode.=
+Export_cited=
+Unable_to_generate_new_database=
Open_console=
Use_default_terminal_emulator=
@@ -2349,30 +2168,22 @@ Execute_command=
Note\:_Use_the_placeholder_%0_for_the_location_of_the_opened_database_file.=
Executing_command_\"%0\"...=
Error_occured_while_executing_the_command_\"%0\".=
-
Reformat_ISSN=
-Unable_to_generate_new_database=
-
-Export_cited=
Countries_and_territories_in_English=
Electrical_engineering_terms=
Enabled=
Internal_list=
+Manage_protected_terms_files=
Months_and_weekdays_in_English=
The_text_after_the_last_line_starting_with_\#_will_be_used=
-
Add_protected_terms_file=
Are_you_sure_you_want_to_remove_the_protected_terms_file?=
Remove_protected_terms_file=
-
-Manage_protected_terms_files=
-
Add_selected_text_to_list=
Add_{}_around_selected_text=
Format_field=
New_protected_terms_file=
-
change_field_%0_of_entry_%1_from_%2_to_%3=
change_key_from_%0_to_%1=
change_string_content_%0_to_%1=
@@ -2382,36 +2193,29 @@ insert_entry_%0=
insert_string_%0=
remove_entry_%0=
remove_string_%0=
-
undefined=
Cannot_get_info_based_on_given_%0\:_%1=
-
Get_BibTeX_data_from_%0=
No_%0_found=
-
Entry_from_%0=
-
Merge_entry_with_%0_information=
Updated_entry_with_info_from_%0=
Connection=
+Connecting...=
Host=
+Port=Poort
Database=
User=
+Connect=Verbinden
Connection_error=
-Driver_error=
Connection_to_%0_server_established.=
Required_field_"%0"_is_empty.=
-
%0_driver_not_available.=
-
The_connection_to_the_server_has_been_terminated.=
-
Connection_lost.=
Reconnect=
Work_offline=
-
Working_offline.=
-
Update_refused.=
Update_refused=
Local_entry=
@@ -2422,7 +2226,12 @@ Local_version\:_%0=
Shared_version\:_%0=
Please_merge_the_shared_entry_with_yours_and_press_"Merge_entries"_to_resolve_this_problem.=
Canceling_this_operation_will_leave_your_changes_unsynchronized._Cancel_anyway?=
-The_BibEntry_you_currently_work_on_has_been_deleted_on_the_shared_side._Hit_"Keep"_to_recover_the_entry.=
+Shared_entry_is_no_longer_present=
+The_BibEntry_you_currently_work_on_has_been_deleted_on_the_shared_side.=
+You_can_restore_the_entry_using_the_"Undo"_operation.=
+Remember_password?=
+You_are_already_connected_to_a_database_using_entered_connection_details.=
+
Cannot_cite_entries_without_BibTeX_keys._Generate_keys_now?=
New_technical_report=
@@ -2432,12 +2241,8 @@ Protected_terms_file=
Style_file=
Open_OpenOffice/LibreOffice_connection=
-
You_must_enter_at_least_one_field_name=
-
-
Non-ASCII_encoded_character_found=
-
Toggle_web_search_interface=
Background_color_for_resolved_fields=
Color_code_for_resolved_fields=
@@ -2451,13 +2256,59 @@ There_were_%0_files_which_could_not_be_imported.=
Migration_help_information=
Entered_database_has_obsolete_structure_and_is_no_longer_supported.=
However,_a_new_database_was_created_alongside_the_pre-3.6_one.=
-
Click_here_to_learn_about_the_migration_of_pre-3.6_databases.=
-
-Connecting...=
Opens_JabRef's_Facebook_page=
Opens_JabRef's_blog=
Opens_JabRef's_website=
-
Opens_a_link_where_the_current_development_version_can_be_downloaded=
See_what_has_been_changed_in_the_JabRef_versions=
+Referenced_BibTeX_key_does_not_exist=
+Finished_downloading_full_text_document_for_entry_%0.=
+Full_text_document_download_failed_for_entry_%0.=
+Look_up_full_text_documents=
+You_are_about_to_look_up_full_text_documents_for_%0_entries.=
+last_four_nonpunctuation_characters_should_be_numerals=
+shared=
+should_contain_an_integer_or_a_literal=
+should_have_the_first_letter_capitalized=
+
+ID=
+ID_type=
+ID-based_entry_generator=
+Fetcher_'%0'_did_not_find_an_entry_for_id_'%1'.=
+
+Select_first_entry=
+Select_last_entry=
+
+Invalid_ISBN\:_'%0'.=
+should_be_an_integer_or_normalized=
+should_be_normalized=
+
+Empty_search_ID=
+The_given_search_ID_was_empty.=
+Copy_BibTeX_key_and_link=
+empty_BibTeX_key=
+BibLaTeX_field_only=
+
+Error_while_generating_fetch_URL=
+Error_while_parsing_ID_list=
+Unable_to_get_PubMed_IDs=
+Backup_found=
+A_backup_file_for_'%0'_was_found.=
+This_could_indicate_that_JabRef_did_not_shut_down_cleanly_last_time_the_file_was_used.=
+Do_you_want_to_recover_the_database_from_the_backup_file?=
+Firstname_Lastname=
+
+Recommended_for_%0=
+This_might_be_caused_by_reaching_the_traffic_limitation_of_Google_Scholar_(see_'Help'_for_details).=
+
+Problem_downloading_from_%1=
+
+File_directory_pattern=
+Update_with_bibliographic_information_from_the_web=
+
+Could_not_find_any_bibliographic_information.=
+BibTeX_key_%0_deviates_from_generated_key_%1=
+DOI_%0_is_invalid=
+
+Jump_to_entry=
diff --git a/src/main/resources/l10n/JabRef_no.properties b/src/main/resources/l10n/JabRef_no.properties
index c8e9ccd..c70b508 100644
--- a/src/main/resources/l10n/JabRef_no.properties
+++ b/src/main/resources/l10n/JabRef_no.properties
@@ -1,6 +1,6 @@
#!
-#! created/edited by Popeye version 0.55 (https\://github.com/koppor/popeye)
-#! encoding:ISO-8859-1
+#! created/edited by Popeye version 0.55 (github.com/JabRef/popeye)
+#! encoding:UTF-8
%0_contains_the_regular_expression_<b>%1</b>=%0_inneholder_regul\u00e6ruttrykket_<b>%1</b>
@@ -12,26 +12,18 @@
%0_export_successful=%0-eksport_lyktes
-
%0_matches_the_regular_expression_<b>%1</b>=%0_matcher_regul\u00e6ruttrykket_<b>%1</b>
%0_matches_the_term_<b>%1</b>=%0_matcher_uttrykket_<b>%1</b>
-<field_name>=<feltnavn>
-
<HTML>Could_not_find_file_'%0'<BR>linked_from_entry_'%1'</HTML>=<HTML>Kunne_ikke_finne_filen_'%0'<BR>linket_fra_enheten_'%1'</HTML>
-
<select>=<velg>
-<select_word>=<velg_ord>
-
Abbreviate_journal_names_of_the_selected_entries_(ISO_abbreviation)=Forkort_journalnavn_for_de_valgte_enhetene_(ISO-forkortelse)
-
Abbreviate_journal_names_of_the_selected_entries_(MEDLINE_abbreviation)=Forkort_journalnavn_for_de_valgte_enhetene_(MEDLINE-forkortelse)
Abbreviate_names=Forkort_navn
-
Abbreviated_%0_journal_names.=Fortkortet_%0_journalnavn.
Abbreviation=Forkortelse
@@ -48,11 +40,11 @@ Action=Aksjon
Add=Legg_til
-Add_a_(compiled)_custom_ImportFormat_class_from_a_class_path.=Legg_til_en_(kompilert)_egendefinert_ImportFormat-klasse_fra_en_classpath.
+Add_a_(compiled)_custom_Importer_class_from_a_class_path.=Legg_til_en_(kompilert)_egendefinert_Importer-klasse_fra_en_classpath.
The_path_need_not_be_on_the_classpath_of_JabRef.=Stien_trenger_ikke_\u00e5_v\u00e6re_p\u00e5_JabRefs_classpath.
-Add_a_(compiled)_custom_ImportFormat_class_from_a_ZIP-archive.=Legg_til_en_(kompilert)_egendefinert_ImportFormat-klasse_fra_en_zip-fil.
-The_ZIP-archive_need_not_be_on_the_classpath_of_JabRef.=ZIP-filen_trenger_ikke_\u00e5_v\u00e6re_p\u00e5_JabRefs_classpath.
+Add_a_(compiled)_custom_Importer_class_from_a_ZIP-archive.=Legg_til_en_(kompilert)_egendefinert_Importer-klasse_fra_en_zip-fil.
+The_ZIP-archive_need_not_be_on_the_classpath_of_JabRef.=ZIP-filen_trenger_ikke_\u00e5_v\u00e6re_p\u00e5_JabRefs_classpath.
Add_entry_selection_to_this_group=Legg_valgte_enheter_til_denne_gruppen
@@ -79,24 +71,18 @@ Added_string=La_til_streng
Additionally,_entries_whose_<b>%0</b>_field_does_not_contain_<b>%1</b>_can_be_assigned_manually_to_this_group_by_selecting_them_then_using_either_drag_and_drop_or_the_context_menu._This_process_adds_the_term_<b>%1</b>_to_each_entry's_<b>%0</b>_field._Entries_can_be_removed_manually_from_this_group_by_selecting_them_then_using_the_context_menu._This_process_removes_the_term_<b>%1</b>_from_each_entry's_<b>%0</b>_field.=Dessuten,_enheter_hvis_<b>%0</b>-felt_ikke_inneholder_<b>%1</b>_kan_leg [...]
Advanced=Avansert
-
-
-
All_entries=Alle_enheter
-
All_entries_of_this_type_will_be_declared_typeless._Continue?=Alle_enhetene_av_denne_typen_vil_bli_klassifisert_som_typel\u00f8se._Fortsette?
All_fields=Alle_felter
All_subgroups_(recursively)=Alle_undergrupper_(rekursivt)
-
-An_exception_occurred_while_accessing_'%0'=En_feil_oppsto_ved_lesing_av_'%0'
+Always_reformat_BIB_file_on_save_and_export=
A_SAX_exception_occurred_while_parsing_'%0'\:=En_SAXException_forekom_ved_lesing_av_'%0'\:
-and=og
-
+and=og
and_the_class_must_be_available_in_your_classpath_next_time_you_start_JabRef.=og_klassen_m\u00e5_v\u00e6re_tilgjengelig_i_CLASSPATH_neste_gang_du_starter_JabRef.
any_field_that_matches_the_regular_expression_<b>%0</b>=ethvert_felt_som_matcher_regul\u00e6ruttrykket_<b>%0</b>
@@ -104,13 +90,11 @@ any_field_that_matches_the_regular_expression_<b>%0</b>=ethvert_felt_som_matcher
Appearance=Utseende
Append=Legg_til
-
Append_contents_from_a_BibTeX_database_into_the_currently_viewed_database=Legg_til_innhold_fra_en_BibTeX-database_i_den_\u00e5pne_database
Append_database=Append_database
Append_the_selected_text_to_BibTeX_field=Legg_til_den_valgte_teksten_til_BibTeX-n\u00f8kkelen
-
Application=Applikasjon
Apply=Utf\u00f8r
@@ -127,21 +111,16 @@ Assigned_%0_entries_to_group_"%1".=La_til_%0_enheter_til_gruppen_"%1".
Assigned_1_entry_to_group_"%0".=La_til_1_enhet_til_gruppen_"%0".
-
Attach_URL=Tilordne_URL
Attempt_to_automatically_set_file_links_for_your_entries._Automatically_setting_works_if_a_file_in_your_file_directory<BR>or_a_subdirectory_is_named_identically_to_an_entry's_BibTeX_key,_plus_extension.=Pr\u00f8v_\u00e5_sette_fil-linker_automatisk_for_dine_enheter._Dette_virker_dersom_en_fil_i_fil-katalogen_din_eller_en_underkatalog<BR>har_navn_likt_en_enhets_BibTeX-n\u00f8kkel,_pluss_etternavn.
-
Auto=Auto
Autodetect_format=Autodetekter_format
-
Autogenerate_BibTeX_keys=Autogenerer_BibTeX-n\u00f8kler
-
-
Autolink_files_with_names_starting_with_the_BibTeX_key=Autolink_filer_med_navn_som_starter_med_BibTeX-n\u00f8kkelen
Autolink_only_files_that_match_the_BibTeX_key=Autolink_bare_filer_med_navn_som_samsvarer_med_BibTeX-n\u00f8kkelen
@@ -153,10 +132,10 @@ Automatically_create_groups_for_database.=Generer_grupper_for_databasen.
Automatically_created_groups=Genererte_grupper_automatisk
Automatically_remove_exact_duplicates=Fjern_eksakte_duplikater_automatisk
-Allow_overwriting_existing_links.=Tillat_overskriving_av_eksisterende_linker.
-Do_not_overwrite_existing_links.=Skriv_ikke_over_eksisterende_linker.
+Allow_overwriting_existing_links.=Tillat_overskriving_av_eksisterende_linker.
+Do_not_overwrite_existing_links.=Skriv_ikke_over_eksisterende_linker.
AUX_file_import=AUX-fil_import
@@ -172,13 +151,9 @@ Background_color_for_required_fields=Bakgrunnsfarge_for_n\u00f8dvendige_felter
Backup_old_file_when_saving=Lag_sikkerhetskopi_ved_lagring
-
BibTeX_key_is_unique.=BibTeX-n\u00f8kkelen_er_unik
-
-BibTeX_source=BibTeX-kilde
-
-
+%0_source=%0-kilde
Broken_link=Ugyldig_link
@@ -211,7 +186,6 @@ change_assignment_of_entries=endre_tilordning_av_enheter
Change_case=Endre_store/sm\u00e5_bokstaver
Change_entry_type=Endre_enhetstype
-
Change_file_type=Endre_filtype
@@ -219,11 +193,8 @@ Change_of_Grouping_Method=Endre_grupperingsm\u00e5te
change_preamble=endre_'preamble'
-
-
Change_table_column_and_General_fields_settings_to_use_the_new_feature=Endre_oppsett_for_tabellkollonner_og_generelle_felter_for_\u00e5_ta_i_bruk_den_nye_funksjonen
-
Changed_font_settings=Endret_skriftoppsett
Changed_language_settings=Endret_spr\u00e5koppsett
@@ -239,25 +210,22 @@ Check_existing_file_links=Sjekk_eksisterende_fil-linker
Check_links=Sjekk_eksterne_linker
Choose_the_URL_to_download.=Velg_URL_for_nedlasting.
-
Cite_command=Siteringskommando
Class_name=Klassenavn
Clear=Opphev
-
Clear_fields=Slett_felter
-
Close=Lukk
Close_others=
Close_all=
+
Close_dialog=Lukk_dialog
Close_the_current_database=Lukk_denne_databasen
-
Close_window=Lukk_vindu
Closed_database=Lukket_database
@@ -272,9 +240,6 @@ Column_width=Kolonnebredde
Command_line_id=Kommandolinje-id
-Connect=Koble_til
-
-
Contained_in=Inneholdt_i
@@ -291,38 +256,30 @@ Copied_keys=Kopierte_n\u00f8kler
Copy=Kopier
Copy_BibTeX_key=Kopier_BibTeX-n\u00f8kkel
-
Copy_file_to_file_directory=Kopier_fil_til_filkatalog
-
Copy_to_clipboard=Kopier_til_utklippstavle
Could_not_call_executable=Kunne_ikke_kalle_programfilen
-
Could_not_connect_to_Vim_server._Make_sure_that_Vim_is_running<BR>with_correct_server_name.=Kunne_ikke_koble_til_Vim-server._Sjekk_at_Vim_kj\u00f8rer<BR>med_riktig_servernavn.
Could_not_export_file=Kunne_ikke_eksportere
Could_not_export_preferences=Kunne_ikke_eksportere_innstillinger
-# I have reformulated the following lines, because the 1st person form is not suitable\:
Could_not_find_a_suitable_import_format.=Fant_ikke_noe_passende_importformat.
-
Could_not_import_preferences=Kunne_ikke_importere_innstillinger
Could_not_instantiate_%0=Kunne_ikke_instansiere_%0
-
Could_not_instantiate_%0_%1=Kunne_ikke_instansiere_%0_%1
-
Could_not_instantiate_%0._Have_you_chosen_the_correct_package_path?=Kunne_ikke_instansiere_%0._Har_du_valgt_riktig_katalog?
-
Could_not_open_link=Kunne_ikke_\u00e5pne_link
-
Could_not_print_preview=Kunne_ikke_skrive_ut_forh\u00e5ndsvisningen
Could_not_run_the_'vim'_program.=Kunne_ikke_kj\u00f8re_'vim'-programmet
+Could_not_save_file.=
Character_encoding_'%0'_is_not_supported.=Tegnkodingen_'%0'_er_ikke_st\u00f8ttet.
Created_groups.=Opprettet_grupper.
@@ -367,7 +324,6 @@ Default_look_and_feel=Standard_utseende
Default_pattern=Default_pattern
Default_sort_criteria=Standard_sorteringskriteria
-
Define_'%0'=Definer_'%0'
Delete=Slett
@@ -388,6 +344,8 @@ Delete_strings=Slett_strenger
Deleted=Slettet
+Delete_local_file=
+
Delimit_fields_with_semicolon,_ex.=Avgrens_felter_med_semikolon,_f.eks.
Descending=Synkende
@@ -395,11 +353,8 @@ Descending=Synkende
Description=Beskrivelse
Deselect_all=Velg_ingen
-
Deselect_all_duplicates=Velg_bort_alle_duplikater
-
-
Disable_this_confirmation_dialog=Deaktiver_denne_kontrolldialogen
Display_all_entries_belonging_to_one_or_more_of_the_selected_groups.=Vis_alle_enheter_inneholdt_i_minst_en_av_de_valgte_gruppene.
@@ -409,7 +364,6 @@ Display_all_error_messages=Vis_alle_feilmeldinger
Display_help_on_command_line_options=Vis_kommandolinjehjelp
Display_only_entries_belonging_to_all_selected_groups.=Vis_kun_enheter_inneholdt_i_alle_valgte_grupper.
-
Display_version=Vis_versjonsnummer
Displaying_no_groups=Viser_ingen_grupper
@@ -423,7 +377,6 @@ Do_not_import_entry=Ikke_importer_enhet
Do_not_open_any_files_at_startup=\u00c5pne_ingen_filer_ved_oppstart
Do_not_overwrite_existing_keys=Ikke_skriv_over_eksisterende_n\u00f8kler
-
Do_not_show_these_options_in_the_future=Ikke_vis_disse_valgene_igjen
Do_not_wrap_the_following_fields_when_saving=Ikke_introduser_linjeskift_i_f\u00f8lgende_felter_ved_lagring
@@ -431,6 +384,7 @@ Do_not_write_the_following_fields_to_XMP_Metadata\:=Ikke_skriv_de_f\u00f8lgende_
Do_you_want_JabRef_to_do_the_following_operations?=Vil_du_at_JabRef_skal_gj\u00f8re_de_f\u00f8lgende_operasjonene?
+Donate_to_JabRef=
Down=Ned
@@ -440,19 +394,14 @@ Download_file=Last_ned_fil
Downloading...=Laster_ned...
-
-
Drop_%0=Slipp_%0
-
-
duplicate_removal=fjerning_av_duplikater
Duplicate_string_name=Ikke_unikt_navn_p\u00e5_streng
Duplicates_found=Duplikater_funnet
-
Dynamic_groups=Dynamiske_grupper
Dynamically_group_entries_by_a_free-form_search_expression=Grupper_enheter_dynamisk_ved_hjelp_av_et_standard_s\u00f8keuttrykk
@@ -464,11 +413,8 @@ Each_line_must_be_on_the_following_form=Hver_av_linjene_m\u00e5_v\u00e6re_p\u00e
Edit=Rediger
Edit_custom_export=Rediger_eksternt_eksportfilter
-
Edit_entry=Rediger_enhet
-
Save_file=Rediger_link
-
Edit_file_type=Rediger_filtype
Edit_group=Rediger_gruppe
@@ -476,9 +422,7 @@ Edit_group=Rediger_gruppe
Edit_journal=Rediger_journal
Edit_preamble=Rediger_'preamble'
-
Edit_strings=Rediger_strenger
-
Editor_options=Alternativer_for_redigering
Empty_BibTeX_key=Tom_BibTeX-n\u00f8kkel
@@ -486,10 +430,8 @@ Empty_BibTeX_key=Tom_BibTeX-n\u00f8kkel
Grouping_may_not_work_for_this_entry.=Gruppering_kan_feile_for_denne_enheten.
empty_database=tom_database
-
Enable_word/name_autocompletion=Aktiver_autokomplettering_av_navn/ord
-
Enter_URL=Skriv_inn_URL
Enter_URL_to_download=Skriv_inn_URL_som_skal_lastes_ned
@@ -501,7 +443,6 @@ Entries_cannot_be_manually_assigned_to_or_removed_from_this_group.=Enheter_kan_i
Entries_exported_to_clipboard=Enheter_eksportert_til_utklippstavle
-
entry=enhet
Entry_editor=Enhetsskjema
@@ -519,23 +460,15 @@ Entry_type_names_are_not_allowed_to_contain_white_space_or_the_following_charact
Entry_types=Enhetstyper
Error=Feil
-
-
-
Error_exporting_to_clipboard=Feil_ved_eksport_til_utklippstavle
-##Error\:_check_your_External_viewer_settings_in_Preferences=Feil\:_unders\u00f8k_innstillingene_for_Eksterne_programmer_i_Innstillinger
-
Error_occurred_when_parsing_entry=En_feil_oppsto_ved_lesing_av_enhet
Error_opening_file=Feil_ved_\u00e5pning_av_fil
Error_setting_field=Problem_med_\u00e5_sette_felt
-
-
Error_while_writing=En_feil_oppsto_ved_skriving
-
Error_writing_to_%0_file(s).=Feil_ved_skriving_til_%0_fil(er).
@@ -544,7 +477,6 @@ Exceptions=Feilinformasjon
Existing_file=Eksisterende_fil
'%0'_exists._Overwrite_file?='%0'_eksisterer._Erstatt_filen?
-
Overwrite_file?=Erstatt_filen?
Expand_subtree=\u00c5pne_forgrening
@@ -561,9 +493,7 @@ Export_properties=Egenskaper_for_eksportfilter
Export_to_clipboard=Eksporter_til_utklippstavle
-
Exporting=Eksporterer
-
Extension=Etternavn
External_changes=Eksterne_endringer
@@ -576,20 +506,15 @@ External_programs=Eksterne_programmer
External_viewer_called=Eksternt_program_kalt_opp
-
Fetch=Hent
Field=Felt
field=felt
-# Integrity check is a process that checks for indications of wrongly filled out BibTeX fields. "Scan" is the button that starts the check.
-
Field_name=Feltnavn
-
Field_names_are_not_allowed_to_contain_white_space_or_the_following_characters=Feltnavn_kan_ikke_inneholde_opperom_eller_de_f\u00f8lgende_tegnene
-
Field_to_filter=Felt_som_skal_filtreres
Field_to_group_by=Grupperingsfelt
@@ -597,7 +522,6 @@ Field_to_group_by=Grupperingsfelt
File=Fil
file=fil
-
File_'%0'_is_already_open.=Filen_'%0'_er_allerede_\u00e5pen.
File_'%0'_not_found=Fant_ikke_filen_'%0'
@@ -607,15 +531,11 @@ File_directory_is_'%0'\:=Filkatalogen_er_'%0'\:
File_directory_is_not_set_or_does_not_exist\!=Filkatalogen_er_ikke_satt_eller_eksisterer_ikke\!
-
-
File_exists=Filen_eksisterer
-
File_has_been_updated_externally._What_do_you_want_to_do?=Filen_har_blitt_endret_eksternt._Hva_vil_du_gj\u00f8re?
File_not_found=Fant_ikke_filen
-
File_type=Filtype
File_updated_externally=Filen_har_blitt_endret_eksternt
@@ -629,9 +549,7 @@ Filter=Filter
Finished_automatically_setting_external_links.=Fullf\u00f8rte_automatisk_setting_av_eksterne_linker.
Finished_synchronizing_file_links._Entries_changed\:_%0.=Fullf\u00f8rte_synkronisering_av_fil-linker._Enheter_endret\:_%0.
-
Finished_writing_XMP-metadata._Wrote_to_%0_file(s).=Fullf\u00f8rte_skriving_av_XMP-metadata._Skrev_til_%0_fil(er).
-
Finished_writing_XMP_for_%0_file_(%1_skipped,_%2_errors).=Fullf\u00f8rte_skriving_av_XMP-data_for_%0_fil(er)_(hoppet_over_%1,_%2_mislyktes).
First_select_the_entries_you_want_keys_to_be_generated_for.=Velg_f\u00f8rst_hvilke_enheter_du_vil_generere_n\u00f8kler_for.
@@ -639,7 +557,6 @@ First_select_the_entries_you_want_keys_to_be_generated_for.=Velg_f\u00f8rst_hvil
Fit_table_horizontally_on_screen=Tilpass_tabellbredden_horisontalt
Float=Flyt
-
Float_marked_entries=Sorter_merkede_enheter_\u00f8verst
Font_family=Familie
@@ -655,14 +572,11 @@ Font_selection=Fontvelger
for=for
Format_of_author_and_editor_names=Formatering_av_forfatter-_og_redakt\u00f8rnavn
-
Format_string=Formatstreng
Format_used=Format_brukt
-
Formatter_name=Navn_p\u00e5_formaterer
-
found_in_AUX_file=funnet_i_AUX-fil
Full_name=Fullt_navn
@@ -678,7 +592,6 @@ Generate_BibTeX_key=Generere_BibTeX-n\u00f8kkel
Generate_keys=Generer_n\u00f8kler
Generate_keys_before_saving_(for_entries_without_a_key)=Generer_n\u00f8kler_f\u00f8r_lagring_(for_enheter_uten_n\u00f8kkel))
-
Generate_keys_for_imported_entries=Generer_n\u00f8kler_automatisk_for_importerte_enheter
Generate_now=Generer_n\u00e5
@@ -686,49 +599,39 @@ Generate_now=Generer_n\u00e5
Generated_BibTeX_key_for=Genererte_BibTeX-n\u00f8kkel_for
Generating_BibTeX_key_for=Genererer_BibTeX-n\u00f8kkel_for
-
+Get_fulltext=
Grab=Fang_hurtigtast
Gray_out_entries_not_in_group_selection=Skraver_enheter_utenfor_valgte_grupper
Gray_out_non-hits=Vis_ikke-treff_i-gr\u00e5tt
-
Groups=Gruppering
-
Have_you_chosen_the_correct_package_path?=Har_du_valgt_riktig_pakkenavn?
Help=Hjelp
-
Help_on_groups=Hjelp_om_grupper
Help_on_key_patterns=Hjelp_om_n\u00f8kkelgenerering
-
-
Help_on_regular_expression_search=Hjelp_for_s\u00f8k_med_regul\u00e6ruttrykk
Hide_non-hits=Skjul_ikke-treff
-
Hierarchical_context=Gruppehierarki
Highlight=Uthev
-
Highlight_groups_matching_all_selected_entries=Uthev_grupper_som_inneholder_alle_valgte_enheter
-
Highlight_groups_matching_any_selected_entry=Uthev_grupper_som_inneholder_minst_en_av_de_valgte_enhetene
+Disable_highlight_groups_matching_entries=
Highlight_overlapping_groups=Uthev_overlappende_grupper
Hint\:_To_search_specific_fields_only,_enter_for_example\:<p><tt>author\=smith_and_title\=electrical</tt>=Hint\:_For_bare_\u00e5_s\u00f8ke_i_spesifikke_felt,_skriv_f._eks.\:<p><tt>author\=smith_and_title\=electrical</tt>
-
HTML_table=HTML-tabell
-
HTML_table_(with_Abstract_&_BibTeX)=HTML-tabell_(med_Abstract_&_BibTeX)
-
Icon=Ikon
Ignore=Ignorer
@@ -759,40 +662,31 @@ Import_strings=Importer_strenger
Import_to_open_tab=Importer_til_\u00e5pen_tab
-Import_word_selector_definitions=Importer_definisjoner_for_hurtigvelgere
-
-
Imported_entries=Importerte_enheter
Imported_from_database=Importerte_fra_databasen
-ImportFormat_class=ImportFormat-klasse
+Importer_class=Importer-klasse
Importing=Importerer
Importing_in_unknown_format=Importerer_ukjent_format
-
Include_abstracts=Inkluder_sammendrag
-
Include_entries=Inkluder_enheter
-Include_subgroups\:_When_selected,_view_entries_contained_in_this_group_or_its_subgroups=Inkluder_undergrupper\:_Vis_enheter_inneholdt_i_denne_gruppen_eller_en_undergruppe
-
+Include_subgroups\:_When_selected,_view_entries_contained_in_this_group_or_its_subgroups=Inkluder_undergrupper\:_Vis_enheter_inneholdt_i_denne_gruppen_eller_en_undergruppe
Independent_group\:_When_selected,_view_only_this_group's_entries=Uavhengig_gruppe\:_Vis_bare_denne_gruppens_enheter
Initially_show_groups_tree_expanded=Vis_gruppetreet_ekspandert_i_utgangspunktet
-Input_error=Inputfeil
+Work_options=
Insert=Legg_til
Insert_rows=Legg_til_rader
-
-
-
Intersection=Snitt
Invalid_BibTeX_key=Ugyldig_BibTeX-n\u00f8kkel
@@ -838,44 +732,30 @@ Language=Spr\u00e5k
Last_modified=Sist_endret
LaTeX_AUX_file=LaTeX_AUX-fil
-
Leave_file_in_its_current_directory=La_filen_ligge_i_katalogen_den_ligger_i_n\u00e5
-
Left=Venstre
Level=
-
Limit_to_fields=Begrens_til_f\u00f8lgende_felter
Limit_to_selected_entries=Begrens_til_valgte_enheter
Link=Link
-
Link_local_file=Link_til_lokal_fil
-
Link_to_file_%0=Link_til_filen_%0
Listen_for_remote_operation_on_port=Lytt_etter_fjernoperasjoner_p\u00c3\u00a5_port
-
Load_and_Save_preferences_from/to_jabref.xml_on_start-up_(memory_stick_mode)=Hent_og_lagre_innstillinger_fra/til_jabef.xml_ved_oppstart_(minnepinne-modus)
-
-
Look_and_feel=Utseende
-
-
-
Main_file_directory=Hovedkatalog_for_filer
Main_layout_file=Hoved-layoutfil
-Manage=Sett_opp
-
Manage_custom_exports=Sett_opp_eksterne_eksportfiltre
Manage_custom_imports=Sett_opp_eksterne_importfiltre
-
Manage_external_file_types=Sett_opp_eksterne_filtyper
Manage_journal_abbreviations=Sett_opp_journalforkortelser
@@ -908,26 +788,20 @@ Modify=Endre
modify_group=endre_gruppe
-
Move=Flytt
Move_down=Flytt_ned
Move_entries_in_group_selection_to_the_top=Flytt_enheter_i_valgte_grupper_\u00f8verst
-
Move_external_links_to_'file'_field=Flytt_eksterne_linker_til_'file'-feltet
-
move_group=flytt_gruppe
Move_up=Flytt_opp
Moved_group_"%0".=Flyttet_gruppen_"%0".
-
-
Name=Navn
-
Name_formatter=Navneformaterer
Natbib_style=Natbib-stil
@@ -938,7 +812,6 @@ New=Ny
new=ny
-
New_BibTeX_entry=Ny_BibTeX-enhet
New_BibTeX_subdatabase=Ny_BibTeX-deldatabase
@@ -946,11 +819,10 @@ New_BibTeX_subdatabase=Ny_BibTeX-deldatabase
New_content=Nytt_innhold
New_database_created.=Opprettet_ny_database.
-
+New_%0_database=
New_field_value=Ny_verdi
New_file=Ny_fil
-
New_file_link_(INSERT)=Ny_link_(INSERT)
New_group=Ny_gruppe
@@ -959,7 +831,6 @@ New_string=Ny_streng
Next_entry=Neste_enhet
-
No_actual_changes_found.=Ingen_reelle_endringer_funnet.
no_base-BibTeX-file_specified=ingen_basis-BibTeXfil_spesifisert
@@ -968,14 +839,12 @@ no_database_generated=ingen_database_generert
No_entries_found._Please_make_sure_you_are_using_the_correct_import_filter.=Ingen_enheter_funnet._Kontroller_at_du_bruker_riktig_importfilter.
+
No_entries_found_for_the_search_string_'%0'=Fant_ingen_enheter_for_s\u00f8keteksten_'%0'
No_entries_imported.=Ingen_enheter_importert.
-
-
No_exceptions_have_occurred.=Ingen_feiltilstander_har_inntruffet.
-
No_files_found.=Ingen_filer_funnet.
No_GUI._Only_process_command_line_options.=Ingen_GUI._Bare_behandle_kommandolinjevalg.
@@ -983,38 +852,27 @@ No_GUI._Only_process_command_line_options.=Ingen_GUI._Bare_behandle_kommandolinj
No_journal_names_could_be_abbreviated.=Ingen_journalnavn_kunne_forkortes.
No_journal_names_could_be_unabbreviated.=Ingen_journalnavn_kunne_ekspanderes.
-
No_PDF_linked=Ingen_PDF_linket
-No_references_found=Ingen_referanser_funnet
-
-
No_URL_defined=Ingen_url_er_definert
-
not=ikke
not_found=ikke_funnet
-
Note_that_you_must_specify_the_fully_qualified_class_name_for_the_look_and_feel,=Merk_at_du_m\u00e5_spesifisere_det_fullstendige_klassenavnet_for_utseendet,
Nothing_to_redo=Ingenting_\u00e5_gjenta
Nothing_to_undo=Ingenting_\u00e5_angre
-# The next is used like in "References found\: 1 Number of references to fetch?"
-Number_of_references_to_fetch?=Antall_referanser_som_skal_hentes?
-
occurrences=treff
OK=OK
-
One_or_more_file_links_are_of_the_type_'%0',_which_is_undefined._What_do_you_want_to_do?=En_eller_flere_linker_er_av_typen_'%0'_som_er_udefinert._Hva_vil_du_gj\u00f8re?
One_or_more_keys_will_be_overwritten._Continue?=En_eller_flere_n\u00f8kler_vil_bli_skrevet_over._Fortsett?
-
Open=\u00c5pne
Open_BibTeX_database=\u00c5pne_BibTeX-database
@@ -1027,22 +885,19 @@ Open_file=\u00c5pne_fil
Open_last_edited_databases_at_startup=\u00c5pne_sist_viste_databaser_ved_oppstart
-Open_shared_database=
+Connect_to_shared_database=
Open_terminal_here=
Open_URL_or_DOI=\u00c5pne_URL_eller_DOI
-
Opened_database=\u00c5pnet_database
Opening=\u00c5pner
Opening_preferences...=\u00c5pner_innstillinger...
-
Operation_canceled.=Operasjonen_avbrutt.
-
Operation_not_supported=Operasjonen_er_ikke_st\u00f8ttet
Optional_fields=Valgfrie_felter
@@ -1051,7 +906,6 @@ Options=Valg
or=eller
-
Output=Output
Output_or_export_file=Lagre_eller_eksporter_fil
@@ -1064,8 +918,8 @@ Override_default_font_settings=Overstyr_standardfonter
Override_the_BibTeX_field_by_the_selected_text=Overskriv_BibTeX-n\u00f8kkelen_med_den_valgte_teksten
-Overwrite=Skriv_over
+Overwrite=Skriv_over
Overwrite_existing_field_values=Skriv_over_eksisterende_verdier
Overwrite_keys=Skriv_over_n\u00f8kler
@@ -1078,7 +932,6 @@ Paste=Lim_inn
paste_entries=lim_inn
paste_entry=lim_inn
-
Paste_from_clipboard=Lim_inn_fra_utklippstavle
Pasted=Limte_inn
@@ -1105,7 +958,6 @@ Please_select_an_importer.=Velg_et_importfilter.
Please_select_exactly_one_group_to_move.=Velg_eksakt_en_gruppe_for_flytting.
-
Possible_duplicate_entries=Mulige_duplikater
Possible_duplicate_of_existing_entry._Click_to_resolve.=Mulig_duplikat_av_eksisterende_enhet._Klikk_for_\u00e5_h\u00e5ndtere.
@@ -1117,21 +969,23 @@ Preferences=Oppsett
Preferences_recorded.=Lagret_oppsett.
Preview=Forh\u00e5ndsvisning
+Citation_Style=
+Current_Preview=
+Cannot_generate_preview_based_on_selected_citation_style.=
+Bad_character_inside_entry=
+Error_while_generating_citation_style=
+Preview_style_changed_to\:_%0=
+Next_preview_layout=
+Previous_preview_layout=
Previous_entry=Forrige_enhet
Primary_sort_criterion=Prim\u00e6rt_sorteringskriterium
-
-
Problem_with_parsing_entry=Problem_med_\u00e5_lese_enhet
-
-
Processing_%0=Arbeider_%0
-
Program_output=Output_fra_program
Pull_changes_from_shared_database=
-
Pushed_citations_to_%0=Sendte_enheter_til_%0
Quit_JabRef=Avslutt_JabRef
@@ -1140,17 +994,15 @@ Quit_synchronization=Avslutt_synkronisering
Raw_source=Kilde
-
Rearrange_tabs_alphabetically_by_title=Rearranger_databasene_alfabetisk_etter_navn
Redo=Gjenta
Reference_database=Referansedatabase
-# The next two lines are used like in "References found\: 1 Number of references to fetch?"
-References_found=Referanser_funnet
-Refine_supergroup\:_When_selected,_view_entries_contained_in_both_this_group_and_its_supergroup=Undergruppe\:_Vis_enheter_innehold_b\u00e5de_i_denne_gruppen_og_gruppen_over
+%0_references_found._Number_of_references_to_fetch?=Referanser_funnet\:_%0._Antall_referanser_som_skal_hentes?
+Refine_supergroup\:_When_selected,_view_entries_contained_in_both_this_group_and_its_supergroup=Undergruppe\:_Vis_enheter_innehold_b\u00e5de_i_denne_gruppen_og_gruppen_over
regular_expression=Regul\u00e6ruttrykk
@@ -1162,22 +1014,17 @@ Remote_server_port=Port_for_fjernstyring
Remove=Fjern
-
Remove_subgroups=Fjern_undergrupper
Remove_all_subgroups_of_"%0"?=Remove_all_subgroups_of_"%0"?
-
-
Remove_entry_from_import=Fjern_enhet_fra_import
Remove_entry_selection_from_this_group=Fjern_valgte_enheter_fra_denne_gruppen
Remove_entry_type=Slett_enhetstype
-
Remove_file_link_(DELETE)=Slett_link_(DELETE)
-
Remove_from_group=Fjern_fra_gruppe
Remove_group=Fjern_gruppe
@@ -1200,7 +1047,6 @@ Remove_old_entry=Fjern_gammel_enhet
Remove_selected_strings=Slett_valgte_strenger
-
Removed_group_"%0".=Fjernet_gruppen_"%0"
Removed_group_"%0"_and_its_subgroups.=Fjernet_gruppen_"%0"_og_dens_undergrupper
@@ -1221,14 +1067,11 @@ Required_fields=N\u00f8dvendige_felter
Reset_all=Tilbakestill_alle
-
Resolve_strings_for_all_fields_except=Sl\u00e5_opp_strenger_for_alle_felter_unntatt
-
Resolve_strings_for_standard_BibTeX_fields_only=Sl\u00e5_opp_strenger_kun_for_standard_BibTeX-felter
resolved=tatt_h\u00e5nd_om
-
Revert_to_original_source=Resett_til_opprinnelig_kildekode
Review=Kommentarer
@@ -1238,7 +1081,6 @@ Review_changes=Se_over_endringer
Right=H\u00f8yre
Save=Lagre
-
Save_all_finished.=Fullf\u00f8rte_lagring_av_alle_databaser
Save_all_open_databases=Lagre_alle_\u00e5pne_databaser
@@ -1246,7 +1088,6 @@ Save_all_open_databases=Lagre_alle_\u00e5pne_databaser
Save_before_closing=Lagre_f\u00f8r_databasen_lukkes
Save_database=Lagre_database
-
Save_database_as...=Lagre_database_som_...
Save_entries_in_their_original_order=Lagre_enheter_i_opprinnelig_rekkef\u00f8lge
@@ -1255,38 +1096,23 @@ Save_failed=Lagring_mislyktes
Save_failed_during_backup_creation=Lagring_mislyktes_ved_opprettelse_av_sikkerhetskopi
-Save_failed_while_committing_changes\:_%0=Lagring_mislyktes_ved_sluttf\u00f8ring_av_endringer\:_%0
-
Save_selected_as...=Lagre_valgte_som_...
Saved_database=Lagret_database
Saved_selected_to_'%0'.=Lagret_valgte_i_'%0'.
-
Saving=Lagrer
-
Saving_all_databases...=Lagrer_alle_databaser...
Saving_database=Lagrer_database
-# Integrity check is a process that checks for indications of wrongly filled out BibTeX fields. "Scan" is the button that starts the check.
-
Search=S\u00f8k
-
-
Search_expression=S\u00f8keuttrykk
Search_for=S\u00f8k_etter
-
-
-
-
-
-
-
Searching_for_duplicates...=S\u00f8ker_etter_duplikater...
Searching_for_files=S\u00f8ker_etter_filer
@@ -1297,46 +1123,30 @@ Select=Velg
-
Select_all=Velg_alle
-
Select_encoding=Velg_koding
-
Select_entry_type=Velg_enhetstype
-
Select_external_application=Velg_ekstern_applikasjon
Select_file_from_ZIP-archive=Velg_fil_fra_ZIP-fil
-
-
-
-
Select_the_tree_nodes_to_view_and_accept_or_reject_changes=Velg_trenodene_for_\u00e5_inspisere_og_akseptere_eller_avsl\u00e5_endringer
-
Selected_entries=Valgte_enheter
-
-
-
Set_field=Sett_felt
-
Set_fields=Sett_felter
Set_general_fields=Tilpass_generelle_felter
-
Set_main_external_file_directory=Sett_hovedkatalog_for_eksterne_linker
Set_table_font=Velg_tabellfont
Settings=Innstillinger
-
-
Shortcut=Snarvei
-Show/edit_BibTeX_source=Vis/rediger_BibTeX-kilde
+Show/edit_%0_source=Vis/rediger_%0-kilde
Show_'Firstname_Lastname'=Vis_'Fornavn_Etternavn'
@@ -1344,7 +1154,6 @@ Show_'Lastname,_Firstname'=Vis_'Etternavn,_Fornavn'
Show_BibTeX_source_by_default=Vis_BibTeX-kode_som_standard
-
Show_confirmation_dialog_when_deleting_entries=Vis_dialog_for_\u00e5_bekrefte_sletting_av_enheter
Show_description=Vis_beskrivelse
@@ -1356,37 +1165,27 @@ Show_entries_<b>not</b>_in_group_selection=Vis_enheter_<b>utenfor</b>_valgte_gru
Show_file_column=Vis_'file'-kolonne
Show_icons_for_groups=Vis_ikoner_for_grupper
-
Show_last_names_only=Vis_bare_etternavn
Show_names_unchanged=Vis_navn_uforandret
-
-
Show_optional_fields=Vis_valgfrie_felter
-
Show_required_fields=Vis_n\u00f8dvendige_felter
Show_URL/DOI_column=Vis_URL/DOI-kolonne
-
-
Simple_HTML=Enkel_HTML
Size=St\u00f8rrelse
-
Skipped_-_No_PDF_linked=Hoppet_over_-_ingen_PDF-fil_linket
-
Skipped_-_PDF_does_not_exist=Hoppet_over_-_PDF-filen_finnes_ikke
Skipped_entry.=Hoppet_over_enhet.
Sort_alphabetically=Sorter_alfabetisk
-
-
sort_subgroups=sorter_undergrupper
Sorted_all_subgroups_recursively.=Sorterte_alle_undergrupper_rekursivt.
@@ -1394,14 +1193,10 @@ Sorted_all_subgroups_recursively.=Sorterte_alle_undergrupper_rekursivt.
Sorted_immediate_subgroups.=Sorterte_n\u00e6rmeste_undergrupper.
source_edit=redigering_av_kilde
-
Special_name_formatters=Spesielle_navneformaterere
Special_table_columns=Spesielle_kolonner
-
-
-
Starting_import=Starter_import
Statically_group_entries_by_manual_assignment=Grupper_enheter_statisk_ved_manuell_tildeling
@@ -1412,7 +1207,6 @@ Stop=Stopp
Store_journal_abbreviations=Lagre_journalforkortelser
-
Stored_entry=Lagret_enhet
Strings=Strenger
@@ -1421,7 +1215,6 @@ Strings_for_database=Strenger_for_database
Subdatabase_from_AUX=Deldatabase_fra_AUX-fil
-
Switches_between_full_and_abbreviated_journal_name_if_the_journal_name_is_known.=Bytter_mellom_fullt_og_forkortet_journalnavn_dersom_navnet_er_kjent.
Synchronize_file_links=Synkroniser_eksterne_linker
@@ -1437,7 +1230,6 @@ Table_grid_color=Farge_p\u00e5_linjer_i_tabell
Table_text_color=Tekstfarge_i_tabell
Tabname=Tabnavn
-
Target_file_cannot_be_a_directory.=M\u00e5lfilen_kan_ikke_v\u00e6re_en_katalog.
Tertiary_sort_criterion=Tredje_sorteringskriterium
@@ -1447,6 +1239,7 @@ Test=Test
paste_text_here=Inndatafelt
The_chosen_date_format_for_new_entries_is_not_valid=Det_valgte_datoformatet_er_ugyldig
+
The_chosen_encoding_'%0'_could_not_encode_the_following_characters\:=Den_valgte_tegnkodingen_'%0'_kunne_ikke_kode_f\u00f8lgende_tegn\:
@@ -1463,7 +1256,6 @@ The_label_of_the_string_cannot_contain_spaces.=Navnet_p\u00e5_strengen_kan_ikke_
The_label_of_the_string_cannot_contain_the_'\#'_character.=Navnet_p\u00e5_strengen_kan_ikke_inneholde_tegnet_'\#'.
The_output_option_depends_on_a_valid_import_option.=Lagre-operasjonen_er_avhengig_av_en_gyldig_import-operasjon.
-
The_PDF_contains_one_or_several_BibTeX-records.=PDF-filen_inneholder_en_eller_flere_BibTeX-enheter.
Do_you_want_to_import_these_as_new_entries_into_the_current_database?=Vil_du_importere_disse_som_nye_enheter_i_den_\u00e5pne_databasen?
@@ -1477,7 +1269,6 @@ The_string_has_been_removed_locally=Strengen_har_blitt_slettet_lokalt
There_are_possible_duplicates_(marked_with_an_icon)_that_haven't_been_resolved._Continue?=Det_finnes_mulige_duplikater_(merket_med_et_ikon)_som_ikke_har_blitt_h\u00e5ndtert._Fortsette?
-
This_entry_has_no_BibTeX_key._Generate_key_now?=Denne_enheten_har_ingen_BibTeX-n\u00f8kkel._Generer_n\u00f8kkel_n\u00e5?
This_entry_is_incomplete=Denne_enheten_er_ufullstendig
@@ -1488,41 +1279,26 @@ This_external_link_is_of_the_type_'%0',_which_is_undefined._What_do_you_want_to_
This_group_contains_entries_based_on_manual_assignment._Entries_can_be_assigned_to_this_group_by_selecting_them_then_using_either_drag_and_drop_or_the_context_menu._Entries_can_be_removed_from_this_group_by_selecting_them_then_using_the_context_menu.=Denne_gruppen_inneholder_enheter_basert_p\u00e5_manuell_tilordning._Enheter_kan_tilordnes_til_denne_gruppen_ved_\u00e5_velge_dem_og_deretter_trekke_dem_over_til_gruppen,_eller_ved_hjelp_av_h\u00f8yreklikkmenyen.
-
-
-
This_group_contains_entries_whose_<b>%0</b>_field_contains_the_keyword_<b>%1</b>=Denne_gruppen_inneholder_enheter_hvis_<b>%0</b>-felt_inneholder_n\u00f8kkelordet_<b>%1</b>
This_group_contains_entries_whose_<b>%0</b>_field_contains_the_regular_expression_<b>%1</b>=Denne_gruppen_inneholder_enheter_hvis_<b>%0</b>-felt_stemmer_med_regul\u00e6ruttrykket_<b>%1</b>
-
This_makes_JabRef_look_up_each_file_link_and_check_if_the_file_exists._If_not,_you_will_be_given_options<BR>to_resolve_the_problem.=Dette_f\u00e5r_JabRef_til_\u00e5_unders\u00f8ke_hver_av_fil-linkene,_og_sjekke_om_filen_eksisterer._Hvis_ikke_vil_du_bli_gitt_valg<BR>for_\u00e5_l\u00f8se_problemet.
This_operation_requires_all_selected_entries_to_have_BibTeX_keys_defined.=Denne_operasjonen_krever_at_alle_valgte_enheter_har_definerte_BibTeX-n\u00f8kler.
-
This_operation_requires_one_or_more_entries_to_be_selected.=Denne_operasjonen_krever_at_en_eller_flere_enheter_er_valgt.
-
Toggle_abbreviation=Forkort/ekspander
-
Toggle_entry_preview=Vis/skjul_forh\u00e5ndsvisning
-
Toggle_groups_interface=Vis/skjul_grupperingskontroll
-
-
Try_different_encoding=Pr\u00f8v_en_annen_tegnkoding
-
Unabbreviate_journal_names_of_the_selected_entries=Ekspander_journalnavn_for_de_valgte_enhetene
-
Unabbreviated_%0_journal_names.=Ekspanderte_%0_journalnavn.
Unable_to_open_file.=Kan_ikke_\u00e5pne_fil.
-
Unable_to_open_link._The_application_'%0'_associated_with_the_file_type_'%1'_could_not_be_called.=Kan_ikke_\u00e5pne_link._Applikasjonen_'%0'_assosiert_med_filtypen_'%1'_kunne_ikke_kalles.
-
unable_to_write_to=kunne_ikke_skrive_til
-
Undefined_file_type=Udefinert_filtype
Undo=Angre
@@ -1533,7 +1309,6 @@ Unknown_BibTeX_entries=Ukjente_BibTeX-enheter
unknown_edit=ukjent_endring
-
Unknown_export_format=Ukjent_eksportformat
Unmark_all=Fjern_merking_fra_alle
@@ -1542,10 +1317,6 @@ Unmark_entries=Fjern_merking
Unmark_entry=Fjern_merking
-
-
-Unsupported_version_of_class_%0\:_%1=Ikke_st\u00f8ttet_versjon_av_klassen_%0\:_%1
-
untitled=uten_navn
Up=Opp
@@ -1553,28 +1324,16 @@ Up=Opp
Update_to_current_column_widths=Bruk_n\u00e5v\u00e6rende_kolonnebredder
Updated_group_selection=Updated_group_selection
-
Upgrade_external_PDF/PS_links_to_use_the_'%0'_field.=Oppgrader_eksterne_PDF-_og_PS-linker_til_\u00e5_bruke_'%0'-feltet.
-
Upgrade_file=Oppgrader_fil
-
Upgrade_old_external_file_links_to_use_the_new_feature=Oppgrader_gamle_eksterne_linker_for_\u00e5_bruke_den_nye_funksjonen
-
-
-
-
usage=bruk
-
Use_autocompletion_for_the_following_fields=Bruk_autokomplettering_for_f\u00f8lgende_felter
-
-
Use_other_look_and_feel=Bruk_annet_utseende
-
Use_regular_expression_search=S\u00f8k_med_regul\u00e6ruttrykk
-
Username=Brukernavn
Value_cleared_externally=Verdien_slettet_eksternt
@@ -1584,7 +1343,6 @@ Value_set_externally=Verdi_satt_eksternt
verify_that_LyX_is_running_and_that_the_lyxpipe_is_valid=kontroller_at_LyX_kj\u00f8rer,_og_at_den_angitte_lyxpipe_stemmer
View=Vis
-
Vim_server_name=Navn_p\u00e5_Vim-server
Waiting_for_ArXiv...=Venter_p\u00e5_ArXiv
@@ -1602,257 +1360,137 @@ web_link=link
What_do_you_want_to_do?=Hva_vil_du_gj\u00f8re?
When_adding/removing_keywords,_separate_them_by=N\u00e5r_n\u00f8kkelord_legges_til_eller_fjernes_skill_dem_med
-
Will_write_XMP-metadata_to_the_PDFs_linked_from_selected_entries.=Vil_skrive_XMP-metadata_til_PDFene_linket_fra_de_valgte_enhetene.
with=med
-
Write_BibTeXEntry_as_XMP-metadata_to_PDF.=Skriv_BibTeX-enheten_som_XMP-metadata_til_PDF.
Write_XMP=Skriv_XMP
-
Write_XMP-metadata=Skriv_XMP-metadata
-
Write_XMP-metadata_for_all_PDFs_in_current_database?=Skriv_XMP-metadata_for_alle_PDFer_i_denne_databasen?
-
-
Writing_XMP-metadata...=Skriver_XMP-metadata...
-
Writing_XMP-metadata_for_selected_entries...=Skriver_XMP-metadata_for_de_valgte_enhetene...
-
-
Wrote_XMP-metadata=Skrev_XMP-metadata
-
XMP-annotated_PDF=XMP-annotert_PDF
-
XMP_export_privacy_settings=Innstillinger_for_XMP-eksport
-
XMP-metadata=XMP-metadata
-
XMP-metadata_found_in_PDF\:_%0=XMP-metadata_funnet_i_PDF\:_%0
-
You_must_restart_JabRef_for_this_to_come_into_effect.=Du_m\u00e5_starte_JabRef_p\u00e5_nytt_for_at_dette_skal_tre_i_kraft.
-
You_have_changed_the_language_setting.=Du_har_valgt_et_nytt_spr\u00e5k.
-
You_have_changed_the_look_and_feel_setting.=Du_har_endret_instillingen_for_utseende.
-
You_have_entered_an_invalid_search_'%0'.=Ugyldig_s\u00f8keuttrykk_'%0'.
You_must_choose_a_filename_to_store_journal_abbreviations=Du_m\u00e5_velge_et_filnavn_for_\u00e5_lagre_journalforkortelser
You_must_restart_JabRef_for_the_new_key_bindings_to_work_properly.=Du_m\u00e5_starte_JabRef_p\u00e5_nytt_for_at_de_nye_hurtigtastene_skal_fungere.
-
Your_new_key_bindings_have_been_stored.=Dine_nye_hurtigtaster_har_blitt_lagret.
The_following_fetchers_are_available\:=De_f\u00f8lgende_nedlasterne_er_tilgjengelige\:
-
Could_not_find_fetcher_'%0'=Kunne_ikke_finne_nedlasteren_'%0'
-
Running_query_'%0'_with_fetcher_'%1'.=Utf\u00f8rer_s\u00f8k_'%0'_med_nedlaster_'%1'.
-
Query_'%0'_with_fetcher_'%1'_did_not_return_any_results.=S\u00f8ket_'%0'_med_nedlaster_'%1'_ga_ingen_resultater.
-
-
Move/Rename_file=Flytt/endre_navn_p\u00e5_fil
-
File_moved=Flyttet_fil
-
Move_file_failed=Flytting_av_fil_mislyktes
-
Could_not_move_file_'%0'.=Kunne_ikke_flytte_filen_'%0'.
-
Could_not_find_file_'%0'.=Kunne_ikke_finne_filen_'%0'.
-
Number_of_entries_successfully_imported=Antall_enheter_importert
-
Import_canceled_by_user=Import_avbrutt_av_bruker
-
Progress\:_%0_of_%1=Framdrift\:_%0_av_%1
-
Error_while_fetching_from_%0=Feil_ved_henting_fra_%0
-Fetching_Medline_by_id...=Henter_Melding_ved_hjelp_av_ID...
-
-Fetching_Medline_by_term...=Henter_Medline_ved_hjelp_av_n\u00f8kkelord...
-
-%0_import_canceled=%0-import_kansellert
-
Please_enter_a_valid_number=Vennligst_skriv_inn_et_gyldig_tall
-
-Please_enter_a_comma_separated_list_of_Medline_IDs_(numbers)_or_search_terms.=Vennligst_skriv_inn_en_kommaseparert_liste_av_Medline-IDer_(tall)_eller_s\u00f8keord.
-
-
-
-
-
-
-
Show_search_results_in_a_window=Vis_s\u00f8keresultatene_i_et_vundu
-
-
+Show_global_search_results_in_a_window=
+Search_in_all_open_databases=
Move_file_to_file_directory?=Flytt_filen_til_hovedkatalogen_for_filer?
-
Rename_to_'%0'=Endre_navn_til_'%0'
-
-
You_have_changed_the_menu_and_label_font_size.=Du_har_endret_skriftst\u00f8rrelser.
Database_is_protected._Cannot_save_until_external_changes_have_been_reviewed.=Databasen_er_beskyttet._Kan_ikke_lagre_f\u00f8r_eksterne_endringer_har_blitt_gjennomg\u00e5tt.
-
Protected_database=Beskyttet_database
-
Refuse_to_save_the_database_before_external_changes_have_been_reviewed.=Nekt_\u00e5_lagre_databasen_f\u00f8r_eksterne_endringer_har_blitt_gjennomg\u00e5tt.
-
Database_protection=Databasebeskyttelse
-
Unable_to_save_database=Kan_ikke_lagre_databasen
BibTeX_key_generator=BibTeX-n\u00f8kkelgenerator
-
Unable_to_open_link.=Kan_ikke_\u00e5pne_link.
-
-
-
-
Move_the_keyboard_focus_to_the_entry_table=Flytt_fokus_til_hovedtabellen
-
MIME_type=MIME-type
This_feature_lets_new_files_be_opened_or_imported_into_an_already_running_instance_of_JabRef<BR>instead_of_opening_a_new_instance._For_instance,_this_is_useful_when_you_open_a_file_in_JabRef<br>from_your_web_browser.<BR>Note_that_this_will_prevent_you_from_running_more_than_one_instance_of_JabRef_at_a_time.=Denne_funksjonen_lar_deg_\u00e5pne_eller_importere_nye_filer_til_en_allerede_kj\u00f8rende_instans_av_JabRef<br>fra_nettleseren_din.<br>Merk_at_dette_vil_hindre_deg_i_\u00e5_kj\u00f8r [...]
-
-
Run_fetcher,_e.g._"--fetch\=Medline\:cancer"=
The_ACM_Digital_Library=ACM_Digital_Library
-
Reset=Resett
Use_IEEE_LaTeX_abbreviations=Bruk_IEEE-LaTeX-forkortelser
-
The_Guide_to_Computing_Literature=The_Guide_to_Computing_Literature
-
-
When_opening_file_link,_search_for_matching_file_if_no_link_is_defined=Ved_\u00e5pning_av_linke,_s\u00b8k_etter_matchende_fil_hvis_ingen_er_definert
-
Settings_for_%0=Innstillinger_for_%0
-
-
-
-
Mark_entries_imported_into_an_existing_database=Merk_enheter_som_importeres_til_en_eksisterende_database
-
Unmark_all_entries_before_importing_new_entries_into_an_existing_database=Fjern_merking_fra_alle_merkede_enheter_f\u00b8r_nye_importeres
Forward=Fram
-
Back=Tilbake
-
Sort_the_following_fields_as_numeric_fields=Sorter_de_f\u00c3\u00b8lgende_feltene_som_tall
-
Line_%0\:_Found_corrupted_BibTeX_key.=Linje_%0\:_Fant_ugyldig_BibTeX-n\u00b8kkel.
-
Line_%0\:_Found_corrupted_BibTeX_key_(contains_whitespaces).=Linje_%0\:_Fant_ugyldig_BibTeX-n\u00b8kkel_(inneholder_mellomrom).
-
Line_%0\:_Found_corrupted_BibTeX_key_(comma_missing).=Linje_%0\:_Fant_ugyldig_BibTeX-n\u00b8kkel_(manglende_komma).
-
-Finished_downloading_full_text_document=Fullf\u00b8rte_nedlasting_av_fulltekstdokument
-
-
Full_text_document_download_failed=Kunne_ikke_laste_ned_fulltekstdokument
-
Update_to_current_column_order=Oppdater_til_n\u00e5v\u00e6rende_rekkef\u00b8lge_p\u00e5_kolonner
-
+Download_from_URL=
Rename_field=Endre_navn_p\u00e5_felt
-
Set/clear/rename_fields=Sett/slett/endre_navn_p\u00e5_felt
-
Rename_field_to=Endre_navn_p\u00e5_felt_til
-
Move_contents_of_a_field_into_a_field_with_a_different_name=Flytt_innholdet_i_et_felt_til_et_annet_felt
-
You_can_only_rename_one_field_at_a_time=Du_kan_bare_endre_navn_p\u00e5_ett_felt_av_gangen
Remove_all_broken_links=Fjern_alle_ugyldige_linker
Cannot_use_port_%0_for_remote_operation;_another_application_may_be_using_it._Try_specifying_another_port.=Kan_ikke_bruke_port_%0_for_fjernstyring;_den_kan_v\u00e6re_i_bruk_av_et_annet_program._Pr\u00b8v_\u00e5_spesifisere_en_annen_port.
-
-
-
-
Looking_for_full_text_document...=Ser_etter_fulltekstdokument...
-
-
Autosave=Autolagring
-
-Prompt_before_recovering_a_database_from_an_autosave_file=Sp\u00b8r_f\u00b8r_en_database_gjenopprettes_fra_autolagret_fil
-
-Autosave_interval_(minutes)=Intervall_for_autolagring_(minutter)
-
-Do_you_want_to_recover_the_database_from_the_autosave_file?=Vil_du_gjenopprette_databasen_fra_den_autolagrede_filen?
-
-Recover_from_autosave=Gjenopprette_fra_autolagret_fil
-
+A_local_copy_will_be_opened.=
+Autosave_local_databases=
+Automatically_save_the_database_to=
+Please_enter_a_valid_file_path.=
Export_in_current_table_sort_order=Eksporter_i_n\u00e5v\u00e6rende_sortering
-
Export_entries_in_their_original_order=Eksporter_enheter_i_deres_opprinnelige_rekkef\u00b8lge
-
Error_opening_file_'%0'.=Feil_ved_\u00e5pning_av_filen_'%0'.
-Autosave_of_file_'%0'=Autolagring_av_filen_'%0'
-
-Error_opening_autosave_of_'%0'._Trying_to_load_'%0'_instead.=Feil_ved_\u00e5pning_av_autolagret_versjon_av_'%0'._Pr\u00b8ver_\u00e5_laste_'%0'_i_stedet.
-
Formatter_not_found\:_%0=Fant_ikke_formaterer\:_%0
-
Clear_inputarea=T\u00b8m_inputfelt
Automatically_set_file_links_for_this_entry=Set_fillinker_for_denne_enheten_automatisk
-
Could_not_save,_file_locked_by_another_JabRef_instance.=Kunne_ikke_lagre,_filen_er_l\u00e5st_av_en_annen_instans_av_JabRef.
-
File_is_locked_by_another_JabRef_instance.=Filen_er_l\u00e5st_av_en_annen_instans_av_JabRef.
-
Do_you_want_to_override_the_file_lock?=Vil_du_overstyre_fill\u00e5sen?
-
File_locked=Filen_er_l\u00e5st
-
Current_tmp_value=N\u00e5v\u00e6rende_tmp-verdi
-
Metadata_change=Endring_av_metadata
-
Changes_have_been_made_to_the_following_metadata_elements=Endringer_er_gjort_for_de_f\u00b8lgende_metadata-elementene
Generate_groups_for_author_last_names=Generer_grupper_for_etternavn_fra_author-feltet
-
Generate_groups_for_editor_last_names=Generer_grupper_for_etternavn_fra_editor-feltet
-
Generate_groups_from_keywords_in_a_BibTeX_field=Generer_grupper_fra_n\u00b8kkelord_i_et_BibTeX-felt
-
Enforce_legal_characters_in_BibTeX_keys=Forby_tegn_i_BibTeX-n\u00b8kler_som_ikke_aksepteres_av_BibTeX
-
-
Save_without_backup?=Lagre_uten_backup?
-
Unable_to_create_backup=Kan_ikke_lagre_backup?
-
Move_file_to_file_directory=Flytt_fil_til_filkatalog
-
Rename_file_to=Endre_navn_p\u00e5_fil_til
-
<b>All_Entries</b>_(this_group_cannot_be_edited_or_removed)=<b>Alle_enheter</b>_(denne_gruppen_kan_ikke_endres_eller_slettes)
-
static_group=statisk_gruppe
dynamic_group=dynamisk_gruppe
refines_supergroup=subset_av_gruppen_over
@@ -1860,291 +1498,141 @@ includes_subgroups=inkluderer_gruppen_over
contains=inneholder
search_expression=s\u00b8keutryk
-
-
-
-
Optional_fields_2=Valgfrie_felter_2
-
Waiting_for_save_operation_to_finish=Venter_p\u00e5_lagringsoperasjon
-
Resolving_duplicate_BibTeX_keys...=S\u00f8k_etter_dupliserte_BibTeX-n\u00f8kler
-
Finished_resolving_duplicate_BibTeX_keys._%0_entries_modified.=Fullf\u00f8rte_s\u00f8k_etter_dupliserte_BibTeX-n\u00f8kler._%0_enheter_endret.
-
This_database_contains_one_or_more_duplicated_BibTeX_keys.=Denne_database_inneholder_en_eller_flere_dupliserte_BibTeX-n\u00f8kler
-
Do_you_want_to_resolve_duplicate_keys_now?=Vil_du_ordne_opp_i_dupliserte_n\u00f8kler_n\u00e5?
Find_and_remove_duplicate_BibTeX_keys=Finn_og_fjern_dupliserte_BibTeX-n\u00f8kler
-
Expected_syntax_for_--fetch\='<name_of_fetcher>\:<query>'=
-
Duplicate_BibTeX_key=Duplisert_BibTeX-n\u00f8kkel
-
-
-
Import_marking_color=Farge_som_markerer_importerte_enheter
-
Always_add_letter_(a,_b,_...)_to_generated_keys=Legg_alltid_til_en_bokstav_(a,_b,_...)_til_genererte_n\u00f8kler
Ensure_unique_keys_using_letters_(a,_b,_...)=Sikre_unike_n\u00f8kler_ved_bruk_av_bokstaver_(a,_b,_...)
-
Ensure_unique_keys_using_letters_(b,_c,_...)=Sikre_unike_n\u00f8kler_ved_bruk_av_bokstaver_(b,_c,_...)
-
Entry_editor_active_background_color=Bakgrunnsfarge_for_aktivt_felt_i_enhetsskjema
-
Entry_editor_background_color=Bakgrunnsfarge_i_enhetsskjema
-
Entry_editor_font_color=Tekstfarge_i_enhetsskjema
-
Entry_editor_invalid_field_color=Bakgrunnsfarge_for_ugyldige_felt_i_enhetsskjema
Table_and_entry_editor_colors=Farger_i_tabell_og_enhetsskjema
-
-
General_file_directory=Standard_filkatalog
-
User-specific_file_directory=Brukerdefinert_filkatalog
-
Search_failed\:_illegal_search_expression=Kunne_ikke_s\u00f8ke\:_feil_i_s\u00f8keuttrykk
-
Show_ArXiv_column=Vis_ArXiv-kolonne
-
-
Highlight_groups_that_contain_entries_contained_in_any_currently_selected_group=Uthev_grupper_som_inneholder_enheter_inneholdt_i_valgte_grupper
You_must_enter_an_integer_value_in_the_interval_1025-65535_in_the_text_field_for=Du_m\u00e5_velge_en_heltallsverdi_i_intervallet_1025-65535_i_feltet_for
-
Automatically_open_browse_dialog_when_creating_new_file_link=\u00c5pne_fildialog_automatisk_n\u00e5r_ny_link_opprettes
-
Import_metadata_from\:=Importer_metadata_fra\:
-
Choose_the_source_for_the_metadata_import=Velg_kilde_for_import_av_metadata
-
Create_entry_based_on_XMP_data=Lag_enhet_basert_p\u00e5_XMP-data
-
Create_blank_entry_linking_the_PDF=Lag_blank_enhet_med_lenke_til_PDF
-
Only_attach_PDF=Bare_lenk_til_PDF
-
Title=Tittel
-
-No_internet_connection.=Ingen_internettforbindelse
-
Create_new_entry=Lag_ny_enhet
-
Update_existing_entry=Oppdater_eksisterende_enhet
-
Autocomplete_names_in_'Firstname_Lastname'_format_only=Autokompletter_navn_i_'Fornavn_Etternavn'-format
-
Autocomplete_names_in_'Lastname,_Firstname'_format_only=Autokompletter_navn_i_'Etternavn,_Fornavn'-format
-
Autocomplete_names_in_both_formats=Autokompletter_navn_i_begge_format
-
Marking_color_%0=Markeringsfarge_%0
-
The_name_'comment'_cannot_be_used_as_an_entry_type_name.=Navnet_'comment'_kan_ikke_brukes_som_navn_p\u00e5_en_enhetstype
-
You_must_enter_an_integer_value_in_the_text_field_for=Du_m\u00e5_skrive_inn_en_heltallverdi_i_tekstfeltet_for
-
Send_as_email=Send_som_e-post
-
References=Referanser
-
Sending_of_emails=Sending_av_e-post
-
Subject_for_sending_an_email_with_references=Emne_for_sending_av_e-post_med_referanser
-
Automatically_open_folders_of_attached_files=\u00c5pne_automatisk_mapper_for_vedlegg
-
Create_entry_based_on_content=Opprett_enhet_basert_p\u00e5_innhold
-
Do_not_show_this_box_again_for_this_import=Ikke_vis_denne_dialogboksen_igjen_for_denne_importen
-
Always_use_this_PDF_import_style_(and_do_not_ask_for_each_import)=Alltid_bruk_denne_PDF-importmetoden_(ikke_sp\u00f8r_for_hver_enkelt_import)
-
Error_creating_email=Feil_ved_opprettelse_av_e-post
-
Entries_added_to_an_email=Enheter_lagt_til_en_e-post
-
exportFormat=Eksportformat
-
Output_file_missing=Utfil_mangler
-
No_search_matches.=Ingen_s\u00f8keresultater
-
The_output_option_depends_on_a_valid_input_option.=Output-innstillingen_krever_en_gyldig_input-innstilling
-
Default_import_style_for_drag_and_drop_of_PDFs=Standard_importmetode_for_PDF-filer
-
Default_PDF_file_link_action=Standardaksjon_for_PDF-fillinker
-
Filename_format_pattern=M\u00f8nster_for_filnavn
-
-
-
Additional_parameters=Ytterligere_parametre
-
-
Cite_selected_entries_between_parenthesis=Referer_valgte_enheter
-
Cite_selected_entries_with_in-text_citation=Referer_valgte_enheter_med_referanse_i_teksten
-
Cite_special=Referanse_med_ekstra_informasjon
-
Extra_information_(e.g._page_number)=Ekstra_informasjon_(f.eks._sidenummer)
-
Manage_citations=Administrer_referanser
-
Problem_modifying_citation=Det_oppsto_et_problem_ved_endring_av_referansen
-
Citation=Referanse
-
Extra_information=Ekstra_informasjon
-
Could_not_resolve_BibTeX_entry_for_citation_marker_'%0'.=Kunne_ikke_finne_BibTeX-enhet_for_referansen_'%0'.
-
-
Select_style=Velg_stil
-
-
Journals=Tidsskrifter
-
Cite=Referer
-
Cite_in-text=Referer_i_teksten
-
Insert_empty_citation=Sett_in_tom_referanse
-
Merge_citations=Sl\u00e5_sammen_referanser
-
Manual_connect=Manuell_tilkobling
-
Select_Writer_document=Velg_Writer-dokument
-
Sync_OpenOffice/LibreOffice_bibliography=Synkroniser_OpenOffice/LibreOffice-bibliografi
-
-
Select_which_open_Writer_document_to_work_on=Velg_hvilket_\u00e5pent_Writer-dokument_du_vil_jobbe_med
-
Connected_to_document=Koblet_til_dokument
-
Insert_a_citation_without_text_(the_entry_will_appear_in_the_reference_list)=Sett_inn_en_referanse_uten_tekst_(enheten_vil_bli_med_i_referanselisten)
-
Cite_selected_entries_with_extra_information=Referer_valgte_enheter_med_ekstra_informasjon
-
Ensure_that_the_bibliography_is_up-to-date=S\u00f8rg_for_at_bibliografien_er_oppdatert
-
Your_OpenOffice/LibreOffice_document_references_the_BibTeX_key_'%0',_which_could_not_be_found_in_your_current_database.=OpenOffice/LibreOffice-dokumentet_referer_til_BibTeX-n\u00f8kkelen_'%0',_som_ikke_finnes_i_din_aktuelle_database.
-
Unable_to_synchronize_bibliography=Kunne_ikke_synkronisere_bibliografien
-
Combine_pairs_of_citations_that_are_separated_by_spaces_only=Sl\u00e5_sammen_par_av_referanser_som_bare_er_adskilt_av_mellomrom
-
Autodetection_failed=Autodeteksjon_mislyktes
-
Connecting=Kobler_til
-
Please_wait...=Vennligst_vent...
-
Set_connection_parameters=Sett_opp_tilkoblingsparametre
-
Path_to_OpenOffice/LibreOffice_directory=Sti_til_OpenOffice/LibreOffice-katalog
-
Path_to_OpenOffice/LibreOffice_executable=Sti_til_OpenOffice/LibreOffice-startfil
-
Path_to_OpenOffice/LibreOffice_library_dir=Sti_til_OpenOffice/LibreOffice-bibliotekkatalog
-
Connection_lost=Mistet_forbindelsen
-
The_paragraph_format_is_controlled_by_the_property_'ReferenceParagraphFormat'_or_'ReferenceHeaderParagraphFormat'_in_the_style_file.=Dette_avsnittsformatet_styres_av_innstillingen_'ReferenceParagraphFormat'_eller_'ReferenceHeaderParagraphFormat'_i_stilfilen.
-
The_character_format_is_controlled_by_the_citation_property_'CitationCharacterFormat'_in_the_style_file.=Tegnformatet_styres_av_referanseinnstillingen_'CitationCharacterFormat'_i_stilfilen.
-
Automatically_sync_bibliography_when_inserting_citations=Sykroniser_automatisk_bibliografien_n\u00e5r_nye_referanser_legges_til
-
Look_up_BibTeX_entries_in_the_active_tab_only=Se_etter_BibTeX-enheter_bare_i_den_aktive_databasen
-
Look_up_BibTeX_entries_in_all_open_databases=Se_etter_BibTeX-enheter_i_alle_\u00e5pne_databaser
-
-
-
Autodetecting_paths...=Autodetekterer_kataloger
-
-
Could_not_find_OpenOffice/LibreOffice_installation=Kunne_ikke_finne_OpenOffice/LibreOffice-installasjonen
-
Directories=Kataloger
-
Found_more_than_one_OpenOffice/LibreOffice_executable.=Fant_mer_enn_en_OpenOffice/LibreOffice-startfil.
Please_choose_which_one_to_connect_to\:=Vennligst_velg_hvilken_du_vil_koble_til\:
-
Choose_OpenOffice/LibreOffice_executable=Velg_OpenOffice/LibreOffice-startfil
-
Select_document=Velg_dokument
-
Edit_group_membership=Rediger_gruppetilh\u00f8righet
-
-
-
HTML_list=HTML-liste
-
Click_group_to_toggle_membership_of_selected_entries=Klikk_p\u00e5_gruppe_for_\u00e5_endre_tilh\u00f8righet_for_de_valgte_enhetene
-
-Use_EMACS_23_insertion_string=Bruk_EMACS-23-innsettingsstreng
-
If_possible,_normalize_this_list_of_names_to_conform_to_standard_BibTeX_name_formatting=Om_mulig,_normaliser_denne_navnelisten_til_standard_BibTeX-navneformatering
-
Could_not_open_%0=Kunne_ikke_\u00e5pne_%0
-
Unknown_import_format=Ukjent_importformat
-
-
Web_search=Webs\u00f8k
-
-
-
-
-
-
Style_selection=Valg_av_stil
-
-
-
-
-
No_valid_style_file_defined=Ingen_gyldig_stilfil_definert
-
Choose_pattern=Velg_m\u00f8nster
-
Use_the_BIB_file_location_as_primary_file_directory=Bruk_plasseringen_av_BIB-filen_som_standard_filkatalog
-
Could_not_run_the_gnuclient/emacsclient_program._Make_sure_you_have_the_emacsclient/gnuclient_program_installed_and_available_in_the_PATH.=Kunne_ikke_kalle_gnuclient/emacsclient._Sjekk_at_du_har_programmet_installert_og_tilgjengelig_i_PATH.
-
Built-in_journal_list=Innebygget_journalliste
-
OpenOffice/LibreOffice_connection=Kobling_til_OpenOffice/LibreOffice
-
You_can_add_additional_journal_names_by_setting_up_a_personal_journal_list,<br>as_well_as_linking_to_external_journal_lists.=Du_kan_legge_til_flere_journalnavn_ved_\u00e5_sette_opp_en_personlig_liste,<br>eller_lenke_til_eksterne_lister.
-
JabRef_includes_a_built-in_list_of_journal_abbreviations.=JabRef_har_en_innebygget_liste_over_journalforkortelser.
-
You_must_select_either_a_valid_style_file,_or_use_one_of_the_default_styles.=Du_m\u00e5_enten_velge_en_gyldig_stilfil_eller_bruke_en_av_standardstilene.
-
-
This_is_a_simple_copy_and_paste_dialog._First_load_or_paste_some_text_into_the_text_input_area.<br>After_that,_you_can_mark_text_and_assign_it_to_a_BibTeX_field.=Dette_er_et_enkelt_klipp-og-lim-vindu._F\u00f8rst_last_inn_eller_lim_inn_tekst_i_tekstfeltet.<br>Deretter_kan_du_merke_tekst_og_tilordne_den_til_BibTeX-felter.
-
This_feature_generates_a_new_database_based_on_which_entries_are_needed_in_an_existing_LaTeX_document.=Denne_funksjonen_genererer_en_ny_database_basert_p\u00e5_hvilke_enheter_som_trengs_i_et_eksisterende_LaTeX-dokument.
-
You_need_to_select_one_of_your_open_databases_from_which_to_choose_entries,_as_well_as_the_AUX_file_produced_by_LaTeX_when_compiling_your_document.=Du_m\u00e5_velge_en_av_de_\u00e5pne_databasene_hvor_enheter_skal_hentes_fra,_i_tillegg_til_AUX-filen_generert_av_LaTeX_n\u00e5r_dokumentet_kompileres.
First_select_entries_to_clean_up.=
Cleanup_entry=
Autogenerate_PDF_Names=
Auto-generating_PDF-Names_does_not_support_undo._Continue?=
+
Use_full_firstname_whenever_possible=
Use_abbreviated_firstname_whenever_possible=
Use_abbreviated_and_full_firstname=
@@ -2153,9 +1641,8 @@ Autocomplete_after_following_number_of_characters=
Name_format_used_for_autocompletion=
Treatment_of_first_names=
Cleanup_entries=
-%0_mode=%0-modus
Automatically_assign_new_entry_to_selected_groups=Tilordne_automatisk_nye_enheter_til_valgte_grupper
-
+%0_mode=%0-modus
Move_DOIs_from_note_and_URL_field_to_DOI_field_and_remove_http_prefix=
Make_paths_of_linked_files_relative_(if_possible)=
Rename_PDFs_to_given_filename_format_pattern=
@@ -2166,7 +1653,6 @@ No_entry_needed_a_clean_up=
One_entry_needed_a_clean_up=
%0_entries_needed_a_clean_up=
-
Error_downloading_file_'%0'=Feil_ved_nedlasting_av_filen_'%0'
Download_failed=Nedlasting_mislyktes
@@ -2174,7 +1660,6 @@ Remove_selected=Fjern_merkede
Group_tree_could_not_be_parsed._If_you_save_the_BibTeX_database,_all_groups_will_be_lost.=
Attach_file=
-
Setting_all_preferences_to_default_values.=
Resetting_preference_key_'%0'=
Unknown_preference_key_'%0'=
@@ -2217,7 +1702,6 @@ Five_stars=
Four_stars=
Help_on_special_fields=
Keywords_of_selected_entries=
-Manage_content_selectors=
Manage_keywords=
No_priority_information=
No_rank_information=
@@ -2245,9 +1729,10 @@ Two_stars=
Update_keywords=
Write_values_of_special_fields_as_separate_fields_to_BibTeX=
You_have_changed_settings_for_special_fields.=
-
%0_entries_found._To_reduce_server_load,_only_%1_will_be_downloaded.=
+A_string_with_that_label_already_exists=Det_finnes_allerede_en_streng_med_det_navnet
Connection_to_OpenOffice/LibreOffice_has_been_lost._Please_make_sure_OpenOffice/LibreOffice_is_running,_and_try_to_reconnect.=
+
Correct_the_entry,_and_reopen_editor_to_display/edit_source.=
Could_not_connect_to_a_running_gnuserv_process._Make_sure_that_Emacs_or_XEmacs_is_running,<BR>and_that_the_server_has_been_started_(by_running_the_command_'server-start'/'gnuserv-start').=
Could_not_connect_to_running_OpenOffice/LibreOffice.=
@@ -2269,19 +1754,14 @@ Your_style_file_specifies_the_paragraph_format_'%0',_which_is_undefined_in_your_
Searching...=
You_have_selected_more_than_%0_entries_for_download._Some_web_sites_might_block_you_if_you_make_too_many_rapid_downloads._Do_you_want_to_continue?=
Confirm_selection=
-Unknown_DOI\:_'%0'.=
Add_{}_to_specified_title_words_on_search_to_keep_the_correct_case=
Import_conversions=
Please_enter_a_search_string=
Please_open_or_start_a_new_database_before_searching=
-An_error_occurred_while_fetching_from_ADS_(%0)\:=
-An_error_occurred_while_parsing_abstract=
-Unknown_DiVA_entry\:_'%0'.=
-Get_BibTeX_entry_from_DiVA=
Log=
-
Canceled_merging_entries=
+
Format_units_by_adding_non-breaking_separators_and_keeping_the_correct_case_on_search=
Merge_entries=
Merged_entries=
@@ -2295,29 +1775,35 @@ Use_Emacs_key_bindings=
You_have_to_choose_exactly_two_entries_to_merge.=
Update_timestamp_on_modification=
-
All_key_bindings_will_be_reset_to_their_defaults.=
+
Automatically_set_file_links=
Continue?=
Resetting_all_key_bindings=
-
Hostname=
Invalid_setting=
Network=
Please_specify_both_hostname_and_port=
+Please_specify_both_username_and_password=
+
Use_custom_proxy_configuration=
+Proxy_requires_authentication=
+Attention\:_Password_is_stored_in_plain_text\!=
Clear_connection_settings=
Cleared_connection_settings.=
+
Rebind_C-a,_too=
+Rebind_C-f,_too=
Show_number_of_elements_contained_in_each_group=
Open_folder=
Searches_for_unlinked_PDF_files_on_the_file_system=
-
Export_entries_ordered_as_specified=
Export_sort_order=
+Export_sorting=
Newline_separator=
+
Save_entries_ordered_as_specified=
Save_sort_order=
Show_extra_columns=
@@ -2328,7 +1814,6 @@ Move_to_group=
Clear_read_status=
Convert_to_BibLatex_format_(for_example,_move_the_value_of_the_'journal'_field_to_'journaltitle')=
-Could_not_apply_changes.=
Deprecated_fields=
Hide/show_toolbar=
No_read_status_information=
@@ -2340,127 +1825,111 @@ Save_selected_as_plain_BibTeX...=
Set_read_status_to_read=
Set_read_status_to_skimmed=
Show_deprecated_BibTeX_fields=
+
Show_gridlines=
Show_printed_status=
Show_read_status=
Table_row_height_padding=
-Marked_all_%0_selected_entries=
Marked_selected_entry=
-Toggle_print_status=
-Unmarked_all_%0_selected_entries=
+Marked_all_%0_selected_entries=
Unmarked_selected_entry=
+Unmarked_all_%0_selected_entries=
+Toggle_print_status=
+
Unmarked_all_entries=
Unable_to_find_the_requested_look_and_feel_and_thus_the_default_one_is_used.=
-Could_not_open_browser.=
Opens_JabRef's_GitHub_page=
-
-Rebind_C-f,_too=
-This_group_contains_all_entries._It_cannot_be_edited_or_removed.=
+Could_not_open_browser.=
+Please_open_%0_manually.=
+The_link_has_been_copied_to_the_clipboard.=
Open_%0_file=
Cannot_delete_file=
-Convert=
-Delete_local_file=
File_permission_error=
-Help_on_Name_Formatting=
-Normalize_to_BibTeX_name_format=
-Path_to_%0=Sti_til_%0
Push_to_%0=Send_til_%0
+Path_to_%0=Sti_til_%0
+Convert=
+Normalize_to_BibTeX_name_format=
+Help_on_Name_Formatting=
Add_new_file_type=
-Follow_DOI_or_URL_link_and_try_to_locate_PDF_full_text_document=
+
Left_entry=
-No_information_added=
+Right_entry=
+Use=
Original_entry=
Replace_original_entry=
-Right_entry=
+No_information_added=
Select_at_least_one_entry_to_manage_keywords.=
-Use=
-Could_not_save_file.=
-Changed_type_to_'%0'_for=Endret_type_til_'%0'_for
-Database_'%0'_has_changed.=
-Copy_\\cite{BibTeX_key}=Kopier_\\cite{BibTeX-n\u00f8kkel}
-Copy_BibTeX_key_and_title=Kopier_BibTeX-n\u00f8kkel_og_tittel
-File_rename_failed_for_%0_entries.=
-To_set_up,_go_to=For_\u00e5_sette_opp,_g\u00e5_til
-Search_%0=S\u00f8l_%0
-Invalid_DOI\:_'%0'.=Ugyldig_DOI\:_'%0'.
-Could_not_connect_to_%0=Kunne_ikke_koble_til_%0
-
+OpenDocument_text=
+OpenDocument_spreadsheet=
+OpenDocument_presentation=
%0_image=
-%0_problem(s)_found=
-'%0'_is_not_a_valid_ADS_bibcode.=
-Accepting_the_change_replaces_the_complete_groups_tree_with_the_externally_modified_groups_tree.=
Added_entry=
-Added_new_'%0'_entry.=
-Deleted_entry=
-Discard_changes=
-Donate_to_JabRef=
-Export_with_selected_format=
-Field_is_missing=
-Filled=
-From_import=
-Keep_left=
-Keep_merged_entry_only=
-Keep_right=
-Merged_BibTeX_source_code=
Modified_entry=
+Deleted_entry=
Modified_groups_tree=
-Multiple_entries_selected._Do_you_want_to_change_the_type_of_all_these_to_'%0'?=
-No_problems_found.=
-Old_entry=
-OpenDocument_presentation=
-OpenDocument_spreadsheet=
-OpenDocument_text=
-Please_move_the_file_manually_and_link_in_place.=
-Print_entry_preview=
-Really_delete_the_%0_selected_entries?=
-Really_delete_the_selected_entry?=
Removed_all_groups=
-Return_to_JabRef=
-Save_changes=
+Accepting_the_change_replaces_the_complete_groups_tree_with_the_externally_modified_groups_tree.=
Select_export_format=
+Return_to_JabRef=
+Please_move_the_file_manually_and_link_in_place.=
+Could_not_connect_to_%0=Kunne_ikke_koble_til_%0
Warning\:_%0_out_of_%1_entries_have_undefined_BibTeX_key.=
-large_capitals_are_not_masked_using_curly_brackets_{}=
occurrence=
-should_contain_a_four_digit_number=
-should_contain_a_valid_page_number_range=
-should_end_with_a_name=
+Added_new_'%0'_entry.=
+Multiple_entries_selected._Do_you_want_to_change_the_type_of_all_these_to_'%0'?=
+Changed_type_to_'%0'_for=Endret_type_til_'%0'_for
+Really_delete_the_selected_entry?=
+Really_delete_the_%0_selected_entries?=
+Keep_merged_entry_only=
+Keep_left=
+Keep_right=
+Old_entry=
+From_import=
+No_problems_found.=
+%0_problem(s)_found=
+Save_changes=
+Discard_changes=
+Database_'%0'_has_changed.=
+Print_entry_preview=
+Copy_\\cite{BibTeX_key}=Kopier_\\cite{BibTeX-n\u00f8kkel}
+Copy_BibTeX_key_and_title=Kopier_BibTeX-n\u00f8kkel_og_tittel
+File_rename_failed_for_%0_entries.=
+To_set_up,_go_to=For_\u00e5_sette_opp,_g\u00e5_til
+Merged_BibTeX_source_code=
+Invalid_DOI\:_'%0'.=Ugyldig_DOI\:_'%0'.
should_start_with_a_name=
+should_end_with_a_name=
unexpected_closing_curly_bracket=
unexpected_opening_curly_bracket=
+capital_letters_are_not_masked_using_curly_brackets_{}=
+should_contain_a_four_digit_number=
+should_contain_a_valid_page_number_range=
+Filled=
+Field_is_missing=
+Search_%0=S\u00f8l_%0
-Work_options=
-
-Advanced_search_active.=
-Found_%0_results.=
-No_results_found.=
-Normal_search_active.=
-Search_globally=
-Search_in_all_open_databases=
Search_results_in_all_databases_for_%0=
Search_results_in_database_%0_for_%1=
-This_search_contains_entries_in_which=
+Search_globally=
+No_results_found.=
+Found_%0_results.=
+Advanced_search_active.=
+Normal_search_active.=
+plain_text=
This_search_contains_entries_in_which_any_field_contains_the_regular_expression_<b>%0</b>=
This_search_contains_entries_in_which_any_field_contains_the_term_<b>%0</b>=
-plain_text=
-
-Attention\:_Password_is_stored_in_plain_text\!=
-Please_specify_both_username_and_password=
-Proxy_requires_authentication=
+This_search_contains_entries_in_which=
-An_autosave_file_was_found_for_this_database._This_could_indicate_that_JabRef_did_not_shut_down_cleanly_last_time_the_file_was_used.=
-Note\:_A_full_text_search_is_currently_not_supported_for_%0=
Unable_to_autodetect_OpenOffice/LibreOffice_installation._Please_choose_the_installation_directory_manually.=
-
JabRef_no_longer_supports_'ps'_or_'pdf'_fields.<br>File_links_are_now_stored_in_the_'file'_field_and_files_are_stored_in_an_external_file_directory.<br>To_make_use_of_this_feature,_JabRef_needs_to_upgrade_file_links.<br><br>=
This_database_uses_outdated_file_links.=
-A_string_with_that_label_already_exists=Det_finnes_allerede_en_streng_med_det_navnet
Clear_search=
Close_database=
@@ -2497,55 +1966,32 @@ Resolve_duplicate_BibTeX_keys=
Save_all=
String_dialog,_add_string=
String_dialog,_remove_string=
-Switch_preview_layout=
Synchronize_files=
Unabbreviate=
-
should_contain_a_protocol=
Copy_preview=
-
Automatically_setting_file_links=
Regenerating_BibTeX_keys_according_to_metadata=
No_meta_data_present_in_BIB_file._Cannot_regenerate_BibTeX_keys=
-
Regenerate_all_keys_for_the_entries_in_a_BibTeX_file=
-
Show_debug_level_messages=
-
-Export_sorting=
-
-New_%0_database=
-
-New_%0_database_created.=
-
-No_entry_found_for_ISBN_%0_at_www.ebook.de=
-
-Save_actions=
-Enable_save_actions=
-Always_reformat_BIB_file_on_save_and_export=
-
Default_bibliography_mode=
-
-
+New_%0_database_created.=
Show_only_preferences_deviating_from_their_default_value=
default=
key=
type=
value=
-
Show_preferences=
-
+Save_actions=
+Enable_save_actions=
Other_fields=
Show_remaining_fields=
link_should_refer_to_a_correct_file_path=
-
abbreviation_detected=
wrong_entry_type_as_proceedings_has_page_numbers=
-
-Run_field_formatter\:=
-
Abbreviate_journal_names=
Abbreviating...=
Adding_fetched_entries=
@@ -2557,27 +2003,22 @@ Unabbreviate_journal_names=
Unabbreviating...=
Usage=
-Adds_{}_brackets_around_acronyms,_month_names_and_countries_to_preserve_their_case.=
-Converts_units_to_LaTeX_formatting.=
-Does_nothing.=
+Adds_{}_brackets_around_acronyms,_month_names_and_countries_to_preserve_their_case.=
Are_you_sure_you_want_to_reset_all_settings_to_default_values?=
Reset_preferences=
-
Ill-formed_entrytype_comment_in_BIB_file=
+
+Move_linked_files_to_default_file_directory_%0=
+
Clipboard=
Could_not_paste_entry_as_text\:=
Do_you_still_want_to_continue?=
This_action_will_modify_the_following_field(s)_in_at_least_one_entry_each\:=
This_could_cause_undesired_changes_to_your_entries.=
-
-Disable_highlight_groups_matching_entries=
-
-
+Run_field_formatter\:=
Table_font_size_is_%0=
-
-Move_linked_files_to_default_file_directory_%0=
-
+%0_import_canceled=%0-import_kansellert
Internal_style=
Add_style_file=
Are_you_sure_you_want_to_remove_the_style?=
@@ -2585,7 +2026,6 @@ Current_style_is_'%0'=
Remove_style=
Select_one_of_the_available_styles_or_add_a_style_file_from_disk.=
You_must_select_a_valid_style_file.=
-
Reload=
Capitalize=
@@ -2596,9 +2036,11 @@ Changes_all_letters_to_upper_case.=
Changes_the_first_letter_of_all_words_to_capital_case_and_the_remaining_letters_to_lower_case.=
Cleans_up_LaTeX_code.=
Converts_HTML_code_to_LaTeX_code.=
+Converts_HTML_code_to_Unicode.=
Converts_LaTeX_encoding_to_Unicode_characters.=
Converts_Unicode_characters_to_LaTeX_encoding.=
Converts_ordinals_to_LaTeX_superscripts.=
+Converts_units_to_LaTeX_formatting.=
HTML_to_LaTeX=
LaTeX_cleanup=
LaTeX_to_Unicode=
@@ -2622,16 +2064,13 @@ Title_case=
Unicode_to_LaTeX=
Units_to_LaTeX=
Upper_case=
+Does_nothing.=
Identity=
-
Clears_the_field_completely.=
Directory_not_found=
Main_file_directory_not_set\!=
-
This_operation_requires_exactly_one_item_to_be_selected.=
-
Importing_in_%0_format=
-
Female_name=
Female_names=
Male_name=
@@ -2640,7 +2079,6 @@ Mixed_names=
Neuter_name=
Neuter_names=
-
Lookup_DOI=
Audio_CD=
@@ -2677,38 +2115,29 @@ U.S._patent=
U.S._patent_request=
Verse=
-
change_entries_of_group=
odd_number_of_unescaped_'\#'=
+
Plain_text=
Show_diff=
character=
word=
-
Show_symmetric_diff=
HTML_encoded_character_found=
-
booktitle_ends_with_'conference_on'=
+
All_external_files=
OpenOffice/LibreOffice_integration=
incorrect_control_digit=
incorrect_format=
-
-Expected_"%0"_to_contain_whitespace=
-Syntax_error_in_regular-expression_pattern=
-
Copy_version_to_clipboard=
Copied_version_to_clipboard=
+
BibTeX_key=
Message=
-
-Get_fulltext=
-
-Download_from_URL=
-
Decryption_not_supported.=
Cleared_'%0'_for_%1_entries=
@@ -2727,16 +2156,11 @@ To_see_what_is_new_view_the_changelog.=
A_new_version_of_JabRef_has_been_released.=
JabRef_is_up-to-date.=
Latest_version=
-
-Please_open_%0_manually.=
-
-The_link_has_been_copied_to_the_clipboard.=
-
Online_help_forum=
-
Custom=
-Converts_HTML_code_to_Unicode.=
+Export_cited=
+Unable_to_generate_new_database=
Open_console=
Use_default_terminal_emulator=
@@ -2744,28 +2168,22 @@ Execute_command=
Note\:_Use_the_placeholder_%0_for_the_location_of_the_opened_database_file.=
Executing_command_\"%0\"...=
Error_occured_while_executing_the_command_\"%0\".=
-
Reformat_ISSN=
-Unable_to_generate_new_database=
-Export_cited=
Countries_and_territories_in_English=
Electrical_engineering_terms=
Enabled=
Internal_list=
+Manage_protected_terms_files=
Months_and_weekdays_in_English=
The_text_after_the_last_line_starting_with_\#_will_be_used=
-
Add_protected_terms_file=
Are_you_sure_you_want_to_remove_the_protected_terms_file?=
Remove_protected_terms_file=
-Manage_protected_terms_files=
-
Add_selected_text_to_list=
Add_{}_around_selected_text=
Format_field=
New_protected_terms_file=
-
change_field_%0_of_entry_%1_from_%2_to_%3=
change_key_from_%0_to_%1=
change_string_content_%0_to_%1=
@@ -2775,35 +2193,29 @@ insert_entry_%0=
insert_string_%0=
remove_entry_%0=
remove_string_%0=
-
undefined=
Cannot_get_info_based_on_given_%0\:_%1=
Get_BibTeX_data_from_%0=
No_%0_found=
Entry_from_%0=
-
Merge_entry_with_%0_information=
Updated_entry_with_info_from_%0=
Connection=
+Connecting...=
Host=
Port=
Database=
User=
+Connect=Koble_til
Connection_error=
-Driver_error=
Connection_to_%0_server_established.=
Required_field_"%0"_is_empty.=
-
%0_driver_not_available.=
-
The_connection_to_the_server_has_been_terminated.=
-
Connection_lost.=
Reconnect=
Work_offline=
-
Working_offline.=
-
Update_refused.=
Update_refused=
Local_entry=
@@ -2814,7 +2226,12 @@ Local_version\:_%0=
Shared_version\:_%0=
Please_merge_the_shared_entry_with_yours_and_press_"Merge_entries"_to_resolve_this_problem.=
Canceling_this_operation_will_leave_your_changes_unsynchronized._Cancel_anyway?=
-The_BibEntry_you_currently_work_on_has_been_deleted_on_the_shared_side._Hit_"Keep"_to_recover_the_entry.=
+Shared_entry_is_no_longer_present=
+The_BibEntry_you_currently_work_on_has_been_deleted_on_the_shared_side.=
+You_can_restore_the_entry_using_the_"Undo"_operation.=
+Remember_password?=
+You_are_already_connected_to_a_database_using_entered_connection_details.=
+
Cannot_cite_entries_without_BibTeX_keys._Generate_keys_now?=
New_technical_report=
@@ -2824,12 +2241,8 @@ Protected_terms_file=
Style_file=
Open_OpenOffice/LibreOffice_connection=
-
You_must_enter_at_least_one_field_name=
-
-
Non-ASCII_encoded_character_found=
-
Toggle_web_search_interface=
Background_color_for_resolved_fields=
Color_code_for_resolved_fields=
@@ -2843,13 +2256,59 @@ There_were_%0_files_which_could_not_be_imported.=
Migration_help_information=
Entered_database_has_obsolete_structure_and_is_no_longer_supported.=
However,_a_new_database_was_created_alongside_the_pre-3.6_one.=
-
Click_here_to_learn_about_the_migration_of_pre-3.6_databases.=
-
-Connecting...=
Opens_JabRef's_Facebook_page=
Opens_JabRef's_blog=
Opens_JabRef's_website=
-
Opens_a_link_where_the_current_development_version_can_be_downloaded=
See_what_has_been_changed_in_the_JabRef_versions=
+Referenced_BibTeX_key_does_not_exist=
+Finished_downloading_full_text_document_for_entry_%0.=
+Full_text_document_download_failed_for_entry_%0.=
+Look_up_full_text_documents=
+You_are_about_to_look_up_full_text_documents_for_%0_entries.=
+last_four_nonpunctuation_characters_should_be_numerals=
+shared=
+should_contain_an_integer_or_a_literal=
+should_have_the_first_letter_capitalized=
+
+ID=
+ID_type=
+ID-based_entry_generator=
+Fetcher_'%0'_did_not_find_an_entry_for_id_'%1'.=
+
+Select_first_entry=
+Select_last_entry=
+
+Invalid_ISBN\:_'%0'.=
+should_be_an_integer_or_normalized=
+should_be_normalized=
+
+Empty_search_ID=
+The_given_search_ID_was_empty.=
+Copy_BibTeX_key_and_link=
+empty_BibTeX_key=
+BibLaTeX_field_only=
+
+Error_while_generating_fetch_URL=
+Error_while_parsing_ID_list=
+Unable_to_get_PubMed_IDs=
+Backup_found=
+A_backup_file_for_'%0'_was_found.=
+This_could_indicate_that_JabRef_did_not_shut_down_cleanly_last_time_the_file_was_used.=
+Do_you_want_to_recover_the_database_from_the_backup_file?=
+Firstname_Lastname=
+
+Recommended_for_%0=
+This_might_be_caused_by_reaching_the_traffic_limitation_of_Google_Scholar_(see_'Help'_for_details).=
+
+Problem_downloading_from_%1=
+
+File_directory_pattern=
+Update_with_bibliographic_information_from_the_web=
+
+Could_not_find_any_bibliographic_information.=
+BibTeX_key_%0_deviates_from_generated_key_%1=
+DOI_%0_is_invalid=
+
+Jump_to_entry=
diff --git a/src/main/resources/l10n/JabRef_pt_BR.properties b/src/main/resources/l10n/JabRef_pt_BR.properties
index 9a471f7..551f280 100644
--- a/src/main/resources/l10n/JabRef_pt_BR.properties
+++ b/src/main/resources/l10n/JabRef_pt_BR.properties
@@ -1,763 +1,1396 @@
#!
-#! created/edited by Popeye version 0.55 (https\://github.com/koppor/popeye)
+#! created/edited by Popeye version 0.55 (github.com/JabRef/popeye)
#! encoding:UTF-8
+
%0_contains_the_regular_expression_<b>%1</b>=%0_contém_a_Expressão_Regular_<b>%1</b>
+
%0_contains_the_term_<b>%1</b>=%0_contém_o_termo_<b>%1</b>
+
%0_doesn't_contain_the_regular_expression_<b>%1</b>=%0_não_contém_a_Expressão_Regular_<b>%1</b>
+
%0_doesn't_contain_the_term_<b>%1</b>=%0_não_contém_o_termo_<b>%1</b>
+
%0_export_successful=%0_exportado_com_sucesso
+
%0_matches_the_regular_expression_<b>%1</b>=%0_encontrada_a_expressão_regular_<b>%1</b>
+
%0_matches_the_term_<b>%1</b>=%0_encontrado_o_termo_<b>%1</b>
-<field_name>=<nome_do_campo>
+
<HTML>Could_not_find_file_'%0'<BR>linked_from_entry_'%1'</HTML>=<HTML>Não_foi_possível_encontrar_o_arquivo_'%0'<BR>a_partir_da_referência_'%1'</HTML>
+
<select>=<selecionar>
-<select_word>=<selecionar_palavra>
+
Abbreviate_journal_names_of_the_selected_entries_(ISO_abbreviation)=Abreviar_nomes_de_periódicos_das_referências_selecionadas_(abreviação_ISO)
Abbreviate_journal_names_of_the_selected_entries_(MEDLINE_abbreviation)=Abreviar_nomes_de_periódicos_das_referências_selecionadas_(abreviação_MEDLINE)
+
Abbreviate_names=Abreviar_nomes
Abbreviated_%0_journal_names.=%0_nomes_de_periódicos_foram_abreviados.
+
Abbreviation=Abreviação
+
About_JabRef=Sobre_JabRef
+
Abstract=Resumo
+
Accept=Aceitar
+
Accept_change=Aceitar_modificação
+
Action=Ação
+
Add=Adicionar
-Add_a_(compiled)_custom_ImportFormat_class_from_a_class_path.=Adicionar_uma_classe_ImportFormat_customizada_(compilada)_a_partir_de_um_classpath.
+
+Add_a_(compiled)_custom_Importer_class_from_a_class_path.=Adicionar_uma_classe_Importer_customizada_(compilada)_a_partir_de_um_classpath.
The_path_need_not_be_on_the_classpath_of_JabRef.=O_caminho_não_precisa_estar_no_classpath_do_JabRef.
-Add_a_(compiled)_custom_ImportFormat_class_from_a_ZIP-archive.=Adicionar_uma_classe_ImportFormat_customizada_(compilada)_a_partir_de_um_arquivo_zip.
+
+Add_a_(compiled)_custom_Importer_class_from_a_ZIP-archive.=Adicionar_uma_classe_Importer_customizada_(compilada)_a_partir_de_um_arquivo_zip.
The_ZIP-archive_need_not_be_on_the_classpath_of_JabRef.=O_arquivo_zip_não_precisa_estar_no_classpath_do_JabRef.
+
Add_entry_selection_to_this_group=Adicionar_referências_selecionadas_a_um_grupo
+
Add_from_folder=Adicionar_a_partir_de_uma_pasta
+
Add_from_JAR=Adicionar_a_partir_de_um_JAR
+
add_group=adicionar_grupo
+
Add_group=Adicionar_grupo
+
Add_new=Adicionar_novo
+
Add_subgroup=Adicionar_subgrupo
+
Add_to_group=Adicionar_ao_grupo
+
Added_group_"%0".=O_grupo_"%0"_foi_adicionado.
+
Added_new=Adicionado_novo
+
Added_string=Adicionada_string
+
Additionally,_entries_whose_<b>%0</b>_field_does_not_contain_<b>%1</b>_can_be_assigned_manually_to_this_group_by_selecting_them_then_using_either_drag_and_drop_or_the_context_menu._This_process_adds_the_term_<b>%1</b>_to_each_entry's_<b>%0</b>_field._Entries_can_be_removed_manually_from_this_group_by_selecting_them_then_using_the_context_menu._This_process_removes_the_term_<b>%1</b>_from_each_entry's_<b>%0</b>_field.=Adicionalmente,_as_referências_cujo_campo_<b>%0</b>não_contem_<b>%1</b> [...]
+
Advanced=Avançado
All_entries=Todas_as_referências
All_entries_of_this_type_will_be_declared_typeless._Continue?=Todas_as_referências_serão_consideradas_sem_tipo._Continuar?
+
All_fields=Todos_os_campos
+
All_subgroups_(recursively)=Todos_os_subgrupos_(recursivamente)
-An_exception_occurred_while_accessing_'%0'=Uma_exceção_ocorreu_durante_ao_acesso_a_'%0'
+
+Always_reformat_BIB_file_on_save_and_export=
+
A_SAX_exception_occurred_while_parsing_'%0'\:=Uma_exceção_ocorreu_durante_a_análise_de_'%0'
+
and=e
and_the_class_must_be_available_in_your_classpath_next_time_you_start_JabRef.=e_a_classe_deve_estar_disponível_em_seu_classpath_na_próxima_vez_que_você_iniciar_o_JabRef.
+
any_field_that_matches_the_regular_expression_<b>%0</b>=qualquer_campo_que_corresponde_a_expressão_regular_<b>%0</b>
+
Appearance=Aparência
+
Append=Anexar
Append_contents_from_a_BibTeX_database_into_the_currently_viewed_database=Anexar_o_conteúdo_de_uma_base_de_dados_BibTeX_à_base_de_dados_atual
+
Append_database=Anexar_base_de_dados
+
Append_the_selected_text_to_BibTeX_field=Anexar_o_texto_selecionado_à_chave_BibTeX
Application=Aplicação
+
Apply=Aplicar
+
Arguments_passed_on_to_running_JabRef_instance._Shutting_down.=Parâmetros_passados_ao_JabRef_em_execução._Encerrando_o_programa.
+
Assign_entry_selection_exclusively_to_this_group=Atribuir_referências_selecionadas_exclusivamente_para_este_grupo
+
Assign_new_file=Associar_novo_arquivo
+
Assign_the_original_group's_entries_to_this_group?=Atribuir_as_referênciass_originais_do_grupo_à_este_grupo?
+
Assigned_%0_entries_to_group_"%1".=%0_referências_atribuídas_ao_grupo_"%1"
+
Assigned_1_entry_to_group_"%0".=1_referência_atribuído_ao_grupo_"%0"
+
Attach_URL=Anexar_a_URL
+
Attempt_to_automatically_set_file_links_for_your_entries._Automatically_setting_works_if_a_file_in_your_file_directory<BR>or_a_subdirectory_is_named_identically_to_an_entry's_BibTeX_key,_plus_extension.=Tentativa_de_definir_automaticamente_links_de_arquivos_para_suas_referências._A_definição_automática_funciona_se_um_arquivo_em_seu_diretório_arquivo_ou_um_subdiretório<BR>tem_o_mesmo_nome_de_uma_chave_BibTeX_de_uma_referência,_mais_sua_extensão.
+
Auto=Auto
+
Autodetect_format=Detecção_automática_de_formato
+
Autogenerate_BibTeX_keys=Geração_automática_de_chaves_BibTeX
+
Autolink_files_with_names_starting_with_the_BibTeX_key=Criar_links_automaticamente_arquivos_com_nomes_iniciando_pela_chave_BibTeX
+
Autolink_only_files_that_match_the_BibTeX_key=Criar_links_automaticamente_somente_os_arquivos_que_correspondem_à_chave_BibTeX
+
Automatically_create_groups=Criar_grupos_automaticamente
+
Automatically_create_groups_for_database.=Criar_grupos_automaticamente_para_a_base_de_dados.
+
Automatically_created_groups=Grupos_criados_automaticamente
+
Automatically_remove_exact_duplicates=Remover_automaticamente_duplicatas_exatas
+
Allow_overwriting_existing_links.=Sobrescrever_links_existentes.
+
Do_not_overwrite_existing_links.=Não_sobrescrever_links_existentes.
+
AUX_file_import=Importação_de_arquivos_AUX
+
Available_export_formats=Formatos_de_exportação_disponíveis
+
Available_BibTeX_fields=Campos_disponíveis
+
Available_import_formats=Formatos_de_importação_disponíveis
+
Background_color_for_optional_fields=Cor_de_fundo_para_campos_opcionais
+
Background_color_for_required_fields=Cor_de_fundo_para_campos_obrigatórios
+
Backup_old_file_when_saving=Criar_uma_cópia_de_segurança_do_arquivo_antigo_quando_salvar
+
BibTeX_key_is_unique.=A_chave_BibTeX_é_única.
-BibTeX_source=Fonte_BibTeX
+
+%0_source=Fonte_%0
+
Broken_link=Link_quebrado
+
Browse=Explorar
+
by=por
+
Cancel=Cancelar
+
Cannot_add_entries_to_group_without_generating_keys._Generate_keys_now?=Não_é_possível_adicionar_referências_ao_grupo_sem_gerar_as_chaves._Gerar_as_chaves_agora?
+
Cannot_merge_this_change=Não_é_possível_mesclar_esta_mudança.
+
Cannot_move_group_"%0"_down.=Não_é_possível_mover_o_grupo_"%0"_para_baixo.
+
Cannot_move_group_"%0"_left.=Não_é_possível_mover_o_grupo_"%0"_para_a_esquerda.
+
Cannot_move_group_"%0"_right.=Não_é_possível_mover_o_grupo_"%0"_para_a_direita.
+
Cannot_move_group_"%0"_up.=Não_é_possível_mover_o_grupo_"%0"_para_cima.
+
case_insensitive=Insensível_ao_caso
+
case_sensitive=sensível_ao_caso
+
Case_sensitive=Sensível_ao_caso
+
change_assignment_of_entries=Alterar_atribuição_de_referências
+
Change_case=Modificar_caso
+
Change_entry_type=Modificar_tipo_de_referência
Change_file_type=Modificar_tipo_do_arquivo
+
+
Change_of_Grouping_Method=Modificar_método_de_agrupamento
+
change_preamble=modificar_preâmbulo
+
Change_table_column_and_General_fields_settings_to_use_the_new_feature=Modificar_coluna_da_tabela_e_configurações_gerais_do_campo_para_utilizar_a_nova_funcionalidade
+
Changed_font_settings=Configurações_de_fonte_modificadas
+
Changed_language_settings=Configurações_de_idioma_modificadas
+
Changed_look_and_feel_settings=Configurações_do_esquema_de_cores_modificadas
+
Changed_preamble=Preâmbulo_modificado
+
Characters_to_ignore=Caracteres_para_ignorar
+
Check_existing_file_links=Verificar_links_de_arquivos_existentes
+
Check_links=Verificar_links
+
Choose_the_URL_to_download.=Escolha_a_URL_para_baixar.
Cite_command=Comando_citar
+
Class_name=Nome_da_classe
+
Clear=Limpar
+
Clear_fields=Limpar_campos
+
Close=Fechar
Close_others=Fechar_os_outros
Close_all=Fechar_todos
+
Close_dialog=Fechar_janela_de_diálogo
+
Close_the_current_database=Fechar_a_base_de_dados_atual
+
Close_window=Fechar_Janela
+
Closed_database=Base_de_dados_fechada
+
Collapse_subtree=Colapsar_subárvore
+
Color_codes_for_required_and_optional_fields=Códigos_de_cores_para_campos_obrigatórios_e_opcionais
+
Color_for_marking_incomplete_entries=Cores_para_marcar_referências_incompletas
+
Column_width=Largura_da_coluna
+
Command_line_id=ID_da_linha_de_comando
-Connect=Conectar
+
+
Contained_in=Contido_em
+
Content=Conteúdo
+
Copied=Copiado
+
Copied_cell_contents=Conteúdos_da_célula_copiados
+
Copied_key=Chave_BibTeX_copiada
+
Copied_keys=Chaves_BibTeX_copiadas
+
Copy=Copiar
+
Copy_BibTeX_key=Copiar_chave_BibTeX
Copy_file_to_file_directory=Copiar_arquivo_para_o_diretório_de_arquivos
+
Copy_to_clipboard=Copiar_para_a_área_de_transferência
+
Could_not_call_executable=Não_é_possível_chamar_o_executável
Could_not_connect_to_Vim_server._Make_sure_that_Vim_is_running<BR>with_correct_server_name.=Não_foi_possível_conectar_ao_servidor_Vim._Certifique-se_que_o_Vim_está_sendo_executado<br>_com_o_nome_de_servidor_correto.
+
Could_not_export_file=Não_foi_possível_exportar_os_arquivos
+
Could_not_export_preferences=Não_foi_possível_exportar_as_preferências
+
Could_not_find_a_suitable_import_format.=Não_foi_possível_encontrar_um_formato_de_importação_compatível.
Could_not_import_preferences=Não_foi_possível_importar_as_preferências
+
Could_not_instantiate_%0=Não_foi_possível_instanciar_%0
Could_not_instantiate_%0_%1=Não_foi_possível_instanciar_%0_%1
Could_not_instantiate_%0._Have_you_chosen_the_correct_package_path?=Não_foi_possível_instanciar_%0._Você_escolheu_o_caminho_correto_do_pacote?
Could_not_open_link=Não_foi_possível_abrir_o_link
+
Could_not_print_preview=Não_foi_possível_imprimir_a_previsualização
+
Could_not_run_the_'vim'_program.=Não_foi_possível_executar_o_programa_'vim'.
+
Could_not_save_file.=Não_foi_possível_salvar_o_arquivo.
Character_encoding_'%0'_is_not_supported.=A_codificação_de_caracteres_'%0'_não_é_suportada.
+
Created_groups.=Grupos_criados.
+
crossreferenced_entries_included=Registros_com_referências_cruzadas_incluídos
+
Current_content=Conteúdo_atual
+
Current_value=Valor_atual
+
Custom_entry_types=Tipos_de_referências_personalizados
+
Custom_entry_types_found_in_file=Tipos_de_referências_personalizadas_encontradas_no_arquivo
+
Customize_entry_types=Personalizar_tipos_de_referências
+
Customize_key_bindings=Personalizar_combinações_de_teclas
+
Cut=Recortar
+
cut_entries=Recortar_referências
+
cut_entry=Recortar_referência
+
+
Database_encoding=Codificação_da_base_de_dados
+
Database_properties=Propriedades_da_base_de_dados
Database_type=
+
Date_format=Formato_de_data
+
Default=Padrão
+
Default_encoding=Codificação_padrão
+
Default_grouping_field=Agrupamento_de_campo_padrão
+
Default_look_and_feel=Aparência_padrão
+
Default_pattern=Ppadrão_predefinido
+
Default_sort_criteria=Critério_de_ordenação_padrão
Define_'%0'=Definir_'%0'
+
Delete=Remover
+
Delete_custom_format=Remover_formato_personalizado
+
delete_entries=remover_referências
+
Delete_entry=Remover_referência
+
delete_entry=remover_referência
+
Delete_multiple_entries=Remover_múltiplos_referências
+
Delete_rows=Remover_linhas
+
Delete_strings=Remover_strings
+
Deleted=Removido
+
+Delete_local_file=Remover_arquivo_local
+
Delimit_fields_with_semicolon,_ex.=Delimitar_campos_com_ponto_e_vírgula,_ex.
+
Descending=Descendente
+
Description=Descrição
+
Deselect_all=Desmarcar_todos
Deselect_all_duplicates=Desmarcar_todas_as_duplicatas
+
Disable_this_confirmation_dialog=Desativar_este_janela_de_confirmação
+
Display_all_entries_belonging_to_one_or_more_of_the_selected_groups.=Exibir_todas_as_referências_pertencentes_a_um_ou_mais_grupos_selecionados.
+
Display_all_error_messages=Exibir_todas_as_mensagens_de_erro
+
Display_help_on_command_line_options=Exibir_ajuda_para_opções_de_linha_de_comando
+
Display_only_entries_belonging_to_all_selected_groups.=Exibir_apenas_referências_pertencentes_aos_grupos_selecionados.
Display_version=Exibir_versão
+
Displaying_no_groups=Nenhum_grupo_sendo_exibido
+
Do_not_abbreviate_names=Não_abreviar_nomes
+
Do_not_automatically_set=Não_definir_automaticamente
+
Do_not_import_entry=Não_importar_a_referência
+
Do_not_open_any_files_at_startup=Não_abrir_arquivos_ao_iniciar
+
Do_not_overwrite_existing_keys=Não_sobrescrever_chaves_existentes
Do_not_show_these_options_in_the_future=Não_exibir_estas_opções_no_futuro
+
Do_not_wrap_the_following_fields_when_saving=Não_agregar_os_seguintes_campos_ao_salvar
Do_not_write_the_following_fields_to_XMP_Metadata\:=Não_escrever_os_seguintes_campos_para_metadados_XMP\:
+
Do_you_want_JabRef_to_do_the_following_operations?=Você_deseja_que_o_JabRef_realize_as_seguintes_operações?
+
+Donate_to_JabRef=
+
Down=Abaixo
+
Download=Download
+
Download_file=Download_do_arquivo
+
Downloading...=Download_em_curso...
Drop_%0=Soltar_%0
+
duplicate_removal=remoção_de_duplicatas
+
Duplicate_string_name=Duplicar_nome_da_string
+
Duplicates_found=Duplicatas_encontradas
+
Dynamic_groups=Grupos_dinâmicos
+
Dynamically_group_entries_by_a_free-form_search_expression=Agrupar_referências_dinamicamente_utilizando_uma_expressão_de_busca_em_forma_livre
+
Dynamically_group_entries_by_searching_a_field_for_a_keyword=Agrupar_referências_dinamicamente_selecionando_um_campo_ou_palavra-chave
+
Each_line_must_be_on_the_following_form=Cada_linha_deve_posuir_o_seguinte_formato
+
Edit=Editar
+
Edit_custom_export=Editar_exportação_personalizada
Edit_entry=Editar_referência
Save_file=Editar_link_do_arquivo
Edit_file_type=Editar_tipo_de_arquivo
+
Edit_group=Editar_grupo
+
Edit_journal=Editar_periódico
+
Edit_preamble=Editar_preâmbulo
Edit_strings=Editar_strings
Editor_options=Opções_do_editor
+
Empty_BibTeX_key=Chave_BibTeX_vazia
+
Grouping_may_not_work_for_this_entry.=O_agrupamento_pode_não_funcionar_para_esta_referência.
+
empty_database=base_de_dados_vazio
Enable_word/name_autocompletion=Ativar_auto_completar_para_palavras/nomes
+
Enter_URL=Digite_a_URL
+
Enter_URL_to_download=Digite_a_URl_para_download
+
entries=referências
+
Entries_cannot_be_manually_assigned_to_or_removed_from_this_group.=As_referências_não_podem_ser_manualmente_atribuídas_ou_removidas_deste_grupo.
+
Entries_exported_to_clipboard=Referências_exportadas_para_a_área_de_transferência
+
+
entry=referência
+
Entry_editor=Editor_de_referência
+
Entry_preview=Previsualização_da_referência
+
Entry_table=Tabela_de_referências
+
Entry_table_columns=Colunas_da_tabela_de_referências
+
Entry_type=Tipo_de_referência
+
Entry_type_names_are_not_allowed_to_contain_white_space_or_the_following_characters=Os_nomes_dos_tipos_de_referência_não_devem_possuir_espaços_em_branco_ou_os_seguintes_caracteres
+
Entry_types=Tipos_de_referência
+
Error=Erro
Error_exporting_to_clipboard=Erro_ao_exportar_para_a_área_de_transferência
+
Error_occurred_when_parsing_entry=Ocorreu_um_erro_ao_analisar_a_referência
+
Error_opening_file=Erro_ao_abrir_o_arquivo
+
Error_setting_field=Erro_ao_confgurar_campo
Error_while_writing=Erro_durante_a_escrita
Error_writing_to_%0_file(s).=Erro_ao_escrever_para_%0_arquivos.
+
+
Exceptions=Exceções
+
Existing_file=Arquivo_existente
+
'%0'_exists._Overwrite_file?='%0'_existe._Sobrescrever_o_arquivo?
Overwrite_file?=Sobrescrever_o_arquivo??
+
Expand_subtree=Expandir_a_subárvore
+
Export=Exportar
+
Export_name=Exportar_nome
+
Export_preferences=Exportar_preferências
+
Export_preferences_to_file=Exportar_preferências_do_arquivo
+
Export_properties=Propriedades_de_exportação
+
Export_to_clipboard=Exportar_para_a_área_de_transferência
+
Exporting=Exportando
Extension=Extensão
+
External_changes=Modificações_externas
+
External_file_links=Links_de_arquivos_externos
+
External_files=Arquivos_externos
+
External_programs=Programas_externos
+
External_viewer_called=Visualizador_externo_chamado
+
Fetch=Recuperar
+
Field=Campo
+
field=campo
+
Field_name=Nome_do_campo
Field_names_are_not_allowed_to_contain_white_space_or_the_following_characters=O_nome_dos_campos_não_devem_possuir_espaços_em_branco_ou_os_seguintes_caracteres
+
Field_to_filter=Campos_a_serem_filtrados
+
Field_to_group_by=Campos_como_critério_de_agrupamento
+
File=Arquivo
+
file=arquivo
File_'%0'_is_already_open.=O_arquivo_'%0'_já_está_aberto.
+
File_'%0'_not_found=O_arquivo_'%0'_não_foi_encontrado
+
File_changed=Arquivo_modificado
File_directory_is_'%0'\:=O_diretório_do_arquivo_é_'%0'\:
+
File_directory_is_not_set_or_does_not_exist\!=O_diretório_do_arquivo_não_foi_condiguração_ou_não_existe\!
File_exists=O_arquivo_existe
+
File_has_been_updated_externally._What_do_you_want_to_do?=O_arquivo_foi_atualizado_externamente._O_que_você_deseja_fazer?
+
File_not_found=Arquivo_não_encontrado
File_type=Tipo_de_arquivo
+
File_updated_externally=Arquivo_atualizado_externamente
+
filename=nome_do_arquivo
+
Files_opened=Arquivos_abertos
+
Filter=Filtro
+
Finished_automatically_setting_external_links.=A_definição_automática_de_links_externos_foi_finalizada.
+
Finished_synchronizing_file_links._Entries_changed\:_%0.=A_sincronização_de_arquivo_links_foi_finalizada._Referências_modificadas\:_%0.
Finished_writing_XMP-metadata._Wrote_to_%0_file(s).=A_escrita_de_metadados_XMP_terminou._Escrita_realizada_para_%0_arquivo(s).
Finished_writing_XMP_for_%0_file_(%1_skipped,_%2_errors).=A_escrita_de_metadados_XMP_para_o_arquivo_%0_terminou_(%1_ignorado,_%2_erros).
+
First_select_the_entries_you_want_keys_to_be_generated_for.=Primeiro_selecione_as_referências_para_as_quais_você_deseja_ter_chaves_geradas.
+
Fit_table_horizontally_on_screen=Ajustar_tabela_horizontalmente_na_tela
+
Float=Manter_no_topo
Float_marked_entries=Flutuar_referências_marcadas
+
Font_family=Família_da_fonte
+
Font_preview=Previsualização_da_fonte
+
Font_size=Tamanho_da_fonte
+
Font_style=Estilo_de_fonte
+
Font_selection=Font_selection
+
for=para
+
Format_of_author_and_editor_names=Formato_dos_nomes_do_autor_e_editor
Format_string=Formato_de_string
+
Format_used=Formato_utilizado
Formatter_name=Nome_do_formatador
+
found_in_AUX_file=encontrado_em_arquivo_AUX
+
Full_name=Nome_completo
+
General=Geral
+
General_fields=Campos_gerais
+
Generate=Gerar
+
Generate_BibTeX_key=Gerar_chave_BibTeX
+
Generate_keys=Gerar_chaves
+
Generate_keys_before_saving_(for_entries_without_a_key)=Gerar_chaves_antes_de_salvar
Generate_keys_for_imported_entries=Gerar_chaves_para_referências_importadas
+
Generate_now=Gerar_agora
+
Generated_BibTeX_key_for=Chave_BibTeX_gerada_para
+
Generating_BibTeX_key_for=Gerando_chave_BibTeX_para
+Get_fulltext=
Grab=Capturar
+
Gray_out_entries_not_in_group_selection=Esmaecer_referências_fora_da_seleção_do_grupo
+
Gray_out_non-hits=Esmaecer_referências_não_encontradas
+
Groups=Grupos
+
Have_you_chosen_the_correct_package_path?=Você_escolheu_o_caminho_de_pacote_correto?
+
Help=Ajuda
+
Help_on_groups=Ajuda_sobre_grupos
+
Help_on_key_patterns=Ajuda_sobre_modelos_de_chave
Help_on_regular_expression_search=Ajuda_sobre_busca_por_expressão_regular
+
Hide_non-hits=Ocultar_referências_não_encontradas
+
Hierarchical_context=Contexo_hierárquico
+
Highlight=Destacar
Highlight_groups_matching_all_selected_entries=Destacar_grupos_que_contém_todas_as_referências_selecionadas
Highlight_groups_matching_any_selected_entry=Destacar_grupos_que_contém_qualquer_referência_selecionada
+Disable_highlight_groups_matching_entries=
+
Highlight_overlapping_groups=Destacar_grupos_sobrepostos
+
Hint\:_To_search_specific_fields_only,_enter_for_example\:<p><tt>author\=smith_and_title\=electrical</tt>=Dica\:_Para_procurar_apenas_campos_específicos,_digite_por_exemplo\:<p><tt>author\=smith_and_title\=electrical</tt>
+
HTML_table=Tabela_HTML
HTML_table_(with_Abstract_&_BibTeX)=Tabela_HTML_(_com_resumo_(abstract)_&_BibTeX)
Icon=Ícone
+
Ignore=Ignorar
+
Immediate_subgroups=Subgrupos_imediatos
+
Import=Importar
+
Import_and_keep_old_entry=Importar_e_manter_referências_antigas
+
Import_and_remove_old_entry=Importar_e_remover_referências_antigas
+
Import_entries=Importar_referências
+
Import_failed=A_importação_falhou
+
Import_file=Importar_arquivo
+
Import_group_definitions=Importar_definições_de_grupo
+
Import_name=Importar_o_nome
+
Import_preferences=Importar_preferências
+
Import_preferences_from_file=Importar_preferências_a_partir_de_um_arquivo
+
Import_strings=Importar_strings
+
Import_to_open_tab=Importar_para_abrir_aba
-Import_word_selector_definitions=Importar_definições_de_seleção_de_palavra
+
Imported_entries=Referências_importadas
+
Imported_from_database=Importado_a_partir_da_base_de_dados
-ImportFormat_class=Classe_ImportFormat
+
+Importer_class=Classe_Importer
+
Importing=Importando
+
Importing_in_unknown_format=Importando_em_formato_desconhecido
+
Include_abstracts=Incluir_resumos
Include_entries=Incluir_referências
+
Include_subgroups\:_When_selected,_view_entries_contained_in_this_group_or_its_subgroups=Incluir_subgrupos\:_Quando_selecionado,_visualizar_referências_contidas_neste_grupo_ou_em_seus_subgrupos
+
Independent_group\:_When_selected,_view_only_this_group's_entries=Grupo_independente\:_Quando_selecionado,_mostra_apenas_as_referências_deste_grupo
+
Initially_show_groups_tree_expanded=Inicialmente_mostra_árvore_de_grupos_expandida
+
Work_options=Atribuição_do_campo
-Input_error=Erro_de_atribução
+
Insert=Inserir
+
Insert_rows=Inseir_linhas
Intersection=Interseção
+
Invalid_BibTeX_key=Chave_BibTeX_inválida
+
Invalid_date_format=Formato_de_data_inválido
+
Invalid_URL=URL_inválida
+
Inverted=invertido
+
ISO_abbreviation=Abreviação_ISO
+
Online_help=
+
JabRef_preferences=Preferências_do_JabRef
+
Journal_abbreviations=Abreviações_de_periódico
+
Journal_list_preview=Previsualização_da_lista_de_periódicos
+
Journal_name=Nome_do_periódico
+
Keep=Manter
+
Keep_both=Manter_ambos
+
Key_bindings=Combinações_de_tecla
+
Key_bindings_changed=Combinações_de_teclas_modificadas
+
Key_generator_settings=Configurações_do_gerador_de_chaves
+
Key_pattern=Padrão_de_chave
+
keys_in_database=chaves_na_base_de_dados
+
Keyword=Palavra-chave
+
Label=Rótulo
+
Language=Idioma
+
Last_modified=Última_modificação
+
LaTeX_AUX_file=Arquivo_LaTeX_AUX
Leave_file_in_its_current_directory=Manter_arquivos_em_seu_diretório_atual
+
Left=Esquerdo(a)
Level=
+
Limit_to_fields=Limitar_aos_campos
+
Limit_to_selected_entries=Limitar_às_referência_selecionadas
+
Link=Linkar
Link_local_file=Link_arquivo_local
Link_to_file_%0=Link_para_o_arquivo_%0
+
Listen_for_remote_operation_on_port=Escutar_operações_remotas_na_porta
Load_and_Save_preferences_from/to_jabref.xml_on_start-up_(memory_stick_mode)=Carregar_e_salvar_preferências_a_partir_de/para_jabref.xml_ao_iniciar_(modo_cartão_de_memória)
+
Look_and_feel=Aparência
Main_file_directory=Diretório_de_arquivos_principal
+
Main_layout_file=Arquivo_de_leiaute_principal
-Manage=Gerenciar
+
Manage_custom_exports=Gerenciar_exportações_personalizadas
+
Manage_custom_imports=Gerenciar_importações_personalizadas
Manage_external_file_types=Gerenciar_tipos_de_arquivo_externos
+
Manage_journal_abbreviations=Gerenciar_abreviações_de_periódicos
+
Mark_entries=Marcar_referências
+
Mark_entry=Marcar_referências
+
Mark_new_entries_with_addition_date=Marcar_novas_referências_com_a_data_de_criação
+
Mark_new_entries_with_owner_name=Marcar_novas_referências_com_o_nome_do_usuário
+
Memory_stick_mode=Modo_cartão_de_memória
+
Menu_and_label_font_size=Tamanho_da_fonte_do_menu_e_dos_rótulo
+
Merged_external_changes=Mudanças_externas_mescladas
+
Messages=Mensagens
+
Modification_of_field=Modificação_do_campo
+
Modified_group_"%0".=Grupo_"%0"_modificado
+
Modified_groups=Grupos_modificados
+
Modified_string=String_modificada
+
Modify=Modificar
+
modify_group=Modificar_grupo
+
Move=Mover
+
Move_down=Mover_para_baixo
+
Move_entries_in_group_selection_to_the_top=Mover_referências_nos_grupos_selecionados_para_o_topo
Move_external_links_to_'file'_field=Mover_links_externos_para_o_campo_'arquivo'
+
move_group=mover_grupo
+
Move_up=Mover_para_cima
+
Moved_group_"%0".=Grupo_"%0"_movido
+
Name=Nome
Name_formatter=Formatador_de_nomes
+
Natbib_style=Estilo_Natbib
+
nested_AUX_files=arquivos_AUXiliares_aninhados
+
New=Novo
+
new=novo
+
New_BibTeX_entry=Nova_referência_BibTeX
+
New_BibTeX_subdatabase=Nova_sub-base_de_dados_BibTeX
+
New_content=Novo_conteúdo
+
New_database_created.=Nova_base_de_dados_criada
+New_%0_database=%0_novas_bases_de_dados
New_field_value=Novo_valor_de_campo
+
New_file=Novo_arquivo
New_file_link_(INSERT)=Novo_link_de_arquivo_(INSERT)
+
New_group=Novo_grupo
+
New_string=Nova_string
+
Next_entry=Próxima_referência
+
No_actual_changes_found.=Nenhuma_mudança_atual_encontrada.
+
no_base-BibTeX-file_specified=nenhum_arquivo_BibTeX_de_base_especificado
+
no_database_generated=Nenhuma_base_de_dados_gerada
+
No_entries_found._Please_make_sure_you_are_using_the_correct_import_filter.=Nenhuma_referência_encontrada._Por_favor,_certifique-se_que_você_está_utilizando_o_filtro_de_importação_correto.
+
+
No_entries_found_for_the_search_string_'%0'=Nenhuma_referência_encontrada_para_a_string_pesquisada_'%0'
+
No_entries_imported.=Nenhuma_referência_importada.
+
No_exceptions_have_occurred.=Nenhuma_exceção_ocorreu.
No_files_found.=Nenhum_arquivo_encontrado.
+
No_GUI._Only_process_command_line_options.=Nenhuma_interface_gráfica._Apenas_processar_opções_de_comandos_de_linha.
+
No_journal_names_could_be_abbreviated.=Nenhum_nome_de_periódico_pôde_ser_abreviado.
+
No_journal_names_could_be_unabbreviated.=Nenhum_nome_de_periódico_pôde_ser_desabreviado.
No_PDF_linked=Nenhum_PDF_linkado
-No_references_found=Nenhuma_referência_encontrada
+
No_URL_defined=Nenhuma_URL_definida
not=não
+
not_found=não_encontrado
+
Note_that_you_must_specify_the_fully_qualified_class_name_for_the_look_and_feel,=Note_que_você_deve_especificar_completamente_o_nome_de_classe_da_aparência,
+
Nothing_to_redo=Nada_para_refazer
+
Nothing_to_undo=Nada_para_desfazer
-Number_of_references_to_fetch?=Números_de_referências_para_recuperar?
+
occurrences=ocorrências
+
OK=Ok
One_or_more_file_links_are_of_the_type_'%0',_which_is_undefined._What_do_you_want_to_do?=Um_ou_mais_links_de_arquivos_são_do_tipo_'%0',_que_não_está_definido._O_que_você_deseja_fazer?
+
One_or_more_keys_will_be_overwritten._Continue?=Uma_ou_mais_chaves_serão_sobrescritas._Continuar?
+
Open=Abrir
+
Open_BibTeX_database=Abrir_base_de_dados_BibTeX
+
Open_database=Abrir_base_de_dados
+
Open_editor_when_a_new_entry_is_created=Abrir_o_editor_quando_uma_nova_referência_é_criada
+
Open_file=Abrir_arquivo
+
Open_last_edited_databases_at_startup=Abrir_as_últimas_base_de_dados_editadas_ao_iniciar
-Open_shared_database=
+
+Connect_to_shared_database=
+
Open_terminal_here=
+
Open_URL_or_DOI=Abrir_URL_ou_DOI
+
Opened_database=Base_de_dados_aberta
+
Opening=Abrindo
+
Opening_preferences...=Abrindo_preferências
+
Operation_canceled.=Operação_cancelada.
Operation_not_supported=Operação_não_suportada
+
Optional_fields=Campos_opcionais
+
Options=Opções
+
or=ou
+
Output=Saída
+
Output_or_export_file=Saída_ou_arquivo_de_exportação
+
Override=Substituir
+
Override_default_file_directories=Substituir_os_diretórios_de_arquivo_padrão
+
Override_default_font_settings=Substituir_configurações_de_fonte_padrão
+
Override_the_BibTeX_field_by_the_selected_text=Substituir_a_chave_BibTeX_pelo_texto_selecionado
+
+
Overwrite=Sobrescrever
Overwrite_existing_field_values=Sobrescrever_valores_de_campo_existentes
+
Overwrite_keys=Sobrescrever_chaves
+
pairs_processed=pares_processados
Password=Senha
+
Paste=Colar
+
paste_entries=colar_referências
+
paste_entry=colar_referência
Paste_from_clipboard=Colar_a_partir_da_área_de_transferência
+
Pasted=Colado
+
Path_to_%0_not_defined=Caminho_para_%0_não_definido
+
Path_to_LyX_pipe=Caminho_para_o_canal_de_transmissão_LyX
+
PDF_does_not_exist=O_PDF_não_existe
+
Personal_journal_list=Lista_pessoal_de_periódicos
+
Plain_text_import=Importação_de_texto_puro
+
Please_enter_a_name_for_the_group.=Por_favor,_digite_um_nome_para_o_grupo.
+
Please_enter_a_search_term._For_example,_to_search_all_fields_for_<b>Smith</b>,_enter\:<p><tt>smith</tt><p>To_search_the_field_<b>Author</b>_for_<b>Smith</b>_and_the_field_<b>Title</b>_for_<b>electrical</b>,_enter\:<p><tt>author\=smith_and_title\=electrical</tt>=Por_favor_digite_um_termo_de_pesquisa._Por_exemplo,_para_pesquisar_todos_os_campos_por_<b>Smith</b>,_digite_\:<p><tt>smith</tt><p>Para_pesquisar_no_campo_<b>Author</b>_por_<b>Smith</b>_e_no_campo_<b>Title</b>_por_<b>electrical</b [...]
+
Please_enter_the_field_to_search_(e.g._<b>keywords</b>)_and_the_keyword_to_search_it_for_(e.g._<b>electrical</b>).=Por_favor,_digite_o_campo_a_ser_pesquisado_(e.g._<b>palavras-chave</b>)_e_a_palavra-chave_de_pesquisa_(e.g._<b>elétrico</b>).
+
Please_enter_the_string's_label=Por_favor,_digite_o_rótulo_da_string
+
Please_select_an_importer.=Por_favor,_selecione_um_importador.
+
Please_select_exactly_one_group_to_move.=Por_favor,_selecione_exatamente_um_grupo_a_ser_movido.
+
Possible_duplicate_entries=Possíveis_referências_duplicadas
+
Possible_duplicate_of_existing_entry._Click_to_resolve.=Possível_duplicata_de_referência_existente._Clique_para_resolver.
+
Preamble=Preâmbulo
+
Preferences=Preferências
+
Preferences_recorded.=Preferências_salvas.
+
Preview=Previsualização
+Citation_Style=
+Current_Preview=
+Cannot_generate_preview_based_on_selected_citation_style.=
+Bad_character_inside_entry=
+Error_while_generating_citation_style=
+Preview_style_changed_to\:_%0=
+Next_preview_layout=
+Previous_preview_layout=
+
Previous_entry=Referência_anterior
+
Primary_sort_criterion=Critério_de_ordenação_primário
Problem_with_parsing_entry=Problema_ao_analisar_a_referência
-
Processing_%0=Processando_%0
Program_output=Saída_do_programa
Pull_changes_from_shared_database=
+
Pushed_citations_to_%0=Citações_enviadas_para_%0
+
Quit_JabRef=Sair_do_JabRef
+
Quit_synchronization=Sair_da_sincronização
+
Raw_source=Fonte_primária
+
Rearrange_tabs_alphabetically_by_title=Rearranjar_abas_alfabeticamente_por_título
+
Redo=Refazer
+
Reference_database=Base_de_dados_de_referência
-References_found=Referências_encontradas
+
+%0_references_found._Number_of_references_to_fetch?=Referências_encontradas\:_%0._Números_de_referências_para_recuperar?
+
Refine_supergroup\:_When_selected,_view_entries_contained_in_both_this_group_and_its_supergroup=Refinar_supergrupo\:_Quando_selecionado,_visualiza_referências_contidas_em_ambos_os_grupos_e_seu_supergrupo.
+
regular_expression=Expressão_regular
+
Remember_these_entry_types?=Lembrar_destes_tipos_de_referências?
+
Remote_operation=Operação_remota
+
Remote_server_port=Remover_porta_do_servidor
+
Remove=Remover
+
Remove_subgroups=Remover_todos_os_subgrupos
+
Remove_all_subgroups_of_"%0"?=Remover_todos_os_subgrupos_de_"%0"?
+
Remove_entry_from_import=Remover_referência_da_importação
+
Remove_entry_selection_from_this_group=Remover_seleção_de_referências_deste_grupo
+
Remove_entry_type=remover_tipo_de_referência
Remove_file_link_(DELETE)=Remover_link_de_arquivo_(DELETE)
+
Remove_from_group=Remover_do_grupo
+
Remove_group=Remover_grupo
+
Remove_group,_keep_subgroups=Remover_grupo,_manter_subgrupos
+
Remove_group_"%0"?=Remover_grupo_"%0"?
+
Remove_group_"%0"_and_its_subgroups?=Remover_grupo_"%0"_e_seus_subgrupos?
+
remove_group_(keep_subgroups)=remover_grupo_(manter_subgrupos)
+
remove_group_and_subgroups=remover_grupos_e_subgrupos
+
Remove_group_and_subgroups=Remover_grupos_e_subgrupos
+
Remove_link=Remover_link
+
Remove_old_entry=Remover_referência_antiga
+
Remove_selected_strings=Remover_string_selecionadas
+
Removed_group_"%0".=Grupo_"%0"_removido.
+
Removed_group_"%0"_and_its_subgroups.=Grupo_"%0"_e_seus_subgrupos_removidos.
+
Removed_string=String_removida
+
Renamed_string=String_renomeada
+
Replace_(regular_expression)=Substituir_(expressão_regular)
+
Replace_string=Substituir_string
+
Replace_with=Substituir_por
+
Replaced=Substituído
+
Required_fields=Campos_obrigatórios
+
Reset_all=Resetar_todos
+
Resolve_strings_for_all_fields_except=Resolver_strings_para_todos_os_campos_exceto
Resolve_strings_for_standard_BibTeX_fields_only=Resolver_strings_apenas_para_campos_BibTeX_padrões
+
resolved=resolvido
+
Revert_to_original_source=Reverter_para_o_original
+
Review=Revisar
+
Review_changes=Revisar_mudanças
+
Right=Direito
+
Save=Salvar
Save_all_finished.=Salvar_todos_os_concluídos.
+
Save_all_open_databases=Salvar_todas_as_preferências
+
Save_before_closing=Salvar_antes_de_fechar
+
Save_database=Salvar_base_de_dados
Save_database_as...=Salvar_base_de_dados_como...
+
Save_entries_in_their_original_order=Referências_salvas_em_sua_ordem_original
+
Save_failed=Falha_ao_salvar
+
Save_failed_during_backup_creation=Falha_ao_salvar_durante_a_criação_do_backup
-Save_failed_while_committing_changes\:_%0=Falha_ao_salvar_durante_o_armazenamento_das_mudanças\:_%0
+
Save_selected_as...=Salvar_selecionados_como...
+
Saved_database=Base_de_dados_salva
+
Saved_selected_to_'%0'.=Seleção_salva_para_'%0'.
+
Saving=Salvando...
Saving_all_databases...=Salvando_todas_as_bases_de_dados...
+
Saving_database=Salvando_base_de_dados...
+
Search=Pesquisar
+
Search_expression=Pesquisar_expressão
+
Search_for=Pesquisar_por
+
Searching_for_duplicates...=Procurando_por_duplicatas...
+
Searching_for_files=Procurando_por_arquivos...
+
Secondary_sort_criterion=Critério_de_ordenação_secundário
+
Select=Selecionar
+
+
Select_all=Selecionar_tudo
+
Select_encoding=Selecionar_codificação
+
Select_entry_type=Selecionar_tipo_de_referência
Select_external_application=Selecionar_aplicação_externa
+
Select_file_from_ZIP-archive=Selecionar_arquivo_a_partir_de_um_arquivo_ZIP
+
Select_the_tree_nodes_to_view_and_accept_or_reject_changes=Selecione_os_nós_da_árvore_para_visualizar_e_aceitar_ou_rejeitar_mudanças
Selected_entries=Referências_selecionadas
Set_field=Configurar_campo
Set_fields=Configurar_campos
+
Set_general_fields=Definir_campos_gerais
Set_main_external_file_directory=Definir_diretório_principal_de_arquivo_externo
+
Set_table_font=Definir_fonte_da_tabela
+
Settings=Configurações
+
Shortcut=Atalho
-Show/edit_BibTeX_source=Exibir/editar_fonte_BibTeX
+
+Show/edit_%0_source=Exibir/editar_fonte_%0
+
Show_'Firstname_Lastname'=Exibir_'Nome,_Sobrenome'
+
Show_'Lastname,_Firstname'=Exibir_'Sobrenome,_Nome'
+
Show_BibTeX_source_by_default=Exibir_o_fonte_BibTeX_por_padrão
+
Show_confirmation_dialog_when_deleting_entries=Exibir_diálogo_de_confirmação_ao_remover_referências
+
Show_description=Exibir_descrição
+
Show_dynamic_groups_in_<i>italics</i>=Exibir_grupos_dinâmicos_em_<i>itálico</i>
+
Show_entries_<b>not</b>_in_group_selection=Exibir_referências_que_<b>não</b>_estão_no_grupo_selecionado
+
Show_file_column=Exibir_coluna_de_arquivo
+
Show_icons_for_groups=Exibir_ícones_para_grupos
Show_last_names_only=Exibir_apenas_últimos_nomes
+
Show_names_unchanged=Exibir_nomes_não_modificados
+
Show_optional_fields=Exibir_campos_opcionais
+
Show_required_fields=Exibir_campos_obrigatórios
+
Show_URL/DOI_column=Exibir_coluna_URL/DOI
+
Simple_HTML=HTML_simples
+
Size=Tamanho
+
Skipped_-_No_PDF_linked=Omitido_-_Nenhum_PDF_linkado
Skipped_-_PDF_does_not_exist=Omitido_-_O_PDF_não_existe
+
Skipped_entry.=Referência_omitida.
+
Sort_alphabetically=Ordenar_alfabeticamente
+
sort_subgroups=ordenar_subgrupos
+
Sorted_all_subgroups_recursively.=Todos_os_grupos_foram_recursivamente_ordenados.
+
Sorted_immediate_subgroups.=Grupos_imediatos_ordenados.
+
source_edit=edição_de_fonte
Special_name_formatters=Formatadores_de_nome_espepciais
+
Special_table_columns=Colunas_de_tabela_especiais
+
Starting_import=Iniciando_importação
+
Statically_group_entries_by_manual_assignment=Agrupar_referências_manualmente
+
Status=Status
+
Stop=Parar
+
Store_journal_abbreviations=Armazenar_abreviações_de_periódicos
+
Stored_entry=Referência_armazenada
+
Strings=Strings
+
Strings_for_database=Strings_para_a_base_de_dados
+
Subdatabase_from_AUX=Sub-base_de_dados_a_partir_do_LaTeX_AUX
+
Switches_between_full_and_abbreviated_journal_name_if_the_journal_name_is_known.=Alterna_entre_nomes_de_periódicos_abreviados_e_completos_se_o_nome_do_periódico_é_conhecido.
+
Synchronize_file_links=Sincronizar_links_de_arquivos
+
Synchronizing_file_links...=Sincronizando_links_de_arquivos.
+
Table_appearance=Aparência_da_tabela
+
Table_background_color=Cor_de_fundo_da_tabela
+
Table_grid_color=Cor_do_grade_da_tabela
+
Table_text_color=Cor_do_texto_da_tabela
+
Tabname=Nome_da_aba
Target_file_cannot_be_a_directory.=O_arquivo_destino_não_pode_ser_um_diretório
+
Tertiary_sort_criterion=Critério_de_ordenação_terciário
+
Test=Teste
+
paste_text_here=Area_de_inserção_de_texto
+
The_chosen_date_format_for_new_entries_is_not_valid=O_formato_de_data_escolhido_não_é_válido
+
The_chosen_encoding_'%0'_could_not_encode_the_following_characters\:=A_codificação_'%0'_não_pode_codificar_os_seguintes_caracteres\:
+
+
the_field_<b>%0</b>=o_campo_<b>%0</b>
+
The_file<BR>'%0'<BR>has_been_modified<BR>externally\!=O_arquivo<BR>'%0'<BR>foi_modificado<BR>externamente\!
+
The_group_"%0"_already_contains_the_selection.=O_grupo_"%0"_já_contém_a_seleção.
+
The_label_of_the_string_cannot_be_a_number.=O_rótulo_da_string_não_pode_ser_um_número.
+
The_label_of_the_string_cannot_contain_spaces.=O_rótulo_da_string_não_pode_conter_espaços.
+
The_label_of_the_string_cannot_contain_the_'\#'_character.=O_rótulo_da_string_não_pode_conter_o_caracter_'\#'.
+
The_output_option_depends_on_a_valid_import_option.=A_opção_de_output_depende_de_uma_opção_de_importação_válida.
The_PDF_contains_one_or_several_BibTeX-records.=O_PDF_contém_um_ou_mais_referências_BibTeX.
Do_you_want_to_import_these_as_new_entries_into_the_current_database?=Você_quer_importar_as_novas_referências_para_a_base_de_dados_atual?
+
The_regular_expression_<b>%0</b>_is_invalid\:=A_expressão_regular_<b>%0</b>_é_inválida\:
+
The_search_is_case_insensitive.=A_busca_não_é_sensível_ao_caso.
+
The_search_is_case_sensitive.=A_busca_é_sensível_ao_caso.
+
The_string_has_been_removed_locally=Esta_string_foi_removida_localmente
+
There_are_possible_duplicates_(marked_with_an_icon)_that_haven't_been_resolved._Continue?=Existem_possíveis_duplicatadas_(marcadas_com_um_ícone)_que_não_foram_resolvidas._Continuar?
+
This_entry_has_no_BibTeX_key._Generate_key_now?=Esta_referência_não_possui_chave_BibTeX._Deseja_gerar_uma_chave?
+
This_entry_is_incomplete=Esta_referência_está_incompleta
+
This_entry_type_cannot_be_removed.=Este_tipo_de_referência_não_pode_ser_removida.
+
This_external_link_is_of_the_type_'%0',_which_is_undefined._What_do_you_want_to_do?=Este_link_externo_é_do_tipo_'%0',_o_qual_não_está_definido._O_que_você_deseja_fazer?
+
This_group_contains_entries_based_on_manual_assignment._Entries_can_be_assigned_to_this_group_by_selecting_them_then_using_either_drag_and_drop_or_the_context_menu._Entries_can_be_removed_from_this_group_by_selecting_them_then_using_the_context_menu.=Este_grupo_contém_referências_baseadas_em_associações_manuais._Referências_pode_ser_associadas_para_este_grupo_selecionando-as_e_então_usando_arrastar_e_soltar_ou_o_menu_de_contexto._Referências_podem_ser_removidas_deste_grupo_selecionando-a [...]
+
This_group_contains_entries_whose_<b>%0</b>_field_contains_the_keyword_<b>%1</b>=Este_grupo_contém_referências_cujo_campo_<b>%0</b>_contém_a_palavra-chave_<b>%1</b>
+
This_group_contains_entries_whose_<b>%0</b>_field_contains_the_regular_expression_<b>%1</b>=Este_grupo_contém_referências_cujo_campo_<b>%0</b>_contém_a_expressão_regular_<b>%1</b>
This_makes_JabRef_look_up_each_file_link_and_check_if_the_file_exists._If_not,_you_will_be_given_options<BR>to_resolve_the_problem.=Isto_faz_com_que_o_JabRed_busque_cada_link_de arquivos_e_verifique_se_o_arquivo_existe._Caso_não_exista,_serão_exibidas_opções<BR>_para_resolver_o_problema.
+
This_operation_requires_all_selected_entries_to_have_BibTeX_keys_defined.=Esta_operação_requer_que_todas_as_referências_selecionadas_tenham_chaves_BibTeX_definidas.
+
This_operation_requires_one_or_more_entries_to_be_selected.=Esta_operação_exige_que_uma_ou_mais_referências_sejam_selecionadas
+
Toggle_abbreviation=Habilitar/Desabilitar_abreviação
Toggle_entry_preview=Habilitar/Desabilitar_previsualização_da_referência
Toggle_groups_interface=Habilitar/Desabilitar_interface_de_grupos
Try_different_encoding=Tente_uma_codificação_diferente
+
Unabbreviate_journal_names_of_the_selected_entries=Reverter_abreviações_dos_nomes_de_periódicos_das_referências_selecionadas
Unabbreviated_%0_journal_names.=Revertidas_abreviações_de_%0_nomes_de_periódicos.
+
Unable_to_open_file.=Não_foi_possível_abrir_o_arquivo.
Unable_to_open_link._The_application_'%0'_associated_with_the_file_type_'%1'_could_not_be_called.=Não_foi_possível_abrir_o_link._A_aplicaçaõ_'%0'_associada_com_o_tipo_de_arquivo_'%1'_não_pôde_ser_chamada.
unable_to_write_to=não_foi_possível_escrever_para
Undefined_file_type=Tipo_de_arquivo_indefinido
+
Undo=Desfazer
+
Union=União
+
Unknown_BibTeX_entries=Referências_BibTeX_desconhecidas
+
unknown_edit=edição_desconhecida
+
Unknown_export_format=Formato_de_exportação_desconhecido
+
Unmark_all=Desmarcar_todos
+
Unmark_entries=Desmarcar_referências
+
Unmark_entry=Desmarcar_referência
-Unsupported_version_of_class_%0\:_%1=Versão_não_suportada_da_classe_%0\:_%1
+
untitled=Sem_título
+
Up=Acima
+
Update_to_current_column_widths=Atualizar_para_a_largura_de_coluna_atual
+
Updated_group_selection=Seleção_de_grupo_atualizada
Upgrade_external_PDF/PS_links_to_use_the_'%0'_field.=Atualizar_links_PDF/PS_externos_para_utilizar_o_campo_'%0'
Upgrade_file=Atualizar_arquivo
Upgrade_old_external_file_links_to_use_the_new_feature=Atualize_os_links_de_arquivos_externos_para_utilizar_o_novo_recurso
+
usage=utilização
Use_autocompletion_for_the_following_fields=Utilizar_o_autocompletar_para_os_seguintes_campos
+
Use_other_look_and_feel=Utilizar_uma_outra_aparência
Use_regular_expression_search=Utilizar_pesquisa_por_expressão_regular
+
Username=Nome_de_usuário
+
Value_cleared_externally=Valor_apagado_externamente
+
Value_set_externally=Valor_definido_externamente
+
verify_that_LyX_is_running_and_that_the_lyxpipe_is_valid=verifique_que_o_LyX_está_sendo_executado_e_que_o_lyxpipe_é_válido
+
View=Visualizar
Vim_server_name=Nome_do_servidor_Vim
+
Waiting_for_ArXiv...=Aguardando_por_ArXiv...
+
Warn_about_unresolved_duplicates_when_closing_inspection_window=Alertar_sobre_duplicatas_não_resolvidas_ao_fechar_a_janela_de_inspeção
+
Warn_before_overwriting_existing_keys=Alertar_ao_sobrescrever_chaves_existentes
+
Warning=Alerta
+
Warnings=Alertas
+
web_link=link_web
+
What_do_you_want_to_do?=O_que_você_deseja_fazer?
+
When_adding/removing_keywords,_separate_them_by=Ao_adicionar/remover_palavras-cave,_separá-las_por
Will_write_XMP-metadata_to_the_PDFs_linked_from_selected_entries.=Irá_escrever_todos_os_metadados_XMP_para_os_PDF_linkados_a_partir_das_referências_selecionadas.
+
with=com
+
Write_BibTeXEntry_as_XMP-metadata_to_PDF.=Escrever_BibTeXEntry_como_um_metadado_XMP_para_o_PDF.
+
Write_XMP=Escrever_XMP
Write_XMP-metadata=Escrever_metadados_XMP
Write_XMP-metadata_for_all_PDFs_in_current_database?=Escrever_metadados_XMP_para_todos_os_PDF's_no_banco_de_dados_atual?
Writing_XMP-metadata...=Escrevendo_metadados_XMP...
Writing_XMP-metadata_for_selected_entries...=Escrevendo_metadados_XMP_para_as_referências_selecionadas...
+
Wrote_XMP-metadata=Metadados_XMP_escritos
+
XMP-annotated_PDF=PDF_com_anotações_XMP
XMP_export_privacy_settings=Configurações_de_privacidade_para_a_exportação_XMP
XMP-metadata=Metaddos_XMP
XMP-metadata_found_in_PDF\:_%0=Metadados_XMP_encontrados_no_PDF\:_%0
You_must_restart_JabRef_for_this_to_come_into_effect.=Você_deve_reiniciar_o_JabRef_para_a_alteração_tenha_efeito.
You_have_changed_the_language_setting.=Você_configurou_a_configuração_de_idioma.
+
You_have_changed_the_look_and_feel_setting.=Você_alterou_a_configuração_de_aparência.
+
You_have_entered_an_invalid_search_'%0'.=Você_digitou_um_termo_de_busca_inválido_'%0'.
+
You_must_choose_a_filename_to_store_journal_abbreviations=Você_deve_escolher_um_nome_de_arquivo_para_armazenar_abreviações_de_periódicos
+
You_must_restart_JabRef_for_the_new_key_bindings_to_work_properly.=_O_JabRef_precisa_ser_reiniciado_para_que_as_novas_atribuições_de_chave_funcionem_corretamente.
+
Your_new_key_bindings_have_been_stored.=Suas_novas_atribuições_de_chave_foram_armazenadas.
+
The_following_fetchers_are_available\:=As_seguintes_ferramentas_de_pesquisa_estão_disponíveis\:
Could_not_find_fetcher_'%0'=Não_foi_possível_encontrar_a_ferramenta_de_pesquisa_'%0'
Running_query_'%0'_with_fetcher_'%1'.=Executando_consulta_'%0'_com_ferramenta_de_pesquisa_'%1'.
@@ -771,63 +1404,74 @@ Number_of_entries_successfully_imported=Número_de_referências_importadas_com_s
Import_canceled_by_user=Importação_cancelada_pelo_usuário
Progress\:_%0_of_%1=Progresso\:_%0_de_%1
Error_while_fetching_from_%0=Erro_ao_recuperar_do_%0
-Fetching_Medline_by_id...=Recuperando_do_Medline_por_id...
-Fetching_Medline_by_term...=Recuperando_do_Medline_por_termo...
-%0_import_canceled=Importação_a_partir_do_%0_cancelada
+
Please_enter_a_valid_number=Por_favor,_digite_um_número_válido
-Please_enter_a_comma_separated_list_of_Medline_IDs_(numbers)_or_search_terms.=Por_favor,_digite_uma_lista_separada_por_vírgulas_de_IDs_ou_termos_de_busca_Medline.
Show_search_results_in_a_window=Exibir_resultados_de_busca_em_uma_janela
+Show_global_search_results_in_a_window=
+Search_in_all_open_databases=
Move_file_to_file_directory?=Mover_arquivo_para_o_diretório_de_arquivos?
Rename_to_'%0'=Renomear_para_'%0'
You_have_changed_the_menu_and_label_font_size.=Você_alterou_o_menu_e_tamanho_de_fonte_dos_rótulos.
+
Database_is_protected._Cannot_save_until_external_changes_have_been_reviewed.=A_base_de_dados_está_protegida._Não_é_possível_salvar_antes_que_mudanças_externas_sejam_revisadas.
Protected_database=Base_de_dados_protegida
Refuse_to_save_the_database_before_external_changes_have_been_reviewed.=Recusa_em_salvar_a_base_de_dados_antes_de_mudanças_externas_serem_revisadas.
Database_protection=Proteção_da_base_de_dados
Unable_to_save_database=Não_foi_possível_salvar_a_base_de_dados
+
BibTeX_key_generator=Gerador_de_chaves_BibTeX
Unable_to_open_link.=Não_foi_possível_abrir_link.
Move_the_keyboard_focus_to_the_entry_table=Mover_o_foco_do_teclado_para_a_tabela_de_referências
MIME_type=MIME_type
+
This_feature_lets_new_files_be_opened_or_imported_into_an_already_running_instance_of_JabRef<BR>instead_of_opening_a_new_instance._For_instance,_this_is_useful_when_you_open_a_file_in_JabRef<br>from_your_web_browser.<BR>Note_that_this_will_prevent_you_from_running_more_than_one_instance_of_JabRef_at_a_time.=Esta_funcionalidade_permite_que_novos_arquivos_sejam_abertos_ou_importados_para_uma_instância_do_JabRef_já_aberta<br>_ao_invés_de_abrir_uma_nova_instância._Por_exemplo,_isto_é_útil_qu [...]
Run_fetcher,_e.g._"--fetch\=Medline\:cancer"=Executar_Pesquisar_,_e.g.,_"--fetch\=Medline\:cancer"
+
The_ACM_Digital_Library=A_Biblioteca_Digital_ACM
Reset=Redefinir
+
Use_IEEE_LaTeX_abbreviations=Utilizar_abreviações_LaTeX_IEEE
The_Guide_to_Computing_Literature=O_Guia_da_Literatura_em_Computação
+
When_opening_file_link,_search_for_matching_file_if_no_link_is_defined=Ao_abrir_o_link_do_arquivo,_procurar_por_arquivo_correspondente_se_nenhum_link_está_definido
Settings_for_%0=Configurações_para_%0
Mark_entries_imported_into_an_existing_database=Marcar_referências_importadas_para_uma_nova_base_de_dados_existente
Unmark_all_entries_before_importing_new_entries_into_an_existing_database=Desmarcar_todas_as_referências_antes_de_importar_novas_referências_para_uma_base_de_dados_existente
+
Forward=Avançar
Back=Voltar
Sort_the_following_fields_as_numeric_fields=Ordenar_os_seguintes_campos_como_campos_numéricos
Line_%0\:_Found_corrupted_BibTeX_key.=Linha_%0\:_Chave_BibTeX_corrompida_encontrada.
Line_%0\:_Found_corrupted_BibTeX_key_(contains_whitespaces).=Linha_%0\:_Chave_BibTeX_corrompida_encontrada_(contém_espaços_em_branco).
Line_%0\:_Found_corrupted_BibTeX_key_(comma_missing).=Linha_%0\:_Chave_BibTeX_corrompida_encontrada_(vírgula_faltando).
-Finished_downloading_full_text_document=O_download_do_texto_completo_foi_finalizado
Full_text_document_download_failed=O_download_do_artigo_completo_falhou
Update_to_current_column_order=Atualizar_para_ordenação_de_coluna_atual
+Download_from_URL=
Rename_field=Renomear_campo
Set/clear/rename_fields=Definir/limpar/renomear_campos
Rename_field_to=Renomear_campo_para
Move_contents_of_a_field_into_a_field_with_a_different_name=Mover_conteúdo_de_um_campo_para_um_campo_com_nome_diferente
You_can_only_rename_one_field_at_a_time=Você_pode_renomear_apenas_um_campo_por_vez
+
Remove_all_broken_links=Remover_todos_os_links_inválidos
+
Cannot_use_port_%0_for_remote_operation;_another_application_may_be_using_it._Try_specifying_another_port.=Não_é_possível_utilizar_a_porta_%0_para_operação_remota;_outra_aplicação_pode_estar_usando-a._Tente_utilizar_uma_outra_porta.
+
Looking_for_full_text_document...=Pesquisando_por_documento_completo...
Autosave=Salvar_automaticamente
-Prompt_before_recovering_a_database_from_an_autosave_file=Perguntar_antes_de_recuperar_uma_base_de_dados_a_partir_de_um_arquivo_salvo_automaticamente
-Autosave_interval_(minutes)=Intervalo_de_salvamento_automático_(minutos)
-Do_you_want_to_recover_the_database_from_the_autosave_file?=Você_deseja_recuperar_a_base_de_dados_a_partir_do_arquivo_salvo_automaticamente?
-Recover_from_autosave=Recuperar_a_partir_de_um_salvamento_automático
+A_local_copy_will_be_opened.=
+Autosave_local_databases=
+Automatically_save_the_database_to=
+Please_enter_a_valid_file_path.=
+
+
Export_in_current_table_sort_order=Exportar_na_ordenação_atual_da_tabela
Export_entries_in_their_original_order=Exportar_referências_em_sua_ordem_original
Error_opening_file_'%0'.=Erro_ao_abrir_arquivo_'%0'.
-Autosave_of_file_'%0'=Salvamento_automático_do_arquivo_'%0'
-Error_opening_autosave_of_'%0'._Trying_to_load_'%0'_instead.=Erro_ao_abrir_o_autosave_de_'%0'._Tentando_carregar_'%0'_no_lugar.
+
Formatter_not_found\:_%0=Formatador_não_encontrado\:_%0
Clear_inputarea=Limpar_área_de_entrada
+
Automatically_set_file_links_for_this_entry=Links_de_arquivos_automaticamente_definidos_para_esta_referência.
Could_not_save,_file_locked_by_another_JabRef_instance.=Não_foi_possível_salvar,_o_arquivo_está_bloqueado_por_outra_instância_JabRef.
File_is_locked_by_another_JabRef_instance.=O_arquivo_está_bloqueado_por_outra_instância_JabRef.
@@ -836,10 +1480,12 @@ File_locked=Arquivo_bloqueado
Current_tmp_value=Valor_tmp_atual
Metadata_change=Mudança_de_metadados
Changes_have_been_made_to_the_following_metadata_elements=Mudanças_foram_realizadas_nos_seguintes_elementos_de_metadados
+
Generate_groups_for_author_last_names=Gerar_grupos_a_partir_dos_últimos_nomes_dos_autores
Generate_groups_for_editor_last_names=Gerar_grupos_pelos_últimos_nomes_dos_editores
Generate_groups_from_keywords_in_a_BibTeX_field=Gerar_grupos_a_partir_de_palavras_chaves_em_um_campo_BibTeX
Enforce_legal_characters_in_BibTeX_keys=Forçar_caracteres_permitidos_em_chaves_BibTeX
+
Save_without_backup?=Salvar_sem_backup?
Unable_to_create_backup=Não_foi_possível_criar_o_backup
Move_file_to_file_directory=Mover_arquivo_para_diretório_de_arquivo
@@ -851,29 +1497,35 @@ refines_supergroup=redefine_o_supergrupo
includes_subgroups=incluir_subgrupos
contains=contém
search_expression=expressão_de_pesquisa
+
Optional_fields_2=Campos_opcionais_2
Waiting_for_save_operation_to_finish=Aguardando_a_operação_de_salvamento_ser_finalizada
Resolving_duplicate_BibTeX_keys...=Resolvendo_chaves_BibTeX_duplicadas...
Finished_resolving_duplicate_BibTeX_keys._%0_entries_modified.=Resolução_de_chaves_BibTeX_duplicadas_finalizada._%0_referências_foram_modificadas.
This_database_contains_one_or_more_duplicated_BibTeX_keys.=Esta_base_de_dados_contém_uma_ou_mais_chaves_BibTeX_duplicadas.
Do_you_want_to_resolve_duplicate_keys_now?=Deseja_resolver_chaves_duplicadas_agora?
+
Find_and_remove_duplicate_BibTeX_keys=Encontrar_e_remover_chaves_BibTeX_duplicadas
Expected_syntax_for_--fetch\='<name_of_fetcher>\:<query>'=Sintaxe_esperada_para_--fetch='<name_of_fetcher>\:<query>'
Duplicate_BibTeX_key=Duplicar_chave_BibTeX
Import_marking_color=Importar_cores_de_marcação
Always_add_letter_(a,_b,_...)_to_generated_keys=Sempre_adicionar_uma_letra_(a,_b,_...)às_chaves_geradas
+
Ensure_unique_keys_using_letters_(a,_b,_...)=Garantir_chaves_únicas_utilizando_letras_(a,_b,_...)
Ensure_unique_keys_using_letters_(b,_c,_...)=Garantir_chaves_únicas_utilizando_letras_(b,_c,_...)
Entry_editor_active_background_color=Editor_de_referências
Entry_editor_background_color=Cor_de_fundo_do_editor_de_referências
Entry_editor_font_color=Cor_da_fonte_do_editor_de_referências
Entry_editor_invalid_field_color=Cor_de_campo_inválido_do_editor_de_referências
+
Table_and_entry_editor_colors=Cores_do_editor_de_tabela_e_referências
+
General_file_directory=Diretório_geral_de_arquivos
User-specific_file_directory=Diretório_de_arquivo_específico_do_usuário
Search_failed\:_illegal_search_expression=A_pesquisa_falhou\:_expressão_de_pesquisa_ilegal
Show_ArXiv_column=Exibir_coluna_ArXiv
Highlight_groups_that_contain_entries_contained_in_any_currently_selected_group=Destacar_grupos_que_contém_referências_presentes_em_qualquer_um_dos_grupos_selecionados
+
You_must_enter_an_integer_value_in_the_interval_1025-65535_in_the_text_field_for=Você_deve_digitar_um_valor_inteiro_entre_1025_e_65535_no_campo_de_texto_para
Automatically_open_browse_dialog_when_creating_new_file_link=Abrir_janela_de_diálogo_automaticamente_ao_criar_um_novo_link_de_arquivo
Import_metadata_from\:=Importar_metadados_a_partir_de\:
@@ -882,7 +1534,6 @@ Create_entry_based_on_XMP_data=Criar_referência_baseada_em_dados_XMP
Create_blank_entry_linking_the_PDF=Criar_referência_em_branco_linkando_o_PDF
Only_attach_PDF=Anexar_apenas_PDF
Title=Título
-No_internet_connection.=Sem_conexão_com_a_internet.
Create_new_entry=Criar_nova_referência
Update_existing_entry=Atualizar_referência_existente
Autocomplete_names_in_'Firstname_Lastname'_format_only=Autocompletar_nome_em_um_formato_'Nome,_Sobrenome'_apenas
@@ -958,7 +1609,6 @@ Select_document=Selecionar_documento
Edit_group_membership=Editar_membros_do_grupo
HTML_list=Lista_HTML
Click_group_to_toggle_membership_of_selected_entries=Clique_em_um_grupo_para_habilitar/desabilitar_participação_das_referências_selecionadas
-Use_EMACS_23_insertion_string=Utilizar_string_de_inserção_EMACS_23
If_possible,_normalize_this_list_of_names_to_conform_to_standard_BibTeX_name_formatting=Se_possível,_normalize_esta_lista_de_nomes_conforme_à_formação_de_nomes_BibTeX_padrão
Could_not_open_%0=Não_foi_possível_abrir_%0
Unknown_import_format=Formato_de_importação_desconhecido
@@ -973,16 +1623,16 @@ OpenOffice/LibreOffice_connection=Conexão_OpenOffice/LibreOffice
You_can_add_additional_journal_names_by_setting_up_a_personal_journal_list,<br>as_well_as_linking_to_external_journal_lists.=Você_pode_adicionar_novos_nomes_de_periódicos_configurando_uma_lista_pessoal_de_periódicos,<br>_bem_como_linagr_esta_lista_a_listas_externas.
JabRef_includes_a_built-in_list_of_journal_abbreviations.=O_JabRef_inclui_uma_lista_de_abreviações_de_periódicos_embutida.
You_must_select_either_a_valid_style_file,_or_use_one_of_the_default_styles.=Você_deve_selecionar_um_arquivo_de_estilo_válido_ou_utilizar_um_dos_estilos_padrão.
+
This_is_a_simple_copy_and_paste_dialog._First_load_or_paste_some_text_into_the_text_input_area.<br>After_that,_you_can_mark_text_and_assign_it_to_a_BibTeX_field.=Esta_é_uma_simples_janela_de_diálogo_Copiar_e_Colar._Primeiro_carregue_ou_cole_algum_texto_na_área_de_inserção_de_texto.<br>Em_seguida,_você_pode_marcar_o_texto_e_designá-lo_a_um_campo_BibTeX.
-#This_feature_generates_a_new_database_based_on_which_entries_are_needed_in_an_existing_LaTeX_document.=Esta_funcionalidade_cria_um_novo_banco_de_dados_baseado_em_quais_entradas_são_necessárias_em_um_documento_LaTeX.
This_feature_generates_a_new_database_based_on_which_entries_are_needed_in_an_existing_LaTeX_document.=Esta_funcionalidade_gera_uma_nova_base_de_dados_na_qual_as_referências_são_necessárias_em_um_documento_LaTex_existente
-#You_need_to_select_one_of_your_open_databases_from_which_to_choose_entries,_as_well_as_the_AUX_file_produced_by_LaTeX_when_compiling_your_document.=Você_precisa_selecionar_um_de_seus_bancos_de_dados_abertos_para_que_entradas_sejam_selecionadas,_bem_como_o_arquivo_AUX_produzido_pelo_LaTeX_ao_compilar_seu_documento.
You_need_to_select_one_of_your_open_databases_from_which_to_choose_entries,_as_well_as_the_AUX_file_produced_by_LaTeX_when_compiling_your_document.=Você_precisa_selecionar_uma_das_bases_de_dados_abertas_a_partir_da_qual_serão_selecionadas_as_referências,_bem_como_um_arquivo_AUX_produzido_pela_compilação_do_seu_arquivo_LaTex.
-%0_mode=Modo_%0
+
First_select_entries_to_clean_up.=Selecione_as_entradas_a_limpar
Cleanup_entry=Limpar_referência
Autogenerate_PDF_Names=Gerar_nomes_dos_PDFs_automaticamente
Auto-generating_PDF-Names_does_not_support_undo._Continue?=Não_será_possível_desfazer_a_auto_geração_de_nomes_de_PDFs._Continuar_mesmo_assim?
+
Use_full_firstname_whenever_possible=Usar_primeiro_nome_inteiro_sempre_que_possível
Use_abbreviated_firstname_whenever_possible=Usar_primeiro_nome_abreviado_sempre_que_possível
Use_abbreviated_and_full_firstname=Usar_primeiro_nome_abreviado_e_inteiro
@@ -992,6 +1642,7 @@ Name_format_used_for_autocompletion=Formato_de_nome_usado_para_autocompletar
Treatment_of_first_names=Tratamento_dos_primeiros_nomes
Cleanup_entries=Limpar_entradas
Automatically_assign_new_entry_to_selected_groups=Designar_automaticamente_novas_referências_para_os_grupos_selecionados
+%0_mode=Modo_%0
Move_DOIs_from_note_and_URL_field_to_DOI_field_and_remove_http_prefix=Mover_DOIs_dos_campos_note_e_URL_para_o_campo_DOI_e_remover_o_prefixo_http
Make_paths_of_linked_files_relative_(if_possible)=Tornar_os_caminhos_dos_arquivos_relativos_(se_possível)
Rename_PDFs_to_given_filename_format_pattern=Renomear_PDFs_para_o_padrão_de_nome_definido
@@ -1001,13 +1652,14 @@ Doing_a_cleanup_for_%0_entries...=Limpando_%0_entradas...
No_entry_needed_a_clean_up=Nenhuma_referência_precisou_de_limpeza
One_entry_needed_a_clean_up=Uma_referência_necessitou_limpeza
%0_entries_needed_a_clean_up=%0_entradas_necessitaram_limpeza
+
Error_downloading_file_'%0'=Erro_ao_baixar_arquivo_'%0'
Download_failed=O_download_falhou
Remove_selected=Remover_Selecionados
+
Group_tree_could_not_be_parsed._If_you_save_the_BibTeX_database,_all_groups_will_be_lost.=Árvore_de_agrupamento_não_pode_ser_interpretada._Se_você_salvar_sua_base_de_dados_BibTeX,_todos_os_grupos_serão_perdidos
Attach_file=Anexar_arquivo
-
Setting_all_preferences_to_default_values.=Definindo_todas_as_preferências_para_os_valores_padrão
Resetting_preference_key_'%0'=Redefinindo_preferência_'%0'
Unknown_preference_key_'%0'=Preferência_desconhecida_'%0"
@@ -1050,7 +1702,6 @@ Five_stars=Cinco_estrelas
Four_stars=Quatro_estrelas
Help_on_special_fields=Ajuda_com_campos_especiais
Keywords_of_selected_entries=Palavras-chave_das_entradas_selecionadas
-Manage_content_selectors=Gerenciar_seletores_de_conteúdo
Manage_keywords=Gerenciar_palavras-chave
No_priority_information=Sem_informações_de_prioridade
No_rank_information=Sem_informações_de_classificação
@@ -1078,10 +1729,10 @@ Two_stars=Duas_estrelas
Update_keywords=Atualizar_palavras-chave
Write_values_of_special_fields_as_separate_fields_to_BibTeX=Escrever_valores_dos_campos_especiais_como_campos_separados_do_BibTeX
You_have_changed_settings_for_special_fields.=Você_alterou_as_configurações_de_campos_especiais
-
%0_entries_found._To_reduce_server_load,_only_%1_will_be_downloaded.=%0_entradas_encontradas._Para_reduzir_a_carga_do_servidor,_apenas_%1_serão_baixados.
A_string_with_that_label_already_exists=Uma_string_com_esse_label_já_existe
Connection_to_OpenOffice/LibreOffice_has_been_lost._Please_make_sure_OpenOffice/LibreOffice_is_running,_and_try_to_reconnect.=Conexão_com_o_OpenOffice/LibreOffice_foi_perdida._Por_favor_certifique-se_de_que_o_OpenOffice/LibreOffice_está_rodando,_e_tente_reconectar
+
Correct_the_entry,_and_reopen_editor_to_display/edit_source.=Corrija_a_referência,_e_abra_o_editor_novamente_para_mostrar/editar_o_fonte
Could_not_connect_to_a_running_gnuserv_process._Make_sure_that_Emacs_or_XEmacs_is_running,<BR>and_that_the_server_has_been_started_(by_running_the_command_'server-start'/'gnuserv-start').=Não_foi_possível_conectar_a_um_processo_gnuserv._Assegure-se_de_que_o_Emacs_ou_XEmacs_está_rodando,<BR>e_que_o_servidor_foi_iniciado_(por_meio_do_comando_'server-start1/'gnu-serv-start').
Could_not_connect_to_running_OpenOffice/LibreOffice.=Não_foi_possível_conectar_ao_OpenOffice/LibreOffice.
@@ -1103,19 +1754,14 @@ Your_style_file_specifies_the_paragraph_format_'%0',_which_is_undefined_in_your_
Searching...=Buscando...
You_have_selected_more_than_%0_entries_for_download._Some_web_sites_might_block_you_if_you_make_too_many_rapid_downloads._Do_you_want_to_continue?=Você_selecionou_mais_de_%0_entradas_para_download._Alguns_sites_podem_bloquear_seu_acesso_se_você_fizer_muitos_downloads_num_período_curto_de_tempo._Deseja_continuar_mesmo_assim?
Confirm_selection=Confirmar_seleção
-Unknown_DOI\:_'%0'.=DOI_desconhecido\:_'%0'.
Add_{}_to_specified_title_words_on_search_to_keep_the_correct_case=Adicione_{}_às_palavras_do_título_na_busca_para_manter_maiúsculas_minúsculas
Import_conversions=Importar_conversões
Please_enter_a_search_string=Favor_digitar_uma_string_de_busca
Please_open_or_start_a_new_database_before_searching=Por_favor,_abra_ou_inicie_uma_base_de_dados_antes_de_realizar_a_busca
-An_error_occurred_while_fetching_from_ADS_(%0)\:=Um_Erro_ocorreu_enquanto_pensquisando_a_partir_do_ADS_(%0)\:
-An_error_occurred_while_parsing_abstract=Um_erro_ocorreu_durante_a_interpretação_do_abstract_(resumo)
-Unknown_DiVA_entry\:_'%0'.=Referência_DiVA_desconhecida\:_'%0'
-Get_BibTeX_entry_from_DiVA=Obter_referência_BibTeX_a_partir_do_DiVA
Log=Log
-
Canceled_merging_entries=União_das_referências_cancelada
+
Format_units_by_adding_non-breaking_separators_and_keeping_the_correct_case_on_search=Formatar_unidades_adicionando_separadores_sem_quebras_e_manter_maiúsculas_e_minúsculas_na_busca
Merge_entries=Mesclar_referências
Merged_entries=Mesclou_referências_em_uma_nova_e_manteve_a_antiga
@@ -1129,29 +1775,35 @@ Use_Emacs_key_bindings=Usar_combinações_de_teclas_do_Emacs
You_have_to_choose_exactly_two_entries_to_merge.=Você_deve_escolher_exatamente_duas_referências_para_mesclar
Update_timestamp_on_modification=Atualizar_timestamp_na_modificação
-
All_key_bindings_will_be_reset_to_their_defaults.=Todas_as_teclas_de_atalho_serão_reconfiguradas_para_seus_valores_padrão.
+
Automatically_set_file_links=Definir_links_para_os_arquivos_automaticamente
Continue?=Continuar?
Resetting_all_key_bindings=Redefinindo_todas_as_teclas_de_atalho
-
Hostname=Host
Invalid_setting=Configuração_Inválida
Network=Rede
Please_specify_both_hostname_and_port=Por_favor,_especifique_o_hostname_e_a_porta
+Please_specify_both_username_and_password=
+
Use_custom_proxy_configuration=Usar_configurações_personalizadas_de_proxy
+Proxy_requires_authentication=
+Attention\:_Password_is_stored_in_plain_text\!=
Clear_connection_settings=Limpar_configurações_da_conexão
Cleared_connection_settings.=Configurações_de_conexão_foram_limpas.
+
Rebind_C-a,_too=Recombinar_C-a_também
+Rebind_C-f,_too=Recombinar_C-f_também
Show_number_of_elements_contained_in_each_group=Mostrar_número_de_elementos_em_cada_grupo
-Open_folder=Abrir_pasta
+Open_folder=Abrir_pasta
Searches_for_unlinked_PDF_files_on_the_file_system=Busca_por_arquivos_PDF_não_referenciados_no_sistema_de_arquivos
-
Export_entries_ordered_as_specified=Exportar_entradas_como_especificado
Export_sort_order=Exportar_ordenação
+Export_sorting=
Newline_separator=Separador_de_quebra_de_linha
+
Save_entries_ordered_as_specified=Salvar_entradas_como_especificado
Save_sort_order=Salvar_ordenação
Show_extra_columns=Mostrar_colunas_extra
@@ -1162,7 +1814,6 @@ Move_to_group=Mover_para_grupo
Clear_read_status=Limpar_status_de_leitura
Convert_to_BibLatex_format_(for_example,_move_the_value_of_the_'journal'_field_to_'journaltitle')=Converter_para_o_formato_Biblatex_(por_exemplo,_mude_o_valor_do_campo_'journal'_para_'journaltitle')
-Could_not_apply_changes.=Não_foi_possível_realizar_as_mudanças.
Deprecated_fields=Campo_em_desuso
Hide/show_toolbar=Mostrar/esconder_barra_de_ferramentas
No_read_status_information=Sem_informação_sobre_status_da_leitura
@@ -1174,120 +1825,109 @@ Save_selected_as_plain_BibTeX...=Salvar_selecionado_como_BibTeX_simples
Set_read_status_to_read=Definir_como_Lido
Set_read_status_to_skimmed=Definir_como_Folheado
Show_deprecated_BibTeX_fields=Mostrar_campos_BibTeX_em_desuso
+
Show_gridlines=Mostrar_linhas_de_grade
Show_printed_status=Mostrar_status_de_impressão
Show_read_status=Mostrar_status_da_leitura
Table_row_height_padding=Preenchimento_(padding)_da_altura_das_linhas_da_tabela
-Marked_all_%0_selected_entries=Marcadas_todos_os_%0_registros
Marked_selected_entry=Registro_selecionado_marcado
-Toggle_print_status=Status_de_leitura_alternado
-Unmarked_all_%0_selected_entries=Desmarcados_todos_os_%0_registros
+Marked_all_%0_selected_entries=Marcadas_todos_os_%0_registros
Unmarked_selected_entry=Registro_selecionado_desmarcado
+Unmarked_all_%0_selected_entries=Desmarcados_todos_os_%0_registros
+Toggle_print_status=Status_de_leitura_alternado
+
Unmarked_all_entries=Todos_os_registros_desmarcados
Unable_to_find_the_requested_look_and_feel_and_thus_the_default_one_is_used.=Não_foi_possivel_encontrar_o_look_and_feel_selecionado,_o_look_and_feel_padrão_sera_usado.
-Could_not_open_browser.=Não_foi_possível_abrir_o_navegador.
Opens_JabRef's_GitHub_page=Abrir_a_página_do_JabRef_no_GitHub
-
-Rebind_C-f,_too=Recombinar_C-f_também
-This_group_contains_all_entries._It_cannot_be_edited_or_removed.=Este_grupo_tem_todas_as_entradas._Ele_não_pode_ser_editado_ou_removido.
+Could_not_open_browser.=Não_foi_possível_abrir_o_navegador.
+Please_open_%0_manually.=
+The_link_has_been_copied_to_the_clipboard.=
Open_%0_file=Abrir_%0_arquivo
Cannot_delete_file=Impossível_remover_arquivo
-Convert=Converter
-Delete_local_file=Remover_arquivo_local
File_permission_error=Erro_de_permissão_de_arquivo
-Help_on_Name_Formatting=Ajuda_na_formatação_do_nome
-Normalize_to_BibTeX_name_format=Normalizar para o formato_de_nome_do_BibTeX
-Path_to_%0=Caminho_para_%0
Push_to_%0=Mover_para_%0
+Path_to_%0=Caminho_para_%0
+Convert=Converter
+Normalize_to_BibTeX_name_format=Normalizar para o formato_de_nome_do_BibTeX
+Help_on_Name_Formatting=Ajuda_na_formatação_do_nome
Add_new_file_type=Adicionar_novo_tipo_de_arquivo
-Follow_DOI_or_URL_link_and_try_to_locate_PDF_full_text_document=
+
Left_entry=
-No_information_added=
+Right_entry=
+Use=
Original_entry=
Replace_original_entry=
-Right_entry=
+No_information_added=
Select_at_least_one_entry_to_manage_keywords.=
-Use=
-Changed_type_to_'%0'_for=Tipo_modificado_para_'%0'_para
-Database_'%0'_has_changed.=Base_de_dados_'%0'_mudou.
-Copy_\\cite{BibTeX_key}=Copiar_como_\\cite{chave_BibTeX}
-Copy_BibTeX_key_and_title=Copiar_chave_BibTeX_e_título
-File_rename_failed_for_%0_entries.=
-To_set_up,_go_to=Para_configurar,_acesse_o_menu
-Search_%0=Pesquisar_na_%0
-Invalid_DOI\:_'%0'.=DOI_inválida\:_'%0'.
-Could_not_connect_to_%0=Não_foi_possível_conectar_a_%0
+OpenDocument_text=
+OpenDocument_spreadsheet=
+OpenDocument_presentation=
%0_image=
-%0_problem(s)_found=
-'%0'_is_not_a_valid_ADS_bibcode.=
-Accepting_the_change_replaces_the_complete_groups_tree_with_the_externally_modified_groups_tree.=
Added_entry=Referência_adicionada
-Added_new_'%0'_entry.=
-Deleted_entry=Referência_deletada
-Discard_changes=
-Donate_to_JabRef=
-Export_with_selected_format=Exportar_com_formato_selecionado
-Field_is_missing=
-Filled=
-From_import=
-Keep_left=
-Keep_merged_entry_only=
-Keep_right=
-Merged_BibTeX_source_code=
Modified_entry=Referência_modificada
+Deleted_entry=Referência_deletada
Modified_groups_tree=
-Multiple_entries_selected._Do_you_want_to_change_the_type_of_all_these_to_'%0'?=
-No_problems_found.=Nenhum_problema_encontrado.
-Old_entry=Referência_antiga
-OpenDocument_presentation=
-OpenDocument_spreadsheet=
-OpenDocument_text=
-Please_move_the_file_manually_and_link_in_place.=
-Print_entry_preview=
-Really_delete_the_%0_selected_entries?=
-Really_delete_the_selected_entry?=
Removed_all_groups=
-Return_to_JabRef=
-Save_changes=Salvar_mudanças.
+Accepting_the_change_replaces_the_complete_groups_tree_with_the_externally_modified_groups_tree.=
Select_export_format=
+Return_to_JabRef=
+Please_move_the_file_manually_and_link_in_place.=
+Could_not_connect_to_%0=Não_foi_possível_conectar_a_%0
Warning\:_%0_out_of_%1_entries_have_undefined_BibTeX_key.=
-large_capitals_are_not_masked_using_curly_brackets_{}=
occurrence=
-should_contain_a_four_digit_number=
-should_contain_a_valid_page_number_range=
-should_end_with_a_name=
+Added_new_'%0'_entry.=
+Multiple_entries_selected._Do_you_want_to_change_the_type_of_all_these_to_'%0'?=
+Changed_type_to_'%0'_for=Tipo_modificado_para_'%0'_para
+Really_delete_the_selected_entry?=
+Really_delete_the_%0_selected_entries?=
+Keep_merged_entry_only=
+Keep_left=
+Keep_right=
+Old_entry=Referência_antiga
+From_import=
+No_problems_found.=Nenhum_problema_encontrado.
+%0_problem(s)_found=
+Save_changes=Salvar_mudanças.
+Discard_changes=
+Database_'%0'_has_changed.=Base_de_dados_'%0'_mudou.
+Print_entry_preview=
+Copy_\\cite{BibTeX_key}=Copiar_como_\\cite{chave_BibTeX}
+Copy_BibTeX_key_and_title=Copiar_chave_BibTeX_e_título
+File_rename_failed_for_%0_entries.=
+To_set_up,_go_to=Para_configurar,_acesse_o_menu
+Merged_BibTeX_source_code=
+Invalid_DOI\:_'%0'.=DOI_inválida\:_'%0'.
should_start_with_a_name=
+should_end_with_a_name=
unexpected_closing_curly_bracket=
unexpected_opening_curly_bracket=
+capital_letters_are_not_masked_using_curly_brackets_{}=
+should_contain_a_four_digit_number=
+should_contain_a_valid_page_number_range=
+Filled=
+Field_is_missing=
+Search_%0=Pesquisar_na_%0
-Advanced_search_active.=Busca_avançada_ativa.
-Found_%0_results.=Encontrados_%0_resultados.
-No_results_found.=Nenhum_resultado_encontrado.
-Normal_search_active.=
-Search_globally=
-Search_in_all_open_databases=
Search_results_in_all_databases_for_%0=
Search_results_in_database_%0_for_%1=
-This_search_contains_entries_in_which=
+Search_globally=
+No_results_found.=Nenhum_resultado_encontrado.
+Found_%0_results.=Encontrados_%0_resultados.
+Advanced_search_active.=Busca_avançada_ativa.
+Normal_search_active.=
+plain_text=
This_search_contains_entries_in_which_any_field_contains_the_regular_expression_<b>%0</b>=
This_search_contains_entries_in_which_any_field_contains_the_term_<b>%0</b>=
-plain_text=
-
-Attention\:_Password_is_stored_in_plain_text\!=
-Please_specify_both_username_and_password=
-Proxy_requires_authentication=
+This_search_contains_entries_in_which=
-An_autosave_file_was_found_for_this_database._This_could_indicate_that_JabRef_did_not_shut_down_cleanly_last_time_the_file_was_used.=
-Note\:_A_full_text_search_is_currently_not_supported_for_%0=
Unable_to_autodetect_OpenOffice/LibreOffice_installation._Please_choose_the_installation_directory_manually.=
-
JabRef_no_longer_supports_'ps'_or_'pdf'_fields.<br>File_links_are_now_stored_in_the_'file'_field_and_files_are_stored_in_an_external_file_directory.<br>To_make_use_of_this_feature,_JabRef_needs_to_upgrade_file_links.<br><br>=
This_database_uses_outdated_file_links.=
@@ -1326,53 +1966,32 @@ Resolve_duplicate_BibTeX_keys=
Save_all=Salvar_todos
String_dialog,_add_string=
String_dialog,_remove_string=
-Switch_preview_layout=
Synchronize_files=Sincronizar_arquivos
Unabbreviate=Reverter_abreviações
-
should_contain_a_protocol=
Copy_preview=
-
Automatically_setting_file_links=
Regenerating_BibTeX_keys_according_to_metadata=
No_meta_data_present_in_BIB_file._Cannot_regenerate_BibTeX_keys=
-
Regenerate_all_keys_for_the_entries_in_a_BibTeX_file=
-
Show_debug_level_messages=
-
-Export_sorting=
-
-New_%0_database=%0_novas_bases_de_dados
-
-New_%0_database_created.=%0_novas_bases_de_dados_foram_criadas.
-
-No_entry_found_for_ISBN_%0_at_www.ebook.de=
-
-Save_actions=Salvar_ações
-Enable_save_actions=Habilitar_salvar_ações
-Always_reformat_BIB_file_on_save_and_export=
-
Default_bibliography_mode=
-
-
+New_%0_database_created.=%0_novas_bases_de_dados_foram_criadas.
Show_only_preferences_deviating_from_their_default_value=
default=padrão
key=chave
type=tipo
value=valor
-
Show_preferences=Mostrar_preferências
-
+Save_actions=Salvar_ações
+Enable_save_actions=Habilitar_salvar_ações
Other_fields=Outros_campos
Show_remaining_fields=Mostrar_campos_restantes
link_should_refer_to_a_correct_file_path=
-
abbreviation_detected=abreviação_detectada
wrong_entry_type_as_proceedings_has_page_numbers=
-
Abbreviate_journal_names=Abreviar_nomes_de_periódicos
Abbreviating...=Abreviando...
Adding_fetched_entries=Adicionando_referências_recuperadas
@@ -1384,28 +2003,22 @@ Unabbreviate_journal_names=Reverter_Abreviar_nomes_de_periódicos
Unabbreviating...=Revertendo_abreviação
Usage=Utilização
+
+Adds_{}_brackets_around_acronyms,_month_names_and_countries_to_preserve_their_case.=
Are_you_sure_you_want_to_reset_all_settings_to_default_values?=Você_tem_certeza_que_deseja_redefinir_todas_as_configurações_para_valores_padrão?
Reset_preferences=Redefinir_preferências
-
Ill-formed_entrytype_comment_in_BIB_file=
+
+Move_linked_files_to_default_file_directory_%0=
+
Clipboard=Área_de_transferência
Could_not_paste_entry_as_text\:=
Do_you_still_want_to_continue?=
This_action_will_modify_the_following_field(s)_in_at_least_one_entry_each\:=
This_could_cause_undesired_changes_to_your_entries.=
-
-Disable_highlight_groups_matching_entries=
Run_field_formatter\:=
-
-Adds_{}_brackets_around_acronyms,_month_names_and_countries_to_preserve_their_case.=
-Converts_units_to_LaTeX_formatting.=
-Does_nothing.=
-
-
Table_font_size_is_%0=
-
-Move_linked_files_to_default_file_directory_%0=
-
+%0_import_canceled=Importação_a_partir_do_%0_cancelada
Internal_style=
Add_style_file=
Are_you_sure_you_want_to_remove_the_style?=
@@ -1413,7 +2026,6 @@ Current_style_is_'%0'=
Remove_style=
Select_one_of_the_available_styles_or_add_a_style_file_from_disk.=
You_must_select_a_valid_style_file.=
-
Reload=
Capitalize=
@@ -1424,9 +2036,11 @@ Changes_all_letters_to_upper_case.=
Changes_the_first_letter_of_all_words_to_capital_case_and_the_remaining_letters_to_lower_case.=
Cleans_up_LaTeX_code.=
Converts_HTML_code_to_LaTeX_code.=
+Converts_HTML_code_to_Unicode.=
Converts_LaTeX_encoding_to_Unicode_characters.=
Converts_Unicode_characters_to_LaTeX_encoding.=
Converts_ordinals_to_LaTeX_superscripts.=
+Converts_units_to_LaTeX_formatting.=
HTML_to_LaTeX=
LaTeX_cleanup=
LaTeX_to_Unicode=
@@ -1450,16 +2064,13 @@ Title_case=
Unicode_to_LaTeX=
Units_to_LaTeX=
Upper_case=
+Does_nothing.=
Identity=
-
Clears_the_field_completely.=
Directory_not_found=
Main_file_directory_not_set\!=
-
This_operation_requires_exactly_one_item_to_be_selected.=
-
Importing_in_%0_format=
-
Female_name=
Female_names=
Male_name=
@@ -1468,7 +2079,6 @@ Mixed_names=
Neuter_name=
Neuter_names=
-
Lookup_DOI=
Audio_CD=
@@ -1507,35 +2117,27 @@ Verse=
change_entries_of_group=
odd_number_of_unescaped_'\#'=
+
Plain_text=
Show_diff=
character=
word=
-
Show_symmetric_diff=
HTML_encoded_character_found=
-
booktitle_ends_with_'conference_on'=
+
All_external_files=
OpenOffice/LibreOffice_integration=
incorrect_control_digit=
incorrect_format=
-
-Expected_"%0"_to_contain_whitespace=
-Syntax_error_in_regular-expression_pattern=
-
Copy_version_to_clipboard=
Copied_version_to_clipboard=
+
BibTeX_key=
Message=
-
-Get_fulltext=
-
-Download_from_URL=
-
Decryption_not_supported.=
Cleared_'%0'_for_%1_entries=
@@ -1554,16 +2156,11 @@ To_see_what_is_new_view_the_changelog.=
A_new_version_of_JabRef_has_been_released.=
JabRef_is_up-to-date.=
Latest_version=
-
-Please_open_%0_manually.=
-
-The_link_has_been_copied_to_the_clipboard.=
-
Online_help_forum=
-
Custom=
-Converts_HTML_code_to_Unicode.=
+Export_cited=
+Unable_to_generate_new_database=
Open_console=
Use_default_terminal_emulator=
@@ -1571,31 +2168,22 @@ Execute_command=
Note\:_Use_the_placeholder_%0_for_the_location_of_the_opened_database_file.=
Executing_command_\"%0\"...=
Error_occured_while_executing_the_command_\"%0\".=
-
Reformat_ISSN=
-Unable_to_generate_new_database=
-
-Export_cited=
Countries_and_territories_in_English=
Electrical_engineering_terms=
Enabled=
Internal_list=
+Manage_protected_terms_files=
Months_and_weekdays_in_English=
The_text_after_the_last_line_starting_with_\#_will_be_used=
-
Add_protected_terms_file=
Are_you_sure_you_want_to_remove_the_protected_terms_file?=
Remove_protected_terms_file=
-
-Manage_protected_terms_files=
-
Add_selected_text_to_list=
Add_{}_around_selected_text=
Format_field=
New_protected_terms_file=
-
-
change_field_%0_of_entry_%1_from_%2_to_%3=
change_key_from_%0_to_%1=
change_string_content_%0_to_%1=
@@ -1605,37 +2193,29 @@ insert_entry_%0=
insert_string_%0=
remove_entry_%0=
remove_string_%0=
-
undefined=
-
-
Cannot_get_info_based_on_given_%0\:_%1=
Get_BibTeX_data_from_%0=
No_%0_found=
Entry_from_%0=
-
Merge_entry_with_%0_information=
Updated_entry_with_info_from_%0=
Connection=
+Connecting...=
Host=
Port=
Database=
User=
+Connect=Conectar
Connection_error=
-Driver_error=
Connection_to_%0_server_established.=
Required_field_"%0"_is_empty.=
-
%0_driver_not_available.=
-
The_connection_to_the_server_has_been_terminated.=
-
Connection_lost.=
Reconnect=
Work_offline=
-
Working_offline.=
-
Update_refused.=
Update_refused=
Local_entry=
@@ -1646,7 +2226,12 @@ Local_version\:_%0=
Shared_version\:_%0=
Please_merge_the_shared_entry_with_yours_and_press_"Merge_entries"_to_resolve_this_problem.=
Canceling_this_operation_will_leave_your_changes_unsynchronized._Cancel_anyway?=
-The_BibEntry_you_currently_work_on_has_been_deleted_on_the_shared_side._Hit_"Keep"_to_recover_the_entry.=
+Shared_entry_is_no_longer_present=
+The_BibEntry_you_currently_work_on_has_been_deleted_on_the_shared_side.=
+You_can_restore_the_entry_using_the_"Undo"_operation.=
+Remember_password?=
+You_are_already_connected_to_a_database_using_entered_connection_details.=
+
Cannot_cite_entries_without_BibTeX_keys._Generate_keys_now?=
New_technical_report=
@@ -1656,12 +2241,8 @@ Protected_terms_file=
Style_file=
Open_OpenOffice/LibreOffice_connection=
-
You_must_enter_at_least_one_field_name=
-
-
Non-ASCII_encoded_character_found=
-
Toggle_web_search_interface=
Background_color_for_resolved_fields=
Color_code_for_resolved_fields=
@@ -1675,13 +2256,59 @@ There_were_%0_files_which_could_not_be_imported.=
Migration_help_information=
Entered_database_has_obsolete_structure_and_is_no_longer_supported.=
However,_a_new_database_was_created_alongside_the_pre-3.6_one.=
-
Click_here_to_learn_about_the_migration_of_pre-3.6_databases.=
-
-Connecting...=
Opens_JabRef's_Facebook_page=
Opens_JabRef's_blog=
Opens_JabRef's_website=
-
Opens_a_link_where_the_current_development_version_can_be_downloaded=
See_what_has_been_changed_in_the_JabRef_versions=
+Referenced_BibTeX_key_does_not_exist=
+Finished_downloading_full_text_document_for_entry_%0.=
+Full_text_document_download_failed_for_entry_%0.=
+Look_up_full_text_documents=
+You_are_about_to_look_up_full_text_documents_for_%0_entries.=
+last_four_nonpunctuation_characters_should_be_numerals=
+shared=
+should_contain_an_integer_or_a_literal=
+should_have_the_first_letter_capitalized=
+
+ID=
+ID_type=
+ID-based_entry_generator=
+Fetcher_'%0'_did_not_find_an_entry_for_id_'%1'.=
+
+Select_first_entry=
+Select_last_entry=
+
+Invalid_ISBN\:_'%0'.=
+should_be_an_integer_or_normalized=
+should_be_normalized=
+
+Empty_search_ID=
+The_given_search_ID_was_empty.=
+Copy_BibTeX_key_and_link=
+empty_BibTeX_key=
+BibLaTeX_field_only=
+
+Error_while_generating_fetch_URL=
+Error_while_parsing_ID_list=
+Unable_to_get_PubMed_IDs=
+Backup_found=
+A_backup_file_for_'%0'_was_found.=
+This_could_indicate_that_JabRef_did_not_shut_down_cleanly_last_time_the_file_was_used.=
+Do_you_want_to_recover_the_database_from_the_backup_file?=
+Firstname_Lastname=
+
+Recommended_for_%0=
+This_might_be_caused_by_reaching_the_traffic_limitation_of_Google_Scholar_(see_'Help'_for_details).=
+
+Problem_downloading_from_%1=
+
+File_directory_pattern=
+Update_with_bibliographic_information_from_the_web=
+
+Could_not_find_any_bibliographic_information.=
+BibTeX_key_%0_deviates_from_generated_key_%1=
+DOI_%0_is_invalid=
+
+Jump_to_entry=
diff --git a/src/main/resources/l10n/JabRef_ru.properties b/src/main/resources/l10n/JabRef_ru.properties
index 59c40eb..c93605b 100644
--- a/src/main/resources/l10n/JabRef_ru.properties
+++ b/src/main/resources/l10n/JabRef_ru.properties
@@ -1,27 +1,37 @@
#!
-#! created/edited by created/edited by wuw (01/08/15)
+#! created/edited by Popeye version 0.55 (github.com/JabRef/popeye)
#! encoding:UTF-8
%0_contains_the_regular_expression_<b>%1</b>=%0_содержит_регулярное_выражение_<b>%1</b>
+
%0_contains_the_term_<b>%1</b>=%0_содержит_условие_<b>%1</b>
+
%0_doesn't_contain_the_regular_expression_<b>%1</b>=%0_не_содержит_регулярного_выражения_<b>%1</b>
+
%0_doesn't_contain_the_term_<b>%1</b>=%0_не_содержит_условия_<b>%1</b>
+
%0_export_successful=%0_успешно_экспортировано
+
%0_matches_the_regular_expression_<b>%1</b>=%0_соответствует_регулярному_выражению_<b>%1</b>
%0_matches_the_term_<b>%1</b>=%0_соответствует_условию_<b>%1</b>
-<field_name>=<имя_поля>
<HTML>Could_not_find_file_'%0'<BR>linked_from_entry_'%1'</HTML>=<HTML>Не_обнаружен_файл_'%0'<BR>по_ссылке_из_записи_'%1'</HTML>
+
<select>=<выбрать>
-<select_word>=<выбрать_слово>
+
Abbreviate_journal_names_of_the_selected_entries_(ISO_abbreviation)=Сокращения_названий_журналов_для_выбранных_записей_(аббр._ISO)
Abbreviate_journal_names_of_the_selected_entries_(MEDLINE_abbreviation)=Сокращения_названий_журналов_для_выбранных_записей_(аббр._MEDLINE)
+
Abbreviate_names=Сокращения_названий
Abbreviated_%0_journal_names.=Сокращения_для_%0_названий_журналов.
+
Abbreviation=Сокращение
+
About_JabRef=О_программе_JabRef
+
Abstract=Резюме
+
Accept=Принять
Accept_change=Принять_изменение
@@ -30,13 +40,12 @@ Action=Действие
Add=Добавить
-Add_a_(compiled)_custom_ImportFormat_class_from_a_class_path.=Добавить_(скомпил.)_пользовательский_класс_ImportFormat_из_пути_класса.
+Add_a_(compiled)_custom_Importer_class_from_a_class_path.=Добавить_(скомпил.)_пользовательский_класс_Importer_из_пути_класса.
The_path_need_not_be_on_the_classpath_of_JabRef.=Путь_может_не_совпадать_с_путем_классов_JabRef.
-Add_a_(compiled)_custom_ImportFormat_class_from_a_ZIP-archive.=Добавить_(скомпил.)_пользовательский_класс_ImportFormat_из_ZIP-архива.
+Add_a_(compiled)_custom_Importer_class_from_a_ZIP-archive.=Добавить_(скомпил.)_пользовательский_класс_Importer_из_ZIP-архива.
The_ZIP-archive_need_not_be_on_the_classpath_of_JabRef.=ZIP-архив_может_не_совпадать_с_путем_классов_JabRef.
-
Add_entry_selection_to_this_group=Добавить_выбранные_записи_в_эту_группу
Add_from_folder=Добавить_из_папки
@@ -62,8 +71,6 @@ Added_string=Строка_добавлена
Additionally,_entries_whose_<b>%0</b>_field_does_not_contain_<b>%1</b>_can_be_assigned_manually_to_this_group_by_selecting_them_then_using_either_drag_and_drop_or_the_context_menu._This_process_adds_the_term_<b>%1</b>_to_each_entry's_<b>%0</b>_field._Entries_can_be_removed_manually_from_this_group_by_selecting_them_then_using_the_context_menu._This_process_removes_the_term_<b>%1</b>_from_each_entry's_<b>%0</b>_field.=Кроме_того,_записи,_в_которых_поле_<b>%0</b>_не_содержит_<b>%1</b>_могу [...]
Advanced=Расширенные
-
-
All_entries=Все_записи
All_entries_of_this_type_will_be_declared_typeless._Continue?=Все_записи_этого_типа_будут_объявлены_записями_'без_типа'._Продолжть?
@@ -71,11 +78,11 @@ All_fields=Все_поля
All_subgroups_(recursively)=Все_подгруппы_(рекурсивно)
-An_exception_occurred_while_accessing_'%0'=Исключение_при_доступе_к_'%0'
+Always_reformat_BIB_file_on_save_and_export=Всегда_преобразовывать_формат_файла_BIB_при_сохранении_и_экспорте
+
A_SAX_exception_occurred_while_parsing_'%0'\:=Исключение_SAX_при_анализе_'%0'\:
and=и
-
and_the_class_must_be_available_in_your_classpath_next_time_you_start_JabRef.=и_класс_должен_быть_доступен_в_пути_класса_при_следующем_запуске_JabRef.
any_field_that_matches_the_regular_expression_<b>%0</b>=любое_поле,_соответствующее_регулярному_выражению_<b>%0</b>
@@ -114,7 +121,6 @@ Autodetect_format=Автоопределение_формата
Autogenerate_BibTeX_keys=Автосоздание_ключей_BibTeX
-
Autolink_files_with_names_starting_with_the_BibTeX_key=Автоматическая_привязка_файлов_с_именами,_начинающимися_с_ключа_BibTeX
Autolink_only_files_that_match_the_BibTeX_key=Автоматическая_привязка_только_файлов_с_соответствием_ключу_BibTeX
@@ -147,9 +153,7 @@ Backup_old_file_when_saving=Создание_резервной_копии_ст
BibTeX_key_is_unique.=Ключ_BibTeX_является_уникальным.
-
-BibTeX_source=Источник_BibTeX
-
+%0_source=Источник_%0
Broken_link=Ссылка_с_ошибкой
@@ -189,10 +193,8 @@ Change_of_Grouping_Method=Изменить_метод_группировки
change_preamble=изменить_преамбулу
-
Change_table_column_and_General_fields_settings_to_use_the_new_feature=Измените_столбец_таблицы_и_общие_настройки_полей_для_использования_новых_свойств
-
Changed_font_settings=Измененные_настройки_шрифта
Changed_language_settings=Измененные_настройки_языка
@@ -214,18 +216,16 @@ Class_name=Имя_класса
Clear=Очистить
-
Clear_fields=Очистить_поля
-
Close=Закрыть
-Close_others=
-Close_all=
+Close_others=Закрыть_другие
+Close_all=Закрыть_все
+
Close_dialog=Закрыть_диалоговое_окно
Close_the_current_database=Закрыть_текущую_БД
-
Close_window=Закрыть_окно
Closed_database=Закрытая_БД
@@ -240,7 +240,6 @@ Column_width=Ширина_столбца
Command_line_id=Ид._командной_строки
-Connect=Подключение
Contained_in=Содержится_в
@@ -310,7 +309,7 @@ Database_encoding=Кодировка_БД
Database_properties=Свойства_БД
-Database_type=
+Database_type=Тип_БД
Date_format=Формат_БД
@@ -345,6 +344,8 @@ Delete_strings=Удалить_строки
Deleted=Удалено
+Delete_local_file=Удалить_локальный_файл
+
Delimit_fields_with_semicolon,_ex.=Разделитель_для_полей\:_точка_с_запятой,_напр.\:
Descending=В_порядке_убывания
@@ -354,8 +355,6 @@ Description=Описание
Deselect_all=Отменить_выбор_всех
Deselect_all_duplicates=Отменить_выбор_всех_дубликатов
-
-
Disable_this_confirmation_dialog=Отключить_это_диалоговое_окно_подтверждения
Display_all_entries_belonging_to_one_or_more_of_the_selected_groups.=Отображать_все_записи,_принадлежащие_более_чем_одной_из_выбранных_групп.
@@ -385,6 +384,7 @@ Do_not_write_the_following_fields_to_XMP_Metadata\:=Не_записывать_с
Do_you_want_JabRef_to_do_the_following_operations?=Приложение_JabRef_выполнит_следующие_операции._Продолжить?
+Donate_to_JabRef=Поддержать_JabRef
Down=Вниз
@@ -396,15 +396,12 @@ Downloading...=Выполняется_загрузка...
Drop_%0=Отброшено\:_%0
-
-
duplicate_removal=удаление_дубликатов
Duplicate_string_name=Дубликат_имени_строки
Duplicates_found=Найдены_дубликаты
-
Dynamic_groups=Динамические_группы
Dynamically_group_entries_by_a_free-form_search_expression=Динамическая_группировка_записей_по_произвольному_условию_поиска
@@ -435,7 +432,6 @@ Grouping_may_not_work_for_this_entry.=Возможна_ошибка_группи
empty_database=пустая_база_данных
Enable_word/name_autocompletion=Включить_автозавершение_для_слов/названий
-
Enter_URL=Ввод_URL-адреса
Enter_URL_to_download=Ввод_URL-адреса_загрузки
@@ -447,12 +443,11 @@ Entries_cannot_be_manually_assigned_to_or_removed_from_this_group.=Невозм
Entries_exported_to_clipboard=Записи_экспортированы_в_буфер_обмена
-
entry=запись
Entry_editor=Редактор_записей
-Entry_preview=Предпросмотр_записи
+Entry_preview=Предварительный_просмотр_записи
Entry_table=Таблица_записей
@@ -498,7 +493,7 @@ Export_properties=Экспорт_свойств
Export_to_clipboard=Экспорт_в_буфер_обмена
-Exporting=Экспорт
+Exporting=Выполняется_экспорт
Extension=Расширение
External_changes=Внешние_изменения
@@ -511,14 +506,12 @@ External_programs=Внешние_программы
External_viewer_called=Вызов_внешней_программы_просмотра
-
Fetch=Выборка
Field=Поле
field=поле
-
Field_name=Имя_поля
Field_names_are_not_allowed_to_contain_white_space_or_the_following_characters=Имена_полей_не_должны_содержать_пробелов_или_следующих_знаков
@@ -529,7 +522,6 @@ Field_to_group_by=Поле_для_группировки
File=Файл
file=файл
-
File_'%0'_is_already_open.=Файл_'%0'_уже_открыт.
File_'%0'_not_found=Файл_'%0'_не_найден
@@ -569,7 +561,7 @@ Float_marked_entries=Записи_с_метками_как_нефиксиров
Font_family=Гарнитура_шрифта
-Font_preview=Предпросмотр_шрифта
+Font_preview=Предварительный_просмотр_шрифта
Font_size=Кегль
@@ -607,22 +599,19 @@ Generate_now=Создать_сейчас
Generated_BibTeX_key_for=Создать_ключ_BibTeX_для
Generating_BibTeX_key_for=Создание_ключа_BibTeX_для
-
+Get_fulltext=Получить_весь_текст
Grab=Захват
Gray_out_entries_not_in_group_selection=Деактивировать_записи,_не_выделенные_в_группу
Gray_out_non-hits=Деактивировать_неподходящие
-
Groups=Группы
-
Have_you_chosen_the_correct_package_path?=Проверьте_правильность_пути_пакета.
Help=Справка
-
Help_on_groups=Справка_по_группам
Help_on_key_patterns=Справка_по_шаблонам_ключей
@@ -630,12 +619,12 @@ Help_on_regular_expression_search=Справка_по_поиску_с_помощ
Hide_non-hits=Скрыть_неподходящие
-
Hierarchical_context=Иерархический_контекст
Highlight=Выделение
Highlight_groups_matching_all_selected_entries=Выделить_группы_с_соответствием_для_всех_выбранных_записей
Highlight_groups_matching_any_selected_entry=Выделить_группы_с_соответствием_для_любой_выбранной_записи
+Disable_highlight_groups_matching_entries=Отключить_выделение_групп_с_соответствием_выделенным_записям
Highlight_overlapping_groups=Выделить_пересекающиеся_группы
@@ -673,43 +662,31 @@ Import_strings=Импорт_строк
Import_to_open_tab=Импорт_в_открытую_вкладку
-Import_word_selector_definitions=Импорт_определений_выбора_слов
-
-
Imported_entries=Импортированные_записи
Imported_from_database=Импортировано_из_БД
-ImportFormat_class=Класс_ImportFormat
+Importer_class=Класс_Importer
Importing=Импорт
Importing_in_unknown_format=Импорт_неизвестного_формата
-
Include_abstracts=Включить_конспект
Include_entries=Включить_записи
Include_subgroups\:_When_selected,_view_entries_contained_in_this_group_or_its_subgroups=Включить_подгруппы\:_Просмотр_записей,_содержащихся_в_этой_группе_или_ее_подгруппах_(если_выбрано)
-
-
-
Independent_group\:_When_selected,_view_only_this_group's_entries=Независимая_группа\:_Просмотр_записей_только_этой_группы_(если_выбрано)
Initially_show_groups_tree_expanded=Разворачивать_дерево_групп_по_умолчанию
Work_options=Рабочие_параметры
-Input_error=Ошибка_ввода
-
Insert=Вставить
Insert_rows=Вставить_строки
-
-
-
Intersection=Пересечение
Invalid_BibTeX_key=Недопустимый_ключ_BibTeX
@@ -722,13 +699,13 @@ Inverted=Обратный
ISO_abbreviation=Сокращение_(ISO)
-Online_help=
+Online_help=Онлайн-справка
JabRef_preferences=Пользовательские_настройки_JabRef
Journal_abbreviations=Сокращения_для_журналов
-Journal_list_preview=Предпросмотр_списка_журналов
+Journal_list_preview=Предварительный_просмотр_списка_журналов
Journal_name=Название_журнала
@@ -758,8 +735,7 @@ LaTeX_AUX_file=Файл_AUX_для_LaTeX
Leave_file_in_its_current_directory=Сохранить_файл_в_текущем_каталоге
Left=Левый
-Level=
-
+Level=Уровень
Limit_to_fields=Ограничение_для_полей
@@ -772,15 +748,11 @@ Link_to_file_%0=Ссылка_на_файл_%0
Listen_for_remote_operation_on_port=Прослушивать_удаленные_подключения_для_порта
Load_and_Save_preferences_from/to_jabref.xml_on_start-up_(memory_stick_mode)=Загрузка_или_сохранение_пользовательских_настроек_из/в_файл_jabref.xml_при_запуске_(режим_флеш-памяти)
-
-
Look_and_feel=Интерфейс
Main_file_directory=Основной_каталог_файлов
Main_layout_file=Главный_файл_макета
-Manage=Управление
-
Manage_custom_exports=Управление_пользовательским_экспортом
Manage_custom_imports=Управление_пользовательским_импортом
@@ -816,7 +788,6 @@ Modify=Модифицировать
modify_group=модифицировать_группу
-
Move=Переместить
Move_down=Переместить_вниз
@@ -841,7 +812,6 @@ New=Создать
new=создать
-
New_BibTeX_entry=Создать_запись_BibTeX
New_BibTeX_subdatabase=Создать_подчиненную_БД_BibTeX
@@ -849,6 +819,7 @@ New_BibTeX_subdatabase=Создать_подчиненную_БД_BibTeX
New_content=Создать_контент
New_database_created.=Создана_новая_БД.
+New_%0_database=Создать_БД_%0
New_field_value=Создать_значение_поля
New_file=Создать_файл
@@ -860,7 +831,6 @@ New_string=Создать_строку
Next_entry=Следующая_запись
-
No_actual_changes_found.=Изменений_не_найдено.
no_base-BibTeX-file_specified=не_указан_базовый_файл_BibTeX
@@ -874,7 +844,6 @@ No_entries_found_for_the_search_string_'%0'=Не_найдены_записи_д
No_entries_imported.=Записи_не_импортированы.
-
No_exceptions_have_occurred.=Исключения_отсутствуют.
No_files_found.=Файлы_не_найдены.
@@ -885,23 +854,17 @@ No_journal_names_could_be_abbreviated.=Названия_журналов_не_м
No_journal_names_could_be_unabbreviated.=Названия_журналов_не_могут_быть_развернуты.
No_PDF_linked=Без_ссылок_на_PDF
-No_references_found=Ссылки_не_найдены
-
-
No_URL_defined=URL-адрес_не_определен
not=не
not_found=не_найдено
-
-Note_that_you_must_specify_the_fully_qualified_class_name_for_the_look_and_feel,=Обратите_внимание,_что_следует_указать_полностью_квалифицированное_имя_класса_для_интерфейса
+Note_that_you_must_specify_the_fully_qualified_class_name_for_the_look_and_feel,=Обратите_внимание,_что_следует_указать_полностью_квалифицированное_имя_класса_для_интерфейса,
Nothing_to_redo=Нет_действий_для_повтора
Nothing_to_undo=Нет_действий_для_отмены
-Number_of_references_to_fetch?=Число_ссылок_для_выборки?
-
occurrences=встречаемость
OK=OK
@@ -922,9 +885,9 @@ Open_file=Открыть_файл
Open_last_edited_databases_at_startup=Открыть_БД_с_последним_временем_редактирования_при_запуске
-Open_shared_database=
+Connect_to_shared_database=
-Open_terminal_here=
+Open_terminal_here=Открыть_терминал_в_текущей_директории
Open_URL_or_DOI=Открыть_URL-адрес_или_DOI
@@ -1003,20 +966,25 @@ Preamble=Преамбула
Preferences=Пользовательские_настройки
-Preferences_recorded.=Выполнена_запись_пользовательских_настроек.
+Preferences_recorded.=Пользовательские_настройки_записаны.
-Preview=Предпросмотр
+Preview=Предварительный_просмотр
+Citation_Style=
+Current_Preview=
+Cannot_generate_preview_based_on_selected_citation_style.=
+Bad_character_inside_entry=
+Error_while_generating_citation_style=
+Preview_style_changed_to\:_%0=
+Next_preview_layout=
+Previous_preview_layout=
Previous_entry=Предыдущая_запись
Primary_sort_criterion=Первичный_критерий_сортировки
-
Problem_with_parsing_entry=Ошибка_анализа_записи
-
Processing_%0=Выполняется_обработка_%0
Program_output=Вывод_программы
-Pull_changes_from_shared_database=
-
+Pull_changes_from_shared_database=Загрузить_изменения_из_БД_с_общим_доступом
Pushed_citations_to_%0=Цитаты_переданы_в_%0
@@ -1026,18 +994,16 @@ Quit_synchronization=Завершить_синхронизацию
Raw_source=Необработанный_источник
-
Rearrange_tabs_alphabetically_by_title=Переупорядочить_вкладки_в_алфавитном_порядке_по_заголовку
Redo=Повторить
Reference_database=БД_для_ссылки
-References_found=Найдены_ссылки
+%0_references_found._Number_of_references_to_fetch?=Найдены_ссылки\:_%0._Число_ссылок_для_выборки?
Refine_supergroup\:_When_selected,_view_entries_contained_in_both_this_group_and_its_supergroup=Детализировать_супергруппу\:_Просмотр_записей,_содержащихся_в_группе_и_ее_супергруппе_(если_выбрано)
-
regular_expression=Регулярное_выражение
Remember_these_entry_types?=Запомнить_эти_типы_записей?
@@ -1048,13 +1014,10 @@ Remote_server_port=Порт_сервера_удаленного_подключе
Remove=Удалить
-
Remove_subgroups=Удалить_подгруппы
Remove_all_subgroups_of_"%0"?=Удалить_все_подгруппы_"%0"?
-
-
Remove_entry_from_import=Удалить_запись_из_импортируемых
Remove_entry_selection_from_this_group=Удалить_выбранные_записи_из_этой_группы
@@ -1062,7 +1025,6 @@ Remove_entry_selection_from_this_group=Удалить_выбранные_зап
Remove_entry_type=Удалить_тип_записи
Remove_file_link_(DELETE)=Удалить_ссылку_для_файла_(DELETE)
-
Remove_from_group=Удалить_из_группы
Remove_group=Удалить_группу
@@ -1085,7 +1047,6 @@ Remove_old_entry=Удалить_старую_запись
Remove_selected_strings=Удалить_выбранные_строки
-
Removed_group_"%0".=Группа_"%0"_удалена.
Removed_group_"%0"_and_its_subgroups.=Группа_"%0"_и_ее_подгруппы_удалены.
@@ -1111,7 +1072,6 @@ Resolve_strings_for_standard_BibTeX_fields_only=Разрешение_для_ст
resolved=разрешено
-
Revert_to_original_source=Восстановить_исходный_источник
Review=Просмотр
@@ -1136,21 +1096,17 @@ Save_failed=Ошибка_сохранения
Save_failed_during_backup_creation=Ошибка_сохранения_при_создании_резервной_копии
-Save_failed_while_committing_changes\:_%0=Ошибка_сохранения_при_подтверждении_изменений\:_%0
-
Save_selected_as...=Сохранить_выбранное_как...
Saved_database=БД_сохранена
Saved_selected_to_'%0'.=Сохранить_выбранное_в_'%0'.
-
Saving=Выполняется_сохранение
Saving_all_databases...=Выполняется_сохранение_всех_БД...
Saving_database=Выполняется_сохранение_БД
-
Search=Поиск
Search_expression=Выражение_для_поиска
@@ -1167,21 +1123,15 @@ Select=Выбрать
-
Select_all=Выбрать_все
-
Select_encoding=Выбрать_кодировку
-
Select_entry_type=Выбрать_тип_записи
Select_external_application=Выбрать_внешнее_приложение
Select_file_from_ZIP-archive=Выбрать_файл_из_ZIP-архива
-
-
-
Select_the_tree_nodes_to_view_and_accept_or_reject_changes=Выбрать_узлы_дерева_для_просмотра_и_применения/отклонения_изменений
Selected_entries=Записи_выбраны
Set_field=Настройка_поля
@@ -1194,11 +1144,9 @@ Set_table_font=Настройка_шрифта_таблицы
Settings=Параметры
-
-
Shortcut=Ярлык
-Show/edit_BibTeX_source=Показать/изменить_источник_BibTeX
+Show/edit_%0_source=Показать/изменить_источник_%0
Show_'Firstname_Lastname'=Порядок_вывода_'Имя_Фамилия'
@@ -1206,7 +1154,6 @@ Show_'Lastname,_Firstname'=Порядок_вывода_'Фамилия,_Имя'
Show_BibTeX_source_by_default=Показать_источник_BibTeX_по_умолчанию
-
Show_confirmation_dialog_when_deleting_entries=Запрос_подтверждения_при_удалении_записей
Show_description=Показать_описание
@@ -1222,17 +1169,12 @@ Show_last_names_only=Показать_только_фамилии
Show_names_unchanged=Показать_имена_без_изменений
-
-
Show_optional_fields=Показать_дополнительные_поля
-
Show_required_fields=Показать_обязательные_поля
Show_URL/DOI_column=Показать_столбец_URL/DOI
-
-
Simple_HTML=HTML_(простой)
Size=Размер
@@ -1244,8 +1186,6 @@ Skipped_entry.=Запись_пропущена.
Sort_alphabetically=Сортировка_в_алфавитном_порядке
-
-
sort_subgroups=сортировка_подгрупп
Sorted_all_subgroups_recursively.=Все_подгруппы_с_рекурсивной_сортировкой.
@@ -1257,7 +1197,6 @@ Special_name_formatters=Особые_программы_форматирован
Special_table_columns=Особые_столбцы_таблицы
-
Starting_import=Запустить_импорт
Statically_group_entries_by_manual_assignment=Фиксированная_группировка_записей_назначением_вручную
@@ -1268,7 +1207,6 @@ Stop=Остановить
Store_journal_abbreviations=Сохранить_сокращения_для_журналов
-
Stored_entry=Запись_сохранена
Strings=Строки
@@ -1277,9 +1215,12 @@ Strings_for_database=Строки_БД
Subdatabase_from_AUX=Подчиненная_БД_из_AUX
-
Switches_between_full_and_abbreviated_journal_name_if_the_journal_name_is_known.=Переключение_полного/сокращенного_имени_журнала_для_известных_имен_журналов.
+Synchronize_file_links=Синхронизировать_ссылки_на_файлы
+
+Synchronizing_file_links...=Выполняется_синхронизация_ссылок_файл...
+
Table_appearance=Представление_таблицы
Table_background_color=Цвет_фона_таблицы
@@ -1295,9 +1236,6 @@ Tertiary_sort_criterion=Третичный_критерий_сортировки
Test=Тест
-Synchronize_file_links=Синхронизировать_ссылки_на_файлы
-
-Synchronizing_file_links...=Выполняется_синхронизация_ссылок_файл...
paste_text_here=место_вставки_текста
The_chosen_date_format_for_new_entries_is_not_valid=Выбранный_формат_даты_для_новых_записей_недопустим
@@ -1305,12 +1243,12 @@ The_chosen_date_format_for_new_entries_is_not_valid=Выбранный_форм
The_chosen_encoding_'%0'_could_not_encode_the_following_characters\:=В_выбранной_кодировке_'%0'_невозможно_прочитать_следующие_символы\:
-
the_field_<b>%0</b>=поле_<b>%0</b>
The_file<BR>'%0'<BR>has_been_modified<BR>externally\!=Файл_<BR>'%0'<BR>изменен<BR>внешними_средствами\!
The_group_"%0"_already_contains_the_selection.=Группа_"%0"_уже_содержит_выбранное.
+
The_label_of_the_string_cannot_be_a_number.=Метка_строки_не_может_быть_числом.
The_label_of_the_string_cannot_contain_spaces.=Метка_строки_не_может_содержать_пробелов.
@@ -1341,22 +1279,18 @@ This_external_link_is_of_the_type_'%0',_which_is_undefined._What_do_you_want_to_
This_group_contains_entries_based_on_manual_assignment._Entries_can_be_assigned_to_this_group_by_selecting_them_then_using_either_drag_and_drop_or_the_context_menu._Entries_can_be_removed_from_this_group_by_selecting_them_then_using_the_context_menu.=Группа_содержит_записи,_на_основе_назначений_вручную._Чтобы_назначить_запись_этой_группе,_выберите_запись_и_перетащите_ее_в_группу_или_выберите_команду_контекстного_меню._Чтобы_удалить_запись_из_этой_группы,_выделите_запись_и_выберите_команд [...]
-
-
-
This_group_contains_entries_whose_<b>%0</b>_field_contains_the_keyword_<b>%1</b>=Группа_содержит_записи,_в_которых_поле_<b>%0</b>_содержит_ключевое_слово_<b>%1</b>_
This_group_contains_entries_whose_<b>%0</b>_field_contains_the_regular_expression_<b>%1</b>=Группа_содержит_записи,_в_которых_поле_<b>%0</b>_содержит_регулярное_выражение_<b>%1</b>_
+This_makes_JabRef_look_up_each_file_link_and_check_if_the_file_exists._If_not,_you_will_be_given_options<BR>to_resolve_the_problem.=При_этом_JabRef_произведет_поиск_всех_ссылок_файл_с_проверкой_наличия_файла._В_противном_случае_будет_выведен_запрос<BR>на_разрешение_проблемы.
This_operation_requires_all_selected_entries_to_have_BibTeX_keys_defined.=Для_этой_операции_необходимо_определение_ключей_BibTeX_всех_выбранных_записей.
This_operation_requires_one_or_more_entries_to_be_selected.=Для_этой_операции_необходимо_выбрать_одну_или_несколько_записей.
-
Toggle_abbreviation=Показать/скрыть_сокращения
Toggle_entry_preview=Показать/скрыть_просмотр_записи
Toggle_groups_interface=Показать/скрыть_интерфейс_групп
-
Try_different_encoding=Используйте_другую_кодировку
Unabbreviate_journal_names_of_the_selected_entries=Развернуть_названия_журналов_для_выбранных_записей
@@ -1369,14 +1303,12 @@ Undefined_file_type=Тип_файла_не_определен
Undo=Отмена
-This_makes_JabRef_look_up_each_file_link_and_check_if_the_file_exists._If_not,_you_will_be_given_options<BR>to_resolve_the_problem.=При_этом_JabRef_произведет_поиск_всех_ссылок_файл_с_проверкой_наличия_файла._В_противном_случае_будет_выведен_запрос<BR>на_разрешение_проблемы.
Union=Объединение
Unknown_BibTeX_entries=Неизвестные_записи_BibTeX
unknown_edit=неизвестное_изменение
-
Unknown_export_format=Неизвестный_формат_экспорта
Unmark_all=Снять_все_метки
@@ -1385,10 +1317,6 @@ Unmark_entries=Снять_метки_записей
Unmark_entry=Снять_метку_записи
-
-
-Unsupported_version_of_class_%0\:_%1=Неподдерживаемая_версия_класса_%0\:_%1
-
untitled=без_заглавия
Up=Вверх
@@ -1403,7 +1331,6 @@ Upgrade_old_external_file_links_to_use_the_new_feature=Обновить_стар
usage=использование
Use_autocompletion_for_the_following_fields=Автозавершение_для_следующих_полей
-
Use_other_look_and_feel=Использовать_другой_интерфейс
Use_regular_expression_search=Поиск_с_использованием_регулярных_выражений
@@ -1420,7 +1347,7 @@ Vim_server_name=Имя_сервера_Vim
Waiting_for_ArXiv...=Ожидание_ArXiv...
-Warn_about_unresolved_duplicates_when_closing_inspection_window=Выдать_предупреждение_о_неразрешенных_дубликатах_при_закрытии_контрольного_окна
+Warn_about_unresolved_duplicates_when_closing_inspection_window=Выдать_предупреждение_о_неразрешенных_дубликатах_при_закрытии_окна_контроля
Warn_before_overwriting_existing_keys=Выдать_предупреждение_при_перезаписи_текущих_ключей
@@ -1445,7 +1372,6 @@ Write_XMP-metadata_for_all_PDFs_in_current_database?=Выполнить_запи
Writing_XMP-metadata...=Выполняется_запись_метаданных_XMP...
Writing_XMP-metadata_for_selected_entries...=Выполняется_запись_метаданных_XMPдля_выбранных_записей...
-
Wrote_XMP-metadata=Метаданные_XMP_записаны
XMP-annotated_PDF=PDF_с_аннотациями_XMP
@@ -1457,17 +1383,14 @@ You_have_changed_the_language_setting.=Настройки_языка_измен
You_have_changed_the_look_and_feel_setting.=Настройки_интерфейса_изменены_пользователем.
-
You_have_entered_an_invalid_search_'%0'.=Указано_недопустимое_значение_для_поиска_'%0'.
You_must_choose_a_filename_to_store_journal_abbreviations=Необходимо_выбрать_имя_файла_для_хранения_сокращений_названий_журналов
You_must_restart_JabRef_for_the_new_key_bindings_to_work_properly.=Для_правильной_работы_новых_назначений_функциональных_клавиш_необходимо_перезапустить_JabRef.
-
Your_new_key_bindings_have_been_stored.=Новые_назначения_функциональных_клавиш_сохранены.
-
The_following_fetchers_are_available\:=Доступны_следующие_инструменты_выборки\:
Could_not_find_fetcher_'%0'=Не_удалось_найти_инструмент_выборки_'%0'
Running_query_'%0'_with_fetcher_'%1'.=Выполняется_запрос_'%0'_для_инструмента_выборки_'%1'.
@@ -1482,13 +1405,10 @@ Import_canceled_by_user=Импорт_отменен_пользователем
Progress\:_%0_of_%1=Выполнено\:_%0_из_%1
Error_while_fetching_from_%0=Ошибка_выполнения_выборки_%0
-Fetching_Medline_by_id...=Выполняется_выборка_Medline_по_ид...
-
-Fetching_Medline_by_term...=Выполняется_выборка_Medline_по_условию...
Please_enter_a_valid_number=Введите_допустимое_число
-Please_enter_a_comma_separated_list_of_Medline_IDs_(numbers)_or_search_terms.=Введите_список_ид._Medline_(числ.),_разделенных_запятыми_или_условия_поиска.
-
Show_search_results_in_a_window=Показать_результаты_в_окне
+Show_global_search_results_in_a_window=
+Search_in_all_open_databases=Поиск_во_всех_открытых_БД
Move_file_to_file_directory?=Файл_будет_перемещен_в_каталог_файлов._Продолжить?
Rename_to_'%0'=Переименовать_в_'%0'
You_have_changed_the_menu_and_label_font_size.=Кегль_меню_и_надписи_изменен_пользователем.
@@ -1515,9 +1435,6 @@ The_Guide_to_Computing_Literature=ACM_-_Каталог_публикаций_по
When_opening_file_link,_search_for_matching_file_if_no_link_is_defined=При_переходе_по_ссылке_выполнять_поиск_соответствующего_файла,_если_ссылка_не_определена
Settings_for_%0=Настройки_для_%0
-
-
-
Mark_entries_imported_into_an_existing_database=Пометить_записи,_импортированные_в_текущую_БД
Unmark_all_entries_before_importing_new_entries_into_an_existing_database=Снять_метки_всех_записей_перед_выполнением_импорта_новых_записей_в_существующую_БД
@@ -1527,10 +1444,9 @@ Sort_the_following_fields_as_numeric_fields=Сортировать_следую
Line_%0\:_Found_corrupted_BibTeX_key.=Строка_%0\:_Найден_поврежденный_ключ_BibTeX.
Line_%0\:_Found_corrupted_BibTeX_key_(contains_whitespaces).=Строка_%0\:_Найден_поврежденный_ключ_BibTeX_(содержит_пробелы)
Line_%0\:_Found_corrupted_BibTeX_key_(comma_missing).=Строка_%0\:_Найден_поврежденный_ключ_BibTeX_(пропущена_запятая)
-Finished_downloading_full_text_document=Загрузка_цитируемого_документа_завершена
Full_text_document_download_failed=Ошибка_загрузки_цитируемой_статьи
Update_to_current_column_order=Сохранить_текущий_порядок_столбцов
-
+Download_from_URL=Загрузить_из_URL-адреса
Rename_field=Переименовать_поле
Set/clear/rename_fields=Задать/очистить/переименовать_поля
Rename_field_to=Переименовать_поле_в
@@ -1543,16 +1459,15 @@ Cannot_use_port_%0_for_remote_operation;_another_application_may_be_using_it._Tr
Looking_for_full_text_document...=Поиск_цитируемого_документа...
Autosave=Автосохранение
-Prompt_before_recovering_a_database_from_an_autosave_file=Выдать_предупреждение_при_восстановлении_БД_из_файла_автосохранения
-Autosave_interval_(minutes)=Интервал_автосохранения_(в_мин.)
-Do_you_want_to_recover_the_database_from_the_autosave_file?=Будет_выполнено_восстановление_БД_из_файла_автосохранения._Продолжить?
-Recover_from_autosave=Восстановление_из_файла_автосохранения
+A_local_copy_will_be_opened.=
+Autosave_local_databases=
+Automatically_save_the_database_to=
+Please_enter_a_valid_file_path.=
+
-Export_in_current_table_sort_order=Экспорт_с_текущим_порядком_сортировки_для_таблицы
+Export_in_current_table_sort_order=Экспорт_в_текущем_порядке_сортировки_таблицы
Export_entries_in_their_original_order=Экспорт_записей_в_исходном_порядке
Error_opening_file_'%0'.=Ошибка_при_открытии_файла_'%0'.
-Autosave_of_file_'%0'=Автосохранение_файла_'%0'
-Error_opening_autosave_of_'%0'._Trying_to_load_'%0'_instead.=Ошибка_при_открытии_автоматически_сохраненной_копии_'%0'._Попробуйте_загрузить_'%0'.
Formatter_not_found\:_%0=Не_найдена_программа_форматирования\:_%0
Clear_inputarea=Очистить_область_ввода
@@ -1583,7 +1498,6 @@ includes_subgroups=включает_подгруппы
contains=содержит
search_expression=выражение_для_поиска
-
Optional_fields_2=Дополнительные_поля_2
Waiting_for_save_operation_to_finish=Ожидается_завершение_операции_сохранения
Resolving_duplicate_BibTeX_keys...=Выполняется_разрешение_дубликатов_ключей_BibTeX...
@@ -1620,7 +1534,6 @@ Create_entry_based_on_XMP_data=Создание_записи_на_основе_
Create_blank_entry_linking_the_PDF=Создание_пустой_записи_со_ссылкой_на_PDF
Only_attach_PDF=Приложить_только_PDF
Title=Заглавие
-No_internet_connection.=Интернет-подключение_отсутствует.
Create_new_entry=Создание_новой_записи
Update_existing_entry=Изменение_существующей_записи
Autocomplete_names_in_'Firstname_Lastname'_format_only=Автозавершение_имен_только_для_формата_'Имя_Фамилия'
@@ -1696,7 +1609,6 @@ Select_document=Выбрать_документ
Edit_group_membership=Изменить_принадлежность_к_группе
HTML_list=Список_HTML
Click_group_to_toggle_membership_of_selected_entries=Щелкните_группу_для_переключения_принадлежности_выбранных_записей
-Use_EMACS_23_insertion_string=Использовать_строку_вставки_EMACS_23
If_possible,_normalize_this_list_of_names_to_conform_to_standard_BibTeX_name_formatting=Если_возможно,_приведите_список_имен_в_соответствие_со_стандартным_форматированием_имен_BibTeX
Could_not_open_%0=Не_удалось_открыть_%0
Unknown_import_format=Неизвестный_формат_импорта
@@ -1720,7 +1632,7 @@ First_select_entries_to_clean_up.=Необходимо_сначала_выбра
Cleanup_entry=Очистка_записей
Autogenerate_PDF_Names=Автосоздание_имен_PDF
Auto-generating_PDF-Names_does_not_support_undo._Continue?=Операция_отмены-не_поддерживается_для_автосоздания_имен_PDF._Продолжить?
-%0_mode=Режим_%0
+
Use_full_firstname_whenever_possible=Использовать_полное_имя_(если_возможно)
Use_abbreviated_firstname_whenever_possible=Использовать_сокращенное_имя_(если_возможно)
Use_abbreviated_and_full_firstname=Использовать_сокращенное_и_полное_имя
@@ -1730,7 +1642,7 @@ Name_format_used_for_autocompletion=Формат_имени_для_автоза
Treatment_of_first_names=Способ_обработки_имен
Cleanup_entries=Очистить_записи
Automatically_assign_new_entry_to_selected_groups=Автоматически_назначать_новую_запись_выбранным_группам
-
+%0_mode=Режим_%0
Move_DOIs_from_note_and_URL_field_to_DOI_field_and_remove_http_prefix=Перемещать_DOI_из_поля_примечания_и_URL-адреса_в_поле_DOI_и_удалять_префикс_http
Make_paths_of_linked_files_relative_(if_possible)=Создавать_относительные_пути_для_связанных_файлов_(если_возможно)
Rename_PDFs_to_given_filename_format_pattern=Переименовать_PDF_в_соответствии_с_указанным_шаблоном_формата_имени
@@ -1790,7 +1702,6 @@ Five_stars=Пять_звезд
Four_stars=Четыре_звезды
Help_on_special_fields=Справка_для_полей_особых_отметок
Keywords_of_selected_entries=Ключевые_слова_для_выбранных_записей
-Manage_content_selectors=Управление_выбором_содержимого
Manage_keywords=Управление_ключевыми_словами
No_priority_information=Без_данных_о_приоритете
No_rank_information=Без_данных_о_ранге
@@ -1843,15 +1754,10 @@ Your_style_file_specifies_the_paragraph_format_'%0',_which_is_undefined_in_your_
Searching...=Выполняется_поиск...
You_have_selected_more_than_%0_entries_for_download._Some_web_sites_might_block_you_if_you_make_too_many_rapid_downloads._Do_you_want_to_continue?=Выбрано_более_%0_записей_для_загрузки._Возможна_блокировка_пользователя_некоторыми_веб-сайтами_при_большом_числе_быстрых_загрузок._Продолжить?
Confirm_selection=Подтвердить_выбор
-Unknown_DOI\:_'%0'.=Неизвестный_DOI\:_'%0'.
Add_{}_to_specified_title_words_on_search_to_keep_the_correct_case=Добавлять_{}_к_указанным_заглавным_словам_при_поиске_для_соблюдения_правильности_регистра
Import_conversions=Импорт_преобразований
Please_enter_a_search_string=Введите_строку_для_поиска
Please_open_or_start_a_new_database_before_searching=Для_начала_поиска_откройте_существующую_БД_или_создайте_новую_БД
-An_error_occurred_while_fetching_from_ADS_(%0)\:=Ошибка_выборки_из_ADS_(%0)\:
-An_error_occurred_while_parsing_abstract=Ошибка_анализа_конспекта
-Unknown_DiVA_entry\:_'%0'.=Неизвестная_запись_DiVA\:_'%0'.
-Get_BibTeX_entry_from_DiVA=Получить_запись_BibTeX_из_DiVA
Log=Отчет
Canceled_merging_entries=Слияние_записей_отменено
@@ -1878,9 +1784,11 @@ Hostname=Хост
Invalid_setting=Недопустимые_параметры
Network=Сеть
Please_specify_both_hostname_and_port=Укажите_имя_хоста_и_порт
-Port=Порт
+Please_specify_both_username_and_password=Укажите_имя_пользователя_и_пароль
-Use_custom_proxy_configuration=Использовать_пользовательские_настройки_прокси
+Use_custom_proxy_configuration=Использовать_пользовательские_настройки_прокси-сервера
+Proxy_requires_authentication=Для_прокси-сервера_требуется_авторизация
+Attention\:_Password_is_stored_in_plain_text\!=Внимание._Пароль_сохранен_в_виде_простого_текста.
Clear_connection_settings=Удалить_настройки_подключения
Cleared_connection_settings.=Настройки_подключения_удалены.
@@ -1892,7 +1800,8 @@ Show_number_of_elements_contained_in_each_group=Показать_число_эл
Open_folder=Открыть_папку
Searches_for_unlinked_PDF_files_on_the_file_system=Выполняет_поиск_несвязанных_файлов_PDF_в_файловой_системе
Export_entries_ordered_as_specified=Экспорт_записей_в_указанном_порядке
-Export_sort_order=Экспорт_порядка_сортировки
+Export_sort_order=Экспорт_в_порядке_сортировки
+Export_sorting=Сортировка_при_экспорте
Newline_separator=Разделитель_для_новой_строки
Save_entries_ordered_as_specified=Сохранить_записи_в_указанном_порядке
@@ -1905,7 +1814,6 @@ Move_to_group=Переместить_в_группу
Clear_read_status=Очистить_статус_"для_чтения"
Convert_to_BibLatex_format_(for_example,_move_the_value_of_the_'journal'_field_to_'journaltitle')=Преобразовать_в_формат_BibLatex_(например,_переместить_значение_из_поля_'journal'_в_'journaltitle')
-Could_not_apply_changes.=Не_удалось_применить_изменения.
Deprecated_fields=Устаревшие_поля
Hide/show_toolbar=Показать/скрыть_панель_инструментов
No_read_status_information=Без_сведений_статуса_"чтение"
@@ -1934,499 +1842,473 @@ Unmarked_all_entries=Отмена_отметки_всех_записей
Unable_to_find_the_requested_look_and_feel_and_thus_the_default_one_is_used.=Не_удалось_найти_запрошенное_представление._Используется_представление_по_умолчанию.
-Opens_JabRef's_GitHub_page=Открывает_страницу_JabRef_на_GitHub
+Opens_JabRef's_GitHub_page=Открыть_страницу_JabRef_на_GitHub
Could_not_open_browser.=Не_удалось_открыть_браузер.
+Please_open_%0_manually.=Откройте_%0_вручную.
+The_link_has_been_copied_to_the_clipboard.=Ссылка_скопирована_в_буфер_обмена.
-This_group_contains_all_entries._It_cannot_be_edited_or_removed.=Эта_группа_содержит_все_записи._Ее_удаление_или_изменение_невозможно.
-
-
-Open_%0_file=
+Open_%0_file=Открыть_файл_%0
-Cannot_delete_file=
-Convert=
-Delete_local_file=
-File_permission_error=
-Help_on_Name_Formatting=
-Normalize_to_BibTeX_name_format=
+Cannot_delete_file=Невозможно_удалить_файл
+File_permission_error=Ошибка_прав_доступа_для_файла
+Push_to_%0=Передать_в_%0
Path_to_%0=Путь_к_%0
-Add_new_file_type=
-Follow_DOI_or_URL_link_and_try_to_locate_PDF_full_text_document=
-Left_entry=
-No_information_added=
-Original_entry=
-Replace_original_entry=
-Right_entry=
-Select_at_least_one_entry_to_manage_keywords.=
-Use=
+Convert=Преобразовать
+Normalize_to_BibTeX_name_format=Нормализовать_в_формат_имени_BibTeX
+Help_on_Name_Formatting=Справка_по_форматированию_имен
+
+Add_new_file_type=Добавить_новый_тип_файлов
+
+Left_entry=Запись_слева
+Right_entry=Запись_справа
+Use=Использовать
+Original_entry=Исходная_запись
+Replace_original_entry=Заменить_исходную_запись
+No_information_added=Сведения_не_добавлены
+Select_at_least_one_entry_to_manage_keywords.=Выберите_минимум_одну_запись_для_управления_ключевыми_словами.
+OpenDocument_text=Текст_OpenDocument
+OpenDocument_spreadsheet=Таблица_OpenDocument
+OpenDocument_presentation=Презентация_OpenDocument
+%0_image=Изображение_%0
+Added_entry=Добавленная_запись
+Modified_entry=Модифицированная_запись
+Deleted_entry=Удаленная_запись
+Modified_groups_tree=Модифицированное_дерево_групп
+Removed_all_groups=Удаление_всех_групп
+Accepting_the_change_replaces_the_complete_groups_tree_with_the_externally_modified_groups_tree.=При_принятии_данного_изменения_все_дерево_групп_будет_заменено_на_дерево_групп_с_внешними_изменениями.
+Select_export_format=Выбрать_формат_экспорта
+Return_to_JabRef=Вернуться_в_JabRef
+Please_move_the_file_manually_and_link_in_place.=Переместите_файл_вручную_и_укажите_локальную_ссылку.
+Could_not_connect_to_%0=Не_удалось_подключиться_к_серверу_%0
+Warning\:_%0_out_of_%1_entries_have_undefined_BibTeX_key.=Предупреждение._Для_%0_из_%1_записей_не_определен_ключ_BibTeX.
+occurrence=вхождения
+Added_new_'%0'_entry.=Добавлена_новая_запись_'%0'.
+Multiple_entries_selected._Do_you_want_to_change_the_type_of_all_these_to_'%0'?=Выбрано_несколько_записей._Изменить_тип_всех_этих_записей_на_'%0'?
Changed_type_to_'%0'_for=Тип_с_изменением_на_'%0'_для
+Really_delete_the_selected_entry?=Подтвердите_удаление_выбранной_записи.
+Really_delete_the_%0_selected_entries?=Подтвердите_удаление_выбранных_%0_записей.
+Keep_merged_entry_only=Сохранить_только_объединенные_записи
+Keep_left=Сохранить_слева
+Keep_right=Сохранить_справа
+Old_entry=Старая_запись
+From_import=Из_импорта
+No_problems_found.=Ошибки_не_найдены.
+%0_problem(s)_found=Найдено_ошибок_:_%0
+Save_changes=Сохранить_изменения
+Discard_changes=Отменить_изменения
Database_'%0'_has_changed.=БД_'%0'_изменена.
+Print_entry_preview=Предварительный_просмотр_записи_для_печати
Copy_\\cite{BibTeX_key}=Копировать_\\цитировать{ключ_BibTeX}
Copy_BibTeX_key_and_title=Копировать_ключ_и_заголовок_BibTeX
File_rename_failed_for_%0_entries.=Ошибка_переименования_файла_для_%0_записи.
To_set_up,_go_to=Для_настройки_перейдите\:
-Search_%0=Поиск_%0
+Merged_BibTeX_source_code=Объединенный_исходный_код_BibTeX
Invalid_DOI\:_'%0'.=Недопустимый_DOI-адрес\:_'%0'.
-Could_not_connect_to_%0=Не_удалось_подключиться_к_серверу_%0
-Push_to_%0=Передать_в_%0
-%0_image=
-%0_problem(s)_found=
-'%0'_is_not_a_valid_ADS_bibcode.=
-Accepting_the_change_replaces_the_complete_groups_tree_with_the_externally_modified_groups_tree.=
-Added_entry=
-Added_new_'%0'_entry.=
-Deleted_entry=
-Discard_changes=
-Donate_to_JabRef=
-Export_with_selected_format=
-Field_is_missing=
-Filled=
-From_import=
-Keep_left=
-Keep_merged_entry_only=
-Keep_right=
-Merged_BibTeX_source_code=
-Modified_entry=
-Modified_groups_tree=
-Multiple_entries_selected._Do_you_want_to_change_the_type_of_all_these_to_'%0'?=
-No_problems_found.=
-Old_entry=
-OpenDocument_presentation=
-OpenDocument_spreadsheet=
-OpenDocument_text=
-Please_move_the_file_manually_and_link_in_place.=
-Print_entry_preview=
-Really_delete_the_%0_selected_entries?=
-Really_delete_the_selected_entry?=
-Removed_all_groups=
-Return_to_JabRef=
-Save_changes=
-Select_export_format=
-Warning\:_%0_out_of_%1_entries_have_undefined_BibTeX_key.=
-large_capitals_are_not_masked_using_curly_brackets_{}=
-occurrence=
-should_contain_a_four_digit_number=
-should_contain_a_valid_page_number_range=
-should_end_with_a_name=
-should_start_with_a_name=
-unexpected_closing_curly_bracket=
-unexpected_opening_curly_bracket=
-
-Advanced_search_active.=
-Found_%0_results.=
-No_results_found.=
-Normal_search_active.=
-Search_globally=
-Search_in_all_open_databases=
-Search_results_in_all_databases_for_%0=
-Search_results_in_database_%0_for_%1=
-This_search_contains_entries_in_which=
-This_search_contains_entries_in_which_any_field_contains_the_regular_expression_<b>%0</b>=
-This_search_contains_entries_in_which_any_field_contains_the_term_<b>%0</b>=
-plain_text=
-
-Attention\:_Password_is_stored_in_plain_text\!=
-Please_specify_both_username_and_password=
-Proxy_requires_authentication=
-
-An_autosave_file_was_found_for_this_database._This_could_indicate_that_JabRef_did_not_shut_down_cleanly_last_time_the_file_was_used.=
-Note\:_A_full_text_search_is_currently_not_supported_for_%0=
-Unable_to_autodetect_OpenOffice/LibreOffice_installation._Please_choose_the_installation_directory_manually.=
-
-JabRef_no_longer_supports_'ps'_or_'pdf'_fields.<br>File_links_are_now_stored_in_the_'file'_field_and_files_are_stored_in_an_external_file_directory.<br>To_make_use_of_this_feature,_JabRef_needs_to_upgrade_file_links.<br><br>=
-This_database_uses_outdated_file_links.=
-
-Clear_search=
-Close_database=
-Close_entry_editor=
-Decrease_table_font_size=
-Entry_editor,_next_entry=
-Entry_editor,_next_panel=
-Entry_editor,_next_panel_2=
-Entry_editor,_previous_entry=
-Entry_editor,_previous_panel=
-Entry_editor,_previous_panel_2=
-Entry_editor,_store_field=
-File_list_editor,_move_entry_down=
-File_list_editor,_move_entry_up=
-Focus_entry_table=
-Import_into_current_database=
-Import_into_new_database=
-Increase_table_font_size=
-New_article=
-New_book=
-New_entry=
-New_from_plain_text=
-New_inbook=
-New_mastersthesis=
-New_phdthesis=
-New_proceedings=
-New_unpublished=
-Next_tab=
-Preamble_editor,_store_changes=
-Previous_tab=
-Push_to_application=
-Refresh_OpenOffice/LibreOffice=
-Resolve_duplicate_BibTeX_keys=
-Save_all=
-String_dialog,_add_string=
-String_dialog,_remove_string=
-Switch_preview_layout=
-Synchronize_files=
-Unabbreviate=
-
-should_contain_a_protocol=
-Copy_preview=
-
-Automatically_setting_file_links=
-Regenerating_BibTeX_keys_according_to_metadata=
-No_meta_data_present_in_BIB_file._Cannot_regenerate_BibTeX_keys=
-
-Regenerate_all_keys_for_the_entries_in_a_BibTeX_file=
-
-Show_debug_level_messages=
-
-Export_sorting=
-
-New_%0_database=
-
-New_%0_database_created.=
-
-No_entry_found_for_ISBN_%0_at_www.ebook.de=
-
-
-Save_actions=
-Enable_save_actions=
-Always_reformat_BIB_file_on_save_and_export=
-Default_bibliography_mode=
-
-
-Show_only_preferences_deviating_from_their_default_value=
-default=
-key=
-type=
-value=
-
-Show_preferences=
-
-
-
-Other_fields=
-Show_remaining_fields=
-
-link_should_refer_to_a_correct_file_path=
-
-abbreviation_detected=
-wrong_entry_type_as_proceedings_has_page_numbers=
-
-Abbreviate_journal_names=
-Abbreviating...=
-Adding_fetched_entries=
-Display_keywords_appearing_in_ALL_entries=
-Display_keywords_appearing_in_ANY_entry=
-Fetching_entries_from_Inspire=
-None_of_the_selected_entries_have_BibTeX_keys.=
-Unabbreviate_journal_names=
-Unabbreviating...=
-Usage=
-
-Are_you_sure_you_want_to_reset_all_settings_to_default_values?=
-Reset_preferences=
-
-Ill-formed_entrytype_comment_in_BIB_file=
-Clipboard=
-Could_not_paste_entry_as_text\:=
-Do_you_still_want_to_continue?=
-This_action_will_modify_the_following_field(s)_in_at_least_one_entry_each\:=
-This_could_cause_undesired_changes_to_your_entries.=
-
-Disable_highlight_groups_matching_entries=
-Run_field_formatter\:=
-
-Adds_{}_brackets_around_acronyms,_month_names_and_countries_to_preserve_their_case.=
-Converts_units_to_LaTeX_formatting.=
-Does_nothing.=
-
-
-Table_font_size_is_%0=
-
-Move_linked_files_to_default_file_directory_%0=
-%0_import_canceled=
-
-Internal_style=
-Add_style_file=
-Are_you_sure_you_want_to_remove_the_style?=
-Current_style_is_'%0'=
-Remove_style=
-Select_one_of_the_available_styles_or_add_a_style_file_from_disk.=
-You_must_select_a_valid_style_file.=
-
-Reload=
-
-Capitalize=
-Capitalize_all_words,_but_converts_articles,_prepositions,_and_conjunctions_to_lower_case.=
-Capitalize_the_first_word,_changes_other_words_to_lower_case.=
-Changes_all_letters_to_lower_case.=
-Changes_all_letters_to_upper_case.=
-Changes_the_first_letter_of_all_words_to_capital_case_and_the_remaining_letters_to_lower_case.=
-Cleans_up_LaTeX_code.=
-Converts_HTML_code_to_LaTeX_code.=
-Converts_LaTeX_encoding_to_Unicode_characters.=
-Converts_Unicode_characters_to_LaTeX_encoding.=
-Converts_ordinals_to_LaTeX_superscripts.=
-HTML_to_LaTeX=
-LaTeX_cleanup=
-LaTeX_to_Unicode=
-Lower_case=
-Minify_list_of_person_names=
-Normalize_date=
-Normalize_month=
-Normalize_month_to_BibTeX_standard_abbreviation.=
-Normalize_names_of_persons=
-Normalize_page_numbers=
-Normalize_pages_to_BibTeX_standard.=
-Normalizes_lists_of_persons_to_the_BibTeX_standard.=
-Normalizes_the_date_to_ISO_date_format.=
-Ordinals_to_LaTeX_superscript=
-Protect_terms=
-Remove_enclosing_braces=
-Removes_braces_encapsulating_the_complete_field_content.=
-Sentence_case=
-Shortens_lists_of_persons_if_there_are_more_than_2_persons_to_"et_al.".=
-Title_case=
-Unicode_to_LaTeX=
-Units_to_LaTeX=
-Upper_case=
-Identity=
-
-Clears_the_field_completely.=
-Directory_not_found=
-Main_file_directory_not_set\!=
-
-This_operation_requires_exactly_one_item_to_be_selected.=
-
-Importing_in_%0_format=
-
-Female_name=
-Female_names=
-Male_name=
-Male_names=
-Mixed_names=
-Neuter_name=
-Neuter_names=
-
-
-Lookup_DOI=
-
-Audio_CD=
-British_patent=
-British_patent_request=
-Candidate_thesis=
-Collaborator=
-Column=
-Compiler=
-Continuator=
-Data_CD=
-Editor=
-European_patent=
-European_patent_request=
-Founder=
-French_patent=
-French_patent_request=
-German_patent=
-German_patent_request=
-Line=
-Master's_thesis=
-Page=
-Paragraph=
-Patent=
-Patent_request=
-PhD_thesis=
-Redactor=
-Research_report=
-Reviser=
-Section=
-Software=
-Technical_report=
-U.S._patent=
-U.S._patent_request=
-Verse=
-
-
-change_entries_of_group=
-odd_number_of_unescaped_'\#'=
-Plain_text=
-Show_diff=
-character=
-word=
-
-Show_symmetric_diff=
-
-HTML_encoded_character_found=
-
-booktitle_ends_with_'conference_on'=
-All_external_files=
-
-OpenOffice/LibreOffice_integration=
-
-incorrect_control_digit=
-incorrect_format=
-
-Expected_"%0"_to_contain_whitespace=
-Syntax_error_in_regular-expression_pattern=
-
-Copy_version_to_clipboard=
-Copied_version_to_clipboard=
-BibTeX_key=
-Message=
-
-Get_fulltext=
-
-Download_from_URL=
-
-Decryption_not_supported.=
-
-Cleared_'%0'_for_%1_entries=
+should_start_with_a_name=должно_начинаться_с_имени
+should_end_with_a_name=должно_заканчиваться_именем
+unexpected_closing_curly_bracket=непредвиденная_закрывающая_фигурная_скобка
+unexpected_opening_curly_bracket=непредвиденная_открывающая_фигурная_скобка
+capital_letters_are_not_masked_using_curly_brackets_{}=Прописные_не_помечены_с_помощью_фигурных_скобок_{}
+should_contain_a_four_digit_number=должно_содержать_четырехзначное_число
+should_contain_a_valid_page_number_range=должно_содержать_допустимый_диапазон_номеров_страниц
+Filled=Заполнено
+Field_is_missing=Отсутствует_поле
+Search_%0=Поиск_%0
+
+Search_results_in_all_databases_for_%0=Результаты_поиска_во_всех_БД_для_%0
+Search_results_in_database_%0_for_%1=Результаты_поиска_в_БД_%0_для_%1
+Search_globally=Глобальный_поиск
+No_results_found.=Результаты_не_найдены.
+Found_%0_results.=Найдено_%0_результатов.
+Advanced_search_active.=Включен_расширенный_поиск.
+Normal_search_active.=Включен_нормальный_поиск.
+plain_text=обычный_текст
+This_search_contains_entries_in_which_any_field_contains_the_regular_expression_<b>%0</b>=Поиск_содержит_записи,_в_которых_любое_поле_содержит_регулярное_выражение_<b>%0</b>
+This_search_contains_entries_in_which_any_field_contains_the_term_<b>%0</b>=Поиск_содержит_записи,_в_которых_любое_поле_содержит_условие_<b>%0</b>
+This_search_contains_entries_in_which=Поиск_содержит_записи,_в_которых
+
+Unable_to_autodetect_OpenOffice/LibreOffice_installation._Please_choose_the_installation_directory_manually.=Не_удалось_выполнить_автоопределение_установки_OpenOffice/LibreOffice._Укажите_каталог_установки_вручную.
+JabRef_no_longer_supports_'ps'_or_'pdf'_fields.<br>File_links_are_now_stored_in_the_'file'_field_and_files_are_stored_in_an_external_file_directory.<br>To_make_use_of_this_feature,_JabRef_needs_to_upgrade_file_links.<br><br>=Поддержка_полей_'ps'_или_'pdf'_в_JabRef_отключена.<br>Теперь_ссылки_на_файлы_сохраняются_в_поле_'file',_а_файлы_хранятся_во_внешнем_каталоге_файлов.<br>Для_использования_этих_возможностей_необходимо_обновить_ссылки_на_файлы_в_JabRef.<br><br>
+This_database_uses_outdated_file_links.=Эта_БД_использует_устаревшие_ссылки_на_файлы.
+
+Clear_search=Очистить_поиск
+Close_database=Закрыть_БД
+Close_entry_editor=Закрыть_редактор_записей
+Decrease_table_font_size=Уменьшить_шрифт_в_таблице
+Entry_editor,_next_entry=Редактор_записей,_следующая_запись
+Entry_editor,_next_panel=Редактор_записей,_следующая_панель
+Entry_editor,_next_panel_2=Редактор_записей,_следующая_панель_2
+Entry_editor,_previous_entry=Редактор_записей,_предыдущая_запись
+Entry_editor,_previous_panel=Редактор_записей,_предыдущая_панель
+Entry_editor,_previous_panel_2=Редактор_записей,_предыдущая_панель_2
+Entry_editor,_store_field=Редактор_записей,_сохранить_поле
+File_list_editor,_move_entry_down=Редактор_списка_файлов,_переместить_запись_вниз
+File_list_editor,_move_entry_up=Редактор_списка_файлов,_переместить_запись_вверх
+Focus_entry_table=Поместить_курсор_в_таблицу_записей
+Import_into_current_database=Импорт_в_текущую_БД
+Import_into_new_database=Импорт_в_новую_БД
+Increase_table_font_size=Увеличить_шрифт_в_таблице
+New_article=Создать_статью
+New_book=Создать_книгу
+New_entry=Создать_запись
+New_from_plain_text=Создать_из_неформатированного_текста
+New_inbook=Новая_часть_книги_(inbook)
+New_mastersthesis=Новая_магистерская_дисс.
+New_phdthesis=Новая_докторская_дисс.
+New_proceedings=Новые_протоколы
+New_unpublished=Новое_неопубликованное
+Next_tab=Следующая_вкладка
+Preamble_editor,_store_changes=Редактор_преамбул,_сохранить_изменения
+Previous_tab=Предыдущая_вкладка
+Push_to_application=Передать_в_приложение
+Refresh_OpenOffice/LibreOffice=Обновить_OpenOffice/LibreOffice
+Resolve_duplicate_BibTeX_keys=Разрешение_дубликатов_ключей_BibTeX
+Save_all=Сохранить_все
+String_dialog,_add_string=Диалоговое_окно_строк,_добавить_строку
+String_dialog,_remove_string=Диалоговое_окно_строк,_удалить_строку
+Synchronize_files=Синхронизировать_файлы
+Unabbreviate=Отменить_сокращения
+should_contain_a_protocol=должно_содержать_протокол
+Copy_preview=Копировать_предварительный_просмотр
+Automatically_setting_file_links=Автоуказание_ссылок_на_файлы
+Regenerating_BibTeX_keys_according_to_metadata=Восстановление_ключей_BibTeX_на_основе_метаданных
+No_meta_data_present_in_BIB_file._Cannot_regenerate_BibTeX_keys=В_файле_BIB_отсутствуют_метаданные._Восстановление_ключей_BibTeX_невозможно.
+Regenerate_all_keys_for_the_entries_in_a_BibTeX_file=Восстановление_всех_ключей_для_записей_в_файле_BibTeX
+Show_debug_level_messages=Показать_сообщения_об_отладке
+Default_bibliography_mode=Режим_библиографии_по_умолчанию
+New_%0_database_created.=Создана_новая_БД_%0.
+Show_only_preferences_deviating_from_their_default_value=Показать_только_пользовательские_настройки,_отличающиеся_от_значений_по_умолчанию
+default=по_умолчанию
+key=ключ
+type=тип
+value=значение
+Show_preferences=Показать_пользовательские_настройки
+Save_actions=Действия_при_сохранении
+Enable_save_actions=Включить_действия_при_сохранении
+
+Other_fields=Прочие_поля
+Show_remaining_fields=Показать_оставшиеся_поля
+
+link_should_refer_to_a_correct_file_path=Ссылка_должна_указывать_на_корректный_путь_к_файлу
+abbreviation_detected=обнаружены_сокращения
+wrong_entry_type_as_proceedings_has_page_numbers=неверный_тип_записи,_так_как_протоколы_имеют_номера_страниц
+Abbreviate_journal_names=Сокращения_названий_журналов
+Abbreviating...=Создание_сокращений...
+Adding_fetched_entries=Добавление_записей_из_выборки
+Display_keywords_appearing_in_ALL_entries=Отображение_ключевых_слов,_относящихся_ко_ВСЕМ_записям
+Display_keywords_appearing_in_ANY_entry=Отображение_ключевых_слов,_относящихся_к_КАКОЙ-ЛИБО_записи
+Fetching_entries_from_Inspire=Выборка_записей_из_Inspire
+None_of_the_selected_entries_have_BibTeX_keys.=Для_выбранных_записей_отсутствуют_ключи_BibTeX.
+Unabbreviate_journal_names=Полные_названия_журналов
+Unabbreviating...=Отмена_сокращений...
+Usage=Использование
+
+
+Adds_{}_brackets_around_acronyms,_month_names_and_countries_to_preserve_their_case.=Пометка_{}_скобками_акронимов,_названий_месяцев_и_стран_для_соблюдения_регистра_их_написания.
+Are_you_sure_you_want_to_reset_all_settings_to_default_values?=Подтвердите_сброс_всех_настроек_на_значения_по_умолчанию.
+Reset_preferences=Сброс_пользовательских_настроек
+Ill-formed_entrytype_comment_in_BIB_file=Неверный_формат_комментария_для_типа_записи_в_файле_BIB
+
+Move_linked_files_to_default_file_directory_%0=Переместить_связанные_файлы_в_каталог_файлов_по_умолчанию_%0
+
+Clipboard=Буфер_обмена
+Could_not_paste_entry_as_text\:=Не_удалось_вставить_запись_как_текст:
+Do_you_still_want_to_continue?=Продолжить?
+This_action_will_modify_the_following_field(s)_in_at_least_one_entry_each\:=Это_действие_изменит_минимум_одну_запись_в_каждом_из_следующих_полей:
+This_could_cause_undesired_changes_to_your_entries.=Это_может_привести_к_нежелательным_изменениям_ваших_записей.
+Run_field_formatter\:=Запуск_средства_форматирования_полей:
+Table_font_size_is_%0=Размер_шрифта_в_таблице:_%0
+%0_import_canceled=Импорт_%0_отменен
+Internal_style=Встроенный_стиль
+Add_style_file=Добавить_файл_стиля
+Are_you_sure_you_want_to_remove_the_style?=Подтвердите_удаление_стиля.
+Current_style_is_'%0'=Текущий_стиль:_'%0'
+Remove_style=Удалить_стиль
+Select_one_of_the_available_styles_or_add_a_style_file_from_disk.=Выберите_один_из_доступных_стилей_или_добавьте_файл_стиля_с_диска.
+You_must_select_a_valid_style_file.=Необходимо_выбрать_допустимый_файл_стиля.
+Reload=Перезагрузка
+
+Capitalize=Капитализация
+Capitalize_all_words,_but_converts_articles,_prepositions,_and_conjunctions_to_lower_case.=Капитализировать_все_слова,_написание_артиклей,_предлогов_и_союзов_строчными.
+Capitalize_the_first_word,_changes_other_words_to_lower_case.=Капитализация_первого_слова,_остальные_слова_пишутся_строчными.
+Changes_all_letters_to_lower_case.=Изменение_регистра_всех_знаков_на_нижний.
+Changes_all_letters_to_upper_case.=Изменение_регистра_всех_знаков_на_верхний.
+Changes_the_first_letter_of_all_words_to_capital_case_and_the_remaining_letters_to_lower_case.=Изменение_первой_буквы_всех_слов_на_прописные,_остальные_знаки_пишутся_строчными.
+Cleans_up_LaTeX_code.=Очистка_кода_LaTeX.
+Converts_HTML_code_to_LaTeX_code.=Преобразование_кода_HTML_в_код_LaTeX.
+Converts_HTML_code_to_Unicode.=Преобразование_кода_HTML_в_Юникод.
+Converts_LaTeX_encoding_to_Unicode_characters.=Преобразование_кодировки_LaTeX_в_символы_Юникода.
+Converts_Unicode_characters_to_LaTeX_encoding.=Преобразование_символов_Юникода_в_кодировку_LaTeX.
+Converts_ordinals_to_LaTeX_superscripts.=Преобразование_порядковых_числительных_в_надстрочник_LaTeX.
+Converts_units_to_LaTeX_formatting.=Преобразование_единиц_в_формат_LaTeX.
+HTML_to_LaTeX=HTML_в_LaTeX
+LaTeX_cleanup=Очистка_LaTeX
+LaTeX_to_Unicode=LaTeX_в_Юникод
+Lower_case=Строчные
+Minify_list_of_person_names=Сокращение_списка_имен_лиц
+Normalize_date=Нормализовать_дату
+Normalize_month=Нормализовать_месяц
+Normalize_month_to_BibTeX_standard_abbreviation.=Нормализовать_месяц_по_стандартному_сокращению_BibTeX
+Normalize_names_of_persons=Нормализовать_личные_имена
+Normalize_page_numbers=Нормализовать_номера_страниц
+Normalize_pages_to_BibTeX_standard.=Нормализовать_страницы_по_стандарту_BibTeX.
+Normalizes_lists_of_persons_to_the_BibTeX_standard.=Нормализовать_список_лиц_по_стандарту_BibTeX.
+Normalizes_the_date_to_ISO_date_format.=Нормализовать_дату_по_формату_дат_ISO.
+Ordinals_to_LaTeX_superscript=Порядковые_числительные_в_надстрочник_LaTeX
+Protect_terms=Защита_терминов
+Remove_enclosing_braces=Удалить_окружающие_скобки
+Removes_braces_encapsulating_the_complete_field_content.=Удаление_скобок,_заключающих_все_содержимое_поля.
+Sentence_case=Как_в_предложении
+Shortens_lists_of_persons_if_there_are_more_than_2_persons_to_"et_al.".=Сокращение_списка_лиц,_если_существует_более_2_лиц_для_\"et_al.\".
+Title_case=Заглавные
+Unicode_to_LaTeX=Юникод_в_LaTeX
+Units_to_LaTeX=Единицы_в_LaTeX
+Upper_case=Прописные
+Does_nothing.=Не_выполнять_действий.
+Identity=Идентичность
+Clears_the_field_completely.=Полная_очистка_поля.
+Directory_not_found=Каталог_не_найден
+Main_file_directory_not_set\!=Не_указан_основной_каталог_файлов!
+This_operation_requires_exactly_one_item_to_be_selected.=Для_этой_операции_необходимо_выбрать_только_одну_запись.
+Importing_in_%0_format=Импорт_в_формате_%0
+Female_name=Имя_женского_рода
+Female_names=Имена_женского_рода
+Male_name=Имя_мужского_рода
+Male_names=Имена_мужского_рода
+Mixed_names=Смешанные_имена
+Neuter_name=Имя_среднего_рода
+Neuter_names=Имена_среднего_рода
+
+Lookup_DOI=DOI_для_поиска
+
+Audio_CD=Аудио_CD
+British_patent=Патент_(Британия)
+British_patent_request=Запрос_патента_(Британия)
+Candidate_thesis=Кандидатская_диссертация
+Collaborator=Участник
+Column=Столбец
+Compiler=Составитель
+Continuator=Продолжатель
+Data_CD=CD_с_данными
+Editor=Редактор
+European_patent=Патент_(Европа)
+European_patent_request=Запрос_патента_(Европа)
+Founder=Основатель
+French_patent=Патент_(Франция)
+French_patent_request=Запрос_патента_(Франция)
+German_patent=Патент_(Германия)
+German_patent_request=Запрос_патента_(Германия)
+Line=Строка
+Master's_thesis=Магистерская_диссертация
+Page=Страница
+Paragraph=Параграф
+Patent=Патент
+Patent_request=Запрос_патента
+PhD_thesis=Докторская_диссертация
+Redactor=Редактор-составитель
+Research_report=Отчет_о_НИР
+Reviser=Корректор
+Section=Раздел
+Software=Программное_обеспечение
+Technical_report=Технический_отчет
+U.S._patent=Патент_(США)
+U.S._patent_request=Запрос_патента_(США)
+Verse=Стихотворение
+
+change_entries_of_group=изменить_записи_в_группе
+odd_number_of_unescaped_'\#'=нечетное_число_несброшенных_'#'
+
+Plain_text=Обычный_текст
+Show_diff=Показать_разницу
+character=знак
+word=слово
+Show_symmetric_diff=Показать_симметрическую_разность
+
+HTML_encoded_character_found=Обнаружен_символ_в_кодировке_HTML
+booktitle_ends_with_'conference_on'=заголовок_книги_оканчивается_на_'conference_on'_('конференция_по')
+
+All_external_files=Все_внешние_файлы
+
+OpenOffice/LibreOffice_integration=Интеграция_с_OpenOffice/LibreOffice
+
+incorrect_control_digit=неверное_контрольное_число
+incorrect_format=неверный_формат
+Copy_version_to_clipboard=Копирование_версии_в_буфер_обмена
+Copied_version_to_clipboard=Версия,_скопированная_в_буфер_обмена
+
+BibTeX_key=Ключ_BibTeX
+Message=Сообщение
+Decryption_not_supported.=Дешифрование_не_поддерживается
+
+Cleared_'%0'_for_%1_entries=Очищено_'%0'_для_%1_записей
Set_'%0'_to_'%1'_for_%2_entries=Установить_'%0'_'%1'_для_%2_записей
Toggled_'%0'_for_%1_entries=Изменение_'%0'_для_%1_записей
-Check_for_updates=
-Download_update=
-New_version_available=
-Installed_version=
-Remind_me_later=
-Ignore_this_update=
-Could_not_connect_to_the_update_server.=
-Please_try_again_later_and/or_check_your_network_connection.=
-To_see_what_is_new_view_the_changelog.=
-A_new_version_of_JabRef_has_been_released.=
-JabRef_is_up-to-date.=
-Latest_version=
-
-Please_open_%0_manually.=
-
-The_link_has_been_copied_to_the_clipboard.=
-
-Online_help_forum=
-
-Custom=
-
-Converts_HTML_code_to_Unicode.=
-
-Open_console=
-Use_default_terminal_emulator=
-Execute_command=
-Note\:_Use_the_placeholder_%0_for_the_location_of_the_opened_database_file.=
-Executing_command_\"%0\"...=
-Error_occured_while_executing_the_command_\"%0\".=
-
-Reformat_ISSN=
-Unable_to_generate_new_database=
-
-Export_cited=
-Countries_and_territories_in_English=
-Electrical_engineering_terms=
-Enabled=
-Internal_list=
-Months_and_weekdays_in_English=
-The_text_after_the_last_line_starting_with_\#_will_be_used=
-
-Add_protected_terms_file=
-Are_you_sure_you_want_to_remove_the_protected_terms_file?=
-Remove_protected_terms_file=
-
-Manage_protected_terms_files=
-Add_selected_text_to_list=
-Add_{}_around_selected_text=
-Format_field=
-New_protected_terms_file=
-
-
-change_field_%0_of_entry_%1_from_%2_to_%3=
-change_key_from_%0_to_%1=
-change_string_content_%0_to_%1=
-change_string_name_%0_to_%1=
-change_type_of_entry_%0_from_%1_to_%2=
-insert_entry_%0=
-insert_string_%0=
-remove_entry_%0=
-remove_string_%0=
-
-undefined=
-
-Cannot_get_info_based_on_given_%0\:_%1=
-
-Get_BibTeX_data_from_%0=
-No_%0_found=
-
-Entry_from_%0=
-
-Merge_entry_with_%0_information=
-Updated_entry_with_info_from_%0=
-Connection=
-Host=
-Database=
-User=
-Connection_error=
-Driver_error=
-Connection_to_%0_server_established.=
-Required_field_"%0"_is_empty.=
-
-%0_driver_not_available.=
-
-The_connection_to_the_server_has_been_terminated.=
-
-Connection_lost.=
-Reconnect=
-Work_offline=
-
-Working_offline.=
-
-Update_refused.=
-Update_refused=
-Local_entry=
-Shared_entry=
-Update_could_not_be_performed_due_to_existing_change_conflicts.=
-You_are_not_working_on_the_newest_version_of_BibEntry.=
-Local_version\:_%0=
-Shared_version\:_%0=
-Please_merge_the_shared_entry_with_yours_and_press_"Merge_entries"_to_resolve_this_problem.=
-Canceling_this_operation_will_leave_your_changes_unsynchronized._Cancel_anyway?=
-The_BibEntry_you_currently_work_on_has_been_deleted_on_the_shared_side._Hit_"Keep"_to_recover_the_entry.=
-Cannot_cite_entries_without_BibTeX_keys._Generate_keys_now?=
+Check_for_updates=Проверить_обновления
+Download_update=Загрузить_обновления
+New_version_available=Доступна_новая_версия
+Installed_version=Установленная_версия
+Remind_me_later=Напомнить_позже
+Ignore_this_update=Игнорировать_это_обновление
+Could_not_connect_to_the_update_server.=Не_удалось_подключиться_к_серверу_обновлений.
+Please_try_again_later_and/or_check_your_network_connection.=Повторите_попытку_позже_и/или_проверьте_настройки_сетевого_подключения.
+To_see_what_is_new_view_the_changelog.=Для_просмотра_сведений_об_изменениях_см._журнал_изменений.
+A_new_version_of_JabRef_has_been_released.=Выпущена_новая_версия_JabRef.
+JabRef_is_up-to-date.=Установлена_актуальная_версия_JabRef.
+Latest_version=Последняя_версия
+Online_help_forum=Форум_онлайн-поддержки
+Custom=Определено_пользователем
+
+Export_cited=Экспорт_цитированного
+Unable_to_generate_new_database=Не_удалось_создать_новую_БД
+
+Open_console=Открыть_консоль
+Use_default_terminal_emulator=Использовать_эмуляцию_терминала_по_умолчанию
+Execute_command=Выполнить_команду
+Note\:_Use_the_placeholder_%0_for_the_location_of_the_opened_database_file.=Примечание._Используйте_подстановочный_знак_%0_для_указания_расположения_открытой_БД.
+Executing_command_\"%0\"...=Выполнение_команды_\"%0\"...
+Error_occured_while_executing_the_command_\"%0\".=Ошибка_при_выполнении_команды_\"%0\".
+Reformat_ISSN=Переформатировать_ISSN
+
+Countries_and_territories_in_English=Страны_и_территории_на_английском
+Electrical_engineering_terms=Термины_электротехники
+Enabled=Включено
+Internal_list=Встроенный_список
+Manage_protected_terms_files=Управление_файлами_защищенных_терминов
+Months_and_weekdays_in_English=Месяцы_и_рабочие_дни_на_английском
+The_text_after_the_last_line_starting_with_\#_will_be_used=Будет_использован_текст_после_последней_строки,_начинающейся_с_#
+Add_protected_terms_file=Добавить_файл_с_защищенными_терминами
+Are_you_sure_you_want_to_remove_the_protected_terms_file?=Файл_с_защищенными_терминами_будет_удален._Продолжить?
+Remove_protected_terms_file=Удалить_файл_с_защищенными_терминами
+Add_selected_text_to_list=Добавить_выбранный_текст_в_список
+Add_{}_around_selected_text=Поместить_выбранный_текст_в_{}
+Format_field=Форматировать_поле
+New_protected_terms_file=Создать_файл_с_защищенными_терминами
+change_field_%0_of_entry_%1_from_%2_to_%3=изменить_поле_%0_записи_%1_с_%2_на_%3
+change_key_from_%0_to_%1=изменить_ключ_с_%0_на_%1
+change_string_content_%0_to_%1=изменить_содержимое_строки_%0_на_%1
+change_string_name_%0_to_%1=изменить_имя_строки_%0_на_%1
+change_type_of_entry_%0_from_%1_to_%2=изменить_тип_записи_%0_с_%1_на_%2
+insert_entry_%0=вставить_запись_%0
+insert_string_%0=вставить_строку_%0
+remove_entry_%0=удалить_запись_%0
+remove_string_%0=удалить_строку_%0
+undefined=не_определено
+Cannot_get_info_based_on_given_%0\:_%1=Не_удалось_получить_сведения_на_основе_заданного_%0:_%1
+Get_BibTeX_data_from_%0=Получение_данных_BibTeX_из_%0
+No_%0_found=Не_найдены_%0
+Entry_from_%0=Запись_из_%0
+Merge_entry_with_%0_information=Объединение_записи_со_сведениями_%0
+Updated_entry_with_info_from_%0=Обновленная_запись_со_сведениями_из_%0
+Connection=Подключение
+Connecting...=
+Host=Хост
+Port=Порт
+Database=База_данных
+User=Пользователь
+Connect=Подключение
+Connection_error=Ошибка_подключения
+Connection_to_%0_server_established.=Соединение_с_сервером_%0_установлено.
+Required_field_"%0"_is_empty.=Не_заполнено_обязательное_поле_\"%0\".
+%0_driver_not_available.=Драйвер_%0_недоступен.
+The_connection_to_the_server_has_been_terminated.=Соединение_с_сервером_было_прервано.
+Connection_lost.=Соединение_прервано.
+Reconnect=Повторное_подключение
+Work_offline=Работать_автономно
+Working_offline.=Работа_в_автономном_режиме.
+Update_refused.=Обновление_отклонено.
+Update_refused=Обновление_отклонено
+Local_entry=Локальная_запись
+Shared_entry=Запись_с_общим_доступом
+Update_could_not_be_performed_due_to_existing_change_conflicts.=Не_удалось_выполнить_обновление_из-за_существующих_конфликтов_изменений.
+You_are_not_working_on_the_newest_version_of_BibEntry.=Вы_используете_не_самую_последнюю_версию_BibEntry.
+Local_version\:_%0=Локальная_версия:_%0
+Shared_version\:_%0=Версия_с_общим_доступом:_%0
+Please_merge_the_shared_entry_with_yours_and_press_"Merge_entries"_to_resolve_this_problem.=Объедините_запись_с_общим_доступом_и_вашу_запись,_а_затем_нажмите_\"Объединение_записей\"_для_разрешения_этой_проблемы.
+Canceling_this_operation_will_leave_your_changes_unsynchronized._Cancel_anyway?=При_отмене_этой_операции_ваши_изменения_не_будут_синхронизированы._Отменить_операцию?
+Shared_entry_is_no_longer_present=
+The_BibEntry_you_currently_work_on_has_been_deleted_on_the_shared_side.=Текущая_рабочая_запись_BibEntry_удалена_на_стороне_общего_доступа.
+You_can_restore_the_entry_using_the_"Undo"_operation.=
+Remember_password?=
+You_are_already_connected_to_a_database_using_entered_connection_details.=
+
+Cannot_cite_entries_without_BibTeX_keys._Generate_keys_now?=Цитирование_записей_без_ключей_BibTeX_невозможно._Создать_ключи_сейчас?
New_technical_report=
-%0_file=
-Custom_layout_file=
-Protected_terms_file=
-Style_file=
-
-Open_OpenOffice/LibreOffice_connection=
-
-You_must_enter_at_least_one_field_name=
-
-
-Non-ASCII_encoded_character_found=
-
-Toggle_web_search_interface=
-Background_color_for_resolved_fields=
-Color_code_for_resolved_fields=
-%0_files_found=
-%0_of_%1=
-One_file_found=
-The_import_finished_with_warnings\:=
-There_was_one_file_that_could_not_be_imported.=
-There_were_%0_files_which_could_not_be_imported.=
+%0_file=Файл_%0
+Custom_layout_file=Файл_макета_пользователя
+Protected_terms_file=Файл_с_защищенными_терминами
+Style_file=Файл_стиля
+
+Open_OpenOffice/LibreOffice_connection=Установить_подключение_к_Open_OpenOffice/LibreOffice
+You_must_enter_at_least_one_field_name=Необходимо_ввести_минимум_одно_имя_поля
+Non-ASCII_encoded_character_found=Обнаружен_символ_не_в_кодировке_ASCII
+Toggle_web_search_interface=Переключение_интерфейса_веб-поиска
+Background_color_for_resolved_fields=Цвет_фона_для_полей_c_разрешенными_ошибками
+Color_code_for_resolved_fields=Цветовой_код_для_полей_с_разрешенными_ошибками
+%0_files_found=Найдено_файлов:_%0
+%0_of_%1=%0_из_%1
+One_file_found=Найден_один_файл
+The_import_finished_with_warnings\:=Импорт_завершен_с_предупреждениями:
+There_was_one_file_that_could_not_be_imported.=Существует_один_файл,_который_не_удалось_импортировать.
+There_were_%0_files_which_could_not_be_imported.=Существует_%0_файлов,_которые_не_удалось_импортировать.
Migration_help_information=
Entered_database_has_obsolete_structure_and_is_no_longer_supported.=
However,_a_new_database_was_created_alongside_the_pre-3.6_one.=
-
Click_here_to_learn_about_the_migration_of_pre-3.6_databases.=
-
-Connecting...=
Opens_JabRef's_Facebook_page=
Opens_JabRef's_blog=
Opens_JabRef's_website=
-
Opens_a_link_where_the_current_development_version_can_be_downloaded=
See_what_has_been_changed_in_the_JabRef_versions=
+Referenced_BibTeX_key_does_not_exist=
+Finished_downloading_full_text_document_for_entry_%0.=
+Full_text_document_download_failed_for_entry_%0.=
+Look_up_full_text_documents=
+You_are_about_to_look_up_full_text_documents_for_%0_entries.=
+last_four_nonpunctuation_characters_should_be_numerals=
+shared=
+should_contain_an_integer_or_a_literal=
+should_have_the_first_letter_capitalized=
+
+ID=
+ID_type=
+ID-based_entry_generator=
+Fetcher_'%0'_did_not_find_an_entry_for_id_'%1'.=
+
+Select_first_entry=
+Select_last_entry=
+
+Invalid_ISBN\:_'%0'.=
+should_be_an_integer_or_normalized=
+should_be_normalized=
+
+Empty_search_ID=
+The_given_search_ID_was_empty.=
+Copy_BibTeX_key_and_link=
+empty_BibTeX_key=
+BibLaTeX_field_only=
+
+Error_while_generating_fetch_URL=
+Error_while_parsing_ID_list=
+Unable_to_get_PubMed_IDs=
+Backup_found=
+A_backup_file_for_'%0'_was_found.=
+This_could_indicate_that_JabRef_did_not_shut_down_cleanly_last_time_the_file_was_used.=
+Do_you_want_to_recover_the_database_from_the_backup_file?=
+Firstname_Lastname=
+
+Recommended_for_%0=
+This_might_be_caused_by_reaching_the_traffic_limitation_of_Google_Scholar_(see_'Help'_for_details).=
+
+Problem_downloading_from_%1=
+
+File_directory_pattern=
+Update_with_bibliographic_information_from_the_web=
+
+Could_not_find_any_bibliographic_information.=
+BibTeX_key_%0_deviates_from_generated_key_%1=
+DOI_%0_is_invalid=
+
+Jump_to_entry=
diff --git a/src/main/resources/l10n/JabRef_sv.properties b/src/main/resources/l10n/JabRef_sv.properties
index a292ab3..c4bc7a1 100644
--- a/src/main/resources/l10n/JabRef_sv.properties
+++ b/src/main/resources/l10n/JabRef_sv.properties
@@ -1,1352 +1,2024 @@
-# Swedish translation of JabRef
+#!
+#! created/edited by Popeye version 0.55 (github.com/JabRef/popeye)
+#! encoding:UTF-8
+
%0_contains_the_regular_expression_<b>%1</b>=%0_innehåller_det_reguljära_uttrycket_<b>%1</b>
+
%0_contains_the_term_<b>%1</b>=%0_innehåller_termen_<b>%1</b>
+
%0_doesn't_contain_the_regular_expression_<b>%1</b>=%0_innehåller_inte_det_reguljära_uttrycket_<b>%1</b>
+
%0_doesn't_contain_the_term_<b>%1</b>=%0_innehåller_inte_termen_<b>%1</b>
-%0_entries_found._To_reduce_server_load,_only_%1_will_be_downloaded.=%0_poster_hittades._För_att_minska_lasten_på_servern_kommer_bara_%1_att_laddas_ned.
-%0_entries_needed_a_clean_up=%0_poster_behövde_städas_upp
+
%0_export_successful=%0-export_lyckades
-%0_image=%0-bild
+
%0_matches_the_regular_expression_<b>%1</b>=%0_matchar_det_reguljära_uttrycket_<b>%1</b>
+
%0_matches_the_term_<b>%1</b>=%0_matchar_termen_<b>%1</b>
-%0_mode=%0-läge
-%0_problem(s)_found=%0_problem_hittades
-'%0'_exists._Overwrite_file?='%0'_finns_redan._Skriv_över_filen?
-'%0'_is_not_a_valid_ADS_bibcode.='%0'_är_inte_en_giltig_ADS-bibkod.
+
<HTML>Could_not_find_file_'%0'<BR>linked_from_entry_'%1'</HTML>=<HTML>Hittar_inte_filen_'%0'<BR>som_länkas_från_posten_'%1'</HTML>
-<No_selection>=<Inget_val>
-<b>All_Entries</b>_(this_group_cannot_be_edited_or_removed)=<b>Alla_poster</b>_(den_här_gruppen_kan_inte_ändras_eller_tas_bort)
-<field_name>=<fältnamn>
+
<select>=<välj>
-<select_word>=<välj_ord>
-AUX_file_import=Import_från_AUX-fil
-A_string_with_that_label_already_exists=En_sträng_med_det_namnet_finns_redan
-Abbreviate_journal_names=Förkorta_tidskriftsnamn
+
Abbreviate_journal_names_of_the_selected_entries_(ISO_abbreviation)=Förkorta_tidskriftsnamnen_för_valda_poster_(ISO-förkortningar)
Abbreviate_journal_names_of_the_selected_entries_(MEDLINE_abbreviation)=Förkorta_tidskriftsnamnen_för_valda_poster_(MEDLINE-förkortningar)
+
Abbreviate_names=Förkorta_namn
Abbreviated_%0_journal_names.=Förkortade_%0_tidskriftsnamn.
-Abbreviating...=Förkortar...
+
Abbreviation=Förkortning
+
About_JabRef=Om_JabRef
+
Abstract=Sammanfattning
+
Accept=Acceptera
+
Accept_change=Acceptera_ändring
-Accepting_the_change_replaces_the_complete_groups_tree_with_the_externally_modified_groups_tree.=Om_ändringarna_accepteras_så_kommer_hela_gruppträdet_att_ersättas_av_det_externt_ändrade_gruppträdet.
+
Action=Händelse
+
Add=Lägg_till
-Add_a_(compiled)_custom_ImportFormat_class_from_a_ZIP-archive.=Lägg_till_en_(kompilerad)_ImportFormat-klass_från_en_zip-fil.
-Add_a_(compiled)_custom_ImportFormat_class_from_a_class_path.=Lägg_till_en_(kompilerad)_ImportFormat-klass_från_en_sökväg_till_en_klass.
+
+Add_a_(compiled)_custom_Importer_class_from_a_class_path.=Lägg_till_en_(kompilerad)_Importer-klass_från_en_sökväg_till_en_klass.
+The_path_need_not_be_on_the_classpath_of_JabRef.=
+
+Add_a_(compiled)_custom_Importer_class_from_a_ZIP-archive.=Lägg_till_en_(kompilerad)_Importer-klass_från_en_zip-fil.
+The_ZIP-archive_need_not_be_on_the_classpath_of_JabRef.=
+
Add_entry_selection_to_this_group=Lägg_till_valda_poster_till_denna_grupp
+
Add_from_folder=Lägg_till_från_mapp
+
Add_from_JAR=Lägg_till_från_JAR-fil
+
+add_group=lägg_till_grupp
+
Add_group=Lägg_till_grupp
+
Add_new=Lägg_till_ny
-Add_new_file_type=Lägg_till_ny_filtyp
+
Add_subgroup=Lägg_till_undergrupp
+
Add_to_group=Lägg_till_i_grupp
-Add_{}_to_specified_title_words_on_search_to_keep_the_correct_case=Lägg_till_{}_runt_skyddade_ord_i_titeln_för_att_bevara_skiftläget_vid_sökning
-Added_entry=Lade_till_post
+
Added_group_"%0".=Lade_till_gruppen_"%0".
+
Added_new=Lade_till_ny
-Added_new_'%0'_entry.=Lade_till_ny_'%0'-post.
+
Added_string=Lade_till_sträng
-Adding_fetched_entries=Lägger_till_hämtade_poster
-Additional_parameters=Ytterligare_parametrar
+
Additionally,_entries_whose_<b>%0</b>_field_does_not_contain_<b>%1</b>_can_be_assigned_manually_to_this_group_by_selecting_them_then_using_either_drag_and_drop_or_the_context_menu._This_process_adds_the_term_<b>%1</b>_to_each_entry's_<b>%0</b>_field._Entries_can_be_removed_manually_from_this_group_by_selecting_them_then_using_the_context_menu._This_process_removes_the_term_<b>%1</b>_from_each_entry's_<b>%0</b>_field.=
-Adds_{}_brackets_around_acronyms,_month_names_and_countries_to_preserve_their_case.=
+
Advanced=Avancerad
-Advanced_search_active.=Avancerad_sökning_aktiv.
All_entries=Alla_poster
All_entries_of_this_type_will_be_declared_typeless._Continue?=Alla_poster_av_denna_typ_kommer_att_bli_typlösa._Fortsätt?
+
All_fields=Alla_fält
-All_key_bindings_will_be_reset_to_their_defaults.=Alla_tangentbordsbindingar_kommer_att_återställas_till_standardvärden.
+
All_subgroups_(recursively)=Alla_undergrupper_(rekursivt)
-Allow_overwriting_existing_links.=Tillåt_att_befintliga_länkar_skrivs_över.
-Always_add_letter_(a,_b,_...)_to_generated_keys=Lägg_alltid_till_en_bokstav_(a,_b_...)_på_genererade_nycklar
+
Always_reformat_BIB_file_on_save_and_export=Formattera_alltid_om_BIB-filen_vid_när_den_sparas_eller_exporteras
-Always_use_this_PDF_import_style_(and_do_not_ask_for_each_import)=Använd_alltid_detta_vid_import_av_PDF_(och_fråga_inte_för_varje_fil)
-An_error_occurred_while_fetching_from_ADS_(%0)\:=Ett_fel_inträffade_vid_hämtning_från_ADS_(%0)\:
-An_error_occurred_while_parsing_abstract=Ett_fel_inträffade_när_sammanfattningen_tolkades
-An_exception_occurred_while_accessing_'%0'=Ett_undantag_inträffade_när_'%0'_accessades
+
A_SAX_exception_occurred_while_parsing_'%0'\:=Ett_SAX-undantag_inträffade_när_'%0'_tolkades\:
-An_autosave_file_was_found_for_this_database._This_could_indicate_that_JabRef_did_not_shut_down_cleanly_last_time_the_file_was_used.=En_automatiskt_sparad_fil_hittades_för_databasen._Det_kan_betyda_att_JabRef_inte_avslutades_korrekt_senaste_gången_databasen_användes.
+
+and=och
+and_the_class_must_be_available_in_your_classpath_next_time_you_start_JabRef.=och_klassen_måste_finnas_i_din_sökväg_för_klasser_nästa_gång_du_startar_JabRef.
+
+any_field_that_matches_the_regular_expression_<b>%0</b>=något_fält_som_matchar_det_reguljära_uttrycket_<b>%0</b>
+
Appearance=Utseende
+
Append=Lägg_till
Append_contents_from_a_BibTeX_database_into_the_currently_viewed_database=Lägg_till_innehåll_från_en_BibTeX-databas_till_den_nu_aktiva_databasen
+
Append_database=Lägg_till_databas
+
Append_the_selected_text_to_BibTeX_field=Lägg_till_vald_text_till_BibTeX-nyckeln
Application=Program
+
Apply=Tillämpa
-Are_you_sure_you_want_to_reset_all_settings_to_default_values?=Är_du_säker_att_du_vill_återställa_alla_inställningar_till_standardvärden?
+
Arguments_passed_on_to_running_JabRef_instance._Shutting_down.=Argumenten_skickades_till_JabRef-instansen_som_redan_kördes._Stänger_ned.
+
Assign_entry_selection_exclusively_to_this_group=
+
Assign_new_file=Tilldela_ny_fil
+
Assign_the_original_group's_entries_to_this_group?=Tilldela_den_ursprungliga_gruppens_poster_till_denna_grupp?
+
Assigned_%0_entries_to_group_"%1".=Tilldelade_%0_poster_till_gruppen_"%1".
+
Assigned_1_entry_to_group_"%0".=Tilldelade_en_post_till_gruppen_"%0".
+
Attach_URL=Lägg_till_URL
-Attach_file=Lägg_till_fil
+
Attempt_to_automatically_set_file_links_for_your_entries._Automatically_setting_works_if_a_file_in_your_file_directory<BR>or_a_subdirectory_is_named_identically_to_an_entry's_BibTeX_key,_plus_extension.=
-Attention\:_Password_is_stored_in_plain_text\!=OBS\!_Lösenordet_sparas_i_klartext\!
-Auto-generating_PDF-Names_does_not_support_undo._Continue?=Du_kan_inte_ångra_automatisk_generering_av_PDF-namn._Fortsätt?
+
Auto=Automatiskt
-Autocomplete_after_following_number_of_characters=Komplettera_automatiskt_efter_följande_antal_bokstäver
-Autocomplete_names_in_'Firstname_Lastname'_format_only=Komplettera_enbart_namn_i_'Förnamn_Efternamn'-format
-Autocomplete_names_in_'Lastname,_Firstname'_format_only=Komplettera_enbart_namn_i_'Efternamn,_Förnamn'-format
-Autocomplete_names_in_both_formats=Komplettera_namn_automatiskt_i_bägge_formaten
-Autocompletion_options=Inställningar_för_automatisk_komplettering
+
Autodetect_format=Bestäm_format_automatiskt
-Autodetecting_paths...=Detekterar_sökvägar...
-Autodetection_failed=Kunde_inte_detektera_sökvägar
+
Autogenerate_BibTeX_keys=Generera_BibTeX-nycklar_automatiskt
-Autogenerate_PDF_Names=Generera_PDF-namn_automatiskt
+
Autolink_files_with_names_starting_with_the_BibTeX_key=Länka_filer_vars_namn_börjar_med_BibTeX-nyckeln_automatiskt
+
Autolink_only_files_that_match_the_BibTeX_key=Länka_bara_filer_vars_namn_är_BibTeX-nyckeln_automatiskt
-Automatically_assign_new_entry_to_selected_groups=Tilldela_automatiskt_nya_poster_till_valda_grupper
+
Automatically_create_groups=Skapa_grupper_automatiskt
+
Automatically_create_groups_for_database.=Skapa_grupper_automatiskt_för_databasen.
+
Automatically_created_groups=Skapade_grupper_automatiskt
-Automatically_open_browse_dialog_when_creating_new_file_link=Öppna_fildialog_automatiskt_när_ny_fillänk_skapas
-Automatically_open_folders_of_attached_files=Öppna_automatiskt_mappar_där_filer_som_ska_skickas_med_finns
+
Automatically_remove_exact_duplicates=Ta_bort_exakta_dubbletter_automatiskt
-Automatically_set_file_links=Skapa_fillänkar_automatiskt
-Automatically_set_file_links_for_this_entry=Skapa_fillänkar_automatiskt_för_denna_post
-Automatically_setting_file_links=Skapar_fillänkar_automatiskt
-Automatically_sync_bibliography_when_inserting_citations=Synkronisera_bibliografin_automatiskt_när_citeringar_infogas
-Autosave=Automatisk_sparning
-Autosave_interval_(minutes)=Intervall_för_automatisk_sparning_(minuter)
-Autosave_of_file_'%0'=Automatisk_sparning_av_filen_'%0'
-Available_BibTeX_fields=Tillgängliga_BibTeX-fält
+
+Allow_overwriting_existing_links.=Tillåt_att_befintliga_länkar_skrivs_över.
+
+Do_not_overwrite_existing_links.=Skriv_inte_över_befintliga_länkar.
+
+AUX_file_import=Import_från_AUX-fil
+
Available_export_formats=Tillgängliga_format_för_export
+
+Available_BibTeX_fields=Tillgängliga_BibTeX-fält
+
Available_import_formats=Tillgängliga_format_för_import
-Back=Bakåt
+
Background_color_for_optional_fields=Bakgrundsfärg_för_valfria_fält
+
Background_color_for_required_fields=Bakgrundsfärg_för_obligatoriska_fält
+
Backup_old_file_when_saving=Skapa_en_säkerhetskopia_av_den_gamla_filen_vid_sparning
-BibTeX_entry_creation=Skapande_av_BibTeX-poster
-BibTeX_key_generator=BibTeX-nyckelgenerator
+
BibTeX_key_is_unique.=BibTeX-nyckeln_är_unik.
-BibTeX_key_patterns=BibTeX-nyckelmönster
-BibTeX_source=BibTeX-källkod
+
+%0_source=%0_källkod
+
Broken_link=Trasig_länk
+
Browse=Bläddra
-Built-in_journal_list=Inbyggd_tidskriftslista
+
+by=med
+
Cancel=Avbryt
-Canceled_merging_entries=Avbröt_sammanslagning_av_poster
+
Cannot_add_entries_to_group_without_generating_keys._Generate_keys_now?=Kan_inte_lägga_till_poster_till_grupp_utan_att_generera_nycklar._Generera_nycklar_nu?
-Cannot_delete_file=Kan_inte_radera_fil
+
Cannot_merge_this_change=Kan_inte_införa_den_här_ändringen
+
Cannot_move_group_"%0"_down.=Kan_inte_flytta_gruppen_"%0"_nedåt.
+
Cannot_move_group_"%0"_left.=Kan_inte_flytta_gruppen_"%0"_till_vänster.
+
Cannot_move_group_"%0"_right.=Kan_inte_flytta_gruppen_"%0"_till_höger.
+
Cannot_move_group_"%0"_up.=Kan_inte_flytta_gruppen_"%0"_uppåt.
-Cannot_use_port_%0_for_remote_operation;_another_application_may_be_using_it._Try_specifying_another_port.=Kan_inte_använda_port_"%0"_för_fjärråtkomst;_ett_annat_program_kanske_använder_den._Försök_med_en_annan_port.
+
+case_insensitive=ej_skiftlägeskänsligt
+
+case_sensitive=skiftlägeskänsligt
+
Case_sensitive=Shiftlägeskänlig
+
+change_assignment_of_entries=ändra_tilldelning_av_poster
+
Change_case=Ändra_shiftläge
+
Change_entry_type=Ändra_posttyp
Change_file_type=Ändra_filtyp
+
+
Change_of_Grouping_Method=
+
+change_preamble=ändra_preamble
+
Change_table_column_and_General_fields_settings_to_use_the_new_feature=
+
Changed_font_settings=Ändra_typsnittsinställningar
+
Changed_language_settings=Ändra_språkinställningar
+
Changed_look_and_feel_settings=Ändra_inställningar_för_look-and-feel
+
Changed_preamble=Ändrade_preamble
-Changed_special_field_settings=Ändrade_inställningar_för_specialfält
-Changed_type_to_'%0'_for=Ändrade_typ_till_'%0'_för
-Changes_have_been_made_to_the_following_metadata_elements=Ändringar_har_gjorts_i_följande_metadata-element
-Character_encoding_'%0'_is_not_supported.=Teckenkodningen_'%0'_stöds_inte.
+
Characters_to_ignore=Bokstäver_att_ignorera
+
Check_existing_file_links=Kontrollera_befintliga_fillänkar
+
Check_links=Kontrollera_länkar
-Choose_OpenOffice/LibreOffice_executable=Välj_OpenOffice/LibreOffice-program
-Choose_pattern=Välj_mönster
+
Choose_the_URL_to_download.=Välj_URL_att_ladda_ned.
-Choose_the_source_for_the_metadata_import=Välj_källa_för_metadata-import
-Citation=Citering
-Cite=Referera
Cite_command=Citeringskommando
-Cite_in-text=Referera_i_löpande_text
-Cite_selected_entries_between_parenthesis=Referera_till_valda_poster_inom_paranteser
-Cite_selected_entries_with_extra_information=Referera_till_valda_poster_och_lägg_till_extra_information
-Cite_selected_entries_with_in-text_citation=Referera_till_valda_poster_i_löpande_text
-Cite_special=Specialcitering
+
Class_name=Klassnamn
-Cleanup_entries=Städa_upp_poster
-Cleanup_entry=Städa_upp_post
+
Clear=Rensa
-Clear_connection_settings=Rensa_anslutningsinställningar
+
Clear_fields=Rensa_fält
-Clear_inputarea=Rensa_inmatningsområdet
-Clear_priority=Rensa_prioritet
-Clear_rank=Rensa_ranking
-Clear_read_status=Rensa_lässtatus
-Clear_search=Rensa_sökning
-Cleared_connection_settings.=Rensade_anslutningsinställningar.
-Click_group_to_toggle_membership_of_selected_entries=Klicka_grupp_för_att_växla_valda_posters_tillhörighet
-Clipboard=Urklipp
+
Close=Stäng
-Close_all=Stäng_alla
Close_others=Stäng_andra
-Close_database=Stäng_databas
+Close_all=Stäng_alla
+
Close_dialog=Stäng_dialog
-Close_entry_editor=Stäng_posteditor
+
Close_the_current_database=Stäng_aktuell_databas
+
Close_window=Stäng_fönster
+
Closed_database=Stängde_databasen
-Collapse_all=Fäll_ihop_alla
+
Collapse_subtree=Fäll_ihop_delträd
+
Color_codes_for_required_and_optional_fields=Färgkodning_av_obligatoriska_och_valfria_fält
+
Color_for_marking_incomplete_entries=Färg_för_markering_av_ofullständiga_poster
+
Column_width=Kolumnbredd
-Combine_pairs_of_citations_that_are_separated_by_spaces_only=Slå_ihop_citeringar_som_bara_separareras_av_mellanslag
+
Command_line_id=Kommandorads-id
-Confirm_selection=Bekräfta_val
-Connect=Anslut
-Connected_to_document=Ansluten_till_dokument
-Connecting=Ansluter
-Connection_lost=Tappade_anslutning
-Connection_to_OpenOffice/LibreOffice_has_been_lost._Please_make_sure_OpenOffice/LibreOffice_is_running,_and_try_to_reconnect.=Anslutningen_till_OpenOffice/LibreOffice_försvann._Se_till_att_OpenOffice/LibreOffice_körs_och_anslut_på_nytt.
+
+
Contained_in=Finns_i
+
Content=Innehåll
-Continue?=Fortsätt?
-Convert=Konvertera
-Convert_to_BibLatex_format_(for_example,_move_the_value_of_the_'journal'_field_to_'journaltitle')=Konvertera_till_BibLatex-format_(t._ex._genom_att_flytta_data_från_'journal'-fältet_till_'journaltitle'-fältet)
-Converts_units_to_LaTeX_formatting.=Formatterar_enheter_så_att_det_ser_bra_ut
+
Copied=Kopierade
+
Copied_cell_contents=Kopierade_cellinnehåll
+
Copied_key=Kopierade_nyckel
+
Copied_keys=Kopierade_nycklar
+
Copy=Kopiera
+
Copy_BibTeX_key=Kopiera_BibTeX-nyckel
-Copy_BibTeX_key_and_title=Kopiera_BibTeX-nyckel_och_titel
-Copy_\\cite{BibTeX_key}=Kopiera_\\cite{BibTeX-nyckel}
Copy_file_to_file_directory=Kopiera_fil_till_filmappen
-Copy_preview=Kopiera_postvisning
+
Copy_to_clipboard=Kopiera_till_urklipp
-Correct_the_entry,_and_reopen_editor_to_display/edit_source.=
-Could_not_apply_changes.=Kunde_inte_tillämpa_inte_ändringar.
+
Could_not_call_executable=Kunde_inte_anropa_program
-Could_not_connect_to_%0=Kunde_inte_ansluta_till_%0
Could_not_connect_to_Vim_server._Make_sure_that_Vim_is_running<BR>with_correct_server_name.=Kunde_inte_ansluta_till_Vim-servern._Se_till_att_Vim_körs_med_rätt_servernamn.
-Could_not_connect_to_a_running_gnuserv_process._Make_sure_that_Emacs_or_XEmacs_is_running,<BR>and_that_the_server_has_been_started_(by_running_the_command_'server-start'/'gnuserv-start').=
-Could_not_connect_to_running_OpenOffice/LibreOffice.=Kunde_inte_ansluta_till_OpenOffice/LibreOffice.
+
Could_not_export_file=Kunde_inte_exportera_filen
+
Could_not_export_preferences=Kunde_inte_exportera_inställningar
-Could_not_find_OpenOffice/LibreOffice_installation=Kunde_inte_hitta_någon_OpenOffice/LibreOffice-installation
+
Could_not_find_a_suitable_import_format.=Kunde_inte_hitta_ett_lämpligt_importformat.
-Could_not_find_fetcher_'%0'=Kunde_inte_hitta_hämtaren_'%0'
-Could_not_find_file_'%0'.=Kunde_inte_hitta_filen_'%0'.
Could_not_import_preferences=Kunde_inte_importera_inställningar
-Could_not_instantiate_%0._Have_you_chosen_the_correct_package_path?=Kunde_inte_instansiera_%0._Har_du_valt_rätt_sökväg?
+
Could_not_instantiate_%0=Kunde_inte_instansiera_%0
Could_not_instantiate_%0_%1=Kunde_inte_instansiera_%0_%1
-Could_not_move_file_'%0'.=Kunde_inte_flytta_filen_'%0'
-Could_not_open_%0=Kunde_inte_öppna_%0
-Could_not_open_browser.=Kunde_inte_öppna_webbläsaren.
+Could_not_instantiate_%0._Have_you_chosen_the_correct_package_path?=Kunde_inte_instansiera_%0._Har_du_valt_rätt_sökväg?
Could_not_open_link=Kunde_inte_öppna_länk
-Could_not_paste_entry_as_text\:=Kunde_inte_klista_in_post_so_text\:
+
Could_not_print_preview=Kunde_inte_skriva_ut_postvisning
-Could_not_resolve_BibTeX_entry_for_citation_marker_'%0'.=Kunde_inte_hitta_en_BibTeX-post_för_referensmarkören_'%0'.
+
Could_not_run_the_'vim'_program.=Kunde_inte_köra_'vim'.
-Could_not_run_the_gnuclient/emacsclient_program._Make_sure_you_have_the_emacsclient/gnuclient_program_installed_and_available_in_the_PATH.=
-Could_not_save,_file_locked_by_another_JabRef_instance.=Kunde_inte_spara._Filen_låst_av_en_annan_JabRef-instans.
+
Could_not_save_file.=Kunde_inte_spara_fil.
-Create_new_entry=Skapa_ny_post
-Create_blank_entry_linking_the_PDF=Skapa_tom_post_som_länkar_till_PDF\:en
-Create_directory_based_keywords=Skapa_nyckelord_baserade_på_mapp
-Create_entry_based_on_XMP_data=Skapa_post_baserat_på_XMP-data
-Create_entry_based_on_content=Skapa_post_baserat_på_innehåll
-Created_group_"%0".=Skapade_grupp_"%0".
+Character_encoding_'%0'_is_not_supported.=Teckenkodningen_'%0'_stöds_inte.
+
Created_groups.=Skapade_grupper.
-Creates_keywords_in_created_entrys_with_directory_pathnames=Skapar_nyckelord_med_sökvägen_till_mappen_i_de_skapade_posterna
+
+crossreferenced_entries_included=korsrefererade_poster_inkluderade
+
Current_content=Nuvarande_innehåll
-Current_tmp_value=Nuvarande_temporära_värde
+
Current_value=Nuvarande_värde
+
Custom_entry_types=Anpassade_posttyper
+
Custom_entry_types_found_in_file=Anpassade_posttyper_hittades_i_fil
+
Customize_entry_types=Anpassa_posttyper
+
Customize_key_bindings=Anpassa_tangentbordsbindningar
+
Cut=Klipp
-Database_'%0'_has_changed.=Databasen_'%0'_har_ändrats.
+
+cut_entries=klipp_ut_poster
+
+cut_entry=klipp_ut_post
+
+
Database_encoding=Teckenkodning_för_databas
-Database_is_protected._Cannot_save_until_external_changes_have_been_reviewed.=Databasen_är_skyddad._Kan_inte_spara_innan_externa_ändringar_är_kontrollerade.
+
Database_properties=Databasegenskaper
Database_type=Databastyp
-Database_protection=Databasskydd
+
Date_format=Datumformat
-Decrease_table_font_size=Minska_typsnittsstorlek_för_tabellen
+
Default=Standard
-Default_PDF_file_link_action=Standardhändelse_för_PDF-fil
-Default_bibliography_mode=Standardläge_för_databas
+
Default_encoding=Standardteckenkodning
+
Default_grouping_field=Standardfält_för_gruppering
-Default_import_style_for_drag_and_drop_of_PDFs=
+
Default_look_and_feel=Standard-'look-and-feel'
+
Default_pattern=Standardmönster
+
Default_sort_criteria=Standardsortering
Define_'%0'=Definiera_'%0'
+
Delete=Radera
+
Delete_custom_format=Radera_eget_format
+
+delete_entries=radera_poster
+
Delete_entry=Radera_post
-Delete_local_file=Radera_lokal_fil
+
+delete_entry=radera_post
+
Delete_multiple_entries=Radera_flera_poster
+
Delete_rows=Radera_rader
+
Delete_strings=Radera_strängar
+
Deleted=Raderade
-Deleted_entry=Raderade_post
+
+Delete_local_file=Radera_lokal_fil
+
Delimit_fields_with_semicolon,_ex.=Avgränsa_fält_med_semikolon,_t.ex.
-Deprecated_fields=
+
Descending=Fallande
+
Description=Beskrivning
+
Deselect_all=
Deselect_all_duplicates=
-Directories=Mappar
-Disable_highlight_groups_matching_entries=Avvaktivera_framhävandet_av_grupper_som_matchar_poster
+
Disable_this_confirmation_dialog=Avaktivera_denna_bekräftelsedialog
-Discard_changes=Ignorera_ändringar
+
Display_all_entries_belonging_to_one_or_more_of_the_selected_groups.=Visa_alla_poster_som_ingår_i_en_eller_flera_valda_grupper.
+
Display_all_error_messages=Visa_alla_felmeddelanden
+
Display_help_on_command_line_options=Visa_hjälp_för_kommandoradsalternativ
-Display_keywords_appearing_in_ALL_entries=Visa_nyckelord_som_finns_i_ALLA_poster
-Display_keywords_appearing_in_ANY_entry=Visa_nyckelord_som_finns_i_NÅGON_post
+
Display_only_entries_belonging_to_all_selected_groups.=Visa_bara_poster_som_ingår_i_alla_valda_grupper.
Display_version=Visa_version
+
Displaying_no_groups=Visar_inga_grupper
+
Do_not_abbreviate_names=Förkorta_ej_namn
+
Do_not_automatically_set=Sätt_ej_automatiskt
+
Do_not_import_entry=Importera_inte_post
+
Do_not_open_any_files_at_startup=Öppna_inga_filer_vid_uppstart
+
Do_not_overwrite_existing_keys=Skriv_inte_över_befintliga_nycklar
-Do_not_overwrite_existing_links.=Skriv_inte_över_befintliga_länkar.
Do_not_show_these_options_in_the_future=Visa_inte_dessa_alternativ_igen
-Do_not_show_this_box_again_for_this_import=Visa_inte_denna_ruta_igen_för_den_här_importen
+
Do_not_wrap_the_following_fields_when_saving=Radbryt_inte_följande_fält_vid_sparning
Do_not_write_the_following_fields_to_XMP_Metadata\:=Vill_du_skriva_följande_fält_till_XMP-metadata?
-Do_you_still_want_to_continue?=Vill_du_fortfarande_fortsätta`?
+
Do_you_want_JabRef_to_do_the_following_operations?=Vill_du_att_JabRef_ska_göra_följande?
-Do_you_want_to_import_these_as_new_entries_into_the_current_database?=Vill_du_importera_dessa_som_nya_poster_i_den_befintliga_databasen?
-Do_you_want_to_override_the_file_lock?=
-Do_you_want_to_recover_the_database_from_the_autosave_file?=Vill_du_återskapa_databasen_från_den_automatiska_sparningen?
-Do_you_want_to_resolve_duplicate_keys_now?=Vill_du_hantera_dubblerade_nycklar_nu?
-Does_nothing.=Gör_ingenting.
-Doing_a_cleanup_for_%0_entries...=Städar_upp_%0_poster
+
Donate_to_JabRef=Donera_till_JabRef
+
Down=Nedåt
+
Download=Ladda_ned
-Download_failed=Nedladdning_misslyckades
+
Download_file=Ladda_ned_fil
+
Downloading...=Laddar_ned...
Drop_%0=Släpp_%0
-Duplicate_BibTeX_key=Dubblerad_BibTeX-nyckel
+
+duplicate_removal=ta_bort_dubbletter
+
Duplicate_string_name=Dubblerat_strängnamn
+
Duplicates_found=Dubbletter_hittades
+
Dynamic_groups=Dynamiska_grupper
+
Dynamically_group_entries_by_a_free-form_search_expression=
+
Dynamically_group_entries_by_searching_a_field_for_a_keyword=
+
Each_line_must_be_on_the_following_form=Varje_rad_måste_vara_på_följande_form
+
Edit=Editera
-Edit_group_membership=Ändra_gruppmedlemskap
+
Edit_custom_export=Ändra_egen_exporterare
Edit_entry=Ändra_post
+Save_file=Spara_fil
Edit_file_type=Ändra_filtyp
+
Edit_group=Ändra_grupp
+
Edit_journal=Ändra_tidsskrift
+
Edit_preamble=Ändra_preamble
Edit_strings=Ändra_strängar
Editor_options=Editoralternativ
+
Empty_BibTeX_key=Tom_BibTeX-nyckel
-Enable_save_actions=Aktivera_automatiska_händelser_vid_sparning
-Enable_special_fields=Aktivera_specialfält
+
+Grouping_may_not_work_for_this_entry.=Grupper_kanske_inte_fungerar_för_denna_post.
+
+empty_database=tom_databas
Enable_word/name_autocompletion=Aktivera_automatisk_komplettering_av_ord/namn
-Enforce_legal_characters_in_BibTeX_keys=Framtvinga_giltiga_tecken_i_BibTeX-nycklar
-Ensure_that_the_bibliography_is_up-to-date=Se_till_att_bibliografin_är_uppdaterad
-Ensure_unique_keys_using_letters_(a,_b,_...)=Garantera_unika_nycklar_med_bokstäver_(a,_b,_...)
-Ensure_unique_keys_using_letters_(b,_c,_...)=Garantera_unika_nycklar_med_bokstäver_(b,_c,_...)
+
Enter_URL=Ange_URL
+
Enter_URL_to_download=Ange_URL_att_ladda_ned
-Entries_added_to_an_email=Poster_lades_till_ett_epostmeddelande
+
+entries=poster
+
Entries_cannot_be_manually_assigned_to_or_removed_from_this_group.=Poster_kan_inte_manuellt_tilldelas_eller_tas_bort_från_denna_grupp.
+
Entries_exported_to_clipboard=Poster_exporterades_till_urklipp
-Entry_editor,_next_entry=Posteditor,_nästa_post
-Entry_editor,_next_panel=Posteditor,_nästa_panel
-Entry_editor,_next_panel_2=Posteditor,_nästa_panel_2
-Entry_editor,_previous_entry=Posteditor,_föregående_post
-Entry_editor,_previous_panel=Posteditor,_föregående_panel
-Entry_editor,_previous_panel_2=Posteditor,_föregående_panel_2
-Entry_editor,_store_field=Posteditor,_spara_fält
+
+
+entry=post
+
Entry_editor=Posteditor
-Entry_editor_active_background_color=Bakgrundfärg_för_aktiv_post_i_posteditor
-Entry_editor_background_color=Bakgrundfärg_för_posteditor
-Entry_editor_font_color=Typsnittfärg_för_posteditor
-Entry_editor_invalid_field_color=Färg_för_ogiltiga_fält_i_posteditor
+
Entry_preview=Postvisning
+
Entry_table=Tabell
+
Entry_table_columns=Tabellkolumner
+
Entry_type=Posttyp
+
Entry_type_names_are_not_allowed_to_contain_white_space_or_the_following_characters=
-Entry_type_to_be_created\:=Posttyper_som_kommer_att_skapas\:
+
Entry_types=Posttyper
+
Error=Fel
-Error_creating_email=Fel_vid_skapande_av_epost
-Error_downloading_file_'%0'=Fel_när_filen_'%0'_skulle laddas_ned
Error_exporting_to_clipboard=Fel_vid_export_till_urklipp
-Error_message\:=Felmeddelande\:
+
Error_occurred_when_parsing_entry=Fel_vid_inläsning_av_post
-Error_opening_autosave_of_'%0'._Trying_to_load_'%0'_instead.=Kunde_inte_öppna_automatiskt_sparad_version_av_'%0'._Försöker_öppna_'%0'_istället.
+
Error_opening_file=Fel_vid_öppning_av_fil
-Error_opening_file_'%0'.=Fel_vid_öppning_av_fil_'%0'.
+
Error_setting_field=
-Error_while_fetching_from_%0=Fel_vid_hämtning_från_%0
Error_while_writing=Fel_vid_skrivning
Error_writing_to_%0_file(s).=Fel_vid_skrivning_till_%0_fil(er).
+
+
Exceptions=Undantag
+
Existing_file=Existerande_fil
-Expand_all=Expandera_alla
+
+'%0'_exists._Overwrite_file?='%0'_finns_redan._Skriv_över_filen?
+Overwrite_file?=Skriva_över_fil?
+
Expand_subtree=Expandera_delträd
-Expected_syntax_for_--fetch\='<name_of_fetcher>\:<query>'=
+
Export=Exportera
-Export_sorting=Sortering_vid_export
-Export_entries_in_their_original_order=Exportera_poster_i_den_ursprungliga_ordningen
-Export_entries_ordered_as_specified=Exportera_poster_enligt_inställningar
-Export_in_current_table_sort_order=Exportera_poster_enligt_nuvarande_sortering
+
Export_name=Exportnamn
+
Export_preferences=Exportera_inställningar
+
Export_preferences_to_file=Exportera_inställningar_till_fil
+
Export_properties=Exportera_egenskaper
-Export_sort_order=Soteringsordning_vid_export
+
Export_to_clipboard=Exportera_till_utklipp
-Export_with_selected_format=Exportera_med_valt_format
+
Exporting=Exporterar
Extension=Filändelse
+
External_changes=Externa_ändringar
+
External_file_links=Externa_fillänkar
+
External_files=Externa_filer
+
External_programs=Externa_program
+
External_viewer_called=Öppnar_i_externt_program
-Extra_information=Extrainformation
-Extra_information_(e.g._page_number)=Extrainformation_(t._ex._sidnummer)
+
Fetch=Hämta
-Fetching_Medline_by_id...=Hämta_från_Medline_med_id...
-Fetching_Medline_by_term...=Hämta_från_Medline_med_sökterm...
-Fetching_entries_from_Inspire=Hämtar_poster_från_Inspire
+
Field=Fält
-Field_is_missing=Fält_saknas
+
+field=fält
+
Field_name=Fältnamn
Field_names_are_not_allowed_to_contain_white_space_or_the_following_characters=
+
Field_to_filter=Fält_att_filtrera
+
Field_to_group_by=Fält_att_använda_för_gruppering
+
File=Fil
+
+file=fil
File_'%0'_is_already_open.=Filen_'%0'_är_redan_öppen.
+
File_'%0'_not_found=Filen_'%0'_hittades_inte
+
File_changed=Fil_ändrad
File_directory_is_'%0'\:=Filmapp_är_'%0'\:
+
File_directory_is_not_set_or_does_not_exist\!=Filmapp_är_inte_satt_eller_existerar_inte\!
File_exists=Filen_finns_redan
+
File_has_been_updated_externally._What_do_you_want_to_do?=Fil_har_ändrats_utanför_JabRef._Vad_vill_du_göra?
-File_is_locked_by_another_JabRef_instance.=Filen_är_låst_av_en_annan_JabRef-instans.
-File_list_editor,_move_entry_down=
-File_list_editor,_move_entry_up=
-File_locked=Filen_är_låst
-File_moved=Filen_flyttad
+
File_not_found=Hittar_ej_filen
-File_permission_error=Rättighetsfel_för_fil
-File_rename_failed_for_%0_entries.=Döpa_om_filen_misslyckades_för_%0_poster.
File_type=Filtyp
+
File_updated_externally=Filen_uppdaterad_utanför_JabRef
-Filename_format_pattern=Filnamnsmönster
+
+filename=filnamn
+
Files_opened=Filer_öppnade
-Filled=Fyllde
+
Filter=Filtrera
-Find_and_remove_duplicate_BibTeX_keys=Hitta_och_ta_bort_duplicerade_BibTeX-nycklar
-Find_unlinked_files=Hitta_olänkade_filer
+
Finished_automatically_setting_external_links.=
-Finished_downloading_full_text_document=Nedladdning_av_dokument_avslutad
-Finished_resolving_duplicate_BibTeX_keys._%0_entries_modified.=
+
Finished_synchronizing_file_links._Entries_changed\:_%0.=Synkronisering_av_fillänkar_avslutad._Ändrade_poster\:_%0.
Finished_writing_XMP-metadata._Wrote_to_%0_file(s).=Skrivning_av_XMP-metadata_avslutad._Skrev_till_%0_fil(er).
Finished_writing_XMP_for_%0_file_(%1_skipped,_%2_errors).=
-First_select_entries_to_clean_up.=Välj_först_de_poster_som_du_vill_städa_upp.
+
First_select_the_entries_you_want_keys_to_be_generated_for.=Välj_först_de_poster_du_vill_generera_nycklar_för.
+
Fit_table_horizontally_on_screen=
-Five_stars=Fem_stjärnor
+
Float=Visa_först
Float_marked_entries=Visa_märkta_poster_först
-Focus_entry_table=Fokusera_tabellen
-Follow_DOI_or_URL_link_and_try_to_locate_PDF_full_text_document=Följ_DOI_eller_URL_och_försök_hitta_en_PDF-version_av_dokumentet
-Font_selection=Typsnittsväljare
+
Font_family=Typsnittsfamilj
+
Font_preview=Typsnittsexempel
+
Font_size=Typsnittsstorlek
+
Font_style=Typsnittsstil
-Format_string=Formatsträng
+
+Font_selection=Typsnittsväljare
+
+for=för
+
Format_of_author_and_editor_names=Format_för_författar-_och_redaktörsnamn
-Format_units_by_adding_non-breaking_separators_and_keeping_the_correct_case_on_search=
+Format_string=Formatsträng
+
Format_used=Använt_format
Formatter_name=Formatnamn
-Formatter_not_found\:_%0=Hittade_ej_formatterare\:_%0
-Forward=Framåt
-Found_%0_results.=Hittade_%0_resultat.
-Found_more_than_one_OpenOffice/LibreOffice_executable.=Hittade_mer_än_ett_OpenOffice/LibreOffice-program.
-Four_stars=Fyra_stjärnor
-From_import=Från_import
+
+found_in_AUX_file=hittades_i_AUX-fil
+
Full_name=
+
General=Generellt
+
General_fields=Generella_fält
-General_file_directory=Generell_filmapp
-Full_text_document_download_failed=Gick_inte_att_ladda_ned_dokument.
+
Generate=Generera
+
Generate_BibTeX_key=Generera_BibTeX-nyckel
-Generate_groups_for_author_last_names=Generera_grupper_baserat_på_författarefternamn
-Generate_groups_for_editor_last_names=Generera_grupper_baserat_på_editorefternamn
-Generate_groups_from_keywords_in_a_BibTeX_field=Generera_grupper_baserat_på_nyckelord_i_ett_fält
+
Generate_keys=Generera_nycklar
+
Generate_keys_before_saving_(for_entries_without_a_key)=Generera_nycklar_innan_sparning_(för_poster_utan_nyckel)
Generate_keys_for_imported_entries=Generera_nycklar_för_importerade_poster
+
Generate_now=Generera_nu
+
Generated_BibTeX_key_for=Genererade_BibTeX-nycklar_för
+
Generating_BibTeX_key_for=Genererar_BibTeX-nycklar_för
-Get_BibTeX_entry_from_DiVA=Hämta_BibTeX-post_från_DIVA
+Get_fulltext=Hämta_dokument
Grab=
+
Gray_out_entries_not_in_group_selection=Skugga_poster_som_inte_är_med_i_en_grupp
+
Gray_out_non-hits=Skugga_icke-träffar
-Group_tree_could_not_be_parsed._If_you_save_the_BibTeX_database,_all_groups_will_be_lost.=Gruppträdet_kunde_inte_läsas_in._Om_du_sparar_din_databas_kommer_alla_grupper_att_förloras.
-Grouping_may_not_work_for_this_entry.=Grupper_kanske_inte_fungerar_för_denna_post.
+
Groups=Grupper
-HTML_list=HTML-lista
-HTML_table=HTML-tabell
-HTML_table_(with_Abstract_&_BibTeX)=HTML-tabell_(med_sammanfattning_och_BibTeX-post)
+
Have_you_chosen_the_correct_package_path?=Har_du_valt_rätt_sökväg_till_paketet?
+
Help=Hjälp
-Help_on_Name_Formatting=Hjälp_för_namnformattering
-Help_on_regular_expression_search=Hjälp_för_sökning_med_reguljära_uttryck
+
Help_on_groups=Hjälp_för_grupper
+
Help_on_key_patterns=Hjälp_för_nyckelmönster
-Help_on_special_fields=Hjälp_för_specialfält
-Hide/show_toolbar=Dölj/visa_verktygslist
+Help_on_regular_expression_search=Hjälp_för_sökning_med_reguljära_uttryck
+
Hide_non-hits=Dölj_icke-träffar
+
Hierarchical_context=Hierarkiskt_sammanhang
+
Highlight=Framhäv
Highlight_groups_matching_all_selected_entries=Framhäv_grupper_som_matchar_alla_valda_poster
Highlight_groups_matching_any_selected_entry=Framhäv_grupper_som_matchar_någon_vald_poster
-Highlight_groups_that_contain_entries_contained_in_any_currently_selected_group=Framhäv_grupper_som_innehåller_poster_från_någon_av_det_valda_grupperna
+Disable_highlight_groups_matching_entries=Avvaktivera_framhävandet_av_grupper_som_matchar_poster
+
Highlight_overlapping_groups=Framhäv_överlappande_grupper
+
Hint\:_To_search_specific_fields_only,_enter_for_example\:<p><tt>author\=smith_and_title\=electrical</tt>=Tips\:_För_att_söka_i_specifika_fält,_skriv_t.ex.\:<p><tt>author\=smith_and_title\=electrical</tt>
-Hostname=Värd
-How_would_you_like_to_link_to_'%0'?=Hur_vill_du_länka_till_'%0'?
-ISO_abbreviation=ISO-förkortning
+
+HTML_table=HTML-tabell
+HTML_table_(with_Abstract_&_BibTeX)=HTML-tabell_(med_sammanfattning_och_BibTeX-post)
Icon=Ikon
-If_a_pasted_or_imported_entry_already_has_the_field_set,_overwrite.=
-If_connecting_manually,_please_verify_program_and_library_paths.=Om_du_ansluter_manuellt,_kontrollera_sökvägar_till_program_och_bibliotek.
-If_possible,_normalize_this_list_of_names_to_conform_to_standard_BibTeX_name_formatting=
+
Ignore=Ignorera
-Ill-formed_entrytype_comment_in_BIB_file=
+
Immediate_subgroups=
+
Import=Importera
-ImportFormat_class=ImportFormat-klass
-Import_metadata_from_PDF=Importera_metadata_från_PDF
+
Import_and_keep_old_entry=Importera_och_behåll_gammal_post
+
Import_and_remove_old_entry=Importera_och_ta_bort_gammal_post
-Import_canceled_by_user=Import_avbröts_av_användare
-Import_conversions=Konverteringar_vid_import
+
Import_entries=Importera_poster
+
Import_failed=Importen_misslyckades
+
Import_file=Importera_fil
+
Import_group_definitions=Importera_gruppdefinitioner
-Import_into_current_database=Importera_till_nuvarande_databas
-Import_into_new_database=Importera_till_ny_databas
-Import_marking_color=Färg_för_importerade_poster
-Import_metadata_from\:=Importera_metadata_från\:
+
Import_name=Importnamn
+
Import_preferences=Importera_inställningar
+
Import_preferences_from_file=Importera_inställningar_från_fil
+
Import_strings=Importera_strängar
+
Import_to_open_tab=Importera_till_öppen_flik
-Import_word_selector_definitions=
+
Imported_entries=Importerade_poster
+
Imported_from_database=Importerade_från_databas
+
+Importer_class=Importer-klass
+
Importing=Importerar
+
Importing_in_unknown_format=Importerar_i_okänt_format
-Importing_into_Database...=Importerar_till_databas...
+
Include_abstracts=Inkludera_sammanfattning
Include_entries=Inkludera_poster
+
Include_subgroups\:_When_selected,_view_entries_contained_in_this_group_or_its_subgroups=
-Increase_table_font_size=Öka_typsnittsstorlek_för_tabellen
+
Independent_group\:_When_selected,_view_only_this_group's_entries=
+
Initially_show_groups_tree_expanded=Visa_gruppträdet_expanderat_från_början
-Input_error=Inmatningsfel
+
+Work_options=
+
Insert=Infoga
-Insert_a_citation_without_text_(the_entry_will_appear_in_the_reference_list)=Infoga_en_citering_utan_text_(posten_kommer_visas_i_referenslistan)
-Insert_empty_citation=Infoga_tom_citering
Insert_rows=Infoga_rader
+
Intersection=Snitt
+
Invalid_BibTeX_key=Ogiltig_BibTeX-nyckel
-Invalid_DOI\:_'%0'.=Ogiltig_DOI\:_'%0'.
-Invalid_URL=Ogiltig_URL
+
Invalid_date_format=Ogiltigt_datumformat
-Invalid_setting=Ogiltig_inställning
+
+Invalid_URL=Ogiltig_URL
+
Inverted=Omvänd
+
+ISO_abbreviation=ISO-förkortning
+
Online_help=Onlinehjälp
-JabRef_includes_a_built-in_list_of_journal_abbreviations.=JabRef_har_en_inbyggd_lista_med_tidskriftsförkortningar
-JabRef_no_longer_supports_'ps'_or_'pdf'_fields.<br>File_links_are_now_stored_in_the_'file'_field_and_files_are_stored_in_an_external_file_directory.<br>To_make_use_of_this_feature,_JabRef_needs_to_upgrade_file_links.<br><br>=
+
JabRef_preferences=Inställningar_för_JabRef
+
Journal_abbreviations=Tidskriftsförkortningar
+
Journal_list_preview=Förhandsvisning_av_tidskriftsförkortningar
+
Journal_name=Tidskriftsnamn
-Journals=Tidskrifter
+
Keep=Behåll
+
Keep_both=Behåll_bägge
-Keep_left=Behåll_vänstra
-Keep_merged_entry_only=Behåll_bara_sammanslagen_post
-Keep_right=Behåll_högra
+
Key_bindings=Tangentbordsbindningar
+
Key_bindings_changed=Tangentbordsbindningar_ändrades
+
Key_generator_settings=Nyckelgeneratorinställningar
+
Key_pattern=Nyckelmönster
+
+keys_in_database=nycklar_i_databas
+
Keyword=Nyckelord
-Keywords_of_selected_entries=Nyckelord_för_valda_poster
-LaTeX_AUX_file=LaTeX_AUX-fil
+
Label=
+
Language=Språk
+
Last_modified=Senast_ändrad
+
+LaTeX_AUX_file=LaTeX_AUX-fil
Leave_file_in_its_current_directory=Lämna_filen_i_nuvarande_mapp
-Leave_this_dialog.=Lämna_denna_dialog.
+
Left=Vänster
Level=Nivå
-Left_entry=Vänster_post
+
Limit_to_fields=Begränsa_till_fält
+
Limit_to_selected_entries=Begränsa_till_valda_poster
-Line_%0\:_Found_corrupted_BibTeX_key.=Rad_%0\:_Hittade_felaktig_BibTeX-nyckel.
-Line_%0\:_Found_corrupted_BibTeX_key_(comma_missing).=Rad_%0\:_Hittade_felaktig_BibTeX-nyckel_(kommatecken_saknas).
-Line_%0\:_Found_corrupted_BibTeX_key_(contains_whitespaces).=
+
Link=Länk
Link_local_file=Länka_till_lokal_fil
Link_to_file_%0=Länka_till_fil_%0
+
Listen_for_remote_operation_on_port=Lyssna_efter_fjärrstyrning_på_port
Load_and_Save_preferences_from/to_jabref.xml_on_start-up_(memory_stick_mode)=
-Log=Logg
+
Look_and_feel='Look-and-feel'
-Look_up_BibTeX_entries_in_all_open_databases=Leta_efter_BibTeX-poster_i_alla_öppna_databaser
-Look_up_BibTeX_entries_in_the_active_tab_only=Leta_bara_efter_BibTeX-poster_i_aktiv_flik
-Looking_for_full_text_document...=Letar_efter_dokument...
-MIME_type=MIME-typ
Main_file_directory=Huvudmapp_för_filer
+
Main_layout_file=Huvudfil_för_layout
-Make_paths_of_linked_files_relative_(if_possible)=Gör_sökvägen_till_länkade_filer_relativ_(om_möjligt)
-Make_sure_you_have_installed_OpenOffice/LibreOffice_with_Java_support.=Kontrollera_att_du_har_installerat_OpenOffice/LibreOffice_med_Java-stöd.
-Manage=Hantera
-Manage_citations=Hantera_citeringar
-Manage_content_selectors=Hantera_innehållsväljare
+
Manage_custom_exports=Hantera_egna_exporterare
+
Manage_custom_imports=Hantera_egna_importerare
Manage_external_file_types=Hantera_externa_filetyper
+
Manage_journal_abbreviations=Hantera_tidskriftsförkortningar
-Manage_keywords=Hantera_nyckelord
-Manual_connect=Anslut_manuellt
+
Mark_entries=Markera_poster
-Mark_entries_imported_into_an_existing_database=Markera_poster_som_importeras_till_en_befintlig_databas
+
Mark_entry=Markera_post
+
Mark_new_entries_with_addition_date=Märk_nya_poster_med_datum_de_lades_till
+
Mark_new_entries_with_owner_name=Märk_nya_poster_med_ägarnamn
-Marked_all_%0_selected_entries=Markerade_alla_%0_valda_poster
-Marked_selected_entry=Markerade_vald_post
-Marking_color_%0=Markeringsfärg_%0
+
Memory_stick_mode=
+
Menu_and_label_font_size=
-Merge_citations=Slå_ihop_citeringar
-Merge_entries=Kombinera_poster
-Merged_BibTeX_source_code=Kombinerad_BibTeX-källkod
-Merged_entries=Kombinerade_poster
-Merged_entry=Kombinerad_post
+
Merged_external_changes=
+
Messages=Meddelanden
-Metadata_change=Ändring_i_metadata
+
Modification_of_field=Ändring_i_fält
-Modified_entry=Ändrad_post
+
Modified_group_"%0".=Modifierade_grupp_"%0".
+
Modified_groups=Modifierade_grupper
-Modified_groups_tree=Modifierade_gruppträd
+
Modified_string=Ändrad_sträng
+
Modify=Ändra
-Move/Rename_file=Flytta/Döp om fil
+
+modify_group=ändra_grupp
+
Move=Flytta
-Move_DOIs_from_note_and_URL_field_to_DOI_field_and_remove_http_prefix=Flytta_DOIs_från_'note'-_och_'URL'-fälten_till_'DOI'-fältet_samt_ta_bort_http-prefix
-Move_contents_of_a_field_into_a_field_with_a_different_name=Flytta_innehållet_i_ett_fält_till_ett_fält_med_ett_annat_namn
+
Move_down=Flytta_nedåt
+
Move_entries_in_group_selection_to_the_top=
Move_external_links_to_'file'_field=Flytta_externa_länkar_till_'file'-fältet
-Move_file_failed=Gick_inte_att_flytta_fil
-Move_file_to_file_directory=Flytta_fil_till_filmapp
-Move_file_to_file_directory?=Flytta_fil_till_filmapp?
-Move_the_keyboard_focus_to_the_entry_table=Flytta_tangentbordsfokus_till_tabellen
-Move_to_group=Flytta_till_grupp
+
+move_group=flytta_grupp
+
Move_up=Flytta_uppåt
+
Moved_group_"%0".=Flyttade_grupp_"%0"
-Multiple_entries_selected._Do_you_want_to_change_the_type_of_all_these_to_'%0'?=Flera_poster_valda._Vill_du_ändra_typen_för_alla_dessa_till_'%0'?
+
Name=Namn
-Name_format_used_for_autocompletion=Namnformat_för_automatisk_komplettering
Name_formatter=Namnformattering
+
Natbib_style=Natbib-stil
-Network=Nätverk
+
+nested_AUX_files=nästlade_AUX-filer
+
New=Ny
-New_%0_database=Ny_%0-databas
-New_%0_database_created.=Ny_%0-databas_skapades.
+
+new=ny
+
New_BibTeX_entry=Ny_BibTeX-post
+
New_BibTeX_subdatabase=
-New_article=Ny_article-post
-New_book=Ny_book-post
+
New_content=
+
New_database_created.=Skapade_ny_databas.
-New_entry=Ny_post
+New_%0_database=Ny_%0-databas
New_field_value=Nytt_fältvärde
+
New_file=Ny_fil
New_file_link_(INSERT)=Ny_fillänk_(INFOGA)
-New_from_plain_text=Ny_från_text
+
New_group=Ny_grupp
-New_inbook=Ny_inbook-post
-New_mastersthesis=Ny_mastersthesis-post
-New_phdthesis=Ny_phdthesis-post
-New_proceedings=Ny_proceedings-post
+
New_string=Ny_sträng
-New_unpublished=Ny_unpublished-post
-Newline_separator=Radbrytningstecken
+
Next_entry=Nästa_post
-Next_tab=Nästa_flik
-No_GUI._Only_process_command_line_options.=
-No_internet_connection.=Ingen_kontakt_med_internet.
-No_PDF_linked=Ingen_PDF_är_länkad
+
No_actual_changes_found.=
+
+no_base-BibTeX-file_specified=
+
+no_database_generated=ingen_databas_genererades
+
No_entries_found._Please_make_sure_you_are_using_the_correct_import_filter.=
+
+
No_entries_found_for_the_search_string_'%0'=Inga_poster_hittades_för_söksträngen_'%0'
+
No_entries_imported.=Inga_poster_importerades.
-No_entry_found_for_ISBN_%0_at_www.ebook.de=Ingen_post_hittades_för_ISBN_%0_på_www.ebook.de
-No_entry_needed_a_clean_up=Ingen_post_behövde_städas_upp
+
No_exceptions_have_occurred.=Inga_undantag_har_inträffat.
No_files_found.=Inga_filer_hittades.
-No_information_added=Ingen_information_tillagd
+
+No_GUI._Only_process_command_line_options.=
+
No_journal_names_could_be_abbreviated.=Inga_tidskriftsnamn_kunde_förkortas.
+
No_journal_names_could_be_unabbreviated.=Inga_tidskriftsnamn_kunde_expanderas.
-No_meta_data_present_in_BIB_file._Cannot_regenerate_BibTeX_keys=
-No_priority_information=Ingen_prioritetsinformation
-No_problems_found.=Inga_problem_hittades.
-No_rank_information=Ingen_rankinginformation
-No_read_status_information=Ingen_information_om_lässtatus
-No_references_found=Inga_referenser_hittades
-No_results_found.=Inga_resultat_hittades.
-No_search_matches.=Sökningen_matchade_inget.
+No_PDF_linked=Ingen_PDF_är_länkad
+
No_URL_defined=Ingen_URL_angiven
-No_valid_style_file_defined=Ingen_giltig_stilfil_definierad
-None=
-None_of_the_selected_entries_have_BibTeX_keys.=Ingen_av_de_valda_posterna_har_någon_BibTeX-nyckel.
-Normal_search_active.=Normal_sökning_aktiv.
-Normalize_to_BibTeX_name_format=
-Not_connected_to_any_Writer_document._Please_make_sure_a_document_is_open,_and_use_the_'Select_Writer_document'_button_to_connect_to_it.=
-Not_overwriting_existing_key._To_change_this_setting,_open_Options_->_Prefererences_->_BibTeX_key_generator=
-Note\:_A_full_text_search_is_currently_not_supported_for_%0=
-Note_that_you_must_specify_the_fully_qualified_class_name_for_the_look_and_feel,=
+not=inte
+
+not_found=hittades_inte
+
+Note_that_you_must_specify_the_fully_qualified_class_name_for_the_look_and_feel,=
+
Nothing_to_redo=Inget_att_göra_om.
+
Nothing_to_undo=Inget_att_ångra.
-Number_of_entries_successfully_imported=Antal_poster_som_lyckades_importeras
-Number_of_references_to_fetch?=Antal_referenser_som_ska_hämtas?
+
+occurrences=förekomster
+
OK=OK
-Old_entry=Gammal_post
-One_entry_needed_a_clean_up=En_post_behövde_städas_upp
One_or_more_file_links_are_of_the_type_'%0',_which_is_undefined._What_do_you_want_to_do?=
+
One_or_more_keys_will_be_overwritten._Continue?=En_eller_flera_BibTeX-nycklar_kommer_skrivas_över._Fortsätt?
-One_star=En_stjärna
-Only_attach_PDF=Lägg_bara_till_PDF
+
Open=Öppna
-OpenDocument_presentation=OpenDocument-presentation
-OpenDocument_spreadsheet=OpenDocument-kalkylark
-OpenDocument_text=OpenDocument-text
-OpenOffice/LibreOffice_connection=OpenOffice/LibreOffice-anslutning
-Open_%0_file=Öppna_%0-fil
+
Open_BibTeX_database=Öppna_BibTeX-databas
-Open_URL_or_DOI=Öppna_URL_eller_DOI
+
Open_database=Öppna_databas
+
Open_editor_when_a_new_entry_is_created=Öppna_posteditorn_när_en_ny_post_skapats
+
Open_file=Öppna_fil
-Open_folder=Öppna_mapp
+
Open_last_edited_databases_at_startup=Öppna_senast_använda_databaser_vid_uppstart
-Open_shared_database=Öppna_delad_databas
+
+Connect_to_shared_database=Öppna_delad_databas
+
Open_terminal_here=Öppna_skalfönster_här
+
+Open_URL_or_DOI=Öppna_URL_eller_DOI
+
Opened_database=Öppnade_databas
+
Opening=Öppnar
+
Opening_preferences...=Öppnar_inställningar...
-Opens_JabRef's_GitHub_page=Öppnar_JabRefs_GitHub-sida
-Opens_the_file_browser.=Öppnar_filbläddraren
+
Operation_canceled.=Operationen_avbruten.
Operation_not_supported=Operationen_stöds_ej
+
Optional_fields=Valfria_fält
-Optional_fields_2=Valfria_fält_2
+
Options=Alternativ
-Original_entry=Ursprunglig_post
-Other_fields=Andra_fält
+
+or=eller
+
Output=
-Output_file_missing=
+
Output_or_export_file=
+
Override=Ignorera
+
Override_default_file_directories=Ignorerar_normala_filmappar
+
Override_default_font_settings=Ignorera_normala_typsnittsinställningar
+
Override_the_BibTeX_field_by_the_selected_text=
+
+
Overwrite=Skriv_över
Overwrite_existing_field_values=Skriv_över_befintligt_fältinnehåll
-Overwrite_file?=Skriva_över_fil?
-Overwrite_key=Skriv_över_nyckel
+
Overwrite_keys=Skriv_över_nycklar
-PDF_does_not_exist=PDF_finns_inte
-Parse=
-Parse_with_FreeCite=
-Parsing_error=
+
+pairs_processed=par_processade
Password=Lösenord
+
Paste=Klistra_in
+
+paste_entries=klistra_in_poster
+
+paste_entry=klistra_in_post
Paste_from_clipboard=Klistra_in_från_urklipp
+
Pasted=Klistrade_in
-Path_to_%0=Sökväg_till_%0
+
Path_to_%0_not_defined=Sökväg_till_%0_är_inte_angiven
+
Path_to_LyX_pipe=Sökväg_till_LyX-pipe
-Path_to_OpenOffice/LibreOffice_directory=Sökväg_till_OpenOffice/LibreOffice-mapp
-Path_to_OpenOffice/LibreOffice_executable=Sökväg_till_OpenOffice/LibreOffice-program
-Path_to_OpenOffice/LibreOffice_library_dir=
+
+PDF_does_not_exist=PDF_finns_inte
+
Personal_journal_list=Personlig_tidskriftslista
+
Plain_text_import=
-Please_choose_which_one_to_connect_to\:=Välj_det_du_vill_ansluta_till\:
-Please_enter_a_comma_separated_list_of_Medline_IDs_(numbers)_or_search_terms.=
+
Please_enter_a_name_for_the_group.=Ange_ett_namn_för_gruppen.
-Please_enter_a_search_string=Ange_en_söksträng
+
Please_enter_a_search_term._For_example,_to_search_all_fields_for_<b>Smith</b>,_enter\:<p><tt>smith</tt><p>To_search_the_field_<b>Author</b>_for_<b>Smith</b>_and_the_field_<b>Title</b>_for_<b>electrical</b>,_enter\:<p><tt>author\=smith_and_title\=electrical</tt>=
-Please_enter_a_valid_number=Ange_ett_giltigt_tal
+
Please_enter_the_field_to_search_(e.g._<b>keywords</b>)_and_the_keyword_to_search_it_for_(e.g._<b>electrical</b>).=Ange_fält_att_söka_i_(t._ex._<b>keywords</b>)_och_termen_att_söka_efter_i_det_(t._ex._<b>electrical</b>).
+
Please_enter_the_string's_label=Ange_namnet_på_strängen
-Please_move_the_file_manually_and_link_in_place.=
-Please_open_or_start_a_new_database_before_searching=Öppna_eller_skapa_en_ny_databas_innan_sökning.
+
Please_select_an_importer.=
+
Please_select_exactly_one_group_to_move.=Välj_exakt_en_grupp_att_flytta.
-Please_specify_both_hostname_and_port=Ange_både_värdnamn_och_port
-Please_specify_both_username_and_password=Ange_både_användarnamn_och_lösenord
-Please_wait...=Vänta...
+
Possible_duplicate_entries=Möjliga_dubbletter
+
Possible_duplicate_of_existing_entry._Click_to_resolve.=Möjlig_dubblett_av_befintlig_post._Klicka_för_att_reda_ut.
+
Preamble=Preamble
-Preamble_editor,_store_changes=Preamble-editorn,_spara_ändringar
+
Preferences=Inställningar
+
Preferences_recorded.=Inställningar_sparade.
+
Preview=Postvisning
+Citation_Style=
+Current_Preview=
+Cannot_generate_preview_based_on_selected_citation_style.=
+Bad_character_inside_entry=
+Error_while_generating_citation_style=
+Preview_style_changed_to\:_%0=
+Next_preview_layout=
+Previous_preview_layout=
+
Previous_entry=Föregående_post
-Previous_tab=Föregående_flik
+
Primary_sort_criterion=Första_sorteringskriteriet
-Print_entry_preview=Skriv_ut_postvisning
-Printed=Utskriven
-Priority=Prioritet
-Priority_high=Hög_prioritet
-Priority_low=Låg_prioritet
-Priority_medium=Medel_prioritet
-Problem_modifying_citation=Problem_att_modifiera_citering
Problem_with_parsing_entry=Problem_att_tolka_post
Processing_%0=Behandlar_%0
Program_output=
-Progress\:_%0_of_%1=Händelseförlopp\:_%0_av_%1
-Prompt_before_recovering_a_database_from_an_autosave_file=Meddela_innan_en_databas_återskapas_från_en_automatiskt_sparad_fil
Pull_changes_from_shared_database=Hämta_ändringar_från_delad_databas
-Protected_database=Skyddad_databas
-Proxy_requires_authentication=Proxyn_kräver_autentisering
-Push_to_%0=Infoga_i_%0
-Push_to_application=Infoga_i_program
+
Pushed_citations_to_%0=Infogade_citeringar_i_%0
-Quality=Kvalitet
-Query_'%0'_with_fetcher_'%1'_did_not_return_any_results.=
+
Quit_JabRef=Avsluta_JabRef
+
Quit_synchronization=Avsluta_synkronisering
-Rank=Ranking
+
Raw_source=Rå_källkod
-Read_status=Lässtatus
-Read_status_read=Läst
-Read_status_skimmed=Skummat
-Really_delete_the_%0_selected_entries?=Verkligen_ta_bort_de_%0_valda_posterna?
-Really_delete_the_selected_entry?=Verkligen_ta_bort_den_valda_posten?
+
Rearrange_tabs_alphabetically_by_title=Sortera_flikar_i_alfabetisk_ordning
-Rebind_C-a,_too=
-Rebind_C-f,_too=
-Recover_from_autosave=Återskapa_från_automatiskt_sparad_fil
+
Redo=Gör_igen
+
Reference_database=Referensdatabas
-References=Referenser
-References_found=Referenser_hittade
+
+%0_references_found._Number_of_references_to_fetch?=Referenser_hittade\:_%0._Antal_referenser_som_ska_hämtas?
+
Refine_supergroup\:_When_selected,_view_entries_contained_in_both_this_group_and_its_supergroup=
-Refresh_OpenOffice/LibreOffice=Uppdatera_OpenOffice/LibreOffice
-Refuse_to_save_the_database_before_external_changes_have_been_reviewed.=Vägra_att_spara_databasen_innan_externa_ändringar_har_kontrollerats.
-Regenerate_all_keys_for_the_entries_in_a_BibTeX_file=Generera_BibTeX-nycklar_för_alla_poster_i_en_BibTeX-fil
-Regenerating_BibTeX_keys_according_to_metadata=Generera_BibTeX-nycklar_enligt_metadata
-Relevance=Relevans
+
+regular_expression=reguljärt_uttryck
+
Remember_these_entry_types?=Kom_ihåg_dessa_posttyper?
+
Remote_operation=Fjärrstyrning
+
Remote_server_port=Port_på_fjärrserver
+
Remove=Ta_bort
-Remove_selected=Ta_bort_valda
-Remove_all_broken_links=Ta_bort_alla_trasiga_länkar
+
+Remove_subgroups=Ta_bort_undergrupper
+
Remove_all_subgroups_of_"%0"?=Ta_bort_alla_undergrupper_till_"%0"?
+
Remove_entry_from_import=Ta_bort_post_från_import
+
Remove_entry_selection_from_this_group=Ta_bort_valda_poster_från_denna_grupp
+
Remove_entry_type=Ta_bort_posttyp
Remove_file_link_(DELETE)=Ta_bort_fillänk_(RADERA)
+
Remove_from_group=Ta_bort_från_grupp
-Remove_group,_keep_subgroups=Ta_bort_grupp,_behåll_undergrupper
+
Remove_group=Ta_bort_grupp
+
+Remove_group,_keep_subgroups=Ta_bort_grupp,_behåll_undergrupper
+
Remove_group_"%0"?=Ta_bort_gruppen_"%0"?
+
Remove_group_"%0"_and_its_subgroups?=Ta_bort_gruppen_"%0"_och_dess_undergrupper?
+
+remove_group_(keep_subgroups)=ta_bort_grupp_(behåll_undergrupper)
+
+remove_group_and_subgroups=ta_bort_grupp_och_undergrupper
+
Remove_group_and_subgroups=Ta_bort_grupp_och_dess_undergrupper
+
Remove_link=Ta_bort_länk
+
Remove_old_entry=Ta_bort_gammal_post
+
Remove_selected_strings=Ta_bort_valda_strängar
-Remove_subgroups=Ta_bort_undergrupper
-Removed_all_groups=Tog_bort_alla_grupper
-Removed_all_subgroups_of_group_"%0".=Tog_bort_alla_undergrupper_för_gruppen_"%0".
+
Removed_group_"%0".=Tog_bort_gruppen_"%0".
+
Removed_group_"%0"_and_its_subgroups.=Tog_bort_gruppen_"%0"_och_dess_undergrupper.
+
Removed_string=Tog_bort_sträng
-Rename_PDFs_to_given_filename_format_pattern=
-Rename_field=Byt_namn_på_fält
-Rename_field_to=Byt_namn_på_fält_till
-Rename_file_to=Byt_namn_på_fil_till
-Rename_only_PDFs_having_a_relative_path=
-Rename_to_'%0'=Byt_namn_till_'%0'
+
Renamed_string=Bytte_namn_på_sträng
+
Replace_(regular_expression)=Ersätt_(reguljärt_uttryck)
-Replace_original_entry=Ersätt_ursprunglig_post
+
Replace_string=Ersätt_sträng
+
Replace_with=Ersätt_med
+
Replaced=Ersatte
+
Required_fields=Obligatoriska_fält
-Reset=Återställ
+
Reset_all=Återställ_alla
-Reset_preferences=Återställ_inställningar
-Reset_preferences_(key1,key2,..._or_'all')=Återställ_inställningar_(nyckel1,nyckel2,..._eller_'all')
-Resetting_all_key_bindings=Återställer_alla_tangentbordsbindningar
-Resetting_preference_key_'%0'=Återställer_inställningsvärde_'%0'
-Resolve_duplicate_BibTeX_keys=Hantera_BibTeX-nyckeldubbletter
+
Resolve_strings_for_all_fields_except=Ersätt_strängar_för_alla_fält_utom
Resolve_strings_for_standard_BibTeX_fields_only=Ersätt_bara_strängar_för_de_vanliga_BibTeX-fälten
-Resolving_duplicate_BibTeX_keys...=
-Result=Resultat
-Return_to_JabRef=Återgå_till_JabRef
+
+resolved=
+
Revert_to_original_source=
+
Review=
+
Review_changes=Kontrollera_ändringar
+
Right=Höger
-Right_entry=Höger_post
-Run_fetcher,_e.g._"--fetch\=Medline\:cancer"=
-Run_field_formatter\:=
-Running_query_'%0'_with_fetcher_'%1'.=
+
Save=Spara
-Save_actions=Händelser_vid_sparning
-Save_all=Spara_alla
Save_all_finished.=Alla_har_sparats.
+
Save_all_open_databases=Spara_alla_öppna_databaser
+
Save_before_closing=Spara_innan_stängning
-Save_changes=Spara_ändringar
+
Save_database=Spara_databas
Save_database_as...=Spara_databas_som_...
+
Save_entries_in_their_original_order=Spara_poster_i_ursprunglig_ordning
-Save_entries_ordered_as_specified=Spara_poster_som_angivet
+
Save_failed=Sparningen_misslyckades
+
Save_failed_during_backup_creation=Sparningen_misslyckades_när_säkerhetskopian_skulle_skapas
-Save_failed_while_committing_changes\:_%0=
-Save_file=Spara_fil
+
Save_selected_as...=Spara_valda_som_...
-Save_selected_as_plain_BibTeX...=Spara_valda_som_enkel_BibTeX...
-Save_sort_order=
-Save_without_backup?=Spara_utan_att_göra_backup?
+
Saved_database=Sparade_databas
+
Saved_selected_to_'%0'.=Sparade_valda_till_'%0'.
+
Saving=Sparar
Saving_all_databases...=Sparar_alla_databaser...
+
Saving_database=Sparar_databas
-Scan_directory=Sök_igenom_mapp
+
Search=Sök
-Search_%0=Sök_%0
+
Search_expression=Sökuttryck
-Search_failed\:_illegal_search_expression=Sökning_misslyckades\:_ogiltigt_sökuttryck
+
Search_for=Sök_efter
-Search_globally=Sök_globalt
-Search_in_all_open_databases=Sök_i_alla_öppna_databaser
-Search_results_in_all_databases_for_%0=Söker_efter_%0_i_alla_databaser
-Search_results_in_database_%0_for_%1=Söker_efter_%1_i_databasen_%0
-Searches_for_unlinked_PDF_files_on_the_file_system=Letar_efter_olänkade_PDF-filer_på_filsystemet
-Searches_the_selected_directory_for_unlinked_files.=Söker_i_den_valda_mappen_efter_filer_som_ej_är_länkade_i_databasen
-Searching...=Söker...
-Searching_file_system...=Söker_på_filsystemet...
+
Searching_for_duplicates...=Söker_efter_dubbletter...
+
Searching_for_files=Söker_efter_filer
+
Secondary_sort_criterion=Andra_sorteringskriteriet
+
Select=Välj
-Select_Writer_document=Välj_Writer-dokument
-Select_a_directory_where_the_search_shall_start.=Välj_en_mapp_där_sökningen_ska_börja.
+
+
Select_all=Välj_alla
-Select_at_least_one_entry_to_manage_keywords.=Välj_åtminstone_en_post_för_att_hantera_nyckelord.
-Select_directory=Välj_mapp
-Select_document=Välj_dokument
+
Select_encoding=Välj_teckenkodning
+
Select_entry_type=Välj_posttyp
-Select_export_format=
Select_external_application=Välj_program
+
Select_file_from_ZIP-archive=Välj_fil_från_ZIP-arkiv
-Select_file_type\:=Välj_filtyp\:
-Select_files=Välj_filer
-Select_style=Välj_stil
+
Select_the_tree_nodes_to_view_and_accept_or_reject_changes=
-Select_which_open_Writer_document_to_work_on=Välj_vilket_öppet_Writer-dokument_som_ska_användas
Selected_entries=Valda_poster
-Send_as_email=Skicka_som_epost
-Sending_of_emails=Skicka_epost
-Set_connection_parameters=Sätt_anslutningsinställningar
-Set/clear/rename_fields=Sätt/rensa/byt_namn_på_fält
Set_field=Sätt_fält
Set_fields=Sätt_fält
+
Set_general_fields=Sätt_generella_fält
Set_main_external_file_directory=Välj_huvudmapp_för_filer
-Set_priority_to_high=Sätt_prioritet_till_hög
-Set_priority_to_low=Sätt_prioritet_till_låg
-Set_priority_to_medium=Sätt_prioritet_till_medel
-Set_read_status_to_read=Sätt_lässtatus_till_läst
-Set_read_status_to_skimmed=Sätt_lässtatus_till_skummat
+
Set_table_font=Sätt_tabelltypsnitt
-Setting_all_preferences_to_default_values.=Återställer_alla_inställningar_till_standardvärden
+
Settings=Alternativ
-Settings_for_%0=Alternativ_för_%0
+
Shortcut=Genväg
-Show/edit_BibTeX_source=Visa/ändra_BibTeX-källkod
+
+Show/edit_%0_source=Visa/Ändra_%0-källkod
+
Show_'Firstname_Lastname'=Visa_som_'Förnamn_Efternamn'
+
Show_'Lastname,_Firstname'=Visa_som_'Efternamn,_Förnamn'
-Show_ArXiv_column=Visa_ArXiv-kolumn
+
Show_BibTeX_source_by_default=Visa_BibTeX-källkod_som_standard
-Show_DOI_first=Visa_DOI_först
-Show_extra_columns=Visa_extrakolumner
-Show_URL/DOI_column=Visa_URL/DOI-kolumn
-Show_URL_first=Visa_URL_först
+
Show_confirmation_dialog_when_deleting_entries=Visa_bekräftelseruta_när_poster_raderas
-Show_debug_level_messages=Visa_fler_felmeddelanden_för_avlusning
-Show_deprecated_BibTeX_fields=
+
Show_description=Visa_beskrivning
+
Show_dynamic_groups_in_<i>italics</i>=Visa_dynamiska_grupper_<i>kursivt</i>
+
Show_entries_<b>not</b>_in_group_selection=Visa_poster_som_<b>inte</b>_är_i_vald_grupp
+
Show_file_column=Visa_filkolumn
-Show_gridlines=Visa_rutnät
+
Show_icons_for_groups=Visa_ikoner_för_grupper
Show_last_names_only=Visa_bara_efternamn
+
Show_names_unchanged=Visa_namnen_som_de_är
-Show_number_of_elements_contained_in_each_group=Visa_antal_poster_i_varje_grupp
-Show_only_preferences_deviating_from_their_default_value=Visa_bara_inställningar_som_skiljer_från_sitt_standardvärde
+
Show_optional_fields=Visa_valfria_fält
-Show_preferences=Visa_inställningar
-Show_printed_status=Visa_utskriftsstatus
-Show_priority=Visa_prioritet
-Show_quality=Visa_kvalitet
-Show_rank=Visa_ranking
-Show_read_status=Visa_lässtatus
-Show_relevance=Visa_relevans
-Show_remaining_fields=Visa_kvarvarande_fält
+
Show_required_fields=Visa_obligatoriska_fält
-Show_search_results_in_a_window=Visa_sökresultaten_i_ett_fönster
+
+Show_URL/DOI_column=Visa_URL/DOI-kolumn
+
Simple_HTML=Enkel_HTML
+
Size=Storlek
+
Skipped_-_No_PDF_linked=Hoppade_över_-_Ingen_PDF_länkad
Skipped_-_PDF_does_not_exist=Hoppade_över_-_PDF_fanns_ej
+
Skipped_entry.=Hoppade_över_post.
+
Sort_alphabetically=Sortera_i_bokstavsordning
-Sort_the_following_fields_as_numeric_fields=Sortera_följande_fält_som_tal
+
+sort_subgroups=sortera_undergrupper
+
Sorted_all_subgroups_recursively.=Sorterade_alla_undergrupper_rekursivt.
+
Sorted_immediate_subgroups.=
+
+source_edit=ändring_av_källkod
Special_name_formatters=Speciella_format_för_namn
+
Special_table_columns=Speciella_kolumner
+
Starting_import=Börjar_importera
-Starts_the_import_of_BibTeX_entries.=Börjar_importen_av_BibTeX-poster.
+
Statically_group_entries_by_manual_assignment=
+
Status=Status
+
Stop=Stanna
+
Store_journal_abbreviations=Spara_tidskriftsförkortningar
+
Stored_entry=Sparade_post
-String_dialog,_add_string=Strängdialog,_lägg_till_sträng
-String_dialog,_remove_string=Strängdialog,_ta_bort_sträng
+
Strings=Strängar
+
Strings_for_database=Strängar_för_databasen
-Style_selection=Stilval
+
Subdatabase_from_AUX=Databas_baserad_på_AUX-fil
-Subject_for_sending_an_email_with_references=Ämne_för_epost_med_referenser
-Switch_preview_layout=Byt_postvisningsstil
+
Switches_between_full_and_abbreviated_journal_name_if_the_journal_name_is_known.=Växlar_mellan_fullt_och_förkortat_tidskiftsnamn_om_tidskriften_är_känd.
-Sync_OpenOffice/LibreOffice_bibliography=Synka_OpenOffic/LibreOffice-bibliografi
+
Synchronize_file_links=Synkronisera_fillänkar
-Synchronize_files=Synkronisera_filer
-Synchronize_with_keywords=Synkronisera_med_nyckelord
-Synchronized_special_fields_based_on_keywords=Synkronisera_specialfält_med_hjälp_av_nyckelord
+
Synchronizing_file_links...=Synkroniserar_fillänkar...
-Table_and_entry_editor_colors=Färger_för_tabell_och_posteditor
+
Table_appearance=Tabellutseende
+
Table_background_color=Bakgrundsfärg_för_tabellen
-Table_font_size_is_%0=Typsnittstorlek_för_tabellen_är_%0
+
Table_grid_color=Rutnätsfärg_för_tabellen
-Table_row_height_padding=Extra_höjd_på_tabellrader
+
Table_text_color=Textfärg_för_tabellen
+
Tabname=Fliknamn
Target_file_cannot_be_a_directory.=Målfilen_kan_inte_vara_en_mapp.
+
Tertiary_sort_criterion=Tredje_sorteringskriteriet
+
Test=Testa
-The_ACM_Digital_Library=ACMs_digitala_bibliotek
-The_Guide_to_Computing_Literature=
-The_PDF_contains_one_or_several_BibTeX-records.=PDFen_innehåller_en_eller_flera_BibTeX-poster.
-The_ZIP-archive_need_not_be_on_the_classpath_of_JabRef.=
-The_character_format_is_controlled_by_the_citation_property_'CitationCharacterFormat'_in_the_style_file.=
+
+paste_text_here=klistra_in_text_här
+
The_chosen_date_format_for_new_entries_is_not_valid=Det_valda_datumformatet_för_nya_poster_är_inte_giltigt
+
The_chosen_encoding_'%0'_could_not_encode_the_following_characters\:=Den_valde_teckenkodningen_'%0'_kan_inte_representera_följande_tecken
-The_current_BibTeX_key_will_be_overwritten._Continue?=Den_aktuella_BibTeX-nyckeln_kommer_att_skrivas_över._Fortsätt?
+
+
+the_field_<b>%0</b>=fältet_<b>%0</b>
+
The_file<BR>'%0'<BR>has_been_modified<BR>externally\!=Filen_<b>'%0'</b>_har_ändrats_utanför_JabRef\!
-The_following_fetchers_are_available\:=
+
The_group_"%0"_already_contains_the_selection.=Gruppen_"%0"_innehåller_redan_de_valda_posterna.
+
The_label_of_the_string_cannot_be_a_number.=Strängnamnet_kan_inte_vara_ett_tal.
+
The_label_of_the_string_cannot_contain_spaces.=Strängnamnet_kan_inte_innehålla_mellanslag.
+
The_label_of_the_string_cannot_contain_the_'\#'_character.=Strängnamnet_kan_inte_innehålla_tecknet_'\#'.
-The_name_'comment'_cannot_be_used_as_an_entry_type_name.=En_posttyp_kan_inte_döpas_till_'comment'.
+
The_output_option_depends_on_a_valid_import_option.=
-The_output_option_depends_on_a_valid_input_option.=
-The_paragraph_format_is_controlled_by_the_property_'ReferenceParagraphFormat'_or_'ReferenceHeaderParagraphFormat'_in_the_style_file.=
-The_path_need_not_be_on_the_classpath_of_JabRef.=
+The_PDF_contains_one_or_several_BibTeX-records.=PDFen_innehåller_en_eller_flera_BibTeX-poster.
+Do_you_want_to_import_these_as_new_entries_into_the_current_database?=Vill_du_importera_dessa_som_nya_poster_i_den_befintliga_databasen?
+
The_regular_expression_<b>%0</b>_is_invalid\:=Det_reguljära_uttycket_<b>%0</b>_är_ogiltigt\:
+
The_search_is_case_insensitive.=Sökningen_är_inte_skiftlägeskänslig.
+
The_search_is_case_sensitive.=Sökningen_är_skiftlägeskänslig.
+
The_string_has_been_removed_locally=Strängen_har_tagit_bort_lokalt
+
There_are_possible_duplicates_(marked_with_an_icon)_that_haven't_been_resolved._Continue?=
-These_files_are_not_linked_in_the_active_database.=Dessa_filerna_är_inte_länkade_i_den_aktiva_databasen.
-This_action_will_modify_the_following_field(s)_in_at_least_one_entry_each\:=
-This_could_cause_undesired_changes_to_your_entries.=Detta_kan_leda_till_oönskade_effekter_för_dina_poster.
-This_database_contains_one_or_more_duplicated_BibTeX_keys.=Denna_databas_innehåller_en_eller_flera_BibTeX-nyckeldubbletter.
-This_database_uses_outdated_file_links.=Denna_databas_använder_utdaterade_fillänkar.
+
This_entry_has_no_BibTeX_key._Generate_key_now?=Denna_post_har_ingen_BibTeX-nyckel._Generera_en_nu?
+
This_entry_is_incomplete=Denna_post_är_ej_komplett
+
This_entry_type_cannot_be_removed.=Denna_posttyp_kan_inte_tas_bort.
+
This_external_link_is_of_the_type_'%0',_which_is_undefined._What_do_you_want_to_do?=Den_här_externa_länken_är_av_typen_'%0',_som_är_odefinierad._Vad_vill_du_göra?
-This_feature_generates_a_new_database_based_on_which_entries_are_needed_in_an_existing_LaTeX_document.=
-This_feature_lets_new_files_be_opened_or_imported_into_an_already_running_instance_of_JabRef<BR>instead_of_opening_a_new_instance._For_instance,_this_is_useful_when_you_open_a_file_in_JabRef<br>from_your_web_browser.<BR>Note_that_this_will_prevent_you_from_running_more_than_one_instance_of_JabRef_at_a_time.=
-This_group_contains_all_entries._It_cannot_be_edited_or_removed.=Denna_grupp_innehåller_alla_poster._Den_kan_inte_ändras_eller_tas_bort.
+
This_group_contains_entries_based_on_manual_assignment._Entries_can_be_assigned_to_this_group_by_selecting_them_then_using_either_drag_and_drop_or_the_context_menu._Entries_can_be_removed_from_this_group_by_selecting_them_then_using_the_context_menu.=
+
This_group_contains_entries_whose_<b>%0</b>_field_contains_the_keyword_<b>%1</b>=Denna_grupp_innehåller_poster_där_fältet_<b>%0</b>_innehåller_nyckelordet_<b>%1</b>
+
This_group_contains_entries_whose_<b>%0</b>_field_contains_the_regular_expression_<b>%1</b>=Denna_grupp_innehåller_poster_där_fältet_<b>%0</b>_innehåller_det_reguljära_uttrycket_<b>%1</b>
-This_is_a_simple_copy_and_paste_dialog._First_load_or_paste_some_text_into_the_text_input_area.<br>After_that,_you_can_mark_text_and_assign_it_to_a_BibTeX_field.=
This_makes_JabRef_look_up_each_file_link_and_check_if_the_file_exists._If_not,_you_will_be_given_options<BR>to_resolve_the_problem.=
+
This_operation_requires_all_selected_entries_to_have_BibTeX_keys_defined.=Denna_operationen_kräver_att_alla_valda_poster_har_en_BibTeX-nyckel.
+
This_operation_requires_one_or_more_entries_to_be_selected.=Den_här_operationen_kräver_att_en_eller_flera_poster_är_valda.
-This_search_contains_entries_in_which=Denna_sökning_innehåller_poster_där
-This_search_contains_entries_in_which_any_field_contains_the_regular_expression_<b>%0</b>=Denna_sökning_innehåller_poster_där_något_fält_innehåller_det_reguljära_uttrycket_<b>%0</b>
-This_search_contains_entries_in_which_any_field_contains_the_term_<b>%0</b>=Denna_sökning_innehåller_poster_där_något_fält_innehåller_termen_<b>%0</b>
-Three_stars=Tre_stjärnor
-Title=Titel
-To_disable_the_memory_stick_mode_rename_or_remove_the_jabref.xml_file_in_the_same_folder_as_JabRef.=
-To_set_up,_go_to=För_att_ställa_in,_gå_till
+
Toggle_abbreviation=Växla_förkortning
Toggle_entry_preview=Växla_postvisning
Toggle_groups_interface=Växla_grupphantering
-Toggle_print_status=Växla_utskriftsstatus
-Toggle_relevance=Växla_relevans
-Toggle_quality_assured=Växla_kvalitetssäkring
-Treatment_of_first_names=Hantering_av_förnamn
Try_different_encoding=Prova_en_annan_teckenkodning
-Two_stars=Två_stjärnor
-Unabbreviate=Expandera_förkortning
-Unabbreviate_journal_names=Expandera_förkortade_tidskriftsnamn
+
Unabbreviate_journal_names_of_the_selected_entries=Expandera_förkortade_tidskriftsnamn_för_de_valda_posterna
Unabbreviated_%0_journal_names.=Expanderade_%0_förkortade_tidskriftsnamn.
-Unabbreviating...=Expanderar_förkortningar...
-Unable_to_autodetect_OpenOffice/LibreOffice_installation._Please_choose_the_installation_directory_manually.=Kan_inte_hitta_OpenOffice/LibreOffice._Ställ_in_sökvägar_manuellt.
-Unable_to_clear_preferences.=Kan_inte_rensa_inställningar.
-Unable_to_connect._One_possible_reason_is_that_JabRef_and_OpenOffice/LibreOffice_are_not_both_running_in_either_32_bit_mode_or_64_bit_mode.=
-Unable_to_connect_to_FreeCite_online_service.=
-Unable_to_create_backup=Kan_inte_skapa_säkerhetskopia
-Unable_to_find_the_requested_look_and_feel_and_thus_the_default_one_is_used.=
+
Unable_to_open_file.=Kan_inte_öppna_fil.
-Unable_to_open_link.=Kan_inte_öppna_länk.
Unable_to_open_link._The_application_'%0'_associated_with_the_file_type_'%1'_could_not_be_called.=Kan_inte_öppna_länk._Programmet_'%0'_som_är_satt_för_filtypen_'%1'_kunde_inte_anropas.
-Unable_to_save_database=Kan_inte_spara_databas
-Unable_to_synchronize_bibliography=Kan_inte_synkronisera_bibliografi
+unable_to_write_to=kan_inte_skriva_till
Undefined_file_type=Odefinierad_filtyp
+
Undo=Ångra
+
Union=Union
-Unknown_DOI\:_'%0'.=Okänt_DOI\:_'%0'
-Unknown_DiVA_entry\:_'%0'.=Okänd_DiVA-post\:_'%0'
+
Unknown_BibTeX_entries=Okända_BibTeX-poster
+
+unknown_edit=okänd_ändring
+
Unknown_export_format=Okänt_exportformat
-Unknown_import_format=Okänt_importformat
-Unknown_preference_key_'%0'=Okänd_inställning_'%0'
+
Unmark_all=Avmarkera_alla
-Unmark_all_entries_before_importing_new_entries_into_an_existing_database=Avmarkera_alla_poster_innan_nya_importeras_till_en_befintlig_databas
+
Unmark_entries=Avmarkera_poster
+
Unmark_entry=Avmarkera_post
-Unmarked_all_%0_selected_entries=Avmarkera_alla_%0_valda_poster
-Unmarked_all_entries=Avmarkera_alla_poster
-Unmarked_selected_entry=Avmarkera_valda_poster
-Unselect_all=
-Unsupported_version_of_class_%0\:_%1=
+
+untitled=namnlös
+
Up=Uppåt
-Update_existing_entry=Uppdatera_befintlig_post
-Update_keywords=Uppdatera_nyckelord
-Update_timestamp_on_modification=Uppdatera_tidsstämpeln_efter_ändring
-Update_to_current_column_order=Uppdatera_till_aktuell_kolumnordning
+
Update_to_current_column_widths=Uppdatera_till_aktuella_kolumnbredder
+
Updated_group_selection=
Upgrade_external_PDF/PS_links_to_use_the_'%0'_field.=Uppgradera_PDF/PS-länkar_att_använda_'%0'-fältet.
Upgrade_file=Uppgradera_fil
Upgrade_old_external_file_links_to_use_the_new_feature=
-Usage=Användning
-Use=Använd
-Use_EMACS_23_insertion_string=
-Use_Emacs_key_bindings=Använd_tangentbordsbindningar_som_i_Emacs
-Use_IEEE_LaTeX_abbreviations=Använd_IEEE_LaTeX-förkortningar
-Use_regular_expression_search=Använd_sökning_med_reguljära_uttryck
-Use_abbreviated_and_full_firstname=Använd_förkortade_och_hela_förnamn
-Use_abbreviated_firstname_whenever_possible=Använd_om_möjligt_förkortade_förnamn
+
+usage=användning
Use_autocompletion_for_the_following_fields=Använd_automatisk_komplettering_för_följande_fält
-Use_custom_proxy_configuration=Använd_egen_proxykonfiguration
-Use_full_firstname_whenever_possible=Använd_hela_förnamnet_om_möjligt
+
Use_other_look_and_feel=Använd_annan_'look-and-feel'
-Use_the_BIB_file_location_as_primary_file_directory=Använd_BIB-filens_plats_som_primär_filmapp
-Use_the_following_delimiter_character(s)\:=Använd_följande_bokstäver_som_avgränsare\:
-User-specific_file_directory=Användarspecifik_filmapp
+Use_regular_expression_search=Använd_sökning_med_reguljära_uttryck
+
Username=Användarnamn
+
Value_cleared_externally=Värdet_raderades_utanför_JabRef
+
Value_set_externally=Värdet_sattes_utanför_JabRef
+
+verify_that_LyX_is_running_and_that_the_lyxpipe_is_valid=kontrollera_att_LyX_körs_och_att_lyxpipe_är_korrekt
+
View=Visa
Vim_server_name=Vim-servernamn
+
Waiting_for_ArXiv...=Väntar_på_ArXiv...
-Waiting_for_save_operation_to_finish=Väntar_på_att_sparningen_ska_bli_färdig
+
Warn_about_unresolved_duplicates_when_closing_inspection_window=
+
Warn_before_overwriting_existing_keys=Varna_innan_befintliga_nycklar_skrivs_över
+
Warning=Varning
-Warning\:_%0_out_of_%1_entries_have_undefined_BibTeX_key.=Varning\:_%0_av_%1_poster_har_odefinierade_BibTeX-nycklar.
+
Warnings=Varningar
-Web_search=Websökning
+
+web_link=weblänk
+
What_do_you_want_to_do?=Vad_vill_du_göra?
-What_would_you_like_to_clean_up?=Vad_vill_du_städa_upp?
+
When_adding/removing_keywords,_separate_them_by=När_nyckelord_läggs_till/tas_bort,_separera_dem_med
-When_downloading_files,_or_moving_linked_files_to_the_file_directory,_prefer_the_BIB_file_location_rather_than_the_file_directory_set_above=
-When_opening_file_link,_search_for_matching_file_if_no_link_is_defined=
Will_write_XMP-metadata_to_the_PDFs_linked_from_selected_entries.=Kommer_skriva_XMP-metadata_till_PDFer_länkade_från_valda_poster.
-Work_options=
+
+with=med
+
Write_BibTeXEntry_as_XMP-metadata_to_PDF.=Skriv_BibTeX-posten_som_XMP-metadata_i_PDF.
+
+Write_XMP=Skriv_XMP
Write_XMP-metadata=Skriv_XMP-metadata
Write_XMP-metadata_for_all_PDFs_in_current_database?=Skriv_XMP-metadata_för_alla_PDFer_i_aktuell_databas?
-Write_XMP=Skriv_XMP
-Write_values_of_special_fields_as_separate_fields_to_BibTeX=
Writing_XMP-metadata...=Skriver_XMP-metadata...
Writing_XMP-metadata_for_selected_entries...=Skriver_XMP-metadata_för_valda_poster...
+
Wrote_XMP-metadata=Skrev_XMP-metadata
+
XMP-annotated_PDF=
XMP_export_privacy_settings=
XMP-metadata=XMP-metadata
XMP-metadata_found_in_PDF\:_%0=XMP-metadata_funnen_i_PDF\:_%0
-You_can_add_additional_journal_names_by_setting_up_a_personal_journal_list,<br>as_well_as_linking_to_external_journal_lists.=
-You_can_only_rename_one_field_at_a_time=Du_kan_bara_döpa_om_en_fil_i_taget
-You_have_changed_settings_for_special_fields.=Du_har_ändrat_inställningarna_för_specialfält.
+You_must_restart_JabRef_for_this_to_come_into_effect.=Du_måste_starta_om_JabRef_för_att_ändringen_ska_slå_igenom.
You_have_changed_the_language_setting.=Du_har_ändrat_språkinställningarna.
+
You_have_changed_the_look_and_feel_setting.=Du_har_ändrat_'look-and-feel'-inställningen.
-You_have_changed_the_menu_and_label_font_size.=
+
You_have_entered_an_invalid_search_'%0'.=Du_har_angett_en_ogiltig_sökning_'%0'.
-You_have_selected_more_than_%0_entries_for_download._Some_web_sites_might_block_you_if_you_make_too_many_rapid_downloads._Do_you_want_to_continue?=
-You_have_to_choose_exactly_two_entries_to_merge.=Du_måste_välja_exakt_två_poster_att_slå_samman.
+
You_must_choose_a_filename_to_store_journal_abbreviations=Du_måste_välja_ett_filnamn_för_att_spara_tidskriftsförkortningar
-You_must_enter_an_integer_value_in_the_interval_1025-65535_in_the_text_field_for=Du_måste_ange_ett_heltal_i_området_1025-65536_i_fältet_för
-You_must_enter_an_integer_value_in_the_text_field_for=Du_måste_ange_ett_heltal_i_fältet_för
+
You_must_restart_JabRef_for_the_new_key_bindings_to_work_properly.=Du_måste_starta_om_JabRef_för_att_tangentbordsbindningarna_ska_fungera_ordentligt.
-You_must_restart_JabRef_for_this_to_come_into_effect.=Du_måste_starta_om_JabRef_för_att_ändringen_ska_slå_igenom.
+
+Your_new_key_bindings_have_been_stored.=Dina_nya_tangentbordsbindningar_har_lagrats
+
+The_following_fetchers_are_available\:=
+Could_not_find_fetcher_'%0'=Kunde_inte_hitta_hämtaren_'%0'
+Running_query_'%0'_with_fetcher_'%1'.=
+Query_'%0'_with_fetcher_'%1'_did_not_return_any_results.=
+Move/Rename_file=Flytta/Döp om fil
+File_moved=Filen_flyttad
+Move_file_failed=Gick_inte_att_flytta_fil
+Could_not_move_file_'%0'.=Kunde_inte_flytta_filen_'%0'
+Could_not_find_file_'%0'.=Kunde_inte_hitta_filen_'%0'.
+Number_of_entries_successfully_imported=Antal_poster_som_lyckades_importeras
+Import_canceled_by_user=Import_avbröts_av_användare
+Progress\:_%0_of_%1=Händelseförlopp\:_%0_av_%1
+Error_while_fetching_from_%0=Fel_vid_hämtning_från_%0
+
+Please_enter_a_valid_number=Ange_ett_giltigt_tal
+Show_search_results_in_a_window=Visa_sökresultaten_i_ett_fönster
+Show_global_search_results_in_a_window=
+Search_in_all_open_databases=
+Move_file_to_file_directory?=Flytta_fil_till_filmapp?
+Rename_to_'%0'=Byt_namn_till_'%0'
+You_have_changed_the_menu_and_label_font_size.=
+
+Database_is_protected._Cannot_save_until_external_changes_have_been_reviewed.=Databasen_är_skyddad._Kan_inte_spara_innan_externa_ändringar_är_kontrollerade.
+Protected_database=Skyddad_databas
+Refuse_to_save_the_database_before_external_changes_have_been_reviewed.=Vägra_att_spara_databasen_innan_externa_ändringar_har_kontrollerats.
+Database_protection=Databasskydd
+Unable_to_save_database=Kan_inte_spara_databas
+
+BibTeX_key_generator=BibTeX-nyckelgenerator
+Unable_to_open_link.=Kan_inte_öppna_länk.
+Move_the_keyboard_focus_to_the_entry_table=Flytta_tangentbordsfokus_till_tabellen
+MIME_type=MIME-typ
+
+This_feature_lets_new_files_be_opened_or_imported_into_an_already_running_instance_of_JabRef<BR>instead_of_opening_a_new_instance._For_instance,_this_is_useful_when_you_open_a_file_in_JabRef<br>from_your_web_browser.<BR>Note_that_this_will_prevent_you_from_running_more_than_one_instance_of_JabRef_at_a_time.=
+Run_fetcher,_e.g._"--fetch\=Medline\:cancer"=
+
+The_ACM_Digital_Library=ACMs_digitala_bibliotek
+Reset=Återställ
+
+Use_IEEE_LaTeX_abbreviations=Använd_IEEE_LaTeX-förkortningar
+The_Guide_to_Computing_Literature=
+
+When_opening_file_link,_search_for_matching_file_if_no_link_is_defined=
+Settings_for_%0=Alternativ_för_%0
+Mark_entries_imported_into_an_existing_database=Markera_poster_som_importeras_till_en_befintlig_databas
+Unmark_all_entries_before_importing_new_entries_into_an_existing_database=Avmarkera_alla_poster_innan_nya_importeras_till_en_befintlig_databas
+
+Forward=Framåt
+Back=Bakåt
+Sort_the_following_fields_as_numeric_fields=Sortera_följande_fält_som_tal
+Line_%0\:_Found_corrupted_BibTeX_key.=Rad_%0\:_Hittade_felaktig_BibTeX-nyckel.
+Line_%0\:_Found_corrupted_BibTeX_key_(contains_whitespaces).=
+Line_%0\:_Found_corrupted_BibTeX_key_(comma_missing).=Rad_%0\:_Hittade_felaktig_BibTeX-nyckel_(kommatecken_saknas).
+Full_text_document_download_failed=Gick_inte_att_ladda_ned_dokument.
+Update_to_current_column_order=Uppdatera_till_aktuell_kolumnordning
+Download_from_URL=Ladda_ned_från_URL
+Rename_field=Byt_namn_på_fält
+Set/clear/rename_fields=Sätt/rensa/byt_namn_på_fält
+Rename_field_to=Byt_namn_på_fält_till
+Move_contents_of_a_field_into_a_field_with_a_different_name=Flytta_innehållet_i_ett_fält_till_ett_fält_med_ett_annat_namn
+You_can_only_rename_one_field_at_a_time=Du_kan_bara_döpa_om_en_fil_i_taget
+
+Remove_all_broken_links=Ta_bort_alla_trasiga_länkar
+
+Cannot_use_port_%0_for_remote_operation;_another_application_may_be_using_it._Try_specifying_another_port.=Kan_inte_använda_port_"%0"_för_fjärråtkomst;_ett_annat_program_kanske_använder_den._Försök_med_en_annan_port.
+
+Looking_for_full_text_document...=Letar_efter_dokument...
+Autosave=Automatisk_sparning
+A_local_copy_will_be_opened.=
+Autosave_local_databases=
+Automatically_save_the_database_to=
+Please_enter_a_valid_file_path.=
+
+
+Export_in_current_table_sort_order=Exportera_poster_enligt_nuvarande_sortering
+Export_entries_in_their_original_order=Exportera_poster_i_den_ursprungliga_ordningen
+Error_opening_file_'%0'.=Fel_vid_öppning_av_fil_'%0'.
+
+Formatter_not_found\:_%0=Hittade_ej_formatterare\:_%0
+Clear_inputarea=Rensa_inmatningsområdet
+
+Automatically_set_file_links_for_this_entry=Skapa_fillänkar_automatiskt_för_denna_post
+Could_not_save,_file_locked_by_another_JabRef_instance.=Kunde_inte_spara._Filen_låst_av_en_annan_JabRef-instans.
+File_is_locked_by_another_JabRef_instance.=Filen_är_låst_av_en_annan_JabRef-instans.
+Do_you_want_to_override_the_file_lock?=
+File_locked=Filen_är_låst
+Current_tmp_value=Nuvarande_temporära_värde
+Metadata_change=Ändring_i_metadata
+Changes_have_been_made_to_the_following_metadata_elements=Ändringar_har_gjorts_i_följande_metadata-element
+
+Generate_groups_for_author_last_names=Generera_grupper_baserat_på_författarefternamn
+Generate_groups_for_editor_last_names=Generera_grupper_baserat_på_editorefternamn
+Generate_groups_from_keywords_in_a_BibTeX_field=Generera_grupper_baserat_på_nyckelord_i_ett_fält
+Enforce_legal_characters_in_BibTeX_keys=Framtvinga_giltiga_tecken_i_BibTeX-nycklar
+
+Save_without_backup?=Spara_utan_att_göra_backup?
+Unable_to_create_backup=Kan_inte_skapa_säkerhetskopia
+Move_file_to_file_directory=Flytta_fil_till_filmapp
+Rename_file_to=Byt_namn_på_fil_till
+<b>All_Entries</b>_(this_group_cannot_be_edited_or_removed)=<b>Alla_poster</b>_(den_här_gruppen_kan_inte_ändras_eller_tas_bort)
+static_group=statisk_grupp
+dynamic_group=dynamisk_grupp
+refines_supergroup=
+includes_subgroups=inkluderar_undergrupper
+contains=innehåller
+search_expression=sökuttryck
+
+Optional_fields_2=Valfria_fält_2
+Waiting_for_save_operation_to_finish=Väntar_på_att_sparningen_ska_bli_färdig
+Resolving_duplicate_BibTeX_keys...=
+Finished_resolving_duplicate_BibTeX_keys._%0_entries_modified.=
+This_database_contains_one_or_more_duplicated_BibTeX_keys.=Denna_databas_innehåller_en_eller_flera_BibTeX-nyckeldubbletter.
+Do_you_want_to_resolve_duplicate_keys_now?=Vill_du_hantera_dubblerade_nycklar_nu?
+
+Find_and_remove_duplicate_BibTeX_keys=Hitta_och_ta_bort_duplicerade_BibTeX-nycklar
+Expected_syntax_for_--fetch\='<name_of_fetcher>\:<query>'=
+Duplicate_BibTeX_key=Dubblerad_BibTeX-nyckel
+Import_marking_color=Färg_för_importerade_poster
+Always_add_letter_(a,_b,_...)_to_generated_keys=Lägg_alltid_till_en_bokstav_(a,_b_...)_på_genererade_nycklar
+
+Ensure_unique_keys_using_letters_(a,_b,_...)=Garantera_unika_nycklar_med_bokstäver_(a,_b,_...)
+Ensure_unique_keys_using_letters_(b,_c,_...)=Garantera_unika_nycklar_med_bokstäver_(b,_c,_...)
+Entry_editor_active_background_color=Bakgrundfärg_för_aktiv_post_i_posteditor
+Entry_editor_background_color=Bakgrundfärg_för_posteditor
+Entry_editor_font_color=Typsnittfärg_för_posteditor
+Entry_editor_invalid_field_color=Färg_för_ogiltiga_fält_i_posteditor
+
+Table_and_entry_editor_colors=Färger_för_tabell_och_posteditor
+
+General_file_directory=Generell_filmapp
+User-specific_file_directory=Användarspecifik_filmapp
+Search_failed\:_illegal_search_expression=Sökning_misslyckades\:_ogiltigt_sökuttryck
+Show_ArXiv_column=Visa_ArXiv-kolumn
+Highlight_groups_that_contain_entries_contained_in_any_currently_selected_group=Framhäv_grupper_som_innehåller_poster_från_någon_av_det_valda_grupperna
+
+You_must_enter_an_integer_value_in_the_interval_1025-65535_in_the_text_field_for=Du_måste_ange_ett_heltal_i_området_1025-65536_i_fältet_för
+Automatically_open_browse_dialog_when_creating_new_file_link=Öppna_fildialog_automatiskt_när_ny_fillänk_skapas
+Import_metadata_from\:=Importera_metadata_från\:
+Choose_the_source_for_the_metadata_import=Välj_källa_för_metadata-import
+Create_entry_based_on_XMP_data=Skapa_post_baserat_på_XMP-data
+Create_blank_entry_linking_the_PDF=Skapa_tom_post_som_länkar_till_PDF\:en
+Only_attach_PDF=Lägg_bara_till_PDF
+Title=Titel
+Create_new_entry=Skapa_ny_post
+Update_existing_entry=Uppdatera_befintlig_post
+Autocomplete_names_in_'Firstname_Lastname'_format_only=Komplettera_enbart_namn_i_'Förnamn_Efternamn'-format
+Autocomplete_names_in_'Lastname,_Firstname'_format_only=Komplettera_enbart_namn_i_'Efternamn,_Förnamn'-format
+Autocomplete_names_in_both_formats=Komplettera_namn_automatiskt_i_bägge_formaten
+Marking_color_%0=Markeringsfärg_%0
+The_name_'comment'_cannot_be_used_as_an_entry_type_name.=En_posttyp_kan_inte_döpas_till_'comment'.
+You_must_enter_an_integer_value_in_the_text_field_for=Du_måste_ange_ett_heltal_i_fältet_för
+Send_as_email=Skicka_som_epost
+References=Referenser
+Sending_of_emails=Skicka_epost
+Subject_for_sending_an_email_with_references=Ämne_för_epost_med_referenser
+Automatically_open_folders_of_attached_files=Öppna_automatiskt_mappar_där_filer_som_ska_skickas_med_finns
+Create_entry_based_on_content=Skapa_post_baserat_på_innehåll
+Do_not_show_this_box_again_for_this_import=Visa_inte_denna_ruta_igen_för_den_här_importen
+Always_use_this_PDF_import_style_(and_do_not_ask_for_each_import)=Använd_alltid_detta_vid_import_av_PDF_(och_fråga_inte_för_varje_fil)
+Error_creating_email=Fel_vid_skapande_av_epost
+Entries_added_to_an_email=Poster_lades_till_ett_epostmeddelande
+exportFormat=exportformat
+Output_file_missing=
+No_search_matches.=Sökningen_matchade_inget.
+The_output_option_depends_on_a_valid_input_option.=
+Default_import_style_for_drag_and_drop_of_PDFs=
+Default_PDF_file_link_action=Standardhändelse_för_PDF-fil
+Filename_format_pattern=Filnamnsmönster
+Additional_parameters=Ytterligare_parametrar
+Cite_selected_entries_between_parenthesis=Referera_till_valda_poster_inom_paranteser
+Cite_selected_entries_with_in-text_citation=Referera_till_valda_poster_i_löpande_text
+Cite_special=Specialcitering
+Extra_information_(e.g._page_number)=Extrainformation_(t._ex._sidnummer)
+Manage_citations=Hantera_citeringar
+Problem_modifying_citation=Problem_att_modifiera_citering
+Citation=Citering
+Extra_information=Extrainformation
+Could_not_resolve_BibTeX_entry_for_citation_marker_'%0'.=Kunde_inte_hitta_en_BibTeX-post_för_referensmarkören_'%0'.
+Select_style=Välj_stil
+Journals=Tidskrifter
+Cite=Referera
+Cite_in-text=Referera_i_löpande_text
+Insert_empty_citation=Infoga_tom_citering
+Merge_citations=Slå_ihop_citeringar
+Manual_connect=Anslut_manuellt
+Select_Writer_document=Välj_Writer-dokument
+Sync_OpenOffice/LibreOffice_bibliography=Synka_OpenOffic/LibreOffice-bibliografi
+Select_which_open_Writer_document_to_work_on=Välj_vilket_öppet_Writer-dokument_som_ska_användas
+Connected_to_document=Ansluten_till_dokument
+Insert_a_citation_without_text_(the_entry_will_appear_in_the_reference_list)=Infoga_en_citering_utan_text_(posten_kommer_visas_i_referenslistan)
+Cite_selected_entries_with_extra_information=Referera_till_valda_poster_och_lägg_till_extra_information
+Ensure_that_the_bibliography_is_up-to-date=Se_till_att_bibliografin_är_uppdaterad
+Your_OpenOffice/LibreOffice_document_references_the_BibTeX_key_'%0',_which_could_not_be_found_in_your_current_database.=Ditt_OpenOffice/LibreOffice-dokument_refererar_till_BibTeX-nyckeln_'%0',_som_inte_kan_hittas_i_din_aktuella_databas.
+Unable_to_synchronize_bibliography=Kan_inte_synkronisera_bibliografi
+Combine_pairs_of_citations_that_are_separated_by_spaces_only=Slå_ihop_citeringar_som_bara_separareras_av_mellanslag
+Autodetection_failed=Kunde_inte_detektera_sökvägar
+Connecting=Ansluter
+Please_wait...=Vänta...
+Set_connection_parameters=Sätt_anslutningsinställningar
+Path_to_OpenOffice/LibreOffice_directory=Sökväg_till_OpenOffice/LibreOffice-mapp
+Path_to_OpenOffice/LibreOffice_executable=Sökväg_till_OpenOffice/LibreOffice-program
+Path_to_OpenOffice/LibreOffice_library_dir=
+Connection_lost=Tappade_anslutning
+The_paragraph_format_is_controlled_by_the_property_'ReferenceParagraphFormat'_or_'ReferenceHeaderParagraphFormat'_in_the_style_file.=
+The_character_format_is_controlled_by_the_citation_property_'CitationCharacterFormat'_in_the_style_file.=
+Automatically_sync_bibliography_when_inserting_citations=Synkronisera_bibliografin_automatiskt_när_citeringar_infogas
+Look_up_BibTeX_entries_in_the_active_tab_only=Leta_bara_efter_BibTeX-poster_i_aktiv_flik
+Look_up_BibTeX_entries_in_all_open_databases=Leta_efter_BibTeX-poster_i_alla_öppna_databaser
+Autodetecting_paths...=Detekterar_sökvägar...
+Could_not_find_OpenOffice/LibreOffice_installation=Kunde_inte_hitta_någon_OpenOffice/LibreOffice-installation
+Directories=Mappar
+Found_more_than_one_OpenOffice/LibreOffice_executable.=Hittade_mer_än_ett_OpenOffice/LibreOffice-program.
+Please_choose_which_one_to_connect_to\:=Välj_det_du_vill_ansluta_till\:
+Choose_OpenOffice/LibreOffice_executable=Välj_OpenOffice/LibreOffice-program
+Select_document=Välj_dokument
+Edit_group_membership=Ändra_gruppmedlemskap
+HTML_list=HTML-lista
+Click_group_to_toggle_membership_of_selected_entries=Klicka_grupp_för_att_växla_valda_posters_tillhörighet
+If_possible,_normalize_this_list_of_names_to_conform_to_standard_BibTeX_name_formatting=
+Could_not_open_%0=Kunde_inte_öppna_%0
+Unknown_import_format=Okänt_importformat
+Web_search=Websökning
+Style_selection=Stilval
+No_valid_style_file_defined=Ingen_giltig_stilfil_definierad
+Choose_pattern=Välj_mönster
+Use_the_BIB_file_location_as_primary_file_directory=Använd_BIB-filens_plats_som_primär_filmapp
+Could_not_run_the_gnuclient/emacsclient_program._Make_sure_you_have_the_emacsclient/gnuclient_program_installed_and_available_in_the_PATH.=
+Built-in_journal_list=Inbyggd_tidskriftslista
+OpenOffice/LibreOffice_connection=OpenOffice/LibreOffice-anslutning
+You_can_add_additional_journal_names_by_setting_up_a_personal_journal_list,<br>as_well_as_linking_to_external_journal_lists.=
+JabRef_includes_a_built-in_list_of_journal_abbreviations.=JabRef_har_en_inbyggd_lista_med_tidskriftsförkortningar
You_must_select_either_a_valid_style_file,_or_use_one_of_the_default_styles.=Du_måste_antingen_välja_en_giltig_stilfil_eller_använda_en_av_standardstilarna.
+
+This_is_a_simple_copy_and_paste_dialog._First_load_or_paste_some_text_into_the_text_input_area.<br>After_that,_you_can_mark_text_and_assign_it_to_a_BibTeX_field.=
+This_feature_generates_a_new_database_based_on_which_entries_are_needed_in_an_existing_LaTeX_document.=
You_need_to_select_one_of_your_open_databases_from_which_to_choose_entries,_as_well_as_the_AUX_file_produced_by_LaTeX_when_compiling_your_document.=
-Your_OpenOffice/LibreOffice_document_references_the_BibTeX_key_'%0',_which_could_not_be_found_in_your_current_database.=Ditt_OpenOffice/LibreOffice-dokument_refererar_till_BibTeX-nyckeln_'%0',_som_inte_kan_hittas_i_din_aktuella_databas.
-Your_new_key_bindings_have_been_stored.=Dina_nya_tangentbordsbindningar_har_lagrats
+
+First_select_entries_to_clean_up.=Välj_först_de_poster_som_du_vill_städa_upp.
+Cleanup_entry=Städa_upp_post
+Autogenerate_PDF_Names=Generera_PDF-namn_automatiskt
+Auto-generating_PDF-Names_does_not_support_undo._Continue?=Du_kan_inte_ångra_automatisk_generering_av_PDF-namn._Fortsätt?
+
+Use_full_firstname_whenever_possible=Använd_hela_förnamnet_om_möjligt
+Use_abbreviated_firstname_whenever_possible=Använd_om_möjligt_förkortade_förnamn
+Use_abbreviated_and_full_firstname=Använd_förkortade_och_hela_förnamn
+Autocompletion_options=Inställningar_för_automatisk_komplettering
+Autocomplete_after_following_number_of_characters=Komplettera_automatiskt_efter_följande_antal_bokstäver
+Name_format_used_for_autocompletion=Namnformat_för_automatisk_komplettering
+Treatment_of_first_names=Hantering_av_förnamn
+Cleanup_entries=Städa_upp_poster
+Automatically_assign_new_entry_to_selected_groups=Tilldela_automatiskt_nya_poster_till_valda_grupper
+%0_mode=%0-läge
+Move_DOIs_from_note_and_URL_field_to_DOI_field_and_remove_http_prefix=Flytta_DOIs_från_'note'-_och_'URL'-fälten_till_'DOI'-fältet_samt_ta_bort_http-prefix
+Make_paths_of_linked_files_relative_(if_possible)=Gör_sökvägen_till_länkade_filer_relativ_(om_möjligt)
+Rename_PDFs_to_given_filename_format_pattern=
+Rename_only_PDFs_having_a_relative_path=
+What_would_you_like_to_clean_up?=Vad_vill_du_städa_upp?
+Doing_a_cleanup_for_%0_entries...=Städar_upp_%0_poster
+No_entry_needed_a_clean_up=Ingen_post_behövde_städas_upp
+One_entry_needed_a_clean_up=En_post_behövde_städas_upp
+%0_entries_needed_a_clean_up=%0_poster_behövde_städas_upp
+
+Error_downloading_file_'%0'=Fel_när_filen_'%0'_skulle laddas_ned
+Download_failed=Nedladdning_misslyckades
+
+Remove_selected=Ta_bort_valda
+
+Group_tree_could_not_be_parsed._If_you_save_the_BibTeX_database,_all_groups_will_be_lost.=Gruppträdet_kunde_inte_läsas_in._Om_du_sparar_din_databas_kommer_alla_grupper_att_förloras.
+Attach_file=Lägg_till_fil
+Setting_all_preferences_to_default_values.=Återställer_alla_inställningar_till_standardvärden
+Resetting_preference_key_'%0'=Återställer_inställningsvärde_'%0'
+Unknown_preference_key_'%0'=Okänd_inställning_'%0'
+Unable_to_clear_preferences.=Kan_inte_rensa_inställningar.
+
+Reset_preferences_(key1,key2,..._or_'all')=Återställ_inställningar_(nyckel1,nyckel2,..._eller_'all')
+Find_unlinked_files=Hitta_olänkade_filer
+Unselect_all=
+Expand_all=Expandera_alla
+Collapse_all=Fäll_ihop_alla
+Opens_the_file_browser.=Öppnar_filbläddraren
+Scan_directory=Sök_igenom_mapp
+Searches_the_selected_directory_for_unlinked_files.=Söker_i_den_valda_mappen_efter_filer_som_ej_är_länkade_i_databasen
+Starts_the_import_of_BibTeX_entries.=Börjar_importen_av_BibTeX-poster.
+Leave_this_dialog.=Lämna_denna_dialog.
+Create_directory_based_keywords=Skapa_nyckelord_baserade_på_mapp
+Creates_keywords_in_created_entrys_with_directory_pathnames=Skapar_nyckelord_med_sökvägen_till_mappen_i_de_skapade_posterna
+Select_a_directory_where_the_search_shall_start.=Välj_en_mapp_där_sökningen_ska_börja.
+Select_file_type\:=Välj_filtyp\:
+These_files_are_not_linked_in_the_active_database.=Dessa_filerna_är_inte_länkade_i_den_aktiva_databasen.
+Entry_type_to_be_created\:=Posttyper_som_kommer_att_skapas\:
+Searching_file_system...=Söker_på_filsystemet...
+Importing_into_Database...=Importerar_till_databas...
+Select_directory=Välj_mapp
+Select_files=Välj_filer
+BibTeX_entry_creation=Skapande_av_BibTeX-poster
+<No_selection>=<Inget_val>
+Unable_to_connect_to_FreeCite_online_service.=
+Parse_with_FreeCite=
+The_current_BibTeX_key_will_be_overwritten._Continue?=Den_aktuella_BibTeX-nyckeln_kommer_att_skrivas_över._Fortsätt?
+Overwrite_key=Skriv_över_nyckel
+Not_overwriting_existing_key._To_change_this_setting,_open_Options_->_Prefererences_->_BibTeX_key_generator=
+How_would_you_like_to_link_to_'%0'?=Hur_vill_du_länka_till_'%0'?
+BibTeX_key_patterns=BibTeX-nyckelmönster
+Changed_special_field_settings=Ändrade_inställningar_för_specialfält
+Clear_priority=Rensa_prioritet
+Clear_rank=Rensa_ranking
+Enable_special_fields=Aktivera_specialfält
+Five_stars=Fem_stjärnor
+Four_stars=Fyra_stjärnor
+Help_on_special_fields=Hjälp_för_specialfält
+Keywords_of_selected_entries=Nyckelord_för_valda_poster
+Manage_keywords=Hantera_nyckelord
+No_priority_information=Ingen_prioritetsinformation
+No_rank_information=Ingen_rankinginformation
+One_star=En_stjärna
+Priority=Prioritet
+Priority_high=Hög_prioritet
+Priority_low=Låg_prioritet
+Priority_medium=Medel_prioritet
+Quality=Kvalitet
+Rank=Ranking
+Relevance=Relevans
+Set_priority_to_high=Sätt_prioritet_till_hög
+Set_priority_to_low=Sätt_prioritet_till_låg
+Set_priority_to_medium=Sätt_prioritet_till_medel
+Show_priority=Visa_prioritet
+Show_quality=Visa_kvalitet
+Show_rank=Visa_ranking
+Show_relevance=Visa_relevans
+Synchronize_with_keywords=Synkronisera_med_nyckelord
+Synchronized_special_fields_based_on_keywords=Synkronisera_specialfält_med_hjälp_av_nyckelord
+Three_stars=Tre_stjärnor
+Toggle_relevance=Växla_relevans
+Toggle_quality_assured=Växla_kvalitetssäkring
+Two_stars=Två_stjärnor
+Update_keywords=Uppdatera_nyckelord
+Write_values_of_special_fields_as_separate_fields_to_BibTeX=
+You_have_changed_settings_for_special_fields.=Du_har_ändrat_inställningarna_för_specialfält.
+%0_entries_found._To_reduce_server_load,_only_%1_will_be_downloaded.=%0_poster_hittades._För_att_minska_lasten_på_servern_kommer_bara_%1_att_laddas_ned.
+A_string_with_that_label_already_exists=En_sträng_med_det_namnet_finns_redan
+Connection_to_OpenOffice/LibreOffice_has_been_lost._Please_make_sure_OpenOffice/LibreOffice_is_running,_and_try_to_reconnect.=Anslutningen_till_OpenOffice/LibreOffice_försvann._Se_till_att_OpenOffice/LibreOffice_körs_och_anslut_på_nytt.
+
+Correct_the_entry,_and_reopen_editor_to_display/edit_source.=
+Could_not_connect_to_a_running_gnuserv_process._Make_sure_that_Emacs_or_XEmacs_is_running,<BR>and_that_the_server_has_been_started_(by_running_the_command_'server-start'/'gnuserv-start').=
+Could_not_connect_to_running_OpenOffice/LibreOffice.=Kunde_inte_ansluta_till_OpenOffice/LibreOffice.
+Make_sure_you_have_installed_OpenOffice/LibreOffice_with_Java_support.=Kontrollera_att_du_har_installerat_OpenOffice/LibreOffice_med_Java-stöd.
+If_connecting_manually,_please_verify_program_and_library_paths.=Om_du_ansluter_manuellt,_kontrollera_sökvägar_till_program_och_bibliotek.
+Error_message\:=Felmeddelande\:
+Created_group_"%0".=Skapade_grupp_"%0".
+If_a_pasted_or_imported_entry_already_has_the_field_set,_overwrite.=
+Import_metadata_from_PDF=Importera_metadata_från_PDF
+Not_connected_to_any_Writer_document._Please_make_sure_a_document_is_open,_and_use_the_'Select_Writer_document'_button_to_connect_to_it.=
+Removed_all_subgroups_of_group_"%0".=Tog_bort_alla_undergrupper_för_gruppen_"%0".
+To_disable_the_memory_stick_mode_rename_or_remove_the_jabref.xml_file_in_the_same_folder_as_JabRef.=
+Unable_to_connect._One_possible_reason_is_that_JabRef_and_OpenOffice/LibreOffice_are_not_both_running_in_either_32_bit_mode_or_64_bit_mode.=
+Use_the_following_delimiter_character(s)\:=Använd_följande_bokstäver_som_avgränsare\:
+When_downloading_files,_or_moving_linked_files_to_the_file_directory,_prefer_the_BIB_file_location_rather_than_the_file_directory_set_above=
Your_style_file_specifies_the_character_format_'%0',_which_is_undefined_in_your_current_OpenOffice/LibreOffice_document.=Din_stilfil_anger_bokstavsformatet_'%0',_som_är_odefinierat_i_ditt_nuvarande_OpenOffice/LibreOffice-dokument.
Your_style_file_specifies_the_paragraph_format_'%0',_which_is_undefined_in_your_current_OpenOffice/LibreOffice_document.=Din_stilfil_anger_styckesformatet_'%0',_som_är_odefinierat_i_ditt_nuvarande_OpenOffice/LibreOffice-dokument.
-abbreviation_detected=förkortning_upptäcktes
-add_group=lägg_till_grupp
-and=och
-and_the_class_must_be_available_in_your_classpath_next_time_you_start_JabRef.=och_klassen_måste_finnas_i_din_sökväg_för_klasser_nästa_gång_du_startar_JabRef.
-any_field_that_matches_the_regular_expression_<b>%0</b>=något_fält_som_matchar_det_reguljära_uttrycket_<b>%0</b>
-by=med
-case_insensitive=ej_skiftlägeskänsligt
-case_sensitive=skiftlägeskänsligt
-change_assignment_of_entries=ändra_tilldelning_av_poster
-change_preamble=ändra_preamble
-contains=innehåller
-crossreferenced_entries_included=korsrefererade_poster_inkluderade
-cut_entries=klipp_ut_poster
-cut_entry=klipp_ut_post
-default=standard
-delete_entries=radera_poster
-delete_entry=radera_post
-duplicate_removal=ta_bort_dubbletter
-dynamic_group=dynamisk_grupp
-empty_database=tom_databas
-entries=poster
-entry=post
-exportFormat=exportformat
-field=fält
-file=fil
-filename=filnamn
-for=för
-found_in_AUX_file=hittades_i_AUX-fil
+
+Searching...=Söker...
+You_have_selected_more_than_%0_entries_for_download._Some_web_sites_might_block_you_if_you_make_too_many_rapid_downloads._Do_you_want_to_continue?=
+Confirm_selection=Bekräfta_val
+Add_{}_to_specified_title_words_on_search_to_keep_the_correct_case=Lägg_till_{}_runt_skyddade_ord_i_titeln_för_att_bevara_skiftläget_vid_sökning
+Import_conversions=Konverteringar_vid_import
+Please_enter_a_search_string=Ange_en_söksträng
+Please_open_or_start_a_new_database_before_searching=Öppna_eller_skapa_en_ny_databas_innan_sökning.
+Log=Logg
+
+Canceled_merging_entries=Avbröt_sammanslagning_av_poster
+
+Format_units_by_adding_non-breaking_separators_and_keeping_the_correct_case_on_search=
+Merge_entries=Kombinera_poster
+Merged_entries=Kombinerade_poster
+Merged_entry=Kombinerad_post
+None=
+Parse=
+Result=Resultat
+Show_DOI_first=Visa_DOI_först
+Show_URL_first=Visa_URL_först
+Use_Emacs_key_bindings=Använd_tangentbordsbindningar_som_i_Emacs
+You_have_to_choose_exactly_two_entries_to_merge.=Du_måste_välja_exakt_två_poster_att_slå_samman.
+
+Update_timestamp_on_modification=Uppdatera_tidsstämpeln_efter_ändring
+All_key_bindings_will_be_reset_to_their_defaults.=Alla_tangentbordsbindingar_kommer_att_återställas_till_standardvärden.
+
+Automatically_set_file_links=Skapa_fillänkar_automatiskt
+Continue?=Fortsätt?
+Resetting_all_key_bindings=Återställer_alla_tangentbordsbindningar
+Hostname=Värd
+Invalid_setting=Ogiltig_inställning
+Network=Nätverk
+Please_specify_both_hostname_and_port=Ange_både_värdnamn_och_port
+Please_specify_both_username_and_password=Ange_både_användarnamn_och_lösenord
+
+Use_custom_proxy_configuration=Använd_egen_proxykonfiguration
+Proxy_requires_authentication=Proxyn_kräver_autentisering
+Attention\:_Password_is_stored_in_plain_text\!=OBS\!_Lösenordet_sparas_i_klartext\!
+Clear_connection_settings=Rensa_anslutningsinställningar
+Cleared_connection_settings.=Rensade_anslutningsinställningar.
+
+Rebind_C-a,_too=
+Rebind_C-f,_too=
+
+Show_number_of_elements_contained_in_each_group=Visa_antal_poster_i_varje_grupp
+
+Open_folder=Öppna_mapp
+Searches_for_unlinked_PDF_files_on_the_file_system=Letar_efter_olänkade_PDF-filer_på_filsystemet
+Export_entries_ordered_as_specified=Exportera_poster_enligt_inställningar
+Export_sort_order=Soteringsordning_vid_export
+Export_sorting=Sortering_vid_export
+Newline_separator=Radbrytningstecken
+
+Save_entries_ordered_as_specified=Spara_poster_som_angivet
+Save_sort_order=
+Show_extra_columns=Visa_extrakolumner
+Parsing_error=
illegal_backslash_expression=
-includes_subgroups=inkluderar_undergrupper
-key=nyckel
-keys_in_database=nycklar_i_databas
-large_capitals_are_not_masked_using_curly_brackets_{}=stora_bokstäver_är_inte_skyddade_med_måsvingar_{}
-link_should_refer_to_a_correct_file_path=länken_ska_ange_en_korrekt_sökväg
-modify_group=ändra_grupp
-move_group=flytta_grupp
-nested_AUX_files=nästlade_AUX-filer
-new=ny
-no_base-BibTeX-file_specified=
-no_database_generated=ingen_databas_genererades
-not=inte
-not_found=hittades_inte
+
+Move_to_group=Flytta_till_grupp
+
+Clear_read_status=Rensa_lässtatus
+Convert_to_BibLatex_format_(for_example,_move_the_value_of_the_'journal'_field_to_'journaltitle')=Konvertera_till_BibLatex-format_(t._ex._genom_att_flytta_data_från_'journal'-fältet_till_'journaltitle'-fältet)
+Deprecated_fields=
+Hide/show_toolbar=Dölj/visa_verktygslist
+No_read_status_information=Ingen_information_om_lässtatus
+Printed=Utskriven
+Read_status=Lässtatus
+Read_status_read=Läst
+Read_status_skimmed=Skummat
+Save_selected_as_plain_BibTeX...=Spara_valda_som_enkel_BibTeX...
+Set_read_status_to_read=Sätt_lässtatus_till_läst
+Set_read_status_to_skimmed=Sätt_lässtatus_till_skummat
+Show_deprecated_BibTeX_fields=
+
+Show_gridlines=Visa_rutnät
+Show_printed_status=Visa_utskriftsstatus
+Show_read_status=Visa_lässtatus
+Table_row_height_padding=Extra_höjd_på_tabellrader
+
+Marked_selected_entry=Markerade_vald_post
+Marked_all_%0_selected_entries=Markerade_alla_%0_valda_poster
+Unmarked_selected_entry=Avmarkerade_valda_poster
+Unmarked_all_%0_selected_entries=Avmarkerade_alla_%0_valda_poster
+Toggle_print_status=Växla_utskriftsstatus
+
+
+Unmarked_all_entries=Avmarkerade_alla_poster
+
+Unable_to_find_the_requested_look_and_feel_and_thus_the_default_one_is_used.=
+
+Opens_JabRef's_GitHub_page=Öppnar_JabRefs_GitHub-sida
+Could_not_open_browser.=Kunde_inte_öppna_webbläsaren.
+Please_open_%0_manually.=Öppna_%0_för_hand.
+The_link_has_been_copied_to_the_clipboard.=Länken_har_kopierats_till_urklipp.
+
+Open_%0_file=Öppna_%0-fil
+
+Cannot_delete_file=Kan_inte_radera_fil
+File_permission_error=Rättighetsfel_för_fil
+Push_to_%0=Infoga_i_%0
+Path_to_%0=Sökväg_till_%0
+Convert=Konvertera
+Normalize_to_BibTeX_name_format=
+Help_on_Name_Formatting=Hjälp_för_namnformattering
+
+Add_new_file_type=Lägg_till_ny_filtyp
+
+Left_entry=Vänster_post
+Right_entry=Höger_post
+Use=Använd
+Original_entry=Ursprunglig_post
+Replace_original_entry=Ersätt_ursprunglig_post
+No_information_added=Ingen_information_tillagd
+Select_at_least_one_entry_to_manage_keywords.=Välj_åtminstone_en_post_för_att_hantera_nyckelord.
+OpenDocument_text=OpenDocument-text
+OpenDocument_spreadsheet=OpenDocument-kalkylark
+OpenDocument_presentation=OpenDocument-presentation
+%0_image=%0-bild
+Added_entry=Lade_till_post
+Modified_entry=Ändrad_post
+Deleted_entry=Raderade_post
+Modified_groups_tree=Modifierade_gruppträd
+Removed_all_groups=Tog_bort_alla_grupper
+Accepting_the_change_replaces_the_complete_groups_tree_with_the_externally_modified_groups_tree.=Om_ändringarna_accepteras_så_kommer_hela_gruppträdet_att_ersättas_av_det_externt_ändrade_gruppträdet.
+Select_export_format=
+Return_to_JabRef=Återgå_till_JabRef
+Please_move_the_file_manually_and_link_in_place.=
+Could_not_connect_to_%0=Kunde_inte_ansluta_till_%0
+Warning\:_%0_out_of_%1_entries_have_undefined_BibTeX_key.=Varning\:_%0_av_%1_poster_har_odefinierade_BibTeX-nycklar.
occurrence=förekomst
-occurrences=förekomster
-or=eller
-pairs_processed=par_processade
-paste_entries=klistra_in_poster
-paste_entry=klistra_in_post
-paste_text_here=klistra_in_text_här
-plain_text=klartext
-refines_supergroup=
-regular_expression=reguljärt_uttryck
-remove_group_(keep_subgroups)=ta_bort_grupp_(behåll_undergrupper)
-remove_group_and_subgroups=ta_bort_grupp_och_undergrupper
-resolved=
-search_expression=sökuttryck
-should_contain_a_four_digit_number=ska_innehålla_ett_fyrsiffrigt_tal
-should_contain_a_protocol=ska_innehålla_ett_protokoll
-should_contain_a_valid_page_number_range=ska_innehålla_ett_giltligt_sidintervall
-should_end_with_a_name=ska_avslutas_med_ett_namn
+Added_new_'%0'_entry.=Lade_till_ny_'%0'-post.
+Multiple_entries_selected._Do_you_want_to_change_the_type_of_all_these_to_'%0'?=Flera_poster_valda._Vill_du_ändra_typen_för_alla_dessa_till_'%0'?
+Changed_type_to_'%0'_for=Ändrade_typ_till_'%0'_för
+Really_delete_the_selected_entry?=Verkligen_ta_bort_den_valda_posten?
+Really_delete_the_%0_selected_entries?=Verkligen_ta_bort_de_%0_valda_posterna?
+Keep_merged_entry_only=Behåll_bara_sammanslagen_post
+Keep_left=Behåll_vänstra
+Keep_right=Behåll_högra
+Old_entry=Gammal_post
+From_import=Från_import
+No_problems_found.=Inga_problem_hittades.
+%0_problem(s)_found=%0_problem_hittades
+Save_changes=Spara_ändringar
+Discard_changes=Ignorera_ändringar
+Database_'%0'_has_changed.=Databasen_'%0'_har_ändrats.
+Print_entry_preview=Skriv_ut_postvisning
+Copy_\\cite{BibTeX_key}=Kopiera_\\cite{BibTeX-nyckel}
+Copy_BibTeX_key_and_title=Kopiera_BibTeX-nyckel_och_titel
+File_rename_failed_for_%0_entries.=Döpa_om_filen_misslyckades_för_%0_poster.
+To_set_up,_go_to=För_att_ställa_in,_gå_till
+Merged_BibTeX_source_code=Kombinerad_BibTeX-källkod
+Invalid_DOI\:_'%0'.=Ogiltig_DOI\:_'%0'.
should_start_with_a_name=ska_börja_med_ett_namn
-sort_subgroups=sortera_undergrupper
-source_edit=ändring_av_källkod
-static_group=statisk_grupp
-the_field_<b>%0</b>=fältet_<b>%0</b>
-type=typ
-unable_to_write_to=kan_inte_skriva_till
+should_end_with_a_name=ska_avslutas_med_ett_namn
unexpected_closing_curly_bracket=oväntad_avslutande_måsvinge
unexpected_opening_curly_bracket=oväntad_startande_måsvinge
-unknown_edit=okänd_ändring
-untitled=namnlös
-usage=användning
+capital_letters_are_not_masked_using_curly_brackets_{}=stora_bokstäver_är_inte_skyddade_med_måsvingar_{}
+should_contain_a_four_digit_number=ska_innehålla_ett_fyrsiffrigt_tal
+should_contain_a_valid_page_number_range=ska_innehålla_ett_giltligt_sidintervall
+Filled=Fyllde
+Field_is_missing=Fält_saknas
+Search_%0=Sök_%0
+
+Search_results_in_all_databases_for_%0=Söker_efter_%0_i_alla_databaser
+Search_results_in_database_%0_for_%1=Söker_efter_%1_i_databasen_%0
+Search_globally=Sök_globalt
+No_results_found.=Inga_resultat_hittades.
+Found_%0_results.=Hittade_%0_resultat.
+Advanced_search_active.=Avancerad_sökning_aktiv.
+Normal_search_active.=Normal_sökning_aktiv.
+plain_text=klartext
+This_search_contains_entries_in_which_any_field_contains_the_regular_expression_<b>%0</b>=Denna_sökning_innehåller_poster_där_något_fält_innehåller_det_reguljära_uttrycket_<b>%0</b>
+This_search_contains_entries_in_which_any_field_contains_the_term_<b>%0</b>=Denna_sökning_innehåller_poster_där_något_fält_innehåller_termen_<b>%0</b>
+This_search_contains_entries_in_which=Denna_sökning_innehåller_poster_där
+
+Unable_to_autodetect_OpenOffice/LibreOffice_installation._Please_choose_the_installation_directory_manually.=Kan_inte_hitta_OpenOffice/LibreOffice._Ställ_in_sökvägar_manuellt.
+JabRef_no_longer_supports_'ps'_or_'pdf'_fields.<br>File_links_are_now_stored_in_the_'file'_field_and_files_are_stored_in_an_external_file_directory.<br>To_make_use_of_this_feature,_JabRef_needs_to_upgrade_file_links.<br><br>=
+This_database_uses_outdated_file_links.=Denna_databas_använder_utdaterade_fillänkar.
+
+Clear_search=Rensa_sökning
+Close_database=Stäng_databas
+Close_entry_editor=Stäng_posteditor
+Decrease_table_font_size=Minska_typsnittsstorlek_för_tabellen
+Entry_editor,_next_entry=Posteditor,_nästa_post
+Entry_editor,_next_panel=Posteditor,_nästa_panel
+Entry_editor,_next_panel_2=Posteditor,_nästa_panel_2
+Entry_editor,_previous_entry=Posteditor,_föregående_post
+Entry_editor,_previous_panel=Posteditor,_föregående_panel
+Entry_editor,_previous_panel_2=Posteditor,_föregående_panel_2
+Entry_editor,_store_field=Posteditor,_spara_fält
+File_list_editor,_move_entry_down=
+File_list_editor,_move_entry_up=
+Focus_entry_table=Fokusera_tabellen
+Import_into_current_database=Importera_till_nuvarande_databas
+Import_into_new_database=Importera_till_ny_databas
+Increase_table_font_size=Öka_typsnittsstorlek_för_tabellen
+New_article=Ny_article-post
+New_book=Ny_book-post
+New_entry=Ny_post
+New_from_plain_text=Ny_från_text
+New_inbook=Ny_inbook-post
+New_mastersthesis=Ny_mastersthesis-post
+New_phdthesis=Ny_phdthesis-post
+New_proceedings=Ny_proceedings-post
+New_unpublished=Ny_unpublished-post
+Next_tab=Nästa_flik
+Preamble_editor,_store_changes=Preamble-editorn,_spara_ändringar
+Previous_tab=Föregående_flik
+Push_to_application=Infoga_i_program
+Refresh_OpenOffice/LibreOffice=Uppdatera_OpenOffice/LibreOffice
+Resolve_duplicate_BibTeX_keys=Hantera_BibTeX-nyckeldubbletter
+Save_all=Spara_alla
+String_dialog,_add_string=Strängdialog,_lägg_till_sträng
+String_dialog,_remove_string=Strängdialog,_ta_bort_sträng
+Synchronize_files=Synkronisera_filer
+Unabbreviate=Expandera_förkortning
+should_contain_a_protocol=ska_innehålla_ett_protokoll
+Copy_preview=Kopiera_postvisning
+Automatically_setting_file_links=Skapar_fillänkar_automatiskt
+Regenerating_BibTeX_keys_according_to_metadata=Generera_BibTeX-nycklar_enligt_metadata
+No_meta_data_present_in_BIB_file._Cannot_regenerate_BibTeX_keys=
+Regenerate_all_keys_for_the_entries_in_a_BibTeX_file=Generera_BibTeX-nycklar_för_alla_poster_i_en_BibTeX-fil
+Show_debug_level_messages=Visa_fler_felmeddelanden_för_avlusning
+Default_bibliography_mode=Standardläge_för_databas
+New_%0_database_created.=Ny_%0-databas_skapades.
+Show_only_preferences_deviating_from_their_default_value=Visa_bara_inställningar_som_skiljer_från_sitt_standardvärde
+default=standard
+key=nyckel
+type=typ
value=värde
-verify_that_LyX_is_running_and_that_the_lyxpipe_is_valid=kontrollera_att_LyX_körs_och_att_lyxpipe_är_korrekt
-web_link=weblänk
-with=med
+Show_preferences=Visa_inställningar
+Save_actions=Händelser_vid_sparning
+Enable_save_actions=Aktivera_automatiska_händelser_vid_sparning
+
+Other_fields=Andra_fält
+Show_remaining_fields=Visa_kvarvarande_fält
+
+link_should_refer_to_a_correct_file_path=länken_ska_ange_en_korrekt_sökväg
+abbreviation_detected=förkortning_upptäcktes
wrong_entry_type_as_proceedings_has_page_numbers=fel_posttyp_eftersom_proceeding_har_sidnummer
-%0_import_canceled=Import_från_%0_avbruten
+Abbreviate_journal_names=Förkorta_tidskriftsnamn
+Abbreviating...=Förkortar...
+Adding_fetched_entries=Lägger_till_hämtade_poster
+Display_keywords_appearing_in_ALL_entries=Visa_nyckelord_som_finns_i_ALLA_poster
+Display_keywords_appearing_in_ANY_entry=Visa_nyckelord_som_finns_i_NÅGON_post
+Fetching_entries_from_Inspire=Hämtar_poster_från_Inspire
+None_of_the_selected_entries_have_BibTeX_keys.=Ingen_av_de_valda_posterna_har_någon_BibTeX-nyckel.
+Unabbreviate_journal_names=Expandera_förkortade_tidskriftsnamn
+Unabbreviating...=Expanderar_förkortningar...
+Usage=Användning
+
+Adds_{}_brackets_around_acronyms,_month_names_and_countries_to_preserve_their_case.=
+Are_you_sure_you_want_to_reset_all_settings_to_default_values?=Är_du_säker_att_du_vill_återställa_alla_inställningar_till_standardvärden?
+Reset_preferences=Återställ_inställningar
+Ill-formed_entrytype_comment_in_BIB_file=
+
+Move_linked_files_to_default_file_directory_%0=Flytta_länkade_filer_till_standardfilmappen_%0
+
+Clipboard=Urklipp
+Could_not_paste_entry_as_text\:=Kunde_inte_klista_in_post_so_text\:
+Do_you_still_want_to_continue?=Vill_du_fortfarande_fortsätta`?
+This_action_will_modify_the_following_field(s)_in_at_least_one_entry_each\:=
+This_could_cause_undesired_changes_to_your_entries.=Detta_kan_leda_till_oönskade_effekter_för_dina_poster.
+Run_field_formatter\:=
+Table_font_size_is_%0=Typsnittstorlek_för_tabellen_är_%0
+%0_import_canceled=Import_från_%0_avbruten
Internal_style=Intern_stil
Add_style_file=Lägg_till_stilfil
Are_you_sure_you_want_to_remove_the_style?=Är_du_säker_på_att_du_vill_ta_bort_stilen?
@@ -1368,6 +2040,7 @@ Converts_HTML_code_to_Unicode.=Konverterar_HTML-koder_till_Unicode-tecken.
Converts_LaTeX_encoding_to_Unicode_characters.=Konverterar_Latex-koder_till_Unicode-tecken.
Converts_Unicode_characters_to_LaTeX_encoding.=Konverterar_Unicode-tecken_till_LaTeX-kod.
Converts_ordinals_to_LaTeX_superscripts.=Konverterar_ordningsnummer_till_LaTeX_\\superscript{}.
+Converts_units_to_LaTeX_formatting.=Formatterar_enheter_så_att_det_ser_bra_ut
HTML_to_LaTeX=HTML_till_LaTeX
LaTeX_cleanup=LaTeX-städning
LaTeX_to_Unicode=LaTeX_till_Unicode
@@ -1375,6 +2048,7 @@ Lower_case=Gemener
Minify_list_of_person_names=Minimera_personlista
Normalize_date=Normalisera_datum
Normalize_month=Normalisera_månader
+Normalize_month_to_BibTeX_standard_abbreviation.=Nomralisera_månader_till_BibTeX-standardförkortning.
Normalize_names_of_persons=Normalisera_personnamn
Normalize_page_numbers=Normalisera_sidnummer
Normalize_pages_to_BibTeX_standard.=Normaliserar_sidnummer_till_BibTeX-standard.
@@ -1390,19 +2064,13 @@ Title_case=
Unicode_to_LaTeX=Unicode_till_LaTeX
Units_to_LaTeX=Enheter_till_LaTeX
Upper_case=Versaler
+Does_nothing.=Gör_ingenting.
Identity=Identitet
-
Clears_the_field_completely.=Tömmer_fältet_helt.
Directory_not_found=Kan_ej_hitta_mapp
Main_file_directory_not_set\!=Huvudfilmapp_ej_satt\!
-
This_operation_requires_exactly_one_item_to_be_selected.=Denna_operationen_kräver_att_exakt_en_post_är_vald.
-
-Normalize_month_to_BibTeX_standard_abbreviation.=Nomralisera_månader_till_BibTeX-standardförkortning.
-
-Move_linked_files_to_default_file_directory_%0=Flytta_länkade_filer_till_standardfilmappen_%0
Importing_in_%0_format=Importerar_i_%0-format
-
Female_name=Ett_kvinnonamn
Female_names=Flera_kvinnonamn
Male_name=Ett_mansnamn
@@ -1411,8 +2079,6 @@ Mixed_names=_Blandade_namn
Neuter_name=Ett_neutrumnamn
Neuter_names=Flera_neutrumnamn
-
-
Lookup_DOI=Leta_efter_DOI
Audio_CD=Ljud-CD
@@ -1456,11 +2122,10 @@ Plain_text=Klartext
Show_diff=Visa_skillnad
character=bokstav
word=ord
-
Show_symmetric_diff=Visa_skillnad_symmetriskt
-booktitle_ends_with_'conference_on'=boktiteln_slutar_med_'conference_on'
HTML_encoded_character_found=HTML-kodade_tecken_hittades
+booktitle_ends_with_'conference_on'=boktiteln_slutar_med_'conference_on'
All_external_files=Alla_externa_filer
@@ -1468,18 +2133,11 @@ OpenOffice/LibreOffice_integration=OpenOffice/LibreOffice-integration
incorrect_control_digit=felaktig_kontrollsiffra
incorrect_format=felaktigit_format
-
-Expected_"%0"_to_contain_whitespace=Förväntade_"%0"_att_innehålla_mellanslag
-Syntax_error_in_regular-expression_pattern=Syntaxfel_i_det_reguljära_uttrycket
-
Copy_version_to_clipboard=Kopiera_version_till_urklipp
Copied_version_to_clipboard=Kopierade_version_till_urklipp
BibTeX_key=BibTeX-nyckel
Message=Meddelande
-
-Get_fulltext=Hämta_dokument
-Download_from_URL=Ladda_ned_från_URL
Decryption_not_supported.=Avkryptering_stöds_ej.
Cleared_'%0'_for_%1_entries=Rensade_'%0'_för_%1_poster
@@ -1498,15 +2156,11 @@ To_see_what_is_new_view_the_changelog.=För_att_få_reda_på_vad_som_är_nytt_se
A_new_version_of_JabRef_has_been_released.=En_ny_version_av_JabRef_har_släppts-
JabRef_is_up-to-date.=JabRef_är_uppdaterad.
Latest_version=Senaste_version
-
-Please_open_%0_manually.=Öppna_%0_för_hand.
-
-The_link_has_been_copied_to_the_clipboard.=Länken_har_kopierats_till_urklipp.
-
Online_help_forum=Onlineforum
Custom=Egna
-
+Export_cited=Exportera_citerade
+Unable_to_generate_new_database=Kan_inte_generera_ny_databas
Open_console=Öppna_konsoll
Use_default_terminal_emulator=Använd_standardterminalen
@@ -1514,32 +2168,22 @@ Execute_command=Kör_kommando
Note\:_Use_the_placeholder_%0_for_the_location_of_the_opened_database_file.=Använd_%0_för_att_infoga_mappen_för_databasfilen.
Executing_command_\"%0\"...=Kör_kommandot_\"%0\"...
Error_occured_while_executing_the_command_\"%0\".=Fel_när_kommandot_\"%0\"_kördes.
-
Reformat_ISSN=Formattera_om_ISSN
-Unable_to_generate_new_database=Kan_inte_generera_ny_databas
-
-Export_cited=Exportera_citerade
-
Countries_and_territories_in_English=Länder_och_territorier_på_engelska
Electrical_engineering_terms=Elektrotekniktermer
Enabled=Aktiverad
Internal_list=Intern_lista
+Manage_protected_terms_files=Hantera_filer_med_skyddade_ord
Months_and_weekdays_in_English=Månader_och_veckodagar_på_engelska
The_text_after_the_last_line_starting_with_\#_will_be_used=Texten_efter_sista_raden_som_startar_med_\#_kommer_användas
-
Add_protected_terms_file=Lägg_till_fil_med_skyddade_ord
Are_you_sure_you_want_to_remove_the_protected_terms_file?=Är_du_säker_på_att_du_vill_ta_bort_filen_med_skyddade_ord?
Remove_protected_terms_file=Ta_bort_fil_med_skyddade_ord
-
-Manage_protected_terms_files=Hantera_filer_med_skyddade_ord
-
Add_selected_text_to_list=Lägg_till_markerad_text_till_lista
Add_{}_around_selected_text=Lägg_till_{}_runt_markerad_text
Format_field=Formattera_fält
New_protected_terms_file=Ny_lista_med_skyddade_ord
-
-
change_field_%0_of_entry_%1_from_%2_to_%3=ändra_fält_%0_för_post_%1_från_%2_till_%3
change_key_from_%0_to_%1=ändra_nyckel_från_%0_till_%1
change_string_content_%0_to_%1=ändra_stränginnehåll_från_%0_till_%1
@@ -1549,38 +2193,29 @@ insert_entry_%0=infoga_post_%0
insert_string_%0=infoga_sträng_%0
remove_entry_%0=ta_bort_post_%0
remove_string_%0=ta_bort_sträng_%0
-
undefined=odefinierad
-
-
Cannot_get_info_based_on_given_%0\:_%1=Kan_inte_hämta_info_från_det_angivna_%0\:_%1
-
Get_BibTeX_data_from_%0=Hämta_BibTeX-data_från_%0
No_%0_found=Inget_%0_hittades
Entry_from_%0=Post_från_%0
-
Merge_entry_with_%0_information=Kombinera_post_med_information_från_%0
Updated_entry_with_info_from_%0=Uppdaterade_post_med_information_från_%0
Connection=Anslutning
+Connecting...=Ansluter...
Host=Värd
Port=Port
Database=Databas
User=Användare
+Connect=Anslut
Connection_error=Anslutningsfel
-Driver_error=
Connection_to_%0_server_established.=Anslutning_till_%0-server_skapades.
Required_field_"%0"_is_empty.=Det_obligatoriska_fältet_"%0"_är_tomt.
-
%0_driver_not_available.=
-
The_connection_to_the_server_has_been_terminated.=Anslutningen_till_servern_avbröts.
-
Connection_lost.=Anslutningen_förlorades.
Reconnect=Anslut_igen
Work_offline=Arbeta_frånkopplad
-
Working_offline.=Arbetar_frånkopplad.
-
Update_refused.=Uppdateringen_avvisades.
Update_refused=Uppdateringen_avvisades
Local_entry=Lokal_post
@@ -1591,7 +2226,12 @@ Local_version\:_%0=Lokal_version\:_%0
Shared_version\:_%0=Delad_version\:_%0
Please_merge_the_shared_entry_with_yours_and_press_"Merge_entries"_to_resolve_this_problem.=
Canceling_this_operation_will_leave_your_changes_unsynchronized._Cancel_anyway?=Om_denna_operation_avbryts_kommer_din_ändringar_ej_bli_synkroniserade._Avbryt_ändå?
-The_BibEntry_you_currently_work_on_has_been_deleted_on_the_shared_side._Hit_"Keep"_to_recover_the_entry.=Posten_du_arbetar_med_har_tagits_bort_från_den_delade_databasen,_Tryck_"Behåll"_för_att_återskapa_posten.
+Shared_entry_is_no_longer_present=
+The_BibEntry_you_currently_work_on_has_been_deleted_on_the_shared_side.=Posten_du_arbetar_med_har_tagits_bort_från_den_delade_databasen.
+You_can_restore_the_entry_using_the_"Undo"_operation.=
+Remember_password?=Kom_ihåg_lösenord?
+You_are_already_connected_to_a_database_using_entered_connection_details.=
+
Cannot_cite_entries_without_BibTeX_keys._Generate_keys_now?=Kan_inte_citera_poster_utan_BibTeX-nycklar._Generera_nycklar_nu?
New_technical_report=Ny_teknisk_rapport
@@ -1601,34 +2241,74 @@ Protected_terms_file=Fil_med_skyddade_termer
Style_file=Stilfil_för_OpenOffice/LibreOffice
Open_OpenOffice/LibreOffice_connection=Öppna_OpenOffice/LibreOffice-anslutning
-
You_must_enter_at_least_one_field_name=Du_måste_ange_minst_ett_fältnamn
-
-
Non-ASCII_encoded_character_found=Bokstäver_som_inte_är_ASCII-kodade_hittades
-
Toggle_web_search_interface=Växla_webbsökning
-
Background_color_for_resolved_fields=Bakgrundsfärg_för_uppslagna_fält
Color_code_for_resolved_fields=Färgkodning_av_uppslagna_fält
-
%0_files_found=%0_filer_hittades
%0_of_%1=%0_av_%1
One_file_found=En_fil_hittades
The_import_finished_with_warnings\:=Importen_avslutades_med_varningar\:
There_was_one_file_that_could_not_be_imported.=Det_fanns_en_fil_som_ej_kunde_importeras.
There_were_%0_files_which_could_not_be_imported.=Det_fanns_%0_filer_som_ej_kunde_importeras.
+
Migration_help_information=Migrationshjälp
Entered_database_has_obsolete_structure_and_is_no_longer_supported.=
However,_a_new_database_was_created_alongside_the_pre-3.6_one.=
-
Click_here_to_learn_about_the_migration_of_pre-3.6_databases.=Klicka_här_för_att_se_mer_information_om_migration_av_databaser_från_innan_version_3.6.
-
-Connecting...=Ansluter...
-
Opens_JabRef's_Facebook_page=Öppnar_Jabrefs_Facebooksida
Opens_JabRef's_blog=Öppnar_Jabrefs_blogg
Opens_JabRef's_website=Öppnar_JabRefs_hemsida
-
Opens_a_link_where_the_current_development_version_can_be_downloaded=Öpnnar_en_länk_där_den_senaste_utvecklingsversionen_kan_laddas_ned
See_what_has_been_changed_in_the_JabRef_versions=Se_vad_som_har_ändrats_i_de_olika_JabRef-versionerna
+Referenced_BibTeX_key_does_not_exist=Refererad_BibTeX-nyckel_finns_ej
+Finished_downloading_full_text_document_for_entry_%0.=
+Full_text_document_download_failed_for_entry_%0.=
+Look_up_full_text_documents=
+You_are_about_to_look_up_full_text_documents_for_%0_entries.=
+last_four_nonpunctuation_characters_should_be_numerals=
+shared=delad
+should_contain_an_integer_or_a_literal=
+should_have_the_first_letter_capitalized=
+
+ID=
+ID_type=
+ID-based_entry_generator=
+Fetcher_'%0'_did_not_find_an_entry_for_id_'%1'.=
+
+Select_first_entry=
+Select_last_entry=
+
+Invalid_ISBN\:_'%0'.=
+should_be_an_integer_or_normalized=
+should_be_normalized=
+
+Empty_search_ID=
+The_given_search_ID_was_empty.=
+Copy_BibTeX_key_and_link=
+empty_BibTeX_key=
+BibLaTeX_field_only=
+
+Error_while_generating_fetch_URL=
+Error_while_parsing_ID_list=
+Unable_to_get_PubMed_IDs=
+Backup_found=
+A_backup_file_for_'%0'_was_found.=
+This_could_indicate_that_JabRef_did_not_shut_down_cleanly_last_time_the_file_was_used.=
+Do_you_want_to_recover_the_database_from_the_backup_file?=
+Firstname_Lastname=
+
+Recommended_for_%0=
+This_might_be_caused_by_reaching_the_traffic_limitation_of_Google_Scholar_(see_'Help'_for_details).=
+
+Problem_downloading_from_%1=
+
+File_directory_pattern=
+Update_with_bibliographic_information_from_the_web=
+
+Could_not_find_any_bibliographic_information.=
+BibTeX_key_%0_deviates_from_generated_key_%1=
+DOI_%0_is_invalid=
+
+Jump_to_entry=
diff --git a/src/main/resources/l10n/JabRef_tr.properties b/src/main/resources/l10n/JabRef_tr.properties
index d81081c..3598678 100644
--- a/src/main/resources/l10n/JabRef_tr.properties
+++ b/src/main/resources/l10n/JabRef_tr.properties
@@ -1,764 +1,1396 @@
#!
-#! created/edited by Popeye version 0.55 (https\://github.com/koppor/popeye)
+#! created/edited by Popeye version 0.55 (github.com/JabRef/popeye)
#! encoding:UTF-8
+
%0_contains_the_regular_expression_<b>%1</b>=%0_şu_Düzenli_İfadeyi_içeriyor_<b>%1</b>
+
%0_contains_the_term_<b>%1</b>=%0_şu_terimi_içeriyor_<b>%1</b>
+
%0_doesn't_contain_the_regular_expression_<b>%1</b>=%0_şu_Düzenli_İfadeyi_içermiyor_<b>%1</b>
+
%0_doesn't_contain_the_term_<b>%1</b>=%0_şu_terimi_içermiyor_<b>%1</b>
+
%0_export_successful=%0_dışa_aktarım_başarılı
+
%0_matches_the_regular_expression_<b>%1</b>=%0_şu_Düzenli_İfadeyle_eşleşiyor_<b>%1</b>
+
%0_matches_the_term_<b>%1</b>=%0_şu_terimle_eşleşiyor_<b>%1</b>
-<field_name>=<alan_adı>
+
<HTML>Could_not_find_file_'%0'<BR>linked_from_entry_'%1'</HTML>=<HTML>'%1'_girdisinden_bağlantılı<BR>'%0'_dosyası_bulunamadı</HTML>
+
<select>=<seç>
-<select_word>=<sözcük_seç>
+
Abbreviate_journal_names_of_the_selected_entries_(ISO_abbreviation)=Seçili_girdilerin_dergi_isimlerini_kısalt_(ISO_kısaltması)
Abbreviate_journal_names_of_the_selected_entries_(MEDLINE_abbreviation)=Seçili_girdilerin_dergi_isimlerini_kısalt_(MEDLINE_kısaltması)
+
Abbreviate_names=İsimleri_kısalt
Abbreviated_%0_journal_names.=Kısaltılmış_%0_dergi_isimleri.
+
Abbreviation=Kısaltma
+
About_JabRef=JabRef_Hakkında
+
Abstract=Özet
+
Accept=Kabul_et
+
Accept_change=Değişikliği_kabul_et
+
Action=Eylem
+
Add=Ekle
-Add_a_(compiled)_custom_ImportFormat_class_from_a_class_path.=Bir_sınıf_yolundan_(derlenmiş)_özel_İçeAlmaBiçemi_sınıfı_ekle.
+
+Add_a_(compiled)_custom_Importer_class_from_a_class_path.=Bir_sınıf_yolundan_(derlenmiş)_özel_İçeAlmaBiçemi_sınıfı_ekle.
The_path_need_not_be_on_the_classpath_of_JabRef.=Yolun_JabRef'in_sınıf_yolunda_olması_gerekmez.
-Add_a_(compiled)_custom_ImportFormat_class_from_a_ZIP-archive.=Bir_ZIP_arşivinden_(derlenmiş)_özel_İçeAlmaBiçemi_sınıfı_ekle.
+
+Add_a_(compiled)_custom_Importer_class_from_a_ZIP-archive.=Bir_ZIP_arşivinden_(derlenmiş)_özel_İçeAlmaBiçemi_sınıfı_ekle.
The_ZIP-archive_need_not_be_on_the_classpath_of_JabRef.=Yolun_JabRef'in_sınıf_yolunda_olması_gerekmez.
+
Add_entry_selection_to_this_group=Bu_gruba_girdi_seçimini_ekle
+
Add_from_folder=Klasörden_ekle
+
Add_from_JAR=Jar'dan_ekle
+
add_group=grup_ekle
+
Add_group=Grup_Ekle
+
Add_new=Yeni_ekle
+
Add_subgroup=Altgrup_ekle
+
Add_to_group=Gruba_ekle
+
Added_group_"%0".="%0"_grubu_eklendi.
+
Added_new=Yeni_eklendi
+
Added_string=Dizgi_eklendi
+
Additionally,_entries_whose_<b>%0</b>_field_does_not_contain_<b>%1</b>_can_be_assigned_manually_to_this_group_by_selecting_them_then_using_either_drag_and_drop_or_the_context_menu._This_process_adds_the_term_<b>%1</b>_to_each_entry's_<b>%0</b>_field._Entries_can_be_removed_manually_from_this_group_by_selecting_them_then_using_the_context_menu._This_process_removes_the_term_<b>%1</b>_from_each_entry's_<b>%0</b>_field.=Ek_olarak,_<b>%0</b>_alanları_<b>%1</b>_içermeyen_girdiler_seçilip,_bu_ [...]
+
Advanced=Gelişmiş
All_entries=Tüm_girdiler
All_entries_of_this_type_will_be_declared_typeless._Continue?=Bu_türeden_tüm_girdiler_türsüz_olarak_bildirilecek._Devam_edilsin_mi?
+
All_fields=Tüm_alanlar
+
All_subgroups_(recursively)=Tüm_alt-gruplar_(özyinelemeli)
-An_exception_occurred_while_accessing_'%0'='%0''e_erişilirken_bir_istisna_oluştu
+
+Always_reformat_BIB_file_on_save_and_export=Kaydetme_ve_dışa_aktarmada_BIB_dosyasını_her_zaman_yeniden_biçemle
+
A_SAX_exception_occurred_while_parsing_'%0'\:='%0'_ayrıştırılırken_bir_SAXİstisnası_oluştu\:
+
and=ve
and_the_class_must_be_available_in_your_classpath_next_time_you_start_JabRef.=ve_bir_dahaki_sefer_JabRef'i_başlattığınızda_sınıf_sınıf_yolunuzda_bulunmalıdır.
+
any_field_that_matches_the_regular_expression_<b>%0</b>=<b>%0</b>_düzenli_ifadesine_uyan_herhangi_bir_alan
+
Appearance=Görünüm
+
Append=Sonuna_ekle
Append_contents_from_a_BibTeX_database_into_the_currently_viewed_database=Bir_BibTeX_veritabanının_içeriğini_halen_görüntülenen_veritabanının_sonuna_ekle
+
Append_database=Veritabanını_sonuna_ekle
+
Append_the_selected_text_to_BibTeX_field=Seçili_metni_BibTeX_anahtarının_sonuna_ekle
Application=Uygulama
+
Apply=Uygula
+
Arguments_passed_on_to_running_JabRef_instance._Shutting_down.=Argümanlar_çalışan_JabRef_oturumuna_aktarıldı._Kapatılıyor.
+
Assign_entry_selection_exclusively_to_this_group=Girdi_seçimini_özellikle_bu_gruba_ata
+
Assign_new_file=Yeni_dosya_ata
+
Assign_the_original_group's_entries_to_this_group?=Orijinal_grubun_girdileri_bu_gruba_atansın_mı?
+
Assigned_%0_entries_to_group_"%1".=%0_girdi_"%1"_grubuna_atandı.
+
Assigned_1_entry_to_group_"%0".=Bir_girdi_"%0"_grubuna_atandı.
+
Attach_URL=URL_ekle
+
Attempt_to_automatically_set_file_links_for_your_entries._Automatically_setting_works_if_a_file_in_your_file_directory<BR>or_a_subdirectory_is_named_identically_to_an_entry's_BibTeX_key,_plus_extension.=Girdileriniz_için_dosya_link_otokurma_girişiminde_bulunuluyor._Otokur,_eğer_dosya_dizinindeki_ya_da_bir_<BR>_altdizinindeki_dosyası_bir_BibTeX_anahtarıyla_özdeş_adlandırılmış_artı_uzantılandılılmışsa_çalışır.
+
Auto=Oto
+
Autodetect_format=Biçemi_otomatik_tanı
+
Autogenerate_BibTeX_keys=BibTeX_anahtarlarını_otomatik_oluştur
+
Autolink_files_with_names_starting_with_the_BibTeX_key=Adları_BibTeX_anahtarıyla_başlayan_dosyaları_otomatik_bağla
+
Autolink_only_files_that_match_the_BibTeX_key=Yalnızca_BibTeX_anahtarıyla_eşleşen_dosyaları_otomatik_bağla
+
Automatically_create_groups=Grupları_otomatik_oluştur
+
Automatically_create_groups_for_database.=Veritabanı_için_grupları_otomatik_oluştur
+
Automatically_created_groups=Otomatik_oluşturulmuş_gruplar
+
Automatically_remove_exact_duplicates=Tıpkı_çift_nüshaları_otomatik_sil
+
Allow_overwriting_existing_links.=Mevcut_linklerin_üzerine_yazmaya_izin_ver.
+
Do_not_overwrite_existing_links.=Mevcut_linklerin_üzerine_yazma.
+
AUX_file_import=AUX_dosya_içe_aktarımı
+
Available_export_formats=Mevcut_dışa_aktarım_biçemleri
+
Available_BibTeX_fields=Mevcut_alanlar
+
Available_import_formats=Mevcut_içe_aktarım_biçemleri
+
Background_color_for_optional_fields=Seçmeli_alanlar_için_arkaplan_rengi
+
Background_color_for_required_fields=Zorunlu_alanlar_için_arkaplan_rengi
+
Backup_old_file_when_saving=Kaydederken_eski_dosyayı_yedekle
+
BibTeX_key_is_unique.=BibTeX_anahtarı_benzersizdir.
-BibTeX_source=BibTeX_kaynağı
+
+%0_source=%0_kaynağı
+
Broken_link=Bozuk_link
+
Browse=Göz_at
+
by=ile
+
Cancel=İptal
+
Cannot_add_entries_to_group_without_generating_keys._Generate_keys_now?=Anahtarlar_oluşturulmadan_gruba_girdiler_eklenemez._Anahtarlar_oluşturulsun_mu?
+
Cannot_merge_this_change=Bu_değişiklik_birleştirilemiyor
+
Cannot_move_group_"%0"_down.="%0"_grubu_aşağıya_taşınamıyor.
+
Cannot_move_group_"%0"_left.="%0"_grubu_sola_taşınamıyor.
+
Cannot_move_group_"%0"_right.="%0"_grubu_sağa_taşınamıyor.
+
Cannot_move_group_"%0"_up.="%0"_grubu_yukarıya_taşınamıyor.
+
case_insensitive=büyük/kü.ük_harfe_duyarsız
+
case_sensitive=büyük/küçük_harfe_duyarlı
+
Case_sensitive=Büyük/küçük_harfe_duyarlı
+
change_assignment_of_entries=girdilerin_atanmasını_değiştir
+
Change_case=Büyük/küçük_harf_değiştir
+
Change_entry_type=Girdi_türünü_değiştir
Change_file_type=Dosya_türünü_değiştir
+
+
Change_of_Grouping_Method=Gruplama_Yöntemi_Değişikliği
+
change_preamble=öncülü_değiştir
+
Change_table_column_and_General_fields_settings_to_use_the_new_feature=Yeni_özelliği_kullanmak_için_tablo_sütun_ve_Genel_alan_ayarlarını_değiştirin
+
Changed_font_settings=Font_ayarları_değişti
+
Changed_language_settings=Dil_ayarları_değişti
+
Changed_look_and_feel_settings=Görünüm_ve_tema_ayarları_değişti
+
Changed_preamble=Öncül_değişti
+
Characters_to_ignore=Yoksayılacak_karakterler
+
Check_existing_file_links=Mevcut_dosya_linki_kontrol_ediniz
+
Check_links=Linkleri_kontrol_ediniz
+
Choose_the_URL_to_download.=İndirilecek_URL'i_seçiniz.
Cite_command=Alıntı_komutu
+
Class_name=Sınıf_adı
+
Clear=Sil
+
Clear_fields=Alanları_sil
+
Close=Kapat
Close_others=Diğerlerini_Kapat
Close_all=Tümünü_Kapat
+
Close_dialog=Dialoğu_kapat
+
Close_the_current_database=Güncel_veritabanını_kapat
+
Close_window=Pencereyi_kapat
+
Closed_database=Kapalı_veritabanı
+
Collapse_subtree=Altağacı_daralt
+
Color_codes_for_required_and_optional_fields=Zorunlu_ve_seçmeli_alanlar_için_renk_kodları
+
Color_for_marking_incomplete_entries=Tamamlanmamış_girdileri_işaretlemek_için_renk
+
Column_width=Sütun_genişliği
+
Command_line_id=Komut_satır_no
-Connect=Bağlan
+
+
Contained_in=Şunun_içinde
+
Content=İçerik
+
Copied=Kopyalandı
+
Copied_cell_contents=Hücre_içerikleri_kopyalandı
+
Copied_key=Kopyalanan_anahtar
+
Copied_keys=Kopyalanan_anahtarlar
+
Copy=Kopyala
+
Copy_BibTeX_key=BibTeX_anahtarını_kopyala
Copy_file_to_file_directory=Dosyayı_dosya_dizinine_kopyala
+
Copy_to_clipboard=Panoya_kopyala
+
Could_not_call_executable=Program_çağrılamıyor
Could_not_connect_to_Vim_server._Make_sure_that_Vim_is_running<BR>with_correct_server_name.=Vim_sunucusuna_bağlanılamıyor._Vim'in_doğru_sunucu_adıyla<BR>çalıştığına_emin_olun.
+
Could_not_export_file=Dosya_dışa_aktarılamıyor
+
Could_not_export_preferences=Tercihler_dışa_aktarılamıyor
+
Could_not_find_a_suitable_import_format.=Uygun_içe_aktarım_biçemi_bulunamıyor.
Could_not_import_preferences=Tercihler_içe_aktarılamıyor
+
Could_not_instantiate_%0=%0_somutlaştırılamıyor
Could_not_instantiate_%0_%1=%0_%1_somutlaştırılamıyor
Could_not_instantiate_%0._Have_you_chosen_the_correct_package_path?=%0_somutlaştırılamıyor._Doğru_paket_yolunu_seçmiş_miydiniz?
Could_not_open_link=Link_açılamıyor
+
Could_not_print_preview=Yazdırma_önizlenemiyor
+
Could_not_run_the_'vim'_program.='Vim'_programı_çalıştırılamıyor.
+
Could_not_save_file.=Dosya_kaydedilemiyor.
Character_encoding_'%0'_is_not_supported.='%0'_karakter_kodlaması_desteklenmiyor.
+
Created_groups.=Oluşturulmuş_gruplar.
+
crossreferenced_entries_included=çapraz_bağlantılı_girdiler_dahil_edildi
+
Current_content=Güncel_içerik
+
Current_value=Güncel_değer
+
Custom_entry_types=Özel_girdi_türleri
+
Custom_entry_types_found_in_file=Dosyada_özel_girdi_türleri_bulundu
+
Customize_entry_types=Girdi_türlerini_özelleştir
+
Customize_key_bindings=Tuş_bağlantılarını_özelleştir
+
Cut=Kes
+
cut_entries=girdileri_kes
+
cut_entry=girdiyi_kes
+
+
Database_encoding=Veritabanı_kodlaması
+
Database_properties=Veritabanı_özellikleri
Database_type=Veritabanı_türü
+
Date_format=Tarih_biçemi
+
Default=Öntanımlı
+
Default_encoding=Öntanımlı_kodlama
+
Default_grouping_field=Öntanımlı_gruplama_alanı
+
Default_look_and_feel=Öntanımlı_görünüm_ve_tema
+
Default_pattern=Öntanımlı_desen
+
Default_sort_criteria=Öntanımlı_sıralama_ölçütleri
Define_'%0'='%0'i_tanımla
+
Delete=Sil
+
Delete_custom_format=Özel_biçemi_sil
+
delete_entries=girdileri_sil
+
Delete_entry=Girdiyi_sil
+
delete_entry=girdiyi_sil
+
Delete_multiple_entries=Çok_sayıda_girdiyi_sil
+
Delete_rows=Satırları_sil
+
Delete_strings=Dizgeleri_sil
+
Deleted=Silindi
+
+Delete_local_file=Yerel_dosyayı_sil
+
Delimit_fields_with_semicolon,_ex.=Alanları_ör._noktalı_virgülle_sınırlandır
+
Descending=Azalan
+
Description=Tarif
+
Deselect_all=Tümünün_seçimini_kaldır
Deselect_all_duplicates=Tüm_çift_nüshaların_seçimini_kaldır
+
Disable_this_confirmation_dialog=Bu_onaylama_penceresini_etkisizleştir
+
Display_all_entries_belonging_to_one_or_more_of_the_selected_groups.=Seçili_bir_ya_da_daha_fazla_gruba_ait_tüm_girdileri_göster.
+
Display_all_error_messages=Tüm_hata_mesajlarını_göster
+
Display_help_on_command_line_options=Komut_satırı_seçenekleri_hakkındaki_yardımı_göster
+
Display_only_entries_belonging_to_all_selected_groups.=Yalnızca_seçili_tüm_gruplara_ait_girdileri_göster.
Display_version=Sürümü_göster
+
Displaying_no_groups=Gruplar_gösterilmiyor
+
Do_not_abbreviate_names=İsimleri_kısaltma
+
Do_not_automatically_set=Otomatik_kurma
+
Do_not_import_entry=Girdiyi_içe_aktarma
+
Do_not_open_any_files_at_startup=Başlangıçta_hiçbir_dosyayı_açma
+
Do_not_overwrite_existing_keys=Mevcut_anahtarların_üzerine_yazma
Do_not_show_these_options_in_the_future=Gelecekte_bu_seçenekleri_gösterme
+
Do_not_wrap_the_following_fields_when_saving=Kaydederken_aşağıdaki_alanları_sarmalama
Do_not_write_the_following_fields_to_XMP_Metadata\:=Aşağıdaki_alanları_XMP_Metadata'ya_yazma\:
+
Do_you_want_JabRef_to_do_the_following_operations?=JabRef'in_aşağıdaki_işlemleri_yapmasını_ister_misiniz?
+
+Donate_to_JabRef=JabRef'e_bağış_yap
+
Down=Aşağı
+
Download=İndir
+
Download_file=Dosya_indir
+
Downloading...=İndiriliyor...
Drop_%0=%0'i_bırak
+
duplicate_removal=çift_nüsha_silme
+
Duplicate_string_name=Çift_nüsha_dizge_adı
+
Duplicates_found=Çift_nüshalar_bulundu
+
Dynamic_groups=Devingen_gruplar
+
Dynamically_group_entries_by_a_free-form_search_expression=Serbest_form_arama_ifadesiyle_devingence_grup_girdileri
+
Dynamically_group_entries_by_searching_a_field_for_a_keyword=Bir_alan_ya_da_anahtar_sözcük_aramayla_devingence_grup_girdileri
+
Each_line_must_be_on_the_following_form=Her_satır_aşağıdaki_biçimde_olmalıdır
+
Edit=Düzenle
+
Edit_custom_export=Özel_dışa_aktarımı_düzenle
Edit_entry=Girdiyi_düzenle
Save_file=Dosya_linkini_düzenle
Edit_file_type=Dosya_türünü_düzenle
+
Edit_group=Grubu_düzenle
+
Edit_journal=Dergiyi_düzenle
+
Edit_preamble=Öncülü_düzenle
Edit_strings=Dizgeleri_düzenle
Editor_options=Düzenleyici_seçenekleri
+
Empty_BibTeX_key=Boş_BibTeX_anahtarı
+
Grouping_may_not_work_for_this_entry.=Bu_giriş_için_gruplama_çalışmayabilir.
+
empty_database=boş_veritabanı
Enable_word/name_autocompletion=Sözcük/isim_ototamamlamayı_etkinleştir
+
Enter_URL=URL_gir
+
Enter_URL_to_download=İndirilecek_URL'yi_girin
+
entries=girdiler
+
Entries_cannot_be_manually_assigned_to_or_removed_from_this_group.=Girdiler_elle_bu_gruptan_silinemez_ya_da_bu_gruba_eklenemez.
+
Entries_exported_to_clipboard=Girdiler_panoya_aktarıldı
+
+
entry=girdi
+
Entry_editor=Girdi_düzenleyici
+
Entry_preview=Girdi_önizlemesi
+
Entry_table=Girdi_tablosu
+
Entry_table_columns=Girdi_tablosu_sütunları
+
Entry_type=Girdi_türü
+
Entry_type_names_are_not_allowed_to_contain_white_space_or_the_following_characters=Girdi_türü_adlarının_boşluk_ya_da_aşağıdaki_karakterleri_içermesine_izin_verilmez
+
Entry_types=Girdi_türleri
+
Error=Hata
Error_exporting_to_clipboard=Panoya_aktarmada_hata
+
Error_occurred_when_parsing_entry=Girdi_ayrıştırılırken_hata_oluştu
+
Error_opening_file=Dosya_açmada_hata
+
Error_setting_field=Alan_atamada_hata
Error_while_writing=Yazarken_hata
Error_writing_to_%0_file(s).=%0_dosya(lar)_yazılırken_hata.
+
+
Exceptions=İstisnalar
+
Existing_file=Varolan_dosya
+
'%0'_exists._Overwrite_file?='%0'_mevcut._Dosyanın_üzerine_yazılsın_mı?
Overwrite_file?=_Dosyanın_üzerine_yazılsın_mı?
+
Expand_subtree=Altağacı_genişlet
+
Export=Dışa_aktar
+
Export_name=Adı_dışa_aktar
+
Export_preferences=Tercihleri_dışa_aktar
+
Export_preferences_to_file=Tercihleri_dosyaya_aktar
+
Export_properties=Özellikleri_dışa_aktar
+
Export_to_clipboard=Panoya_aktar
+
Exporting=Dışa_aktarılıyor
Extension=Uzantı
+
External_changes=Harici_değişiklikler
+
External_file_links=Harici_dosya_linkleri
+
External_files=Harici_dosyalar
+
External_programs=Harici_programlar
+
External_viewer_called=Harici_görüntüleyici_çağrıldı
+
Fetch=Getir
+
Field=Alan
+
field=alan
+
Field_name=Alan_adı
Field_names_are_not_allowed_to_contain_white_space_or_the_following_characters=Alan_adlarının_boşluk_ya_da_aşağıdaki_karakterleri_içermesine_izin_verilmez
+
Field_to_filter=Süzülecek_alan
+
Field_to_group_by=Gruplanacak_alan
+
File=Dosya
+
file=dosya
File_'%0'_is_already_open.='%0'_dosyası_zaten_açık.
+
File_'%0'_not_found='%0'_dosyası_bulunamadı
+
File_changed=Dosya_değişti
File_directory_is_'%0'\:=Dosya_dizini_'%0'\:
+
File_directory_is_not_set_or_does_not_exist\!=Dosya_dizini_kurulmadı_ya_da_mevcut_değil\!
File_exists=Dosya_mevcut
+
File_has_been_updated_externally._What_do_you_want_to_do?=Dosya_haricen_değiştirildi._Ne_yapmak_istersiniz?
+
File_not_found=Dosya_bulunamadı
File_type=Dosya_türü
+
File_updated_externally=Dosya_haricen_güncellendi
+
filename=dosya_adı
+
Files_opened=Açılmış_dosyalar
+
Filter=Süzgeç
+
Finished_automatically_setting_external_links.=Harici_linklerin_otokurulması_bitti.
+
Finished_synchronizing_file_links._Entries_changed\:_%0.=Dosya_linkin_eşzamanlaması_bitti._Değişen_girdiler\:_%0.
Finished_writing_XMP-metadata._Wrote_to_%0_file(s).=XMP_metadata_yazımı_bitti._%0_dosyaya_yazıldı.
Finished_writing_XMP_for_%0_file_(%1_skipped,_%2_errors).=%0_dosya_için_XMP_yazımı_bitti_(%1_atlandı,_%2_hata).
+
First_select_the_entries_you_want_keys_to_be_generated_for.=Önce_anahtar_oluşturulmasını_istediğiniz_girdileri_seçiniz.
+
Fit_table_horizontally_on_screen=Tabloyu_ekrana_yatay_sığdır
+
Float=Yüzdür
Float_marked_entries=Yüzdür_işaretlenmiş_girdiler
+
Font_family=Yazıtipi_Ailesi
+
Font_preview=Yazıtipi_Önizleme
+
Font_size=Yazıtipi_Boyutu
+
Font_style=Yazıtipi_Stili
+
Font_selection=YazıtipiSeçici
+
for=için
+
Format_of_author_and_editor_names=Yazar_ve_düzenleyici_adları_biçemi
Format_string=Dizgeyi_Biçimle
+
Format_used=Kullanılan_biçem
Formatter_name=Biçimleyici_Adı
+
found_in_AUX_file=yardımcı_dosyada_bulundu
+
Full_name=Tam_ad
+
General=Genel
+
General_fields=Genel_alanlar
+
Generate=Oluştur
+
Generate_BibTeX_key=BibTeX_anahtarı_oluştur
+
Generate_keys=Anahtarları_oluştur
+
Generate_keys_before_saving_(for_entries_without_a_key)=(Anahtarsız_girdiler_için)_Kaydetmeden_önce_anahtarları_oluştur
Generate_keys_for_imported_entries=İçe_aktarılan_girdiler_için_anahtarları_oluştur
+
Generate_now=Şimdi_oluştur
+
Generated_BibTeX_key_for=Şunun_için_BibTeX_anahtarı_oluşturuldu
+
Generating_BibTeX_key_for=Şunun_için_BibTeX_anahtarı_oluşturuluyor
+Get_fulltext=Tammetni_getir
Grab=Yakala
+
Gray_out_entries_not_in_group_selection=Grup_seçiminde_olmayan_girdileri_grileştir
+
Gray_out_non-hits=İsabet_almayanları_grileştir
+
Groups=Gruplar
+
Have_you_chosen_the_correct_package_path?=Doğru_paket_yolunu_seçtiniz_mi?
+
Help=Yardım
+
Help_on_groups=Gruplar_hakkında_yardım
+
Help_on_key_patterns=Tuş_desenleri_hakkında_yardım
Help_on_regular_expression_search=Düzenli_İfade_Arama_hakkında_yardım
+
Hide_non-hits=İsabet_almayanları_sakla
+
Hierarchical_context=Hiyerarşik_içerik
+
Highlight=Vurgula
Highlight_groups_matching_all_selected_entries=Tüm_seçili_girdilerle_eşleşen_grupları_vurgula
Highlight_groups_matching_any_selected_entry=Herhangi_bir_seçili_girdiyle_eşleşen_grupları_vurgula
+Disable_highlight_groups_matching_entries=Vurgulu_gruplarla_eşleşen_girdileri_etkisizleştir
+
Highlight_overlapping_groups=Örtüşen_grupları_vurgula
+
Hint\:_To_search_specific_fields_only,_enter_for_example\:<p><tt>author\=smith_and_title\=electrical</tt>=İpucu\:_Yalnızca_belirli_alanları_aramak_için,_örneğin_şunu_giriniz\:<p><tt>author\=smith_and_title\=electrical</tt>
+
HTML_table=HTML_tablosu
HTML_table_(with_Abstract_&_BibTeX)=(Özet_&_BibTeX_ile)_HTML_tablosu
Icon=Simge
+
Ignore=Yoksay
+
Immediate_subgroups=Bir_sonraki_altgruplar
+
Import=İçe_aktar
+
Import_and_keep_old_entry=İçe_aktar_ve_eski_girdiyi_koru
+
Import_and_remove_old_entry=Eski_girdiyi_içe_aktar_ve_sil.
+
Import_entries=Girdileri_içe_aktar
+
Import_failed=İçe_aktarma_başarısız
+
Import_file=Dosya_içe_aktar
+
Import_group_definitions=Grup_tanımlarını_içe_aktar
+
Import_name=İsim_içe_aktar
+
Import_preferences=İçe_aktarma_tercihleri
+
Import_preferences_from_file=Dosyadan_içe_aktarma_tercihleri
+
Import_strings=Dizgeleri_içe_aktar
+
Import_to_open_tab=Sekme_açmak_için_içe_aktar
-Import_word_selector_definitions=Sözcük_seçici_tanımlarını_içe_aktar
+
Imported_entries=İçe_aktarılmış_girdiler
+
Imported_from_database=Veritabanından_içe_aktarılmış
-ImportFormat_class=ImportFormat_sınıfı
+
+Importer_class=Importer_sınıfı
+
Importing=İçe_aktarılıyor
+
Importing_in_unknown_format=Bilinmeyen_biçemde_içe_aktarılıyor
+
Include_abstracts=Özetleri_içer
Include_entries=Alanları_içer
+
Include_subgroups\:_When_selected,_view_entries_contained_in_this_group_or_its_subgroups=Altgrupları_içer\:_Seçildiğinde,_bu_grup_ya_da_altgruplarındaki_girdileri_göster
+
Independent_group\:_When_selected,_view_only_this_group's_entries=Bağımsız_grup\:_Seçildiğinde,_yalnızca_bu_grubun_girdilerini_göster
+
Initially_show_groups_tree_expanded=Başlangıçta_grup_ağacını_genişletilmiş_göster
+
Work_options=Çalışma_seçenekleri
-Input_error=Girdi_hatası
+
Insert=Ekle
+
Insert_rows=Satır_ekle
Intersection=Kesişim
+
Invalid_BibTeX_key=Geçersiz_BibTeX_anahtarı
+
Invalid_date_format=Geçersiz_tarih_biçemi
+
Invalid_URL=Geçersiz_URL
+
Inverted=Ters_çevrilmiş
+
ISO_abbreviation=ISO_kısaltması
+
Online_help=Çevrimiçi_yardım
+
JabRef_preferences=JabRef_tercihler
+
Journal_abbreviations=Dergi_kısaltmaları
+
Journal_list_preview=Dergi_listesi_önizleme
+
Journal_name=Dergi_adı
+
Keep=Tut
+
Keep_both=İkisini_de_tut
+
Key_bindings=Anahtar_bağlantıları
+
Key_bindings_changed=Anahtar_bağlantıları_değişti
+
Key_generator_settings=Anahtar_oluşturucu_ayarları
+
Key_pattern=Anahtar_deseni
+
keys_in_database=veritabanındaki_anahtarlar
+
Keyword=Anahtar_sözcük
+
Label=Etiket
+
Language=Dil
+
Last_modified=Son_değiştirme
+
LaTeX_AUX_file=LaTex_AUX_dosyası
Leave_file_in_its_current_directory=Dosyayı_şimdiki_dizininde_bırak
+
Left=Sol
Level=Düzey
+
Limit_to_fields=Alanlara_kısıtla
+
Limit_to_selected_entries=Seçili_girdilere_kısıtla
+
Link=Link
Link_local_file=Yerel_dosyayı_bağla
Link_to_file_%0=%0_dosyasına_bağla
+
Listen_for_remote_operation_on_port=Bağlantı_noktasındaki_uzak_işlemi_dinle
Load_and_Save_preferences_from/to_jabref.xml_on_start-up_(memory_stick_mode)=Başlangıçta_tercihleri_jabref.xml'den_yükle_ya_da_buraya_kaydet_(bellek_çubuğu_kipi)
+
Look_and_feel=Görünüm_ve_tema
Main_file_directory=Ana_dosya_dizini
+
Main_layout_file=Ana_yerleşim_dosyası
-Manage=Yönet
+
Manage_custom_exports=Özel_dışa_aktarımları_yönet
+
Manage_custom_imports=Özel_içe_aktarımları_yönet
Manage_external_file_types=Harici_dosya_türlerini_yönet
+
Manage_journal_abbreviations=Degi_kısaltmalarını_yönet
+
Mark_entries=Girdileri_işaretle
+
Mark_entry=Girdiyi_işaretle
+
Mark_new_entries_with_addition_date=Yeni_girdileri_ekleme_tarihiyle_işaretle
+
Mark_new_entries_with_owner_name=Yeni_girdileri_sahip_adıyla_işaretle
+
Memory_stick_mode=Bellek_Çubuğu_Kipi
+
Menu_and_label_font_size=Menü_ve_etiket_yazı_tipi_boyutu
+
Merged_external_changes=Harici_değişiklikler_birleştirildi
+
Messages=Mesajlar
+
Modification_of_field=Alanın_değişikliği
+
Modified_group_"%0".=Değiştirilmiş_grup_"%0".
+
Modified_groups=Değiştirilmiş_gruplar
+
Modified_string=Değiştirilmiş_dizge
+
Modify=Değiştir
+
modify_group=grubu_değiştir
+
Move=Taşı
+
Move_down=Aşağı_taşı
+
Move_entries_in_group_selection_to_the_top=Grup_seçimindeki_girdileri_en_üste_taşı
Move_external_links_to_'file'_field=Harici_linkleri_'dosya'_alanına_taşı
+
move_group=grubu_taşı
+
Move_up=Yukarı_taşı
+
Moved_group_"%0".="%0"_grubu_taşındı.
+
Name=Ad
Name_formatter=Ad_biçemleyici
+
Natbib_style=Natbib_stili
+
nested_AUX_files=içiçe_AUX_dosyaları
+
New=Yeni
+
new=yeni
+
New_BibTeX_entry=Yeni_BibTeX_girdisi
+
New_BibTeX_subdatabase=Yeni_BibTeX_alt_veritabanı
+
New_content=Yeni_içerik
+
New_database_created.=Yeni_veritabanı_oluşturuldu.
+New_%0_database=Yeni_%0_veri_tabanı
New_field_value=Yeni_alan_değeri
+
New_file=Yeni_dosya
New_file_link_(INSERT)=Yeni_dosya_linki_(INSERT)
+
New_group=Yeni_grup
+
New_string=Yeni_dizge
+
Next_entry=Yeni_girdi
+
No_actual_changes_found.=Hiç_fiili_değişiklik_bulunamadı.
+
no_base-BibTeX-file_specified=temel_BibTeX_dosyası_belirtilmedi
+
no_database_generated=veritabanı_üretilmedi
+
No_entries_found._Please_make_sure_you_are_using_the_correct_import_filter.=Girdi_bulunmadı._Lütfen_doğru_içe_aktarma_süzgecini_kullandığınızdan_emin_olun.
+
+
No_entries_found_for_the_search_string_'%0'=Arama_dizgesi_'%0'_için_bir_girdi_bulunmadı
+
No_entries_imported.=Hiçbir_girdi_içe_aktarılmadı.
+
No_exceptions_have_occurred.=Hiçbir_istisna_oluşmadı.
No_files_found.=Hiçbir_dosya_bulunmadı.
+
No_GUI._Only_process_command_line_options.=Grafik_kullanıcı_arayüzü_yok._Yalnızca_komut_satırı_seçenekleri_işlenecek.
+
No_journal_names_could_be_abbreviated.=Hiçbir_dergi_adı_kısaltılamadı.
+
No_journal_names_could_be_unabbreviated.=Hiçbir_dergi_adı_kısaltması_açılamadı.
No_PDF_linked=Hiçbir_PDF_bağlanmamış
-No_references_found=Hiçbir_başvuru_bulunamadı
+
No_URL_defined=Hiç_url_tanımlanmamış
not=hariç
+
not_found=bulunmadı
+
Note_that_you_must_specify_the_fully_qualified_class_name_for_the_look_and_feel,=Görünüm_ve_temalar_için_tam_kalifiye_sınıf_adını_belirtmelisiniz,
+
Nothing_to_redo=Yinelenecek_bir_şey_yok
+
Nothing_to_undo=Geriye_alınacak_bir_şey_yok
-Number_of_references_to_fetch?=Getirilecek_başvuru_sayısı?
+
occurrences=görülme_sıklığı
+
OK=Tamam
One_or_more_file_links_are_of_the_type_'%0',_which_is_undefined._What_do_you_want_to_do?=Bir_ya_da_daha_çok_link,_tanımlanmamış_'%0'_türünde._Ne_yapmak_istersiniz?
+
One_or_more_keys_will_be_overwritten._Continue?=Bir_ya_da_daha_çok_anahtarın_üzerine_yazılacak._Devam_edilsin_mi?
+
Open=Aç
+
Open_BibTeX_database=BibTeX_veritabanı_aç
+
Open_database=Veritabanı_aç
+
Open_editor_when_a_new_entry_is_created=Yeni_bir_girdi_oluşturulduğunda_düzenleyiciyi_aç
+
Open_file=Dosya_aç
+
Open_last_edited_databases_at_startup=Açılışta_son_düzenlenmiş_veritabanlarını_aç
-Open_shared_database=Paylaşılmış_veritabanını_aç
+
+Connect_to_shared_database=Paylaşılmış_veritabanını_aç
+
Open_terminal_here=Terminali_burada_aç
+
Open_URL_or_DOI=URL_ya_da_DOI_aç
+
Opened_database=Açık_veritabanı
+
Opening=Açılıyor
+
Opening_preferences...=Tercihler_açılıyor...
+
Operation_canceled.=İşlem_iptal_edildi.
Operation_not_supported=İşlem_desteklenmiyor
+
Optional_fields=Tercihe_bağlı_alanlar
+
Options=Seçenekler
+
or=ya_da
+
Output=Çıktı
+
Output_or_export_file=Çıktı_ya_da_dışa_aktarım_dosyası
+
Override=Geçersiz_kıl
+
Override_default_file_directories=Öntanımlı_dosya_dizinlerini_geçersiz_kıl
+
Override_default_font_settings=Öntamınlı_yazıtipi_ayarlarını_geçersiz_kıl
+
Override_the_BibTeX_field_by_the_selected_text=BibTeX_anahtarını_seçili_metinle_yenile
+
+
Overwrite=Üzerine_yaz
Overwrite_existing_field_values=Mevcut_alan_değerlerinin_üzerine_yaz
+
Overwrite_keys=Anahtarların_üzerine_yaz
+
pairs_processed=işlenmiş_çiftler
Password=Parola
+
Paste=Yapıştır
+
paste_entries=girdileri_yapıştır
+
paste_entry=girdiyi_yapıştır
Paste_from_clipboard=Panodan_yapıştır
+
Pasted=Yapıştırıldı
+
Path_to_%0_not_defined=%0'in_yolu_tanımlanmamış
+
Path_to_LyX_pipe=LyX_hattının_yolu
+
PDF_does_not_exist=PDF_mevcut_değil
+
Personal_journal_list=Kişisel_dergi_listesi
+
Plain_text_import=Düz_metin_içe_aktarma
+
Please_enter_a_name_for_the_group.=Lütfen_grup_için_bir_isim_giriniz.
+
Please_enter_a_search_term._For_example,_to_search_all_fields_for_<b>Smith</b>,_enter\:<p><tt>smith</tt><p>To_search_the_field_<b>Author</b>_for_<b>Smith</b>_and_the_field_<b>Title</b>_for_<b>electrical</b>,_enter\:<p><tt>author\=smith_and_title\=electrical</tt>=Lütfen_bir_arama_terimi_giriniz._Örneğin,_<b>Smith</b>'i_tüm_alanlarda_aramak_için_\:<p><tt>smith</tt><p>_giriniz._<b>Smith</b>'i_<b>Author</b>_alanında,_<b>electrical</b>'ı_<b>Title</b>_alanında_aramak_için_\:<p><tt>author\=smit [...]
+
Please_enter_the_field_to_search_(e.g._<b>keywords</b>)_and_the_keyword_to_search_it_for_(e.g._<b>electrical</b>).=Lütfen_aranacak_alan_adını_(örneğin_<b>keywords</b>)_ve_aranacak_anahtar_sözcüğü_(örneğin_<b>electrical</b>)_giriniz.
+
Please_enter_the_string's_label=Lütfen_dizgenin_etiketini_giriniz
+
Please_select_an_importer.=Lütfen_bir_içe_aktarıcı_seçiniz.
+
Please_select_exactly_one_group_to_move.=Lütfen_taşımak_için_yalnızca_bir_grup_seçiniz.
+
Possible_duplicate_entries=Olası_çift_nüsha_girdiler
+
Possible_duplicate_of_existing_entry._Click_to_resolve.=Mevcut_girdinin_olası_çift_nüshası._Düzeltmek_için_tıklayınız.
+
Preamble=Öncül
+
Preferences=Tercihler
+
Preferences_recorded.=Tercihler_kaydedildi.
+
Preview=Önizleme
+Citation_Style=
+Current_Preview=
+Cannot_generate_preview_based_on_selected_citation_style.=
+Bad_character_inside_entry=
+Error_while_generating_citation_style=
+Preview_style_changed_to\:_%0=
+Next_preview_layout=
+Previous_preview_layout=
+
Previous_entry=Önceki_girdi
+
Primary_sort_criterion=Birincil_sıralama_kriteri
Problem_with_parsing_entry=Girdi_ayrıştırmada_sorun
-
Processing_%0=İşleniyor_%0
Program_output=Program_çıktısı
Pull_changes_from_shared_database=Paylaşılmış_veritabanından_değişiklikleri_çek
+
Pushed_citations_to_%0=Alıntılar_%0'a_itelendi
+
Quit_JabRef=JabRef'ten_çık
+
Quit_synchronization=Eşzamanlamayı_bitir
+
Raw_source=Ham_kaynak
+
Rearrange_tabs_alphabetically_by_title=Sekmeleri_başlıklarıyla_alfabetik_olarak_yeniden_düzenle
+
Redo=Yeniden_yap
+
Reference_database=Başvuru_veritabanı
-References_found=Bulunan_başvurular
+
+%0_references_found._Number_of_references_to_fetch?=Bulunan_başvurular\:_%0._Getirilecek_başvuru_sayısı?
+
Refine_supergroup\:_When_selected,_view_entries_contained_in_both_this_group_and_its_supergroup=Supergrubu_arıt\:_Seçildiğinde,_hem_bu_grubun,_hem_de_süpergrubunun_içerdiği_girdileri_görüntüle
+
regular_expression=Düzenli_İfade
+
Remember_these_entry_types?=Bu_girdi_türlerini_anımsa?
+
Remote_operation=Uzak_işlem
+
Remote_server_port=Uzak_sunucu_bağlantı_noktası
+
Remove=Sil
+
Remove_subgroups=Tüm_altgrupları_sil
+
Remove_all_subgroups_of_"%0"?="%0"in_tüm_altgruplarını_sil?
+
Remove_entry_from_import=İçe_aktarımdan_girdiyi_sil
+
Remove_entry_selection_from_this_group=Bu_gruptan_girdi_seçimini_sil
+
Remove_entry_type=Girdi_türünü_sil
Remove_file_link_(DELETE)=Dosya_linkini_sil_(DELETE)
+
Remove_from_group=Gruptan_sil
+
Remove_group=Grubu_sil
+
Remove_group,_keep_subgroups=Grubu_sil,_altgrupları_tut
+
Remove_group_"%0"?="%0"_grubu_silinsin_mi?
+
Remove_group_"%0"_and_its_subgroups?="%0"_grubu_ve_altgrupları_silinsin_mi?
+
remove_group_(keep_subgroups)=grubu_sil_(altgrupları_tut)
+
remove_group_and_subgroups=grubu_ve_altgrupları_sil
+
Remove_group_and_subgroups=Grubu_ve_altgrupları_sil
+
Remove_link=Linki_sil
+
Remove_old_entry=Eski_girdiyi_sil
+
Remove_selected_strings=Seçili_dizgeleri_sil
+
Removed_group_"%0".="%0"_grubu_silindi.
+
Removed_group_"%0"_and_its_subgroups.="%0"_grubu_ve_altgrupları_silindi.
+
Removed_string=Dizge_silindi
+
Renamed_string=Dizge_yeniden_adlandırıldı
+
Replace_(regular_expression)=Yerine_koy_(düzenli_ifade)
+
Replace_string=Dizgenin_yerine_koy
+
Replace_with=Şununla_değiştir
+
Replaced=Değiştirildi
+
Required_fields=Zorunlu_alanlar
+
Reset_all=Tümünü_sıfırla
+
Resolve_strings_for_all_fields_except=Şu_hariç_tüm_alanların_dizgelerini_çözümle
Resolve_strings_for_standard_BibTeX_fields_only=Yalnızca_standart_BibTeX_alan_dizgelerini_çözümle
+
resolved=çözümlendi
+
Revert_to_original_source=Orijinal_kaynağa_döndür
+
Review=Gözden_geçir
+
Review_changes=Değişklikleri_incele
+
Right=Sağ
+
Save=Kaydet
Save_all_finished.=Tüm_bitenleri_kaydet.
+
Save_all_open_databases=Tüm_açık_veritabanlarını_kaydet
+
Save_before_closing=Kapatmadan_önce_kaydet
+
Save_database=Veritabanını_kaydet
Save_database_as...=Veritabanını_farklı_kaydet_...
+
Save_entries_in_their_original_order=Girdileri_orijinal_sıralarında_kaydet
+
Save_failed=Kaydetme_başarısız
+
Save_failed_during_backup_creation=Yedek_oluşturulurken_kaydetme_başarısız
-Save_failed_while_committing_changes\:_%0=Değişiklikler_uygulanırken_kaydetme_başarısız\:_%0
+
Save_selected_as...=Seçimi_farklı_kaydet_...
+
Saved_database=Kaydedilmiş_veritabanı
+
Saved_selected_to_'%0'.=Seçim_şuraya_kaydedildi_'%0'.
+
Saving=Kaydediliyor
Saving_all_databases...=Tüm_veritabanları_kaydediliyor...
+
Saving_database=Veritabanı_kaydediliyor
+
Search=Ara
+
Search_expression=İfade_ara
+
Search_for=Şunu_ara
+
Searching_for_duplicates...=Çift_nüshalar_aranıyor...
+
Searching_for_files=Dosyalar_aranıyor
+
Secondary_sort_criterion=İkincil_sıralama_kriteri
+
Select=Seç
+
+
Select_all=Tümünü_seç
+
Select_encoding=Kodlamayı_seç
+
Select_entry_type=Girdi_türünü_seç
Select_external_application=Harici_uygulamayı_seç
+
Select_file_from_ZIP-archive=ZIP_arşivinden_dosyayı_seçiniz
+
Select_the_tree_nodes_to_view_and_accept_or_reject_changes=Değişiklikleri_görmek_ve_kabul_ya_da_reddetmek_için_ağaç_düğümlerini_seçiniz
Selected_entries=Seçili_girdiler
Set_field=Alanı_ata
Set_fields=Alanları_ata
+
Set_general_fields=Genel_alanları_ata
Set_main_external_file_directory=Ana_harici_dosya_dizinini_ayarla
+
Set_table_font=Tablo_yazıtipini_ayarla
+
Settings=Ayarlar
+
Shortcut=Kısayol
-Show/edit_BibTeX_source=BibTeX_kaynağın_göster/düzenle
+
+Show/edit_%0_source=%0_kaynağın_göster/düzenle
+
Show_'Firstname_Lastname'='Ad_Soyad'_göster
+
Show_'Lastname,_Firstname'='Soyad,_Ad'_göster
+
Show_BibTeX_source_by_default=Öntanımlı_olarak_BibTeX_kaynağını_göster
+
Show_confirmation_dialog_when_deleting_entries=Girdileri_silerken_onaylama_iletişim_penceresini_göster
+
Show_description=Açıklamayı_göster
+
Show_dynamic_groups_in_<i>italics</i>=Dinamik_grupları_<i>italik</i>_biçimde_göster
+
Show_entries_<b>not</b>_in_group_selection=Girdileri_grup_seçiminde_göster<b>me</b>
+
Show_file_column=Dosya_sütununu_göster
+
Show_icons_for_groups=Gruplar_için_simgeler_göster
Show_last_names_only=Yalnızca_soyadları_göster
+
Show_names_unchanged=Adları_değiştirmeden_göster
+
Show_optional_fields=Seçmeli_alanları_göster
+
Show_required_fields=Zorunlu_alanları_göster
+
Show_URL/DOI_column=URL/DOI_sütununu_göster
+
Simple_HTML=Basit_HTML
+
Size=Boyut
+
Skipped_-_No_PDF_linked=Atlandı_-_PDF_eklenmedi
Skipped_-_PDF_does_not_exist=Atlandı_-_PDF_mevcut_değil
+
Skipped_entry.=Girdi_atlandı.
+
Sort_alphabetically=Alfabetik_sırala
+
sort_subgroups=altgrupları_sırala
+
Sorted_all_subgroups_recursively.=Tüm_altgruplar_özyineli_sıralandı.
+
Sorted_immediate_subgroups.=En_yakın_altgruplar_sıralandı.
+
source_edit=kaynak_düzenle
Special_name_formatters=Özel_Ad_Biçemleyicileri
+
Special_table_columns=Özel_tablo_sütunları
+
Starting_import=İçe_aktarım_başlatılıyor
+
Statically_group_entries_by_manual_assignment=Elle_atanmış_durağan_grup_girdileri
+
Status=Durum
+
Stop=Dur
+
Store_journal_abbreviations=Dergi_kısaltmalarını_depola
+
Stored_entry=Depolanmış_girdi
+
Strings=Dizgeler
+
Strings_for_database=Veritabanı_için_dizgeler
+
Subdatabase_from_AUX=Yardımcıdan_(AUX)_altveritabanı
+
Switches_between_full_and_abbreviated_journal_name_if_the_journal_name_is_known.=Dergi_adı_biliniyorsa_tam_ve_kısaltılmış_dergi_adı_arasında_geçiş_yapar.
+
Synchronize_file_links=Dosya_linklerini_eşzamanla
+
Synchronizing_file_links...=Dosya_link_eşzamanlanıyor...
+
Table_appearance=Tablo_görünümü
+
Table_background_color=Tablo_arkaplan_rengi
+
Table_grid_color=Tablo_klavuz_çizgileri_rengi
+
Table_text_color=Tablo_metni_rengi
+
Tabname=Sekmeadı
Target_file_cannot_be_a_directory.=Hedef_dosya_bir_dizin_olamaz.
+
Tertiary_sort_criterion=Üçüncül_sıralama_ölçütü
+
Test=Deneme
+
paste_text_here=Metin_Girdi_Alanı
+
The_chosen_date_format_for_new_entries_is_not_valid=Yeni_girdiler_için_seçilen_tarih_biçemi_geçersiz
+
The_chosen_encoding_'%0'_could_not_encode_the_following_characters\:=Seçilen_'%0'_kodlaması_şu_karakterleri_kodlayamıyor\:
+
+
the_field_<b>%0</b>=alan_<b>%0</b>
+
The_file<BR>'%0'<BR>has_been_modified<BR>externally\!=Dosya<BR>'%0'<BR><BR>harici_olarak_değiştirildi\!
+
The_group_"%0"_already_contains_the_selection.="%0"_grubu_seçimi_zaten_kapsıyor.
+
The_label_of_the_string_cannot_be_a_number.=Dizgenin_etiketi_bir_numara_olamaz.
+
The_label_of_the_string_cannot_contain_spaces.=Dizgenin_etiketi_boşluk_içeremez.
+
The_label_of_the_string_cannot_contain_the_'\#'_character.=Dizgenin_etiketi_'\#'_karakterini_içeremez.
+
The_output_option_depends_on_a_valid_import_option.=Çıktı_seçeneği_geçerli_bir_içe_aktarım_seçeneğine_bağlıdır.
The_PDF_contains_one_or_several_BibTeX-records.=PDF,_bir_ya_da_daha_fazla_BibTeX_kaydı_içeriyor.
Do_you_want_to_import_these_as_new_entries_into_the_current_database?=Bunları_mevcut_veritabannına_yeni_girdiler_olarak_aktarmak_ister_misiniz?
+
The_regular_expression_<b>%0</b>_is_invalid\:=Düzenli_ifade_<b>%0</b>_geçersiz\:
+
The_search_is_case_insensitive.=Arama_büyük/küçük_harfe_duyarsız.
+
The_search_is_case_sensitive.=Arama_büyük/küçük_harfe_duyarlı.
+
The_string_has_been_removed_locally=Dizge_yerel_olarak_silindi
+
There_are_possible_duplicates_(marked_with_an_icon)_that_haven't_been_resolved._Continue?=Çözümlenmemiş,_olası_çift_nüshalar_mevcut_(simgesiyle_işaretlenmiş)._Devam_edilsin_mi?
+
This_entry_has_no_BibTeX_key._Generate_key_now?=Bu_girdinin_BibTeX_anahtarı_yok._Şimdi_oluşturulsun_mu?
+
This_entry_is_incomplete=Girdi_eksik
+
This_entry_type_cannot_be_removed.=Bu_girdi_türü_silinemiyor.
+
This_external_link_is_of_the_type_'%0',_which_is_undefined._What_do_you_want_to_do?=Bu_harici_link,_tanımlanmamış_'%0'_türündendir._Ne_yapmak_istersiniz?
+
This_group_contains_entries_based_on_manual_assignment._Entries_can_be_assigned_to_this_group_by_selecting_them_then_using_either_drag_and_drop_or_the_context_menu._Entries_can_be_removed_from_this_group_by_selecting_them_then_using_the_context_menu.=Bu_grup,_elle_atanmış_girdiler_içeriyor._Bu_gruba_girdiler_seçilip_ya_sürükleyip_bırakarak_ya_da_fare_sağ_tıklama_menüsü_kullanılarak_eklenebilir._Bu_gruptan_girdiler_seçilip_fare_sağ_tıklama_menüsü_kullanılarak_silinebilir.
+
This_group_contains_entries_whose_<b>%0</b>_field_contains_the_keyword_<b>%1</b>=Bu_grup,_<b>%0</b>_alanı_<b>%1</b>_anahtar_sözcüğünü_içeren_girdileri_içerir
+
This_group_contains_entries_whose_<b>%0</b>_field_contains_the_regular_expression_<b>%1</b>=Bu_grup,_<b>%0</b>_alanı_<b>%1</b>_düzenli_ifadesini_içeren_girdileri_içerir
This_makes_JabRef_look_up_each_file_link_and_check_if_the_file_exists._If_not,_you_will_be_given_options<BR>to_resolve_the_problem.=Bu,_JabRef'in_her_dosya_linki_bulup_dosyanın_var_olup_olmadığını_kontrol_etmesini_sağlar._Eğer_yoksa,_sorunu<BR>çözmek_için_seçenekler_sunulacaktır.
+
This_operation_requires_all_selected_entries_to_have_BibTeX_keys_defined.=Bu_işlem,_tüm_seçili_girdilerin_tanımlı_BibTeX_anahtarlarının_olmasını_gerektirir.
+
This_operation_requires_one_or_more_entries_to_be_selected.=Bu_işlem,_bir_ya_da_daha_çok_girdinin_seçili_olmasını_gerektirir.
+
Toggle_abbreviation=Kısaltmayı_aç/kapat
Toggle_entry_preview=Girdi_önizlemeyi_aç/kapat
Toggle_groups_interface=Grup_arayüzünü_aç/kapat
Try_different_encoding=Başka_kodlama_deneyin
+
Unabbreviate_journal_names_of_the_selected_entries=Seçili_girdilerin_dergi_adlarını_kısaltma
Unabbreviated_%0_journal_names.=%0_dergi_adı_kısaltması_kaldırıldı.
+
Unable_to_open_file.=Dosya_açılamadı.
Unable_to_open_link._The_application_'%0'_associated_with_the_file_type_'%1'_could_not_be_called.=Link_açılamadı._'%1'_dosya_türüyle_ilişkili_'%0'_uygulaması_çağrılamadı.
unable_to_write_to=Şuraya_yazılamadı
Undefined_file_type=Tanımlanmamış_dosya_türü
+
Undo=Geriye_al
+
Union=Bileşim
+
Unknown_BibTeX_entries=Bilinmeyen_BibTeX_girdileri
+
unknown_edit=bilinmeyen_düzenleme
+
Unknown_export_format=Bilinmeyen_dışa_aktarım_biçemi
+
Unmark_all=Tümünün_işaretini_kaldır
+
Unmark_entries=Girdilerin_işaretini_kaldır
+
Unmark_entry=Girdinin_işaretini_kaldır
-Unsupported_version_of_class_%0\:_%1=%0_sınıfının_desteklenmeyen_sürümü\:_%1
+
untitled=başlıksız
+
Up=Yukarı
+
Update_to_current_column_widths=Mevcut_sütun_genişliklerine_güncelle
+
Updated_group_selection=Grup_seçimi_güncellendi
Upgrade_external_PDF/PS_links_to_use_the_'%0'_field.=Harici_PDF/PS_linklerini_'%0'_alanını_kullanmak_üzere_yeni_sürüme_yükselt.
Upgrade_file=Dosyayı_yeni_sürüme_yükselt
Upgrade_old_external_file_links_to_use_the_new_feature=Eski_harici_dosya_linklerini_yeni_özelliği_kullanmak_üzere_yeni_sürüme_yükselt
+
usage=kullanım
Use_autocompletion_for_the_following_fields=Aşağıdaki_alanlar_için_otomatik_tamamlamayı_kullan
+
Use_other_look_and_feel=Diğer_görünüm_ve_tema_kullan
Use_regular_expression_search=Düzenli_İfade_Aramayı_kullan
+
Username=Kullanıcı_adı
+
Value_cleared_externally=Değer,_haricen_silindi
+
Value_set_externally=Değer,_haricen_atandı
+
verify_that_LyX_is_running_and_that_the_lyxpipe_is_valid=LyX'in_çalıştığını_ve_veri_iletişim_hattının_geçerli_olduğunu_teyid_edin
+
View=Görüntüle
Vim_server_name=Vim_Sunucu_Adı
+
Waiting_for_ArXiv...=ArXiv_bekleniyor...
+
Warn_about_unresolved_duplicates_when_closing_inspection_window=İnceleme_penceresi_kapanırken_çözülmemiş_çift_nüshalar_hakkında_uyar
+
Warn_before_overwriting_existing_keys=Mevcut_anahtarların_üzerine_yazmadan_önce_uyar
+
Warning=Uyarı
+
Warnings=Uyarılar
+
web_link=sanaldoku_linki
+
What_do_you_want_to_do?=Ne_yapmak_istersiniz?
+
When_adding/removing_keywords,_separate_them_by=Anahtar_sözcük_ekler/çıkarırken,_onları_şöyle_ayırın
Will_write_XMP-metadata_to_the_PDFs_linked_from_selected_entries.=Seçili_girdilerle_bağlantılı_PDFlere_XMP_metaverisi_yazılacak.
+
with=ile
+
Write_BibTeXEntry_as_XMP-metadata_to_PDF.=BibTeXGirdisi'ni_PDF'ye_XMP-metaverisi_olarak_yaz.
+
Write_XMP=XMP'yi_yaz
Write_XMP-metadata=XMP-metaverisini_yaz
Write_XMP-metadata_for_all_PDFs_in_current_database?=Mevcut_veritabanındaki_tüm_PFDlere_XMP-metaverisi_yazılsın_mı?
Writing_XMP-metadata...=XMP_metaverisi_yazılıyor...
Writing_XMP-metadata_for_selected_entries...=Seçili_girdiler_için_XMP_metaverisi_yazılıyor...
+
Wrote_XMP-metadata=XMP-metaverisi_yazıldı
+
XMP-annotated_PDF=XMP-ek_notlu_PDF
XMP_export_privacy_settings=Gizlilik_Ayarlarını_XMP_Dışa_Aktar
XMP-metadata=XMP_metaverisi
XMP-metadata_found_in_PDF\:_%0=PDF'de_XMP_metaverisi_bulundu\:_%0
-
You_must_restart_JabRef_for_this_to_come_into_effect.=Bunun_etkinleşmesi_için_JabRefi_yeniden_başlatmalısınız.
You_have_changed_the_language_setting.=Dil_ayarını_değiştirdiniz.
+
You_have_changed_the_look_and_feel_setting.=Görünüm_ve_tema_ayarını_değiştirdiniz.
+
You_have_entered_an_invalid_search_'%0'.=Geçersiz_bir_arama_girdiniz_'%0'.
+
You_must_choose_a_filename_to_store_journal_abbreviations=Dergi_kısaltmalarını_kaydetmek_için_bir_dosya_adı_seçmelisiniz
+
You_must_restart_JabRef_for_the_new_key_bindings_to_work_properly.=Yeni_anahtar_demetlerinin_düzgün_çalışması_için_JabRef'i_yeniden_başlatmalısınız.
+
Your_new_key_bindings_have_been_stored.=Yeni_anahtar_demetleriniz_kaydedildi.
+
The_following_fetchers_are_available\:=Aşağıdaki_getiriciler_kullanıma_hazırdır:
Could_not_find_fetcher_'%0'='%0'_getiricisi_bulunamadı
Running_query_'%0'_with_fetcher_'%1'.='%0'_sorgusu_'%1'_getiricisiyle_çalıştırılıyor.
@@ -772,20 +1404,21 @@ Number_of_entries_successfully_imported=Girdi_sayısı_başarıyla_içe_aktarıl
Import_canceled_by_user=İçe_aktrım_kullanıcı_tarafından_iptal_edildi
Progress\:_%0_of_%1=İlerleme:_%1'in_%0'i
Error_while_fetching_from_%0=%0'dan_getirme_sırasında_hata
-Fetching_Medline_by_id...=Medline_tanıtıcı_aracılığıyla_getirliyor...
-Fetching_Medline_by_term...=Medline_terim_aracılığıyla_getirliyor...
-%0_import_canceled=%0_içe_aktarımı_iptal_edildi
+
Please_enter_a_valid_number=Lütfen_geçerli_bir_sayı_giriniz
-Please_enter_a_comma_separated_list_of_Medline_IDs_(numbers)_or_search_terms.=Lütfen_virgülle_ayrılmış_bir_Medline_No_ya_da_arama_terimi_listesi_giriniz.
Show_search_results_in_a_window=Arama_sonuçlarını_bir_pencerede_göster
+Show_global_search_results_in_a_window=
+Search_in_all_open_databases=Tüm_açık_veri_tabanlarında_ara
Move_file_to_file_directory?=Dosya,_dosya_dizinine_taşınsın_mı?
Rename_to_'%0'='%0'_olarak_yeniden_adlandır
You_have_changed_the_menu_and_label_font_size.=Menü_ve_etiket_yazıtipi_boyutunu_değiştirdiniz.
+
Database_is_protected._Cannot_save_until_external_changes_have_been_reviewed.=Veritabanı_korunuyor._Harici_değişiklikler_gözden_geçirilene_dek_kaydedemezsiniz.
Protected_database=Korunan_veritabanı
Refuse_to_save_the_database_before_external_changes_have_been_reviewed.=Harici_değişiklikler_gözden_geçirilene_dek_veritabanının_kaydedilmesini_reddet.
Database_protection=Veirtabanı_koruması
Unable_to_save_database=Veritabanı_kaydedilemedi
+
BibTeX_key_generator=BibTeX_anahtar_oluşturucusu
Unable_to_open_link.=Bağlantı_açılamadı.
Move_the_keyboard_focus_to_the_entry_table=Klavye_odağını_girdi_tablosuna_taşı
@@ -799,20 +1432,21 @@ Reset=Sıfırla
Use_IEEE_LaTeX_abbreviations=IEEE_LaTeX_kısaltmaları_kullanınız
The_Guide_to_Computing_Literature=Bilgi_İşlem_Literatürü_Klavuzu
+
When_opening_file_link,_search_for_matching_file_if_no_link_is_defined=Dosya_bağlantısını_açarken,_eğer_link_tanımlanmamışsa_eşleşen_dosyayı_ara
Settings_for_%0=%0_için_ayarlar
Mark_entries_imported_into_an_existing_database=Varolan_bir_veritabanına_aktarılmış_girdileri_işaretle
Unmark_all_entries_before_importing_new_entries_into_an_existing_database=Yeni_girdileri_varolan_bir_veritabanına_aktarmadan_önce_tüm_girdilerin_işaretini_sil
+
Forward=İleri
Back=Geri
Sort_the_following_fields_as_numeric_fields=Aşağıdaki_alanları_sayısal_olarak_sırala
Line_%0\:_Found_corrupted_BibTeX_key.=Satır_%0\:_Bozulmuş_BibTeX-anahtarı_bulundu.
Line_%0\:_Found_corrupted_BibTeX_key_(contains_whitespaces).=Satır_%0\:_Bozulmuş_BibTeX-anahtarı_bulundu_(beyaz_boşluk_içeriyor).
Line_%0\:_Found_corrupted_BibTeX_key_(comma_missing).=Satır_%0\:_Bozulmuş_BibTeX-anahtarı_bulundu_(virgül_kayıp).
-Finished_downloading_full_text_document=Tam_metin_belge_indirme_tamamlandı
Full_text_document_download_failed=Tam_metin_makale_indirme_başarısız
Update_to_current_column_order=Varolan_sütun_sırasına_güncelle
-
+Download_from_URL=URL'den_indir
Rename_field=Alanın_adını_değiştir
Set/clear/rename_fields=Alanları_kur/sil/yeniden_adlandır
Rename_field_to=Alan_adını_şuna_değiştir
@@ -820,23 +1454,24 @@ Move_contents_of_a_field_into_a_field_with_a_different_name=Alan_içeriğini_ba
You_can_only_rename_one_field_at_a_time=Bir_seferde_yalnızca_bir_alanın_adını_değiştirebilirsiniz
Remove_all_broken_links=Tüm_bozuk_linkleri_sil
+
Cannot_use_port_%0_for_remote_operation;_another_application_may_be_using_it._Try_specifying_another_port.=Uzak_operasyon_için_bağlantı_noktası_%0_kullanılamıyor;_bir_başka_program_kullanıyor_olabilir._Başka_bir_bağlantı_noktası_deneyin.
Looking_for_full_text_document...=Tam_metin_belge_aranıyor...
Autosave=Otomatik_kaydet
-Prompt_before_recovering_a_database_from_an_autosave_file=Otomatik_kaydedilmiş_bir_dosyadan_veri_tabanını_kurtarmaya_başlamadan_önce_sor
-Autosave_interval_(minutes)=Otomatik_kayıt_aralığı_(dakika)
-Do_you_want_to_recover_the_database_from_the_autosave_file?=Otomatik_kayıt_dosyasından_veritabanını_kurtarmak_ister_misiniz?
-Recover_from_autosave=Otomatik_kayıttan_kurtar
+A_local_copy_will_be_opened.=
+Autosave_local_databases=
+Automatically_save_the_database_to=
+Please_enter_a_valid_file_path.=
+
Export_in_current_table_sort_order=Mevcut_tablo_sıralama_düzeninde_dışa_aktar
Export_entries_in_their_original_order=Girdileri_orijinal_sırasında_dışa_aktar
Error_opening_file_'%0'.=Dosya_açmada_hata_'%0'.
-Autosave_of_file_'%0'='%0'_dosyasının_otomatik_kaydı
-Error_opening_autosave_of_'%0'._Trying_to_load_'%0'_instead.='%0''in_otomatik_kaydını_açmada_hata._Onun_yerine_'%0'_yüklenmeye_çalışıyor.
Formatter_not_found\:_%0=Biçimleyici_bulunamadı\:_%0
Clear_inputarea=Girdi_alanını_temizle
+
Automatically_set_file_links_for_this_entry=Bu_girdi_için_dosya_bağlantılarını_otomatikman_kur
Could_not_save,_file_locked_by_another_JabRef_instance.=Kaydedilemiyor,_dosya_başka_bir_JabRef_oturumunca_kilitlenmiş.
File_is_locked_by_another_JabRef_instance.=Dosya_başka_bir_JabRef_oturumunca_kilitlenmiş.
@@ -861,9 +1496,7 @@ dynamic_group=devingen_grup
refines_supergroup=süpergrubu_rafine_eder
includes_subgroups=altgrupları_içerir
contains=içerir
-search_expression=arama_ifadesi
-
-
+search_expression=arama_ifadesi
Optional_fields_2=Opsiyonel_alanlar_2
Waiting_for_save_operation_to_finish=Kaydetme_işleminin_bitmesi_bekleniyor
@@ -894,7 +1527,6 @@ Show_ArXiv_column=ArXiv_sütununu_göster
Highlight_groups_that_contain_entries_contained_in_any_currently_selected_group=Herhangi_bir_mevcut_seçilmiş_grupça_içerilen_girdileri_içeren_grupları_vurgula
You_must_enter_an_integer_value_in_the_interval_1025-65535_in_the_text_field_for=Metin_alanına_1025-65535_aralığında_bir_tamsayı_girmelisiniz
-
Automatically_open_browse_dialog_when_creating_new_file_link=Yeni_dosya_bağlantısını_oluştururken_gözatma_iletişim_kutusunu_otomatikman_aç
Import_metadata_from\:=Metaverisini_Şuradan_İçe_Aktar\:
Choose_the_source_for_the_metadata_import=Metaverisini_içe_aktarmak_için_kaynağı_seçin
@@ -902,7 +1534,6 @@ Create_entry_based_on_XMP_data=XMP_verisine_dayanarak_girdi_oluştur
Create_blank_entry_linking_the_PDF=PDF'yle_bağlantılı_olarak_boş_girdi_oluştur
Only_attach_PDF=Yalnızca_PDF'yi_ekle
Title=Başlık
-No_internet_connection.=Internet_Bağlantısı_Yok.
Create_new_entry=Yeni_Girdi_Oluştur
Update_existing_entry=Mevcut_Girdiyi_Güncelle
Autocomplete_names_in_'Firstname_Lastname'_format_only=İsimleri_yalnızca_'Ad_Soyad'_biçiminde_otomatik_tamamla
@@ -978,13 +1609,11 @@ Select_document=Belge_seçin
Edit_group_membership=Grup_Üyeliğini_Düzenle
HTML_list=HTML_listesi
Click_group_to_toggle_membership_of_selected_entries=Seçili_girdilerin_üyeliğini_ayarlamak_için_grubu_tıklayın
-Use_EMACS_23_insertion_string=EMACS_23_ekleme_dizgesini_kullan
If_possible,_normalize_this_list_of_names_to_conform_to_standard_BibTeX_name_formatting=eğer_mümkünse,_bu_isim_listesini_standart_BibTeX_isim_biçimiyle_uyumlu_olacak_şekilde_normalleştir
Could_not_open_%0=%0_açılamıyor
Unknown_import_format=Bilinmeyen_içe_aktarım_biçimi
Web_search=Ağ_araması
Style_selection=Stil_seçimi
-
No_valid_style_file_defined=Geçerli_stil_dosyası_tanımlanmadı
Choose_pattern=Desen_seçin
Use_the_BIB_file_location_as_primary_file_directory=bib_dosyası_konumunu_birincil_dosya_dizini_olarak_kullan
@@ -998,11 +1627,12 @@ You_must_select_either_a_valid_style_file,_or_use_one_of_the_default_styles.=Ya_
This_is_a_simple_copy_and_paste_dialog._First_load_or_paste_some_text_into_the_text_input_area.<br>After_that,_you_can_mark_text_and_assign_it_to_a_BibTeX_field.=Bu_basit_bir_kopyala_ve_yapıştır_iletişim_kutusudur._Önce_metin_girme_alanına_bir_metin_yükleyin_ya_da_yapıştırın.<br>Daha_sonra,_metni_işaretleyip_bir_BibTeX_alanına_atayabilirsiniz.
This_feature_generates_a_new_database_based_on_which_entries_are_needed_in_an_existing_LaTeX_document.=Bu_özellik_mevcut_bir_LaTex_belgesinde_hangi_girdilerin_gerekli_olduğuna_dayanan_yeni_bir_veritabanı_oluşturur.
You_need_to_select_one_of_your_open_databases_from_which_to_choose_entries,_as_well_as_the_AUX_file_produced_by_LaTeX_when_compiling_your_document.=Girdilerinizi_seçmek_için_açık_veritabanlarınızdan_birini_ve_belgenizi_derlerken_LaTex'in_oluşturduğu_AUX_dosyasını_seçmelisiniz.
+
First_select_entries_to_clean_up.=Öncelikle_temizlemek_istediğiniz_girdileri_seçiniz.
Cleanup_entry=Girdiyi_temizle
-%0_mode=%0_kipi
Autogenerate_PDF_Names=PFD_Adlarını_Otomatik_Oluştur
Auto-generating_PDF-Names_does_not_support_undo._Continue?=PDF_Adlarını_otomatik_oluşturma_geri_alınamaz._Devam_edilsin_mi?
+
Use_full_firstname_whenever_possible=Mümkün_oldukça_tam_ilk_ismi_kullanınız
Use_abbreviated_firstname_whenever_possible=Mümkün_oldukça_kısaltılmış_ilk_ismi_kullanınız
Use_abbreviated_and_full_firstname=Kısaltılmış_ve_tam_ilk_ismi_kullanınız
@@ -1012,6 +1642,7 @@ Name_format_used_for_autocompletion=Otomatik_tamamlama_için_kullanılan_isim_bi
Treatment_of_first_names=İlk_isimlerin_işlenme_şekli
Cleanup_entries=Girdileri_temizle
Automatically_assign_new_entry_to_selected_groups=Seçili_gruplara_otomatikman_yeni_girdi_ata
+%0_mode=%0_kipi
Move_DOIs_from_note_and_URL_field_to_DOI_field_and_remove_http_prefix=DOI'leri_not_ve_URL_alanlarından_DOI_alanına_taşı_ve_http_ön_ekini_kaldır
Make_paths_of_linked_files_relative_(if_possible)=(Mümkünse)_bağlantılı_dosya_yollarını_göreceli_yapın
Rename_PDFs_to_given_filename_format_pattern=PDF'leri_belirlenmiş_dosya_ismi_biçemi_desenine_göre_yeniden_adlandır
@@ -1026,6 +1657,7 @@ Error_downloading_file_'%0'=Dosya_indirmede_hata_%0'
Download_failed=İndirme_başarısız
Remove_selected=Seçiliyi_Sil
+
Group_tree_could_not_be_parsed._If_you_save_the_BibTeX_database,_all_groups_will_be_lost.=Grup_ağacı_çözümlenemedi._Eğer_BibTeX_veri_tabanını_kaydederseniz_tüm_gruplar_yitecek.
Attach_file=Dosya_ekle
Setting_all_preferences_to_default_values.=Tüm_tercihler_öntanımlı_değerlere_ayarlanıyor.
@@ -1061,7 +1693,6 @@ The_current_BibTeX_key_will_be_overwritten._Continue?=Mevcut_BibTeX_anahtarını
Overwrite_key=Anahtarın_üzerine_yaz
Not_overwriting_existing_key._To_change_this_setting,_open_Options_->_Prefererences_->_BibTeX_key_generator=Mevcut_anahtarın_üzerine_yazılmıyor._Bu_ayarı_değiştirmek_için_Seçenekler_->_Tercihler_->_BibTeX_anahtar_oluşturucusu'nu_açın
How_would_you_like_to_link_to_'%0'?='%0'a_nasıl_bağlantı_istersiniz?
-
BibTeX_key_patterns=BibTeX_anahtar_paternleri
Changed_special_field_settings=Değiştirilmiş_özel_alan_ayarları
Clear_priority=Önceliği_sil
@@ -1071,7 +1702,6 @@ Five_stars=Beş_yıldız
Four_stars=Dört_yıldız
Help_on_special_fields=Özle_alanlar_konusunda_yardım
Keywords_of_selected_entries=Seçili_girdilerin_anahtar_sözcükleri
-Manage_content_selectors=İçerik_seçicileri_yönet
Manage_keywords=Anahtar_sözcükleri_yönet
No_priority_information=Öncelik_bilgisi_yok
No_rank_information=Rütbe_bilgisi_yok
@@ -1099,10 +1729,10 @@ Two_stars=İki_yıldız
Update_keywords=Anahtar_sözcükleri_güncelle
Write_values_of_special_fields_as_separate_fields_to_BibTeX=Özel_alan_değerlerini_BibTeX'e_ayrı_alanlar_olarak_yaz
You_have_changed_settings_for_special_fields.=Özel_alan_ayarlarını_değiştirdiniz.
-
%0_entries_found._To_reduce_server_load,_only_%1_will_be_downloaded.=%0_girdi_bulundu._Sunucu_yükünü_azaltmak_için_yalnızca_%1_indirilecek.
A_string_with_that_label_already_exists=Bu_etikete_sahip_bir_dizge_zaten_mevcut
Connection_to_OpenOffice/LibreOffice_has_been_lost._Please_make_sure_OpenOffice/LibreOffice_is_running,_and_try_to_reconnect.=OpenOffice/LibreOffice_bağlantısı_koptu._Lütfen_OpenOffice/LibreOffice'in_açık_olduğunu_teyid_edin,_ve_tekrar_bağlanmayı_deneyin.
+
Correct_the_entry,_and_reopen_editor_to_display/edit_source.=Girdiyi_düzeltin,_ve_kaynağı_görmek/düzenlemek_için_düzenleyiciyi_tekrar_açın.
Could_not_connect_to_a_running_gnuserv_process._Make_sure_that_Emacs_or_XEmacs_is_running,<BR>and_that_the_server_has_been_started_(by_running_the_command_'server-start'/'gnuserv-start').=Öalışan_bir_gnuserv_sürecine_bağlanılamadı._Emacs_ya_da_XEmacs'ın_çalıştığına_ve<BR>sunucunun_başlatıldığına_('server-start'/'gnuserv-start'_komutu_çalıştırılarak)_emin_olun,
Could_not_connect_to_running_OpenOffice/LibreOffice.=Çalışan_OpenOffice/LibreOffice'e_bağlanılamıyor.
@@ -1122,21 +1752,16 @@ Your_style_file_specifies_the_character_format_'%0',_which_is_undefined_in_your_
Your_style_file_specifies_the_paragraph_format_'%0',_which_is_undefined_in_your_current_OpenOffice/LibreOffice_document.=Stil_dosyanız,_mevcut_OpenOffice/LibreOffice_belgenizde_tanımlanmamış_olan_'%0'_paragraf_formatını_belirtiyor.
Searching...=Arıyor...
-
You_have_selected_more_than_%0_entries_for_download._Some_web_sites_might_block_you_if_you_make_too_many_rapid_downloads._Do_you_want_to_continue?=İndirmek_için_%0'dan_fazla_girdi_seçtiniz._Çok_sayıda_hızlı_indirme_yaparsanız_bazı_web_siteleri_sizi_bloke_edebilir._Devam_etmek_istiyor_musunuz?
Confirm_selection=Seçimi_onayla
-Unknown_DOI\:_'%0'.=Bilinmeyen_DOI\:_'%0'.
Add_{}_to_specified_title_words_on_search_to_keep_the_correct_case=Aramada_doğru_küçük_büyük_harf_seçimi_için_belirli_başlık_sözcüklerine_{}_ekleyin
Import_conversions=Dönüşümleri_içe_aktar
Please_enter_a_search_string=Lütfen_bir_arama_dizgesi_girin
Please_open_or_start_a_new_database_before_searching=Lütfen_aramadan_önce_bir_veri_tabanı_açın_ya_da_başlatın
-An_error_occurred_while_fetching_from_ADS_(%0)\:=ADS'den_getirirken_bir_hata_oluştu_(%0)\:
-An_error_occurred_while_parsing_abstract=Özet_ayrıştırılırken_bir_hata_oluştu
-Unknown_DiVA_entry\:_'%0'.=_'%0'.=Bilinmeyen_DiVA_girdisi\:_'%0'.
-Get_BibTeX_entry_from_DiVA=BibTeX_girdisini_DIVA'dan_al
Log=Kayıt
Canceled_merging_entries=Girdilerin_birleştirilmesi_iptal_edildi
+
Format_units_by_adding_non-breaking_separators_and_keeping_the_correct_case_on_search=Birimleri_bölünemez_ayraçlar_ekleyerek_ve_aramadaki_büyük_küçük_harfleri_koruyarak_biçimle
Merge_entries=Girdileri_birleştir
Merged_entries=Girdiler_yeni_birine_birleştirildi_ve_eskiler_korundu
@@ -1148,8 +1773,10 @@ Show_DOI_first=Önce_DOI'yı_göster
Show_URL_first=Önce_URL'yi_göster
Use_Emacs_key_bindings=Emacs_tuş_bağlantılarını_kullan
You_have_to_choose_exactly_two_entries_to_merge.=Birleştirmek_için_tam_tamına_iki_girdi_seçmelisiniz.
+
Update_timestamp_on_modification=Değiştirirken_zaman_damgasını_güncelle
All_key_bindings_will_be_reset_to_their_defaults.=Tüm_tuş_bağlantıları_öntanımlılara_dönüştürülecek.
+
Automatically_set_file_links=Dosya_bağlantılarını_otomatik_olarak_kur
Continue?=Devam?
Resetting_all_key_bindings=Tüm_tuş_bağlantıları_başa_döndürülüyor
@@ -1157,22 +1784,26 @@ Hostname=Makine
Invalid_setting=Geçersiz_ayar
Network=Ağ
Please_specify_both_hostname_and_port=Lütfen_hem_makine_adını_hem_de_bağlantı_noktasını_belirtin
-Port=Bağlantı_noktası
-Use_custom_proxy_configuration=Özelleştirilmiş_vekil_konfigürasyonu_kullan
-
+Please_specify_both_username_and_password=Lütfen_hem_kullanıcı_adı_hem_de_parolayı_belirtiniz
+Use_custom_proxy_configuration=Özelleştirilmiş_vekil_konfigürasyonu_kullan
+Proxy_requires_authentication=Vekil_sunucu_kimlik_denetleme_gerektiriyor
+Attention\:_Password_is_stored_in_plain_text\!=Dikkat\:_Parola_salt_metin_olarak_kaydedildi\!
Clear_connection_settings=Bağlantı_ayarlarını_sil
Cleared_connection_settings.=Bağlantı_ayarları_silindi.
+
Rebind_C-a,_too=C-a'yı_da_yeniden_bağla
+Rebind_C-f,_too=C-f'yi_de_tekrar_bağla
Show_number_of_elements_contained_in_each_group=Her_grubun_içerdiği_öğe_sayısını_göster
Open_folder=Klasörü_aç
Searches_for_unlinked_PDF_files_on_the_file_system=Dosya_sisteminde_bağlantılanmamış_PDF_dosyalarını_arar
-
Export_entries_ordered_as_specified=Girdileri_belirtilen_sırada_dışa_aktar
Export_sort_order=Sıralama_kriterlerini_dışa_aktar
+Export_sorting=Sıralamayı_dışa_aktar
Newline_separator=Satırbaşı_ayracı
+
Save_entries_ordered_as_specified=Girdileri_belirtilen_sırada_kaydet
Save_sort_order=Sıralama_kriterlerini_kaydet
Show_extra_columns=Ekstra_sütunları_göster
@@ -1183,7 +1814,6 @@ Move_to_group=gruba_taşı
Clear_read_status=Okundu_statüsünü_temizle
Convert_to_BibLatex_format_(for_example,_move_the_value_of_the_'journal'_field_to_'journaltitle')=Biblatex_biçemine_dönüştür_(örneğin_'journal'_alanının_değerini_'journaltitle'a_taşı)
-Could_not_apply_changes.=Değişiklikler_uygulanamadı.
Deprecated_fields=Yürürlükten_kalkmış_alanlar
Hide/show_toolbar=Araç_çubuğunu_gizle/göster
No_read_status_information=Okunma_statüsü_bilgisi_yok
@@ -1195,125 +1825,109 @@ Save_selected_as_plain_BibTeX...=Seçimi_salt_BibTeX_olarak_kaydet...
Set_read_status_to_read=Okunma_statüsünü_okunmuş_olarak_ata
Set_read_status_to_skimmed=Okunma_statüsünü_göz_gezdirilmiş_olarak_ata
Show_deprecated_BibTeX_fields=Yürürlükten_kaldırılmış_BibTeX_alanlarını_göster
+
Show_gridlines=Izgarayı_göster
Show_printed_status=Yazdırma_statüsünü_göster
Show_read_status=Okunma_statüsünü_göster
Table_row_height_padding=Tablo_satır_yüksekliği_dolgusu
-Marked_all_%0_selected_entries=Tüm_%0_seçilmiş_girdi_işaretlendi
Marked_selected_entry=Seçilmiş_girdi_işaretlendi
-Toggle_print_status=Yazdırma_statüsünü_değiştir
-Unmarked_all_%0_selected_entries=Tüm_%0_seçilmiş_girdinin_işareti_kaldırıldı
+Marked_all_%0_selected_entries=Tüm_%0_seçilmiş_girdi_işaretlendi
Unmarked_selected_entry=Seçilmiş_girdinin_işareti_kaldırıldı
+Unmarked_all_%0_selected_entries=Tüm_%0_seçilmiş_girdinin_işareti_kaldırıldı
+Toggle_print_status=Yazdırma_statüsünü_değiştir
+
Unmarked_all_entries=Tüm_girdilerin_işareti_kaldırıldı
Unable_to_find_the_requested_look_and_feel_and_thus_the_default_one_is_used.=Arzu_edilen_Görünüm_ve_Tema_bulunamadığından_öntanımlı_olan_kullanıldı.
-Could_not_open_browser.=Tarayıcı_açılamadı.
Opens_JabRef's_GitHub_page=JabRef'in_GitHub_sayfasını_açar
-
-Rebind_C-f,_too=C-f'yi_de_tekrar_bağla
-This_group_contains_all_entries._It_cannot_be_edited_or_removed.=Bu_grup_tüm_girdileri_içeriyor._Düzenlenemez_ya_da_silinemez.
+Could_not_open_browser.=Tarayıcı_açılamadı.
+Please_open_%0_manually.=Lütfen_%0'i_kendiniz_açın.
+The_link_has_been_copied_to_the_clipboard.=Bağlantı_panoya_kopyalandı.
Open_%0_file=%0_dosyayı_aç
Cannot_delete_file=Dosya_silinemiyor
-Convert=Dönüştür
-Delete_local_file=Yerel_dosyayı_sil
File_permission_error=Dosya_izin_hatası
-Help_on_Name_Formatting=İsim_Biçimlemede_Yardım
-Normalize_to_BibTeX_name_format=BibTeX_adı_biçimine_normalleştir
-Path_to_%0=%0_yolu
Push_to_%0=%0'e_itele
+Path_to_%0=%0_yolu
+Convert=Dönüştür
+Normalize_to_BibTeX_name_format=BibTeX_adı_biçimine_normalleştir
+Help_on_Name_Formatting=İsim_Biçimlemede_Yardım
+
+Add_new_file_type=Yeni_dosya_türü_ekle
-Follow_DOI_or_URL_link_and_try_to_locate_PDF_full_text_document=DOI_ya_da_URL_linikini_izle_ve_PDF_tam_metin_belgesini_bulmaya_çalış
Left_entry=Sol_girdi
-No_information_added=Bilgi_eklenmedi
-Original_entry=Orjinal_girdi
Right_entry=Sağ_girdi
-Select_at_least_one_entry_to_manage_keywords.=Anahtar_sözcükleri_yönetmek_için_en_az_bir_girdi_seçiniz.
Use=Kullan
-Changed_type_to_'%0'_for=Tür_'%0'e_değiştirildi
-Database_'%0'_has_changed.=Veri_tabanı_'%0'_değişti.
-Copy_\\cite{BibTeX_key}=\\cite{BibTeX_anahtarı}'nı_kopyala
-Copy_BibTeX_key_and_title=BibTeX_anahtarı_ve_başlığını_kopyala
-To_set_up,_go_to=Kurmak_için,_şuraya_git
-Search_%0=%0'de_ara
-Invalid_DOI\:_'%0'.=Geçersiz_DOI\:_'%0'.
-Could_not_connect_to_%0=%0'e_bağlanılamadı
-
+Original_entry=Orjinal_girdi
+Replace_original_entry=Orjinal_girdinin_yerine_koy
+No_information_added=Bilgi_eklenmedi
+Select_at_least_one_entry_to_manage_keywords.=Anahtar_sözcükleri_yönetmek_için_en_az_bir_girdi_seçiniz.
+OpenDocument_text=AçıkBelge_metni
+OpenDocument_spreadsheet=AçıkBelge_iş_tablosu
+OpenDocument_presentation=AçıkBelge_sunumu
%0_image=%0_resim
-%0_problem(s)_found=%0_sorun_bulundu
-'%0'_is_not_a_valid_ADS_bibcode.='%0'_geçerli_bir_ADS_bibkodu_değil.
-Accepting_the_change_replaces_the_complete_groups_tree_with_the_externally_modified_groups_tree.=Değişikliği_kabul_etmek,_harici_olarak_değiştirilmiş_grup_ağacını_mevcut_grup_ağacının_tamamının_yerine_koyar.
-Add_new_file_type=Yeni_dosya_türü_ekle
Added_entry=Eklenen_girdi
-Added_new_'%0'_entry.='%0'_yebi_girdi_eklendi.
-Deleted_entry=Girdi_silindi
-Discard_changes=Değişiklikleri_sil
-Donate_to_JabRef=JabRef'e_bağış_yap
-Export_with_selected_format=Seçili_biçimle_dışa_aktar
-Field_is_missing=Kayıp_alan
-File_rename_failed_for_%0_entries.=%0_girdide_dosya_yeniden_adlandırma_başarısız.
-Filled=Dolduruldu
-From_import=İçe_almadan
-Keep_left=Solu_tut
-Keep_merged_entry_only=Yalnızca_birleşik_girdiyi_tut
-Keep_right=Sağı_tut
-Merged_BibTeX_source_code=Birleşik_BibTeX_kaynak_kodu
Modified_entry=Değiştirilmiş_girdi
+Deleted_entry=Girdi_silindi
Modified_groups_tree=Değiştirilmiş_grup_ağacı
-Multiple_entries_selected._Do_you_want_to_change_the_type_of_all_these_to_'%0'?=Çok_sayıda_girdi_seçili._Tüm_bunların_türünü_'%0'e_değiştirmek_ister_misiniz?
-No_problems_found.=Hiçbir_sorun_bulunmadı.
-Old_entry=Eski_girdi
-OpenDocument_presentation=AçıkBelge_sunumu
-OpenDocument_spreadsheet=AçıkBelge_iş_tablosu
-OpenDocument_text=AçıkBelge_metni
-Please_move_the_file_manually_and_link_in_place.=Lütfen_dosyayı_elle_taşıyın_ve_yerinde_bağlantı_kurun.
-Print_entry_preview=Girdi_yazdırma_önizleme
-Really_delete_the_%0_selected_entries?=Gerçekten_seçili_%0_girdi_silinsin_mi?
-Really_delete_the_selected_entry?=Gerçekten_seçili_girdi_silinsin_mi?
Removed_all_groups=Tüm_gruplar_silindi
-Replace_original_entry=Orjinal_girdinin_yerine_koy
-
-
-Return_to_JabRef=JabRef'e_geri_dön
-Save_changes=Değişiklikleri_kaydet
+Accepting_the_change_replaces_the_complete_groups_tree_with_the_externally_modified_groups_tree.=Değişikliği_kabul_etmek,_harici_olarak_değiştirilmiş_grup_ağacını_mevcut_grup_ağacının_tamamının_yerine_koyar.
Select_export_format=Dışa_aktarma_biçemini_seç
+Return_to_JabRef=JabRef'e_geri_dön
+Please_move_the_file_manually_and_link_in_place.=Lütfen_dosyayı_elle_taşıyın_ve_yerinde_bağlantı_kurun.
+Could_not_connect_to_%0=%0'e_bağlanılamadı
Warning\:_%0_out_of_%1_entries_have_undefined_BibTeX_key.=Uyarı\:%1_girdiden_%0'inde_tanımlanmamış_BibTeX_anahtarı_var.
-large_capitals_are_not_masked_using_curly_brackets_{}=küme_parantezleri_{}_kullanarak_büyük_harfler_maskelenmez
occurrence=görülme
-should_contain_a_four_digit_number=dört_basamaklı_bir_numara_içermeli
-should_contain_a_valid_page_number_range=geçerli_bir_sayfa_numarası_aralığı_içermeli
-should_end_with_a_name=bir_isimle_sonlanmalı
+Added_new_'%0'_entry.='%0'_yebi_girdi_eklendi.
+Multiple_entries_selected._Do_you_want_to_change_the_type_of_all_these_to_'%0'?=Çok_sayıda_girdi_seçili._Tüm_bunların_türünü_'%0'e_değiştirmek_ister_misiniz?
+Changed_type_to_'%0'_for=Tür_'%0'e_değiştirildi
+Really_delete_the_selected_entry?=Gerçekten_seçili_girdi_silinsin_mi?
+Really_delete_the_%0_selected_entries?=Gerçekten_seçili_%0_girdi_silinsin_mi?
+Keep_merged_entry_only=Yalnızca_birleşik_girdiyi_tut
+Keep_left=Solu_tut
+Keep_right=Sağı_tut
+Old_entry=Eski_girdi
+From_import=İçe_almadan
+No_problems_found.=Hiçbir_sorun_bulunmadı.
+%0_problem(s)_found=%0_sorun_bulundu
+Save_changes=Değişiklikleri_kaydet
+Discard_changes=Değişiklikleri_sil
+Database_'%0'_has_changed.=Veri_tabanı_'%0'_değişti.
+Print_entry_preview=Girdi_yazdırma_önizleme
+Copy_\\cite{BibTeX_key}=\\cite{BibTeX_anahtarı}'nı_kopyala
+Copy_BibTeX_key_and_title=BibTeX_anahtarı_ve_başlığını_kopyala
+File_rename_failed_for_%0_entries.=%0_girdide_dosya_yeniden_adlandırma_başarısız.
+To_set_up,_go_to=Kurmak_için,_şuraya_git
+Merged_BibTeX_source_code=Birleşik_BibTeX_kaynak_kodu
+Invalid_DOI\:_'%0'.=Geçersiz_DOI\:_'%0'.
should_start_with_a_name=bir_isimle_başlamalı
+should_end_with_a_name=bir_isimle_sonlanmalı
unexpected_closing_curly_bracket=beklenmeyen_küme_parantezi_kapanışı
unexpected_opening_curly_bracket=beklenmeyen_küme_parantezi_açılışı
+capital_letters_are_not_masked_using_curly_brackets_{}=küme_parantezleri_{}_kullanarak_büyük_harfler_maskelenmez
+should_contain_a_four_digit_number=dört_basamaklı_bir_numara_içermeli
+should_contain_a_valid_page_number_range=geçerli_bir_sayfa_numarası_aralığı_içermeli
+Filled=Dolduruldu
+Field_is_missing=Kayıp_alan
+Search_%0=%0'de_ara
-
-Advanced_search_active.=İleri_düzey_arama_aktif.
-Found_%0_results.=%0_sonuç_bulundu.
-No_results_found.=Hiçbir_sonuç_bulunmadı.
-Normal_search_active.=Normal_arama_aktif.
-Search_globally=Küresel_ara
-Search_in_all_open_databases=Tüm_açık_veritabanlarında_ara
Search_results_in_all_databases_for_%0=Sonuçları_%0_için_tüm_veritabanlarında_ara
Search_results_in_database_%0_for_%1=Sonuçları_%1_için_%0_veritabanında_ara
-This_search_contains_entries_in_which=Bu_arama_içinde_şu_olan_girdileri_içerir
+Search_globally=Küresel_ara
+No_results_found.=Hiçbir_sonuç_bulunmadı.
+Found_%0_results.=%0_sonuç_bulundu.
+Advanced_search_active.=İleri_düzey_arama_aktif.
+Normal_search_active.=Normal_arama_aktif.
+plain_text=salt_metin
This_search_contains_entries_in_which_any_field_contains_the_regular_expression_<b>%0</b>=Bu_arama,_<b>%0</b>_düzenli_ifadesini_içeren_herhangi_bir_alan_bulunan_girdileri_içerir
This_search_contains_entries_in_which_any_field_contains_the_term_<b>%0</b>=Bu_arama,_<b>%0</b>_terimini_içeren_herhangi_bir_alan_bulunan_girdileri_içerir
-plain_text=salt_metin
-
-Attention\:_Password_is_stored_in_plain_text\!=Dikkat\:_Parola_salt_metin_olarak_kaydedildi\!
-Please_specify_both_username_and_password=Lütfen_hem_kullanıcı_adı_hem_de_parolayı_belirtiniz
-Proxy_requires_authentication=Vekil_sunucu_kimlik_denetleme_gerektiriyor
-
-An_autosave_file_was_found_for_this_database._This_could_indicate_that_JabRef_did_not_shut_down_cleanly_last_time_the_file_was_used.=Bu_veri_tabanı_için_bir_otomatik_kaydetme_dosyası_bulundu._Bu,_dosya_son_kullanıldığında_JabRef'in_temiz_şekilde_kapanmadığını_belitebilir.
+This_search_contains_entries_in_which=Bu_arama_içinde_şu_olan_girdileri_içerir
-Note\:_A_full_text_search_is_currently_not_supported_for_%0=Not\:%0_için_tam_metin_arama_henüz_desteklenmiyor
Unable_to_autodetect_OpenOffice/LibreOffice_installation._Please_choose_the_installation_directory_manually.=OpenOffice/LibreOffice_kurulumu_otomatik_olarak_bulunamadı._Lütfen_kurulum_dizinini_kendiniz_seçiniz.
-
JabRef_no_longer_supports_'ps'_or_'pdf'_fields.<br>File_links_are_now_stored_in_the_'file'_field_and_files_are_stored_in_an_external_file_directory.<br>To_make_use_of_this_feature,_JabRef_needs_to_upgrade_file_links.<br><br>=JabRef_artık_'ps'_ya_da_'pdf!_alanlarını_desteklemiyor._<br>Dosya_bağlantıları_artık_'dosya'_alanında_ve_dosyalar_da_harici_bir_dosya_dizininde_depolanıyor.<br>Bu_özelliği_kullanabilmek_için_JabRef_dosya_bağlantılarını_yükseltmek_zorunda.<br><br>
This_database_uses_outdated_file_links.=Bu_veri_tabanı_güncelliğini_yitirmiş_dosya_bağlantıları_kullanıyor.
@@ -1352,53 +1966,32 @@ Resolve_duplicate_BibTeX_keys=Çift_kopyalı_BibTeX_anahtarlarını_çözümle
Save_all=Tümünü_kaydet
String_dialog,_add_string=Dizilim_iletişim_kutusu,_dizilim_ekle
String_dialog,_remove_string=Dizilim_iletişim_kutusu,_dizilim_çıkar
-Switch_preview_layout=Önizleme_anahattını_değiştir
Synchronize_files=Dosyaları_eşzamanla
Unabbreviate=Kısaltmayı_kaldır
-
should_contain_a_protocol=bir_protokol_içermeli
Copy_preview=Kopyalama_önizleme
-
Automatically_setting_file_links=Dosya_bağlantıları_otomatik_olarak_ayarlanıyor
Regenerating_BibTeX_keys_according_to_metadata=Üstveri_(metadata)_uyarınca_BibTeX_anahtarları_yeniden_oluşturuluyor
No_meta_data_present_in_BIB_file._Cannot_regenerate_BibTeX_keys=Bibdosyasında_üstveri_yok._Bibtex_anahtarları_yeniden_oluşturulamıyor
-
Regenerate_all_keys_for_the_entries_in_a_BibTeX_file=Bir_BibTeX_dosyasındaki_tüm_girdiler_için_tüm_anahtarları_yeniden_oluştur
-
Show_debug_level_messages=Hata_ayıklama_düzeyi_mesajları_göster
-
-Export_sorting=Sıralamayı_dışa_aktar
-
-New_%0_database=Yeni_%0_veri_tabanı
-
-New_%0_database_created.=Yeni_%0_veri_tabanı_oluşturuldu.
-
-No_entry_found_for_ISBN_%0_at_www.ebook.de=ISBN_%0_için_www.ebook.de'de_girdi_bulunamadı
-
-Save_actions=Eylemleri_kaydet
-Enable_save_actions=Eylemleri_kaydetmeyi_etkinleştir
-Always_reformat_BIB_file_on_save_and_export=Kaydetme_ve_dışa_aktarmada_BIB_dosyasını_her_zaman_yeniden_biçemle
-
Default_bibliography_mode=Öntanımlı_bibliyografya_kipi
-
-
+New_%0_database_created.=Yeni_%0_veri_tabanı_oluşturuldu.
Show_only_preferences_deviating_from_their_default_value=Yalnızca_öntanımlı_değerlerinden_sapan_tercihleri_göster
default=öntanımlı
key=anahtar
type=tür
value=değer
-
Show_preferences=Tercihleri_göster
-
+Save_actions=Eylemleri_kaydet
+Enable_save_actions=Eylemleri_kaydetmeyi_etkinleştir
Other_fields=Diğer_alanlar
Show_remaining_fields=Kalan_alanları_göster
link_should_refer_to_a_correct_file_path=bağlantı_doğru_bir_dosya_yolunu_işaret_etmeli
-
abbreviation_detected=kısaltma_saptandı
wrong_entry_type_as_proceedings_has_page_numbers=yanlış_girdi_türü_zira_tutanaklarda_sayfa_numarası_olur
-
Abbreviate_journal_names=Dergi_adlarını_kısalt
Abbreviating...=Kısaltılıyor...
Adding_fetched_entries=Getirilen_girdiler_ekleniyor
@@ -1410,25 +2003,22 @@ Unabbreviate_journal_names=Dergi_adları_kısaltmalarını_dönüştür
Unabbreviating...=Kısaltmalar_dönüştürülüyor...
Usage=Kullanım
+
+Adds_{}_brackets_around_acronyms,_month_names_and_countries_to_preserve_their_case.=Harf_çeşidini_(büyük/küçük)_korumak_için_%lerin_içindeki_akronim,_ay_adları_ve_ülkelerin_çevresine_küme_parantezi_ekle.
Are_you_sure_you_want_to_reset_all_settings_to_default_values?=Tüm_ayarları_öntanımlı_değerlere_dönüştürmek_istediğinizden_emin_misiniz?
Reset_preferences=Tercihleri_sıfırla
-
Ill-formed_entrytype_comment_in_BIB_file=Bib_dosyasında_kötü_biçimli_girdi_türü_yorumu
+
+Move_linked_files_to_default_file_directory_%0=Bağlantılı_dosyaları_öntanımlı_dosya_dizinine_aktar_%0
+
Clipboard=Pano
Could_not_paste_entry_as_text\:=Girdi_metin_olarak_yapıştırılamıyor\:
Do_you_still_want_to_continue?=Hala_devam_etmek_istiyor_musunuz?
This_action_will_modify_the_following_field(s)_in_at_least_one_entry_each\:=Bu_eylem_aşağıdaki_alanları_en_az_bir_girdide_değiştirecek\:
This_could_cause_undesired_changes_to_your_entries.=Bu,_girdilerinizde_istenmeyen_değişikliklere_yol_açabilir.
-
-Disable_highlight_groups_matching_entries=Vurgulu_gruplarla_eşleşen_girdileri_etkisizleştir
Run_field_formatter\:=Alan_biçimlendiriciyi_çalıştır\:
-
-Adds_{}_brackets_around_acronyms,_month_names_and_countries_to_preserve_their_case.=Harf_çeşidini_(büyük/küçük)_korumak_için_%lerin_içindeki_akronim,_ay_adları_ve_ülkelerin_çevresine_küme_parantezi_ekle.
-Converts_units_to_LaTeX_formatting.=%lerin_içindeki_birimleri_LaTeX_koduna_dönüştürür.
-Does_nothing.=Hiçbir_şey_yapmaz.
-
-
Table_font_size_is_%0=Tablo_yazıtipi_boyutu_%0'dır
+%0_import_canceled=%0_içe_aktarımı_iptal_edildi
Internal_style=Dahili_stil
Add_style_file=Stil_dosyası_ekle
Are_you_sure_you_want_to_remove_the_style?=Stili_silmek_istediğinizden_emin_misiniz?
@@ -1437,6 +2027,7 @@ Remove_style=Stili_sil
Select_one_of_the_available_styles_or_add_a_style_file_from_disk.=Mevcut_stillerden_birini_seçin_ya_da_sürücüden_stil_dosyası_ekleyin.
You_must_select_a_valid_style_file.=Geçerli_bir_stil_dosyası_seçmelisiniz.
Reload=Yeniden_yükle
+
Capitalize=Büyük_harfe_dönüştür
Capitalize_all_words,_but_converts_articles,_prepositions,_and_conjunctions_to_lower_case.=Tüm_sözcükleri_büyük_harfe_dönüştür_ama_artikel,_edat_ve_bağlaçları_küçük_harfe_dönüştür.
Capitalize_the_first_word,_changes_other_words_to_lower_case.=İlk_sözcüğü_büyük_harfe,_diğer_tüm_sözcükleri_küçük_harfe_deönüştür.
@@ -1445,9 +2036,11 @@ Changes_all_letters_to_upper_case.=Tüm_harfleri_büyük_harfe_dönüştür.
Changes_the_first_letter_of_all_words_to_capital_case_and_the_remaining_letters_to_lower_case.=Tüm_sözcüklerin_ilk_harfini_büyük_harfe,_diğer_tüm_harflerini_küçük_harfe_dönüştür.
Cleans_up_LaTeX_code.=LaTeX_kodunu_temizler.
Converts_HTML_code_to_LaTeX_code.=HTML_kodunu_LaTeX_koduna_dönüştürür.
+Converts_HTML_code_to_Unicode.=HTML_kodunu_Unicode'a_dönüştürür.
Converts_LaTeX_encoding_to_Unicode_characters.=LaTeX_kodunu_Unicode_karakterlerine_dönüştürür.
Converts_Unicode_characters_to_LaTeX_encoding.=Unicode_karakterlerini_LaTeX_koduna_dönüştürür.
Converts_ordinals_to_LaTeX_superscripts.=Sıra_sayılarını_LaTeX_üstyazılarına_dönüştürür.
+Converts_units_to_LaTeX_formatting.=%lerin_içindeki_birimleri_LaTeX_koduna_dönüştürür.
HTML_to_LaTeX=HTML'den_LaTeX'e
LaTeX_cleanup=LaTeX_temizleme
LaTeX_to_Unicode=LaTeX'ten_Unicode'a
@@ -1471,6 +2064,7 @@ Title_case=Başlık_(harf)_şekli
Unicode_to_LaTeX=Unicode'dan_LaTeX'e
Units_to_LaTeX=Birimler'den_LaTeX'e
Upper_case=Büyük_harf
+Does_nothing.=Hiçbir_şey_yapmaz.
Identity=Kimlik
Clears_the_field_completely.=Alanı_tamamen_temizler.
Directory_not_found=Dizin_bulunamadı
@@ -1485,11 +2079,8 @@ Mixed_names=Karışık_adlar
Neuter_name=Cinsiyetsiz_ad
Neuter_names=Cinsiyetsiz_adlar
-Move_linked_files_to_default_file_directory_%0=Bağlantılı_dosyaları_öntanımlı_dosya_dizinine_aktar_%0
-
Lookup_DOI=DOI_bul
-booktitle_ends_with_'conference_on'=kitap_başlığı_'konudaki_konferans'_ile_bitiyor
Audio_CD=Müzik_CDsi
British_patent=İngiliz_patenti
British_patent_request=İngiliz_patent_başvurusu
@@ -1531,10 +2122,10 @@ Plain_text=Salt_metin
Show_diff=Diff_göster
character=karakter
word=sözcük
-
Show_symmetric_diff=Simetrik_diff_göster
HTML_encoded_character_found=HTML_kodlu_karakter_bulundu
+booktitle_ends_with_'conference_on'=kitap_başlığı_'konudaki_konferans'_ile_bitiyor
All_external_files=Tüm_harici_dosyalar
@@ -1542,20 +2133,11 @@ OpenOffice/LibreOffice_integration=OpenOffice/LibreOffice_entegrasyonu
incorrect_control_digit=yanlış_kontrol_numarası
incorrect_format=yanlış_biçem
-
-Expected_"%0"_to_contain_whitespace="%0"ın_beyazboşluk_içermesi_bekleniyordu
-Syntax_error_in_regular-expression_pattern=Düzenli_ifade_düzeninde_sözdizimi_hatası
-
Copy_version_to_clipboard=Sürümü_panoya_kopyala
Copied_version_to_clipboard=Sürüm_panoya_kopyalandı
BibTeX_key=BibTeX_anahtarı
Message=Mesaj
-
-Get_fulltext=Tammetni_getir
-
-Download_from_URL=URL'den_indir
-
Decryption_not_supported.=Şifre_çözme_desteklenmiyor.
Cleared_'%0'_for_%1_entries=%1_girdi_için_%0_temizlendi
@@ -1574,16 +2156,11 @@ To_see_what_is_new_view_the_changelog.=Yenilikleri_görmek_için_değişiklik_k
A_new_version_of_JabRef_has_been_released.=JabRef'in_yeni_bir_sürümü_yayınlandı.
JabRef_is_up-to-date.=JabRef_güncel.
Latest_version=En_son_sürüm
-
-Please_open_%0_manually.=Lütfen_%0'i_kendiniz_açın.
-
-The_link_has_been_copied_to_the_clipboard.=Bağlantı_panoya_kopyalandı.
-
Online_help_forum=Çevrimiçi_yardım_forumu
-
Custom=Özel
-Converts_HTML_code_to_Unicode.=HTML_kodunu_Unicode'a_dönüştürür.
+Export_cited=Başvurulanları_dışa_aktar
+Unable_to_generate_new_database=Yeni_veritabanı_oluşturulamadı
Open_console=Konsolu_aç
Use_default_terminal_emulator=Öntanımlı_uçbirim_öykünücüsünü_kullan
@@ -1591,30 +2168,22 @@ Execute_command=Komutu_çalıştır
Note\:_Use_the_placeholder_%0_for_the_location_of_the_opened_database_file.=Not\:Açık_veritabanının_konumu_için_%0_yer_tutucusunu_kullan.
Executing_command_\"%0\"...=\"%0\"_komutu_çalıştırılıyor...
Error_occured_while_executing_the_command_\"%0\".=\"%0\"_komutu_çalıştırılırken_hata_oluştu.
-
Reformat_ISSN=ISSN'i_yeniden_biçimlendir
-Unable_to_generate_new_database=Yeni_veritabanı_oluşturulamadı
-
-Export_cited=Başvurulanları_dışa_aktar
Countries_and_territories_in_English=Ülke_ve_bölgeler_İngilizce
Electrical_engineering_terms=Elektrik_mühendisliği_terimleri
Enabled=Aktifleştirildi
Internal_list=Dahili_liste
+Manage_protected_terms_files=Korunmuş_terimler_dosyasını_yönet
Months_and_weekdays_in_English=Ay_ve_haftanın_günleri_İngilizce
The_text_after_the_last_line_starting_with_\#_will_be_used=\#_ile_başlayan_son_satırdan_sonraki_metin_kullanılacak
-
Add_protected_terms_file=Korunmuş_terimler_dosyası_ekle
Are_you_sure_you_want_to_remove_the_protected_terms_file?=Korunmuş_terimler_dosyasını_silmek_istediğinizden_emin_misiniz?
Remove_protected_terms_file=Korunmuş_terimler_dosyasını_sil
-
-Manage_protected_terms_files=Korunmuş_terimler_dosyasını_yönet
Add_selected_text_to_list=Seçili_metni_listeye_ekle
Add_{}_around_selected_text=Seçili_metnin_çevresine_{}_ekle
Format_field=Alanı_biçimle
New_protected_terms_file=Yeni_korunmuş_terimler_dosyası
-
-
change_field_%0_of_entry_%1_from_%2_to_%3=%1_girdisinin_%0_alanını_%2'den_%3'e_değiştir
change_key_from_%0_to_%1=anahtarı_%0'dan_%1'e_değiştir
change_string_content_%0_to_%1=dizge_içeriğini_%0'dan_%1'e_değiştir
@@ -1624,36 +2193,29 @@ insert_entry_%0=%0_girdisini_ekle
insert_string_%0=%0_dizgesini_ekle
remove_entry_%0=%0_girdisini_sil
remove_string_%0=%0_dizgesini_sil
-
undefined=tanımlanmamış
Cannot_get_info_based_on_given_%0\:_%1=Verilen_%0\:_%1'e_göre_bilgi_alınamıyor
-
Get_BibTeX_data_from_%0=%0'den_BibTeX_verisini_al
No_%0_found=_%0_bulunamadi
-
Entry_from_%0=%0'den_girdi
-
Merge_entry_with_%0_information=%0_bilgisiyle_girdiyi_birleştir
Updated_entry_with_info_from_%0=%0'den_edinilen_bilgiyle_girdi_güncellendi
Connection=Bağlantı
+Connecting...=Bağlanıyor...
Host=Makine
+Port=Bağlantı_noktası
Database=Veritabanı
User=Kullanıcı
+Connect=Bağlan
Connection_error=Bağlantı_hatası
-Driver_error=Sürücü_hatası
Connection_to_%0_server_established.=%0_sunucusuna_bağlantı_sağlandı
Required_field_"%0"_is_empty.=Gerekli_alan_"%0"_boş.
-
%0_driver_not_available.=%0_sürücüsü_yok
-
The_connection_to_the_server_has_been_terminated.=Sunucuyla_olan_bağlantı_sonlandırıldı.
-
Connection_lost.=Bağlantı_koptu.
Reconnect=Yeniden_bağlan
Work_offline=Çevrimdışı_çalış
-
Working_offline.=Çevrimdışı_çalışılıyor.
-
Update_refused.=Güncelleme_reddedildi.
Update_refused=Güncelleme_reddedildi
Local_entry=Yerel_girdi
@@ -1664,7 +2226,12 @@ Local_version\:_%0=Yerel_sürüm\:_%0
Shared_version\:_%0=Paylaşılmış_sürüm\:_%0
Please_merge_the_shared_entry_with_yours_and_press_"Merge_entries"_to_resolve_this_problem.=Bu_sorunu_çözmek_için_lütfen_paylaşılmış_girdiyle_sizinkini_birleştirin_ve_"Girdileri_birleştir"'e_basın.
Canceling_this_operation_will_leave_your_changes_unsynchronized._Cancel_anyway?=Bu_işlemi_iptal_etmek_değişkliklerinizi_eşzamanlanmamış_halde_bırakacak._Yine_de_iptal_edilsin_mi?
-The_BibEntry_you_currently_work_on_has_been_deleted_on_the_shared_side._Hit_"Keep"_to_recover_the_entry.=Üzerinde_çalıştığınız_BibEntry_paylaşılmış_tarafta_silindi._Girdiyi_kurtarmak_için_"Keep"'e_basın.
+Shared_entry_is_no_longer_present=
+The_BibEntry_you_currently_work_on_has_been_deleted_on_the_shared_side.=Üzerinde_çalıştığınız_BibEntry_paylaşılmış_tarafta_silindi.
+You_can_restore_the_entry_using_the_"Undo"_operation.=
+Remember_password?=Parola_hatırlansın_mı?
+You_are_already_connected_to_a_database_using_entered_connection_details.=Girilmiş_bağlantı_ayarlarıyla_bir_veritabanına_zaten_bağlısınız.
+
Cannot_cite_entries_without_BibTeX_keys._Generate_keys_now?=BibTeX_anahtarları_olmadan_girdiler_alıntılanamaz._Anahtarlar_şimdi_oluşturulsun_mu?
New_technical_report=Yeni_teknik_rapor
@@ -1674,34 +2241,74 @@ Protected_terms_file=Korunmuş_terimler_dosyası
Style_file=Stil_dosyası
Open_OpenOffice/LibreOffice_connection=OpenOffice/LibreOffice_bağlantısı_aç
-
You_must_enter_at_least_one_field_name=En_az_bir_alan_adı_girmelisiniz
-
-
Non-ASCII_encoded_character_found=ASCII_koduyla_kodlanmamış_karakter_bulundu
-
Toggle_web_search_interface=Ağ_arama_arayüzünü_değiştir
-
Background_color_for_resolved_fields=Kararlaştırılmış_alanlar_için_arkaplan_rengi
Color_code_for_resolved_fields=Kararlaştırılmış_alanlar_için_renk_kodu
-
%0_files_found=%0_dosya_bulundu
%0_of_%1=%1'in_%0'i
One_file_found=Bir_dosya_bulundu
The_import_finished_with_warnings\:=İçe_aktarım_uyarılarla_bitti\:
There_was_one_file_that_could_not_be_imported.=İçe_aktarılamayan_bir_dosya_mevcuttu.
There_were_%0_files_which_could_not_be_imported.=İçe_aktarılamayan_%0_dosya_mevcuttu.
+
Migration_help_information=Gçö_yardımı_bilgisi
Entered_database_has_obsolete_structure_and_is_no_longer_supported.=Girilen_veritanbanı_kullanılmayan_yapıya_sahip_ve_artık_desteklenmiyor.
However,_a_new_database_was_created_alongside_the_pre-3.6_one.=Ancak,_3.6_öncesinin_yanı_sıra_yeni_bir_veritabanı_oluşturuldu.
-
Click_here_to_learn_about_the_migration_of_pre-3.6_databases.=3.6_öncesi_veritabanlarının_göçünü_öğrenmek_için_burayı_tıklayın.
-
-Connecting...=
-
-Opens_JabRef's_Facebook_page=
-Opens_JabRef's_blog=
-Opens_JabRef's_website=
-
-Opens_a_link_where_the_current_development_version_can_be_downloaded=
-See_what_has_been_changed_in_the_JabRef_versions=
+Opens_JabRef's_Facebook_page=JabRef'in_Facebook_sayfasını_açar
+Opens_JabRef's_blog=JabRef'in_ağ_güncesini_açar
+Opens_JabRef's_website=JabRef'in_web_sitesini_açar
+Opens_a_link_where_the_current_development_version_can_be_downloaded=Mevcut_geliştirme_sürümünün_indirilebileceği_bir_bağlantı_açar
+See_what_has_been_changed_in_the_JabRef_versions=JabRef_sürümlerinde_nelerin_değişmiş_olduğuu_görün
+Referenced_BibTeX_key_does_not_exist=Başvurulan_BibTeX_anahtarı_mevcut_değil
+Finished_downloading_full_text_document_for_entry_%0.=%0_girdisi_için_tam_metin_belgesinin_indirilmesi_bitti.
+Full_text_document_download_failed_for_entry_%0.=%0_girdisi_için_tam_metin_belgesinin_indirilmesi_başarısız.
+Look_up_full_text_documents=Tam_netin_belgeri_ara
+You_are_about_to_look_up_full_text_documents_for_%0_entries.=%0_adet_girdi_için_tam_metin_belgeleri_aramak_üzeresiniz.
+last_four_nonpunctuation_characters_should_be_numerals=noktalama_olmayan_son_dört_karakter_rakam_olmalıdır
+shared=paylaşıldı
+should_contain_an_integer_or_a_literal=bir_tamsayı_ya_da_harf_içermelidir
+should_have_the_first_letter_capitalized=İlk_harf_büyük_olmalıdır
+
+ID=ID(kimlik)
+ID_type=ID_türü
+ID-based_entry_generator=ID-tabanlı_girdi_oluşturucu
+Fetcher_'%0'_did_not_find_an_entry_for_id_'%1'.='%0'_getiricisi_'%1'_kimliği_için_bir_girdi_bulamadı.
+
+Select_first_entry=İlk_girdiyi_seç
+Select_last_entry=Son_girdiyi_seç
+
+Invalid_ISBN\:_'%0'.=Geçersiz_ISBN\:_'%0'.
+should_be_an_integer_or_normalized=bir_tamsayı_olmalı_ya_da_normalleştirilmelidir
+should_be_normalized=normalleştirilmelidir
+
+Empty_search_ID=Boş_arama_IDsi
+The_given_search_ID_was_empty.=Verilen_arama_IDsi_boştu.
+Copy_BibTeX_key_and_link=BibTeX_anahtarı_ve_bağlantısını_kopyala
+empty_BibTeX_key=boş_BibTeX_anahtarı
+BibLaTeX_field_only=Yalnızca_BibLaTeX_alanı
+
+Error_while_generating_fetch_URL=URL'den_getirme_oluşturulurken_hata
+Error_while_parsing_ID_list=ID_listesi_çözümlenirken_hata
+Unable_to_get_PubMed_IDs=PubMed_IDleri_alınamadı
+Backup_found=Yedek_bulundu
+A_backup_file_for_'%0'_was_found.='%0'_için_bir_yedek_dosyası_bulundu.
+This_could_indicate_that_JabRef_did_not_shut_down_cleanly_last_time_the_file_was_used.=Bu,_dosya_son_kullanıldığında_JabRef'in_temiz_kapatılmadığını_belirtiyor_olabilir.
+Do_you_want_to_recover_the_database_from_the_backup_file?=Veritabanınızı_yedek_dosyadan_kurtarmak_ister_misiniz?
+Firstname_Lastname=Ad_Soyad
+
+Recommended_for_%0=%0_için_önerilir
+This_might_be_caused_by_reaching_the_traffic_limitation_of_Google_Scholar_(see_'Help'_for_details).=Bu,_Google_Scholar'ın_trafik_limitine_erişmekten_dolayı_olabilir_(ayrıntılar_için_'Yardım'a_bakınız).
+
+Problem_downloading_from_%1=%1'den_indirmede_hata
+
+File_directory_pattern=
+Update_with_bibliographic_information_from_the_web=
+
+Could_not_find_any_bibliographic_information.=
+BibTeX_key_%0_deviates_from_generated_key_%1=
+DOI_%0_is_invalid=
+
+Jump_to_entry=
diff --git a/src/main/resources/l10n/JabRef_vi.properties b/src/main/resources/l10n/JabRef_vi.properties
index 5fe46f7..91fba67 100644
--- a/src/main/resources/l10n/JabRef_vi.properties
+++ b/src/main/resources/l10n/JabRef_vi.properties
@@ -1,5 +1,5 @@
#!
-#! created/edited by Popeye version 0.55 (https\://github.com/koppor/popeye)
+#! created/edited by Popeye version 0.55 (github.com/JabRef/popeye)
#! encoding:UTF-8
%0_contains_the_regular_expression_<b>%1</b>=%0_chứa_biểu_thức_chính_tắc_<b>%1</b>
@@ -12,18 +12,14 @@
%0_export_successful=%0_xuất_thành_công
-
%0_matches_the_regular_expression_<b>%1</b>=%0_khớp_biểu_thức_chính_tắc_<b>%1</b>
%0_matches_the_term_<b>%1</b>=%0_khớp_thuật_ngữ_<b>%1</b>
-<field_name>=<tên_trường>
<HTML>Could_not_find_file_'%0'<BR>linked_from_entry_'%1'</HTML>=<HTML>Không_thể_tìm_thấy_tập_tin_'%0'<BR>được_liên_kết_từ_mục_'%1'</HTML>
-
<select>=<chọn>
-<select_word>=<chọn_từ>
Abbreviate_journal_names_of_the_selected_entries_(ISO_abbreviation)=Viết_tắt_tên_tạp_chí_của_các_mục_được_chọn_(viết_tắt_kiểu_ISO)
Abbreviate_journal_names_of_the_selected_entries_(MEDLINE_abbreviation)=Viết_tắt_tên_tạp_chí_của_các_mục_được_chọn_(viết_tắt_kiểu_MEDLINE)
@@ -44,13 +40,12 @@ Action=Hành_động
Add=Thêm
-Add_a_(compiled)_custom_ImportFormat_class_from_a_class_path.=Thêm_một_lớp_ĐịnhdạngNhập_tùy_biến_(được_biên_dịch)_từ_đường_dẫn_lớp.
+Add_a_(compiled)_custom_Importer_class_from_a_class_path.=Thêm_một_lớp_ĐịnhdạngNhập_tùy_biến_(được_biên_dịch)_từ_đường_dẫn_lớp.
The_path_need_not_be_on_the_classpath_of_JabRef.=Đường_dẫn_không_được_trùng_với_đường_dẫn_lớp_của_JabRef.
-Add_a_(compiled)_custom_ImportFormat_class_from_a_ZIP-archive.=Thêm_một_lớp_ĐịnhdạngNhập_tùy_biến_(được_biên_dịch)_từ_một_tập_tin-zip._
+Add_a_(compiled)_custom_Importer_class_from_a_ZIP-archive.=Thêm_một_lớp_ĐịnhdạngNhập_tùy_biến_(được_biên_dịch)_từ_một_tập_tin-zip._
The_ZIP-archive_need_not_be_on_the_classpath_of_JabRef.=Tập_tin-zip_không_được_trùng_với_đường_dẫn_lớp_của_JabRef.
-
Add_entry_selection_to_this_group=Thêm_phép_chọn_mục_vào_nhóm_này
Add_from_folder=Thêm_từ_thư_mục
@@ -73,26 +68,24 @@ Added_new=Mới_được_thêm
Added_string=Chuỗi_được_thêm
-Additionally,_entries_whose_<b>%0</b>_field_does_not_contain_<b>%1</b>_can_be_assigned_manually_to_this_group_by_selecting_them_then_using_either_drag_and_drop_or_the_context_menu._This_process_adds_the_term_<b>%1</b>_to_each_entry's_<b>%0</b>_field._Entries_can_be_removed_manually_from_this_group_by_selecting_them_then_using_the_context_menu._This_process_removes_the_term_<b>%1</b>_from_each_entry's_<b>%0</b>_field.=Ngoài_ra,_những_mục_nào_có_trường_<b>%0</b>_không_chứa_<b>%1</b>_có_thể [...]
+Additionally,_entries_whose_<b>%0</b>_field_does_not_contain_<b>%1</b>_can_be_assigned_manually_to_this_group_by_selecting_them_then_using_either_drag_and_drop_or_the_context_menu._This_process_adds_the_term_<b>%1</b>_to_each_entry's_<b>%0</b>_field._Entries_can_be_removed_manually_from_this_group_by_selecting_them_then_using_the_context_menu._This_process_removes_the_term_<b>%1</b>_from_each_entry's_<b>%0</b>_field.=Ngoài_ra,_những_mục_nào_có_dữ_liệu_<b>%0</b>_không_chứa_<b>%1</b>_có_th [...]
Advanced=Nâng_cao
-
-
All_entries=Tất_cả_các_mục
All_entries_of_this_type_will_be_declared_typeless._Continue?=Tất_cả_các_mục_thuộc_kiểu_này_sẽ_được_đổi_thành_không_có_kiểu._Tiếp_tục_không?
-All_fields=Tất_cả_các_trường
+All_fields=Tất_cả_các_dữ_liệu
All_subgroups_(recursively)=Tất_cả_các_nhóm_con_(đệ_quy)
-An_exception_occurred_while_accessing_'%0'=Một_lỗi_xảy_ra_khi_đang_truy_cập_'%0'
+Always_reformat_BIB_file_on_save_and_export=
+
A_SAX_exception_occurred_while_parsing_'%0'\:=Một_lỗi_SAXException_xảy_ra_khi_đang_phân_tách_'%0'\:
and=và
-
and_the_class_must_be_available_in_your_classpath_next_time_you_start_JabRef.=và_lớp_phải_có_trong_đường_dẫn_lớp_lần_sau_khi_bạn_khởi_động_JabRef.
-any_field_that_matches_the_regular_expression_<b>%0</b>=bất_kỳ_trường_nào_khớp_Biểu_thức_Chính_tắc_<b>%0</b>
+any_field_that_matches_the_regular_expression_<b>%0</b>=bất_kỳ_dữ_liệu_nào_khớp_Biểu_thức_Chính_tắc_<b>%0</b>
Appearance=Diện_mạo
@@ -128,7 +121,6 @@ Autodetect_format=Tự_động_phát_hiện_định_dạng
Autogenerate_BibTeX_keys=Tự_động_tạo_các_khóa_BibTeX
-
Autolink_files_with_names_starting_with_the_BibTeX_key=Tự_động_liên_kết_với_các_tên_bắt_đầu_bằng_khóa_BibTeX
Autolink_only_files_that_match_the_BibTeX_key=Chỉ_tự_động_liên_kết_các_tập_tin_nào_khớp_khóa_BibTeX
@@ -142,27 +134,26 @@ Automatically_created_groups=Các_nhóm_được_tạo_ra_tự_động
Automatically_remove_exact_duplicates=Tự_động_loại_bỏ_các_mục_trùng_nhau
Allow_overwriting_existing_links.=Cho_phép_ghi_đè_các_liên_kết_hiện_có.
+
Do_not_overwrite_existing_links.=Không_ghi_đè_các_liên_kết_hiện_có.
AUX_file_import=Nhập_tập_tin_AUX
Available_export_formats=Các_định_dạng_xuất_dùng_được
-Available_BibTeX_fields=Các_trường_BibTeX_dùng_được
+Available_BibTeX_fields=Các_dữ_liệu_BibTeX_dùng_được
Available_import_formats=Các_định_dạng_nhập_dùng_được
-Background_color_for_optional_fields=Màu_nền_cho_các_trường_tùy_chọn
+Background_color_for_optional_fields=Màu_nền_cho_các_dữ_liệu_tùy_chọn
-Background_color_for_required_fields=Màu_nền_cho_các_trường_bắt_buộc
+Background_color_for_required_fields=Màu_nền_cho_các_dữ_liệu_bắt_buộc
Backup_old_file_when_saving=Sao_lại_tập_tin_cũ_khi_lưu
BibTeX_key_is_unique.=Khóa_BibTeX_không_được_trùng.
-
-BibTeX_source=Nguồn_BibTeX
-
+%0_source=Nguồn_%0
Broken_link=Liên_kết_bị_đứt
@@ -202,9 +193,7 @@ Change_of_Grouping_Method=Đổi_Phương_pháp_Gộp_nhóm
change_preamble=đổi_phần_mở_đầu
-
-Change_table_column_and_General_fields_settings_to_use_the_new_feature=Đổi_cột_của_bảng_và_các_thiết_lập_trường_tổng_quát_để_dùng_tính_chất_mới
-
+Change_table_column_and_General_fields_settings_to_use_the_new_feature=Đổi_cột_của_bảng_và_các_thiết_lập_dữ_liệu_tổng_quát_để_dùng_tính_chất_mới
Changed_font_settings=Các_thiết_lập_phông_được_thay_đổi
@@ -227,25 +216,23 @@ Class_name=Tên_lớp
Clear=Xóa
-
-Clear_fields=Xóa_các_trường
-
+Clear_fields=Xóa_các_dữ_liệu
Close=Đóng
-Close_others=
-Close_all=
+Close_others=Đóng_các_mục_khác
+Close_all=Đóng_tất_cả
+
Close_dialog=Đóng_hộp_thoại
Close_the_current_database=Đóng_CSDL_hiện_tại
-
Close_window=Đóng_cửa_sổ
Closed_database=CSDL_được_đóng
Collapse_subtree=Thu_sơ_đồ_phụ_hình_cây_lại
-Color_codes_for_required_and_optional_fields=Đánh_mã_màu_các_trường_bắt_buộc_và_tùy_chọn
+Color_codes_for_required_and_optional_fields=Đánh_mã_màu_các_dữ_liệu_bắt_buộc_và_tùy_chọn
Color_for_marking_incomplete_entries=Màu_để_đánh_dấu_các_mục_chưa_hoàn_tất
@@ -253,7 +240,6 @@ Column_width=Chiều_rộng_cột
Command_line_id=Chỉ_số_(id)_của_dòng_lệnh
-Connect=Kết_nối
Contained_in=Chứa_trong
@@ -290,6 +276,7 @@ Could_not_instantiate_%0._Have_you_chosen_the_correct_package_path?=Không_thể
Could_not_open_link=Không_thể_mở_liên_kết
Could_not_print_preview=Không_thể_in_phần_xem_trước
+
Could_not_run_the_'vim'_program.=Không_thể_chạy_chương_trình_'vim'.
Could_not_save_file.=Không_thể_lưu_tập_tin.
@@ -322,7 +309,7 @@ Database_encoding=Mã_hóa_CSDL
Database_properties=Tính_chất_của_CSDL
-Database_type=
+Database_type=Dạng_CSDL
Date_format=Định_dạng_ngày
@@ -330,7 +317,7 @@ Default=Mặc_định
Default_encoding=Mã_hóa_mặc_định
-Default_grouping_field=Trường_gộp_nhóm_mặc_định
+Default_grouping_field=Dữ_liệu_gộp_nhóm_mặc_định
Default_look_and_feel=Diện_mạo_mặc_định
@@ -357,7 +344,9 @@ Delete_strings=Xóa_chuỗi
Deleted=Bị_xóa
-Delimit_fields_with_semicolon,_ex.=Phân_cách_các_trường_bằng,_ví_dụ_như,_dấu_chấm_phẩy.
+Delete_local_file=Xóa_bỏ_tập_tin_cục_bộ
+
+Delimit_fields_with_semicolon,_ex.=Phân_cách_các_dữ_liệu_bằng,_ví_dụ_như,_dấu_chấm_phẩy.
Descending=Giảm_dần
@@ -366,8 +355,6 @@ Description=Mô_tả
Deselect_all=Khử_chọn_tất_cả
Deselect_all_duplicates=Khử_chọn_tất_cả_các_mục_lặp
-
-
Disable_this_confirmation_dialog=Tắt_hộp_thoại_xác_nhận_này
Display_all_entries_belonging_to_one_or_more_of_the_selected_groups.=Trình_bày_tất_cả_các_mục_thuộc_về_một_hoặc_nhiều_nhóm_được_chọn.
@@ -392,11 +379,12 @@ Do_not_open_any_files_at_startup=Không_mở_tập_tin_nào_lúc_khởi_động
Do_not_overwrite_existing_keys=Không_ghi_đè_các_khóa_hiện_có
Do_not_show_these_options_in_the_future=Không_hiển_thị_những_tùy_chọn_này_trong_tương_lai
-Do_not_wrap_the_following_fields_when_saving=Không_'bọc'_những_trường_dưới_đây_khi_lưu
-Do_not_write_the_following_fields_to_XMP_Metadata\:=Không_ghi_những_trường_dưới_đây_vào_đặc_tả_dữ_liệu_XMP\:
+Do_not_wrap_the_following_fields_when_saving=Không_'bọc'_những_dữ_liệu_dưới_đây_khi_lưu
+Do_not_write_the_following_fields_to_XMP_Metadata\:=Không_ghi_những_dữ_liệu_dưới_đây_vào_đặc_tả_dữ_liệu_XMP\:
Do_you_want_JabRef_to_do_the_following_operations?=Bạn_có_muốn_JabRef_thực_hiện_những_lệnh_sau?
+Donate_to_JabRef=Hỗ_trợ_cho_JabRef
Down=Xuống
@@ -408,20 +396,17 @@ Downloading...=Đang_tải...
Drop_%0=Thả_%0
-
-
duplicate_removal=loại_bỏ_trùng
Duplicate_string_name=Trùng_tên_chuỗi
Duplicates_found=Tìm_thấy_các_mục_trùng
-
Dynamic_groups=Các_nhóm_động
Dynamically_group_entries_by_a_free-form_search_expression=Gộp_nhóm_động_các_mục_bằng_biểu_thức_tìm_kiếm_dạng_tự_do
-Dynamically_group_entries_by_searching_a_field_for_a_keyword=Gộp_nhóm_động_các_mục_bằng_cách_tìm_trường_hoặc_từ_khóa
+Dynamically_group_entries_by_searching_a_field_for_a_keyword=Gộp_nhóm_động_các_mục_bằng_cách_tìm_dữ_liệu_hoặc_từ_khóa
Each_line_must_be_on_the_following_form=Mỗi_dòng_phải_có_dạng_sau
@@ -447,7 +432,6 @@ Grouping_may_not_work_for_this_entry.=Việc_gộp_nhóm_có_thể_không_làm_
empty_database=CSDL_rỗng
Enable_word/name_autocompletion=Bật_chức_năng_tự_hoàn_tất_từ/tên
-
Enter_URL=Nhập_URL
Enter_URL_to_download=Nhập_URL_để_tải_về
@@ -459,7 +443,6 @@ Entries_cannot_be_manually_assigned_to_or_removed_from_this_group.=Không_thể_
Entries_exported_to_clipboard=Các_mục_được_xuất_ra_bộ_nhớ_tạm
-
entry=mục
Entry_editor=Trình_chỉnh_sửa_mục
@@ -479,12 +462,11 @@ Entry_types=Các_kiểu_của_mục
Error=Lỗi
Error_exporting_to_clipboard=Lỗi_xuất_ra_bộ_nhớ_tạm
-##Error\:_check_your_External_viewer_settings_in_Preferences=Error\:_check_your_External_viewer_settings_in_Preferences
Error_occurred_when_parsing_entry=Lỗi_xảy_ra_khi_đang_phân_tách_mục
Error_opening_file=Lỗi_khi_đang_mở_tập_tin
-Error_setting_field=Lỗi_thiết_lập_trường
+Error_setting_field=Lỗi_thiết_lập_dữ_liệu
Error_while_writing=Lỗi_khi_đang_ghi
Error_writing_to_%0_file(s).=Lỗi_khi_đang_ghi_vào_tập_tin_%0.
@@ -499,7 +481,6 @@ Overwrite_file?=Ghi_đè_tập_tin_không?
Expand_subtree=Mổ_rộng_sơ_đồ_cây_phụ
-#previousentrynottranslated.Toviewit,openGroupinterfaceandclickonthe"newgroup"button
Export=Xuất
Export_name=Xuất_tên
@@ -525,26 +506,22 @@ External_programs=Các_chương_trình_ngoài
External_viewer_called=Trình_xem_ngoài_được_gọi
-
Fetch=Lấy_về
-Field=Trường
-
-field=trường
+Field=Dữ_liệu
-#IntegritycheckisaprocessthatchecksforindicationsofwronglyfilledoutBibTeXfields."Scan"isthebuttonthatstartsthecheck.
+field=dữ_liệu
-Field_name=Tên_trường
-Field_names_are_not_allowed_to_contain_white_space_or_the_following_characters=Tên_trường_không_được_phép_chứa_khoảng_trắng_hoặc_các_ký_tự_sau
+Field_name=Tên_dữ_liệu
+Field_names_are_not_allowed_to_contain_white_space_or_the_following_characters=Tên_dữ_liệu_không_được_phép_chứa_khoảng_trắng_hoặc_các_ký_tự_sau
-Field_to_filter=Trường_cần_lọc
+Field_to_filter=Dữ_liệu_cần_lọc
-Field_to_group_by=Trường_gộp_nhóm_theo
+Field_to_group_by=Dữ_liệu_gộp_nhóm_theo
File=Tập_tin
file=tập_tin
-
File_'%0'_is_already_open.=Tập_tin_'%0'_đã_mở.
File_'%0'_not_found=Không_tìm_thấy_tập_tin_'%0'
@@ -606,7 +583,7 @@ Full_name=Tên_đầy_đủ
General=Tổng_quát
-General_fields=Các_trường_tổng_quát
+General_fields=Các_dữ_liệu_tổng_quát
Generate=Tạo
@@ -622,22 +599,19 @@ Generate_now=Tạo_bây_giờ
Generated_BibTeX_key_for=Khóa_BibTeX_được_tạo_ra_cho
Generating_BibTeX_key_for=Đang_tạo_khóa_BibTeX_cho
-
+Get_fulltext=Nhập_toàn_văn_bản
Grab=Lấy
Gray_out_entries_not_in_group_selection=Tô_xám_các_mục_không_thuộc_phép_chọn_nhóm
Gray_out_non-hits=Tô_xám_các_mục_không_gặp
-
Groups=Các_nhóm
-
Have_you_chosen_the_correct_package_path?=Bạn_đã_chọn_đường_dẫn_gói_đúng_chưa?
Help=Trợ_giúp
-
Help_on_groups=Trợ_giúp_về_nhóm
Help_on_key_patterns=Trợ_giúp_về_các_kiểu_khóa
@@ -645,16 +619,16 @@ Help_on_regular_expression_search=Trợ_giúp_về_tìm_kiếm_bằng_biểu_th
Hide_non-hits=Ẩn_các_mục_không_gặp
-
Hierarchical_context=Ngữ_cảnh_có_cấp_bậc
Highlight=Tô_sáng
Highlight_groups_matching_all_selected_entries=Tô_sáng_những_nhóm_khớp_tất_cả_các_mục_được_chọn
Highlight_groups_matching_any_selected_entry=Tô_sáng_các_nhóm_khớp_bất_kỳ_mục_được_chọn_nào
+Disable_highlight_groups_matching_entries=Xóa_bỏ_tô_sáng_những_nhóm_khớp_của_các_mục
Highlight_overlapping_groups=Tô_sáng_các_nhóm_gối_nhau
-Hint\:_To_search_specific_fields_only,_enter_for_example\:<p><tt>author\=smith_and_title\=electrical</tt>=Gợi_ý\:_Để_chỉ_tìm_kiếm_các_trường_đặc_thù,_nhập,_ví_dụ_như\:<p><tt>author\=smith_and_title\=electrical</tt>
+Hint\:_To_search_specific_fields_only,_enter_for_example\:<p><tt>author\=smith_and_title\=electrical</tt>=Gợi_ý\:_Để_chỉ_tìm_kiếm_các_dữ_liệu_đặc_thù,_nhập,_ví_dụ_như\:<p><tt>author\=smith_and_title\=electrical</tt>
HTML_table=Bảng_HTML
HTML_table_(with_Abstract_&_BibTeX)=Bảng_HTML_(với_Tóm_tắt_&_BibTeX)
@@ -688,44 +662,31 @@ Import_strings=Nhập_các_chuỗi
Import_to_open_tab=Nhập_vào_thẻ_đang_mở
-Import_word_selector_definitions=Nhập_các_định_nghĩa_trình_chọn_từ
-
-
Imported_entries=Các_mục_được_nhập
Imported_from_database=được_nhập_từ_CSDL
-ImportFormat_class=Lớp_ĐịnhdạngNhập
+Importer_class=Lớp_ĐịnhdạngNhập
Importing=Đang_nhập
Importing_in_unknown_format=Nhập_vào_thành_định_dạng_không_rõ
-
Include_abstracts=Đưa_vào_cả_phần_tóm_tắt
Include_entries=Đưa_vào_các_mục
Include_subgroups\:_When_selected,_view_entries_contained_in_this_group_or_its_subgroups=Đưa_vào_các_nhóm_con\:_Khi_được_chọn,_xem_các_mục_chứa_trong_nhóm_này_hoặc_các_nhóm_phụ_của_nó
-
-
-
Independent_group\:_When_selected,_view_only_this_group's_entries=Nhóm_độc_lập\:_Khi_được_chọn,_chỉ_xem_các_mục_của_nhóm_này
Initially_show_groups_tree_expanded=Ban_đầu_hiển_thị_cây_sơ_đồ_nhóm_dạng_mở_rộng
Work_options=Các_tùy_chọn_làm_việc
-Input_error=Lỗi_đầu_vào
-
Insert=Chèn
Insert_rows=Chèn_hàng
-
-
-
-#IntegritycheckisaprocessthatchecksforindicationsofwronglyfilledoutBibTeXfields."Scan"isthebuttonthatstartsthecheck.
Intersection=Giao_nhau
Invalid_BibTeX_key=Khóa_BibTeX_không_hợp_lệ
@@ -738,7 +699,7 @@ Inverted=Đảo_ngược
ISO_abbreviation=Viết_tắt_kiểu_ISO
-Online_help=
+Online_help=Trợ_giúp_trực_tuyến
JabRef_preferences=Các_tùy_thích_JabRef
@@ -762,7 +723,6 @@ Key_pattern=Kiểu_mẫu_khóa
keys_in_database=các_khóa_trong_CSDL
-#nottranslated.Toviewit,usemenu"Tools|NewBibTeXfilefromAUxfile",andlaunchtheactiononanon-existantAUXfile.
Keyword=Từ_khóa
Label=Nhãn
@@ -775,10 +735,9 @@ LaTeX_AUX_file=Tập_tin_LaTeX_AUX
Leave_file_in_its_current_directory=Giữ_tập_tin_trong_thư_mục_hiện_tại_của_nó
Left=Trái
-Level=
-
+Level=Mức_độ
-Limit_to_fields=Giới_hạn_theo_các_trường
+Limit_to_fields=Giới_hạn_cho_các_dữ_liệu
Limit_to_selected_entries=Giới_hạn_theo_các_mục_được_chọn
@@ -789,15 +748,11 @@ Link_to_file_%0=Liên_kết_đến_tập_tin_%0
Listen_for_remote_operation_on_port=Lắng_nghe_lệnh_chạy_từ_xa_tại_cổng
Load_and_Save_preferences_from/to_jabref.xml_on_start-up_(memory_stick_mode)=Nạp_và_lưu_các_tùy_thích_từ/đến_tập_tin_jabref.xml_khi_khởi_động_(chế_độ_thẻ_nhớ)
-
-
Look_and_feel=Hình_thức
Main_file_directory=Thư_mục_tập_tin_chính
Main_layout_file=Tập_tin_trình_bày_chính
-Manage=Quản_lý
-
Manage_custom_exports=Quản_lý_các_phép_xuất_tùy_chọn
Manage_custom_imports=Quản_lý_các_phép_nhập_tùy_chọn
@@ -821,7 +776,7 @@ Merged_external_changes=Các_thay_đổi_ngoài_được_gộp_lại
Messages=Các_thông_báo
-Modification_of_field=Sự_điều_chỉnh_của_trường
+Modification_of_field=Sự_điều_chỉnh_của_dữ_liệu
Modified_group_"%0".=Nhóm_"%0"_được_điều_chỉnh.
@@ -833,13 +788,12 @@ Modify=Điều_chỉnh
modify_group=điều_chỉnh_nhóm
-
Move=Chuyển
Move_down=Chuyển_xuống
Move_entries_in_group_selection_to_the_top=Chuyển_các_mục_trong_nhóm_được_chọn_lên_trên_cùng
-Move_external_links_to_'file'_field=Chuyển_các_liên_kết_ngoài_vào_trường_'file'
+Move_external_links_to_'file'_field=Chuyển_các_liên_kết_ngoài_vào_dữ_liệu_'file'
move_group=chuyển_nhóm
@@ -858,7 +812,6 @@ New=Mới
new=mới
-
New_BibTeX_entry=Mục_BibTeX_mới
New_BibTeX_subdatabase=CSDL_con_BibTeX_mới
@@ -866,10 +819,11 @@ New_BibTeX_subdatabase=CSDL_con_BibTeX_mới
New_content=Nội_dung_mới
New_database_created.=CSDL_mới_được_tao_ra.
-New_field_value=Giá_trị_trường_mới
+New_%0_database=CSDL_%0_mới
+New_field_value=Giá_trị_dữ_liệu_mới
New_file=Tập_tin_mới
-New_file_link_(INSERT)=Liên_kết_tập_tin_mới_(INSERT)
+New_file_link_(INSERT)=Lập_đường_liên_kết_tập_tin_mới_(TẠO)
New_group=Nhóm_mới
@@ -877,7 +831,6 @@ New_string=Chuỗi_mới
Next_entry=Mục_tiếp
-
No_actual_changes_found.=Không_thấy_thay_đổi_thực_sự_nào.
no_base-BibTeX-file_specified=tập_tin_kiểu-BibTeX_không_được_chỉ_định
@@ -891,7 +844,6 @@ No_entries_found_for_the_search_string_'%0'=Không_tìm_thấy_mục_nào_với_
No_entries_imported.=Không_mục_nào_được_nhập.
-
No_exceptions_have_occurred.=Không_xảy_ra_ngoại_lệ_nào.
No_files_found.=Không_tìm_thấy_tập_tin_nào.
@@ -902,24 +854,17 @@ No_journal_names_could_be_abbreviated.=Không_có_tên_tạp_chí_nào_có_thể
No_journal_names_could_be_unabbreviated.=Không_có_tên_tạp_chí_nào_có_thể_viết_đầy_đủ.
No_PDF_linked=Không_có_tập_tin_PDF_nào_được_liên_kết
-No_references_found=Không_tìm_thấy_tài_liệu_tham_khảo_nào
-
-
No_URL_defined=Không_có_url_nào_được_định_nghĩa
not=không
not_found=không_tìm_thấy
-
Note_that_you_must_specify_the_fully_qualified_class_name_for_the_look_and_feel,=Lưu_ý_rằng_bạn_phải_chỉ_định_tên_lớp_đủ_điều_kiện_dùng_cho_diện_mạo,
Nothing_to_redo=Không_có_lệnh_nào_để_lặp_lại
Nothing_to_undo=Không_có_lệnh_nào_để_quay_ngược_lại
-#Thenextisusedlikein"Referencesfound\:1Numberofreferencestofetch?"
-Number_of_references_to_fetch?=Số_lượng_tài_liệu_tham_khảo_cần_lấy_về?
-
occurrences=các_lần_xuất_hiện
OK=Đồng_ý
@@ -940,9 +885,9 @@ Open_file=Mở_tập_tin
Open_last_edited_databases_at_startup=Mở_CSDL_chỉnh_sửa_lần_cuối_khi_khởi_động
-Open_shared_database=
+Connect_to_shared_database=Mở_CSDL_chia_sẻ
-Open_terminal_here=
+Open_terminal_here=Mở_terminal_ở_đây
Open_URL_or_DOI=Mở_URL_hoặc_DOI
@@ -955,7 +900,7 @@ Opening_preferences...=Đang_mở_các_tùy_thích...
Operation_canceled.=Lệnh_bị_hủy.
Operation_not_supported=Lệnh_không_được_hỗ_trợ
-Optional_fields=Các_trường_tùy_chọn
+Optional_fields=Các_dữ_liệu_tùy_chọn
Options=Tùy_chọn
@@ -975,7 +920,7 @@ Override_the_BibTeX_field_by_the_selected_text=Ghi_đè_khóa_BibTeX_bằng_ch
Overwrite=Ghi_đè
-Overwrite_existing_field_values=Ghi_đè_các_giá_trị_trường_hiện_có
+Overwrite_existing_field_values=Ghi_đè_các_giá_trị_dữ_liệu_hiện_có
Overwrite_keys=Ghi_đè_các_khóa
@@ -1003,9 +948,9 @@ Plain_text_import=Nhập_văn_bản_trơn
Please_enter_a_name_for_the_group.=Vui_lòng_nhập_tên_cho_nhóm.
-Please_enter_a_search_term._For_example,_to_search_all_fields_for_<b>Smith</b>,_enter\:<p><tt>smith</tt><p>To_search_the_field_<b>Author</b>_for_<b>Smith</b>_and_the_field_<b>Title</b>_for_<b>electrical</b>,_enter\:<p><tt>author\=smith_and_title\=electrical</tt>=Vui_lòng_nhập_một_thuật_ngữ_tìm_kiếm._Ví_dụ,_để_tìm_từ_<b>Smith</b>_trong_tất_cả_các_trường,_nhập\:<p><tt>smith</tt><p>._Để_tìm_từ_<b>Smith</b>_trong_trường_<b>Author</b>_và_từ_<b>electrical</b>_trong_trường_<b>Title</b>,_nhập\:< [...]
+Please_enter_a_search_term._For_example,_to_search_all_fields_for_<b>Smith</b>,_enter\:<p><tt>smith</tt><p>To_search_the_field_<b>Author</b>_for_<b>Smith</b>_and_the_field_<b>Title</b>_for_<b>electrical</b>,_enter\:<p><tt>author\=smith_and_title\=electrical</tt>=Vui_lòng_nhập_một_thuật_ngữ_tìm_kiếm._Ví_dụ,_để_tìm_từ_<b>Smith</b>_trong_tất_cả_các_dữ_liệu,_nhập\:<p><tt>smith</tt><p>._Để_tìm_từ_<b>Smith</b>_trong_dữ_liệu_<b>Author</b>_và_từ_<b>electrical</b>_trong_dữ_liệu_<b>Title</b>,_nhập [...]
-Please_enter_the_field_to_search_(e.g._<b>keywords</b>)_and_the_keyword_to_search_it_for_(e.g._<b>electrical</b>).=Vui_lòng_nhập_trường_cần_tìm_(ví_dụ\:_<b>từ_khoá</b>)_và_từ_khóa_cần_tìm_kiếm_trong_trường_đó_(ví_dụ\:_<b>electrical</b>).
+Please_enter_the_field_to_search_(e.g._<b>keywords</b>)_and_the_keyword_to_search_it_for_(e.g._<b>electrical</b>).=Vui_lòng_nhập_dữ_liệu_cần_tìm_(ví_dụ\:_<b>từ_khoá</b>)_và_từ_khóa_cần_tìm_kiếm_trong_dữ_liệu_đó_(ví_dụ\:_<b>electrical</b>).
Please_enter_the_string's_label=Vui_lòng_nhập_nhãn_của_chuỗi
@@ -1024,17 +969,22 @@ Preferences=Các_tùy_thích
Preferences_recorded.=Các_tùy_thích_được_ghi_lại.
Preview=Xem_trước
+Citation_Style=Kiểu_trích_dẫn
+Current_Preview=Xem_trước_hiện_tại
+Cannot_generate_preview_based_on_selected_citation_style.=Không_thể_tạo_ra_xem_trước_dựa_trên_kiểu_trích_dẫn_đã_chọn.
+Bad_character_inside_entry=Kí_tự_xấu_trong_mục
+Error_while_generating_citation_style=Lỗi_trong_khi_tạo_ra_kiểu_trích_dẫn
+Preview_style_changed_to\:_%0=Thay_đổi_kiểu_xem_trước_theo\:_%0
+Next_preview_layout=Xem_trước_bố_trí_tiếp_theo
+Previous_preview_layout=Xem_trước_bố_trí_trước_đó
Previous_entry=Mục_trước_đó
Primary_sort_criterion=Tiêu_chuẩn_xếp_thứ_tự_chính
-
Problem_with_parsing_entry=Trục_trặc_khi_phân_tách_mục
-
Processing_%0=Đang_xử_lý_%0
Program_output=Đầu_ra_của_chương_trình
-Pull_changes_from_shared_database=
-
+Pull_changes_from_shared_database=Kéo_thay_đổi_từ_CSDL_chia_sẻ
Pushed_citations_to_%0=Các_trích_dẫn_đã_được_đưa_qua_%0
@@ -1044,19 +994,16 @@ Quit_synchronization=Thôi_đồng_bộ_hóa
Raw_source=Nguồn_thô
-
Rearrange_tabs_alphabetically_by_title=Xếp_lại_các_thẻ_theo_thứ_tự_ABC_theo_tiêu_đề
Redo=Lặp_lại_lệnh
Reference_database=CSDL_tham_khảo
-#Thenexttwolinesareusedlikein"Referencesfound\:1Numberofreferencestofetch?"
-References_found=Các_tài_liệu_tham_khảo_được_tìm_thấy
+%0_references_found._Number_of_references_to_fetch?=Các_tài_liệu_tham_khảo_được_tìm_thấy\:_%0._Số_lượng_tài_liệu_tham_khảo_cần_lấy_về?
Refine_supergroup\:_When_selected,_view_entries_contained_in_both_this_group_and_its_supergroup=Tinh_chỉnh_nhóm_lớn\:_Khi_được_chọn,_xem_các_mục_chứa_các_trong_nhóm_này_và_nhóm_lớn_của_nó
-
regular_expression=Biểu_thức_chính_tắc
Remember_these_entry_types?=Nhớ_các_kiểu_mục_này?
@@ -1067,20 +1014,16 @@ Remote_server_port=Cổng_máy_chủ_từ_xa
Remove=Loại_bỏ
-
Remove_subgroups=Loại_bỏ_tất_cả_các_nhóm_con
Remove_all_subgroups_of_"%0"?=Loại_bỏ_tất_cả_các_nhóm_con_của_"%0"?
-
-
Remove_entry_from_import=Loại_bỏ_mục_khỏi_lệnh_nhập
Remove_entry_selection_from_this_group=Loại_bỏ_phép_chọn_mục_khỏi_nhóm_này
Remove_entry_type=Loại_bỏ_kiểu_mục
-Remove_file_link_(DELETE)=Loại_bỏ_liên_kết_tập_tin_(XÓA)
-
+Remove_file_link_(DELETE)=Loại_bỏ_đường_liên_kết_tập_tin_(XÓA)
Remove_from_group=Loại_bỏ_khỏi_nhóm
@@ -1104,7 +1047,6 @@ Remove_old_entry=Loại_bỏ_mục_cũ
Remove_selected_strings=Loại_bỏ_các_chuỗi_được_chọn
-
Removed_group_"%0".=Đã_loại_bỏ_nhóm_"%0".
Removed_group_"%0"_and_its_subgroups.=Đã_loại_bỏ_nhóm_"%0"_và_các_nhóm_con_của_nó.
@@ -1121,16 +1063,15 @@ Replace_with=Thay_thế_bởi
Replaced=Bị_thay_thế
-Required_fields=Các_trường_cần_có
+Required_fields=Các_dữ_liệu_cần_có
Reset_all=Thiết_lập_lại_tất_cả
-Resolve_strings_for_all_fields_except=Giải_các_chuỗi_cho_tất_cả_các_trường_ngoại_trừ
-Resolve_strings_for_standard_BibTeX_fields_only=Chỉ_giải_các_chuỗi_cho_các_trường_BibTeX
+Resolve_strings_for_all_fields_except=Giải_các_chuỗi_cho_tất_cả_các_dữ_liệu_ngoại_trừ
+Resolve_strings_for_standard_BibTeX_fields_only=Chỉ_giải_các_chuỗi_cho_các_dữ_liệu_BibTeX
resolved=được_giải
-
Revert_to_original_source=Trả_ngược_lại_nguồn_ban_đầu
Review=Xem_xét_lại
@@ -1155,36 +1096,23 @@ Save_failed=Việc_lưu_thất_bại
Save_failed_during_backup_creation=Việc_lưu_thất_bại_khi_đang_tạo_bản_sao_lưu
-Save_failed_while_committing_changes\:_%0=Việc_lưu_thất_bại_khi_đang_thực_hiện_những_thay_đổi\:_%0
-
Save_selected_as...=Lưu_phần_chọn_thành_...
Saved_database=Đã_lưu_CSDL
Saved_selected_to_'%0'.=Đã_lưu_phần_chọn_vào_'%0'.
-
Saving=Đang_lưu
Saving_all_databases...=Đang_lưu_tất_cả_CSDL...
Saving_database=Đang_lưu_CSDL
-
Search=Tìm
-
-
Search_expression=Biểu_thức_tìm_kiếm
Search_for=Tìm
-
-
-
-
-
-
-
Searching_for_duplicates...=Đang_tìm_các_mục_bị_lặp...
Searching_for_files=Đang_tìm_các_tập_tin
@@ -1195,46 +1123,37 @@ Select=Chọn
-
Select_all=Chọn_tất_cả
-
Select_encoding=Chọn_bộ_mã_hóa
-
Select_entry_type=Chọn_kiểu_mục
Select_external_application=Chọn_ứng_dụng_ngoài
Select_file_from_ZIP-archive=Chọn_tập_tin_từ_tập_tin_ZIP
-
-
-
Select_the_tree_nodes_to_view_and_accept_or_reject_changes=Chọn_các_nốt_trên_sơ_đồ_hình_cây_để_xem_và_chấp_nhận_hoặc_từ_chối_thay_đổi
Selected_entries=Các_mục_được_chọn
-Set_field=Thiết_lập_trường
-Set_fields=Thiết_lập_các_trường
+Set_field=Thiết_lập_dữ_liệu
+Set_fields=Thiết_lập_các_dữ_liệu
-Set_general_fields=Thiết_lập_các_trường_tổng_quát
+Set_general_fields=Thiết_lập_các_dữ_liệu_tổng_quát
Set_main_external_file_directory=Thiết_lập_thư_mục_tập_tin_ngoài_chính
Set_table_font=Chọn_bảng_phông_chữ
Settings=Các_thiết_lập
-
-
Shortcut=Phím_tắt
-Show/edit_BibTeX_source=Hiển_thị/Chỉnh_sửa_nguồn_BibTeX
+Show/edit_%0_source=Hiển_thị/Chỉnh_sửa_nguồn_%0
-Show_'Firstname_Lastname'=Hiển_thị_'Tên.gọi_Họ'
+Show_'Firstname_Lastname'=Hiển_thị_Tên_Họ
-Show_'Lastname,_Firstname'=Hiển_thị_Tên.gọi,_Họ'
+Show_'Lastname,_Firstname'=Hiển_thị_Họ,_Tên
Show_BibTeX_source_by_default=Hiển_thị_nguồn_BibTeX_theo_mặc_định
-
Show_confirmation_dialog_when_deleting_entries=Hiển_thị_hộp_thoại_xác_nhận_khi_xóa_các_mục
Show_description=Hiển_thị_mô_tả
@@ -1250,17 +1169,12 @@ Show_last_names_only=Chỉ_hiển_thị_Họ
Show_names_unchanged=Hiển_thị_các_tên_không_bị_thay_đổi
+Show_optional_fields=Hiển_thị_các_dữ_liệu_tùy_chọn
-
-Show_optional_fields=Hiển_thị_các_trường_tùy_chọn
-
-
-Show_required_fields=Hiển_thị_các_trường_cần_có
+Show_required_fields=Hiển_thị_các_dữ_liệu_cần_có
Show_URL/DOI_column=Hiển_thị_cột_URL/DOI
-
-
Simple_HTML=HTML_dạng_đơn_giản
Size=Kích_thước
@@ -1272,8 +1186,6 @@ Skipped_entry.=Mục_bị_bỏ_qua.
Sort_alphabetically=Xếp_theo_thứ_tự_ABC
-
-
sort_subgroups=Xếp_thứ_tự_các_nhóm_con
Sorted_all_subgroups_recursively.=Xếp_thứ_tự_tất_cả_các_nhóm_con_theo_cách_đệ_quy.
@@ -1285,7 +1197,6 @@ Special_name_formatters=Các_trình_định_dạng_tên_đặc_biệt
Special_table_columns=Các_cột_bảng_đặc_biệt
-
Starting_import=Đang_bắt_đầu_nhập
Statically_group_entries_by_manual_assignment=Gộp_nhóm_các_mục_theo_cách_tĩnh_bằng_phép_gán_thủ_công
@@ -1296,7 +1207,6 @@ Stop=Dừng
Store_journal_abbreviations=Lưu_trữ_viết_tắt_các_tạp_chí
-
Stored_entry=Mục_được_lưu_trữ
Strings=Các_chuỗi
@@ -1305,7 +1215,6 @@ Strings_for_database=Các_chuỗi_dùng_cho_CSDL
Subdatabase_from_AUX=CSDL_con_từ_AUX
-
Switches_between_full_and_abbreviated_journal_name_if_the_journal_name_is_known.=Chuyển_đổi_giữa_tên_đầy_đủ_và_tên_viết_tắt_tạp_chí_nếu_biết_tên_tạp_chí_đó.
Synchronize_file_links=Đồng_bộ_hóa_các_liên_kết_tập_tin
@@ -1334,8 +1243,7 @@ The_chosen_date_format_for_new_entries_is_not_valid=Định_dạng_ngày_đượ
The_chosen_encoding_'%0'_could_not_encode_the_following_characters\:=Mã_hóa_đã_chọn_'%0'_không_thể_mã_hóa_được_các_ký_tự_sau\:
-
-the_field_<b>%0</b>=trường_<b>%0</b>
+the_field_<b>%0</b>=dữ_liệu_<b>%0</b>
The_file<BR>'%0'<BR>has_been_modified<BR>externally\!=Tập_tin<BR>'%0'<BR>đã_bị_thay_đổi<BR>ngoài_chương_trình\!
@@ -1371,23 +1279,18 @@ This_external_link_is_of_the_type_'%0',_which_is_undefined._What_do_you_want_to_
This_group_contains_entries_based_on_manual_assignment._Entries_can_be_assigned_to_this_group_by_selecting_them_then_using_either_drag_and_drop_or_the_context_menu._Entries_can_be_removed_from_this_group_by_selecting_them_then_using_the_context_menu.=Nhóm_này_chứa_các_mục_căn_cứ_trên_phép_gán_thủ_công._Các_mục_có_thể_được_gán_vào_nhóm_này_bằng_cách_chọn_chúng_rồi_dùng_cách_kéo_thả_hoặc_trình_đơn_ngữ_cảnh._Các_mục_có_thể_bị_loại_bỏ_khỏi_nhóm_này_bằng_cách_chọn_chúng_rồi_dùng_trình_đơn_ngữ_cảnh.
+This_group_contains_entries_whose_<b>%0</b>_field_contains_the_keyword_<b>%1</b>=Nhóm_này_chứa_các_mục_có_dữ_liệu_<b>%0</b>_chứa_từ_khóa_<b>%1</b>_
-
-
-This_group_contains_entries_whose_<b>%0</b>_field_contains_the_keyword_<b>%1</b>=Nhóm_này_chứa_các_mục_có_trường_<b>%0</b>_chứa_từ_khóa_<b>%1</b>_
-
-This_group_contains_entries_whose_<b>%0</b>_field_contains_the_regular_expression_<b>%1</b>=Nhóm_này_chứa_các_mục_có_trường_<b>%0</b>_chứa_biểu_thức_chính_tắc_<b>%1</b>_
+This_group_contains_entries_whose_<b>%0</b>_field_contains_the_regular_expression_<b>%1</b>=Nhóm_này_chứa_các_mục_có_dữ_liệu_<b>%0</b>_chứa_biểu_thức_chính_tắc_<b>%1</b>_
This_makes_JabRef_look_up_each_file_link_and_check_if_the_file_exists._If_not,_you_will_be_given_options<BR>to_resolve_the_problem.=Điều_này_khiến_cho_JabRef_tìm_từng_liên_kết_trong_tổng_số_tập_tin_và_kiểm_tra_xem_tập_tin_có_tồn_tại_không._Nếu_không_bạn_sẽ_được_cung_cấp_các_tùy_chọn<BR>để_giải_quyết_trục_trặc.
This_operation_requires_all_selected_entries_to_have_BibTeX_keys_defined.=Lệnh_này_yêu_cầu_tất_cả_các_mục_được_chọn_phải_có_khóa_BibTeX.
This_operation_requires_one_or_more_entries_to_be_selected.=Lệnh_này_yêu_cầu_phải_chọn_trước_một_hoặc_nhiều_mục.
-
Toggle_abbreviation=Bật/tắt_viết_tắt
Toggle_entry_preview=Bật/tắt_xem_trước_mục
Toggle_groups_interface=Bật/tắt_giao_diện_nhóm
-
Try_different_encoding=Thử_mã_hóa_khác
Unabbreviate_journal_names_of_the_selected_entries=Bỏ_viết_tắt_tên_các_tạp_chí_của_những_mục_được_chọn
@@ -1402,11 +1305,10 @@ Undo=Quay_ngược_lệnh
Union=Hợp_nhất
-Unknown_BibTeX_entries=Các_mục_BibTeX_có_kiểu_không_rõ
+Unknown_BibTeX_entries=Các_mục_BibTeX_không_rõ
unknown_edit=kiểu_chỉnh_sửa_không_biết
-
Unknown_export_format=Định_dạng_xuất_không_biết
Unmark_all=Khử_đánh_dấu_tất_cả
@@ -1415,10 +1317,6 @@ Unmark_entries=Khử_đánh_dấu_các_mục
Unmark_entry=Khử_đánh_dấu_mục
-
-
-Unsupported_version_of_class_%0\:_%1=Phiên_bản_của_lớp_%0_không_được_hỗ_trợ\:_%1
-
untitled=không_tiêu_đề
Up=Lên
@@ -1426,13 +1324,12 @@ Up=Lên
Update_to_current_column_widths=Cập_nhật_chiều_rộng_cột_hiện_tại
Updated_group_selection=Phép_chọn_nhóm_đã_được_cập_nhật
-Upgrade_external_PDF/PS_links_to_use_the_'%0'_field.=Nâng_cấp_các_liên_kết_ngoài_PDF/PS_để_sử_dụng_trường_'%0'.
+Upgrade_external_PDF/PS_links_to_use_the_'%0'_field.=Nâng_cấp_các_liên_kết_ngoài_PDF/PS_để_sử_dụng_dữ_liệu_'%0'.
Upgrade_file=Nâng_cấp_tập_tin
Upgrade_old_external_file_links_to_use_the_new_feature=Nâng_cấp_các_liên_kết_tập_tin_ngoài_để_sử_dụng_tính_chất_mới
usage=cách_dùng
-Use_autocompletion_for_the_following_fields=Dùng_tính_chất_tự_điền_đầy_đủ_cho_các_trường_sau
-
+Use_autocompletion_for_the_following_fields=Dùng_tính_chất_tự_điền_đầy_đủ_cho_các_dữ_liệu_sau
Use_other_look_and_feel=Dùng_diện_mạo_khác
Use_regular_expression_search=Dùng_phép_tìm_bằng_biểu_thức_chính_tắc
@@ -1475,17 +1372,16 @@ Write_XMP-metadata_for_all_PDFs_in_current_database?=Ghi_đặc_tả_dữ_liệu
Writing_XMP-metadata...=Đang_ghi_đặc_tả_dữ_liệu_XMP...
Writing_XMP-metadata_for_selected_entries...=Đang_ghi_đặc_tả_dữ_liệu_XMP_cho_các_mục_được_chọn...
-
Wrote_XMP-metadata=Đã_ghi_đặc_tả_dữ_liệu_XMP
XMP-annotated_PDF=PDF_có_chú_giải_XMP
XMP_export_privacy_settings=Các_thiết_lập_riêng_về_Xuất_XMP
XMP-metadata=Đặc_tả_dữ_liệu_XMP
XMP-metadata_found_in_PDF\:_%0=Đặc_tả_dữ_liệu_XMP_có_trong_PDF\:_%0
-You_must_restart_JabRef_for_this_to_come_into_effect.=
-You_have_changed_the_language_setting.=
-You_have_changed_the_look_and_feel_setting.=
+You_must_restart_JabRef_for_this_to_come_into_effect.=Bạn_phải_khởi_động_lại_JabRef_để_thay_đổi_có_hiệu_lực.
+You_have_changed_the_language_setting.=Bạn_đã_thay_đổi_thiết_lập_ngôn_ngữ.
+You_have_changed_the_look_and_feel_setting.=Bạn_đã_thay_đổi_thiết_lập_diện_mạo_và_hoạt_động_.
You_have_entered_an_invalid_search_'%0'.=Bạn_đã_nhập_một_phép_tìm_không_hợp_lệ_'%0'.
@@ -1493,10 +1389,8 @@ You_must_choose_a_filename_to_store_journal_abbreviations=Bạn_phải_chọn_m
You_must_restart_JabRef_for_the_new_key_bindings_to_work_properly.=Bạn_phải_khởi_động_lại_JabRef_để_các_tổ_hợp_phím_mới_hoạt_động_được.
-
Your_new_key_bindings_have_been_stored.=Tổ_hợp_phím_tắt_mới_của_bạn_đã_được_lưu_trữ.
-
The_following_fetchers_are_available\:=Các_trình_lấy_về_sau_có_thể_dùng_được\:
Could_not_find_fetcher_'%0'=Không_thể_tìm_thấy_trình_lầy_về_'%0'
Running_query_'%0'_with_fetcher_'%1'.=Đang_chạy_truy_vấn_'%0'_với_trình_lấy_về_'%1'.
@@ -1511,17 +1405,13 @@ Import_canceled_by_user=Việc_nhập_bị_người_dùng_hủy
Progress\:_%0_of_%1=Tiến_trình\:_%0_of_%1
Error_while_fetching_from_%0=Lỗi_khi_lấy_về_từ_%0
-Fetching_Medline_by_id...=Lấy_về_từ_Medline_theo_id...
-
-Fetching_Medline_by_term...=Lấy_về_từ_Medline_theo_thuật_ngữ...
Please_enter_a_valid_number=Vui_lòng_nhập_một_con_số_hợp_lệ
-Please_enter_a_comma_separated_list_of_Medline_IDs_(numbers)_or_search_terms.=Vui_lòng_nhập_một_danh_sách_các_id_Medline_(con_số),_cách_nhau_bởi_dấu_phẩy,_hoặc_nhập_thuật_ngữ_cần_tìm.
-%0_import_canceled=Vi\u1ec7c_nh\u1eadp_t\u1eeb_%0_b\u1ecb_h\u1ee7y
-
Show_search_results_in_a_window=Hiển_thị_kết_quả_tìm_trong_một_cửa_sổ
+Show_global_search_results_in_a_window=
+Search_in_all_open_databases=Tìm_kiếm_trong_tất_cả_CSDL_đang_mở
Move_file_to_file_directory?=Di_chuyển_tập_tin_vào_thư_mục_tập_tin?
Rename_to_'%0'=Đổi_tên_thành_'%0'
-You_have_changed_the_menu_and_label_font_size.=
+You_have_changed_the_menu_and_label_font_size.=Bạn_đã_thay_đổi_menu_và_cỡ_phông_nhãn.
Database_is_protected._Cannot_save_until_external_changes_have_been_reviewed.=CSDL_được_bảo_vệ._Không_thể_lưu_cho_đến_khi_những_thay_đổi_ngoài_được_xem_xét.
Protected_database=CSDL_được_bảo_vệ
@@ -1545,27 +1435,23 @@ The_Guide_to_Computing_Literature=Hướng_dẫn_về_tài_liệu_máy_tính
When_opening_file_link,_search_for_matching_file_if_no_link_is_defined=Khi_mở_liên_kết_tập_tin,_tìm_tập_tin_khớp_nếu_liên_kết_không_được_định_nghĩa
Settings_for_%0=Các_thiết_lập_dùng_cho_%0
-
-
-
Mark_entries_imported_into_an_existing_database=Đánh_dấu_các_mục_được_nhập_vào_CSDL_hiện_có
Unmark_all_entries_before_importing_new_entries_into_an_existing_database=Khử_đánh_dấu_tất_cả_các_mục_trước_khi_nhập_các_mục_mới_vào_CSDL_hiện_có
Forward=Tới
Back=Lui
-Sort_the_following_fields_as_numeric_fields=Xếp_thứ_tự_các_trường_sau_như_thể_chúng_là_các_trường_kiểu_số
+Sort_the_following_fields_as_numeric_fields=Xếp_thứ_tự_các_dữ_liệu_sau_như_thể_chúng_là_các_dữ_liệu_kiểu_số
Line_%0\:_Found_corrupted_BibTeX_key.=Dòng_%0\:_Tìm_thấy_khóa-BibTeX_bị_lỗi.
Line_%0\:_Found_corrupted_BibTeX_key_(contains_whitespaces).=Dòng_%0\:_Tìm_thấy_khóa-BibTeX_bị_lỗi_(chứa_khoảng_trắng).
Line_%0\:_Found_corrupted_BibTeX_key_(comma_missing).=Dòng_%0\:_Tìm_thấy_khóa-BibTeX_bị_lỗi_(thiếu_dấu_phẩy).
-Finished_downloading_full_text_document=Tải_về_tài_liệu_đầy_đủ_hoàn_tất
Full_text_document_download_failed=Việc_tải_về_bài_viết_đầy_đủ_thất_bại
Update_to_current_column_order=Cập_nhật_theo_thứ_tự_cột_hiện_tại
-
-Rename_field=Đổi_tên_trường
-Set/clear/rename_fields=Thiết_lập/xóa/đổi_tên_trường
-Rename_field_to=Đổi_tên_trường_thành
-Move_contents_of_a_field_into_a_field_with_a_different_name=Di_chuyển_nội_dung_của_một_trường_sang_một_trường_có_tên_khác
-You_can_only_rename_one_field_at_a_time=Bạn_chỉ_có_thể_đổi_tên_một_trường_một_lần
+Download_from_URL=Kéo_từ_URL
+Rename_field=Đổi_tên_dữ_liệu
+Set/clear/rename_fields=Thiết_lập/xóa/đổi_tên_dữ_liệu
+Rename_field_to=Đổi_tên_dữ_liệu_thành
+Move_contents_of_a_field_into_a_field_with_a_different_name=Di_chuyển_nội_dung_của_một_dữ_liệu_sang_một_dữ_liệu_có_tên_khác
+You_can_only_rename_one_field_at_a_time=Bạn_chỉ_có_thể_đổi_tên_một_dữ_liệu_một_lần
Remove_all_broken_links=Loại_bỏ_tất_cả_các_liên_kết_bị_đứt
@@ -1573,16 +1459,15 @@ Cannot_use_port_%0_for_remote_operation;_another_application_may_be_using_it._Tr
Looking_for_full_text_document...=Đang_tìm_tài_liệu_đầy_đủ...
Autosave=Lưu_tự_động
-Prompt_before_recovering_a_database_from_an_autosave_file=Nhắc_trước_khi_phục_hồi_lại_một_CSDL_từ_một_tập_tin_lưu_tự_động
-Autosave_interval_(minutes)=Khoảng_thời_gian_tự_động_lưu_(phút)
-Do_you_want_to_recover_the_database_from_the_autosave_file?=Bạn_có_muốn_phục_hồi_lại_CSDL_từ_một_tập_tin_lưu_tự_động?
-Recover_from_autosave=Phục_hồi_tự_lệnh_lưu_tự_động
+A_local_copy_will_be_opened.=Bản_sao_cục_bộ_sẽ_được_mở.
+Autosave_local_databases=Tự_động_lưu_CSDL_cục_bộ
+Automatically_save_the_database_to=
+Please_enter_a_valid_file_path.=
+
Export_in_current_table_sort_order=Xuất_ra_theo_trình_tự_xếp_thứ_tự_của_bảng_hiện_tại
Export_entries_in_their_original_order=Xuất_ra_các_mục_theo_thứ_tự_gốc_của_chúng
Error_opening_file_'%0'.=Lỗi_mở_tập_tin_'%0'.
-Autosave_of_file_'%0'=Lưu_tự_động_tập_tin_'%0'
-Error_opening_autosave_of_'%0'._Trying_to_load_'%0'_instead.=Lỗi_khi_mở_tập_tin_lưu_tự_động_'%0'._Cố_gắng_nạp_'%0'_để_thay_thế.
Formatter_not_found\:_%0=Không_tìm_thấy_trình_định_dạng\:_%0
Clear_inputarea=Xóa_trong_vùng_nhập_liệu
@@ -1598,7 +1483,7 @@ Changes_have_been_made_to_the_following_metadata_elements=Các_thay_đổi_đã_
Generate_groups_for_author_last_names=Tạo_các_nhóm_cho_họ_của_tác_giả
Generate_groups_for_editor_last_names=Tạo_các_nhóm_cho_tên_họ_của_người_biên_tập
-Generate_groups_from_keywords_in_a_BibTeX_field=Tạo_các_nhóm_theo_từ_khóa_trong_một_trường_BibTeX
+Generate_groups_from_keywords_in_a_BibTeX_field=Tạo_các_nhóm_theo_từ_khóa_trong_một_dữ_liệu_BibTeX
Enforce_legal_characters_in_BibTeX_keys=Buộc_phải_dùng_những_ký_tự_hợp_lệ_trong_khóa_BibTeX
Save_without_backup?=Lưu_không_có_bản_dự_phòng?
@@ -1613,54 +1498,51 @@ includes_subgroups=kể_cả_các_nhóm_con
contains=chứa
search_expression=biểu_thức_tìm
-
-
-Optional_fields_2=
-Waiting_for_save_operation_to_finish=
-Resolving_duplicate_BibTeX_keys...=
-Finished_resolving_duplicate_BibTeX_keys._%0_entries_modified.=
-This_database_contains_one_or_more_duplicated_BibTeX_keys.=
-Do_you_want_to_resolve_duplicate_keys_now?=
-Find_and_remove_duplicate_BibTeX_keys=
-Expected_syntax_for_--fetch\='<name_of_fetcher>\:<query>'=
-Duplicate_BibTeX_key=
-Import_marking_color=
-Always_add_letter_(a,_b,_...)_to_generated_keys=
-
-Ensure_unique_keys_using_letters_(a,_b,_...)=
-Ensure_unique_keys_using_letters_(b,_c,_...)=
-Entry_editor_active_background_color=
-Entry_editor_background_color=
-Entry_editor_font_color=
-Entry_editor_invalid_field_color=
-
-Table_and_entry_editor_colors=
-
-General_file_directory=
-User-specific_file_directory=
-Search_failed\:_illegal_search_expression=
-Show_ArXiv_column=
-Highlight_groups_that_contain_entries_contained_in_any_currently_selected_group=
-
-You_must_enter_an_integer_value_in_the_interval_1025-65535_in_the_text_field_for=
-Automatically_open_browse_dialog_when_creating_new_file_link=
-
-Import_metadata_from\:=
-Choose_the_source_for_the_metadata_import=
-Create_entry_based_on_XMP_data=
-Create_blank_entry_linking_the_PDF=
-Only_attach_PDF=
-Title=
-No_internet_connection.=
-Create_new_entry=
-Update_existing_entry=
+Optional_fields_2=Các_dữ_liệu_tùy_chọn_2
+Waiting_for_save_operation_to_finish=Chờ_thao_tác_lưu_kết_thúc
+Resolving_duplicate_BibTeX_keys...=Giải_quyết_những_khóa_BibTeX_bị_lặp_lại...
+Finished_resolving_duplicate_BibTeX_keys._%0_entries_modified.=Giải_quyết_những_khóa_BibTeX_bị_lặp_lại_đã_được_kết_thúc._Mục_%0_đã_được_sửa.
+This_database_contains_one_or_more_duplicated_BibTeX_keys.=CSDL_này_có_một_hoặc_nhiều_khóa_BibTeX_bị_lặp_lại.
+Do_you_want_to_resolve_duplicate_keys_now?=Bạn_có_muốn_giải_quyết_những_khóa_lặp_bây_giờ_không?
+
+Find_and_remove_duplicate_BibTeX_keys=Tìm_và_xóa_bỏ_những_khóa_BibTeX_bị_lặp_lại
+Expected_syntax_for_--fetch\='<name_of_fetcher>\:<query>'=Cú_pháp_mong_đợi_cho--fetch\='<Tên_của_fetcher>\:<query>'
+Duplicate_BibTeX_key=Lặp_lại_khóa_BibTeX
+Import_marking_color=Nhập_màu_đánh_dấu
+Always_add_letter_(a,_b,_...)_to_generated_keys=Luôn_thêm_mẫu_tự_(a,_b,_...)_để_tạo_ra_các_khóa
+
+Ensure_unique_keys_using_letters_(a,_b,_...)=Đảm_bảo_các_khóa_duy_nhất_bằng_sử_dụng_mẫu_tự_(a,_b,_...)
+Ensure_unique_keys_using_letters_(b,_c,_...)=Đảm_bảo_các_khóa_duy_nhất_bằng_sử_dụng_mẫu_tự_(b,_c,_...)
+Entry_editor_active_background_color=Trình_soạn_màu_nền_của_thảo_mục_đã_kích_hoạt
+Entry_editor_background_color=Trình_soạn_màu_nền_của_thảo_mục
+Entry_editor_font_color=Trình_soạn_màu_phông_của_thảo_mục
+Entry_editor_invalid_field_color=Trình_soạn_màu_các_dữ_liệu_không_hợp_lệ_của_thảo_mục
+
+Table_and_entry_editor_colors=Bảng_và_trình_soạn_thảo_màu_của_mục
+
+General_file_directory=Tổng_quát_thư_mục_tập_tin
+User-specific_file_directory=Thư_mục_tập_tin_của_người_sử_dụng_cụ_thể
+Search_failed\:_illegal_search_expression=Tìm_kiếm_thất_bại\:_biểu_thức_tìm_kiếm_bất_hợp_lệ
+Show_ArXiv_column=Hiển_thị_cột_ArXiv
+Highlight_groups_that_contain_entries_contained_in_any_currently_selected_group=Làm_nổi_bật_nhóm_chứa_các_mục_có_nội_dung_trong_bất_cứ_nhóm_hiện_được_tuyển_chọn
+
+You_must_enter_an_integer_value_in_the_interval_1025-65535_in_the_text_field_for=Bạn_phải_nhập_giá_trị_nằm_trong_khoảng_cách_1025-65535_trong_các_dữ_liệu_văn_bản_cho
+Automatically_open_browse_dialog_when_creating_new_file_link=Mở_tự_động_hộp_thoại_khi_tạo_ra_đường_dẫn_tập_tin_mới
+Import_metadata_from\:=Nhập_siêu_dữ_liệu_vào_từ
+Choose_the_source_for_the_metadata_import=Chọn_nguồn_để_nhập_vào_siêu_dữ_liệu
+Create_entry_based_on_XMP_data=Tạo_ra_mục_dựa_trên_dữ_liệu_XMP
+Create_blank_entry_linking_the_PDF=Tạo_ra_mục_trống_thuộc_về_PDF
+Only_attach_PDF=Chỉ_kèm_PDF
+Title=Danh_hiệu
+Create_new_entry=Tạo_mục_mới
+Update_existing_entry=Cập_nhật_mục_có_sẵn
Autocomplete_names_in_'Firstname_Lastname'_format_only=
Autocomplete_names_in_'Lastname,_Firstname'_format_only=
Autocomplete_names_in_both_formats=
Marking_color_%0=
The_name_'comment'_cannot_be_used_as_an_entry_type_name.=
You_must_enter_an_integer_value_in_the_text_field_for=
-Send_as_email=
+Send_as_email=Gửi_bằng_email
References=
Sending_of_emails=
Subject_for_sending_an_email_with_references=
@@ -1677,6 +1559,7 @@ The_output_option_depends_on_a_valid_input_option.=
Default_import_style_for_drag_and_drop_of_PDFs=
Default_PDF_file_link_action=
Filename_format_pattern=
+Additional_parameters=
Cite_selected_entries_between_parenthesis=
Cite_selected_entries_with_in-text_citation=
Cite_special=
@@ -1726,19 +1609,17 @@ Select_document=
Edit_group_membership=
HTML_list=
Click_group_to_toggle_membership_of_selected_entries=
-Use_EMACS_23_insertion_string=
If_possible,_normalize_this_list_of_names_to_conform_to_standard_BibTeX_name_formatting=
Could_not_open_%0=
Unknown_import_format=
-Web_search=
+Web_search=Tìm_kiếm_trên_web
Style_selection=
-
No_valid_style_file_defined=
Choose_pattern=
Use_the_BIB_file_location_as_primary_file_directory=
Could_not_run_the_gnuclient/emacsclient_program._Make_sure_you_have_the_emacsclient/gnuclient_program_installed_and_available_in_the_PATH.=
Built-in_journal_list=
-OpenOffice/LibreOffice_connection=
+OpenOffice/LibreOffice_connection=Nối_với_OpenOffice/LibreOffice
You_can_add_additional_journal_names_by_setting_up_a_personal_journal_list,<br>as_well_as_linking_to_external_journal_lists.=
JabRef_includes_a_built-in_list_of_journal_abbreviations.=
You_must_select_either_a_valid_style_file,_or_use_one_of_the_default_styles.=
@@ -1746,11 +1627,12 @@ You_must_select_either_a_valid_style_file,_or_use_one_of_the_default_styles.=
This_is_a_simple_copy_and_paste_dialog._First_load_or_paste_some_text_into_the_text_input_area.<br>After_that,_you_can_mark_text_and_assign_it_to_a_BibTeX_field.=
This_feature_generates_a_new_database_based_on_which_entries_are_needed_in_an_existing_LaTeX_document.=
You_need_to_select_one_of_your_open_databases_from_which_to_choose_entries,_as_well_as_the_AUX_file_produced_by_LaTeX_when_compiling_your_document.=
+
First_select_entries_to_clean_up.=
Cleanup_entry=
-%0_mode=
Autogenerate_PDF_Names=
Auto-generating_PDF-Names_does_not_support_undo._Continue?=
+
Use_full_firstname_whenever_possible=
Use_abbreviated_firstname_whenever_possible=
Use_abbreviated_and_full_firstname=
@@ -1760,6 +1642,7 @@ Name_format_used_for_autocompletion=
Treatment_of_first_names=
Cleanup_entries=
Automatically_assign_new_entry_to_selected_groups=
+%0_mode=
Move_DOIs_from_note_and_URL_field_to_DOI_field_and_remove_http_prefix=
Make_paths_of_linked_files_relative_(if_possible)=
Rename_PDFs_to_given_filename_format_pattern=
@@ -1777,7 +1660,6 @@ Remove_selected=
Group_tree_could_not_be_parsed._If_you_save_the_BibTeX_database,_all_groups_will_be_lost.=
Attach_file=
-
Setting_all_preferences_to_default_values.=
Resetting_preference_key_'%0'=
Unknown_preference_key_'%0'=
@@ -1814,13 +1696,12 @@ How_would_you_like_to_link_to_'%0'?=
BibTeX_key_patterns=
Changed_special_field_settings=
Clear_priority=
-Clear_rank=
+Clear_rank=Xóa_bỏ_hạng
Enable_special_fields=
Five_stars=
Four_stars=
Help_on_special_fields=
Keywords_of_selected_entries=
-Manage_content_selectors=
Manage_keywords=
No_priority_information=
No_rank_information=
@@ -1830,7 +1711,7 @@ Priority_high=
Priority_low=
Priority_medium=
Quality=
-Rank=
+Rank=Xếp_hạng
Relevance=
Set_priority_to_high=
Set_priority_to_low=
@@ -1848,8 +1729,10 @@ Two_stars=
Update_keywords=
Write_values_of_special_fields_as_separate_fields_to_BibTeX=
You_have_changed_settings_for_special_fields.=
-
%0_entries_found._To_reduce_server_load,_only_%1_will_be_downloaded.=
+A_string_with_that_label_already_exists=Một_chuỗi_với_nhãn_đó_đã_có
+Connection_to_OpenOffice/LibreOffice_has_been_lost._Please_make_sure_OpenOffice/LibreOffice_is_running,_and_try_to_reconnect.=
+
Correct_the_entry,_and_reopen_editor_to_display/edit_source.=
Could_not_connect_to_a_running_gnuserv_process._Make_sure_that_Emacs_or_XEmacs_is_running,<BR>and_that_the_server_has_been_started_(by_running_the_command_'server-start'/'gnuserv-start').=
Could_not_connect_to_running_OpenOffice/LibreOffice.=
@@ -1860,7 +1743,9 @@ Created_group_"%0".=
If_a_pasted_or_imported_entry_already_has_the_field_set,_overwrite.=
Import_metadata_from_PDF=
Not_connected_to_any_Writer_document._Please_make_sure_a_document_is_open,_and_use_the_'Select_Writer_document'_button_to_connect_to_it.=
+Removed_all_subgroups_of_group_"%0".=
To_disable_the_memory_stick_mode_rename_or_remove_the_jabref.xml_file_in_the_same_folder_as_JabRef.=
+Unable_to_connect._One_possible_reason_is_that_JabRef_and_OpenOffice/LibreOffice_are_not_both_running_in_either_32_bit_mode_or_64_bit_mode.=
Use_the_following_delimiter_character(s)\:=
When_downloading_files,_or_moving_linked_files_to_the_file_directory,_prefer_the_BIB_file_location_rather_than_the_file_directory_set_above=
Your_style_file_specifies_the_character_format_'%0',_which_is_undefined_in_your_current_OpenOffice/LibreOffice_document.=
@@ -1869,24 +1754,19 @@ Your_style_file_specifies_the_paragraph_format_'%0',_which_is_undefined_in_your_
Searching...=
You_have_selected_more_than_%0_entries_for_download._Some_web_sites_might_block_you_if_you_make_too_many_rapid_downloads._Do_you_want_to_continue?=
Confirm_selection=
-Unknown_DOI\:_'%0'.=
Add_{}_to_specified_title_words_on_search_to_keep_the_correct_case=
Import_conversions=
Please_enter_a_search_string=
Please_open_or_start_a_new_database_before_searching=
-An_error_occurred_while_fetching_from_ADS_(%0)\:=
-An_error_occurred_while_parsing_abstract=
-Unknown_DiVA_entry\:_'%0'.=
-Get_BibTeX_entry_from_DiVA=
Log=
-
Canceled_merging_entries=
+
Format_units_by_adding_non-breaking_separators_and_keeping_the_correct_case_on_search=
-Merge_entries=
+Merge_entries=Phối_các_mục
Merged_entries=
Merged_entry=
-None=
+None=Không_có
Parse=
Result=
Show_DOI_first=
@@ -1895,41 +1775,46 @@ Use_Emacs_key_bindings=
You_have_to_choose_exactly_two_entries_to_merge.=
Update_timestamp_on_modification=
-
All_key_bindings_will_be_reset_to_their_defaults.=
-Automatically_set_file_links=
+
+Automatically_set_file_links=Tự_động_tạo_liên_kết_cho_tập_tin
Continue?=
Resetting_all_key_bindings=
-
Hostname=
Invalid_setting=
Network=
Please_specify_both_hostname_and_port=
+Please_specify_both_username_and_password=
+
Use_custom_proxy_configuration=
+Proxy_requires_authentication=
+Attention\:_Password_is_stored_in_plain_text\!=
Clear_connection_settings=
Cleared_connection_settings.=
+
Rebind_C-a,_too=
+Rebind_C-f,_too=
Show_number_of_elements_contained_in_each_group=
Open_folder=
Searches_for_unlinked_PDF_files_on_the_file_system=
-
Export_entries_ordered_as_specified=
Export_sort_order=
+Export_sorting=
Newline_separator=
+
Save_entries_ordered_as_specified=
Save_sort_order=
Show_extra_columns=
Parsing_error=
illegal_backslash_expression=
-Move_to_group=
+Move_to_group=Di_chuyển_vào_nhóm
Clear_read_status=
Convert_to_BibLatex_format_(for_example,_move_the_value_of_the_'journal'_field_to_'journaltitle')=
-Could_not_apply_changes.=
-Deprecated_fields=
+Deprecated_fields=Các_dữ_liệu_không_tán_thành
Hide/show_toolbar=
No_read_status_information=
Printed=
@@ -1939,132 +1824,115 @@ Read_status_skimmed=
Save_selected_as_plain_BibTeX...=
Set_read_status_to_read=
Set_read_status_to_skimmed=
-Show_deprecated_BibTeX_fields=
+Show_deprecated_BibTeX_fields=Hiển_thị_các_dữ_liệu_BibTex_không_tán_thành
+
Show_gridlines=
Show_printed_status=
Show_read_status=
Table_row_height_padding=
-Marked_all_%0_selected_entries=
Marked_selected_entry=
-Toggle_print_status=
-Unmarked_all_%0_selected_entries=
+Marked_all_%0_selected_entries=
Unmarked_selected_entry=
+Unmarked_all_%0_selected_entries=
+Toggle_print_status=
+
Unmarked_all_entries=
Unable_to_find_the_requested_look_and_feel_and_thus_the_default_one_is_used.=
-Could_not_open_browser.=
Opens_JabRef's_GitHub_page=
-
-Rebind_C-f,_too=
-This_group_contains_all_entries._It_cannot_be_edited_or_removed.=
+Could_not_open_browser.=
+Please_open_%0_manually.=
+The_link_has_been_copied_to_the_clipboard.=
Open_%0_file=
Cannot_delete_file=
-Convert=
-Delete_local_file=
File_permission_error=
-Help_on_Name_Formatting=
-Normalize_to_BibTeX_name_format=
-Path_to_%0=Đường_dẫn_đến_%0
Push_to_%0=
+Path_to_%0=Đường_dẫn_đến_%0
+Convert=
+Normalize_to_BibTeX_name_format=
+Help_on_Name_Formatting=
Add_new_file_type=
-Follow_DOI_or_URL_link_and_try_to_locate_PDF_full_text_document=
+
Left_entry=
-No_information_added=
-Original_entry=
Right_entry=
-Select_at_least_one_entry_to_manage_keywords.=
Use=
-Changed_type_to_'%0'_for=Kiểu_được_đổi_thành_'%0'_dùng_cho
-Database_'%0'_has_changed.=
-Copy_\\cite{BibTeX_key}=Chép\\trích_dẫn{khóa_BibTeX}
-To_set_up,_go_to=Để_cài_đặt,_chọn
-Search_%0=Tìm_trên_%0
-Invalid_DOI\:_'%0'.=DOI_không_hợp_lệ\:_'%0'.
-Could_not_connect_to_%0=Không_thể_kết_nối_đến_%0
-
+Original_entry=
+Replace_original_entry=
+No_information_added=
+Select_at_least_one_entry_to_manage_keywords.=
+OpenDocument_text=
+OpenDocument_spreadsheet=
+OpenDocument_presentation=
%0_image=
-%0_problem(s)_found=
-'%0'_is_not_a_valid_ADS_bibcode.=
-Accepting_the_change_replaces_the_complete_groups_tree_with_the_externally_modified_groups_tree.=
Added_entry=
-Added_new_'%0'_entry.=
-Additional_parameters=
-Connection_to_OpenOffice/LibreOffice_has_been_lost._Please_make_sure_OpenOffice/LibreOffice_is_running,_and_try_to_reconnect.=
-Copy_BibTeX_key_and_title=
-Deleted_entry=
-Discard_changes=
-Donate_to_JabRef=
-Export_with_selected_format=
-Field_is_missing=
-File_rename_failed_for_%0_entries.=
-Filled=
-From_import=
-Keep_left=
-Keep_merged_entry_only=
-Keep_right=
-Merged_BibTeX_source_code=
Modified_entry=
+Deleted_entry=
Modified_groups_tree=
-Multiple_entries_selected._Do_you_want_to_change_the_type_of_all_these_to_'%0'?=
-No_problems_found.=
-Old_entry=
-OpenDocument_presentation=
-OpenDocument_spreadsheet=
-OpenDocument_text=
-Please_move_the_file_manually_and_link_in_place.=
-Print_entry_preview=
-Really_delete_the_%0_selected_entries?=
-Really_delete_the_selected_entry?=
Removed_all_groups=
-Removed_all_subgroups_of_group_"%0".=
-Replace_original_entry=
-Return_to_JabRef=
-Save_changes=
+Accepting_the_change_replaces_the_complete_groups_tree_with_the_externally_modified_groups_tree.=
Select_export_format=
-Unable_to_connect._One_possible_reason_is_that_JabRef_and_OpenOffice/LibreOffice_are_not_both_running_in_either_32_bit_mode_or_64_bit_mode.=
+Return_to_JabRef=
+Please_move_the_file_manually_and_link_in_place.=
+Could_not_connect_to_%0=Không_thể_kết_nối_đến_%0
Warning\:_%0_out_of_%1_entries_have_undefined_BibTeX_key.=
-large_capitals_are_not_masked_using_curly_brackets_{}=
occurrence=
-should_contain_a_four_digit_number=
-should_contain_a_valid_page_number_range=
-should_end_with_a_name=
+Added_new_'%0'_entry.=
+Multiple_entries_selected._Do_you_want_to_change_the_type_of_all_these_to_'%0'?=
+Changed_type_to_'%0'_for=Kiểu_được_đổi_thành_'%0'_dùng_cho
+Really_delete_the_selected_entry?=
+Really_delete_the_%0_selected_entries?=
+Keep_merged_entry_only=
+Keep_left=
+Keep_right=
+Old_entry=
+From_import=
+No_problems_found.=
+%0_problem(s)_found=
+Save_changes=
+Discard_changes=
+Database_'%0'_has_changed.=
+Print_entry_preview=
+Copy_\\cite{BibTeX_key}=Chép\\trích_dẫn{khóa_BibTeX}
+Copy_BibTeX_key_and_title=
+File_rename_failed_for_%0_entries.=
+To_set_up,_go_to=Để_cài_đặt,_chọn
+Merged_BibTeX_source_code=
+Invalid_DOI\:_'%0'.=DOI_không_hợp_lệ\:_'%0'.
should_start_with_a_name=
+should_end_with_a_name=
unexpected_closing_curly_bracket=
unexpected_opening_curly_bracket=
+capital_letters_are_not_masked_using_curly_brackets_{}=
+should_contain_a_four_digit_number=
+should_contain_a_valid_page_number_range=
+Filled=
+Field_is_missing=
+Search_%0=Tìm_trên_%0
-Advanced_search_active.=
-Found_%0_results.=
-No_results_found.=
-Normal_search_active.=
-Search_globally=
-Search_in_all_open_databases=
Search_results_in_all_databases_for_%0=
Search_results_in_database_%0_for_%1=
-This_search_contains_entries_in_which=
+Search_globally=
+No_results_found.=
+Found_%0_results.=
+Advanced_search_active.=
+Normal_search_active.=
+plain_text=
This_search_contains_entries_in_which_any_field_contains_the_regular_expression_<b>%0</b>=
This_search_contains_entries_in_which_any_field_contains_the_term_<b>%0</b>=
-plain_text=
-
-Attention\:_Password_is_stored_in_plain_text\!=
-Please_specify_both_username_and_password=
-Proxy_requires_authentication=
+This_search_contains_entries_in_which=
-An_autosave_file_was_found_for_this_database._This_could_indicate_that_JabRef_did_not_shut_down_cleanly_last_time_the_file_was_used.=
-Note\:_A_full_text_search_is_currently_not_supported_for_%0=
Unable_to_autodetect_OpenOffice/LibreOffice_installation._Please_choose_the_installation_directory_manually.=
-
JabRef_no_longer_supports_'ps'_or_'pdf'_fields.<br>File_links_are_now_stored_in_the_'file'_field_and_files_are_stored_in_an_external_file_directory.<br>To_make_use_of_this_feature,_JabRef_needs_to_upgrade_file_links.<br><br>=
This_database_uses_outdated_file_links.=
-A_string_with_that_label_already_exists=Một_chuỗi_với_nhãn_đó_đã_có
Clear_search=
-Close_database=
+Close_database=Đóng_CSDL
Close_entry_editor=
Decrease_table_font_size=
Entry_editor,_next_entry=
@@ -2080,7 +1948,7 @@ Focus_entry_table=
Import_into_current_database=
Import_into_new_database=
Increase_table_font_size=
-New_article=
+New_article=Bài_viết_mới
New_book=
New_entry=
New_from_plain_text=
@@ -2098,52 +1966,32 @@ Resolve_duplicate_BibTeX_keys=
Save_all=
String_dialog,_add_string=
String_dialog,_remove_string=
-Switch_preview_layout=
Synchronize_files=
Unabbreviate=
-
should_contain_a_protocol=
Copy_preview=
-
-Automatically_setting_file_links=
+Automatically_setting_file_links=Tự_động_thiết_lập_liên_kết_với_tập_tin
Regenerating_BibTeX_keys_according_to_metadata=
No_meta_data_present_in_BIB_file._Cannot_regenerate_BibTeX_keys=
-
Regenerate_all_keys_for_the_entries_in_a_BibTeX_file=
-
Show_debug_level_messages=
-
-Export_sorting=
-
-New_%0_database=
-
-New_%0_database_created.=
-
-No_entry_found_for_ISBN_%0_at_www.ebook.de=
-
-Save_actions=
-Enable_save_actions=
-Always_reformat_BIB_file_on_save_and_export=
-
Default_bibliography_mode=
-
-
+New_%0_database_created.=
Show_only_preferences_deviating_from_their_default_value=
default=
key=
type=
value=
-
Show_preferences=
+Save_actions=
+Enable_save_actions=
+Other_fields=Các_dữ_liệu_khác
+Show_remaining_fields=Hiển_thị_dữ_liệu_duy_trì
-Other_fields=
-Show_remaining_fields=
link_should_refer_to_a_correct_file_path=
-
abbreviation_detected=
wrong_entry_type_as_proceedings_has_page_numbers=
-
Abbreviate_journal_names=
Abbreviating...=
Adding_fetched_entries=
@@ -2155,28 +2003,22 @@ Unabbreviate_journal_names=
Unabbreviating...=
Usage=
+
+Adds_{}_brackets_around_acronyms,_month_names_and_countries_to_preserve_their_case.=
Are_you_sure_you_want_to_reset_all_settings_to_default_values?=
Reset_preferences=
-
Ill-formed_entrytype_comment_in_BIB_file=
+
+Move_linked_files_to_default_file_directory_%0=
+
Clipboard=
Could_not_paste_entry_as_text\:=
Do_you_still_want_to_continue?=
This_action_will_modify_the_following_field(s)_in_at_least_one_entry_each\:=
This_could_cause_undesired_changes_to_your_entries.=
-
-Disable_highlight_groups_matching_entries=
Run_field_formatter\:=
-
-Adds_{}_brackets_around_acronyms,_month_names_and_countries_to_preserve_their_case.=
-Converts_units_to_LaTeX_formatting.=
-Does_nothing.=
-
-
Table_font_size_is_%0=
-
-Move_linked_files_to_default_file_directory_%0=
-
+%0_import_canceled=Vi\u1ec7c_nh\u1eadp_t\u1eeb_%0_b\u1ecb_h\u1ee7y
Internal_style=
Add_style_file=
Are_you_sure_you_want_to_remove_the_style?=
@@ -2184,7 +2026,6 @@ Current_style_is_'%0'=
Remove_style=
Select_one_of_the_available_styles_or_add_a_style_file_from_disk.=
You_must_select_a_valid_style_file.=
-
Reload=
Capitalize=
@@ -2195,9 +2036,11 @@ Changes_all_letters_to_upper_case.=
Changes_the_first_letter_of_all_words_to_capital_case_and_the_remaining_letters_to_lower_case.=
Cleans_up_LaTeX_code.=
Converts_HTML_code_to_LaTeX_code.=
+Converts_HTML_code_to_Unicode.=
Converts_LaTeX_encoding_to_Unicode_characters.=
Converts_Unicode_characters_to_LaTeX_encoding.=
Converts_ordinals_to_LaTeX_superscripts.=
+Converts_units_to_LaTeX_formatting.=
HTML_to_LaTeX=
LaTeX_cleanup=
LaTeX_to_Unicode=
@@ -2221,16 +2064,13 @@ Title_case=
Unicode_to_LaTeX=
Units_to_LaTeX=
Upper_case=
+Does_nothing.=
Identity=
-
Clears_the_field_completely.=
Directory_not_found=
Main_file_directory_not_set\!=
-
This_operation_requires_exactly_one_item_to_be_selected.=
-
Importing_in_%0_format=
-
Female_name=
Female_names=
Male_name=
@@ -2239,80 +2079,72 @@ Mixed_names=
Neuter_name=
Neuter_names=
-Lookup_DOI=
+Lookup_DOI=Tra_từ_DOI
-Audio_CD=
-British_patent=
-British_patent_request=
-Candidate_thesis=
+Audio_CD=Đĩa_âm_thanh
+British_patent=Sáng_chế_của_Anh
+British_patent_request=Yêu_cầu_sáng_chế_của_Anh
+Candidate_thesis=Bài_luận_văn_ứng_viên
Collaborator=
Column=
Compiler=
Continuator=
-Data_CD=
+Data_CD=Đĩa_dữ_liệu
Editor=
-European_patent=
-European_patent_request=
+European_patent=Sáng_chế_của_Châu_Âu
+European_patent_request=Yêu_cầu_sáng_chế_của_Châu_Âu
Founder=
-French_patent=
-French_patent_request=
-German_patent=
-German_patent_request=
+French_patent=Sáng_chế_của_Pháp
+French_patent_request=Yêu_cầu_sáng_chế_của_Pháp
+German_patent=Sáng_chế_của_Đức
+German_patent_request=Yêu_cầu_sáng_chế_của_Đức
Line=
-Master's_thesis=
+Master's_thesis=Bài_luận_văn_chính
Page=
Paragraph=
-Patent=
-Patent_request=
-PhD_thesis=
+Patent=Sáng_chế
+Patent_request=Yêu_cầu_sáng_chế
+PhD_thesis=Bài_luận_văn_PhD
Redactor=
-Research_report=
+Research_report=Bảng_báo_cáo_nghiên_cứu
Reviser=
Section=
-Software=
-Technical_report=
-U.S._patent=
-U.S._patent_request=
+Software=Phần_mềm
+Technical_report=Bảng_báo_cáo_kỹ_thuật
+U.S._patent=Sáng_chế_của_Mỹ
+U.S._patent_request=Yêu_cầu_sáng_chế_của_Mỹ
Verse=
change_entries_of_group=
odd_number_of_unescaped_'\#'=
+
Plain_text=
Show_diff=
character=
word=
-
Show_symmetric_diff=
HTML_encoded_character_found=
-
booktitle_ends_with_'conference_on'=
+
All_external_files=
OpenOffice/LibreOffice_integration=
incorrect_control_digit=
incorrect_format=
-
-Expected_"%0"_to_contain_whitespace=
-Syntax_error_in_regular-expression_pattern=
-
Copy_version_to_clipboard=
Copied_version_to_clipboard=
+
BibTeX_key=
Message=
-
-Get_fulltext=
-
-Download_from_URL=
-
Decryption_not_supported.=
Cleared_'%0'_for_%1_entries=
Set_'%0'_to_'%1'_for_%2_entries=
Toggled_'%0'_for_%1_entries=
-Check_for_updates=
+Check_for_updates=Kiểm_tra_cập_nhật
Download_update=
New_version_available=
Installed_version=
@@ -2322,18 +2154,13 @@ Could_not_connect_to_the_update_server.=
Please_try_again_later_and/or_check_your_network_connection.=
To_see_what_is_new_view_the_changelog.=
A_new_version_of_JabRef_has_been_released.=
-JabRef_is_up-to-date.=
+JabRef_is_up-to-date.=Phiên_bản_JabRef_là_mới_nhất.
Latest_version=
-
-Please_open_%0_manually.=
-
-The_link_has_been_copied_to_the_clipboard.=
-
Online_help_forum=
-
Custom=
-Converts_HTML_code_to_Unicode.=
+Export_cited=
+Unable_to_generate_new_database=
Open_console=
Use_default_terminal_emulator=
@@ -2341,31 +2168,22 @@ Execute_command=
Note\:_Use_the_placeholder_%0_for_the_location_of_the_opened_database_file.=
Executing_command_\"%0\"...=
Error_occured_while_executing_the_command_\"%0\".=
-
Reformat_ISSN=
-Unable_to_generate_new_database=
-
-Export_cited=
Countries_and_territories_in_English=
Electrical_engineering_terms=
Enabled=
Internal_list=
+Manage_protected_terms_files=
Months_and_weekdays_in_English=
The_text_after_the_last_line_starting_with_\#_will_be_used=
-
Add_protected_terms_file=
Are_you_sure_you_want_to_remove_the_protected_terms_file?=
Remove_protected_terms_file=
-
-Manage_protected_terms_files=
-
Add_selected_text_to_list=
Add_{}_around_selected_text=
Format_field=
New_protected_terms_file=
-
-
change_field_%0_of_entry_%1_from_%2_to_%3=
change_key_from_%0_to_%1=
change_string_content_%0_to_%1=
@@ -2375,49 +2193,45 @@ insert_entry_%0=
insert_string_%0=
remove_entry_%0=
remove_string_%0=
-
undefined=
-
Cannot_get_info_based_on_given_%0\:_%1=
-
-Get_BibTeX_data_from_%0=
+Get_BibTeX_data_from_%0=Nhập_dữ_liệu_BibTex_từ_%0
No_%0_found=
-
Entry_from_%0=
-
Merge_entry_with_%0_information=
Updated_entry_with_info_from_%0=
-Connection=
-Host=
-Port=
-Database=
-User=
-Connection_error=
-Driver_error=
-Connection_to_%0_server_established.=
-Required_field_"%0"_is_empty.=
-
-%0_driver_not_available.=
-
-The_connection_to_the_server_has_been_terminated.=
-
-Connection_lost.=
-Reconnect=
-Work_offline=
-
-Working_offline.=
-
-Update_refused.=
-Update_refused=
-Local_entry=
-Shared_entry=
-Update_could_not_be_performed_due_to_existing_change_conflicts.=
-You_are_not_working_on_the_newest_version_of_BibEntry.=
-Local_version\:_%0=
-Shared_version\:_%0=
-Please_merge_the_shared_entry_with_yours_and_press_"Merge_entries"_to_resolve_this_problem.=
-Canceling_this_operation_will_leave_your_changes_unsynchronized._Cancel_anyway?=
-The_BibEntry_you_currently_work_on_has_been_deleted_on_the_shared_side._Hit_"Keep"_to_recover_the_entry.=
+Connection=Sự_kết_nối
+Connecting...=Đang_kết_nối...
+Host=Máy_chủ
+Port=Cổng
+Database=CSDL
+User=Người_sử_dụng
+Connect=Kết_nối
+Connection_error=Kết_nối_bị_lỗi
+Connection_to_%0_server_established.=Tạo_kết_nối_với_máy_chủ_%0.
+Required_field_"%0"_is_empty.=Dữ_liệu_cần_có_"%0"_đang_trống.
+%0_driver_not_available.=Trình_điều_khiển_%0_hiện_không_có.
+The_connection_to_the_server_has_been_terminated.=Kết_nối_đến_máy_chủ_đã_được_kết_thúc.
+Connection_lost.=Mất_kết_nối.
+Reconnect=Kết_nối_lại.
+Work_offline=Làm_việc_ẩn
+Working_offline.=Đang_làm_việc_ẩn.
+Update_refused.=Cập_nhật_bị_từ_chối.
+Update_refused=Cập_nhật_bị_từ_chối
+Local_entry=Mục_cục_bộ
+Shared_entry=Mục_chia_sẻ_
+Update_could_not_be_performed_due_to_existing_change_conflicts.=Cập_nhật_không_thể_được_thực_hiện_vì_hiện_đang_có_thay_đổi_xung_đột.
+You_are_not_working_on_the_newest_version_of_BibEntry.=Bạn_không_làm_việc_trên_phiên_bản_mới_nhất_của_BibEntry.
+Local_version\:_%0=Phiên_bản_cục_bộ\:_%0
+Shared_version\:_%0=Phiên_bản_chia_sẻ\:_%0
+Please_merge_the_shared_entry_with_yours_and_press_"Merge_entries"_to_resolve_this_problem.=Xin_vui_lòng_phối_mục_chia_sẻ_với_mục_của_bạn_và_nhấn_"Phối_các_mục"_để_giải_quyết_lỗi_này.
+Canceling_this_operation_will_leave_your_changes_unsynchronized._Cancel_anyway?=Huỷ_bỏ_thao_tác_này_bạn_sẽ_rời_khỏi_thay_đổi_không_đồng_bộ_hóa_của_bạn._Bạn_vẫn_muốn_hủy?
+Shared_entry_is_no_longer_present=Mục_chia_sẻ_hiện_không_còn_nữa
+The_BibEntry_you_currently_work_on_has_been_deleted_on_the_shared_side.=BibEntry_bạn_hiện_giờ_đang_làm_việc_đã_bị_xoá_bên_chia_sẻ.
+You_can_restore_the_entry_using_the_"Undo"_operation.=Bạn_có_thể_phục_hồi_mục_bằng_cách_sử_dụng_thao_tác_"Hoàn_tác".
+Remember_password?=Lưu_mật_mã?
+You_are_already_connected_to_a_database_using_entered_connection_details.=Bạn_đã_được_kết_nối_với_CSDL_bằng_sử_dụng_cách_nhập_chi_tiết_kết_nối.
+
Cannot_cite_entries_without_BibTeX_keys._Generate_keys_now?=
New_technical_report=
@@ -2427,12 +2241,8 @@ Protected_terms_file=
Style_file=
Open_OpenOffice/LibreOffice_connection=
-
You_must_enter_at_least_one_field_name=
-
-
Non-ASCII_encoded_character_found=
-
Toggle_web_search_interface=
Background_color_for_resolved_fields=
Color_code_for_resolved_fields=
@@ -2443,16 +2253,62 @@ The_import_finished_with_warnings\:=
There_was_one_file_that_could_not_be_imported.=
There_were_%0_files_which_could_not_be_imported.=
-Migration_help_information=
+Migration_help_information=Thông_tin_trợ_giúp_dời_chuyển
Entered_database_has_obsolete_structure_and_is_no_longer_supported.=
-However,_a_new_database_was_created_alongside_the_pre-3.6_one.=
-
-Click_here_to_learn_about_the_migration_of_pre-3.6_databases.=
-
-Connecting...=
+However,_a_new_database_was_created_alongside_the_pre-3.6_one.=Tuy_nhiên,_CSDL_mới_đã_được_tạo_lập_theo_CSDL_trước_3.6.
+Click_here_to_learn_about_the_migration_of_pre-3.6_databases.=Nhấp_vào_đây_để_biết_về_dời_chuyển_của_các_CSDL_trước_3.6.
Opens_JabRef's_Facebook_page=
Opens_JabRef's_blog=
Opens_JabRef's_website=
-
Opens_a_link_where_the_current_development_version_can_be_downloaded=
See_what_has_been_changed_in_the_JabRef_versions=
+Referenced_BibTeX_key_does_not_exist=
+Finished_downloading_full_text_document_for_entry_%0.=
+Full_text_document_download_failed_for_entry_%0.=
+Look_up_full_text_documents=
+You_are_about_to_look_up_full_text_documents_for_%0_entries.=
+last_four_nonpunctuation_characters_should_be_numerals=
+shared=
+should_contain_an_integer_or_a_literal=
+should_have_the_first_letter_capitalized=
+
+ID=Mã_nhận_diện
+ID_type=Loại_mã_nhận_diện
+ID-based_entry_generator=
+Fetcher_'%0'_did_not_find_an_entry_for_id_'%1'.=
+
+Select_first_entry=
+Select_last_entry=
+
+Invalid_ISBN\:_'%0'.=
+should_be_an_integer_or_normalized=
+should_be_normalized=
+
+Empty_search_ID=
+The_given_search_ID_was_empty.=
+Copy_BibTeX_key_and_link=
+empty_BibTeX_key=
+BibLaTeX_field_only=
+
+Error_while_generating_fetch_URL=
+Error_while_parsing_ID_list=
+Unable_to_get_PubMed_IDs=
+Backup_found=Tìm_bản_sao_dự_phòng
+A_backup_file_for_'%0'_was_found.=Bản_sao_lưu_dự_phòng_cho_'%0'_đã_tìm_thấy.
+This_could_indicate_that_JabRef_did_not_shut_down_cleanly_last_time_the_file_was_used.=Điều_này_cho_thấy_là_JabRef_không_được_kết_thúc_hoàn_chỉnh_khi_sử_dụng_tập_tin_lần_cuối.
+Do_you_want_to_recover_the_database_from_the_backup_file?=Bạn_có_muốn_phục_hồi_cơ_sở_dữ_liệu_từ_tập_tin_lưu_dự_phòng_không?
+Firstname_Lastname=Họ_Tên
+
+Recommended_for_%0=
+This_might_be_caused_by_reaching_the_traffic_limitation_of_Google_Scholar_(see_'Help'_for_details).=
+
+Problem_downloading_from_%1=
+
+File_directory_pattern=
+Update_with_bibliographic_information_from_the_web=
+
+Could_not_find_any_bibliographic_information.=
+BibTeX_key_%0_deviates_from_generated_key_%1=
+DOI_%0_is_invalid=
+
+Jump_to_entry=
diff --git a/src/main/resources/l10n/JabRef_zh.properties b/src/main/resources/l10n/JabRef_zh.properties
index e686b20..993076a 100644
--- a/src/main/resources/l10n/JabRef_zh.properties
+++ b/src/main/resources/l10n/JabRef_zh.properties
@@ -1,814 +1,1395 @@
#!
-#! created/edited by Popeye version 0.55 (https://github.com/koppor/popeye)
-#! encoding:UTF8
+#! created/edited by Popeye version 0.55 (github.com/JabRef/popeye)
+#! encoding:UTF-8
+
%0_contains_the_regular_expression_<b>%1</b>=%0_包含正则表达式_<b>%1</b>
+
%0_contains_the_term_<b>%1</b>=%0_包含词组_<b>%1</b>
+
%0_doesn't_contain_the_regular_expression_<b>%1</b>=%0_不包含正则表达式_<b>%1</b>
+
%0_doesn't_contain_the_term_<b>%1</b>=%0_不包含词组_<b>%1</b>
+
%0_export_successful=%0_导出成功
-%0_import_canceled=%0_导入被取消
+
%0_matches_the_regular_expression_<b>%1</b>=%0_匹配正则表达式_<b>%1</b>
+
%0_matches_the_term_<b>%1</b>=%0_匹配词组_<b>%1</b>
-'%0'_exists._Overwrite_file?='%0'_已存在,覆盖文件?
+
<HTML>Could_not_find_file_'%0'<BR>linked_from_entry_'%1'</HTML>=<HTML>无法找到记录'%1'链接的文件'%0'</HTML>
-<field_name>=<域名称>
+
<select>=<选择>
-<select_word>=<下拉菜单项>
-AUX_file_import=AUX_文件导入
-A_string_with_that_label_already_exists=该标签对应的简写字串已存在
+
Abbreviate_journal_names_of_the_selected_entries_(ISO_abbreviation)=缩写选中记录的期刊名_(ISO_格式缩写)
Abbreviate_journal_names_of_the_selected_entries_(MEDLINE_abbreviation)=缩写选中记录的期刊名_(MEDLINE_格式缩写)
+
Abbreviate_names=缩写名
Abbreviated_%0_journal_names.=缩写的_%0_期刊名称。
+
Abbreviation=缩写
+
About_JabRef=关于_JabRef
+
Abstract=摘要
+
Accept=接受
+
Accept_change=接受修改
+
Action=动作
+
Add=添加
-Add_a_(compiled)_custom_ImportFormat_class_from_a_ZIP-archive.=从一个_ZIP_压缩包中添加(编译好的)自定义导入类。
-Add_a_(compiled)_custom_ImportFormat_class_from_a_class_path.=从一个_class_path_添加(编译好的)自定义导入类。
+
+Add_a_(compiled)_custom_Importer_class_from_a_class_path.=从一个_class_path_添加(编译好的)自定义导入类。
+The_path_need_not_be_on_the_classpath_of_JabRef.=该路径不需要在_JabRef_的_classpath_下。
+
+Add_a_(compiled)_custom_Importer_class_from_a_ZIP-archive.=从一个_ZIP_压缩包中添加(编译好的)自定义导入类。
+The_ZIP-archive_need_not_be_on_the_classpath_of_JabRef.=该_ZIP_压缩包不需要在_JabRef_的_classpath_下。
+
Add_entry_selection_to_this_group=添加选中记录到此分组
+
Add_from_folder=从文件夹中添加
+
Add_from_JAR=从_JAR_中添加
+
+add_group=添加分组
+
Add_group=添加分组
+
Add_new=新建
+
Add_subgroup=添加子分组
+
Add_to_group=添加到分组
+
Added_group_"%0".=已添加分组_"%0"。
+
Added_new=已添加
+
Added_string=已添加简写字串
+
Additionally,_entries_whose_<b>%0</b>_field_does_not_contain_<b>%1</b>_can_be_assigned_manually_to_this_group_by_selecting_them_then_using_either_drag_and_drop_or_the_context_menu._This_process_adds_the_term_<b>%1</b>_to_each_entry's_<b>%0</b>_field._Entries_can_be_removed_manually_from_this_group_by_selecting_them_then_using_the_context_menu._This_process_removes_the_term_<b>%1</b>_from_each_entry's_<b>%0</b>_field.=此外,那些“<b>%0</b>”域里不包含“<b>%1</b>”的记录可以被手动添加到此分组(使用拖放或者右键菜单)——这个操作将会把词组“< [...]
+
Advanced=高级
-Advanced_search_active.=高级搜索行为。
All_entries=所有记录
All_entries_of_this_type_will_be_declared_typeless._Continue?=所有此类型记录将被标记为无类型记录,是否继续?
+
All_fields=所有域
+
All_subgroups_(recursively)=所有子分组(递归地)
+
Always_reformat_BIB_file_on_save_and_export=当保存和导出时重新格式化_BIB_文件
-An_exception_occurred_while_accessing_'%0'=当访问_'%0'_时发生了一个异常
+
A_SAX_exception_occurred_while_parsing_'%0'\:=当解析'%0'时发生了一个_SAXException\:
-An_autosave_file_was_found_for_this_database._This_could_indicate_that_JabRef_did_not_shut_down_cleanly_last_time_the_file_was_used.=发现了当前数据库的一个自动保存文件. 这可能意味着上次打开此文件时_JabRef_没有正常退出.
+
+and=和
+and_the_class_must_be_available_in_your_classpath_next_time_you_start_JabRef.=并且下次您启动_JabRef_的时候,请确保该类在您的_classpath_中。
+
+any_field_that_matches_the_regular_expression_<b>%0</b>=匹配正则表达式_<b>%0</b>_的任何域
+
Appearance=外观
+
Append=追加
Append_contents_from_a_BibTeX_database_into_the_currently_viewed_database=从一个_BibTeX_数据库追加内容到当前查看的数据库
+
Append_database=追加数据库
+
Append_the_selected_text_to_BibTeX_field=追加选中的文本到_BibTeX_键值
Application=应用程序
+
Apply=应用
+
Arguments_passed_on_to_running_JabRef_instance._Shutting_down.=参数传递给了正在执行的_JabRef_实例,关闭自身程序。
+
Assign_entry_selection_exclusively_to_this_group=排它地分配记录到此分组
+
Assign_new_file=分配新文件
+
Assign_the_original_group's_entries_to_this_group?=将原分组中的记录分配到此分组?
+
Assigned_%0_entries_to_group_"%1".=分配了_%0_条记录到分组_"%1".
+
Assigned_1_entry_to_group_"%0".=分配了_1_条记录到分组_"%0".
+
Attach_URL=附加_URL
+
Attempt_to_automatically_set_file_links_for_your_entries._Automatically_setting_works_if_a_file_in_your_file_directory<BR>or_a_subdirectory_is_named_identically_to_an_entry's_BibTeX_key,_plus_extension.=尝试为您的记录自动设置_文件_链接,该操作要求和记录_BibTeX_键同名的_文件存在于您的_文件_目录或者子目录中。
-Attention\:_Password_is_stored_in_plain_text\!=注意\:_密码以明文形式保存\!
+
Auto=自动
+
Autodetect_format=自动检测格式
+
Autogenerate_BibTeX_keys=自动生成_BibTeX_键
+
Autolink_files_with_names_starting_with_the_BibTeX_key=自动链接文件名以_BibTeX_键开头的文件
+
Autolink_only_files_that_match_the_BibTeX_key=自动链接文件名匹配_BibTeX_键的文件
+
Automatically_create_groups=自动创建分组
+
Automatically_create_groups_for_database.=自动为数据库创建分组。
+
Automatically_created_groups=自动创建的分组
+
Automatically_remove_exact_duplicates=自动移除完全重复的项
-Automatically_setting_file_links=自动设置文件链接
-Available_BibTeX_fields=可用的_BibTeX_域
+
+Allow_overwriting_existing_links.=允许覆盖已有的链接。
+
+Do_not_overwrite_existing_links.=不要覆盖已有的链接。
+
+AUX_file_import=AUX_文件导入
+
Available_export_formats=可用的导出格式
+
+Available_BibTeX_fields=可用的_BibTeX_域
+
Available_import_formats=可用的导入格式
+
Background_color_for_optional_fields=可选域的背景颜色
+
Background_color_for_required_fields=必选域的背景颜色
+
Backup_old_file_when_saving=保存数据库时保留备份
+
BibTeX_key_is_unique.=BibTeX_键值是唯一的。
-BibTeX_source=BibTeX_源代码
+
+%0_source=%0_源代码
+
Broken_link=失效链接
+
Browse=浏览...
+
+by=为
+
Cancel=取消
+
Cannot_add_entries_to_group_without_generating_keys._Generate_keys_now?=不生成_BibTeX_键就无法添加记录到分组,现在生成键值?
+
Cannot_merge_this_change=无法合并该更改
+
Cannot_move_group_"%0"_down.=无法下移分组_"%0"。
+
Cannot_move_group_"%0"_left.=无法左移分组_"%0"。
+
Cannot_move_group_"%0"_right.=无法右移分组_"%0"。
+
Cannot_move_group_"%0"_up.=无法上移分组_"%0"。
+
+case_insensitive=忽略大小写
+
+case_sensitive=区分大小写
+
Case_sensitive=区分大小写
+
+change_assignment_of_entries=修改记录的组分配
+
Change_case=修改大小写
+
Change_entry_type=更改记录类型
Change_file_type=更改文件类型
+
+
Change_of_Grouping_Method=分组方法改变
+
+change_preamble=修改导言区_(preamble)
+
Change_table_column_and_General_fields_settings_to_use_the_new_feature=修改列外观和_General_域设置以使用新特性
+
Changed_font_settings=已修改字体设置
+
Changed_language_settings=已修改语言设置
+
Changed_look_and_feel_settings=已修改显示效果_(look_and_feel)_设置
+
Changed_preamble=已修改导言区_(preamble)
-Character_encoding_'%0'_is_not_supported.=,不支持编码_'%0'。
+
Characters_to_ignore=要忽略的字符
+
Check_existing_file_links=检查存在的文件链接
+
Check_links=核对链接
+
Choose_the_URL_to_download.=选择要下载的_URL.
Cite_command=引用命令
+
Class_name=类名
+
Clear=清除
+
Clear_fields=清除域内容
-Clear_search=清除搜索
+
Close=关闭
-Close_all=关闭所有
Close_others=关闭其它
-Close_database=关闭数据库
+Close_all=关闭所有
+
Close_dialog=关闭对话框
-Close_entry_editor=关闭记录编辑器
+
Close_the_current_database=关闭当前数据库
+
Close_window=关闭窗口
+
Closed_database=关闭数据库
+
Collapse_subtree=折叠子树
+
Color_codes_for_required_and_optional_fields=列表记录项的可选域和必选域用不同颜色显示
+
Color_for_marking_incomplete_entries=标记不完整记录的颜色
+
Column_width=列宽
+
Command_line_id=命令行_id
-Connect=连接
+
+
Contained_in=包含在
+
Content=内容
+
Copied=已复制
+
Copied_cell_contents=已拷贝单元格内容
+
Copied_key=已复制_BibTeX_键
+
Copied_keys=已复制_BibTeX_键
+
Copy=复制
+
Copy_BibTeX_key=复制_BibTeX_键
Copy_file_to_file_directory=拷贝文件到文件目录。
-Copy_preview=拷贝预览
+
Copy_to_clipboard=复制到剪贴板
+
Could_not_call_executable=无法调用可执行文件
Could_not_connect_to_Vim_server._Make_sure_that_Vim_is_running<BR>with_correct_server_name.=无法连接到_Vim_服务器,请检查_Vim_是否以正确的_Vim_服务器名选项启动。
+
Could_not_export_file=无法导出文件
+
Could_not_export_preferences=无法导出首选项
+
Could_not_find_a_suitable_import_format.=无法找到符合的导入格式.
Could_not_import_preferences=无法导入首选项
-Could_not_instantiate_%0._Have_you_chosen_the_correct_package_path?=无法例示_%0,您选择了正确的包路径吗?
+
Could_not_instantiate_%0=无法例示_%0
Could_not_instantiate_%0_%1=无法例示_%0_%1
+Could_not_instantiate_%0._Have_you_chosen_the_correct_package_path?=无法例示_%0,您选择了正确的包路径吗?
Could_not_open_link=无法打开链接
+
Could_not_print_preview=无法打印预览
+
Could_not_run_the_'vim'_program.=无法运行_'vim'_程序。
+
Could_not_save_file.=无法保存文件
+Character_encoding_'%0'_is_not_supported.=,不支持编码_'%0'。
+
Created_groups.=建立分组
+
+crossreferenced_entries_included=包含交叉引用的记录
+
Current_content=当前内容
+
Current_value=当前值
+
Custom_entry_types=自定义的记录类型
+
Custom_entry_types_found_in_file=文件中包含自定义的记录类型
+
Customize_entry_types=自定义记录类型
+
Customize_key_bindings=自定义热键
+
Cut=剪切
+
+cut_entries=剪切记录
+
+cut_entry=剪切该记录
+
+
Database_encoding=数据库编码
+
Database_properties=数据库属性
-Database_type=
+Database_type=数据库类型
+
Date_format=日期格式
-Decrease_table_font_size=减小表格字号
+
Default=默认
-Default_bibliography_mode=默认的参考文献模式
+
Default_encoding=默认编码
+
Default_grouping_field=默认分组依据域
+
Default_look_and_feel=默认显示效果_(look_and_feel)
+
Default_pattern=默认模式
+
Default_sort_criteria=默认排序规则
Define_'%0'=定义_'%0'
+
Delete=删除
+
Delete_custom_format=删除自定义格式
+
+delete_entries=删除记录
+
Delete_entry=删除该记录
+
+delete_entry=删除该记录
+
Delete_multiple_entries=删除多条记录
+
Delete_rows=删除行
+
Delete_strings=删除简写字串
+
Deleted=已删除
+
+Delete_local_file=删除本地文件
+
Delimit_fields_with_semicolon,_ex.=使用分号分隔域,例如
+
Descending=降序
+
Description=描述
+
Deselect_all=取消所有选定
Deselect_all_duplicates=检测所有重复项
+
Disable_this_confirmation_dialog=不再显示这个确认对话框
+
Display_all_entries_belonging_to_one_or_more_of_the_selected_groups.=显示属于选中任一分组的记录,即显示选中分组的并集。
+
Display_all_error_messages=显示所有错误消息
+
Display_help_on_command_line_options=用命令行选项显示帮助
+
Display_only_entries_belonging_to_all_selected_groups.=只显示属于所有选中分组的记录,即显示选中分组的交集。
Display_version=显示版本
+
Displaying_no_groups=非分组视图
+
Do_not_abbreviate_names=不要缩写姓名
+
Do_not_automatically_set=不要自动设置
+
Do_not_import_entry=不导入记录
+
Do_not_open_any_files_at_startup=启动时不打开任何文件
+
Do_not_overwrite_existing_keys=不覆盖已存在的_BibTeX_键
Do_not_show_these_options_in_the_future=以后不要再显示这些选项
+
Do_not_wrap_the_following_fields_when_saving=保存时不要对下列域添加换行符
Do_not_write_the_following_fields_to_XMP_Metadata\:=不要将以下域写入_XMP_元数据\:
+
Do_you_want_JabRef_to_do_the_following_operations?=您希望_JabRef_做以下操作吗?
-Do_you_want_to_import_these_as_new_entries_into_the_current_database?=您希望导入这些记录到当前数据库中吗?
+
+Donate_to_JabRef=捐款给_JabRef
+
Down=下
+
Download=下载
+
Download_file=下载文件
+
Downloading...=下载中...
Drop_%0=释放_%0
+
+duplicate_removal=移除重复
+
Duplicate_string_name=重复的简写字串名称
+
Duplicates_found=发现重复项
+
Dynamic_groups=动态分组
+
Dynamically_group_entries_by_a_free-form_search_expression=使用自定义的搜索表达式创建动态分组
+
Dynamically_group_entries_by_searching_a_field_for_a_keyword=使用关键词搜索某域创建动态分组
+
Each_line_must_be_on_the_following_form=每一行必须使用以下形式
+
Edit=编辑
+
Edit_custom_export=编辑自定义导出
Edit_entry=编辑记录
+Save_file=编辑文件链接
Edit_file_type=编辑文件类型
+
Edit_group=编辑分组
+
Edit_journal=编辑期刊
+
Edit_preamble=编辑导言区_(preamble)
Edit_strings=编辑简写字串
Editor_options=编辑器选项
+
Empty_BibTeX_key=空_BibTeX_键
-Enable_save_actions=启用保存附加操作
+
+Grouping_may_not_work_for_this_entry.=,该记录可能无法被分组。
+
+empty_database=空数据库
Enable_word/name_autocompletion=启用词组/姓名自动补全
+
Enter_URL=输入_URL
+
Enter_URL_to_download=输入要下载的_URL
+
+entries=记录
+
Entries_cannot_be_manually_assigned_to_or_removed_from_this_group.=此分组中的记录无法进行手动分配。
+
Entries_exported_to_clipboard=记录被导出到剪贴板
-Entry_editor,_next_entry=记录编辑器,下一条记录
-Entry_editor,_next_panel=记录编辑器,下一个面板
-Entry_editor,_next_panel_2=记录编辑器,下一个面板_2
-Entry_editor,_previous_entry=记录编辑器,上一条记录
-Entry_editor,_previous_panel=记录编辑器,上一个面板
-Entry_editor,_previous_panel_2=记录编辑器,上一个面板_2
-Entry_editor,_store_field=记录编辑器,保存域内容
+
+
+entry=记录
+
Entry_editor=记录编辑器
+
Entry_preview=预览记录
+
Entry_table=记录列表
+
Entry_table_columns=记录列
+
Entry_type=记录类型
+
Entry_type_names_are_not_allowed_to_contain_white_space_or_the_following_characters=记录类型名中不允许使用空格或者下列字符
+
Entry_types=记录类型
+
Error=错误
Error_exporting_to_clipboard=导出到剪贴板错误
+
Error_occurred_when_parsing_entry=分析记录时发生错误
+
Error_opening_file=打开文件错误
+
Error_setting_field=设置域错误
Error_while_writing=写入错误
Error_writing_to_%0_file(s).=写入到_%0_文件错误。
+
+
Exceptions=异常
+
Existing_file=已有文件
+
+'%0'_exists._Overwrite_file?='%0'_已存在,覆盖文件?
+Overwrite_file?=覆盖文件?
+
Expand_subtree=展开子树
+
Export=导出
-Export_sorting=导出排序
+
Export_name=导出名称
+
Export_preferences=导出首选项设置
+
Export_preferences_to_file=导出首选项设置到文件
+
Export_properties=导出属性
+
Export_to_clipboard=导出到剪贴板
+
Exporting=正在导出
Extension=扩展名
+
External_changes=外部修改
+
External_file_links=外部文件链接
+
External_files=外部文件
+
External_programs=外部程序
+
External_viewer_called=成功调用外部查看器
+
Fetch=抓取
+
Field=域
+
+field=域
+
Field_name=域名称
Field_names_are_not_allowed_to_contain_white_space_or_the_following_characters=域名中不可含有空格或以下字符
+
Field_to_filter=要过滤的域
+
Field_to_group_by=用来分组的域
+
File=文件
+
+file=文件
File_'%0'_is_already_open.=文件_'%0'_已经被打开。
+
File_'%0'_not_found=无法找到文件_'%0'
+
File_changed=文件已改变
File_directory_is_'%0'\:=文件目录是_'%0'\:
+
File_directory_is_not_set_or_does_not_exist\!=文件目录未设置或该目录不存在!
File_exists=文件已存在
+
File_has_been_updated_externally._What_do_you_want_to_do?=文件被外部程序修改,您要怎么做?
-File_list_editor,_move_entry_down=文件列表编辑器,下移记录
-File_list_editor,_move_entry_up=文件列表编辑器,上移记录
+
File_not_found=无法找到文件
File_type=文件类型
+
File_updated_externally=文件被外部程序修改
+
+filename=文件名
+
Files_opened=已打开文件
+
Filter=过滤
+
Finished_automatically_setting_external_links.=完成自动设置外部链接。
+
Finished_synchronizing_file_links._Entries_changed\:_%0.=完成同步文件条链接,记录改变\:_%0.
Finished_writing_XMP-metadata._Wrote_to_%0_file(s).=完成写入_XMP-元数据,写入_%0_文件。
Finished_writing_XMP_for_%0_file_(%1_skipped,_%2_errors).=完成写入_XMP-元数据到_%0_文件_(跳过_%1_条,%2_条错误).
+
First_select_the_entries_you_want_keys_to_be_generated_for.=首先选中您要生成_BibTeX_键的记录。
+
Fit_table_horizontally_on_screen=列表宽度填满屏幕宽度
+
Float=浮动_(结果上浮到最前)
Float_marked_entries=浮动高亮显示的记录_(上浮到列表最前)
-Focus_entry_table=激活记录列表
-Font_selection=字体下拉菜单项
+
Font_family=字体
+
Font_preview=预览字体
+
Font_size=字号
+
Font_style=字体
-Format_string=格式化简写字串
+
+Font_selection=字体下拉菜单项
+
+for=为
+
Format_of_author_and_editor_names=作者和编者的姓名格式
+Format_string=格式化简写字串
+
Format_used=使用的格式
Formatter_name=格式化器名称
-Found_%0_results.=找到_%0_条结果.
+
+found_in_AUX_file=在_AUX_发现
+
Full_name=全称
+
General=基本设置
+
General_fields=General_域
+
Generate=生成
+
Generate_BibTeX_key=生成_BibTeX_键
+
Generate_keys=生成键
+
Generate_keys_before_saving_(for_entries_without_a_key)=保存数据库前为缺失键值的记录自动生成_BibTeX_键
Generate_keys_for_imported_entries=为导入的记录重新生成_BibTeX_键
+
Generate_now=现在生成
+
Generated_BibTeX_key_for=已生成_BibTeX_键——为
+
Generating_BibTeX_key_for=正在生成_BibTeX_键——为
+Get_fulltext=获取全文
Grab=Grab
+
Gray_out_entries_not_in_group_selection=灰色显示未选中记录
-Gray_out_non-hits=灰色显示未选中
-Grouping_may_not_work_for_this_entry.=,该记录可能无法被分组。
+
+Gray_out_non-hits=置灰未选中
+
Groups=分组
-HTML_table=HTML_表
-HTML_table_(with_Abstract_&_BibTeX)=HTML_表(包含摘要和_BibTeX)
+
Have_you_chosen_the_correct_package_path?=您选择了正确的包路径吗?
+
Help=帮助
-Help_on_regular_expression_search=正则表达式搜索帮助
+
Help_on_groups=分组帮助
+
Help_on_key_patterns=键表达式帮助
+Help_on_regular_expression_search=正则表达式搜索帮助
+
Hide_non-hits=隐藏未选中
+
Hierarchical_context=分级上下文
+
Highlight=高亮
Highlight_groups_matching_all_selected_entries=高亮显示包含所有选中记录的分组
Highlight_groups_matching_any_selected_entry=高亮显示包含任一选中记录的分组
+Disable_highlight_groups_matching_entries=
+
Highlight_overlapping_groups=高亮显示有重叠记录的分组
+
Hint\:_To_search_specific_fields_only,_enter_for_example\:<p><tt>author\=smith_and_title\=electrical</tt>=提示\:_若想只搜索特定域的话,可以像这样写\:<p><tt>author\=smith_and_title\=electrical</tt>
-ISO_abbreviation=ISO_缩写
+
+HTML_table=HTML_表
+HTML_table_(with_Abstract_&_BibTeX)=HTML_表(包含摘要和_BibTeX)
Icon=图标
+
Ignore=忽略
+
Immediate_subgroups=直接子分组
+
Import=导入
-ImportFormat_class=ImportFormat_类
+
Import_and_keep_old_entry=导入且保存旧记录
+
Import_and_remove_old_entry=导入且移除旧记录
+
Import_entries=导入记录
+
Import_failed=导入失败
+
Import_file=导入文件
+
Import_group_definitions=导入分组配置
-Import_into_current_database=导入当前数据库
-Import_into_new_database=导入新建数据库
+
Import_name=导入名称
+
Import_preferences=导入首选项设置
+
Import_preferences_from_file=从文件中导入首选项设置
+
Import_strings=导入简写字串
+
Import_to_open_tab=导入到打开标签页
-Import_word_selector_definitions=导入词组下拉菜单项
+
Imported_entries=已导入记录
+
Imported_from_database=已从数据库导入
+
+Importer_class=Importer_类
+
Importing=正在导入
+
Importing_in_unknown_format=以未知格式导入
+
Include_abstracts=包含摘要
Include_entries=包括的记录
+
Include_subgroups\:_When_selected,_view_entries_contained_in_this_group_or_its_subgroups=包含子分组:当分组被选中时,显示所有它和它的子分组中的记录
-Increase_table_font_size=增大表格字号
+
Independent_group\:_When_selected,_view_only_this_group's_entries=独立分组:当分组被选中时,只显示属于此分组的记录
+
Initially_show_groups_tree_expanded=初始时显示展开的分组树
-Input_error=输入错误
+
+Work_options=工作选项
+
Insert=插入
Insert_rows=插入行
+
Intersection=交集
+
Invalid_BibTeX_key=非法的_BibTeX_键值
-Invalid_URL=非法的_URL
+
Invalid_date_format=非法的日期格式
+
+Invalid_URL=非法的_URL
+
Inverted=补集
-Online_help=
-JabRef_no_longer_supports_'ps'_or_'pdf'_fields.<br>File_links_are_now_stored_in_the_'file'_field_and_files_are_stored_in_an_external_file_directory.<br>To_make_use_of_this_feature,_JabRef_needs_to_upgrade_file_links.<br><br>=JabRef_不再支持_"ps"_或_"pdf"_域。<br>新版本将文件链接保存在_"file"_域中,文件保存在外部文件目录中。<br>为了启用新的特性,JabRef_需要升级文件链接。<br><br>
+
+ISO_abbreviation=ISO_缩写
+
+Online_help=在线帮助
+
JabRef_preferences=JabRef_首选项
+
Journal_abbreviations=期刊缩写名
+
Journal_list_preview=期刊列表预览
+
Journal_name=期刊名
+
Keep=保留
+
Keep_both=保留全部
+
Key_bindings=热键绑定
+
Key_bindings_changed=热键绑定已修改
+
Key_generator_settings=键值生成器设置
+
Key_pattern=键值表达式
+
+keys_in_database=数据库中的键值
+
Keyword=关键字
-LaTeX_AUX_file=LaTeX_AUX_文件
+
Label=标签
+
Language=语言
+
Last_modified=上次修改的
+
+LaTeX_AUX_file=LaTeX_AUX_文件
Leave_file_in_its_current_directory=保留文件的当前位置不改变。
+
Left=Left
-Level=
+Level=级别
+
Limit_to_fields=限制范围到域
+
Limit_to_selected_entries=限制范围为选中的记录
+
Link=链接
Link_local_file=链接本地文件
Link_to_file_%0=到文件_%0_的链接
+
Listen_for_remote_operation_on_port=监听端口
Load_and_Save_preferences_from/to_jabref.xml_on_start-up_(memory_stick_mode)=加载/保存首选项设置从/到_jabref.xml_文件(记忆棒模式)
+
Look_and_feel=显示效果_(look_and_feel)
Main_file_directory=文件主目录
+
Main_layout_file=主_layout_文件
-Manage=管理
+
Manage_custom_exports=管理自定义导出器
+
Manage_custom_imports=管理自定义导入器
Manage_external_file_types=管理外部文件类型
+
Manage_journal_abbreviations=管理期刊名称缩写
+
Mark_entries=高亮标记多条记录
+
Mark_entry=高亮标记该记录
+
Mark_new_entries_with_addition_date=建立新记录时标记时间
+
Mark_new_entries_with_owner_name=建立新记录时标记所有者为
+
Memory_stick_mode=记忆棒模式
+
Menu_and_label_font_size=菜单和标签字号
+
Merged_external_changes=合并外部修改
+
Messages=消息
+
Modification_of_field=域的修改
+
Modified_group_"%0".=已修改分组_"%0".
+
Modified_groups=已修改分组
+
Modified_string=已修改简写字串
+
Modify=修改
+
+modify_group=修改分组
+
Move=移动
+
Move_down=下移
+
Move_entries_in_group_selection_to_the_top=移动选中分组的记录到顶部
Move_external_links_to_'file'_field=移动外部链接到_'file'_域
+
+move_group=移动分组
+
Move_up=上移
+
Moved_group_"%0".=移动了分组_"%0"。
+
Name=名字
Name_formatter=姓名格式化器
+
Natbib_style=Natbib_格式
+
+nested_AUX_files=nested_AUX_文件
+
New=新建
-New_%0_database=新建_%0_数据库
-New_%0_database_created.=成功新建数据库_%0.
+
+new=新建
+
New_BibTeX_entry=新建_BibTeX_记录
+
New_BibTeX_subdatabase=新建_BibTeX_子数据库
-New_article=新建_article
-New_book=新建_book
+
New_content=新内容
+
New_database_created.=创建了新数据库。
-New_entry=新建记录
+New_%0_database=新建_%0_数据库
New_field_value=新的域内容
+
New_file=新建文件
New_file_link_(INSERT)=新建文件链接(插入)
-New_from_plain_text=从纯文本新建
+
New_group=新建分组
-New_inbook=新建_inbook
-New_mastersthesis=新建_mastersthesis
-New_phdthesis=新建_phdthesis
-New_proceedings=新建_proceedings
+
New_string=新建简写字串
-New_unpublished=新建_unpublished
+
Next_entry=下一条
-Next_tab=下个标签
-No_GUI._Only_process_command_line_options.=没有_GUI,只处理命令行选项。
-No_PDF_linked=没有_PDF_链接
+
No_actual_changes_found.=没有实际的修改。
+
+no_base-BibTeX-file_specified=没有指定_base-BibTeX-文件
+
+no_database_generated=没有生成数据库
+
No_entries_found._Please_make_sure_you_are_using_the_correct_import_filter.=没有找到记录,请检查是否使用了正确的导入过滤器。
+
+
No_entries_found_for_the_search_string_'%0'=没有找到符合查询字符串_'%0'_的记录
+
No_entries_imported.=没有导入记录。
-No_entry_found_for_ISBN_%0_at_www.ebook.de=在_www.ebook.de_上没有找到_ISBN_%0_的记录
+
No_exceptions_have_occurred.=没有发生异常。
No_files_found.=没有找到文件。
+
+No_GUI._Only_process_command_line_options.=没有_GUI,只处理命令行选项。
+
No_journal_names_could_be_abbreviated.=没有可供缩写的期刊全称。
+
No_journal_names_could_be_unabbreviated.=没有可供展开的期刊名缩写。
-No_meta_data_present_in_BIB_file._Cannot_regenerate_BibTeX_keys=在_BIB_file_中没有找到_meta_data,无法重建_BibTeX_key
-No_references_found=没有找到引用
-No_results_found.=没有找到结果.
+No_PDF_linked=没有_PDF_链接
+
No_URL_defined=没有定义_url
-Normal_search_active.=普通搜索行为。
-Note\:_A_full_text_search_is_currently_not_supported_for_%0=注意:%0_目前不支持全文检索
+not=非
+
+not_found=无法找到
+
Note_that_you_must_specify_the_fully_qualified_class_name_for_the_look_and_feel,=注意:您必须为显示效果_(look_and_feel)_明确指定完整的经过验证的类名称,
+
Nothing_to_redo=无可重做
+
Nothing_to_undo=无可撤销
-Number_of_references_to_fetch?=要抓取的引用数?
+
+occurrences=次
+
OK=确定
One_or_more_file_links_are_of_the_type_'%0',_which_is_undefined._What_do_you_want_to_do?=一个或多个文件链接是未定义的文件类型_'%0',您希望怎么做?
+
One_or_more_keys_will_be_overwritten._Continue?=一个或多个_BibTeX_键将会被覆盖,是否继续?
+
Open=打开
+
Open_BibTeX_database=打开_BibTeX_数据库
-Open_URL_or_DOI=打开_URL_或_DOI
+
Open_database=打开数据库
+
Open_editor_when_a_new_entry_is_created=创建新记录时打开记录编辑器
+
Open_file=打开文件
+
Open_last_edited_databases_at_startup=启动_JabRef_时打开上次使用的数据库
-Open_shared_database=
+
+Connect_to_shared_database=连接到共享数据库
+
Open_terminal_here=在此处打开终端
+
+Open_URL_or_DOI=打开_URL_或_DOI
+
Opened_database=已打开数据库
+
Opening=正在打开
+
Opening_preferences...=正在打开首选项...
+
Operation_canceled.=操作被取消
Operation_not_supported=不支持的操作
+
Optional_fields=可选域
+
Options=选项
-Other_fields=其它域
+
+or=或
+
Output=输出
+
Output_or_export_file=输出或导出文件
+
Override=跳过
+
Override_default_file_directories=跳过默认文件目录
+
Override_default_font_settings=跳过默认字体设置
+
Override_the_BibTeX_field_by_the_selected_text=使用选中文字覆盖_BibTeX_键值
+
+
Overwrite=覆盖
Overwrite_existing_field_values=覆盖原有域内容
-Overwrite_file?=覆盖文件?
+
Overwrite_keys=覆盖键值
-PDF_does_not_exist=PDF_不存在
+
+pairs_processed=已处理记录对
Password=口令
+
Paste=粘贴
+
+paste_entries=粘贴多条记录
+
+paste_entry=粘贴记录
Paste_from_clipboard=从剪贴板粘贴
+
Pasted=完成粘贴
+
Path_to_%0_not_defined=到_%0_的路径未定义
+
Path_to_LyX_pipe=到_LyX_管道的路径
+
+PDF_does_not_exist=PDF_不存在
+
Personal_journal_list=私有的期刊列表
+
Plain_text_import=纯文本导入
+
Please_enter_a_name_for_the_group.=请为该分组输入一个名字
+
Please_enter_a_search_term._For_example,_to_search_all_fields_for_<b>Smith</b>,_enter\:<p><tt>smith</tt><p>To_search_the_field_<b>Author</b>_for_<b>Smith</b>_and_the_field_<b>Title</b>_for_<b>electrical</b>,_enter\:<p><tt>author\=smith_and_title\=electrical</tt>=请输入一个搜索词组。例如,要在所有域中搜索_<b>Smith</b>,就输入\:<p><tt>smith</tt><p>要在_<b>Author</b>_域中搜索_<b>Smith</b>_并且_<b>Title</b>_域中搜索_<b>electrical</b>,_输入\:<p><tt>author\=smith_and_title\=electrical</tt>
+
Please_enter_the_field_to_search_(e.g._<b>keywords</b>)_and_the_keyword_to_search_it_for_(e.g._<b>electrical</b>).=请输入要搜索的域(例如:_<b>keywords</b>)和要搜索的关键词(例如:_<b>electrical</b>)。
+
Please_enter_the_string's_label=请输入简写字串的标签
+
Please_select_an_importer.=请选择一个导入器。
+
Please_select_exactly_one_group_to_move.=请选中一个分组来移动。
-Please_specify_both_username_and_password=请完整填写用户名和密码
+
Possible_duplicate_entries=可能的重复记录
+
Possible_duplicate_of_existing_entry._Click_to_resolve.=可能与已存在记录重复,点击以解决此问题。
+
Preamble=导言区_(Preamble)
-Preamble_editor,_store_changes=导言编辑器,保存修改
+
Preferences=首选项
+
Preferences_recorded.=首选项被记录。
+
Preview=预览
+Citation_Style=引用样式
+Current_Preview=当前预览
+Cannot_generate_preview_based_on_selected_citation_style.=无法为选中的引用样式生成预览.
+Bad_character_inside_entry=记录是包含非法字符
+Error_while_generating_citation_style=生成引用样式时出错
+Preview_style_changed_to\:_%0=预览样式更改为\:_%0
+Next_preview_layout=下一条预览布局
+Previous_preview_layout=上一条预览布局
+
Previous_entry=上一条
-Previous_tab=上一标签
+
Primary_sort_criterion=排序依据
Problem_with_parsing_entry=解析记录时的问题
Processing_%0=正在处理_%0
Program_output=程序输出
-Pull_changes_from_shared_database=
-Proxy_requires_authentication=HTTP_代理要求认证
-Push_to_application=推送到应用
+Pull_changes_from_shared_database=从共享数据库中更新
+
Pushed_citations_to_%0=已推送文献引用到_%0
+
Quit_JabRef=退出_JabRef
+
Quit_synchronization=退出同步
+
Raw_source=原始源数据
+
Rearrange_tabs_alphabetically_by_title=对标签页以标题按字母表排序
+
Redo=重做
+
Reference_database=参考文献数据库
-References_found=找到参考文献
+
+%0_references_found._Number_of_references_to_fetch?=找到参考文献\:_%0。_要抓取的引用数?
+
Refine_supergroup\:_When_selected,_view_entries_contained_in_both_this_group_and_its_supergroup=提炼父分组:当分组被选中时,显示同时包含在该分组和它父分组中的记录
-Refresh_OpenOffice/LibreOffice=刷新_penOffice/LibreOffice
-Regenerate_all_keys_for_the_entries_in_a_BibTeX_file=重新生成_BibTeX_文件中所有记录的键值
-Regenerating_BibTeX_keys_according_to_metadata=基于_metadata_重新生成_BibTeX_键值
+
+regular_expression=正则表达式
+
Remember_these_entry_types?=记住这些记录类型?
+
Remote_operation=远程操作
+
Remote_server_port=远程服务器端口
+
Remove=移除
+
+Remove_subgroups=移除子分组
+
Remove_all_subgroups_of_"%0"?=移除_"%0"_的所有子分组?
+
Remove_entry_from_import=从导入中移除记录
+
Remove_entry_selection_from_this_group=从该分组中移除记录
+
Remove_entry_type=移除记录类型
Remove_file_link_(DELETE)=移除文件链接(删除)
+
Remove_from_group=从分组中移除
-Remove_group,_keep_subgroups=移除分组,保留子分组
+
Remove_group=移除分组
+
+Remove_group,_keep_subgroups=移除分组,保留子分组
+
Remove_group_"%0"?=移除分组_"%0"?
+
Remove_group_"%0"_and_its_subgroups?=移除分组_"%0"_和它的子分组?
+
+remove_group_(keep_subgroups)=移除分组(保留子分组)
+
+remove_group_and_subgroups=移除分组和子分组
+
Remove_group_and_subgroups=移除分组和子分组
+
Remove_link=移除链接
+
Remove_old_entry=移除旧记录
+
Remove_selected_strings=移除选中的简写字串
-Remove_subgroups=移除子分组
+
Removed_group_"%0".=已移除分组_"%0"。
+
Removed_group_"%0"_and_its_subgroups.=已移除分组_"%0"_和它的子分组。
+
Removed_string=已移除简写字串
+
Renamed_string=重命名简写字串
+
Replace_(regular_expression)=替换_(正则表达式)
+
Replace_string=替换字符串
+
Replace_with=替换为
+
Replaced=被替换
+
Required_fields=必选域
+
Reset_all=重置所有
-Resolve_duplicate_BibTeX_keys=处理重复的_BibTeX_键值
+
Resolve_strings_for_all_fields_except=处理所有域的简写字串,除了
Resolve_strings_for_standard_BibTeX_fields_only=只处理标准_BibTeX_域的简写字串
+
+resolved=已解决
+
Revert_to_original_source=恢复到初始源
+
Review=评论
+
Review_changes=复查修改
+
Right=右
+
Save=保存
-Save_actions=保存时附加操作
-Save_all=保存所有
Save_all_finished.=完成保存全部。
+
Save_all_open_databases=保存所有打开的数据库
+
Save_before_closing=关闭前保存
+
Save_database=保存数据库
Save_database_as...=保存数据库为_...
+
Save_entries_in_their_original_order=以原始顺序保存记录
+
Save_failed=保存失败
+
Save_failed_during_backup_creation=保存失败,无法创建备份
-Save_failed_while_committing_changes\:_%0=保存失败,无法提交修改\:_%0
-Save_file=编辑文件链接
+
Save_selected_as...=选中记录另存为...
+
Saved_database=已保存数据库
+
Saved_selected_to_'%0'.=保存选中到_'%0'.
+
Saving=保存中
Saving_all_databases...=正在保存所有数据库...
+
Saving_database=正在保存数据库
+
Search=查找
+
Search_expression=查找表达式
+
Search_for=查找
-Search_globally=全局搜索
-Search_in_all_open_databases=在所有打开的数据库中搜索
-Search_results_in_all_databases_for_%0=在所有数据库中搜索_%0_的结果
-Search_results_in_database_%0_for_%1=在数据库_%0_中搜索_%1_的结果
+
Searching_for_duplicates...=正在查找重复记录...
+
Searching_for_files=正在查找文件
+
Secondary_sort_criterion=次要依据
+
Select=选择
+
+
Select_all=全选
+
Select_encoding=选择编码
+
Select_entry_type=选择记录类型
Select_external_application=选择外部程序
+
Select_file_from_ZIP-archive=从_ZIP-压缩包中选择文件
+
Select_the_tree_nodes_to_view_and_accept_or_reject_changes=选择树节点查看和接受/拒绝修改
Selected_entries=选中的记录
Set_field=设置域内容
Set_fields=设置域内容
+
Set_general_fields=设置_general_域
Set_main_external_file_directory=设置外部文件的主目录
+
Set_table_font=设置表格字体
+
Settings=设置
+
Shortcut=快捷键
-Show/edit_BibTeX_source=显示/编辑_BibTeX_源代码
+
+Show/edit_%0_source=显示/编辑_%0_源代码
+
Show_'Firstname_Lastname'=显示_'名_(Firstname)_姓_(Lastname)'
+
Show_'Lastname,_Firstname'=显示_'姓_(Lastname),_名_(Firstname)'
+
Show_BibTeX_source_by_default=缺省显示_BibTeX_源代码
-Show_URL/DOI_column=显示_URL/DOI_列
+
Show_confirmation_dialog_when_deleting_entries=删除多条记录时发出警告
-Show_debug_level_messages=显示调试级别消息
+
Show_description=显示描述
+
Show_dynamic_groups_in_<i>italics</i>=用_<i>斜体</i>_显示动态分组
+
Show_entries_<b>not</b>_in_group_selection=显示那些<b>不</b>在选中分组中的记录
+
Show_file_column=显示“文件”列
+
Show_icons_for_groups=显示分组类型图标
Show_last_names_only=只显示“姓_(Lastname)”
+
Show_names_unchanged=显示原始姓名字串
-Show_only_preferences_deviating_from_their_default_value=只显示与默认值不同的首选项
+
Show_optional_fields=显示可选域
-Show_preferences=列表显示首选项
-Show_remaining_fields=显示其它的域
+
Show_required_fields=显示必选域
+
+Show_URL/DOI_column=显示_URL/DOI_列
+
Simple_HTML=简单_HTML
+
Size=大小
+
Skipped_-_No_PDF_linked=跳过-没有_PDF_链接
Skipped_-_PDF_does_not_exist=跳过-PDF_不存在
+
Skipped_entry.=已跳过记录
+
Sort_alphabetically=按字母表排序
+
+sort_subgroups=排序子分组
+
Sorted_all_subgroups_recursively.=递归排序所有子分组。
+
Sorted_immediate_subgroups.=完成排序直接子分组。
+
+source_edit=源代码编辑
Special_name_formatters=特殊的姓名格式化器
+
Special_table_columns=特殊列
+
Starting_import=开始导入
+
Statically_group_entries_by_manual_assignment=手动创建静态分组
+
Status=状态
+
Stop=停止
+
Store_journal_abbreviations=储存期刊缩写
+
Stored_entry=储存的记录
-String_dialog,_add_string=简写字串对话框,添加简写字串
-String_dialog,_remove_string=简写字串对话框,删除简写字串
+
Strings=简写字串
+
Strings_for_database=简写字串列表——数据库
+
Subdatabase_from_AUX=从_AUX_文件生成的子数据库
-Switch_preview_layout=切换预览视图
+
Switches_between_full_and_abbreviated_journal_name_if_the_journal_name_is_known.=在已知的期刊名简写和全称之间切换。
+
Synchronize_file_links=同步文件链接
-Synchronize_files=同步文件
+
Synchronizing_file_links...=正在同步文件链接...
+
Table_appearance=列表外观
+
Table_background_color=列表背景颜色
+
Table_grid_color=列表网格颜色
+
Table_text_color=列表文字颜色
+
Tabname=标签页名
Target_file_cannot_be_a_directory.=目标文件不可为目录。
+
Tertiary_sort_criterion=次要依据
+
Test=测试
-The_PDF_contains_one_or_several_BibTeX-records.=该_PDF_包含一个或多个_BibTeX_记录,
-The_ZIP-archive_need_not_be_on_the_classpath_of_JabRef.=该_ZIP_压缩包不需要在_JabRef_的_classpath_下。
+
+paste_text_here=此处编辑文本
+
The_chosen_date_format_for_new_entries_is_not_valid=为新记录选择的日期格式非法
+
The_chosen_encoding_'%0'_could_not_encode_the_following_characters\:=选择的编码_'%0'_无法支持下列字符\:
+
+
+the_field_<b>%0</b>=域_<b>%0</b>
+
The_file<BR>'%0'<BR>has_been_modified<BR>externally\!=文件<BR>'%0'<BR>已经被外部程序修改!
+
The_group_"%0"_already_contains_the_selection.=分组_"%0"_中已经包含选中的项。
+
The_label_of_the_string_cannot_be_a_number.=该简写字串的_label_不可以为数字。
+
The_label_of_the_string_cannot_contain_spaces.=该简写字串的_label_不可以包含空格。
+
The_label_of_the_string_cannot_contain_the_'\#'_character.=该简写字串的_label_不可以包含_'\#'_字符。
+
The_output_option_depends_on_a_valid_import_option.=输出选项依赖于一个合法的导入选项。
-The_path_need_not_be_on_the_classpath_of_JabRef.=该路径不需要在_JabRef_的_classpath_下。
+The_PDF_contains_one_or_several_BibTeX-records.=该_PDF_包含一个或多个_BibTeX_记录,
+Do_you_want_to_import_these_as_new_entries_into_the_current_database?=您希望导入这些记录到当前数据库中吗?
+
The_regular_expression_<b>%0</b>_is_invalid\:=正则表达式_<b>%0</b>_是非法的\:
+
The_search_is_case_insensitive.=该查询是不区分大小写的。
+
The_search_is_case_sensitive.=该查询是区分大小写的。
+
The_string_has_been_removed_locally=简写字串被本地移除
+
There_are_possible_duplicates_(marked_with_an_icon)_that_haven't_been_resolved._Continue?=存在可能仍未解决的重复项(以'D'图标标记),是否继续?
-This_database_uses_outdated_file_links.=这个数据库使用了过期的文件链接。
+
This_entry_has_no_BibTeX_key._Generate_key_now?=此记录没有_BibTeX_键,现在生成它?
+
This_entry_is_incomplete=该记录是不完整的
+
This_entry_type_cannot_be_removed.=该记录类型无法被移除。
+
This_external_link_is_of_the_type_'%0',_which_is_undefined._What_do_you_want_to_do?=此外部链接类型_'%0'_未定义,您想怎么办?
+
This_group_contains_entries_based_on_manual_assignment._Entries_can_be_assigned_to_this_group_by_selecting_them_then_using_either_drag_and_drop_or_the_context_menu._Entries_can_be_removed_from_this_group_by_selecting_them_then_using_the_context_menu.=
-#! 此分组中的记录系用户手动方式分配。您可以使用拖放或者右键菜单将记录分配到此分组;选中记录后用右键菜单可以将该记录从此分组中移除;分配到此分组中的记录必须有一个唯一的键值,该键值可以随时被更改,但必须保证其唯一性。
+
This_group_contains_entries_whose_<b>%0</b>_field_contains_the_keyword_<b>%1</b>=此分组中记录的_<b>%0</b>_域包含关键词_<b>%1</b>_
+
This_group_contains_entries_whose_<b>%0</b>_field_contains_the_regular_expression_<b>%1</b>=此分组中记录的_<b>%0</b>_域包含正则表达式_<b>%1</b>_
This_makes_JabRef_look_up_each_file_link_and_check_if_the_file_exists._If_not,_you_will_be_given_options<BR>to_resolve_the_problem.=该选项使_JabRef_遍历所有文件链接,检查链接文件是否存在。如果不存在,您将会得到一个选项来处理这个问题。
+
This_operation_requires_all_selected_entries_to_have_BibTeX_keys_defined.=此操作要求所有选中记录的_BibTeX_键值不为空。
+
This_operation_requires_one_or_more_entries_to_be_selected.=这个操作要求选中一条或多条记录。
-This_search_contains_entries_in_which=这次搜索的结果记录符合条件:
-This_search_contains_entries_in_which_any_field_contains_the_regular_expression_<b>%0</b>=这次搜索的结果记录符合条件:记录的任意域包含正则表达式_<b>%0</b>
-This_search_contains_entries_in_which_any_field_contains_the_term_<b>%0</b>=这次搜索的结果记录符合条件:记录的任意域包含词组_<b>%0</b>
+
Toggle_abbreviation=打开/关闭名称缩写
Toggle_entry_preview=打开/关闭记录预览
Toggle_groups_interface=打开/关闭组界面
Try_different_encoding=尝试其它编码
-Unabbreviate=展开缩写
+
Unabbreviate_journal_names_of_the_selected_entries=展开选中记录的缩写期刊名称
Unabbreviated_%0_journal_names.=展开_%0_期刊名称。
-Unable_to_autodetect_OpenOffice/LibreOffice_installation._Please_choose_the_installation_directory_manually.=自动检测_OpenOffice/LibreOffice_安装位置失败,请手动指定安装目录。
+
Unable_to_open_file.=无法打开文件.
Unable_to_open_link._The_application_'%0'_associated_with_the_file_type_'%1'_could_not_be_called.=无法打开链接。无法调用与文件类型_'%1'_关联的应用程序_'%0'_。
+unable_to_write_to=无法写入
Undefined_file_type=未定义的文件类型
+
Undo=撤销
+
Union=并集
+
Unknown_BibTeX_entries=未知的_BibTeX_记录
+
+unknown_edit=未知修改
+
Unknown_export_format=未知的导出格式
+
Unmark_all=撤销所有高亮标记
+
Unmark_entries=撤销选中高亮标记
+
Unmark_entry=撤销记录高亮标记
-Unsupported_version_of_class_%0\:_%1=不支持的类版本_%0\:_%1
+
+untitled=未命名
+
Up=上
+
Update_to_current_column_widths=使用当前视图中的列宽
+
Updated_group_selection=更新分组选择
Upgrade_external_PDF/PS_links_to_use_the_'%0'_field.=升级外部_PDF/PS_链接以使用_'%0'_域。
Upgrade_file=升级文件
Upgrade_old_external_file_links_to_use_the_new_feature=升级旧外部文件链接以使用新特性
-Use_regular_expression_search=使用正则表达式搜索
+
+usage=用法
Use_autocompletion_for_the_following_fields=为以下域开启自动补全功能
+
Use_other_look_and_feel=使用其它显示效果类_(look_and_feel)
+Use_regular_expression_search=使用正则表达式搜索
+
Username=用户名
+
Value_cleared_externally=内容从外部被清除
+
Value_set_externally=内容从外部被设置
+
+verify_that_LyX_is_running_and_that_the_lyxpipe_is_valid=检查_LyX_是否在运行以及_lyx_管道是否可用
+
View=视图
Vim_server_name=Vim_服务器名
+
Waiting_for_ArXiv...=等待_ArXiv...
+
Warn_about_unresolved_duplicates_when_closing_inspection_window=关闭检视窗口时警告未处理的_BibTeX_键重复情况
+
Warn_before_overwriting_existing_keys=覆盖已存在的_BibTeX_键之前发出警告
+
Warning=警告
+
Warnings=警告
+
+web_link=web_链接
+
What_do_you_want_to_do?=您希望做什么?
+
When_adding/removing_keywords,_separate_them_by=当增加/移除关键字时,使用分隔符
Will_write_XMP-metadata_to_the_PDFs_linked_from_selected_entries.=将写入_XMP_元数据到选中记录链接的_PDF_文件。
-Work_options=工作选项
+
+with=以
+
Write_BibTeXEntry_as_XMP-metadata_to_PDF.=将_BibTeX_记录作为_XMP_源数据写入到_PDF_中。
+
+Write_XMP=写入_XMP
Write_XMP-metadata=写入_XMP_元数据
Write_XMP-metadata_for_all_PDFs_in_current_database?=将_XMP_元数据写入到当前数据库中所有_PDF_文件?
-Write_XMP=写入_XMP
Writing_XMP-metadata...=正在写入_XMP_元数据...
Writing_XMP-metadata_for_selected_entries...=正在为选中记录写入_XMP_元数据...
+
Wrote_XMP-metadata=写入_XMP-元数据
+
XMP-annotated_PDF=XMP-annotated_PDF
XMP_export_privacy_settings=XMP_导出隐私设置
XMP-metadata=XMP_元数据
XMP-metadata_found_in_PDF\:_%0=PDF_中的_XMP_元数据\:_%0
+You_must_restart_JabRef_for_this_to_come_into_effect.=为使这项更改生效,您必须重启_JabRef。
You_have_changed_the_language_setting.=您已经修改了语言设置。
+
You_have_changed_the_look_and_feel_setting.=您已经修改了显示效果设置。
+
You_have_entered_an_invalid_search_'%0'.=您输入了一个非法的查询_'%0'.
+
You_must_choose_a_filename_to_store_journal_abbreviations=您必须选择一个文件名来存储期刊名称缩写
+
You_must_restart_JabRef_for_the_new_key_bindings_to_work_properly.=为使热键绑定生效,您必须重启_JabRef。
-You_must_restart_JabRef_for_this_to_come_into_effect.=为使这项更改生效,您必须重启_JabRef。
-Your_new_key_bindings_have_been_stored.=您的热键绑定已经被存储。
-abbreviation_detected=检测到缩写
-add_group=添加分组
-and=和
-and_the_class_must_be_available_in_your_classpath_next_time_you_start_JabRef.=并且下次您启动_JabRef_的时候,请确保该类在您的_classpath_中。
-any_field_that_matches_the_regular_expression_<b>%0</b>=匹配正则表达式_<b>%0</b>_的任何域
-by=为
-case_insensitive=忽略大小写
-case_sensitive=区分大小写
-change_assignment_of_entries=修改记录的组分配
-change_preamble=修改导言区_(preamble)
-crossreferenced_entries_included=包含交叉引用的记录
-cut_entries=剪切记录
-cut_entry=剪切该记录
-default=默认
-delete_entries=删除记录
-delete_entry=删除该记录
-duplicate_removal=移除重复
-empty_database=空数据库
-entries=记录
-entry=记录
-field=域
-file=文件
-filename=文件名
-for=为
-found_in_AUX_file=在_AUX_发现
-key=键值
-keys_in_database=数据库中的键值
+Your_new_key_bindings_have_been_stored.=您的热键绑定已经被存储。
The_following_fetchers_are_available\:=下面列出的是可用的抓取器\:
Could_not_find_fetcher_'%0'=无法找到抓取器_'%0'
@@ -824,13 +1405,10 @@ Import_canceled_by_user=导入操作被用户取消
Progress\:_%0_of_%1=进度\:_%0_of_%1
Error_while_fetching_from_%0=从_%0_抓取发生错误
-Fetching_Medline_by_id...=依据_id_从_Medline_抓取...
-
-Fetching_Medline_by_term...=依据_term_从_Medline_抓取...
Please_enter_a_valid_number=请输入一个合法的数字
-Please_enter_a_comma_separated_list_of_Medline_IDs_(numbers)_or_search_terms.=请输入以逗号分割的_Medline_ID_(数字)_或者_term_列表。
-
Show_search_results_in_a_window=在新窗口中显示查询结果
+Show_global_search_results_in_a_window=在窗口中显示全局搜索结果
+Search_in_all_open_databases=在所有打开的数据库中搜索
Move_file_to_file_directory?=移动文件到文件目录?
Rename_to_'%0'=重命名为_'%0'
You_have_changed_the_menu_and_label_font_size.=您已经修改了菜单和标签的字号。
@@ -857,9 +1435,6 @@ The_Guide_to_Computing_Literature=The_Guide_to_Computing_Literature
When_opening_file_link,_search_for_matching_file_if_no_link_is_defined=打开文件时,如果文件链接未定义,则自动寻找匹配的文件。
Settings_for_%0=%0_的设置
-
-
-
Mark_entries_imported_into_an_existing_database=标记导入到已有数据库的新记录
Unmark_all_entries_before_importing_new_entries_into_an_existing_database=导入新记录到数据库之前移除所有新记录的标记
@@ -869,10 +1444,9 @@ Sort_the_following_fields_as_numeric_fields=以数值方式排序下列域
Line_%0\:_Found_corrupted_BibTeX_key.=第_%0_行\:_发现错误的_BibTeX_键。
Line_%0\:_Found_corrupted_BibTeX_key_(contains_whitespaces).=第_%0_行\:_发现错误的_BibTeX_键(包含空格)。
Line_%0\:_Found_corrupted_BibTeX_key_(comma_missing).=第_%0_行\:_发现错误的_BibTeX_键(逗号丢失)。
-Finished_downloading_full_text_document=完成全文下载
Full_text_document_download_failed=下载全文失败
Update_to_current_column_order=使用当前视图中的列顺序
-
+Download_from_URL=从_URL_下载
Rename_field=重命名域
Set/clear/rename_fields=设置/清除/重命名域
Rename_field_to=重命名该域为
@@ -882,21 +1456,22 @@ You_can_only_rename_one_field_at_a_time=一次只能重命名一个域
Remove_all_broken_links=移除所有失效链接
Cannot_use_port_%0_for_remote_operation;_another_application_may_be_using_it._Try_specifying_another_port.=无法使用端口_%0_进行远程操作;该端口可能被其它应用程序占用,请使用其它端口。
+
Looking_for_full_text_document...=查找文章全文文档
Autosave=自动保存
-Prompt_before_recovering_a_database_from_an_autosave_file=用自动保存的文件恢复数据库时进行提示
-Autosave_interval_(minutes)=自动保存间隔_(分钟)
-Do_you_want_to_recover_the_database_from_the_autosave_file?=您希望用自动保存的文件恢复数据库吗?
-Recover_from_autosave=用自动保存的文件恢复
+A_local_copy_will_be_opened.=将打开一个本地拷贝.
+Autosave_local_databases=自动保存本地数据库
+Automatically_save_the_database_to=自动将数据库保存到
+Please_enter_a_valid_file_path.=请输入一个合法的文件路径.
+
Export_in_current_table_sort_order=按照当前表格排序导出
Export_entries_in_their_original_order=按照原始顺序导出记录
Error_opening_file_'%0'.=打开文件_"%0"_时发生错误
-Autosave_of_file_'%0'=文件_"%0"_的自动保存文件
-Error_opening_autosave_of_'%0'._Trying_to_load_'%0'_instead.=打开_'%0'_的自动保存文件时发生错误,尝试加载_"%0"。
Formatter_not_found\:_%0=无法找到的格式化器:_%0
Clear_inputarea=清空输入框
+
Automatically_set_file_links_for_this_entry=自动为此记录设置文件链接
Could_not_save,_file_locked_by_another_JabRef_instance.=无法保存,文件被另一个_JabRef_实例锁定。
File_is_locked_by_another_JabRef_instance.=文件被另一个_JabRef_实例锁定。
@@ -916,11 +1491,12 @@ Unable_to_create_backup=无法创建备份
Move_file_to_file_directory=移动文件到文件目录。
Rename_file_to=将文件更名为
<b>All_Entries</b>_(this_group_cannot_be_edited_or_removed)=<b>所有记录</b>(此分组无法被编辑或者删除)
+static_group=静态分组
dynamic_group=动态分组
+refines_supergroup=refines_supergroup_(翻译时没找到出处)
includes_subgroups=包含子分组
contains=包含
-
-
+search_expression=查询表达式\:
Optional_fields_2=可选域_2
Waiting_for_save_operation_to_finish=正在等待保存操作完成
@@ -958,7 +1534,6 @@ Create_entry_based_on_XMP_data=基于_XMP_数据新建一条记录
Create_blank_entry_linking_the_PDF=为_PDF_新建一条空白记录
Only_attach_PDF=只附加_PDF_到记录
Title=标题
-No_internet_connection.=无法连接到互联网。
Create_new_entry=创建新记录
Update_existing_entry=更新已有记录
Autocomplete_names_in_'Firstname_Lastname'_format_only=仅自动补全形如_'Firstname_Lastname'_格式的姓名
@@ -1034,13 +1609,11 @@ Select_document=选择文件
Edit_group_membership=编辑分组归属关系
HTML_list=HTML_列表
Click_group_to_toggle_membership_of_selected_entries=点击分组以修改选中记录的归属
-Use_EMACS_23_insertion_string=使用_EMACS_23_插入字符串
If_possible,_normalize_this_list_of_names_to_conform_to_standard_BibTeX_name_formatting=尽可能使用标准_BibTeX_名字格式规范化此列表中的名字
Could_not_open_%0=无法打开_%0
Unknown_import_format=未知的导入格式
Web_search=网页搜索
Style_selection=引用样式选择
-
No_valid_style_file_defined=没有找到合法的_style_文件
Choose_pattern=选择表达式
Use_the_BIB_file_location_as_primary_file_directory=将_BIB_文件所在位置作为文件主目录
@@ -1052,23 +1625,24 @@ JabRef_includes_a_built-in_list_of_journal_abbreviations.=JabRef_内建了一个
You_must_select_either_a_valid_style_file,_or_use_one_of_the_default_styles.=您要么选择一个可用的风格文件,要么使用一种默认风格。
This_is_a_simple_copy_and_paste_dialog._First_load_or_paste_some_text_into_the_text_input_area.<br>After_that,_you_can_mark_text_and_assign_it_to_a_BibTeX_field.=这是一个简单的拷贝粘贴对话框。首先加载或者粘贴一些文本内容到文本框中,<br>然后你可以选中文本分配到一个_BibTeX_域中。
-
This_feature_generates_a_new_database_based_on_which_entries_are_needed_in_an_existing_LaTeX_document.=此功能根据一个_LeTeX_文档,将它使用到的记录生成为一个新的数据库。
You_need_to_select_one_of_your_open_databases_from_which_to_choose_entries,_as_well_as_the_AUX_file_produced_by_LaTeX_when_compiling_your_document.=
+
First_select_entries_to_clean_up.=首先选择要清理的记录。
Cleanup_entry=清理记录
Autogenerate_PDF_Names=自动生成_PDF_名
Auto-generating_PDF-Names_does_not_support_undo._Continue?=自动生成_PDF_名操作不可撤销,是否继续?
+
Use_full_firstname_whenever_possible=尽可能使用完整的_Firstname
Use_abbreviated_firstname_whenever_possible=尽可能使用缩写的_Firstname
Use_abbreviated_and_full_firstname=混杂使用缩写和完整的_Firstname
Autocompletion_options=自动补全选项
-%0_mode=%0_模式
Autocomplete_after_following_number_of_characters=在键入多少字符时开始自动补全
Name_format_used_for_autocompletion=自动补全的姓名格式
Treatment_of_first_names=Firstname_的处理
Cleanup_entries=清理选中记录
Automatically_assign_new_entry_to_selected_groups=新增记录分配到选中分组
+%0_mode=%0_模式
Move_DOIs_from_note_and_URL_field_to_DOI_field_and_remove_http_prefix=
Make_paths_of_linked_files_relative_(if_possible)=
Rename_PDFs_to_given_filename_format_pattern=
@@ -1079,28 +1653,28 @@ No_entry_needed_a_clean_up=
One_entry_needed_a_clean_up=
%0_entries_needed_a_clean_up=
-Error_downloading_file_'%0'=
+Error_downloading_file_'%0'=下载文件_'%0'_失败
Download_failed=下载失败
Remove_selected=移除选中的
+
Group_tree_could_not_be_parsed._If_you_save_the_BibTeX_database,_all_groups_will_be_lost.=
Attach_file=附加文件
-
Setting_all_preferences_to_default_values.=
Resetting_preference_key_'%0'=
Unknown_preference_key_'%0'=
Unable_to_clear_preferences.=
Reset_preferences_(key1,key2,..._or_'all')=
-Find_unlinked_files=
-Unselect_all=
-Expand_all=
-Collapse_all=
-Opens_the_file_browser.=
+Find_unlinked_files=查找未链入的文件
+Unselect_all=取消全选
+Expand_all=展开全部
+Collapse_all=折叠全部
+Opens_the_file_browser.=打开文件浏览器.
Scan_directory=扫描目录
Searches_the_selected_directory_for_unlinked_files.=
Starts_the_import_of_BibTeX_entries.=
-Leave_this_dialog.=
+Leave_this_dialog.=离开对话框.
Create_directory_based_keywords=
Creates_keywords_in_created_entrys_with_directory_pathnames=
Select_a_directory_where_the_search_shall_start.=
@@ -1116,20 +1690,19 @@ BibTeX_entry_creation=
Unable_to_connect_to_FreeCite_online_service.=
Parse_with_FreeCite=
The_current_BibTeX_key_will_be_overwritten._Continue?=
-Overwrite_key=
+Overwrite_key=覆盖_key
Not_overwriting_existing_key._To_change_this_setting,_open_Options_->_Prefererences_->_BibTeX_key_generator=
How_would_you_like_to_link_to_'%0'?=
BibTeX_key_patterns=BibTeX_键值表达式
Changed_special_field_settings=已修改特殊字段设置
-Clear_priority=
+Clear_priority=清除优先级
Clear_rank=清除评分
Enable_special_fields=启用特殊域
Five_stars=五星
Four_stars=四星
Help_on_special_fields=特殊字段帮助
-Keywords_of_selected_entries=
-Manage_content_selectors=
-Manage_keywords=
+Keywords_of_selected_entries=选中记录的关键词
+Manage_keywords=管理关键词
No_priority_information=没有优先级信息
No_rank_information=没有评分信息
One_star=一星
@@ -1156,16 +1729,16 @@ Two_stars=二星
Update_keywords=更新关键词
Write_values_of_special_fields_as_separate_fields_to_BibTeX=将特殊字段的值以独立字段形式写入_BibTeX
You_have_changed_settings_for_special_fields.=您已经修改了特殊字段的设置.
-
%0_entries_found._To_reduce_server_load,_only_%1_will_be_downloaded.=
+A_string_with_that_label_already_exists=该标签对应的简写字串已存在
Connection_to_OpenOffice/LibreOffice_has_been_lost._Please_make_sure_OpenOffice/LibreOffice_is_running,_and_try_to_reconnect.=
+
Correct_the_entry,_and_reopen_editor_to_display/edit_source.=
Could_not_connect_to_a_running_gnuserv_process._Make_sure_that_Emacs_or_XEmacs_is_running,<BR>and_that_the_server_has_been_started_(by_running_the_command_'server-start'/'gnuserv-start').=
Could_not_connect_to_running_OpenOffice/LibreOffice.=
Make_sure_you_have_installed_OpenOffice/LibreOffice_with_Java_support.=
If_connecting_manually,_please_verify_program_and_library_paths.=
Error_message\:=
-
Created_group_"%0".=
If_a_pasted_or_imported_entry_already_has_the_field_set,_overwrite.=
Import_metadata_from_PDF=
@@ -1175,30 +1748,26 @@ To_disable_the_memory_stick_mode_rename_or_remove_the_jabref.xml_file_in_the_sam
Unable_to_connect._One_possible_reason_is_that_JabRef_and_OpenOffice/LibreOffice_are_not_both_running_in_either_32_bit_mode_or_64_bit_mode.=
Use_the_following_delimiter_character(s)\:=
When_downloading_files,_or_moving_linked_files_to_the_file_directory,_prefer_the_BIB_file_location_rather_than_the_file_directory_set_above=
+Your_style_file_specifies_the_character_format_'%0',_which_is_undefined_in_your_current_OpenOffice/LibreOffice_document.=
Your_style_file_specifies_the_paragraph_format_'%0',_which_is_undefined_in_your_current_OpenOffice/LibreOffice_document.=
Searching...=正在搜索...
You_have_selected_more_than_%0_entries_for_download._Some_web_sites_might_block_you_if_you_make_too_many_rapid_downloads._Do_you_want_to_continue?=
Confirm_selection=确认选择
-Unknown_DOI\:_'%0'.=
Add_{}_to_specified_title_words_on_search_to_keep_the_correct_case=搜索时为特殊的标题单词添加_{}_以保证大小写正确
Import_conversions=导入约定
Please_enter_a_search_string=请输入一个搜索字符串
Please_open_or_start_a_new_database_before_searching=
-An_error_occurred_while_fetching_from_ADS_(%0)\:=
-An_error_occurred_while_parsing_abstract=
-Unknown_DiVA_entry\:_'%0'.=
-Get_BibTeX_entry_from_DiVA=从_DiVA_中获取_BibTeX_记录
Log=日志
-
Canceled_merging_entries=已取消记录合并
-Format_units_by_adding_non-breaking_separators_and_keeping_the_correct_case_on_search=
+
+Format_units_by_adding_non-breaking_separators_and_keeping_the_correct_case_on_search=对单元格式化时添加非打断分隔符并在搜索时保留正确的大小写
Merge_entries=合并选中记录
Merged_entries=已合并选中记录
-Merged_entry=
+Merged_entry=已合并的记录
None=
-Parse=
+Parse=解析
Result=结果
Show_DOI_first=优先显示_DOI
Show_URL_first=优先显示_URL
@@ -1206,31 +1775,35 @@ Use_Emacs_key_bindings=使用_Emacs_快捷键映射
You_have_to_choose_exactly_two_entries_to_merge.=
Update_timestamp_on_modification=修改记录时更新时间戳
-
All_key_bindings_will_be_reset_to_their_defaults.=
+
Automatically_set_file_links=自动设置文件链接
-Continue?=
+Continue?=继续?
Resetting_all_key_bindings=
-
Hostname=主机名
Invalid_setting=非法的设置
Network=网络
Please_specify_both_hostname_and_port=
-Port=端口
+Please_specify_both_username_and_password=请完整填写用户名和密码
+
Use_custom_proxy_configuration=使用自定义_HTTP_代理
+Proxy_requires_authentication=HTTP_代理要求认证
+Attention\:_Password_is_stored_in_plain_text\!=注意\:_密码以明文形式保存\!
Clear_connection_settings=
Cleared_connection_settings.=
Rebind_C-a,_too=
+Rebind_C-f,_too=
Show_number_of_elements_contained_in_each_group=显示分组中记录数
Open_folder=打开文件夹
Searches_for_unlinked_PDF_files_on_the_file_system=
-
Export_entries_ordered_as_specified=按照下述顺序导出记录
-Export_sort_order=
+Export_sort_order=导出顺序
+Export_sorting=导出排序
Newline_separator=换行符
+
Save_entries_ordered_as_specified=以下述顺序保存记录
Save_sort_order=记录保存顺序
Show_extra_columns=显示额外的列
@@ -1239,9 +1812,8 @@ illegal_backslash_expression=
Move_to_group=移动到分组
-Clear_read_status=
+Clear_read_status=清除已读状态
Convert_to_BibLatex_format_(for_example,_move_the_value_of_the_'journal'_field_to_'journaltitle')=
-Could_not_apply_changes.=
Deprecated_fields=
Hide/show_toolbar=隐藏/显示工具栏
No_read_status_information=
@@ -1253,138 +1825,173 @@ Save_selected_as_plain_BibTeX...=选择记录另存为_BibTeX_纯文本...
Set_read_status_to_read=
Set_read_status_to_skimmed=
Show_deprecated_BibTeX_fields=
+
Show_gridlines=显示边框
Show_printed_status=显示打印状态
Show_read_status=显示已读状态
Table_row_height_padding=表格行高
-Marked_all_%0_selected_entries=标记共_%0_条选中的记录
Marked_selected_entry=标记选中的记录
-Toggle_print_status=
-Unmarked_all_%0_selected_entries=已取消标记共_%0_条选中的记录
+Marked_all_%0_selected_entries=标记共_%0_条选中的记录
Unmarked_selected_entry=已取消标记选中的记录
+Unmarked_all_%0_selected_entries=已取消标记共_%0_条选中的记录
+Toggle_print_status=
+
Unmarked_all_entries=已取消标记所有记录
Unable_to_find_the_requested_look_and_feel_and_thus_the_default_one_is_used.=无法找到要求的显示效果类,使用默认显示效果。
+Opens_JabRef's_GitHub_page=打开_JabRef_的_GitHub_主页
Could_not_open_browser.=无法打开浏览器。
-Opens_JabRef's_GitHub_page=打开_JabRef_在_GitHub_上的页面
-
-Rebind_C-f,_too=
-This_group_contains_all_entries._It_cannot_be_edited_or_removed.=这个组包含所有记录,不可以被编辑或移除。
+Please_open_%0_manually.=
+The_link_has_been_copied_to_the_clipboard.=
Open_%0_file=打开文件_%0
Cannot_delete_file=无法删除文件
-Convert=转换
-Delete_local_file=删除本地文件
File_permission_error=
-Help_on_Name_Formatting=
-Normalize_to_BibTeX_name_format=
-Path_to_%0=到_%0_管道的路径
Push_to_%0=推送到_%0
+Path_to_%0=到_%0_管道的路径
+Convert=转换
+Normalize_to_BibTeX_name_format=
+Help_on_Name_Formatting=
Add_new_file_type=
-Follow_DOI_or_URL_link_and_try_to_locate_PDF_full_text_document=
+
Left_entry=
-No_information_added=
+Right_entry=
+Use=使用
Original_entry=
Replace_original_entry=
-Right_entry=
+No_information_added=
Select_at_least_one_entry_to_manage_keywords.=选中至少一条记录来管理关键字.
-Use=使用
-Changed_type_to_'%0'_for=
-Database_'%0'_has_changed.=数据库_'%0'_已修改。
-Copy_\\cite{BibTeX_key}=复制_\\cite{BibTeX_键值}
-Copy_BibTeX_key_and_title=复制_BibTeX_键值和标题
-To_set_up,_go_to=要设置的话,请到
-Search_%0=搜索_%0
-Could_not_connect_to_%0=无法连接到_%0
-
+OpenDocument_text=OpenDocument_text
+OpenDocument_spreadsheet=OpenDocument_spreadsheet
+OpenDocument_presentation=OpenDocument_presentation
%0_image=
-%0_problem(s)_found=
-'%0'_is_not_a_valid_ADS_bibcode.=
-Accepting_the_change_replaces_the_complete_groups_tree_with_the_externally_modified_groups_tree.=
Added_entry=已添加记录
-Added_new_'%0'_entry.=已添加新_'%0'_记录。
-Deleted_entry=已删除记录
-Discard_changes=放弃修改
-Donate_to_JabRef=捐款给_JabRef
-Export_with_selected_format=使用选中的格式导出
-Field_is_missing=
-File_rename_failed_for_%0_entries.=
-Filled=
-From_import=
-Invalid_DOI\:_'%0'.=不合法的_DOI\:
-Keep_left=保留左侧
-Keep_merged_entry_only=只保留合并后的记录
-Keep_right=保留右侧
-Merged_BibTeX_source_code=已合并_BibTeX_源代码
Modified_entry=已修改记录
+Deleted_entry=已删除记录
Modified_groups_tree=已修改分组树
-Multiple_entries_selected._Do_you_want_to_change_the_type_of_all_these_to_'%0'?=已选中多条记录,您希望将所有选中记录都修改为_%0_类型?
-No_problems_found.=没有发现问题。
-Old_entry=
-OpenDocument_presentation=OpenDocument_presentation
-OpenDocument_spreadsheet=OpenDocument_spreadsheet
-OpenDocument_text=OpenDocument_text
-Please_move_the_file_manually_and_link_in_place.=
-Print_entry_preview=打印记录预览
-Really_delete_the_%0_selected_entries?=确定删除选中的_%0_条记录?
-Really_delete_the_selected_entry?=确定删除选中的记录?
Removed_all_groups=已移除所有分组
-Return_to_JabRef=返回_JabRef
-Save_changes=保存修改
+Accepting_the_change_replaces_the_complete_groups_tree_with_the_externally_modified_groups_tree.=
Select_export_format=选择导出格式
+Return_to_JabRef=返回_JabRef
+Please_move_the_file_manually_and_link_in_place.=
+Could_not_connect_to_%0=无法连接到_%0
Warning\:_%0_out_of_%1_entries_have_undefined_BibTeX_key.=警告:_%1_条记录中有_%0_条包含未定义的_BibTeX_键值。
-large_capitals_are_not_masked_using_curly_brackets_{}=
-link_should_refer_to_a_correct_file_path=链接应该指向一个正确的文件路径
-modify_group=修改分组
-move_group=移动分组
-nested_AUX_files=nested_AUX_文件
-new=新建
-no_base-BibTeX-file_specified=没有指定_base-BibTeX-文件
-no_database_generated=没有生成数据库
-not=非
-not_found=无法找到
occurrence=
-occurrences=次
-or=或
-pairs_processed=已处理记录对
-paste_entries=粘贴多条记录
-paste_entry=粘贴记录
-paste_text_here=此处编辑文本
-plain_text=纯文本
-refines_supergroup=refines_supergroup_(翻译时没找到出处)
-regular_expression=正则表达式
-remove_group_(keep_subgroups)=移除分组(保留子分组)
-remove_group_and_subgroups=移除分组和子分组
-resolved=已解决
-search_expression=查询表达式\:
-should_contain_a_four_digit_number=应该包含一个_4_位数字
-should_contain_a_protocol=
-should_contain_a_valid_page_number_range=应该包含一个合法的页码范围
-should_end_with_a_name=
+Added_new_'%0'_entry.=已添加新_'%0'_记录。
+Multiple_entries_selected._Do_you_want_to_change_the_type_of_all_these_to_'%0'?=已选中多条记录,您希望将所有选中记录都修改为_%0_类型?
+Changed_type_to_'%0'_for=
+Really_delete_the_selected_entry?=确定删除选中的记录?
+Really_delete_the_%0_selected_entries?=确定删除选中的_%0_条记录?
+Keep_merged_entry_only=只保留合并后的记录
+Keep_left=保留左侧
+Keep_right=保留右侧
+Old_entry=
+From_import=
+No_problems_found.=没有发现问题。
+%0_problem(s)_found=
+Save_changes=保存修改
+Discard_changes=放弃修改
+Database_'%0'_has_changed.=数据库_'%0'_已修改。
+Print_entry_preview=打印记录预览
+Copy_\\cite{BibTeX_key}=复制_\\cite{BibTeX_键值}
+Copy_BibTeX_key_and_title=复制_BibTeX_键值和标题
+File_rename_failed_for_%0_entries.=
+To_set_up,_go_to=要设置的话,请到
+Merged_BibTeX_source_code=已合并_BibTeX_源代码
+Invalid_DOI\:_'%0'.=不合法的_DOI\:
should_start_with_a_name=
-sort_subgroups=排序子分组
-source_edit=源代码编辑
-static_group=静态分组
-the_field_<b>%0</b>=域_<b>%0</b>
-type=类型
-unable_to_write_to=无法写入
+should_end_with_a_name=
unexpected_closing_curly_bracket=
unexpected_opening_curly_bracket=
-unknown_edit=未知修改
-untitled=未命名
-usage=用法
+capital_letters_are_not_masked_using_curly_brackets_{}=
+should_contain_a_four_digit_number=应该包含一个_4_位数字
+should_contain_a_valid_page_number_range=应该包含一个合法的页码范围
+Filled=
+Field_is_missing=
+Search_%0=搜索_%0
+
+Search_results_in_all_databases_for_%0=在所有数据库中搜索_%0_的结果
+Search_results_in_database_%0_for_%1=在数据库_%0_中搜索_%1_的结果
+Search_globally=全局搜索
+No_results_found.=没有找到结果.
+Found_%0_results.=找到_%0_条结果.
+Advanced_search_active.=高级搜索行为。
+Normal_search_active.=普通搜索行为。
+plain_text=纯文本
+This_search_contains_entries_in_which_any_field_contains_the_regular_expression_<b>%0</b>=这次搜索的结果记录符合条件:记录的任意域包含正则表达式_<b>%0</b>
+This_search_contains_entries_in_which_any_field_contains_the_term_<b>%0</b>=这次搜索的结果记录符合条件:记录的任意域包含词组_<b>%0</b>
+This_search_contains_entries_in_which=这次搜索的结果记录符合条件:
+
+Unable_to_autodetect_OpenOffice/LibreOffice_installation._Please_choose_the_installation_directory_manually.=自动检测_OpenOffice/LibreOffice_安装位置失败,请手动指定安装目录。
+JabRef_no_longer_supports_'ps'_or_'pdf'_fields.<br>File_links_are_now_stored_in_the_'file'_field_and_files_are_stored_in_an_external_file_directory.<br>To_make_use_of_this_feature,_JabRef_needs_to_upgrade_file_links.<br><br>=JabRef_不再支持_"ps"_或_"pdf"_域。<br>新版本将文件链接保存在_"file"_域中,文件保存在外部文件目录中。<br>为了启用新的特性,JabRef_需要升级文件链接。<br><br>
+This_database_uses_outdated_file_links.=这个数据库使用了过期的文件链接。
+
+Clear_search=清除搜索
+Close_database=关闭数据库
+Close_entry_editor=关闭记录编辑器
+Decrease_table_font_size=减小表格字号
+Entry_editor,_next_entry=记录编辑器,下一条记录
+Entry_editor,_next_panel=记录编辑器,下一个面板
+Entry_editor,_next_panel_2=记录编辑器,下一个面板_2
+Entry_editor,_previous_entry=记录编辑器,上一条记录
+Entry_editor,_previous_panel=记录编辑器,上一个面板
+Entry_editor,_previous_panel_2=记录编辑器,上一个面板_2
+Entry_editor,_store_field=记录编辑器,保存域内容
+File_list_editor,_move_entry_down=文件列表编辑器,下移记录
+File_list_editor,_move_entry_up=文件列表编辑器,上移记录
+Focus_entry_table=激活记录列表
+Import_into_current_database=导入当前数据库
+Import_into_new_database=导入新建数据库
+Increase_table_font_size=增大表格字号
+New_article=新建_article
+New_book=新建_book
+New_entry=新建记录
+New_from_plain_text=从纯文本新建
+New_inbook=新建_inbook
+New_mastersthesis=新建_mastersthesis
+New_phdthesis=新建_phdthesis
+New_proceedings=新建_proceedings
+New_unpublished=新建_unpublished
+Next_tab=下个标签
+Preamble_editor,_store_changes=导言编辑器,保存修改
+Previous_tab=上一标签
+Push_to_application=推送到应用
+Refresh_OpenOffice/LibreOffice=刷新_penOffice/LibreOffice
+Resolve_duplicate_BibTeX_keys=处理重复的_BibTeX_键值
+Save_all=保存所有
+String_dialog,_add_string=简写字串对话框,添加简写字串
+String_dialog,_remove_string=简写字串对话框,删除简写字串
+Synchronize_files=同步文件
+Unabbreviate=展开缩写
+should_contain_a_protocol=
+Copy_preview=拷贝预览
+Automatically_setting_file_links=自动设置文件链接
+Regenerating_BibTeX_keys_according_to_metadata=基于_metadata_重新生成_BibTeX_键值
+No_meta_data_present_in_BIB_file._Cannot_regenerate_BibTeX_keys=在_BIB_file_中没有找到_meta_data,无法重建_BibTeX_key
+Regenerate_all_keys_for_the_entries_in_a_BibTeX_file=重新生成_BibTeX_文件中所有记录的键值
+Show_debug_level_messages=显示调试级别消息
+Default_bibliography_mode=默认的参考文献模式
+New_%0_database_created.=成功新建数据库_%0.
+Show_only_preferences_deviating_from_their_default_value=只显示与默认值不同的首选项
+default=默认
+key=键值
+type=类型
value=值
-verify_that_LyX_is_running_and_that_the_lyxpipe_is_valid=检查_LyX_是否在运行以及_lyx_管道是否可用
-web_link=web_链接
-with=以
-wrong_entry_type_as_proceedings_has_page_numbers=
-Your_style_file_specifies_the_character_format_'%0',_which_is_undefined_in_your_current_OpenOffice/LibreOffice_document.=
+Show_preferences=列表显示首选项
+Save_actions=保存时附加操作
+Enable_save_actions=启用保存附加操作
+
+Other_fields=其它域
+Show_remaining_fields=显示其它的域
+link_should_refer_to_a_correct_file_path=链接应该指向一个正确的文件路径
+abbreviation_detected=检测到缩写
+wrong_entry_type_as_proceedings_has_page_numbers=
Abbreviate_journal_names=缩写期刊名
Abbreviating...=正在缩写...
Adding_fetched_entries=正在添加抓取的记录
@@ -1396,38 +2003,29 @@ Unabbreviate_journal_names=展开期刊名缩写
Unabbreviating...=正在展开缩写...
Usage=用法
+
+Adds_{}_brackets_around_acronyms,_month_names_and_countries_to_preserve_their_case.=为_%s_里的缩略语、月份和国家添加花括号_{}_以保持大小写不变。
Are_you_sure_you_want_to_reset_all_settings_to_default_values?=您确认希望将所有设置重置为默认值吗?
Reset_preferences=重置所有首选项
-
Ill-formed_entrytype_comment_in_BIB_file=
+
+Move_linked_files_to_default_file_directory_%0=移动链接的文件到默认文件目录_%0
+
Clipboard=剪贴板
Could_not_paste_entry_as_text\:=
Do_you_still_want_to_continue?=是否继续?
This_action_will_modify_the_following_field(s)_in_at_least_one_entry_each\:=
This_could_cause_undesired_changes_to_your_entries.=
-
-Disable_highlight_groups_matching_entries=
Run_field_formatter\:=
-
-Adds_{}_brackets_around_acronyms,_month_names_and_countries_to_preserve_their_case.=为_%s_里的缩略语、月份和国家添加花括号_{}_以保持大小写不变。
-Converts_units_to_LaTeX_formatting.=
-Does_nothing.=什么都没干。
-
-
Table_font_size_is_%0=表格字号是_%0
-Allow_overwriting_existing_links.=允许覆盖已有的链接。
-Do_not_overwrite_existing_links.=不要覆盖已有的链接。
-
-Move_linked_files_to_default_file_directory_%0=移动链接的文件到默认文件目录_%0
-
-Internal_style=
-Add_style_file=
+%0_import_canceled=%0_导入被取消
+Internal_style=内部样式
+Add_style_file=添加样式文件
Are_you_sure_you_want_to_remove_the_style?=
Current_style_is_'%0'=
-Remove_style=
+Remove_style=移除样式
Select_one_of_the_available_styles_or_add_a_style_file_from_disk.=
You_must_select_a_valid_style_file.=
-
Reload=刷新
Capitalize=
@@ -1438,9 +2036,11 @@ Changes_all_letters_to_upper_case.=将所有字母改为大写.
Changes_the_first_letter_of_all_words_to_capital_case_and_the_remaining_letters_to_lower_case.=将每个单词的第一个字母改为大写,_其它字母改为小写.
Cleans_up_LaTeX_code.=清理_LaTeX_代码
Converts_HTML_code_to_LaTeX_code.=将_HTML_代码转换为_LaTeX_代码。
+Converts_HTML_code_to_Unicode.=
Converts_LaTeX_encoding_to_Unicode_characters.=将_LaTeX_编码转换为_Unicode_字符。
Converts_Unicode_characters_to_LaTeX_encoding.=将_Unicode_字符转换为_LaTeX_编码
Converts_ordinals_to_LaTeX_superscripts.=将序号转换成_LaTeX_上标。
+Converts_units_to_LaTeX_formatting.=
HTML_to_LaTeX=HTML_转_LaTeX
LaTeX_cleanup=清理_LaTeX
LaTeX_to_Unicode=LaTeX_转_Unicode
@@ -1464,16 +2064,13 @@ Title_case=首字母大写
Unicode_to_LaTeX=
Units_to_LaTeX=
Upper_case=改为大写
+Does_nothing.=什么都没干。
Identity=
-
Clears_the_field_completely.=完全清除这个字段。
Directory_not_found=目录未找到
Main_file_directory_not_set\!=未设置主文件目录\!
-
This_operation_requires_exactly_one_item_to_be_selected.=这个操作仅限对选中的一条记录进行。
-
Importing_in_%0_format=正在以_%0_格式导入
-
Female_name=
Female_names=
Male_name=
@@ -1525,90 +2122,68 @@ Plain_text=
Show_diff=
character=
word=
-
Show_symmetric_diff=
HTML_encoded_character_found=
-
booktitle_ends_with_'conference_on'=
+
All_external_files=
OpenOffice/LibreOffice_integration=
incorrect_control_digit=
incorrect_format=
-
-Expected_"%0"_to_contain_whitespace=
-Syntax_error_in_regular-expression_pattern=
-
Copy_version_to_clipboard=
Copied_version_to_clipboard=
+
BibTeX_key=
Message=
-
-Get_fulltext=
-
-Download_from_URL=
-
Decryption_not_supported.=
Cleared_'%0'_for_%1_entries=
Set_'%0'_to_'%1'_for_%2_entries=
Toggled_'%0'_for_%1_entries=
-Check_for_updates=
-Download_update=
-New_version_available=
-Installed_version=
-Remind_me_later=
-Ignore_this_update=
-Could_not_connect_to_the_update_server.=
-Please_try_again_later_and/or_check_your_network_connection.=
-To_see_what_is_new_view_the_changelog.=
-A_new_version_of_JabRef_has_been_released.=
-JabRef_is_up-to-date.=
-Latest_version=
-
-Please_open_%0_manually.=
-
-The_link_has_been_copied_to_the_clipboard.=
-
-Online_help_forum=
-
+Check_for_updates=检查更新
+Download_update=下载更新
+New_version_available=发现新版本
+Installed_version=当前版本
+Remind_me_later=稍后提醒我
+Ignore_this_update=跳过这次更新
+Could_not_connect_to_the_update_server.=无法连接到更新服务器.
+Please_try_again_later_and/or_check_your_network_connection.=请重试并检查你的互联网连接.
+To_see_what_is_new_view_the_changelog.=查看更新内容.
+A_new_version_of_JabRef_has_been_released.=发现新版本_JabRef.
+JabRef_is_up-to-date.=JabRef_是最新版本.
+Latest_version=最新版本
+Online_help_forum=在线讨论区
Custom=
-Converts_HTML_code_to_Unicode.=
+Export_cited=
+Unable_to_generate_new_database=
-Open_console=
-Use_default_terminal_emulator=
-Execute_command=
-Note\:_Use_the_placeholder_%0_for_the_location_of_the_opened_database_file.=
+Open_console=打开终端程序
+Use_default_terminal_emulator=使用默认的模拟终端
+Execute_command=执行命令
+Note\:_Use_the_placeholder_%0_for_the_location_of_the_opened_database_file.=注意\:_使用_%0_占位符来表示当前打开的数据库文件位置.
Executing_command_\"%0\"...=
Error_occured_while_executing_the_command_\"%0\".=
-
Reformat_ISSN=
-Unable_to_generate_new_database=
-
-Export_cited=
Countries_and_territories_in_English=
Electrical_engineering_terms=
Enabled=
Internal_list=
+Manage_protected_terms_files=
Months_and_weekdays_in_English=
The_text_after_the_last_line_starting_with_\#_will_be_used=
-
Add_protected_terms_file=
Are_you_sure_you_want_to_remove_the_protected_terms_file?=
Remove_protected_terms_file=
-
-Manage_protected_terms_files=
-
Add_selected_text_to_list=
Add_{}_around_selected_text=
Format_field=
New_protected_terms_file=
-
change_field_%0_of_entry_%1_from_%2_to_%3=
change_key_from_%0_to_%1=
change_string_content_%0_to_%1=
@@ -1618,36 +2193,29 @@ insert_entry_%0=
insert_string_%0=
remove_entry_%0=
remove_string_%0=
-
undefined=
-
Cannot_get_info_based_on_given_%0\:_%1=
-
Get_BibTeX_data_from_%0=从_%0_中获取_BibTeX_数据
No_%0_found=
Entry_from_%0=
-
Merge_entry_with_%0_information=
Updated_entry_with_info_from_%0=已根据_%0_更新记录
Connection=
+Connecting...=
Host=
+Port=端口
Database=
User=
+Connect=连接
Connection_error=
-Driver_error=
Connection_to_%0_server_established.=
Required_field_"%0"_is_empty.=
-
%0_driver_not_available.=
-
The_connection_to_the_server_has_been_terminated.=
-
Connection_lost.=
Reconnect=
Work_offline=
-
Working_offline.=
-
Update_refused.=
Update_refused=
Local_entry=
@@ -1658,7 +2226,12 @@ Local_version\:_%0=
Shared_version\:_%0=
Please_merge_the_shared_entry_with_yours_and_press_"Merge_entries"_to_resolve_this_problem.=
Canceling_this_operation_will_leave_your_changes_unsynchronized._Cancel_anyway?=
-The_BibEntry_you_currently_work_on_has_been_deleted_on_the_shared_side._Hit_"Keep"_to_recover_the_entry.=
+Shared_entry_is_no_longer_present=
+The_BibEntry_you_currently_work_on_has_been_deleted_on_the_shared_side.=
+You_can_restore_the_entry_using_the_"Undo"_operation.=
+Remember_password?=
+You_are_already_connected_to_a_database_using_entered_connection_details.=
+
Cannot_cite_entries_without_BibTeX_keys._Generate_keys_now?=
New_technical_report=
@@ -1668,18 +2241,14 @@ Protected_terms_file=
Style_file=
Open_OpenOffice/LibreOffice_connection=
-
You_must_enter_at_least_one_field_name=
-
-
Non-ASCII_encoded_character_found=
-
-Toggle_web_search_interface=
-Background_color_for_resolved_fields=
-Color_code_for_resolved_fields=
-%0_files_found=
-%0_of_%1=
-One_file_found=
+Toggle_web_search_interface=切换网页搜索面板
+Background_color_for_resolved_fields=resolved_域背景颜色
+Color_code_for_resolved_fields=使用颜色区分_resolved_域
+%0_files_found=找到_%0_个文件
+%0_of_%1=%1_中的_%0
+One_file_found=找到一个文件
The_import_finished_with_warnings\:=
There_was_one_file_that_could_not_be_imported.=
There_were_%0_files_which_could_not_be_imported.=
@@ -1687,13 +2256,59 @@ There_were_%0_files_which_could_not_be_imported.=
Migration_help_information=
Entered_database_has_obsolete_structure_and_is_no_longer_supported.=
However,_a_new_database_was_created_alongside_the_pre-3.6_one.=
-
Click_here_to_learn_about_the_migration_of_pre-3.6_databases.=
-
-Connecting...=
-Opens_JabRef's_Facebook_page=
-Opens_JabRef's_blog=
-Opens_JabRef's_website=
-
+Opens_JabRef's_Facebook_page=打开_JabRef_的_Facebook_主页
+Opens_JabRef's_blog=打开_JabRef_的博客
+Opens_JabRef's_website=打开_JabRef_的主页
Opens_a_link_where_the_current_development_version_can_be_downloaded=
See_what_has_been_changed_in_the_JabRef_versions=
+Referenced_BibTeX_key_does_not_exist=
+Finished_downloading_full_text_document_for_entry_%0.=
+Full_text_document_download_failed_for_entry_%0.=
+Look_up_full_text_documents=
+You_are_about_to_look_up_full_text_documents_for_%0_entries.=
+last_four_nonpunctuation_characters_should_be_numerals=
+shared=
+should_contain_an_integer_or_a_literal=
+should_have_the_first_letter_capitalized=
+
+ID=ID
+ID_type=ID_类型
+ID-based_entry_generator=
+Fetcher_'%0'_did_not_find_an_entry_for_id_'%1'.=
+
+Select_first_entry=
+Select_last_entry=
+
+Invalid_ISBN\:_'%0'.=
+should_be_an_integer_or_normalized=
+should_be_normalized=
+
+Empty_search_ID=
+The_given_search_ID_was_empty.=
+Copy_BibTeX_key_and_link=
+empty_BibTeX_key=
+BibLaTeX_field_only=
+
+Error_while_generating_fetch_URL=
+Error_while_parsing_ID_list=
+Unable_to_get_PubMed_IDs=
+Backup_found=
+A_backup_file_for_'%0'_was_found.=
+This_could_indicate_that_JabRef_did_not_shut_down_cleanly_last_time_the_file_was_used.=
+Do_you_want_to_recover_the_database_from_the_backup_file?=
+Firstname_Lastname=
+
+Recommended_for_%0=
+This_might_be_caused_by_reaching_the_traffic_limitation_of_Google_Scholar_(see_'Help'_for_details).=
+
+Problem_downloading_from_%1=
+
+File_directory_pattern=
+Update_with_bibliographic_information_from_the_web=
+
+Could_not_find_any_bibliographic_information.=
+BibTeX_key_%0_deviates_from_generated_key_%1=
+DOI_%0_is_invalid=
+
+Jump_to_entry=
diff --git a/src/main/resources/l10n/Menu_da.properties b/src/main/resources/l10n/Menu_da.properties
index 7bed336..e999722 100644
--- a/src/main/resources/l10n/Menu_da.properties
+++ b/src/main/resources/l10n/Menu_da.properties
@@ -1,6 +1,7 @@
#!
-#! created/edited by Popeye version 0.54 (popeye.sourceforge.net)
-#! encoding:ISO-8859-1
+#! created/edited by Popeye version 0.55 (github.com/JabRef/popeye)
+#! encoding:UTF-8
+
Abbreviate_journal_names_(ISO)=Forkort_tidsskriftsnavn_(ISO)
Abbreviate_journal_names_(MEDLINE)=Forkort_tidsskriftsnavn_(MEDLINE)
About_JabRef=Om_&JabRef
@@ -14,75 +15,98 @@ Customize_entry_types=&Tilpas_posttyper
Cut=&Klip
Database_properties=Egenskaber_for_database
Edit=&Rediger
+# Bibtex
Edit_entry=&Rediger_post
Edit_preamble=Rediger_præ&ambel
Edit_strings=Rediger_&strenge
Export=&Eksporter
Export_selected_entries_to_clipboard=Eksporter_valgte_poster_til_udklipsholderen
+
+# Menu names
File=&Fil
Find_duplicates=Søg_efter_&dubletter
Help=&Hjælp
Highlight_groups_matching_all_selected_entries=Fremhæv_grupper_som_indeholder_alle_valgte_poster
Highlight_groups_matching_any_selected_entry=Fremhæv_grupper_som_indeholder_mindst_en_af_de_valgte_poster
+Disable_highlight_groups_matching_entries=Deaktiver_fremhævningen_af_grupperede_indgange
+
+# Help
Online_help=
-Manage_content_selectors=Opsæt_ordlister
+Donate_to_JabRef=Doner_til_JabRef
Manage_custom_exports=Administrer_eksterne_&eksportfiltre
Manage_custom_imports=Administrer_eksterne_i&mportfiltre
Manage_journal_abbreviations=&Administrer_tidsskriftsforkortelser
Mark_entries=&Mærk_poster
+# File menu
+New_%0_database=Ny_%0-database
+# Menu BibTeX (BibTeX)
New_entry=N&y_post
New_entry_by_type...=&Ny_post...
New_entry_from_plain_text=Ny_&post_fra_ren_tekst
New_subdatabase_based_on_AUX_file=Ny_deldatabase_baseret_på_AU&X-fil
+# View
Next_tab=&Næste_faneblad
Open_database=&Åbn_database
Open_URL_or_DOI=Åbn_&URL_eller_DOI
-Open_shared_database=
+Connect_to_shared_database=
Open_terminal_here=Åben_terminal_her
Options=&Opsætning
Paste=&Indsæt
+# Options
Preferences=&Indstillinger
Previous_tab=&Forrige_faneblad
Quit=&Afslut
-Recent_files=&Seneste_filer
+Recent_databases=&Seneste_filer
Redo=&Gentag
Replace_string=&Erstat_streng
Save_database=&Gem_database
Save_database_as...=Ge&m_database_som_...
Save_selected_as...=Gem_&valgte_poster_som_...
+# Tools
Search=&Søg
Select_all=&Vælg_alle
Set_up_general_fields=Administrer_&generelle_felter
Show_error_console=Vis_fejlkonsol
Sort_tabs=Sorter_faneblade
-Switch_preview_layout=&Skift_layout_på_forhåndsvisning
+Next_preview_layout=
+Previous_preview_layout=
+# Export menu
Toggle_entry_preview=&Vis/skjul_forhåndsvisning
Toggle_groups_interface=Vis/skjul_&grupperingspanel
Tools=F&unktioner
Unabbreviate_journal_names=Ekspander_tidsskriftsnavn
+# Edit
Undo=&Fortryd
+Mark_specific_color=M&ærk_med_specifik_farve
Unmark_all=Fjern_mærkning_fra_&alle
Unmark_entries=F&jern_mærkning
View=&Vis
Import_into_new_database=Importer_til_ny_database
Import_into_current_database=Importer_til_den_aktive_database
+
+Switch_to_%0_mode=Skift_til_%0-mode
Push_entries_to_external_application_(%0)=Send_poster_til_ekstern_applikation_(%0)
Pull_changes_from_shared_database=
Write_XMP-metadata_to_PDFs=Skriv_XMP-metadata_til_PDF-filer
+
Export_selected_entries=Eksporter_valgte_poster
+
Save_all=Gem_alle
+
Manage_external_file_types=Administrer_eksterne_&filtyper
+
Open_file=Åbn_fil
+
Focus_entry_table=Fokus_på_hovedtabel
+
Increase_table_font_size=For&øg_fontstørrelse_i_hovedtabel
Decrease_table_font_size=For&mindsk_fontstørrelse_i_hovedtabel
Forward=Frem
Back=Tilbage
-Look_up_full_text_document=&Hent_tekstdokument
+Look_up_full_text_documents=
Set/clear/rename_fields=Udfyld/ryd/omdøb_felter
-Mark_specific_color=M&ærk_med_specifik_farve
Resolve_duplicate_BibTeX_keys=Udred_dublerede_BibTeX-nøgler
Copy_BibTeX_key_and_title=Kopier_BibTeX-nøgle_og_titel
@@ -96,26 +120,17 @@ Hide/show_toolbar=Gem/vis_værktøjslinje
Fork_me_on_GitHub=Fork_mig_på_GitHub
Save_selected_as_plain_BibTeX...=Gem_det_markerede_som_rå_BibTeX...
-Donate_to_JabRef=Doner_til_JabRef
Groups=Gruppering
Delete_entry=Slet_post
-
-Switch_to_%0_mode=Skift_til_%0-mode
Check_integrity=Tjek_integritet
Quality=Kvalitet
-
-New_%0_database=Ny_%0-database
-
-Disable_highlight_groups_matching_entries=Deaktiver_fremhævningen_af_grupperede_indgange
-
Online_help_forum=
-
Manage_protected_terms=
-
Website=
Blog=
JabRef_resources=
-
Development_version=
View_change_log=
+Copy_BibTeX_key_and_link=
+Copy_DOI_url=
diff --git a/src/main/resources/l10n/Menu_de.properties b/src/main/resources/l10n/Menu_de.properties
index 6226dd6..427c34b 100644
--- a/src/main/resources/l10n/Menu_de.properties
+++ b/src/main/resources/l10n/Menu_de.properties
@@ -1,219 +1,136 @@
#!
-#! created/edited by Popeye version 0.55 (popeye.sourceforge.net)
-#! encoding:ISO-8859-1
-
-Abbreviate_journal_names_(ISO)=Zeitschriftentitel_abk\u00fcrzen_(&ISO)
-
-Abbreviate_journal_names_(MEDLINE)=Zeitschriftentitel_abk\u00fcrzen_(&MEDLINE)
-
-About_JabRef=\u00dcber_&JabRef
-
-Append_database=Datei_&anh\u00e4ngen
+#! created/edited by Popeye version 0.55 (github.com/JabRef/popeye)
+#! encoding:UTF-8
+Abbreviate_journal_names_(ISO)=Zeitschriftentitel_abkürzen_(&ISO)
+Abbreviate_journal_names_(MEDLINE)=Zeitschriftentitel_abkürzen_(&MEDLINE)
+About_JabRef=Über_&JabRef
+Append_database=Datenbank_&anhängen
Autogenerate_BibTeX_keys=&BibTeX-Keys_automatisch_generieren
-
-
-Close_database=Datei_s&chlie\u00dfen
-
+Close_database=Datenbank_s&chließen
Copy=&Kopieren
-
Copy_\\cite{BibTeX_key}=\\&cite{BibTeX_key}_kopieren
-
Copy_BibTeX_key=&BibTeX_key_kopieren
-
-
-
Customize_entry_types=Eintragstypen_&anpassen
-
Cut=Aus&schneiden
-
-Database_properties=Ei&genschaften_der_Datei
-
-
+Database_properties=Ei&genschaften_der_Datenbank
Edit=&Bearbeiten
-
# Bibtex
Edit_entry=Eintrag_&bearbeiten
-
-Edit_preamble=&Pr\u00e4ambel_bearbeiten
-
+Edit_preamble=&Prämbel_bearbeiten
Edit_strings=&Strings_bearbeiten
-
Export=&Exportieren
-
-Export_selected_entries_to_clipboard=&Ausgw\u00e4hlte_Eintr\u00e4ge_in_die_Zwischenablage_kopieren
-
+Export_selected_entries_to_clipboard=&Ausgwählte_Einträge_in_die_Zwischenablage_kopieren
# Menu names
File=&Datei
-
-
-Find_duplicates=Nach_&doppelten_Eintr\u00e4gen_suchen
-
+Find_duplicates=Nach_&doppelten_Einträgen_suchen
Help=&Hilfe
-
-
-Highlight_groups_matching_all_selected_entries=Gruppen_hervorheben,_die_alle_ausgew\u00e4hlten_Eintr\u00e4ge_enthalten
-Highlight_groups_matching_any_selected_entry=Gruppen_hervorheben,_die_einen_der_ausgew\u00e4hlten_Eintr\u00e4ge_enthalten
-
-
-
-
-
+Highlight_groups_matching_all_selected_entries=Gruppen_hervorheben,_die_alle_ausgewählten_Einträge_enthalten
+Highlight_groups_matching_any_selected_entry=Gruppen_hervorheben,_die_einen_der_ausgewählten_Einträge_enthalten
+Disable_highlight_groups_matching_entries=Keine_Gruppen_hervorheben
# Help
Online_help=Online_Hilfe
-
-
-Manage_content_selectors=W&ortauswahl_verwalten
-
+Donate_to_JabRef=An_JabRef_spenden
Manage_custom_exports=Externe_Exportfilter_&verwalten
-
Manage_custom_imports=Externe_&Importfilter_verwalten
-
-Manage_journal_abbreviations=&Abk\u00fcrzungen_der_Zeitschriften_verwalten
-
-Mark_entries=Eintr\u00e4ge_&markieren
-
+Manage_journal_abbreviations=&Abkürzungen_der_Zeitschriften_verwalten
+Mark_entries=Einträge_&markieren
# File menu
-
+New_%0_database=Neue_%0_Datenbank
# Menu BibTeX (BibTeX)
New_entry=&Neuer_Eintrag
-
New_entry_by_type...=Neuer_&Eintrag...
-
New_entry_from_plain_text=Neuer_Eintrag_aus_&Klartext
-
-New_subdatabase_based_on_AUX_file=&Neue_Teildatei_aus_AUX-Datei
-
+New_subdatabase_based_on_AUX_file=&Neue_Teildatenbank_aus_AUX-Datei
# View
-Next_tab=&N\u00e4chster_Tab
-
-Open_database=Datei_\u00f6&ffnen
-
-
-Open_URL_or_DOI=&URL_oder_DOI_\u00f6ffnen
-
-Open_shared_database=Entfernte_Datenbak_öffnen
-
-Open_terminal_here=Konsole_hier_\u00f6ffnen
-
+Next_tab=&Nächster_Tab
+Open_database=Datenbank_öffnen
+Open_URL_or_DOI=&URL_oder_DOI_öffnen
+Connect_to_shared_database=Geteilte_Datenbak_öffnen
+Open_terminal_here=Konsole_hier_öffnen
Options=&Optionen
-
-Paste=&Einf\u00fcgen
-
+Paste=&Einfügen
# Options
Preferences=&Einstellungen
-
Previous_tab=&Vorheriger_Tab
-
Quit=&Beenden
-
-Recent_files=&Zuletzt_ge\u00f6ffnete_Dateien
-
+Recent_databases=&Zuletzt_geöffneten_Datenbanken
Redo=&Wiederholen
-
Replace_string=E&rsetzen
-
-Save_database=Datei_&speichern
-
-Save_database_as...=Datei_speichern_&unter_...
-
+Save_database=Datenbank_&speichern
+Save_database_as...=Datenbank_speichern_&unter_...
Save_selected_as...=Aus&wahl_speichern_unter_...
-
-
# Tools
Search=&Suchen
-
-
-Select_all=&Alle_ausw\u00e4hlen
-
+Select_all=&Alle_auswählen
Set_up_general_fields=Allgemeine_&Felder_festlegen
-
Show_error_console=Fehlerkonsole_anzeigen
-
Sort_tabs=Tabs_&sortieren
-
-Switch_preview_layout=&Layout_der_Vorschau_wechseln
-
-
+Next_preview_layout=Nächstes_Vorschaulayout
+Previous_preview_layout=Vorheriges_Vorschaulayout
# Export menu
-
Toggle_entry_preview=&Eintragsvorschau_ein-/ausblenden
-
Toggle_groups_interface=&Gruppenansicht_ein-/ausblenden
-
Tools=&Extras
-
-Unabbreviate_journal_names=&Abk\u00fcrzung_der_Zeitschriften_aufheben
-
+Unabbreviate_journal_names=&Abkürzung_der_Zeitschriften_aufheben
# Edit
-Undo=&R\u00fcckg\u00e4ngig
-
-Unmark_all=S\u00e4m&tliche_Markierungen_aufheben
-
+Undo=&Rückgängig
+Mark_specific_color=Mit_bestimmter_&Farbe_markieren
+Unmark_all=Säm&tliche_Markierungen_aufheben
Unmark_entries=Markierung_a&ufheben
-
View=&Ansicht
Import_into_new_database=&Importieren_in_neue_Datenbank
Import_into_current_database=Importieren_in_aktuelle_&Datenbank
-
-Push_entries_to_external_application_(%0)=&Eintr\u00e4ge_in_externe_Anwendung_einf\u00fcgen_(%0)
-Pull_changes_from_shared_database=Entfernte_Änderungen_beziehen
+Switch_to_%0_mode=In_den_%0-Modus_wechseln
+Push_entries_to_external_application_(%0)=&Einträge_in_externe_Anwendung_einfügen_(%0)
+Pull_changes_from_shared_database=Änderungen_der_geteilten_Datenbank_beziehen
Write_XMP-metadata_to_PDFs=&XMP-Metadaten_in_PDFs_schreiben
+Export_selected_entries=Ausgewählte_Einträge_exportieren
-
-Export_selected_entries=Ausgew\u00e4hlte_Eintr\u00e4ge_e&xportieren
Save_all=A&lle_speichern
Manage_external_file_types=Externe_Dateitypen_verwalten
-Open_file=Datei_\u00f6ffnen
+Open_file=Datei_öffnen
+
Focus_entry_table=Fokus_auf_Tabelle_setzen
-Increase_table_font_size=Schriftgr\u00f6\u00dfe_in_der_&Tabelle_vergr\u00f6\u00dfern
-Decrease_table_font_size=Schriftgr\u00f6\u00dfe_in_der_Tabelle_ver&kleinern
+Increase_table_font_size=Schriftgröße_in_der_&Tabelle_vergrößern
+Decrease_table_font_size=Schriftgröße_in_der_Tabelle_verkleinern
Forward=Vor
-Back=Zur\u00fcck
+Back=Zurück
-Look_up_full_text_document=Volltext-Dokument_suchen
-Set/clear/rename_fields=Felder_setzen/l\u00f6schen/umbenennen
+Look_up_full_text_documents=Volltext-Dokumente_suchen
+Set/clear/rename_fields=Felder_setzen/löschen/umbenennen
-Mark_specific_color=Mit_bestimmter_&Farbe_markieren
Resolve_duplicate_BibTeX_keys=Doppelte_BibTeX-Keys_beseitigen
Copy_BibTeX_key_and_title=BibTeX-Key_und_Titel_kopieren
-Cleanup_entries=Eintr\u00e4ge_bereinigen
+Cleanup_entries=Einträge_bereinigen
Manage_keywords=Stichworte_verwalten
-Merge_entries=Eintr\u00e4ge_zusammenf\u00fchren
-Open_folder=Ordner_\u00f6ffnen
+Merge_entries=Einträge_zusammenführen
+Open_folder=Ordner_öffnen
Find_unlinked_files...=Nicht_verlinkte_Dateien_finden...
Hide/show_toolbar=Toolbar_zeigen/verbergen
Fork_me_on_GitHub=Forke_mich_auf_GitHub
-Save_selected_as_plain_BibTeX...=Ausgew\u00e4hlte_Eintr\u00e4ge_als_reines_BibTeX_speichern_\u2026
+Save_selected_as_plain_BibTeX...=Ausgewählte_Einträge_als_reines_BibTeX_speichern...
-Donate_to_JabRef=An_JabRef_spenden
Groups=Gruppen
-Delete_entry=Eintrag_l\u00f6schen
-
-Switch_to_%0_mode=In_den_%0-Modus_wechseln
-Check_integrity=Integrit\u00e4t_pr\u00fcfen
+Delete_entry=Eintrag_löschen
+Check_integrity=Integrität_prüfen
Quality=Qualität
-
-New_%0_database=Neue_%0_Datenbank
-
-Disable_highlight_groups_matching_entries=Keine_Gruppen_hervorheben
-
Online_help_forum=Online-Hilfeforum
-
Manage_protected_terms=Geschützte_Terme_verwalten
-
-View_change_log=Changelog_öffnen
Website=Webseite
Blog=Blog
+JabRef_resources=Mehr_zu_JabRef
Development_version=Entwicklungsversion
-JabRef_resources=Mehr_zu_JabRef
\ No newline at end of file
+View_change_log=Changelog_öffnen
+Copy_BibTeX_key_and_link=BibTeX-Key_und_Link_kopieren
+Copy_DOI_url=DOI-URL_kopieren
diff --git a/src/main/resources/l10n/Menu_en.properties b/src/main/resources/l10n/Menu_en.properties
index 9ee753b..3fe31ae 100644
--- a/src/main/resources/l10n/Menu_en.properties
+++ b/src/main/resources/l10n/Menu_en.properties
@@ -1,6 +1,7 @@
#!
-#! created/edited by Popeye version 0.54 (popeye.sourceforge.net)
-#! encoding:ISO-8859-1
+#! created/edited by Popeye version 0.55 (github.com/JabRef/popeye)
+#! encoding:UTF-8
+
Abbreviate_journal_names_(ISO)=Abbreviate_journal_names_(ISO)
Abbreviate_journal_names_(MEDLINE)=Abbreviate_journal_names_(MEDLINE)
About_JabRef=&About_JabRef
@@ -32,7 +33,6 @@ Disable_highlight_groups_matching_entries=Disable_highlight_groups_matching_entr
# Help
Online_help=Online_help
Donate_to_JabRef=Donate_to_JabRef
-Manage_content_selectors=Manage_&content_selectors
Manage_custom_exports=&Manage_custom_exports
Manage_custom_imports=Manage_custom_&imports
Manage_journal_abbreviations=Manage_&journal_abbreviations
@@ -48,7 +48,7 @@ New_subdatabase_based_on_AUX_file=New_subdatabase_based_on_AU&X_file
Next_tab=&Next_tab
Open_database=&Open_database
Open_URL_or_DOI=Open_&URL_or_DOI
-Open_shared_database=Open_shared_database
+Connect_to_shared_database=Connect_to_shared_database
Open_terminal_here=Open_terminal_here
Options=&Options
Paste=&Paste
@@ -56,7 +56,7 @@ Paste=&Paste
Preferences=&Preferences
Previous_tab=&Previous_tab
Quit=&Quit
-Recent_files=&Recent_files
+Recent_databases=&Recent_databases
Redo=&Redo
Replace_string=&Replace_string
Save_database=&Save_database
@@ -68,7 +68,8 @@ Select_all=Select_&all
Set_up_general_fields=Set_up_&general_fields
Show_error_console=Show_error_console
Sort_tabs=&Sort_tabs
-Switch_preview_layout=&Switch_preview_layout
+Next_preview_layout=&Next_preview_layout
+Previous_preview_layout=&Previous_preview_layout
# Export menu
Toggle_entry_preview=&Toggle_entry_preview
Toggle_groups_interface=Toggle_&groups_interface
@@ -103,7 +104,7 @@ Decrease_table_font_size=&Decrease_table_font_size
Forward=Forward
Back=Back
-Look_up_full_text_document=Look_up_full_text_document
+Look_up_full_text_documents=Look_up_full_text_documents
Set/clear/rename_fields=Set/clear/rename_fields
Resolve_duplicate_BibTeX_keys=Resolve_duplicate_BibTeX_keys
@@ -119,11 +120,11 @@ Hide/show_toolbar=Hide/show_toolbar
Fork_me_on_GitHub=Fork_me_on_GitHub
Save_selected_as_plain_BibTeX...=Save_selected_as_plain_BibTeX...
-Groups=Groups
+Groups=&Groups
Delete_entry=Delete_entry
Check_integrity=Check_integrity
-Quality=Quality
+Quality=&Quality
Online_help_forum=Online_help_forum
Manage_protected_terms=Manage_protected_terms
Website=Website
@@ -131,3 +132,5 @@ Blog=Blog
JabRef_resources=JabRef_resources
Development_version=Development_version
View_change_log=View_change_log
+Copy_BibTeX_key_and_link=Copy_BibTeX_key_and_link
+Copy_DOI_url=Copy_DOI_url
diff --git a/src/main/resources/l10n/Menu_es.properties b/src/main/resources/l10n/Menu_es.properties
index 7d994cd..8c01f6b 100644
--- a/src/main/resources/l10n/Menu_es.properties
+++ b/src/main/resources/l10n/Menu_es.properties
@@ -1,6 +1,7 @@
#!
-#!_created/edited_by_Popeye_version_0.55_(https://github.com/koppor/popeye)
-#!_encoding:ISO-8859-1
+#! created/edited by Popeye version 0.55 (github.com/JabRef/popeye)
+#! encoding:UTF-8
+
Abbreviate_journal_names_(ISO)=Abreviar_nombres_de_revistas_(ISO)
Abbreviate_journal_names_(MEDLINE)=Abreviar_nombres_de_revista_(MEDLINE)
About_JabRef=&Acerca_de_JabRef
@@ -14,68 +15,67 @@ Customize_entry_types=&Personalizar_tipos_de_entrada
Cut=&Cortar
Database_properties=&Propiedades_de_la_base_de_datos
Edit=&Editar
-#_Bibtex
+# Bibtex
Edit_entry=&Editar_registro
Edit_preamble=Editar_&preámbulo
Edit_strings=Editar_&cadenas
Export=&Exportar
Export_selected_entries_to_clipboard=&Exportar_registros_seleccionados_al_portapapeles
-#_Menu_names
+# Menu names
File=&Archivo
Find_duplicates=&Buscar_duplicados
Help=&Ayuda
Highlight_groups_matching_all_selected_entries=Resaltar_los_grupos_donde_coincidan_todos_los_registros_seleccionados
Highlight_groups_matching_any_selected_entry=Resaltar_los_grupos_donde_coincida_cualquier_registro_seleccionado
+Disable_highlight_groups_matching_entries=Inhabilitar_grupos_destacados_coincidentes_con_las_entradas
-#_Help
+# Help
Online_help=
-Manage_content_selectors=Administrar_selectores_de_&contenido
+Donate_to_JabRef=Donar_a_JabRef
Manage_custom_exports=Administrar_&exportaciones_personalizadas
Manage_custom_imports=Administrar_&importaciones_personalizadas
-
Manage_journal_abbreviations=Administrar_abreviaturas_de_publicaciones
-
Mark_entries=&Marcar_registros
-#_File_menu
-#_Menu_BibTeX_(BibTeX)
+# File menu
+New_%0_database=Nueva_base_de_datos_%0
+# Menu BibTeX (BibTeX)
New_entry=Nu&evo_registro
New_entry_by_type...=&Nuevo_registro...
New_entry_from_plain_text=Nue&vo_registro_desde_texto_sin_formato
New_subdatabase_based_on_AUX_file=Nueva_sub-base_de_datos_a_partir_de_archivo_AU&X
-#_View
+# View
Next_tab=Pestaña_&siguiente
Open_database=&Abrir_base_de_datos
Open_URL_or_DOI=Abrir_&URL_o_DOI
-Open_shared_database=
+Connect_to_shared_database=
Open_terminal_here=Abrir_terminal_aquí
Options=&Opciones
Paste=&Pegar
-#_Options
+# Options
Preferences=&Preferencias
Previous_tab=&Pestaña_anterior
Quit=&Salir
-Recent_files=Bases_de_datos_&recientes
+Recent_databases=Bases_de_datos_&recientes
Redo=&Rehacer
Replace_string=&Reemplazar_cadena
Save_database=&Guardar_base_de_datos
Save_database_as...=Gu&ardar_base_de_datos_como...
Save_selected_as...=Guardar_se&leccionados_como...
-#_Tools
+# Tools
Search=&Buscar
-
Select_all=Seleccionar_&todos
Set_up_general_fields=Establecer_&campos_generales
Show_error_console=Mostrar_consola_de_error
-
Sort_tabs=&Ordenar_pestañas
-Switch_preview_layout=&Intercambiar_vista_anterior
-#_Export_menu
+Next_preview_layout=
+Previous_preview_layout=
+# Export menu
Toggle_entry_preview=A&ctivar/Desactivar_previsualización_de_registro
Toggle_groups_interface=Activar/Desactivar_ventana_de_&grupos
Tools=&Herramientas
Unabbreviate_journal_names=Quitar_abreviatción_de_nombres_de_journal
-#_Edit
+# Edit
Undo=&Deshacer
Mark_specific_color=Color_espec\u00edfico_de_la_marca
Unmark_all=Anular_selección_de_todos_los_registros
@@ -84,12 +84,11 @@ View=&Ver
Import_into_new_database=Importar_a_una_nueva_base_de_datos
Import_into_current_database=Importar_a_la_base_de_datos_actual
-
+Switch_to_%0_mode=Cambiar_a_modo_%0
Push_entries_to_external_application_(%0)=Agregar_registros_a_aplicación_externa_(%0)
Pull_changes_from_shared_database=
Write_XMP-metadata_to_PDFs=Escribir_metadatos_XMP_a_PDF
-
Export_selected_entries=Exportar_registros_seleccionados
Save_all=Guardar_todo
@@ -105,7 +104,7 @@ Decrease_table_font_size=&Disminuir_tama\u00f1o_de_fuente_en_tabla
Forward=Avanzar
Back=Retroceder
-Look_up_full_text_document=Buscar_en_todo_el_texto_del_documento
+Look_up_full_text_documents=
Set/clear/rename_fields=Establecer/limpiar/renombrar_campos
Resolve_duplicate_BibTeX_keys=Resolver_claves_BibTeX_duplicadas
@@ -116,33 +115,22 @@ Manage_keywords=Administrar_palabras_clave
Merge_entries=Fusionar_entradas
Open_folder=Abrir_pasta
Find_unlinked_files...=Buscar_archivos_desenlazados...
-
Hide/show_toolbar=Mostrar/ocultar_barra_de_herramientas
Fork_me_on_GitHub=Fork_en_GitHub
Save_selected_as_plain_BibTeX...=Guardar_seleccionados_como_BibTeX_plano...
-Donate_to_JabRef=Donar_a_JabRef
-
Groups=Grupos
Delete_entry=Borrar_entrada
-
-Switch_to_%0_mode=Cambiar_a_modo_%0
Check_integrity=Verificar_Integridad
Quality=Calidad
-
-New_%0_database=Nueva_base_de_datos_%0
-
-Disable_highlight_groups_matching_entries=Inhabilitar_grupos_destacados_coincidentes_con_las_entradas
-
-Online_help_forum=
-
-Manage_protected_terms=
-
-Website=
-Blog=
-JabRef_resources=
-
-Development_version=
-View_change_log=
+Online_help_forum=Foro_de_ayuda_en_línea
+Manage_protected_terms=gestionar_términos_protegidos
+Website=Sitio_web
+Blog=Blog
+JabRef_resources=Recursos_sobre_JabRef
+Development_version=Versión_de_desarrollo
+View_change_log=Ver_registro_de_cambios
+Copy_BibTeX_key_and_link=Copiar_clave_BibTeX_y_enlace
+Copy_DOI_url=Copiar_la_url_del_DOI
diff --git a/src/main/resources/l10n/Menu_fa.properties b/src/main/resources/l10n/Menu_fa.properties
index 03c5c3e..46549a9 100644
--- a/src/main/resources/l10n/Menu_fa.properties
+++ b/src/main/resources/l10n/Menu_fa.properties
@@ -1,6 +1,7 @@
-#! created/edited by Behrouz Javanmardi (javanmardy at live.com), last update: 20150514
-#! ساخته/ویرایش شده توسط بهروز جوانمردی
+#!
+#! created/edited by Popeye version 0.55 (github.com/JabRef/popeye)
#! encoding:UTF-8
+
Abbreviate_journal_names_(ISO)=مخففسازی_نام_ژورنالها
Abbreviate_journal_names_(MEDLINE)=خلاصه_نام_ژورنالها_(MEDLINE)
About_JabRef=دربارهی_JabRef
@@ -27,15 +28,17 @@ Find_duplicates=یافتن_تکراریها
Help=راهنما
Highlight_groups_matching_all_selected_entries=پررنگ_کردن_گروهها_برابری_هر_مورد_منتخب
Highlight_groups_matching_any_selected_entry=پررنگ_کردن_گروهها_برابری_همهی_موارد
+Disable_highlight_groups_matching_entries=گروههای_مشخص_شدهی_مطابق_با_مدخلها_را_حذف_کن
# Help
Online_help=
-Manage_content_selectors=مدیریت_انتخابگران_مضمون
+Donate_to_JabRef=هدیه_دادن_به_JabRef
Manage_custom_exports=مدیریت_فرستادن_سفارشی
Manage_custom_imports=مدیریت_واردکنندگان_سفارشی
Manage_journal_abbreviations=مدیریت_مخفف_ژورنالها
Mark_entries=نشان_گذاری_ورودیها
# File menu
+New_%0_database=پایگاهدادهی_%0_جدید
# Menu BibTeX (BibTeX)
New_entry=ورودی_جدید
New_entry_by_type...=ورودی_جدید...
@@ -45,7 +48,7 @@ New_subdatabase_based_on_AUX_file=پایگاه_داده_جدید_براساس_پ
Next_tab=سربرگ_جدید
Open_database=بازکردن_پایگاه_داده
Open_URL_or_DOI=بازکردن_URL_یا_DOI
-Open_shared_database=
+Connect_to_shared_database=
Open_terminal_here=در_اینجا_پایانه_را_باز_کن
Options=تنظیمات
Paste=چسباندن
@@ -53,7 +56,7 @@ Paste=چسباندن
Preferences=پیکربندی
Previous_tab=سربرگ_قبلی
Quit=خروج
-Recent_files=پروندههای_اخیر
+Recent_databases=پروندههای_اخیر
Redo=دوباره_انجام_دادن
Replace_string=تعویض_رشته
Save_database=ذخیرهی_پایگاه_داده
@@ -64,9 +67,9 @@ Search=جستجو
Select_all=انتخاب_همه
Set_up_general_fields=نصب_کردن_حوزههای_کلی
Show_error_console=نمایش_میزفرمان_خطاها
-
Sort_tabs=دستهبندی_کردن_سربرگها
-Switch_preview_layout=جهش_به_آرایش_قبلی
+Next_preview_layout=
+Previous_preview_layout=
# Export menu
Toggle_entry_preview=انتصاب_پیشنمایش_ورودیها
Toggle_groups_interface=انتصاب_واسط_گروهها
@@ -81,12 +84,11 @@ View=نمایش
Import_into_new_database=وارد_کردن_به_پایگاه_دادهی_جدید
Import_into_current_database=وارد_کردن_به_پایگاه_دادهی_فعلی
-
+Switch_to_%0_mode=تعویض_به_حالت_%0
Push_entries_to_external_application_(%0)=(نشاندن_ورودیها_به_برنامهی_خارجی_(%0
Pull_changes_from_shared_database=
Write_XMP-metadata_to_PDFs=نوشتن_XMP-metadata_در_PDFها
-
Export_selected_entries=فرستادن_موارد_منتخب
Save_all=ذخیرهی_همه
@@ -102,7 +104,7 @@ Decrease_table_font_size=کاهش_اندازهی_قلم_جدول
Forward=بعد
Back=قبل
-Look_up_full_text_document=جستجوی_همهی_متن_سند
+Look_up_full_text_documents=
Set/clear/rename_fields=تنظیم/حذف/تغییرنام_حوزهها
Resolve_duplicate_BibTeX_keys=حل_کلیدهای_تکراری_BibTeX
@@ -118,29 +120,17 @@ Hide/show_toolbar=مخفیکردن/نمایش_نوار_ابزار
Fork_me_on_GitHub=مرا_در_GitHub_منشعب_کن
Save_selected_as_plain_BibTeX...=.=منتخبشده_را_به_صورت_متن_خام_BibTeX_ذخیره_کن
-Donate_to_JabRef=هدیه_دادن_به_JabRef
-
-
Groups=گروهها
Delete_entry=حذف_مدخل
-
-Switch_to_%0_mode=تعویض_به_حالت_%0
Check_integrity=بررسی_بینقصی
Quality=کیفیت
-
-New_%0_database=پایگاهدادهی_%0_جدید
-
-Disable_highlight_groups_matching_entries=گروههای_مشخص_شدهی_مطابق_با_مدخلها_را_حذف_کن
-
-
Online_help_forum=
-
Manage_protected_terms=
-
Website=
Blog=
JabRef_resources=
-
Development_version=
View_change_log=
+Copy_BibTeX_key_and_link=
+Copy_DOI_url=
diff --git a/src/main/resources/l10n/Menu_fr.properties b/src/main/resources/l10n/Menu_fr.properties
index ab02777..a42f572 100644
--- a/src/main/resources/l10n/Menu_fr.properties
+++ b/src/main/resources/l10n/Menu_fr.properties
@@ -1,134 +1,136 @@
#!
-#! created/edited by Popeye version 0.54 (popeye.sourceforge.net)
-#! encoding:ISO-8859-1
-Abbreviate_journal_names_(ISO)=Abr\u00e9ger_les_noms_de_journaux_(IS&O)
-Abbreviate_journal_names_(MEDLINE)=Abr\u00e9ger_les_noms_de_journaux_(MEDLI&NE)
+#! created/edited by Popeye version 0.55 (github.com/JabRef/popeye)
+#! encoding:UTF-8
+
+Abbreviate_journal_names_(ISO)=Abréger_les_noms_de_journaux_(IS&O)
+Abbreviate_journal_names_(MEDLINE)=Abréger_les_noms_de_journaux_(MEDLI&NE)
About_JabRef=A_&propos_de_JabRef
-Append_database=&Joindre_\u00e0_la_base
-Autogenerate_BibTeX_keys=Cr\u00e9ation_&automatique_des_cl\u00e9s_BibTeX
+Append_database=&Joindre_à_la_base
+Autogenerate_BibTeX_keys=Création_&automatique_des_clés_BibTeX
Close_database=&Fermer_la_base
Copy=Co&pier
-Copy_\\cite{BibTeX_key}=Copier_\\c&ite{cl\u00e9_BibTeX}
-Copy_BibTeX_key=Copier_la_cl\u00e9_&BibTeX
-Customize_entry_types=Personnaliser_les_&types_d'entr\u00e9es
+Copy_\\cite{BibTeX_key}=Copier_\\c&ite{clé_BibTeX}
+Copy_BibTeX_key=Copier_la_clé_&BibTeX
+Customize_entry_types=Personnaliser_les_&types_d'entrées
Cut=&Couper
-Database_properties=&Propri\u00e9t\u00e9s_de_la_base_de_donn\u00e9es
+Database_properties=&Propriétés_de_la_base_de_données
Edit=&Edition
-Edit_entry=&Editer_l'entr\u00e9e
-Edit_preamble=Editer_le_&pr\u00e9ambule
-Edit_strings=Editer_les_c&ha\u00eenes
+# Bibtex
+Edit_entry=&Editer_l'entrée
+Edit_preamble=Editer_le_&préambule
+Edit_strings=Editer_les_c&haînes
Export=&Exporter
-Export_selected_entries_to_clipboard=Exporter_les_entr\u00e9es_s\u00e9lectionn\u00e9es_vers_le_presse-papiers
+Export_selected_entries_to_clipboard=Exporter_les_entrées_sélectionnées_vers_le_presse-papiers
+
+# Menu names
File=&Fichier
Find_duplicates=Chercher_les_&doublons
Help=Ai&de
-Highlight_groups_matching_all_selected_entries=Surligner_les_groupes_correspondant_\u00e0_&toutes_les_entr\u00e9es_s\u00e9lectionn\u00e9es
-Highlight_groups_matching_any_selected_entry=Surligner_les_groupes_correspondant_\u00e0_au_moins_&une_des_entr\u00e9es_s\u00e9lectionn\u00e9es
+Highlight_groups_matching_all_selected_entries=Surligner_les_groupes_correspondant_à_&toutes_les_entrées_sélectionnées
+Highlight_groups_matching_any_selected_entry=Surligner_les_groupes_correspondant_à_au_moins_&une_des_entrées_sélectionnées
+Disable_highlight_groups_matching_entries=Désactiver_le_surlignement_des_groupes_correspondant_à_des_entrées
+# Help
Online_help=Aide_en_ligne
-Manage_content_selectors=&G\u00e9rer_les_s\u00e9lecteurs_de_contenu
-Manage_custom_exports=&G\u00e9rer_les_exportations_personnalis\u00e9es
-Manage_custom_imports=G\u00e9rer_les_&importations_personnalis\u00e9es
-Manage_journal_abbreviations=G\u00e9rer_les_abr\u00e9viations_de_&journaux
-Mark_entries=Etiqueter_des_&entr\u00e9es
-New_entry=N&ouvelle_entr\u00e9e
-New_entry_by_type...=&Nouvelle_entr\u00e9e...
-New_entry_from_plain_text=Nouvelle_entr\u00e9e_depuis_&texte_brut
+Donate_to_JabRef=Faire_un_don_à_JabRef
+Manage_custom_exports=&Gérer_les_exportations_personnalisées
+Manage_custom_imports=Gérer_les_&importations_personnalisées
+Manage_journal_abbreviations=Gérer_les_abréviations_de_&journaux
+Mark_entries=Etiqueter_des_&entrées
+# File menu
+New_%0_database=Nouvelle_base_%0
+# Menu BibTeX (BibTeX)
+New_entry=N&ouvelle_entrée
+New_entry_by_type...=&Nouvelle_entrée...
+New_entry_from_plain_text=Nouvelle_entrée_depuis_&texte_brut
New_subdatabase_based_on_AUX_file=Nouveau_Fichier_BibTeX_depuis_fichier_AU&X
+# View
Next_tab=Onglet_&suivant
Open_database=&Ouvrir_base
Open_URL_or_DOI=Ouvrir_&URL_ou_DOI
-Open_shared_database=Ouvrir_base_partagée
+Connect_to_shared_database=Ouvrir_base_partagée
Open_terminal_here=Ouvrir_un_terminal_ici
Options=Opt&ions
Paste=C&oller
-Preferences=&Pr\u00e9f\u00e9rences
-Previous_tab=Onglet_&pr\u00e9c\u00e9dent
+# Options
+Preferences=&Préférences
+Previous_tab=Onglet_&précédent
Quit=&Quitter
-Recent_files=Fichiers_&r\u00e9cents
-Redo=&R\u00e9p\u00e9ter
-Replace_string=Remplacer_la_c&ha\u00eene
+Recent_databases=Fichiers_&récents
+Redo=&Répéter
+Replace_string=Remplacer_la_c&haîne
Save_database=Enregistrer_la_base
Save_database_as...=Enregistrer_la_base_sous_...
-Save_selected_as...=Enregistrer_la_s\u00e9&lection_sous_...
+Save_selected_as...=Enregistrer_la_sé&lection_sous_...
+# Tools
Search=&Recherche
-Select_all=&Tout_s\u00e9lectionner
-Set_up_general_fields=Configurer_les_champs_&g\u00e9n\u00e9raux
+Select_all=&Tout_sélectionner
+Set_up_general_fields=Configurer_les_champs_&généraux
Show_error_console=Afficher_la_console_d'erreur
Sort_tabs=Trier_les_onglets
-Switch_preview_layout=Aper\u00e7u_1/Aper\u00e7u_2
-Toggle_entry_preview=&Afficher/masquer_l'aper\u00e7u
+Next_preview_layout=Mode_d'aperçu_suivant
+Previous_preview_layout=Mode_d'aperçu_précédent
+# Export menu
+Toggle_entry_preview=&Afficher/masquer_l'aperçu
Toggle_groups_interface=Afficher/masquer_l'interface_des_&groupes
Tools=&Outils
-Unabbreviate_journal_names=D\u00e9&velopper_les_noms_de_journaux
+Unabbreviate_journal_names=Dé&velopper_les_noms_de_journaux
+# Edit
Undo=&Annuler
-Unmark_all=To&ut_d\u00e9s\u00e9tiqueter
-Unmark_entries=&D\u00e9s\u00e9tiqueter_des_entr\u00e9es
+Mark_specific_color=Marquer_d'une_couleur_spécifique
+Unmark_all=To&ut_désétiqueter
+Unmark_entries=&Désétiqueter_des_entrées
View=&Affichage
Import_into_new_database=Importer_dans_une_nouvelle_base
Import_into_current_database=Importer_dans_la_base_courante
-
-Push_entries_to_external_application_(%0)=Envoyer_l'entr\u00e9e_vers_l'application_externe_(%0)
+Switch_to_%0_mode=Basculer_dans_le_mode_%0
+Push_entries_to_external_application_(%0)=Envoyer_l'entrée_vers_l'application_externe_(%0)
Pull_changes_from_shared_database=Récupérer_les_modif._depuis_la_base_partagée
-Write_XMP-metadata_to_PDFs=Ecrire_les_m\u00e9tadonn\u00e9es_XMP_dans_les_PDFs
-
+Write_XMP-metadata_to_PDFs=Ecrire_les_métadonnées_XMP_dans_les_PDFs
-Export_selected_entries=Exporter_les_entr\u00e9es_s\u00e9lectionn\u00e9es
+Export_selected_entries=Exporter_les_entrées_sélectionnées
Save_all=Enregistrer_tout
-Manage_external_file_types=G\u00e9rer_les_types_de_fichiers_externes
+Manage_external_file_types=Gérer_les_types_de_fichiers_externes
Open_file=Ouvrir_un_fichier
-Focus_entry_table=Curseur_dans_la_table_des_entr\u00e9es
+Focus_entry_table=Curseur_dans_la_table_des_entrées
Increase_table_font_size=&Augmenter_la_taille_de_police_de_la_table
Decrease_table_font_size=&Diminuer_la_taille_de_police_de_la_table
Forward=Suivant
-Back=Pr\u00e9c\u00e9dent
+Back=Précédent
-Look_up_full_text_document=T\u00e9l\u00e9charger_le_document_cit\u00e9
+Look_up_full_text_documents=Télécharger_les_documents_cité
Set/clear/rename_fields=Configurer/vider/renommer_des_champs
-Mark_specific_color=Marquer_d'une_couleur_sp\u00e9cifique
-Resolve_duplicate_BibTeX_keys=Traitement_des_clefs_BibTeX_dupliqu\u00e9es
+Resolve_duplicate_BibTeX_keys=Traitement_des_clefs_BibTeX_dupliquées
Copy_BibTeX_key_and_title=Copier_la_clef_BibTeX_et_le_titre
-Cleanup_entries=Nettoyage_des_entr\u00e9es
-Manage_keywords=G\u00e9rer_les_mots-clefs
-Merge_entries=Fusionner_les_entr\u00e9es
-Open_folder=Ouvrir_le_r\u00e9pertoire
-
-Find_unlinked_files...=Trouver_les_fichiers_non_li\u00e9s...
+Cleanup_entries=Nettoyage_des_entrées
+Manage_keywords=Gérer_les_mots-clefs
+Merge_entries=Fusionner_les_entrées
+Open_folder=Ouvrir_le_répertoire
+Find_unlinked_files...=Trouver_les_fichiers_non_liés...
Hide/show_toolbar=Afficher/masquer_la_barre_d'outils
-
Fork_me_on_GitHub=Forkez-moi_sur_GitHub
-Save_selected_as_plain_BibTeX...=Enregistrer_la_s\u00e9lection_en_BibTeX_basique...
-
-Donate_to_JabRef=Faire_un_don_à_JabRef
+Save_selected_as_plain_BibTeX...=Enregistrer_la_sélection_en_BibTeX_basique...
Groups=Groupes
-Delete_entry=Supprimer_l'entr\u00e9e
-
-Switch_to_%0_mode=Basculer_dans_le_mode_%0
-Check_integrity=V\u00e9rifier_l'int\u00e9grit\u00e9
+Delete_entry=Supprimer_l'entrée
+Check_integrity=Vérifier_l'intégrité
Quality=Qualité
-
-New_%0_database=Nouvelle_base_%0
-
-Disable_highlight_groups_matching_entries=Désactiver_le_surlignement_des_groupes_correspondant_à_des_entrées
-
Online_help_forum=Forum_d'aide_en_ligne
-
Manage_protected_terms=Gérer_les_termes_protégés
-
Website=Site_Internet
Blog=Blog
JabRef_resources=Plus_sur_JabRef
-
Development_version=Version_en_développement
View_change_log=Afficher_le_fichier_des_changements
+Copy_BibTeX_key_and_link=Copier_la_clef_BibTeX_et_le_lien
+Copy_DOI_url=Copier_l'URL_du_DOI
diff --git a/src/main/resources/l10n/Menu_in.properties b/src/main/resources/l10n/Menu_in.properties
index 53b76dc..db7368b 100644
--- a/src/main/resources/l10n/Menu_in.properties
+++ b/src/main/resources/l10n/Menu_in.properties
@@ -1,12 +1,12 @@
#!
-#! created/edited by Popeye version 0.54 (popeye.sourceforge.net)
-#! encoding:ISO-8859-1
+#! created/edited by Popeye version 0.55 (github.com/JabRef/popeye)
+#! encoding:UTF-8
+
Abbreviate_journal_names_(ISO)=Singkatan_nama_jurnal_(ISO)
Abbreviate_journal_names_(MEDLINE)=Singkatan_nama_jurnal_(MEDLINE)
About_JabRef=Tentang_JabRef
Append_database=Tambah_basisdata
Autogenerate_BibTeX_keys=Otomatis_kunci_BibTeX
-Back=Mundur
Close_database=Tutup_database
Copy=Salin
Copy_\\cite{BibTeX_key}=Salin_\\cite{kunci_BibTeX}
@@ -14,73 +14,99 @@ Copy_BibTeX_key=Salin_kunci_BibTeX
Customize_entry_types=Tipe_entri_atursendiri
Cut=Potong
Database_properties=Properti_basisdata
-Decrease_table_font_size=Kecilkan_ukuran_huruf_tabel
Edit=&Sunting
+# Bibtex
Edit_entry=Sunting_entri
Edit_preamble=Sunting_preamble
Edit_strings=Sunting_string
Export=Ekspor
-Export_selected_entries=Ekspor_entri_pilihan
Export_selected_entries_to_clipboard=Ekspor_entri_pilihan_ke_papanklip
+
+# Menu names
File=&Berkas
Find_duplicates=Temukan_data_yg_sama
-Focus_entry_table=Fokus_tabel_entri
-Forward=Maju
Help=Bant&uan
Highlight_groups_matching_all_selected_entries=Tandai_semua_entri_grup_yang_sesuai
Highlight_groups_matching_any_selected_entry=Tandai_entri_grup_yang_sesuai
-Import_into_current_database=Impor_ke_basisdata_sekarang
-Import_into_new_database=Impor_ke_basisdata_baru
-Increase_table_font_size=Besarkan_ukuran_huruf_tabel
+Disable_highlight_groups_matching_entries=Pewarnaan_grup_entri_yang_sesuai_tidak_aktif
+
+# Help
Online_help=
-Look_up_full_text_document=Lihat_dokumen_teks_lengkap
-Manage_content_selectors=Pengaturan_pengisian_kata
+Donate_to_JabRef=Sumbang_ke_JabRef
Manage_custom_exports=Pengaturan_ekspor_atursendiri
Manage_custom_imports=Pengaturan_impor_atursendiri
-Manage_external_file_types=Pengaturan_tipe_berkas_eksternal
Manage_journal_abbreviations=Pengaturan_singkatan_jurnal
Mark_entries=Tandai_entri
-Mark_specific_color=Tandai_dengan_warna
+# File menu
+New_%0_database=Basisdata_%0_baru
+# Menu BibTeX (BibTeX)
New_entry=Entri_baru
New_entry_by_type...=Entri_baru...
New_entry_from_plain_text=Entri_baru_dari_teks_biasa
New_subdatabase_based_on_AUX_file=Anak_basisdata_baru_dari_berkas_AUX
+# View
Next_tab=Tab_berikutnya
Open_database=Buka_basisdata
-Open_file=Buka_berkas
Open_URL_or_DOI=Buka_URL_atau_DOI
-Open_shared_database=
+Connect_to_shared_database=
Open_terminal_here=Buka_terminal_di_sini
Options=Pen&gaturan
Paste=Tempelkan
+# Options
Preferences=Preferensi
Previous_tab=Tab_sebelumnya
-Push_entries_to_external_application_(%0)=Kirim_entri_ke_program_eksternal_(%0)
-Pull_changes_from_shared_database=
Quit=Keluar
-Recent_files=Berkas_terkini
+Recent_databases=Berkas_terkini
Redo=Jadi_lagi
Replace_string=Ganti_string
-Save_all=Simpan_semua
Save_database=Simpan_basisdata
Save_database_as...=Simpan_basis_data_sebagai...
Save_selected_as...=Simpan_pilihan_sebagai...
+# Tools
Search=Cari
Select_all=Pilih_semua
-Set/clear/rename_fields=Tetapkan/bersihkan/namai_bidang
Set_up_general_fields=Penetapan_bidang_umum
Show_error_console=Tampilkan_pesan_kesalahan
Sort_tabs=Urutkan_tab
-Switch_preview_layout=Ubah_tataletak_tampilan
+Next_preview_layout=
+Previous_preview_layout=
+# Export menu
Toggle_entry_preview=Tampilkan_entri
Toggle_groups_interface=Aktifkan_antarmuka_grup
Tools=&AlatBantuan
Unabbreviate_journal_names=Nama_jurnal_tidak_disingkat
+# Edit
Undo=Tidak_jadi
+Mark_specific_color=Tandai_dengan_warna
Unmark_all=Lepas_tanda_semua
Unmark_entries=Lepas_tanda_entri
View=&Tampilan
+Import_into_new_database=Impor_ke_basisdata_baru
+Import_into_current_database=Impor_ke_basisdata_sekarang
+
+Switch_to_%0_mode=Ubah_ke_mode_%0
+Push_entries_to_external_application_(%0)=Kirim_entri_ke_program_eksternal_(%0)
+Pull_changes_from_shared_database=
Write_XMP-metadata_to_PDFs=Tulis_metadata_XMP_ke_PSF
+
+Export_selected_entries=Ekspor_entri_pilihan
+
+Save_all=Simpan_semua
+
+Manage_external_file_types=Pengaturan_tipe_berkas_eksternal
+
+Open_file=Buka_berkas
+
+Focus_entry_table=Fokus_tabel_entri
+
+Increase_table_font_size=Besarkan_ukuran_huruf_tabel
+Decrease_table_font_size=Kecilkan_ukuran_huruf_tabel
+Forward=Maju
+Back=Mundur
+
+Look_up_full_text_documents=
+Set/clear/rename_fields=Tetapkan/bersihkan/namai_bidang
+
Resolve_duplicate_BibTeX_keys=Menyelesaikan_kesamaan_kunci_BibTeX
Copy_BibTeX_key_and_title=Salin_kunci_BibTeX_dan_judul
@@ -93,27 +119,18 @@ Hide/show_toolbar=Sembunyikan/tunjukkan_toolbar
Fork_me_on_GitHub=Fork_JabRef_di_GitHub
Save_selected_as_plain_BibTeX...=Simpan_seleksi_sebagai_BibTeX_teks_biasa
-Donate_to_JabRef=Sumbang_ke_JabRef
Groups=Grup
Delete_entry=Hapus_entri
-
-Switch_to_%0_mode=Ubah_ke_mode_%0
Check_integrity=Periksa_Integritas
Quality=Kualitas
-
-New_%0_database=Basisdata_%0_baru
-
-Disable_highlight_groups_matching_entries=Pewarnaan_grup_entri_yang_sesuai_tidak_aktif
-
Online_help_forum=
-
Manage_protected_terms=
-
Website=
Blog=
JabRef_resources=
-
Development_version=
View_change_log=
+Copy_BibTeX_key_and_link=
+Copy_DOI_url=
diff --git a/src/main/resources/l10n/Menu_it.properties b/src/main/resources/l10n/Menu_it.properties
index 3775731..a3964cc 100644
--- a/src/main/resources/l10n/Menu_it.properties
+++ b/src/main/resources/l10n/Menu_it.properties
@@ -1,6 +1,7 @@
#!
-#! created/edited by Popeye version 0.54 (popeye.sourceforge.net)
-#! encoding:ISO-8859-1
+#! created/edited by Popeye version 0.55 (github.com/JabRef/popeye)
+#! encoding:UTF-8
+
Abbreviate_journal_names_(ISO)=Abbrevia_nomi_delle_riviste_(ISO)
Abbreviate_journal_names_(MEDLINE)=Abbrevia_nomi_delle_riviste_(MEDLINE)
About_JabRef=&Informazioni_su_JabRef
@@ -27,15 +28,17 @@ Find_duplicates=Ricerca_&duplicati
Help=&Aiuto
Highlight_groups_matching_all_selected_entries=&Evidenzia_i_gruppi_corrispondenti_a_tutte_le_voci_selezionate
Highlight_groups_matching_any_selected_entry=Evi&denzia_i_gruppi_corrispondenti_alle_voci_selezionate
+Disable_highlight_groups_matching_entries=Disattiva_l'evidenziazione_dei_gruppi_corrispondenti_alle_voci
# Help
Online_help=Aiuto_online
-Manage_content_selectors=&Gestione_dei_selettori_di_contenuti
+Donate_to_JabRef=Fai_una_donazione_a_JabRef
Manage_custom_exports=&Gestione_delle_esportazioni_personalizzate
Manage_custom_imports=Gestione_delle_&importazioni_personalizzate
Manage_journal_abbreviations=Gestione_delle_&abbreviazioni_delle_riviste
Mark_entries=E&videnzia
# File menu
+New_%0_database=Nuovo_database_%0
# Menu BibTeX (BibTeX)
New_entry=&Nuova_voce
New_entry_by_type...=N&uova_voce...
@@ -45,7 +48,7 @@ New_subdatabase_based_on_AUX_file=Nuovo_sub-database_da_file_AU&X
Next_tab=&Scheda_successiva
Open_database=&Apri_database
Open_URL_or_DOI=Apri_&URL_o_DOI
-Open_shared_database=Apri_database_condiviso
+Connect_to_shared_database=Apri_database_condiviso
Open_terminal_here=Apri_un_terminale_qui
Options=&Opzioni
Paste=&Incolla
@@ -53,7 +56,7 @@ Paste=&Incolla
Preferences=&Preferenze
Previous_tab=Scheda_&precedente
Quit=&Uscita
-Recent_files=File_recen&ti
+Recent_databases=File_recen&ti
Redo=&Ripeti
Replace_string=&Sostituisci_stringa
Save_database=&Salva_database
@@ -65,7 +68,8 @@ Select_all=Sele&ziona_tutto
Set_up_general_fields=Configura_i_campi_generali
Show_error_console=Mostra_la_console_d'errore
Sort_tabs=Ordina_le_schede
-Switch_preview_layout=S&cambia_layout_anteprima
+Next_preview_layout=Layout_di_anteprima_successivo
+Previous_preview_layout=Layout_di_anteprima_precedente
# Export menu
Toggle_entry_preview=&Visualizza/nascondi_anteprima
Toggle_groups_interface=V&isualizza/nascondi_l'interfaccia_dei_gruppi
@@ -73,14 +77,16 @@ Tools=&Strumenti
Unabbreviate_journal_names=Espandi_nomi_delle_riviste_(MEDLINE)
# Edit
Undo=&Annulla
+Mark_specific_color=E&videnzia_con_un_colore_specifico
Unmark_all=Rim&uovi_tutte_le_evidenziazioni
Unmark_entries=&Rimuovi_evidenziazione
View=&Visualizza
Import_into_new_database=Importa_in_un_nuo&vo_database
Import_into_current_database=Importa_nel_database_&corrente
+
+Switch_to_%0_mode=Passa_in_modalità_%0
Push_entries_to_external_application_(%0)=Invia_le_voci_all'applicazione_esterna_(%0)
Pull_changes_from_shared_database=Recupera_le_modifiche_dal_database_condiviso.
-
Write_XMP-metadata_to_PDFs=Inserisci_metadati_XMP_nei_file_PDF
Export_selected_entries=Esporta_le_voci_selezionate
@@ -98,10 +104,9 @@ Decrease_table_font_size=&Diminuisci_la_dimensione_dei_caratteri_della_tabella
Forward=Seguente
Back=Precedente
-Look_up_full_text_document=Scarica_il_documento_citato
+Look_up_full_text_documents=
Set/clear/rename_fields=Imposta_/_svuota_/_rinomina_i_campi
-Mark_specific_color=E&videnzia_con_un_colore_specifico
Resolve_duplicate_BibTeX_keys=Risolvi_le_chiavi_BibTeX_duplicate
Copy_BibTeX_key_and_title=Copia_la_chiave_BibTeX_ed_il_titolo
@@ -114,27 +119,18 @@ Hide/show_toolbar=Mostra/Nascondi_la_barra_degli_strumenti
Fork_me_on_GitHub=Fork_me_on_GitHub
Save_selected_as_plain_BibTeX...=Salva_la_selezione_in_formato_BibTeX_base...
-Donate_to_JabRef=Fai_una_donazione_a_JabRef
Groups=Gruppi
Delete_entry=Cancella_la_voce
-
-Switch_to_%0_mode=Passa_in_modalità_%0
Check_integrity=Verifica_di_integrità
Quality=Qualità
-
-New_%0_database=Nuovo_database_%0
-
-Disable_highlight_groups_matching_entries=Disattiva_l'evidenziazione_dei_gruppi_corrispondenti_alle_voci
-
Online_help_forum=Forum_di_aiuto_online
-
Manage_protected_terms=Gestione_dei_termini_protetti
-
-Website=
-Blog=
-JabRef_resources=
-
-Development_version=
-View_change_log=
+Website=Sito_web
+Blog=Blog
+JabRef_resources=Risorse_per_JabRef
+Development_version=Versione_di_sviluppo
+View_change_log=Visualizza_la_lista_delle_modifiche
+Copy_BibTeX_key_and_link=Copia_la_chiave_e_il_link_BibTeX
+Copy_DOI_url=Copia_l'url_del_DOI
diff --git a/src/main/resources/l10n/Menu_ja.properties b/src/main/resources/l10n/Menu_ja.properties
index a6c909a..e661816 100644
--- a/src/main/resources/l10n/Menu_ja.properties
+++ b/src/main/resources/l10n/Menu_ja.properties
@@ -1,6 +1,7 @@
#!
-#! created/edited by Popeye version 0.55 (https://github.com/koppor/popeye)
+#! created/edited by Popeye version 0.55 (github.com/JabRef/popeye)
#! encoding:UTF-8
+
Abbreviate_journal_names_(ISO)=学術誌名を短縮形に(ISO)
Abbreviate_journal_names_(MEDLINE)=学術誌名を短縮形に(MEDLINE)
About_JabRef=JabRefについて(&A)
@@ -27,25 +28,27 @@ Find_duplicates=重複を検索(&F)
Help=ヘルプ(&H)
Highlight_groups_matching_all_selected_entries=全選択項目に一致するグループを着色
Highlight_groups_matching_any_selected_entry=任意の選択項目に一致するグループを着色
+Disable_highlight_groups_matching_entries=項目に一致するグループの着色を無効化
# Help
Online_help=オンラインヘルプ
-Manage_content_selectors=内容選択メニューの管理(&C)
+Donate_to_JabRef=JabRefに寄付
Manage_custom_exports=ユーザー書出の管理(&M)
Manage_custom_imports=ユーザー読込の管理(&I)
Manage_journal_abbreviations=誌名短縮形の管理(&J)
Mark_entries=項目に標識を付ける(&M)
# File menu
+New_%0_database=新しい%0データベース
# Menu BibTeX (BibTeX)
New_entry=新規項目(&E)
New_entry_by_type...=新規項目(&N)…
New_entry_from_plain_text=平文から新規項目(&W)
-New_subdatabase_based_on_AUX_file=AU&Xファイルに基づく新規副データベース
+New_subdatabase_based_on_AUX_file=AU&Xファイルからの新規部分データベース
# View
Next_tab=次のタブ(&N)
Open_database=データベースを開く(&O)
Open_URL_or_DOI=&URLまたはDOIを開く
-Open_shared_database=
+Connect_to_shared_database=共有データベースを開く
Open_terminal_here=ここに_ターミナルを選択(開封)する
Options=オプション(&O)
Paste=貼付け(&P)
@@ -53,9 +56,9 @@ Paste=貼付け(&P)
Preferences=設定(&P)
Previous_tab=前のタブ(&P)
Quit=終了(&Q)
-Recent_files=最近開いたファイル(&R)
+Recent_databases=最近開いたファイル(&R)
Redo=再実行(&R)
-Replace_string=文字列を置換(&R)
+Replace_string=文字列の置換(&R)
Save_database=データベースを保存(&S)
Save_database_as...=データベースに名前を付けて保存(&A)…
Save_selected_as...=選択部に名前を付けて保存(&L)…
@@ -64,9 +67,9 @@ Search=検索(&S)
Select_all=全て選択(&A)
Set_up_general_fields=汎用フィールドを設定(&G)
Show_error_console=エラーコンソールを表示
-
Sort_tabs=タブを整序(&S)
-Switch_preview_layout=プレビューのレイアウトを切替(&S)
+Next_preview_layout=次のプレビューレイアウト(&N)
+Previous_preview_layout=前のプレビューレイアウト(&P)
# Export menu
Toggle_entry_preview=項目プレビューを入切(&T)
Toggle_groups_interface=グループ操作面を入切(&G)
@@ -74,23 +77,24 @@ Tools=ツール(&T)
Unabbreviate_journal_names=学術誌名を非短縮形に
# Edit
Undo=取り消し(&U)
+Mark_specific_color=特定色で標識を付ける(&A)
Unmark_all=標識をすべて外す(&L)
Unmark_entries=項目の標識を外す(&N)
View=表示(&V)
Import_into_new_database=新規データベースとして読み込む
Import_into_current_database=現在のデータベースに読み込む
-
+Switch_to_%0_mode=%0モードに切換
Push_entries_to_external_application_(%0)=項目を外部アプリケーション(%0)に転送
-Pull_changes_from_shared_database=
+Pull_changes_from_shared_database=共有データベースから変更点を持ってくる
Write_XMP-metadata_to_PDFs=XMPメタデータをPDFに書き出す
-
Export_selected_entries=選択した項目を書き出す
Save_all=すべて保存
Manage_external_file_types=外部ファイル型の管理
+
Open_file=ファイルを開く
Focus_entry_table=項目表にフォーカス
@@ -100,48 +104,33 @@ Decrease_table_font_size=表フォントを縮小(&D)
Forward=進む
Back=戻る
-
-Look_up_full_text_document=平文文書全体を検索
+Look_up_full_text_documents=
Set/clear/rename_fields=フィールドを設定/クリア/名称変更
-
-Mark_specific_color=特定色で標識を付ける(&A)
Resolve_duplicate_BibTeX_keys=重複したBibTeX鍵を解消する
-
Copy_BibTeX_key_and_title=BibTeX鍵とタイトルをコピー
-Cleanup_entries=項目を消去
+Cleanup_entries=項目の消去
Manage_keywords=キーワードを管理
-Merge_entries=項目を統合
+Merge_entries=項目の統合
Open_folder=フォルダを開く
-Find_unlinked_files...=リンクしていないファイルを検索
-
+Find_unlinked_files...=リンクしていないファイルを検索...
Hide/show_toolbar=ツールバーを表示/非表示
Fork_me_on_GitHub=私をGitHubにフォークして
Save_selected_as_plain_BibTeX...=選択部をplain_BibTeXとして保存...
-Donate_to_JabRef=JabRefに寄付
-
Groups=グループ
Delete_entry=項目を削除
-
-Switch_to_%0_mode=%0モードに切換
Check_integrity=整合性検査
Quality=品質
-
-New_%0_database=新しい%0データベース
-
-Disable_highlight_groups_matching_entries=項目に一致するグループの着色を無効化
-
-Online_help_forum=
-
-Manage_protected_terms=
-
-Website=
-Blog=
-JabRef_resources=
-
-Development_version=
-View_change_log=
+Online_help_forum=オンラインヘルプ フォーラム
+Manage_protected_terms=予約語の管理
+Website=ウェブサイト
+Blog=ブログ
+JabRef_resources=JabRefリソース
+Development_version=開発版
+View_change_log=変更履歴を閲覧
+Copy_BibTeX_key_and_link=BibTeX鍵とリンクをコピー
+Copy_DOI_url=DOIのURLをコピー
diff --git a/src/main/resources/l10n/Menu_nl.properties b/src/main/resources/l10n/Menu_nl.properties
index 00c50df..1f4046c 100644
--- a/src/main/resources/l10n/Menu_nl.properties
+++ b/src/main/resources/l10n/Menu_nl.properties
@@ -1,183 +1,102 @@
#!
-#! created/edited by Popeye version 0.54 (popeye.sourceforge.net)
-#! encoding:ISO-8859-1
+#! created/edited by Popeye version 0.55 (github.com/JabRef/popeye)
+#! encoding:UTF-8
Abbreviate_journal_names_(ISO)=Kort_namen_van_tijdschriften_af_(ISO)
-
Abbreviate_journal_names_(MEDLINE)=Kort_namen_van_tijdschriften_af_(MEDLINE)
-
About_JabRef=Over_JabRef
-
Append_database=Database_bijvoegen
-
Autogenerate_BibTeX_keys=Genereer_BibTeX-sleutels_automatisch
-
-
Close_database=Sluit_database
-
Copy=Kopi\u00ebren
-
Copy_\\cite{BibTeX_key}=Kopieer_\\cite{BibTeX-sleutel}
-
Copy_BibTeX_key=Kopieer_BibTeX-sleutel
-
-
-
Customize_entry_types=Pas_entry_types_aan
-
Cut=Knippen
-
Database_properties=Database_eigenschappen
-
-
Edit=Bewerken
-
# Bibtex
Edit_entry=Bewerk_entry
-
Edit_preamble=Bewerk_inleiding
-
Edit_strings=Bewerk_constanten
-
Export=Exporteren
-
Export_selected_entries_to_clipboard=Exporteer_geselecteerde_entries_naar_het_klembord
-
# Menu names
File=Bestand
-
-
Find_duplicates=Zoek_dubbels
-
Help=Help
-
-
Highlight_groups_matching_all_selected_entries=Markeer_groepen_die_overeenkomen_met_alle_geselecteerde_entries
-
Highlight_groups_matching_any_selected_entry=Markeer_groepen_die_overeenkomen_met_elke_geselecteerde_entry
-
-
-
-
-
+Disable_highlight_groups_matching_entries=Overeenkomende_groepen_van_invoer_oplichten_uitschakelen
# Help
Online_help=
-
-
-Manage_content_selectors=Beheer_inhoud_selectors
-
+Donate_to_JabRef=Doneer_aan_JabRef
Manage_custom_exports=Beheer_externe_exportfilters
-
Manage_custom_imports=Beheer_externe_importfilters
-
Manage_journal_abbreviations=Beheer_tijdschrift_afkortingen
-
Mark_entries=Markeer_entries
-
# File menu
-
+New_%0_database=Nieuwe_%0_database
# Menu BibTeX (BibTeX)
New_entry=Nieuwe_entry
-
New_entry_by_type...=Nieuwe_entry...
-
New_entry_from_plain_text=Nieuwe_entry_van_onopgemaakte_tekst
-
New_subdatabase_based_on_AUX_file=Nieuwe_subdatabase_gebaseerd_op_AUX_bestand
-
# View
Next_tab=Volgende_tabblad
-
Open_database=Open_database
-
-
Open_URL_or_DOI=Open_URL_of_DOI
-
-Open_shared_database=
-
+Connect_to_shared_database=
Open_terminal_here=Open_nieuwe_command_prompt_hier
-
Options=Opties
-
Paste=Plakken
-
# Options
Preferences=Instellingen
-
Previous_tab=Vorige_tabblad
-
Quit=Afsluiten
-
-Recent_files=Recente_bestanden
-
+Recent_databases=Recente_bestanden
Redo=Herstellen
-
Replace_string=Tekst_vervangen
-
Save_database=Database_opslaan
-
Save_database_as...=Database_opslaan_als_...
-
Save_selected_as...=Geselecteerde_opslaan_als_...
-
-
# Tools
Search=Zoeken
-
-
Select_all=Selecteer_alles
-
Set_up_general_fields=Stel_algemene_velden_in
-
Show_error_console=Toon_foutenconsole
-
Sort_tabs=Tabbladen_sorteren
-
-Switch_preview_layout=Toon_voorbeeld_layout
-
+Next_preview_layout=
+Previous_preview_layout=
# Export menu
-
Toggle_entry_preview=Toon_entry_voorbeeld
-
Toggle_groups_interface=Toon_groepenvenster
-
Tools=Extra's
-
Unabbreviate_journal_names=Maak_afkorting_van_tijdschriftnamen_ongedaan
-
# Edit
Undo=Ongedaan_maken
-
+Mark_specific_color=Markeer_specifieke_kleur
Unmark_all=Maak_alle_markeringen_ongedaan
-
Unmark_entries=Maak_markeringen_van_entries_ongedaan
-
View=Beeld
-
-
Import_into_new_database=Importeer_in_nieuwe_database
-
Import_into_current_database=Importeer_in_huidige_database
-
+Switch_to_%0_mode=Switch_naar_%0_modus
Push_entries_to_external_application_(%0)=Stuur_entries_naar_externe_applicatie
Pull_changes_from_shared_database=
-
Write_XMP-metadata_to_PDFs=Schrijf_XMP_metadata_naar_PDFs
-
Export_selected_entries=Exporteer_geseleteerde_records
-
-
Save_all=Bewaar_alles
-
Manage_external_file_types=Beheer_externe_bestandstypen
Open_file=Open_bestand
+
Focus_entry_table=Focus_op_invoertabel
Increase_table_font_size=Tabel_font_groter_maken
@@ -185,10 +104,9 @@ Decrease_table_font_size=Tabel_font_kleiner_maken
Forward=Verder
Back=Terug
-Look_up_full_text_document=Full-text-document_opzoeken
+Look_up_full_text_documents=
Set/clear/rename_fields=Instellen/wissen/hernoemen_van_velden
-Mark_specific_color=Markeer_specifieke_kleur
Resolve_duplicate_BibTeX_keys=Dubbele_BibTeX_steutels_aanpakken
Copy_BibTeX_key_and_title=Kopieer_BibTeX_sleutel_en_titel
@@ -202,27 +120,17 @@ Hide/show_toolbar=Verberg/toon_toolbar
Fork_me_on_GitHub=Forken_op_GitHub
Save_selected_as_plain_BibTeX...=Sla_selectie_op_als_platte_BibTex...
-Donate_to_JabRef=Doneer_aan_JabRef
-
Groups=Groepen
Delete_entry=Verwijder_entry
-
-Switch_to_%0_mode=Switch_naar_%0_modus
Check_integrity=Integriteitscontrole
Quality=Kwaliteit
-
-New_%0_database=Nieuwe_%0_database
-
-Disable_highlight_groups_matching_entries=Overeenkomende_groepen_van_invoer_oplichten_uitschakelen
-
Online_help_forum=
-
Manage_protected_terms=
-
Website=
Blog=
JabRef_resources=
-
Development_version=
View_change_log=
+Copy_BibTeX_key_and_link=
+Copy_DOI_url=
diff --git a/src/main/resources/l10n/Menu_no.properties b/src/main/resources/l10n/Menu_no.properties
index b4c740c..bb3f613 100644
--- a/src/main/resources/l10n/Menu_no.properties
+++ b/src/main/resources/l10n/Menu_no.properties
@@ -1,3 +1,7 @@
+#!
+#! created/edited by Popeye version 0.55 (github.com/JabRef/popeye)
+#! encoding:UTF-8
+
Abbreviate_journal_names_(ISO)=Forkort_journalnavn_(ISO)
Abbreviate_journal_names_(MEDLINE)=Forkort_journalnavn_(MEDLINE)
About_JabRef=Om_&JabRef
@@ -24,15 +28,17 @@ Find_duplicates=Søk_etter_&duplikater
Help=&Hjelp
Highlight_groups_matching_all_selected_entries=Uthev_grupper_som_inneholder_alle_valgte_oppføringer
Highlight_groups_matching_any_selected_entry=Uthev_grupper_som_inneholder_minst_en_av_de_valgte_oppføringene
+Disable_highlight_groups_matching_entries=Deaktiver markerte samsvarende oppføringer
+
# Help
Online_help=Online_hjelp
-Manage_content_selectors=Sett_opp_&ordvelgere
+Donate_to_JabRef=Doner til JabRef
Manage_custom_exports=&Sett_opp_eksterne_eksportfiltre
Manage_custom_imports=Sett_opp_eksterne_&importfiltre
-
Manage_journal_abbreviations=Sett_opp_&journalforkortelser
Mark_entries=&Merk_oppføringer
# File menu
+New_%0_database=Ny %0-database
# Menu BibTeX (BibTeX)
New_entry=N&y_oppføring
New_entry_by_type...=&Ny_oppføring...
@@ -42,7 +48,7 @@ New_subdatabase_based_on_AUX_file=Ny_deldatabase_basert_på_AU&X-fil
Next_tab=&Neste_tab
Open_database=&Åpne_database
Open_URL_or_DOI=Åpne_&URL_eller_DOI
-Open_shared_database=Åpne_felles_database
+Connect_to_shared_database=Åpne_felles_database
Open_terminal_here=Åpne terminal her
Options=V&alg
Paste=&Lim_inn
@@ -50,7 +56,7 @@ Paste=&Lim_inn
Preferences=&Oppsett
Previous_tab=&Forrige_tab
Quit=&Avslutt
-Recent_files=&Siste_filer
+Recent_databases=&Siste_filer
Redo=&Gjenta
Replace_string=&Erstatt_streng
Save_database=&Lagre_database
@@ -62,7 +68,8 @@ Select_all=&Velg_alle
Set_up_general_fields=Sett_opp_&generelle_felter
Show_error_console=Vis_feilkonsoll
Sort_tabs=Sorter_tabs
-Switch_preview_layout=&Skift_layout_på_forhåndsvisning
+Next_preview_layout=
+Previous_preview_layout=
# Export menu
Toggle_entry_preview=&Vis/skjul_forhåndsvisning
Toggle_groups_interface=Vis/skjul_&grupperingskontroll
@@ -70,18 +77,20 @@ Tools=V&erktøy
Unabbreviate_journal_names=Ekspander_journalnavn
# Edit
Undo=&Angre
+Mark_specific_color=M&erk_med_spesifikk_farge
Unmark_all=F&jern_merking_fra_alle
Unmark_entries=&Fjern_merking
View=&Vis
Import_into_new_database=Importer_til_ny_database
Import_into_current_database=Importer_til_den_aktive_databasen
-
+Switch_to_%0_mode=Bytt til %0-modus
Push_entries_to_external_application_(%0)=Send_oppføringer_til_ekstern_applikasjon_(%0)
Pull_changes_from_shared_database=
Write_XMP-metadata_to_PDFs=Skriv_XMP-metadata_til_PDF-filer
Export_selected_entries=Eksporter_valgte_oppføringer
+
Save_all=Lagre_alle
Manage_external_file_types=Sett_opp_eksterne_&filtyper
@@ -95,12 +104,10 @@ Decrease_table_font_size=Reduser_størrelse_på_tabellfont
Forward=Fram
Back=Tilbake
-Look_up_full_text_document=Finn_fulltekstdokument
+Look_up_full_text_documents=
Set/clear/rename_fields=Sett/slett/endre_navn_på_felter
-Mark_specific_color=M&erk_med_spesifikk_farge
Resolve_duplicate_BibTeX_keys=Søk_etter_dupliserte_BibTeX-nøkler
-
Copy_BibTeX_key_and_title=Kopier_BibTeX-nøkkel_og_tittel
Cleanup_entries=Rydd oppføringer
@@ -108,33 +115,22 @@ Manage_keywords=Administrer nøkkelord
Merge_entries=Slå sammen oppføringer
Open_folder=Åpne mapp
Find_unlinked_files...=Finn_filer_som_ikke_er_lenket...
-
Hide/show_toolbar=Gjem/vis verktøylinje
Fork_me_on_GitHub=Fork på GitHub
Save_selected_as_plain_BibTeX...=Lagre valgte som BibTeX
-Donate_to_JabRef=Doner til JabRef
-
Groups=Gruppering
Delete_entry=Slett_oppføring
-
-Switch_to_%0_mode=Bytt til %0-modus
Check_integrity=Sjekk_integritet
Quality=Kvalitet
-
-New_%0_database=Ny %0-database
-
-Disable_highlight_groups_matching_entries=Deaktiver markerte samsvarende oppføringer
-
Online_help_forum=Online_hjelpforum
-
Manage_protected_terms=Administrere_beskyttet_ord
-
Website=Nettsted
Blog=Blogg
JabRef_resources=JabRef-ressurser
-
Development_version=Utviklingsversjon
View_change_log=Vis_endringslogg
+Copy_BibTeX_key_and_link=
+Copy_DOI_url=
diff --git a/src/main/resources/l10n/Menu_pt_BR.properties b/src/main/resources/l10n/Menu_pt_BR.properties
index d344b99..b887ec4 100644
--- a/src/main/resources/l10n/Menu_pt_BR.properties
+++ b/src/main/resources/l10n/Menu_pt_BR.properties
@@ -1,6 +1,7 @@
#!
-#! created/edited by Popeye version 0.55 (https://github.com/koppor/popeye)
-#! encoding:ISO-8859-1
+#! created/edited by Popeye version 0.55 (github.com/JabRef/popeye)
+#! encoding:UTF-8
+
Abbreviate_journal_names_(ISO)=Abreviar_nomes_de_periódico(ISO)
Abbreviate_journal_names_(MEDLINE)=Abreviar_nomes_de_periódico(MEDLINE)
About_JabRef=Sobre_&JabRef
@@ -14,73 +15,98 @@ Customize_entry_types=&Personalizar_tipos_de_referências
Cut=&Recortar
Database_properties=&Propriedades_da_base_de_dados
Edit=&Editar
+# Bibtex
Edit_entry=&Editar_referência
Edit_preamble=&Editar_preâmbulo
Edit_strings=Editar_s&trings
Export=&Exportar
Export_selected_entries_to_clipboard=&Exportar_referências_selecionadas_para_a_área_de_transferência
+
+# Menu names
File=&Arquivo
Find_duplicates=&Encontrar_duplicatas
Help=&Ajuda
Highlight_groups_matching_all_selected_entries=&Destacar_grupos_contendo_todas_as_entradas_selecionadas
Highlight_groups_matching_any_selected_entry=D&estacar_grupos_contendo_qualquer_entrada_selecionada
+Disable_highlight_groups_matching_entries=Desabilitar_destacar_grupos_contendo_referências
+
+# Help
Online_help=
-Manage_content_selectors=Gerenciar_seletores_de_&conteúdo
+Donate_to_JabRef=Doar_para_JabRef
Manage_custom_exports=Gerenciar_&exportadores_personalizados
Manage_custom_imports=Gerenciar_&importadores_personalizados
Manage_journal_abbreviations=Gerenciar_&abreviações_de_periódicos
Mark_entries=&Marcar_referências
+# File menu
+New_%0_database=%0_novas_bases_de_dados
+# Menu BibTeX (BibTeX)
New_entry=No&va_referência
New_entry_by_type...=N&ova_referência...
New_entry_from_plain_text=Nova_referência_a_partir_de_texto_&puro
New_subdatabase_based_on_AUX_file=Nova_base_de_dados_a_partir_de_um_arquivo_AU&X
+# View
Next_tab=Próxima_a&ba
Open_database=&Abrir_base_de_dados
Open_URL_or_DOI=Abrir_&URL_ou_DOI
-Open_shared_database=
+Connect_to_shared_database=
Open_terminal_here=Abrir_terminal_aqui
Options=&Opções
Paste=&Colar
+# Options
Preferences=&Preferências
Previous_tab=A&ba_anterior
Quit=&Sair
-Recent_files=Arquivos_&recentes
+Recent_databases=Arquivos_&recentes
Redo=&Refazer
Replace_string=&Substituir_string
Save_database=&Salvar_base_de_dados
Save_database_as...=S&alvar_base_de_dados_como...
Save_selected_as...=Salvar_os_se&lecionados_como...
+# Tools
Search=&Pesquisar
Select_all=Selecionar_&tudo
Set_up_general_fields=Configurar_&campos_gerais
Show_error_console=Exibir_console_de_erros
Sort_tabs=&Ordenar_abas
-Switch_preview_layout=&Trocar_layout_da_previsualização
+Next_preview_layout=
+Previous_preview_layout=
+# Export menu
Toggle_entry_preview=&Mostrar/Esconder_previsualização_de_referências
Toggle_groups_interface=Mostrar/Esconder_interface_de_&grupos
Tools=&Ferramentas
Unabbreviate_journal_names=Reverter_abreviações_de_nomes_de_periódicos
+# Edit
Undo=&Desfazer
+Mark_specific_color=Marcar_cor_específica
Unmark_all=&Desmarcar_todos
Unmark_entries=Desmarcar_&referências
View=&Visualizar
Import_into_new_database=Importar_para_no&va_base_de_dados
Import_into_current_database=Importar_para_base_de_dados_atual
+
+Switch_to_%0_mode=Trocar_para_modo_%0
Push_entries_to_external_application_(%0)=Enviar_referências_para_um_aplicativo_externo_(%0)
Pull_changes_from_shared_database=
Write_XMP-metadata_to_PDFs=Escrever_metadados_XMP_para_PDFs
+
Export_selected_entries=Exportar_referências_selecionadas
+
Save_all=Salvar_tudo
+
Manage_external_file_types=Gerenciar_tipos_de_arquivos_externos
+
Open_file=Abrir_arquivo
+
Focus_entry_table=Foco_na_tabela_de_referências
+
Increase_table_font_size=&Aumentar_tamanho_da_fonte_da_tabela
Decrease_table_font_size=&Diminuir_tamanho_da_fonte_da_tabela
Forward=Avançar
Back=Voltar
-Look_up_full_text_document=Pesquiar_pelo_documento_de_texto_completo
+
+Look_up_full_text_documents=
Set/clear/rename_fields=Definir/Limpar/Renomear_campos
-Mark_specific_color=Marcar_cor_específica
+
Resolve_duplicate_BibTeX_keys=Resolver_chaves_BibTeX_duplicadas
Copy_BibTeX_key_and_title=Copiar_chave_BibTeX_e_título
@@ -89,33 +115,22 @@ Manage_keywords=Gerenciar_palavras-chave
Merge_entries=Unir_entradas
Open_folder=Abrir_diretório
Find_unlinked_files...=Encontrar_arquivos_não_referenciados
-
Hide/show_toolbar=Mostrar/esconder_barra_de_ferramentas
Fork_me_on_GitHub=Criar_um_fork_no_GitHub
Save_selected_as_plain_BibTeX...=Salvar_selecionado_como_BibTeX_simples
Groups=Grupos
-
-Donate_to_JabRef=Doar_para_JabRef
Delete_entry=Remover_referência
-
-Switch_to_%0_mode=Trocar_para_modo_%0
Check_integrity=Verificação_de_integridade
Quality=Qualidade
-
-New_%0_database=%0_novas_bases_de_dados
-
-Disable_highlight_groups_matching_entries=Desabilitar_destacar_grupos_contendo_referências
-
Online_help_forum=
-
Manage_protected_terms=
-
Website=
Blog=
JabRef_resources=
-
Development_version=
View_change_log=
+Copy_BibTeX_key_and_link=
+Copy_DOI_url=
diff --git a/src/main/resources/l10n/Menu_ru.properties b/src/main/resources/l10n/Menu_ru.properties
index ec69621..05866d9 100644
--- a/src/main/resources/l10n/Menu_ru.properties
+++ b/src/main/resources/l10n/Menu_ru.properties
@@ -1,6 +1,7 @@
#!
-#! created/edited by created/edited by wuw (01/08/15)
+#! created/edited by Popeye version 0.55 (github.com/JabRef/popeye)
#! encoding:UTF-8
+
Abbreviate_journal_names_(ISO)=Сокращения_названий_журналов_(ISO)
Abbreviate_journal_names_(MEDLINE)=Сокращения_названий_журналов_(MEDLINE)
About_JabRef=О_программе_JabRef
@@ -27,15 +28,17 @@ Find_duplicates=Найти_дубликаты
Help=Справка
Highlight_groups_matching_all_selected_entries=Выделить_группы_с_соответствием_для_всех_выбранных_записей
Highlight_groups_matching_any_selected_entry=Выделить_группы_с_соответствием_для_любой_выбранной_записи
+Disable_highlight_groups_matching_entries=Отключить_выделение_групп,_соответствующих_выделенным_записям
# Help
-Online_help=
-Manage_content_selectors=Управление_выбором_содержимого
+Online_help=Онлайн-справка
+Donate_to_JabRef=Поддержать_JabRef
Manage_custom_exports=Управление_пользовательским_экспортом
Manage_custom_imports=Управление_пользовательским_импортом
Manage_journal_abbreviations=Управление_сокращениями_для_журналов
Mark_entries=Метки_записей
# File menu
+New_%0_database=Новая_база_данных_%0
# Menu BibTeX (BibTeX)
New_entry=Создать_запись
New_entry_by_type...=Создать_запись...
@@ -45,7 +48,7 @@ New_subdatabase_based_on_AUX_file=Создать_подчиненную_БД_н
Next_tab=Следующая_вкладка
Open_database=Открыть_БД
Open_URL_or_DOI=Открыть_URL-адрес_или_DOI
-Open_shared_database=
+Connect_to_shared_database=
Open_terminal_here=Открыть_терминал_в_текущей_директории
Options=Параметры
Paste=Вставить
@@ -53,7 +56,7 @@ Paste=Вставить
Preferences=Пользовательские_настройки
Previous_tab=Предыдущая_вкладка
Quit=Выход
-Recent_files=Недавно_открытые_файлы
+Recent_databases=Недавно_открытые_файлы
Redo=Отмена
Replace_string=Заменить_строку
Save_database=Сохранить_БД
@@ -64,9 +67,9 @@ Search=Поиск
Select_all=Выбрать_все
Set_up_general_fields=Настройка_общих_полей
Show_error_console=Показать_консоль_ошибок
-
Sort_tabs=Сортировать_вкладки
-Switch_preview_layout=Переключить_макет_предпросмотра
+Next_preview_layout=
+Previous_preview_layout=
# Export menu
Toggle_entry_preview=Показать/скрыть_просмотр_записи
Toggle_groups_interface=Показать/скрыть_интерфейс_групп
@@ -81,12 +84,11 @@ View=Вид
Import_into_new_database=Импорт_в_новую_БД
Import_into_current_database=Импорт_в_текущую_БД
-
+Switch_to_%0_mode=Переключиться_в_режим_%0
Push_entries_to_external_application_(%0)=Передать_записи_во_внешнее_приложение_(%0)
-Pull_changes_from_shared_database=
+Pull_changes_from_shared_database=Загрузить_изменения_из_БД_с_общим_доступом
Write_XMP-metadata_to_PDFs=Запись_метаданных_XMP_в_PDF-файл
-
Export_selected_entries=Экспорт_выбранных_записей
Save_all=Сохранить_все
@@ -102,7 +104,7 @@ Decrease_table_font_size=Уменьшить_шрифт_в_таблице
Forward=Вперед
Back=Назад
-Look_up_full_text_document=Поиск_цитируемого_документа
+Look_up_full_text_documents=
Set/clear/rename_fields=Задать/очистить/переименовать_поля
Resolve_duplicate_BibTeX_keys=Разрешение_дубликатов_ключей_BibTeX
@@ -118,27 +120,17 @@ Hide/show_toolbar=Показать/скрыть_панель_инструмен
Fork_me_on_GitHub=Моя_ветка_на_GitHub
Save_selected_as_plain_BibTeX...=Сохранить_выбранное_как_неформатированный_BibTeX_...
-Donate_to_JabRef=Поддержать_JabRef
-
Groups=Группы
Delete_entry=Удалить_запись
-
-Switch_to_%0_mode=Переключиться_в_режим_%0
Check_integrity=Проверка_целостности
-Quality=Качество
-
-New_%0_database=Новая_база_данных_%0
-
-Disable_highlight_groups_matching_entries=Отключить_выделение_групп,_соответствующих_выделенным_записям
-
-Online_help_forum=
-
-Manage_protected_terms=
-
-Website=
-Blog=
-JabRef_resources=
-
-Development_version=
-View_change_log=
+Quality=Контроль_качества
+Online_help_forum=Форум_онлайн-поддержки
+Manage_protected_terms=Управление_защищенными_терминами
+Website=Веб-сайт
+Blog=Блог
+JabRef_resources=Ресурсы_JabRef
+Development_version=Версия_для_разработчиков
+View_change_log=Просмотр_журнала_изменений
+Copy_BibTeX_key_and_link=
+Copy_DOI_url=
diff --git a/src/main/resources/l10n/Menu_sv.properties b/src/main/resources/l10n/Menu_sv.properties
index ab3c392..ba8c6dd 100644
--- a/src/main/resources/l10n/Menu_sv.properties
+++ b/src/main/resources/l10n/Menu_sv.properties
@@ -1,4 +1,7 @@
-# Swedish translation of JabRef
+#!
+#! created/edited by Popeye version 0.55 (github.com/JabRef/popeye)
+#! encoding:UTF-8
+
Abbreviate_journal_names_(ISO)=Förkorta_tidskriftsnamn_(ISO)
Abbreviate_journal_names_(MEDLINE)=Förkorta_tidskriftsnamn_(MEDLINE)
About_JabRef=&Om_JabRef
@@ -12,55 +15,67 @@ Customize_entry_types=Anpassa_posttyper
Cut=Klipp_ut
Database_properties=Databasegenskaper
Edit=&Editera
+# Bibtex
Edit_entry=&Editera_post
Edit_preamble=Editera_&preamble
Edit_strings=Editera_&strängar
Export=&Exportera
Export_selected_entries_to_clipboard=Exportera_valda_poster_till_&urklipp
+
+# Menu names
File=&Fil
Find_duplicates=Hitta_dubletter
Help=&Hjälp
Highlight_groups_matching_all_selected_entries=Framhäv_grupper_som_matchar_alla_valda_poster
Highlight_groups_matching_any_selected_entry=Framhäv_grupper_som_matchar_någon_vald_poster
Disable_highlight_groups_matching_entries=Framhäv_inte_grupper_som_matcher_poster
+
+# Help
Online_help=Online&hjälp
Donate_to_JabRef=Donera_till_JabRef
-Manage_content_selectors=Hantera_innehållsväljare
Manage_custom_exports=Hantera_egna_exporterare
Manage_custom_imports=Hantera_egna_importerare
Manage_journal_abbreviations=Hantera_tidskriftsförkortningar
Mark_entries=&Markera_poster
+# File menu
New_%0_database=Ny_%0-databas
+# Menu BibTeX (BibTeX)
New_entry=&Ny_post
New_entry_by_type...=Ny_post_med_&typ...
New_entry_from_plain_text=Ny_post_från_&klartext
New_subdatabase_based_on_AUX_file=&Ny_databas_baserad_på_AUX-fil
+# View
Next_tab=&Nästa_flik
Open_database=&Öppna_databas
Open_URL_or_DOI=Öppna_&URL_eller_DOI
-Open_shared_database=Öppna_delad_databas
+Connect_to_shared_database=Öppna_delad_databas
Open_terminal_here=Öppna_&skalfönster_här
Options=&Alternativ
Paste=Klistra_in
+# Options
Preferences=&Inställningar
Previous_tab=Fö®ående_flik
Quit=&Avsluta
-Recent_files=Senaste_&filer
+Recent_databases=Senaste_&filer
Redo=&Gör_igen
Replace_string=Ersätt_sträng
Save_database=&Spara_databas
Save_database_as...=Spara_&databas_som...
Save_selected_as...=Spara_&valda_som...
+# Tools
Search=&Sök
Select_all=Välj_&alla
Set_up_general_fields=Hantera_generella_fält
Show_error_console=Visa_felmeddelanden
Sort_tabs=Sortera_flikar
-Switch_preview_layout=&Byt_postvisningsstil
+Next_preview_layout=
+Previous_preview_layout=
+# Export menu
Toggle_entry_preview=Växla_&postvisning
Toggle_groups_interface=Växla_&grupphantering
Tools=Verkt&yg
Unabbreviate_journal_names=E&xpandera_förkortade_tidskriftsnamn
+# Edit
Undo=&Ångra
Mark_specific_color=Markera_med_&färg
Unmark_all=&Avmarkera_alla
@@ -68,43 +83,54 @@ Unmark_entries=Avmarkera_&poster
View=&Visa
Import_into_new_database=Importera_till_ny_databas
Import_into_current_database=Importera_till_aktuell_databas
+
Switch_to_%0_mode=Byt_till_%0-läge
Push_entries_to_external_application_(%0)=Infoga_&citeringar_i_externt_program_(%0)
Pull_changes_from_shared_database=Hämta_ändringar_från_delad_databas
Write_XMP-metadata_to_PDFs=Skriv_XMP-metadata_till_PDFer
+
Export_selected_entries=E&xportera_valda_poster
+
Save_all=S¶_alla
+
Manage_external_file_types=Hantera_externa_filtyper
+
Open_file=&Öppna_fil
+
Focus_entry_table=Fokusera_&tabellen
+
Increase_table_font_size=&Öka_typsnittsstorlek_i_tabellen
Decrease_table_font_size=&Minska_typsnittsstorlek_i_tabellen
Forward=&Framåt
Back=&Bakåt
-Look_up_full_text_document=Leta_reda_på_fulltextdokument
+
+Look_up_full_text_documents=
Set/clear/rename_fields=Sätt/rensa/byt_namn_på_fält
+
Resolve_duplicate_BibTeX_keys=Hantera_BibTeX-nyckeldubbletter
Copy_BibTeX_key_and_title=Kopiera_BibTeX-nyckel_och_titel
+
Cleanup_entries=Städa_upp_poster
Manage_keywords=Hantera_nyckelord
Merge_entries=Slå_samman_poster
Open_folder=Öppna_&mapp
Find_unlinked_files...=Hitta_olänkade_filer...
Hide/show_toolbar=Dölj/visa_verktygslist
+
Fork_me_on_GitHub=Skapa_kopia_av_källkoden_på_GitHub
Save_selected_as_plain_BibTeX...=Spara_valda_som_enkel_&BibTeX...
+
Groups=&Grupper
Delete_entry=Radera_post
Check_integrity=Testa_&integriteten
-Quality=&Kvalitet
+Quality=&Kvalitet
Online_help_forum=Onlineforum
-
Manage_protected_terms=Hantera_skyddade_ord
-
Website=Hemsida
Blog=Blogg
JabRef_resources=JabRef-resurser
-
Development_version=Utvecklingsversion
View_change_log=Visa_ändringar
+Copy_BibTeX_key_and_link=
+Copy_DOI_url=
diff --git a/src/main/resources/l10n/Menu_tr.properties b/src/main/resources/l10n/Menu_tr.properties
index b598ca4..a841a0f 100644
--- a/src/main/resources/l10n/Menu_tr.properties
+++ b/src/main/resources/l10n/Menu_tr.properties
@@ -1,6 +1,7 @@
#!
-#! created/edited by Popeye version 0.55 (https://github.com/koppor/popeye)
+#! created/edited by Popeye version 0.55 (github.com/JabRef/popeye)
#! encoding:UTF-8
+
Abbreviate_journal_names_(ISO)=Dergi_adlarını_kısalt_(ISO)
Abbreviate_journal_names_(MEDLINE)=Dergi_adlarını_kısalt_(MEDLINE)
About_JabRef=JabRef_H&akkında
@@ -14,75 +15,98 @@ Customize_entry_types=Girdi_türlerini_&özelleştir
Cut=Ke&s
Database_properties=Veritabanı_ö&zellikleri
Edit=Düz&enle
+# Bibtex
Edit_entry=Girdiyi_düz&enle
Edit_preamble=&Öncülü_düzenle
Edit_strings=Diz&geleri_düzenle
Export=Dı&şa_aktarım
Export_selected_entries_to_clipboard=S&eçili_girdileri_panoya_aktar
+
+# Menu names
File=&Dosya
Find_duplicates=Çift_nüshaları_&bul
Help=&Yardım
Highlight_groups_matching_all_selected_entries=Tüm_seçili_girdilerle_eşleşen_grupları_vurgula
Highlight_groups_matching_any_selected_entry=Herhangi_bir_seçili_girdiyle_eşleşen_grupları_vurgula
+Disable_highlight_groups_matching_entries=Vurgulu_gruplarla_eşleşen_girdileri_etkisizleştir
+
+# Help
Online_help=Çevrimiçi_yardım
-Manage_content_selectors=İçe&rik_seçicileri_yönet
+Donate_to_JabRef=JabRef'e_bağış_yap
Manage_custom_exports=Özel_dışa_aktarı&mları_yönet
Manage_custom_imports=Özel_&içe_aktarımları_yönet
Manage_journal_abbreviations=Der&gi_kısaltmalarını_yönet
Mark_entries=Girdileri_iş&aretle
+# File menu
+New_%0_database=Yeni_%0_veri_tabanı
+# Menu BibTeX (BibTeX)
New_entry=Y&eni_girdi
New_entry_by_type...=Ye&ni_girdi...
New_entry_from_plain_text=Düz_metinden_¥i_girdi
New_subdatabase_based_on_AUX_file=AU&X_dosyası_tabanlı_yeni_altveritabanı
+# View
Next_tab=So&nraki_sekme
Open_database=Veritabanı_&Aç
Open_URL_or_DOI=&URL_ya_da_DOI_aç
-Open_shared_database=Paylaşılmış_veritabanını_aç
+Connect_to_shared_database=Paylaşılmış_veritabanını_aç
Open_terminal_here=Terminali_burada_aç
Options=Se&çenekler
Paste=Ya&pıştır
+# Options
Preferences=&Tercihler
Previous_tab=Ön&ceki_sekme
Quit=&Kapat
-Recent_files=Son_kullanılan_dosyala&r
+Recent_databases=Son_kullanılan_dosyala&r
Redo=Y&inele
Replace_string=Dizgenin_ye&rine_koy
Save_database=Veritabanını_&kaydet
Save_database_as...=Varit&abanını_farklı_kaydet...
Save_selected_as...=Seçimi_fark&lı_kaydet...
+# Tools
Search=A&ra
Select_all=T&ümünü_seç
Set_up_general_fields=&Genel_alanları_ayarla
Show_error_console=Hata_konsolunu_göster
Sort_tabs=&Sekmeleri_sırala
-Switch_preview_layout=Önizleme_yerleşimini_de&ğiştir
+Next_preview_layout=Sonraki_önizleme_düzeni
+Previous_preview_layout=Önceki_önzileme_düzeni
+# Export menu
Toggle_entry_preview=Girdi_önzilemesini_aç/kapa&t
Toggle_groups_interface=&Grup_arayüzünü_aç/kapat
Tools=Ara&çlar
Unabbreviate_journal_names=Kısaltma_dergi_adlarını_aç
+# Edit
Undo=&Geri_al
+Mark_specific_color=Özel_işaretleme_rengi
Unmark_all=Tümünün_işaretini_ka&ldır
Unmark_entries=Girdilerin_işareti&ni_kaldır
View=&Görüntüle
Import_into_new_database=Yeni_veritabanına_aktar
Import_into_current_database=Mevcut_veritabanına_aktar
+
+Switch_to_%0_mode=%0_kipine_geç
Push_entries_to_external_application_(%0)=Girdileri_harici_uygulamaya_itele_(%0)
Pull_changes_from_shared_database=Paylaşılmış_veritabaınından_değişiklikleri_çek
Write_XMP-metadata_to_PDFs=XMP-metaverisini_PDF'ye_yaz
+
Export_selected_entries=Seçili_girdileri_dışa_aktar
+
Save_all=Tümünü_kaydet
+
Manage_external_file_types=Harici_dosya_türlerini_yönet
+
Open_file=Dosya_aç
+
Focus_entry_table=Girdi_tablosuna_odaklan
Increase_table_font_size=Tablo_yazıtipi_boyutunu_arttır
Decrease_table_font_size=Tablo_yazıtipi_boyutunu_azalt
Forward=İleri
Back=Geri
-Look_up_full_text_document=Tam_metin_belge_bul
+
+Look_up_full_text_documents=
Set/clear/rename_fields=Alanları_ata/sil/yeniden_adlandır
-Mark_specific_color=Özel_işaretleme_rengi
Resolve_duplicate_BibTeX_keys=Çifte_BibTeX_anahtarlarını_çözümle
Copy_BibTeX_key_and_title=BibTeX_anahtarı_ve_başlığını_kopyala
@@ -91,33 +115,22 @@ Manage_keywords=Anahtar_sözcükleri_yönet
Merge_entries=Girdileri_birleştir
Open_folder=Klasörü_aç
Find_unlinked_files...=Bağlantılanmamış_dosyaları_bul...
-
Hide/show_toolbar=Araç_çubuğunu_gizle/göster
Fork_me_on_GitHub=Beni_GitHub'da_çatalla
Save_selected_as_plain_BibTeX...=Seçimi_salt_BibTeX_olarak_kaydet_...
-Donate_to_JabRef=JabRef'e_bağış_yap
-
Groups=Gruplar
Delete_entry=Girdiyi_sil
-
-Switch_to_%0_mode=%0_kipine_geç
Check_integrity=Bütünlük_kontrolü
Quality=Kalite
-
-New_%0_database=Yeni_%0_veri_tabanı
-
-Disable_highlight_groups_matching_entries=Vurgulu_gruplarla_eşleşen_girdileri_etkisizleştir
-
Online_help_forum=Çevrimiçi_yardım_forumu
-
Manage_protected_terms=Korunmuş_terimleri_yönet
-
-Website=
-Blog=
-JabRef_resources=
-
-Development_version=
-View_change_log=
+Website=Web_sitesi
+Blog=Ağ_güncesi
+JabRef_resources=JabRef_kaynakları
+Development_version=Geliştirme_sürümü
+View_change_log=Değişiklik_kütüğünü_göster
+Copy_BibTeX_key_and_link=BibTeX_anahtarı_ve_bağlantısını_kopyala
+Copy_DOI_url=DOI_url'sini_kopyala
diff --git a/src/main/resources/l10n/Menu_vi.properties b/src/main/resources/l10n/Menu_vi.properties
index 1b7434e..c828624 100644
--- a/src/main/resources/l10n/Menu_vi.properties
+++ b/src/main/resources/l10n/Menu_vi.properties
@@ -1,146 +1,136 @@
#!
-#! created/edited by Popeye version 0.54 (popeye.sourceforge.net)
+#! created/edited by Popeye version 0.55 (github.com/JabRef/popeye)
#! encoding:UTF-8
+
Abbreviate_journal_names_(ISO)=Viết_tắt_tên_các_tạp_chí_(ISO)
Abbreviate_journal_names_(MEDLINE)=Viết_tắt_tên_các_tạp_chí_(MEDLINE)
-About_JabRef=Nói_&về_JabRef
-Append_database=&Nối_CSDL
-Autogenerate_BibTeX_keys=&Tự_động_tạo_khóa_BibTeX
-Back=Lui
-Close_database=&Đóng_CSDL
-Copy=C&hép
-Copy_\\cite{BibTeX_key}=Chép\\&trích_dẫn{khóa_BibTeX}
-Copy_BibTeX_key=Chép_khóa_&BibTeX
-Customize_entry_types=&Tùy_biến_kiểu_các_mục
-Cut=Cắ&t
-Database_properties=Thuộc_tính_C&SDL
-Decrease_table_font_size=&Giảm_kích_thước_phông_của_bảng
-Edit=Chỉnh_&sửa
+About_JabRef=Nói_về_JabRef
+Append_database=Nối_CSDL
+Autogenerate_BibTeX_keys=Tự_động_tạo_khóa_BibTeX
+Close_database=Đóng_CSDL
+Copy=Sao_chép
+Copy_\\cite{BibTeX_key}=Sao_chép\\trích_dẫn{khóa_BibTeX}
+Copy_BibTeX_key=Sao_chép_khóa_BibTeX
+Customize_entry_types=Tùy_biến_kiểu_các_mục
+Cut=Cắt
+Database_properties=Thuộc_tính_CSDL
+Edit=Chỉnh_sửa
# Bibtex
-Edit_entry=Chỉnh_sửa_&mục
-Edit_preamble=Chỉnh_sửa_&phần_mở_đầu
-Edit_strings=Chỉnh_sửa_&chuỗi
-Export=X&uất
-
-Export_selected_entries=Xuất_các_mục_được_chọn
-Export_selected_entries_to_clipboard=Xuất_các_mục_đã_chọn_ra_&bộ_nhớ_tạm
+Edit_entry=Chỉnh_sửa_mục
+Edit_preamble=Chỉnh_sửa_phần_mở_đầu
+Edit_strings=Chỉnh_sửa_chuỗi
+Export=Xuất
+Export_selected_entries_to_clipboard=Xuất_các_mục_đã_chọn_ra_từ_bộ_nhớ_tạm_thời
# Menu names
-File=Tập_t&in
-Find_duplicates=Tìm_các_mục_t&rùng
-Focus_entry_table=Tập_trung_vào_bảng_chứa_mục
-Forward=Tới
-Help=Trợ_&giúp
+File=Tập_tin
+Find_duplicates=Tìm_các_mục_trùng
+Help=Trợ_giúp
Highlight_groups_matching_all_selected_entries=Tô_sáng_các_nhóm_khớp_tất_cả_các_mục_chọn
Highlight_groups_matching_any_selected_entry=Tô_sáng_các_nhóm_khớp_bất_kỳ_mục_chọn_nào
-Import_into_current_database=Nhập_vào_CSDL_hiện_tại
-Import_into_new_database=Nhập_vào_thành_CSDL_mới
-
-Increase_table_font_size=&Tăng_kích_thước_phông_của_bảng
+Disable_highlight_groups_matching_entries=Xóa_bỏ_tô_sáng_các_nhóm_trùng_khớp_mục
# Help
-Online_help=
-Look_up_full_text_document=Tìm_tài_liệu_đầy_đủ
-Manage_content_selectors=&Quản_lý_các_trình_chọn_nội_dung
-Manage_custom_exports=Quản_lý_&xuất_theo_tùy_chọn
-Manage_custom_imports=Quản_lý_&nhập_theo_tùy_chọn
-Manage_external_file_types=Quản_lý_các_kiểu_tập_tin_ngoài
-Manage_journal_abbreviations=Quản_lý_viết_tắt_tên_tạp_&chí
-
-Mark_entries=Đánh_&dấu_các_mục
+Online_help=Trợ_giúp_trực_tuyến
+Donate_to_JabRef=Hỗ_trợ_cho_JabRef
+Manage_custom_exports=Quản_lý_xuất_theo_tùy_chọn
+Manage_custom_imports=Quản_lý_nhập_theo_tùy_chọn
+Manage_journal_abbreviations=Quản_lý_viết_tắt_tên_tạp_chí
+Mark_entries=Đánh_dấu_các_mục
# File menu
+New_%0_database=Mở_dữ_liệu_%0_mới
# Menu BibTeX (BibTeX)
-New_entry=&Mục_mới
-New_entry_by_type...=&Mục_mới...
-New_entry_from_plain_text=Mục_mới_từ_&văn_bản_trơn
-New_subdatabase_based_on_AUX_file=Cơ_sở_dữ_liệu_con_mới_dựa_trên_tập_tin_AU&X
+New_entry=Mục_mới
+New_entry_by_type...=Mục_mới...
+New_entry_from_plain_text=Mục_mới_từ_văn_bản_trơn
+New_subdatabase_based_on_AUX_file=Cơ_sở_dữ_liệu_con_mới_dựa_trên_tập_tin_AUX
# View
-Next_tab=&Thẻ_tiếp_theo
-Open_database=&Mở_CSDL
-
-Open_file=Mở_tập_tin
-Open_URL_or_DOI=Mở_&URL_hoặc_DOI
-Open_shared_database=
-Open_terminal_here=
-Options=&Tùy_chọn
-Paste=&Dán
-
+Next_tab=Thẻ_tiếp_theo
+Open_database=Mở_CSDL
+Open_URL_or_DOI=Mở_URL_hoặc_DOI
+Connect_to_shared_database=Mở_CSDL_chia_sẻ
+Open_terminal_here=Mở_thiết_bị_đầu_cuối_ở_đây
+Options=Tùy_chọn
+Paste=Nhập_vào
# Options
-Preferences=Tùy_&thích
-Previous_tab=Thẻ_t&rước
-
-Push_entries_to_external_application_(%0)=Đưa_các_mục_ra_ứng_dụng_ngoài_(%0)
-Pull_changes_from_shared_database=
-Quit=Th&oát
-Recent_files=&Các_tập_tin_gần_đây
-Redo=&Làm_lại
-Replace_string=&Thay_chuỗi
-
-Save_all=Lưu_tất_cả
-Save_database=&Lưu_CSDL
-Save_database_as...=Lư&u_CSDL_thành_...
-Save_selected_as...=Lưu_&phần_chọn_thành_...
-
+Preferences=Tùy_thích
+Previous_tab=Thẻ_trước
+Quit=Thoát
+Recent_databases=Các_tập_tin_gần_đây
+Redo=Làm_lại
+Replace_string=Thay_chuỗi
+Save_database=Lưu_CSDL
+Save_database_as...=Lưu_CSDL_thành_...
+Save_selected_as...=Lưu_phần_chọn_thành_...
# Tools
-Search=Tì&m
-
-Select_all=Chọn_tất_&cả
-Set/clear/rename_fields=Thiết_lập/Xóa/Đổi_tên_trường
-
-Set_up_general_fields=Thiết_lập_các_trường_tổng_&quát
-Show_error_console=Hiển_thị_cửa_&sổ_báo_lỗi
-
-Sort_tabs=Phân_loại_t&hẻ
-Switch_preview_layout=&Bật_trình_bày_xem_trước
+Search=Tìm
+Select_all=Chọn_tất_cả
+Set_up_general_fields=Thiết_lập_các_trường_tổng_quát
+Show_error_console=Hiển_thị_cửa_sổ_báo_lỗi
+Sort_tabs=Phân_loại_thẻ
+Next_preview_layout=Xem_trước_bố_trí_tiếp_theo
+Previous_preview_layout=Xem_trước_bố_trí_trước_đó
# Export menu
-Toggle_entry_preview=&Bật/tắt_xem_trước_mục
-Toggle_groups_interface=Bật/tắt_&giao_diện_nhóm
-Tools=&Công_cụ
+Toggle_entry_preview=Bật/tắt_xem_trước_mục
+Toggle_groups_interface=Bật/tắt_giao_diện_nhóm
+Tools=Công_cụ
Unabbreviate_journal_names=Không_viết_tắt_tên_các_tạp_chí
# Edit
-Undo=&Quay_ngược_lệnh
-Unmark_all=&Khử_đánh_dấu_tất_cả
-Unmark_entries=Khử_đánh_&dấu_các_mục
+Undo=Quay_ngược_lệnh
+Mark_specific_color=Đánh_dấu_bằng_màu_cụ_thể
+Unmark_all=Xóa_bỏ_đánh_dấu_tất_cả
+Unmark_entries=Xóa_bỏ_đánh_dấu_các_mục
+View=Xem
+Import_into_new_database=Nhập_vào_thành_CSDL_mới
+Import_into_current_database=Nhập_vào_CSDL_hiện_tại
-View=&Xem
+Switch_to_%0_mode=Chuyển_sang_hệ_%0
+Push_entries_to_external_application_(%0)=Đưa_các_mục_ra_ứng_dụng_ngoài_(%0)
+Pull_changes_from_shared_database=Cập_nhập_thông_tin_từ_CSDL_chia_sẻ
Write_XMP-metadata_to_PDFs=Ghi_XMP-metadata_thành_các_PDF
+Export_selected_entries=Xuất_các_mục_được_chọn
-Mark_specific_color=
-Resolve_duplicate_BibTeX_keys=
-Cleanup_entries=
-Manage_keywords=
-Merge_entries=
-Open_folder=
-Find_unlinked_files...=
-
-Hide/show_toolbar=
-
-Fork_me_on_GitHub=
-Save_selected_as_plain_BibTeX...=
+Save_all=Lưu_tất_cả
-Copy_BibTeX_key_and_title=
-Donate_to_JabRef=
+Manage_external_file_types=Quản_lý_các_kiểu_tập_tin_ngoài
-Groups=Các_nhóm
-Delete_entry=Xóa_mục
+Open_file=Mở_tập_tin
-Switch_to_%0_mode=
-Check_integrity=Kiểm_tra_tính_nguyên_vẹn
+Focus_entry_table=Tập_trung_vào_bảng_chứa_mục
-Quality=
+Increase_table_font_size=Tăng_kích_thước_phông_của_bảng
+Decrease_table_font_size=Giảm_kích_thước_phông_của_bảng
+Forward=Tới
+Back=Lui
-New_%0_database=
+Look_up_full_text_documents=
+Set/clear/rename_fields=Thiết_lập/Xóa/Đổi_tên_trường
-Disable_highlight_groups_matching_entries=
+Resolve_duplicate_BibTeX_keys=Giải_quyết_khóa_Bibtex_bị_lặp_lại
+Copy_BibTeX_key_and_title=Sao_chép_khóa_Bibtex_và_danh_hiệu
-Online_help_forum=
+Cleanup_entries=Dọn_dẹp_các_mục
+Manage_keywords=Quản_lý_các_từ_khóa
+Merge_entries=Phối_các_mục_vào
+Open_folder=Mở_thư_mục
+Find_unlinked_files...=Tìm_các_tập_tin_bị_ngắt_liên_kết...
+Hide/show_toolbar=Tắt/Bật_toolbar
-Manage_protected_terms=
+Fork_me_on_GitHub=Nhánh_rẽ_từ_GitHub
+Save_selected_as_plain_BibTeX...=Lưu_phần_chọn_thành_plain_Bibtex...
-Website=
-Blog=
-JabRef_resources=
+Groups=Các_nhóm
+Delete_entry=Xóa_mục
+Check_integrity=Kiểm_tra_tính_nguyên_vẹn
-Development_version=
-View_change_log=
+Quality=Chất_Lượng
+Online_help_forum=Diễn_đàn_trợ_giúp_trực_tuyến
+Manage_protected_terms=Quản_lý_bảo_vệ_thuật_ngữ
+Website=Trang_web
+Blog=Blog
+JabRef_resources=Nguồn_của_JabRef
+Development_version=Phiên_bản_phát_triển
+View_change_log=Xem_nhật_kí_thay_đổi
+Copy_BibTeX_key_and_link=Sao_chép_khóa_BibTex_và_đường_liên_kết
+Copy_DOI_url=Sao_chép_DOI_url
diff --git a/src/main/resources/l10n/Menu_zh.properties b/src/main/resources/l10n/Menu_zh.properties
index 6ac7982..1462777 100644
--- a/src/main/resources/l10n/Menu_zh.properties
+++ b/src/main/resources/l10n/Menu_zh.properties
@@ -1,6 +1,7 @@
#!
-#! created/edited by Popeye version 0.55 (https://github.com/koppor/popeye)
-#! encoding:UTF8
+#! created/edited by Popeye version 0.55 (github.com/JabRef/popeye)
+#! encoding:UTF-8
+
Abbreviate_journal_names_(ISO)=缩写期刊名称_(ISO)
Abbreviate_journal_names_(MEDLINE)=缩写期刊名称_(MEDLINE)
About_JabRef=关于_JabRef_(&A)
@@ -27,15 +28,17 @@ Find_duplicates=查找重复记录_(&F)
Help=帮助_(&H)
Highlight_groups_matching_all_selected_entries=高亮显示包含所有选中记录的分组
Highlight_groups_matching_any_selected_entry=高亮显示包含任一选中记录的分组
+Disable_highlight_groups_matching_entries=禁用高亮显示包含选中记录的分组
# Help
-Online_help=
-Manage_content_selectors=管理内容下拉菜单_(&C)
+Online_help=在线帮助
+Donate_to_JabRef=捐款给_JabRef
Manage_custom_exports=管理自定义导出器_(&M)
Manage_custom_imports=管理自定义导入器_(&I)
Manage_journal_abbreviations=管理期刊名缩写规则_(&J)
Mark_entries=高亮标记选中记录_(&M)
# File menu
+New_%0_database=新建_%0_数据库
# Menu BibTeX (BibTeX)
New_entry=新建记录向导_(&e)
New_entry_by_type...=新建记录_(&N)...
@@ -45,7 +48,7 @@ New_subdatabase_based_on_AUX_file=根据_AU&X_文件新建子数据库
Next_tab=下一标签页_(&N)
Open_database=打开数据库_(&O)
Open_URL_or_DOI=打开_&URL_或_DOI
-Open_shared_database=
+Connect_to_shared_database=连接到共享数据库
Open_terminal_here=在此处打开终端
Options=选项_(&O)
Paste=粘贴_(&P)
@@ -53,7 +56,7 @@ Paste=粘贴_(&P)
Preferences=首选项_(&P)
Previous_tab=上一标签页_(&P)
Quit=退出_(&Q)
-Recent_files=最近打开的文件_(&R)
+Recent_databases=最近打开的文件_(&R)
Redo=重做_(&R)
Replace_string=替换字符串_(&R)
Save_database=保存数据库_(&S)
@@ -64,9 +67,9 @@ Search=查找_(&S)
Select_all=全选_(&A)
Set_up_general_fields=配置_&general_域
Show_error_console=打开错误显示终端
-
Sort_tabs=标签页排序_(&S)
-Switch_preview_layout=切换记录预览方式_(&S)
+Next_preview_layout=下一个预览布局
+Previous_preview_layout=上一个预览布局
# Export menu
Toggle_entry_preview=打开/关闭记录预览_(&T)
Toggle_groups_interface=打开/关闭分组界面_(&G)
@@ -74,15 +77,16 @@ Tools=工具_(&T)
Unabbreviate_journal_names=展开期刊名称
# Edit
Undo=撤销_(&U)
+Mark_specific_color=用指定颜色标记_(&a)
Unmark_all=撤销所有高亮标记_(&L)
Unmark_entries=撤销选中高亮标记_(&N)
View=视图_(&V)
Import_into_new_database=导入到新数据库
Import_into_current_database=导入到当前数据库
-
+Switch_to_%0_mode=切换到_%0_模式
Push_entries_to_external_application_(%0)=推送选中记录到外部程序_(%0)
-Pull_changes_from_shared_database=
+Pull_changes_from_shared_database=从共享数据库更新数据
Write_XMP-metadata_to_PDFs=将_XMP_元数据写入到_PDF_中
Export_selected_entries=导出选中记录
@@ -100,11 +104,9 @@ Decrease_table_font_size=缩小列表字体_(&D)
Forward=前进
Back=后退
-Look_up_full_text_document=查找完整文档
-
+Look_up_full_text_documents=
Set/clear/rename_fields=设置/清除/重命名_域
-Mark_specific_color=用指定颜色标记_(&a)
Resolve_duplicate_BibTeX_keys=处理重复的_BibTeX_键值
Copy_BibTeX_key_and_title=复制_BibTeX_键值和标题
@@ -113,33 +115,22 @@ Manage_keywords=管理关键词
Merge_entries=合并记录
Open_folder=打开文件夹
Find_unlinked_files...=查询未被(记录)链接的文件
-
Hide/show_toolbar=隐藏/显示工具栏
Fork_me_on_GitHub=去_GitHub_Fork_JabRef
Save_selected_as_plain_BibTeX...=选择记录另存为_BibTeX_纯文本...
-Donate_to_JabRef=捐款给_JabRef
-
Groups=分组
Delete_entry=删除该记录
-
-Switch_to_%0_mode=切换到_%0_模式
Check_integrity=完整性检查
Quality=质量
-
-New_%0_database=新建_%0_数据库
-
-Disable_highlight_groups_matching_entries=禁用高亮显示包含选中记录的分组
-
-Online_help_forum=
-
-Manage_protected_terms=
-
-Website=
-Blog=
-JabRef_resources=
-
-Development_version=
-View_change_log=
+Online_help_forum=在线讨论区
+Manage_protected_terms=管理受保护的术语
+Website=网站
+Blog=博客
+JabRef_resources=JabRef_资源
+Development_version=开发中版本
+View_change_log=查看变更记录
+Copy_BibTeX_key_and_link=拷贝_BibTeX_key_和链接
+Copy_DOI_url=拷贝_DOI_URL
diff --git a/src/main/resources/resource/layout/bibtexml.begin.layout b/src/main/resources/resource/layout/bibtexml.begin.layout
deleted file mode 100644
index 140a9b8..0000000
--- a/src/main/resources/resource/layout/bibtexml.begin.layout
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" ?>
-<bibtex:file xmlns:bibtex="http://bibtexml.sf.net/">
-<!-- This file was exported from JabRef jabref.sf.net -->
-<!-- 2006-01-17 added DOI XML character formatting, because DOI can contain < and > -->
-
diff --git a/src/main/resources/resource/layout/bibtexml.end.layout b/src/main/resources/resource/layout/bibtexml.end.layout
deleted file mode 100644
index 0447a2f..0000000
--- a/src/main/resources/resource/layout/bibtexml.end.layout
+++ /dev/null
@@ -1 +0,0 @@
-</bibtex:file>
diff --git a/src/main/resources/resource/layout/bibtexml.layout b/src/main/resources/resource/layout/bibtexml.layout
deleted file mode 100644
index 2d582f6..0000000
--- a/src/main/resources/resource/layout/bibtexml.layout
+++ /dev/null
@@ -1,36 +0,0 @@
-<bibtex:entry id="\bibtexkey">
- <bibtex:\format[ToLowerCase]{\entrytype}>
-\begin{author} <bibtex:author>\format[XMLChars,AuthorFirstFirst]{\author}</bibtex:author>\end{author}
-\begin{editor} <bibtex:editor>\format[XMLChars,AuthorFirstFirst]{\editor}</bibtex:editor>\end{editor}
-\begin{title} <bibtex:title>\format[XMLChars]{\title}</bibtex:title>\end{title}
-\begin{booktitle} <bibtex:booktitle>\format[XMLChars]{\booktitle}</bibtex:booktitle>\end{booktitle}
-\begin{journal} <bibtex:journal>\format[XMLChars]{\journal}</bibtex:journal>\end{journal}
-\begin{publisher} <bibtex:publisher>\format[XMLChars]{\publisher}</bibtex:publisher>\end{publisher}
-\begin{year} <bibtex:year>\year</bibtex:year>\end{year}
-\begin{volume} <bibtex:volume>\format[XMLChars]{\volume}</bibtex:volume>\end{volume}
-\begin{month} <bibtex:month>\format[XMLChars]{\month}</bibtex:month>\end{month}
-\begin{chapter} <bibtex:chapter>\format[XMLChars]{\chapter}</bibtex:chapter>\end{chapter}
-\begin{pages} <bibtex:pages>\format[FormatPagesForXML]{\pages}</bibtex:pages>\end{pages}
-\begin{number} <bibtex:number>\format[XMLChars]{\number}</bibtex:number>\end{number}
-\begin{edition} <bibtex:edition>\format[XMLChars]{\edition}</bibtex:edition>\end{edition}
-\begin{series} <bibtex:series>\format[XMLChars]{\series}</bibtex:series>\end{series}
-\begin{institution} <bibtex:institution>\format[XMLChars]{\institution}</bibtex:institution>\end{institution}
-\begin{organization} <bibtex:organization>\format[XMLChars]{\organization}</bibtex:organization>\end{organization}
-\begin{school} <bibtex:school>\format[XMLChars]{\school}</bibtex:school>\end{school}
-\begin{address} <bibtex:address>\format[XMLChars]{\address}</bibtex:address>\end{address}
-\begin{howpublished} <bibtex:howpublished>\format[XMLChars]{\howpublished}</bibtex:howpublished>\end{howpublished}
-\begin{abstract} <bibtex:abstract>\format[XMLChars]{\abstract}</bibtex:abstract>\end{abstract}
-\begin{url} <bibtex:url>\format[XMLChars]{\url}</bibtex:url>\end{url}
-\begin{doi} <bibtex:doi>\format[DOIStrip,XMLChars]{\doi}</bibtex:doi>\end{doi}
-\begin{eid} <bibtex:eid>\format[XMLChars]{\eid}</bibtex:eid>\end{eid}
-\begin{type} <bibtex:type>\format[XMLChars]{\type}</bibtex:type>\end{type}
-\begin{crossref} <bibtex:crossref>\format[XMLChars]{\crossref}</bibtex:crossref>\end{crossref}
-\begin{annote} <bibtex:annote>\format[XMLChars]{\annote}</bibtex:annote>\end{annote}
-\begin{keywords} <bibtex:keywords>\format[XMLChars]{\keywords}</bibtex:keywords>\end{keywords}
-\begin{comment} <bibtex:comment>\format[XMLChars]{\comment}</bibtex:comment>\end{comment}
-\begin{note} <bibtex:note>\format[XMLChars]{\note}</bibtex:note>\end{note}
-\begin{key} <bibtex:key>\format[XMLChars]{\key}</bibtex:key>\end{key}
-\begin{review} <bibtex:nstandard name="review">\format[XMLChars]{\review}</bibtex:nstandard>\end{review}
-\begin{file}\format[WrapFileLinks( <bibtex:nstandard name="file" type="\x" description="\d">\p</bibtex:nstandard>\n)]{\file}\end{file}
- </bibtex:\format[ToLowerCase]{\entrytype}>
-</bibtex:entry>
diff --git a/src/main/resources/resource/ods/meta.xml b/src/main/resources/resource/ods/meta.xml
index f249a95..30af36f 100644
--- a/src/main/resources/resource/ods/meta.xml
+++ b/src/main/resources/resource/ods/meta.xml
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
-<office:document-meta xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" office:version="1.0">
+<office:document-meta xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
+ xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" office:version="1.0">
<office:meta>
<meta:generator>JabRef version ${version}
</meta:generator>
@@ -11,4 +12,4 @@
<meta:user-defined meta:name="Info 4"/>
<!-- <meta:document-statistic meta:table-count="3" meta:cell-count="4"/>-->
</office:meta>
-</office:document-meta>
\ No newline at end of file
+</office:document-meta>
diff --git a/src/main/resources/resource/ods/settings.xml b/src/main/resources/resource/ods/settings.xml
index 711c200..2c778e8 100644
--- a/src/main/resources/resource/ods/settings.xml
+++ b/src/main/resources/resource/ods/settings.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
-<office:document-settings xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" office:version="1.0">
+<office:document-settings xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" office:version="1.0">
-</office:document-settings>
\ No newline at end of file
+</office:document-settings>
diff --git a/src/main/resources/resource/openoffice/default_authoryear.jstyle b/src/main/resources/resource/openoffice/default_authoryear.jstyle
index a4ede87..e0c5b24 100644
--- a/src/main/resources/resource/openoffice/default_authoryear.jstyle
+++ b/src/main/resources/resource/openoffice/default_authoryear.jstyle
@@ -1,5 +1,4 @@
-# Written by Morten O. Alver.
-# This file is licensed under the terms of the GPL version 2 (or later).
+# SPDX-License-Identifier: MIT
NAME
Default [Author year] style file
diff --git a/src/main/resources/resource/openoffice/default_numerical.jstyle b/src/main/resources/resource/openoffice/default_numerical.jstyle
index 11693c1..047caee 100644
--- a/src/main/resources/resource/openoffice/default_numerical.jstyle
+++ b/src/main/resources/resource/openoffice/default_numerical.jstyle
@@ -1,5 +1,4 @@
-# Written by Morten O. Alver.
-# This file is licensed under the terms of the GPL version 2 (or later).
+# SPDX-License-Identifier: MIT
NAME
Default [number] style file.
diff --git a/src/main/resources/resource/openoffice/meta.xml b/src/main/resources/resource/openoffice/meta.xml
index da66cea..9a5b669 100644
--- a/src/main/resources/resource/openoffice/meta.xml
+++ b/src/main/resources/resource/openoffice/meta.xml
@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE office:document-meta PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "office.dtd">
-<office:document-meta xmlns:office="http://openoffice.org/2000/office" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="http://openoffice.org/2000/meta" office:version="1.0">
+<office:document-meta xmlns:office="http://openoffice.org/2000/office" xmlns:meta="http://openoffice.org/2000/meta"
+ office:version="1.0">
<office:meta>
<meta:generator>JabRef ${version}</meta:generator>
</office:meta>
-</office:document-meta>
\ No newline at end of file
+</office:document-meta>
diff --git a/src/main/resources/xjc/mods/mods-3-6.xsd b/src/main/resources/xjc/mods/mods-3-6.xsd
new file mode 100644
index 0000000..5c536f8
--- /dev/null
+++ b/src/main/resources/xjc/mods/mods-3-6.xsd
@@ -0,0 +1,1513 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Source: www.loc.gov/standards/mods/mods-schemas.html. -->
+<!-- Editor: Ray Denenberg, Library of Congress; rden at loc.gov -->
+<xs:schema xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://www.loc.gov/mods/v3" targetNamespace="http://www.loc.gov/mods/v3" elementFormDefault="qualified" attributeFormDefault="unqualified">
+ <!-- -->
+ <xs:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="http://www.loc.gov/mods/xml.xsd"/>
+ <xs:import namespace="http://www.w3.org/1999/xlink" schemaLocation="http://www.loc.gov/standards/xlink/xlink.xsd"/>
+ <!--
+MODS: Metadata Object Description Schema. See http://www.loc.gov/standards/mods/
+
+ ****************************************************************
+ *
+ * MODS 3.6
+ *
+ * May 5, 2015
+ *
+ *****************************************************************w
+
+
+***************************************************
+Changes in version 3.6
+1. nonSort definition revised in 3.6. to add attribute @xml:space.
+
+2. HierarchicalGeographic enhancements.
+ - <province> depricated in favor of <state> (<state> re-defined in guidelines)
+ - Attributes @areaType, @regionType, and @citySectionType
+ defined for elements <area>, <region>, and <citySection>
+ - Attribute @level defined for all place type elements to indicate hierarchical level.
+ - Authority attributeGroup added to all place type elements.
+ - Attribute @period defined. Indicates that the described entity once existed but no longer exists.
+
+3. Four new attributes for <relatedItem>
+ • @otherType
+ • @otherTypeAuth
+ • @otherTypeAuthURI
+ • @otherTypeURI
+
+
+4. New element <nameIdentifier>, subelement of <name>, re-using the existing <identifier> definition
+
+
+5. <cartographics>(subelement of <subject>) is made extensible.
+
+
+6. New element <recordInfoNote>, subelement of <recordInfo>, re-using the existing <note> definition
+
+7. New element <itemIdentifier>, subelement of <location><physicalLocation><holdingSimple><copyInformation>
+ with attribute @type, for example:
+ <itemIdentifer type="barcode">
+ <itemIdentifier type="copyNumber">
+ <itemIdentifier type="accessionNumber">
+
+*********************************************************************************************
+
+ *************************************
+ Organization of this schema
+ *************************************
+The schema has three parts:
+
+1. Structural declarations and definitions
+2. Elements (top level elements and their subelements)
+3. Auxiliary Definitions
+
+ ***********************************************************************
+ ***********************************************************************
+ Part 1: Structural Declarations and Definitions
+ ***********************************************************************
+ ***********************************************************************
+- Definition of a single MODS record and a MODS collection
+- modsGroup, listing the top level MODS elements
+
+***********************************************************************
+** Definition of a single MODS record **
+**********************************************************************
+-->
+ <xs:element name="mods" type="modsDefinition"/>
+ <!-- -->
+ <xs:complexType name="modsDefinition">
+ <xs:group ref="modsGroup" maxOccurs="unbounded"/>
+ <xs:attribute name="ID" type="xs:ID"/>
+ <xs:attribute name="version">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="3.6"/>
+ <xs:enumeration value="3.5"/>
+ <xs:enumeration value="3.4"/>
+ <xs:enumeration value="3.3"/>
+ <xs:enumeration value="3.2"/>
+ <xs:enumeration value="3.1"/>
+ <xs:enumeration value="3.0"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ </xs:complexType>
+ <!--
+***********************************************************************
+** Definition of a MODS collection **
+**********************************************************************
+-->
+ <xs:element name="modsCollection" type="modsCollectionDefinition"/>
+ <!-- -->
+ <xs:complexType name="modsCollectionDefinition">
+ <xs:sequence>
+ <xs:element ref="mods" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ <!--
+
+************************************************
+** Group Definition
+***********************************************
+This forms the basis of the mods record definition, and also relatedItem.
+The difference between a MODS record and a relatedItem
+(as they pertain to their usage of the group definition)
+is that mods requires at least one element and relatedItem does not.
+The group definition is used by both, where relatedItem says
+minOccurs="0" and for the mods record definition minOccurs="1" (default).
+
+-->
+ <xs:group name="modsGroup">
+ <xs:choice>
+ <!--
+***********************************************************************
+** These are the "top level" MODS elements **
+**********************************************************************
+-->
+ <xs:element ref="abstract"/>
+ <xs:element ref="accessCondition"/>
+ <xs:element ref="classification"/>
+ <xs:element ref="extension"/>
+ <xs:element ref="genre"/>
+ <xs:element ref="identifier"/>
+ <xs:element ref="language"/>
+ <xs:element ref="location"/>
+ <xs:element ref="name"/>
+ <xs:element ref="note"/>
+ <xs:element ref="originInfo"/>
+ <xs:element ref="part"/>
+ <xs:element ref="physicalDescription"/>
+ <xs:element ref="recordInfo"/>
+ <xs:element ref="relatedItem"/>
+ <xs:element ref="subject"/>
+ <xs:element ref="tableOfContents"/>
+ <xs:element ref="targetAudience"/>
+ <xs:element ref="titleInfo"/>
+ <xs:element ref="typeOfResource"/>
+ <!--
+End list of "top level" MODS elements
+-->
+ </xs:choice>
+ </xs:group>
+ <!--
+ ***********************************************************************
+ ***********************************************************************
+ Part 2: Elements (top level elements and their subelements)
+ ************************************************************************
+ ***********************************************************************
+-->
+ <!--
+*********************************************
+* Top Level Element <abstract> *
+*********************************************
+ -->
+ <xs:element name="abstract" type="abstractDefinition"/>
+ <!-- -->
+ <xs:complexType name="abstractDefinition">
+ <xs:simpleContent>
+ <xs:extension base="stringPlusLanguage">
+ <xs:attribute name="displayLabel" type="xs:string"/>
+ <xs:attribute name="type" type="xs:string"/>
+ <xs:attributeGroup ref="xlink:simpleLink"/>
+ <xs:attribute name="shareable" fixed="no"/>
+ <xs:attribute name="altRepGroup" type="xs:string"/>
+ <xs:attributeGroup ref="altFormatAttributeGroup"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <!--
+
+****************************************************
+* Top Level Element <accessCondition> *
+*****************************************************
+ -->
+ <xs:element name="accessCondition" type="accessConditionDefinition"/>
+ <!-- -->
+ <xs:complexType name="accessConditionDefinition" mixed="true">
+ <xs:complexContent mixed="true">
+ <xs:extension base="extensionDefinition">
+ <xs:attributeGroup ref="xlink:simpleLink"/>
+ <xs:attributeGroup ref="languageAttributeGroup"/>
+ <xs:attribute name="type" type="xs:string"/>
+ <xs:attribute name="altRepGroup" type="xs:string"/>
+ <xs:attributeGroup ref="altFormatAttributeGroup"/>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ <!--
+****************************************************
+* Top Level Element <classification> *
+*****************************************************
+-->
+ <xs:element name="classification" type="classificationDefinition"/>
+ <!-- -->
+ <xs:complexType name="classificationDefinition">
+ <xs:simpleContent>
+ <xs:extension base="stringPlusLanguagePlusAuthority">
+ <xs:attribute name="edition" type="xs:string"/>
+ <xs:attribute name="displayLabel" type="xs:string"/>
+ <xs:attribute name="altRepGroup" type="xs:string"/>
+ <xs:attribute name="usage" fixed="primary"/>
+ <xs:attribute name="generator" type="xs:string"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <!--
+****************************************************
+* Top Level Element <extension> *
+*****************************************************
+ -->
+ <xs:element name="extension" type="extensionDefinition"/>
+ <!-- -->
+ <xs:complexType name="extensionDefinition" mixed="true">
+ <xs:sequence>
+ <xs:any processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="displayLabel" type="xs:string"/>
+ </xs:complexType>
+ <!--
+****************************************************
+* Top Level Element <genre> *
+*****************************************************
+-->
+ <xs:element name="genre" type="genreDefinition"/>
+ <!-- -->
+ <xs:complexType name="genreDefinition">
+ <xs:simpleContent>
+ <xs:extension base="stringPlusLanguagePlusAuthority">
+ <xs:attribute name="type" type="xs:string"/>
+ <xs:attribute name="displayLabel" type="xs:string"/>
+ <xs:attribute name="altRepGroup" type="xs:string"/>
+ <xs:attribute name="usage" fixed="primary"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <!--
+****************************************************
+* Top Level Element <identifier> *
+*****************************************************
+-->
+ <xs:element name="identifier" type="identifierDefinition"/>
+ <!-- -->
+ <xs:complexType name="identifierDefinition">
+ <xs:simpleContent>
+ <xs:extension base="stringPlusLanguage">
+ <xs:attribute name="displayLabel" type="xs:string"/>
+ <xs:attribute name="type" type="xs:string"/>
+ <xs:attribute name="typeURI" type="xs:anyURI"/>
+ <xs:attribute name="invalid" fixed="yes"/>
+ <xs:attribute name="altRepGroup" type="xs:string"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <!--
+****************************************************
+* Top Level Element <language> *
+*****************************************************
+-->
+ <xs:element name="language" type="languageDefinition"/>
+ <!-- -->
+ <xs:complexType name="languageDefinition">
+ <xs:sequence>
+ <xs:element ref="languageTerm" maxOccurs="unbounded"/>
+ <xs:element ref="scriptTerm" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="objectPart" type="xs:string"/>
+ <xs:attributeGroup ref="languageAttributeGroup"/>
+ <xs:attribute name="displayLabel" type="xs:string"/>
+ <xs:attribute name="altRepGroup" type="xs:string"/>
+ <xs:attribute name="usage" fixed="primary"/>
+ </xs:complexType>
+ <!--
+
+******** Subordinate Elements for <language>
+ -->
+ <xs:element name="languageTerm" type="languageTermDefinition"/>
+ <!-- -->
+ <xs:complexType name="languageTermDefinition">
+ <xs:simpleContent>
+ <xs:extension base="stringPlusLanguage">
+ <xs:attribute name="authorityURI" type="xs:anyURI"/>
+ <xs:attribute name="valueURI" type="xs:anyURI"/>
+ <xs:attribute name="authority">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="rfc3066"/>
+ <xs:enumeration value="iso639-2b"/>
+ <xs:enumeration value="iso639-3"/>
+ <xs:enumeration value="rfc4646"/>
+ <xs:enumeration value="rfc5646"/>
+ <!-- -->
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="type" type="codeOrText"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <!--
+*****************scriptTerm ************************
+-->
+ <xs:element name="scriptTerm" type="scriptTermDefinition"/>
+ <!-- -->
+ <xs:complexType name="scriptTermDefinition">
+ <xs:simpleContent>
+ <xs:extension base="stringPlusLanguagePlusAuthority">
+ <xs:attribute name="type" type="codeOrText"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <!--
+
+****************************************************
+* Top Level Element <location> *
+*****************************************************
+ -->
+ <xs:element name="location" type="locationDefinition"/>
+ <!-- -->
+ <xs:complexType name="locationDefinition">
+ <xs:sequence>
+ <xs:element ref="physicalLocation" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element ref="shelfLocator" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element ref="url" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element ref="holdingSimple" minOccurs="0"/>
+ <xs:element ref="holdingExternal" minOccurs="0"/>
+ </xs:sequence>
+ <xs:attributeGroup ref="languageAttributeGroup"/>
+ <xs:attribute name="displayLabel" type="xs:string"/>
+ <xs:attribute name="altRepGroup" type="xs:string"/>
+ </xs:complexType>
+ <!--
+
+******** Subordinate Elements for <location>
+ -->
+ <!--
+********** physicalLocation **********
+-->
+ <xs:element name="physicalLocation" type="physicalLocationDefinition"/>
+ <!-- -->
+ <xs:complexType name="physicalLocationDefinition">
+ <xs:simpleContent>
+ <xs:extension base="stringPlusLanguagePlusAuthority">
+ <xs:attributeGroup ref="xlink:simpleLink"/>
+ <xs:attribute name="displayLabel" type="xs:string"/>
+ <xs:attribute name="type" type="xs:string"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <!-- -->
+ <xs:element name="shelfLocator" type="stringPlusLanguage"/>
+ <!--
+********** holdingSimple **********
+ -->
+ <xs:element name="holdingSimple" type="holdingSimpleDefinition"/>
+ <!-- -->
+ <xs:complexType name="holdingSimpleDefinition">
+ <xs:sequence>
+ <xs:element ref="copyInformation" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ <!--
+**********copyInformation **********
+ -->
+ <xs:element name="copyInformation" type="copyInformationDefinition"/>
+ <!-- -->
+ <xs:complexType name="copyInformationDefinition">
+ <xs:sequence>
+ <xs:element ref="form" minOccurs="0"/>
+ <xs:element ref="subLocation" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element ref="shelfLocator" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element ref="electronicLocator" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="note" minOccurs="0" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:simpleContent>
+ <xs:extension base="stringPlusLanguage">
+ <xs:attribute name="displayLabel" type="xs:string"/>
+ <xs:attribute name="type" type="xs:string"/>
+ <xs:attributeGroup ref="xlink:simpleLink"/>
+ <xs:attribute name="ID" type="xs:ID"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ </xs:element>
+ <xs:element ref="enumerationAndChronology" minOccurs="0" maxOccurs="unbounded"/>
+ <!--
+ ******************the following element <itemIdentifer> added in 3.6 -->
+ <xs:element ref="itemIdentifier" minOccurs="0" maxOccurs="unbounded"/>
+ <!-- -->
+ </xs:sequence>
+ </xs:complexType>
+
+
+ <!-- following definition is new in 3.6 -->
+ <xs:element name="itemIdentifier" type="itemIdentifierDefinition"/>
+ <xs:complexType name="itemIdentifierDefinition">
+ <xs:simpleContent>
+ <xs:extension base="stringPlusLanguage">
+ <xs:attribute name="type" type="xs:string"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <!--
+**********form**********
+ -->
+ <xs:element name="form" type="formDefinition"/>
+ <!-- -->
+ <xs:complexType name="formDefinition">
+ <xs:simpleContent>
+ <xs:extension base="stringPlusLanguagePlusAuthority">
+ <xs:attribute name="type" type="xs:string"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <!-- -->
+ <xs:element name="subLocation" type="stringPlusLanguage"/>
+ <xs:element name="electronicLocator" type="stringPlusLanguage"/>
+ <!--
+**********enumerationAndChronology **********
+ -->
+ <xs:element name="enumerationAndChronology" type="enumerationAndChronologyDefinition"/>
+ <!-- -->
+ <xs:complexType name="enumerationAndChronologyDefinition">
+ <xs:simpleContent>
+ <xs:extension base="stringPlusLanguage">
+ <xs:attribute name="unitType">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="1"/>
+ <xs:enumeration value="2"/>
+ <xs:enumeration value="3"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <!--
+ ********** url **********
+ -->
+ <xs:element name="url" type="urlDefinition"/>
+ <!-- -->
+ <xs:complexType name="urlDefinition">
+ <xs:simpleContent>
+ <xs:extension base="xs:anyURI">
+ <xs:attribute name="dateLastAccessed" type="xs:string"/>
+ <xs:attribute name="displayLabel" type="xs:string"/>
+ <xs:attribute name="note" type="xs:string"/>
+ <xs:attribute name="access">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="preview"/>
+ <xs:enumeration value="raw object"/>
+ <xs:enumeration value="object in context"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="usage">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="primary display"/>
+ <xs:enumeration value="primary"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <!-- -->
+ <xs:element name="holdingExternal" type="extensionDefinition"/>
+ <!--
+****************************************************
+* Top Level Element <name> *
+*****************************************************
+-->
+ <xs:element name="name" type="nameDefinition"/>
+ <!-- -->
+ <xs:complexType name="nameDefinition">
+ <xs:choice>
+
+ <!-- this choice give two ways to do this.
+ The second way allows the element <etal>, to express "et. al."
+
+Choice one. WITHOUT <etal>.
+-->
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element ref="namePart"/>
+ <xs:element ref="displayForm"/>
+ <xs:element ref="affiliation"/>
+ <xs:element ref="role"/>
+ <xs:element ref="description"/>
+ <!--
+ the following element, <nameIdentifier>, is introduced in version 3.6,
+ to allow the inclusion of an identifier for the object named by this <name>.
+ It is typed as "indentifierDefinition", the same definition that
+ top-level element <identifier> uses.
+ -->
+ <xs:element ref="nameIdentifier"/>
+ <!-- -->
+ </xs:choice>
+ <!--
+Choice two. With <etal>.
+ The presence of <etal> indicates that there are names that cannot
+ be explicitily included. It may be empty, or it may have simple content
+ - e.g. <etal>et al.</etal>. In the latter case the content is what is
+ suggested for display.
+ When <etal> occurs:
+ - <namePart>, <displayForm>, and <identifier> MAY NOT occur;
+ - <affiliation>, <role>, <description> MAY occur (but are NOT repeatable).
+ <etal> is not repeatable within a given <name>, however there may be
+ mutilple <etal> elements, each within in a separate <name> element.
+-->
+ <xs:sequence>
+ <!--
+ <etal> is mandatory, nonrepeatable, and must occur first.
+ After that <affiliation>, <role>, and <description> may occur, in any order or number.
+ <nameIdentifier> is not used with <etal>
+-->
+ <xs:element ref="etal"/>
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element ref="affiliation"/>
+ <xs:element ref="role"/>
+ <xs:element ref="description"/>
+ </xs:choice>
+ </xs:sequence>
+ <!-- -->
+ </xs:choice>
+ <xs:attribute name="ID" type="xs:ID"/>
+ <xs:attributeGroup ref="authorityAttributeGroup"/>
+ <xs:attributeGroup ref="xlink:simpleLink"/>
+ <xs:attributeGroup ref="languageAttributeGroup"/>
+ <xs:attribute name="displayLabel" type="xs:string"/>
+ <xs:attribute name="altRepGroup" type="xs:string"/>
+ <xs:attribute name="nameTitleGroup" type="xs:string"/>
+ <xs:attribute name="usage" fixed="primary"/>
+ <xs:attribute name="type">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="personal"/>
+ <xs:enumeration value="corporate"/>
+ <xs:enumeration value="conference"/>
+ <xs:enumeration value="family"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ </xs:complexType>
+ <!--
+
+******** Subordinate Elements for <name>
+ -->
+ <!-- namePart-->
+ <xs:element name="namePart" type="namePartDefinition"/>
+ <!-- -->
+ <xs:complexType name="namePartDefinition">
+ <xs:simpleContent>
+ <xs:extension base="stringPlusLanguage">
+ <xs:attribute name="type">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="date"/>
+ <xs:enumeration value="family"/>
+ <xs:enumeration value="given"/>
+ <xs:enumeration value="termsOfAddress"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <!-- displayForm, affiliation, description -->
+ <xs:element name="displayForm" type="stringPlusLanguage"/>
+ <xs:element name="affiliation" type="stringPlusLanguage"/>
+ <xs:element name="description" type="stringPlusLanguage"/>
+ <!-- new in 3.6 -->
+ <!-- nameIdentifier -->
+ <xs:element name="nameIdentifier" type="identifierDefinition"/>
+ <!--
+******** role *********************
+ -->
+ <xs:element name="role" type="roleDefinition"/>
+ <!-- -->
+ <xs:complexType name="roleDefinition">
+ <xs:sequence maxOccurs="unbounded">
+ <xs:element ref="roleTerm"/>
+ </xs:sequence>
+ </xs:complexType>
+ <!--
+***************roleTerm ***********************
+ -->
+ <xs:element name="roleTerm" type="roleTermDefinition"/>
+ <!-- -->
+ <xs:complexType name="roleTermDefinition">
+ <xs:simpleContent>
+ <xs:extension base="stringPlusLanguagePlusAuthority">
+ <xs:attribute name="type" type="codeOrText"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <!--
+******** etal ********
+-->
+ <xs:element name="etal" type="stringPlusLanguage"/>
+ <!--
+
+****************************************************
+* Top Level Element <note> *
+*****************************************************
+-->
+ <xs:element name="note" type="noteDefinition"/>
+ <!-- -->
+ <xs:complexType name="noteDefinition">
+ <xs:simpleContent>
+ <xs:extension base="stringPlusLanguage">
+ <xs:attribute name="displayLabel" type="xs:string"/>
+ <xs:attribute name="type" type="xs:string"/>
+ <xs:attribute name="typeURI" type="xs:anyURI"/>
+ <xs:attributeGroup ref="xlink:simpleLink"/>
+ <xs:attribute name="ID" type="xs:ID"/>
+ <xs:attribute name="altRepGroup" type="xs:string"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <!--
+
+****************************************************
+* Top Level Element <originInfo> *
+*****************************************************
+-->
+ <xs:element name="originInfo" type="originInfoDefinition"/>
+ <!-- -->
+ <xs:complexType name="originInfoDefinition">
+ <xs:choice maxOccurs="unbounded">
+ <xs:element ref="place"/>
+ <xs:element ref="publisher"/>
+ <xs:element ref="dateIssued"/>
+ <xs:element ref="dateCreated"/>
+ <xs:element ref="dateCaptured"/>
+ <xs:element ref="dateValid"/>
+ <xs:element ref="dateModified"/>
+ <xs:element ref="copyrightDate"/>
+ <xs:element ref="dateOther"/>
+ <xs:element ref="edition"/>
+ <xs:element ref="issuance"/>
+ <xs:element ref="frequency"/>
+ </xs:choice>
+ <xs:attributeGroup ref="languageAttributeGroup"/>
+ <xs:attribute name="displayLabel" type="xs:string"/>
+ <xs:attribute name="altRepGroup" type="xs:string"/>
+ <xs:attribute name="eventType" type="xs:string"/>
+ </xs:complexType>
+ <!--
+
+******** Subordinate Elements for <originInfo>
+ -->
+ <!--
+*** place ***
+-->
+ <xs:element name="place" type="placeDefinition"/>
+ <!-- -->
+ <xs:complexType name="placeDefinition">
+ <xs:sequence>
+ <xs:element ref="placeTerm" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="supplied" fixed="yes"/>
+ </xs:complexType>
+ <!--
+*** placeTerm ***
+-->
+ <xs:element name="placeTerm" type="placeTermDefinition"/>
+ <!-- -->
+ <xs:complexType name="placeTermDefinition">
+ <xs:simpleContent>
+ <xs:extension base="stringPlusLanguage">
+ <xs:attribute name="authorityURI" type="xs:anyURI"/>
+ <xs:attribute name="valueURI" type="xs:anyURI"/>
+ <xs:attribute name="authority">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="marcgac"/>
+ <xs:enumeration value="marccountry"/>
+ <xs:enumeration value="iso3166"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="type" type="codeOrText"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <!--
+*** publisher ***
+-->
+ <xs:element name="publisher" type="stringPlusLanguagePlusSupplied"/>
+ <!--
+********** dates **********
+-->
+ <xs:element name="dateIssued" type="dateDefinition"/>
+ <xs:element name="dateCreated" type="dateDefinition"/>
+ <xs:element name="dateCaptured" type="dateDefinition"/>
+ <xs:element name="dateValid" type="dateDefinition"/>
+ <xs:element name="dateModified" type="dateDefinition"/>
+ <xs:element name="copyrightDate" type="dateDefinition"/>
+ <xs:element name="dateOther" type="dateOtherDefinition"/>
+ <!-- -->
+ <xs:complexType name="dateDefinition">
+ <xs:simpleContent>
+ <xs:extension base="stringPlusLanguage">
+ <xs:attribute name="encoding">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="w3cdtf"/>
+ <xs:enumeration value="iso8601"/>
+ <xs:enumeration value="marc"/>
+ <xs:enumeration value="temper"/>
+ <xs:enumeration value="edtf"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="qualifier">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="approximate"/>
+ <xs:enumeration value="inferred"/>
+ <xs:enumeration value="questionable"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="point">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="start"/>
+ <xs:enumeration value="end"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="keyDate" fixed="yes"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <!--
+ ********** dateOther **********
+-->
+ <xs:complexType name="dateOtherDefinition">
+ <xs:simpleContent>
+ <xs:extension base="dateDefinition">
+ <xs:attribute name="type" type="xs:string"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <!--
+ ********** edition **********
+-->
+ <xs:element name="edition" type="stringPlusLanguagePlusSupplied"/>
+ <!--
+********** issuance **********
+ -->
+ <xs:element name="issuance" type="issuanceDefinition"/>
+ <!-- -->
+ <xs:simpleType name="issuanceDefinition">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="continuing"/>
+ <xs:enumeration value="monographic"/>
+ <xs:enumeration value="single unit"/>
+ <xs:enumeration value="multipart monograph"/>
+ <xs:enumeration value="serial"/>
+ <xs:enumeration value="integrating resource"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <!--
+ ********** frequency**********
+-->
+ <xs:element name="frequency" type="stringPlusLanguagePlusAuthority"/>
+ <!--
+
+****************************************************
+* Top Level Element <part> *
+*****************************************************
+-->
+ <xs:element name="part" type="partDefinition"/>
+ <!-- -->
+ <xs:complexType name="partDefinition">
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element ref="detail"/>
+ <xs:element name="extent" type="extentDefinition"/>
+ <xs:element ref="date"/>
+ <xs:element ref="text"/>
+ </xs:choice>
+ <xs:attribute name="ID" type="xs:ID"/>
+ <xs:attribute name="type" type="xs:string"/>
+ <xs:attribute name="order" type="xs:integer"/>
+ <xs:attributeGroup ref="languageAttributeGroup"/>
+ <xs:attribute name="displayLabel" type="xs:string"/>
+ <xs:attribute name="altRepGroup" type="xs:string"/>
+ </xs:complexType>
+ <!--
+
+******** Subordinate Elements for <part>
+ -->
+ <!--
+********** detail **********
+-->
+ <xs:element name="detail" type="detailDefinition"/>
+ <!-- -->
+ <xs:complexType name="detailDefinition">
+ <xs:choice maxOccurs="unbounded">
+ <xs:element ref="number"/>
+ <xs:element ref="caption"/>
+ <xs:element ref="title"/>
+ </xs:choice>
+ <xs:attribute name="type" type="xs:string"/>
+ <xs:attribute name="level" type="xs:positiveInteger"/>
+ </xs:complexType>
+ <!-- -->
+ <xs:element name="number" type="stringPlusLanguage"/>
+ <xs:element name="caption" type="stringPlusLanguage"/>
+ <!--
+********** extent **********
+-->
+ <xs:complexType name="extentDefinition">
+ <xs:sequence>
+ <xs:element ref="start" minOccurs="0"/>
+ <xs:element ref="end" minOccurs="0"/>
+ <xs:element ref="total" minOccurs="0"/>
+ <xs:element ref="list" minOccurs="0"/>
+ </xs:sequence>
+ <xs:attribute name="unit" type="xs:string"/>
+ </xs:complexType>
+ <!-- -->
+ <xs:element name="start" type="stringPlusLanguage"/>
+ <xs:element name="end" type="stringPlusLanguage"/>
+ <xs:element name="total" type="xs:positiveInteger"/>
+ <xs:element name="list" type="stringPlusLanguage"/>
+ <!--
+***************** date ***
+-->
+ <xs:element name="date" type="dateDefinition"/>
+ <!--
+***************** text ***
+-->
+ <xs:element name="text">
+ <xs:complexType>
+ <xs:simpleContent>
+ <xs:extension base="stringPlusLanguage">
+ <xs:attribute name="displayLabel" type="xs:string"/>
+ <xs:attribute name="type" type="xs:string"/>
+ <xs:attributeGroup ref="xlink:simpleLink"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ </xs:element>
+ <!--
+
+****************************************************
+* Top Level Element <physicalDescription> *
+*****************************************************
+ -->
+ <xs:element name="physicalDescription" type="physicalDescriptionDefinition"/>
+ <!-- -->
+ <xs:complexType name="physicalDescriptionDefinition">
+ <xs:choice maxOccurs="unbounded">
+ <xs:element ref="form"/>
+ <!-- same definition as is used in copyInformation -->
+ <xs:element ref="reformattingQuality"/>
+ <xs:element ref="internetMediaType"/>
+ <xs:element ref="extent"/>
+ <xs:element ref="digitalOrigin"/>
+ <xs:element name="note" type="physicalDescriptionNote"/>
+ </xs:choice>
+ <xs:attributeGroup ref="languageAttributeGroup"/>
+ <xs:attribute name="displayLabel" type="xs:string"/>
+ <xs:attribute name="altRepGroup" type="xs:string"/>
+ </xs:complexType>
+ <!--
+
+******** Subordinate Elements for <physicalDescription>
+ -->
+ <!--
+**********reformattingQuality **********
+ -->
+ <xs:element name="reformattingQuality" type="reformattingQualityDefinition"/>
+ <!-- -->
+ <xs:simpleType name="reformattingQualityDefinition">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="access"/>
+ <xs:enumeration value="preservation"/>
+ <xs:enumeration value="replacement"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <!--
+**********internetMediaType **********
+ -->
+ <xs:element name="internetMediaType" type="stringPlusLanguage"/>
+ <!--
+********** extent **********
+ -->
+ <xs:element name="extent">
+ <xs:complexType>
+ <xs:simpleContent>
+ <xs:extension base="stringPlusLanguagePlusSupplied">
+ <xs:attribute name="unit"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ </xs:element>
+ <!--
+********** digitalOrigin **********
+ -->
+ <xs:element name="digitalOrigin" type="digitalOriginDefinition"/>
+ <!-- -->
+ <xs:simpleType name="digitalOriginDefinition">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="born digital"/>
+ <xs:enumeration value="reformatted digital"/>
+ <xs:enumeration value="digitized microfilm"/>
+ <xs:enumeration value="digitized other analog"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <!--
+********** note **********
+ -->
+ <xs:complexType name="physicalDescriptionNote">
+ <xs:simpleContent>
+ <xs:extension base="stringPlusLanguage">
+ <xs:attribute name="displayLabel" type="xs:string"/>
+ <xs:attribute name="type" type="xs:string"/>
+ <xs:attribute name="typeURI" type="xs:anyURI"/>
+ <xs:attributeGroup ref="xlink:simpleLink"/>
+ <xs:attribute name="ID" type="xs:ID"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <!--
+****************************************************
+* Top Level Element <recordInfo> *
+*****************************************************
+
+********** recordInfo **********
+-->
+ <xs:element name="recordInfo" type="recordInfoDefinition"/>
+ <!-- -->
+ <xs:complexType name="recordInfoDefinition">
+ <xs:choice maxOccurs="unbounded">
+ <xs:element ref="recordContentSource"/>
+ <xs:element ref="recordCreationDate"/>
+ <xs:element ref="recordChangeDate"/>
+ <xs:element ref="recordIdentifier"/>
+ <xs:element ref="languageOfCataloging"/>
+ <xs:element ref="recordOrigin"/>
+ <xs:element ref="descriptionStandard"/>
+ <!--
+ *****************following added in 3.6 -->
+ <xs:element ref="recordInfoNote"/>
+<!-- -->
+ </xs:choice>
+ <xs:attributeGroup ref="languageAttributeGroup"/>
+ <xs:attribute name="displayLabel" type="xs:string"/>
+ <xs:attribute name="altRepGroup" type="xs:string"/>
+ </xs:complexType>
+ <!--
+
+******** Subordinate Elements for <recordInfo>
+ -->
+ <xs:element name="recordContentSource" type="stringPlusLanguagePlusAuthority"/>
+ <xs:element name="recordCreationDate" type="dateDefinition"/>
+ <xs:element name="recordChangeDate" type="dateDefinition"/>
+ <!--
+ *****************following added in 3.6 -->
+ <xs:element name="recordInfoNote" type="noteDefinition"/>
+ <!--
+********** recordIdentifier
+-->
+ <xs:element name="recordIdentifier" type="recordIdentifierDefinition"/>
+ <!-- -->
+ <xs:complexType name="recordIdentifierDefinition">
+ <xs:simpleContent>
+ <xs:extension base="stringPlusLanguage">
+ <xs:attribute name="source" type="xs:string"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <!-- -->
+ <xs:element name="languageOfCataloging" type="languageDefinition"/>
+ <xs:element name="recordOrigin" type="stringPlusLanguage"/>
+ <xs:element name="descriptionStandard" type="stringPlusLanguagePlusAuthority"/>
+ <!--
+
+****************************************************
+* Top Level Element <relatedItem> *
+*****************************************************
+
+********** relatedItem **********
+-->
+ <xs:element name="relatedItem" type="relatedItemDefinition"/>
+ <!-- -->
+ <xs:complexType name="relatedItemDefinition">
+ <xs:group ref="modsGroup" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:attribute name="type">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="preceding"/>
+ <xs:enumeration value="succeeding"/>
+ <xs:enumeration value="original"/>
+ <xs:enumeration value="host"/>
+ <xs:enumeration value="constituent"/>
+ <xs:enumeration value="series"/>
+ <xs:enumeration value="otherVersion"/>
+ <xs:enumeration value="otherFormat"/>
+ <xs:enumeration value="isReferencedBy"/>
+ <xs:enumeration value="references"/>
+ <xs:enumeration value="reviewOf"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <!--
+ Following four attributes are new in 3.6
+ -->
+ <xs:attribute name="otherType" type="xs:string"/>
+ <xs:attribute name="otherTypeAuth" type="xs:string"/>
+ <xs:attribute name="otherTypeAuthURI" type="xs:string"/>
+ <xs:attribute name="otherTypeURI" type="xs:string"/>
+ <!-- -->
+
+ <xs:attribute name="displayLabel" type="xs:string"/>
+ <xs:attribute name="ID" type="xs:ID"/>
+ <xs:attributeGroup ref="xlink:simpleLink"/>
+
+ </xs:complexType>
+ <!--
+
+****************************************************
+* Top Level Element <subject> *
+*****************************************************
+-->
+ <xs:element name="subject" type="subjectDefinition"/>
+ <!-- -->
+ <xs:complexType name="subjectDefinition">
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element ref="topic"/>
+ <xs:element ref="geographic"/>
+ <xs:element ref="temporal"/>
+ <xs:element name="titleInfo" type="subjectTitleInfoDefinition"/>
+ <xs:element name="name" type="subjectNameDefinition"/>
+ <xs:element ref="geographicCode"/>
+ <xs:element ref="hierarchicalGeographic"/>
+ <xs:element ref="cartographics"/>
+ <xs:element ref="occupation"/>
+ <xs:element ref="genre"/>
+ <!-- uses top-level genre definition -->
+ </xs:choice>
+ <xs:attribute name="ID" type="xs:ID"/>
+ <xs:attributeGroup ref="authorityAttributeGroup"/>
+ <xs:attributeGroup ref="languageAttributeGroup"/>
+ <xs:attributeGroup ref="xlink:simpleLink"/>
+ <xs:attribute name="displayLabel" type="xs:string"/>
+ <xs:attribute name="altRepGroup" type="xs:string"/>
+ <xs:attribute name="usage" fixed="primary"/>
+ </xs:complexType>
+ <!--
+
+******** Subordinate Elements for <subject>
+ -->
+ <!-- topic, geographic -->
+ <xs:element name="topic" type="stringPlusLanguagePlusAuthority"/>
+ <xs:element name="geographic" type="stringPlusLanguagePlusAuthority"/>
+ <!--
+*****************temporal ************************
+ -->
+ <xs:element name="temporal" type="temporalDefinition"/>
+ <!-- -->
+ <xs:complexType name="temporalDefinition">
+ <xs:simpleContent>
+ <xs:extension base="dateDefinition">
+ <xs:attributeGroup ref="authorityAttributeGroup"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <!--
+*****************subjectTitleInfo ************************
+-->
+ <xs:complexType name="subjectTitleInfoDefinition">
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element ref="title"/>
+ <xs:element ref="subTitle"/>
+ <xs:element ref="partNumber"/>
+ <xs:element ref="partName"/>
+ <xs:element ref="nonSort"/>
+ </xs:choice>
+ <xs:attribute name="ID" type="xs:ID"/>
+ <xs:attributeGroup ref="authorityAttributeGroup"/>
+ <xs:attributeGroup ref="xlink:simpleLink"/>
+ <xs:attributeGroup ref="languageAttributeGroup"/>
+ <xs:attribute name="displayLabel" type="xs:string"/>
+ <xs:attribute name="type">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="abbreviated"/>
+ <xs:enumeration value="translated"/>
+ <xs:enumeration value="alternative"/>
+ <xs:enumeration value="uniform"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ </xs:complexType>
+ <!--
+*****************subjectName ************************
+-->
+ <xs:complexType name="subjectNameDefinition">
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element ref="namePart"/>
+ <xs:element ref="displayForm"/>
+ <xs:element ref="affiliation"/>
+ <xs:element ref="role"/>
+ <xs:element ref="description"/>
+<!-- ****** following element <nameIdentifier> new in 3.6. -->
+ <xs:element ref="nameIdentifier"/>
+ <!-- -->
+ </xs:choice>
+ <xs:attribute name="type">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="personal"/>
+ <xs:enumeration value="corporate"/>
+ <xs:enumeration value="conference"/>
+ <xs:enumeration value="family"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="ID" type="xs:ID"/>
+ <xs:attributeGroup ref="authorityAttributeGroup"/>
+ <xs:attributeGroup ref="xlink:simpleLink"/>
+ <xs:attributeGroup ref="languageAttributeGroup"/>
+ <xs:attribute name="displayLabel" type="xs:string"/>
+ </xs:complexType>
+ <!--
+ ********** geographicCode **********
+-->
+ <xs:element name="geographicCode" type="geographicCodeDefinition"/>
+ <!-- -->
+ <xs:complexType name="geographicCodeDefinition">
+ <xs:simpleContent>
+ <xs:extension base="stringPlusLanguage">
+ <xs:attribute name="authorityURI" type="xs:anyURI"/>
+ <xs:attribute name="valueURI" type="xs:anyURI"/>
+ <xs:attribute name="authority">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="marcgac"/>
+ <xs:enumeration value="marccountry"/>
+ <xs:enumeration value="iso3166"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <!--
+********** hierarchicalGeographic **********
+-->
+ <xs:element name="hierarchicalGeographic" type="hierarchicalGeographicDefinition"/>
+ <!-- -->
+ <xs:complexType name="hierarchicalGeographicDefinition">
+ <xs:choice maxOccurs="unbounded">
+ <xs:element ref="extraTerrestrialArea"/>
+ <xs:element ref="continent"/>
+ <xs:element ref="country"/>
+ <xs:element ref="province"/>
+ <!-- province is deprecated in version 3.6. Use <state> instead. -->
+ <xs:element ref="region"/>
+ <xs:element ref="state"/>
+ <!-- <state> definition broadened in 3.6. Use <state> for all first order political divisions, e.g. province. -->
+ <xs:element ref="territory"/>
+ <xs:element ref="county"/>
+ <xs:element ref="city"/>
+ <xs:element ref="citySection"/>
+ <xs:element ref="island"/>
+ <xs:element ref="area"/>
+ </xs:choice>
+ <xs:attributeGroup ref="authorityAttributeGroup"/>
+ </xs:complexType>
+ <!-- -->
+ <!--
+ New in 3.6:
+ all the above elements were previously stringPlusLanguage.
+ Now the following attributes are added:
+ - @level (for all)
+ - @authority, @authorityURI, and @valueURI (the authority attributeGroup) (for all)
+ - @period (for all)
+ - @areaType, @regionType, and @citySectionType (for area, region, and citySection, respectively)
+
+ So there is a new auxiliary definition, hierarchicalPart which adds @level, authority group, and @period
+ as well as three new definitions each extending hierarchicalPart, for area, region, and city section, each
+ adding its respective attribute.
+ -->
+
+ <!--
+ ********** hierarchicalPart *** new in 3.6, auxiliary definition
+ -->
+ <xs:complexType name="hierarchicalPart">
+ <xs:simpleContent>
+ <xs:extension base="stringPlusLanguage">
+ <xs:attribute name="level"/>
+ <xs:attribute name="period"/>
+ <xs:attributeGroup ref="authorityAttributeGroup"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <!--
+ Next, definitions for the place elements, starting with area, region, and citySection
+ -->
+
+ <xs:element name="area" type="areaDefinition"/>
+ <!-- -->
+ <xs:complexType name="areaDefinition">
+ <xs:simpleContent>
+ <xs:extension base="hierarchicalPart">
+ <xs:attribute name="areaType"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <!-- -->
+
+ <xs:element name="region" type="regionDefinition"/>
+ <!-- -->
+ <xs:complexType name="regionDefinition">
+ <xs:simpleContent>
+ <xs:extension base="hierarchicalPart">
+ <xs:attribute name="regionType"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+
+ <xs:element name="citySection" type="citySectionDefinition"/>
+ <!-- -->
+ <xs:complexType name="citySectionDefinition">
+ <xs:simpleContent>
+ <xs:extension base="hierarchicalPart">
+ <xs:attribute name="citySectionType"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <!--
+ For the rest, "stringPlusLanguage" is changed to "hierarchicalPart" ......
+ -->
+ <xs:element name="extraTerrestrialArea" type="hierarchicalPart"/>
+ <xs:element name="city" type="hierarchicalPart"/>
+ <xs:element name="continent" type="hierarchicalPart"/>
+ <xs:element name="country" type="hierarchicalPart"/>
+ <xs:element name="county" type="hierarchicalPart"/>
+ <xs:element name="island" type="hierarchicalPart"/>
+ <xs:element name="state" type="hierarchicalPart"/>
+ <xs:element name="territory" type="hierarchicalPart"/>
+ <!--
+ ..... except for province, which remains the same
+ -->
+ <xs:element name="province" type="stringPlusLanguage"/>
+ <!--
+ ********** cartographics **********
+-->
+ <xs:element name="cartographics" type="cartographicsDefinition"/>
+ <!-- -->
+ <xs:complexType name="cartographicsDefinition">
+
+ <xs:sequence>
+ <xs:element ref="scale" minOccurs="0"/>
+ <xs:element ref="projection" minOccurs="0"/>
+ <xs:element ref="coordinates" minOccurs="0" maxOccurs="unbounded"/>
+ <!--
+ *********** Following is new in 3.6, to allow an extension schema. -->
+ <xs:element ref="cartographicExtension" minOccurs="0" maxOccurs="unbounded"/>
+<!-- -->
+ </xs:sequence>
+
+ <xs:attributeGroup ref="authorityAttributeGroup"/>
+ </xs:complexType>
+ <!-- -->
+ <xs:element name="scale" type="stringPlusLanguage"/>
+ <xs:element name="projection" type="stringPlusLanguage"/>
+ <xs:element name="coordinates" type="stringPlusLanguage"/>
+<!-- *********** Following is new in 3.6, -->
+ <xs:element name="cartographicExtension" type="extensionDefinition"/>
+ <!--
+ ********** occupation **********
+-->
+ <xs:element name="occupation" type="stringPlusLanguagePlusAuthority"/>
+ <!--
+****************************************************
+* Top Level Element <tableOfContents> *
+*****************************************************
+ -->
+ <xs:element name="tableOfContents" type="tableOfContentsDefinition"/>
+ <!-- -->
+ <xs:complexType name="tableOfContentsDefinition">
+ <xs:simpleContent>
+ <xs:extension base="stringPlusLanguage">
+ <xs:attribute name="displayLabel" type="xs:string"/>
+ <xs:attribute name="type" type="xs:string"/>
+ <xs:attributeGroup ref="xlink:simpleLink"/>
+ <xs:attribute name="shareable" fixed="no"/>
+ <xs:attribute name="altRepGroup" type="xs:string"/>
+ <xs:attributeGroup ref="altFormatAttributeGroup"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <!--
+
+****************************************************
+* Top Level Element <targetAudience> *
+*****************************************************
+ -->
+ <xs:element name="targetAudience" type="targetAudienceDefinition"/>
+ <!-- -->
+ <xs:complexType name="targetAudienceDefinition">
+ <xs:simpleContent>
+ <xs:extension base="stringPlusLanguagePlusAuthority">
+ <xs:attribute name="displayLabel" type="xs:string"/>
+ <xs:attribute name="altRepGroup" type="xs:string"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <!--
+****************************************************
+* Top Level Element <titleInfo> *
+*****************************************************
+ -->
+ <xs:element name="titleInfo" type="titleInfoDefinition"/>
+ <!-- -->
+ <xs:complexType name="titleInfoDefinition">
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element ref="title"/>
+ <xs:element ref="subTitle"/>
+ <xs:element ref="partNumber"/>
+ <xs:element ref="partName"/>
+ <xs:element ref="nonSort"/>
+ </xs:choice>
+ <xs:attribute name="type">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="abbreviated"/>
+ <xs:enumeration value="translated"/>
+ <xs:enumeration value="alternative"/>
+ <xs:enumeration value="uniform"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="otherType"/>
+ <xs:attribute name="supplied" fixed="yes"/>
+ <xs:attribute name="altRepGroup" type="xs:string"/>
+ <xs:attributeGroup ref="altFormatAttributeGroup"/>
+ <xs:attribute name="nameTitleGroup" type="xs:string"/>
+ <xs:attribute name="usage" fixed="primary"/>
+ <xs:attribute name="ID" type="xs:ID"/>
+ <xs:attributeGroup ref="authorityAttributeGroup"/>
+ <xs:attributeGroup ref="xlink:simpleLink"/>
+ <xs:attributeGroup ref="languageAttributeGroup"/>
+ <xs:attribute name="displayLabel" type="xs:string"/>
+ </xs:complexType>
+ <!--
+
+******** Subordinate Elements for <titleInfo>
+ -->
+ <xs:element name="title" type="stringPlusLanguage"/>
+ <xs:element name="subTitle" type="stringPlusLanguage"/>
+ <xs:element name="partNumber" type="stringPlusLanguage"/>
+ <xs:element name="partName" type="stringPlusLanguage"/>
+ <!--
+********* nonSort definition revised in 3.6. to add attribute xml:space.
+ -->
+ <xs:element name="nonSort">
+ <xs:complexType>
+ <xs:simpleContent>
+ <xs:extension base="stringPlusLanguage">
+ <xs:attribute ref="xml:space"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ </xs:element>
+ <!--
+****************************************************
+* Top Level Element <typeOfResource> *
+*****************************************************
+ -->
+ <xs:element name="typeOfResource" type="typeOfResourceDefinition"/>
+ <!-- -->
+ <xs:complexType name="typeOfResourceDefinition">
+ <xs:simpleContent>
+ <xs:extension base="resourceTypeDefinition">
+ <xs:attribute name="collection" fixed="yes"/>
+ <xs:attribute name="manuscript" fixed="yes"/>
+ <xs:attribute name="displayLabel" type="xs:string"/>
+ <xs:attribute name="altRepGroup" type="xs:string"/>
+ <xs:attribute name="usage" fixed="primary"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <!--
+
+******** Subordinate Definitions for <typeOfResource>
+ -->
+ <!--
+ ******* resourceTypeDefinition ********
+-->
+ <xs:simpleType name="resourceTypeDefinition">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="text"/>
+ <xs:enumeration value="cartographic"/>
+ <xs:enumeration value="notated music"/>
+ <xs:enumeration value="sound recording-musical"/>
+ <xs:enumeration value="sound recording-nonmusical"/>
+ <xs:enumeration value="sound recording"/>
+ <xs:enumeration value="still image"/>
+ <xs:enumeration value="moving image"/>
+ <xs:enumeration value="three dimensional object"/>
+ <xs:enumeration value="software, multimedia"/>
+ <xs:enumeration value="mixed material"/>
+ <xs:enumeration value=""/>
+ </xs:restriction>
+ </xs:simpleType>
+ <!--
+ *********************************
+ *********************************
+ Part 3: Auxiliary definitions
+ *********************************
+ *********************************
+
+**********************************
+String Definitions
+**********************************
+-->
+ <!--
+********** stringPlusLanguage
+ -->
+ <xs:complexType name="stringPlusLanguage">
+ <xs:simpleContent>
+ <xs:extension base="xs:string">
+ <xs:attributeGroup ref="languageAttributeGroup"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <!--
+************************* stringPlusLanguagePlusAuthority *************************
+ -->
+ <xs:complexType name="stringPlusLanguagePlusAuthority">
+ <xs:simpleContent>
+ <xs:extension base="stringPlusLanguage">
+ <xs:attributeGroup ref="authorityAttributeGroup"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <!--
+************************* stringPlusLanguagePlusSupplied *************************
+ -->
+ <xs:complexType name="stringPlusLanguagePlusSupplied">
+ <xs:simpleContent>
+ <xs:extension base="stringPlusLanguage">
+ <xs:attribute name="supplied" fixed="yes"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <!--
+**********************************
+ Attribute Group Definitions
+**********************************
+-->
+ <!--
+ ********** authorityAttributeGroup **********
+ -->
+ <xs:attributeGroup name="authorityAttributeGroup">
+ <!-- new in 3.4 -->
+ <xs:attribute name="authority" type="xs:string"/>
+ <xs:attribute name="authorityURI" type="xs:anyURI"/>
+ <xs:attribute name="valueURI" type="xs:anyURI"/>
+ </xs:attributeGroup>
+ <!--
+ ********** languageAttributeGroup **********
+-->
+ <xs:attributeGroup name="languageAttributeGroup">
+ <xs:attribute name="lang" type="xs:string"/>
+ <xs:attribute ref="xml:lang"/>
+ <xs:attribute name="script" type="xs:string"/>
+ <xs:attribute name="transliteration" type="xs:string"/>
+ </xs:attributeGroup>
+ <!--
+ ********** altFormatAttributeGroup **********
+-->
+ <xs:attributeGroup name="altFormatAttributeGroup">
+ <xs:attribute name="altFormat" type="xs:anyURI"/>
+ <xs:attribute name="contentType" type="xs:string"/>
+ </xs:attributeGroup>
+ <!--
+****************************************************
+ - Attribute definitions (simpleTypes)
+*****************************************************
+-->
+ <!--
+ ********** codeOrText
+ ******** used by type attribute for elements that distinguish code from text:
+ ******** <languageTerm>, <placeTerm>, <roleTerm>, <scriptTerm>
+ -->
+ <xs:simpleType name="codeOrText">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="code"/>
+ <xs:enumeration value="text"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <!-- -->
+</xs:schema>
diff --git a/src/main/resources/xjc/mods/mods-binding.xjb b/src/main/resources/xjc/mods/mods-binding.xjb
new file mode 100644
index 0000000..a5dc2d4
--- /dev/null
+++ b/src/main/resources/xjc/mods/mods-binding.xjb
@@ -0,0 +1,96 @@
+<jxb:bindings version="2.0" xmlns:jxb="http://java.sun.com/xml/ns/jaxb" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+
+ <jxb:bindings schemaLocation="mods-3-6.xsd" node="/xsd:schema">
+
+ <jxb:bindings node="//xsd:complexType[@name='namePartDefinition']">
+ <jxb:bindings node=".//xsd:attribute[@name='type']">
+ <jxb:property name="atType" />
+ </jxb:bindings>
+ </jxb:bindings>
+
+ <jxb:bindings node="//xsd:complexType[@name='noteDefinition']">
+ <jxb:bindings node=".//xsd:attribute[@name='type']">
+ <jxb:property name="atType" />
+ </jxb:bindings>
+ </jxb:bindings>
+
+ <jxb:bindings node="//*[@name='text']">
+ <jxb:bindings node=".//xsd:attribute[@name='type']">
+ <jxb:property name="atType" />
+ </jxb:bindings>
+ </jxb:bindings>
+
+ <jxb:bindings node="//*[@name='languageAttributeGroup']">
+ <jxb:bindings node=".//xsd:attribute[@name='lang']">
+ <jxb:property name="atlang" />
+ </jxb:bindings>
+ </jxb:bindings>
+
+ <jxb:bindings node="//*[@name='titleInfoDefinition']">
+ <jxb:bindings node=".//xsd:attribute[@name='type']">
+ <jxb:property name="atType" />
+ </jxb:bindings>
+ </jxb:bindings>
+
+ <jxb:bindings node="//*[@name='relatedItemDefinition']">
+ <jxb:bindings node=".//xsd:attribute[@name='type']">
+ <jxb:property name="atType" />
+ </jxb:bindings>
+ </jxb:bindings>
+
+ <jxb:bindings node="//*[@name='subjectNameDefinition']">
+ <jxb:bindings node=".//xsd:attribute[@name='type']">
+ <jxb:property name="atType" />
+ </jxb:bindings>
+ </jxb:bindings>
+
+ <jxb:bindings node="//*[@name='subjectTitleInfoDefinition']">
+ <jxb:bindings node=".//xsd:attribute[@name='type']">
+ <jxb:property name="atType" />
+ </jxb:bindings>
+ </jxb:bindings>
+
+ <jxb:bindings node="//*[@name='tableOfContentsDefinition']">
+ <jxb:bindings node=".//xsd:attribute[@name='type']">
+ <jxb:property name="atType" />
+ </jxb:bindings>
+ </jxb:bindings>
+
+ <jxb:bindings node="//*[@name='physicalDescriptionNote']">
+ <jxb:bindings node=".//xsd:attribute[@name='type']">
+ <jxb:property name="atType" />
+ </jxb:bindings>
+ </jxb:bindings>
+
+ <jxb:bindings node="//*[@name='nameDefinition']">
+ <jxb:bindings node=".//xsd:attribute[@name='type']">
+ <jxb:property name="atType" />
+ </jxb:bindings>
+ </jxb:bindings>
+
+ <jxb:bindings node="//*[@name='copyInformationDefinition']">
+ <jxb:bindings node=".//xsd:attribute[@name='type']">
+ <jxb:property name="atType" />
+ </jxb:bindings>
+ </jxb:bindings>
+
+ <jxb:bindings node="//*[@name='physicalLocationDefinition']">
+ <jxb:bindings node=".//xsd:attribute[@name='type']">
+ <jxb:property name="atType" />
+ </jxb:bindings>
+ </jxb:bindings>
+
+ <jxb:bindings node="//*[@name='accessConditionDefinition']">
+ <jxb:bindings node=".//xsd:attribute[@name='type']">
+ <jxb:property name="atType" />
+ </jxb:bindings>
+ </jxb:bindings>
+
+ <jxb:bindings node="//*[@name='abstractDefinition']">
+ <jxb:bindings node=".//xsd:attribute[@name='type']">
+ <jxb:property name="atType" />
+ </jxb:bindings>
+ </jxb:bindings>
+
+ </jxb:bindings>
+</jxb:bindings>
diff --git a/src/test/java/net/sf/jabref/ArchitectureTests.java b/src/test/java/net/sf/jabref/ArchitectureTests.java
index ab495bc..a8bb3ce 100644
--- a/src/test/java/net/sf/jabref/ArchitectureTests.java
+++ b/src/test/java/net/sf/jabref/ArchitectureTests.java
@@ -6,6 +6,7 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
@@ -17,11 +18,12 @@ import org.junit.runners.Parameterized;
@RunWith(Parameterized.class)
public class ArchitectureTests {
- public static final String PACKAGE_JAVAX_SWING = "javax.swing";
- public static final String PACKAGE_JAVA_AWT = "java.awt";
- public static final String PACKAGE_NET_SF_JABREF_GUI = "net.sf.jabref.gui";
- public static final String PACKAGE_NET_SF_JABREF_LOGIC = "net.sf.jabref.logic";
- public static final String PACKAGE_NET_SF_JABREF_MODEL = "net.sf.jabref.model";
+ private static final String PACKAGE_JAVAX_SWING = "javax.swing";
+ private static final String PACKAGE_JAVA_AWT = "java.awt";
+ private static final String PACKAGE_NET_SF_JABREF_GUI = "net.sf.jabref.gui";
+ private static final String PACKAGE_NET_SF_JABREF_LOGIC = "net.sf.jabref.logic";
+ private static final String PACKAGE_NET_SF_JABREF_MODEL = "net.sf.jabref.model";
+ private static final String CLASS_NET_SF_JABREF_GLOBALS = "net.sf.jabref.Globals";
private final String firstPackage;
private final String secondPackage;
@@ -38,11 +40,13 @@ public class ArchitectureTests {
{PACKAGE_NET_SF_JABREF_LOGIC, PACKAGE_JAVA_AWT},
{PACKAGE_NET_SF_JABREF_LOGIC, PACKAGE_JAVAX_SWING},
{PACKAGE_NET_SF_JABREF_LOGIC, PACKAGE_NET_SF_JABREF_GUI},
+ {PACKAGE_NET_SF_JABREF_LOGIC, CLASS_NET_SF_JABREF_GLOBALS},
{PACKAGE_NET_SF_JABREF_MODEL, PACKAGE_JAVA_AWT},
{PACKAGE_NET_SF_JABREF_MODEL, PACKAGE_JAVAX_SWING},
{PACKAGE_NET_SF_JABREF_MODEL, PACKAGE_NET_SF_JABREF_GUI},
- {PACKAGE_NET_SF_JABREF_MODEL, PACKAGE_NET_SF_JABREF_LOGIC}
+ {PACKAGE_NET_SF_JABREF_MODEL, PACKAGE_NET_SF_JABREF_LOGIC},
+ {PACKAGE_NET_SF_JABREF_MODEL, CLASS_NET_SF_JABREF_GLOBALS}
}
);
}
@@ -50,11 +54,7 @@ public class ArchitectureTests {
@Test
- public void testLogicIndependentOfSwingAndGui() throws IOException {
- assertIndependenceOfPackages();
- }
-
- private void assertIndependenceOfPackages() throws IOException {
+ public void fistPackageIsIndependentOfSecondPackage() throws IOException {
List<Path> files = Files.walk(Paths.get("src"))
.filter(p -> p.toString().endsWith(".java"))
.filter(p -> {
@@ -73,9 +73,7 @@ public class ArchitectureTests {
}
}).collect(Collectors.toList());
- if(!files.isEmpty()) {
- Assert.fail(files.toString());
- }
+ Assert.assertEquals(Collections.emptyList(), files);
}
}
diff --git a/src/test/java/net/sf/jabref/BibDatabaseContextTest.java b/src/test/java/net/sf/jabref/BibDatabaseContextTest.java
deleted file mode 100644
index ae29817..0000000
--- a/src/test/java/net/sf/jabref/BibDatabaseContextTest.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package net.sf.jabref;
-
-import net.sf.jabref.model.database.BibDatabase;
-import net.sf.jabref.model.database.BibDatabaseMode;
-import net.sf.jabref.preferences.JabRefPreferences;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-
-public class BibDatabaseContextTest {
-
- @Before
- public void setUp() throws Exception {
- Globals.prefs = JabRefPreferences.getInstance();
- }
-
- @Test
- public void testTypeBasedOnDefaultBibtex() {
- BibDatabaseContext bibDatabaseContext = new BibDatabaseContext(new BibDatabase(), new MetaData(), new Defaults(BibDatabaseMode.BIBTEX));
- assertEquals(BibDatabaseMode.BIBTEX, bibDatabaseContext.getMode());
-
- bibDatabaseContext.setMode(BibDatabaseMode.BIBLATEX);
- assertEquals(BibDatabaseMode.BIBLATEX, bibDatabaseContext.getMode());
- }
-
- @Test
- public void testTypeBasedOnDefaultBiblatex() {
- BibDatabaseContext bibDatabaseContext = new BibDatabaseContext(new BibDatabase(), new MetaData(), new Defaults(BibDatabaseMode.BIBLATEX));
- assertEquals(BibDatabaseMode.BIBLATEX, bibDatabaseContext.getMode());
-
- bibDatabaseContext.setMode(BibDatabaseMode.BIBTEX);
- assertEquals(BibDatabaseMode.BIBTEX, bibDatabaseContext.getMode());
- }
-
-}
diff --git a/src/test/java/net/sf/jabref/BibtexTestData.java b/src/test/java/net/sf/jabref/BibtexTestData.java
index bda74c9..f9e88fc 100644
--- a/src/test/java/net/sf/jabref/BibtexTestData.java
+++ b/src/test/java/net/sf/jabref/BibtexTestData.java
@@ -17,17 +17,16 @@ public class BibtexTestData {
}
public static BibDatabase getBibtexDatabase(ImportFormatPreferences importFormatPreferences) throws IOException {
- StringReader reader = new StringReader(
- "@ARTICLE{HipKro03,\n" + " author = {Eric von Hippel and Georg von Krogh},\n"
+ String article = "@ARTICLE{HipKro03,\n" + " author = {Eric von Hippel and Georg von Krogh},\n"
+ " title = {Open Source Software and the \"Private-Collective\" Innovation Model: Issues for Organization Science},\n"
+ " journal = {Organization Science},\n" + " year = {2003},\n" + " volume = {14},\n"
+ " pages = {209--223},\n" + " number = {2},\n"
+ " address = {Institute for Operations Research and the Management Sciences (INFORMS), Linthicum, Maryland, USA},\n"
+ " doi = {http://dx.doi.org/10.1287/orsc.14.2.209.14992}," + "\n" + " issn = {1526-5455},"
- + "\n" + " publisher = {INFORMS}\n" + "}");
+ + "\n" + " publisher = {INFORMS}\n" + "}";
- BibtexParser parser = new BibtexParser(reader, importFormatPreferences);
- ParserResult result = parser.parse();
+ BibtexParser parser = new BibtexParser(importFormatPreferences);
+ ParserResult result = parser.parse(new StringReader(article));
return result.getDatabase();
}
diff --git a/src/test/java/net/sf/jabref/CodeStyleTests.java b/src/test/java/net/sf/jabref/CodeStyleTests.java
new file mode 100644
index 0000000..3fcac48
--- /dev/null
+++ b/src/test/java/net/sf/jabref/CodeStyleTests.java
@@ -0,0 +1,24 @@
+package net.sf.jabref;
+
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import net.sf.jabref.model.strings.StringUtil;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class CodeStyleTests {
+
+ @Test
+ public void StringUtilClassIsSmall() throws Exception {
+ Path path = Paths.get("src", "main", "java", StringUtil.class.getName().replace('.', '/') + ".java");
+ int lineCount = Files.readAllLines(path, StandardCharsets.UTF_8).size();
+
+ Assert.assertTrue("StringUtil increased in size. "
+ + "We try to keep this class as small as possible. "
+ + "Thus think twice if you add something to StringUtil.", lineCount <= 709);
+ }
+}
diff --git a/src/test/java/net/sf/jabref/MetaDataTest.java b/src/test/java/net/sf/jabref/MetaDataTest.java
index 667eed4..088af60 100644
--- a/src/test/java/net/sf/jabref/MetaDataTest.java
+++ b/src/test/java/net/sf/jabref/MetaDataTest.java
@@ -2,13 +2,16 @@ package net.sf.jabref;
import java.util.Collections;
import java.util.Map;
+import java.util.Optional;
import java.util.TreeMap;
-import net.sf.jabref.logic.cleanup.FieldFormatterCleanup;
-import net.sf.jabref.logic.exporter.FieldFormatterCleanups;
+import net.sf.jabref.logic.exporter.MetaDataSerializer;
import net.sf.jabref.logic.formatter.casechanger.LowerCaseFormatter;
import net.sf.jabref.logic.util.OS;
-import net.sf.jabref.preferences.JabRefPreferences;
+import net.sf.jabref.model.bibtexkeypattern.GlobalBibtexKeyPattern;
+import net.sf.jabref.model.cleanup.FieldFormatterCleanup;
+import net.sf.jabref.model.cleanup.FieldFormatterCleanups;
+import net.sf.jabref.model.metadata.MetaData;
import org.junit.Before;
import org.junit.Test;
@@ -18,16 +21,17 @@ import static org.junit.Assert.assertEquals;
public class MetaDataTest {
private MetaData metaData;
+ private GlobalBibtexKeyPattern pattern;
@Before
public void setUp() {
- Globals.prefs = JabRefPreferences.getInstance();
metaData = new MetaData();
+ pattern = GlobalBibtexKeyPattern.fromPattern("[auth][year]");
}
@Test
public void serializeNewMetadataReturnsEmptyMap() throws Exception {
- assertEquals(Collections.emptyMap(), metaData.getAsStringMap());
+ assertEquals(Collections.emptyMap(), MetaDataSerializer.getSerializedStringMap(metaData, pattern));
}
@Test
@@ -39,6 +43,11 @@ public class MetaDataTest {
Map<String, String> expectedSerialization = new TreeMap<>();
expectedSerialization.put("saveActions",
"enabled;" + OS.NEWLINE + "title[lower_case]" + OS.NEWLINE + ";");
- assertEquals(expectedSerialization, metaData.getAsStringMap());
+ assertEquals(expectedSerialization, MetaDataSerializer.getSerializedStringMap(metaData, pattern));
+ }
+
+ @Test
+ public void emptyGroupsIfNotSet() {
+ assertEquals(Optional.empty(), metaData.getGroups());
}
}
diff --git a/src/test/java/net/sf/jabref/cleanup/CleanupActionsListModelTest.java b/src/test/java/net/sf/jabref/cleanup/CleanupActionsListModelTest.java
index d15e7ab..86a0a86 100644
--- a/src/test/java/net/sf/jabref/cleanup/CleanupActionsListModelTest.java
+++ b/src/test/java/net/sf/jabref/cleanup/CleanupActionsListModelTest.java
@@ -9,9 +9,10 @@ import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import net.sf.jabref.gui.cleanup.CleanupActionsListModel;
-import net.sf.jabref.logic.cleanup.FieldFormatterCleanup;
-import net.sf.jabref.logic.exporter.FieldFormatterCleanups;
+import net.sf.jabref.logic.cleanup.Cleanups;
import net.sf.jabref.logic.formatter.bibtexfields.ClearFormatter;
+import net.sf.jabref.model.cleanup.FieldFormatterCleanup;
+import net.sf.jabref.model.cleanup.FieldFormatterCleanups;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
@@ -51,7 +52,7 @@ public class CleanupActionsListModelTest {
}
public List<FieldFormatterCleanup> getDefaultFieldFormatterCleanups() {
- FieldFormatterCleanups formatters = FieldFormatterCleanups.DEFAULT_SAVE_ACTIONS;
+ FieldFormatterCleanups formatters = Cleanups.DEFAULT_SAVE_ACTIONS;
//new ArrayList because configured actions is an unmodifiable collection
return new ArrayList<>(formatters.getConfiguredActions());
}
@@ -93,4 +94,4 @@ public class CleanupActionsListModelTest {
}
-}
\ No newline at end of file
+}
diff --git a/src/test/java/net/sf/jabref/cli/AuxCommandLineTest.java b/src/test/java/net/sf/jabref/cli/AuxCommandLineTest.java
index 9fad4fc..be880e4 100644
--- a/src/test/java/net/sf/jabref/cli/AuxCommandLineTest.java
+++ b/src/test/java/net/sf/jabref/cli/AuxCommandLineTest.java
@@ -8,7 +8,6 @@ import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Paths;
-import net.sf.jabref.logic.importer.ImportFormatPreferences;
import net.sf.jabref.logic.importer.ParserResult;
import net.sf.jabref.logic.importer.fileformat.BibtexParser;
import net.sf.jabref.model.database.BibDatabase;
@@ -26,7 +25,7 @@ public class AuxCommandLineTest {
File auxFile = Paths.get(AuxCommandLineTest.class.getResource("paper.aux").toURI()).toFile();
try (InputStreamReader originalReader = new InputStreamReader(originalStream, StandardCharsets.UTF_8)) {
ParserResult result = BibtexParser.parse(originalReader,
- ImportFormatPreferences.fromPreferences(JabRefPreferences.getInstance()));
+ JabRefPreferences.getInstance().getImportFormatPreferences());
AuxCommandLine auxCommandLine = new AuxCommandLine(auxFile.getAbsolutePath(), result.getDatabase());
BibDatabase newDB = auxCommandLine.perform();
diff --git a/src/test/java/net/sf/jabref/external/ExternalFileTypeTest.java b/src/test/java/net/sf/jabref/external/ExternalFileTypeTest.java
deleted file mode 100644
index ce1c818..0000000
--- a/src/test/java/net/sf/jabref/external/ExternalFileTypeTest.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package net.sf.jabref.external;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertNotNull;
-
-public class ExternalFileTypeTest {
-
- @Test
- public void getOpenWithApplicationMustNotReturnNull() throws Exception {
- ExternalFileType type = new ExternalFileType(null, null, null, null, null, null);
-
- assertNotNull(type.getOpenWithApplication());
- }
-
- @Test
- public void getExtensionMustNotReturnNull() throws Exception {
- ExternalFileType type = new ExternalFileType(null, null, null, null, null, null);
-
- assertNotNull(type.getExtension());
- }
-
- @Test
- public void getMimeTypeMustNotReturnNull() throws Exception {
- ExternalFileType type = new ExternalFileType(null, null, null, null, null, null);
-
- assertNotNull(type.getMimeType());
- }
-
-}
\ No newline at end of file
diff --git a/src/test/java/net/sf/jabref/external/RegExpFileSearchTests.java b/src/test/java/net/sf/jabref/external/RegExpFileSearchTests.java
deleted file mode 100644
index 02d5e35..0000000
--- a/src/test/java/net/sf/jabref/external/RegExpFileSearchTests.java
+++ /dev/null
@@ -1,157 +0,0 @@
-package net.sf.jabref.external;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.StringReader;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-import net.sf.jabref.Globals;
-import net.sf.jabref.logic.importer.ImportFormatPreferences;
-import net.sf.jabref.logic.importer.ParserResult;
-import net.sf.jabref.logic.importer.fileformat.BibtexParser;
-import net.sf.jabref.logic.layout.format.NameFormatter;
-import net.sf.jabref.model.database.BibDatabase;
-import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.model.entry.BibtexEntryTypes;
-import net.sf.jabref.preferences.JabRefPreferences;
-
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-
-public class RegExpFileSearchTests {
-
- private static final String filesDirectory = "src/test/resources/net/sf/jabref/imports/unlinkedFilesTestFolder";
- private BibDatabase database;
- private BibEntry entry;
-
- @Before
- public void setUp() throws IOException {
- Globals.prefs = JabRefPreferences.getInstance();
-
- StringReader reader = new StringReader(
- "@ARTICLE{HipKro03," + "\n" + " author = {Eric von Hippel and Georg von Krogh}," + "\n"
- + " title = {Open Source Software and the \"Private-Collective\" Innovation Model: Issues for Organization Science},"
- + "\n" + " journal = {Organization Science}," + "\n" + " year = {2003}," + "\n"
- + " volume = {14}," + "\n" + " pages = {209--223}," + "\n" + " number = {2}," + "\n"
- + " address = {Institute for Operations Research and the Management Sciences (INFORMS), Linthicum, Maryland, USA},"
- + "\n" + " doi = {http://dx.doi.org/10.1287/orsc.14.2.209.14992}," + "\n"
- + " issn = {1526-5455}," + "\n" + " publisher = {INFORMS}" + "\n" + "}");
-
- BibtexParser parser = new BibtexParser(reader, ImportFormatPreferences.fromPreferences(Globals.prefs));
- ParserResult result = null;
-
- result = parser.parse();
-
- database = result.getDatabase();
- entry = database.getEntryByKey("HipKro03").get();
-
- Assert.assertNotNull(database);
- Assert.assertNotNull(entry);
- }
-
- @Test
- public void testFindFiles() {
- //given
- List<BibEntry> entries = new ArrayList<>();
- BibEntry localEntry = new BibEntry("123", BibtexEntryTypes.ARTICLE.getName());
- localEntry.setCiteKey("pdfInDatabase");
- localEntry.setField("year", "2001");
- entries.add(localEntry);
-
- List<String> extensions = Arrays.asList("pdf");
-
- List<File> dirs = Arrays.asList(new File(filesDirectory));
-
- //when
- Map<BibEntry, java.util.List<File>> result = RegExpFileSearch.findFilesForSet(entries, extensions, dirs,
- "**/[bibtexkey].*\\\\.[extension]");
-
- //then
- assertEquals(1, result.keySet().size());
- }
-
- @Test
- public void testFieldAndFormat() {
- assertEquals("Eric von Hippel and Georg von Krogh",
- RegExpFileSearch.getFieldAndFormat("[author]", entry, database));
-
- assertEquals("Eric von Hippel and Georg von Krogh",
- RegExpFileSearch.getFieldAndFormat("author", entry, database));
-
- assertEquals("", RegExpFileSearch.getFieldAndFormat("[unknownkey]", entry, database));
-
- assertEquals("", RegExpFileSearch.getFieldAndFormat("[:]", entry, database));
-
- assertEquals("", RegExpFileSearch.getFieldAndFormat("[:lower]", entry, database));
-
- assertEquals("eric von hippel and georg von krogh",
- RegExpFileSearch.getFieldAndFormat("[author:lower]", entry, database));
-
- assertEquals("HipKro03", RegExpFileSearch.getFieldAndFormat("[bibtexkey]", entry, database));
-
- assertEquals("HipKro03", RegExpFileSearch.getFieldAndFormat("[bibtexkey:]", entry, database));
- }
-
- @Test
- @Ignore
- public void testUserFieldAndFormat() {
-
- List<String> names = Globals.prefs.getStringList(NameFormatter.NAME_FORMATER_KEY);
-
- List<String> formats = Globals.prefs.getStringList(NameFormatter.NAME_FORMATTER_VALUE);
-
- try {
-
- List<String> f = new LinkedList<>(formats);
- List<String> n = new LinkedList<>(names);
-
- n.add("testMe123454321");
- f.add("*@*@test");
-
- Globals.prefs.putStringList(NameFormatter.NAME_FORMATER_KEY, n);
- Globals.prefs.putStringList(NameFormatter.NAME_FORMATTER_VALUE, f);
-
- assertEquals("testtest", RegExpFileSearch.getFieldAndFormat("[author:testMe123454321]", entry, database));
-
- } finally {
- Globals.prefs.putStringList(NameFormatter.NAME_FORMATER_KEY, names);
- Globals.prefs.putStringList(NameFormatter.NAME_FORMATTER_VALUE, formats);
- }
- }
-
- @Test
- public void testExpandBrackets() {
-
- assertEquals("", RegExpFileSearch.expandBrackets("", entry, database));
-
- assertEquals("dropped", RegExpFileSearch.expandBrackets("drop[unknownkey]ped", entry, database));
-
- assertEquals("Eric von Hippel and Georg von Krogh",
- RegExpFileSearch.expandBrackets("[author]", entry, database));
-
- assertEquals("Eric von Hippel and Georg von Krogh are two famous authors.",
- RegExpFileSearch.expandBrackets("[author] are two famous authors.", entry, database));
-
- assertEquals("Eric von Hippel and Georg von Krogh are two famous authors.",
- RegExpFileSearch.expandBrackets("[author] are two famous authors.", entry, database));
-
- assertEquals(
- "Eric von Hippel and Georg von Krogh have published Open Source Software and the \"Private-Collective\" Innovation Model: Issues for Organization Science in Organization Science.",
- RegExpFileSearch.expandBrackets("[author] have published [title] in [journal].", entry, database));
- }
-
- @After
- public void tearDown(){
- Globals.prefs = null;
- }
-
-}
diff --git a/src/test/java/net/sf/jabref/gui/AWTExceptionHandler.java b/src/test/java/net/sf/jabref/gui/AWTExceptionHandler.java
new file mode 100644
index 0000000..e681788
--- /dev/null
+++ b/src/test/java/net/sf/jabref/gui/AWTExceptionHandler.java
@@ -0,0 +1,25 @@
+package net.sf.jabref.gui;
+
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import javax.swing.SwingUtilities;
+
+/**
+ * Can catch any exceptions occurring on the EDT thread for assertion.
+ */
+public class AWTExceptionHandler {
+
+ private final List<Throwable> list = new CopyOnWriteArrayList<>();
+
+ public void installExceptionDetectionInEDT() {
+ SwingUtilities.invokeLater(() -> Thread.currentThread().setUncaughtExceptionHandler((t, e) -> list.add(e)));
+ }
+
+ public void assertNoExceptions() {
+ if (!list.isEmpty()) {
+ throw new AssertionError("Uncaught exception in EDT", list.get(0));
+ }
+ }
+
+}
diff --git a/src/test/java/net/sf/jabref/gui/AbstractUITest.java b/src/test/java/net/sf/jabref/gui/AbstractUITest.java
new file mode 100644
index 0000000..4355628
--- /dev/null
+++ b/src/test/java/net/sf/jabref/gui/AbstractUITest.java
@@ -0,0 +1,111 @@
+package net.sf.jabref.gui;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import net.sf.jabref.JabRefMain;
+import net.sf.jabref.testutils.category.GUITests;
+
+import org.assertj.swing.fixture.AbstractWindowFixture;
+import org.assertj.swing.fixture.FrameFixture;
+import org.assertj.swing.fixture.JFileChooserFixture;
+import org.assertj.swing.fixture.JTableFixture;
+import org.assertj.swing.image.ScreenshotTaker;
+import org.assertj.swing.junit.testcase.AssertJSwingJUnitTestCase;
+import org.assertj.swing.timing.Pause;
+import org.junit.Assert;
+import org.junit.experimental.categories.Category;
+
+import static org.assertj.swing.finder.WindowFinder.findFrame;
+import static org.assertj.swing.launcher.ApplicationLauncher.application;
+
+ at Category(GUITests.class)
+public abstract class AbstractUITest extends AssertJSwingJUnitTestCase {
+
+ protected final static int SPEED_NORMAL = 50;
+
+ protected AWTExceptionHandler awtExceptionHandler;
+ protected FrameFixture mainFrame;
+
+ @Override
+ protected void onSetUp() {
+ awtExceptionHandler = new AWTExceptionHandler();
+ awtExceptionHandler.installExceptionDetectionInEDT();
+ application(JabRefMain.class).start();
+
+ robot().waitForIdle();
+
+ robot().settings().timeoutToFindSubMenu(1_000);
+ robot().settings().delayBetweenEvents(SPEED_NORMAL);
+
+ mainFrame = findFrame(JabRefFrame.class).withTimeout(10_000).using(robot());
+ robot().waitForIdle();
+ }
+
+ /**
+ * Returns the absolute Path of the given relative Path
+ * The backlashes are replaced with forwardslashes b/c assertJ can't type the former one on windows
+ * @param relativePath the relative path to the resource database
+ */
+ protected String getAbsolutePath(String relativePath) {
+ final URL resource = this.getClass().getClassLoader().getResource(relativePath);
+ try {
+ return Paths.get(resource.toURI()).toAbsolutePath().toString().replace("\\", "/");
+ } catch (URISyntaxException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ /**
+ * opens a database and gives JabRef a second to open it before proceeding
+ */
+ protected void importBibIntoNewDatabase(String path) {
+ mainFrame.menuItemWithPath("File", "Import into new database").click();
+ JFileChooserFixture openFileDialog = mainFrame.fileChooser();
+ robot().settings().delayBetweenEvents(1);
+ openFileDialog.fileNameTextBox().enterText(path);
+ openFileDialog.approve();
+ Pause.pause(1_000);
+ }
+
+ protected void exitJabRef() {
+ mainFrame.menuItemWithPath("File", "Quit").click();
+ awtExceptionHandler.assertNoExceptions();
+ }
+
+ protected void newDatabase() {
+ mainFrame.menuItemWithPath("File", "New BibTeX database").click();
+ }
+
+ protected void closeDatabase() {
+ mainFrame.menuItemWithPath("File", "Close database").click();
+ }
+
+ protected void takeScreenshot(AbstractWindowFixture<?, ?, ?> dialog, String filename) throws IOException {
+ ScreenshotTaker screenshotTaker = new ScreenshotTaker();
+ Path folder = Paths.get("build", "screenshots");
+ // Create build/srceenshots folder if not present
+ if (!Files.exists(folder)) {
+ Files.createDirectory(folder);
+ }
+ Path file = folder.resolve(filename + ".png").toAbsolutePath();
+ // Delete already present file
+ if (Files.exists(file)) {
+ Files.delete(file);
+ }
+ screenshotTaker.saveComponentAsPng(dialog.target(), file.toString());
+ }
+
+ protected void assertColumnValue(JTableFixture table, int rowIndex, int columnIndex, String selectionValue){
+ String[][] tableContent;
+ tableContent = table.contents();
+
+ String value = tableContent[rowIndex][columnIndex];
+ Assert.assertEquals(value, selectionValue);
+ }
+}
diff --git a/src/test/java/net/sf/jabref/gui/DialogTest.java b/src/test/java/net/sf/jabref/gui/DialogTest.java
new file mode 100644
index 0000000..e0f272c
--- /dev/null
+++ b/src/test/java/net/sf/jabref/gui/DialogTest.java
@@ -0,0 +1,52 @@
+package net.sf.jabref.gui;
+
+import javax.swing.JButton;
+import javax.swing.JDialog;
+
+import net.sf.jabref.testutils.category.GUITests;
+
+import org.assertj.swing.core.GenericTypeMatcher;
+import org.assertj.swing.dependency.jsr305.Nonnull;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import static org.assertj.swing.finder.WindowFinder.findDialog;
+/**
+ * This test has been split to work, the other part can be found at DialogTest2
+ */
+ at Category(GUITests.class)
+public class DialogTest extends AbstractUITest {
+
+ @Test
+ public void testCancelStyleSelectDialog() {
+ mainFrame.menuItemWithPath("Tools", "OpenOffice/LibreOffice connection").click();
+
+ GenericTypeMatcher<JButton> buttonMatcher = new GenericTypeMatcher<JButton>(JButton.class) {
+
+ @Override
+ protected boolean isMatching(@Nonnull JButton jButton) {
+ return "Select style".equals(jButton.getText());
+ }
+ };
+
+ mainFrame.button(buttonMatcher).click();
+
+ GenericTypeMatcher<JDialog> styleDialogMatcher = new GenericTypeMatcher<JDialog>(JDialog.class) {
+
+ @Override
+ protected boolean isMatching(JDialog dialog) {
+ return "Select style".equals(dialog.getTitle()); // Only a single SidePane
+ }
+ };
+
+ GenericTypeMatcher<JButton> buttonMatcher2 = new GenericTypeMatcher<JButton>(JButton.class) {
+
+ @Override
+ protected boolean isMatching(@Nonnull JButton jButton) {
+ return "Cancel".equals(jButton.getText());
+ }
+ };
+ findDialog(styleDialogMatcher).withTimeout(10_000).using(robot()).button(buttonMatcher2).click();
+ exitJabRef();
+ }
+}
diff --git a/src/test/java/net/sf/jabref/gui/DialogTest2.java b/src/test/java/net/sf/jabref/gui/DialogTest2.java
new file mode 100644
index 0000000..d3bd257
--- /dev/null
+++ b/src/test/java/net/sf/jabref/gui/DialogTest2.java
@@ -0,0 +1,46 @@
+package net.sf.jabref.gui;
+
+
+import javax.swing.JButton;
+import javax.swing.JDialog;
+
+import net.sf.jabref.testutils.category.GUITests;
+
+import org.assertj.swing.core.GenericTypeMatcher;
+import org.assertj.swing.dependency.jsr305.Nonnull;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import static org.assertj.swing.finder.WindowFinder.findDialog;
+
+/**
+ * Split of DialogTest, since the test cases were only running separately
+ */
+ at Category(GUITests.class)
+public class DialogTest2 extends AbstractUITest {
+ @Test
+ public void testCloseStyleSelectDialog() {
+ mainFrame.menuItemWithPath("Tools", "OpenOffice/LibreOffice connection").click();
+
+ GenericTypeMatcher<JButton> buttonMatcher = new GenericTypeMatcher<JButton>(JButton.class) {
+
+ @Override
+ protected boolean isMatching(@Nonnull JButton jButton) {
+ return "Select style".equals(jButton.getText());
+ }
+ };
+
+ mainFrame.button(buttonMatcher).click();
+
+ GenericTypeMatcher<JDialog> styleDialogMatcher = new GenericTypeMatcher<JDialog>(JDialog.class) {
+
+ @Override
+ protected boolean isMatching(JDialog dialog) {
+ return "Select style".equals(dialog.getTitle()); // Only a single SidePane
+ }
+ };
+
+ findDialog(styleDialogMatcher).withTimeout(10_000).using(robot()).close();
+ exitJabRef();
+ }
+}
diff --git a/src/test/java/net/sf/jabref/gui/EntryTableTest.java b/src/test/java/net/sf/jabref/gui/EntryTableTest.java
new file mode 100644
index 0000000..e224970
--- /dev/null
+++ b/src/test/java/net/sf/jabref/gui/EntryTableTest.java
@@ -0,0 +1,68 @@
+package net.sf.jabref.gui;
+
+import java.awt.event.KeyEvent;
+import java.util.regex.Pattern;
+
+import net.sf.jabref.testutils.category.GUITests;
+
+import org.assertj.swing.fixture.JTableCellFixture;
+import org.assertj.swing.fixture.JTableFixture;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+/**
+ * Specific Use-Case:
+ * I import a database. Then I doubleclick on the first entry in the table to open the entry editor.
+ * Then I click on the first entry again, and scroll through all of the lists entries, without having to click
+ * on the table again.
+ */
+ at Category(GUITests.class)
+public class EntryTableTest extends AbstractUITest{
+
+ private final static int SCROLL_ACTION_EXECUTION = 5;
+ private final static String TEST_FILE_NAME = "testbib/testjabref.bib";
+ private final static int DOWN = KeyEvent.VK_DOWN;
+ private final static int UP = KeyEvent.VK_UP;
+ private final static int TITLE_COLUMN_INDEX = 5;
+
+ @Test
+ public void scrollThroughEntryList() {
+ String path = getAbsolutePath(TEST_FILE_NAME);
+
+ importBibIntoNewDatabase(path);
+
+ JTableFixture entryTable = mainFrame.table();
+
+ //use a pattern from the first row to select it since it seems to be the best way to get the cell object
+ Pattern pattern = Pattern.compile("256.*");
+ JTableCellFixture firstCell = entryTable.cell(pattern);
+
+ entryTable.selectRows(0).doubleClick();
+ //delay has to be shortened so that double click is recognized
+ robot().settings().delayBetweenEvents(0);
+ firstCell.doubleClick();
+ robot().settings().delayBetweenEvents(SPEED_NORMAL);
+
+ firstCell.click();
+ //is the first table entry selected?
+ assertColumnValue(entryTable, 0, TITLE_COLUMN_INDEX, entryTable.selectionValue());
+
+ //go throught the table and check if the entry with the correct index is selected
+ for (int i=0; i < SCROLL_ACTION_EXECUTION; i++) {
+ robot().pressAndReleaseKey(DOWN);
+ Assert.assertTrue(entryTable.selectionValue() != null);
+ assertColumnValue(entryTable, i+1, TITLE_COLUMN_INDEX, entryTable.selectionValue());
+ }
+ //do the same going up again
+ for (int i = SCROLL_ACTION_EXECUTION; i > 0; i--) {
+ robot().pressAndReleaseKey(UP);
+ Assert.assertTrue(entryTable.selectionValue() != null);
+ assertColumnValue(entryTable, i-1, TITLE_COLUMN_INDEX, entryTable.selectionValue());
+ }
+
+ closeDatabase();
+ exitJabRef();
+ }
+
+}
diff --git a/src/test/java/net/sf/jabref/gui/GUITest.java b/src/test/java/net/sf/jabref/gui/GUITest.java
new file mode 100644
index 0000000..835411a
--- /dev/null
+++ b/src/test/java/net/sf/jabref/gui/GUITest.java
@@ -0,0 +1,119 @@
+package net.sf.jabref.gui;
+
+import java.io.IOException;
+
+import javax.swing.JButton;
+
+import net.sf.jabref.gui.dbproperties.DatabasePropertiesDialog;
+import net.sf.jabref.gui.preftabs.PreferencesDialog;
+import net.sf.jabref.testutils.category.GUITests;
+
+import org.assertj.swing.core.GenericTypeMatcher;
+import org.assertj.swing.dependency.jsr305.Nonnull;
+import org.assertj.swing.fixture.DialogFixture;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import static org.assertj.swing.finder.WindowFinder.findDialog;
+
+ at Category(GUITests.class)
+public class GUITest extends AbstractUITest {
+
+ @Test
+ public void testExit() {
+ exitJabRef();
+ }
+
+ @Test
+ public void testNewFile() {
+ newDatabase();
+ closeDatabase();
+ exitJabRef();
+ }
+
+ @Test
+ public void testCreateBibtexEntry() throws IOException {
+ newDatabase();
+
+ mainFrame.menuItemWithPath("BibTeX", "New entry...").click();
+ findDialog(EntryTypeDialog.class).withTimeout(10_000).using(robot())
+ .button(new GenericTypeMatcher<JButton>(JButton.class) {
+ @Override
+ protected boolean isMatching(@Nonnull JButton jButton) {
+ return "Book".equals(jButton.getText());
+ }
+ }).click();
+ takeScreenshot(mainFrame, "MainWindowWithOneDatabase");
+ }
+
+ @Test
+ public void testOpenAndSavePreferences() throws IOException {
+ mainFrame.menuItemWithPath("Options", "Preferences").click();
+
+ robot().waitForIdle();
+
+ DialogFixture preferencesDialog = findDialog(PreferencesDialog.class).withTimeout(10_000).using(robot());
+ takeScreenshot(preferencesDialog, "PreferencesDialog");
+ preferencesDialog.button(new GenericTypeMatcher<JButton>(JButton.class) {
+ @Override
+ protected boolean isMatching(@Nonnull JButton jButton) {
+ return "OK".equals(jButton.getText());
+ }
+ }).click();
+
+ exitJabRef();
+ }
+
+ /**
+ * tests different buttons
+ * sometimes this test clicks some buttons twice to reverse their effect and leaves JabRef as it was before
+ */
+ @Test
+ public void testViewChanges() {
+ newDatabase();
+
+ mainFrame.menuItemWithPath("View", "Increase table font size").click();
+ mainFrame.menuItemWithPath("View", "Decrease table font size").click();
+
+ mainFrame.menuItemWithPath("View", "Web search").click();
+ mainFrame.menuItemWithPath("View", "Web search").click();
+
+ mainFrame.menuItemWithPath("View", "Toggle groups interface").click();
+ mainFrame.menuItemWithPath("View", "Toggle groups interface").click();
+
+ mainFrame.menuItemWithPath("View", "Toggle entry preview").click();
+ mainFrame.menuItemWithPath("View", "Toggle entry preview").click();
+
+ mainFrame.menuItemWithPath("View", "Next preview layout").click();
+ mainFrame.menuItemWithPath("View", "Previous preview layout").click();
+
+ mainFrame.menuItemWithPath("View", "Hide/show toolbar").click();
+ mainFrame.menuItemWithPath("View", "Hide/show toolbar").click();
+
+ mainFrame.menuItemWithPath("View", "Focus entry table").click();
+
+ closeDatabase();
+ exitJabRef();
+ }
+
+ @Test
+ public void testDatabasePropertiesDialog() throws IOException {
+ newDatabase();
+
+ mainFrame.menuItemWithPath("File", "Database properties").click();
+
+ robot().waitForIdle();
+
+ DialogFixture databasePropertiesDialog = findDialog(DatabasePropertiesDialog.class).withTimeout(10_000).using(robot());
+ takeScreenshot(databasePropertiesDialog, "DatabasePropertiesDialog");
+ databasePropertiesDialog.button(new GenericTypeMatcher<JButton>(JButton.class) {
+ @Override
+ protected boolean isMatching(@Nonnull JButton jButton) {
+ return "OK".equals(jButton.getText());
+ }
+ }).click();
+
+ closeDatabase();
+ exitJabRef();
+ }
+}
diff --git a/src/test/java/net/sf/jabref/gui/IdFetcherDialogTest.java b/src/test/java/net/sf/jabref/gui/IdFetcherDialogTest.java
new file mode 100644
index 0000000..8f18e9b
--- /dev/null
+++ b/src/test/java/net/sf/jabref/gui/IdFetcherDialogTest.java
@@ -0,0 +1,136 @@
+package net.sf.jabref.gui;
+
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JDialog;
+import javax.swing.text.JTextComponent;
+
+import net.sf.jabref.testutils.category.GUITests;
+
+import org.assertj.swing.core.GenericTypeMatcher;
+import org.assertj.swing.dependency.jsr305.Nonnull;
+import org.assertj.swing.fixture.JTableFixture;
+import org.assertj.swing.timing.Condition;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import static org.assertj.swing.finder.WindowFinder.findDialog;
+import static org.assertj.swing.timing.Pause.pause;
+
+ at RunWith(Parameterized.class)
+ at Category(GUITests.class)
+public class IdFetcherDialogTest extends AbstractUITest {
+
+ private final String databaseMode, fetcherType, fetchID;
+
+ public IdFetcherDialogTest(String databaseMode, String fetcherType, String fetchID) {
+ this.databaseMode = databaseMode;
+ this.fetcherType = fetcherType;
+ this.fetchID = fetchID;
+ }
+
+ @Test
+ public void insertEmptySearchID() {
+ mainFrame.menuItemWithPath("File", "New " + databaseMode + " database").click();
+ JTableFixture entryTable = mainFrame.table();
+
+ entryTable.requireRowCount(0);
+ mainFrame.menuItemWithPath("BibTeX", "New entry...").click();
+
+ GenericTypeMatcher<JDialog> matcher = new GenericTypeMatcher<JDialog>(JDialog.class) {
+ @Override
+ protected boolean isMatching(JDialog dialog) {
+ return "Select entry type".equals(dialog.getTitle());
+ }
+ };
+
+ findDialog(matcher).withTimeout(10_000).using(robot()).button(new GenericTypeMatcher<JButton>(JButton.class) {
+
+ @Override
+ protected boolean isMatching(@Nonnull JButton jButton) {
+ return "Generate".equals(jButton.getText());
+ }
+ }).click();
+
+ GenericTypeMatcher<JDialog> matcherEmptyDialog = new GenericTypeMatcher<JDialog>(JDialog.class) {
+ @Override
+ protected boolean isMatching(JDialog dialog) {
+ return "Empty search ID".equals(dialog.getTitle());
+ }
+ };
+
+ findDialog(matcherEmptyDialog).withTimeout(10_000).using(robot()).button(new GenericTypeMatcher<JButton>(JButton.class) {
+
+ @Override
+ protected boolean isMatching(@Nonnull JButton jButton) {
+ return "OK".equals(jButton.getText());
+ }
+ }).click();
+
+ entryTable.requireRowCount(0);
+ }
+
+ @Test
+ public void testFetcherDialog() {
+ mainFrame.menuItemWithPath("File", "New " + databaseMode + " database").click();
+ JTableFixture entryTable = mainFrame.table();
+
+ entryTable.requireRowCount(0);
+ mainFrame.menuItemWithPath("BibTeX", "New entry...").click();
+
+ GenericTypeMatcher<JDialog> matcher = new GenericTypeMatcher<JDialog>(JDialog.class) {
+ @Override
+ protected boolean isMatching(JDialog dialog) {
+ return "Select entry type".equals(dialog.getTitle());
+ }
+ };
+
+ findDialog(matcher).withTimeout(10_000).using(robot()).comboBox(new GenericTypeMatcher<JComboBox>(JComboBox.class) {
+ @Override
+ protected boolean isMatching(@Nonnull JComboBox component) {
+ return true;
+ }
+ }).selectItem(fetcherType);
+
+ findDialog(matcher).withTimeout(10_000).using(robot()).textBox(new GenericTypeMatcher<JTextComponent>(JTextComponent.class) {
+ @Override
+ protected boolean isMatching(@Nonnull JTextComponent component) {
+ return true;
+ }
+ }).enterText(fetchID);
+
+ findDialog(matcher).withTimeout(10_000).using(robot()).button(new GenericTypeMatcher<JButton>(JButton.class) {
+ @Override
+ protected boolean isMatching(@Nonnull JButton jButton) {
+ return "Generate".equals(jButton.getText());
+ }
+ }).click();
+
+ pause(new Condition("entrySize") {
+ @Override
+ public boolean test() {
+ return entryTable.rowCount() == 1;
+ }
+ }, 10_000);
+
+ entryTable.requireRowCount(1);
+ }
+
+
+ @Parameterized.Parameters(name = "{index}: {0} : {1} : {2}")
+ public static Collection<Object[]> instancesToTest() {
+ return Arrays.asList(
+ new Object[]{"BibTeX", "DOI", "10.1002/9781118257517"},
+ new Object[]{"BibLaTeX", "DOI", "10.1002/9781118257517"},
+ new Object[]{"BibTeX", "ISBN", "9780321356680"},
+ new Object[]{"BibLaTeX", "ISBN", "9780321356680"}
+ );
+ }
+
+}
diff --git a/src/test/java/net/sf/jabref/gui/ParameterizedDialogNewEntryTest.java b/src/test/java/net/sf/jabref/gui/ParameterizedDialogNewEntryTest.java
new file mode 100644
index 0000000..b9104f4
--- /dev/null
+++ b/src/test/java/net/sf/jabref/gui/ParameterizedDialogNewEntryTest.java
@@ -0,0 +1,203 @@
+package net.sf.jabref.gui;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Locale;
+
+import javax.swing.JButton;
+import javax.swing.JDialog;
+
+import net.sf.jabref.testutils.category.GUITests;
+
+import org.assertj.swing.core.GenericTypeMatcher;
+import org.assertj.swing.dependency.jsr305.Nonnull;
+import org.assertj.swing.fixture.JTableFixture;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import static org.assertj.swing.finder.WindowFinder.findDialog;
+
+ at RunWith(Parameterized.class)
+ at Category(GUITests.class)
+public class ParameterizedDialogNewEntryTest extends AbstractUITest {
+
+ private final String databaseMode;
+ private final String entryType;
+
+
+ public ParameterizedDialogNewEntryTest(String databaseMode, String entryType) {
+ this.databaseMode = databaseMode;
+ this.entryType = entryType;
+ }
+
+ @Test
+ public void addEntryOfGivenType() {
+ mainFrame.menuItemWithPath("File", "New " + databaseMode + " database").click();
+ JTableFixture entryTable = mainFrame.table();
+
+ entryTable.requireRowCount(0);
+ mainFrame.menuItemWithPath("BibTeX", "New entry...").click();
+
+ selectEntryType();
+
+ entryTable.requireRowCount(1);
+ }
+
+ private void selectEntryType() {
+ GenericTypeMatcher<JDialog> matcher = new GenericTypeMatcher<JDialog>(JDialog.class) {
+
+ @Override
+ protected boolean isMatching(JDialog dialog) {
+ return "Select entry type".equals(dialog.getTitle());
+ }
+ };
+
+ findDialog(matcher).withTimeout(10_000).using(robot()).button(new GenericTypeMatcher<JButton>(JButton.class) {
+
+ @Override
+ protected boolean isMatching(@Nonnull JButton jButton) {
+ return entryType.equals(jButton.getText());
+ }
+ }).click();
+ }
+
+ @Test
+ public void addEntryPlainTextOfGivenType() {
+ mainFrame.menuItemWithPath("File", "New " + databaseMode + " database").click();
+ JTableFixture entryTable = mainFrame.table();
+
+ entryTable.requireRowCount(0);
+ mainFrame.menuItemWithPath("BibTeX", "New entry from plain text...").click();
+
+ selectEntryType();
+
+ GenericTypeMatcher<JDialog> matcher2 = plainTextMatcher();
+
+ findDialog(matcher2).withTimeout(10_000).using(robot()).button(new GenericTypeMatcher<JButton>(JButton.class) {
+
+ @Override
+ protected boolean isMatching(@Nonnull JButton jButton) {
+ return "Accept".equals(jButton.getText());
+ }
+ }).click();
+
+ entryTable.requireRowCount(1);
+ }
+
+ @Test
+ public void closeAddingEntryPlainTextOfGivenType() {
+ mainFrame.menuItemWithPath("File", "New " + databaseMode + " database").click();
+ JTableFixture entryTable = mainFrame.table();
+
+ entryTable.requireRowCount(0);
+ mainFrame.menuItemWithPath("BibTeX", "New entry from plain text...").click();
+
+ selectEntryType();
+
+ GenericTypeMatcher<JDialog> matcher2 = plainTextMatcher();
+
+ findDialog(matcher2).withTimeout(10_000).using(robot()).close();
+ entryTable.requireRowCount(0);
+ }
+
+ @Test
+ public void cancelAddingEntryPlainTextOfGivenType() {
+ mainFrame.menuItemWithPath("File", "New " + databaseMode + " database").click();
+ JTableFixture entryTable = mainFrame.table();
+
+ entryTable.requireRowCount(0);
+ mainFrame.menuItemWithPath("BibTeX", "New entry from plain text...").click();
+
+ selectEntryType();
+
+ GenericTypeMatcher<JDialog> matcher2 = plainTextMatcher();
+
+ findDialog(matcher2).withTimeout(10_000).using(robot()).button(new GenericTypeMatcher<JButton>(JButton.class) {
+
+ @Override
+ protected boolean isMatching(@Nonnull JButton jButton) {
+ return "Cancel".equals(jButton.getText());
+ }
+ }).click();
+
+ entryTable.requireRowCount(0);
+ }
+
+ private GenericTypeMatcher<JDialog> plainTextMatcher() {
+ GenericTypeMatcher<JDialog> matcher2 = new GenericTypeMatcher<JDialog>(JDialog.class) {
+
+ @Override
+ protected boolean isMatching(JDialog dialog) {
+ return ("Plain text import for " + entryType.toLowerCase(Locale.ENGLISH)).equals(dialog.getTitle());
+ }
+ };
+ return matcher2;
+ }
+
+ @Parameterized.Parameters(name = "{index}: {0} : {1}")
+ public static Collection<Object[]> instancesToTest() {
+ // Create entry from menu
+ // Structure:
+ // {"BibTeX"/"BibLaTeX", "type"}
+ // @formatter:off
+ return Arrays.asList(
+ new Object[]{"BibTeX", "Article"},
+/* new Object[]{"BibTeX", "InBook"},
+ new Object[]{"BibTeX", "Book"},
+ new Object[]{"BibTeX", "Booklet"},
+ new Object[]{"BibTeX", "InCollection"},
+ new Object[]{"BibTeX", "Conference"},
+ new Object[]{"BibTeX", "InProceedings"},
+ new Object[]{"BibTeX", "Proceedings"},
+ new Object[]{"BibTeX", "Manual"},
+ new Object[]{"BibTeX", "MastersThesis"},
+ new Object[]{"BibTeX", "PhdThesis"},
+ new Object[]{"BibTeX", "TechReport"},
+ new Object[]{"BibTeX", "Unpublished"},
+ new Object[]{"BibTeX", "Misc"},
+ new Object[]{"BibTeX", "Electronic"},
+ new Object[]{"BibTeX", "IEEEtranBSTCTL"},
+ new Object[]{"BibTeX", "Periodical"},
+ new Object[]{"BibTeX", "Patent"},
+ new Object[]{"BibTeX", "Standard"},
+ new Object[]{"BibLaTeX", "Article"},
+ new Object[]{"BibLaTeX", "Book"},
+ new Object[]{"BibLaTeX", "BookInBook"},
+ new Object[]{"BibLaTeX", "Booklet"},
+ new Object[]{"BibLaTeX", "Collection"},
+ new Object[]{"BibLaTeX", "Conference"},
+ new Object[]{"BibLaTeX", "Electronic"},
+ new Object[]{"BibLaTeX", "IEEEtranBSTCTL"},
+ new Object[]{"BibLaTeX", "InBook"},
+ new Object[]{"BibLaTeX", "InCollection"},
+ new Object[]{"BibLaTeX", "InProceedings"},
+ new Object[]{"BibLaTeX", "InReference"},
+ new Object[]{"BibLaTeX", "Manual"},
+ new Object[]{"BibLaTeX", "MastersThesis"},
+ new Object[]{"BibLaTeX", "Misc"},
+ new Object[]{"BibLaTeX", "MvBook"},
+ new Object[]{"BibLaTeX", "MvCollection"},
+ new Object[]{"BibLaTeX", "MvProceedings"},
+ new Object[]{"BibLaTeX", "MvReference"},
+ new Object[]{"BibLaTeX", "Online"},
+ new Object[]{"BibLaTeX", "Patent"},
+ new Object[]{"BibLaTeX", "Periodical"},
+ new Object[]{"BibLaTeX", "PhdThesis"},
+ new Object[]{"BibLaTeX", "Proceedings"},
+ new Object[]{"BibLaTeX", "Reference"},
+ new Object[]{"BibLaTeX", "Report"},
+ new Object[]{"BibLaTeX", "Set"},
+ new Object[]{"BibLaTeX", "SuppBook"},
+ new Object[]{"BibLaTeX", "SuppCollection"},
+ new Object[]{"BibLaTeX", "SuppPeriodical"},
+ new Object[]{"BibLaTeX", "TechReport"},
+ new Object[]{"BibLaTeX", "Thesis"},
+ new Object[]{"BibLaTeX", "Unpublished"},*/
+ new Object[]{"BibLaTeX", "WWW"}
+ );
+ // @formatter:on
+ }
+
+}
diff --git a/src/test/java/net/sf/jabref/gui/ParameterizedDialogTest.java b/src/test/java/net/sf/jabref/gui/ParameterizedDialogTest.java
new file mode 100644
index 0000000..86a6de6
--- /dev/null
+++ b/src/test/java/net/sf/jabref/gui/ParameterizedDialogTest.java
@@ -0,0 +1,154 @@
+package net.sf.jabref.gui;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import javax.swing.JButton;
+import javax.swing.JDialog;
+
+import net.sf.jabref.testutils.category.GUITests;
+
+import org.assertj.swing.core.GenericTypeMatcher;
+import org.assertj.swing.dependency.jsr305.Nonnull;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import static org.assertj.swing.finder.WindowFinder.findDialog;
+
+ at RunWith(Parameterized.class)
+ at Category(GUITests.class)
+public class ParameterizedDialogTest extends AbstractUITest {
+
+ private final boolean createDatabase;
+ private final String[] menuPath;
+ private final String dialogTitle;
+ private final String buttonName;
+ private final boolean closeButton;
+
+
+ public ParameterizedDialogTest(boolean createDatabase, String[] menuPath, String dialogTitle, String buttonName,
+ boolean closeButton) {
+ this.createDatabase = createDatabase;
+ this.menuPath = menuPath;
+ this.dialogTitle = dialogTitle;
+ this.buttonName = buttonName;
+ this.closeButton = closeButton;
+ }
+
+ @Test
+ public void openAndExitDialog() {
+ if (createDatabase) {
+ newDatabase();
+ }
+ mainFrame.menuItemWithPath(menuPath).click();
+ GenericTypeMatcher<JDialog> matcher = new GenericTypeMatcher<JDialog>(JDialog.class) {
+
+ @Override
+ protected boolean isMatching(JDialog dialog) {
+ return dialogTitle.equals(dialog.getTitle());
+ }
+ };
+
+ if (closeButton) {
+ findDialog(matcher).withTimeout(10_000).using(robot()).close();
+ } else {
+ findDialog(matcher).withTimeout(10_000).using(robot())
+ .button(new GenericTypeMatcher<JButton>(JButton.class) {
+
+ @Override
+ protected boolean isMatching(@Nonnull JButton jButton) {
+ return buttonName.equals(jButton.getText());
+ }
+ }).click();
+ }
+ if (createDatabase) {
+ closeDatabase();
+ }
+ exitJabRef();
+ }
+
+ @Parameterized.Parameters(name = "{index}: {1} -> {2} : {3}")
+ public static Collection<Object[]> instancesToTest() {
+ // Opening and closing (in different ways) the dialogs accessible from the menus without doing anything else
+ // Structure:
+ // {create new database, {"Menu", "Submenu", "Sub-sub-menu"}, "Dialog title", "Button name", use close button}
+ // @formatter:off
+ return Arrays.asList(
+ new Object[]{false, new String[]{"File", "Open database"}, "Open", "Cancel", false},
+ new Object[]{false, new String[]{"File", "Open database"}, "Open", "Close button", true},
+ new Object[]{true, new String[]{"File", "Append database"}, "Append database", "Cancel", false},
+ new Object[]{true, new String[]{"File", "Append database"}, "Append database", "Close button", true},
+ new Object[]{true, new String[]{"File", "Save database"}, "Save", "Cancel", false},
+ new Object[]{true, new String[]{"File", "Save database"}, "Save", "Close button", true},
+ new Object[]{true, new String[]{"File", "Save database as..."}, "Save", "Cancel", false},
+ new Object[]{true, new String[]{"File", "Save database as..."}, "Save", "Close button", true},
+ new Object[]{true, new String[]{"File", "Save all"}, "Save", "Cancel", false},
+ new Object[]{true, new String[]{"File", "Save all"}, "Save", "Close button", true},
+ new Object[]{false, new String[]{"File", "Import into new database"}, "Open", "Cancel", false},
+ new Object[]{false, new String[]{"File", "Import into new database"}, "Open", "Close button", true},
+ new Object[]{true, new String[]{"File", "Import into current database"}, "Open", "Cancel", false},
+ new Object[]{true, new String[]{"File", "Import into current database"}, "Open", "Close button", true},
+ new Object[]{true, new String[]{"File", "Export"}, "Save", "Cancel", false},
+ new Object[]{true, new String[]{"File", "Export"}, "Save", "Close button", true},
+ new Object[]{true, new String[]{"File", "Open shared database"}, "Open shared database", "Cancel", false},
+ new Object[]{true, new String[]{"File", "Database properties"}, "Database properties", "Cancel", false},
+ new Object[]{true, new String[]{"File", "Database properties"}, "Database properties", "OK", false},
+ new Object[]{true, new String[]{"File", "Database properties"}, "Database properties", "Close button", true},
+ new Object[]{true, new String[]{"Edit", "Set/clear/rename fields..."}, "Set/clear/rename fields", "Cancel", false},
+ //new Object[]{true, new String[]{"Edit", "Set/clear/rename fields..."}, "Set/clear/rename fields", "OK", false},
+ new Object[]{true, new String[]{"Edit", "Set/clear/rename fields..."}, "Set/clear/rename fields", "Close button", true},
+ new Object[]{true, new String[]{"Search", "Replace string..."}, "Replace string", "Cancel", false},
+ new Object[]{true, new String[]{"Search", "Replace string..."}, "Replace string", "Close button", true},
+ new Object[]{true, new String[]{"Groups", "Add to group..."}, "Add to group", "Cancel", false},
+ new Object[]{true, new String[]{"Groups", "Add to group..."}, "Add to group", "Close button", true},
+ new Object[]{true, new String[]{"Groups", "Remove from group..."}, "Remove from group", "Cancel", false},
+ new Object[]{true, new String[]{"Groups", "Remove from group..."}, "Remove from group", "Close button", true},
+ new Object[]{true, new String[]{"Groups", "Move to group..."}, "Move to group", "Cancel", false},
+ new Object[]{true, new String[]{"Groups", "Move to group..."}, "Move to group", "Close button", true},
+ new Object[]{true, new String[]{"BibTeX", "New entry..."}, "Select entry type", "Cancel", false},
+ new Object[]{true, new String[]{"BibTeX", "New entry..."}, "Select entry type", "Close button", true},
+ new Object[]{true, new String[]{"BibTeX", "Edit preamble"}, "Edit preamble", "Close button", true},
+ new Object[]{true, new String[]{"BibTeX", "Edit strings"}, "Strings for database: untitled", "Close button", true},
+ new Object[]{true, new String[]{"BibTeX", "Customize entry types"}, "Customize entry types", "Cancel", false},
+ new Object[]{true, new String[]{"BibTeX", "Customize entry types"}, "Customize entry types", "OK", false},
+ new Object[]{true, new String[]{"BibTeX", "Customize entry types"}, "Customize entry types", "Close button", true},
+ new Object[]{true, new String[]{"Quality", "Synchronize file links..."}, "Synchronize file links", "Cancel", false},
+ new Object[]{true, new String[]{"Quality", "Synchronize file links..."}, "Synchronize file links", "Close button", true},
+ new Object[]{true, new String[]{"Quality", "Find unlinked files..."}, "Find unlinked files", "Close", false},
+ new Object[]{true, new String[]{"Quality", "Find unlinked files..."}, "Find unlinked files", "Close button", true},
+ new Object[]{true, new String[]{"Tools", "New subdatabase based on AUX file..."}, "AUX file import", "Cancel", false},
+ new Object[]{true, new String[]{"Tools", "New subdatabase based on AUX file..."}, "AUX file import", "Close button", true},
+ new Object[]{false, new String[]{"Options", "Preferences"}, "JabRef preferences", "Cancel", false},
+ new Object[]{false, new String[]{"Options", "Preferences"}, "JabRef preferences", "OK", false},
+ new Object[]{false, new String[]{"Options", "Preferences"}, "JabRef preferences", "Close button", true},
+ new Object[]{false, new String[]{"Options", "Set up general fields"}, "Set general fields", "Cancel", false},
+ new Object[]{false, new String[]{"Options", "Set up general fields"}, "Set general fields", "OK", false},
+ new Object[]{false, new String[]{"Options", "Set up general fields"}, "Set general fields", "Close button", true},
+ new Object[]{false, new String[]{"Options", "Manage custom exports"}, "Manage custom exports", "Close", false},
+ new Object[]{false, new String[]{"Options", "Manage custom exports"}, "Manage custom exports", "Close button", true},
+ new Object[]{false, new String[]{"Options", "Manage custom imports"}, "Manage custom imports", "Close", false},
+ new Object[]{false, new String[]{"Options", "Manage custom imports"}, "Manage custom imports", "Close button", true},
+ new Object[]{false, new String[]{"Options", "Manage external file types"}, "Manage external file types", "Cancel", false},
+ new Object[]{false, new String[]{"Options", "Manage external file types"}, "Manage external file types", "OK", false},
+ new Object[]{false, new String[]{"Options", "Manage external file types"}, "Manage external file types", "Close button", true},
+ new Object[]{false, new String[]{"Options", "Manage journal abbreviations"}, "Journal abbreviations", "Cancel", false},
+ new Object[]{false, new String[]{"Options", "Manage journal abbreviations"}, "Journal abbreviations", "OK", false},
+ new Object[]{false, new String[]{"Options", "Manage journal abbreviations"}, "Journal abbreviations", "Close button", true},
+ new Object[]{true, new String[]{"Options", "Manage content selectors"}, "Manage content selectors", "Cancel", false},
+ // new Object[]{true, new String[]{"Options", "Manage content selectors"}, "Manage content selectors", "OK", false},
+ new Object[]{true, new String[]{"Options", "Manage content selectors"}, "Manage content selectors", "Close button", true},
+ new Object[]{false, new String[]{"Options", "Manage protected terms"}, "Manage protected terms files", "Cancel", false},
+ new Object[]{false, new String[]{"Options", "Manage protected terms"}, "Manage protected terms files", "OK", false},
+ new Object[]{false, new String[]{"Options", "Manage protected terms"}, "Manage protected terms files", "Close button", true},
+ new Object[]{false, new String[]{"Options", "Customize key bindings"}, "Key bindings", "Cancel", false},
+ new Object[]{false, new String[]{"Options", "Customize key bindings"}, "Key bindings", "Close button", true},
+ new Object[]{false, new String[]{"Help", "Show error console"}, "Program output", "OK", false},
+ new Object[]{false, new String[]{"Help", "Show error console"}, "Program output", "Close button", true},
+ new Object[]{false, new String[]{"Help", "About JabRef"}, "About JabRef", "Close button", true}
+ );
+ // @formatter:on
+ }
+
+}
diff --git a/src/test/java/net/sf/jabref/gui/ParameterizedMenuNewEntryTest.java b/src/test/java/net/sf/jabref/gui/ParameterizedMenuNewEntryTest.java
new file mode 100644
index 0000000..0b23974
--- /dev/null
+++ b/src/test/java/net/sf/jabref/gui/ParameterizedMenuNewEntryTest.java
@@ -0,0 +1,78 @@
+package net.sf.jabref.gui;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import net.sf.jabref.model.strings.StringUtil;
+import net.sf.jabref.testutils.category.GUITests;
+
+import org.assertj.swing.fixture.JTableFixture;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+ at RunWith(Parameterized.class)
+ at Category(GUITests.class)
+public class ParameterizedMenuNewEntryTest extends AbstractUITest {
+
+ private final String databaseMode;
+ private final String entryType;
+
+
+ public ParameterizedMenuNewEntryTest(String databaseMode, String entryType) {
+ this.databaseMode = databaseMode;
+ this.entryType = entryType;
+ }
+
+ // Not working on Travis
+ @Test
+ public void addEntryOfGivenType() {
+ mainFrame.menuItemWithPath("File", "New " + databaseMode + " database").click();
+ JTableFixture entryTable = mainFrame.table();
+
+ entryTable.requireRowCount(0);
+ mainFrame.menuItemWithPath("BibTeX", "New entry by type...", StringUtil.capitalizeFirst(entryType)).click();
+ entryTable.requireRowCount(1);
+ }
+
+ @Parameterized.Parameters(name = "{index}: {0} : {1}")
+ public static Collection<Object[]> instancesToTest() {
+ // Create entry from menu
+ // Structure:
+ // {"BibTeX"/"BibLaTeX", "type"}
+ // @formatter:off
+ return Arrays.asList(
+ new Object[]{"BibTeX", "article"},
+ new Object[]{"BibTeX", "inbook"},
+ new Object[]{"BibTeX", "book"},
+ new Object[]{"BibTeX", "booklet"},
+ new Object[]{"BibTeX", "incollection"},
+ new Object[]{"BibTeX", "conference"},
+ new Object[]{"BibTeX", "inproceedings"},
+ new Object[]{"BibTeX", "proceedings"},
+ new Object[]{"BibTeX", "manual"},
+ new Object[]{"BibTeX", "mastersthesis"},
+ new Object[]{"BibTeX", "phdthesis"},
+ new Object[]{"BibTeX", "techreport"},
+ new Object[]{"BibTeX", "unpublished"},
+ new Object[]{"BibTeX", "misc"},
+ new Object[]{"BibLaTeX", "article"},
+ new Object[]{"BibLaTeX", "inbook"},
+ new Object[]{"BibLaTeX", "book"},
+ new Object[]{"BibLaTeX", "booklet"},
+ new Object[]{"BibLaTeX", "incollection"},
+ new Object[]{"BibLaTeX", "conference"},
+ new Object[]{"BibLaTeX", "inproceedings"},
+ new Object[]{"BibLaTeX", "proceedings"},
+ new Object[]{"BibLaTeX", "manual"},
+ new Object[]{"BibLaTeX", "mastersthesis"},
+ new Object[]{"BibLaTeX", "phdthesis"},
+ new Object[]{"BibLaTeX", "techreport"},
+ new Object[]{"BibLaTeX", "unpublished"},
+ new Object[]{"BibLaTeX", "misc"}
+ );
+ // @formatter:on
+ }
+
+}
diff --git a/src/test/java/net/sf/jabref/gui/UndoTest.java b/src/test/java/net/sf/jabref/gui/UndoTest.java
new file mode 100644
index 0000000..95d3f21
--- /dev/null
+++ b/src/test/java/net/sf/jabref/gui/UndoTest.java
@@ -0,0 +1,68 @@
+package net.sf.jabref.gui;
+
+import javax.swing.JButton;
+
+import net.sf.jabref.testutils.category.GUITests;
+
+import org.assertj.swing.core.GenericTypeMatcher;
+import org.assertj.swing.dependency.jsr305.Nonnull;
+import org.assertj.swing.fixture.JTableFixture;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import static org.assertj.swing.finder.WindowFinder.findDialog;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+ at Category(GUITests.class)
+public class UndoTest extends AbstractUITest {
+
+ @Test
+ public void undoCutOfMultipleEntries() {
+ importBibIntoNewDatabase(getAbsolutePath("testbib/testjabref.bib"));
+
+ JTableFixture entryTable = mainFrame.table();
+
+ assertTrue("The database must have at least 2 entries for the test to begin!", entryTable.rowCount() >= 2);
+ entryTable.selectRows(0, 1);
+ entryTable.requireSelectedRows(0, 1);
+
+ int oldRowCount = entryTable.rowCount();
+ mainFrame.menuItemWithPath("Edit", "Cut").click();
+ mainFrame.menuItemWithPath("Edit", "Undo").click();
+ entryTable.requireRowCount(oldRowCount);
+
+ closeDatabase();
+ exitJabRef();
+ }
+
+ @Test
+ public void undoRedoUpdatedCorrectly() {
+ newDatabase();
+ assertFalse(mainFrame.menuItemWithPath("Edit", "Undo").isEnabled());
+ assertFalse(mainFrame.menuItemWithPath("Edit", "Redo").isEnabled());
+ JTableFixture entryTable = mainFrame.table();
+ mainFrame.menuItemWithPath("BibTeX", "New entry...").click();
+ findDialog(EntryTypeDialog.class).withTimeout(10_000).using(robot())
+ .button(new GenericTypeMatcher<JButton>(JButton.class) {
+
+ @Override
+ protected boolean isMatching(@Nonnull JButton jButton) {
+ return "Book".equals(jButton.getText());
+ }
+ }).click();
+
+ assertTrue(mainFrame.menuItemWithPath("Edit", "Undo").isEnabled());
+ assertFalse(mainFrame.menuItemWithPath("Edit", "Redo").isEnabled());
+ entryTable.requireRowCount(1);
+
+ mainFrame.menuItemWithPath("Edit", "Undo").click();
+ assertFalse(mainFrame.menuItemWithPath("Edit", "Undo").isEnabled());
+ assertTrue(mainFrame.menuItemWithPath("Edit", "Redo").isEnabled());
+ entryTable.requireRowCount(0);
+
+ closeDatabase();
+ exitJabRef();
+ }
+
+}
diff --git a/src/test/java/net/sf/jabref/gui/entryeditor/EntryEditorTest.java b/src/test/java/net/sf/jabref/gui/entryeditor/EntryEditorTest.java
index c739ae0..5d17e14 100644
--- a/src/test/java/net/sf/jabref/gui/entryeditor/EntryEditorTest.java
+++ b/src/test/java/net/sf/jabref/gui/entryeditor/EntryEditorTest.java
@@ -10,11 +10,14 @@ import net.sf.jabref.gui.fieldeditors.TextArea;
import net.sf.jabref.logic.autocompleter.AutoCompleter;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.testutils.TestUtils;
+import net.sf.jabref.testutils.category.GUITests;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
+import org.junit.experimental.categories.Category;
+ at Category(GUITests.class)
public class EntryEditorTest {
@Test
diff --git a/src/test/java/net/sf/jabref/gui/externalfiletype/ExternalFileTypeTest.java b/src/test/java/net/sf/jabref/gui/externalfiletype/ExternalFileTypeTest.java
new file mode 100644
index 0000000..53453c2
--- /dev/null
+++ b/src/test/java/net/sf/jabref/gui/externalfiletype/ExternalFileTypeTest.java
@@ -0,0 +1,34 @@
+package net.sf.jabref.gui.externalfiletype;
+
+import net.sf.jabref.testutils.category.GUITests;
+
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import static org.junit.Assert.assertNotNull;
+
+ at Category(GUITests.class)
+public class ExternalFileTypeTest {
+
+ @Test
+ public void getOpenWithApplicationMustNotReturnNull() throws Exception {
+ ExternalFileType type = new ExternalFileType(null, null, null, null, null, null);
+
+ assertNotNull(type.getOpenWithApplication());
+ }
+
+ @Test
+ public void getExtensionMustNotReturnNull() throws Exception {
+ ExternalFileType type = new ExternalFileType(null, null, null, null, null, null);
+
+ assertNotNull(type.getExtension());
+ }
+
+ @Test
+ public void getMimeTypeMustNotReturnNull() throws Exception {
+ ExternalFileType type = new ExternalFileType(null, null, null, null, null, null);
+
+ assertNotNull(type.getMimeType());
+ }
+
+}
diff --git a/src/test/java/net/sf/jabref/gui/importer/EntryFromFileCreatorManagerTest.java b/src/test/java/net/sf/jabref/gui/importer/EntryFromFileCreatorManagerTest.java
index 02ee4f3..639b7e2 100644
--- a/src/test/java/net/sf/jabref/gui/importer/EntryFromFileCreatorManagerTest.java
+++ b/src/test/java/net/sf/jabref/gui/importer/EntryFromFileCreatorManagerTest.java
@@ -11,21 +11,20 @@ import java.util.List;
import net.sf.jabref.Globals;
import net.sf.jabref.logic.importer.ImportDataTest;
-import net.sf.jabref.logic.importer.ImportFormatPreferences;
import net.sf.jabref.logic.importer.ParserResult;
import net.sf.jabref.logic.importer.fileformat.BibtexParser;
import net.sf.jabref.model.database.BibDatabase;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.preferences.JabRefPreferences;
+import net.sf.jabref.testutils.category.GUITests;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
+import org.junit.experimental.categories.Category;
-/**
- * @version 11.11.2008 | 21:51:54
- */
+ at Category(GUITests.class)
public class EntryFromFileCreatorManagerTest {
// Needed to initialize ExternalFileTypes
@@ -50,7 +49,7 @@ public class EntryFromFileCreatorManagerTest {
public void testAddEntrysFromFiles() throws FileNotFoundException, IOException {
try (FileInputStream stream = new FileInputStream(ImportDataTest.UNLINKED_FILES_TEST_BIB);
InputStreamReader reader = new InputStreamReader(stream, StandardCharsets.UTF_8)) {
- ParserResult result = BibtexParser.parse(reader, ImportFormatPreferences.fromPreferences(Globals.prefs));
+ ParserResult result = BibtexParser.parse(reader, Globals.prefs.getImportFormatPreferences());
BibDatabase database = result.getDatabase();
List<File> files = new ArrayList<>();
@@ -69,7 +68,7 @@ public class EntryFromFileCreatorManagerTest {
boolean file1Found = false;
boolean file2Found = false;
for (BibEntry entry : database.getEntries()) {
- String filesInfo = entry.getFieldOptional("file").get();
+ String filesInfo = entry.getField("file").get();
if (filesInfo.contains(files.get(0).getName())) {
file1Found = true;
}
diff --git a/src/test/java/net/sf/jabref/gui/importer/EntryFromPDFCreatorTest.java b/src/test/java/net/sf/jabref/gui/importer/EntryFromPDFCreatorTest.java
index bd649da..739df70 100644
--- a/src/test/java/net/sf/jabref/gui/importer/EntryFromPDFCreatorTest.java
+++ b/src/test/java/net/sf/jabref/gui/importer/EntryFromPDFCreatorTest.java
@@ -9,14 +9,17 @@ import net.sf.jabref.gui.JabRefFrame;
import net.sf.jabref.logic.importer.ImportDataTest;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.preferences.JabRefPreferences;
+import net.sf.jabref.testutils.category.GUITests;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
+import org.junit.experimental.categories.Category;
import static org.mockito.Mockito.mock;
+ at Category(GUITests.class)
public class EntryFromPDFCreatorTest {
private EntryFromPDFCreator entryCreator;
@@ -45,13 +48,13 @@ public class EntryFromPDFCreatorTest {
}
@Test
- @Ignore
+ @Ignore //Can't mock basepanel and maintable
public void testCreationOfEntryNotInDatabase() {
Optional<BibEntry> entry = entryCreator.createEntry(ImportDataTest.FILE_NOT_IN_DATABASE, false);
Assert.assertTrue(entry.isPresent());
- Assert.assertTrue(entry.get().getFieldOptional("file").get().endsWith(":PDF"));
+ Assert.assertTrue(entry.get().getField("file").get().endsWith(":PDF"));
Assert.assertEquals(Optional.of(ImportDataTest.FILE_NOT_IN_DATABASE.getName()),
- entry.get().getFieldOptional("title"));
+ entry.get().getField("title"));
}
-}
\ No newline at end of file
+}
diff --git a/src/test/java/net/sf/jabref/gui/importer/actions/ConvertLegacyExplicitGroupsTest.java b/src/test/java/net/sf/jabref/gui/importer/actions/ConvertLegacyExplicitGroupsTest.java
index 3ed2cfa..518c6c4 100644
--- a/src/test/java/net/sf/jabref/gui/importer/actions/ConvertLegacyExplicitGroupsTest.java
+++ b/src/test/java/net/sf/jabref/gui/importer/actions/ConvertLegacyExplicitGroupsTest.java
@@ -3,23 +3,24 @@ package net.sf.jabref.gui.importer.actions;
import java.util.Collections;
import java.util.Optional;
-import net.sf.jabref.Globals;
import net.sf.jabref.gui.BasePanel;
-import net.sf.jabref.logic.groups.AllEntriesGroup;
-import net.sf.jabref.logic.groups.ExplicitGroup;
-import net.sf.jabref.logic.groups.GroupHierarchyType;
-import net.sf.jabref.logic.groups.GroupTreeNode;
import net.sf.jabref.logic.importer.ParserResult;
import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.preferences.JabRefPreferences;
+import net.sf.jabref.model.groups.AllEntriesGroup;
+import net.sf.jabref.model.groups.ExplicitGroup;
+import net.sf.jabref.model.groups.GroupHierarchyType;
+import net.sf.jabref.model.groups.GroupTreeNode;
+import net.sf.jabref.testutils.category.GUITests;
import org.junit.Before;
import org.junit.Test;
+import org.junit.experimental.categories.Category;
import org.mockito.Mock;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+ at Category(GUITests.class)
public class ConvertLegacyExplicitGroupsTest {
private ConvertLegacyExplicitGroups action;
@@ -29,28 +30,26 @@ public class ConvertLegacyExplicitGroupsTest {
@Before
public void setUp() throws Exception {
- Globals.prefs = JabRefPreferences.getInstance();
-
action = new ConvertLegacyExplicitGroups();
entry = new BibEntry();
entry.setCiteKey("Entry1");
- group = new ExplicitGroup("TestGroup", GroupHierarchyType.INCLUDING, Globals.prefs);
+ group = new ExplicitGroup("TestGroup", GroupHierarchyType.INCLUDING, ',');
group.addLegacyEntryKey("Entry1");
}
@Test
public void performActionWritesGroupMembershipInEntry() throws Exception {
- ParserResult parserResult = generateParserResult(entry, GroupTreeNode.fromGroup(group));
+ ParserResult parserResult = generateParserResult(GroupTreeNode.fromGroup(group));
action.performAction(basePanel, parserResult);
- assertEquals(Optional.of("TestGroup"), entry.getFieldOptional("groups"));
+ assertEquals(Optional.of("TestGroup"), entry.getField("groups"));
}
@Test
public void performActionClearsLegacyKeys() throws Exception {
- ParserResult parserResult = generateParserResult(entry, GroupTreeNode.fromGroup(group));
+ ParserResult parserResult = generateParserResult(GroupTreeNode.fromGroup(group));
action.performAction(basePanel, parserResult);
@@ -59,24 +58,24 @@ public class ConvertLegacyExplicitGroupsTest {
@Test
public void performActionWritesGroupMembershipInEntryForComplexGroupTree() throws Exception {
- GroupTreeNode root = GroupTreeNode.fromGroup(new AllEntriesGroup());
- root.addSubgroup(new ExplicitGroup("TestGroup2", GroupHierarchyType.INCLUDING, Globals.prefs));
+ GroupTreeNode root = GroupTreeNode.fromGroup(new AllEntriesGroup(""));
+ root.addSubgroup(new ExplicitGroup("TestGroup2", GroupHierarchyType.INCLUDING, ','));
root.addSubgroup(group);
- ParserResult parserResult = generateParserResult(entry, root);
+ ParserResult parserResult = generateParserResult(root);
action.performAction(basePanel, parserResult);
- assertEquals(Optional.of("TestGroup"), entry.getFieldOptional("groups"));
+ assertEquals(Optional.of("TestGroup"), entry.getField("groups"));
}
@Test
public void isActionNecessaryReturnsTrueIfGroupContainsLegacyKeys() throws Exception {
- ParserResult parserResult = generateParserResult(entry, GroupTreeNode.fromGroup(group));
+ ParserResult parserResult = generateParserResult(GroupTreeNode.fromGroup(group));
assertTrue(action.isActionNecessary(parserResult));
}
- private ParserResult generateParserResult(BibEntry entry, GroupTreeNode groupRoot) {
+ private ParserResult generateParserResult(GroupTreeNode groupRoot) {
ParserResult parserResult = new ParserResult(Collections.singletonList(entry));
parserResult.getMetaData().setGroups(groupRoot);
return parserResult;
diff --git a/src/test/java/net/sf/jabref/gui/importer/fetcher/GeneralFetcherTest.java b/src/test/java/net/sf/jabref/gui/importer/fetcher/GeneralFetcherTest.java
deleted file mode 100644
index 5bdb204..0000000
--- a/src/test/java/net/sf/jabref/gui/importer/fetcher/GeneralFetcherTest.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package net.sf.jabref.gui.importer.fetcher;
-
-import java.util.ArrayList;
-
-import javax.swing.JButton;
-import javax.swing.JTextField;
-
-import net.sf.jabref.JabRefGUI;
-import net.sf.jabref.JabRefMain;
-import net.sf.jabref.gui.JabRefFrame;
-import net.sf.jabref.gui.SidePaneManager;
-import net.sf.jabref.testutils.GuiTestUtils;
-
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-
-/**
- * Tests GeneralFetcher
- *
- * @author Dennis Hartrampf, Ines Moosdorf
- */
-public class GeneralFetcherTest {
-
- private static JabRefFrame jrf;
- private static SidePaneManager spm;
- private static GeneralFetcher gf;
- private static ACMPortalFetcher acmpf;
-
-
- /**
- * Tests the reset-button. Types a text into tf, pushs reset and check tf's
- * text
- *
- * @throws Exception
- */
- @Test @Ignore
- public void testResetButton() throws Exception {
- String testString = "test string";
- JTextField tf = (JTextField) GuiTestUtils.getChildNamed(GeneralFetcherTest.gf, "tf");
- Assert.assertNotNull(tf); // tf found?
- tf.setText(testString);
- tf.postActionEvent(); // send message
- Assert.assertEquals(testString, tf.getText());
- JButton reset = (JButton) GuiTestUtils.getChildNamed(GeneralFetcherTest.gf, "reset");
- Assert.assertNotNull(reset); // reset found?
- reset.doClick(); // "click" reset
- Assert.assertEquals("", tf.getText());
- }
-
- /**
- * Get an instance of JabRef via its singleton and get a GeneralFetcher and an ACMPortalFetcher
- */
- @Before
- public void setUp() {
- JabRefMain.main(new String[0]);
- GeneralFetcherTest.jrf = JabRefGUI.getMainFrame();
- GeneralFetcherTest.spm = GeneralFetcherTest.jrf.getSidePaneManager();
- GeneralFetcherTest.acmpf = new ACMPortalFetcher();
- ArrayList<EntryFetcher> al = new ArrayList<>();
- al.add(GeneralFetcherTest.acmpf);
- GeneralFetcherTest.gf = new GeneralFetcher(GeneralFetcherTest.spm, GeneralFetcherTest.jrf);
- }
-
- @After
- public void tearDown() {
- GeneralFetcherTest.gf = null;
- GeneralFetcherTest.acmpf = null;
- GeneralFetcherTest.spm = null;
- GeneralFetcherTest.jrf = null;
- }
-
-}
diff --git a/src/test/java/net/sf/jabref/gui/importer/fetcher/OAI2HandlerFetcherTest.java b/src/test/java/net/sf/jabref/gui/importer/fetcher/OAI2HandlerFetcherTest.java
index 0aa5f49..f951556 100644
--- a/src/test/java/net/sf/jabref/gui/importer/fetcher/OAI2HandlerFetcherTest.java
+++ b/src/test/java/net/sf/jabref/gui/importer/fetcher/OAI2HandlerFetcherTest.java
@@ -10,11 +10,13 @@ import javax.xml.parsers.SAXParserFactory;
import net.sf.jabref.logic.importer.util.OAI2Handler;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.IdGenerator;
+import net.sf.jabref.testutils.category.GUITests;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
+import org.junit.experimental.categories.Category;
import org.xml.sax.SAXException;
/**
@@ -24,6 +26,7 @@ import org.xml.sax.SAXException;
* @author Christian Kopf
* @author Christopher Oezbek
*/
+ at Category(GUITests.class)
public class OAI2HandlerFetcherTest {
protected OAI2Handler handler;
@@ -56,22 +59,22 @@ public class OAI2HandlerFetcherTest {
public void testParse() throws Throwable {
try {
saxParser.parse(this.getClass().getResourceAsStream("oai2.xml"), handler);
- Assert.assertEquals(Optional.of("hep-ph/0408155"), be.getFieldOptional("eprint"));
+ Assert.assertEquals(Optional.of("hep-ph/0408155"), be.getField("eprint"));
Assert.assertEquals(Optional.of("G. F. Giudice and A. Riotto and A. Zaffaroni and J. López-Peña"),
- be.getFieldOptional("author"));
- Assert.assertEquals(Optional.of("Nucl.Phys. B"), be.getFieldOptional("journal"));
- Assert.assertEquals(Optional.of("710"), be.getFieldOptional("volume"));
- Assert.assertEquals(Optional.of("2005"), be.getFieldOptional("year"));
- Assert.assertEquals(Optional.of("511-525"), be.getFieldOptional("pages"));
+ be.getField("author"));
+ Assert.assertEquals(Optional.of("Nucl.Phys. B"), be.getField("journal"));
+ Assert.assertEquals(Optional.of("710"), be.getField("volume"));
+ Assert.assertEquals(Optional.of("2005"), be.getField("year"));
+ Assert.assertEquals(Optional.of("511-525"), be.getField("pages"));
// Citekey is only generated if the user says so in the import
// inspection dialog.
Assert.assertEquals(Optional.empty(), be.getCiteKeyOptional());
- Assert.assertEquals(Optional.of("Heavy Particles from Inflation"), be.getFieldOptional("title"));
- Assert.assertTrue(be.getFieldOptional("abstract").isPresent());
- Assert.assertEquals(Optional.of("23 pages"), be.getFieldOptional("comments"));
- Assert.assertEquals(Optional.of("CERN-PH-TH/2004-151"), be.getFieldOptional("reportno"));
+ Assert.assertEquals(Optional.of("Heavy Particles from Inflation"), be.getField("title"));
+ Assert.assertTrue(be.getField("abstract").isPresent());
+ Assert.assertEquals(Optional.of("23 pages"), be.getField("comments"));
+ Assert.assertEquals(Optional.of("CERN-PH-TH/2004-151"), be.getField("reportno"));
} catch (SAXException e) {
throw e.getException();
}
@@ -81,7 +84,7 @@ public class OAI2HandlerFetcherTest {
public void testOai22xml() throws SAXException, IOException {
saxParser.parse(this.getClass().getResourceAsStream("oai22.xml"), handler);
- Assert.assertEquals(Optional.of("2005"), be.getFieldOptional("year"));
+ Assert.assertEquals(Optional.of("2005"), be.getField("year"));
}
@@ -89,7 +92,7 @@ public class OAI2HandlerFetcherTest {
public void testOai23xml() throws SAXException, IOException {
saxParser.parse(this.getClass().getResourceAsStream("oai23.xml"), handler);
- Assert.assertEquals(Optional.of("Javier López Peña and Gabriel Navarro"), be.getFieldOptional("author"));
+ Assert.assertEquals(Optional.of("Javier López Peña and Gabriel Navarro"), be.getField("author"));
}
@@ -119,18 +122,18 @@ public class OAI2HandlerFetcherTest {
@Test
@Ignore
- public void testOnline() throws InterruptedException {
+ public void testOnline() throws InterruptedException, IOException, SAXException {
{
OAI2Fetcher fetcher = new OAI2Fetcher();
be = fetcher.importOai2Entry("math.RA/0612188");
Assert.assertNotNull(be);
- Assert.assertEquals(Optional.of("math/0612188"), be.getFieldOptional("eprint"));
+ Assert.assertEquals(Optional.of("math/0612188"), be.getField("eprint"));
Assert.assertEquals(Optional.of("On the classification and properties of noncommutative duplicates"),
- be.getFieldOptional("title"));
- Assert.assertEquals(Optional.of("Javier López Peña and Gabriel Navarro"), be.getFieldOptional("author"));
- Assert.assertEquals(Optional.of("2007"), be.getFieldOptional("year"));
+ be.getField("title"));
+ Assert.assertEquals(Optional.of("Javier López Peña and Gabriel Navarro"), be.getField("author"));
+ Assert.assertEquals(Optional.of("2007"), be.getField("year"));
Thread.sleep(20000);
}
@@ -140,11 +143,11 @@ public class OAI2HandlerFetcherTest {
be = fetcher.importOai2Entry("astro-ph/0702080");
Assert.assertNotNull(be);
- Assert.assertEquals(Optional.of("astro-ph/0702080"), be.getFieldOptional("eprint"));
+ Assert.assertEquals(Optional.of("astro-ph/0702080"), be.getField("eprint"));
Assert.assertEquals(
Optional.of(
"Magnetized Hypermassive Neutron Star Collapse: a candidate central engine for short-hard GRBs"),
- be.getFieldOptional("title"));
+ be.getField("title"));
Thread.sleep(20000);
}
@@ -154,7 +157,7 @@ public class OAI2HandlerFetcherTest {
be = fetcher.importOai2Entry("math.QA/0601001");
Assert.assertNotNull(be);
- Assert.assertEquals(Optional.of("math/0601001"), be.getFieldOptional("eprint"));
+ Assert.assertEquals(Optional.of("math/0601001"), be.getField("eprint"));
Thread.sleep(20000);
}
@@ -163,7 +166,7 @@ public class OAI2HandlerFetcherTest {
be = fetcher.importOai2Entry("hep-ph/0408155");
Assert.assertNotNull(be);
- Assert.assertEquals(Optional.of("hep-ph/0408155"), be.getFieldOptional("eprint"));
+ Assert.assertEquals(Optional.of("hep-ph/0408155"), be.getField("eprint"));
Thread.sleep(20000);
}
@@ -171,8 +174,8 @@ public class OAI2HandlerFetcherTest {
be = fetcher.importOai2Entry("0709.3040");
Assert.assertNotNull(be);
- Assert.assertEquals(Optional.of("2007"), be.getFieldOptional("year"));
- Assert.assertEquals(Optional.of("#sep#"), be.getFieldOptional("month"));
+ Assert.assertEquals(Optional.of("2007"), be.getField("year"));
+ Assert.assertEquals(Optional.of("#sep#"), be.getField("month"));
}
}
diff --git a/src/test/java/net/sf/jabref/gui/search/SearchResultsTest.java b/src/test/java/net/sf/jabref/gui/search/SearchResultsTest.java
new file mode 100644
index 0000000..c03c7d2
--- /dev/null
+++ b/src/test/java/net/sf/jabref/gui/search/SearchResultsTest.java
@@ -0,0 +1,97 @@
+package net.sf.jabref.gui.search;
+
+import java.util.Collection;
+import java.util.concurrent.TimeUnit;
+
+import javax.swing.JFrame;
+
+import net.sf.jabref.gui.BasePanel;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.testutils.TestUtils;
+import net.sf.jabref.testutils.category.GUITests;
+
+import org.assertj.swing.core.ComponentFinder;
+import org.assertj.swing.edt.FailOnThreadViolationRepaintManager;
+import org.assertj.swing.finder.WindowFinder;
+import org.assertj.swing.fixture.FrameFixture;
+import org.assertj.swing.fixture.JTextComponentFixture;
+import org.assertj.swing.junit.testcase.AssertJSwingJUnitTestCase;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+ at Category(GUITests.class)
+public class SearchResultsTest extends AssertJSwingJUnitTestCase {
+
+ private FrameFixture frameFixture;
+
+
+ @BeforeClass
+ public static void before() {
+ FailOnThreadViolationRepaintManager.uninstall();
+ }
+
+ @Override
+ protected void onSetUp() {
+ TestUtils.initJabRef();
+ frameFixture = WindowFinder.findFrame(JFrame.class).withTimeout(15, TimeUnit.SECONDS).using(robot());
+ }
+
+ @Override
+ protected void onTearDown() {
+ frameFixture.close();
+ frameFixture = null;
+
+ TestUtils.closeJabRef();
+ }
+
+ @Test
+ public void testSearchFieldQuery() {
+ frameFixture.menuItemWithPath("Search", "Search").click();
+ JTextComponentFixture searchField = frameFixture.textBox();
+ ComponentFinder finder = robot().finder();
+ BasePanel panel = finder.findByType(BasePanel.class);
+ Collection<BibEntry> entries = panel.getDatabase().getEntries();
+
+ searchField.deleteText().enterText("");
+ Assert.assertEquals(19, entries.size());
+
+ searchField.deleteText().enterText("entrytype=article");
+ Assert.assertFalse(entries.stream().noneMatch(entry -> entry.isSearchHit()));
+ Assert.assertEquals(5, entries.stream().filter(entry -> entry.isSearchHit()).count());
+
+ searchField.deleteText().enterText("entrytype=proceedings");
+ Assert.assertFalse(entries.stream().noneMatch(entry -> entry.isSearchHit()));
+ Assert.assertEquals(13, entries.stream().filter(entry -> entry.isSearchHit()).count());
+
+ searchField.deleteText().enterText("entrytype=book");
+ Assert.assertFalse(entries.stream().noneMatch(entry -> entry.isSearchHit()));
+ Assert.assertEquals(1, entries.stream().filter(entry -> entry.isSearchHit()).count());
+ }
+
+ @Test
+ public void testSeachWithoutResults() {
+ frameFixture.menuItemWithPath("Search", "Search").click();
+ JTextComponentFixture searchField = frameFixture.textBox();
+ ComponentFinder finder = robot().finder();
+ BasePanel panel = finder.findByType(BasePanel.class);
+ Collection<BibEntry> entries = panel.getDatabase().getEntries();
+
+ searchField.deleteText().enterText("asdf");
+ Assert.assertTrue(entries.stream().noneMatch(entry -> entry.isSearchHit()));
+ }
+
+ @Test
+ public void testSearchInvalidQuery() {
+ frameFixture.menuItemWithPath("Search", "Search").click();
+ JTextComponentFixture searchField = frameFixture.textBox();
+ ComponentFinder finder = robot().finder();
+ BasePanel panel = finder.findByType(BasePanel.class);
+ Collection<BibEntry> entries = panel.getDatabase().getEntries();
+
+ searchField.deleteText().enterText("asdf[");
+ Assert.assertTrue(entries.stream().noneMatch(entry -> entry.isSearchHit()));
+ }
+
+}
diff --git a/src/test/java/net/sf/jabref/logic/autosaveandbackup/BackupManagerTest.java b/src/test/java/net/sf/jabref/logic/autosaveandbackup/BackupManagerTest.java
new file mode 100644
index 0000000..0d8e6c0
--- /dev/null
+++ b/src/test/java/net/sf/jabref/logic/autosaveandbackup/BackupManagerTest.java
@@ -0,0 +1,18 @@
+package net.sf.jabref.logic.autosaveandbackup;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class BackupManagerTest {
+
+ @Test
+ public void backupFileNameIsCorrectlyGeneratedWithinTmpDirectory() {
+ Path bibPath = Paths.get("tmp", "test.bib");
+ Path savPath = BackupManager.getBackupPath(bibPath);
+ Assert.assertEquals(Paths.get("tmp", "test.bib.sav"), savPath);
+ }
+
+}
diff --git a/src/test/java/net/sf/jabref/logic/auxparser/AuxParserTest.java b/src/test/java/net/sf/jabref/logic/auxparser/AuxParserTest.java
index 8ada8c4..7ca7211 100644
--- a/src/test/java/net/sf/jabref/logic/auxparser/AuxParserTest.java
+++ b/src/test/java/net/sf/jabref/logic/auxparser/AuxParserTest.java
@@ -7,6 +7,7 @@ import java.io.InputStreamReader;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Paths;
+import java.util.Optional;
import net.sf.jabref.logic.importer.ImportFormatPreferences;
import net.sf.jabref.logic.importer.ParserResult;
@@ -14,20 +15,25 @@ import net.sf.jabref.logic.importer.fileformat.BibtexParser;
import net.sf.jabref.model.database.BibDatabase;
import net.sf.jabref.preferences.JabRefPreferences;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class AuxParserTest {
-
private ImportFormatPreferences importFormatPreferences;
-
@Before
public void setUp() {
- importFormatPreferences = ImportFormatPreferences.fromPreferences(JabRefPreferences.getInstance());
+ importFormatPreferences = JabRefPreferences.getInstance().getImportFormatPreferences();
+ }
+
+ @After
+ public void tearDown() {
+ importFormatPreferences = null;
}
@Test
@@ -46,7 +52,7 @@ public class AuxParserTest {
assertEquals(2, newDB.getEntries().size());
assertEquals(2, auxResult.getResolvedKeysCount());
assertEquals(2, auxResult.getFoundKeysInAux());
- assertEquals(auxResult.getFoundKeysInAux(),
+ assertEquals(auxResult.getFoundKeysInAux() + auxResult.getCrossRefEntriesCount(),
auxResult.getResolvedKeysCount() + auxResult.getUnresolvedKeysCount());
assertEquals(0, auxResult.getCrossRefEntriesCount());
}
@@ -69,7 +75,7 @@ public class AuxParserTest {
assertEquals(2, newDB.getEntries().size());
assertEquals(2, auxResult.getResolvedKeysCount());
assertEquals(3, auxResult.getFoundKeysInAux());
- assertEquals(auxResult.getFoundKeysInAux(),
+ assertEquals(auxResult.getFoundKeysInAux() + auxResult.getCrossRefEntriesCount(),
auxResult.getResolvedKeysCount() + auxResult.getUnresolvedKeysCount());
assertEquals(0, auxResult.getCrossRefEntriesCount());
}
@@ -86,7 +92,7 @@ public class AuxParserTest {
AuxParserResult auxResult = auxParser.parse();
BibDatabase db = auxResult.getGeneratedBibDatabase();
- assertEquals("\"Maintained by \" # maintainer", db.getPreamble());
+ assertEquals(Optional.of("\"Maintained by \" # maintainer"), db.getPreamble());
assertEquals(1, db.getStringCount());
}
}
@@ -107,9 +113,47 @@ public class AuxParserTest {
assertEquals(2, newDB.getEntries().size());
assertEquals(2, auxResult.getResolvedKeysCount());
assertEquals(2, auxResult.getFoundKeysInAux());
- assertEquals(auxResult.getFoundKeysInAux(),
+ assertEquals(auxResult.getFoundKeysInAux() + auxResult.getCrossRefEntriesCount(),
auxResult.getResolvedKeysCount() + auxResult.getUnresolvedKeysCount());
assertEquals(0, auxResult.getCrossRefEntriesCount());
}
}
+
+ @Test
+ public void testCrossRef() throws URISyntaxException, IOException {
+ InputStream originalStream = AuxParserTest.class.getResourceAsStream("origin.bib");
+ File auxFile = Paths.get(AuxParserTest.class.getResource("crossref.aux").toURI()).toFile();
+ try (InputStreamReader originalReader = new InputStreamReader(originalStream, StandardCharsets.UTF_8)) {
+ ParserResult result = BibtexParser.parse(originalReader, importFormatPreferences);
+
+ AuxParser auxParser = new AuxParser(auxFile.getAbsolutePath(), result.getDatabase());
+ AuxParserResult auxResult = auxParser.parse();
+
+ assertTrue(auxResult.getGeneratedBibDatabase().hasEntries());
+ assertEquals(2, auxResult.getUnresolvedKeysCount());
+ BibDatabase newDB = auxResult.getGeneratedBibDatabase();
+ assertEquals(4, newDB.getEntries().size());
+ assertEquals(3, auxResult.getResolvedKeysCount());
+ assertEquals(4, auxResult.getFoundKeysInAux());
+ assertEquals(auxResult.getFoundKeysInAux() + auxResult.getCrossRefEntriesCount(),
+ auxResult.getResolvedKeysCount() + auxResult.getUnresolvedKeysCount());
+ assertEquals(1, auxResult.getCrossRefEntriesCount());
+ }
+ }
+
+ @Test
+ public void testFileNotFound() {
+ AuxParser auxParser = new AuxParser("unknownfile.bib", new BibDatabase());
+ AuxParserResult auxResult = auxParser.parse();
+
+ assertFalse(auxResult.getGeneratedBibDatabase().hasEntries());
+ assertEquals(0, auxResult.getUnresolvedKeysCount());
+ BibDatabase newDB = auxResult.getGeneratedBibDatabase();
+ assertEquals(0, newDB.getEntries().size());
+ assertEquals(0, auxResult.getResolvedKeysCount());
+ assertEquals(0, auxResult.getFoundKeysInAux());
+ assertEquals(auxResult.getFoundKeysInAux() + auxResult.getCrossRefEntriesCount(),
+ auxResult.getResolvedKeysCount() + auxResult.getUnresolvedKeysCount());
+ assertEquals(0, auxResult.getCrossRefEntriesCount());
+ }
}
diff --git a/src/test/java/net/sf/jabref/logic/bibtex/BibEntryAssert.java b/src/test/java/net/sf/jabref/logic/bibtex/BibEntryAssert.java
index 64d013f..e715167 100644
--- a/src/test/java/net/sf/jabref/logic/bibtex/BibEntryAssert.java
+++ b/src/test/java/net/sf/jabref/logic/bibtex/BibEntryAssert.java
@@ -6,17 +6,15 @@ import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URISyntaxException;
import java.net.URL;
-import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.List;
-import net.sf.jabref.logic.importer.ImportFormatPreferences;
+import net.sf.jabref.logic.importer.Importer;
import net.sf.jabref.logic.importer.ParserResult;
import net.sf.jabref.logic.importer.fileformat.BibtexParser;
-import net.sf.jabref.logic.importer.fileformat.ImportFormat;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.preferences.JabRefPreferences;
@@ -63,9 +61,8 @@ public class BibEntryAssert {
private static List<BibEntry> getListFromInputStream(InputStream is) throws IOException {
ParserResult result;
try (Reader reader = new InputStreamReader(is, StandardCharsets.UTF_8)) {
- BibtexParser parser = new BibtexParser(reader,
- ImportFormatPreferences.fromPreferences(JabRefPreferences.getInstance()));
- result = parser.parse();
+ BibtexParser parser = new BibtexParser(JabRefPreferences.getInstance().getImportFormatPreferences());
+ result = parser.parse(reader);
}
Assert.assertNotNull(result);
Assert.assertFalse(result.isNullResult());
@@ -105,38 +102,38 @@ public class BibEntryAssert {
}
/**
- * Compares two InputStreams. For each InputStream a list will be created. expectedIs is read directly, actualIs is filtered through importFormat to convert to a list of BibEntries.
+ * Compares two InputStreams. For each InputStream a list will be created. expectedIs is read directly, actualIs is filtered through importer to convert to a list of BibEntries.
* @param expectedIs A BibtexImporter InputStream.
* @param fileToImport The path to the file to be imported.
- * @param importFormat The fileformat you want to use to read the passed file to get the list of expected BibEntries
+ * @param importer The fileformat you want to use to read the passed file to get the list of expected BibEntries
* @throws IOException
*/
- public static void assertEquals(InputStream expectedIs, Path fileToImport, ImportFormat importFormat)
+ public static void assertEquals(InputStream expectedIs, Path fileToImport, Importer importer)
throws IOException {
- assertEquals(getListFromInputStream(expectedIs), fileToImport, importFormat);
+ assertEquals(getListFromInputStream(expectedIs), fileToImport, importer);
}
- public static void assertEquals(InputStream expectedIs, URL fileToImport, ImportFormat importFormat)
+ public static void assertEquals(InputStream expectedIs, URL fileToImport, Importer importer)
throws URISyntaxException, IOException {
- assertEquals(expectedIs, Paths.get(fileToImport.toURI()), importFormat);
+ assertEquals(expectedIs, Paths.get(fileToImport.toURI()), importer);
}
/**
* Compares a list of BibEntries to an InputStream. actualIs is filtered through importerForActualIs to convert to a list of BibEntries.
* @param expected A BibtexImporter InputStream.
* @param fileToImport The path to the file to be imported.
- * @param importFormat The fileformat you want to use to read the passed file to get the list of expected BibEntries
+ * @param importer The fileformat you want to use to read the passed file to get the list of expected BibEntries
* @throws IOException
*/
- public static void assertEquals(List<BibEntry> expected, Path fileToImport, ImportFormat importFormat)
+ public static void assertEquals(List<BibEntry> expected, Path fileToImport, Importer importer)
throws IOException {
- List<BibEntry> actualEntries = importFormat.importDatabase(fileToImport, Charset.defaultCharset())
+ List<BibEntry> actualEntries = importer.importDatabase(fileToImport, StandardCharsets.UTF_8)
.getDatabase().getEntries();
Assert.assertEquals(expected, actualEntries);
}
- public static void assertEquals(List<BibEntry> expected, URL fileToImport, ImportFormat importFormat)
+ public static void assertEquals(List<BibEntry> expected, URL fileToImport, Importer importer)
throws URISyntaxException, IOException {
- assertEquals(expected, Paths.get(fileToImport.toURI()), importFormat);
+ assertEquals(expected, Paths.get(fileToImport.toURI()), importer);
}
}
diff --git a/src/test/java/net/sf/jabref/logic/bibtex/BibEntryWriterTest.java b/src/test/java/net/sf/jabref/logic/bibtex/BibEntryWriterTest.java
index fe232ce..b3c70b8 100644
--- a/src/test/java/net/sf/jabref/logic/bibtex/BibEntryWriterTest.java
+++ b/src/test/java/net/sf/jabref/logic/bibtex/BibEntryWriterTest.java
@@ -28,9 +28,9 @@ public class BibEntryWriterTest {
@Before
public void setUpWriter() {
- importFormatPreferences = ImportFormatPreferences.fromPreferences(JabRefPreferences.getInstance());
- writer = new BibEntryWriter(new LatexFieldFormatter(
- LatexFieldFormatterPreferences.fromPreferences(JabRefPreferences.getInstance())), true);
+ importFormatPreferences = JabRefPreferences.getInstance().getImportFormatPreferences();
+ writer = new BibEntryWriter(
+ new LatexFieldFormatter(JabRefPreferences.getInstance().getLatexFieldFormatterPreferences()), true);
}
@Test
@@ -62,6 +62,44 @@ public class BibEntryWriterTest {
}
@Test
+ public void writeOtherTypeTest() throws Exception {
+ String expected = OS.NEWLINE + "@Other{test," + OS.NEWLINE +
+ " comment = {testentry}," + OS.NEWLINE +
+ "}"+ OS.NEWLINE;
+
+ BibEntry entry = new BibEntry();
+ entry.setType("other");
+ entry.setField("Comment","testentry");
+ entry.setCiteKey("test");
+
+ //write out bibtex string
+ StringWriter stringWriter = new StringWriter();
+ writer.write(entry, stringWriter, BibDatabaseMode.BIBTEX);
+ String actual = stringWriter.toString();
+
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void writeReallyunknownTypeTest() throws Exception {
+ String expected = OS.NEWLINE + "@Reallyunknowntype{test," + OS.NEWLINE +
+ " comment = {testentry}," + OS.NEWLINE +
+ "}"+ OS.NEWLINE;
+
+ BibEntry entry = new BibEntry();
+ entry.setType("ReallyUnknownType");
+ entry.setField("Comment","testentry");
+ entry.setCiteKey("test");
+
+ //write out bibtex string
+ StringWriter stringWriter = new StringWriter();
+ writer.write(entry, stringWriter, BibDatabaseMode.BIBTEX);
+ String actual = stringWriter.toString();
+
+ assertEquals(expected, actual);
+ }
+
+ @Test
public void roundTripTest() throws IOException {
// @formatter:off
String bibtexEntry = "@Article{test," + OS.NEWLINE +
@@ -295,7 +333,7 @@ public class BibEntryWriterTest {
// modify month field
Set<String> fields = entry.getFieldNames();
assertTrue(fields.contains("month"));
- assertEquals("#mar#", entry.getFieldOptional("month").get());
+ assertEquals("#mar#", entry.getField("month").get());
//write out bibtex string
StringWriter stringWriter = new StringWriter();
diff --git a/src/test/java/net/sf/jabref/logic/bibtex/EntryTypesTestBibLatex.java b/src/test/java/net/sf/jabref/logic/bibtex/EntryTypesTestBibLatex.java
index 0f2f6fa..20b430a 100644
--- a/src/test/java/net/sf/jabref/logic/bibtex/EntryTypesTestBibLatex.java
+++ b/src/test/java/net/sf/jabref/logic/bibtex/EntryTypesTestBibLatex.java
@@ -6,6 +6,7 @@ import net.sf.jabref.model.EntryTypes;
import net.sf.jabref.model.database.BibDatabaseMode;
import net.sf.jabref.model.entry.BibLatexEntryTypes;
+import org.junit.Ignore;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
@@ -14,6 +15,7 @@ public class EntryTypesTestBibLatex {
@Test
+ @Ignore("This fails of unknown reasons - will be fixed with https://github.com/JabRef/jabref/pull/2331")
public void testBibLatexMode() {
// BibLatex mode
assertEquals(BibLatexEntryTypes.ARTICLE, EntryTypes.getType("article", BibDatabaseMode.BIBLATEX).get());
diff --git a/src/test/java/net/sf/jabref/logic/bibtex/LatexFieldFormatterTests.java b/src/test/java/net/sf/jabref/logic/bibtex/LatexFieldFormatterTests.java
index 34ecef6..6d7dcbd 100644
--- a/src/test/java/net/sf/jabref/logic/bibtex/LatexFieldFormatterTests.java
+++ b/src/test/java/net/sf/jabref/logic/bibtex/LatexFieldFormatterTests.java
@@ -14,8 +14,7 @@ public class LatexFieldFormatterTests {
@Before
public void setUp() {
- this.formatter = new LatexFieldFormatter(
- LatexFieldFormatterPreferences.fromPreferences(JabRefPreferences.getInstance()));
+ this.formatter = new LatexFieldFormatter(JabRefPreferences.getInstance().getLatexFieldFormatterPreferences());
}
@Test
diff --git a/src/test/java/net/sf/jabref/logic/bibtex/comparator/CrossRefEntryComparatorTest.java b/src/test/java/net/sf/jabref/logic/bibtex/comparator/CrossRefEntryComparatorTest.java
new file mode 100644
index 0000000..9932f50
--- /dev/null
+++ b/src/test/java/net/sf/jabref/logic/bibtex/comparator/CrossRefEntryComparatorTest.java
@@ -0,0 +1,56 @@
+package net.sf.jabref.logic.bibtex.comparator;
+
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldName;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class CrossRefEntryComparatorTest {
+ private CrossRefEntryComparator comparator;
+
+ @Before
+ public void setUp() {
+ comparator = new CrossRefEntryComparator();
+ }
+
+ @After
+ public void tearDown() {
+ comparator = null;
+ }
+
+ @Test
+ public void isEqualForEntriesWithoutCrossRef() {
+ BibEntry e1 = new BibEntry();
+ BibEntry e2 = new BibEntry();
+ assertEquals(0, comparator.compare(e1, e2));
+ }
+
+ @Test
+ public void isEqualForEntriesWithCrossRef() {
+ BibEntry e1 = new BibEntry();
+ e1.setField(FieldName.CROSSREF, "1");
+ BibEntry e2 = new BibEntry();
+ e2.setField(FieldName.CROSSREF, "2");
+ assertEquals(0, comparator.compare(e1, e2));
+ }
+
+ @Test
+ public void isGreaterForEntriesWithoutCrossRef() {
+ BibEntry e1 = new BibEntry();
+ BibEntry e2 = new BibEntry();
+ e2.setField(FieldName.CROSSREF, "1");
+ assertEquals(1, comparator.compare(e1, e2));
+ }
+
+ @Test
+ public void isSmallerForEntriesWithCrossRef() {
+ BibEntry e1 = new BibEntry();
+ e1.setField(FieldName.CROSSREF, "1");
+ BibEntry e2 = new BibEntry();
+ assertEquals(-1, comparator.compare(e1, e2));
+ }
+}
diff --git a/src/test/java/net/sf/jabref/logic/bibtex/comparator/EntryComparatorTest.java b/src/test/java/net/sf/jabref/logic/bibtex/comparator/EntryComparatorTest.java
new file mode 100644
index 0000000..c808705
--- /dev/null
+++ b/src/test/java/net/sf/jabref/logic/bibtex/comparator/EntryComparatorTest.java
@@ -0,0 +1,16 @@
+package net.sf.jabref.logic.bibtex.comparator;
+
+import net.sf.jabref.model.entry.BibEntry;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class EntryComparatorTest {
+ @Test
+ public void recognizeIdenticObjectsAsEqual() {
+ BibEntry e1 = new BibEntry();
+ BibEntry e2 = e1;
+ assertEquals(0, new EntryComparator(false, false, "").compare(e1, e2));
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/net/sf/jabref/logic/bibtexkeypattern/BibtexKeyPatternUtilTest.java b/src/test/java/net/sf/jabref/logic/bibtexkeypattern/BibtexKeyPatternUtilTest.java
index ae0346b..6047f23 100644
--- a/src/test/java/net/sf/jabref/logic/bibtexkeypattern/BibtexKeyPatternUtilTest.java
+++ b/src/test/java/net/sf/jabref/logic/bibtexkeypattern/BibtexKeyPatternUtilTest.java
@@ -40,11 +40,9 @@ public class BibtexKeyPatternUtilTest {
private static ImportFormatPreferences importFormatPreferences;
-
@Before
public void setUp() {
- importFormatPreferences = ImportFormatPreferences.fromPreferences(JabRefPreferences.getInstance());
- BibtexKeyPatternUtil.setDataBase(new BibDatabase());
+ importFormatPreferences = JabRefPreferences.getInstance().getImportFormatPreferences();
}
@Test
@@ -52,7 +50,8 @@ public class BibtexKeyPatternUtilTest {
Optional<BibEntry> entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Simon Holland}}",
importFormatPreferences);
assertEquals("Holland",
- BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry0.get(), "auth"), true));
+ BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry0.get(), "auth",
+ ',', new BibDatabase()), true));
}
@Test
@@ -60,7 +59,8 @@ public class BibtexKeyPatternUtilTest {
String bibtexString = "@ARTICLE{whatevery, author={Mari D. Herland and Mona-Iren Hauge and Ingeborg M. Helgeland}}";
Optional<BibEntry> entry = BibtexParser.singleFromString(bibtexString, importFormatPreferences);
assertEquals("HerlandHaugeHelgeland",
- BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry.get(), "authors3"), true));
+ BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry.get(), "authors3",
+ ',', new BibDatabase()), true));
}
@Test
@@ -68,7 +68,8 @@ public class BibtexKeyPatternUtilTest {
Optional<BibEntry> entry = BibtexParser.singleFromString(
"@ARTICLE{kohn, author={Simon Popovi\\v{c}ov\\'{a}}}", importFormatPreferences);
assertEquals("Popovicova",
- BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry.get(), "auth"), true));
+ BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry.get(), "auth",
+ ',', new BibDatabase()), true));
}
/**
@@ -81,62 +82,74 @@ public class BibtexKeyPatternUtilTest {
Optional<BibEntry> entry0 = BibtexParser.singleFromString(
"@ARTICLE{kohn, author={Andreas Köning}, year={2000}}", importFormatPreferences);
assertEquals("Koen",
- BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry0.get(), "auth3"), true));
+ BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry0.get(), "auth3",
+ ',', new BibDatabase()), true));
entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Áöning}, year={2000}}",
importFormatPreferences);
assertEquals("Aoen",
- BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry0.get(), "auth3"), true));
+ BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry0.get(), "auth3",
+ ',', new BibDatabase()), true));
entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Éöning}, year={2000}}",
importFormatPreferences);
assertEquals("Eoen",
- BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry0.get(), "auth3"), true));
+ BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry0.get(), "auth3",
+ ',', new BibDatabase()), true));
entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Íöning}, year={2000}}",
importFormatPreferences);
assertEquals("Ioen",
- BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry0.get(), "auth3"), true));
+ BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry0.get(), "auth3",
+ ',', new BibDatabase()), true));
entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Ĺöning}, year={2000}}",
importFormatPreferences);
assertEquals("Loen",
- BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry0.get(), "auth3"), true));
+ BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry0.get(), "auth3",
+ ',', new BibDatabase()), true));
entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Ńöning}, year={2000}}",
importFormatPreferences);
assertEquals("Noen",
- BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry0.get(), "auth3"), true));
+ BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry0.get(), "auth3",
+ ',', new BibDatabase()), true));
entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Óöning}, year={2000}}",
importFormatPreferences);
assertEquals("Ooen",
- BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry0.get(), "auth3"), true));
+ BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry0.get(), "auth3",
+ ',', new BibDatabase()), true));
entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Ŕöning}, year={2000}}",
importFormatPreferences);
assertEquals("Roen",
- BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry0.get(), "auth3"), true));
+ BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry0.get(), "auth3",
+ ',', new BibDatabase()), true));
entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Śöning}, year={2000}}",
importFormatPreferences);
assertEquals("Soen",
- BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry0.get(), "auth3"), true));
+ BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry0.get(), "auth3",
+ ',', new BibDatabase()), true));
entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Úöning}, year={2000}}",
importFormatPreferences);
assertEquals("Uoen",
- BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry0.get(), "auth3"), true));
+ BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry0.get(), "auth3",
+ ',', new BibDatabase()), true));
entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Ýöning}, year={2000}}",
importFormatPreferences);
assertEquals("Yoen",
- BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry0.get(), "auth3"), true));
+ BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry0.get(), "auth3",
+ ',', new BibDatabase()), true));
entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Źöning}, year={2000}}",
importFormatPreferences);
assertEquals("Zoen",
- BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry0.get(), "auth3"), true));
+ BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry0.get(), "auth3",
+ ',', new BibDatabase()), true));
}
/**
@@ -147,27 +160,32 @@ public class BibtexKeyPatternUtilTest {
Optional<BibEntry> entry0 = BibtexParser.singleFromString(
"@ARTICLE{kohn, author={Andreas Àöning}, year={2000}}", importFormatPreferences);
assertEquals("Aoen",
- BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry0.get(), "auth3"), true));
+ BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry0.get(), "auth3",
+ ',', new BibDatabase()), true));
entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Èöning}, year={2000}}",
importFormatPreferences);
assertEquals("Eoen",
- BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry0.get(), "auth3"), true));
+ BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry0.get(), "auth3",
+ ',', new BibDatabase()), true));
entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Ìöning}, year={2000}}",
importFormatPreferences);
assertEquals("Ioen",
- BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry0.get(), "auth3"), true));
+ BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry0.get(), "auth3",
+ ',', new BibDatabase()), true));
entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Òöning}, year={2000}}",
importFormatPreferences);
assertEquals("Ooen",
- BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry0.get(), "auth3"), true));
+ BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry0.get(), "auth3",
+ ',', new BibDatabase()), true));
entry0 = BibtexParser.singleFromString("@ARTICLE{kohn, author={Andreas Ùöning}, year={2000}}",
importFormatPreferences);
assertEquals("Uoen",
- BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry0.get(), "auth3"), true));
+ BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry0.get(), "auth3",
+ ',', new BibDatabase()), true));
}
/**
@@ -255,7 +273,8 @@ public class BibtexKeyPatternUtilTest {
Optional<BibEntry> entry = BibtexParser.singleFromString(
"@ARTICLE{kohn, author={{Link{\\\"{o}}ping University}}}", importFormatPreferences);
assertEquals("UniLinkoeping",
- BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry.get(), "auth"), true));
+ BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry.get(), "auth",
+ ',', new BibDatabase()), true));
}
@Test
@@ -264,7 +283,8 @@ public class BibtexKeyPatternUtilTest {
"@ARTICLE{kohn, author={{Link{\\\"{o}}ping University, Department of Electrical Engineering}}}",
importFormatPreferences);
assertEquals("UniLinkoepingEE",
- BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry.get(), "auth"), true));
+ BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry.get(), "auth",
+ ',', new BibDatabase()), true));
}
@Test
@@ -273,7 +293,8 @@ public class BibtexKeyPatternUtilTest {
"@ARTICLE{kohn, author={{Link{\\\"{o}}ping University, School of Computer Engineering}}}",
importFormatPreferences);
assertEquals("UniLinkoepingCE",
- BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry.get(), "auth"), true));
+ BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry.get(), "auth",
+ ',', new BibDatabase()), true));
}
@Test
@@ -281,7 +302,8 @@ public class BibtexKeyPatternUtilTest {
Optional<BibEntry> entry = BibtexParser.singleFromString(
"@ARTICLE{kohn, author={{Massachusetts Institute of Technology}}}", importFormatPreferences);
assertEquals("MIT",
- BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry.get(), "auth"), true));
+ BibtexKeyPatternUtil.checkLegalKey(BibtexKeyPatternUtil.makeLabel(entry.get(), "auth",
+ ',', new BibDatabase()), true));
}
@Test
@@ -306,6 +328,11 @@ public class BibtexKeyPatternUtilTest {
BibtexKeyPatternUtil.authIniN(null, 3);
}
+ @Test
+ public void testAuthIniNEmptyReturnsEmpty() {
+ assertEquals("", BibtexKeyPatternUtil.authIniN("", 1));
+ }
+
/**
* Tests [auth.auth.ea]
*/
@@ -318,6 +345,11 @@ public class BibtexKeyPatternUtilTest {
BibtexKeyPatternUtil.authAuthEa(AUTHOR_STRING_FIRSTNAME_FULL_LASTNAME_FULL_COUNT_3));
}
+ @Test
+ public void testAuthEaEmptyReturnsEmpty() {
+ assertEquals("", BibtexKeyPatternUtil.authAuthEa(""));
+ }
+
/**
* Tests the [auth.etal] and [authEtAl] patterns
*/
@@ -354,6 +386,11 @@ public class BibtexKeyPatternUtilTest {
assertEquals("Newton", BibtexKeyPatternUtil.authshort(AUTHOR_STRING_FIRSTNAME_INITIAL_LASTNAME_FULL_COUNT_1));
}
+ @Test
+ public void testAuthShortEmptyReturnsEmpty() {
+ assertEquals("", BibtexKeyPatternUtil.authshort(""));
+ }
+
/**
* Test the [authN_M] pattern
*/
@@ -521,6 +558,11 @@ public class BibtexKeyPatternUtilTest {
BibtexKeyPatternUtil.nAuthors(AUTHOR_STRING_FIRSTNAME_INITIAL_LASTNAME_FULL_COUNT_4, 1));
}
+ @Test
+ public void testNAuthors1EmptyReturnEmpty() {
+ assertEquals("", BibtexKeyPatternUtil.nAuthors("", 1));
+ }
+
/**
* Tests the [authorsN] pattern. -> [authors3]
*/
@@ -621,15 +663,15 @@ public class BibtexKeyPatternUtilTest {
BibEntry entry = new BibEntry();
entry.setField("keywords", "w1, w2a w2b, w3");
- String result = BibtexKeyPatternUtil.makeLabel(entry, "keyword1");
+ String result = BibtexKeyPatternUtil.makeLabel(entry, "keyword1", ',', new BibDatabase());
assertEquals("w1", result);
// check keywords with space
- result = BibtexKeyPatternUtil.makeLabel(entry, "keyword2");
+ result = BibtexKeyPatternUtil.makeLabel(entry, "keyword2", ',', new BibDatabase());
assertEquals("w2a w2b", result);
// check out of range
- result = BibtexKeyPatternUtil.makeLabel(entry, "keyword4");
+ result = BibtexKeyPatternUtil.makeLabel(entry, "keyword4", ',', new BibDatabase());
assertEquals("", result);
}
@@ -639,15 +681,15 @@ public class BibtexKeyPatternUtilTest {
entry.setField("keywords", "w1, w2a w2b, w3");
// all keywords
- String result = BibtexKeyPatternUtil.makeLabel(entry, "keywords");
+ String result = BibtexKeyPatternUtil.makeLabel(entry, "keywords", ',', new BibDatabase());
assertEquals("w1w2aw2bw3", result);
// check keywords with space
- result = BibtexKeyPatternUtil.makeLabel(entry, "keywords2");
+ result = BibtexKeyPatternUtil.makeLabel(entry, "keywords2", ',', new BibDatabase());
assertEquals("w1w2aw2b", result);
// check out of range
- result = BibtexKeyPatternUtil.makeLabel(entry, "keywords55");
+ result = BibtexKeyPatternUtil.makeLabel(entry, "keywords55", ',', new BibDatabase());
assertEquals("w1w2aw2bw3", result);
}
@@ -675,8 +717,9 @@ public class BibtexKeyPatternUtilTest {
public void testApplyModifiers() {
BibEntry entry = new BibEntry();
entry.setField("title", "Green Scheduling of Whatever");
- assertEquals("GSW", BibtexKeyPatternUtil.makeLabel(entry, "shorttitleINI"));
- assertEquals("GreenSchedulingWhatever", BibtexKeyPatternUtil.makeLabel(entry, "shorttitle"));
+ assertEquals("GSW", BibtexKeyPatternUtil.makeLabel(entry, "shorttitleINI", ',', new BibDatabase()));
+ assertEquals("GreenSchedulingWhatever", BibtexKeyPatternUtil.makeLabel(entry, "shorttitle",
+ ',', new BibDatabase()));
}
}
diff --git a/src/test/java/net/sf/jabref/logic/bibtexkeypattern/MakeLabelWithDatabaseTest.java b/src/test/java/net/sf/jabref/logic/bibtexkeypattern/MakeLabelWithDatabaseTest.java
new file mode 100644
index 0000000..5e82c71
--- /dev/null
+++ b/src/test/java/net/sf/jabref/logic/bibtexkeypattern/MakeLabelWithDatabaseTest.java
@@ -0,0 +1,323 @@
+package net.sf.jabref.logic.bibtexkeypattern;
+
+import java.util.Optional;
+
+import net.sf.jabref.model.bibtexkeypattern.DatabaseBibtexKeyPattern;
+import net.sf.jabref.model.bibtexkeypattern.GlobalBibtexKeyPattern;
+import net.sf.jabref.model.database.BibDatabase;
+import net.sf.jabref.model.entry.BibEntry;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class MakeLabelWithDatabaseTest {
+
+ private BibDatabase database;
+ private BibtexKeyPatternPreferences preferences;
+ private GlobalBibtexKeyPattern pattern;
+ private DatabaseBibtexKeyPattern bibtexKeyPattern;
+ private BibEntry entry;
+
+ @Before
+ public void setUp() {
+ database = new BibDatabase();
+
+ entry = new BibEntry();
+ entry.setField("author", "John Doe");
+ entry.setField("year", "2016");
+ entry.setField("title", "An awesome paper on JabRef");
+ database.insertEntry(entry);
+ pattern = GlobalBibtexKeyPattern.fromPattern("[auth][year]");
+ bibtexKeyPattern = new DatabaseBibtexKeyPattern(pattern);
+ preferences = new BibtexKeyPatternPreferences("", "", false, true, true, pattern, ',');
+ }
+
+ @Test
+ public void generateDefaultKey() {
+ BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences);
+ assertEquals(Optional.of("Doe2016"), entry.getCiteKeyOptional());
+ }
+
+ @Test
+ public void generateDefaultKeyAlreadyExistsDuplicatesStartAtA() {
+ BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences);
+ BibEntry entry2 = new BibEntry();
+ entry2.setField("author", "John Doe");
+ entry2.setField("year", "2016");
+ BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry2, preferences);
+ assertEquals(Optional.of("Doe2016a"), entry2.getCiteKeyOptional());
+ }
+
+ @Test
+ public void generateDefaultKeyAlwaysLetter() {
+ preferences = new BibtexKeyPatternPreferences("", "", true, true, true, pattern, ',');
+ BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences);
+ assertEquals(Optional.of("Doe2016a"), entry.getCiteKeyOptional());
+ }
+
+ @Test
+ public void generateDefaultKeyAlwaysLetterAlreadyExistsDuplicatesStartAtB() {
+ preferences = new BibtexKeyPatternPreferences("", "", true, true, true, pattern, ',');
+
+ BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences);
+ BibEntry entry2 = new BibEntry();
+ entry2.setField("author", "John Doe");
+ entry2.setField("year", "2016");
+ BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry2, preferences);
+ assertEquals(Optional.of("Doe2016b"), entry2.getCiteKeyOptional());
+ }
+
+ @Test
+ public void generateDefaultKeyStartDuplicatesAtB() {
+ preferences = new BibtexKeyPatternPreferences("", "", false, false, true, pattern, ',');
+ BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences);
+ assertEquals(Optional.of("Doe2016"), entry.getCiteKeyOptional());
+ }
+
+ @Test
+ public void generateDefaultKeyAlreadyExistsDuplicatesStartAtB() {
+ preferences = new BibtexKeyPatternPreferences("", "", false, false, true, pattern, ',');
+
+ BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences);
+ BibEntry entry2 = new BibEntry();
+ entry2.setField("author", "John Doe");
+ entry2.setField("year", "2016");
+ BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry2, preferences);
+ assertEquals(Optional.of("Doe2016b"), entry2.getCiteKeyOptional());
+ }
+
+ @Test
+ public void generateDefaultKeyAlreadyExistsManyDuplicates() {
+ BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences);
+ BibEntry entry2 = new BibEntry();
+ entry2.setField("author", "John Doe");
+ entry2.setField("year", "2016");
+ entry2.setCiteKey(entry.getCiteKeyOptional().get());
+ database.insertEntry(entry2);
+ BibEntry entry3 = new BibEntry();
+ entry3.setField("author", "John Doe");
+ entry3.setField("year", "2016");
+ entry3.setCiteKey(entry.getCiteKeyOptional().get());
+ database.insertEntry(entry3);
+ BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry3, preferences);
+ assertEquals(Optional.of("Doe2016a"), entry3.getCiteKeyOptional());
+ }
+
+ @Test
+ public void generateDefaultKeyFirstTwoAlreadyExists() {
+ BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences);
+ BibEntry entry2 = new BibEntry();
+ entry2.setField("author", "John Doe");
+ entry2.setField("year", "2016");
+ BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry2, preferences);
+ database.insertEntry(entry2);
+ BibEntry entry3 = new BibEntry();
+ entry3.setField("author", "John Doe");
+ entry3.setField("year", "2016");
+ entry3.setCiteKey(entry.getCiteKeyOptional().get());
+ database.insertEntry(entry3);
+ BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry3, preferences);
+ assertEquals(Optional.of("Doe2016b"), entry3.getCiteKeyOptional());
+ }
+
+ @Test
+ public void generateDefaultKeyLowerModified() {
+ bibtexKeyPattern.setDefaultValue("[auth:lower][year]");
+ BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences);
+ assertEquals(Optional.of("doe2016"), entry.getCiteKeyOptional());
+ }
+
+ @Test
+ public void generateDefaultKeyUpperModified() {
+ bibtexKeyPattern.setDefaultValue("[auth:upper][year]");
+ BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences);
+ assertEquals(Optional.of("DOE2016"), entry.getCiteKeyOptional());
+ }
+
+ @Test
+ public void generateDefaultKeyFixedValue() {
+ bibtexKeyPattern.setDefaultValue("[auth]Test[year]");
+ BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences);
+ assertEquals(Optional.of("DoeTest2016"), entry.getCiteKeyOptional());
+ }
+
+ @Test
+ public void generateKeyShortYear() {
+ bibtexKeyPattern.setDefaultValue("[shortyear]");
+ BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences);
+ assertEquals(Optional.of("16"), entry.getCiteKeyOptional());
+ }
+
+ @Test
+ public void generateKeyAuthN() {
+ bibtexKeyPattern.setDefaultValue("[auth2]");
+ BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences);
+ assertEquals(Optional.of("Do"), entry.getCiteKeyOptional());
+ }
+
+ @Test
+ public void generateKeyAuthNShortName() {
+ bibtexKeyPattern.setDefaultValue("[auth10]");
+ BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences);
+ assertEquals(Optional.of("Doe"), entry.getCiteKeyOptional());
+ }
+
+ @Test
+ public void generateKeyEmptyField() {
+ entry = new BibEntry();
+ BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences);
+ assertEquals(Optional.empty(), entry.getCiteKeyOptional());
+ }
+
+ @Test
+ public void generateKeyEmptyFieldDefaultText() {
+ bibtexKeyPattern.setDefaultValue("[author:(No Author Provided)]");
+ entry.clearField("author");
+ BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences);
+ assertEquals(Optional.of("NoAuthorProvided"), entry.getCiteKeyOptional());
+ }
+
+ @Test
+ public void generateKeyEmptyFieldColonInDefaultText() {
+ bibtexKeyPattern.setDefaultValue("[author:(Problem:No Author Provided)]");
+ entry.clearField("author");
+ BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences);
+ assertEquals(Optional.of("Problem:NoAuthorProvided"), entry.getCiteKeyOptional());
+ }
+
+ @Test
+ public void generateKeyTitle() {
+ bibtexKeyPattern.setDefaultValue("[title]");
+ BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences);
+ assertEquals(Optional.of("AnawesomepaperonJabRef"), entry.getCiteKeyOptional());
+ }
+
+ @Test
+ public void generateKeyTitleAbbr() {
+ bibtexKeyPattern.setDefaultValue("[title:abbr]");
+ BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences);
+ assertEquals(Optional.of("AapoJ"), entry.getCiteKeyOptional());
+ }
+
+ @Test
+ public void generateKeyShorttitle() {
+ bibtexKeyPattern.setDefaultValue("[shorttitle]");
+ BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences);
+ assertEquals(Optional.of("awesomepaperJabRef"), entry.getCiteKeyOptional());
+ }
+
+ @Test
+ public void generateKeyVeryshorttitle() {
+ bibtexKeyPattern.setDefaultValue("[veryshorttitle]");
+ BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences);
+ assertEquals(Optional.of("awesome"), entry.getCiteKeyOptional());
+ }
+
+ @Test
+ public void generateKeyShorttitleINI() {
+ bibtexKeyPattern.setDefaultValue("[shorttitleINI]");
+ BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences);
+ assertEquals(Optional.of("apJ"), entry.getCiteKeyOptional());
+ }
+
+ @Test
+ public void generateKeyAuthNM() {
+ bibtexKeyPattern.setDefaultValue("[auth4_3]");
+ entry.setField("author", "John Doe and Donald Smith and Will Wonder");
+ BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences);
+ assertEquals(Optional.of("Wond"), entry.getCiteKeyOptional());
+ }
+
+ @Test
+ public void generateKeyAuthNMLargeN() {
+ bibtexKeyPattern.setDefaultValue("[auth20_3]");
+ entry.setField("author", "John Doe and Donald Smith and Will Wonder");
+ BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences);
+ assertEquals(Optional.of("Wonder"), entry.getCiteKeyOptional());
+ }
+
+ @Test
+ public void generateKeyAuthNMLargeM() {
+ bibtexKeyPattern.setDefaultValue("[auth2_4]");
+ entry.setField("author", "John Doe and Donald Smith and Will Wonder");
+ BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences);
+ assertEquals(Optional.empty(), entry.getCiteKeyOptional());
+ }
+
+ @Test
+ public void generateKeyAuthNMLargeMReallyReturnsEmptyString() {
+ bibtexKeyPattern.setDefaultValue("[auth2_4][year]");
+ entry.setField("author", "John Doe and Donald Smith and Will Wonder");
+ BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences);
+ assertEquals(Optional.of("2016"), entry.getCiteKeyOptional());
+ }
+
+ @Test
+ public void generateKeyRegExReplace() {
+ preferences = new BibtexKeyPatternPreferences("2", "3", false, true, true, pattern, ',');
+ bibtexKeyPattern.setDefaultValue("[auth][year]");
+ entry.setField("author", "John Doe and Donald Smith and Will Wonder");
+ BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences);
+ assertEquals(Optional.of("Doe3016"), entry.getCiteKeyOptional());
+ }
+
+ @Test
+ public void generateKeyAuthIni() {
+ bibtexKeyPattern.setDefaultValue("[authIni2]");
+ entry.setField("author", "John Doe and Donald Smith and Will Wonder");
+ BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences);
+ assertEquals(Optional.of("DS"), entry.getCiteKeyOptional());
+ }
+
+ @Test
+ public void generateKeyAuthIniMany() {
+ bibtexKeyPattern.setDefaultValue("[authIni10]");
+ entry.setField("author", "John Doe and Donald Smith and Will Wonder");
+ BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences);
+ assertEquals(Optional.of("DoeSmiWon"), entry.getCiteKeyOptional());
+ }
+
+ @Test
+ public void generateKeyTitleTitleCase() {
+ bibtexKeyPattern.setDefaultValue("[title:title_case]");
+ BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences);
+ assertEquals(Optional.of("AnAwesomePaperonJabref"), entry.getCiteKeyOptional());
+ }
+
+ @Test
+ public void generateKeyTitleCapitalize() {
+ bibtexKeyPattern.setDefaultValue("[title:capitalize]");
+ BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences);
+ assertEquals(Optional.of("AnAwesomePaperOnJabref"), entry.getCiteKeyOptional());
+ }
+
+ @Test
+ public void generateKeyTitleSentenceCase() {
+ bibtexKeyPattern.setDefaultValue("[title:sentence_case]");
+ BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences);
+ assertEquals(Optional.of("Anawesomepaperonjabref"), entry.getCiteKeyOptional());
+ }
+
+ @Test
+ public void generateKeyTitleTitleCaseAbbr() {
+ bibtexKeyPattern.setDefaultValue("[title:title_case:abbr]");
+ BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences);
+ assertEquals(Optional.of("AAPoJ"), entry.getCiteKeyOptional());
+ }
+
+ @Test
+ public void generateKeyTitleCapitalizeAbbr() {
+ bibtexKeyPattern.setDefaultValue("[title:capitalize:abbr]");
+ BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences);
+ assertEquals(Optional.of("AAPOJ"), entry.getCiteKeyOptional());
+ }
+
+ @Test
+ public void generateKeyTitleSentenceCaseAbbr() {
+ bibtexKeyPattern.setDefaultValue("[title:sentence_case:abbr]");
+ BibtexKeyPatternUtil.makeAndSetLabel(bibtexKeyPattern, database, entry, preferences);
+ assertEquals(Optional.of("Aapoj"), entry.getCiteKeyOptional());
+ }
+}
diff --git a/src/test/java/net/sf/jabref/logic/bst/TestVM.java b/src/test/java/net/sf/jabref/logic/bst/TestVM.java
index f291480..1a3a39a 100644
--- a/src/test/java/net/sf/jabref/logic/bst/TestVM.java
+++ b/src/test/java/net/sf/jabref/logic/bst/TestVM.java
@@ -10,7 +10,6 @@ import java.util.Optional;
import net.sf.jabref.logic.bst.VM.BstEntry;
import net.sf.jabref.logic.bst.VM.StackFunction;
-import net.sf.jabref.logic.importer.ImportFormatPreferences;
import net.sf.jabref.logic.importer.ParserResult;
import net.sf.jabref.logic.importer.fileformat.BibtexParser;
import net.sf.jabref.model.entry.BibEntry;
@@ -642,7 +641,7 @@ public class TestVM {
private static BibEntry bibtexString2BibtexEntry(String s) throws IOException {
ParserResult result = BibtexParser.parse(new StringReader(s),
- ImportFormatPreferences.fromPreferences(JabRefPreferences.getInstance()));
+ JabRefPreferences.getInstance().getImportFormatPreferences());
Collection<BibEntry> c = result.getDatabase().getEntries();
Assert.assertEquals(1, c.size());
return c.iterator().next();
diff --git a/src/test/java/net/sf/jabref/logic/cleanup/BiblatexCleanupTest.java b/src/test/java/net/sf/jabref/logic/cleanup/BiblatexCleanupTest.java
new file mode 100644
index 0000000..8403006
--- /dev/null
+++ b/src/test/java/net/sf/jabref/logic/cleanup/BiblatexCleanupTest.java
@@ -0,0 +1,45 @@
+package net.sf.jabref.logic.cleanup;
+
+import java.util.Optional;
+
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldName;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class BiblatexCleanupTest {
+
+ private BiblatexCleanup worker;
+
+ @Before
+ public void setUp() {
+ worker = new BiblatexCleanup();
+ }
+
+ @Test
+ public void convertToBiblatexMovesYearMonthToDate() {
+ BibEntry entry = new BibEntry();
+ entry.setField("year", "2011");
+ entry.setField("month", "#jan#");
+
+ worker.cleanup(entry);
+ Assert.assertEquals(Optional.empty(), entry.getField(FieldName.YEAR));
+ Assert.assertEquals(Optional.empty(), entry.getField(FieldName.MONTH));
+ Assert.assertEquals(Optional.of("2011-01"), entry.getField(FieldName.DATE));
+ }
+
+ @Test
+ public void convertToBiblatexDateAlreadyPresent() {
+ BibEntry entry = new BibEntry();
+ entry.setField("year", "2011");
+ entry.setField("month", "#jan#");
+ entry.setField("date", "2012");
+
+ worker.cleanup(entry);
+ Assert.assertEquals(Optional.of("2011"), entry.getField(FieldName.YEAR));
+ Assert.assertEquals(Optional.of("#jan#"), entry.getField(FieldName.MONTH));
+ Assert.assertEquals(Optional.of("2012"), entry.getField(FieldName.DATE));
+ }
+}
diff --git a/src/test/java/net/sf/jabref/logic/cleanup/CleanupWorkerTest.java b/src/test/java/net/sf/jabref/logic/cleanup/CleanupWorkerTest.java
index 404e688..cc03b46 100644
--- a/src/test/java/net/sf/jabref/logic/cleanup/CleanupWorkerTest.java
+++ b/src/test/java/net/sf/jabref/logic/cleanup/CleanupWorkerTest.java
@@ -8,10 +8,6 @@ import java.util.EnumSet;
import java.util.List;
import java.util.Optional;
-import net.sf.jabref.BibDatabaseContext;
-import net.sf.jabref.Globals;
-import net.sf.jabref.MetaData;
-import net.sf.jabref.logic.exporter.FieldFormatterCleanups;
import net.sf.jabref.logic.formatter.bibtexfields.HtmlToLatexFormatter;
import net.sf.jabref.logic.formatter.bibtexfields.LatexCleanupFormatter;
import net.sf.jabref.logic.formatter.bibtexfields.NormalizeDateFormatter;
@@ -19,14 +15,18 @@ import net.sf.jabref.logic.formatter.bibtexfields.NormalizeMonthFormatter;
import net.sf.jabref.logic.formatter.bibtexfields.NormalizePagesFormatter;
import net.sf.jabref.logic.formatter.bibtexfields.UnitsToLatexFormatter;
import net.sf.jabref.logic.formatter.casechanger.ProtectTermsFormatter;
-import net.sf.jabref.logic.layout.LayoutFormatterPreferences;
+import net.sf.jabref.logic.journals.JournalAbbreviationLoader;
import net.sf.jabref.logic.protectedterms.ProtectedTermsLoader;
import net.sf.jabref.logic.protectedterms.ProtectedTermsPreferences;
import net.sf.jabref.model.FieldChange;
+import net.sf.jabref.model.cleanup.FieldFormatterCleanup;
+import net.sf.jabref.model.cleanup.FieldFormatterCleanups;
import net.sf.jabref.model.database.BibDatabase;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.FileField;
import net.sf.jabref.model.entry.ParsedFileField;
+import net.sf.jabref.model.metadata.MetaData;
import net.sf.jabref.preferences.JabRefPreferences;
import org.junit.Assert;
@@ -46,20 +46,22 @@ public class CleanupWorkerTest {
private CleanupWorker worker;
private File pdfFolder;
-
@Before
public void setUp() throws IOException {
- if (Globals.prefs == null) {
- Globals.prefs = JabRefPreferences.getInstance();
- }
-
pdfFolder = bibFolder.newFolder();
MetaData metaData = new MetaData();
metaData.setDefaultFileDirectory(pdfFolder.getAbsolutePath());
BibDatabaseContext context = new BibDatabaseContext(new BibDatabase(), metaData, bibFolder.newFile("test.bib"));
- worker = new CleanupWorker(context, Globals.prefs.get(JabRefPreferences.IMPORT_FILENAMEPATTERN),
- mock(LayoutFormatterPreferences.class));
+
+ JabRefPreferences prefs = JabRefPreferences.getInstance();
+
+ worker = new CleanupWorker(context,
+ new CleanupPreferences(JabRefPreferences.getInstance().get(JabRefPreferences.IMPORT_FILENAMEPATTERN),
+ "", //empty fileDirPattern for backwards compatibility
+ prefs.getLayoutFormatterPreferences(mock(JournalAbbreviationLoader.class)),
+ prefs.getFileDirectoryPreferences()));
+
}
@Test(expected = NullPointerException.class)
@@ -103,8 +105,8 @@ public class CleanupWorkerTest {
entry.setField("pdf", "aPdfFile");
worker.cleanup(preset, entry);
- Assert.assertEquals(Optional.empty(), entry.getFieldOptional("pdf"));
- Assert.assertEquals(Optional.of("aPdfFile:aPdfFile:PDF"), entry.getFieldOptional("file"));
+ Assert.assertEquals(Optional.empty(), entry.getField("pdf"));
+ Assert.assertEquals(Optional.of("aPdfFile:aPdfFile:PDF"), entry.getField("file"));
}
@Test
@@ -114,8 +116,8 @@ public class CleanupWorkerTest {
entry.setField("ps", "aPsFile");
worker.cleanup(preset, entry);
- Assert.assertEquals(Optional.empty(), entry.getFieldOptional("pdf"));
- Assert.assertEquals(Optional.of("aPsFile:aPsFile:PostScript"), entry.getFieldOptional("file"));
+ Assert.assertEquals(Optional.empty(), entry.getField("pdf"));
+ Assert.assertEquals(Optional.of("aPsFile:aPsFile:PostScript"), entry.getField("file"));
}
@Test
@@ -125,7 +127,7 @@ public class CleanupWorkerTest {
entry.setField("doi", "http://dx.doi.org/10.1016/0001-8708(80)90035-3");
worker.cleanup(preset, entry);
- Assert.assertEquals(Optional.of("10.1016/0001-8708(80)90035-3"), entry.getFieldOptional("doi"));
+ Assert.assertEquals(Optional.of("10.1016/0001-8708(80)90035-3"), entry.getField("doi"));
}
@Test
@@ -148,8 +150,8 @@ public class CleanupWorkerTest {
entry.setField("url", "http://dx.doi.org/10.1016/0001-8708(80)90035-3");
worker.cleanup(preset, entry);
- Assert.assertEquals(Optional.of("10.1016/0001-8708(80)90035-3"), entry.getFieldOptional("doi"));
- Assert.assertEquals(Optional.empty(), entry.getFieldOptional("url"));
+ Assert.assertEquals(Optional.of("10.1016/0001-8708(80)90035-3"), entry.getField("doi"));
+ Assert.assertEquals(Optional.empty(), entry.getField("url"));
}
@Test
@@ -173,7 +175,7 @@ public class CleanupWorkerTest {
entry.setField("month", "01");
worker.cleanup(preset, entry);
- Assert.assertEquals(Optional.of("#jan#"), entry.getFieldOptional("month"));
+ Assert.assertEquals(Optional.of("#jan#"), entry.getField("month"));
}
@Test
@@ -184,7 +186,7 @@ public class CleanupWorkerTest {
entry.setField("pages", "1-2");
worker.cleanup(preset, entry);
- Assert.assertEquals(Optional.of("1--2"), entry.getFieldOptional("pages"));
+ Assert.assertEquals(Optional.of("1--2"), entry.getField("pages"));
}
@Test
@@ -195,7 +197,7 @@ public class CleanupWorkerTest {
entry.setField("date", "01/1999");
worker.cleanup(preset, entry);
- Assert.assertEquals(Optional.of("1999-01"), entry.getFieldOptional("date"));
+ Assert.assertEquals(Optional.of("1999-01"), entry.getField("date"));
}
@Test
@@ -205,7 +207,7 @@ public class CleanupWorkerTest {
entry.setField("file", "link::");
worker.cleanup(preset, entry);
- Assert.assertEquals(Optional.of(":link:"), entry.getFieldOptional("file"));
+ Assert.assertEquals(Optional.of(":link:"), entry.getField("file"));
}
@Test
@@ -221,8 +223,7 @@ public class CleanupWorkerTest {
worker.cleanup(preset, entry);
ParsedFileField newFileField = new ParsedFileField("", tempFile.getName(), "");
- Assert.assertEquals(Optional.of(FileField.getStringRepresentation(newFileField)),
- entry.getFieldOptional("file"));
+ Assert.assertEquals(Optional.of(FileField.getStringRepresentation(newFileField)), entry.getField("file"));
}
@Test
@@ -236,8 +237,7 @@ public class CleanupWorkerTest {
worker.cleanup(preset, entry);
ParsedFileField newFileField = new ParsedFileField("", tempFile.getName(), "");
- Assert.assertEquals(Optional.of(FileField.getStringRepresentation(newFileField)),
- entry.getFieldOptional("file"));
+ Assert.assertEquals(Optional.of(FileField.getStringRepresentation(newFileField)), entry.getField("file"));
}
@Test
@@ -252,8 +252,7 @@ public class CleanupWorkerTest {
worker.cleanup(preset, entry);
ParsedFileField newFileField = new ParsedFileField("", "Toot.tmp", "");
- Assert.assertEquals(Optional.of(FileField.getStringRepresentation(newFileField)),
- entry.getFieldOptional("file"));
+ Assert.assertEquals(Optional.of(FileField.getStringRepresentation(newFileField)), entry.getField("file"));
}
@Test
@@ -264,7 +263,7 @@ public class CleanupWorkerTest {
entry.setField("title", "Ε");
worker.cleanup(preset, entry);
- Assert.assertEquals(Optional.of("{{$\\Epsilon$}}"), entry.getFieldOptional("title"));
+ Assert.assertEquals(Optional.of("{{$\\Epsilon$}}"), entry.getField("title"));
}
@Test
@@ -275,7 +274,7 @@ public class CleanupWorkerTest {
entry.setField("title", "1 A");
worker.cleanup(preset, entry);
- Assert.assertEquals(Optional.of("1~{A}"), entry.getFieldOptional("title"));
+ Assert.assertEquals(Optional.of("1~{A}"), entry.getField("title"));
}
@Test
@@ -284,13 +283,13 @@ public class CleanupWorkerTest {
new ProtectedTermsPreferences(ProtectedTermsLoader.getInternalLists(), Collections.emptyList(),
Collections.emptyList(), Collections.emptyList()));
Assert.assertNotEquals(Collections.emptyList(), protectedTermsLoader.getProtectedTerms());
- CleanupPreset preset = new CleanupPreset(new FieldFormatterCleanups(true,
- Collections.singletonList(new FieldFormatterCleanup("title", new ProtectTermsFormatter(protectedTermsLoader)))));
+ CleanupPreset preset = new CleanupPreset(new FieldFormatterCleanups(true, Collections
+ .singletonList(new FieldFormatterCleanup("title", new ProtectTermsFormatter(protectedTermsLoader)))));
BibEntry entry = new BibEntry();
entry.setField("title", "AlGaAs");
worker.cleanup(preset, entry);
- Assert.assertEquals(Optional.of("{AlGaAs}"), entry.getFieldOptional("title"));
+ Assert.assertEquals(Optional.of("{AlGaAs}"), entry.getField("title"));
}
@Test
@@ -301,7 +300,7 @@ public class CleanupWorkerTest {
entry.setField("title", "$\\alpha$$\\beta$");
worker.cleanup(preset, entry);
- Assert.assertEquals(Optional.of("$\\alpha\\beta$"), entry.getFieldOptional("title"));
+ Assert.assertEquals(Optional.of("$\\alpha\\beta$"), entry.getField("title"));
}
@Test
@@ -311,8 +310,8 @@ public class CleanupWorkerTest {
entry.setField("journal", "test");
worker.cleanup(preset, entry);
- Assert.assertEquals(Optional.empty(), entry.getFieldOptional("journal"));
- Assert.assertEquals(Optional.of("test"), entry.getFieldOptional("journaltitle"));
+ Assert.assertEquals(Optional.empty(), entry.getField("journal"));
+ Assert.assertEquals(Optional.of("test"), entry.getField("journaltitle"));
}
@Test
@@ -323,6 +322,7 @@ public class CleanupWorkerTest {
entry.setField("month", "01");
worker.cleanup(preset, entry);
- Assert.assertEquals(Optional.of("01"), entry.getFieldOptional("month"));
+ Assert.assertEquals(Optional.of("01"), entry.getField("month"));
}
+
}
diff --git a/src/test/java/net/sf/jabref/logic/cleanup/FieldFormatterCleanupTest.java b/src/test/java/net/sf/jabref/logic/cleanup/FieldFormatterCleanupTest.java
new file mode 100644
index 0000000..6710f97
--- /dev/null
+++ b/src/test/java/net/sf/jabref/logic/cleanup/FieldFormatterCleanupTest.java
@@ -0,0 +1,66 @@
+package net.sf.jabref.logic.cleanup;
+
+
+import java.util.HashMap;
+import java.util.Map;
+
+import net.sf.jabref.logic.formatter.casechanger.UpperCaseFormatter;
+import net.sf.jabref.model.cleanup.FieldFormatterCleanup;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.BibtexEntryTypes;
+import net.sf.jabref.model.entry.FieldName;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class FieldFormatterCleanupTest {
+
+ private BibEntry entry;
+ private Map <String, String> fieldMap;
+
+ @Before
+ public void setUp() {
+ fieldMap = new HashMap<>();
+ entry = new BibEntry();
+
+ entry.setType(BibtexEntryTypes.ARTICLE);
+ fieldMap.put("title", "JabRef");
+ fieldMap.put("booktitle", "JabRefBook");
+ fieldMap.put("year", "twohundredsixteen");
+ fieldMap.put("month", "october");
+ fieldMap.put("abstract", "JabRefAbstract");
+ fieldMap.put("doi", "jabrefdoi");
+ fieldMap.put("issn", "jabrefissn");
+ entry.setField(fieldMap);
+
+ }
+
+ @Test
+ public void testInternalAllField() throws Exception {
+ FieldFormatterCleanup cleanup = new FieldFormatterCleanup(FieldName.INTERNAL_ALL_FIELD, new UpperCaseFormatter());
+ cleanup.cleanup(entry);
+
+ Assert.assertEquals(fieldMap.get("title").toUpperCase(), entry.getField("title").get());
+ Assert.assertEquals(fieldMap.get("booktitle").toUpperCase(), entry.getField("booktitle").get());
+ Assert.assertEquals(fieldMap.get("year").toUpperCase(), entry.getField("year").get());
+ Assert.assertEquals(fieldMap.get("month").toUpperCase(), entry.getField("month").get());
+ Assert.assertEquals(fieldMap.get("abstract").toUpperCase(), entry.getField("abstract").get());
+ Assert.assertEquals(fieldMap.get("doi").toUpperCase(), entry.getField("doi").get());
+ Assert.assertEquals(fieldMap.get("issn").toUpperCase(), entry.getField("issn").get());
+ }
+
+ @Test
+ public void testInternalAllTextFieldsField() throws Exception {
+ FieldFormatterCleanup cleanup = new FieldFormatterCleanup(FieldName.INTERNAL_ALL_TEXT_FIELDS_FIELD, new UpperCaseFormatter());
+ cleanup.cleanup(entry);
+
+ Assert.assertEquals(fieldMap.get("title").toUpperCase(), entry.getField("title").get());
+ Assert.assertEquals(fieldMap.get("booktitle").toUpperCase(), entry.getField("booktitle").get());
+ Assert.assertEquals(fieldMap.get("year"), entry.getField("year").get());
+ Assert.assertEquals(fieldMap.get("month"), entry.getField("month").get());
+ Assert.assertEquals(fieldMap.get("abstract").toUpperCase(), entry.getField("abstract").get());
+ Assert.assertEquals(fieldMap.get("doi"), entry.getField("doi").get());
+ Assert.assertEquals(fieldMap.get("issn"), entry.getField("issn").get());
+ }
+}
diff --git a/src/test/java/net/sf/jabref/logic/cleanup/ISSNCleanupTest.java b/src/test/java/net/sf/jabref/logic/cleanup/ISSNCleanupTest.java
index 6fce1cb..cdce06a 100644
--- a/src/test/java/net/sf/jabref/logic/cleanup/ISSNCleanupTest.java
+++ b/src/test/java/net/sf/jabref/logic/cleanup/ISSNCleanupTest.java
@@ -2,9 +2,10 @@ package net.sf.jabref.logic.cleanup;
import java.util.Optional;
-import net.sf.jabref.BibDatabaseContext;
import net.sf.jabref.logic.layout.LayoutFormatterPreferences;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.metadata.FileDirectoryPreferences;
import org.junit.Assert;
import org.junit.Before;
@@ -19,7 +20,9 @@ public class ISSNCleanupTest {
@Before
public void setUp() {
- worker = new CleanupWorker(mock(BibDatabaseContext.class), "", mock(LayoutFormatterPreferences.class));
+ worker = new CleanupWorker(mock(BibDatabaseContext.class),
+ new CleanupPreferences("", "", mock(LayoutFormatterPreferences.class),
+ mock(FileDirectoryPreferences.class)));
}
@Test
@@ -29,7 +32,7 @@ public class ISSNCleanupTest {
entry.setField("issn", "0123-4567");
worker.cleanup(preset, entry);
- Assert.assertEquals(Optional.of("0123-4567"), entry.getFieldOptional("issn"));
+ Assert.assertEquals(Optional.of("0123-4567"), entry.getField("issn"));
}
@Test
@@ -39,7 +42,7 @@ public class ISSNCleanupTest {
entry.setField("issn", "01234567");
worker.cleanup(preset, entry);
- Assert.assertEquals(Optional.of("0123-4567"), entry.getFieldOptional("issn"));
+ Assert.assertEquals(Optional.of("0123-4567"), entry.getField("issn"));
}
@Test
@@ -49,7 +52,7 @@ public class ISSNCleanupTest {
entry.setField("issn", "Banana");
worker.cleanup(preset, entry);
- Assert.assertEquals(Optional.of("Banana"), entry.getFieldOptional("issn"));
+ Assert.assertEquals(Optional.of("Banana"), entry.getField("issn"));
}
}
diff --git a/src/test/java/net/sf/jabref/logic/cleanup/MoveFilesCleanupTest.java b/src/test/java/net/sf/jabref/logic/cleanup/MoveFilesCleanupTest.java
index 071969e..cf75d01 100644
--- a/src/test/java/net/sf/jabref/logic/cleanup/MoveFilesCleanupTest.java
+++ b/src/test/java/net/sf/jabref/logic/cleanup/MoveFilesCleanupTest.java
@@ -5,13 +5,12 @@ import java.io.IOException;
import java.util.Arrays;
import java.util.Optional;
-import net.sf.jabref.BibDatabaseContext;
-import net.sf.jabref.Globals;
-import net.sf.jabref.MetaData;
import net.sf.jabref.model.database.BibDatabase;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.FileField;
import net.sf.jabref.model.entry.ParsedFileField;
+import net.sf.jabref.model.metadata.MetaData;
import net.sf.jabref.preferences.JabRefPreferences;
import org.junit.Before;
@@ -34,14 +33,12 @@ public class MoveFilesCleanupTest {
@Before
public void setUp() throws IOException {
- Globals.prefs = JabRefPreferences.getInstance();
-
pdfFolder = bibFolder.newFolder();
MetaData metaData = new MetaData();
metaData.setDefaultFileDirectory(pdfFolder.getAbsolutePath());
databaseContext = new BibDatabaseContext(new BibDatabase(), metaData, bibFolder.newFile("test.bib"));
- cleanup = new MoveFilesCleanup(databaseContext);
+ cleanup = new MoveFilesCleanup(databaseContext, JabRefPreferences.getInstance().getFileDirectoryPreferences());
}
@Test
@@ -62,7 +59,7 @@ public class MoveFilesCleanupTest {
assertTrue(fileAfter.exists());
assertEquals(Optional.of(FileField.getStringRepresentation(new ParsedFileField("", fileAfter.getName(), ""))),
- entry.getFieldOptional("file"));
+ entry.getField("file"));
}
@Test
@@ -85,6 +82,6 @@ public class MoveFilesCleanupTest {
assertEquals(
Optional.of(FileField.getStringRepresentation(Arrays.asList(new ParsedFileField("", "", ""),
new ParsedFileField("", fileAfter.getName(), ""), new ParsedFileField("", "", "")))),
- entry.getFieldOptional("file"));
+ entry.getField("file"));
}
}
\ No newline at end of file
diff --git a/src/test/java/net/sf/jabref/logic/cleanup/RenamePdfCleanupTest.java b/src/test/java/net/sf/jabref/logic/cleanup/RenamePdfCleanupTest.java
index 20365a2..b3d2189 100644
--- a/src/test/java/net/sf/jabref/logic/cleanup/RenamePdfCleanupTest.java
+++ b/src/test/java/net/sf/jabref/logic/cleanup/RenamePdfCleanupTest.java
@@ -2,19 +2,21 @@ package net.sf.jabref.logic.cleanup;
import java.io.File;
import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.Arrays;
import java.util.Optional;
-import net.sf.jabref.BibDatabaseContext;
-import net.sf.jabref.Defaults;
-import net.sf.jabref.Globals;
-import net.sf.jabref.MetaData;
import net.sf.jabref.logic.journals.JournalAbbreviationLoader;
import net.sf.jabref.logic.layout.LayoutFormatterPreferences;
+import net.sf.jabref.model.Defaults;
import net.sf.jabref.model.database.BibDatabase;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.FileField;
import net.sf.jabref.model.entry.ParsedFileField;
+import net.sf.jabref.model.metadata.FileDirectoryPreferences;
+import net.sf.jabref.model.metadata.MetaData;
import net.sf.jabref.preferences.JabRefPreferences;
import org.junit.Before;
@@ -24,6 +26,7 @@ import org.junit.rules.TemporaryFolder;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
public class RenamePdfCleanupTest {
@@ -31,15 +34,20 @@ public class RenamePdfCleanupTest {
public TemporaryFolder testFolder = new TemporaryFolder();
private BibDatabaseContext context;
private BibEntry entry;
+ private JabRefPreferences prefs;
+
+ private FileDirectoryPreferences fileDirPrefs;
@Before
public void setUp() throws Exception {
- Globals.prefs = mock(JabRefPreferences.class);
-
+ prefs = JabRefPreferences.getInstance();
MetaData metaData = new MetaData();
context = new BibDatabaseContext(new BibDatabase(), metaData, new Defaults());
context.setDatabaseFile(testFolder.newFile("test.bib"));
+ fileDirPrefs = mock(FileDirectoryPreferences.class);
+ when(fileDirPrefs.isBibLocationAsPrimary()).thenReturn(true); //Set Biblocation as Primary Directory, otherwise the tmp folders won't be cleaned up correctly
+
entry = new BibEntry();
entry.setCiteKey("Toot");
}
@@ -50,66 +58,165 @@ public class RenamePdfCleanupTest {
@Test
public void cleanupRenamePdfRenamesFileEvenIfOnlyDifferenceIsCase() throws IOException {
String fileNamePattern = "\\bibtexkey";
+ String fileDirPattern = "";
File tempFile = testFolder.newFile("toot.tmp");
ParsedFileField fileField = new ParsedFileField("", tempFile.getAbsolutePath(), "");
entry.setField("file", FileField.getStringRepresentation(fileField));
- RenamePdfCleanup cleanup = new RenamePdfCleanup(false, context, fileNamePattern,
- mock(LayoutFormatterPreferences.class));
+ RenamePdfCleanup cleanup = new RenamePdfCleanup(false, context, fileNamePattern, fileDirPattern,
+ mock(LayoutFormatterPreferences.class), fileDirPrefs);
cleanup.cleanup(entry);
ParsedFileField newFileField = new ParsedFileField("", "Toot.tmp", "");
- assertEquals(Optional.of(FileField.getStringRepresentation(newFileField)), entry.getFieldOptional("file"));
+ assertEquals(Optional.of(FileField.getStringRepresentation(newFileField)), entry.getField("file"));
}
@Test
public void cleanupRenamePdfRenamesWithMultipleFiles() throws IOException {
String fileNamePattern = "\\bibtexkey - \\title";
+ String fileDirPattern = "";
File tempFile = testFolder.newFile("Toot.tmp");
entry.setField("title", "test title");
- entry.setField("file", FileField.getStringRepresentation(Arrays.asList(new ParsedFileField("","",""),
- new ParsedFileField("", tempFile.getAbsolutePath(), ""), new ParsedFileField("","",""))));
+ entry.setField("file", FileField.getStringRepresentation(Arrays.asList(new ParsedFileField("", "", ""),
+ new ParsedFileField("", tempFile.getAbsolutePath(), ""), new ParsedFileField("", "", ""))));
- RenamePdfCleanup cleanup = new RenamePdfCleanup(false, context, fileNamePattern,
- mock(LayoutFormatterPreferences.class));
+ RenamePdfCleanup cleanup = new RenamePdfCleanup(false, context, fileNamePattern, fileDirPattern,
+ mock(LayoutFormatterPreferences.class), fileDirPrefs);
cleanup.cleanup(entry);
assertEquals(
Optional.of(FileField.getStringRepresentation(Arrays.asList(new ParsedFileField("", "", ""),
new ParsedFileField("", "Toot - test title.tmp", ""), new ParsedFileField("", "", "")))),
- entry.getFieldOptional("file"));
+ entry.getField("file"));
}
@Test
public void cleanupRenamePdfRenamesFileStartingWithBibtexKey() throws IOException {
String fileNamePattern = "\\bibtexkey - \\title";
+ String fileDirPattern = "";
+
File tempFile = testFolder.newFile("Toot.tmp");
ParsedFileField fileField = new ParsedFileField("", tempFile.getAbsolutePath(), "");
entry.setField("file", FileField.getStringRepresentation(fileField));
entry.setField("title", "test title");
- RenamePdfCleanup cleanup = new RenamePdfCleanup(false, context, fileNamePattern,
- mock(LayoutFormatterPreferences.class));
+ RenamePdfCleanup cleanup = new RenamePdfCleanup(false, context, fileNamePattern, fileDirPattern,
+ mock(LayoutFormatterPreferences.class), fileDirPrefs);
cleanup.cleanup(entry);
ParsedFileField newFileField = new ParsedFileField("", "Toot - test title.tmp", "");
- assertEquals(Optional.of(FileField.getStringRepresentation(newFileField)), entry.getFieldOptional("file"));
+ assertEquals(Optional.of(FileField.getStringRepresentation(newFileField)), entry.getField("file"));
}
@Test
public void cleanupRenamePdfRenamesFileInSameFolder() throws IOException {
String fileNamePattern = "\\bibtexkey\\begin{title} - \\format[RemoveBrackets]{\\title}\\end{title}";
+ String fileDirPattern = "";
testFolder.newFile("Toot.pdf");
ParsedFileField fileField = new ParsedFileField("", "Toot.pdf", "PDF");
entry.setField("file", FileField.getStringRepresentation(fileField));
entry.setField("title", "test title");
- RenamePdfCleanup cleanup = new RenamePdfCleanup(false, context, fileNamePattern,
- LayoutFormatterPreferences.fromPreferences(Globals.prefs, mock(JournalAbbreviationLoader.class)));
+ RenamePdfCleanup cleanup = new RenamePdfCleanup(false, context, fileNamePattern, fileDirPattern,
+ prefs.getLayoutFormatterPreferences(mock(JournalAbbreviationLoader.class)),
+ fileDirPrefs);
cleanup.cleanup(entry);
ParsedFileField newFileField = new ParsedFileField("", "Toot - test title.pdf", "PDF");
- assertEquals(Optional.of(FileField.getStringRepresentation(newFileField)), entry.getFieldOptional("file"));
+ assertEquals(Optional.of(FileField.getStringRepresentation(newFileField)), entry.getField("file"));
+ }
+
+ @Test
+ public void cleanUpRenamePdfRenameFileDirectoryPattern() throws IOException {
+ String fileNamePattern = "\\bibtexkey\\begin{title} - \\format[RemoveBrackets]{\\title}\\end{title}";
+ String fileDirPattern = "\\EntryType";
+
+ testFolder.newFile("Toot.pdf");
+ ParsedFileField fileField = new ParsedFileField("", "Toot.pdf", "PDF");
+ entry.setField("file", FileField.getStringRepresentation(fileField));
+ entry.setField("title", "test title");
+
+ RenamePdfCleanup cleanup = new RenamePdfCleanup(false, context, fileNamePattern, fileDirPattern,
+ prefs.getLayoutFormatterPreferences(mock(JournalAbbreviationLoader.class)),
+ fileDirPrefs);
+ cleanup.cleanup(entry);
+
+ Path parent = context.getFirstExistingFileDir(prefs.getFileDirectoryPreferences()).get();
+ String relativeFile = parent.relativize(parent.resolve("Misc/Toot - test title.pdf")).toString();
+
+ ParsedFileField newFileField = new ParsedFileField("", relativeFile, "PDF");
+ assertEquals(Optional.of(FileField.getStringRepresentation(newFileField)), entry.getField("file"));
+ }
+
+ @Test
+ public void cleanUpRenamePdfRenameFileDirectoryPatternSubDirectory() throws IOException {
+ String fileNamePattern = "\\bibtexkey\\begin{title} - \\format[RemoveBrackets]{\\title}\\end{title}";
+ String fileDirPattern = "\\EntryType";
+
+ File subFolder = testFolder.newFolder("subbfolder");
+ Path file = Files.createTempFile(subFolder.toPath(), "Toot", "pdf");
+
+ ParsedFileField fileField = new ParsedFileField("", file.toString(), "PDF");
+ entry.setField("file", FileField.getStringRepresentation(fileField));
+ entry.setField("title", "test title");
+
+ RenamePdfCleanup cleanup = new RenamePdfCleanup(false, context, fileNamePattern, fileDirPattern,
+ prefs.getLayoutFormatterPreferences(mock(JournalAbbreviationLoader.class)),
+ fileDirPrefs);
+ cleanup.cleanup(entry);
+
+ Path parent = context.getFirstExistingFileDir(prefs.getFileDirectoryPreferences()).get();
+ String relativeFile = parent.relativize(parent.resolve("Misc/Toot - test title.pdf")).toString();
+
+ ParsedFileField newFileField = new ParsedFileField("", relativeFile, "PDF");
+ assertEquals(Optional.of(FileField.getStringRepresentation(newFileField)), entry.getField("file"));
}
+
+ @Test
+ public void cleanUpRenamePdfRenameFileDirectoryPatternSameAsFilePattern() throws IOException {
+ String fileNamePattern = "\\bibtexkey\\begin{title} - \\format[RemoveBrackets]{\\title}\\end{title}";
+ String fileDirPattern = "\\bibtexkey\\begin{title} - \\format[RemoveBrackets]{\\title}\\end{title}";
+
+ testFolder.newFile("Toot.pdf");
+
+ ParsedFileField fileField = new ParsedFileField("", "Toot.pdf", "PDF");
+ entry.setField("file", FileField.getStringRepresentation(fileField));
+ entry.setField("title", "test title");
+
+ RenamePdfCleanup cleanup = new RenamePdfCleanup(false, context, fileNamePattern, fileDirPattern,
+ prefs.getLayoutFormatterPreferences(mock(JournalAbbreviationLoader.class)),
+ fileDirPrefs);
+ cleanup.cleanup(entry);
+
+ Path parent = context.getFirstExistingFileDir(prefs.getFileDirectoryPreferences()).get();
+ String relativeFile = parent.relativize(parent.resolve("Toot - test title/Toot - test title.pdf")).toString();
+
+ ParsedFileField newFileField = new ParsedFileField("", relativeFile, "PDF");
+ assertEquals(Optional.of(FileField.getStringRepresentation(newFileField)), entry.getField("file"));
+ }
+
+ @Test
+ public void cleanUpRenamePdfRenameFileDirectoryPatternEmptyFileName() throws IOException {
+ String fileNamePattern = "";
+ String fileDirPattern = "\\bibtexkey\\begin{title} - \\format[RemoveBrackets]{\\title}\\end{title}";
+
+ testFolder.newFile("Toot.pdf");
+
+ ParsedFileField fileField = new ParsedFileField("", "Toot.pdf", "PDF");
+ entry.setField("file", FileField.getStringRepresentation(fileField));
+ entry.setField("title", "test title");
+
+ RenamePdfCleanup cleanup = new RenamePdfCleanup(false, context, fileNamePattern, fileDirPattern,
+ prefs.getLayoutFormatterPreferences(mock(JournalAbbreviationLoader.class)),
+ fileDirPrefs);
+ cleanup.cleanup(entry);
+
+ Path parent = context.getFirstExistingFileDir(prefs.getFileDirectoryPreferences()).get();
+ String relativeFile = parent.relativize(parent.resolve("Toot - test title/Toot.pdf")).toString();
+
+ ParsedFileField newFileField = new ParsedFileField("", relativeFile, "PDF");
+ assertEquals(Optional.of(FileField.getStringRepresentation(newFileField)), entry.getField("file"));
+ }
+
}
diff --git a/src/test/java/net/sf/jabref/logic/exporter/BibTeXMLExporterTestFiles.java b/src/test/java/net/sf/jabref/logic/exporter/BibTeXMLExporterTestFiles.java
new file mode 100644
index 0000000..d9cc71d
--- /dev/null
+++ b/src/test/java/net/sf/jabref/logic/exporter/BibTeXMLExporterTestFiles.java
@@ -0,0 +1,89 @@
+package net.sf.jabref.logic.exporter;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import net.sf.jabref.logic.importer.fileformat.BibtexImporter;
+import net.sf.jabref.model.database.BibDatabaseContext;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.preferences.JabRefPreferences;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+import org.xmlunit.builder.Input;
+import org.xmlunit.builder.Input.Builder;
+import org.xmlunit.diff.DefaultNodeMatcher;
+import org.xmlunit.diff.ElementSelectors;
+import org.xmlunit.matchers.CompareMatcher;
+
+
+ at RunWith(Parameterized.class)
+public class BibTeXMLExporterTestFiles {
+
+ public BibDatabaseContext databaseContext;
+ public Charset charset;
+ public File tempFile;
+ public BibTeXMLExportFormat bibtexmlExportFormat;
+ public BibtexImporter testImporter;
+
+ @Parameter
+ public String filename;
+ public Path resourceDir;
+
+ @Rule
+ public TemporaryFolder testFolder = new TemporaryFolder();
+
+
+ @Parameters(name = "{0}")
+ public static Collection<String> fileNames() throws IOException, URISyntaxException {
+ try (Stream<Path> stream = Files.list(Paths.get(BibTeXMLExporterTestFiles.class.getResource("").toURI()))) {
+ return stream.map(n -> n.getFileName().toString()).filter(n -> n.endsWith(".bib"))
+ .filter(n -> n.startsWith("BibTeXML")).collect(Collectors.toList());
+ }
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ resourceDir = Paths.get(BibTeXMLExporterTestFiles.class.getResource("").toURI());
+ databaseContext = new BibDatabaseContext();
+ charset = StandardCharsets.UTF_8;
+ bibtexmlExportFormat = new BibTeXMLExportFormat();
+ tempFile = testFolder.newFile();
+ testImporter = new BibtexImporter(JabRefPreferences.getInstance().getImportFormatPreferences());
+ }
+
+ @Test
+ public final void testPerformExport() throws IOException, SaveException {
+ String xmlFileName = filename.replace(".bib", ".xml");
+ Path importFile = resourceDir.resolve(filename);
+ String tempFilename = tempFile.getCanonicalPath();
+
+ List<BibEntry> entries = testImporter.importDatabase(importFile, StandardCharsets.UTF_8).getDatabase()
+ .getEntries();
+
+ bibtexmlExportFormat.performExport(databaseContext, tempFile.getPath(), charset, entries);
+
+ Builder control = Input.from(Files.newInputStream(resourceDir.resolve(xmlFileName)));
+ Builder test = Input.from(Files.newInputStream(Paths.get(tempFilename)));
+
+ Assert.assertThat(test, CompareMatcher.isSimilarTo(control)
+ .withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.byNameAndText)).throwComparisonFailure());
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/net/sf/jabref/logic/exporter/BibtexDatabaseWriterTest.java b/src/test/java/net/sf/jabref/logic/exporter/BibtexDatabaseWriterTest.java
index e096de1..3e776f2 100644
--- a/src/test/java/net/sf/jabref/logic/exporter/BibtexDatabaseWriterTest.java
+++ b/src/test/java/net/sf/jabref/logic/exporter/BibtexDatabaseWriterTest.java
@@ -4,36 +4,35 @@ import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
-import java.util.Arrays;
import java.util.Collections;
import java.util.Scanner;
-import net.sf.jabref.BibDatabaseContext;
-import net.sf.jabref.Defaults;
-import net.sf.jabref.Globals;
-import net.sf.jabref.MetaData;
-import net.sf.jabref.logic.cleanup.FieldFormatterCleanup;
-import net.sf.jabref.logic.config.SaveOrderConfig;
import net.sf.jabref.logic.formatter.casechanger.LowerCaseFormatter;
-import net.sf.jabref.logic.groups.AllEntriesGroup;
-import net.sf.jabref.logic.groups.ExplicitGroup;
-import net.sf.jabref.logic.groups.GroupHierarchyType;
-import net.sf.jabref.logic.groups.GroupTreeNode;
import net.sf.jabref.logic.importer.ImportFormatPreferences;
+import net.sf.jabref.logic.importer.Importer;
import net.sf.jabref.logic.importer.ParserResult;
import net.sf.jabref.logic.importer.fileformat.BibtexParser;
-import net.sf.jabref.logic.importer.fileformat.ImportFormat;
import net.sf.jabref.logic.util.OS;
+import net.sf.jabref.model.Defaults;
import net.sf.jabref.model.EntryTypes;
import net.sf.jabref.model.bibtexkeypattern.AbstractBibtexKeyPattern;
import net.sf.jabref.model.bibtexkeypattern.DatabaseBibtexKeyPattern;
+import net.sf.jabref.model.cleanup.FieldFormatterCleanup;
+import net.sf.jabref.model.cleanup.FieldFormatterCleanups;
import net.sf.jabref.model.database.BibDatabase;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.database.BibDatabaseMode;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.BibtexEntryTypes;
import net.sf.jabref.model.entry.BibtexString;
import net.sf.jabref.model.entry.CustomEntryType;
import net.sf.jabref.model.entry.IdGenerator;
+import net.sf.jabref.model.groups.AllEntriesGroup;
+import net.sf.jabref.model.groups.ExplicitGroup;
+import net.sf.jabref.model.groups.GroupHierarchyType;
+import net.sf.jabref.model.groups.GroupTreeNode;
+import net.sf.jabref.model.metadata.MetaData;
+import net.sf.jabref.model.metadata.SaveOrderConfig;
import net.sf.jabref.preferences.JabRefPreferences;
import com.google.common.base.Charsets;
@@ -49,10 +48,11 @@ public class BibtexDatabaseWriterTest {
private MetaData metaData;
private BibDatabaseContext bibtexContext;
private ImportFormatPreferences importFormatPreferences;
+ private JabRefPreferences prefs;
@Before
public void setUp() {
- Globals.prefs = JabRefPreferences.getInstance();
+ prefs = JabRefPreferences.getInstance();
// Write to a string instead of to a file
databaseWriter = new BibtexDatabaseWriter<>(StringSaveSession::new);
@@ -60,7 +60,7 @@ public class BibtexDatabaseWriterTest {
database = new BibDatabase();
metaData = new MetaData();
bibtexContext = new BibDatabaseContext(database, metaData, new Defaults(BibDatabaseMode.BIBTEX));
- importFormatPreferences = ImportFormatPreferences.fromPreferences(Globals.prefs);
+ importFormatPreferences = prefs.getImportFormatPreferences();
}
@Test(expected = NullPointerException.class)
@@ -159,9 +159,9 @@ public class BibtexDatabaseWriterTest {
@Test
public void writeMetadata() throws Exception {
- DatabaseBibtexKeyPattern bibtexKeyPattern = new DatabaseBibtexKeyPattern(Globals.prefs.getKeyPattern());
+ DatabaseBibtexKeyPattern bibtexKeyPattern = new DatabaseBibtexKeyPattern(prefs.getKeyPattern());
bibtexKeyPattern.setDefaultValue("test");
- metaData.setBibtexKeyPattern(bibtexKeyPattern);
+ metaData.setCiteKeyPattern(bibtexKeyPattern);
StringSaveSession session = databaseWriter.savePartOfDatabase(bibtexContext, Collections.emptyList(), new SavePreferences());
@@ -172,9 +172,9 @@ public class BibtexDatabaseWriterTest {
@Test
public void writeMetadataAndEncoding() throws Exception {
SavePreferences preferences = new SavePreferences().withEncoding(Charsets.US_ASCII);
- DatabaseBibtexKeyPattern bibtexKeyPattern = new DatabaseBibtexKeyPattern(Globals.prefs.getKeyPattern());
+ DatabaseBibtexKeyPattern bibtexKeyPattern = new DatabaseBibtexKeyPattern(prefs.getKeyPattern());
bibtexKeyPattern.setDefaultValue("test");
- metaData.setBibtexKeyPattern(bibtexKeyPattern);
+ metaData.setCiteKeyPattern(bibtexKeyPattern);
StringSaveSession session = databaseWriter.savePartOfDatabase(bibtexContext, Collections.emptyList(), preferences);
@@ -185,8 +185,8 @@ public class BibtexDatabaseWriterTest {
@Test
public void writeGroups() throws Exception {
- GroupTreeNode groupRoot = GroupTreeNode.fromGroup(new AllEntriesGroup());
- groupRoot.addSubgroup(new ExplicitGroup("test", GroupHierarchyType.INCLUDING, Globals.prefs));
+ GroupTreeNode groupRoot = GroupTreeNode.fromGroup(new AllEntriesGroup(""));
+ groupRoot.addSubgroup(new ExplicitGroup("test", GroupHierarchyType.INCLUDING, ','));
metaData.setGroups(groupRoot);
StringSaveSession session = databaseWriter.savePartOfDatabase(bibtexContext, Collections.emptyList(), new SavePreferences());
@@ -204,9 +204,8 @@ public class BibtexDatabaseWriterTest {
public void writeGroupsAndEncoding() throws Exception {
SavePreferences preferences = new SavePreferences().withEncoding(Charsets.US_ASCII);
- GroupTreeNode groupRoot = GroupTreeNode.fromGroup(new AllEntriesGroup());
- groupRoot.addChild(
- GroupTreeNode.fromGroup(new ExplicitGroup("test", GroupHierarchyType.INCLUDING, Globals.prefs)));
+ GroupTreeNode groupRoot = GroupTreeNode.fromGroup(new AllEntriesGroup(""));
+ groupRoot.addChild(GroupTreeNode.fromGroup(new ExplicitGroup("test", GroupHierarchyType.INCLUDING, ',')));
metaData.setGroups(groupRoot);
StringSaveSession session = databaseWriter.savePartOfDatabase(bibtexContext, Collections.emptyList(), preferences);
@@ -268,7 +267,7 @@ public class BibtexDatabaseWriterTest {
public void roundtrip() throws Exception {
Path testBibtexFile = Paths.get("src/test/resources/testbib/complex.bib");
Charset encoding = StandardCharsets.UTF_8;
- ParserResult result = BibtexParser.parse(ImportFormat.getReader(testBibtexFile, encoding),
+ ParserResult result = BibtexParser.parse(Importer.getReader(testBibtexFile, encoding),
importFormatPreferences);
SavePreferences preferences = new SavePreferences().withEncoding(encoding).withSaveInOriginalOrder(true);
@@ -285,7 +284,7 @@ public class BibtexDatabaseWriterTest {
public void roundtripWithUserComment() throws Exception {
Path testBibtexFile = Paths.get("src/test/resources/testbib/bibWithUserComments.bib");
Charset encoding = StandardCharsets.UTF_8;
- ParserResult result = BibtexParser.parse(ImportFormat.getReader(testBibtexFile, encoding),
+ ParserResult result = BibtexParser.parse(Importer.getReader(testBibtexFile, encoding),
importFormatPreferences);
SavePreferences preferences = new SavePreferences().withEncoding(encoding).withSaveInOriginalOrder(true);
@@ -302,7 +301,7 @@ public class BibtexDatabaseWriterTest {
public void roundtripWithUserCommentAndEntryChange() throws Exception {
Path testBibtexFile = Paths.get("src/test/resources/testbib/bibWithUserComments.bib");
Charset encoding = StandardCharsets.UTF_8;
- ParserResult result = BibtexParser.parse(ImportFormat.getReader(testBibtexFile, encoding),
+ ParserResult result = BibtexParser.parse(Importer.getReader(testBibtexFile, encoding),
importFormatPreferences);
BibEntry entry = result.getDatabase().getEntryByKey("1137631").get();
@@ -323,7 +322,7 @@ public class BibtexDatabaseWriterTest {
public void roundtripWithUserCommentBeforeStringAndChange() throws Exception {
Path testBibtexFile = Paths.get("src/test/resources/testbib/complex.bib");
Charset encoding = StandardCharsets.UTF_8;
- ParserResult result = BibtexParser.parse(ImportFormat.getReader(testBibtexFile, encoding),
+ ParserResult result = BibtexParser.parse(Importer.getReader(testBibtexFile, encoding),
importFormatPreferences);
for (BibtexString string : result.getDatabase().getStringValues()) {
@@ -429,10 +428,10 @@ public class BibtexDatabaseWriterTest {
@Test
public void writeCustomKeyPattern() throws Exception {
- AbstractBibtexKeyPattern pattern = new DatabaseBibtexKeyPattern(Globals.prefs.getKeyPattern());
+ AbstractBibtexKeyPattern pattern = new DatabaseBibtexKeyPattern(prefs.getKeyPattern());
pattern.setDefaultValue("test");
pattern.addBibtexKeyPattern("article", "articleTest");
- metaData.setBibtexKeyPattern(pattern);
+ metaData.setCiteKeyPattern(pattern);
StringSaveSession session = databaseWriter.savePartOfDatabase(bibtexContext, Collections.emptyList(), new SavePreferences());
@@ -462,16 +461,6 @@ public class BibtexDatabaseWriterTest {
}
@Test
- public void writeContentSelectors() throws Exception {
- metaData.setContentSelectors("title", Arrays.asList("testWord", "word2"));
-
- StringSaveSession session = databaseWriter.savePartOfDatabase(bibtexContext, Collections.emptyList(), new SavePreferences());
-
- assertEquals(OS.NEWLINE + "@Comment{jabref-meta: selector_title:testWord;word2;}" + OS.NEWLINE,
- session.getStringValue());
- }
-
- @Test
public void writeFileDirectories() throws Exception {
metaData.setDefaultFileDirectory("\\Literature\\");
metaData.setUserFileDirectory("defaultOwner-user", "D:\\Documents");
@@ -484,24 +473,6 @@ public class BibtexDatabaseWriterTest {
}
@Test
- public void writeNotEmptyContentSelectors() throws Exception {
- metaData.setContentSelectors("title", Collections.singletonList(""));
-
- StringSaveSession session = databaseWriter.savePartOfDatabase(bibtexContext, Collections.emptyList(), new SavePreferences());
-
- assertEquals("", session.getStringValue());
- }
-
- @Test
- public void writeNotCompletelyEmptyContentSelectors() throws Exception {
- metaData.setContentSelectors("title", Collections.emptyList());
-
- StringSaveSession session = databaseWriter.savePartOfDatabase(bibtexContext, Collections.emptyList(), new SavePreferences());
-
- assertEquals("", session.getStringValue());
- }
-
- @Test
public void writeEntriesSorted() throws Exception {
SaveOrderConfig saveOrderConfig = new SaveOrderConfig(false, new SaveOrderConfig.SortCriterion("author", false),
new SaveOrderConfig.SortCriterion("year", true),
diff --git a/src/test/java/net/sf/jabref/logic/exporter/ExportFormatTest.java b/src/test/java/net/sf/jabref/logic/exporter/ExportFormatTest.java
index 9a531b7..ff715e6 100644
--- a/src/test/java/net/sf/jabref/logic/exporter/ExportFormatTest.java
+++ b/src/test/java/net/sf/jabref/logic/exporter/ExportFormatTest.java
@@ -9,10 +9,9 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
-import net.sf.jabref.BibDatabaseContext;
-import net.sf.jabref.Globals;
import net.sf.jabref.logic.journals.JournalAbbreviationLoader;
import net.sf.jabref.logic.layout.LayoutFormatterPreferences;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.preferences.JabRefPreferences;
@@ -76,14 +75,14 @@ public class ExportFormatTest {
@Parameterized.Parameters(name = "{index}: {1}")
public static Collection<Object[]> exportFormats() {
Collection<Object[]> result = new ArrayList<>();
- Globals.prefs = JabRefPreferences.getInstance();
+ JabRefPreferences prefs = JabRefPreferences.getInstance();
JournalAbbreviationLoader journalAbbreviationLoader = new JournalAbbreviationLoader();
- Map<String, ExportFormat> customFormats = Globals.prefs.customExports.getCustomExportFormats(Globals.prefs,
+ Map<String, ExportFormat> customFormats = prefs.customExports.getCustomExportFormats(prefs,
journalAbbreviationLoader);
- LayoutFormatterPreferences layoutPreferences = LayoutFormatterPreferences.fromPreferences(Globals.prefs,
- journalAbbreviationLoader);
- SavePreferences savePreferences = SavePreferences.loadForExportFromPreferences(Globals.prefs);
+ LayoutFormatterPreferences layoutPreferences = prefs
+ .getLayoutFormatterPreferences(journalAbbreviationLoader);
+ SavePreferences savePreferences = SavePreferences.loadForExportFromPreferences(prefs);
ExportFormats.initAllExports(customFormats, layoutPreferences, savePreferences);
for (IExportFormat format : ExportFormats.getExportFormats().values()) {
diff --git a/src/test/java/net/sf/jabref/logic/exporter/FieldFormatterCleanupsTest.java b/src/test/java/net/sf/jabref/logic/exporter/FieldFormatterCleanupsTest.java
index a164cab..d2d9eb6 100644
--- a/src/test/java/net/sf/jabref/logic/exporter/FieldFormatterCleanupsTest.java
+++ b/src/test/java/net/sf/jabref/logic/exporter/FieldFormatterCleanupsTest.java
@@ -5,11 +5,13 @@ import java.util.Collections;
import java.util.List;
import java.util.Optional;
-import net.sf.jabref.logic.cleanup.FieldFormatterCleanup;
+import net.sf.jabref.logic.cleanup.Cleanups;
import net.sf.jabref.logic.formatter.IdentityFormatter;
import net.sf.jabref.logic.formatter.bibtexfields.NormalizeDateFormatter;
import net.sf.jabref.logic.formatter.bibtexfields.NormalizePagesFormatter;
import net.sf.jabref.logic.formatter.casechanger.LowerCaseFormatter;
+import net.sf.jabref.model.cleanup.FieldFormatterCleanup;
+import net.sf.jabref.model.cleanup.FieldFormatterCleanups;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.BibtexEntryTypes;
@@ -41,44 +43,44 @@ public class FieldFormatterCleanupsTest {
@Test
public void checkSimpleUseCase() {
- FieldFormatterCleanups actions = new FieldFormatterCleanups(true, "title[identity]");
+ FieldFormatterCleanups actions = new FieldFormatterCleanups(true, Cleanups.parse("title[identity]"));
FieldFormatterCleanup identityInTitle = new FieldFormatterCleanup("title", new IdentityFormatter());
assertEquals(Collections.singletonList(identityInTitle), actions.getConfiguredActions());
actions.applySaveActions(entry);
- assertEquals(Optional.of("Educational session 1"), entry.getFieldOptional("title"));
+ assertEquals(Optional.of("Educational session 1"), entry.getField("title"));
}
@Test
public void invalidSaveActionSting() {
- FieldFormatterCleanups actions = new FieldFormatterCleanups(true, "title");
+ FieldFormatterCleanups actions = new FieldFormatterCleanups(true, Cleanups.parse("title"));
assertEquals(Collections.emptyList(), actions.getConfiguredActions());
actions.applySaveActions(entry);
- assertEquals(Optional.of("Educational session 1"), entry.getFieldOptional("title"));
+ assertEquals(Optional.of("Educational session 1"), entry.getField("title"));
}
@Test
public void checkLowerCaseSaveAction() {
- FieldFormatterCleanups actions = new FieldFormatterCleanups(true, "title[lower_case]");
+ FieldFormatterCleanups actions = new FieldFormatterCleanups(true, Cleanups.parse("title[lower_case]"));
FieldFormatterCleanup lowerCaseTitle = new FieldFormatterCleanup("title", new LowerCaseFormatter());
assertEquals(Collections.singletonList(lowerCaseTitle), actions.getConfiguredActions());
actions.applySaveActions(entry);
- assertEquals(Optional.of("educational session 1"), entry.getFieldOptional("title"));
+ assertEquals(Optional.of("educational session 1"), entry.getField("title"));
}
@Test
public void checkTwoSaveActionsForOneField() {
- FieldFormatterCleanups actions = new FieldFormatterCleanups(true, "title[lower_case,identity]");
+ FieldFormatterCleanups actions = new FieldFormatterCleanups(true, Cleanups.parse("title[lower_case,identity]"));
FieldFormatterCleanup lowerCaseTitle = new FieldFormatterCleanup("title", new LowerCaseFormatter());
FieldFormatterCleanup identityInTitle = new FieldFormatterCleanup("title", new IdentityFormatter());
@@ -86,13 +88,13 @@ public class FieldFormatterCleanupsTest {
actions.applySaveActions(entry);
- assertEquals(Optional.of("educational session 1"), entry.getFieldOptional("title"));
+ assertEquals(Optional.of("educational session 1"), entry.getField("title"));
}
@Test
public void checkThreeSaveActionsForOneField() {
- FieldFormatterCleanups actions = new FieldFormatterCleanups(true, "title[lower_case,identity,normalize_date]");
+ FieldFormatterCleanups actions = new FieldFormatterCleanups(true, Cleanups.parse("title[lower_case,identity,normalize_date]"));
FieldFormatterCleanup lowerCaseTitle = new FieldFormatterCleanup("title", new LowerCaseFormatter());
FieldFormatterCleanup identityInTitle = new FieldFormatterCleanup("title", new IdentityFormatter());
@@ -101,13 +103,13 @@ public class FieldFormatterCleanupsTest {
actions.applySaveActions(entry);
- assertEquals(Optional.of("educational session 1"), entry.getFieldOptional("title"));
+ assertEquals(Optional.of("educational session 1"), entry.getField("title"));
}
@Test
public void checkMultipleSaveActions() {
- FieldFormatterCleanups actions = new FieldFormatterCleanups(true, "pages[normalize_page_numbers]title[lower_case]");
+ FieldFormatterCleanups actions = new FieldFormatterCleanups(true, Cleanups.parse("pages[normalize_page_numbers]title[lower_case]"));
List<FieldFormatterCleanup> formatterCleanups = actions.getConfiguredActions();
FieldFormatterCleanup normalizePages = new FieldFormatterCleanup("pages", new NormalizePagesFormatter());
@@ -116,15 +118,15 @@ public class FieldFormatterCleanupsTest {
actions.applySaveActions(entry);
- assertEquals(Optional.of("educational session 1"), entry.getFieldOptional("title"));
- assertEquals(Optional.of("1--7"), entry.getFieldOptional("pages"));
+ assertEquals(Optional.of("educational session 1"), entry.getField("title"));
+ assertEquals(Optional.of("1--7"), entry.getField("pages"));
}
@Test
public void checkMultipleSaveActionsWithMultipleFormatters() {
FieldFormatterCleanups actions = new FieldFormatterCleanups(true,
- "pages[normalize_page_numbers,normalize_date]title[lower_case]");
+ Cleanups.parse("pages[normalize_page_numbers,normalize_date]title[lower_case]"));
List<FieldFormatterCleanup> formatterCleanups = actions.getConfiguredActions();
FieldFormatterCleanup normalizePages = new FieldFormatterCleanup("pages", new NormalizePagesFormatter());
@@ -134,15 +136,15 @@ public class FieldFormatterCleanupsTest {
actions.applySaveActions(entry);
- assertEquals(Optional.of("educational session 1"), entry.getFieldOptional("title"));
- assertEquals(Optional.of("1--7"), entry.getFieldOptional("pages"));
+ assertEquals(Optional.of("educational session 1"), entry.getField("title"));
+ assertEquals(Optional.of("1--7"), entry.getField("pages"));
}
@Test
public void clearFormatterRemovesField() {
- FieldFormatterCleanups actions = new FieldFormatterCleanups(true, "mont[clear]");
+ FieldFormatterCleanups actions = new FieldFormatterCleanups(true, Cleanups.parse("mont[clear]"));
actions.applySaveActions(entry);
- assertEquals(Optional.empty(), entry.getFieldOptional("mont"));
+ assertEquals(Optional.empty(), entry.getField("mont"));
}
}
diff --git a/src/test/java/net/sf/jabref/logic/exporter/HtmlExportFormatTest.java b/src/test/java/net/sf/jabref/logic/exporter/HtmlExportFormatTest.java
index 3e56fc5..e2182f4 100644
--- a/src/test/java/net/sf/jabref/logic/exporter/HtmlExportFormatTest.java
+++ b/src/test/java/net/sf/jabref/logic/exporter/HtmlExportFormatTest.java
@@ -7,10 +7,9 @@ import java.util.Arrays;
import java.util.List;
import java.util.Map;
-import net.sf.jabref.BibDatabaseContext;
-import net.sf.jabref.Globals;
import net.sf.jabref.logic.journals.JournalAbbreviationLoader;
import net.sf.jabref.logic.layout.LayoutFormatterPreferences;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.preferences.JabRefPreferences;
@@ -34,13 +33,12 @@ public class HtmlExportFormatTest {
@Before
public void setUp() {
- Globals.prefs = JabRefPreferences.getInstance();
+ JabRefPreferences prefs = JabRefPreferences.getInstance();
JournalAbbreviationLoader journalAbbreviationLoader = new JournalAbbreviationLoader();
- Map<String, ExportFormat> customFormats = Globals.prefs.customExports.getCustomExportFormats(Globals.prefs,
+ Map<String, ExportFormat> customFormats = prefs.customExports.getCustomExportFormats(prefs,
journalAbbreviationLoader);
- LayoutFormatterPreferences layoutPreferences = LayoutFormatterPreferences.fromPreferences(Globals.prefs,
- journalAbbreviationLoader);
- SavePreferences savePreferences = SavePreferences.loadForExportFromPreferences(Globals.prefs);
+ LayoutFormatterPreferences layoutPreferences = prefs.getLayoutFormatterPreferences(journalAbbreviationLoader);
+ SavePreferences savePreferences = SavePreferences.loadForExportFromPreferences(prefs);
ExportFormats.initAllExports(customFormats, layoutPreferences, savePreferences);
exportFormat = ExportFormats.getExportFormat("html");
diff --git a/src/test/java/net/sf/jabref/logic/exporter/MSBibExportFormatTestFiles.java b/src/test/java/net/sf/jabref/logic/exporter/MSBibExportFormatTestFiles.java
index 911b01a..e6e2609 100644
--- a/src/test/java/net/sf/jabref/logic/exporter/MSBibExportFormatTestFiles.java
+++ b/src/test/java/net/sf/jabref/logic/exporter/MSBibExportFormatTestFiles.java
@@ -9,14 +9,12 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collection;
-import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
-import net.sf.jabref.BibDatabaseContext;
-import net.sf.jabref.logic.importer.ImportFormatPreferences;
import net.sf.jabref.logic.importer.fileformat.BibtexImporter;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.preferences.JabRefPreferences;
@@ -28,8 +26,13 @@ import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
+import org.xmlunit.builder.Input;
+import org.xmlunit.builder.Input.Builder;
+import org.xmlunit.diff.DefaultNodeMatcher;
+import org.xmlunit.diff.ElementSelectors;
+import org.xmlunit.matchers.CompareMatcher;
-import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
@RunWith(Parameterized.class)
public class MSBibExportFormatTestFiles {
@@ -63,7 +66,7 @@ public class MSBibExportFormatTestFiles {
charset = StandardCharsets.UTF_8;
msBibExportFormat = new MSBibExportFormat();
tempFile = testFolder.newFile();
- testImporter = new BibtexImporter(ImportFormatPreferences.fromPreferences(JabRefPreferences.getInstance()));
+ testImporter = new BibtexImporter(JabRefPreferences.getInstance().getImportFormatPreferences());
}
@Test
@@ -71,15 +74,16 @@ public class MSBibExportFormatTestFiles {
String xmlFileName = filename.replace(".bib", ".xml");
Path importFile = resourceDir.resolve(filename);
String tempFilename = tempFile.getCanonicalPath();
+
List<BibEntry> entries = testImporter.importDatabase(importFile, StandardCharsets.UTF_8).getDatabase()
.getEntries();
msBibExportFormat.performExport(databaseContext, tempFile.getPath(), charset, entries);
- List<String> expected = Files.readAllLines(resourceDir.resolve(xmlFileName));
- List<String> exported = Files.readAllLines(Paths.get(tempFilename));
- Collections.sort(expected);
- Collections.sort(exported);
- assertEquals(expected, exported);
+ Builder control = Input.from(Files.newInputStream(resourceDir.resolve(xmlFileName)));
+ Builder test = Input.from(Files.newInputStream(Paths.get(tempFilename)));
+
+ assertThat(test, CompareMatcher.isSimilarTo(control)
+ .withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.byNameAndText)).throwComparisonFailure());
}
}
diff --git a/src/test/java/net/sf/jabref/logic/exporter/ModsExportFormatTest.java b/src/test/java/net/sf/jabref/logic/exporter/ModsExportFormatTest.java
new file mode 100644
index 0000000..edb87a9
--- /dev/null
+++ b/src/test/java/net/sf/jabref/logic/exporter/ModsExportFormatTest.java
@@ -0,0 +1,61 @@
+package net.sf.jabref.logic.exporter;
+
+import java.io.File;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Collections;
+import java.util.List;
+
+import net.sf.jabref.logic.importer.fileformat.BibtexImporter;
+import net.sf.jabref.model.database.BibDatabaseContext;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.preferences.JabRefPreferences;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+
+public class ModsExportFormatTest {
+
+ public Charset charset;
+ private ModsExportFormat modsExportFormat;
+ private BibDatabaseContext databaseContext;
+ private BibtexImporter bibtexImporter;
+ private File tempFile;
+
+ @Rule
+ public TemporaryFolder testFolder = new TemporaryFolder();
+ private Path importFile;
+
+
+ @Before
+ public void setUp() throws Exception {
+ databaseContext = new BibDatabaseContext();
+ charset = StandardCharsets.UTF_8;
+ modsExportFormat = new ModsExportFormat();
+ bibtexImporter = new BibtexImporter(JabRefPreferences.getInstance().getImportFormatPreferences());
+ tempFile = testFolder.newFile();
+ importFile = Paths.get(ModsExportFormatTest.class.getResource("ModsExportFormatTestAllFields.bib").toURI());
+ }
+
+ @Test(expected = SaveException.class)
+ public final void testPerformExportTrowsSaveException() throws Exception {
+ List<BibEntry> entries = bibtexImporter.importDatabase(importFile, charset).getDatabase()
+ .getEntries();
+
+ modsExportFormat.performExport(databaseContext, "", charset, entries);
+ }
+
+ @Test
+ public final void testPerformExportEmptyEntry() throws Exception {
+ String canonicalPath = tempFile.getCanonicalPath();
+ modsExportFormat.performExport(databaseContext, canonicalPath, charset, Collections.emptyList());
+ Assert.assertEquals(Collections.emptyList(), Files.readAllLines(Paths.get(canonicalPath)));
+ }
+}
diff --git a/src/test/java/net/sf/jabref/logic/exporter/ModsExportFormatTestFiles.java b/src/test/java/net/sf/jabref/logic/exporter/ModsExportFormatTestFiles.java
new file mode 100644
index 0000000..9ef9282
--- /dev/null
+++ b/src/test/java/net/sf/jabref/logic/exporter/ModsExportFormatTestFiles.java
@@ -0,0 +1,116 @@
+package net.sf.jabref.logic.exporter;
+
+import java.io.File;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import net.sf.jabref.logic.bibtex.BibEntryAssert;
+import net.sf.jabref.logic.importer.fileformat.BibtexImporter;
+import net.sf.jabref.logic.importer.fileformat.ModsImporter;
+import net.sf.jabref.model.database.BibDatabaseContext;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.preferences.JabRefPreferences;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+import org.xmlunit.builder.Input;
+import org.xmlunit.builder.Input.Builder;
+import org.xmlunit.diff.DefaultNodeMatcher;
+import org.xmlunit.diff.ElementSelectors;
+import org.xmlunit.matchers.CompareMatcher;
+
+ at RunWith(Parameterized.class)
+public class ModsExportFormatTestFiles {
+
+ public Charset charset;
+ private BibDatabaseContext databaseContext;
+ private File tempFile;
+ private ModsExportFormat modsExportFormat;
+ private BibtexImporter bibtexImporter;
+ private ModsImporter modsImporter;
+ private Path importFile;
+
+
+ @Parameter
+ public String filename;
+
+ @Rule
+ public TemporaryFolder testFolder = new TemporaryFolder();
+
+
+ @Parameters(name = "{0}")
+ public static Collection<String> fileNames() throws Exception {
+ try (Stream<Path> stream = Files.list(Paths.get(ModsExportFormatTestFiles.class.getResource("").toURI()))) {
+ // stream.forEach(n -> System.out.println(n));
+ return stream.map(n -> n.getFileName().toString()).filter(n -> n.endsWith(".bib"))
+ .filter(n -> n.startsWith("Mods")).collect(Collectors.toList());
+ }
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ databaseContext = new BibDatabaseContext();
+ importFile = Paths.get(ModsExportFormatTestFiles.class.getResource(filename).toURI());
+ charset = StandardCharsets.UTF_8;
+ modsExportFormat = new ModsExportFormat();
+ tempFile = testFolder.newFile();
+ bibtexImporter = new BibtexImporter(JabRefPreferences.getInstance().getImportFormatPreferences());
+ modsImporter = new ModsImporter();
+ }
+
+ @Test
+ public final void testPerformExport() throws Exception {
+ String xmlFileName = filename.replace(".bib", ".xml");
+ String tempFilename = tempFile.getCanonicalPath();
+ List<BibEntry> entries = bibtexImporter.importDatabase(importFile, charset).getDatabase().getEntries();
+ Path xmlFile = Paths.get(ModsExportFormatTestFiles.class.getResource(xmlFileName).toURI());
+
+ modsExportFormat.performExport(databaseContext, tempFile.getPath(), charset, entries);
+
+ Builder control = Input.from(Files.newInputStream(xmlFile));
+ Builder test = Input.from(Files.newInputStream(Paths.get(tempFilename)));
+
+ Assert.assertThat(test, CompareMatcher.isSimilarTo(control)
+ .withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.byNameAndText)).throwComparisonFailure());
+ }
+
+ @Test
+ public final void testExportAsModsAndThenImportAsMods() throws Exception {
+ List<BibEntry> entries = bibtexImporter.importDatabase(importFile, charset).getDatabase().getEntries();
+
+ modsExportFormat.performExport(databaseContext, tempFile.getPath(), charset, entries);
+ BibEntryAssert.assertEquals(entries, Paths.get(tempFile.getPath()), modsImporter);
+ }
+
+ @Test
+ public final void testImportAsModsAndExportAsMods() throws Exception {
+ String xmlFileName = filename.replace(".bib", ".xml");
+ String tempFilename = tempFile.getCanonicalPath();
+ Path xmlFile = Paths.get(ModsExportFormatTestFiles.class.getResource(xmlFileName).toURI());
+
+ List<BibEntry> entries = modsImporter.importDatabase(xmlFile, charset).getDatabase().getEntries();
+
+ modsExportFormat.performExport(databaseContext, tempFile.getPath(), charset, entries);
+
+ Builder control = Input.from(Files.newInputStream(xmlFile));
+ Builder test = Input.from(Files.newInputStream(Paths.get(tempFilename)));
+
+ Assert.assertThat(test, CompareMatcher.isSimilarTo(control)
+ .withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.byNameAndText)).throwComparisonFailure());
+ }
+
+}
diff --git a/src/test/java/net/sf/jabref/logic/exporter/MsBibExportFormatTest.java b/src/test/java/net/sf/jabref/logic/exporter/MsBibExportFormatTest.java
index 43da39f..5550d75 100644
--- a/src/test/java/net/sf/jabref/logic/exporter/MsBibExportFormatTest.java
+++ b/src/test/java/net/sf/jabref/logic/exporter/MsBibExportFormatTest.java
@@ -7,7 +7,7 @@ import java.nio.file.Files;
import java.util.Collections;
import java.util.List;
-import net.sf.jabref.BibDatabaseContext;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.entry.BibEntry;
import com.google.common.base.Charsets;
diff --git a/src/test/java/net/sf/jabref/logic/formatter/FormatterTest.java b/src/test/java/net/sf/jabref/logic/formatter/FormatterTest.java
index 7704855..0737f26 100644
--- a/src/test/java/net/sf/jabref/logic/formatter/FormatterTest.java
+++ b/src/test/java/net/sf/jabref/logic/formatter/FormatterTest.java
@@ -26,6 +26,7 @@ import net.sf.jabref.logic.formatter.minifier.MinifyNameListFormatter;
import net.sf.jabref.logic.layout.format.LatexToUnicodeFormatter;
import net.sf.jabref.logic.protectedterms.ProtectedTermsLoader;
import net.sf.jabref.logic.protectedterms.ProtectedTermsPreferences;
+import net.sf.jabref.model.cleanup.Formatter;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -102,7 +103,7 @@ public class FormatterTest {
@Parameterized.Parameters(name = "{index}: {0}")
public static Collection<Object[]> instancesToTest() {
- // all classes implementing {@link net.sf.jabref.logic.formatter.Formatter}
+ // all classes implementing {@link net.sf.jabref.model.cleanup.Formatter}
// sorted alphabetically
// Alternative: Use reflection - https://github.com/ronmamo/reflections
// @formatter:off
@@ -131,4 +132,4 @@ public class FormatterTest {
);
// @formatter:on
}
-}
\ No newline at end of file
+}
diff --git a/src/test/java/net/sf/jabref/logic/formatter/bibtexfields/NormalizeNamesFormatterTest.java b/src/test/java/net/sf/jabref/logic/formatter/bibtexfields/NormalizeNamesFormatterTest.java
index 316578e..536a0d1 100644
--- a/src/test/java/net/sf/jabref/logic/formatter/bibtexfields/NormalizeNamesFormatterTest.java
+++ b/src/test/java/net/sf/jabref/logic/formatter/bibtexfields/NormalizeNamesFormatterTest.java
@@ -1,6 +1,5 @@
package net.sf.jabref.logic.formatter.bibtexfields;
-import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
@@ -20,91 +19,160 @@ public class NormalizeNamesFormatterTest {
@Test
public void testNormalizeAuthorList() {
- expectCorrect("Staci D Bilbo", "Bilbo, Staci D.");
- expectCorrect("Staci D. Bilbo", "Bilbo, Staci D.");
+ assertEquals("Bilbo, Staci D.", formatter.format("Staci D Bilbo"));
+ assertEquals("Bilbo, Staci D.", formatter.format("Staci D. Bilbo"));
- expectCorrect("Staci D Bilbo and Smith SH and Jaclyn M Schwarz", "Bilbo, Staci D. and Smith, S. H. and Schwarz, Jaclyn M.");
+ assertEquals("Bilbo, Staci D. and Smith, S. H. and Schwarz, Jaclyn M.", formatter.format("Staci D Bilbo and Smith SH and Jaclyn M Schwarz"));
- expectCorrect("Ølver MA", "Ølver, M. A.");
+ assertEquals("Ølver, M. A.", formatter.format("Ølver MA"));
- expectCorrect("Ølver MA; GG Øie; Øie GG; Alfredsen JÅÅ; Jo Alfredsen; Olsen Y.Y. and Olsen YY.",
- "Ølver, M. A. and Øie, G. G. and Øie, G. G. and Alfredsen, J. Å. Å. and Alfredsen, Jo and Olsen, Y. Y. and Olsen, Y. Y.");
+ assertEquals("Ølver, M. A. and Øie, G. G. and Øie, G. G. and Alfredsen, J. Å. Å. and Alfredsen, Jo and Olsen, Y. Y. and Olsen, Y. Y.",
+ formatter.format("Ølver MA; GG Øie; Øie GG; Alfredsen JÅÅ; Jo Alfredsen; Olsen Y.Y. and Olsen YY."));
- expectCorrect("Ølver MA; GG Øie; Øie GG; Alfredsen JÅÅ; Jo Alfredsen; Olsen Y.Y.; Olsen YY.",
- "Ølver, M. A. and Øie, G. G. and Øie, G. G. and Alfredsen, J. Å. Å. and Alfredsen, Jo and Olsen, Y. Y. and Olsen, Y. Y.");
+ assertEquals("Ølver, M. A. and Øie, G. G. and Øie, G. G. and Alfredsen, J. Å. Å. and Alfredsen, Jo and Olsen, Y. Y. and Olsen, Y. Y.",
+ formatter.format("Ølver MA; GG Øie; Øie GG; Alfredsen JÅÅ; Jo Alfredsen; Olsen Y.Y.; Olsen YY."));
- expectCorrect("Alver, Morten and Alver, Morten O and Alfredsen, JA and Olsen, Y.Y.", "Alver, Morten and Alver, Morten O. and Alfredsen, J. A. and Olsen, Y. Y.");
+ assertEquals("Alver, Morten and Alver, Morten O. and Alfredsen, J. A. and Olsen, Y. Y.", formatter.format("Alver, Morten and Alver, Morten O and Alfredsen, JA and Olsen, Y.Y."));
- expectCorrect("Alver, MA; Alfredsen, JA; Olsen Y.Y.", "Alver, M. A. and Alfredsen, J. A. and Olsen, Y. Y.");
+ assertEquals("Alver, M. A. and Alfredsen, J. A. and Olsen, Y. Y.", formatter.format("Alver, MA; Alfredsen, JA; Olsen Y.Y."));
- expectCorrect("Kolb, Stefan and J{\\\"o}rg Lenhard and Wirtz, Guido", "Kolb, Stefan and Lenhard, J{\\\"o}rg and Wirtz, Guido");
+ assertEquals("Kolb, Stefan and Lenhard, J{\\\"o}rg and Wirtz, Guido", formatter.format("Kolb, Stefan and J{\\\"o}rg Lenhard and Wirtz, Guido"));
}
@Test
public void twoAuthorsSeperatedByColon() {
- expectCorrect("Staci Bilbo; Morten Alver", "Bilbo, Staci and Alver, Morten");
+ assertEquals("Bilbo, Staci and Alver, Morten", formatter.format("Staci Bilbo; Morten Alver"));
}
@Test
public void threeAuthorsSeperatedByColon() {
- expectCorrect("Staci Bilbo; Morten Alver; Test Name", "Bilbo, Staci and Alver, Morten and Name, Test");
+ assertEquals("Bilbo, Staci and Alver, Morten and Name, Test", formatter.format("Staci Bilbo; Morten Alver; Test Name"));
}
// Test for https://github.com/JabRef/jabref/issues/318
@Test
public void threeAuthorsSeperatedByAnd() {
- expectCorrect("Stefan Kolb and J{\\\"o}rg Lenhard and Guido Wirtz", "Kolb, Stefan and Lenhard, J{\\\"o}rg and Wirtz, Guido");
+ assertEquals("Kolb, Stefan and Lenhard, J{\\\"o}rg and Wirtz, Guido", formatter.format("Stefan Kolb and J{\\\"o}rg Lenhard and Guido Wirtz"));
}
// Test for https://github.com/JabRef/jabref/issues/318
@Test
public void threeAuthorsSeperatedByAndWithDash() {
- expectCorrect("Heng-Yu Jian and Xu, Z. and Chang, M.-C.F.", "Jian, Heng-Yu and Xu, Z. and Chang, M.-C. F.");
+ assertEquals("Jian, Heng-Yu and Xu, Z. and Chang, M.-C. F.", formatter.format("Heng-Yu Jian and Xu, Z. and Chang, M.-C.F."));
}
// Test for https://github.com/JabRef/jabref/issues/318
@Test
public void threeAuthorsSeperatedByAndWithLatex() {
- expectCorrect("Oscar Gustafsson and Linda S. DeBrunner and Victor DeBrunner and H{\\aa}kan Johansson", "Gustafsson, Oscar and DeBrunner, Linda S. and DeBrunner, Victor and Johansson, H{\\aa}kan");
+ assertEquals("Gustafsson, Oscar and DeBrunner, Linda S. and DeBrunner, Victor and Johansson, H{\\aa}kan",
+ formatter.format("Oscar Gustafsson and Linda S. DeBrunner and Victor DeBrunner and H{\\aa}kan Johansson"));
}
@Test
public void lastThenInitial() {
- expectCorrect("Smith S", "Smith, S.");
+ assertEquals("Smith, S.", formatter.format("Smith S"));
}
@Test
public void lastThenInitials() {
- expectCorrect("Smith SH", "Smith, S. H.");
+ assertEquals("Smith, S. H.", formatter.format("Smith SH"));
}
@Test
public void initialThenLast() {
- expectCorrect("S Smith", "Smith, S.");
+ assertEquals("Smith, S.", formatter.format("S Smith"));
}
@Test
public void initialDotThenLast() {
- expectCorrect("S. Smith", "Smith, S.");
+ assertEquals("Smith, S.", formatter.format("S. Smith"));
}
@Test
public void initialsThenLast() {
- expectCorrect("SH Smith", "Smith, S. H.");
+ assertEquals("Smith, S. H.", formatter.format("SH Smith"));
}
@Test
public void lastThenJuniorThenFirst() {
- expectCorrect("Name, della, first", "Name, della, first");
+ assertEquals("Name, della, first", formatter.format("Name, della, first"));
}
- private void expectCorrect(String input, String expected) {
- Assert.assertEquals(expected, formatter.format(input));
+ @Test
+ public void testConcatenationOfAuthorsWithCommas() {
+ assertEquals("Ali Babar, M. and Dingsøyr, T. and Lago, P. and van der Vliet, H.", formatter.format("Ali Babar, M., Dingsøyr, T., Lago, P., van der Vliet, H."));
+ assertEquals("Ali Babar, M.", formatter.format("Ali Babar, M."));
+ }
+
+ @Test
+ public void testOddCountOfCommas() {
+ assertEquals("Ali Babar, M., Dingsøyr T. Lago P.", formatter.format("Ali Babar, M., Dingsøyr, T., Lago P."));
}
@Test
public void formatExample() {
- assertEquals("Einstein, Albert and Turing, Alan", formatter.format(formatter.getExampleInput()));
+ assertEquals(formatter.format(formatter.getExampleInput()), "Einstein, Albert and Turing, Alan");
+ }
+
+ @Test
+ public void testNameAffixe() {
+ assertEquals("Surname, jr, First and Surname2, First2", formatter.format("Surname, jr, First, Surname2, First2"));
+ }
+
+ @Test
+ public void testAvoidSpecialCharacter() {
+ assertEquals("Surname, {, First; Surname2, First2", formatter.format("Surname, {, First; Surname2, First2"));
+ }
+
+ @Test
+ public void testAndInName() {
+ assertEquals("Surname and , First, Surname2 First2", formatter.format("Surname, and , First, Surname2, First2"));
+ }
+
+ @Test
+ public void testMultipleNameAffixes() {
+ assertEquals("Mair, Jr, Daniel and Brühl, Sr, Daniel", formatter.format("Mair, Jr, Daniel, Brühl, Sr, Daniel"));
+ }
+
+ @Test
+ public void testCommaSeperatedNames() {
+ assertEquals("Bosoi, Cristina and Oliveira, Mariana and Sanchez, Rafael Ochoa and Tremblay, Mélanie and TenHave, Gabrie and Deutz, Nicoolas and Rose, Christopher F. and Bemeur, Chantal",
+ formatter.format("Cristina Bosoi, Mariana Oliveira, Rafael Ochoa Sanchez, Mélanie Tremblay, Gabrie TenHave, Nicoolas Deutz, Christopher F. Rose, Chantal Bemeur"));
+ }
+
+ @Test
+ public void testMultipleSpaces() {
+ assertEquals("Bosoi, Cristina and Oliveira, Mariana and Sanchez, Rafael Ochoa and Tremblay, Mélanie and TenHave, Gabrie and Deutz, Nicoolas and Rose, Christopher F. and Bemeur, Chantal",
+ formatter.format("Cristina Bosoi, Mariana Oliveira, Rafael Ochoa Sanchez , Mélanie Tremblay , Gabrie TenHave, Nicoolas Deutz, Christopher F. Rose, Chantal Bemeur"));
+ }
+
+ @Test
+ public void testAvoidPreposition() {
+ assertEquals("von Zimmer, Hans and van Oberbergern, Michael and zu Berger, Kevin", formatter.format("Hans von Zimmer, Michael van Oberbergern, Kevin zu Berger"));
+ }
+
+ @Test
+ public void testPreposition() {
+ assertEquals("von Zimmer, Hans and van Oberbergern, Michael and zu Berger, Kevin", formatter.format("Hans von Zimmer, Michael van Oberbergern, Kevin zu Berger"));
}
+ @Test
+ public void testAvoidNameAffixes() {
+ assertEquals("der Barbar, Canon and der Große, Alexander", formatter.format("Canon der Barbar, Alexander der Große"));
+ }
+
+ @Test
+ public void testUpperCaseSensitiveList() {
+ assertEquals("der Barbar, Canon and der Große, Alexander", formatter.format("Canon der Barbar AND Alexander der Große"));
+ assertEquals("der Barbar, Canon and der Große, Alexander", formatter.format("Canon der Barbar aNd Alexander der Große"));
+ assertEquals("der Barbar, Canon and der Große, Alexander", formatter.format("Canon der Barbar AnD Alexander der Große"));
+ }
+
+ @Test
+ public void testSemiCorrectNamesWithSemicolon() {
+ assertEquals("Last, First and Last2, First2 and Last3, First3", formatter.format("Last, First; Last2, First2; Last3, First3"));
+ assertEquals("Last, Jr, First and Last2, First2", formatter.format("Last, Jr, First; Last2, First2"));
+ assertEquals("Last, First and Last2, First2 and Last3, First3 and Last4, First4", formatter.format("Last, First; Last2, First2; Last3, First3; First4 Last4"));
+ assertEquals("Last and Last2, First2 and Last3, First3 and Last4, First4", formatter.format("Last; Last2, First2; Last3, First3; Last4, First4"));
+ }
}
\ No newline at end of file
diff --git a/src/test/java/net/sf/jabref/logic/formatter/casechanger/TitleCaseFormatterTest.java b/src/test/java/net/sf/jabref/logic/formatter/casechanger/TitleCaseFormatterTest.java
index d500d46..215ba24 100644
--- a/src/test/java/net/sf/jabref/logic/formatter/casechanger/TitleCaseFormatterTest.java
+++ b/src/test/java/net/sf/jabref/logic/formatter/casechanger/TitleCaseFormatterTest.java
@@ -17,21 +17,71 @@ public class TitleCaseFormatterTest {
}
@Test
- public void test() {
+ public void eachFirstLetterIsUppercased() {
Assert.assertEquals("Upper Each First", formatter.format("upper each first"));
+ }
+
+ @Test
+ public void eachFirstLetterIsUppercasedAndOthersLowercased() {
+ Assert.assertEquals("Upper Each First", formatter.format("upper eACH first"));
+ }
+
+ @Test
+ public void eachFirstLetterIsUppercasedAndATralingAndIsAlsoUppercased() {
Assert.assertEquals("An Upper Each First And", formatter.format("an upper each first and"));
+ }
+
+ @Test
+ public void eachFirstLetterIsUppercasedAndATralingAndIsAlsoCorrectlyCased() {
+ Assert.assertEquals("An Upper Each First And", formatter.format("an upper each first AND"));
+ }
+
+ @Test
+ public void eachFirstLetterIsUppercasedButIntermediateAndsAreKeptLowercase(){
Assert.assertEquals("An Upper Each of the and First And",
formatter.format("an upper each of the and first and"));
+ }
+
+ @Test
+ public void eachFirstLetterIsUppercasedButIntermediateAndsArePutLowercase(){
+ Assert.assertEquals("An Upper Each of the and First And",
+ formatter.format("an upper each of the AND first and"));
+ }
+
+ @Test
+ public void theAfterColonGetsCapitalized() {
Assert.assertEquals("An Upper Each of: The and First And",
formatter.format("an upper each of: the and first and"));
+ }
+
+ @Test
+ public void completeWordsInCurlyBracketsIsLeftUnchanged() {
Assert.assertEquals("An Upper First with and without {CURLY} {brackets}",
formatter.format("AN UPPER FIRST WITH AND WITHOUT {CURLY} {brackets}"));
+ }
+
+ @Test
+ public void lettersInCurlyBracketsIsLeftUnchanged() {
Assert.assertEquals("An Upper First with {A}nd without {C}urly {b}rackets",
formatter.format("AN UPPER FIRST WITH {A}ND WITHOUT {C}URLY {b}rackets"));
}
@Test
+ public void intraWordLettersInCurlyBracketsIsLeftUnchanged() {
+ Assert.assertEquals("{b}rackets {b}rac{K}ets Brack{E}ts",
+ formatter.format("{b}RaCKeTS {b}RaC{K}eTS bRaCK{E}ts"));
+ }
+
+ @Test
+ public void testTwoExperiencesTitle() {
+ Assert.assertEquals(
+ "Two Experiences Designing for Effective Security",
+ formatter.format("Two experiences designing for effective security"));
+ }
+
+ @Test
public void formatExample() {
Assert.assertEquals("{BPMN} Conformance in Open Source Engines", formatter.format(formatter.getExampleInput()));
}
+
}
diff --git a/src/test/java/net/sf/jabref/logic/groups/AbstractGroupTest.java b/src/test/java/net/sf/jabref/logic/groups/AbstractGroupTest.java
deleted file mode 100644
index 7d69d0c..0000000
--- a/src/test/java/net/sf/jabref/logic/groups/AbstractGroupTest.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package net.sf.jabref.logic.groups;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import net.sf.jabref.model.entry.BibEntry;
-
-import org.junit.Before;
-import org.mockito.Mockito;
-
-import static org.mockito.Mockito.mock;
-
-public class AbstractGroupTest {
-
- private AbstractGroup group;
- private List<BibEntry> entries = new ArrayList<>();
-
- @Before
- public void setUp() throws Exception {
- group = mock(AbstractGroup.class, Mockito.CALLS_REAL_METHODS);
-
- entries.add(new BibEntry().withField("author", "author1 and author2"));
- entries.add(new BibEntry().withField("author", "author1"));
- }
-}
diff --git a/src/test/java/net/sf/jabref/logic/groups/AllEntriesGroupTest.java b/src/test/java/net/sf/jabref/logic/groups/AllEntriesGroupTest.java
deleted file mode 100644
index 0d4eedc..0000000
--- a/src/test/java/net/sf/jabref/logic/groups/AllEntriesGroupTest.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package net.sf.jabref.logic.groups;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-
-public class AllEntriesGroupTest {
-
- @Test
- public void testToString() {
- assertEquals("AllEntriesGroup:", new AllEntriesGroup().toString());
- }
-
-}
\ No newline at end of file
diff --git a/src/test/java/net/sf/jabref/logic/groups/ExplicitGroupTest.java b/src/test/java/net/sf/jabref/logic/groups/ExplicitGroupTest.java
deleted file mode 100644
index ba72d90..0000000
--- a/src/test/java/net/sf/jabref/logic/groups/ExplicitGroupTest.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package net.sf.jabref.logic.groups;
-
-import net.sf.jabref.logic.importer.util.ParseException;
-import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.model.entry.BibtexEntryTypes;
-import net.sf.jabref.model.entry.IdGenerator;
-import net.sf.jabref.preferences.JabRefPreferences;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-
-public class ExplicitGroupTest {
-
-
- @Test
- public void testToStringSimple() throws ParseException {
- ExplicitGroup group = new ExplicitGroup("myExplicitGroup", GroupHierarchyType.INDEPENDENT,
- JabRefPreferences.getInstance());
- assertEquals("ExplicitGroup:myExplicitGroup;0;", group.toString());
- }
-
- @Test
- public void toStringDoesNotWriteAssignedEntries() throws ParseException {
- ExplicitGroup group = new ExplicitGroup("myExplicitGroup", GroupHierarchyType.INCLUDING,
- JabRefPreferences.getInstance());
- group.add(makeBibtexEntry());
- assertEquals("ExplicitGroup:myExplicitGroup;2;", group.toString());
- }
-
- public BibEntry makeBibtexEntry() {
- BibEntry e = new BibEntry(IdGenerator.next(), BibtexEntryTypes.INCOLLECTION.getName());
- e.setField("title", "Marine finfish larviculture in Europe");
- e.setField("bibtexkey", "shields01");
- e.setField("year", "2001");
- e.setField("author", "Kevin Shields");
- return e;
- }
-
-}
diff --git a/src/test/java/net/sf/jabref/logic/groups/GroupTreeNodeTest.java b/src/test/java/net/sf/jabref/logic/groups/GroupTreeNodeTest.java
deleted file mode 100644
index fdea3bb..0000000
--- a/src/test/java/net/sf/jabref/logic/groups/GroupTreeNodeTest.java
+++ /dev/null
@@ -1,337 +0,0 @@
-package net.sf.jabref.logic.groups;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-import net.sf.jabref.logic.importer.util.ParseException;
-import net.sf.jabref.logic.search.matchers.AndMatcher;
-import net.sf.jabref.logic.search.matchers.OrMatcher;
-import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.preferences.JabRefPreferences;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-public class GroupTreeNodeTest {
-
- private final List<BibEntry> entries = new ArrayList<>();
- private BibEntry entry;
-
- @Before
- public void setUp() throws Exception {
- entries.clear();
- entry = new BibEntry();
- entries.add(entry);
- entries.add(new BibEntry().withField("author", "author1 and author2"));
- entries.add(new BibEntry().withField("author", "author1"));
- }
-
-
- /**
- * Gets the marked node in the following tree of explicit groups:
- * Root
- * A ExplicitA, Including
- * A ExplicitParent, Independent (= parent)
- * B ExplicitNode, Refining (<-- this)
- */
- private GroupTreeNode getNodeInSimpleTree(GroupTreeNode root) throws ParseException {
- root.addSubgroup(new ExplicitGroup("ExplicitA", GroupHierarchyType.INCLUDING, JabRefPreferences.getInstance()));
- GroupTreeNode parent = root
- .addSubgroup(new ExplicitGroup("ExplicitParent", GroupHierarchyType.INDEPENDENT,
- JabRefPreferences.getInstance()));
- GroupTreeNode node = parent
- .addSubgroup(new ExplicitGroup("ExplicitNode", GroupHierarchyType.REFINING,
- JabRefPreferences.getInstance()));
- return node;
- }
-
- private GroupTreeNode getNodeInSimpleTree() throws ParseException {
- return getNodeInSimpleTree(getRoot());
- }
-
- /**
- * Gets the marked node in the following tree:
- * Root
- * A SearchA
- * A ExplicitA, Including
- * A ExplicitGrandParent (= grand parent)
- * B ExplicitB
- * B KeywordParent (= parent)
- * C KeywordNode (<-- this)
- * D ExplicitChild (= child)
- * C SearchC
- * C ExplicitC
- * C KeywordC
- * B SearchB
- * B KeywordB
- * A KeywordA
- */
- private GroupTreeNode getNodeInComplexTree(GroupTreeNode root) throws ParseException {
- root.addSubgroup(getSearchGroup("SearchA"));
- root.addSubgroup(new ExplicitGroup("ExplicitA", GroupHierarchyType.INCLUDING, JabRefPreferences.getInstance()));
- GroupTreeNode grandParent = root
- .addSubgroup(new ExplicitGroup("ExplicitGrandParent", GroupHierarchyType.INDEPENDENT,
- JabRefPreferences.getInstance()));
- root.addSubgroup(getKeywordGroup("KeywordA"));
-
- grandParent.addSubgroup(getExplict("ExplicitB"));
- GroupTreeNode parent = grandParent.addSubgroup(getKeywordGroup("KeywordParent"));
- grandParent.addSubgroup(getSearchGroup("SearchB"));
- grandParent.addSubgroup(getKeywordGroup("KeywordB"));
-
- GroupTreeNode node = parent.addSubgroup(getKeywordGroup("KeywordNode"));
- parent.addSubgroup(getSearchGroup("SearchC"));
- parent.addSubgroup(getExplict("ExplicitC"));
- parent.addSubgroup(getKeywordGroup("KeywordC"));
-
- node.addSubgroup(getExplict("ExplicitChild"));
- return node;
- }
-
- private AbstractGroup getKeywordGroup(String name) throws ParseException {
- return new KeywordGroup(name, "searchField", "searchExpression", true, false, GroupHierarchyType.INDEPENDENT,
- JabRefPreferences.getInstance());
- }
-
- private AbstractGroup getSearchGroup(String name) {
- return new SearchGroup(name, "searchExpression", true, false, GroupHierarchyType.INCLUDING);
- }
-
- private AbstractGroup getExplict(String name) throws ParseException {
- return new ExplicitGroup(name, GroupHierarchyType.REFINING, JabRefPreferences.getInstance());
- }
-
- /*
- public GroupTreeNode getNodeInComplexTree() {
- return getNodeInComplexTree(new TreeNodeMock());
- }
- */
-
- /**
- * Gets the marked in the following tree:
- * Root
- * A
- * A
- * A (<- this)
- * A
- */
- /*
- public GroupTreeNode getNodeAsChild(TreeNodeMock root) {
- root.addChild(new TreeNodeMock());
- root.addChild(new TreeNodeMock());
- TreeNodeMock node = new TreeNodeMock();
- root.addChild(node);
- root.addChild(new TreeNodeMock());
- return node;
- }
- */
- private GroupTreeNode getRoot() {
- return GroupTreeNode.fromGroup(new AllEntriesGroup());
- }
-
- @Test
- public void getTreeAsStringInSimpleTree() throws Exception {
- GroupTreeNode root = getRoot();
- getNodeInSimpleTree(root);
-
- List<String> expected = Arrays.asList(
- "0 AllEntriesGroup:",
- "1 ExplicitGroup:ExplicitA;2;",
- "1 ExplicitGroup:ExplicitParent;0;",
- "2 ExplicitGroup:ExplicitNode;1;"
- );
- assertEquals(expected, root.getTreeAsString());
- }
-
- @Test
- public void getTreeAsStringInComplexTree() throws Exception {
- GroupTreeNode root = getRoot();
- getNodeInComplexTree(root);
-
- List<String> expected = Arrays.asList(
- "0 AllEntriesGroup:",
- "1 SearchGroup:SearchA;2;searchExpression;1;0;",
- "1 ExplicitGroup:ExplicitA;2;",
- "1 ExplicitGroup:ExplicitGrandParent;0;",
- "2 ExplicitGroup:ExplicitB;1;",
- "2 KeywordGroup:KeywordParent;0;searchField;searchExpression;1;0;",
- "3 KeywordGroup:KeywordNode;0;searchField;searchExpression;1;0;",
- "4 ExplicitGroup:ExplicitChild;1;",
- "3 SearchGroup:SearchC;2;searchExpression;1;0;",
- "3 ExplicitGroup:ExplicitC;1;",
- "3 KeywordGroup:KeywordC;0;searchField;searchExpression;1;0;",
- "2 SearchGroup:SearchB;2;searchExpression;1;0;",
- "2 KeywordGroup:KeywordB;0;searchField;searchExpression;1;0;",
- "1 KeywordGroup:KeywordA;0;searchField;searchExpression;1;0;"
- );
- assertEquals(expected, root.getTreeAsString());
- }
-
- @Test
- public void getSearchRuleForIndependentGroupReturnsGroupAsMatcher() throws ParseException {
- GroupTreeNode node = GroupTreeNode
- .fromGroup(new ExplicitGroup("node", GroupHierarchyType.INDEPENDENT, JabRefPreferences.getInstance()));
- assertEquals(node.getGroup(), node.getSearchRule());
- }
-
- @Test
- public void getSearchRuleForRefiningGroupReturnsParentAndGroupAsMatcher() throws ParseException {
- GroupTreeNode parent = GroupTreeNode
- .fromGroup(
- new ExplicitGroup("parent", GroupHierarchyType.INDEPENDENT, JabRefPreferences.getInstance()));
- GroupTreeNode node = parent
- .addSubgroup(new ExplicitGroup("node", GroupHierarchyType.REFINING, JabRefPreferences.getInstance()));
-
- AndMatcher matcher = new AndMatcher();
- matcher.addRule(node.getGroup());
- matcher.addRule(parent.getGroup());
- assertEquals(matcher, node.getSearchRule());
- }
-
- @Test
- public void getSearchRuleForIncludingGroupReturnsGroupOrSubgroupAsMatcher() throws ParseException {
- GroupTreeNode node = GroupTreeNode
- .fromGroup(new ExplicitGroup("node", GroupHierarchyType.INCLUDING, JabRefPreferences.getInstance()));
- GroupTreeNode child = node
- .addSubgroup(
- new ExplicitGroup("child", GroupHierarchyType.INDEPENDENT, JabRefPreferences.getInstance()));
-
- OrMatcher matcher = new OrMatcher();
- matcher.addRule(node.getGroup());
- matcher.addRule(child.getGroup());
- assertEquals(matcher, node.getSearchRule());
- }
-
- @Test
- public void numberOfHitsReturnsZeroForEmptyList() throws Exception {
- assertEquals(0, getNodeInSimpleTree().numberOfHits(Collections.emptyList()));
- }
-
- @Test
- public void numberOfHitsMatchesOneEntry() throws Exception {
- GroupTreeNode parent = getNodeInSimpleTree();
- GroupTreeNode node = parent.addSubgroup(
- new KeywordGroup("node", "author", "author2", true, false, GroupHierarchyType.INDEPENDENT,
- JabRefPreferences.getInstance()));
- assertEquals(1, node.numberOfHits(entries));
- }
-
- @Test
- public void numberOfHitsMatchesMultipleEntries() throws Exception {
- GroupTreeNode parent = getNodeInSimpleTree();
- GroupTreeNode node = parent.addSubgroup(
- new KeywordGroup("node", "author", "author1", true, false, GroupHierarchyType.INDEPENDENT,
- JabRefPreferences.getInstance()));
- assertEquals(2, node.numberOfHits(entries));
- }
-
- @Test
- public void numberOfHitsWorksForRefiningGroups() throws Exception {
- GroupTreeNode grandParent = getNodeInSimpleTree();
- GroupTreeNode parent = grandParent.addSubgroup(
- new KeywordGroup("node", "author", "author2", true, false, GroupHierarchyType.INDEPENDENT,
- JabRefPreferences.getInstance()));
- GroupTreeNode node = parent.addSubgroup(
- new KeywordGroup("node", "author", "author1", true, false, GroupHierarchyType.REFINING,
- JabRefPreferences.getInstance()));
- assertEquals(1, node.numberOfHits(entries));
- }
-
- @Test
- public void numberOfHitsWorksForHierarchyOfIndependentGroups() throws Exception {
- GroupTreeNode grandParent = getNodeInSimpleTree();
- GroupTreeNode parent = grandParent.addSubgroup(
- new KeywordGroup("node", "author", "author2", true, false, GroupHierarchyType.INDEPENDENT,
- JabRefPreferences.getInstance()));
- GroupTreeNode node = parent.addSubgroup(
- new KeywordGroup("node", "author", "author1", true, false, GroupHierarchyType.INDEPENDENT,
- JabRefPreferences.getInstance()));
- assertEquals(2, node.numberOfHits(entries));
- }
-
- @Test
- public void setGroupChangesUnderlyingGroup() throws Exception {
- GroupTreeNode node = getNodeInSimpleTree();
- AbstractGroup newGroup = new ExplicitGroup("NewGroup", GroupHierarchyType.INDEPENDENT,
- JabRefPreferences.getInstance());
-
- node.setGroup(newGroup, true, entries);
-
- assertEquals(newGroup, node.getGroup());
- }
-
- @Test
- public void setGroupAddsPreviousAssignmentsExplicitToExplicit() throws Exception {
- AbstractGroup oldGroup = new ExplicitGroup("OldGroup", GroupHierarchyType.INDEPENDENT,
- JabRefPreferences.getInstance());
- oldGroup.add(entry);
- GroupTreeNode node = GroupTreeNode.fromGroup(oldGroup);
- AbstractGroup newGroup = new ExplicitGroup("NewGroup", GroupHierarchyType.INDEPENDENT,
- JabRefPreferences.getInstance());
-
- node.setGroup(newGroup, true, entries);
-
- assertTrue(newGroup.isMatch(entry));
- }
-
- @Test
- public void setGroupWithFalseDoesNotAddsPreviousAssignments() throws Exception {
- AbstractGroup oldGroup = new ExplicitGroup("OldGroup", GroupHierarchyType.INDEPENDENT,
- JabRefPreferences.getInstance());
- oldGroup.add(entry);
- GroupTreeNode node = GroupTreeNode.fromGroup(oldGroup);
- AbstractGroup newGroup = new ExplicitGroup("NewGroup", GroupHierarchyType.INDEPENDENT,
- JabRefPreferences.getInstance());
-
- node.setGroup(newGroup, false, entries);
-
- assertFalse(newGroup.isMatch(entry));
- }
-
- @Test
- public void setGroupAddsOnlyPreviousAssignments() throws Exception {
- AbstractGroup oldGroup = new ExplicitGroup("OldGroup", GroupHierarchyType.INDEPENDENT,
- JabRefPreferences.getInstance());
- assertFalse(oldGroup.isMatch(entry));
- GroupTreeNode node = GroupTreeNode.fromGroup(oldGroup);
- AbstractGroup newGroup = new ExplicitGroup("NewGroup", GroupHierarchyType.INDEPENDENT,
- JabRefPreferences.getInstance());
-
- node.setGroup(newGroup, true, entries);
-
- assertFalse(newGroup.isMatch(entry));
- }
-
- @Test
- public void setGroupExplicitToSearchDoesNotKeepPreviousAssignments() throws Exception {
- AbstractGroup oldGroup = new ExplicitGroup("OldGroup", GroupHierarchyType.INDEPENDENT,
- JabRefPreferences.getInstance());
- oldGroup.add(entry);
- GroupTreeNode node = GroupTreeNode.fromGroup(oldGroup);
- AbstractGroup newGroup = new SearchGroup("NewGroup", "test", false, false, GroupHierarchyType.INDEPENDENT);
-
- node.setGroup(newGroup, true, entries);
-
- assertFalse(newGroup.isMatch(entry));
- }
-
- @Test
- public void setGroupExplicitToExplicitIsRenameAndSoRemovesPreviousAssignment() throws Exception {
- AbstractGroup oldGroup = new ExplicitGroup("OldGroup", GroupHierarchyType.INDEPENDENT,
- JabRefPreferences.getInstance());
- oldGroup.add(entry);
- GroupTreeNode node = GroupTreeNode.fromGroup(oldGroup);
- AbstractGroup newGroup = new ExplicitGroup("NewGroup", GroupHierarchyType.INDEPENDENT,
- JabRefPreferences.getInstance());
-
- node.setGroup(newGroup, true, entries);
-
- assertFalse(oldGroup.isMatch(entry));
- }
-}
diff --git a/src/test/java/net/sf/jabref/logic/groups/GroupsUtilTest.java b/src/test/java/net/sf/jabref/logic/groups/GroupsUtilTest.java
index 3da94fc..44eb959 100644
--- a/src/test/java/net/sf/jabref/logic/groups/GroupsUtilTest.java
+++ b/src/test/java/net/sf/jabref/logic/groups/GroupsUtilTest.java
@@ -9,10 +9,10 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Set;
-import net.sf.jabref.logic.importer.ImportFormatPreferences;
import net.sf.jabref.logic.importer.ParserResult;
import net.sf.jabref.logic.importer.fileformat.BibtexParser;
import net.sf.jabref.model.database.BibDatabase;
+import net.sf.jabref.model.groups.GroupsUtil;
import net.sf.jabref.preferences.JabRefPreferences;
import org.junit.Test;
@@ -29,7 +29,7 @@ public class GroupsUtilTest {
StandardCharsets.UTF_8)) {
ParserResult result = BibtexParser.parse(fr,
- ImportFormatPreferences.fromPreferences(JabRefPreferences.getInstance()));
+ JabRefPreferences.getInstance().getImportFormatPreferences());
BibDatabase db = result.getDatabase();
diff --git a/src/test/java/net/sf/jabref/logic/groups/KeywordGroupTest.java b/src/test/java/net/sf/jabref/logic/groups/KeywordGroupTest.java
deleted file mode 100644
index c87d71a..0000000
--- a/src/test/java/net/sf/jabref/logic/groups/KeywordGroupTest.java
+++ /dev/null
@@ -1,90 +0,0 @@
-package net.sf.jabref.logic.groups;
-
-import net.sf.jabref.logic.importer.util.ParseException;
-import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.preferences.JabRefPreferences;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-public class KeywordGroupTest {
-
- @Test
- public void testToString() throws ParseException {
- KeywordGroup group = new KeywordGroup("myExplicitGroup", "author","asdf", true, true,
- GroupHierarchyType.INDEPENDENT, JabRefPreferences.getInstance());
- assertEquals("KeywordGroup:myExplicitGroup;0;author;asdf;1;1;", group.toString());
- }
-
- @Test
- public void testToString2() throws ParseException {
- KeywordGroup group = new KeywordGroup("myExplicitGroup", "author","asdf", false, true,
- GroupHierarchyType.REFINING, JabRefPreferences.getInstance());
- assertEquals("KeywordGroup:myExplicitGroup;1;author;asdf;0;1;", group.toString());
- }
-
- @Test
- public void containsSimpleWord() throws Exception {
- KeywordGroup group = new KeywordGroup("name", "keywords", "test", false, false, GroupHierarchyType.INDEPENDENT,
- JabRefPreferences.getInstance());
- BibEntry entry = new BibEntry().withField("keywords", "test");
-
- assertTrue(group.isMatch(entry));
- }
-
- @Test
- public void containsSimpleWordInSentence() throws Exception {
- KeywordGroup group = new KeywordGroup("name", "keywords", "test", false, false, GroupHierarchyType.INDEPENDENT,
- JabRefPreferences.getInstance());
- BibEntry entry = new BibEntry().withField("keywords", "Some sentence containing test word");
-
- assertTrue(group.isMatch(entry));
- }
-
- @Test
- public void containsSimpleWordCommaSeparated() throws Exception {
- KeywordGroup group = new KeywordGroup("name", "keywords", "test", false, false, GroupHierarchyType.INDEPENDENT,
- JabRefPreferences.getInstance());
- BibEntry entry = new BibEntry().withField("keywords", "Some,list,containing,test,word");
-
- assertTrue(group.isMatch(entry));
- }
-
- @Test
- public void containsSimpleWordSemicolonSeparated() throws Exception {
- KeywordGroup group = new KeywordGroup("name", "keywords", "test", false, false, GroupHierarchyType.INDEPENDENT,
- JabRefPreferences.getInstance());
- BibEntry entry = new BibEntry().withField("keywords", "Some;list;containing;test;word");
-
- assertTrue(group.isMatch(entry));
- }
-
- @Test
- public void containsComplexWord() throws Exception {
- KeywordGroup group = new KeywordGroup("name", "keywords", "\\H2O", false, false, GroupHierarchyType.INDEPENDENT,
- JabRefPreferences.getInstance());
- BibEntry entry = new BibEntry().withField("keywords", "\\H2O");
-
- assertTrue(group.isMatch(entry));
- }
-
- @Test
- public void containsComplexWordInSentence() throws Exception {
- KeywordGroup group = new KeywordGroup("name", "keywords", "\\H2O", false, false, GroupHierarchyType.INDEPENDENT,
- JabRefPreferences.getInstance());
- BibEntry entry = new BibEntry().withField("keywords", "Some sentence containing \\H2O word");
-
- assertTrue(group.isMatch(entry));
- }
-
- @Test
- public void containsWordWithWhitespaceInSentence() throws Exception {
- KeywordGroup group = new KeywordGroup("name", "keywords", "test word", false, false,
- GroupHierarchyType.INDEPENDENT, JabRefPreferences.getInstance());
- BibEntry entry = new BibEntry().withField("keywords", "Some sentence containing test word");
-
- assertTrue(group.isMatch(entry));
- }
-}
diff --git a/src/test/java/net/sf/jabref/logic/groups/SearchGroupTest.java b/src/test/java/net/sf/jabref/logic/groups/SearchGroupTest.java
deleted file mode 100644
index eb4bc0a..0000000
--- a/src/test/java/net/sf/jabref/logic/groups/SearchGroupTest.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package net.sf.jabref.logic.groups;
-
-import net.sf.jabref.model.entry.BibEntry;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-public class SearchGroupTest {
-
-
- @Test
- public void testContains() {
- SearchGroup group = new SearchGroup("myExplicitGroup", "review",
- true, true, GroupHierarchyType.INDEPENDENT);
- assertEquals("SearchGroup:myExplicitGroup;0;review;1;1;", group.toString());
-
- BibEntry entry = new BibEntry();
- assertFalse(group.contains(entry));
-
- entry.addKeyword("review", ", ");
- assertTrue(group.contains(entry));
- }
-
- @Test
- public void testToStringSimple() {
- SearchGroup group = new SearchGroup("myExplicitGroup", "author=harrer",
- true, true, GroupHierarchyType.INDEPENDENT);
- assertEquals("SearchGroup:myExplicitGroup;0;author=harrer;1;1;", group.toString());
- }
-
- @Test
- public void testToStringComplex() {
- SearchGroup group = new SearchGroup("myExplicitGroup", "author=\"harrer\"", true, false,
- GroupHierarchyType.INCLUDING);
- assertEquals("SearchGroup:myExplicitGroup;2;author=\"harrer\";1;0;", group.toString());
- }
-
-}
\ No newline at end of file
diff --git a/src/test/java/net/sf/jabref/logic/groups/TreeNodeTest.java b/src/test/java/net/sf/jabref/logic/groups/TreeNodeTest.java
deleted file mode 100644
index 39d27ac..0000000
--- a/src/test/java/net/sf/jabref/logic/groups/TreeNodeTest.java
+++ /dev/null
@@ -1,709 +0,0 @@
-package net.sf.jabref.logic.groups;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Optional;
-import java.util.function.Consumer;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-public class TreeNodeTest {
-
- /**
- * Gets the marked node in the following tree:
- * Root
- * A
- * A (= parent)
- * B (<-- this)
- */
- public TreeNodeMock getNodeInSimpleTree(TreeNodeMock root) {
- root.addChild(new TreeNodeMock());
- TreeNodeMock parent = new TreeNodeMock();
- root.addChild(parent);
- TreeNodeMock node = new TreeNodeMock();
- parent.addChild(node);
- return node;
- }
-
- public TreeNodeMock getNodeInSimpleTree() {
- return getNodeInSimpleTree(new TreeNodeMock());
- }
-
- /**
- * Gets the marked node in the following tree:
- * Root
- * A
- * A
- * A (= grand parent)
- * B
- * B (= parent)
- * C (<-- this)
- * D (= child)
- * C
- * C
- * C
- * B
- * B
- * A
- */
- public TreeNodeMock getNodeInComplexTree(TreeNodeMock root) {
- root.addChild(new TreeNodeMock());
- root.addChild(new TreeNodeMock());
- TreeNodeMock grandParent = new TreeNodeMock();
- root.addChild(grandParent);
- root.addChild(new TreeNodeMock());
-
- grandParent.addChild(new TreeNodeMock());
- TreeNodeMock parent = new TreeNodeMock();
- grandParent.addChild(parent);
- grandParent.addChild(new TreeNodeMock());
- grandParent.addChild(new TreeNodeMock());
-
- TreeNodeMock node = new TreeNodeMock();
- parent.addChild(node);
- parent.addChild(new TreeNodeMock());
- parent.addChild(new TreeNodeMock());
- parent.addChild(new TreeNodeMock());
-
- node.addChild(new TreeNodeMock());
- return node;
- }
-
- public TreeNodeMock getNodeInComplexTree() {
- return getNodeInComplexTree(new TreeNodeMock());
- }
-
- /**
- * Gets the marked in the following tree:
- * Root
- * A
- * A
- * A (<- this)
- * A
- */
- public TreeNodeMock getNodeAsChild(TreeNodeMock root) {
- root.addChild(new TreeNodeMock());
- root.addChild(new TreeNodeMock());
- TreeNodeMock node = new TreeNodeMock();
- root.addChild(node);
- root.addChild(new TreeNodeMock());
- return node;
- }
-
- @SuppressWarnings("unused")
- @Test(expected = UnsupportedOperationException.class)
- public void constructorChecksThatClassImplementsCorrectInterface() {
- new WrongTreeNodeImplementation();
- }
-
- @Test
- public void constructorExceptsCorrectImplementation() {
- TreeNodeMock treeNode = new TreeNodeMock();
- assertNotNull(treeNode);
- }
-
- @Test
- public void newTreeNodeHasNoParentOrChildren() {
- TreeNodeMock treeNode = new TreeNodeMock();
- assertEquals(Optional.empty(), treeNode.getParent());
- assertEquals(Collections.emptyList(), treeNode.getChildren());
- assertNotNull(treeNode);
- }
-
- @Test
- public void getIndexedPathFromRootReturnsEmptyListForRoot() {
- TreeNodeMock root = new TreeNodeMock();
- assertEquals(Collections.emptyList(), root.getIndexedPathFromRoot());
- }
-
- @Test
- public void getIndexedPathFromRootSimplePath() {
- assertEquals(Arrays.asList(1, 0), getNodeInSimpleTree().getIndexedPathFromRoot());
- }
-
- @Test
- public void getIndexedPathFromRootComplexPath() {
- assertEquals(Arrays.asList(2, 1, 0), getNodeInComplexTree().getIndexedPathFromRoot());
- }
-
- @Test
- public void getDescendantSimplePath() {
- TreeNodeMock root = new TreeNodeMock();
- TreeNodeMock node = getNodeInSimpleTree(root);
- assertEquals(node, root.getDescendant(Arrays.asList(1, 0)).get());
- }
-
- @Test
- public void getDescendantComplexPath() {
- TreeNodeMock root = new TreeNodeMock();
- TreeNodeMock node = getNodeInComplexTree(root);
- assertEquals(node, root.getDescendant(Arrays.asList(2, 1, 0)).get());
- }
-
- @Test
- public void getDescendantNonExistentReturnsEmpty() {
- TreeNodeMock root = new TreeNodeMock();
- getNodeInComplexTree(root);
- assertEquals(Optional.empty(), root.getDescendant(Arrays.asList(1, 100, 0)));
- }
-
- @Test(expected = UnsupportedOperationException.class)
- public void getPositionInParentForRootThrowsException() {
- TreeNodeMock root = new TreeNodeMock();
- root.getPositionInParent();
- }
-
- @Test
- public void getPositionInParentSimpleTree() {
- TreeNodeMock root = new TreeNodeMock();
- TreeNodeMock node = getNodeAsChild(root);
- assertEquals(2, node.getPositionInParent());
- }
-
- @Test
- public void getIndexOfNonExistentChildReturnsEmpty() {
- TreeNodeMock root = new TreeNodeMock();
- assertEquals(Optional.empty(), root.getIndexOfChild(new TreeNodeMock()));
- }
-
- @Test
- public void getIndexOfChild() {
- TreeNodeMock root = new TreeNodeMock();
- TreeNodeMock node = getNodeAsChild(root);
- assertEquals((Integer)2, root.getIndexOfChild(node).get());
- }
-
- @Test
- public void getLevelOfRoot() {
- TreeNodeMock root = new TreeNodeMock();
- assertEquals(0, root.getLevel());
- }
-
- @Test
- public void getLevelInSimpleTree() {
- assertEquals(2, getNodeInSimpleTree().getLevel());
- }
-
- @Test
- public void getLevelInComplexTree() {
- assertEquals(3, getNodeInComplexTree().getLevel());
- }
-
- @Test
- public void getChildCountInSimpleTree() {
- TreeNodeMock root = new TreeNodeMock();
- getNodeInSimpleTree(root);
- assertEquals(2, root.getNumberOfChildren());
- }
-
- @Test
- public void getChildCountInComplexTree() {
- TreeNodeMock root = new TreeNodeMock();
- getNodeInComplexTree(root);
- assertEquals(4, root.getNumberOfChildren());
- }
-
- @Test
- public void moveToAddsAsLastChildInSimpleTree() {
- TreeNodeMock root = new TreeNodeMock();
- TreeNodeMock node = getNodeInSimpleTree(root);
- node.moveTo(root);
- assertEquals((Integer)2, root.getIndexOfChild(node).get());
- }
-
- @Test
- public void moveToAddsAsLastChildInComplexTree() {
- TreeNodeMock root = new TreeNodeMock();
- TreeNodeMock node = getNodeInComplexTree(root);
- node.moveTo(root);
- assertEquals((Integer)4, root.getIndexOfChild(node).get());
- }
-
- @Test
- public void moveToChangesParent() {
- TreeNodeMock root = new TreeNodeMock();
- TreeNodeMock node = getNodeInSimpleTree(root);
- node.moveTo(root);
- assertEquals(root, node.getParent().get());
- }
-
- @Test
- public void moveToInSameLevelAddsAtEnd() {
- TreeNodeMock root = new TreeNodeMock();
- TreeNodeMock child1 = new TreeNodeMock();
- TreeNodeMock child2 = new TreeNodeMock();
- root.addChild(child1);
- root.addChild(child2);
-
- child1.moveTo(root);
-
- assertEquals(Arrays.asList(child2, child1), root.getChildren());
- }
-
- @Test
- public void getPathFromRootInSimpleTree() {
- TreeNodeMock root = new TreeNodeMock();
- TreeNodeMock node = getNodeInSimpleTree(root);
-
- List<TreeNodeMock> path = node.getPathFromRoot();
- assertEquals(3, path.size());
- assertEquals(root, path.get(0));
- assertEquals(node, path.get(2));
- }
-
- @Test
- public void getPathFromRootInComplexTree() {
- TreeNodeMock root = new TreeNodeMock();
- TreeNodeMock node = getNodeInComplexTree(root);
-
- List<TreeNodeMock> path = node.getPathFromRoot();
- assertEquals(4, path.size());
- assertEquals(root, path.get(0));
- assertEquals(node, path.get(3));
- }
-
- @Test
- public void getPreviousSiblingReturnsCorrect() {
- TreeNodeMock root = new TreeNodeMock();
- root.addChild(new TreeNodeMock());
- TreeNodeMock previous = new TreeNodeMock();
- root.addChild(previous);
- TreeNodeMock node = new TreeNodeMock();
- root.addChild(node);
- root.addChild(new TreeNodeMock());
-
- assertEquals(previous, node.getPreviousSibling().get());
- }
-
- @Test
- public void getPreviousSiblingForRootReturnsEmpty() {
- TreeNodeMock root = new TreeNodeMock();
- assertEquals(Optional.empty(), root.getPreviousSibling());
- }
-
- @Test
- public void getPreviousSiblingForNonexistentReturnsEmpty() {
- TreeNodeMock root = new TreeNodeMock();
- TreeNodeMock node = new TreeNodeMock();
- root.addChild(node);
- assertEquals(Optional.empty(), node.getPreviousSibling());
- }
-
- @Test
- public void getNextSiblingReturnsCorrect() {
- TreeNodeMock root = new TreeNodeMock();
- root.addChild(new TreeNodeMock());
- TreeNodeMock node = new TreeNodeMock();
- root.addChild(node);
- TreeNodeMock next = new TreeNodeMock();
- root.addChild(next);
- root.addChild(new TreeNodeMock());
-
- assertEquals(next, node.getNextSibling().get());
- }
-
- @Test
- public void getNextSiblingForRootReturnsEmpty() {
- TreeNodeMock root = new TreeNodeMock();
- assertEquals(Optional.empty(), root.getNextSibling());
- }
-
- @Test
- public void getNextSiblingForNonexistentReturnsEmpty() {
- TreeNodeMock root = new TreeNodeMock();
- TreeNodeMock node = new TreeNodeMock();
- root.addChild(node);
- assertEquals(Optional.empty(), node.getPreviousSibling());
- }
-
- @Test
- public void getParentReturnsCorrect() {
- TreeNodeMock root = new TreeNodeMock();
- TreeNodeMock node = getNodeAsChild(root);
-
- assertEquals(root, node.getParent().get());
- }
-
- @Test
- public void getParentForRootReturnsEmpty() {
- TreeNodeMock root = new TreeNodeMock();
- assertEquals(Optional.empty(), root.getParent());
- }
-
- @Test
- public void getChildAtReturnsCorrect() {
- TreeNodeMock root = new TreeNodeMock();
- TreeNodeMock node = getNodeAsChild(root);
-
- assertEquals(node, root.getChildAt(2).get());
- }
-
- @Test
- public void getChildAtInvalidIndexReturnsEmpty() {
- TreeNodeMock root = new TreeNodeMock();
- root.addChild(new TreeNodeMock());
- root.addChild(new TreeNodeMock());
- assertEquals(Optional.empty(), root.getChildAt(10));
- }
-
- @Test
- public void getRootReturnsTrueForRoot() {
- TreeNodeMock root = new TreeNodeMock();
- assertTrue(root.isRoot());
- }
-
- @Test
- public void getRootReturnsFalseForChild() {
- assertFalse(getNodeInSimpleTree().isRoot());
- }
-
- @Test
- public void nodeIsAncestorOfItself() {
- TreeNodeMock root = new TreeNodeMock();
- assertTrue(root.isAncestorOf(root));
- }
-
- @Test
- public void isAncestorOfInSimpleTree() {
- TreeNodeMock root = new TreeNodeMock();
- TreeNodeMock node = getNodeInSimpleTree(root);
- assertTrue(root.isAncestorOf(node));
- }
-
- @Test
- public void isAncestorOfInComplexTree() {
- TreeNodeMock root = new TreeNodeMock();
- TreeNodeMock node = getNodeInComplexTree(root);
- assertTrue(root.isAncestorOf(node));
- }
-
- @Test
- public void getRootOfSingleNode() {
- TreeNodeMock root = new TreeNodeMock();
- assertEquals(root, root.getRoot());
- }
-
- @Test
- public void getRootInSimpleTree() {
- TreeNodeMock root = new TreeNodeMock();
- TreeNodeMock node = getNodeInSimpleTree(root);
- assertEquals(root, node.getRoot());
- }
-
- @Test
- public void getRootInComplexTree() {
- TreeNodeMock root = new TreeNodeMock();
- TreeNodeMock node = getNodeInComplexTree(root);
- assertEquals(root, node.getRoot());
- }
-
- @Test
- public void isLeafIsCorrectForRootWithoutChildren() {
- TreeNodeMock root = new TreeNodeMock();
- assertTrue(root.isLeaf());
- }
-
- @Test
- public void removeFromParentSetsParentToEmpty() {
- TreeNodeMock root = new TreeNodeMock();
- TreeNodeMock node = getNodeAsChild(root);
-
- node.removeFromParent();
- assertEquals(Optional.empty(), node.getParent());
- }
-
- @Test
- public void removeFromParentRemovesNodeFromChildrenCollection() {
- TreeNodeMock root = new TreeNodeMock();
- TreeNodeMock node = getNodeAsChild(root);
-
- node.removeFromParent();
- assertFalse(root.getChildren().contains(node));
- }
-
- @Test
- public void removeAllChildrenSetsParentOfChildToEmpty() {
- TreeNodeMock root = new TreeNodeMock();
- TreeNodeMock node = getNodeAsChild(root);
-
- root.removeAllChildren();
- assertEquals(Optional.empty(), node.getParent());
- }
-
- @Test
- public void removeAllChildrenRemovesAllNodesFromChildrenCollection() {
- TreeNodeMock root = new TreeNodeMock();
- getNodeAsChild(root);
-
- root.removeAllChildren();
- assertEquals(Collections.emptyList(), root.getChildren());
- }
-
- @Test
- public void getFirstChildAtReturnsCorrect() {
- TreeNodeMock root = new TreeNodeMock();
- TreeNodeMock node = new TreeNodeMock();
- root.addChild(node);
-
- assertEquals(node, root.getFirstChild().get());
- }
-
- @Test
- public void getFirstChildAtLeafReturnsEmpty() {
- TreeNodeMock root = new TreeNodeMock();
- TreeNodeMock leaf = getNodeAsChild(root);
- assertEquals(Optional.empty(), leaf.getFirstChild());
- }
-
- @Test
- public void isNodeDescendantInFirstLevel() {
- TreeNodeMock root = new TreeNodeMock();
- TreeNodeMock child = getNodeAsChild(root);
- assertTrue(root.isNodeDescendant(child));
- }
-
- @Test
- public void isNodeDescendantInComplex() {
- TreeNodeMock root = new TreeNodeMock();
- TreeNodeMock descendant = getNodeInComplexTree(root);
- assertTrue(root.isNodeDescendant(descendant));
- }
-
- @Test
- public void getChildrenReturnsAllChildren() {
- TreeNodeMock root = new TreeNodeMock();
- TreeNodeMock child1 = new TreeNodeMock();
- TreeNodeMock child2 = new TreeNodeMock();
- root.addChild(child1);
- root.addChild(child2);
-
- assertEquals(Arrays.asList(child1, child2), root.getChildren());
- }
-
- @Test
- public void removeChildSetsParentToEmpty() {
- TreeNodeMock root = new TreeNodeMock();
- TreeNodeMock node = getNodeAsChild(root);
-
- root.removeChild(node);
- assertEquals(Optional.empty(), node.getParent());
- }
-
- @Test
- public void removeChildRemovesNodeFromChildrenCollection() {
- TreeNodeMock root = new TreeNodeMock();
- TreeNodeMock node = getNodeAsChild(root);
-
- root.removeChild(node);
- assertFalse(root.getChildren().contains(node));
- }
-
- @Test
- public void removeChildIndexSetsParentToEmpty() {
- TreeNodeMock root = new TreeNodeMock();
- TreeNodeMock node = getNodeAsChild(root);
-
- root.removeChild(2);
- assertEquals(Optional.empty(), node.getParent());
- }
-
- @Test
- public void removeChildIndexRemovesNodeFromChildrenCollection() {
- TreeNodeMock root = new TreeNodeMock();
- TreeNodeMock node = getNodeAsChild(root);
-
- root.removeChild(2);
- assertFalse(root.getChildren().contains(node));
- }
-
- @Test(expected = UnsupportedOperationException.class)
- public void addThrowsExceptionIfNodeHasParent() {
- TreeNodeMock root = new TreeNodeMock();
- TreeNodeMock node = getNodeAsChild(root);
- root.addChild(node);
- }
-
- @Test
- public void moveAllChildrenToAddsAtSpecifiedPosition() {
- TreeNodeMock root = new TreeNodeMock();
- TreeNodeMock node = new TreeNodeMock();
- root.addChild(node);
- TreeNodeMock child1 = new TreeNodeMock();
- TreeNodeMock child2 = new TreeNodeMock();
- node.addChild(child1);
- node.addChild(child2);
-
- node.moveAllChildrenTo(root, 0);
- assertEquals(Arrays.asList(child1, child2, node), root.getChildren());
- }
-
- @Test
- public void moveAllChildrenToChangesParent() {
- TreeNodeMock root = new TreeNodeMock();
- TreeNodeMock node = new TreeNodeMock();
- root.addChild(node);
- TreeNodeMock child1 = new TreeNodeMock();
- TreeNodeMock child2 = new TreeNodeMock();
- node.addChild(child1);
- node.addChild(child2);
-
- node.moveAllChildrenTo(root, 0);
- assertEquals(root, child1.getParent().get());
- assertEquals(root, child2.getParent().get());
- }
-
- @Test(expected = UnsupportedOperationException.class)
- public void moveAllChildrenToDescendantThrowsException() {
- TreeNodeMock root = new TreeNodeMock();
- TreeNodeMock node = getNodeAsChild(root);
-
- root.moveAllChildrenTo(node, 0);
- }
-
- @Test
- public void sortChildrenSortsInFirstLevel() {
- TreeNodeMock root = new TreeNodeMock();
- TreeNodeMock child1 = new TreeNodeMock("a");
- TreeNodeMock child2 = new TreeNodeMock("b");
- TreeNodeMock child3 = new TreeNodeMock("c");
- root.addChild(child2);
- root.addChild(child3);
- root.addChild(child1);
-
- root.sortChildren((o1, o2) -> o1.getName().compareToIgnoreCase(o2.getName()), false);
- assertEquals(Arrays.asList(child1, child2, child3), root.getChildren());
- }
-
- @Test
- public void sortChildrenRecursiveSortsInDeeperLevel() {
- TreeNodeMock root = new TreeNodeMock();
- TreeNodeMock node = getNodeInSimpleTree(root);
- TreeNodeMock child1 = new TreeNodeMock("a");
- TreeNodeMock child2 = new TreeNodeMock("b");
- TreeNodeMock child3 = new TreeNodeMock("c");
- node.addChild(child2);
- node.addChild(child3);
- node.addChild(child1);
-
- root.sortChildren((o1, o2) -> o1.getName().compareToIgnoreCase(o2.getName()), true);
- assertEquals(Arrays.asList(child1, child2, child3), node.getChildren());
- }
-
- @Test
- public void copySubtreeCopiesChildren() {
- TreeNodeMock root = new TreeNodeMock();
- TreeNodeMock node = getNodeAsChild(root);
-
- TreeNodeMock copiedRoot = root.copySubtree();
- assertEquals(Optional.empty(), copiedRoot.getParent());
- assertFalse(copiedRoot.getChildren().contains(node));
- assertEquals(root.getNumberOfChildren(), copiedRoot.getNumberOfChildren());
- }
-
- @Test
- public void addChildSomewhereInTreeInvokesChangeEvent() {
- TreeNodeMock root = new TreeNodeMock();
- TreeNodeMock node = getNodeInComplexTree(root);
-
- Consumer<TreeNodeMock> subscriber = mock(Consumer.class);
- root.subscribeToDescendantChanged(subscriber);
-
- node.addChild(new TreeNodeMock());
- verify(subscriber).accept(node);
- }
-
- @Test
- public void moveNodeSomewhereInTreeInvokesChangeEvent() {
- TreeNodeMock root = new TreeNodeMock();
- TreeNodeMock node = getNodeInComplexTree(root);
- TreeNodeMock oldParent = node.getParent().get();
-
- Consumer<TreeNodeMock> subscriber = mock(Consumer.class);
- root.subscribeToDescendantChanged(subscriber);
-
- node.moveTo(root);
- verify(subscriber).accept(root);
- verify(subscriber).accept(oldParent);
- }
-
- @Test
- public void removeChildSomewhereInTreeInvokesChangeEvent() {
- TreeNodeMock root = new TreeNodeMock();
- TreeNodeMock node = getNodeInComplexTree(root);
- TreeNodeMock child = node.addChild(new TreeNodeMock());
-
- Consumer<TreeNodeMock> subscriber = mock(Consumer.class);
- root.subscribeToDescendantChanged(subscriber);
-
- node.removeChild(child);
- verify(subscriber).accept(node);
- }
-
- @Test
- public void removeChildIndexSomewhereInTreeInvokesChangeEvent() {
- TreeNodeMock root = new TreeNodeMock();
- TreeNodeMock node = getNodeInComplexTree(root);
- node.addChild(new TreeNodeMock());
-
- Consumer<TreeNodeMock> subscriber = mock(Consumer.class);
- root.subscribeToDescendantChanged(subscriber);
-
- node.removeChild(0);
- verify(subscriber).accept(node);
- }
-
- /**
- * This is just a dummy class deriving from TreeNode<T> so that we can test the generic class
- */
- private class TreeNodeMock extends TreeNode<TreeNodeMock> {
-
- private final String name;
-
- public TreeNodeMock() {
- this("");
- }
-
- public TreeNodeMock(String name) {
- super(TreeNodeMock.class);
- this.name = name;
- }
-
- public String getName() {
- return name;
- }
-
- @Override
- public String toString() {
- return "TreeNodeMock{" +
- "name='" + name + '\'' +
- '}';
- }
-
- @Override
- public TreeNodeMock copyNode() {
- return new TreeNodeMock(name);
- }
- }
-
- private static class WrongTreeNodeImplementation extends TreeNode<TreeNodeMock> {
- // This class is a wrong derived class of TreeNode<T>
- // since it does not extends TreeNode<WrongTreeNodeImplementation>
- // See test constructorChecksThatClassImplementsCorrectInterface
- public WrongTreeNodeImplementation() {
- super(TreeNodeMock.class);
- }
-
- @Override
- public TreeNodeMock copyNode() {
- return null;
- }
- }
-}
diff --git a/src/test/java/net/sf/jabref/logic/importer/BibDatabaseTestsWithFiles.java b/src/test/java/net/sf/jabref/logic/importer/BibDatabaseTestsWithFiles.java
index fcd7544..d62a17f 100644
--- a/src/test/java/net/sf/jabref/logic/importer/BibDatabaseTestsWithFiles.java
+++ b/src/test/java/net/sf/jabref/logic/importer/BibDatabaseTestsWithFiles.java
@@ -20,7 +20,7 @@ public class BibDatabaseTestsWithFiles {
@Before
public void setUp() {
- importFormatPreferences = ImportFormatPreferences.fromPreferences(JabRefPreferences.getInstance());
+ importFormatPreferences = JabRefPreferences.getInstance().getImportFormatPreferences();
}
@Test
diff --git a/src/test/java/net/sf/jabref/logic/importer/DatabaseFileLookupTest.java b/src/test/java/net/sf/jabref/logic/importer/DatabaseFileLookupTest.java
index 1094820..249652d 100644
--- a/src/test/java/net/sf/jabref/logic/importer/DatabaseFileLookupTest.java
+++ b/src/test/java/net/sf/jabref/logic/importer/DatabaseFileLookupTest.java
@@ -34,7 +34,7 @@ public class DatabaseFileLookupTest {
try (FileInputStream stream = new FileInputStream(ImportDataTest.UNLINKED_FILES_TEST_BIB);
InputStreamReader reader = new InputStreamReader(stream, StandardCharsets.UTF_8)) {
ParserResult result = BibtexParser.parse(reader,
- ImportFormatPreferences.fromPreferences(JabRefPreferences.getInstance()));
+ JabRefPreferences.getInstance().getImportFormatPreferences());
database = result.getDatabase();
entries = database.getEntries();
diff --git a/src/test/java/net/sf/jabref/logic/importer/FulltextFetchersTest.java b/src/test/java/net/sf/jabref/logic/importer/FulltextFetchersTest.java
index 5386e73..b4c0ce2 100644
--- a/src/test/java/net/sf/jabref/logic/importer/FulltextFetchersTest.java
+++ b/src/test/java/net/sf/jabref/logic/importer/FulltextFetchersTest.java
@@ -9,7 +9,6 @@ import net.sf.jabref.model.entry.BibEntry;
import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
@@ -27,7 +26,6 @@ public class FulltextFetchersTest {
entry = null;
}
- @Ignore
@Test
public void acceptPdfUrls() throws MalformedURLException {
URL pdfUrl = new URL("http://docs.oasis-open.org/wsbpel/2.0/OS/wsbpel-v2.0-OS.pdf");
@@ -37,7 +35,6 @@ public class FulltextFetchersTest {
assertEquals(Optional.of(pdfUrl), fetcher.findFullTextPDF(entry));
}
- @Ignore // Fails on travis
@Test
public void rejectNonPdfUrls() throws MalformedURLException {
URL pdfUrl = new URL("https://github.com/JabRef/jabref/blob/master/README.md");
diff --git a/src/test/java/net/sf/jabref/logic/importer/ImportFormatReaderIntegrationTest.java b/src/test/java/net/sf/jabref/logic/importer/ImportFormatReaderIntegrationTest.java
index 817b464..da2bf0a 100644
--- a/src/test/java/net/sf/jabref/logic/importer/ImportFormatReaderIntegrationTest.java
+++ b/src/test/java/net/sf/jabref/logic/importer/ImportFormatReaderIntegrationTest.java
@@ -1,14 +1,11 @@
package net.sf.jabref.logic.importer;
-import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
-import net.sf.jabref.Globals;
-import net.sf.jabref.logic.xmp.XMPPreferences;
import net.sf.jabref.preferences.JabRefPreferences;
import org.junit.Before;
@@ -37,20 +34,19 @@ public class ImportFormatReaderIntegrationTest {
@Before
public void setUp() {
- Globals.prefs = JabRefPreferences.getInstance(); // Needed for special fields
reader = new ImportFormatReader();
- reader.resetImportFormats(ImportFormatPreferences.fromPreferences(Globals.prefs),
- XMPPreferences.fromPreferences(JabRefPreferences.getInstance()));
+ reader.resetImportFormats(JabRefPreferences.getInstance().getImportFormatPreferences(),
+ JabRefPreferences.getInstance().getXMPPreferences());
}
@Test
- public void testImportUnknownFormat() {
+ public void testImportUnknownFormat() throws Exception {
ImportFormatReader.UnknownFormatImport unknownFormat = reader.importUnknownFormat(file);
assertEquals(count, unknownFormat.parserResult.getDatabase().getEntryCount());
}
@Test
- public void testImportFormatFromFile() throws IOException {
+ public void testImportFormatFromFile() throws Exception {
assertEquals(count, reader.importFromFile(format, file).getDatabase().getEntries().size());
}
diff --git a/src/test/java/net/sf/jabref/logic/importer/ImportFormatReaderTestParameterless.java b/src/test/java/net/sf/jabref/logic/importer/ImportFormatReaderTestParameterless.java
index 96eb463..53c34e1 100644
--- a/src/test/java/net/sf/jabref/logic/importer/ImportFormatReaderTestParameterless.java
+++ b/src/test/java/net/sf/jabref/logic/importer/ImportFormatReaderTestParameterless.java
@@ -1,18 +1,13 @@
package net.sf.jabref.logic.importer;
-import java.io.IOException;
-import java.net.URISyntaxException;
import java.nio.file.Path;
import java.nio.file.Paths;
-import net.sf.jabref.Globals;
-import net.sf.jabref.logic.xmp.XMPPreferences;
import net.sf.jabref.preferences.JabRefPreferences;
import org.junit.Before;
import org.junit.Test;
-import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
public class ImportFormatReaderTestParameterless {
@@ -21,27 +16,26 @@ public class ImportFormatReaderTestParameterless {
@Before
public void setUp() {
- Globals.prefs = JabRefPreferences.getInstance(); // Needed for special fields
reader = new ImportFormatReader();
- reader.resetImportFormats(ImportFormatPreferences.fromPreferences(Globals.prefs),
- XMPPreferences.fromPreferences(Globals.prefs));
+ reader.resetImportFormats(JabRefPreferences.getInstance().getImportFormatPreferences(),
+ JabRefPreferences.getInstance().getXMPPreferences());
}
- @Test
- public void testImportUnknownFormatNotWorking() throws URISyntaxException {
+ @Test(expected = ImportException.class)
+ public void importUnknownFormatThrowsExceptionIfNoMatchingImporterWasFound() throws Exception {
Path file = Paths.get(ImportFormatReaderTestParameterless.class.getResource("fileformat/emptyFile.xml").toURI());
- ImportFormatReader.UnknownFormatImport unknownFormat = reader.importUnknownFormat(file);
- assertNull(unknownFormat);
+ reader.importUnknownFormat(file);
+ fail();
}
@Test(expected = NullPointerException.class)
- public void testNullImportUnknownFormat() {
- reader.importUnknownFormat((Path)null);
+ public void testNullImportUnknownFormat() throws Exception {
+ reader.importUnknownFormat(null);
fail();
}
- @Test(expected = IllegalArgumentException.class)
- public void testImportFromFileUnknownFormat() throws IOException {
+ @Test(expected = ImportException.class)
+ public void importFromFileWithUnknownFormatThrowsException() throws Exception {
reader.importFromFile("someunknownformat", Paths.get("somepath"));
fail();
}
diff --git a/src/test/java/net/sf/jabref/logic/importer/ImporterTest.java b/src/test/java/net/sf/jabref/logic/importer/ImporterTest.java
new file mode 100644
index 0000000..d892a6b
--- /dev/null
+++ b/src/test/java/net/sf/jabref/logic/importer/ImporterTest.java
@@ -0,0 +1,118 @@
+package net.sf.jabref.logic.importer;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.regex.Pattern;
+
+import net.sf.jabref.logic.importer.fileformat.BibTeXMLImporter;
+import net.sf.jabref.logic.importer.fileformat.BiblioscapeImporter;
+import net.sf.jabref.logic.importer.fileformat.BibtexImporter;
+import net.sf.jabref.logic.importer.fileformat.CopacImporter;
+import net.sf.jabref.logic.importer.fileformat.EndnoteImporter;
+import net.sf.jabref.logic.importer.fileformat.FreeCiteImporter;
+import net.sf.jabref.logic.importer.fileformat.InspecImporter;
+import net.sf.jabref.logic.importer.fileformat.IsiImporter;
+import net.sf.jabref.logic.importer.fileformat.MedlineImporter;
+import net.sf.jabref.logic.importer.fileformat.MedlinePlainImporter;
+import net.sf.jabref.logic.importer.fileformat.ModsImporter;
+import net.sf.jabref.logic.importer.fileformat.MsBibImporter;
+import net.sf.jabref.logic.importer.fileformat.OvidImporter;
+import net.sf.jabref.logic.importer.fileformat.PdfContentImporter;
+import net.sf.jabref.logic.importer.fileformat.PdfXmpImporter;
+import net.sf.jabref.logic.importer.fileformat.RepecNepImporter;
+import net.sf.jabref.logic.importer.fileformat.RisImporter;
+import net.sf.jabref.logic.importer.fileformat.SilverPlatterImporter;
+import net.sf.jabref.logic.xmp.XMPPreferences;
+import net.sf.jabref.preferences.JabRefPreferences;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+import org.mockito.Mockito;
+
+import static org.mockito.Mockito.when;
+
+ at RunWith(Parameterized.class)
+public class ImporterTest {
+
+ @Parameter
+ public Importer format;
+
+ @Test(expected = NullPointerException.class)
+ public void isRecognizedFormatWithNullThrowsException() throws IOException {
+ format.isRecognizedFormat(null);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void importDatabaseWithNullThrowsException() throws IOException {
+ format.importDatabase(null);
+ }
+
+ @Test
+ public void getFormatterNameDoesNotReturnNull() {
+ Assert.assertNotNull(format.getName());
+ }
+
+ @Test
+ public void getExtensionsDoesNotReturnNull() {
+ Assert.assertNotNull(format.getExtensions());
+ }
+
+ @Test
+ public void getIdDoesNotReturnNull() {
+ Assert.assertNotNull(format.getId());
+ }
+
+ @Test
+ public void getIdDoesNotContainWhitespace() {
+ Pattern whitespacePattern = Pattern.compile("\\s");
+ Assert.assertFalse(whitespacePattern.matcher(format.getId()).find());
+ }
+
+ @Test
+ public void getIdStripsSpecialCharactersAndConvertsToLowercase() {
+ Importer importer = Mockito.mock(Importer.class, Mockito.CALLS_REAL_METHODS);
+ when(importer.getName()).thenReturn("*Test-Importer");
+ Assert.assertEquals("testimporter", importer.getId());
+ }
+
+ @Test
+ public void getDescriptionDoesNotReturnNull() {
+ Assert.assertNotNull(format.getDescription());
+ }
+
+ @Parameters(name = "{index}: {0}")
+ public static Collection<Object[]> instancesToTest() {
+ // all classes implementing {@link Importer}
+ // sorted alphabetically
+
+ ImportFormatPreferences importFormatPreferences = JabRefPreferences.getInstance().getImportFormatPreferences();
+ XMPPreferences xmpPreferences = JabRefPreferences.getInstance().getXMPPreferences();
+ // @formatter:off
+ return Arrays.asList(
+ new Object[]{new BiblioscapeImporter()},
+ new Object[]{new BibtexImporter(importFormatPreferences)},
+ new Object[]{new BibTeXMLImporter()},
+ new Object[]{new CopacImporter()},
+ new Object[]{new EndnoteImporter(importFormatPreferences)},
+ new Object[]{new FreeCiteImporter(importFormatPreferences)},
+ new Object[]{new InspecImporter()},
+ new Object[]{new IsiImporter()},
+ new Object[]{new MedlineImporter()},
+ new Object[]{new MedlinePlainImporter()},
+ new Object[]{new ModsImporter()},
+ new Object[]{new MsBibImporter()},
+ new Object[]{new OvidImporter()},
+ new Object[]{new PdfContentImporter(importFormatPreferences)},
+ new Object[]{new PdfXmpImporter(xmpPreferences)},
+ new Object[]{new RepecNepImporter(importFormatPreferences)},
+ new Object[]{new RisImporter()},
+ new Object[]{new SilverPlatterImporter()}
+ );
+ // @formatter:on
+ }
+}
diff --git a/src/test/java/net/sf/jabref/logic/importer/OpenDatabaseTest.java b/src/test/java/net/sf/jabref/logic/importer/OpenDatabaseTest.java
index 9288c6c..05dcf22 100644
--- a/src/test/java/net/sf/jabref/logic/importer/OpenDatabaseTest.java
+++ b/src/test/java/net/sf/jabref/logic/importer/OpenDatabaseTest.java
@@ -9,14 +9,12 @@ import java.nio.file.Paths;
import java.util.Collection;
import java.util.Optional;
-import net.sf.jabref.Globals;
import net.sf.jabref.model.database.BibDatabase;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.preferences.JabRefPreferences;
import org.junit.Assert;
import org.junit.Before;
-import org.junit.BeforeClass;
import org.junit.Test;
public class OpenDatabaseTest {
@@ -40,15 +38,9 @@ public class OpenDatabaseTest {
.get(OpenDatabaseTest.class.getResource("encodingWithoutNewline.bib").toURI()).toFile();
}
- @BeforeClass
- public static void setUpGlobalsPrefs() {
- // otherwise FieldContentParser (called by BibtexParser) and SpecialFields crashes
- Globals.prefs = JabRefPreferences.getInstance();
- }
-
@Before
public void setUp() {
- importFormatPreferences = ImportFormatPreferences.fromPreferences(JabRefPreferences.getInstance());
+ importFormatPreferences = JabRefPreferences.getInstance().getImportFormatPreferences();
}
@Test
@@ -84,7 +76,7 @@ public class OpenDatabaseTest {
// Entry
Assert.assertEquals(1, db.getEntryCount());
- Assert.assertEquals(Optional.of("2014"), db.getEntryByKey("1").get().getFieldOptional("year"));
+ Assert.assertEquals(Optional.of("2014"), db.getEntryByKey("1").get().getField("year"));
}
@Test
@@ -94,7 +86,7 @@ public class OpenDatabaseTest {
// Entry
Assert.assertEquals(1, db.getEntryCount());
- Assert.assertEquals(Optional.of("2014"), db.getEntryByKey("1").get().getFieldOptional("year"));
+ Assert.assertEquals(Optional.of("2014"), db.getEntryByKey("1").get().getField("year"));
}
@Test
@@ -104,7 +96,7 @@ public class OpenDatabaseTest {
// Entry
Assert.assertEquals(1, db.getEntryCount());
- Assert.assertEquals(Optional.of("2014"), db.getEntryByKey("1").get().getFieldOptional("year"));
+ Assert.assertEquals(Optional.of("2014"), db.getEntryByKey("1").get().getField("year"));
}
/**
@@ -116,7 +108,7 @@ public class OpenDatabaseTest {
Assert.assertEquals(StandardCharsets.US_ASCII, result.getMetaData().getEncoding().get());
BibDatabase db = result.getDatabase();
- Assert.assertEquals("testPreamble", db.getPreamble());
+ Assert.assertEquals(Optional.of("testPreamble"), db.getPreamble());
Collection<BibEntry> entries = db.getEntries();
Assert.assertEquals(1, entries.size());
diff --git a/src/test/java/net/sf/jabref/logic/importer/ParsedBibEntryTests.java b/src/test/java/net/sf/jabref/logic/importer/ParsedBibEntryTests.java
index 639461e..ecebc8b 100644
--- a/src/test/java/net/sf/jabref/logic/importer/ParsedBibEntryTests.java
+++ b/src/test/java/net/sf/jabref/logic/importer/ParsedBibEntryTests.java
@@ -17,7 +17,7 @@ public class ParsedBibEntryTests {
@Before
public void setUp() {
- importFormatPreferences = ImportFormatPreferences.fromPreferences(JabRefPreferences.getInstance());
+ importFormatPreferences = JabRefPreferences.getInstance().getImportFormatPreferences();
}
@Test
diff --git a/src/test/java/net/sf/jabref/logic/importer/fetcher/ACSTest.java b/src/test/java/net/sf/jabref/logic/importer/fetcher/ACSTest.java
index 431c4b2..39d1394 100644
--- a/src/test/java/net/sf/jabref/logic/importer/fetcher/ACSTest.java
+++ b/src/test/java/net/sf/jabref/logic/importer/fetcher/ACSTest.java
@@ -6,12 +6,15 @@ import java.util.Optional;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.support.DevEnvironment;
+import net.sf.jabref.testutils.category.FetcherTests;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Before;
import org.junit.Test;
+import org.junit.experimental.categories.Category;
+ at Category(FetcherTests.class)
public class ACSTest {
private ACS finder;
diff --git a/src/test/java/net/sf/jabref/logic/importer/fetcher/ArXivTest.java b/src/test/java/net/sf/jabref/logic/importer/fetcher/ArXivTest.java
index 6445308..a5c914f 100644
--- a/src/test/java/net/sf/jabref/logic/importer/fetcher/ArXivTest.java
+++ b/src/test/java/net/sf/jabref/logic/importer/fetcher/ArXivTest.java
@@ -6,17 +6,23 @@ import java.util.Collections;
import java.util.Optional;
import net.sf.jabref.logic.importer.FetcherException;
+import net.sf.jabref.logic.importer.ImportFormatPreferences;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.BibLatexEntryTypes;
+import net.sf.jabref.testutils.category.FetcherTests;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.experimental.categories.Category;
import org.junit.rules.ExpectedException;
import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+ at Category(FetcherTests.class)
public class ArXivTest {
@Rule public ExpectedException expectedException = ExpectedException.none();
@@ -26,7 +32,9 @@ public class ArXivTest {
@Before
public void setUp() {
- finder = new ArXiv();
+ ImportFormatPreferences importFormatPreferences = mock(ImportFormatPreferences.class);
+ when(importFormatPreferences.getKeywordSeparator()).thenReturn(',');
+ finder = new ArXiv(importFormatPreferences);
entry = new BibEntry();
sliceTheoremPaper = new BibEntry();
@@ -134,7 +142,7 @@ public class ArXivTest {
public void searchEntryByIdWith5Digits() throws Exception {
assertEquals(Optional.of(
"An Optimal Convergence Theorem for Mean Curvature Flow of Arbitrary Codimension in Hyperbolic Spaces"),
- finder.performSearchById("1503.06747").flatMap(entry -> entry.getFieldOptional("title")));
+ finder.performSearchById("1503.06747").flatMap(entry -> entry.getField("title")));
}
@Test
diff --git a/src/test/java/net/sf/jabref/logic/importer/fetcher/AstrophysicsDataSystemTest.java b/src/test/java/net/sf/jabref/logic/importer/fetcher/AstrophysicsDataSystemTest.java
new file mode 100644
index 0000000..ff21e22
--- /dev/null
+++ b/src/test/java/net/sf/jabref/logic/importer/fetcher/AstrophysicsDataSystemTest.java
@@ -0,0 +1,203 @@
+package net.sf.jabref.logic.importer.fetcher;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+import net.sf.jabref.logic.bibtex.FieldContentParserPreferences;
+import net.sf.jabref.logic.importer.ImportFormatPreferences;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.BibLatexEntryTypes;
+import net.sf.jabref.model.entry.BibtexEntryTypes;
+import net.sf.jabref.model.entry.FieldName;
+import net.sf.jabref.testutils.category.FetcherTests;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import static net.sf.jabref.logic.util.OS.NEWLINE;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+ at Category(FetcherTests.class)
+public class AstrophysicsDataSystemTest {
+
+ private AstrophysicsDataSystem fetcher;
+ private BibEntry diezSliceTheoremEntry, famaeyMcGaughEntry, sunWelchEntry, xiongSunEntry, ingersollPollardEntry, luceyPaulEntry;
+
+ @Before
+ public void setUp() throws Exception {
+ ImportFormatPreferences importFormatPreferences = mock(ImportFormatPreferences.class);
+ when(importFormatPreferences.getFieldContentParserPreferences()).thenReturn(
+ mock(FieldContentParserPreferences.class));
+ fetcher = new AstrophysicsDataSystem(importFormatPreferences);
+
+ diezSliceTheoremEntry = new BibEntry();
+ diezSliceTheoremEntry.setType(BibtexEntryTypes.ARTICLE);
+ diezSliceTheoremEntry.setCiteKey("2014arXiv1405.2249D");
+ diezSliceTheoremEntry.setField("author", "Diez, T.");
+ diezSliceTheoremEntry.setField("title", "Slice theorem for Fr$\\backslash$'echet group actions and covariant symplectic field theory");
+ diezSliceTheoremEntry.setField("year", "2014");
+ diezSliceTheoremEntry.setField("archiveprefix", "arXiv");
+ diezSliceTheoremEntry.setField("eprint", "1405.2249");
+ diezSliceTheoremEntry.setField("journal", "ArXiv e-prints");
+ diezSliceTheoremEntry.setField("keywords", "Mathematical Physics, Mathematics - Differential Geometry, Mathematics - Symplectic Geometry, 58B99, 58Z05, 58B25, 22E65, 58D19, 53D20, 53D42");
+ diezSliceTheoremEntry.setField("month", "#may#");
+ diezSliceTheoremEntry.setField("primaryclass", "math-ph");
+ diezSliceTheoremEntry.setField("abstract",
+ "A general slice theorem for the action of a Fr$\\backslash$'echet Lie group on a" + NEWLINE
+ + "Fr$\\backslash$'echet manifolds is established. The Nash-Moser theorem provides the" + NEWLINE
+ + "fundamental tool to generalize the result of Palais to this" + NEWLINE
+ + "infinite-dimensional setting. The presented slice theorem is illustrated" + NEWLINE
+ + "by its application to gauge theories: the action of the gauge" + NEWLINE
+ + "transformation group admits smooth slices at every point and thus the" + NEWLINE
+ + "gauge orbit space is stratified by Fr$\\backslash$'echet manifolds. Furthermore, a" + NEWLINE
+ + "covariant and symplectic formulation of classical field theory is" + NEWLINE
+ + "proposed and extensively discussed. At the root of this novel framework" + NEWLINE
+ + "is the incorporation of field degrees of freedom F and spacetime M into" + NEWLINE
+ + "the product manifold F * M. The induced bigrading of differential forms" + NEWLINE
+ + "is used in order to carry over the usual symplectic theory to this new" + NEWLINE
+ + "setting. The examples of the Klein-Gordon field and general Yang-Mills" + NEWLINE
+ + "theory illustrate that the presented approach conveniently handles the" + NEWLINE
+ + "occurring symmetries." + NEWLINE);
+
+ famaeyMcGaughEntry = new BibEntry();
+ famaeyMcGaughEntry.setType(BibLatexEntryTypes.ARTICLE);
+ famaeyMcGaughEntry.setField("bibtexkey", "2012LRR....15...10F");
+ famaeyMcGaughEntry.setField("author", "Famaey, B. and McGaugh, S. S.");
+ famaeyMcGaughEntry.setField("title", "Modified Newtonian Dynamics (MOND): Observational Phenomenology and Relativistic Extensions");
+ famaeyMcGaughEntry.setField("journal", "Living Reviews in Relativity");
+ famaeyMcGaughEntry.setField("year", "2012");
+ famaeyMcGaughEntry.setField("volume", "15");
+ famaeyMcGaughEntry.setField("month", "#dec#");
+ famaeyMcGaughEntry.setField("archiveprefix", "arXiv");
+ famaeyMcGaughEntry.setField("doi", "10.12942/lrr-2012-10");
+ famaeyMcGaughEntry.setField("eid", "10");
+ famaeyMcGaughEntry.setField("eprint", "1112.3960");
+ famaeyMcGaughEntry.setField("pages", "10");
+ famaeyMcGaughEntry.setField("keywords", "astronomical observations, Newtonian limit, equations of motion, extragalactic astronomy, cosmology, theories of gravity, fundamental physics, astrophysics");
+
+ sunWelchEntry = new BibEntry();
+ sunWelchEntry.setType(BibLatexEntryTypes.ARTICLE);
+ sunWelchEntry.setField("bibtexkey", "2012NatMa..11...44S");
+ sunWelchEntry.setField("author", "Sun, Y. and Welch, G. C. and Leong, W. L. and Takacs, C. J. and Bazan, G. C. and Heeger, A. J.");
+ sunWelchEntry.setField("doi", "10.1038/nmat3160");
+ sunWelchEntry.setField("journal", "Nature Materials");
+ sunWelchEntry.setField("month", "#jan#");
+ sunWelchEntry.setField("pages", "44-48");
+ sunWelchEntry.setField("title", "Solution-processed small-molecule solar cells with 6.7\\% efficiency");
+ sunWelchEntry.setField("volume", "11");
+ sunWelchEntry.setField("year", "2012");
+
+ xiongSunEntry = new BibEntry();
+ xiongSunEntry.setType(BibLatexEntryTypes.ARTICLE);
+ xiongSunEntry.setField("bibtexkey", "2007ITGRS..45..879X");
+ xiongSunEntry.setField("author", "Xiong, X. and Sun, J. and Barnes, W. and Salomonson, V. and Esposito, J. and Erives, H. and Guenther, B.");
+ xiongSunEntry.setField("doi", "10.1109/TGRS.2006.890567");
+ xiongSunEntry.setField("journal", "IEEE Transactions on Geoscience and Remote Sensing");
+ xiongSunEntry.setField("month", "#apr#");
+ xiongSunEntry.setField("pages", "879-889");
+ xiongSunEntry.setField("title", "Multiyear On-Orbit Calibration and Performance of Terra MODIS Reflective Solar Bands");
+ xiongSunEntry.setField("volume", "45");
+ xiongSunEntry.setField("year", "2007");
+
+ ingersollPollardEntry = new BibEntry();
+ ingersollPollardEntry.setType(BibLatexEntryTypes.ARTICLE);
+ ingersollPollardEntry.setField("bibtexkey", "1982Icar...52...62I");
+ ingersollPollardEntry.setField("author", "Ingersoll, A. P. and Pollard, D.");
+ ingersollPollardEntry.setField("doi", "10.1016/0019-1035(82)90169-5");
+ ingersollPollardEntry.setField("journal", "\\icarus");
+ ingersollPollardEntry.setField("keywords", "Atmospheric Circulation, Barotropic Flow, Convective Flow, Flow Stability, Jupiter Atmosphere, Rotating Fluids, Saturn Atmosphere, Adiabatic Flow, Anelasticity, Compressible Fluids, Planetary Rotation, Rotating Cylinders, Scaling Laws, Wind Profiles, PLANETS, JUPITER, SATURN, MOTION, INTERIORS, ATMOSPHERE, ANALYSIS, SCALE, BAROTROPY, CHARACTERISTICS, STRUCTURE, WINDS, VISCOSITY, DATA, CONVECTION, ROTATION, EDDY EFFECTS, ENERGY, ADIABATI [...]
+ ingersollPollardEntry.setField("month", "#oct#");
+ ingersollPollardEntry.setField("pages", "62-80");
+ ingersollPollardEntry.setField("title", "Motion in the interiors and atmospheres of Jupiter and Saturn - Scale analysis, anelastic equations, barotropic stability criterion");
+ ingersollPollardEntry.setField("volume", "52");
+ ingersollPollardEntry.setField("year", "1982");
+
+ luceyPaulEntry = new BibEntry();
+ luceyPaulEntry.setType(BibLatexEntryTypes.ARTICLE);
+ luceyPaulEntry.setField("bibtexkey", "2000JGR...10520297L");
+ luceyPaulEntry.setField("author", "Lucey, P. G. and Blewett, D. T. and Jolliff, B. L.");
+ luceyPaulEntry.setField("doi", "10.1029/1999JE001117");
+ luceyPaulEntry.setField("journal", "\\jgr");
+ luceyPaulEntry.setField("keywords", "Planetology: Solid Surface Planets: Composition, Planetology: Solid Surface Planets: Remote sensing, Planetology: Solid Surface Planets: Surface materials and properties, Planetology: Solar System Objects: Moon (1221)");
+ luceyPaulEntry.setField("pages", "20297-20306");
+ luceyPaulEntry.setField("title", "Lunar iron and titanium abundance algorithms based on final processing of Clementine ultraviolet-visible images");
+ luceyPaulEntry.setField("volume", "105");
+ luceyPaulEntry.setField("year", "2000");
+ }
+
+ @Test
+ public void testHelpPage() {
+ assertEquals("ADS", fetcher.getHelpPage().getPageName());
+ }
+
+ @Test
+ public void testGetName() {
+ assertEquals("SAO/NASA Astrophysics Data System", fetcher.getName());
+ }
+
+ @Test
+ public void searchByQueryFindsEntry() throws Exception {
+ List<BibEntry> fetchedEntries = fetcher.performSearch("Diez slice theorem");
+ assertEquals(Collections.singletonList(diezSliceTheoremEntry), fetchedEntries);
+ }
+
+ @Test
+ public void searchByEntryFindsEntry() throws Exception {
+ BibEntry searchEntry = new BibEntry();
+ searchEntry.setField("title", "slice theorem");
+ searchEntry.setField("author", "Diez");
+
+ List<BibEntry> fetchedEntries = fetcher.performSearch(searchEntry);
+ assertFalse(fetchedEntries.isEmpty());
+ assertEquals(diezSliceTheoremEntry, fetchedEntries.get(0));
+ }
+
+ @Test
+ public void testPerformSearchByFamaeyMcGaughEntry() throws Exception {
+ Optional<BibEntry> fetchedEntry = fetcher.performSearchById("10.12942/lrr-2012-10");
+ fetchedEntry.ifPresent(entry -> entry.clearField(FieldName.ABSTRACT));//Remove abstract due to copyright
+ assertEquals(Optional.of(famaeyMcGaughEntry), fetchedEntry);
+ }
+
+ @Test
+ public void testPerformSearchByIdEmptyDOI() throws Exception {
+ Optional<BibEntry> fetchedEntry = fetcher.performSearchById("");
+ assertEquals(Optional.empty(), fetchedEntry);
+ }
+
+ @Test
+ public void testPerformSearchByIdInvalidDoi() throws Exception {
+ Optional<BibEntry> fetchedEntry = fetcher.performSearchById("this.doi.will.fail");
+ assertEquals(Optional.empty(), fetchedEntry);
+ }
+
+ @Test
+ public void testPerformSearchBySunWelchEntry() throws Exception {
+ Optional<BibEntry> fetchedEntry = fetcher.performSearchById("10.1038/nmat3160");
+ fetchedEntry.ifPresent(entry -> entry.clearField(FieldName.ABSTRACT)); //Remove abstract due to copyright
+ assertEquals(Optional.of(sunWelchEntry), fetchedEntry);
+ }
+
+ @Test
+ public void testPerformSearchByXiongSunEntry() throws Exception {
+ Optional<BibEntry> fetchedEntry = fetcher.performSearchById("10.1109/TGRS.2006.890567");
+ assertEquals(Optional.of(xiongSunEntry), fetchedEntry);
+ }
+
+ @Test
+ public void testPerformSearchByIngersollPollardEntry() throws Exception {
+ Optional<BibEntry> fetchedEntry = fetcher.performSearchById("10.1016/0019-1035(82)90169-5");
+ assertEquals(Optional.of(ingersollPollardEntry), fetchedEntry);
+ }
+
+ @Test
+ public void testPerformSearchByLuceyPaulEntry() throws Exception {
+ Optional<BibEntry> fetchedEntry = fetcher.performSearchById("10.1029/1999JE001117");
+ assertEquals(Optional.of(luceyPaulEntry), fetchedEntry);
+ }
+}
diff --git a/src/test/java/net/sf/jabref/logic/importer/fetcher/CrossRefTest.java b/src/test/java/net/sf/jabref/logic/importer/fetcher/CrossRefTest.java
index 919f655..ae7c618 100644
--- a/src/test/java/net/sf/jabref/logic/importer/fetcher/CrossRefTest.java
+++ b/src/test/java/net/sf/jabref/logic/importer/fetcher/CrossRefTest.java
@@ -4,11 +4,14 @@ import java.util.Locale;
import java.util.Optional;
import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.testutils.category.FetcherTests;
import org.junit.Test;
+import org.junit.experimental.categories.Category;
import static org.junit.Assert.assertEquals;
+ at Category(FetcherTests.class)
public class CrossRefTest {
@Test
public void findExactData() {
@@ -65,4 +68,4 @@ public class CrossRefTest {
entry.setField("author", "Stefan Kolb and Simon Harrer");
assertEquals("10.1109/sose.2014.26", CrossRef.findDOI(entry).get().getDOI().toLowerCase(Locale.ENGLISH));
}
-}
\ No newline at end of file
+}
diff --git a/src/test/java/net/sf/jabref/logic/importer/fetcher/DBLPFetcherTest.java b/src/test/java/net/sf/jabref/logic/importer/fetcher/DBLPFetcherTest.java
new file mode 100644
index 0000000..e9a4bc6
--- /dev/null
+++ b/src/test/java/net/sf/jabref/logic/importer/fetcher/DBLPFetcherTest.java
@@ -0,0 +1,68 @@
+package net.sf.jabref.logic.importer.fetcher;
+
+import java.util.Collections;
+import java.util.List;
+
+import net.sf.jabref.logic.bibtex.FieldContentParserPreferences;
+import net.sf.jabref.logic.importer.FetcherException;
+import net.sf.jabref.logic.importer.ImportFormatPreferences;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.BibtexEntryTypes;
+import net.sf.jabref.model.entry.FieldName;
+import net.sf.jabref.testutils.category.FetcherTests;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+ at Category(FetcherTests.class)
+public class DBLPFetcherTest {
+
+ private DBLPFetcher dblpFetcher;
+ private BibEntry entry;
+
+ @Before
+ public void setUp() {
+ ImportFormatPreferences importFormatPreferences = mock(ImportFormatPreferences.class);
+ when(importFormatPreferences.getFieldContentParserPreferences())
+ .thenReturn(mock(FieldContentParserPreferences.class));
+ dblpFetcher = new DBLPFetcher(importFormatPreferences);
+ entry = new BibEntry();
+
+ entry.setType(BibtexEntryTypes.ARTICLE.getName());
+ entry.setCiteKey("DBLP:journals/stt/GeigerHL16");
+ entry.setField(FieldName.TITLE,
+ "Process Engine Benchmarking with Betsy in the Context of {ISO/IEC} Quality Standards");
+ entry.setField(FieldName.AUTHOR, "Matthias Geiger and Simon Harrer and J{\\\"{o}}rg Lenhard");
+ entry.setField(FieldName.JOURNAL, "Softwaretechnik-Trends");
+ entry.setField(FieldName.VOLUME, "36");
+ entry.setField(FieldName.NUMBER, "2");
+ entry.setField(FieldName.YEAR, "2016");
+ entry.setField(FieldName.URL,
+ "http://pi.informatik.uni-siegen.de/stt/36_2/./03_Technische_Beitraege/ZEUS2016/beitrag_2.pdf");
+ entry.setField("biburl", "http://dblp.dagstuhl.de/rec/bib/journals/stt/GeigerHL16");
+ entry.setField("bibsource", "dblp computer science bibliography, http://dblp.org");
+
+ }
+
+ @Test
+ public void findSingleEntry() throws FetcherException {
+ String query = "Process Engine Benchmarking with Betsy in the Context of {ISO/IEC} Quality Standards";
+ List<BibEntry> result = dblpFetcher.performSearch(query);
+
+ Assert.assertEquals(Collections.singletonList(entry), result);
+ }
+
+ @Test
+ public void findSingleEntryUsingComplexOperators() throws FetcherException {
+ String query = "geiger harrer -wirtz betsy$ softw.trends";
+ List<BibEntry> result = dblpFetcher.performSearch(query);
+
+ Assert.assertEquals(Collections.singletonList(entry), result);
+ }
+
+}
diff --git a/src/test/java/net/sf/jabref/logic/importer/fetcher/DiVATest.java b/src/test/java/net/sf/jabref/logic/importer/fetcher/DiVATest.java
index 357e5fb..b8ad21b 100644
--- a/src/test/java/net/sf/jabref/logic/importer/fetcher/DiVATest.java
+++ b/src/test/java/net/sf/jabref/logic/importer/fetcher/DiVATest.java
@@ -3,18 +3,21 @@ package net.sf.jabref.logic.importer.fetcher;
import java.util.Optional;
import net.sf.jabref.logic.help.HelpFile;
-import net.sf.jabref.logic.importer.ImportFormatPreferences;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.preferences.JabRefPreferences;
+import net.sf.jabref.testutils.category.FetcherTests;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
+import org.junit.experimental.categories.Category;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+ at Category(FetcherTests.class)
public class DiVATest {
private DiVA fetcher;
@@ -22,7 +25,7 @@ public class DiVATest {
@Before
public void setUp() {
- fetcher = new DiVA(ImportFormatPreferences.fromPreferences(JabRefPreferences.getInstance()));
+ fetcher = new DiVA(JabRefPreferences.getInstance().getImportFormatPreferences());
}
@Test
@@ -36,6 +39,7 @@ public class DiVATest {
}
@Test
+ @Ignore("Server currently sends 500")
public void testPerformSearchById() throws Exception {
BibEntry entry = new BibEntry();
entry.setType("article");
diff --git a/src/test/java/net/sf/jabref/logic/importer/fetcher/DoiFetcherTest.java b/src/test/java/net/sf/jabref/logic/importer/fetcher/DoiFetcherTest.java
new file mode 100644
index 0000000..1eb3d20
--- /dev/null
+++ b/src/test/java/net/sf/jabref/logic/importer/fetcher/DoiFetcherTest.java
@@ -0,0 +1,85 @@
+package net.sf.jabref.logic.importer.fetcher;
+
+import java.util.Optional;
+
+import net.sf.jabref.logic.importer.FetcherException;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.BibLatexEntryTypes;
+import net.sf.jabref.preferences.JabRefPreferences;
+import net.sf.jabref.testutils.category.FetcherTests;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+ at Category(FetcherTests.class)
+public class DoiFetcherTest {
+
+ private DoiFetcher fetcher;
+ private BibEntry bibEntryBurd2011, bibEntryDecker2007;
+
+ @Before
+ public void setUp() {
+ fetcher = new DoiFetcher(JabRefPreferences.getInstance().getImportFormatPreferences());
+
+ bibEntryBurd2011 = new BibEntry();
+ bibEntryBurd2011.setType(BibLatexEntryTypes.BOOK);
+ bibEntryBurd2011.setField("bibtexkey", "Burd_2011");
+ bibEntryBurd2011.setField("title", "Java{\\textregistered} For Dummies{\\textregistered}");
+ bibEntryBurd2011.setField("publisher", "Wiley-Blackwell");
+ bibEntryBurd2011.setField("year", "2011");
+ bibEntryBurd2011.setField("author", "Barry Burd");
+ bibEntryBurd2011.setField("month", "jul");
+ bibEntryBurd2011.setField("doi", "10.1002/9781118257517");
+ bibEntryBurd2011.setField("url", "http://dx.doi.org/10.1002/9781118257517");
+
+ bibEntryDecker2007 = new BibEntry();
+ bibEntryDecker2007.setType(BibLatexEntryTypes.INPROCEEDINGS);
+ bibEntryDecker2007.setField("bibtexkey", "Decker_2007");
+ bibEntryDecker2007.setField("author", "Gero Decker and Oliver Kopp and Frank Leymann and Mathias Weske");
+ bibEntryDecker2007.setField("booktitle", "{IEEE} International Conference on Web Services ({ICWS} 2007)");
+ bibEntryDecker2007.setField("month", "jul");
+ bibEntryDecker2007.setField("publisher", "Institute of Electrical and Electronics Engineers ({IEEE})");
+ bibEntryDecker2007.setField("title", "{BPEL}4Chor: Extending {BPEL} for Modeling Choreographies");
+ bibEntryDecker2007.setField("url", "http://dx.doi.org/10.1109/ICWS.2007.59");
+ bibEntryDecker2007.setField("year", "2007");
+ bibEntryDecker2007.setField("doi", "10.1109/icws.2007.59");
+ }
+
+ @Test
+ public void testGetName() {
+ assertEquals("DOI", fetcher.getName());
+ }
+
+ @Test
+ public void testGetHelpPage() {
+ assertEquals("DOItoBibTeX", fetcher.getHelpPage().getPageName());
+ }
+
+ @Test
+ public void testPerformSearchBurd2011() throws FetcherException {
+ Optional<BibEntry> fetchedEntry = fetcher.performSearchById("10.1002/9781118257517");
+ assertEquals(Optional.of(bibEntryBurd2011), fetchedEntry);
+ }
+
+ @Test
+ public void testPerformSearchDecker2007() throws FetcherException {
+ Optional<BibEntry> fetchedEntry = fetcher.performSearchById("10.1109/ICWS.2007.59");
+ assertEquals(Optional.of(bibEntryDecker2007), fetchedEntry);
+ }
+
+ @Test(expected = FetcherException.class)
+ public void testPerformSearchEmptyDOI() throws FetcherException {
+ Optional<BibEntry> fetchedEntry = fetcher.performSearchById("");
+ assertEquals(Optional.empty(), fetchedEntry);
+ }
+
+ @Test(expected = FetcherException.class)
+ public void testPerformSearchInvalidDOI() throws FetcherException {
+ fetcher.performSearchById("10.1002/9781118257517F");
+ fail();
+ }
+}
diff --git a/src/test/java/net/sf/jabref/logic/importer/fetcher/DoiResolutionTest.java b/src/test/java/net/sf/jabref/logic/importer/fetcher/DoiResolutionTest.java
index 65247a2..dd4af49 100644
--- a/src/test/java/net/sf/jabref/logic/importer/fetcher/DoiResolutionTest.java
+++ b/src/test/java/net/sf/jabref/logic/importer/fetcher/DoiResolutionTest.java
@@ -6,13 +6,15 @@ import java.util.Optional;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.support.DevEnvironment;
+import net.sf.jabref.testutils.category.FetcherTests;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
+import org.junit.experimental.categories.Category;
+ at Category(FetcherTests.class)
public class DoiResolutionTest {
private DoiResolution finder;
@@ -48,10 +50,10 @@ public class DoiResolutionTest {
);
}
- @Ignore
@Test
public void notReturnAnythingWhenMultipleLinksAreFound() throws IOException {
- // To be implemented
+ entry.setField("doi", "10.1051/0004-6361/201527330; 10.1051/0004-6361/20152711233");
+ Assert.assertEquals(Optional.empty(), finder.findFullText(entry));
}
@Test
diff --git a/src/test/java/net/sf/jabref/logic/importer/fetcher/GVKParserTest.java b/src/test/java/net/sf/jabref/logic/importer/fetcher/GVKParserTest.java
deleted file mode 100644
index b66c755..0000000
--- a/src/test/java/net/sf/jabref/logic/importer/fetcher/GVKParserTest.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package net.sf.jabref.logic.importer.fetcher;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Optional;
-
-import javax.xml.parsers.ParserConfigurationException;
-
-import net.sf.jabref.logic.bibtex.BibEntryAssert;
-import net.sf.jabref.model.entry.BibEntry;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.xml.sax.SAXException;
-
-public class GVKParserTest {
-
- private void doTest(String xmlName, int expectedSize, List<String> resourceNames)
- throws ParserConfigurationException, SAXException, IOException {
- try (InputStream is = GVKParser.class.getResourceAsStream(xmlName)) {
- GVKParser parser = new GVKParser();
- List<BibEntry> entries = parser.parseEntries(is);
- Assert.assertNotNull(entries);
- Assert.assertEquals(expectedSize, entries.size());
- int i = 0;
- for (String resourceName : resourceNames) {
- BibEntryAssert.assertEquals(GVKParser.class, resourceName, entries.get(i));
- i++;
- }
- }
- }
-
- @Test
- public void emptyResult() throws Exception {
- doTest("gvk_empty_result_becaue_of_bad_query.xml", 0, Collections.emptyList());
- }
-
- @Test
- public void resultFor797485368() throws Exception {
- doTest("gvk_result_for_797485368.xml", 1, Arrays.asList("gvk_result_for_797485368.bib"));
- }
-
- @Test
- public void testGMP() throws Exception {
- doTest("gvk_gmp.xml", 2, Arrays.asList("gvk_gmp.1.bib", "gvk_gmp.2.bib"));
- }
-
- @Test
- public void subTitleTest() throws IOException, ParserConfigurationException, SAXException {
- try (InputStream is = GVKParser.class.getResourceAsStream("gvk_artificial_subtitle_test.xml")) {
- GVKParser parser = new GVKParser();
- List<BibEntry> entries = parser.parseEntries(is);
- Assert.assertNotNull(entries);
- Assert.assertEquals(5, entries.size());
-
- BibEntry entry = entries.get(0);
- Assert.assertEquals(Optional.empty(), entry.getFieldOptional("subtitle"));
-
- entry = entries.get(1);
- Assert.assertEquals(Optional.of("C"), entry.getFieldOptional("subtitle"));
-
- entry = entries.get(2);
- Assert.assertEquals(Optional.of("Word"), entry.getFieldOptional("subtitle"));
-
- entry = entries.get(3);
- Assert.assertEquals(Optional.of("Word1 word2"), entry.getFieldOptional("subtitle"));
-
- entry = entries.get(4);
- Assert.assertEquals(Optional.of("Word1 word2"), entry.getFieldOptional("subtitle"));
- }
- }
-}
diff --git a/src/test/java/net/sf/jabref/logic/importer/fetcher/GoogleScholarTest.java b/src/test/java/net/sf/jabref/logic/importer/fetcher/GoogleScholarTest.java
index 2f6ac2c..3aa21f4 100644
--- a/src/test/java/net/sf/jabref/logic/importer/fetcher/GoogleScholarTest.java
+++ b/src/test/java/net/sf/jabref/logic/importer/fetcher/GoogleScholarTest.java
@@ -2,16 +2,29 @@ package net.sf.jabref.logic.importer.fetcher;
import java.io.IOException;
import java.net.URL;
+import java.util.Collections;
+import java.util.List;
import java.util.Optional;
+import net.sf.jabref.logic.bibtex.FieldContentParserPreferences;
+import net.sf.jabref.logic.importer.FetcherException;
+import net.sf.jabref.logic.importer.ImportFormatPreferences;
import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.BibtexEntryTypes;
+import net.sf.jabref.model.entry.FieldName;
import net.sf.jabref.support.DevEnvironment;
+import net.sf.jabref.testutils.category.FetcherTests;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Before;
import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+ at Category(FetcherTests.class)
public class GoogleScholarTest {
private GoogleScholar finder;
@@ -19,25 +32,28 @@ public class GoogleScholarTest {
@Before
public void setUp() {
- finder = new GoogleScholar();
+ ImportFormatPreferences importFormatPreferences = mock(ImportFormatPreferences.class);
+ when(importFormatPreferences.getFieldContentParserPreferences()).thenReturn(
+ mock(FieldContentParserPreferences.class));
+ finder = new GoogleScholar(importFormatPreferences);
entry = new BibEntry();
}
@Test(expected = NullPointerException.class)
- public void rejectNullParameter() throws IOException {
+ public void rejectNullParameter() throws IOException, FetcherException {
finder.findFullText(null);
Assert.fail();
}
@Test
- public void requiresEntryTitle() throws IOException {
+ public void requiresEntryTitle() throws IOException, FetcherException {
Assert.assertEquals(Optional.empty(), finder.findFullText(entry));
}
@Test
- public void linkFound() throws IOException {
+ public void linkFound() throws IOException, FetcherException {
// CI server is blocked by Google
- Assume.assumeFalse(DevEnvironment.isCIServer());
+ Assume.assumeFalse(DevEnvironment.isCircleCI() || DevEnvironment.isSnapCI());
entry.setField("title", "Towards Application Portability in Platform as a Service");
@@ -48,12 +64,40 @@ public class GoogleScholarTest {
}
@Test
- public void noLinkFound() throws IOException {
+ public void noLinkFound() throws IOException, FetcherException {
// CI server is blocked by Google
- Assume.assumeFalse(DevEnvironment.isCIServer());
+ Assume.assumeFalse(DevEnvironment.isCircleCI() || DevEnvironment.isSnapCI());
entry.setField("title", "Pro WF: Windows Workflow in NET 3.5");
Assert.assertEquals(Optional.empty(), finder.findFullText(entry));
}
+
+ @Test
+ public void findSingleEntry() throws FetcherException {
+ // CI server is blocked by Google
+ Assume.assumeFalse(DevEnvironment.isCircleCI() || DevEnvironment.isSnapCI());
+
+ entry.setType(BibtexEntryTypes.INPROCEEDINGS.getName());
+ entry.setCiteKey("geiger2013detecting");
+ entry.setField(FieldName.TITLE, "Detecting Interoperability and Correctness Issues in BPMN 2.0 Process Models.");
+ entry.setField(FieldName.AUTHOR, "Geiger, Matthias and Wirtz, Guido");
+ entry.setField(FieldName.BOOKTITLE, "ZEUS");
+ entry.setField(FieldName.YEAR, "2013");
+ entry.setField(FieldName.PAGES, "41--44");
+
+ List<BibEntry> foundEntries = finder.performSearch("info:RExzBa3OlkQJ:scholar.google.com");
+
+ Assert.assertEquals(Collections.singletonList(entry), foundEntries);
+ }
+
+ @Test
+ public void find20Entries() throws FetcherException {
+ // CI server is blocked by Google
+ Assume.assumeFalse(DevEnvironment.isCircleCI() || DevEnvironment.isSnapCI());
+
+ List<BibEntry> foundEntries = finder.performSearch("random test string");
+
+ Assert.assertEquals(20, foundEntries.size());
+ }
}
diff --git a/src/test/java/net/sf/jabref/logic/importer/fetcher/GvkFetcherTest.java b/src/test/java/net/sf/jabref/logic/importer/fetcher/GvkFetcherTest.java
index 285b9ce..70f5ed3 100644
--- a/src/test/java/net/sf/jabref/logic/importer/fetcher/GvkFetcherTest.java
+++ b/src/test/java/net/sf/jabref/logic/importer/fetcher/GvkFetcherTest.java
@@ -9,13 +9,16 @@ import java.util.List;
import net.sf.jabref.logic.importer.FetcherException;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.BibLatexEntryTypes;
+import net.sf.jabref.testutils.category.FetcherTests;
import org.junit.Before;
import org.junit.Test;
+import org.junit.experimental.categories.Category;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+ at Category(FetcherTests.class)
public class GvkFetcherTest {
private GvkFetcher fetcher;
@@ -61,7 +64,7 @@ public class GvkFetcherTest {
@Test
public void testGetHelpPage() {
- assertEquals("GVKHelp", fetcher.getHelpPage().getPageName());
+ assertEquals("GVK", fetcher.getHelpPage().getPageName());
}
@Test
@@ -74,7 +77,7 @@ public class GvkFetcherTest {
@Test
public void simpleSearchQueryURLCorrect() throws MalformedURLException, URISyntaxException, FetcherException {
String query = "java jdk";
- URL url = fetcher.getQueryURL(query);
+ URL url = fetcher.getURLForQuery(query);
assertEquals("http://sru.gbv.de/gvk?version=1.1&operation=searchRetrieve&query=pica.all%3Djava+jdk&maximumRecords=50&recordSchema=picaxml&sortKeys=Year%2C%2C1", url.toString());
}
@@ -88,7 +91,7 @@ public class GvkFetcherTest {
@Test
public void complexSearchQueryURLCorrect() throws MalformedURLException, URISyntaxException, FetcherException {
String query = "kon java tit jdk";
- URL url = fetcher.getQueryURL(query);
+ URL url = fetcher.getURLForQuery(query);
assertEquals("http://sru.gbv.de/gvk?version=1.1&operation=searchRetrieve&query=pica.kon%3Djava+and+pica.tit%3Djdk&maximumRecords=50&recordSchema=picaxml&sortKeys=Year%2C%2C1", url.toString());
}
diff --git a/src/test/java/net/sf/jabref/logic/importer/fetcher/GvkParserTest.java b/src/test/java/net/sf/jabref/logic/importer/fetcher/GvkParserTest.java
new file mode 100644
index 0000000..ae3184b
--- /dev/null
+++ b/src/test/java/net/sf/jabref/logic/importer/fetcher/GvkParserTest.java
@@ -0,0 +1,71 @@
+package net.sf.jabref.logic.importer.fetcher;
+
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+import net.sf.jabref.logic.bibtex.BibEntryAssert;
+import net.sf.jabref.logic.importer.fileformat.GvkParser;
+import net.sf.jabref.model.entry.BibEntry;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class GvkParserTest {
+
+ private void doTest(String xmlName, int expectedSize, List<String> resourceNames) throws Exception {
+ try (InputStream is = GvkParserTest.class.getResourceAsStream(xmlName)) {
+ GvkParser parser = new GvkParser();
+ List<BibEntry> entries = parser.parseEntries(is);
+ Assert.assertNotNull(entries);
+ Assert.assertEquals(expectedSize, entries.size());
+ int i = 0;
+ for (String resourceName : resourceNames) {
+ BibEntryAssert.assertEquals(GvkParserTest.class, resourceName, entries.get(i));
+ i++;
+ }
+ }
+ }
+
+ @Test
+ public void emptyResult() throws Exception {
+ doTest("gvk_empty_result_because_of_bad_query.xml", 0, Collections.emptyList());
+ }
+
+ @Test
+ public void resultFor797485368() throws Exception {
+ doTest("gvk_result_for_797485368.xml", 1, Collections.singletonList("gvk_result_for_797485368.bib"));
+ }
+
+ @Test
+ public void testGMP() throws Exception {
+ doTest("gvk_gmp.xml", 2, Arrays.asList("gvk_gmp.1.bib", "gvk_gmp.2.bib"));
+ }
+
+ @Test
+ public void subTitleTest() throws Exception {
+ try (InputStream is = GvkParserTest.class.getResourceAsStream("gvk_artificial_subtitle_test.xml")) {
+ GvkParser parser = new GvkParser();
+ List<BibEntry> entries = parser.parseEntries(is);
+ Assert.assertNotNull(entries);
+ Assert.assertEquals(5, entries.size());
+
+ BibEntry entry = entries.get(0);
+ Assert.assertEquals(Optional.empty(), entry.getField("subtitle"));
+
+ entry = entries.get(1);
+ Assert.assertEquals(Optional.of("C"), entry.getField("subtitle"));
+
+ entry = entries.get(2);
+ Assert.assertEquals(Optional.of("Word"), entry.getField("subtitle"));
+
+ entry = entries.get(3);
+ Assert.assertEquals(Optional.of("Word1 word2"), entry.getField("subtitle"));
+
+ entry = entries.get(4);
+ Assert.assertEquals(Optional.of("Word1 word2"), entry.getField("subtitle"));
+ }
+ }
+}
diff --git a/src/test/java/net/sf/jabref/logic/importer/fetcher/IEEETest.java b/src/test/java/net/sf/jabref/logic/importer/fetcher/IEEETest.java
index 6a3b148..ec273e2 100644
--- a/src/test/java/net/sf/jabref/logic/importer/fetcher/IEEETest.java
+++ b/src/test/java/net/sf/jabref/logic/importer/fetcher/IEEETest.java
@@ -6,12 +6,16 @@ import java.util.Optional;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.support.DevEnvironment;
+import net.sf.jabref.testutils.category.FetcherTests;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
+import org.junit.experimental.categories.Category;
+ at Category(FetcherTests.class)
public class IEEETest {
private IEEE finder;
private BibEntry entry;
@@ -34,10 +38,8 @@ public class IEEETest {
}
@Test
+ @Ignore("Fails both locally and on TravisCI")
public void findByDOI() throws IOException {
- // CI server is unreliable
- Assume.assumeFalse(DevEnvironment.isCIServer());
-
entry.setField("doi", "10.1109/ACCESS.2016.2535486");
Assert.assertEquals(
@@ -47,10 +49,8 @@ public class IEEETest {
}
@Test
+ @Ignore("Fails both locally and on TravisCI")
public void findByURL() throws IOException {
- // CI server is unreliable
- Assume.assumeFalse(DevEnvironment.isCIServer());
-
entry.setField("url", "http://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=7421926");
Assert.assertEquals(
@@ -60,10 +60,8 @@ public class IEEETest {
}
@Test
+ @Ignore("Fails both locally and on TravisCI")
public void findByOldURL() throws IOException {
- // CI server is unreliable
- Assume.assumeFalse(DevEnvironment.isCIServer());
-
entry.setField("url", "http://ieeexplore.ieee.org/stamp/stamp.jsp?arnumber=7421926");
Assert.assertEquals(
@@ -73,10 +71,8 @@ public class IEEETest {
}
@Test
+ @Ignore("Fails both locally and on TravisCI")
public void findByDOIButNotURL() throws IOException {
- // CI server is unreliable
- Assume.assumeFalse(DevEnvironment.isCIServer());
-
entry.setField("doi", "10.1109/ACCESS.2016.2535486");
entry.setField("url", "http://dx.doi.org/10.1109/ACCESS.2016.2535486");
diff --git a/src/test/java/net/sf/jabref/logic/importer/fetcher/IsbnFetcherTest.java b/src/test/java/net/sf/jabref/logic/importer/fetcher/IsbnFetcherTest.java
new file mode 100644
index 0000000..8c133a6
--- /dev/null
+++ b/src/test/java/net/sf/jabref/logic/importer/fetcher/IsbnFetcherTest.java
@@ -0,0 +1,93 @@
+package net.sf.jabref.logic.importer.fetcher;
+
+import java.util.Optional;
+
+import net.sf.jabref.logic.importer.FetcherException;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.BibLatexEntryTypes;
+import net.sf.jabref.preferences.JabRefPreferences;
+import net.sf.jabref.testutils.category.FetcherTests;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import static org.junit.Assert.assertEquals;
+
+ at Category(FetcherTests.class)
+public class IsbnFetcherTest {
+
+ private IsbnFetcher fetcher;
+ private BibEntry bibEntry;
+
+ @Before
+ public void setUp() {
+ fetcher = new IsbnFetcher(JabRefPreferences.getInstance().getImportFormatPreferences());
+
+ bibEntry = new BibEntry();
+ bibEntry.setType(BibLatexEntryTypes.BOOK);
+ bibEntry.setField("bibtexkey", "9780321356680");
+ bibEntry.setField("title", "Effective Java");
+ bibEntry.setField("publisher", "Addison Wesley");
+ bibEntry.setField("year", "2008");
+ bibEntry.setField("author", "Joshua Bloch");
+ bibEntry.setField("date", "2008-05-08");
+ bibEntry.setField("ean", "9780321356680");
+ bibEntry.setField("isbn", "0321356683");
+ bibEntry.setField("pagetotal", "384");
+ }
+
+ @Test
+ public void testName() {
+ assertEquals("ISBN", fetcher.getName());
+ }
+
+ @Test
+ public void testHelpPage() {
+ assertEquals("ISBNtoBibTeX", fetcher.getHelpPage().getPageName());
+ }
+
+ @Test
+ public void searchByIdSuccessfulWithShortISBN() throws FetcherException {
+ Optional<BibEntry> fetchedEntry = fetcher.performSearchById("0321356683");
+ assertEquals(Optional.of(bibEntry), fetchedEntry);
+ }
+
+ @Test
+ public void searchByIdSuccessfulWithLongISBN() throws FetcherException {
+ Optional<BibEntry> fetchedEntry = fetcher.performSearchById("978-0321356680");
+ assertEquals(Optional.of(bibEntry), fetchedEntry);
+ }
+
+ @Test
+ public void searchByIdReturnsEmptyWithEmptyISBN() throws FetcherException {
+ Optional<BibEntry> fetchedEntry = fetcher.performSearchById("");
+ assertEquals(Optional.empty(), fetchedEntry);
+ }
+
+ @Test(expected = FetcherException.class)
+ public void searchByIdThrowsExceptionForShortInvalidISBN() throws FetcherException {
+ fetcher.performSearchById("123456789");
+ }
+
+ @Test(expected = FetcherException.class)
+ public void searchByIdThrowsExceptionForLongInvalidISB() throws FetcherException {
+ fetcher.performSearchById("012345678910");
+ }
+
+ @Test(expected = FetcherException.class)
+ public void searchByIdThrowsExceptionForInvalidISBN() throws FetcherException {
+ fetcher.performSearchById("jabref-4-ever");
+ }
+
+ /**
+ * This test searches for a valid ISBN. See https://www.amazon.de/dp/3728128155/?tag=jabref-21
+ * However, this ISBN is not available on ebook.de. The fetcher should return nothing rather than throwing an exeption.
+ */
+ @Test
+ public void searchForValidButNotFoundISBN() throws Exception {
+ Optional<BibEntry> fetchedEntry = fetcher.performSearchById("3728128155");
+ assertEquals(Optional.empty(), fetchedEntry);
+ }
+
+}
diff --git a/src/test/java/net/sf/jabref/logic/importer/fetcher/MathSciNetTest.java b/src/test/java/net/sf/jabref/logic/importer/fetcher/MathSciNetTest.java
new file mode 100644
index 0000000..ebd2ceb
--- /dev/null
+++ b/src/test/java/net/sf/jabref/logic/importer/fetcher/MathSciNetTest.java
@@ -0,0 +1,72 @@
+package net.sf.jabref.logic.importer.fetcher;
+
+import java.util.List;
+
+import net.sf.jabref.logic.bibtex.FieldContentParserPreferences;
+import net.sf.jabref.logic.importer.ImportFormatPreferences;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.BibtexEntryTypes;
+import net.sf.jabref.support.DevEnvironment;
+import net.sf.jabref.testutils.category.FetcherTests;
+
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+ at Category(FetcherTests.class)
+public class MathSciNetTest {
+
+ MathSciNet fetcher;
+ BibEntry ratiuEntry;
+
+ @Before
+ public void setUp() throws Exception {
+ ImportFormatPreferences importFormatPreferences = mock(ImportFormatPreferences.class);
+ when(importFormatPreferences.getFieldContentParserPreferences()).thenReturn(
+ mock(FieldContentParserPreferences.class));
+ fetcher = new MathSciNet(importFormatPreferences);
+
+ ratiuEntry = new BibEntry();
+ ratiuEntry.setType(BibtexEntryTypes.ARTICLE);
+ ratiuEntry.setCiteKey("MR3537908");
+ ratiuEntry.setField("author", "Chechkin, Gregory A. and Ratiu, Tudor S. and Romanov, Maxim S. and Samokhin, Vyacheslav N.");
+ ratiuEntry.setField("title", "Existence and uniqueness theorems for the two-dimensional {E}ricksen-{L}eslie system");
+ ratiuEntry.setField("journal", "Journal of Mathematical Fluid Mechanics");
+ ratiuEntry.setField("volume", "18");
+ ratiuEntry.setField("year", "2016");
+ ratiuEntry.setField("number", "3");
+ ratiuEntry.setField("pages", "571--589");
+ ratiuEntry.setField("issn", "1422-6928");
+ ratiuEntry.setField("keywords", "76A15 (35A01 35A02 35K61)");
+ ratiuEntry.setField("mrnumber", "3537908");
+ ratiuEntry.setField("doi", "10.1007/s00021-016-0250-0");
+ }
+
+ @Test
+ public void searchByEntryFindsEntry() throws Exception {
+ BibEntry searchEntry = new BibEntry();
+ searchEntry.setField("title", "existence");
+ searchEntry.setField("author", "Ratiu");
+ searchEntry.setField("journal", "fluid");
+
+ List<BibEntry> fetchedEntries = fetcher.performSearch(searchEntry);
+ assertFalse(fetchedEntries.isEmpty());
+ assertEquals(ratiuEntry, fetchedEntries.get(0));
+ }
+
+ @Test
+ public void searchByQueryFindsEntry() throws Exception {
+ // CI has no subscription to zbMath and thus gets 401 response
+ Assume.assumeFalse(DevEnvironment.isCIServer());
+
+ List<BibEntry> fetchedEntries = fetcher.performSearch("Two-Dimensional Ericksen Leslie System");
+ assertFalse(fetchedEntries.isEmpty());
+ assertEquals(ratiuEntry, fetchedEntries.get(0));
+ }
+}
diff --git a/src/test/java/net/sf/jabref/logic/importer/fetcher/MedlineFetcherTest.java b/src/test/java/net/sf/jabref/logic/importer/fetcher/MedlineFetcherTest.java
new file mode 100644
index 0000000..8ff31a5
--- /dev/null
+++ b/src/test/java/net/sf/jabref/logic/importer/fetcher/MedlineFetcherTest.java
@@ -0,0 +1,192 @@
+package net.sf.jabref.logic.importer.fetcher;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+import net.sf.jabref.logic.importer.FetcherException;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.BibLatexEntryTypes;
+import net.sf.jabref.model.entry.FieldName;
+import net.sf.jabref.testutils.category.FetcherTests;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+ at Category(FetcherTests.class)
+public class MedlineFetcherTest {
+
+ private MedlineFetcher fetcher;
+ private BibEntry entryWijedasa, entryEndharti, bibEntryIchikawa, bibEntrySari;
+
+ @Before
+ public void setUp() {
+ fetcher = new MedlineFetcher();
+
+ entryWijedasa = new BibEntry();
+ entryWijedasa.setType(BibLatexEntryTypes.ARTICLE);
+ entryWijedasa.setField("author", "Wijedasa, Lahiru S and Jauhiainen, Jyrki and Könönen, Mari and Lampela, Maija and Vasander, Harri and LeBlanc, Marie-Claire and Evers, Stephanie and Smith, Thomas E L and Yule, Catherine M and Varkkey, Helena and Lupascu, Massimo and Parish, Faizal and Singleton, Ian and Clements, Gopalasamy R and Aziz, Sheema Abdul and Harrison, Mark E and Cheyne, Susan and Anshari, Gusti Z and Meijaard, Erik and Goldstein, Jenny E and Waldron, Susan and Hergoua [...]
+ entryWijedasa.setField("created", "2016-09-27");
+ entryWijedasa.setField("country", "England");
+ entryWijedasa.setField("doi", "10.1111/gcb.13516");
+ entryWijedasa.setField("issn", "1365-2486");
+ entryWijedasa.setField("issn-linking", "1354-1013");
+ entryWijedasa.setField("journal", "Global change biology");
+ entryWijedasa.setField("keywords", "Acacia; Agriculture; Emissions; Subsidence; Sustainability; Tropical peatlands; oil palm");
+ entryWijedasa.setField("month", "Sep");
+ entryWijedasa.setField("nlm-id", "9888746");
+ entryWijedasa.setField("owner", "NLM");
+ entryWijedasa.setField("pmid", "27670948");
+ entryWijedasa.setField("pubmodel", "Print-Electronic");
+ entryWijedasa.setField("pubstatus", "aheadofprint");
+ entryWijedasa.setField("revised", "2016-09-27");
+ entryWijedasa.setField("title", "Denial of long-term issues with agriculture on tropical peatlands will have devastating consequences.");
+ entryWijedasa.setField("year", "2016");
+
+ entryEndharti = new BibEntry();
+ entryEndharti.setType(BibLatexEntryTypes.ARTICLE);
+ entryEndharti.setField("title", "Dendrophthoe pentandra (L.) Miq extract effectively inhibits inflammation, proliferation and induces p53 expression on colitis-associated colon cancer.");
+ entryEndharti.setField("author", "Endharti, Agustina Tri and Wulandari, Adisti and Listyana, Anik and Norahmawati, Eviana and Permana, Sofy");
+ entryEndharti.setField("created", "2016-09-27");
+ entryEndharti.setField("country", "England");
+ entryEndharti.setField("doi", "10.1186/s12906-016-1345-0");
+ entryEndharti.setField("pii", "10.1186/s12906-016-1345-0");
+ entryEndharti.setField("pmc", "PMC5037598");
+ entryEndharti.setField("issn", "1472-6882");
+ entryEndharti.setField("issn-linking", "1472-6882");
+ entryEndharti.setField("issue", "1");
+ entryEndharti.setField("journal", "BMC complementary and alternative medicine");
+ entryEndharti.setField("keywords", "CAC; Dendrophtoe pentandra; IL-22; MPO; Proliferation; p53");
+ entryEndharti.setField("nlm-id", "101088661");
+ entryEndharti.setField("owner", "NLM");
+ entryEndharti.setField("pages", "374");
+ entryEndharti.setField("month", "Sep");
+ entryEndharti.setField("pmid", "27670445");
+ entryEndharti.setField("pubmodel", "Electronic");
+ entryEndharti.setField("pubstatus", "epublish");
+ entryEndharti.setField("revised", "2016-10-11");
+ entryEndharti.setField("volume", "16");
+ entryEndharti.setField("year", "2016");
+
+ bibEntryIchikawa = new BibEntry();
+ bibEntryIchikawa.setType(BibLatexEntryTypes.ARTICLE);
+ bibEntryIchikawa.setField("author", "Ichikawa-Seki, Madoka and Guswanto, Azirwan and Allamanda, Puttik and Mariamah, Euis Siti and Wibowo, Putut Eko and Igarashi, Ikuo and Nishikawa, Yoshifumi");
+ bibEntryIchikawa.setField("chemicals", "Antibodies, Protozoan, Antigens, Protozoan, GRA7 protein, Toxoplasma gondii, Protozoan Proteins");
+ bibEntryIchikawa.setField("citation-subset", "IM");
+ bibEntryIchikawa.setField("completed", "2016-07-26");
+ bibEntryIchikawa.setField("country", "Netherlands");
+ bibEntryIchikawa.setField("created", "2015-09-26");
+ bibEntryIchikawa.setField("doi", "10.1016/j.parint.2015.07.004");
+ bibEntryIchikawa.setField("issn", "1873-0329");
+ bibEntryIchikawa.setField("pubstatus", "ppublish");
+ bibEntryIchikawa.setField("revised", "2015-09-26");
+ bibEntryIchikawa.setField("issn-linking", "1383-5769");
+ bibEntryIchikawa.setField("issue", "6");
+ bibEntryIchikawa.setField("journal", "Parasitology international");
+ bibEntryIchikawa.setField("keywords", "Animals; Antibodies, Protozoan, blood; Antigens, Protozoan, immunology; Cattle, parasitology; Cattle Diseases, epidemiology, parasitology; Enzyme-Linked Immunosorbent Assay, veterinary; Geography; Humans; Indonesia, epidemiology; Livestock, immunology, parasitology; Meat, parasitology; Protozoan Proteins, immunology; Seroepidemiologic Studies; Swine, parasitology; Swine Diseases, epidemiology, parasitology; Toxoplasma, immunology; Toxoplasmo [...]
+ bibEntryIchikawa.setField("month", "Dec");
+ bibEntryIchikawa.setField("nlm-id", "9708549");
+ bibEntryIchikawa.setField("owner", "NLM");
+ bibEntryIchikawa.setField("pages", "484--486");
+ bibEntryIchikawa.setField("pii", "S1383-5769(15)00124-5");
+ bibEntryIchikawa.setField("pmid", "26197440");
+ bibEntryIchikawa.setField("pubmodel", "Print-Electronic");
+ bibEntryIchikawa.setField("title", "Seroprevalence of antibody to TgGRA7 antigen of Toxoplasma gondii in livestock animals from Western Java, Indonesia.");
+ bibEntryIchikawa.setField("volume", "64");
+ bibEntryIchikawa.setField("year", "2015");
+
+ bibEntrySari = new BibEntry();
+ bibEntrySari.setType(BibLatexEntryTypes.ARTICLE);
+ bibEntrySari.setField("author", "Sari, Yulia and Haryati, Sri and Raharjo, Irvan and Prasetyo, Afiono Agung");
+ bibEntrySari.setField("chemicals", "Antibodies, Protozoan, Antibodies, Viral, HTLV-I Antibodies, HTLV-II Antibodies, Hepatitis Antibodies, Hepatitis B Antibodies, Hepatitis C Antibodies, Immunoglobulin G, Immunoglobulin M");
+ bibEntrySari.setField("citation-subset", "IM");
+ bibEntrySari.setField("completed", "2016-04-21");
+ bibEntrySari.setField("country", "Thailand");
+ bibEntrySari.setField("created", "2016-02-12");
+ bibEntrySari.setField("issn", "0125-1562");
+ bibEntrySari.setField("issn-linking", "0125-1562");
+ bibEntrySari.setField("issue", "6");
+ bibEntrySari.setField("journal", "The Southeast Asian journal of tropical medicine and public health");
+ bibEntrySari.setField("keywords", "Antibodies, Protozoan; Antibodies, Viral, immunology; Coinfection, epidemiology, immunology; Female; HIV Infections, epidemiology; HTLV-I Antibodies, immunology; HTLV-I Infections, epidemiology, immunology; HTLV-II Antibodies, immunology; HTLV-II Infections, epidemiology, immunology; Hepatitis Antibodies, immunology; Hepatitis B Antibodies, immunology; Hepatitis C Antibodies, immunology; Hepatitis Delta Virus, immunology; Hepatitis, Viral, Human [...]
+ bibEntrySari.setField("month", "Nov");
+ bibEntrySari.setField("pubstatus", "ppublish");
+ bibEntrySari.setField("revised", "2016-02-12");
+ bibEntrySari.setField("nlm-id", "0266303");
+ bibEntrySari.setField("owner", "NLM");
+ bibEntrySari.setField("pages", "977--985");
+ bibEntrySari.setField("pmid", "26867355");
+ bibEntrySari.setField("pubmodel", "Print");
+ bibEntrySari.setField("title", "TOXOPLASMA AND VIRAL ANTIBODIES AMONG HIV PATIENTS AND INMATES IN CENTRAL JAVA, INDONESIA.");
+ bibEntrySari.setField("volume", "46");
+ bibEntrySari.setField("year", "2015");
+ }
+
+ @Test
+ public void testGetName() {
+ assertEquals("Medline", fetcher.getName());
+ }
+
+ @Test
+ public void testGetHelpPage() {
+ assertEquals("Medline", fetcher.getHelpPage().getPageName());
+ }
+
+ @Test
+ public void testSearchByIDWijedasa() throws Exception {
+ Optional<BibEntry> fetchedEntry = fetcher.performSearchById("27670948");
+ fetchedEntry.get().clearField(FieldName.ABSTRACT); //Remove abstract due to copyright
+ assertEquals(Optional.of(entryWijedasa), fetchedEntry);
+ }
+
+ @Test
+ public void testSearchByIDEndharti() throws Exception {
+ Optional<BibEntry> fetchedEntry = fetcher.performSearchById("27670445");
+ fetchedEntry.get().clearField(FieldName.ABSTRACT); //Remove abstract due to copyright
+ assertEquals(Optional.of(entryEndharti), fetchedEntry);
+ }
+
+ @Test
+ public void testSearchByIDIchikawa() throws Exception {
+ Optional<BibEntry> fetchedEntry = fetcher.performSearchById("26197440");
+ fetchedEntry.get().clearField(FieldName.ABSTRACT); //Remove abstract due to copyright
+ assertEquals(Optional.of(bibEntryIchikawa), fetchedEntry);
+ }
+
+ @Test
+ public void testSearchByIDSari() throws Exception {
+ Optional<BibEntry> fetchedEntry = fetcher.performSearchById("26867355");
+ fetchedEntry.get().clearField(FieldName.ABSTRACT); //Remove abstract due to copyright
+ assertEquals(Optional.of(bibEntrySari), fetchedEntry);
+ }
+
+ @Test
+ public void testMultipleEntries() throws Exception {
+ List<BibEntry> entryList = fetcher.performSearch("java");
+ entryList.forEach(entry -> entry.clearField(FieldName.ABSTRACT)); //Remove abstract due to copyright);
+ assertEquals(50, entryList.size());
+ assertTrue(entryList.contains(bibEntryIchikawa));
+ assertTrue(entryList.contains(bibEntrySari));
+ }
+
+ @Test(expected = FetcherException.class)//caused by Optional.of(entry.get(0))
+ public void testInvalidSearchTermCauseIndexOutOfBoundsException() throws Exception {
+ fetcher.performSearchById("this.is.a.invalid.search.term.for.the.medline.fetcher");
+ fail();
+ }
+
+ @Test
+ public void testEmptyEntryList() throws Exception {
+ List<BibEntry> entryList = fetcher.performSearch("java is fantastic and awesome ");
+ assertEquals(Collections.emptyList(), entryList);
+ }
+
+ @Test
+ public void testEmptyInput() throws Exception {
+ assertEquals(Collections.emptyList(), fetcher.performSearch(""));
+ }
+}
diff --git a/src/test/java/net/sf/jabref/logic/importer/fetcher/ScienceDirectTest.java b/src/test/java/net/sf/jabref/logic/importer/fetcher/ScienceDirectTest.java
index 34bb1c7..e186570 100644
--- a/src/test/java/net/sf/jabref/logic/importer/fetcher/ScienceDirectTest.java
+++ b/src/test/java/net/sf/jabref/logic/importer/fetcher/ScienceDirectTest.java
@@ -6,12 +6,15 @@ import java.util.Optional;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.support.DevEnvironment;
+import net.sf.jabref.testutils.category.FetcherTests;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Before;
import org.junit.Test;
+import org.junit.experimental.categories.Category;
+ at Category(FetcherTests.class)
public class ScienceDirectTest {
private ScienceDirect finder;
diff --git a/src/test/java/net/sf/jabref/logic/importer/fetcher/SpringerLinkTest.java b/src/test/java/net/sf/jabref/logic/importer/fetcher/SpringerLinkTest.java
index 7dca120..dff5eb6 100644
--- a/src/test/java/net/sf/jabref/logic/importer/fetcher/SpringerLinkTest.java
+++ b/src/test/java/net/sf/jabref/logic/importer/fetcher/SpringerLinkTest.java
@@ -5,11 +5,14 @@ import java.net.URL;
import java.util.Optional;
import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.testutils.category.FetcherTests;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
+import org.junit.experimental.categories.Category;
+ at Category(FetcherTests.class)
public class SpringerLinkTest {
private SpringerLink finder;
@@ -34,8 +37,6 @@ public class SpringerLinkTest {
@Test
public void findByDOI() throws IOException {
-
-
entry.setField("doi", "10.1186/s13677-015-0042-8");
Assert.assertEquals(
diff --git a/src/test/java/net/sf/jabref/logic/importer/fetcher/zbMATHTest.java b/src/test/java/net/sf/jabref/logic/importer/fetcher/zbMATHTest.java
new file mode 100644
index 0000000..4fc3e87
--- /dev/null
+++ b/src/test/java/net/sf/jabref/logic/importer/fetcher/zbMATHTest.java
@@ -0,0 +1,58 @@
+package net.sf.jabref.logic.importer.fetcher;
+
+import java.util.Collections;
+import java.util.List;
+
+import net.sf.jabref.logic.bibtex.FieldContentParserPreferences;
+import net.sf.jabref.logic.importer.ImportFormatPreferences;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.BibtexEntryTypes;
+import net.sf.jabref.support.DevEnvironment;
+import net.sf.jabref.testutils.category.FetcherTests;
+
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+ at Category(FetcherTests.class)
+public class zbMATHTest {
+ private zbMATH fetcher;
+ private BibEntry donaldsonEntry;
+
+ @Before
+ public void setUp() throws Exception {
+ ImportFormatPreferences importFormatPreferences = mock(ImportFormatPreferences.class);
+ when(importFormatPreferences.getFieldContentParserPreferences()).thenReturn(
+ mock(FieldContentParserPreferences.class));
+ fetcher = new zbMATH(importFormatPreferences);
+
+ donaldsonEntry = new BibEntry();
+ donaldsonEntry.setType(BibtexEntryTypes.ARTICLE);
+ donaldsonEntry.setCiteKey("zbMATH03800580");
+ donaldsonEntry.setField("author", "S.K. {Donaldson}");
+ donaldsonEntry.setField("journal", "Journal of Differential Geometry");
+ donaldsonEntry.setField("issn", "0022-040X; 1945-743X/e");
+ donaldsonEntry.setField("language", "English");
+ donaldsonEntry.setField("keywords", "57N13 57R10 53C05 58J99 57R65");
+ donaldsonEntry.setField("pages", "279--315");
+ donaldsonEntry.setField("publisher", "International Press of Boston, Somerville, MA");
+ donaldsonEntry.setField("title", "An application of gauge theory to four dimensional topology.");
+ donaldsonEntry.setField("volume", "18");
+ donaldsonEntry.setField("year", "1983");
+ donaldsonEntry.setField("zbl", "0507.57010");
+ }
+
+ @Test
+ public void searchByQueryFindsEntry() throws Exception {
+ // CI has no subscription to zbMath and thus gets 401 response
+ Assume.assumeFalse(DevEnvironment.isCIServer());
+
+ List<BibEntry> fetchedEntries = fetcher.performSearch("an:0507.57010");
+ assertEquals(Collections.singletonList(donaldsonEntry), fetchedEntries);
+ }
+}
diff --git a/src/test/java/net/sf/jabref/logic/importer/fileformat/BibTeXMLImporterTest.java b/src/test/java/net/sf/jabref/logic/importer/fileformat/BibTeXMLImporterTest.java
index 32de731..2ddc242 100644
--- a/src/test/java/net/sf/jabref/logic/importer/fileformat/BibTeXMLImporterTest.java
+++ b/src/test/java/net/sf/jabref/logic/importer/fileformat/BibTeXMLImporterTest.java
@@ -1,14 +1,13 @@
package net.sf.jabref.logic.importer.fileformat;
import java.io.IOException;
-import java.nio.charset.Charset;
-import java.nio.file.DirectoryStream;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
-import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
import net.sf.jabref.logic.util.FileExtensions;
@@ -23,7 +22,6 @@ import static org.junit.Assert.assertFalse;
@RunWith(MockitoJUnitRunner.class)
public class BibTeXMLImporterTest {
- private static final String FILEFORMAT_PATH = "src/test/resources/net/sf/jabref/logic/importer/fileformat";
private BibTeXMLImporter importer;
@@ -33,12 +31,10 @@ public class BibTeXMLImporterTest {
* @return A list of Names
* @throws IOException
*/
- public List<Path> getTestFiles() throws IOException {
- List<Path> files = new ArrayList<>();
- try (DirectoryStream<Path> stream = Files.newDirectoryStream(Paths.get(FILEFORMAT_PATH))) {
- stream.forEach(files::add);
+ public List<Path> getTestFiles() throws Exception {
+ try (Stream<Path> stream = Files.list(Paths.get(BibTeXMLImporterTest.class.getResource("").toURI()))) {
+ return stream.filter(p -> !Files.isDirectory(p)).collect(Collectors.toList());
}
- return files;
}
@@ -49,7 +45,7 @@ public class BibTeXMLImporterTest {
@Test
public void testGetFormatName() {
- assertEquals("BibTeXML", importer.getFormatName());
+ assertEquals("BibTeXML", importer.getName());
}
@Test
@@ -68,13 +64,13 @@ public class BibTeXMLImporterTest {
}
@Test
- public void testIsRecognizedFormatReject() throws IOException {
+ public void testIsRecognizedFormatReject() throws Exception {
List<Path> list = getTestFiles().stream()
.filter(n -> !n.getFileName().toString().startsWith("BibTeXMLImporterTest"))
.collect(Collectors.toList());
for (Path file : list) {
- assertFalse(file.toString(), importer.isRecognizedFormat(file, Charset.defaultCharset()));
+ assertFalse(file.toString(), importer.isRecognizedFormat(file, StandardCharsets.UTF_8));
}
}
}
diff --git a/src/test/java/net/sf/jabref/logic/importer/fileformat/BibTeXMLImporterTestFiles.java b/src/test/java/net/sf/jabref/logic/importer/fileformat/BibTeXMLImporterTestFiles.java
index 18aae27..502fa94 100644
--- a/src/test/java/net/sf/jabref/logic/importer/fileformat/BibTeXMLImporterTestFiles.java
+++ b/src/test/java/net/sf/jabref/logic/importer/fileformat/BibTeXMLImporterTestFiles.java
@@ -1,17 +1,15 @@
package net.sf.jabref.logic.importer.fileformat;
import java.io.IOException;
-import java.nio.charset.Charset;
-import java.nio.file.DirectoryStream;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
import net.sf.jabref.logic.bibtex.BibEntryAssert;
import net.sf.jabref.model.entry.BibEntry;
@@ -28,7 +26,6 @@ import org.junit.runners.Parameterized.Parameters;
public class BibTeXMLImporterTestFiles {
private static final Pattern PATTERN = Pattern.compile("\\D*[0123456789]");
- private final static String FILEFORMAT_PATH = "src/test/resources/net/sf/jabref/logic/importer/fileformat";
private BibTeXMLImporter bibtexmlImporter;
@@ -42,23 +39,22 @@ public class BibTeXMLImporterTestFiles {
}
@Parameters(name = "{0}")
- public static Collection<Path> files() throws IOException {
- List<Path> files = new ArrayList<>();
- try (DirectoryStream<Path> stream = Files.newDirectoryStream(Paths.get(FILEFORMAT_PATH))) {
- stream.forEach(files::add);
+ public static List<Path> files() throws Exception {
+ try (Stream<Path> stream = Files.list(Paths.get(BibTeXMLImporterTest.class.getResource("").toURI()))) {
+ return stream.filter(n -> n.getFileName().toString().startsWith("BibTeXMLImporterTest")
+ && n.getFileName().toString().endsWith(".xml")).collect(Collectors.toList());
}
- return files.stream().filter(n -> n.getFileName().toString().startsWith("BibTeXMLImporterTest") && n.getFileName().toString().endsWith(".xml"))
- .collect(Collectors.toList());
}
@Test
public void testIsRecognizedFormat() throws IOException {
- Assert.assertTrue(bibtexmlImporter.isRecognizedFormat(importFile, Charset.defaultCharset()));
+ Assert.assertTrue(bibtexmlImporter.isRecognizedFormat(importFile, StandardCharsets.UTF_8));
}
@Test
public void testImportEntries() throws IOException {
- List<BibEntry> bibtexmlEntries = bibtexmlImporter.importDatabase(importFile, Charset.defaultCharset()).getDatabase().getEntries();
+ List<BibEntry> bibtexmlEntries = bibtexmlImporter.importDatabase(importFile, StandardCharsets.UTF_8)
+ .getDatabase().getEntries();
String bibFileName = importFile.getFileName().toString().replace(".xml", ".bib");
while (PATTERN.matcher(bibFileName).find()) {
diff --git a/src/test/java/net/sf/jabref/logic/importer/fileformat/BiblioscapeImporterTest.java b/src/test/java/net/sf/jabref/logic/importer/fileformat/BiblioscapeImporterTest.java
index d0e08ea..67bd0ad 100644
--- a/src/test/java/net/sf/jabref/logic/importer/fileformat/BiblioscapeImporterTest.java
+++ b/src/test/java/net/sf/jabref/logic/importer/fileformat/BiblioscapeImporterTest.java
@@ -1,6 +1,6 @@
package net.sf.jabref.logic.importer.fileformat;
-import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
@@ -23,7 +23,7 @@ public class BiblioscapeImporterTest {
@Test
public void testGetFormatName() {
- Assert.assertEquals(importer.getFormatName(), "Biblioscape");
+ Assert.assertEquals(importer.getName(), "Biblioscape");
}
@Test
@@ -46,6 +46,6 @@ public class BiblioscapeImporterTest {
public void testImportEntriesAbortion() throws Throwable {
Path file = Paths.get(BiblioscapeImporter.class.getResource("BiblioscapeImporterTestCorrupt.txt").toURI());
Assert.assertEquals(Collections.emptyList(),
- importer.importDatabase(file, Charset.defaultCharset()).getDatabase().getEntries());
+ importer.importDatabase(file, StandardCharsets.UTF_8).getDatabase().getEntries());
}
}
diff --git a/src/test/java/net/sf/jabref/logic/importer/fileformat/BiblioscapeImporterTestFiles.java b/src/test/java/net/sf/jabref/logic/importer/fileformat/BiblioscapeImporterTestFiles.java
index dba8cc5..bcd57b2 100644
--- a/src/test/java/net/sf/jabref/logic/importer/fileformat/BiblioscapeImporterTestFiles.java
+++ b/src/test/java/net/sf/jabref/logic/importer/fileformat/BiblioscapeImporterTestFiles.java
@@ -2,7 +2,7 @@ package net.sf.jabref.logic.importer.fileformat;
import java.io.IOException;
import java.net.URISyntaxException;
-import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
@@ -27,6 +27,7 @@ public class BiblioscapeImporterTestFiles {
public Path importFile;
public String bibFile;
+
public BiblioscapeImporterTestFiles(String fileName) throws URISyntaxException {
importFile = Paths.get(BiblioscapeImporterTest.class.getResource(fileName + ".txt").toURI());
bibFile = fileName + ".bib";
@@ -39,26 +40,21 @@ public class BiblioscapeImporterTestFiles {
@Parameters(name = "{0}")
public static Collection<String> fileNames() {
- return Arrays.asList(
- "BiblioscapeImporterTestOptionalFields",
- "BiblioscapeImporterTestComments",
- "BiblioscapeImporterTestUnknownFields",
- "BiblioscapeImporterTestKeywords",
- "BiblioscapeImporterTestJournalArticle",
- "BiblioscapeImporterTestInbook",
- "BiblioscapeImporterTestUnknownType",
- "BiblioscapeImporterTestArticleST"
- );
+ return Arrays.asList("BiblioscapeImporterTestOptionalFields", "BiblioscapeImporterTestComments",
+ "BiblioscapeImporterTestUnknownFields", "BiblioscapeImporterTestKeywords",
+ "BiblioscapeImporterTestJournalArticle", "BiblioscapeImporterTestInbook",
+ "BiblioscapeImporterTestUnknownType", "BiblioscapeImporterTestArticleST");
}
@Test
public void testIsRecognizedFormat() throws IOException {
- Assert.assertTrue(bsImporter.isRecognizedFormat(importFile, Charset.defaultCharset()));
+ Assert.assertTrue(bsImporter.isRecognizedFormat(importFile, StandardCharsets.UTF_8));
}
@Test
public void testImportEntries() throws IOException {
- List<BibEntry> bsEntries = bsImporter.importDatabase(importFile, Charset.defaultCharset()).getDatabase().getEntries();
+ List<BibEntry> bsEntries = bsImporter.importDatabase(importFile, StandardCharsets.UTF_8).getDatabase()
+ .getEntries();
Assert.assertEquals(1, bsEntries.size());
BibEntryAssert.assertEquals(BiblioscapeImporterTest.class, bibFile, bsEntries);
}
diff --git a/src/test/java/net/sf/jabref/logic/importer/fileformat/BibtexImporterTest.java b/src/test/java/net/sf/jabref/logic/importer/fileformat/BibtexImporterTest.java
index a47c4e8..e32094c 100644
--- a/src/test/java/net/sf/jabref/logic/importer/fileformat/BibtexImporterTest.java
+++ b/src/test/java/net/sf/jabref/logic/importer/fileformat/BibtexImporterTest.java
@@ -2,13 +2,12 @@ package net.sf.jabref.logic.importer.fileformat;
import java.io.IOException;
import java.net.URISyntaxException;
-import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Optional;
-import net.sf.jabref.logic.importer.ImportFormatPreferences;
import net.sf.jabref.logic.util.FileExtensions;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.preferences.JabRefPreferences;
@@ -31,21 +30,22 @@ public class BibtexImporterTest {
private BibtexImporter importer;
+
@Before
public void setUp() {
- importer = new BibtexImporter(ImportFormatPreferences.fromPreferences(JabRefPreferences.getInstance()));
+ importer = new BibtexImporter(JabRefPreferences.getInstance().getImportFormatPreferences());
}
@Test
public void testIsRecognizedFormat() throws IOException, URISyntaxException {
Path file = Paths.get(BibtexImporterTest.class.getResource("BibtexImporter.examples.bib").toURI());
- assertTrue(importer.isRecognizedFormat(file, Charset.defaultCharset()));
+ assertTrue(importer.isRecognizedFormat(file, StandardCharsets.UTF_8));
}
@Test
public void testImportEntries() throws IOException, URISyntaxException {
Path file = Paths.get(BibtexImporterTest.class.getResource("BibtexImporter.examples.bib").toURI());
- List<BibEntry> bibEntries = importer.importDatabase(file, Charset.defaultCharset()).getDatabase().getEntries();
+ List<BibEntry> bibEntries = importer.importDatabase(file, StandardCharsets.UTF_8).getDatabase().getEntries();
assertEquals(4, bibEntries.size());
@@ -56,54 +56,56 @@ public class BibtexImporterTest {
Optional.of(
"Aks{\\i}n, {\\\"O}zge and T{\\\"u}rkmen, Hayati and Artok, Levent and {\\c{C}}etinkaya, "
+ "Bekir and Ni, Chaoying and B{\\\"u}y{\\\"u}kg{\\\"u}ng{\\\"o}r, Orhan and {\\\"O}zkal, Erhan"),
- entry.getFieldOptional("author"));
- assertEquals(Optional.of("aksin"), entry.getFieldOptional("bibtexkey"));
- assertEquals(Optional.of("2006"), entry.getFieldOptional("date"));
- assertEquals(Optional.of("Effect of immobilization on catalytic characteristics"), entry.getFieldOptional("indextitle"));
- assertEquals(Optional.of("#jomch#"), entry.getFieldOptional("journaltitle"));
- assertEquals(Optional.of("13"), entry.getFieldOptional("number"));
- assertEquals(Optional.of("3027-3036"), entry.getFieldOptional("pages"));
+ entry.getField("author"));
+ assertEquals(Optional.of("aksin"), entry.getField("bibtexkey"));
+ assertEquals(Optional.of("2006"), entry.getField("date"));
+ assertEquals(Optional.of("Effect of immobilization on catalytic characteristics"),
+ entry.getField("indextitle"));
+ assertEquals(Optional.of("#jomch#"), entry.getField("journaltitle"));
+ assertEquals(Optional.of("13"), entry.getField("number"));
+ assertEquals(Optional.of("3027-3036"), entry.getField("pages"));
assertEquals(Optional
.of("Effect of immobilization on catalytic characteristics of saturated {Pd-N}-heterocyclic "
+ "carbenes in {Mizoroki-Heck} reactions"),
- entry.getFieldOptional("title"));
- assertEquals(Optional.of("691"), entry.getFieldOptional("volume"));
+ entry.getField("title"));
+ assertEquals(Optional.of("691"), entry.getField("volume"));
} else if (entry.getCiteKeyOptional().get().equals("stdmodel")) {
assertEquals(Optional
- .of("A \\texttt{set} with three members discussing the standard model of particle physics. " +
- "The \\texttt{crossref} field in the \\texttt{@set} entry and the \\texttt{entryset} field in " +
- "each set member entry is needed only when using BibTeX as the backend"),
- entry.getFieldOptional("annotation"));
- assertEquals(Optional.of("stdmodel"), entry.getFieldOptional("bibtexkey"));
- assertEquals(Optional.of("glashow,weinberg,salam"), entry.getFieldOptional("entryset"));
+ .of("A \\texttt{set} with three members discussing the standard model of particle physics. "
+ + "The \\texttt{crossref} field in the \\texttt{@set} entry and the \\texttt{entryset} field in "
+ + "each set member entry is needed only when using BibTeX as the backend"),
+ entry.getField("annotation"));
+ assertEquals(Optional.of("stdmodel"), entry.getField("bibtexkey"));
+ assertEquals(Optional.of("glashow,weinberg,salam"), entry.getField("entryset"));
} else if (entry.getCiteKeyOptional().get().equals("set")) {
assertEquals(Optional
- .of("A \\texttt{set} with three members. The \\texttt{crossref} field in the \\texttt{@set} " +
- "entry and the \\texttt{entryset} field in each set member entry is needed only when using " +
- "BibTeX as the backend"),
- entry.getFieldOptional("annotation"));
- assertEquals(Optional.of("set"), entry.getFieldOptional("bibtexkey"));
- assertEquals(Optional.of("herrmann,aksin,yoon"), entry.getFieldOptional("entryset"));
+ .of("A \\texttt{set} with three members. The \\texttt{crossref} field in the \\texttt{@set} "
+ + "entry and the \\texttt{entryset} field in each set member entry is needed only when using "
+ + "BibTeX as the backend"),
+ entry.getField("annotation"));
+ assertEquals(Optional.of("set"), entry.getField("bibtexkey"));
+ assertEquals(Optional.of("herrmann,aksin,yoon"), entry.getField("entryset"));
} else if (entry.getCiteKeyOptional().get().equals("Preissel2016")) {
- assertEquals(Optional.of("Heidelberg"), entry.getFieldOptional("address"));
- assertEquals(Optional.of("Preißel, René"), entry.getFieldOptional("author"));
- assertEquals(Optional.of("Preissel2016"), entry.getFieldOptional("bibtexkey"));
- assertEquals(Optional.of("3., aktualisierte und erweiterte Auflage"), entry.getFieldOptional("edition"));
- assertEquals(Optional.of("978-3-86490-311-3"), entry.getFieldOptional("isbn"));
- assertEquals(Optional.of("Versionsverwaltung"), entry.getFieldOptional("keywords"));
- assertEquals(Optional.of("XX, 327 Seiten"), entry.getFieldOptional("pages"));
- assertEquals(Optional.of("dpunkt.verlag"), entry.getFieldOptional("publisher"));
+ assertEquals(Optional.of("Heidelberg"), entry.getField("address"));
+ assertEquals(Optional.of("Preißel, René"), entry.getField("author"));
+ assertEquals(Optional.of("Preissel2016"), entry.getField("bibtexkey"));
+ assertEquals(Optional.of("3., aktualisierte und erweiterte Auflage"),
+ entry.getField("edition"));
+ assertEquals(Optional.of("978-3-86490-311-3"), entry.getField("isbn"));
+ assertEquals(Optional.of("Versionsverwaltung"), entry.getField("keywords"));
+ assertEquals(Optional.of("XX, 327 Seiten"), entry.getField("pages"));
+ assertEquals(Optional.of("dpunkt.verlag"), entry.getField("publisher"));
assertEquals(Optional.of("Git: dezentrale Versionsverwaltung im Team : Grundlagen und Workflows"),
- entry.getFieldOptional("title"));
- assertEquals(Optional.of("http://d-nb.info/107601965X"), entry.getFieldOptional("url"));
- assertEquals(Optional.of("2016"), entry.getFieldOptional("year"));
+ entry.getField("title"));
+ assertEquals(Optional.of("http://d-nb.info/107601965X"), entry.getField("url"));
+ assertEquals(Optional.of("2016"), entry.getField("year"));
}
}
}
@Test
public void testGetFormatName() {
- assertEquals("BibTeX", importer.getFormatName());
+ assertEquals("BibTeX", importer.getName());
}
@Test
@@ -113,8 +115,17 @@ public class BibtexImporterTest {
@Test
public void testGetDescription() {
- assertEquals("This importer exists only to enable `--importToOpen someEntry.bib`\n" +
- "It is NOT intended to import a BIB file. This is done via the option action, which treats the metadata fields.\n" +
- "The metadata is not required to be read here, as this class is NOT called at --import.", importer.getDescription());
+ assertEquals(
+ "This importer exists only to enable `--importToOpen someEntry.bib`\n"
+ + "It is NOT intended to import a BIB file. This is done via the option action, which treats the metadata fields.\n"
+ + "The metadata is not required to be read here, as this class is NOT called at --import.",
+ importer.getDescription());
+ }
+
+ @Test
+ public void testRecognizesDatabaseID() throws Exception {
+ Path file = Paths.get(BibtexImporterTest.class.getResource("AutosavedSharedDatabase.bib").toURI());
+ String sharedDatabaseID = importer.importDatabase(file, StandardCharsets.UTF_8).getDatabase().getSharedDatabaseID().get();
+ assertEquals("13ceoc8dm42f5g1iitao3dj2ap", sharedDatabaseID);
}
}
diff --git a/src/test/java/net/sf/jabref/logic/importer/fileformat/BibtexParserTest.java b/src/test/java/net/sf/jabref/logic/importer/fileformat/BibtexParserTest.java
index 9ad7b75..40df97d 100644
--- a/src/test/java/net/sf/jabref/logic/importer/fileformat/BibtexParserTest.java
+++ b/src/test/java/net/sf/jabref/logic/importer/fileformat/BibtexParserTest.java
@@ -12,28 +12,29 @@ import java.util.Map;
import java.util.Optional;
import java.util.Set;
-import net.sf.jabref.Globals;
-import net.sf.jabref.logic.cleanup.FieldFormatterCleanup;
-import net.sf.jabref.logic.config.SaveOrderConfig;
-import net.sf.jabref.logic.exporter.FieldFormatterCleanups;
import net.sf.jabref.logic.exporter.SavePreferences;
import net.sf.jabref.logic.formatter.casechanger.LowerCaseFormatter;
-import net.sf.jabref.logic.groups.AllEntriesGroup;
-import net.sf.jabref.logic.groups.ExplicitGroup;
-import net.sf.jabref.logic.groups.GroupHierarchyType;
-import net.sf.jabref.logic.groups.GroupTreeNode;
-import net.sf.jabref.logic.groups.KeywordGroup;
import net.sf.jabref.logic.importer.ImportFormatPreferences;
+import net.sf.jabref.logic.importer.ParseException;
import net.sf.jabref.logic.importer.ParserResult;
-import net.sf.jabref.logic.importer.util.ParseException;
import net.sf.jabref.logic.util.OS;
import net.sf.jabref.model.bibtexkeypattern.AbstractBibtexKeyPattern;
import net.sf.jabref.model.bibtexkeypattern.DatabaseBibtexKeyPattern;
+import net.sf.jabref.model.bibtexkeypattern.GlobalBibtexKeyPattern;
+import net.sf.jabref.model.cleanup.FieldFormatterCleanup;
+import net.sf.jabref.model.cleanup.FieldFormatterCleanups;
import net.sf.jabref.model.database.BibDatabaseMode;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.BibtexString;
import net.sf.jabref.model.entry.EntryType;
import net.sf.jabref.model.entry.IdGenerator;
+import net.sf.jabref.model.groups.AllEntriesGroup;
+import net.sf.jabref.model.groups.ExplicitGroup;
+import net.sf.jabref.model.groups.GroupHierarchyType;
+import net.sf.jabref.model.groups.GroupTreeNode;
+import net.sf.jabref.model.groups.KeywordGroup;
+import net.sf.jabref.model.metadata.MetaData;
+import net.sf.jabref.model.metadata.SaveOrderConfig;
import net.sf.jabref.preferences.JabRefPreferences;
import org.junit.BeforeClass;
@@ -52,22 +53,20 @@ public class BibtexParserTest {
private static ImportFormatPreferences importFormatPreferences;
+
@BeforeClass
public static void setUp() {
- Globals.prefs = JabRefPreferences.getInstance();
- importFormatPreferences = ImportFormatPreferences.fromPreferences(Globals.prefs);
+ importFormatPreferences = JabRefPreferences.getInstance().getImportFormatPreferences();
}
- @SuppressWarnings("unused")
@Test(expected = NullPointerException.class)
- public void initalizationWithNullThrowsNullPointerException() {
- new BibtexParser(null, importFormatPreferences);
+ public void parseWithNullThrowsNullPointerException() throws Exception {
+ new BibtexParser(importFormatPreferences).parse(null);
}
@Test
public void fromStringRecognizesEntry() {
- List<BibEntry> parsed = BibtexParser.fromString("@article{test,author={Ed von Test}}",
- importFormatPreferences);
+ List<BibEntry> parsed = BibtexParser.fromString("@article{test,author={Ed von Test}}", importFormatPreferences);
BibEntry expected = new BibEntry();
expected.setType("article");
@@ -78,16 +77,14 @@ public class BibtexParserTest {
@Test
public void fromStringReturnsEmptyListFromEmptyString() {
- Collection<BibEntry> parsed = BibtexParser.fromString("",
- importFormatPreferences);
+ Collection<BibEntry> parsed = BibtexParser.fromString("", importFormatPreferences);
assertNotNull(parsed);
assertEquals(Collections.emptyList(), parsed);
}
@Test
public void fromStringReturnsEmptyListIfNoEntryRecognized() {
- Collection<BibEntry> parsed = BibtexParser.fromString("@@article@@{{{{{{}",
- importFormatPreferences);
+ Collection<BibEntry> parsed = BibtexParser.fromString("@@article@@{{{{{{}", importFormatPreferences);
assertNotNull(parsed);
assertEquals(Collections.emptyList(), parsed);
}
@@ -108,10 +105,10 @@ public class BibtexParserTest {
@Test
public void singleFromStringRecognizesEntryInMultiple() {
- Optional<BibEntry> parsed = BibtexParser
- .singleFromString("@article{canh05," + " author = {Crowston, K. and Annabi, H.},\n"
- + " title = {Title A}}\n" + "@inProceedings{foo," + " author={Norton Bar}}",
- importFormatPreferences);
+ Optional<BibEntry> parsed = BibtexParser.singleFromString(
+ "@article{canh05," + " author = {Crowston, K. and Annabi, H.},\n" + " title = {Title A}}\n"
+ + "@inProceedings{foo," + " author={Norton Bar}}",
+ importFormatPreferences);
assertTrue(parsed.get().getCiteKeyOptional().equals(Optional.of("canh05"))
|| parsed.get().getCiteKeyOptional().equals(Optional.of("foo")));
@@ -125,21 +122,11 @@ public class BibtexParserTest {
@Test
public void singleFromStringReturnsNullIfNoEntryRecognized() {
- Optional<BibEntry> parsed = BibtexParser.singleFromString("@@article@@{{{{{{}",
- importFormatPreferences);
+ Optional<BibEntry> parsed = BibtexParser.singleFromString("@@article@@{{{{{{}", importFormatPreferences);
assertEquals(Optional.empty(), parsed);
}
@Test
- public void parseTwoTimesReturnsSameResult() throws IOException {
- BibtexParser parser = new BibtexParser(new StringReader("@article{test,author={Ed von Test}}"),
- importFormatPreferences);
- ParserResult result = parser.parse();
-
- assertEquals(result, parser.parse());
- }
-
- @Test
public void parseRecognizesEntry() throws IOException {
ParserResult result = BibtexParser.parse(new StringReader("@article{test,author={Ed von Test}}"),
importFormatPreferences);
@@ -151,7 +138,7 @@ public class BibtexParserTest {
assertEquals("article", e.getType());
assertEquals(Optional.of("test"), e.getCiteKeyOptional());
assertEquals(2, e.getFieldNames().size());
- assertEquals(Optional.of("Ed von Test"), e.getFieldOptional("author"));
+ assertEquals(Optional.of("Ed von Test"), e.getField("author"));
}
@Test
@@ -167,14 +154,13 @@ public class BibtexParserTest {
assertEquals("article", e.getType());
assertEquals(Optional.of("test"), e.getCiteKeyOptional());
assertEquals(2, e.getFieldNames().size());
- assertEquals(Optional.of("Ed von Test"), e.getFieldOptional("author"));
+ assertEquals(Optional.of("Ed von Test"), e.getField("author"));
}
@Test
public void parseRecognizesEntryOnlyWithKey() throws IOException {
- ParserResult result = BibtexParser.parse(new StringReader("@article{test}"),
- importFormatPreferences);
+ ParserResult result = BibtexParser.parse(new StringReader("@article{test}"), importFormatPreferences);
List<BibEntry> parsed = result.getDatabase().getEntries();
assertEquals(1, parsed.size());
@@ -197,7 +183,7 @@ public class BibtexParserTest {
assertEquals("article", e.getType());
assertEquals(Optional.of("test"), e.getCiteKeyOptional());
assertEquals(2, e.getFieldNames().size());
- assertEquals(Optional.of("Ed von Test"), e.getFieldOptional("author"));
+ assertEquals(Optional.of("Ed von Test"), e.getField("author"));
}
@Test
@@ -213,7 +199,7 @@ public class BibtexParserTest {
assertEquals("article", e.getType());
assertEquals(Optional.of("test"), e.getCiteKeyOptional());
assertEquals(2, e.getFieldNames().size());
- assertEquals(Optional.of("Ed von Test"), e.getFieldOptional("author"));
+ assertEquals(Optional.of("Ed von Test"), e.getField("author"));
}
@Test
@@ -229,7 +215,7 @@ public class BibtexParserTest {
assertEquals("article", e.getType());
assertEquals(Optional.of("test"), e.getCiteKeyOptional());
assertEquals(2, e.getFieldNames().size());
- assertEquals(Optional.of("Ed von Test"), e.getFieldOptional("author"));
+ assertEquals(Optional.of("Ed von Test"), e.getField("author"));
}
@Test
@@ -245,7 +231,39 @@ public class BibtexParserTest {
assertEquals("unknown", e.getType());
assertEquals(Optional.of("test"), e.getCiteKeyOptional());
assertEquals(2, e.getFieldNames().size());
- assertEquals(Optional.of("Ed von Test"), e.getFieldOptional("author"));
+ assertEquals(Optional.of("Ed von Test"), e.getField("author"));
+ }
+
+ @Test
+ public void parseReallyUnknownType() throws Exception {
+ String bibtexEntry = "@ReallyUnknownType{test," + OS.NEWLINE +
+ " Comment = {testentry}" + OS.NEWLINE +
+ "}";
+
+ Collection<BibEntry> entries = new BibtexParser(importFormatPreferences).parseEntries(bibtexEntry);
+
+ BibEntry expectedEntry = new BibEntry();
+ expectedEntry.setType("Reallyunknowntype");
+ expectedEntry.setCiteKey("test");
+ expectedEntry.setField("comment", "testentry");
+
+ assertEquals(Collections.singletonList(expectedEntry), entries);
+ }
+
+ @Test
+ public void parseOtherTypeTest() throws Exception {
+ String bibtexEntry = "@Other{test," + OS.NEWLINE +
+ " Comment = {testentry}" + OS.NEWLINE +
+ "}";
+
+ Collection<BibEntry> entries = new BibtexParser(importFormatPreferences).parseEntries(bibtexEntry);
+
+ BibEntry expectedEntry = new BibEntry();
+ expectedEntry.setType("Other");
+ expectedEntry.setCiteKey("test");
+ expectedEntry.setField("comment", "testentry");
+
+ assertEquals(Collections.singletonList(expectedEntry), entries);
}
@Test
@@ -262,7 +280,7 @@ public class BibtexParserTest {
assertEquals("thisisalongstringtotestmaybeitistolongwhoknowsnotme", e.getType());
assertEquals(Optional.of("test"), e.getCiteKeyOptional());
assertEquals(2, e.getFieldNames().size());
- assertEquals(Optional.of("Ed von Test"), e.getFieldOptional("author"));
+ assertEquals(Optional.of("Ed von Test"), e.getField("author"));
}
@Test
@@ -278,7 +296,7 @@ public class BibtexParserTest {
assertEquals("article", e.getType());
assertEquals(Optional.of("test"), e.getCiteKeyOptional());
assertEquals(2, e.getFieldNames().size());
- assertEquals(Optional.of("Ed von Test"), e.getFieldOptional("author"));
+ assertEquals(Optional.of("Ed von Test"), e.getField("author"));
}
/**
@@ -296,17 +314,17 @@ public class BibtexParserTest {
assertEquals("article", e.getType());
assertEquals(Optional.of("canh05"), e.getCiteKeyOptional());
- assertEquals(Optional.of("1234567890123456789"), e.getFieldOptional("isbn"));
- assertEquals(Optional.of("1234567890123456789"), e.getFieldOptional("isbn2"));
- assertEquals(Optional.of("1234"), e.getFieldOptional("small"));
+ assertEquals(Optional.of("1234567890123456789"), e.getField("isbn"));
+ assertEquals(Optional.of("1234567890123456789"), e.getField("isbn2"));
+ assertEquals(Optional.of("1234"), e.getField("small"));
}
@Test
public void parseRecognizesBibtexKeyWithSpecialCharacters() throws IOException {
- ParserResult result = BibtexParser
- .parse(new StringReader("@article{te_st:with-special(characters),author={Ed von Test}}"),
- importFormatPreferences);
+ ParserResult result = BibtexParser.parse(
+ new StringReader("@article{te_st:with-special(characters),author={Ed von Test}}"),
+ importFormatPreferences);
Collection<BibEntry> c = result.getDatabase().getEntries();
BibEntry e = c.iterator().next();
@@ -314,7 +332,7 @@ public class BibtexParserTest {
assertEquals("article", e.getType());
assertEquals(Optional.of("te_st:with-special(characters)"), e.getCiteKeyOptional());
assertEquals(2, e.getFieldNames().size());
- assertEquals(Optional.of("Ed von Test"), e.getFieldOptional("author"));
+ assertEquals(Optional.of("Ed von Test"), e.getField("author"));
}
@Test
@@ -330,10 +348,11 @@ public class BibtexParserTest {
assertEquals("article", e.getType());
assertEquals(Optional.of("test"), e.getCiteKeyOptional());
assertEquals(2, e.getFieldNames().size());
- assertEquals(Optional.of("Ed von Test"), e.getFieldOptional("author"));
+ assertEquals(Optional.of("Ed von Test"), e.getField("author"));
}
- @Test public void parseRecognizesEntryWithAtInField() throws IOException {
+ @Test
+ public void parseRecognizesEntryWithAtInField() throws IOException {
ParserResult result = BibtexParser.parse(new StringReader("@article{test,author={Ed von T at st}}"),
importFormatPreferences);
@@ -345,7 +364,8 @@ public class BibtexParserTest {
assertEquals(Collections.singletonList(expected), parsed);
}
- @Test public void parseRecognizesEntryPrecedingComment() throws IOException {
+ @Test
+ public void parseRecognizesEntryPrecedingComment() throws IOException {
String comment = "@Comment{@article{myarticle,}" + OS.NEWLINE
+ "@inproceedings{blabla, title={the proceedings of bl at bl@}; }" + OS.NEWLINE + "}";
String entryWithComment = comment + OS.NEWLINE + "@article{test,author={Ed von T at st}}";
@@ -365,14 +385,10 @@ public class BibtexParserTest {
@Test
public void parseRecognizesMultipleEntries() throws IOException {
- ParserResult result = BibtexParser
- .parse(new StringReader(
- "@article{canh05,"
- + " author = {Crowston, K. and Annabi, H.},\n"
- + " title = {Title A}}\n"
- + "@inProceedings{foo,"
- + " author={Norton Bar}}"),
- importFormatPreferences);
+ ParserResult result = BibtexParser.parse(
+ new StringReader("@article{canh05," + " author = {Crowston, K. and Annabi, H.},\n"
+ + " title = {Title A}}\n" + "@inProceedings{foo," + " author={Norton Bar}}"),
+ importFormatPreferences);
List<BibEntry> parsed = result.getDatabase().getEntries();
List<BibEntry> expected = new ArrayList<>();
@@ -394,11 +410,8 @@ public class BibtexParserTest {
@Test
public void parseSetsParsedSerialization() throws IOException {
- String firstEntry = "@article{canh05,"
- + " author = {Crowston, K. and Annabi, H.},"
- + OS.NEWLINE
- + " title = {Title A}}"
- + OS.NEWLINE;
+ String firstEntry = "@article{canh05," + " author = {Crowston, K. and Annabi, H.}," + OS.NEWLINE
+ + " title = {Title A}}" + OS.NEWLINE;
String secondEntry = "@inProceedings{foo," + " author={Norton Bar}}";
ParserResult result = BibtexParser.parse(new StringReader(firstEntry + secondEntry), importFormatPreferences);
@@ -447,7 +460,7 @@ public class BibtexParserTest {
assertEquals("article", e.getType());
assertEquals(Optional.of("test"), e.getCiteKeyOptional());
assertEquals(2, e.getFieldNames().size());
- assertEquals(Optional.of("Ed von Test and Second Author and Third Author"), e.getFieldOptional("author"));
+ assertEquals(Optional.of("Ed von Test and Second Author and Third Author"), e.getField("author"));
}
@Test
@@ -464,7 +477,7 @@ public class BibtexParserTest {
assertEquals("article", e.getType());
assertEquals(Optional.of("test"), e.getCiteKeyOptional());
assertEquals(2, e.getFieldNames().size());
- assertEquals(Optional.of("Ed von Test and Second Author and Third Author"), e.getFieldOptional("editor"));
+ assertEquals(Optional.of("Ed von Test and Second Author and Third Author"), e.getField("editor"));
}
/**
@@ -484,35 +497,18 @@ public class BibtexParserTest {
assertEquals("article", e.getType());
assertEquals(Optional.of("test"), e.getCiteKeyOptional());
assertEquals(2, e.getFieldNames().size());
- assertEquals(Optional.of("Test, Second Keyword, Third Keyword"), e.getFieldOptional("keywords"));
+ assertEquals(Optional.of("Test, Second Keyword, Third Keyword"), e.getField("keywords"));
}
@Test
public void parseRecognizesHeaderButIgnoresEncoding() throws IOException {
- ParserResult result = BibtexParser.parse(new StringReader(
- "This file was created with JabRef 2.1 beta 2."
- + "\n"
- + "Encoding: Cp1252"
- + "\n"
- + ""
- + "\n"
- + "@INPROCEEDINGS{CroAnnHow05,"
- + "\n"
- + " author = {Crowston, K. and Annabi, H. and Howison, J. and Masango, C.},"
- + "\n"
- + " title = {Effective work practices for floss development: A model and propositions},"
- + "\n"
- + " booktitle = {Hawaii International Conference On System Sciences (HICSS)},"
- + "\n"
- + " year = {2005},"
- + "\n"
- + " owner = {oezbek},"
- + "\n"
- + " timestamp = {2006.05.29},"
- + "\n"
- + " url = {http://james.howison.name/publications.html}"
- + "\n"
- + "}))"),
+ ParserResult result = BibtexParser.parse(new StringReader("This file was created with JabRef 2.1 beta 2." + "\n"
+ + "Encoding: Cp1252" + "\n" + "" + "\n" + "@INPROCEEDINGS{CroAnnHow05," + "\n"
+ + " author = {Crowston, K. and Annabi, H. and Howison, J. and Masango, C.}," + "\n"
+ + " title = {Effective work practices for floss development: A model and propositions}," + "\n"
+ + " booktitle = {Hawaii International Conference On System Sciences (HICSS)}," + "\n"
+ + " year = {2005}," + "\n" + " owner = {oezbek}," + "\n" + " timestamp = {2006.05.29}," + "\n"
+ + " url = {http://james.howison.name/publications.html}" + "\n" + "}))"),
importFormatPreferences);
assertEquals(Optional.empty(), result.getMetaData().getEncoding());
@@ -523,35 +519,28 @@ public class BibtexParserTest {
assertEquals("inproceedings", e.getType());
assertEquals(8, e.getFieldNames().size());
assertEquals(Optional.of("CroAnnHow05"), e.getCiteKeyOptional());
- assertEquals(Optional.of("Crowston, K. and Annabi, H. and Howison, J. and Masango, C."), e.getFieldOptional("author"));
- assertEquals(Optional.of("Effective work practices for floss development: A model and propositions"), e.getFieldOptional("title"));
- assertEquals(Optional.of("Hawaii International Conference On System Sciences (HICSS)"), e.getFieldOptional("booktitle"));
- assertEquals(Optional.of("2005"), e.getFieldOptional("year"));
- assertEquals(Optional.of("oezbek"), e.getFieldOptional("owner"));
- assertEquals(Optional.of("2006.05.29"), e.getFieldOptional("timestamp"));
- assertEquals(Optional.of("http://james.howison.name/publications.html"), e.getFieldOptional("url"));
+ assertEquals(Optional.of("Crowston, K. and Annabi, H. and Howison, J. and Masango, C."),
+ e.getField("author"));
+ assertEquals(Optional.of("Effective work practices for floss development: A model and propositions"),
+ e.getField("title"));
+ assertEquals(Optional.of("Hawaii International Conference On System Sciences (HICSS)"),
+ e.getField("booktitle"));
+ assertEquals(Optional.of("2005"), e.getField("year"));
+ assertEquals(Optional.of("oezbek"), e.getField("owner"));
+ assertEquals(Optional.of("2006.05.29"), e.getField("timestamp"));
+ assertEquals(Optional.of("http://james.howison.name/publications.html"), e.getField("url"));
}
@Test
public void parseRecognizesFormatedEntry() throws IOException {
- ParserResult result = BibtexParser.parse(new StringReader(""
- + "@INPROCEEDINGS{CroAnnHow05," +
- "\n"
- + " author = {Crowston, K. and Annabi, H. and Howison, J. and Masango, C.},"
- + "\n"
- + " title = {Effective work practices for floss development: A model and propositions},"
- + "\n"
- + " booktitle = {Hawaii International Conference On System Sciences (HICSS)},"
- + "\n"
- + " year = {2005},"
- + "\n"
- + " owner = {oezbek},"
- + "\n"
- + " timestamp = {2006.05.29},"
- + "\n"
- + " url = {http://james.howison.name/publications.html}"
- + "\n"
- + "}))"), importFormatPreferences);
+ ParserResult result = BibtexParser.parse(
+ new StringReader("" + "@INPROCEEDINGS{CroAnnHow05," + "\n"
+ + " author = {Crowston, K. and Annabi, H. and Howison, J. and Masango, C.}," + "\n"
+ + " title = {Effective work practices for floss development: A model and propositions}," + "\n"
+ + " booktitle = {Hawaii International Conference On System Sciences (HICSS)}," + "\n"
+ + " year = {2005}," + "\n" + " owner = {oezbek}," + "\n" + " timestamp = {2006.05.29},"
+ + "\n" + " url = {http://james.howison.name/publications.html}" + "\n" + "}))"),
+ importFormatPreferences);
Collection<BibEntry> c = result.getDatabase().getEntries();
assertEquals(1, c.size());
@@ -559,13 +548,16 @@ public class BibtexParserTest {
assertEquals("inproceedings", e.getType());
assertEquals(8, e.getFieldNames().size());
assertEquals(Optional.of("CroAnnHow05"), e.getCiteKeyOptional());
- assertEquals(Optional.of("Crowston, K. and Annabi, H. and Howison, J. and Masango, C."), e.getFieldOptional("author"));
- assertEquals(Optional.of("Effective work practices for floss development: A model and propositions"), e.getFieldOptional("title"));
- assertEquals(Optional.of("Hawaii International Conference On System Sciences (HICSS)"), e.getFieldOptional("booktitle"));
- assertEquals(Optional.of("2005"), e.getFieldOptional("year"));
- assertEquals(Optional.of("oezbek"), e.getFieldOptional("owner"));
- assertEquals(Optional.of("2006.05.29"), e.getFieldOptional("timestamp"));
- assertEquals(Optional.of("http://james.howison.name/publications.html"), e.getFieldOptional("url"));
+ assertEquals(Optional.of("Crowston, K. and Annabi, H. and Howison, J. and Masango, C."),
+ e.getField("author"));
+ assertEquals(Optional.of("Effective work practices for floss development: A model and propositions"),
+ e.getField("title"));
+ assertEquals(Optional.of("Hawaii International Conference On System Sciences (HICSS)"),
+ e.getField("booktitle"));
+ assertEquals(Optional.of("2005"), e.getField("year"));
+ assertEquals(Optional.of("oezbek"), e.getField("owner"));
+ assertEquals(Optional.of("2006.05.29"), e.getField("timestamp"));
+ assertEquals(Optional.of("http://james.howison.name/publications.html"), e.getField("url"));
}
@Test
@@ -581,7 +573,7 @@ public class BibtexParserTest {
assertEquals("article", e.getType());
assertEquals(Optional.of("test"), e.getCiteKeyOptional());
assertEquals(2, e.getFieldNames().size());
- assertEquals(Optional.of("Ed von Test"), e.getFieldOptional("author"));
+ assertEquals(Optional.of("Ed von Test"), e.getField("author"));
}
@Test
@@ -597,7 +589,7 @@ public class BibtexParserTest {
assertEquals("article", e.getType());
assertEquals(Optional.of("test"), e.getCiteKeyOptional());
assertEquals(2, e.getFieldNames().size());
- assertEquals(Optional.of("2005"), e.getFieldOptional("year"));
+ assertEquals(Optional.of("2005"), e.getField("year"));
}
@Test
@@ -613,7 +605,7 @@ public class BibtexParserTest {
assertEquals("article", e.getType());
assertEquals(Optional.of("test"), e.getCiteKeyOptional());
assertEquals(2, e.getFieldNames().size());
- assertEquals(Optional.of("Ed von Test"), e.getFieldOptional("author"));
+ assertEquals(Optional.of("Ed von Test"), e.getField("author"));
}
/**
@@ -622,9 +614,9 @@ public class BibtexParserTest {
@Test
public void parseRecognizesAbsoluteFile() throws IOException {
- ParserResult result = BibtexParser
- .parse(new StringReader("@article{test,file = {D:\\Documents\\literature\\Tansel-PRL2006.pdf}}"),
- importFormatPreferences);
+ ParserResult result = BibtexParser.parse(
+ new StringReader("@article{test,file = {D:\\Documents\\literature\\Tansel-PRL2006.pdf}}"),
+ importFormatPreferences);
Collection<BibEntry> c = result.getDatabase().getEntries();
assertEquals(1, c.size());
@@ -633,7 +625,7 @@ public class BibtexParserTest {
assertEquals("article", e.getType());
assertEquals(Optional.of("test"), e.getCiteKeyOptional());
assertEquals(2, e.getFieldNames().size());
- assertEquals(Optional.of("D:\\Documents\\literature\\Tansel-PRL2006.pdf"), e.getFieldOptional("file"));
+ assertEquals(Optional.of("D:\\Documents\\literature\\Tansel-PRL2006.pdf"), e.getField("file"));
}
/**
@@ -652,29 +644,18 @@ public class BibtexParserTest {
assertEquals("article", e.getType());
assertEquals(Optional.of("test"), e.getCiteKeyOptional());
assertEquals(2, e.getFieldNames().size());
- assertEquals(Optional.of("1-4~#nov#"), e.getFieldOptional("date"));
+ assertEquals(Optional.of("1-4~#nov#"), e.getField("date"));
}
@Test
public void parseReturnsEmptyListIfNoEntryRecognized() throws IOException {
- ParserResult result = BibtexParser
- .parse(new StringReader(
- " author = {Crowston, K. and Annabi, H. and Howison, J. and Masango, C.},"
- + "\n"
- + " title = {Effective work practices for floss development: A model and propositions},"
- + "\n"
- + " booktitle = {Hawaii International Conference On System Sciences (HICSS)},"
- + "\n"
- + " year = {2005},"
- + "\n"
- + " owner = {oezbek},"
- + "\n"
- + " timestamp = {2006.05.29},"
- + "\n"
- + " url = {http://james.howison.name/publications.html}"
- + "\n"
- + "}))"),
- importFormatPreferences);
+ ParserResult result = BibtexParser.parse(
+ new StringReader(" author = {Crowston, K. and Annabi, H. and Howison, J. and Masango, C.}," + "\n"
+ + " title = {Effective work practices for floss development: A model and propositions}," + "\n"
+ + " booktitle = {Hawaii International Conference On System Sciences (HICSS)}," + "\n"
+ + " year = {2005}," + "\n" + " owner = {oezbek}," + "\n" + " timestamp = {2006.05.29},"
+ + "\n" + " url = {http://james.howison.name/publications.html}" + "\n" + "}))"),
+ importFormatPreferences);
Collection<BibEntry> c = result.getDatabase().getEntries();
assertEquals(0, c.size());
}
@@ -682,9 +663,9 @@ public class BibtexParserTest {
@Test
public void parseReturnsEmptyListIfNoEntryExistent() throws IOException {
- ParserResult result = BibtexParser
- .parse(new StringReader("This was created with JabRef 2.1 beta 2." + "\n" + "Encoding: Cp1252" + "\n"),
- importFormatPreferences);
+ ParserResult result = BibtexParser.parse(
+ new StringReader("This was created with JabRef 2.1 beta 2." + "\n" + "Encoding: Cp1252" + "\n"),
+ importFormatPreferences);
Collection<BibEntry> c = result.getDatabase().getEntries();
assertEquals(0, c.size());
}
@@ -748,7 +729,7 @@ public class BibtexParserTest {
BibEntry e = c.iterator().next();
assertEquals("article", e.getType());
assertEquals(Optional.of("test"), e.getCiteKeyOptional());
- assertEquals(Optional.of("escaped \\{ bracket"), e.getFieldOptional("review"));
+ assertEquals(Optional.of("escaped \\{ bracket"), e.getField("review"));
}
@Test
@@ -765,7 +746,7 @@ public class BibtexParserTest {
BibEntry e = c.iterator().next();
assertEquals("article", e.getType());
assertEquals(Optional.of("test"), e.getCiteKeyOptional());
- assertEquals(Optional.of("escaped \\} bracket"), e.getFieldOptional("review"));
+ assertEquals(Optional.of("escaped \\} bracket"), e.getField("review"));
}
@Test
@@ -827,7 +808,7 @@ public class BibtexParserTest {
entries.addAll(c);
assertEquals(1, entries.size());
- assertEquals(Optional.of("author @ good"), entries.get(0).getFieldOptional("author"));
+ assertEquals(Optional.of("author @ good"), entries.get(0).getField("author"));
}
@Test
@@ -843,7 +824,7 @@ public class BibtexParserTest {
assertEquals("article", e.getType());
assertEquals(Optional.of("test"), e.getCiteKeyOptional());
assertEquals(2, e.getFieldNames().size());
- assertEquals(Optional.of("author @ good"), e.getFieldOptional("author"));
+ assertEquals(Optional.of("author @ good"), e.getField("author"));
}
@Test
@@ -859,7 +840,7 @@ public class BibtexParserTest {
assertEquals("article", e.getType());
assertEquals(Optional.of("test"), e.getCiteKeyOptional());
assertEquals(2, e.getFieldNames().size());
- assertEquals(Optional.of("Test {Ed {von} Test}"), e.getFieldOptional("author"));
+ assertEquals(Optional.of("Test {Ed {von} Test}"), e.getField("author"));
}
@Test
@@ -876,7 +857,7 @@ public class BibtexParserTest {
assertEquals("article", e.getType());
assertEquals(Optional.of("test"), e.getCiteKeyOptional());
assertEquals(2, e.getFieldNames().size());
- assertEquals(Optional.of("Test {\" Test}"), e.getFieldOptional("author"));
+ assertEquals(Optional.of("Test {\" Test}"), e.getField("author"));
}
@Test
@@ -894,8 +875,9 @@ public class BibtexParserTest {
@Test
public void parseIgnoresAndWarnsAboutCorruptedEntryButRecognizeOthers() throws IOException {
- ParserResult result = BibtexParser.parse(new StringReader(
- "@article{test,author={author missing bracket}" + "@article{test,author={Ed von Test}}"),
+ ParserResult result = BibtexParser.parse(
+ new StringReader(
+ "@article{test,author={author missing bracket}" + "@article{test,author={Ed von Test}}"),
importFormatPreferences);
assertTrue(result.hasWarnings());
@@ -907,7 +889,7 @@ public class BibtexParserTest {
assertEquals("article", e.getType());
assertEquals(Optional.of("test"), e.getCiteKeyOptional());
assertEquals(2, e.getFieldNames().size());
- assertEquals(Optional.of("Ed von Test"), e.getFieldOptional("author"));
+ assertEquals(Optional.of("Ed von Test"), e.getField("author"));
}
/**
@@ -926,8 +908,8 @@ public class BibtexParserTest {
assertEquals("article", e.getType());
assertEquals(Optional.of("test"), e.getCiteKeyOptional());
assertEquals(3, e.getFieldNames().size());
- assertEquals(Optional.of("Ed von Test"), e.getFieldOptional("author"));
- assertEquals(Optional.of("8,"), e.getFieldOptional("month"));
+ assertEquals(Optional.of("Ed von Test"), e.getField("author"));
+ assertEquals(Optional.of("8,"), e.getField("month"));
}
@Test
@@ -935,7 +917,7 @@ public class BibtexParserTest {
ParserResult result = BibtexParser.parse(new StringReader("@preamble{some text and \\latex}"),
importFormatPreferences);
- assertEquals("some text and \\latex", result.getDatabase().getPreamble());
+ assertEquals(Optional.of("some text and \\latex"), result.getDatabase().getPreamble());
}
@Test
@@ -943,7 +925,7 @@ public class BibtexParserTest {
ParserResult result = BibtexParser.parse(new StringReader("@PREAMBLE{some text and \\latex}"),
importFormatPreferences);
- assertEquals("some text and \\latex", result.getDatabase().getPreamble());
+ assertEquals(Optional.of("some text and \\latex"), result.getDatabase().getPreamble());
}
@Test
@@ -951,7 +933,7 @@ public class BibtexParserTest {
ParserResult result = BibtexParser.parse(new StringReader("@preamble {some text and \\latex}"),
importFormatPreferences);
- assertEquals("some text and \\latex", result.getDatabase().getPreamble());
+ assertEquals(Optional.of("some text and \\latex"), result.getDatabase().getPreamble());
}
@Test
@@ -959,7 +941,7 @@ public class BibtexParserTest {
ParserResult result = BibtexParser.parse(new StringReader("@preamble(some text and \\latex)"),
importFormatPreferences);
- assertEquals("some text and \\latex", result.getDatabase().getPreamble());
+ assertEquals(Optional.of("some text and \\latex"), result.getDatabase().getPreamble());
}
@Test
@@ -967,7 +949,7 @@ public class BibtexParserTest {
ParserResult result = BibtexParser.parse(new StringReader("@preamble{\"some text\" # \"and \\latex\"}"),
importFormatPreferences);
- assertEquals("\"some text\" # \"and \\latex\"", result.getDatabase().getPreamble());
+ assertEquals(Optional.of("\"some text\" # \"and \\latex\""), result.getDatabase().getPreamble());
}
@Test
@@ -1021,9 +1003,9 @@ public class BibtexParserTest {
@Test
public void parseRecognizesMultipleStrings() throws IOException {
- ParserResult result = BibtexParser
- .parse(new StringReader("@string{bourdieu = {Bourdieu, Pierre}}" + "@string{adieu = {Adieu, Pierre}}"),
- importFormatPreferences);
+ ParserResult result = BibtexParser.parse(
+ new StringReader("@string{bourdieu = {Bourdieu, Pierre}}" + "@string{adieu = {Adieu, Pierre}}"),
+ importFormatPreferences);
assertEquals(2, result.getDatabase().getStringCount());
Iterator<BibtexString> iterator = result.getDatabase().getStringValues().iterator();
@@ -1046,17 +1028,11 @@ public class BibtexParserTest {
@Test
public void parseRecognizesStringAndEntry() throws IOException {
- ParserResult result = BibtexParser.parse(new StringReader(
- ""
- + "@string{bourdieu = {Bourdieu, Pierre}}"
- + "@book{bourdieu-2002-questions-sociologie, "
- + " Address = {Paris},"
- + " Author = bourdieu,"
- + " Isbn = 2707318256,"
- + " Publisher = {Minuit},"
- + " Title = {Questions de sociologie},"
- + " Year = 2002"
- + "}"),
+ ParserResult result = BibtexParser.parse(
+ new StringReader("" + "@string{bourdieu = {Bourdieu, Pierre}}"
+ + "@book{bourdieu-2002-questions-sociologie, " + " Address = {Paris}," + " Author = bourdieu,"
+ + " Isbn = 2707318256," + " Publisher = {Minuit}," + " Title = {Questions de sociologie},"
+ + " Year = 2002" + "}"),
importFormatPreferences);
assertEquals(1, result.getDatabase().getStringCount());
@@ -1071,20 +1047,20 @@ public class BibtexParserTest {
assertEquals("book", e.getType());
assertEquals(Optional.of("bourdieu-2002-questions-sociologie"), e.getCiteKeyOptional());
- assertEquals(Optional.of("Paris"), e.getFieldOptional("address"));
- assertEquals(Optional.of("#bourdieu#"), e.getFieldOptional("author"));
- assertEquals(Optional.of("2707318256"), e.getFieldOptional("isbn"));
- assertEquals(Optional.of("Minuit"), e.getFieldOptional("publisher"));
- assertEquals(Optional.of("Questions de sociologie"), e.getFieldOptional("title"));
- assertEquals(Optional.of("2002"), e.getFieldOptional("year"));
+ assertEquals(Optional.of("Paris"), e.getField("address"));
+ assertEquals(Optional.of("#bourdieu#"), e.getField("author"));
+ assertEquals(Optional.of("2707318256"), e.getField("isbn"));
+ assertEquals(Optional.of("Minuit"), e.getField("publisher"));
+ assertEquals(Optional.of("Questions de sociologie"), e.getField("title"));
+ assertEquals(Optional.of("2002"), e.getField("year"));
}
@Test
public void parseWarnsAboutStringsWithSameNameAndOnlyKeepsOne() throws IOException {
- ParserResult result = BibtexParser
- .parse(new StringReader("@string{bourdieu = {Bourdieu, Pierre}}" + "@string{bourdieu = {Other}}"),
- importFormatPreferences);
+ ParserResult result = BibtexParser.parse(
+ new StringReader("@string{bourdieu = {Bourdieu, Pierre}}" + "@string{bourdieu = {Other}}"),
+ importFormatPreferences);
assertTrue(result.hasWarnings());
assertEquals(1, result.getDatabase().getStringCount());
}
@@ -1108,9 +1084,9 @@ public class BibtexParserTest {
@Test
public void parseIgnoresCommentsBeforeEntry() throws IOException {
- ParserResult result = BibtexParser
- .parse(new StringReader("@comment{some text and \\latex}" + "@article{test,author={Ed von Test}}"),
- importFormatPreferences);
+ ParserResult result = BibtexParser.parse(
+ new StringReader("@comment{some text and \\latex}" + "@article{test,author={Ed von Test}}"),
+ importFormatPreferences);
Collection<BibEntry> c = result.getDatabase().getEntries();
assertEquals(1, c.size());
@@ -1118,15 +1094,15 @@ public class BibtexParserTest {
assertEquals("article", e.getType());
assertEquals(Optional.of("test"), e.getCiteKeyOptional());
assertEquals(2, e.getFieldNames().size());
- assertEquals(Optional.of("Ed von Test"), e.getFieldOptional("author"));
+ assertEquals(Optional.of("Ed von Test"), e.getField("author"));
}
@Test
public void parseIgnoresCommentsAfterEntry() throws IOException {
- ParserResult result = BibtexParser
- .parse(new StringReader("@article{test,author={Ed von Test}}" + "@comment{some text and \\latex}"),
- importFormatPreferences);
+ ParserResult result = BibtexParser.parse(
+ new StringReader("@article{test,author={Ed von Test}}" + "@comment{some text and \\latex}"),
+ importFormatPreferences);
Collection<BibEntry> c = result.getDatabase().getEntries();
assertEquals(1, c.size());
@@ -1134,7 +1110,7 @@ public class BibtexParserTest {
assertEquals("article", e.getType());
assertEquals(Optional.of("test"), e.getCiteKeyOptional());
assertEquals(2, e.getFieldNames().size());
- assertEquals(Optional.of("Ed von Test"), e.getFieldOptional("author"));
+ assertEquals(Optional.of("Ed von Test"), e.getField("author"));
}
@Test
@@ -1148,9 +1124,9 @@ public class BibtexParserTest {
@Test
public void parseIgnoresTextBeforeEntry() throws IOException {
- ParserResult result = BibtexParser
- .parse(new StringReader("comment{some text and \\latex" + "@article{test,author={Ed von Test}}"),
- importFormatPreferences);
+ ParserResult result = BibtexParser.parse(
+ new StringReader("comment{some text and \\latex" + "@article{test,author={Ed von Test}}"),
+ importFormatPreferences);
Collection<BibEntry> c = result.getDatabase().getEntries();
assertEquals(1, c.size());
@@ -1158,15 +1134,15 @@ public class BibtexParserTest {
assertEquals("article", e.getType());
assertEquals(Optional.of("test"), e.getCiteKeyOptional());
assertEquals(2, e.getFieldNames().size());
- assertEquals(Optional.of("Ed von Test"), e.getFieldOptional("author"));
+ assertEquals(Optional.of("Ed von Test"), e.getField("author"));
}
@Test
public void parseIgnoresTextAfterEntry() throws IOException {
- ParserResult result = BibtexParser
- .parse(new StringReader("@article{test,author={Ed von Test}}" + "comment{some text and \\latex"),
- importFormatPreferences);
+ ParserResult result = BibtexParser.parse(
+ new StringReader("@article{test,author={Ed von Test}}" + "comment{some text and \\latex"),
+ importFormatPreferences);
Collection<BibEntry> c = result.getDatabase().getEntries();
assertEquals(1, c.size());
@@ -1174,7 +1150,7 @@ public class BibtexParserTest {
assertEquals("article", e.getType());
assertEquals(Optional.of("test"), e.getCiteKeyOptional());
assertEquals(2, e.getFieldNames().size());
- assertEquals(Optional.of("Ed von Test"), e.getFieldOptional("author"));
+ assertEquals(Optional.of("Ed von Test"), e.getField("author"));
}
@Test
@@ -1185,21 +1161,21 @@ public class BibtexParserTest {
Collection<BibEntry> c = result.getDatabase().getEntries();
BibEntry e = c.iterator().next();
- assertEquals(Optional.of("a b"), e.getFieldOptional("a"));
+ assertEquals(Optional.of("a b"), e.getField("a"));
}
@Test
public void parseConvertsMultipleNewlinesToSpace() throws IOException {
- ParserResult result = BibtexParser
- .parse(new StringReader("@article{test,a = {a\n\nb}," + "b = {a\n \nb}," + "c = {a \n \n b}}"),
- importFormatPreferences);
+ ParserResult result = BibtexParser.parse(
+ new StringReader("@article{test,a = {a\n\nb}," + "b = {a\n \nb}," + "c = {a \n \n b}}"),
+ importFormatPreferences);
Collection<BibEntry> c = result.getDatabase().getEntries();
BibEntry e = c.iterator().next();
- assertEquals(Optional.of("a b"), e.getFieldOptional("a"));
- assertEquals(Optional.of("a b"), e.getFieldOptional("b"));
- assertEquals(Optional.of("a b"), e.getFieldOptional("c"));
+ assertEquals(Optional.of("a b"), e.getField("a"));
+ assertEquals(Optional.of("a b"), e.getField("b"));
+ assertEquals(Optional.of("a b"), e.getField("c"));
}
@Test
@@ -1210,21 +1186,21 @@ public class BibtexParserTest {
Collection<BibEntry> c = result.getDatabase().getEntries();
BibEntry e = c.iterator().next();
- assertEquals(Optional.of("a b"), e.getFieldOptional("a"));
+ assertEquals(Optional.of("a b"), e.getField("a"));
}
@Test
public void parseConvertsMultipleTabsToSpace() throws IOException {
- ParserResult result = BibtexParser
- .parse(new StringReader("@article{test,a = {a\t\tb}," + "b = {a\t \tb}," + "c = {a \t \t b}}"),
- importFormatPreferences);
+ ParserResult result = BibtexParser.parse(
+ new StringReader("@article{test,a = {a\t\tb}," + "b = {a\t \tb}," + "c = {a \t \t b}}"),
+ importFormatPreferences);
Collection<BibEntry> c = result.getDatabase().getEntries();
BibEntry e = c.iterator().next();
- assertEquals(Optional.of("a b"), e.getFieldOptional("a"));
- assertEquals(Optional.of("a b"), e.getFieldOptional("b"));
- assertEquals(Optional.of("a b"), e.getFieldOptional("c"));
+ assertEquals(Optional.of("a b"), e.getField("a"));
+ assertEquals(Optional.of("a b"), e.getField("b"));
+ assertEquals(Optional.of("a b"), e.getField("c"));
}
/**
@@ -1240,7 +1216,7 @@ public class BibtexParserTest {
Collection<BibEntry> c = result.getDatabase().getEntries();
BibEntry e = c.iterator().next();
- assertEquals(Optional.of("ups sala"), e.getFieldOptional("file"));
+ assertEquals(Optional.of("ups sala"), e.getField("file"));
}
/**
@@ -1257,7 +1233,7 @@ public class BibtexParserTest {
Collection<BibEntry> c = result.getDatabase().getEntries();
BibEntry e = c.iterator().next();
- assertEquals(Optional.of("ups sala"), e.getFieldOptional("file"));
+ assertEquals(Optional.of("ups sala"), e.getField("file"));
}
/**
@@ -1274,7 +1250,7 @@ public class BibtexParserTest {
Collection<BibEntry> c = result.getDatabase().getEntries();
BibEntry e = c.iterator().next();
- assertEquals(Optional.of("ups sala"), e.getFieldOptional("file"));
+ assertEquals(Optional.of("ups sala"), e.getField("file"));
}
/**
@@ -1293,7 +1269,7 @@ public class BibtexParserTest {
BibEntry e = c.iterator().next();
assertEquals("article", e.getType());
assertEquals(Optional.of("test"), e.getCiteKeyOptional());
- assertEquals(Optional.of("H\'{e}lne Fiaux"), e.getFieldOptional("author"));
+ assertEquals(Optional.of("H\'{e}lne Fiaux"), e.getField("author"));
}
/**
@@ -1302,12 +1278,12 @@ public class BibtexParserTest {
@Test
public void parsePreambleAndEntryWithoutNewLine() throws IOException {
- ParserResult result = BibtexParser
- .parse(new StringReader("@preamble{some text and \\latex}@article{test,author = {H\'{e}lne Fiaux}}"),
- importFormatPreferences);
+ ParserResult result = BibtexParser.parse(
+ new StringReader("@preamble{some text and \\latex}@article{test,author = {H\'{e}lne Fiaux}}"),
+ importFormatPreferences);
assertFalse(result.hasWarnings());
- assertEquals("some text and \\latex", result.getDatabase().getPreamble());
+ assertEquals(Optional.of("some text and \\latex"), result.getDatabase().getPreamble());
Collection<BibEntry> c = result.getDatabase().getEntries();
assertEquals(1, c.size());
@@ -1315,7 +1291,7 @@ public class BibtexParserTest {
BibEntry e = c.iterator().next();
assertEquals("article", e.getType());
assertEquals(Optional.of("test"), e.getCiteKeyOptional());
- assertEquals(Optional.of("H\'{e}lne Fiaux"), e.getFieldOptional("author"));
+ assertEquals(Optional.of("H\'{e}lne Fiaux"), e.getField("author"));
}
/**
@@ -1324,12 +1300,11 @@ public class BibtexParserTest {
@Test
public void parseFileHeaderAndPreambleWithoutNewLine() throws IOException {
- ParserResult result = BibtexParser
- .parse(new StringReader("% Encoding: US-ASCII at preamble{some text and \\latex}"),
- importFormatPreferences);
+ ParserResult result = BibtexParser.parse(
+ new StringReader("% Encoding: US-ASCII at preamble{some text and \\latex}"), importFormatPreferences);
assertFalse(result.hasWarnings());
- assertEquals("some text and \\latex", result.getDatabase().getPreamble());
+ assertEquals(Optional.of("some text and \\latex"), result.getDatabase().getPreamble());
}
@Test
@@ -1358,8 +1333,8 @@ public class BibtexParserTest {
@Test
public void parseSavesNewlinesBeforeEntryInParsedSerialization() throws IOException {
String testEntry = "@article{test,author={Ed von Test}}";
- ParserResult result = BibtexParser
- .parse(new StringReader(OS.NEWLINE + OS.NEWLINE + OS.NEWLINE + testEntry), importFormatPreferences);
+ ParserResult result = BibtexParser.parse(new StringReader(OS.NEWLINE + OS.NEWLINE + OS.NEWLINE + testEntry),
+ importFormatPreferences);
Collection<BibEntry> c = result.getDatabase().getEntries();
assertEquals(1, c.size());
@@ -1415,8 +1390,9 @@ public class BibtexParserTest {
@Test
public void parseIgnoresWhitespaceInEpilogueAfterEntry() throws IOException {
String testEntry = "@article{test,author={Ed von Test}}";
- ParserResult result = BibtexParser.parse(new StringReader(
- testEntry + OS.NEWLINE + OS.NEWLINE + OS.NEWLINE + " " + OS.NEWLINE), importFormatPreferences);
+ ParserResult result = BibtexParser.parse(
+ new StringReader(testEntry + OS.NEWLINE + OS.NEWLINE + OS.NEWLINE + " " + OS.NEWLINE),
+ importFormatPreferences);
Collection<BibEntry> c = result.getDatabase().getEntries();
assertEquals(1, c.size());
@@ -1428,8 +1404,9 @@ public class BibtexParserTest {
@Test
public void parseTrimsWhitespaceInEpilogueAfterEntry() throws IOException {
String testEntry = "@article{test,author={Ed von Test}}";
- ParserResult result = BibtexParser.parse(new StringReader(
- testEntry + OS.NEWLINE + OS.NEWLINE + OS.NEWLINE + " epilogue " + OS.NEWLINE), importFormatPreferences);
+ ParserResult result = BibtexParser.parse(
+ new StringReader(testEntry + OS.NEWLINE + OS.NEWLINE + OS.NEWLINE + " epilogue " + OS.NEWLINE),
+ importFormatPreferences);
Collection<BibEntry> c = result.getDatabase().getEntries();
assertEquals(1, c.size());
@@ -1440,7 +1417,9 @@ public class BibtexParserTest {
@Test
public void parseRecognizesSaveActionsAfterEntry() throws IOException {
- BibtexParser parser = new BibtexParser(
+ BibtexParser parser = new BibtexParser(importFormatPreferences);
+
+ ParserResult parserResult = parser.parse(
new StringReader("@InProceedings{6055279,\n" + " Title = {Educational session 1},\n"
+ " Booktitle = {Custom Integrated Circuits Conference (CICC), 2011 IEEE},\n"
+ " Year = {2011},\n" + " Month = {Sept},\n"
@@ -1448,10 +1427,8 @@ public class BibtexParserTest {
+ " Abstract = {Start of the above-titled section of the conference proceedings record.},\n"
+ " DOI = {10.1109/CICC.2011.6055279},\n"
+ " ISSN = {0886-5930}\n" + "}\n" + "\n"
- + "@comment{jabref-meta: saveActions:enabled;title[lower_case]}"),
- importFormatPreferences);
-
- ParserResult parserResult = parser.parse();
+ + "@comment{jabref-meta: saveActions:enabled;title[lower_case]}")
+ );
FieldFormatterCleanups saveActions = parserResult.getMetaData().getSaveActions().get();
@@ -1461,12 +1438,44 @@ public class BibtexParserTest {
}
@Test
+ public void parseRecognizesDatabaseID() throws Exception {
+ BibtexParser parser = new BibtexParser(importFormatPreferences);
+
+ String expectedDatabaseID = "q1w2e3r4t5z6";
+
+ StringBuilder sharedDatabaseFileContent = new StringBuilder()
+ .append("% DBID: ").append(expectedDatabaseID)
+ .append(OS.NEWLINE)
+ .append("@Article{a}");
+
+ ParserResult parserResult = parser.parse(new StringReader(sharedDatabaseFileContent.toString()));
+
+ String actualDatabaseID = parserResult.getDatabase().getSharedDatabaseID().get();
+
+ assertEquals(expectedDatabaseID, actualDatabaseID);
+ }
+
+ @Test
+ public void parseDoesNotRecognizeDatabaseIDasUserComment() throws Exception {
+ BibtexParser parser = new BibtexParser(importFormatPreferences);
+ StringBuilder sharedDatabaseFileContent = new StringBuilder()
+ .append("% Encoding: UTF-8").append(OS.NEWLINE)
+ .append("% DBID: q1w2e3r4t5z6").append(OS.NEWLINE)
+ .append("@Article{a}");
+
+ ParserResult parserResult = parser.parse(new StringReader(sharedDatabaseFileContent.toString()));
+ List<BibEntry> entries = parserResult.getDatabase().getEntries();
+
+ assertEquals(1, entries.size());
+ assertEquals("", entries.get(0).getUserComments());
+ }
+
+ @Test
public void integrationTestSaveActions() throws IOException {
- BibtexParser parser = new BibtexParser(
- new StringReader("@comment{jabref-meta: saveActions:enabled;title[lower_case]}"),
- importFormatPreferences);
+ BibtexParser parser = new BibtexParser(importFormatPreferences);
- ParserResult parserResult = parser.parse();
+ ParserResult parserResult = parser.parse(
+ new StringReader("@comment{jabref-meta: saveActions:enabled;title[lower_case]}"));
FieldFormatterCleanups saveActions = parserResult.getMetaData().getSaveActions().get();
assertTrue(saveActions.isEnabled());
@@ -1492,30 +1501,28 @@ public class BibtexParserTest {
@Test
public void integrationTestSaveOrderConfig() throws IOException {
- ParserResult result = BibtexParser.parse(new StringReader(
- "@Comment{jabref-meta: saveOrderConfig:specified;author;false;year;true;abstract;false;}"),
+ ParserResult result = BibtexParser.parse(
+ new StringReader(
+ "@Comment{jabref-meta: saveOrderConfig:specified;author;false;year;true;abstract;false;}"),
importFormatPreferences);
Optional<SaveOrderConfig> saveOrderConfig = result.getMetaData().getSaveOrderConfig();
assertEquals(new SaveOrderConfig(false, new SaveOrderConfig.SortCriterion("author", false),
- new SaveOrderConfig.SortCriterion("year", true), new SaveOrderConfig.SortCriterion("abstract", false)),
+ new SaveOrderConfig.SortCriterion("year", true), new SaveOrderConfig.SortCriterion("abstract", false)),
saveOrderConfig.get());
}
@Test
public void integrationTestCustomKeyPattern() throws IOException {
ParserResult result = BibtexParser
- .parse(new StringReader(
- "@comment{jabref-meta: keypattern_article:articleTest;}"
- + OS.NEWLINE
- + "@comment{jabref-meta: keypatterndefault:test;}"),
- importFormatPreferences);
+ .parse(new StringReader("@comment{jabref-meta: keypattern_article:articleTest;}" + OS.NEWLINE
+ + "@comment{jabref-meta: keypatterndefault:test;}"), importFormatPreferences);
- AbstractBibtexKeyPattern bibtexKeyPattern = result.getMetaData()
- .getBibtexKeyPattern(Globals.prefs.getKeyPattern());
+ GlobalBibtexKeyPattern pattern = JabRefPreferences.getInstance().getKeyPattern();
+ AbstractBibtexKeyPattern bibtexKeyPattern = result.getMetaData().getCiteKeyPattern(pattern);
- AbstractBibtexKeyPattern expectedPattern = new DatabaseBibtexKeyPattern(Globals.prefs.getKeyPattern());
+ AbstractBibtexKeyPattern expectedPattern = new DatabaseBibtexKeyPattern(pattern);
expectedPattern.setDefaultValue("test");
expectedPattern.addBibtexKeyPattern("article", "articleTest");
@@ -1534,34 +1541,25 @@ public class BibtexParserTest {
@Test
public void integrationTestGroupTree() throws IOException, ParseException {
- ParserResult result = BibtexParser.parse(new StringReader(
- "@comment{jabref-meta: groupsversion:3;}"
- + OS.NEWLINE +
- "@comment{jabref-meta: groupstree:"
- + OS.NEWLINE
- + "0 AllEntriesGroup:;"
- + OS.NEWLINE
- + "1 KeywordGroup:Fréchet\\;0\\;keywords\\;FrechetSpace\\;0\\;1\\;;"
- + OS.NEWLINE
- + "1 KeywordGroup:Invariant theory\\;0\\;keywords\\;GIT\\;0\\;0\\;;"
- + OS.NEWLINE
- + "1 ExplicitGroup:TestGroup\\;0\\;Key1\\;Key2\\;;"
- + "}"),
- importFormatPreferences);
-
- GroupTreeNode root = result.getMetaData().getGroups();
-
- assertEquals(new AllEntriesGroup(), root.getGroup());
+ ParserResult result = BibtexParser.parse(new StringReader("@comment{jabref-meta: groupsversion:3;}" + OS.NEWLINE
+ + "@comment{jabref-meta: groupstree:" + OS.NEWLINE + "0 AllEntriesGroup:;" + OS.NEWLINE
+ + "1 KeywordGroup:Fréchet\\;0\\;keywords\\;FrechetSpace\\;0\\;1\\;;" + OS.NEWLINE
+ + "1 KeywordGroup:Invariant theory\\;0\\;keywords\\;GIT\\;0\\;0\\;;" + OS.NEWLINE
+ + "1 ExplicitGroup:TestGroup\\;0\\;Key1\\;Key2\\;;" + "}"), importFormatPreferences);
+
+ GroupTreeNode root = result.getMetaData().getGroups().get();
+
+ assertEquals(new AllEntriesGroup(""), root.getGroup());
assertEquals(3, root.getNumberOfChildren());
assertEquals(
new KeywordGroup("Fréchet", "keywords", "FrechetSpace", false, true, GroupHierarchyType.INDEPENDENT,
- Globals.prefs),
- root.getChildren().get(0).getGroup());
+ ','), root.getChildren().get(0).getGroup());
assertEquals(
new KeywordGroup("Invariant theory", "keywords", "GIT", false, false, GroupHierarchyType.INDEPENDENT,
- Globals.prefs),
+ ','),
root.getChildren().get(1).getGroup());
- assertEquals(Arrays.asList("Key1", "Key2"), ((ExplicitGroup) root.getChildren().get(2).getGroup()).getLegacyEntryKeys());
+ assertEquals(Arrays.asList("Key1", "Key2"),
+ ((ExplicitGroup) root.getChildren().get(2).getGroup()).getLegacyEntryKeys());
}
@Test
@@ -1573,21 +1571,19 @@ public class BibtexParserTest {
}
@Test
- public void integrationTestContentSelectors() throws IOException {
- ParserResult result = BibtexParser
- .parse(new StringReader("@comment{jabref-meta: selector_title:testWord;word2;}"),
- importFormatPreferences);
+ public void integrationTestOldContentSelectorsAreIgnored() throws IOException {
+ ParserResult result = BibtexParser.parse(
+ new StringReader("@comment{jabref-meta: selector_title:testWord;word2;}"), importFormatPreferences);
- assertEquals(Arrays.asList("testWord", "word2"), result.getMetaData().getContentSelectors("title"));
+ assertEquals(new MetaData(), result.getMetaData());
}
@Test
public void integrationTestFileDirectories() throws IOException {
- ParserResult result = BibtexParser
- .parse(new StringReader(
- "@comment{jabref-meta: fileDirectory:\\\\Literature\\\\;}"
- + "@comment{jabref-meta: fileDirectory-defaultOwner-user:D:\\\\Documents;}"),
- importFormatPreferences);
+ ParserResult result = BibtexParser.parse(
+ new StringReader("@comment{jabref-meta: fileDirectory:\\\\Literature\\\\;}"
+ + "@comment{jabref-meta: fileDirectory-defaultOwner-user:D:\\\\Documents;}"),
+ importFormatPreferences);
assertEquals("\\Literature\\", result.getMetaData().getDefaultFileDirectory().get());
assertEquals("D:\\Documents", result.getMetaData().getUserFileDirectory("defaultOwner-user").get());
@@ -1595,8 +1591,8 @@ public class BibtexParserTest {
@Test
public void parseReturnsEntriesInSameOrder() throws IOException {
- ParserResult result = BibtexParser.parse(new StringReader(
- "@article{a}" + OS.NEWLINE + "@article{b}" + OS.NEWLINE + "@inProceedings{c}"),
+ ParserResult result = BibtexParser.parse(
+ new StringReader("@article{a}" + OS.NEWLINE + "@article{b}" + OS.NEWLINE + "@inProceedings{c}"),
importFormatPreferences);
List<BibEntry> expected = new ArrayList<>();
@@ -1641,7 +1637,7 @@ public class BibtexParserTest {
assertEquals(5, entry.getFieldNames().size());
Set<String> fields = entry.getFieldNames();
assertTrue(fields.contains("author"));
- assertEquals(Optional.of("Foo Bar"), entry.getFieldOptional("author"));
+ assertEquals(Optional.of("Foo Bar"), entry.getField("author"));
assertEquals(bibtexEntry, entry.getParsedSerialization());
}
@@ -1667,7 +1663,7 @@ public class BibtexParserTest {
assertEquals(5, entry.getFieldNames().size());
Set<String> fields = entry.getFieldNames();
assertTrue(fields.contains("author"));
- assertEquals(Optional.of("Foo Bar"), entry.getFieldOptional("author"));
+ assertEquals(Optional.of("Foo Bar"), entry.getField("author"));
assertEquals(bibtexEntry, entry.getParsedSerialization());
}
@@ -1711,7 +1707,7 @@ public class BibtexParserTest {
}
@Test
- public void parseCommentWithoutBrackets () throws IOException {
+ public void parseCommentWithoutBrackets() throws IOException {
String commentText = "@Comment someComment";
ParserResult result = BibtexParser.parse(new StringReader(commentText), importFormatPreferences);
@@ -1779,4 +1775,17 @@ public class BibtexParserTest {
assertEquals(bibtexEntry, entry.getParsedSerialization());
}
+ @Test
+ public void parseEmptyPreambleLeadsToEmpty() throws IOException {
+ ParserResult result = BibtexParser.parse(new StringReader("@preamble{}"), importFormatPreferences);
+ assertFalse(result.hasWarnings());
+ assertEquals(Optional.empty(), result.getDatabase().getPreamble());
+ }
+
+ @Test
+ public void parseEmptyFileLeadsToPreamble() throws IOException {
+ ParserResult result = BibtexParser.parse(new StringReader(""), importFormatPreferences);
+ assertFalse(result.hasWarnings());
+ assertEquals(Optional.empty(), result.getDatabase().getPreamble());
+ }
}
diff --git a/src/test/java/net/sf/jabref/logic/importer/fileformat/CopacImporterTest.java b/src/test/java/net/sf/jabref/logic/importer/fileformat/CopacImporterTest.java
index 3979019..78dac68 100644
--- a/src/test/java/net/sf/jabref/logic/importer/fileformat/CopacImporterTest.java
+++ b/src/test/java/net/sf/jabref/logic/importer/fileformat/CopacImporterTest.java
@@ -1,16 +1,14 @@
package net.sf.jabref.logic.importer.fileformat;
import java.io.IOException;
-import java.net.URISyntaxException;
-import java.nio.charset.Charset;
-import java.nio.file.DirectoryStream;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
-import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
import net.sf.jabref.logic.util.FileExtensions;
import net.sf.jabref.model.entry.BibEntry;
@@ -21,7 +19,6 @@ import org.junit.Test;
public class CopacImporterTest {
- private static final String FILEFORMAT_PATH = "src/test/resources/net/sf/jabref/logic/importer/fileformat";
private CopacImporter importer;
@@ -31,12 +28,12 @@ public class CopacImporterTest {
* @return A list of Names
* @throws IOException
*/
- public List<String> getTestFiles() throws IOException {
- List<String> files = new ArrayList<>();
- try (DirectoryStream<Path> stream = Files.newDirectoryStream(Paths.get(FILEFORMAT_PATH))) {
- stream.forEach(n -> files.add(n.getFileName().toString()));
+ public List<String> getTestFiles() throws Exception {
+ try (Stream<Path> stream = Files.list(Paths.get(CopacImporterTest.class.getResource("").toURI()))) {
+ return stream.filter(p -> !Files.isDirectory(p)).map(f -> f.getFileName().toString())
+ .collect(Collectors.toList());
+
}
- return files;
}
@Before
@@ -56,19 +53,19 @@ public class CopacImporterTest {
}
@Test
- public void testIsNotRecognizedFormat() throws IOException, URISyntaxException {
+ public void testIsNotRecognizedFormat() throws Exception {
List<String> list = getTestFiles().stream().filter(n -> !n.startsWith("CopacImporterTest"))
.collect(Collectors.toList());
for (String str : list) {
Path file = Paths.get(CopacImporterTest.class.getResource(str).toURI());
- Assert.assertFalse(importer.isRecognizedFormat(file, Charset.defaultCharset()));
+ Assert.assertFalse(importer.isRecognizedFormat(file, StandardCharsets.UTF_8));
}
}
@Test
- public void testImportEmptyEntries() throws IOException, URISyntaxException {
+ public void testImportEmptyEntries() throws Exception {
Path path = Paths.get(CopacImporterTest.class.getResource("Empty.txt").toURI());
- List<BibEntry> entries = importer.importDatabase(path, Charset.defaultCharset()).getDatabase().getEntries();
+ List<BibEntry> entries = importer.importDatabase(path, StandardCharsets.UTF_8).getDatabase().getEntries();
Assert.assertEquals(Collections.emptyList(), entries);
}
}
diff --git a/src/test/java/net/sf/jabref/logic/importer/fileformat/CopacImporterTestFiles.java b/src/test/java/net/sf/jabref/logic/importer/fileformat/CopacImporterTestFiles.java
index fe6c8fa..4ce1bc7 100644
--- a/src/test/java/net/sf/jabref/logic/importer/fileformat/CopacImporterTestFiles.java
+++ b/src/test/java/net/sf/jabref/logic/importer/fileformat/CopacImporterTestFiles.java
@@ -1,17 +1,13 @@
package net.sf.jabref.logic.importer.fileformat;
-import java.io.IOException;
import java.io.InputStream;
-import java.net.URISyntaxException;
-import java.nio.charset.Charset;
-import java.nio.file.DirectoryStream;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
-import java.util.ArrayList;
import java.util.Collection;
-import java.util.List;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
import net.sf.jabref.logic.bibtex.BibEntryAssert;
@@ -27,7 +23,6 @@ import org.junit.runners.Parameterized.Parameters;
public class CopacImporterTestFiles {
private CopacImporter copacImporter;
- private final static String FILEFORMAT_PATH = "src/test/resources/net/sf/jabref/logic/importer/fileformat";
@Parameter
public String fileName;
@@ -39,23 +34,24 @@ public class CopacImporterTestFiles {
}
@Parameters(name = "{0}")
- public static Collection<String> fileNames() throws IOException {
- List<String> files = new ArrayList<>();
- try (DirectoryStream<Path> stream = Files.newDirectoryStream(Paths.get(FILEFORMAT_PATH))) {
- stream.forEach(n -> files.add(n.getFileName().toString()));
+ public static Collection<String> fileNames() throws Exception {
+
+ try (Stream<Path> stream = Files.list(Paths.get(CopacImporterTestFiles.class.getResource("").toURI()))) {
+ return stream
+ .filter(n -> n.getFileName().toString().startsWith("CopacImporterTest")
+ && n.getFileName().toString().endsWith(".txt"))
+ .map(f -> f.getFileName().toString()).collect(Collectors.toList());
}
- return files.stream().filter(n -> n.startsWith("CopacImporterTest")).filter(n -> n.endsWith(".txt"))
- .collect(Collectors.toList());
}
@Test
- public void testIsRecognizedFormat() throws IOException, URISyntaxException {
+ public void testIsRecognizedFormat() throws Exception {
Path file = Paths.get(CopacImporterTest.class.getResource(fileName).toURI());
- Assert.assertTrue(copacImporter.isRecognizedFormat(file, Charset.defaultCharset()));
+ Assert.assertTrue(copacImporter.isRecognizedFormat(file, StandardCharsets.UTF_8));
}
@Test
- public void testImportEntries() throws IOException, URISyntaxException {
+ public void testImportEntries() throws Exception {
String bibFileName = fileName.replace(".txt", ".bib");
try (InputStream bibStream = BibtexImporterTest.class.getResourceAsStream(bibFileName)) {
diff --git a/src/test/java/net/sf/jabref/logic/importer/fileformat/CustomImporterTest.java b/src/test/java/net/sf/jabref/logic/importer/fileformat/CustomImporterTest.java
index 2d0b1fa..2f302c9 100644
--- a/src/test/java/net/sf/jabref/logic/importer/fileformat/CustomImporterTest.java
+++ b/src/test/java/net/sf/jabref/logic/importer/fileformat/CustomImporterTest.java
@@ -1,14 +1,14 @@
package net.sf.jabref.logic.importer.fileformat;
-import java.io.File;
+import java.nio.file.Paths;
import java.util.Arrays;
-import java.util.List;
+
+import net.sf.jabref.logic.importer.Importer;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
public class CustomImporterTest {
@@ -16,8 +16,8 @@ public class CustomImporterTest {
private CustomImporter importer;
@Before
- public void setUp() {
- importer = new CustomImporter(new CopacImporter());
+ public void setUp() throws Exception {
+ importer = asCustomImporter(new CopacImporter());
}
@Test
@@ -26,8 +26,8 @@ public class CustomImporterTest {
}
@Test
- public void testGetCliId() {
- assertEquals("cpc", importer.getClidId());
+ public void testGetId() {
+ assertEquals("cpc", importer.getId());
}
@Test
@@ -37,65 +37,45 @@ public class CustomImporterTest {
@Test
public void testGetBasePath() {
- assertEquals("src/main/java/net/sf/jabref/logic/importer/fileformat/CopacImporter.java",
+ assertEquals(Paths.get("src/main/java/net/sf/jabref/logic/importer/fileformat/CopacImporter.java"),
importer.getBasePath());
}
@Test
- public void testGetInstance() throws Exception {
- assertEquals(new CopacImporter(), importer.getInstance());
- }
-
- @Test
- public void testGetFileFromBasePath() {
- assertEquals(new File("src/main/java/net/sf/jabref/logic/importer/fileformat/CopacImporter.java"),
- importer.getFileFromBasePath());
- }
-
- @Test
- public void testGetBasePathUrl() throws Exception {
- assertEquals(
- new File("src/main/java/net/sf/jabref/logic/importer/fileformat/CopacImporter.java").toURI().toURL(),
- importer.getBasePathUrl());
- }
-
- @Test
public void testGetAsStringList() {
- assertEquals("Copac", importer.getAsStringList().get(0));
- assertEquals("cpc", importer.getAsStringList().get(1));
- assertEquals("net.sf.jabref.logic.importer.fileformat.CopacImporter", importer.getAsStringList().get(2));
- assertEquals("src/main/java/net/sf/jabref/logic/importer/fileformat/CopacImporter.java",
- importer.getAsStringList().get(3));
+ assertEquals(Arrays.asList("src/main/java/net/sf/jabref/logic/importer/fileformat/CopacImporter.java",
+ "net.sf.jabref.logic.importer.fileformat.CopacImporter"), importer.getAsStringList());
}
@Test
- public void testEqualsTrue() {
+ public void equalsWithSameReference() {
assertEquals(importer, importer);
}
@Test
- public void testEqualsFalse() {
- assertNotEquals(new CopacImporter(), importer);
+ public void equalsIsBasedOnName() {
+ //noinspection AssertEqualsBetweenInconvertibleTypes
+ assertEquals(new CopacImporter(), importer);
}
@Test
- public void testCompareToSmaller() {
- CustomImporter ovidImporter = new CustomImporter(new OvidImporter());
+ public void testCompareToSmaller() throws Exception {
+ CustomImporter ovidImporter = asCustomImporter(new OvidImporter());
assertTrue(importer.compareTo(ovidImporter) < 0);
}
@Test
- public void testCompareToGreater() {
- CustomImporter bibtexmlImporter = new CustomImporter(new BibTeXMLImporter());
- CustomImporter ovidImporter = new CustomImporter(new OvidImporter());
+ public void testCompareToGreater() throws Exception {
+ CustomImporter bibtexmlImporter = asCustomImporter(new BibTeXMLImporter());
+ CustomImporter ovidImporter = asCustomImporter(new OvidImporter());
assertTrue(ovidImporter.compareTo(bibtexmlImporter) > 0);
}
@Test
- public void testCompareToEven() {
- assertEquals(0, importer.compareTo(new CustomImporter(new CopacImporter())));
+ public void testCompareToEven() throws Exception {
+ assertEquals(0, importer.compareTo(asCustomImporter(new CopacImporter())));
}
@Test
@@ -104,33 +84,16 @@ public class CustomImporterTest {
}
@Test
- public void testClassicConstructor() {
- CustomImporter customImporter = new CustomImporter("Copac", "cpc",
- "net.sf.jabref.logic.importer.fileformat.CopacImporter",
- "src/main/java/net/sf/jabref/logic/importer/fileformat/CopacImporter.java");
+ public void testClassicConstructor() throws Exception {
+ CustomImporter customImporter = new CustomImporter(
+ "src/main/java/net/sf/jabref/logic/importer/fileformat/CopacImporter.java",
+ "net.sf.jabref.logic.importer.fileformat.CopacImporter");
assertEquals(importer, customImporter);
}
- @Test
- public void testListConstructor() {
- List<String> dataTest = Arrays.asList("Ovid", "ovid", "net.sf.jabref.logic.importer.fileformat.OvidImporter",
- "src/main/java/net/sf/jabref/logic/importer/fileformat/OvidImporter.java");
- CustomImporter customImporter = new CustomImporter(dataTest);
- CustomImporter customOvidImporter = new CustomImporter(new OvidImporter());
-
- assertEquals(customImporter, customOvidImporter);
- }
-
- @Test
- public void testEmptyConstructor() {
- CustomImporter customImporter = new CustomImporter();
- customImporter.setName("Ovid");
- customImporter.setCliId("ovid");
- customImporter.setClassName("net.sf.jabref.logic.importer.fileformat.OvidImporter");
- customImporter.setBasePath("src/main/java/net/sf/jabref/logic/importer/fileformat/OvidImporter.java");
-
- CustomImporter customOvidImporter = new CustomImporter(new OvidImporter());
-
- assertEquals(customImporter, customOvidImporter);
+ private CustomImporter asCustomImporter(Importer importer) throws Exception {
+ return new CustomImporter(
+ "src/main/java/net/sf/jabref/logic/importer/fileformat/" + importer.getName() + "Importer.java",
+ importer.getClass().getName());
}
}
diff --git a/src/test/java/net/sf/jabref/logic/importer/fileformat/EndnoteImporterTest.java b/src/test/java/net/sf/jabref/logic/importer/fileformat/EndnoteImporterTest.java
index 9d6f38e..4f7846c 100644
--- a/src/test/java/net/sf/jabref/logic/importer/fileformat/EndnoteImporterTest.java
+++ b/src/test/java/net/sf/jabref/logic/importer/fileformat/EndnoteImporterTest.java
@@ -5,13 +5,13 @@ import java.io.IOException;
import java.io.StringReader;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
-import net.sf.jabref.logic.importer.ImportFormatPreferences;
import net.sf.jabref.logic.util.FileExtensions;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.preferences.JabRefPreferences;
@@ -23,19 +23,19 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-
public class EndnoteImporterTest {
private EndnoteImporter importer;
+
@Before
public void setUp() {
- importer = new EndnoteImporter(ImportFormatPreferences.fromPreferences(JabRefPreferences.getInstance()));
+ importer = new EndnoteImporter(JabRefPreferences.getInstance().getImportFormatPreferences());
}
@Test
public void testGetFormatName() {
- assertEquals("Refer/Endnote", importer.getFormatName());
+ assertEquals("Refer/Endnote", importer.getName());
}
@Test
@@ -52,8 +52,8 @@ public class EndnoteImporterTest {
@Test
public void testGetDescription() {
- assertEquals("Importer for the Refer/Endnote format." +
- " Modified to use article number for pages if pages are missing.", importer.getDescription());
+ assertEquals("Importer for the Refer/Endnote format."
+ + " Modified to use article number for pages if pages are missing.", importer.getDescription());
}
@Test
@@ -62,7 +62,7 @@ public class EndnoteImporterTest {
for (String str : list) {
Path file = Paths.get(EndnoteImporterTest.class.getResource(str).toURI());
- assertTrue(importer.isRecognizedFormat(file, Charset.defaultCharset()));
+ assertTrue(importer.isRecognizedFormat(file, StandardCharsets.UTF_8));
}
}
@@ -81,79 +81,81 @@ public class EndnoteImporterTest {
@Test
public void testImportEntries0() throws IOException, URISyntaxException {
Path file = Paths.get(EndnoteImporterTest.class.getResource("Endnote.entries.enw").toURI());
- List<BibEntry> bibEntries = importer.importDatabase(file, Charset.defaultCharset()).getDatabase().getEntries();
+ List<BibEntry> bibEntries = importer.importDatabase(file, StandardCharsets.UTF_8).getDatabase().getEntries();
assertEquals(5, bibEntries.size());
BibEntry be0 = bibEntries.get(0);
assertEquals("misc", be0.getType());
- assertEquals(Optional.of("testA0 and testA1"), be0.getFieldOptional("author"));
- assertEquals(Optional.of("testE0 and testE1"), be0.getFieldOptional("editor"));
- assertEquals(Optional.of("testT"), be0.getFieldOptional("title"));
+ assertEquals(Optional.of("testA0 and testA1"), be0.getField("author"));
+ assertEquals(Optional.of("testE0 and testE1"), be0.getField("editor"));
+ assertEquals(Optional.of("testT"), be0.getField("title"));
BibEntry be1 = bibEntries.get(1);
assertEquals("misc", be1.getType());
- assertEquals(Optional.of("testC"), be1.getFieldOptional("address"));
- assertEquals(Optional.of("testB2"), be1.getFieldOptional("booktitle"));
- assertEquals(Optional.of("test8"), be1.getFieldOptional("date"));
- assertEquals(Optional.of("test7"), be1.getFieldOptional("edition"));
- assertEquals(Optional.of("testJ"), be1.getFieldOptional("journal"));
- assertEquals(Optional.of("testD"), be1.getFieldOptional("year"));
+ assertEquals(Optional.of("testC"), be1.getField("address"));
+ assertEquals(Optional.of("testB2"), be1.getField("booktitle"));
+ assertEquals(Optional.of("test8"), be1.getField("date"));
+ assertEquals(Optional.of("test7"), be1.getField("edition"));
+ assertEquals(Optional.of("testJ"), be1.getField("journal"));
+ assertEquals(Optional.of("testD"), be1.getField("year"));
BibEntry be2 = bibEntries.get(2);
assertEquals("article", be2.getType());
- assertEquals(Optional.of("testB0"), be2.getFieldOptional("journal"));
+ assertEquals(Optional.of("testB0"), be2.getField("journal"));
BibEntry be3 = bibEntries.get(3);
assertEquals("book", be3.getType());
- assertEquals(Optional.of("testI0"), be3.getFieldOptional("publisher"));
- assertEquals(Optional.of("testB1"), be3.getFieldOptional("series"));
+ assertEquals(Optional.of("testI0"), be3.getField("publisher"));
+ assertEquals(Optional.of("testB1"), be3.getField("series"));
BibEntry be4 = bibEntries.get(4);
assertEquals("mastersthesis", be4.getType());
- assertEquals(Optional.of("testX"), be4.getFieldOptional("abstract"));
- assertEquals(Optional.of("testF"), be4.getFieldOptional("bibtexkey"));
- assertEquals(Optional.of("testR"), be4.getFieldOptional("doi"));
- assertEquals(Optional.of("testK"), be4.getFieldOptional("keywords"));
- assertEquals(Optional.of("testO1"), be4.getFieldOptional("note"));
- assertEquals(Optional.of("testN"), be4.getFieldOptional("number"));
- assertEquals(Optional.of("testP"), be4.getFieldOptional("pages"));
- assertEquals(Optional.of("testI1"), be4.getFieldOptional("school"));
- assertEquals(Optional.of("testU"), be4.getFieldOptional("url"));
- assertEquals(Optional.of("testV"), be4.getFieldOptional("volume"));
+ assertEquals(Optional.of("testX"), be4.getField("abstract"));
+ assertEquals(Optional.of("testF"), be4.getField("bibtexkey"));
+ assertEquals(Optional.of("testR"), be4.getField("doi"));
+ assertEquals(Optional.of("testK"), be4.getField("keywords"));
+ assertEquals(Optional.of("testO1"), be4.getField("note"));
+ assertEquals(Optional.of("testN"), be4.getField("number"));
+ assertEquals(Optional.of("testP"), be4.getField("pages"));
+ assertEquals(Optional.of("testI1"), be4.getField("school"));
+ assertEquals(Optional.of("testU"), be4.getField("url"));
+ assertEquals(Optional.of("testV"), be4.getField("volume"));
}
@Test
public void testImportEntries1() throws IOException {
String s = "%O Artn\\\\s testO\n%A testA,\n%E testE0, testE1";
- List<BibEntry> bibEntries = importer.importDatabase(new BufferedReader(new StringReader(s))).getDatabase().getEntries();
+ List<BibEntry> bibEntries = importer.importDatabase(new BufferedReader(new StringReader(s))).getDatabase()
+ .getEntries();
assertEquals(1, bibEntries.size());
BibEntry be = bibEntries.get(0);
assertEquals("misc", be.getType());
- assertEquals(Optional.of("testA"), be.getFieldOptional("author"));
- assertEquals(Optional.of("testE0, testE1"), be.getFieldOptional("editor"));
- assertEquals(Optional.of("testO"), be.getFieldOptional("pages"));
+ assertEquals(Optional.of("testA"), be.getField("author"));
+ assertEquals(Optional.of("testE0, testE1"), be.getField("editor"));
+ assertEquals(Optional.of("testO"), be.getField("pages"));
}
@Test
public void testImportEntriesBookExample() throws IOException, URISyntaxException {
Path file = Paths.get(EndnoteImporterTest.class.getResource("Endnote.book.example.enw").toURI());
- List<BibEntry> bibEntries = importer.importDatabase(file, Charset.defaultCharset()).getDatabase().getEntries();
+ List<BibEntry> bibEntries = importer.importDatabase(file, StandardCharsets.UTF_8).getDatabase().getEntries();
assertEquals(1, bibEntries.size());
BibEntry be = bibEntries.get(0);
assertEquals("book", be.getType());
- assertEquals(Optional.of("Heidelberg"), be.getFieldOptional("address"));
- assertEquals(Optional.of("Preißel, René and Stachmann, Bjørn"), be.getFieldOptional("author"));
- assertEquals(Optional.of("3., aktualisierte und erweiterte Auflage"), be.getFieldOptional("edition"));
- assertEquals(Optional.of("Versionsverwaltung"), be.getFieldOptional("keywords"));
- assertEquals(Optional.of("XX, 327"), be.getFieldOptional("pages"));
- assertEquals(Optional.of("dpunkt.verlag"), be.getFieldOptional("publisher"));
- assertEquals(Optional.of("Git : dezentrale Versionsverwaltung im Team : Grundlagen und Workflows"), be.getFieldOptional("title"));
- assertEquals(Optional.of("http://d-nb.info/107601965X"), be.getFieldOptional("url"));
- assertEquals(Optional.of("2016"), be.getFieldOptional("year"));
+ assertEquals(Optional.of("Heidelberg"), be.getField("address"));
+ assertEquals(Optional.of("Preißel, René and Stachmann, Bjørn"), be.getField("author"));
+ assertEquals(Optional.of("3., aktualisierte und erweiterte Auflage"), be.getField("edition"));
+ assertEquals(Optional.of("Versionsverwaltung"), be.getField("keywords"));
+ assertEquals(Optional.of("XX, 327"), be.getField("pages"));
+ assertEquals(Optional.of("dpunkt.verlag"), be.getField("publisher"));
+ assertEquals(Optional.of("Git : dezentrale Versionsverwaltung im Team : Grundlagen und Workflows"),
+ be.getField("title"));
+ assertEquals(Optional.of("http://d-nb.info/107601965X"), be.getField("url"));
+ assertEquals(Optional.of("2016"), be.getField("year"));
}
}
diff --git a/src/test/java/net/sf/jabref/logic/importer/fileformat/FreeCiteImporterTest.java b/src/test/java/net/sf/jabref/logic/importer/fileformat/FreeCiteImporterTest.java
index 2126590..ce3e89f 100644
--- a/src/test/java/net/sf/jabref/logic/importer/fileformat/FreeCiteImporterTest.java
+++ b/src/test/java/net/sf/jabref/logic/importer/fileformat/FreeCiteImporterTest.java
@@ -1,6 +1,5 @@
package net.sf.jabref.logic.importer.fileformat;
-import net.sf.jabref.logic.importer.ImportFormatPreferences;
import net.sf.jabref.logic.util.FileExtensions;
import net.sf.jabref.preferences.JabRefPreferences;
@@ -16,12 +15,12 @@ public class FreeCiteImporterTest {
@Before
public void setUp() {
- importer = new FreeCiteImporter(ImportFormatPreferences.fromPreferences(JabRefPreferences.getInstance()));
+ importer = new FreeCiteImporter(JabRefPreferences.getInstance().getImportFormatPreferences());
}
@Test
public void testGetFormatName() {
- assertEquals("text citations", importer.getFormatName());
+ assertEquals("text citations", importer.getName());
}
@Test
diff --git a/src/test/java/net/sf/jabref/logic/importer/fileformat/ImportFormatTest.java b/src/test/java/net/sf/jabref/logic/importer/fileformat/ImportFormatTest.java
deleted file mode 100644
index 0213315..0000000
--- a/src/test/java/net/sf/jabref/logic/importer/fileformat/ImportFormatTest.java
+++ /dev/null
@@ -1,101 +0,0 @@
-package net.sf.jabref.logic.importer.fileformat;
-
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.regex.Pattern;
-
-import net.sf.jabref.logic.importer.ImportFormatPreferences;
-import net.sf.jabref.logic.xmp.XMPPreferences;
-import net.sf.jabref.preferences.JabRefPreferences;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameter;
-import org.junit.runners.Parameterized.Parameters;
-import org.mockito.Mockito;
-
-import static org.mockito.Mockito.when;
-
- at RunWith(Parameterized.class)
-public class ImportFormatTest {
-
- @Parameter
- public ImportFormat format;
-
- @Test(expected = NullPointerException.class)
- public void isRecognizedFormatWithNullThrowsException() throws IOException {
- format.isRecognizedFormat(null);
- }
-
- @Test(expected = NullPointerException.class)
- public void importDatabaseWithNullThrowsException() throws IOException {
- format.importDatabase(null);
- }
-
- @Test
- public void getFormatterNameDoesNotReturnNull() {
- Assert.assertNotNull(format.getFormatName());
- }
-
- @Test
- public void getExtensionsDoesNotReturnNull() {
- Assert.assertNotNull(format.getExtensions());
- }
-
- @Test
- public void getIdDoesNotReturnNull() {
- Assert.assertNotNull(format.getId());
- }
-
- @Test
- public void getIdDoesNotContainWhitespace() {
- Pattern whitespacePattern = Pattern.compile("\\s");
- Assert.assertFalse(whitespacePattern.matcher(format.getId()).find());
- }
-
- @Test
- public void getIdStripsSpecialCharactersAndConvertsToLowercase() {
- ImportFormat importFormat = Mockito.mock(ImportFormat.class, Mockito.CALLS_REAL_METHODS);
- when(importFormat.getFormatName()).thenReturn("*Test-Importer");
- Assert.assertEquals("testimporter", importFormat.getId());
- }
-
- @Test
- public void getDescriptionDoesNotReturnNull() {
- Assert.assertNotNull(format.getDescription());
- }
-
- @Parameters(name = "{index}: {0}")
- public static Collection<Object[]> instancesToTest() {
- // all classes implementing {@link ImportFormat}
- // sorted alphabetically
-
- ImportFormatPreferences importFormatPreferences = ImportFormatPreferences
- .fromPreferences(JabRefPreferences.getInstance());
- XMPPreferences xmpPreferences = XMPPreferences.fromPreferences(JabRefPreferences.getInstance());
- // @formatter:off
- return Arrays.asList(
- new Object[]{new BiblioscapeImporter()},
- new Object[]{new BibtexImporter(importFormatPreferences)},
- new Object[]{new BibTeXMLImporter()},
- new Object[]{new CopacImporter()},
- new Object[]{new EndnoteImporter(importFormatPreferences)},
- new Object[]{new FreeCiteImporter(importFormatPreferences)},
- new Object[]{new InspecImporter()},
- new Object[]{new IsiImporter()},
- new Object[]{new MedlineImporter()},
- new Object[]{new MedlinePlainImporter()},
- new Object[]{new MsBibImporter()},
- new Object[]{new OvidImporter()},
- new Object[]{new PdfContentImporter(importFormatPreferences)},
- new Object[]{new PdfXmpImporter(xmpPreferences)},
- new Object[]{new RepecNepImporter(importFormatPreferences)},
- new Object[]{new RisImporter()},
- new Object[]{new SilverPlatterImporter()}
- );
- // @formatter:on
- }
-}
diff --git a/src/test/java/net/sf/jabref/logic/importer/fileformat/InspecImportTest.java b/src/test/java/net/sf/jabref/logic/importer/fileformat/InspecImportTest.java
index 9e526da..363ebfc 100644
--- a/src/test/java/net/sf/jabref/logic/importer/fileformat/InspecImportTest.java
+++ b/src/test/java/net/sf/jabref/logic/importer/fileformat/InspecImportTest.java
@@ -4,7 +4,7 @@ import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.net.URISyntaxException;
-import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
@@ -36,7 +36,7 @@ public class InspecImportTest {
List<String> testList = Arrays.asList("InspecImportTest.txt", "InspecImportTest2.txt");
for (String str : testList) {
Path file = Paths.get(InspecImportTest.class.getResource(str).toURI());
- assertTrue(importer.isRecognizedFormat(file, Charset.defaultCharset()));
+ assertTrue(importer.isRecognizedFormat(file, StandardCharsets.UTF_8));
}
}
@@ -47,7 +47,7 @@ public class InspecImportTest {
"IsiImporterTestMedline.isi", "RisImporterTest1.ris", "InspecImportTestFalse.txt");
for (String str : testList) {
Path file = Paths.get(InspecImportTest.class.getResource(str).toURI());
- assertFalse(importer.isRecognizedFormat(file, Charset.defaultCharset()));
+ assertFalse(importer.isRecognizedFormat(file, StandardCharsets.UTF_8));
}
}
@@ -105,7 +105,7 @@ public class InspecImportTest {
@Test
public void testGetFormatName() {
- assertEquals("INSPEC", importer.getFormatName());
+ assertEquals("INSPEC", importer.getName());
}
@Test
diff --git a/src/test/java/net/sf/jabref/logic/importer/fileformat/IsiImporterTest.java b/src/test/java/net/sf/jabref/logic/importer/fileformat/IsiImporterTest.java
index 53d198f..21f0809 100644
--- a/src/test/java/net/sf/jabref/logic/importer/fileformat/IsiImporterTest.java
+++ b/src/test/java/net/sf/jabref/logic/importer/fileformat/IsiImporterTest.java
@@ -2,7 +2,7 @@ package net.sf.jabref.logic.importer.fileformat;
import java.io.IOException;
import java.net.URISyntaxException;
-import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
@@ -39,7 +39,7 @@ public class IsiImporterTest {
@Test
public void testGetFormatName() {
- assertEquals(importer.getFormatName(), "ISI");
+ assertEquals(importer.getName(), "ISI");
}
@Test
@@ -65,7 +65,7 @@ public class IsiImporterTest {
for (String str : list) {
Path file = Paths.get(IsiImporterTest.class.getResource(str).toURI());
- assertTrue(importer.isRecognizedFormat(file, Charset.defaultCharset()));
+ assertTrue(importer.isRecognizedFormat(file, StandardCharsets.UTF_8));
}
}
@@ -75,7 +75,7 @@ public class IsiImporterTest {
for (String str : list) {
Path file = Paths.get(IsiImporterTest.class.getResource(str).toURI());
- assertFalse(importer.isRecognizedFormat(file, Charset.defaultCharset()));
+ assertFalse(importer.isRecognizedFormat(file, StandardCharsets.UTF_8));
}
}
@@ -127,51 +127,51 @@ public class IsiImporterTest {
@Test
public void testImportEntries1() throws IOException, URISyntaxException {
Path file = Paths.get(IsiImporterTest.class.getResource("IsiImporterTest1.isi").toURI());
- List<BibEntry> entries = importer.importDatabase(file, Charset.defaultCharset()).getDatabase().getEntries();
+ List<BibEntry> entries = importer.importDatabase(file, StandardCharsets.UTF_8).getDatabase().getEntries();
assertEquals(1, entries.size());
BibEntry entry = entries.get(0);
assertEquals(Optional.of("Optical properties of MgO doped LiNbO$_3$ single crystals"),
- entry.getFieldOptional("title"));
+ entry.getField("title"));
assertEquals(
Optional.of(
"James Brown and James Marc Brown and Brown, J. M. and Brown, J. and Brown, J. M. and Brown, J."),
- entry.getFieldOptional("author"));
+ entry.getField("author"));
assertEquals("article", entry.getType());
- assertEquals(Optional.of("Optical Materials"), entry.getFieldOptional("journal"));
- assertEquals(Optional.of("2006"), entry.getFieldOptional("year"));
- assertEquals(Optional.of("28"), entry.getFieldOptional("volume"));
- assertEquals(Optional.of("5"), entry.getFieldOptional("number"));
- assertEquals(Optional.of("467--72"), entry.getFieldOptional("pages"));
+ assertEquals(Optional.of("Optical Materials"), entry.getField("journal"));
+ assertEquals(Optional.of("2006"), entry.getField("year"));
+ assertEquals(Optional.of("28"), entry.getField("volume"));
+ assertEquals(Optional.of("5"), entry.getField("number"));
+ assertEquals(Optional.of("467--72"), entry.getField("pages"));
}
@Test
public void testImportEntries2() throws IOException, URISyntaxException {
Path file = Paths.get(IsiImporterTest.class.getResource("IsiImporterTest2.isi").toURI());
- List<BibEntry> entries = importer.importDatabase(file, Charset.defaultCharset()).getDatabase().getEntries();
+ List<BibEntry> entries = importer.importDatabase(file, StandardCharsets.UTF_8).getDatabase().getEntries();
assertEquals(3, entries.size());
BibEntry entry = entries.get(0);
assertEquals(Optional.of("Optical properties of MgO doped LiNbO$_3$ single crystals"),
- entry.getFieldOptional("title"));
+ entry.getField("title"));
assertEquals("misc", entry.getType());
- assertEquals(Optional.of("Optical Materials"), entry.getFieldOptional("journal"));
- assertEquals(Optional.of("2006"), entry.getFieldOptional("year"));
- assertEquals(Optional.of("28"), entry.getFieldOptional("volume"));
- assertEquals(Optional.of("5"), entry.getFieldOptional("number"));
- assertEquals(Optional.of("467-72"), entry.getFieldOptional("pages"));
+ assertEquals(Optional.of("Optical Materials"), entry.getField("journal"));
+ assertEquals(Optional.of("2006"), entry.getField("year"));
+ assertEquals(Optional.of("28"), entry.getField("volume"));
+ assertEquals(Optional.of("5"), entry.getField("number"));
+ assertEquals(Optional.of("467-72"), entry.getField("pages"));
}
@Test
public void testImportEntriesINSPEC() throws IOException, URISyntaxException {
Path file = Paths.get(IsiImporterTest.class.getResource("IsiImporterTestInspec.isi").toURI());
- List<BibEntry> entries = importer.importDatabase(file, Charset.defaultCharset()).getDatabase().getEntries();
+ List<BibEntry> entries = importer.importDatabase(file, StandardCharsets.UTF_8).getDatabase().getEntries();
assertEquals(2, entries.size());
BibEntry a = entries.get(0);
BibEntry b = entries.get(1);
- if (a.getFieldOptional("title").equals(
+ if (a.getField("title").equals(
Optional.of("Optical and photoelectric spectroscopy of photorefractive Sn$_2$P$_2$S$_6$ crystals"))) {
BibEntry tmp = a;
a = b;
@@ -181,40 +181,40 @@ public class IsiImporterTest {
assertEquals(
Optional.of(
"Second harmonic generation of continuous wave ultraviolet light and production of beta -BaB$_2$O$_4$ optical waveguides"),
- a.getFieldOptional("title"));
+ a.getField("title"));
assertEquals("article", a.getType());
assertEquals(Optional.of("Degl'Innocenti, R. and Guarino, A. and Poberaj, G. and Gunter, P."),
- a.getFieldOptional("author"));
- assertEquals(Optional.of("Applied Physics Letters"), a.getFieldOptional("journal"));
- assertEquals(Optional.of("2006"), a.getFieldOptional("year"));
- assertEquals(Optional.of("#jul#"), a.getFieldOptional("month"));
- assertEquals(Optional.of("89"), a.getFieldOptional("volume"));
- assertEquals(Optional.of("4"), a.getFieldOptional("number"));
- assertEquals(Optional.of("Lorem ipsum abstract"), a.getFieldOptional("abstract"));
- assertEquals(Optional.of("Aip"), a.getFieldOptional("publisher"));
+ a.getField("author"));
+ assertEquals(Optional.of("Applied Physics Letters"), a.getField("journal"));
+ assertEquals(Optional.of("2006"), a.getField("year"));
+ assertEquals(Optional.of("#jul#"), a.getField("month"));
+ assertEquals(Optional.of("89"), a.getField("volume"));
+ assertEquals(Optional.of("4"), a.getField("number"));
+ assertEquals(Optional.of("Lorem ipsum abstract"), a.getField("abstract"));
+ assertEquals(Optional.of("Aip"), a.getField("publisher"));
assertEquals(
Optional.of("Optical and photoelectric spectroscopy of photorefractive Sn$_2$P$_2$S$_6$ crystals"),
- b.getFieldOptional("title"));
+ b.getField("title"));
assertEquals("article", b.getType());
}
@Test
public void testImportEntriesWOS() throws IOException, URISyntaxException {
Path file = Paths.get(IsiImporterTest.class.getResource("IsiImporterTestWOS.isi").toURI());
- List<BibEntry> entries = importer.importDatabase(file, Charset.defaultCharset()).getDatabase().getEntries();
+ List<BibEntry> entries = importer.importDatabase(file, StandardCharsets.UTF_8).getDatabase().getEntries();
assertEquals(2, entries.size());
BibEntry a = entries.get(0);
BibEntry b = entries.get(1);
assertEquals(Optional.of("Optical and photoelectric spectroscopy of photorefractive Sn2P2S6 crystals"),
- a.getFieldOptional("title"));
+ a.getField("title"));
assertEquals(Optional.of("Optical waveguides in Sn2P2S6 by low fluence MeV He+ ion implantation"),
- b.getFieldOptional("title"));
+ b.getField("title"));
- assertEquals(Optional.of("Journal of Physics-condensed Matter"), a.getFieldOptional("journal"));
+ assertEquals(Optional.of("Journal of Physics-condensed Matter"), a.getField("journal"));
}
@Test
@@ -260,56 +260,56 @@ public class IsiImporterTest {
@Test
public void testImportIEEEExport() throws IOException, URISyntaxException {
Path file = Paths.get(IsiImporterTest.class.getResource("IEEEImport1.txt").toURI());
- List<BibEntry> entries = importer.importDatabase(file, Charset.defaultCharset()).getDatabase().getEntries();
+ List<BibEntry> entries = importer.importDatabase(file, StandardCharsets.UTF_8).getDatabase().getEntries();
assertEquals(1, entries.size());
BibEntry a = entries.get(0);
assertEquals("article", a.getType());
- assertEquals(Optional.of("Geoscience and Remote Sensing Letters, IEEE"), a.getFieldOptional("journal"));
+ assertEquals(Optional.of("Geoscience and Remote Sensing Letters, IEEE"), a.getField("journal"));
assertEquals(Optional.of("Improving Urban Road Extraction in High-Resolution "
+ "Images Exploiting Directional Filtering, Perceptual " + "Grouping, and Simple Topological Concepts"),
- a.getFieldOptional("title"));
- assertEquals(Optional.of("4"), a.getFieldOptional("volume"));
- assertEquals(Optional.of("3"), a.getFieldOptional("number"));
- assertEquals(Optional.of("1545-598X"), a.getFieldOptional("SN"));
- assertEquals(Optional.of("387--391"), a.getFieldOptional("pages"));
- assertEquals(Optional.of("Gamba, P. and Dell'Acqua, F. and Lisini, G."), a.getFieldOptional("author"));
- assertEquals(Optional.of("2006"), a.getFieldOptional("year"));
+ a.getField("title"));
+ assertEquals(Optional.of("4"), a.getField("volume"));
+ assertEquals(Optional.of("3"), a.getField("number"));
+ assertEquals(Optional.of("1545-598X"), a.getField("SN"));
+ assertEquals(Optional.of("387--391"), a.getField("pages"));
+ assertEquals(Optional.of("Gamba, P. and Dell'Acqua, F. and Lisini, G."), a.getField("author"));
+ assertEquals(Optional.of("2006"), a.getField("year"));
assertEquals(Optional.of("Perceptual grouping, street extraction, urban remote sensing"),
- a.getFieldOptional("keywords"));
- assertEquals(Optional.of("Lorem ipsum abstract"), a.getFieldOptional("abstract"));
+ a.getField("keywords"));
+ assertEquals(Optional.of("Lorem ipsum abstract"), a.getField("abstract"));
}
@Test
public void testIEEEImport() throws IOException, URISyntaxException {
Path file = Paths.get(IsiImporterTest.class.getResource("IEEEImport1.txt").toURI());
- List<BibEntry> entries = importer.importDatabase(file, Charset.defaultCharset()).getDatabase().getEntries();
+ List<BibEntry> entries = importer.importDatabase(file, StandardCharsets.UTF_8).getDatabase().getEntries();
assertEquals(1, entries.size());
BibEntry a = entries.get(0);
assertEquals("article", a.getType());
- assertEquals(Optional.of("Geoscience and Remote Sensing Letters, IEEE"), a.getFieldOptional("journal"));
+ assertEquals(Optional.of("Geoscience and Remote Sensing Letters, IEEE"), a.getField("journal"));
assertEquals(
Optional.of(
"Improving Urban Road Extraction in High-Resolution Images Exploiting Directional Filtering, Perceptual Grouping, and Simple Topological Concepts"),
- a.getFieldOptional("title"));
- assertEquals(Optional.of("4"), a.getFieldOptional("volume"));
- assertEquals(Optional.of("3"), a.getFieldOptional("number"));
- assertEquals(Optional.of("1545-598X"), a.getFieldOptional("SN"));
- assertEquals(Optional.of("387--391"), a.getFieldOptional("pages"));
- assertEquals(Optional.of("Gamba, P. and Dell'Acqua, F. and Lisini, G."), a.getFieldOptional("author"));
- assertEquals(Optional.of("2006"), a.getFieldOptional("year"));
+ a.getField("title"));
+ assertEquals(Optional.of("4"), a.getField("volume"));
+ assertEquals(Optional.of("3"), a.getField("number"));
+ assertEquals(Optional.of("1545-598X"), a.getField("SN"));
+ assertEquals(Optional.of("387--391"), a.getField("pages"));
+ assertEquals(Optional.of("Gamba, P. and Dell'Acqua, F. and Lisini, G."), a.getField("author"));
+ assertEquals(Optional.of("2006"), a.getField("year"));
assertEquals(Optional.of("Perceptual grouping, street extraction, urban remote sensing"),
- a.getFieldOptional("keywords"));
- assertEquals(Optional.of("Lorem ipsum abstract"), a.getFieldOptional("abstract"));
+ a.getField("keywords"));
+ assertEquals(Optional.of("Lorem ipsum abstract"), a.getField("abstract"));
}
@Test
public void testImportEntriesMedline() throws IOException, URISyntaxException {
Path file = Paths.get(IsiImporterTest.class.getResource("IsiImporterTestMedline.isi").toURI());
- List<BibEntry> entries = importer.importDatabase(file, Charset.defaultCharset()).getDatabase().getEntries();
+ List<BibEntry> entries = importer.importDatabase(file, StandardCharsets.UTF_8).getDatabase().getEntries();
assertEquals(2, entries.size());
BibEntry a = entries.get(0);
@@ -317,30 +317,30 @@ public class IsiImporterTest {
assertEquals(
Optional.of("Effects of modafinil on cognitive performance and alertness during sleep deprivation."),
- a.getFieldOptional("title"));
-
- assertEquals(Optional.of("Wesensten, Nancy J."), a.getFieldOptional("author"));
- assertEquals(Optional.of("Curr Pharm Des"), a.getFieldOptional("journal"));
- assertEquals(Optional.of("2006"), a.getFieldOptional("year"));
- assertEquals(Optional.empty(), a.getFieldOptional("month"));
- assertEquals(Optional.of("12"), a.getFieldOptional("volume"));
- assertEquals(Optional.of("20"), a.getFieldOptional("number"));
- assertEquals(Optional.of("2457--71"), a.getFieldOptional("pages"));
+ a.getField("title"));
+
+ assertEquals(Optional.of("Wesensten, Nancy J."), a.getField("author"));
+ assertEquals(Optional.of("Curr Pharm Des"), a.getField("journal"));
+ assertEquals(Optional.of("2006"), a.getField("year"));
+ assertEquals(Optional.empty(), a.getField("month"));
+ assertEquals(Optional.of("12"), a.getField("volume"));
+ assertEquals(Optional.of("20"), a.getField("number"));
+ assertEquals(Optional.of("2457--71"), a.getField("pages"));
assertEquals("article", a.getType());
assertEquals(
Optional.of(
"Estrogen therapy selectively enhances prefrontal cognitive processes: a randomized, double-blind, placebo-controlled study with functional magnetic resonance imaging in perimenopausal and recently postmenopausal women."),
- b.getFieldOptional("title"));
+ b.getField("title"));
assertEquals(
Optional.of(
"Joffe, Hadine and Hall, Janet E. and Gruber, Staci and Sarmiento, Ingrid A. and Cohen, Lee S. and Yurgelun-Todd, Deborah and Martin, Kathryn A."),
- b.getFieldOptional("author"));
- assertEquals(Optional.of("2006"), b.getFieldOptional("year"));
- assertEquals(Optional.of("#may#"), b.getFieldOptional("month"));
- assertEquals(Optional.of("13"), b.getFieldOptional("volume"));
- assertEquals(Optional.of("3"), b.getFieldOptional("number"));
- assertEquals(Optional.of("411--22"), b.getFieldOptional("pages"));
+ b.getField("author"));
+ assertEquals(Optional.of("2006"), b.getField("year"));
+ assertEquals(Optional.of("#may#"), b.getField("month"));
+ assertEquals(Optional.of("13"), b.getField("volume"));
+ assertEquals(Optional.of("3"), b.getField("number"));
+ assertEquals(Optional.of("411--22"), b.getField("pages"));
assertEquals("article", b.getType());
}
@@ -348,7 +348,7 @@ public class IsiImporterTest {
public void testImportEntriesEmpty() throws IOException, URISyntaxException {
Path file = Paths.get(IsiImporterTest.class.getResource("IsiImporterTestEmpty.isi").toURI());
- List<BibEntry> entries = importer.importDatabase(file, Charset.defaultCharset()).getDatabase().getEntries();
+ List<BibEntry> entries = importer.importDatabase(file, StandardCharsets.UTF_8).getDatabase().getEntries();
assertEquals(1, entries.size());
}
diff --git a/src/test/java/net/sf/jabref/logic/importer/fileformat/MedlineImporterTest.java b/src/test/java/net/sf/jabref/logic/importer/fileformat/MedlineImporterTest.java
index bbb1547..f463c0f 100644
--- a/src/test/java/net/sf/jabref/logic/importer/fileformat/MedlineImporterTest.java
+++ b/src/test/java/net/sf/jabref/logic/importer/fileformat/MedlineImporterTest.java
@@ -2,13 +2,12 @@ package net.sf.jabref.logic.importer.fileformat;
import java.io.IOException;
import java.nio.charset.Charset;
-import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
-import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
import net.sf.jabref.logic.util.FileExtensions;
@@ -35,7 +34,6 @@ import static org.junit.Assert.assertEquals;
public class MedlineImporterTest {
private MedlineImporter importer;
- private static final String FILEFORMAT_PATH = "src/test/resources/net/sf/jabref/logic/importer/fileformat";
/**
@@ -43,12 +41,10 @@ public class MedlineImporterTest {
* @return A list of Names
* @throws IOException
*/
- public List<Path> getTestFiles() throws IOException {
- List<Path> files = new ArrayList<>();
- try (DirectoryStream<Path> stream = Files.newDirectoryStream(Paths.get(FILEFORMAT_PATH))) {
- stream.forEach(files::add);
+ public List<Path> getTestFiles() throws Exception {
+ try (Stream<Path> stream = Files.list(Paths.get(MedlineImporterTest.class.getResource("").toURI()))) {
+ return stream.filter(p -> !Files.isDirectory(p)).collect(Collectors.toList());
}
- return files;
}
@Before
@@ -58,7 +54,7 @@ public class MedlineImporterTest {
@Test
public void testGetFormatName() {
- assertEquals("Medline", importer.getFormatName());
+ assertEquals("Medline", importer.getName());
}
@Test
@@ -77,7 +73,7 @@ public class MedlineImporterTest {
}
@Test
- public void testIsRecognizedFormatReject() throws IOException {
+ public void testIsRecognizedFormatReject() throws Exception {
List<Path> list = getTestFiles().stream().filter(n -> !n.getFileName().toString().startsWith("MedlineImporter"))
.collect(Collectors.toList());
diff --git a/src/test/java/net/sf/jabref/logic/importer/fileformat/MedlineImporterTestFiles.java b/src/test/java/net/sf/jabref/logic/importer/fileformat/MedlineImporterTestFiles.java
index cdb29d9..11f0d48 100644
--- a/src/test/java/net/sf/jabref/logic/importer/fileformat/MedlineImporterTestFiles.java
+++ b/src/test/java/net/sf/jabref/logic/importer/fileformat/MedlineImporterTestFiles.java
@@ -1,16 +1,15 @@
package net.sf.jabref.logic.importer.fileformat;
import java.io.IOException;
-import java.nio.charset.Charset;
-import java.nio.file.DirectoryStream;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
-import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
import net.sf.jabref.logic.bibtex.BibEntryAssert;
import net.sf.jabref.model.entry.BibEntry;
@@ -28,8 +27,6 @@ import static org.junit.Assert.assertEquals;
@RunWith(Parameterized.class)
public class MedlineImporterTestFiles {
- private final static String FILEFORMAT_PATH = "src/test/resources/net/sf/jabref/logic/importer/fileformat";
-
private MedlineImporter medlineImporter;
@Parameter
@@ -42,29 +39,27 @@ public class MedlineImporterTestFiles {
}
@Parameters(name = "{0}")
- public static Collection<Path> files() throws IOException {
- List<Path> files = new ArrayList<>();
- try (DirectoryStream<Path> stream = Files.newDirectoryStream(Paths.get(FILEFORMAT_PATH))) {
- stream.forEach(files::add);
+ public static Collection<Path> files() throws Exception {
+ try (Stream<Path> stream = Files.list(Paths.get(MedlineImporterTestFiles.class.getResource("").toURI()))) {
+ return stream.filter(n -> n.getFileName().toString().startsWith("MedlineImporterTest")
+ && n.getFileName().toString().endsWith(".xml")).collect(Collectors.toList());
}
- return files.stream().filter(n -> n.getFileName().toString().startsWith("MedlineImporterTest")
- && n.getFileName().toString().endsWith(".xml"))
- .collect(Collectors.toList());
}
@Test
public void testIsRecognizedFormat() throws IOException {
- Assert.assertTrue(medlineImporter.isRecognizedFormat(importFile, Charset.defaultCharset()));
+ Assert.assertTrue(medlineImporter.isRecognizedFormat(importFile, StandardCharsets.UTF_8));
}
@Test
public void testImportEntries() throws IOException {
- List<BibEntry> medlineEntries = medlineImporter.importDatabase(importFile, Charset.defaultCharset()).getDatabase().getEntries();
- String bibFileName = importFile.getFileName().toString().replace(".xml", ".bib");
- if (medlineEntries.isEmpty()) {
- assertEquals(Collections.emptyList(), medlineEntries);
- } else {
- BibEntryAssert.assertEquals(MedlineImporterTest.class, bibFileName, medlineEntries);
- }
+ List<BibEntry> medlineEntries = medlineImporter.importDatabase(importFile, StandardCharsets.UTF_8).getDatabase()
+ .getEntries();
+ String bibFileName = importFile.getFileName().toString().replace(".xml", ".bib");
+ if (medlineEntries.isEmpty()) {
+ assertEquals(Collections.emptyList(), medlineEntries);
+ } else {
+ BibEntryAssert.assertEquals(MedlineImporterTest.class, bibFileName, medlineEntries);
+ }
}
}
diff --git a/src/test/java/net/sf/jabref/logic/importer/fileformat/MedlinePlainImporterTest.java b/src/test/java/net/sf/jabref/logic/importer/fileformat/MedlinePlainImporterTest.java
index 55de39f..61fc753 100644
--- a/src/test/java/net/sf/jabref/logic/importer/fileformat/MedlinePlainImporterTest.java
+++ b/src/test/java/net/sf/jabref/logic/importer/fileformat/MedlinePlainImporterTest.java
@@ -5,7 +5,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.net.URISyntaxException;
-import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
@@ -55,7 +55,7 @@ public class MedlinePlainImporterTest {
"IsiImporterTestInspec.isi", "IsiImporterTestWOS.isi", "IsiImporterTestMedline.isi");
for (String str : list) {
Path file = Paths.get(MedlinePlainImporter.class.getResource(str).toURI());
- Assert.assertFalse(importer.isRecognizedFormat(file, Charset.defaultCharset()));
+ Assert.assertFalse(importer.isRecognizedFormat(file, StandardCharsets.UTF_8));
}
}
@@ -67,7 +67,7 @@ public class MedlinePlainImporterTest {
"MedlinePlainImporterTestInproceeding.txt");
for (String str : list) {
Path file = Paths.get(MedlinePlainImporter.class.getResource(str).toURI());
- Assert.assertTrue(importer.isRecognizedFormat(file, Charset.defaultCharset()));
+ Assert.assertTrue(importer.isRecognizedFormat(file, StandardCharsets.UTF_8));
}
}
@@ -81,39 +81,39 @@ public class MedlinePlainImporterTest {
Path inputFile = Paths
.get(MedlinePlainImporter.class.getResource("MedlinePlainImporterTestMultipleEntries.txt").toURI());
- List<BibEntry> entries = importer.importDatabase(inputFile, Charset.defaultCharset()).getDatabase()
+ List<BibEntry> entries = importer.importDatabase(inputFile, StandardCharsets.UTF_8).getDatabase()
.getEntries();
assertEquals(7, entries.size());
BibEntry testEntry = entries.get(0);
assertEquals("article", testEntry.getType());
- assertEquals(Optional.empty(), testEntry.getFieldOptional("month"));
- assertEquals(Optional.of("Long, Vicky and Marland, Hilary"), testEntry.getFieldOptional("author"));
+ assertEquals(Optional.empty(), testEntry.getField("month"));
+ assertEquals(Optional.of("Long, Vicky and Marland, Hilary"), testEntry.getField("author"));
assertEquals(
Optional.of(
"From danger and motherhood to health and beauty: health advice for the factory girl in early twentieth-century Britain."),
- testEntry.getFieldOptional("title"));
+ testEntry.getField("title"));
testEntry = entries.get(1);
assertEquals("conference", testEntry.getType());
- assertEquals(Optional.of("06"), testEntry.getFieldOptional("month"));
- assertEquals(Optional.empty(), testEntry.getFieldOptional("author"));
- assertEquals(Optional.empty(), testEntry.getFieldOptional("title"));
+ assertEquals(Optional.of("06"), testEntry.getField("month"));
+ assertEquals(Optional.empty(), testEntry.getField("author"));
+ assertEquals(Optional.empty(), testEntry.getField("title"));
testEntry = entries.get(2);
assertEquals("book", testEntry.getType());
assertEquals(
Optional.of(
"This is a Testtitle: This title should be appended: This title should also be appended. Another append to the Title? LastTitle"),
- testEntry.getFieldOptional("title"));
+ testEntry.getField("title"));
testEntry = entries.get(3);
assertEquals("techreport", testEntry.getType());
- Assert.assertTrue(testEntry.getFieldOptional("doi").isPresent());
+ Assert.assertTrue(testEntry.getField("doi").isPresent());
testEntry = entries.get(4);
assertEquals("inproceedings", testEntry.getType());
- assertEquals(Optional.of("Inproceedings book title"), testEntry.getFieldOptional("booktitle"));
+ assertEquals(Optional.of("Inproceedings book title"), testEntry.getField("booktitle"));
BibEntry expectedEntry5 = new BibEntry();
expectedEntry5.setType("proceedings");
@@ -148,7 +148,7 @@ public class MedlinePlainImporterTest {
throws IOException, URISyntaxException {
Path file = Paths.get(MedlinePlainImporter.class.getResource(medlineFile).toURI());
try (InputStream nis = MedlinePlainImporter.class.getResourceAsStream(bibtexFile)) {
- List<BibEntry> entries = importer.importDatabase(file, Charset.defaultCharset()).getDatabase().getEntries();
+ List<BibEntry> entries = importer.importDatabase(file, StandardCharsets.UTF_8).getDatabase().getEntries();
Assert.assertNotNull(entries);
assertEquals(1, entries.size());
BibEntryAssert.assertEquals(nis, entries.get(0));
@@ -188,7 +188,7 @@ public class MedlinePlainImporterTest {
@Test
public void testWithNbibFile() throws IOException, URISyntaxException {
Path file = Paths.get(MedlinePlainImporter.class.getResource("NbibImporterTest.nbib").toURI());
- List<BibEntry> entries = importer.importDatabase(file, Charset.defaultCharset()).getDatabase().getEntries();
+ List<BibEntry> entries = importer.importDatabase(file, StandardCharsets.UTF_8).getDatabase().getEntries();
BibEntryAssert.assertEquals(MedlinePlainImporter.class, "NbibImporterTest.bib", entries);
}
@@ -232,7 +232,7 @@ public class MedlinePlainImporterTest {
@Test
public void testGetFormatName() {
- assertEquals("MedlinePlain", importer.getFormatName());
+ assertEquals("MedlinePlain", importer.getName());
}
@Test
diff --git a/src/test/java/net/sf/jabref/logic/importer/fileformat/ModsImporterTestFiles.java b/src/test/java/net/sf/jabref/logic/importer/fileformat/ModsImporterTestFiles.java
new file mode 100644
index 0000000..8adb95e
--- /dev/null
+++ b/src/test/java/net/sf/jabref/logic/importer/fileformat/ModsImporterTestFiles.java
@@ -0,0 +1,63 @@
+package net.sf.jabref.logic.importer.fileformat;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import net.sf.jabref.logic.bibtex.BibEntryAssert;
+import net.sf.jabref.model.entry.BibEntry;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+ at RunWith(Parameterized.class)
+public class ModsImporterTestFiles {
+
+ @Parameter
+ public String fileName;
+ public Path resourceDir;
+
+ private ModsImporter testImporter;
+
+
+ @Before
+ public void setUp() throws Exception {
+ resourceDir = Paths.get(ModsImporterTestFiles.class.getResource("").toURI());
+ testImporter = new ModsImporter();
+ }
+
+ @Parameters(name = "{0}")
+ public static Collection<String> fileNames() throws IOException, URISyntaxException {
+ try (Stream<Path> stream = Files.list(Paths.get(ModsImporterTestFiles.class.getResource("").toURI()))) {
+ return stream.map(n -> n.getFileName().toString()).filter(n -> n.endsWith(".xml"))
+ .filter(n -> n.startsWith("MODS")).collect(Collectors.toList());
+ }
+ }
+
+ @Test
+ public void testIsRecognizedFormat() throws IOException {
+ Assert.assertTrue(testImporter.isRecognizedFormat(resourceDir.resolve(fileName), StandardCharsets.UTF_8));
+ }
+
+ @Test
+ public void testImportEntries() throws Exception {
+ String bibFileName = fileName.replace(".xml", ".bib");
+ Path xmlFile = resourceDir.resolve(fileName);
+
+ List<BibEntry> result = testImporter.importDatabase(xmlFile, StandardCharsets.UTF_8).getDatabase().getEntries();
+ BibEntryAssert.assertEquals(ModsImporter.class, bibFileName, result);
+
+ }
+}
diff --git a/src/test/java/net/sf/jabref/logic/importer/fileformat/MsBibImporterTest.java b/src/test/java/net/sf/jabref/logic/importer/fileformat/MsBibImporterTest.java
index 1093b0a..f81ae50 100644
--- a/src/test/java/net/sf/jabref/logic/importer/fileformat/MsBibImporterTest.java
+++ b/src/test/java/net/sf/jabref/logic/importer/fileformat/MsBibImporterTest.java
@@ -61,7 +61,7 @@ public class MsBibImporterTest {
@Test
public final void testGetFormatName() {
MsBibImporter testImporter = new MsBibImporter();
- assertEquals("MSBib", testImporter.getFormatName());
+ assertEquals("MSBib", testImporter.getName());
}
@Test
diff --git a/src/test/java/net/sf/jabref/logic/importer/fileformat/OvidImporterTest.java b/src/test/java/net/sf/jabref/logic/importer/fileformat/OvidImporterTest.java
index 6dce2e6..336533e 100644
--- a/src/test/java/net/sf/jabref/logic/importer/fileformat/OvidImporterTest.java
+++ b/src/test/java/net/sf/jabref/logic/importer/fileformat/OvidImporterTest.java
@@ -3,7 +3,7 @@ package net.sf.jabref.logic.importer.fileformat;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
-import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
@@ -31,7 +31,7 @@ public class OvidImporterTest {
@Test
public void testGetFormatName() {
- Assert.assertEquals("Ovid", importer.getFormatName());
+ Assert.assertEquals("Ovid", importer.getName());
}
@Test
@@ -57,7 +57,7 @@ public class OvidImporterTest {
for (String str : list) {
Path file = Paths.get(OvidImporter.class.getResource(str).toURI());
- Assert.assertTrue(importer.isRecognizedFormat(file, Charset.defaultCharset()));
+ Assert.assertTrue(importer.isRecognizedFormat(file, StandardCharsets.UTF_8));
}
}
@@ -68,74 +68,74 @@ public class OvidImporterTest {
for (String str : list) {
Path file = Paths.get(OvidImporter.class.getResource(str).toURI());
- Assert.assertFalse(importer.isRecognizedFormat(file, Charset.defaultCharset()));
+ Assert.assertFalse(importer.isRecognizedFormat(file, StandardCharsets.UTF_8));
}
}
@Test
public void testImportEmpty() throws IOException, URISyntaxException {
Path file = Paths.get(OvidImporter.class.getResource("Empty.txt").toURI());
- List<BibEntry> entries = importer.importDatabase(file, Charset.defaultCharset()).getDatabase().getEntries();
+ List<BibEntry> entries = importer.importDatabase(file, StandardCharsets.UTF_8).getDatabase().getEntries();
Assert.assertEquals(Collections.emptyList(), entries);
}
@Test
public void testImportEntries1() throws IOException, URISyntaxException {
Path file = Paths.get(OvidImporter.class.getResource("OvidImporterTest1.txt").toURI());
- List<BibEntry> entries = importer.importDatabase(file, Charset.defaultCharset()).getDatabase().getEntries();
+ List<BibEntry> entries = importer.importDatabase(file, StandardCharsets.UTF_8).getDatabase().getEntries();
Assert.assertEquals(5, entries.size());
BibEntry entry = entries.get(0);
Assert.assertEquals("misc", entry.getType());
- Assert.assertEquals(Optional.of("Mustermann and Musterfrau"), entry.getFieldOptional("author"));
- Assert.assertEquals(Optional.of("Short abstract"), entry.getFieldOptional("abstract"));
- Assert.assertEquals(Optional.of("Musterbuch"), entry.getFieldOptional("title"));
- Assert.assertEquals(Optional.of("Einleitung"), entry.getFieldOptional("chaptertitle"));
+ Assert.assertEquals(Optional.of("Mustermann and Musterfrau"), entry.getField("author"));
+ Assert.assertEquals(Optional.of("Short abstract"), entry.getField("abstract"));
+ Assert.assertEquals(Optional.of("Musterbuch"), entry.getField("title"));
+ Assert.assertEquals(Optional.of("Einleitung"), entry.getField("chaptertitle"));
entry = entries.get(1);
Assert.assertEquals("inproceedings", entry.getType());
- Assert.assertEquals(Optional.of("Max"), entry.getFieldOptional("editor"));
- Assert.assertEquals(Optional.of("Max the Editor"), entry.getFieldOptional("title"));
- Assert.assertEquals(Optional.of("Very Long Title"), entry.getFieldOptional("journal"));
- Assert.assertEquals(Optional.of("28"), entry.getFieldOptional("volume"));
- Assert.assertEquals(Optional.of("2"), entry.getFieldOptional("issue"));
- Assert.assertEquals(Optional.of("2015"), entry.getFieldOptional("year"));
- Assert.assertEquals(Optional.of("103--106"), entry.getFieldOptional("pages"));
+ Assert.assertEquals(Optional.of("Max"), entry.getField("editor"));
+ Assert.assertEquals(Optional.of("Max the Editor"), entry.getField("title"));
+ Assert.assertEquals(Optional.of("Very Long Title"), entry.getField("journal"));
+ Assert.assertEquals(Optional.of("28"), entry.getField("volume"));
+ Assert.assertEquals(Optional.of("2"), entry.getField("issue"));
+ Assert.assertEquals(Optional.of("2015"), entry.getField("year"));
+ Assert.assertEquals(Optional.of("103--106"), entry.getField("pages"));
entry = entries.get(2);
Assert.assertEquals("incollection", entry.getType());
- Assert.assertEquals(Optional.of("Max"), entry.getFieldOptional("author"));
- Assert.assertEquals(Optional.of("Test"), entry.getFieldOptional("title"));
- Assert.assertEquals(Optional.of("Very Long Title"), entry.getFieldOptional("journal"));
- Assert.assertEquals(Optional.of("28"), entry.getFieldOptional("volume"));
- Assert.assertEquals(Optional.of("2"), entry.getFieldOptional("issue"));
- Assert.assertEquals(Optional.of("April"), entry.getFieldOptional("month"));
- Assert.assertEquals(Optional.of("2015"), entry.getFieldOptional("year"));
- Assert.assertEquals(Optional.of("103--106"), entry.getFieldOptional("pages"));
+ Assert.assertEquals(Optional.of("Max"), entry.getField("author"));
+ Assert.assertEquals(Optional.of("Test"), entry.getField("title"));
+ Assert.assertEquals(Optional.of("Very Long Title"), entry.getField("journal"));
+ Assert.assertEquals(Optional.of("28"), entry.getField("volume"));
+ Assert.assertEquals(Optional.of("2"), entry.getField("issue"));
+ Assert.assertEquals(Optional.of("April"), entry.getField("month"));
+ Assert.assertEquals(Optional.of("2015"), entry.getField("year"));
+ Assert.assertEquals(Optional.of("103--106"), entry.getField("pages"));
entry = entries.get(3);
Assert.assertEquals("book", entry.getType());
- Assert.assertEquals(Optional.of("Max"), entry.getFieldOptional("author"));
- Assert.assertEquals(Optional.of("2015"), entry.getFieldOptional("year"));
- Assert.assertEquals(Optional.of("Editor"), entry.getFieldOptional("editor"));
- Assert.assertEquals(Optional.of("Very Long Title"), entry.getFieldOptional("booktitle"));
- Assert.assertEquals(Optional.of("103--106"), entry.getFieldOptional("pages"));
- Assert.assertEquals(Optional.of("Address"), entry.getFieldOptional("address"));
- Assert.assertEquals(Optional.of("Publisher"), entry.getFieldOptional("publisher"));
+ Assert.assertEquals(Optional.of("Max"), entry.getField("author"));
+ Assert.assertEquals(Optional.of("2015"), entry.getField("year"));
+ Assert.assertEquals(Optional.of("Editor"), entry.getField("editor"));
+ Assert.assertEquals(Optional.of("Very Long Title"), entry.getField("booktitle"));
+ Assert.assertEquals(Optional.of("103--106"), entry.getField("pages"));
+ Assert.assertEquals(Optional.of("Address"), entry.getField("address"));
+ Assert.assertEquals(Optional.of("Publisher"), entry.getField("publisher"));
entry = entries.get(4);
Assert.assertEquals("article", entry.getType());
- Assert.assertEquals(Optional.of("2014"), entry.getFieldOptional("year"));
- Assert.assertEquals(Optional.of("58"), entry.getFieldOptional("pages"));
- Assert.assertEquals(Optional.of("Test"), entry.getFieldOptional("address"));
- Assert.assertEquals(Optional.empty(), entry.getFieldOptional("title"));
- Assert.assertEquals(Optional.of("TestPublisher"), entry.getFieldOptional("publisher"));
+ Assert.assertEquals(Optional.of("2014"), entry.getField("year"));
+ Assert.assertEquals(Optional.of("58"), entry.getField("pages"));
+ Assert.assertEquals(Optional.of("Test"), entry.getField("address"));
+ Assert.assertEquals(Optional.empty(), entry.getField("title"));
+ Assert.assertEquals(Optional.of("TestPublisher"), entry.getField("publisher"));
}
@Test
public void testImportEntries2() throws IOException, URISyntaxException {
Path file = Paths.get(OvidImporter.class.getResource("OvidImporterTest2.txt").toURI());
- List<BibEntry> entries = importer.importDatabase(file, Charset.defaultCharset()).getDatabase().getEntries();
+ List<BibEntry> entries = importer.importDatabase(file, StandardCharsets.UTF_8).getDatabase().getEntries();
Assert.assertEquals(Collections.emptyList(), entries);
}
@@ -145,7 +145,8 @@ public class OvidImporterTest {
for (int n = 3; n <= 7; n++) {
Path file = Paths.get(OvidImporter.class.getResource("OvidImporterTest" + n + ".txt").toURI());
try (InputStream nis = OvidImporter.class.getResourceAsStream("OvidImporterTestBib" + n + ".bib")) {
- List<BibEntry> entries = importer.importDatabase(file, Charset.defaultCharset()).getDatabase().getEntries();
+ List<BibEntry> entries = importer.importDatabase(file, StandardCharsets.UTF_8).getDatabase()
+ .getEntries();
Assert.assertNotNull(entries);
Assert.assertEquals(1, entries.size());
BibEntryAssert.assertEquals(nis, entries.get(0));
diff --git a/src/test/java/net/sf/jabref/logic/importer/fileformat/PdfContentImporterTest.java b/src/test/java/net/sf/jabref/logic/importer/fileformat/PdfContentImporterTest.java
index 1d67561..c5e8979 100644
--- a/src/test/java/net/sf/jabref/logic/importer/fileformat/PdfContentImporterTest.java
+++ b/src/test/java/net/sf/jabref/logic/importer/fileformat/PdfContentImporterTest.java
@@ -1,13 +1,12 @@
package net.sf.jabref.logic.importer.fileformat;
import java.net.URISyntaxException;
-import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.List;
-import net.sf.jabref.logic.importer.ImportFormatPreferences;
import net.sf.jabref.logic.util.FileExtensions;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.preferences.JabRefPreferences;
@@ -24,7 +23,7 @@ public class PdfContentImporterTest {
@Before
public void setUp() {
- importer = new PdfContentImporter(ImportFormatPreferences.fromPreferences(JabRefPreferences.getInstance()));
+ importer = new PdfContentImporter(JabRefPreferences.getInstance().getImportFormatPreferences());
}
@Test
@@ -34,13 +33,15 @@ public class PdfContentImporterTest {
@Test
public void testGetDescription() {
- assertEquals("PdfContentImporter parses data of the first page of the PDF and creates a BibTeX entry. Currently, Springer and IEEE formats are supported.", importer.getDescription());
+ assertEquals(
+ "PdfContentImporter parses data of the first page of the PDF and creates a BibTeX entry. Currently, Springer and IEEE formats are supported.",
+ importer.getDescription());
}
@Test
public void doesNotHandleEncryptedPdfs() throws URISyntaxException {
Path file = Paths.get(PdfContentImporter.class.getResource("/pdfs/encrypted.pdf").toURI());
- List<BibEntry> result = importer.importDatabase(file, Charset.defaultCharset()).getDatabase().getEntries();
+ List<BibEntry> result = importer.importDatabase(file, StandardCharsets.UTF_8).getDatabase().getEntries();
assertEquals(Collections.emptyList(), result);
}
diff --git a/src/test/java/net/sf/jabref/logic/importer/fileformat/PdfContentImporterTestFiles.java b/src/test/java/net/sf/jabref/logic/importer/fileformat/PdfContentImporterTestFiles.java
index 730753d..ab695d2 100644
--- a/src/test/java/net/sf/jabref/logic/importer/fileformat/PdfContentImporterTestFiles.java
+++ b/src/test/java/net/sf/jabref/logic/importer/fileformat/PdfContentImporterTestFiles.java
@@ -10,7 +10,6 @@ import java.util.Collection;
import java.util.List;
import net.sf.jabref.logic.bibtex.BibEntryAssert;
-import net.sf.jabref.logic.importer.ImportFormatPreferences;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.preferences.JabRefPreferences;
@@ -45,7 +44,7 @@ public class PdfContentImporterTestFiles {
String pdfFileName = fileName + ".pdf";
String bibFileName = fileName + ".bib";
PdfContentImporter importer = new PdfContentImporter(
- ImportFormatPreferences.fromPreferences(JabRefPreferences.getInstance()));
+ JabRefPreferences.getInstance().getImportFormatPreferences());
Path pdfFile = Paths.get(PdfContentImporter.class.getResource(pdfFileName).toURI());
List<BibEntry> result = importer.importDatabase(pdfFile, StandardCharsets.UTF_8).getDatabase().getEntries();
BibEntryAssert.assertEquals(PdfContentImporterTest.class, bibFileName, result);
diff --git a/src/test/java/net/sf/jabref/logic/importer/fileformat/PdfXmpImporterTest.java b/src/test/java/net/sf/jabref/logic/importer/fileformat/PdfXmpImporterTest.java
index 56b6b70..dcb4a41 100644
--- a/src/test/java/net/sf/jabref/logic/importer/fileformat/PdfXmpImporterTest.java
+++ b/src/test/java/net/sf/jabref/logic/importer/fileformat/PdfXmpImporterTest.java
@@ -2,7 +2,7 @@ package net.sf.jabref.logic.importer.fileformat;
import java.io.IOException;
import java.net.URISyntaxException;
-import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
@@ -11,7 +11,6 @@ import java.util.Optional;
import net.sf.jabref.logic.importer.ParserResult;
import net.sf.jabref.logic.util.FileExtensions;
-import net.sf.jabref.logic.xmp.XMPPreferences;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.preferences.JabRefPreferences;
@@ -30,12 +29,12 @@ public class PdfXmpImporterTest {
@Before
public void setUp() {
- importer = new PdfXmpImporter(XMPPreferences.fromPreferences(JabRefPreferences.getInstance()));
+ importer = new PdfXmpImporter(JabRefPreferences.getInstance().getXMPPreferences());
}
@Test
public void testGetFormatName() {
- assertEquals("XMP-annotated PDF", importer.getFormatName());
+ assertEquals("XMP-annotated PDF", importer.getName());
}
@Test
@@ -45,34 +44,34 @@ public class PdfXmpImporterTest {
@Test
public void testGetDescription() {
- assertEquals("Wraps the XMPUtility function to be used as an ImportFormat.", importer.getDescription());
+ assertEquals("Wraps the XMPUtility function to be used as an Importer.", importer.getDescription());
}
@Test
public void importEncryptedFileReturnsError() throws URISyntaxException {
Path file = Paths.get(PdfXmpImporterTest.class.getResource("/pdfs/encrypted.pdf").toURI());
- ParserResult result = importer.importDatabase(file, Charset.defaultCharset());
+ ParserResult result = importer.importDatabase(file, StandardCharsets.UTF_8);
Assert.assertTrue(result.hasWarnings());
}
@Test
public void testImportEntries() throws URISyntaxException {
Path file = Paths.get(PdfXmpImporterTest.class.getResource("annotated.pdf").toURI());
- List<BibEntry> bibEntries = importer.importDatabase(file, Charset.defaultCharset()).getDatabase().getEntries();
+ List<BibEntry> bibEntries = importer.importDatabase(file, StandardCharsets.UTF_8).getDatabase().getEntries();
assertEquals(1, bibEntries.size());
BibEntry be0 = bibEntries.get(0);
- assertEquals(Optional.of("how to annotate a pdf"), be0.getFieldOptional("abstract"));
- assertEquals(Optional.of("Chris"), be0.getFieldOptional("author"));
- assertEquals(Optional.of("pdf, annotation"), be0.getFieldOptional("keywords"));
- assertEquals(Optional.of("The best Pdf ever"), be0.getFieldOptional("title"));
+ assertEquals(Optional.of("how to annotate a pdf"), be0.getField("abstract"));
+ assertEquals(Optional.of("Chris"), be0.getField("author"));
+ assertEquals(Optional.of("pdf, annotation"), be0.getField("keywords"));
+ assertEquals(Optional.of("The best Pdf ever"), be0.getField("title"));
}
@Test
public void testIsRecognizedFormat() throws IOException, URISyntaxException {
Path file = Paths.get(PdfXmpImporterTest.class.getResource("annotated.pdf").toURI());
- assertTrue(importer.isRecognizedFormat(file, Charset.defaultCharset()));
+ assertTrue(importer.isRecognizedFormat(file, StandardCharsets.UTF_8));
}
@Test
@@ -82,7 +81,7 @@ public class PdfXmpImporterTest {
for (String str : list) {
Path file = Paths.get(PdfXmpImporterTest.class.getResource(str).toURI());
- assertFalse(importer.isRecognizedFormat(file, Charset.defaultCharset()));
+ assertFalse(importer.isRecognizedFormat(file, StandardCharsets.UTF_8));
}
}
diff --git a/src/test/java/net/sf/jabref/logic/importer/fileformat/RISImporterTest.java b/src/test/java/net/sf/jabref/logic/importer/fileformat/RISImporterTest.java
index 3807c66..675acaa 100644
--- a/src/test/java/net/sf/jabref/logic/importer/fileformat/RISImporterTest.java
+++ b/src/test/java/net/sf/jabref/logic/importer/fileformat/RISImporterTest.java
@@ -2,7 +2,7 @@ package net.sf.jabref.logic.importer.fileformat;
import java.io.IOException;
import java.net.URISyntaxException;
-import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -24,7 +24,7 @@ public class RISImporterTest {
@Test
public void testGetFormatName() {
- Assert.assertEquals(importer.getFormatName(), "RIS");
+ Assert.assertEquals(importer.getName(), "RIS");
}
@Test
@@ -45,7 +45,7 @@ public class RISImporterTest {
@Test
public void testIfNotRecognizedFormat() throws IOException, URISyntaxException {
Path file = Paths.get(RISImporterTest.class.getResource("RisImporterCorrupted.ris").toURI());
- Assert.assertFalse(importer.isRecognizedFormat(file, Charset.defaultCharset()));
+ Assert.assertFalse(importer.isRecognizedFormat(file, StandardCharsets.UTF_8));
}
}
diff --git a/src/test/java/net/sf/jabref/logic/importer/fileformat/RISImporterTestFiles.java b/src/test/java/net/sf/jabref/logic/importer/fileformat/RISImporterTestFiles.java
index dd9c161..af84c5e 100644
--- a/src/test/java/net/sf/jabref/logic/importer/fileformat/RISImporterTestFiles.java
+++ b/src/test/java/net/sf/jabref/logic/importer/fileformat/RISImporterTestFiles.java
@@ -2,7 +2,7 @@ package net.sf.jabref.logic.importer.fileformat;
import java.io.IOException;
import java.net.URISyntaxException;
-import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
@@ -30,6 +30,7 @@ public class RISImporterTestFiles {
private Path risFile;
+
@Before
public void setUp() throws URISyntaxException {
risImporter = new RisImporter();
@@ -39,17 +40,19 @@ public class RISImporterTestFiles {
@Parameters(name = "{0}")
public static Collection<String> fileNames() {
return Arrays.asList("RisImporterTest1", "RisImporterTest3", "RisImporterTest4a", "RisImporterTest4b",
- "RisImporterTest4c", "RisImporterTest5a", "RisImporterTest5b", "RisImporterTest6");
+ "RisImporterTest4c", "RisImporterTest5a", "RisImporterTest5b", "RisImporterTest6",
+ "RisImporterTestDoiAndJournalTitle", "RisImporterTestScopus");
}
@Test
public void testIsRecognizedFormat() throws IOException {
- Assert.assertTrue(risImporter.isRecognizedFormat(risFile, Charset.defaultCharset()));
+ Assert.assertTrue(risImporter.isRecognizedFormat(risFile, StandardCharsets.UTF_8));
}
@Test
public void testImportEntries() throws IOException {
- List<BibEntry> risEntries = risImporter.importDatabase(risFile, Charset.defaultCharset()).getDatabase().getEntries();
+ List<BibEntry> risEntries = risImporter.importDatabase(risFile, StandardCharsets.UTF_8).getDatabase()
+ .getEntries();
BibEntryAssert.assertEquals(RISImporterTest.class, fileName + ".bib", risEntries);
}
}
diff --git a/src/test/java/net/sf/jabref/logic/importer/fileformat/RepecNepImporterTest.java b/src/test/java/net/sf/jabref/logic/importer/fileformat/RepecNepImporterTest.java
index 655f55a..1a0b37b 100644
--- a/src/test/java/net/sf/jabref/logic/importer/fileformat/RepecNepImporterTest.java
+++ b/src/test/java/net/sf/jabref/logic/importer/fileformat/RepecNepImporterTest.java
@@ -3,14 +3,13 @@ package net.sf.jabref.logic.importer.fileformat;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
-import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import net.sf.jabref.logic.bibtex.BibEntryAssert;
-import net.sf.jabref.logic.importer.ImportFormatPreferences;
import net.sf.jabref.logic.util.FileExtensions;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.preferences.JabRefPreferences;
@@ -26,7 +25,7 @@ public class RepecNepImporterTest {
@Before
public void setUp() {
- testImporter = new RepecNepImporter(ImportFormatPreferences.fromPreferences(JabRefPreferences.getInstance()));
+ testImporter = new RepecNepImporter(JabRefPreferences.getInstance().getImportFormatPreferences());
}
@Test
@@ -35,7 +34,7 @@ public class RepecNepImporterTest {
"RepecNepImporterTest3.txt");
for (String s : accepted) {
Path file = Paths.get(RepecNepImporter.class.getResource(s).toURI());
- Assert.assertTrue(testImporter.isRecognizedFormat(file, Charset.defaultCharset()));
+ Assert.assertTrue(testImporter.isRecognizedFormat(file, StandardCharsets.UTF_8));
}
}
@@ -45,7 +44,7 @@ public class RepecNepImporterTest {
"CopacImporterTest2.txt", "IEEEImport1.txt");
for (String s : notAccepted) {
Path file = Paths.get(RepecNepImporter.class.getResource(s).toURI());
- Assert.assertFalse(testImporter.isRecognizedFormat(file, Charset.defaultCharset()));
+ Assert.assertFalse(testImporter.isRecognizedFormat(file, StandardCharsets.UTF_8));
}
}
@@ -53,7 +52,8 @@ public class RepecNepImporterTest {
public final void testImportEntries1() throws IOException, URISyntaxException {
Path file = Paths.get(RepecNepImporter.class.getResource("RepecNepImporterTest1.txt").toURI());
try (InputStream bibIn = RepecNepImporter.class.getResourceAsStream("RepecNepImporterTest1.bib")) {
- List<BibEntry> entries = testImporter.importDatabase(file, Charset.defaultCharset()).getDatabase().getEntries();
+ List<BibEntry> entries = testImporter.importDatabase(file, StandardCharsets.UTF_8).getDatabase()
+ .getEntries();
Assert.assertEquals(1, entries.size());
BibEntryAssert.assertEquals(bibIn, entries.get(0));
}
@@ -63,7 +63,8 @@ public class RepecNepImporterTest {
public final void testImportEntries2() throws IOException, URISyntaxException {
Path file = Paths.get(RepecNepImporter.class.getResource("RepecNepImporterTest2.txt").toURI());
try (InputStream bibIn = RepecNepImporter.class.getResourceAsStream("RepecNepImporterTest2.bib")) {
- List<BibEntry> entries = testImporter.importDatabase(file, Charset.defaultCharset()).getDatabase().getEntries();
+ List<BibEntry> entries = testImporter.importDatabase(file, StandardCharsets.UTF_8).getDatabase()
+ .getEntries();
Assert.assertEquals(1, entries.size());
BibEntryAssert.assertEquals(bibIn, entries.get(0));
}
@@ -73,7 +74,8 @@ public class RepecNepImporterTest {
public final void testImportEntries3() throws IOException, URISyntaxException {
Path file = Paths.get(RepecNepImporter.class.getResource("RepecNepImporterTest3.txt").toURI());
try (InputStream bibIn = RepecNepImporter.class.getResourceAsStream("RepecNepImporterTest3.bib")) {
- List<BibEntry> entries = testImporter.importDatabase(file, Charset.defaultCharset()).getDatabase().getEntries();
+ List<BibEntry> entries = testImporter.importDatabase(file, StandardCharsets.UTF_8).getDatabase()
+ .getEntries();
Assert.assertEquals(1, entries.size());
BibEntryAssert.assertEquals(bibIn, entries.get(0));
}
@@ -81,7 +83,7 @@ public class RepecNepImporterTest {
@Test
public final void testGetFormatName() {
- Assert.assertEquals("REPEC New Economic Papers (NEP)", testImporter.getFormatName());
+ Assert.assertEquals("REPEC New Economic Papers (NEP)", testImporter.getName());
}
@@ -97,6 +99,7 @@ public class RepecNepImporterTest {
@Test
public final void testGetDescription() {
- Assert.assertEquals("Imports a New Economics Papers-Message from the REPEC-NEP Service.", testImporter.getDescription());
+ Assert.assertEquals("Imports a New Economics Papers-Message from the REPEC-NEP Service.",
+ testImporter.getDescription());
}
}
diff --git a/src/test/java/net/sf/jabref/logic/importer/fileformat/SilverPlatterImporterTest.java b/src/test/java/net/sf/jabref/logic/importer/fileformat/SilverPlatterImporterTest.java
index 098931a..e89376c 100644
--- a/src/test/java/net/sf/jabref/logic/importer/fileformat/SilverPlatterImporterTest.java
+++ b/src/test/java/net/sf/jabref/logic/importer/fileformat/SilverPlatterImporterTest.java
@@ -1,7 +1,7 @@
package net.sf.jabref.logic.importer.fileformat;
import java.io.InputStream;
-import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
@@ -59,13 +59,14 @@ public class SilverPlatterImporterTest {
@Test
public final void testIsRecognizedFormat() throws Exception {
- Assert.assertTrue(testImporter.isRecognizedFormat(txtFile, Charset.defaultCharset()));
+ Assert.assertTrue(testImporter.isRecognizedFormat(txtFile, StandardCharsets.UTF_8));
}
@Test
public final void testImportEntries() throws Exception {
try (InputStream bibIn = SilverPlatterImporterTest.class.getResourceAsStream(bibName)) {
- List<BibEntry> entries = testImporter.importDatabase(txtFile, Charset.defaultCharset()).getDatabase().getEntries();
+ List<BibEntry> entries = testImporter.importDatabase(txtFile, StandardCharsets.UTF_8).getDatabase()
+ .getEntries();
BibEntryAssert.assertEquals(bibIn, entries);
}
}
diff --git a/src/test/java/net/sf/jabref/logic/importer/fileformat/SilverPlatterImporterTestNotRecognized.java b/src/test/java/net/sf/jabref/logic/importer/fileformat/SilverPlatterImporterTestNotRecognized.java
index 6b2e0ae..9875ad1 100644
--- a/src/test/java/net/sf/jabref/logic/importer/fileformat/SilverPlatterImporterTestNotRecognized.java
+++ b/src/test/java/net/sf/jabref/logic/importer/fileformat/SilverPlatterImporterTestNotRecognized.java
@@ -1,7 +1,7 @@
package net.sf.jabref.logic.importer.fileformat;
import java.net.URL;
-import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
@@ -31,7 +31,7 @@ public class SilverPlatterImporterTestNotRecognized {
URL resource = SilverPlatterImporter.class.getResource(s);
assertNotNull("resource " + s + " must be available", resource);
Path file = Paths.get(resource.toURI());
- Assert.assertFalse(testImporter.isRecognizedFormat(file, Charset.defaultCharset()));
+ Assert.assertFalse(testImporter.isRecognizedFormat(file, StandardCharsets.UTF_8));
}
}
diff --git a/src/test/java/net/sf/jabref/logic/importer/util/JSONEntryParserTest.java b/src/test/java/net/sf/jabref/logic/importer/util/JSONEntryParserTest.java
index 796d54f..0719748 100644
--- a/src/test/java/net/sf/jabref/logic/importer/util/JSONEntryParserTest.java
+++ b/src/test/java/net/sf/jabref/logic/importer/util/JSONEntryParserTest.java
@@ -25,17 +25,17 @@ public class JSONEntryParserTest {
+ "\"id\": \"1563-5171\"},{\"type\": \"doi\",\"id\": \"10.1155/2014/217495\""
+ "}],\"created_date\":\"2014-05-09T19:38:31Z\"}\"";
JSONObject jsonObject = new JSONObject(jsonString);
- BibEntry bibEntry = jc.parseBibJSONtoBibtex(jsonObject, ", ");
+ BibEntry bibEntry = jc.parseBibJSONtoBibtex(jsonObject, ',');
Assert.assertEquals("article", bibEntry.getType());
- Assert.assertEquals(Optional.of("VLSI Design"), bibEntry.getFieldOptional("journal"));
- Assert.assertEquals(Optional.of("10.1155/2014/217495"), bibEntry.getFieldOptional("doi"));
- Assert.assertEquals(Optional.of("Syed Asad Alam and Oscar Gustafsson"), bibEntry.getFieldOptional("author"));
+ Assert.assertEquals(Optional.of("VLSI Design"), bibEntry.getField("journal"));
+ Assert.assertEquals(Optional.of("10.1155/2014/217495"), bibEntry.getField("doi"));
+ Assert.assertEquals(Optional.of("Syed Asad Alam and Oscar Gustafsson"), bibEntry.getField("author"));
Assert.assertEquals(
Optional.of(
"Design of Finite Word Length Linear-Phase FIR Filters in the Logarithmic Number System Domain"),
- bibEntry.getFieldOptional("title"));
- Assert.assertEquals(Optional.of("2014"), bibEntry.getFieldOptional("year"));
+ bibEntry.getField("title"));
+ Assert.assertEquals(Optional.of("2014"), bibEntry.getField("year"));
}
@Test
@@ -52,13 +52,13 @@ public class JSONEntryParserTest {
JSONObject jsonObject = new JSONObject(jsonString);
BibEntry bibEntry = JSONEntryParser.parseSpringerJSONtoBibtex(jsonObject);
- Assert.assertEquals(Optional.of("1992"), bibEntry.getFieldOptional("year"));
- Assert.assertEquals(Optional.of("5"), bibEntry.getFieldOptional("number"));
- Assert.assertEquals(Optional.of("#sep#"), bibEntry.getFieldOptional("month"));
- Assert.assertEquals(Optional.of("10.1007/BF01201962"), bibEntry.getFieldOptional("doi"));
- Assert.assertEquals(Optional.of("8"), bibEntry.getFieldOptional("volume"));
- Assert.assertEquals(Optional.of("Springer"), bibEntry.getFieldOptional("publisher"));
- Assert.assertEquals(Optional.of("1992-09-01"), bibEntry.getFieldOptional("date"));
+ Assert.assertEquals(Optional.of("1992"), bibEntry.getField("year"));
+ Assert.assertEquals(Optional.of("5"), bibEntry.getField("number"));
+ Assert.assertEquals(Optional.of("#sep#"), bibEntry.getField("month"));
+ Assert.assertEquals(Optional.of("10.1007/BF01201962"), bibEntry.getField("doi"));
+ Assert.assertEquals(Optional.of("8"), bibEntry.getField("volume"));
+ Assert.assertEquals(Optional.of("Springer"), bibEntry.getField("publisher"));
+ Assert.assertEquals(Optional.of("1992-09-01"), bibEntry.getField("date"));
}
}
diff --git a/src/test/java/net/sf/jabref/logic/integrity/EntryLinkCheckerTest.java b/src/test/java/net/sf/jabref/logic/integrity/EntryLinkCheckerTest.java
new file mode 100644
index 0000000..e19a6a4
--- /dev/null
+++ b/src/test/java/net/sf/jabref/logic/integrity/EntryLinkCheckerTest.java
@@ -0,0 +1,103 @@
+package net.sf.jabref.logic.integrity;
+
+import java.util.Collections;
+import java.util.List;
+
+import net.sf.jabref.model.database.BibDatabase;
+import net.sf.jabref.model.entry.BibEntry;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.fail;
+
+
+public class EntryLinkCheckerTest {
+
+ private BibDatabase database;
+ private EntryLinkChecker checker;
+ private BibEntry entry;
+
+
+ @Before
+ public void setUp() {
+ database = new BibDatabase();
+ checker = new EntryLinkChecker(database);
+ entry = new BibEntry();
+ database.insertEntry(entry);
+ }
+
+ @SuppressWarnings("unused")
+ @Test(expected = NullPointerException.class)
+ public void testEntryLinkChecker() {
+ new EntryLinkChecker(null);
+ fail();
+ }
+
+ @Test
+ public void testCheckNoFields() {
+ assertEquals(Collections.emptyList(), checker.check(entry));
+ }
+
+ @Test
+ public void testCheckNonRelatedFieldsOnly() {
+ entry.setField("year", "2016");
+ assertEquals(Collections.emptyList(), checker.check(entry));
+ }
+
+ @Test
+ public void testCheckNonExistingCrossref() {
+ entry.setField("crossref", "banana");
+
+ List<IntegrityMessage> message = checker.check(entry);
+ assertFalse(message.toString(), message.isEmpty());
+ }
+
+ @Test
+ public void testCheckExistingCrossref() {
+ entry.setField("crossref", "banana");
+
+ BibEntry entry2 = new BibEntry();
+ entry2.setCiteKey("banana");
+ database.insertEntry(entry2);
+
+ List<IntegrityMessage> message = checker.check(entry);
+ assertEquals(Collections.emptyList(), message);
+ }
+
+ @Test
+ public void testCheckExistingRelated() {
+ entry.setField("related", "banana,pineapple");
+
+ BibEntry entry2 = new BibEntry();
+ entry2.setCiteKey("banana");
+ database.insertEntry(entry2);
+
+ BibEntry entry3 = new BibEntry();
+ entry3.setCiteKey("pineapple");
+ database.insertEntry(entry3);
+
+ List<IntegrityMessage> message = checker.check(entry);
+ assertEquals(Collections.emptyList(), message);
+ }
+
+ @Test
+ public void testCheckNonExistingRelated() {
+ BibEntry entry1 = new BibEntry();
+ entry1.setField("related", "banana,pineapple,strawberry");
+ database.insertEntry(entry1);
+
+ BibEntry entry2 = new BibEntry();
+ entry2.setCiteKey("banana");
+ database.insertEntry(entry2);
+
+ BibEntry entry3 = new BibEntry();
+ entry3.setCiteKey("pineapple");
+ database.insertEntry(entry3);
+
+ List<IntegrityMessage> message = checker.check(entry1);
+ assertFalse(message.toString(), message.isEmpty());
+ }
+}
diff --git a/src/test/java/net/sf/jabref/logic/integrity/IntegrityCheckTest.java b/src/test/java/net/sf/jabref/logic/integrity/IntegrityCheckTest.java
index 354d2a6..3fd4c3e 100644
--- a/src/test/java/net/sf/jabref/logic/integrity/IntegrityCheckTest.java
+++ b/src/test/java/net/sf/jabref/logic/integrity/IntegrityCheckTest.java
@@ -7,17 +7,17 @@ import java.util.Collections;
import java.util.List;
import java.util.Optional;
-import net.sf.jabref.BibDatabaseContext;
-import net.sf.jabref.Defaults;
-import net.sf.jabref.Globals;
-import net.sf.jabref.MetaData;
+import net.sf.jabref.logic.bibtexkeypattern.BibtexKeyPatternPreferences;
+import net.sf.jabref.model.Defaults;
+import net.sf.jabref.model.bibtexkeypattern.GlobalBibtexKeyPattern;
import net.sf.jabref.model.database.BibDatabase;
+import net.sf.jabref.model.database.BibDatabaseContext;
import net.sf.jabref.model.database.BibDatabaseMode;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.model.entry.InternalBibtexFields;
+import net.sf.jabref.model.metadata.MetaData;
import net.sf.jabref.preferences.JabRefPreferences;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
@@ -32,11 +32,6 @@ public class IntegrityCheckTest {
@Rule
public TemporaryFolder testFolder = new TemporaryFolder();
- @Before
- public void setUp() {
- Globals.prefs = JabRefPreferences.getInstance();
- }
-
@Test
public void testUrlChecks() {
assertCorrect(createContext("url", "http://www.google.com"));
@@ -52,9 +47,89 @@ public class IntegrityCheckTest {
public void testYearChecks() {
assertCorrect(createContext("year", "2014"));
assertCorrect(createContext("year", "1986"));
+ assertCorrect(createContext("year", "around 1986"));
+ assertCorrect(createContext("year", "(around 1986)"));
+ assertCorrect(createContext("year", "1986,"));
+ assertCorrect(createContext("year", "1986}%"));
+ assertCorrect(createContext("year", "1986(){},.;!?<>%&$"));
assertWrong(createContext("year", "abc"));
assertWrong(createContext("year", "86"));
assertWrong(createContext("year", "204"));
+ assertWrong(createContext("year", "1986a"));
+ assertWrong(createContext("year", "(1986a)"));
+ assertWrong(createContext("year", "1986a,"));
+ assertWrong(createContext("year", "1986}a%"));
+ assertWrong(createContext("year", "1986a(){},.;!?<>%&$"));
+ }
+
+ @Test
+ public void testEditionChecks() {
+ assertCorrect(withMode(createContext("edition", "Second"), BibDatabaseMode.BIBTEX));
+ assertCorrect(withMode(createContext("edition", "Third"), BibDatabaseMode.BIBTEX));
+ assertWrong(withMode(createContext("edition", "second"), BibDatabaseMode.BIBTEX));
+ assertWrong(withMode(createContext("edition", "2"), BibDatabaseMode.BIBTEX));
+ assertWrong(withMode(createContext("edition", "2nd"), BibDatabaseMode.BIBTEX));
+ assertCorrect(withMode(createContext("edition", "2"), BibDatabaseMode.BIBLATEX));
+ assertCorrect(withMode(createContext("edition", "10"), BibDatabaseMode.BIBLATEX));
+ assertCorrect(
+ withMode(createContext("edition", "Third, revised and expanded edition"), BibDatabaseMode.BIBLATEX));
+ assertCorrect(withMode(createContext("edition", "Edition 2000"), BibDatabaseMode.BIBLATEX));
+ assertWrong(withMode(createContext("edition", "2nd"), BibDatabaseMode.BIBLATEX));
+ }
+
+ @Test
+ public void testNoteChecks() {
+ assertCorrect(withMode(createContext("note", "Lorem ipsum"), BibDatabaseMode.BIBTEX));
+ assertCorrect(withMode(createContext("note", "Lorem ipsum? 10"), BibDatabaseMode.BIBTEX));
+ assertWrong(withMode(createContext("note", "lorem ipsum"), BibDatabaseMode.BIBTEX));
+ assertCorrect(withMode(createContext("note", "Lorem ipsum"), BibDatabaseMode.BIBLATEX));
+ assertCorrect(withMode(createContext("note", "lorem ipsum"), BibDatabaseMode.BIBLATEX));
+ }
+
+ @Test
+ public void testHowpublishedChecks() {
+ assertCorrect(withMode(createContext("howpublished", "Lorem ipsum"), BibDatabaseMode.BIBTEX));
+ assertCorrect(withMode(createContext("howpublished", "Lorem ipsum? 10"), BibDatabaseMode.BIBTEX));
+ assertWrong(withMode(createContext("howpublished", "lorem ipsum"), BibDatabaseMode.BIBTEX));
+ assertCorrect(withMode(createContext("howpublished", "Lorem ipsum"), BibDatabaseMode.BIBLATEX));
+ assertCorrect(withMode(createContext("howpublished", "lorem ipsum"), BibDatabaseMode.BIBLATEX));
+ }
+
+ @Test
+ public void testMonthChecks() {
+ assertCorrect(withMode(createContext("month", "#mar#"), BibDatabaseMode.BIBTEX));
+ assertCorrect(withMode(createContext("month", "#dec#"), BibDatabaseMode.BIBTEX));
+ assertWrong(withMode(createContext("month", "#bla#"), BibDatabaseMode.BIBTEX));
+ assertWrong(withMode(createContext("month", "Dec"), BibDatabaseMode.BIBTEX));
+ assertWrong(withMode(createContext("month", "December"), BibDatabaseMode.BIBTEX));
+ assertWrong(withMode(createContext("month", "Lorem"), BibDatabaseMode.BIBTEX));
+ assertWrong(withMode(createContext("month", "10"), BibDatabaseMode.BIBTEX));
+ assertCorrect(withMode(createContext("month", "1"), BibDatabaseMode.BIBLATEX));
+ assertCorrect(withMode(createContext("month", "10"), BibDatabaseMode.BIBLATEX));
+ assertCorrect(withMode(createContext("month", "#jan#"), BibDatabaseMode.BIBLATEX));
+ assertWrong(withMode(createContext("month", "jan"), BibDatabaseMode.BIBLATEX));
+ assertWrong(withMode(createContext("month", "january"), BibDatabaseMode.BIBLATEX));
+ assertWrong(withMode(createContext("month", "January"), BibDatabaseMode.BIBLATEX));
+ assertWrong(withMode(createContext("month", "Lorem"), BibDatabaseMode.BIBLATEX));
+ }
+
+ @Test
+ public void testJournaltitleChecks() {
+ assertCorrect(withMode(createContext("journaltitle", "A journal"), BibDatabaseMode.BIBLATEX));
+ assertWrong(withMode(createContext("journaltitle", "A journal"), BibDatabaseMode.BIBTEX));
+ }
+
+ @Test
+ public void testBibtexkeyChecks() {
+ final BibDatabaseContext correctContext = createContext("bibtexkey", "Knuth2014");
+ correctContext.getDatabase().getEntries().get(0).setField("author","Knuth");
+ correctContext.getDatabase().getEntries().get(0).setField("year","2014");
+ assertCorrect(correctContext);
+
+ final BibDatabaseContext wrongContext = createContext("bibtexkey", "Knuth2014a");
+ wrongContext.getDatabase().getEntries().get(0).setField("author","Knuth");
+ wrongContext.getDatabase().getEntries().get(0).setField("year","2014");
+ assertWrong(wrongContext);
}
@Test
@@ -69,7 +144,7 @@ public class IntegrityCheckTest {
@Test
public void testAuthorNameChecks() {
- for (String field : InternalBibtexFields.BIBLATEX_PERSON_NAME_FIELDS) {
+ for (String field : InternalBibtexFields.getPersonNameFields()) {
assertCorrect(createContext(field, ""));
assertCorrect(createContext(field, "Knuth"));
assertCorrect(createContext(field, " Knuth, Donald E. "));
@@ -189,6 +264,7 @@ public class IntegrityCheckTest {
assertCorrect(createContext("title", "Not a single {HTML} character"));
assertCorrect(createContext("month", "#jan#"));
assertCorrect(createContext("author", "A. Einstein and I. Newton"));
+ assertCorrect(createContext("url", "http://www.thinkmind.org/index.php?view=article&articleid=cloud_computing_2013_1_20_20130"));
assertWrong(createContext("author", "Lenhard, Jörg"));
assertWrong(createContext("author", "Lenhard, Jãrg"));
assertWrong(createContext("journal", "Ärling Ström for – ‱"));
@@ -214,6 +290,14 @@ public class IntegrityCheckTest {
}
@Test
+ public void testDOIChecks() {
+ assertCorrect(createContext("doi", "10.1023/A:1022883727209"));
+ assertCorrect(createContext("doi", "10.17487/rfc1436"));
+ assertCorrect(createContext("doi", "10.1002/(SICI)1097-4571(199205)43:4<284::AID-ASI3>3.0.CO;2-0"));
+ assertWrong(createContext("doi", "asdf"));
+ }
+
+ @Test
public void testASCIIChecks() {
assertCorrect(createContext("title", "Only ascii characters!'@12"));
assertWrong(createContext("month", "Umlauts are nöt ällowed"));
@@ -242,15 +326,32 @@ public class IntegrityCheckTest {
}
private void assertWrong(BibDatabaseContext context) {
- List<IntegrityMessage> messages = new IntegrityCheck(context).checkBibtexDatabase();
+ List<IntegrityMessage> messages = new IntegrityCheck(context,
+ JabRefPreferences.getInstance().getFileDirectoryPreferences(),
+ createBibtexKeyPatternPreferences())
+ .checkBibtexDatabase();
assertFalse(messages.toString(), messages.isEmpty());
}
private void assertCorrect(BibDatabaseContext context) {
- List<IntegrityMessage> messages = new IntegrityCheck(context).checkBibtexDatabase();
+ List<IntegrityMessage> messages = new IntegrityCheck(context,
+ JabRefPreferences.getInstance().getFileDirectoryPreferences(),
+ createBibtexKeyPatternPreferences()).checkBibtexDatabase();
assertEquals(Collections.emptyList(), messages);
}
+ private BibtexKeyPatternPreferences createBibtexKeyPatternPreferences() {
+ final GlobalBibtexKeyPattern keyPattern = GlobalBibtexKeyPattern.fromPattern("[auth][year]");
+ return new BibtexKeyPatternPreferences(
+ "",
+ "",
+ false,
+ false,
+ false,
+ keyPattern,
+ ',');
+ }
+
private BibDatabaseContext withMode(BibDatabaseContext context, BibDatabaseMode mode) {
context.setMode(mode);
return context;
diff --git a/src/test/java/net/sf/jabref/logic/journals/AbbreviationsTest.java b/src/test/java/net/sf/jabref/logic/journals/AbbreviationsTest.java
index 73b609b..9726b46 100644
--- a/src/test/java/net/sf/jabref/logic/journals/AbbreviationsTest.java
+++ b/src/test/java/net/sf/jabref/logic/journals/AbbreviationsTest.java
@@ -1,7 +1,5 @@
package net.sf.jabref.logic.journals;
-import net.sf.jabref.preferences.JabRefPreferences;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -15,7 +13,7 @@ import static org.mockito.Mockito.when;
public class AbbreviationsTest {
@Mock
- private JabRefPreferences prefs;
+ private JournalAbbreviationPreferences prefs;
private JournalAbbreviationLoader abbreviations;
@Before
@@ -25,40 +23,40 @@ public class AbbreviationsTest {
@Test
public void getNextAbbreviationAbbreviatesIEEEJournalTitle() {
- when(prefs.getBoolean(JabRefPreferences.USE_IEEE_ABRV)).thenReturn(true);
+ when(prefs.isUseIEEEAbbreviations()).thenReturn(true);
assertEquals("#IEEE_J_PROC#",
- abbreviations.getRepository(JournalAbbreviationPreferences.fromPreferences(prefs))
+ abbreviations.getRepository(prefs)
.getNextAbbreviation("Proceedings of the IEEE").get());
}
@Test
public void getNextAbbreviationExpandsIEEEAbbreviation() {
- when(prefs.getBoolean(JabRefPreferences.USE_IEEE_ABRV)).thenReturn(true);
+ when(prefs.isUseIEEEAbbreviations()).thenReturn(true);
assertEquals("Proceedings of the IEEE",
- abbreviations.getRepository(JournalAbbreviationPreferences.fromPreferences(prefs))
+ abbreviations.getRepository(prefs)
.getNextAbbreviation("#IEEE_J_PROC#").get());
}
@Test
public void getNextAbbreviationAbbreviatesJournalTitle() {
assertEquals("Proc. IEEE",
- abbreviations.getRepository(JournalAbbreviationPreferences.fromPreferences(prefs))
+ abbreviations.getRepository(prefs)
.getNextAbbreviation("Proceedings of the IEEE").get());
}
@Test
public void getNextAbbreviationRemovesPoint() {
assertEquals("Proc IEEE",
- abbreviations.getRepository(JournalAbbreviationPreferences.fromPreferences(prefs))
+ abbreviations.getRepository(prefs)
.getNextAbbreviation("Proc. IEEE").get());
}
@Test
public void getNextAbbreviationExpandsAbbreviation() {
assertEquals("Proceedings of the IEEE",
- abbreviations.getRepository(JournalAbbreviationPreferences.fromPreferences(prefs))
+ abbreviations.getRepository(prefs)
.getNextAbbreviation("Proc IEEE").get());
}
diff --git a/src/test/java/net/sf/jabref/logic/l10n/EncodingsTest.java b/src/test/java/net/sf/jabref/logic/l10n/EncodingsTest.java
new file mode 100644
index 0000000..7f4880b
--- /dev/null
+++ b/src/test/java/net/sf/jabref/logic/l10n/EncodingsTest.java
@@ -0,0 +1,28 @@
+package net.sf.jabref.logic.l10n;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+
+public class EncodingsTest {
+ @Test
+ public void charsetsShouldNotBeNull() {
+ assertNotNull(Encodings.ENCODINGS);
+ }
+
+ @Test
+ public void displayNamesShouldNotBeNull() {
+ assertNotNull(Encodings.ENCODINGS_DISPLAYNAMES);
+ }
+
+ @Test
+ public void charsetsShouldNotBeEmpty() {
+ assertNotEquals(0, Encodings.ENCODINGS.length);
+ }
+
+ @Test
+ public void displayNamesShouldNotBeEmpty() {
+ assertNotEquals(0, Encodings.ENCODINGS_DISPLAYNAMES.length);
+ }
+}
diff --git a/src/test/java/net/sf/jabref/logic/l10n/LanguagesTest.java b/src/test/java/net/sf/jabref/logic/l10n/LanguagesTest.java
index 4fdc45d..748a638 100644
--- a/src/test/java/net/sf/jabref/logic/l10n/LanguagesTest.java
+++ b/src/test/java/net/sf/jabref/logic/l10n/LanguagesTest.java
@@ -1,5 +1,6 @@
package net.sf.jabref.logic.l10n;
+import java.util.Locale;
import java.util.Optional;
import org.junit.Test;
@@ -7,17 +8,33 @@ import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class LanguagesTest {
+ @Test
+ public void convertKnownLanguageOnly() {
+ assertEquals(Optional.of(new Locale("en")), Languages.convertToSupportedLocale("en"));
+ }
+
+ @Test
+ public void convertUnknownLanguage() {
+ assertEquals(Optional.empty(), Languages.convertToSupportedLocale("This is not a locale"));
+ }
+
+ @Test
+ public void convertKnownLanguageAndCountryOnly() {
+ assertEquals(Optional.of(new Locale("en")), Languages.convertToSupportedLocale("en_US"));
+ }
+
+ @Test
+ public void convertKnownLanguageAndUnknownCountry() {
+ assertEquals(Optional.of(new Locale("en")), Languages.convertToSupportedLocale("en_GB_unknownvariant"));
+ }
@Test
- public void testConvertToKnownLocale() {
- assertEquals(Optional.of("en"), Languages.convertToKnownLocale("en"));
- assertEquals(Optional.of("en"), Languages.convertToKnownLocale("en_US"));
- assertEquals(Optional.of("de"), Languages.convertToKnownLocale("de_DE"));
- assertEquals(Optional.empty(), Languages.convertToKnownLocale("WHATEVER"));
+ public void convertUnknownKnownLanguageAndUnknownCountry() {
+ assertEquals(Optional.empty(), Languages.convertToSupportedLocale("language_country_variant"));
}
@Test(expected = NullPointerException.class)
- public void testConvertToKnownLocaleNull() {
- Languages.convertToKnownLocale(null);
+ public void convertToKnownLocaleNull() {
+ Languages.convertToSupportedLocale(null);
}
-}
\ No newline at end of file
+}
diff --git a/src/test/java/net/sf/jabref/logic/l10n/LocalizationConsistencyTest.java b/src/test/java/net/sf/jabref/logic/l10n/LocalizationConsistencyTest.java
index c38225c..4682214 100644
--- a/src/test/java/net/sf/jabref/logic/l10n/LocalizationConsistencyTest.java
+++ b/src/test/java/net/sf/jabref/logic/l10n/LocalizationConsistencyTest.java
@@ -10,13 +10,11 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
-import java.util.StringJoiner;
import java.util.stream.Collectors;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
public class LocalizationConsistencyTest {
@@ -124,12 +122,13 @@ public class LocalizationConsistencyTest {
List<LocalizationEntry> missingKeys = LocalizationParser.find(LocalizationBundle.LANG).stream().sorted()
.distinct().collect(Collectors.toList());
- printInfos(missingKeys);
-
- String resultString = missingKeys.stream().map(Object::toString).collect(Collectors.joining("\n"));
- assertEquals(
- "source code contains language keys for the messages which are not in the corresponding properties file",
- "", resultString);
+ assertEquals("DETECTED LANGUAGE KEYS WHICH ARE NOT IN THE ENGLISH LANGUAGE FILE\n" +
+ "1. PASTE THESE INTO THE ENGLISH LANGUAGE FILE\n" +
+ "2. EXECUTE: gradlew localizationUpdate\n" +
+ missingKeys.parallelStream()
+ .map(key -> String.format("%s=%s", key.getKey(), key.getKey()))
+ .collect(Collectors.toList()),
+ Collections.<LocalizationEntry>emptyList(), missingKeys);
}
@Test
@@ -137,72 +136,35 @@ public class LocalizationConsistencyTest {
List<LocalizationEntry> missingKeys = LocalizationParser.find(LocalizationBundle.MENU).stream()
.collect(Collectors.toList());
- printInfos(missingKeys);
-
- String resultString = missingKeys.stream().map(Object::toString).collect(Collectors.joining("\n"));
- assertEquals(
- "source code contains language keys for the menu which are not in the corresponding properties file",
- "", resultString);
+ assertEquals("DETECTED LANGUAGE KEYS WHICH ARE NOT IN THE ENGLISH MENU FILE\n" +
+ "1. PASTE THESE INTO THE ENGLISH MENU FILE\n" +
+ "2. EXECUTE: gradlew localizationUpdate\n" +
+ missingKeys.parallelStream()
+ .map(key -> String.format("%s=%s", key.getKey(), key.getKey()))
+ .collect(Collectors.toList()),
+ Collections.<LocalizationEntry>emptyList(), missingKeys);
}
@Test
public void findObsoleteLocalizationKeys() throws IOException {
List<String> obsoleteKeys = LocalizationParser.findObsolete(LocalizationBundle.LANG);
- if (!obsoleteKeys.isEmpty()) {
- System.out.println();
- System.out.println("Obsolete keys found:");
- System.out.println(obsoleteKeys.stream().map(Object::toString).collect(Collectors.joining("\n")));
- System.out.println();
- System.out.println("1. REMOVE THESE FROM THE ENGLISH LANGUAGE FILE");
- System.out.println("2. EXECUTE gradlew -b localization.gradle generateMissingTranslationKeys TO");
- System.out.println("REMOVE THESE FROM THE NON-ENGLISH LANGUAGE FILES");
- fail("Obsolete keys " + obsoleteKeys + " found in properties file which should be removed");
- }
+ assertEquals("Obsolete keys found in language properties file: " + obsoleteKeys + "\n" +
+ "1. CHECK IF THE KEY IS REALLY NOT USED ANYMORE\n" +
+ "2. REMOVE THESE FROM THE ENGLISH LANGUAGE FILE\n" +
+ "3. EXECUTE: gradlew localizationUpdate\n",
+ Collections.<String>emptyList(), obsoleteKeys);
}
@Test
public void findObsoleteMenuLocalizationKeys() throws IOException {
List<String> obsoleteKeys = LocalizationParser.findObsolete(LocalizationBundle.MENU);
- if (!obsoleteKeys.isEmpty()) {
- System.out.println();
- System.out.println("Obsolete menu keys found:");
- System.out.println(obsoleteKeys.stream().map(Object::toString).collect(Collectors.joining("\n")));
- System.out.println();
- System.out.println("1. REMOVE THESE FROM THE ENGLISH LANGUAGE FILE");
- System.out.println("2. EXECUTE gradlew -b localization.gradle generateMissingTranslationKeys" + " TO");
- System.out.println("REMOVE THESE FROM THE NON-ENGLISH LANGUAGE FILES");
- fail("Obsolete keys " + obsoleteKeys + " found in menu properties file which should be removed");
- }
- }
-
- private void printInfos(List<LocalizationEntry> missingKeys) {
- if (!missingKeys.isEmpty()) {
- System.out.println(convertToEnglishPropertiesFile(missingKeys));
- System.out.println();
- System.out.println();
- System.out.println(convertPropertiesFile(missingKeys));
- }
- }
-
- private String convertToEnglishPropertiesFile(List<LocalizationEntry> missingKeys) {
- System.out.println("PASTE THIS INTO THE ENGLISH LANGUAGE FILE");
- StringJoiner result = new StringJoiner("\n");
- for (LocalizationEntry key : missingKeys) {
- result.add(String.format("%s=%s", key.getKey(), key.getKey()));
- }
- return result.toString();
- }
-
- private String convertPropertiesFile(List<LocalizationEntry> missingKeys) {
- System.out.println("EXECUTE gradlew -b localization.gradle generateMissingTranslationKeys TO");
- System.out.println("PASTE THIS INTO THE NON-ENGLISH LANGUAGE FILES");
- StringJoiner result = new StringJoiner("\n");
- for (LocalizationEntry key : missingKeys) {
- result.add(String.format("%s=", key.getKey()));
- }
- return result.toString();
+ assertEquals("Obsolete keys found in the menu properties file: " + obsoleteKeys + "\n" +
+ "1. CHECK IF THE KEY IS REALLY NOT USED ANYMORE\n" +
+ "2. REMOVE THESE FROM THE ENGLISH MENU FILE\n" +
+ "3. EXECUTE: gradlew localizationUpdate\n",
+ Collections.<String>emptyList(), obsoleteKeys);
}
}
diff --git a/src/test/java/net/sf/jabref/logic/l10n/LocalizationTest.java b/src/test/java/net/sf/jabref/logic/l10n/LocalizationTest.java
index 154ba1f..c710596 100644
--- a/src/test/java/net/sf/jabref/logic/l10n/LocalizationTest.java
+++ b/src/test/java/net/sf/jabref/logic/l10n/LocalizationTest.java
@@ -45,7 +45,8 @@ public class LocalizationTest {
Localization.setLanguage("en");
String knownKey = "Groups";
assertEquals(knownKey, Localization.lang(knownKey));
- assertEquals(knownKey, Localization.menuTitle(knownKey));
+ String knownValueWithMnemonics = "&Groups";
+ assertEquals(knownValueWithMnemonics, Localization.menuTitle(knownKey));
}
@Test
@@ -53,7 +54,8 @@ public class LocalizationTest {
Localization.setLanguage("en_US");
String knownKey = "Groups";
assertEquals(knownKey, Localization.lang(knownKey));
- assertEquals(knownKey, Localization.menuTitle(knownKey));
+ String knownValueWithMnemonics = "&Groups";
+ assertEquals(knownValueWithMnemonics, Localization.menuTitle(knownKey));
}
@Test
@@ -64,4 +66,12 @@ public class LocalizationTest {
assertEquals(knownKey, Localization.menuTitle(knownKey));
}
-}
\ No newline at end of file
+ @Test
+ public void testUnsetLanguageTranslation() {
+ String knownKey = "Groups";
+ assertEquals(knownKey, Localization.lang(knownKey));
+ String knownValueWithMnemonics = "&Groups";
+ assertEquals(knownValueWithMnemonics, Localization.menuTitle(knownKey));
+ }
+
+}
diff --git a/src/test/java/net/sf/jabref/logic/layout/LayoutEntryTest.java b/src/test/java/net/sf/jabref/logic/layout/LayoutEntryTest.java
index a791adf..33b7cef 100644
--- a/src/test/java/net/sf/jabref/logic/layout/LayoutEntryTest.java
+++ b/src/test/java/net/sf/jabref/logic/layout/LayoutEntryTest.java
@@ -2,17 +2,13 @@ package net.sf.jabref.logic.layout;
import java.io.IOException;
import java.io.StringReader;
-import java.util.Optional;
-import java.util.regex.Pattern;
-import net.sf.jabref.Globals;
import net.sf.jabref.logic.journals.JournalAbbreviationLoader;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.preferences.JabRefPreferences;
import org.junit.Assert;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import static org.mockito.Mockito.mock;
@@ -25,11 +21,7 @@ import static org.mockito.Mockito.mock;
* To test the Highlighting Feature, an instance of LayoutEntry will be instantiated via Layout and LayoutHelper.
* With these instance the doLayout() Method is called several times for each test case.
* To simulate a search, a BibEntry will be created, which will be used by LayoutEntry.
- * The definition of the search is set by
- * <p/>
- * LayoutEntry.setWordsToHighlight(words); and
- * Globals.prefs.putBoolean("caseSensitiveSearch", false);
- * <p/>
+ *
* There are five test cases:
* - The shown result text has no words which should be highlighted.
* - There is one word which will be highlighted ignoring case sensitivity.
@@ -50,10 +42,6 @@ public class LayoutEntryTest {
*/
@Before
public void setUp() {
- if (Globals.prefs == null) {
- Globals.prefs = JabRefPreferences.getInstance();
- Globals.prefs.putBoolean("highLightWords", Boolean.TRUE);
- }
// create Bibtext Entry
@@ -84,106 +72,19 @@ public class LayoutEntryTest {
// helper Methods
- public String layout(String layoutFile, BibEntry entry, Optional<Pattern> highlightPattern) throws IOException {
+ public String layout(String layoutFile, BibEntry entry) throws IOException {
StringReader sr = new StringReader(layoutFile.replace("__NEWLINE__", "\n"));
Layout layout = new LayoutHelper(sr,
- LayoutFormatterPreferences.fromPreferences(Globals.prefs, mock(JournalAbbreviationLoader.class)))
+ JabRefPreferences.getInstance().getLayoutFormatterPreferences(mock(JournalAbbreviationLoader.class)))
.getLayoutFromText();
- return layout.doLayout(entry, null, highlightPattern);
+ return layout.doLayout(entry, null);
}
/*************************/
/****** tests Cases ******/
/*************************/
- /**
- * @throws Exception
- */
- @Test
- @Ignore
- public void testNoHighlighting() throws IOException {
- // say that this bibtex object was found
- mBTE.setSearchHit(true);
-
- String result = this.layout("<font face=\"arial\">\\begin{abstract}<BR><BR><b>Abstract: </b> \\format[HTMLChars]{\\abstract}\\end{abstract}</font>", mBTE, Optional.empty());
- String expecting = "<font face=\"arial\"><BR><BR><b>Abstract: </b> In this paper, we initiate a formal study of security on Android: Google's new open-source platform for mobile devices. Tags: Paper android google Open-Source Devices</font>";
-
- Assert.assertEquals(expecting, result);
- }
-
- /**
- * @throws Exception
- */
- @Test
- public void testHighlightingOneWordCaseInsesitive() throws IOException {
- // say that this bibtex object was found
- mBTE.setSearchHit(true);
-
- Optional<Pattern> highlightPattern = Optional.of(Pattern.compile("(google)", Pattern.CASE_INSENSITIVE));
-
- String result = this.layout("<font face=\"arial\">\\begin{abstract}<BR><BR><b>Abstract: </b> \\format[HTMLChars]{\\abstract}\\end{abstract}</font>", mBTE, highlightPattern);
- String containing = "<span style=\"background-color:#3399FF;\">Google</span>";
-
- // check
- Assert.assertTrue("Actual message: " + result, result.contains(containing));
- }
-
- /**
- * @throws Exception
- */
- @Test
- public void testHighlightingTwoWordsCaseInsesitive() throws IOException {
- // say that this bibtex object was found
- mBTE.setSearchHit(true);
-
- Optional<Pattern> highlightPattern = Optional.of(Pattern.compile("(Android|study)", Pattern.CASE_INSENSITIVE));
-
- String result = this.layout("<font face=\"arial\">\\begin{abstract}<BR><BR><b>Abstract: </b> \\format[HTMLChars]{\\abstract}\\end{abstract}</font>", mBTE, highlightPattern);
-
- String containing = "<span style=\"background-color:#3399FF;\">Android</span>";
- String containing2 = "<span style=\"background-color:#3399FF;\">study</span>";
-
- // check
- Assert.assertTrue(result.contains(containing));
- Assert.assertTrue(result.contains(containing2));
- }
-
- /**
- * @throws Exception
- */
- @Test
- public void testHighlightingOneWordCaseSesitive() throws IOException {
- // say that this bibtex object was found
- mBTE.setSearchHit(true);
-
- Optional<Pattern> highlightPattern = Optional.of(Pattern.compile("(google)"));
-
- String result = this.layout("<font face=\"arial\">\\begin{abstract}<BR><BR><b>Abstract: </b> \\format[HTMLChars]{\\abstract}\\end{abstract}</font>", mBTE, highlightPattern);
- String expected = "<font face=\"arial\"><BR><BR><b>Abstract: </b> In this paper, we initiate a formal study of security on Android: Google's new open-source platform for mobile devices. Tags: Paper android <span style=\"background-color:#3399FF;\">google</span> Open-Source Devices</font>";
-
- // check
- Assert.assertEquals(expected, result);
- }
-
- /**
- * @throws Exception
- */
- @Test
- public void testHighlightingMoreWordsCaseSesitive() throws IOException {
- // say that this bibtex object was found
- mBTE.setSearchHit(true);
-
- Optional<Pattern> highlightPattern = Optional.of(Pattern.compile("(Android|study|Open)", Pattern.CASE_INSENSITIVE));
-
- String highlightColor = "#3399FF;";
- String result = this.layout("<font face=\"arial\">\\begin{abstract}<BR><BR><b>Abstract: </b> \\format[HTMLChars]{\\abstract}\\end{abstract}</font>", mBTE, highlightPattern);
- String expected = "<font face=\"arial\"><BR><BR><b>Abstract: </b> In this paper, we initiate a formal <span style=\"background-color:" + highlightColor + "\">study</span> of security on <span style=\"background-color:" + highlightColor + "\">Android</span>: Google's new <span style=\"background-color:" + highlightColor + "\">open</span>-source platform for mobile devices. Tags: Paper <span style=\"background-color:" + highlightColor + "\">android</span> google <span style=\"backg [...]
-
- // check
- Assert.assertEquals(expected, result);
- }
-
@Test
public void testParseMethodCalls() {
diff --git a/src/test/java/net/sf/jabref/logic/layout/LayoutTest.java b/src/test/java/net/sf/jabref/logic/layout/LayoutTest.java
index 6b52baa..7da69c0 100644
--- a/src/test/java/net/sf/jabref/logic/layout/LayoutTest.java
+++ b/src/test/java/net/sf/jabref/logic/layout/LayoutTest.java
@@ -1,13 +1,17 @@
package net.sf.jabref.logic.layout;
+import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.util.Collection;
+import java.util.Collections;
-import net.sf.jabref.logic.importer.ImportFormatPreferences;
import net.sf.jabref.logic.importer.ParserResult;
import net.sf.jabref.logic.importer.fileformat.BibtexParser;
import net.sf.jabref.logic.journals.JournalAbbreviationLoader;
+import net.sf.jabref.logic.journals.JournalAbbreviationPreferences;
+import net.sf.jabref.logic.layout.format.FileLinkPreferences;
+import net.sf.jabref.logic.layout.format.NameFormatterPreferences;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.preferences.JabRefPreferences;
@@ -28,8 +32,7 @@ public class LayoutTest {
*/
@Before
public void setUp() {
- prefs = LayoutFormatterPreferences.fromPreferences(JabRefPreferences.getInstance(),
- mock(JournalAbbreviationLoader.class));
+ prefs = JabRefPreferences.getInstance().getLayoutFormatterPreferences(mock(JournalAbbreviationLoader.class));
}
/**
@@ -46,7 +49,7 @@ public class LayoutTest {
public static BibEntry bibtexString2BibtexEntry(String s) throws IOException {
ParserResult result = BibtexParser.parse(new StringReader(s),
- ImportFormatPreferences.fromPreferences(JabRefPreferences.getInstance()));
+JabRefPreferences.getInstance().getImportFormatPreferences());
Collection<BibEntry> c = result.getDatabase().getEntries();
Assert.assertEquals(1, c.size());
return c.iterator().next();
@@ -115,4 +118,18 @@ public class LayoutTest {
"<font face=\"arial\"><BR><BR><b>Abstract: </b> ñ ñ í ı ı</font>",
layoutText);
}
+
+ @Test
+ // Test for http://discourse.jabref.org/t/the-wrapfilelinks-formatter/172 (the example in the help files)
+ public void testWrapFileLinksLayout() throws IOException {
+ prefs = new LayoutFormatterPreferences(mock(NameFormatterPreferences.class),
+ mock(JournalAbbreviationPreferences.class),
+ new FileLinkPreferences(Collections.emptyList(), Collections.singletonList("src/test/resources/pdfs/")),
+ mock(JournalAbbreviationLoader.class));
+ String layoutText = layout("\\begin{file}\\format[WrapFileLinks(\\i. \\d (\\p))]{\\file}\\end{file}",
+ "@other{bla, file={Test file:encrypted.pdf:PDF}}");
+ Assert.assertEquals(
+ "1. Test file (" + new File("src/test/resources/pdfs/encrypted.pdf").getCanonicalPath() + ")",
+ layoutText);
+ }
}
diff --git a/src/test/java/net/sf/jabref/logic/layout/format/AuthorsTest.java b/src/test/java/net/sf/jabref/logic/layout/format/AuthorsTest.java
index 2059a37..f5f5dd2 100644
--- a/src/test/java/net/sf/jabref/logic/layout/format/AuthorsTest.java
+++ b/src/test/java/net/sf/jabref/logic/layout/format/AuthorsTest.java
@@ -131,10 +131,27 @@ public class AuthorsTest {
}
@Test
+ public void testEtAl() {
+ ParamLayoutFormatter a = new Authors();
+ a.setArgument("2,1");
+ Assert.assertEquals("B. C. Bruce et al.",
+ a.format("Bruce, Bob Croydon and Charles Kermit von Manson and Jumper, Jolly"));
+ }
+
+ @Test
+ public void testEtAlNotEnoughAuthors() {
+ ParamLayoutFormatter a = new Authors();
+ a.setArgument("2,1");
+ Assert.assertEquals("B. C. Bruce and C. K. von Manson",
+ a.format("Bruce, Bob Croydon and Charles Kermit von Manson"));
+ }
+
+ @Test
public void testEmptyEtAl() {
ParamLayoutFormatter a = new Authors();
a.setArgument("fullname, LastFirst, Comma, 3, etal=");
Assert.assertEquals("Bruce, Bob Croydon",
a.format("Bob Croydon Bruce and Charles Manson and Jolly Jumper and Chuck Chuckles"));
}
+
}
diff --git a/src/test/java/net/sf/jabref/logic/layout/format/FileLinkTest.java b/src/test/java/net/sf/jabref/logic/layout/format/FileLinkTest.java
index e33e7d5..a0b24ff 100644
--- a/src/test/java/net/sf/jabref/logic/layout/format/FileLinkTest.java
+++ b/src/test/java/net/sf/jabref/logic/layout/format/FileLinkTest.java
@@ -14,7 +14,7 @@ public class FileLinkTest {
private FileLinkPreferences prefs;
@Before
public void setUp() throws Exception {
- prefs = FileLinkPreferences.fromPreferences(JabRefPreferences.getInstance());
+ prefs = JabRefPreferences.getInstance().getFileLinkPreferences();
}
@Test
diff --git a/src/test/java/net/sf/jabref/logic/layout/format/RTFCharsTest.java b/src/test/java/net/sf/jabref/logic/layout/format/RTFCharsTest.java
index 9fd8559..e67b753 100644
--- a/src/test/java/net/sf/jabref/logic/layout/format/RTFCharsTest.java
+++ b/src/test/java/net/sf/jabref/logic/layout/format/RTFCharsTest.java
@@ -5,7 +5,6 @@ import net.sf.jabref.logic.layout.LayoutFormatter;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
public class RTFCharsTest {
@@ -27,12 +26,11 @@ public class RTFCharsTest {
Assert.assertEquals("hallo", formatter.format("hallo"));
- // We should be able to replace the ? with e
- Assert.assertEquals("R\\u233?flexions sur le timing de la quantit\\u233?",
+ Assert.assertEquals("R\\u233eflexions sur le timing de la quantit\\u233e",
formatter.format("Réflexions sur le timing de la quantité"));
- Assert.assertEquals("h\\u225allo", formatter.format("h\\'allo"));
- Assert.assertEquals("h\\u225allo", formatter.format("h\\'allo"));
+ Assert.assertEquals("h\\'e1llo", formatter.format("h\\'allo"));
+ Assert.assertEquals("h\\'e1llo", formatter.format("h\\'allo"));
}
@Test
@@ -49,51 +47,142 @@ public class RTFCharsTest {
}
@Test
- @Ignore
public void testComplicated() {
- Assert.assertEquals("R\\u233eflexions sur le timing de la quantit\\u233e \\u230ae should be \\u230ae",
- formatter.format("Réflexions sur le timing de la quantité \\ae should be æ"));
+ Assert.assertEquals("R\\u233eflexions sur le timing de la quantit\\u233e {\\u230ae} should be \\u230ae",
+ formatter.format("Réflexions sur le timing de la quantité {\\ae} should be æ"));
+ }
+
+ @Test
+ public void testComplicated2() {
+ Assert.assertEquals("h\\'e1ll{\\u339oe}", formatter.format("h\\'all{\\oe}"));
+ }
- Assert.assertEquals("h\\u225all{\\uc2\\u339oe}", formatter.format("h\\'all\\oe "));
+ @Test
+ public void testComplicated3() {
+ Assert.assertEquals("Le c\\u339oeur d\\u233e\\u231cu mais l'\\u226ame plut\\u244ot na\\u239ive, Lou\\u255ys r" +
+ "\\u234eva de crapa\\u252?ter en cano\\u235e au del\\u224a des \\u238iles, pr\\u232es du m\\u228alstr" +
+ "\\u246om o\\u249u br\\u251ulent les nov\\u230ae.", formatter.format("Le cœur déçu mais l'âme plutôt " +
+ "naïve, Louÿs rêva de crapaüter en canoë au delà des îles, près du mälström où brûlent les novæ."));
+ }
+
+ @Test
+ public void testComplicated4() {
+ Assert.assertEquals("l'\\u238ile exigu\\u235e\n" +
+ " O\\u249u l'ob\\u232ese jury m\\u251ur\n" +
+ " F\\u234ete l'ha\\u239i volap\\u252?k,\n" +
+ " \\u194Ane ex a\\u233equo au whist,\n" +
+ " \\u212Otez ce v\\u339oeu d\\u233e\\u231cu.", formatter.format("l'île exiguë\n" +
+ " Où l'obèse jury mûr\n" +
+ " Fête l'haï volapük,\n" +
+ " Âne ex aéquo au whist,\n" +
+ " Ôtez ce vœu déçu."));
+ }
+
+ @Test
+ public void testComplicated5() {
+ Assert.assertEquals("\\u193Arv\\u237izt\\u369?r\\u337? t\\u252?k\\u246orf\\u250ur\\u243og\\u233ep",
+ formatter.format("Árvíztűrő tükörfúrógép"));
+ }
+
+ @Test
+ public void testComplicated6() {
+ Assert.assertEquals("Pchn\\u261a\\u263c w t\\u281e \\u322l\\u243od\\u378z je\\u380za lub o\\u347sm skrzy\\u324n fig"
+ ,formatter.format("Pchnąć w tę łódź jeża lub ośm skrzyń fig"));
}
@Test
- @Ignore
public void testSpecialCharacters() {
- Assert.assertEquals("\\u243o", formatter.format("\\'{o}")); // ó
+ Assert.assertEquals("\\'f3", formatter.format("\\'{o}")); // ó
Assert.assertEquals("\\'f2", formatter.format("\\`{o}")); // ò
Assert.assertEquals("\\'f4", formatter.format("\\^{o}")); // ô
Assert.assertEquals("\\'f6", formatter.format("\\\"{o}")); // ö
Assert.assertEquals("\\u245o", formatter.format("\\~{o}")); // õ
Assert.assertEquals("\\u333o", formatter.format("\\={o}"));
- Assert.assertEquals("\\u334O", formatter.format("\\u{o}"));
- Assert.assertEquals("\\u231c", formatter.format("\\c{c}")); // ç
- Assert.assertEquals("{\\uc2\\u339oe}", formatter.format("\\oe"));
- Assert.assertEquals("{\\uc2\\u338OE}", formatter.format("\\OE"));
- Assert.assertEquals("{\\uc2\\u230ae}", formatter.format("\\ae")); // æ
- Assert.assertEquals("{\\uc2\\u198AE}", formatter.format("\\AE")); // Æ
+ Assert.assertEquals("\\u335o", formatter.format("{\\uo}"));
+ Assert.assertEquals("\\u231c", formatter.format("{\\cc}")); // ç
+ Assert.assertEquals("{\\u339oe}", formatter.format("{\\oe}"));
+ Assert.assertEquals("{\\u338OE}", formatter.format("{\\OE}"));
+ Assert.assertEquals("{\\u230ae}", formatter.format("{\\ae}")); // æ
+ Assert.assertEquals("{\\u198AE}", formatter.format("{\\AE}")); // Æ
Assert.assertEquals("", formatter.format("\\.{o}")); // ???
- Assert.assertEquals("", formatter.format("\\v{o}")); // ???
- Assert.assertEquals("", formatter.format("\\H{a}")); // ã // ???
- Assert.assertEquals("", formatter.format("\\t{oo}"));
- Assert.assertEquals("", formatter.format("\\d{o}")); // ???
- Assert.assertEquals("", formatter.format("\\b{o}")); // ???
- Assert.assertEquals("", formatter.format("\\aa")); // å
- Assert.assertEquals("", formatter.format("\\AA")); // Å
- Assert.assertEquals("", formatter.format("\\o")); // ø
- Assert.assertEquals("", formatter.format("\\O")); // Ø
- Assert.assertEquals("", formatter.format("\\l"));
- Assert.assertEquals("", formatter.format("\\L"));
- Assert.assertEquals("{\\uc2\\u223ss}", formatter.format("\\ss")); // ß
- Assert.assertEquals("", formatter.format("?`")); // ¿
- Assert.assertEquals("", formatter.format("!`")); // ¡
+ Assert.assertEquals("", formatter.format("\\vo")); // ???
+ Assert.assertEquals("", formatter.format("\\Ha")); // ã // ???
+ Assert.assertEquals("", formatter.format("\\too"));
+ Assert.assertEquals("", formatter.format("\\do")); // ???
+ Assert.assertEquals("", formatter.format("\\bo")); // ???
+ Assert.assertEquals("\\u229a", formatter.format("{\\aa}")); // å
+ Assert.assertEquals("\\u197A", formatter.format("{\\AA}")); // Å
+ Assert.assertEquals("\\u248o", formatter.format("{\\o}")); // ø
+ Assert.assertEquals("\\u216O", formatter.format("{\\O}")); // Ø
+ Assert.assertEquals("\\u322l", formatter.format("{\\l}"));
+ Assert.assertEquals("\\u321L", formatter.format("{\\L}"));
+ Assert.assertEquals("\\u223ss", formatter.format("{\\ss}")); // ß
+ Assert.assertEquals("\\u191?", formatter.format("\\`?")); // ¿
+ Assert.assertEquals("\\u161!", formatter.format("\\`!")); // ¡
Assert.assertEquals("", formatter.format("\\dag"));
Assert.assertEquals("", formatter.format("\\ddag"));
- Assert.assertEquals("", formatter.format("\\S")); // §
- Assert.assertEquals("", formatter.format("\\P")); // ¶
- Assert.assertEquals("", formatter.format("\\copyright")); // ©
- Assert.assertEquals("", formatter.format("\\pounds")); // £
+ Assert.assertEquals("\\u167S", formatter.format("{\\S}")); // §
+ Assert.assertEquals("\\u182P", formatter.format("{\\P}")); // ¶
+ Assert.assertEquals("\\u169?", formatter.format("{\\copyright}")); // ©
+ Assert.assertEquals("\\u163?", formatter.format("{\\pounds}")); // £
+ }
+
+ @Test
+ public void testRTFCharacters(){
+ Assert.assertEquals("\\'e0",formatter.format("\\`{a}"));
+ Assert.assertEquals("\\'e8",formatter.format("\\`{e}"));
+ Assert.assertEquals("\\'ec",formatter.format("\\`{i}"));
+ Assert.assertEquals("\\'f2",formatter.format("\\`{o}"));
+ Assert.assertEquals("\\'f9",formatter.format("\\`{u}"));
+
+ Assert.assertEquals("\\'e1",formatter.format("\\'a"));
+ Assert.assertEquals("\\'e9",formatter.format("\\'e"));
+ Assert.assertEquals("\\'ed",formatter.format("\\'i"));
+ Assert.assertEquals("\\'f3",formatter.format("\\'o"));
+ Assert.assertEquals("\\'fa",formatter.format("\\'u"));
+
+ Assert.assertEquals("\\'e2",formatter.format("\\^a"));
+ Assert.assertEquals("\\'ea",formatter.format("\\^e"));
+ Assert.assertEquals("\\'ee",formatter.format("\\^i"));
+ Assert.assertEquals("\\'f4",formatter.format("\\^o"));
+ Assert.assertEquals("\\'fa",formatter.format("\\^u"));
+
+ Assert.assertEquals("\\'e4",formatter.format("\\\"a"));
+ Assert.assertEquals("\\'eb",formatter.format("\\\"e"));
+ Assert.assertEquals("\\'ef",formatter.format("\\\"i"));
+ Assert.assertEquals("\\'f6",formatter.format("\\\"o"));
+ Assert.assertEquals("\\u252u",formatter.format("\\\"u"));
+
+ Assert.assertEquals("\\'f1",formatter.format("\\~n"));
}
+
+ @Test
+ public void testRTFCharactersCapital() {
+ Assert.assertEquals("\\'c0",formatter.format("\\`A"));
+ Assert.assertEquals("\\'c8",formatter.format("\\`E"));
+ Assert.assertEquals("\\'cc",formatter.format("\\`I"));
+ Assert.assertEquals("\\'d2",formatter.format("\\`O"));
+ Assert.assertEquals("\\'d9",formatter.format("\\`U"));
+
+ Assert.assertEquals("\\'c1",formatter.format("\\'A"));
+ Assert.assertEquals("\\'c9",formatter.format("\\'E"));
+ Assert.assertEquals("\\'cd",formatter.format("\\'I"));
+ Assert.assertEquals("\\'d3",formatter.format("\\'O"));
+ Assert.assertEquals("\\'da",formatter.format("\\'U"));
+
+ Assert.assertEquals("\\'c2",formatter.format("\\^A"));
+ Assert.assertEquals("\\'ca",formatter.format("\\^E"));
+ Assert.assertEquals("\\'ce",formatter.format("\\^I"));
+ Assert.assertEquals("\\'d4",formatter.format("\\^O"));
+ Assert.assertEquals("\\'db",formatter.format("\\^U"));
+
+ Assert.assertEquals("\\'c4",formatter.format("\\\"A"));
+ Assert.assertEquals("\\'cb",formatter.format("\\\"E"));
+ Assert.assertEquals("\\'cf",formatter.format("\\\"I"));
+ Assert.assertEquals("\\'d6",formatter.format("\\\"O"));
+ Assert.assertEquals("\\'dc",formatter.format("\\\"U"));
+ }
+
}
diff --git a/src/test/java/net/sf/jabref/logic/layout/format/WrapFileLinksTest.java b/src/test/java/net/sf/jabref/logic/layout/format/WrapFileLinksTest.java
new file mode 100644
index 0000000..fcb816c
--- /dev/null
+++ b/src/test/java/net/sf/jabref/logic/layout/format/WrapFileLinksTest.java
@@ -0,0 +1,135 @@
+package net.sf.jabref.logic.layout.format;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collections;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+
+public class WrapFileLinksTest {
+
+ private WrapFileLinks formatter;
+
+
+ @Before
+ public void setUp() {
+ FileLinkPreferences preferences = new FileLinkPreferences(Collections.emptyList(), Collections.emptyList());
+ formatter = new WrapFileLinks(preferences);
+ }
+
+ @Test
+ public void testEmpty() {
+ assertEquals("", formatter.format(""));
+ }
+
+ @Test
+ public void testNull() {
+ assertEquals("", formatter.format(null));
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testNoFormatSetNonEmptyString() {
+ formatter.format("test.pdf");
+ fail();
+ }
+
+ @Test
+ public void testFileExtension() {
+ formatter.setArgument("\\x");
+ assertEquals("pdf", formatter.format("test.pdf"));
+ }
+
+ @Test
+ public void testFileExtensionNoExtension() {
+ formatter.setArgument("\\x");
+ assertEquals("", formatter.format("test"));
+ }
+
+ @Test
+ public void testPlainTextString() {
+ formatter.setArgument("x");
+ assertEquals("x", formatter.format("test.pdf"));
+ }
+
+ @Test
+ public void testDescription() {
+ formatter.setArgument("\\d");
+ assertEquals("Test file", formatter.format("Test file:test.pdf:PDF"));
+ }
+
+ @Test
+ public void testDescriptionNoDescription() {
+ formatter.setArgument("\\d");
+ assertEquals("", formatter.format("test.pdf"));
+ }
+
+ @Test
+ public void testType() {
+ formatter.setArgument("\\f");
+ assertEquals("PDF", formatter.format("Test file:test.pdf:PDF"));
+ }
+
+ @Test
+ public void testTypeNoType() {
+ formatter.setArgument("\\f");
+ assertEquals("", formatter.format("test.pdf"));
+ }
+
+ @Test
+ public void testIterator() {
+ formatter.setArgument("\\i");
+ assertEquals("1", formatter.format("Test file:test.pdf:PDF"));
+ }
+
+ @Test
+ public void testIteratorTwoItems() {
+ formatter.setArgument("\\i\n");
+ assertEquals("1\n2\n", formatter.format("Test file:test.pdf:PDF;test2.pdf"));
+ }
+
+ @Test
+ public void testEndingBracket() {
+ formatter.setArgument("(\\d)");
+ assertEquals("(Test file)", formatter.format("Test file:test.pdf:PDF"));
+ }
+
+ @Test
+ public void testPath() throws IOException {
+ FileLinkPreferences preferences = new FileLinkPreferences(Collections.emptyList(),
+ Collections.singletonList("src/test/resources/pdfs/"));
+ formatter = new WrapFileLinks(preferences);
+ formatter.setArgument("\\p");
+ assertEquals(new File("src/test/resources/pdfs/encrypted.pdf").getCanonicalPath(),
+ formatter.format("Preferences:encrypted.pdf:PDF"));
+ }
+
+ @Test
+ public void testPathFallBackToGeneratedDir() throws IOException {
+ FileLinkPreferences preferences = new FileLinkPreferences(Collections.singletonList("src/test/resources/pdfs/"),
+ Collections.emptyList());
+ formatter = new WrapFileLinks(preferences);
+ formatter.setArgument("\\p");
+ assertEquals(new File("src/test/resources/pdfs/encrypted.pdf").getCanonicalPath(),
+ formatter.format("Preferences:encrypted.pdf:PDF"));
+ }
+
+ @Test
+ public void testPathReturnsRelativePathIfNotFound() {
+ FileLinkPreferences preferences = new FileLinkPreferences(Collections.emptyList(),
+ Collections.singletonList("src/test/resources/pdfs/"));
+ formatter = new WrapFileLinks(preferences);
+ formatter.setArgument("\\p");
+ assertEquals("test.pdf", formatter.format("Preferences:test.pdf:PDF"));
+ }
+
+ @Test
+ public void testRelativePath() {
+ formatter.setArgument("\\r");
+ assertEquals("test.pdf", formatter.format("Test file:test.pdf:PDF"));
+ }
+}
diff --git a/src/test/java/net/sf/jabref/logic/net/URLDownloadTest.java b/src/test/java/net/sf/jabref/logic/net/URLDownloadTest.java
index d8cea3c..0a4b2e1 100644
--- a/src/test/java/net/sf/jabref/logic/net/URLDownloadTest.java
+++ b/src/test/java/net/sf/jabref/logic/net/URLDownloadTest.java
@@ -50,4 +50,20 @@ public class URLDownloadTest {
Assert.assertTrue(dl.determineMimeType().startsWith("text/html"));
}
-}
\ No newline at end of file
+ @Test
+ public void downloadToTemporaryFilePathWithoutFileSavesAsTmpFile() throws IOException {
+ URLDownload google = new URLDownload(new URL("http://www.google.com"));
+
+ String path = google.downloadToTemporaryFile().toString();
+ Assert.assertTrue(path, path.endsWith(".tmp"));
+ }
+
+ @Test
+ public void downloadToTemporaryFileKeepsName() throws IOException {
+ URLDownload google = new URLDownload(new URL("https://github.com/JabRef/jabref/blob/master/LICENSE.md"));
+
+ String path = google.downloadToTemporaryFile().toString();
+ Assert.assertTrue(path, path.contains("LICENSE") && path.endsWith(".md"));
+ }
+
+}
diff --git a/src/test/java/net/sf/jabref/logic/net/URLUtilTest.java b/src/test/java/net/sf/jabref/logic/net/URLUtilTest.java
index 909f430..db90b4f 100644
--- a/src/test/java/net/sf/jabref/logic/net/URLUtilTest.java
+++ b/src/test/java/net/sf/jabref/logic/net/URLUtilTest.java
@@ -13,6 +13,8 @@ public class URLUtilTest {
Assert.assertEquals("this is no url!", URLUtil.cleanGoogleSearchURL("this is no url!"));
// no Google search URL
Assert.assertEquals("http://dl.acm.org/citation.cfm?id=321811", URLUtil.cleanGoogleSearchURL("http://dl.acm.org/citation.cfm?id=321811"));
+ // malformed Google URL
+ Assert.assertEquals("https://www.google.de/url♥", URLUtil.cleanGoogleSearchURL("https://www.google.de/url♥"));
// no queries
Assert.assertEquals("https://www.google.de/url", URLUtil.cleanGoogleSearchURL("https://www.google.de/url"));
Assert.assertEquals("https://www.google.de/url?", URLUtil.cleanGoogleSearchURL("https://www.google.de/url?"));
diff --git a/src/test/java/net/sf/jabref/logic/openoffice/OOBibStyleTest.java b/src/test/java/net/sf/jabref/logic/openoffice/OOBibStyleTest.java
index bd24224..4568c6b 100644
--- a/src/test/java/net/sf/jabref/logic/openoffice/OOBibStyleTest.java
+++ b/src/test/java/net/sf/jabref/logic/openoffice/OOBibStyleTest.java
@@ -14,10 +14,9 @@ import java.util.Map;
import java.util.Set;
import net.sf.jabref.JabRefMain;
-import net.sf.jabref.logic.importer.ImportFormatPreferences;
+import net.sf.jabref.logic.importer.Importer;
import net.sf.jabref.logic.importer.ParserResult;
import net.sf.jabref.logic.importer.fileformat.BibtexParser;
-import net.sf.jabref.logic.importer.fileformat.ImportFormat;
import net.sf.jabref.logic.journals.JournalAbbreviationLoader;
import net.sf.jabref.logic.layout.Layout;
import net.sf.jabref.logic.layout.LayoutFormatterPreferences;
@@ -42,8 +41,8 @@ public class OOBibStyleTest {
@Before
public void setUp() {
- layoutFormatterPreferences = LayoutFormatterPreferences.fromPreferences(JabRefPreferences.getInstance(),
- mock(JournalAbbreviationLoader.class));
+ layoutFormatterPreferences = JabRefPreferences.getInstance()
+ .getLayoutFormatterPreferences(mock(JournalAbbreviationLoader.class));
}
@Test
@@ -143,8 +142,8 @@ public class OOBibStyleTest {
@Test
public void testGetCitationMarker() throws IOException {
Path testBibtexFile = Paths.get("src/test/resources/testbib/complex.bib");
- ParserResult result = BibtexParser.parse(ImportFormat.getReader(testBibtexFile, StandardCharsets.UTF_8),
- ImportFormatPreferences.fromPreferences(JabRefPreferences.getInstance()));
+ ParserResult result = BibtexParser.parse(Importer.getReader(testBibtexFile, StandardCharsets.UTF_8),
+ JabRefPreferences.getInstance().getImportFormatPreferences());
OOBibStyle style = new OOBibStyle(StyleLoader.DEFAULT_NUMERICAL_STYLE_PATH,
layoutFormatterPreferences);
Map<BibEntry, BibDatabase> entryDBMap = new HashMap<>();
@@ -165,8 +164,8 @@ public class OOBibStyleTest {
@Test
public void testLayout() throws IOException {
Path testBibtexFile = Paths.get("src/test/resources/testbib/complex.bib");
- ParserResult result = BibtexParser.parse(ImportFormat.getReader(testBibtexFile, StandardCharsets.UTF_8),
- ImportFormatPreferences.fromPreferences(JabRefPreferences.getInstance()));
+ ParserResult result = BibtexParser.parse(Importer.getReader(testBibtexFile, StandardCharsets.UTF_8),
+ JabRefPreferences.getInstance().getImportFormatPreferences());
OOBibStyle style = new OOBibStyle(StyleLoader.DEFAULT_NUMERICAL_STYLE_PATH,
layoutFormatterPreferences);
BibDatabase db = result.getDatabase();
diff --git a/src/test/java/net/sf/jabref/logic/openoffice/StyleLoaderTest.java b/src/test/java/net/sf/jabref/logic/openoffice/StyleLoaderTest.java
index cc4b0dd..43c0b67 100644
--- a/src/test/java/net/sf/jabref/logic/openoffice/StyleLoaderTest.java
+++ b/src/test/java/net/sf/jabref/logic/openoffice/StyleLoaderTest.java
@@ -33,8 +33,8 @@ public class StyleLoaderTest {
@Before
public void setUp() {
preferences = new OpenOfficePreferences(JabRefPreferences.getInstance());
- layoutPreferences = LayoutFormatterPreferences.fromPreferences(JabRefPreferences.getInstance(),
- mock(JournalAbbreviationLoader.class));
+ layoutPreferences = JabRefPreferences.getInstance()
+ .getLayoutFormatterPreferences(mock(JournalAbbreviationLoader.class));
encoding = JabRefPreferences.getInstance().getDefaultEncoding();
}
@@ -48,7 +48,7 @@ public class StyleLoaderTest {
@Test(expected = NullPointerException.class)
public void throwNPEWithNullRepository() {
loader = new StyleLoader(mock(OpenOfficePreferences.class),
- LayoutFormatterPreferences.fromPreferences(JabRefPreferences.getInstance(), null), mock(Charset.class));
+ JabRefPreferences.getInstance().getLayoutFormatterPreferences(null), mock(Charset.class));
fail();
}
diff --git a/src/test/java/net/sf/jabref/logic/remote/RemotePreferencesTest.java b/src/test/java/net/sf/jabref/logic/remote/RemotePreferencesTest.java
new file mode 100644
index 0000000..4620986
--- /dev/null
+++ b/src/test/java/net/sf/jabref/logic/remote/RemotePreferencesTest.java
@@ -0,0 +1,53 @@
+package net.sf.jabref.logic.remote;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+
+public class RemotePreferencesTest {
+
+ private RemotePreferences preferences;
+
+
+ @Before
+ public void setUp() {
+ preferences = new RemotePreferences(1000, true);
+ }
+
+ @Test
+ public void testGetPort() {
+ assertEquals(1000, preferences.getPort());
+ }
+
+ @Test
+ public void testSetPort() {
+ preferences.setPort(2000);
+ assertEquals(2000, preferences.getPort());
+ }
+
+ @Test
+ public void testUseRemoteServer() {
+ assertTrue(preferences.useRemoteServer());
+ }
+
+ @Test
+ public void testSetUseRemoteServer() {
+ preferences.setUseRemoteServer(false);
+ assertFalse(preferences.useRemoteServer());
+ }
+
+ @Test
+ public void testIsDifferentPortTrue() {
+ assertTrue(preferences.isDifferentPort(2000));
+ }
+
+ @Test
+ public void testIsDifferentPortFalse() {
+ assertFalse(preferences.isDifferentPort(1000));
+ }
+
+}
diff --git a/src/test/java/net/sf/jabref/logic/search/DatabaseSearcherTest.java b/src/test/java/net/sf/jabref/logic/search/DatabaseSearcherTest.java
index bf3a96f..9d4ad28 100644
--- a/src/test/java/net/sf/jabref/logic/search/DatabaseSearcherTest.java
+++ b/src/test/java/net/sf/jabref/logic/search/DatabaseSearcherTest.java
@@ -5,7 +5,9 @@ import java.util.List;
import net.sf.jabref.model.database.BibDatabase;
import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.BibtexEntryTypes;
+import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
@@ -14,32 +16,35 @@ public class DatabaseSearcherTest {
public static final SearchQuery INVALID_SEARCH_QUERY = new SearchQuery("\\asd123{}asdf", true, true);
+ private BibDatabase database;
+
+
+ @Before
+ public void setUp() {
+ database = new BibDatabase();
+ }
@Test
- public void testGetDatabaseFromMatchesEmptyDatabase() {
- BibDatabase database = new BibDatabase();
+ public void testNoMatchesFromEmptyDatabase() {
List<BibEntry> matches = new DatabaseSearcher(new SearchQuery("whatever", true, true), database).getMatches();
assertEquals(Collections.emptyList(), matches);
}
@Test
- public void testGetDatabaseFromMatchesEmptyDatabaseInvalidSearchExpression() {
- BibDatabase database = new BibDatabase();
+ public void testNoMatchesFromEmptyDatabaseWithInvalidSearchExpression() {
List<BibEntry> matches = new DatabaseSearcher(INVALID_SEARCH_QUERY, database).getMatches();
assertEquals(Collections.emptyList(), matches);
}
@Test
public void testGetDatabaseFromMatchesDatabaseWithEmptyEntries() {
- BibDatabase database = new BibDatabase();
database.insertEntry(new BibEntry());
List<BibEntry> matches = new DatabaseSearcher(new SearchQuery("whatever", true, true), database).getMatches();
assertEquals(Collections.emptyList(), matches);
}
@Test
- public void testGetDatabaseFromMatchesDatabaseWithEntries() {
- BibDatabase database = new BibDatabase();
+ public void testNoMatchesFromDatabaseWithArticleTypeEntry() {
BibEntry entry = new BibEntry();
entry.setType("article");
entry.setField("author", "harrer");
@@ -49,8 +54,7 @@ public class DatabaseSearcherTest {
}
@Test
- public void testGetDatabaseFromMatchesDatabaseWithEntriesWithCorrectMatch() {
- BibDatabase database = new BibDatabase();
+ public void testCorrectMatchFromDatabaseWithArticleTypeEntry() {
BibEntry entry = new BibEntry();
entry.setType("article");
entry.setField("author", "harrer");
@@ -58,4 +62,66 @@ public class DatabaseSearcherTest {
List<BibEntry> matches = new DatabaseSearcher(new SearchQuery("harrer", true, true), database).getMatches();
assertEquals(Collections.singletonList(entry), matches);
}
+
+ @Test
+ public void testNoMatchesFromEmptyDatabaseWithInvalidQuery() {
+ SearchQuery query = new SearchQuery("asdf[", true, true);
+
+ DatabaseSearcher databaseSearcher = new DatabaseSearcher(query, database);
+
+ assertEquals(Collections.emptyList(), databaseSearcher.getMatches());
+ }
+
+ @Test
+ public void testCorrectMatchFromDatabaseWithIncollectionTypeEntry() {
+ BibEntry entry = new BibEntry();
+ entry.setType(BibtexEntryTypes.INCOLLECTION);
+ entry.setField("author", "tonho");
+ database.insertEntry(entry);
+
+ SearchQuery query = new SearchQuery("tonho", true, true);
+ List<BibEntry> matches = new DatabaseSearcher(query, database).getMatches();
+
+ assertEquals(Collections.singletonList(entry), matches);
+ }
+
+ @Test
+ public void testNoMatchesFromDatabaseWithTwoEntries() {
+ BibEntry entry = new BibEntry();
+ database.insertEntry(entry);
+
+ entry = new BibEntry();
+ entry.setType(BibtexEntryTypes.INCOLLECTION);
+ entry.setField("author", "tonho");
+ database.insertEntry(entry);
+
+ SearchQuery query = new SearchQuery("tonho", true, true);
+ DatabaseSearcher databaseSearcher = new DatabaseSearcher(query, database);
+
+ assertEquals(Collections.singletonList(entry), databaseSearcher.getMatches());
+ }
+
+ @Test
+ public void testNoMatchesFromDabaseWithIncollectionTypeEntry() {
+ BibEntry entry = new BibEntry();
+ entry.setType(BibtexEntryTypes.INCOLLECTION);
+ entry.setField("author", "tonho");
+ database.insertEntry(entry);
+
+ SearchQuery query = new SearchQuery("asdf", true, true);
+ DatabaseSearcher databaseSearcher = new DatabaseSearcher(query, database);
+
+ assertEquals(Collections.emptyList(), databaseSearcher.getMatches());
+ }
+
+ @Test
+ public void testNoMatchFromDatabaseWithEmptyEntry() {
+ BibEntry entry = new BibEntry();
+ database.insertEntry(entry);
+
+ SearchQuery query = new SearchQuery("tonho", true, true);
+ DatabaseSearcher databaseSearcher = new DatabaseSearcher(query, database);
+
+ assertEquals(Collections.emptyList(), databaseSearcher.getMatches());
+ }
}
diff --git a/src/test/java/net/sf/jabref/logic/search/GrammarBasedSearchRuleDescriberTest.java b/src/test/java/net/sf/jabref/logic/search/GrammarBasedSearchRuleDescriberTest.java
index e0e40c3..4c97d09 100644
--- a/src/test/java/net/sf/jabref/logic/search/GrammarBasedSearchRuleDescriberTest.java
+++ b/src/test/java/net/sf/jabref/logic/search/GrammarBasedSearchRuleDescriberTest.java
@@ -1,7 +1,7 @@
package net.sf.jabref.logic.search;
-import net.sf.jabref.logic.search.rules.GrammarBasedSearchRule;
import net.sf.jabref.logic.search.rules.describer.GrammarBasedSearchRuleDescriber;
+import net.sf.jabref.model.search.rules.GrammarBasedSearchRule;
import org.junit.Test;
diff --git a/src/test/java/net/sf/jabref/logic/search/MatchesHighlighterTest.java b/src/test/java/net/sf/jabref/logic/search/MatchesHighlighterTest.java
deleted file mode 100644
index a2310fb..0000000
--- a/src/test/java/net/sf/jabref/logic/search/MatchesHighlighterTest.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package net.sf.jabref.logic.search;
-
-import java.util.Collections;
-import java.util.Optional;
-import java.util.function.Predicate;
-import java.util.regex.Pattern;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-public class MatchesHighlighterTest {
-
- @Test
- public void testHighlightWords() {
- assertEquals("", MatchesHighlighter.highlightWordsWithHTML("", Optional.empty()));
- assertEquals("Einstein", MatchesHighlighter.highlightWordsWithHTML("Einstein", Optional.empty()));
- assertEquals("<span style=\"background-color:#3399FF;\">Einstein</span>", MatchesHighlighter.highlightWordsWithHTML("Einstein", Optional.of(Pattern.compile("Einstein"))));
- }
-
- @Test(expected = NullPointerException.class)
- public void testNullText() {
- MatchesHighlighter.highlightWordsWithHTML(null, Optional.empty());
- }
-
- @Test(expected = NullPointerException.class)
- public void testNullList() {
- MatchesHighlighter.highlightWordsWithHTML("", null);
- }
-
- @Test
- public void testNoWords() {
- assertEquals(Optional.empty(), SearchQueryHighlightObservable.getPatternForWords(Collections.emptyList(), true, true));
- }
-
- @Test
- public void testPatternCaseInsensitive() {
- Predicate<String> predicate = SearchQueryHighlightObservable.getPatternForWords(Collections.singletonList("abc"), true, false).get().asPredicate();
- assertTrue(predicate.test("abc"));
- assertTrue(predicate.test("ABC"));
- assertFalse(predicate.test("abd"));
- assertFalse(predicate.test("ab"));
- }
-
- @Test
- public void testPatternCaseSensitive() {
- Predicate<String> predicate = SearchQueryHighlightObservable.getPatternForWords(Collections.singletonList("abc"), true, true).get().asPredicate();
- assertTrue(predicate.test("abc"));
- assertFalse(predicate.test("ABC"));
- assertFalse(predicate.test("abd"));
- assertFalse(predicate.test("ab"));
- }
-}
\ No newline at end of file
diff --git a/src/test/java/net/sf/jabref/logic/search/SearchQueryHighlightObservableTest.java b/src/test/java/net/sf/jabref/logic/search/SearchQueryHighlightObservableTest.java
index 612dd80..c623346 100644
--- a/src/test/java/net/sf/jabref/logic/search/SearchQueryHighlightObservableTest.java
+++ b/src/test/java/net/sf/jabref/logic/search/SearchQueryHighlightObservableTest.java
@@ -1,33 +1,60 @@
package net.sf.jabref.logic.search;
import java.util.Optional;
+import java.util.regex.Pattern;
+import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.verify;
+ at RunWith(MockitoJUnitRunner.class)
public class SearchQueryHighlightObservableTest {
+ @Captor ArgumentCaptor<Optional<Pattern>> captor;
+ @Mock private SearchQueryHighlightListener listener;
+ private SearchQueryHighlightObservable observable;
+
+ @Before
+ public void setUp() throws Exception {
+ observable = new SearchQueryHighlightObservable();
+ }
+
@Test
- public void testUsage() {
- SearchQueryHighlightObservable observable = new SearchQueryHighlightObservable();
- assertEquals(0, observable.getListenerCount());
+ public void addSearchListenerNotifiesListenerAboutPreviousPattern() throws Exception {
observable.fireSearchlistenerEvent(new SearchQuery("test", false, false));
- SearchQueryHighlightListener listener = highlightPattern -> assertTrue("pattern must be there", highlightPattern.isPresent());
+
observable.addSearchListener(listener);
- assertEquals(1, observable.getListenerCount());
+ verify(listener).highlightPattern(captor.capture());
+ assertEquals("(\\Qtest\\E)", captor.getValue().get().pattern());
+ }
+
+ @Test
+ public void addSearchListenerNotifiesRegisteredListener() throws Exception {
observable.addSearchListener(listener);
- assertEquals(1, observable.getListenerCount());
- observable.fireSearchlistenerEvent(new SearchQuery("test", true, true));
- observable.removeSearchListener(listener);
- assertEquals(0, observable.getListenerCount());
+ observable.fireSearchlistenerEvent(new SearchQuery("test", false, false));
- observable.fireSearchlistenerEvent(new SearchQuery("author=harrer", true, true));
- observable.addSearchListener(p -> assertEquals(Optional.empty(), p));
- assertEquals(1, observable.getListenerCount());
+ verify(listener, atLeastOnce()).highlightPattern(captor.capture());
+ assertEquals("(\\Qtest\\E)", captor.getValue().get().pattern());
}
-}
\ No newline at end of file
+ @Test
+ public void addSearchListenerNotifiesRegisteredListenerAboutGrammarBasedSearches() throws Exception {
+ observable.addSearchListener(listener);
+
+ observable.fireSearchlistenerEvent(new SearchQuery("author=harrer", false, false));
+
+ verify(listener, atLeastOnce()).highlightPattern(captor.capture());
+ // TODO: We would expect "harrer" here
+ assertEquals("(\\Qauthor=harrer\\E)", captor.getValue().get().pattern());
+ }
+}
diff --git a/src/test/java/net/sf/jabref/logic/search/SearchQueryTest.java b/src/test/java/net/sf/jabref/logic/search/SearchQueryTest.java
index 55381e0..573cf7e 100644
--- a/src/test/java/net/sf/jabref/logic/search/SearchQueryTest.java
+++ b/src/test/java/net/sf/jabref/logic/search/SearchQueryTest.java
@@ -21,22 +21,22 @@ public class SearchQueryTest {
@Test
public void testIsContainsBasedSearch() {
- assertTrue(new SearchQuery("asdf", true, false).isContainsBasedSearch());
+ assertFalse(new SearchQuery("asdf", true, false).isContainsBasedSearch());
assertFalse(new SearchQuery("asdf", true, true).isContainsBasedSearch());
assertFalse(new SearchQuery("author=asdf", true, false).isContainsBasedSearch());
}
@Test
public void testIsGrammarBasedSearch() {
- assertFalse(new SearchQuery("asdf", true, false).isGrammarBasedSearch());
- assertFalse(new SearchQuery("asdf", true, true).isGrammarBasedSearch());
+ assertTrue(new SearchQuery("asdf", true, false).isGrammarBasedSearch());
+ assertTrue(new SearchQuery("asdf", true, true).isGrammarBasedSearch());
assertTrue(new SearchQuery("author=asdf", true, false).isGrammarBasedSearch());
}
@Test
public void testGrammarSearch() {
BibEntry entry = new BibEntry();
- entry.addKeyword("one two", ", ");
+ entry.addKeyword("one two", ',');
SearchQuery searchQuery = new SearchQuery("keywords=\"one two\"", false, false);
assertTrue(searchQuery.isMatch(entry));
}
@@ -66,4 +66,124 @@ public class SearchQueryTest {
assertTrue(searchQuery.isMatch(e));
}
+ @Test
+ public void testSearchMatchesSingleKeywordNotPart() {
+ BibEntry e = new BibEntry(IdGenerator.next(), BibtexEntryTypes.INPROCEEDINGS.getName());
+ e.setField("keywords", "banana, pineapple, orange");
+
+ SearchQuery searchQuery = new SearchQuery("anykeyword==apple", false, false);
+ assertFalse(searchQuery.isMatch(e));
+ }
+
+ @Test
+ public void testSearchMatchesSingleKeyword() {
+ BibEntry e = new BibEntry(IdGenerator.next(), BibtexEntryTypes.INPROCEEDINGS.getName());
+ e.setField("keywords", "banana, pineapple, orange");
+
+ SearchQuery searchQuery = new SearchQuery("anykeyword==pineapple", false, false);
+ assertTrue(searchQuery.isMatch(e));
+ }
+
+ @Test
+ public void testSearchAllFields() {
+ BibEntry e = new BibEntry(IdGenerator.next(), BibtexEntryTypes.INPROCEEDINGS.getName());
+ e.setField("title", "Fruity features");
+ e.setField("keywords", "banana, pineapple, orange");
+
+ SearchQuery searchQuery = new SearchQuery("anyfield==\"fruity features\"", false, false);
+ assertTrue(searchQuery.isMatch(e));
+ }
+
+ @Test
+ public void testSearchAllFieldsNotForSpecificField() {
+ BibEntry e = new BibEntry(IdGenerator.next(), BibtexEntryTypes.INPROCEEDINGS.getName());
+ e.setField("title", "Fruity features");
+ e.setField("keywords", "banana, pineapple, orange");
+
+ SearchQuery searchQuery = new SearchQuery("anyfield=fruit and keywords!=banana", false, false);
+ assertFalse(searchQuery.isMatch(e));
+ }
+
+ @Test
+ public void testSearchAllFieldsAndSpecificField() {
+ BibEntry e = new BibEntry(IdGenerator.next(), BibtexEntryTypes.INPROCEEDINGS.getName());
+ e.setField("title", "Fruity features");
+ e.setField("keywords", "banana, pineapple, orange");
+
+ SearchQuery searchQuery = new SearchQuery("anyfield=fruit and keywords=apple", false, false);
+ assertTrue(searchQuery.isMatch(e));
+ }
+
+ @Test
+ public void testIsMatch() {
+ BibEntry entry = new BibEntry();
+ entry.setType(BibtexEntryTypes.ARTICLE);
+ entry.setField("author", "asdf");
+
+ assertFalse(new SearchQuery("qwer", true, true).isMatch(entry));
+ assertTrue(new SearchQuery("asdf", true, true).isMatch(entry));
+ assertTrue(new SearchQuery("author=asdf", true, true).isMatch(entry));
+ }
+
+ @Test
+ public void testIsValidQueryNotAsRegEx() {
+ assertTrue(new SearchQuery("asdf", true, false).isValid());
+ }
+
+ @Test
+ public void testIsValidQueryContainsBracketNotAsRegEx() {
+ assertTrue(new SearchQuery("asdf[", true, false).isValid());
+ }
+
+ @Test
+ public void testIsNotValidQueryContainsBracketNotAsRegEx() {
+ assertTrue(new SearchQuery("asdf[", true, true).isValid());
+ }
+
+ @Test
+ public void testIsValidQueryAsRegEx() {
+ assertTrue(new SearchQuery("asdf", true, true).isValid());
+ }
+
+ @Test
+ public void testIsValidQueryWithNumbersAsRegEx() {
+ assertTrue(new SearchQuery("123", true, true).isValid());
+ }
+
+ @Test
+ public void testIsValidQueryContainsBracketAsRegEx() {
+ assertTrue(new SearchQuery("asdf[", true, true).isValid());
+ }
+
+ @Test
+ public void testIsValidQueryWithEqualSignAsRegEx() {
+ assertTrue(new SearchQuery("author=asdf", true, true).isValid());
+ }
+
+ @Test
+ public void testIsValidQueryWithNumbersAndEqualSignAsRegEx() {
+ assertTrue(new SearchQuery("author=123", true, true).isValid());
+ }
+
+ @Test
+ public void testIsValidQueryWithEqualSignNotAsRegEx() {
+ assertTrue(new SearchQuery("author=asdf", true, false).isValid());
+ }
+
+ @Test
+ public void testIsValidQueryWithNumbersAndEqualSignNotAsRegEx() {
+ assertTrue(new SearchQuery("author=123", true, false).isValid());
+ }
+
+ @Test
+ public void isMatchedForNormalAndFieldBasedSearchMixed() {
+ BibEntry entry = new BibEntry();
+ entry.setType(BibtexEntryTypes.ARTICLE);
+ entry.setField("author", "asdf");
+ entry.setField("abstract", "text");
+
+ assertTrue(new SearchQuery("text AND author=asdf", true, true).isMatch(entry));
+
+ }
+
}
diff --git a/src/test/java/net/sf/jabref/logic/search/matchers/MatcherSetsTest.java b/src/test/java/net/sf/jabref/logic/search/matchers/MatcherSetsTest.java
deleted file mode 100644
index 38ef520..0000000
--- a/src/test/java/net/sf/jabref/logic/search/matchers/MatcherSetsTest.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package net.sf.jabref.logic.search.matchers;
-
-import net.sf.jabref.logic.search.rules.MockSearchMatcher;
-import net.sf.jabref.model.entry.BibEntry;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-
-public class MatcherSetsTest {
-
- @Test
- public void testBuildAnd() {
- MatcherSet matcherSet = MatcherSets.build(MatcherSets.MatcherType.AND);
- assertTrue(matcherSet.isMatch(new BibEntry()));
-
- matcherSet.addRule(new MockSearchMatcher(true));
- assertTrue(matcherSet.isMatch(new BibEntry()));
-
- matcherSet.addRule(new MockSearchMatcher(false));
- assertFalse(matcherSet.isMatch(new BibEntry()));
- }
-
- @Test
- public void testBuildOr() {
- MatcherSet matcherSet = MatcherSets.build(MatcherSets.MatcherType.OR);
- assertFalse(matcherSet.isMatch(new BibEntry()));
-
- matcherSet.addRule(new MockSearchMatcher(true));
- assertTrue(matcherSet.isMatch(new BibEntry()));
-
- matcherSet.addRule(new MockSearchMatcher(false));
- assertTrue(matcherSet.isMatch(new BibEntry()));
- }
-
- @Test
- public void testBuildNotWithTrue() {
- NotMatcher matcher = new NotMatcher(new MockSearchMatcher(true));
- assertFalse(matcher.isMatch(new BibEntry()));
- }
-
- @Test
- public void testBuildNotWithFalse() {
- NotMatcher matcher = new NotMatcher(new MockSearchMatcher(false));
- assertTrue(matcher.isMatch(new BibEntry()));
- }
-
-}
diff --git a/src/test/java/net/sf/jabref/logic/search/rules/ContainBasedSearchRuleTest.java b/src/test/java/net/sf/jabref/logic/search/rules/ContainBasedSearchRuleTest.java
deleted file mode 100644
index 49063d4..0000000
--- a/src/test/java/net/sf/jabref/logic/search/rules/ContainBasedSearchRuleTest.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package net.sf.jabref.logic.search.rules;
-
-import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.model.entry.BibtexEntryTypes;
-import net.sf.jabref.model.entry.IdGenerator;
-
-import org.junit.Assert;
-import org.junit.Test;
-
-/**
- * Test case for ContainBasedSearchRule.
- */
-public class ContainBasedSearchRuleTest {
-
- @Test
- public void testBasicSearchParsing() {
- BibEntry be = makeBibtexEntry();
- ContainBasedSearchRule bsCaseSensitive = new ContainBasedSearchRule(true);
- ContainBasedSearchRule bsCaseInsensitive = new ContainBasedSearchRule(false);
- RegexBasedSearchRule bsCaseSensitiveRegexp = new RegexBasedSearchRule(true);
- RegexBasedSearchRule bsCaseInsensitiveRegexp = new RegexBasedSearchRule(false);
-
- String query = "marine 2001 shields";
-
- Assert.assertEquals(false, bsCaseSensitive.applyRule(query, be));
- Assert.assertEquals(true, bsCaseInsensitive.applyRule(query, be));
- Assert.assertEquals(false, bsCaseSensitiveRegexp.applyRule(query, be));
- Assert.assertEquals(false, bsCaseInsensitiveRegexp.applyRule(query, be));
-
- query = "\"marine larviculture\"";
-
- Assert.assertEquals(false, bsCaseSensitive.applyRule(query, be));
- Assert.assertEquals(false, bsCaseInsensitive.applyRule(query, be));
- Assert.assertEquals(false, bsCaseSensitiveRegexp.applyRule(query, be));
- Assert.assertEquals(false, bsCaseInsensitiveRegexp.applyRule(query, be));
-
- query = "marine [A-Za-z]* larviculture";
-
- Assert.assertEquals(false, bsCaseSensitive.applyRule(query, be));
- Assert.assertEquals(false, bsCaseInsensitive.applyRule(query, be));
- Assert.assertEquals(false, bsCaseSensitiveRegexp.applyRule(query, be));
- Assert.assertEquals(true, bsCaseInsensitiveRegexp.applyRule(query, be));
-
- }
-
- public BibEntry makeBibtexEntry() {
- BibEntry e = new BibEntry(IdGenerator.next(), BibtexEntryTypes.INCOLLECTION.getName());
- e.setField("title", "Marine finfish larviculture in Europe");
- e.setField("bibtexkey", "shields01");
- e.setField("year", "2001");
- e.setField("author", "Kevin Shields");
- return e;
- }
-}
diff --git a/src/test/java/net/sf/jabref/logic/search/rules/MockSearchMatcher.java b/src/test/java/net/sf/jabref/logic/search/rules/MockSearchMatcher.java
deleted file mode 100644
index 777523a..0000000
--- a/src/test/java/net/sf/jabref/logic/search/rules/MockSearchMatcher.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package net.sf.jabref.logic.search.rules;
-
-import net.sf.jabref.logic.search.SearchMatcher;
-import net.sf.jabref.model.entry.BibEntry;
-
-/**
- * Mock search rule that returns the values passed. Useful for testing.
- */
-public class MockSearchMatcher implements SearchMatcher {
-
- private final boolean result;
-
- public MockSearchMatcher(boolean result) {
- this.result = result;
- }
-
- @Override
- public boolean isMatch(BibEntry entry) {
- return result;
- }
-}
diff --git a/src/test/java/net/sf/jabref/logic/search/rules/SentenceAnalyzerTest.java b/src/test/java/net/sf/jabref/logic/search/rules/SentenceAnalyzerTest.java
deleted file mode 100644
index 4ce3ed8..0000000
--- a/src/test/java/net/sf/jabref/logic/search/rules/SentenceAnalyzerTest.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package net.sf.jabref.logic.search.rules;
-
-import java.util.Arrays;
-import java.util.Collections;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-
-public class SentenceAnalyzerTest {
-
- @Test
- public void testGetWords() {
- assertEquals(Arrays.asList("a","b"), new SentenceAnalyzer("a b").getWords());
- assertEquals(Arrays.asList("a","b"), new SentenceAnalyzer(" a b ").getWords());
- assertEquals(Collections.singletonList("b "), new SentenceAnalyzer("\"b \" ").getWords());
- assertEquals(Collections.singletonList(" a"), new SentenceAnalyzer(" \\ a").getWords());
- }
-
-}
\ No newline at end of file
diff --git a/src/test/java/net/sf/jabref/logic/specialfields/SpecialFieldsUtilsTest.java b/src/test/java/net/sf/jabref/logic/specialfields/SpecialFieldsUtilsTest.java
new file mode 100644
index 0000000..c42b8d6
--- /dev/null
+++ b/src/test/java/net/sf/jabref/logic/specialfields/SpecialFieldsUtilsTest.java
@@ -0,0 +1,72 @@
+package net.sf.jabref.logic.specialfields;
+
+import java.util.List;
+import java.util.Optional;
+
+import net.sf.jabref.model.FieldChange;
+import net.sf.jabref.model.entry.BibEntry;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+
+public class SpecialFieldsUtilsTest {
+
+ @Test
+ public void syncKeywordsFromSpecialFieldsWritesToKeywords() {
+ BibEntry entry = new BibEntry();
+ entry.setField("ranking", "rank2");
+ SpecialFieldsUtils.syncKeywordsFromSpecialFields(entry, true, ',');
+ assertEquals(Optional.of("rank2"), entry.getField("keywords"));
+ }
+
+ @Test
+ public void syncKeywordsFromSpecialFieldsCausesChange() {
+ BibEntry entry = new BibEntry();
+ entry.setField("ranking", "rank2");
+ List<FieldChange> changes = SpecialFieldsUtils.syncKeywordsFromSpecialFields(entry, true, ',');
+ assertTrue(changes.size() > 0);
+ }
+
+ @Test
+ public void syncKeywordsFromSpecialFieldsOverwritesKeywords() {
+ BibEntry entry = new BibEntry();
+ entry.setField("ranking", "rank2");
+ entry.setField("keywords", "rank3");
+ SpecialFieldsUtils.syncKeywordsFromSpecialFields(entry, true, ',');
+ assertEquals(Optional.of("rank2"), entry.getField("keywords"));
+ }
+
+ @Test
+ public void syncKeywordsFromSpecialFieldsForEmptyFieldCausesNoChange() {
+ BibEntry entry = new BibEntry();
+ List<FieldChange> changes = SpecialFieldsUtils.syncKeywordsFromSpecialFields(entry, true, ',');
+ assertFalse(changes.size() > 0);
+ }
+
+ @Test
+ public void syncSpecialFieldsFromKeywordWritesToSpecialField() {
+ BibEntry entry = new BibEntry();
+ entry.setField("keywords", "rank2");
+ SpecialFieldsUtils.syncSpecialFieldsFromKeywords(entry, ',');
+ assertEquals(Optional.of("rank2"), entry.getField("ranking"));
+ }
+
+ @Test
+ public void syncSpecialFieldsFromKeywordCausesChange() {
+ BibEntry entry = new BibEntry();
+ entry.setField("keywords", "rank2");
+ List<FieldChange> changes = SpecialFieldsUtils.syncSpecialFieldsFromKeywords(entry, ',');
+ assertTrue(changes.size() > 0);
+ }
+
+ @Test
+ public void syncSpecialFieldsFromKeywordCausesNoChangeWhenKeywordsAreEmpty() {
+ BibEntry entry = new BibEntry();
+ List<FieldChange> changes = SpecialFieldsUtils.syncSpecialFieldsFromKeywords(entry, ',');
+ assertFalse(changes.size() > 0);
+ }
+}
diff --git a/src/test/java/net/sf/jabref/logic/util/DevelopmentStageTest.java b/src/test/java/net/sf/jabref/logic/util/DevelopmentStageTest.java
new file mode 100644
index 0000000..c81679c
--- /dev/null
+++ b/src/test/java/net/sf/jabref/logic/util/DevelopmentStageTest.java
@@ -0,0 +1,37 @@
+package net.sf.jabref.logic.util;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class DevelopmentStageTest {
+
+ @Test
+ public void checkStabilityOrder() {
+ assertTrue(Version.DevelopmentStage.ALPHA.isMoreStableThan(Version.DevelopmentStage.UNKNOWN));
+ assertTrue(Version.DevelopmentStage.BETA.isMoreStableThan(Version.DevelopmentStage.ALPHA));
+ assertTrue(Version.DevelopmentStage.STABLE.isMoreStableThan(Version.DevelopmentStage.BETA));
+
+ assertEquals("It seems that the development stages have been changed, please adjust the test",
+ Version.DevelopmentStage.values().length, 4);
+ }
+
+ @Test
+ public void parseStages() {
+ assertEquals(Version.DevelopmentStage.parse("-alpha"), Version.DevelopmentStage.ALPHA);
+ assertEquals(Version.DevelopmentStage.parse("-beta"), Version.DevelopmentStage.BETA);
+ assertEquals(Version.DevelopmentStage.parse(""), Version.DevelopmentStage.STABLE);
+ }
+
+ @Test
+ public void parseNull() {
+ assertEquals(Version.DevelopmentStage.parse(null), Version.DevelopmentStage.UNKNOWN);
+ }
+
+ @Test
+ public void parseUnknownString() {
+ assertEquals(Version.DevelopmentStage.parse("asdf"), Version.DevelopmentStage.UNKNOWN);
+ }
+
+}
diff --git a/src/test/java/net/sf/jabref/logic/util/UpdateFieldTest.java b/src/test/java/net/sf/jabref/logic/util/UpdateFieldTest.java
index abe04bc..1c0b095 100644
--- a/src/test/java/net/sf/jabref/logic/util/UpdateFieldTest.java
+++ b/src/test/java/net/sf/jabref/logic/util/UpdateFieldTest.java
@@ -29,14 +29,14 @@ public class UpdateFieldTest {
public void testUpdateFieldWorksEmptyField() {
assertFalse(entry.hasField("year"));
UpdateField.updateField(entry, "year", "2016");
- assertEquals(Optional.of("2016"), entry.getFieldOptional("year"));
+ assertEquals(Optional.of("2016"), entry.getField("year"));
}
@Test
public void testUpdateFieldWorksNonEmptyField() {
entry.setField("year", "2015");
UpdateField.updateField(entry, "year", "2016");
- assertEquals(Optional.of("2016"), entry.getFieldOptional("year"));
+ assertEquals(Optional.of("2016"), entry.getField("year"));
}
@Test
@@ -159,7 +159,7 @@ public class UpdateFieldTest {
assertFalse(entry.hasField("year"));
UpdateField.updateNonDisplayableField(entry, "year", "2016");
assertTrue(entry.hasField("year"));
- assertEquals(Optional.of("2016"), entry.getFieldOptional("year"));
+ assertEquals(Optional.of("2016"), entry.getField("year"));
}
@Test
diff --git a/src/test/java/net/sf/jabref/logic/util/VersionTest.java b/src/test/java/net/sf/jabref/logic/util/VersionTest.java
new file mode 100644
index 0000000..6f80905
--- /dev/null
+++ b/src/test/java/net/sf/jabref/logic/util/VersionTest.java
@@ -0,0 +1,280 @@
+package net.sf.jabref.logic.util;
+
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class VersionTest {
+
+ @Test
+ public void unknownVersionAsString() {
+ Version version = Version.parse(BuildInfo.UNKNOWN_VERSION);
+ assertEquals(BuildInfo.UNKNOWN_VERSION, version.getFullVersion());
+ }
+
+ @Test
+ public void unknownVersionAsNull() {
+ Version version = Version.parse(null);
+ assertEquals(BuildInfo.UNKNOWN_VERSION, version.getFullVersion());
+ }
+
+ @Test
+ public void unknownVersionAsEmptyString() {
+ Version version = Version.parse("");
+ assertEquals(BuildInfo.UNKNOWN_VERSION, version.getFullVersion());
+ }
+
+ @Test
+ public void initVersionFromWrongStringResultsInUnknownVersion() {
+ Version version = Version.parse("${version}");
+ assertEquals(BuildInfo.UNKNOWN_VERSION, version.getFullVersion());
+ }
+
+ @Test
+ public void versionOneDigit() {
+ String versionText = "1";
+ Version version = Version.parse(versionText);
+ assertEquals(versionText, version.getFullVersion());
+ assertEquals(1, version.getMajor());
+ assertEquals(0, version.getMinor());
+ assertEquals(0, version.getPatch());
+ assertFalse(version.isDevelopmentVersion());
+ }
+
+ @Test
+ public void versionTwoDigits() {
+ String versionText = "1.2";
+ Version version = Version.parse(versionText);
+ assertEquals(versionText, version.getFullVersion());
+ assertEquals(1, version.getMajor());
+ assertEquals(2, version.getMinor());
+ assertEquals(0, version.getPatch());
+ assertFalse(version.isDevelopmentVersion());
+ }
+
+ @Test
+ public void versionThreeDigits() {
+ String versionText = "1.2.3";
+ Version version = Version.parse(versionText);
+ assertEquals(versionText, version.getFullVersion());
+ assertEquals(1, version.getMajor());
+ assertEquals(2, version.getMinor());
+ assertEquals(3, version.getPatch());
+ assertFalse(version.isDevelopmentVersion());
+ }
+
+ @Test
+ public void versionOneDigitDevVersion() {
+ String versionText = "1dev";
+ Version version = Version.parse(versionText);
+ assertEquals(versionText, version.getFullVersion());
+ assertEquals(1, version.getMajor());
+ assertEquals(0, version.getMinor());
+ assertEquals(0, version.getPatch());
+ assertTrue(version.isDevelopmentVersion());
+ }
+
+ @Test
+ public void versionTwoDigitDevVersion() {
+ String versionText = "1.2dev";
+ Version version = Version.parse(versionText);
+ assertEquals(versionText, version.getFullVersion());
+ assertEquals(1, version.getMajor());
+ assertEquals(2, version.getMinor());
+ assertEquals(0, version.getPatch());
+ assertTrue(version.isDevelopmentVersion());
+ }
+
+ @Test
+ public void versionThreeDigitDevVersion() {
+ String versionText = "1.2.3dev";
+ Version version = Version.parse(versionText);
+ assertEquals(versionText, version.getFullVersion());
+ assertEquals(1, version.getMajor());
+ assertEquals(2, version.getMinor());
+ assertEquals(3, version.getPatch());
+ assertTrue(version.isDevelopmentVersion());
+ }
+
+ @Test
+ public void validVersionIsNotNewerThanUnknownVersion() {
+ // Reason: unknown version should only happen for developer builds where we don't want an update notification
+ Version unknownVersion = Version.parse(BuildInfo.UNKNOWN_VERSION);
+ Version validVersion = Version.parse("4.2");
+ assertFalse(validVersion.isNewerThan(unknownVersion));
+ }
+
+ @Test
+ public void unknownVersionIsNotNewerThanValidVersion() {
+ Version unknownVersion = Version.parse(BuildInfo.UNKNOWN_VERSION);
+ Version validVersion = Version.parse("4.2");
+ assertFalse(unknownVersion.isNewerThan(validVersion));
+ }
+
+ @Test
+ public void versionNewerThan() {
+ Version olderVersion = Version.parse("2.4");
+ Version newerVersion = Version.parse("4.2");
+ assertTrue(newerVersion.isNewerThan(olderVersion));
+ }
+
+ @Test
+ public void versionNotNewerThan() {
+ Version olderVersion = Version.parse("2.4");
+ Version newerVersion = Version.parse("4.2");
+ assertFalse(olderVersion.isNewerThan(newerVersion));
+ }
+
+ @Test
+ public void versionNotNewerThanSameVersion() {
+ Version version1 = Version.parse("4.2");
+ Version version2 = Version.parse("4.2");
+ assertFalse(version1.isNewerThan(version2));
+ }
+
+ @Test
+ public void versionNewerThanDevTwoDigits() {
+ Version older = Version.parse("4.2");
+ Version newer = Version.parse("4.3dev");
+ assertTrue(newer.isNewerThan(older));
+ }
+
+ @Test
+ public void versionNewerThanDevVersion() {
+ Version older = Version.parse("1.2dev");
+ Version newer = Version.parse("1.2");
+ assertTrue(newer.isNewerThan(older));
+ assertFalse(older.isNewerThan(newer));
+ }
+
+ @Test
+ public void versionNewerThanDevThreeDigits() {
+ Version older = Version.parse("4.2.1");
+ Version newer = Version.parse("4.3dev");
+ assertTrue(newer.isNewerThan(older));
+ }
+
+ @Test
+ public void versionNewerMinor() {
+ Version older = Version.parse("4.1");
+ Version newer = Version.parse("4.2.1");
+ assertTrue(newer.isNewerThan(older));
+ }
+
+ @Test
+ public void versionNotNewerMinor() {
+ Version older = Version.parse("4.1");
+ Version newer = Version.parse("4.2.1");
+ assertFalse(older.isNewerThan(newer));
+ }
+
+ @Test
+ public void versionNewerPatch() {
+ Version older = Version.parse("4.2.1");
+ Version newer = Version.parse("4.2.2");
+ assertTrue(newer.isNewerThan(older));
+ }
+
+ @Test
+ public void versionNotNewerPatch() {
+ Version older = Version.parse("4.2.1");
+ Version newer = Version.parse("4.2.2");
+ assertFalse(older.isNewerThan(newer));
+ }
+
+ @Test
+ public void equalVersionsNotNewer() {
+ Version version1 = Version.parse("4.2.2");
+ Version version2 = Version.parse("4.2.2");
+ assertFalse(version1.isNewerThan(version2));
+ }
+
+ @Test
+ public void changelogOfDevelopmentVersionWithDash() {
+ Version version = Version.parse("4.0-dev");
+ assertEquals("https://github.com/JabRef/jabref/blob/master/CHANGELOG.md#unreleased", version.getChangelogUrl());
+ }
+
+ @Test
+ public void changelogOfDevelopmentVersionWithoutDash() {
+ Version version = Version.parse("3.7dev");
+ assertEquals("https://github.com/JabRef/jabref/blob/master/CHANGELOG.md#unreleased", version.getChangelogUrl());
+ }
+
+ @Test
+ public void changelogWithTwoDigits() {
+ Version version = Version.parse("3.4");
+ assertEquals("https://github.com/JabRef/jabref/blob/v3.4/CHANGELOG.md", version.getChangelogUrl());
+ }
+
+ @Test
+ public void changelogWithThreeDigits() {
+ Version version = Version.parse("3.4.1");
+ assertEquals("https://github.com/JabRef/jabref/blob/v3.4.1/CHANGELOG.md", version.getChangelogUrl());
+ }
+
+ @Test
+ public void versionNull() {
+ String versionText = null;
+ Version version = Version.parse(versionText);
+ assertEquals(BuildInfo.UNKNOWN_VERSION, version.getFullVersion());
+ }
+
+ @Test
+ public void versionEmpty() {
+ String versionText = "";
+ Version version = Version.parse(versionText);
+ assertEquals(BuildInfo.UNKNOWN_VERSION, version.getFullVersion());
+ }
+
+ @Test
+ public void betaNewerThanAlpha() {
+ Version older = Version.parse("2.7-alpha");
+ Version newer = Version.parse("2.7-beta");
+ assertTrue(newer.isNewerThan(older));
+ }
+
+ @Test
+ public void stableNewerThanBeta() {
+ Version older = Version.parse("2.8-alpha");
+ Version newer = Version.parse("2.8");
+ assertTrue(newer.isNewerThan(older));
+ }
+
+ @Test
+ public void alphaShouldBeUpdatedToBeta() {
+ Version alpha = Version.parse("2.8-alpha");
+ Version beta = Version.parse("2.8-beta");
+ assertTrue(alpha.shouldBeUpdatedTo(beta));
+ }
+
+ @Test
+ public void betaShouldBeUpdatedToStable() {
+ Version beta = Version.parse("2.8-beta");
+ Version stable = Version.parse("2.8");
+ assertTrue(beta.shouldBeUpdatedTo(stable));
+ }
+
+ @Test
+ public void stableShouldNotBeUpdatedToAlpha() {
+ Version stable = Version.parse("2.8");
+ Version alpha = Version.parse("2.9-alpha");
+ assertFalse(stable.shouldBeUpdatedTo(alpha));
+ }
+
+ @Test
+ public void alphaShouldBeUpdatedToStables() {
+ Version alpha = Version.parse("2.8-alpha");
+ Version stable = Version.parse("2.8");
+ List<Version> availableVersions = Arrays.asList(Version.parse("2.8-beta"), stable);
+ assertEquals(Optional.of(stable), alpha.shouldBeUpdatedTo(availableVersions));
+ }
+
+}
diff --git a/src/test/java/net/sf/jabref/logic/util/io/FileHistoryTest.java b/src/test/java/net/sf/jabref/logic/util/io/FileHistoryTest.java
index 2311bf0..a94f4a2 100644
--- a/src/test/java/net/sf/jabref/logic/util/io/FileHistoryTest.java
+++ b/src/test/java/net/sf/jabref/logic/util/io/FileHistoryTest.java
@@ -19,12 +19,12 @@ public class FileHistoryTest {
@Before
public void setUp() {
prefs = JabRefPreferences.getInstance();
- oldFileNames = prefs.getStringList(JabRefPreferences.RECENT_FILES);
+ oldFileNames = prefs.getStringList(JabRefPreferences.RECENT_DATABASES);
}
@After
public void restore() {
- prefs.putStringList(JabRefPreferences.RECENT_FILES, oldFileNames);
+ prefs.putStringList(JabRefPreferences.RECENT_DATABASES, oldFileNames);
}
@Test
@@ -65,7 +65,7 @@ public class FileHistoryTest {
fh.removeItem("aa");
prefs.storeFileHistory(fh);
assertArrayEquals(new String[] {"ii", "hh", "gg"},
- prefs.getStringList(JabRefPreferences.RECENT_FILES).toArray(new String[0]));
+ prefs.getStringList(JabRefPreferences.RECENT_DATABASES).toArray(new String[0]));
}
}
diff --git a/src/test/java/net/sf/jabref/logic/util/io/FileUtilTest.java b/src/test/java/net/sf/jabref/logic/util/io/FileUtilTest.java
index 9f4242d..2e210c3 100644
--- a/src/test/java/net/sf/jabref/logic/util/io/FileUtilTest.java
+++ b/src/test/java/net/sf/jabref/logic/util/io/FileUtilTest.java
@@ -1,22 +1,59 @@
package net.sf.jabref.logic.util.io;
import java.io.File;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
import java.util.Arrays;
import java.util.List;
+import java.util.Optional;
import net.sf.jabref.logic.journals.JournalAbbreviationLoader;
import net.sf.jabref.logic.layout.LayoutFormatterPreferences;
import net.sf.jabref.model.entry.BibEntry;
import net.sf.jabref.preferences.JabRefPreferences;
+import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
public class FileUtilTest {
+ @Rule
+ public TemporaryFolder temporaryFolder = new TemporaryFolder();
+ public TemporaryFolder otherTemporaryFolder = new TemporaryFolder();
+
+ private final Path nonExistingTestPath = Paths.get("nonExistingTestPath");
+ private Path existingTestFile;
+ private Path otherExistingTestFile;
+
+ @Before
+ public void setUpViewModel() throws IOException {
+ existingTestFile = createTemporaryTestFile("existingTestFile.txt");
+ otherExistingTestFile = createTemporaryTestFile("otherExistingTestFile.txt");
+ otherTemporaryFolder.create();
+ }
+
+ @Test
+ public void extensionBakAddedCorrectly() {
+ assertEquals(Paths.get("demo.bib.bak"),
+ FileUtil.addExtension(Paths.get("demo.bib"), ".bak"));
+ }
+
+ @Test
+ public void extensionBakAddedCorrectlyToAFileContainedInTmpDirectory() {
+ assertEquals(Paths.get("tmp", "demo.bib.bak"),
+ FileUtil.addExtension(Paths.get("tmp", "demo.bib"), ".bak"));
+ }
@Test
public void testGetLinkedFileNameDefault() {
@@ -27,8 +64,8 @@ public class FileUtilTest {
entry.setField("title", "mytitle");
assertEquals("1234 - mytitle",
- FileUtil.createFileNameFromPattern(null, entry, fileNamePattern, LayoutFormatterPreferences
- .fromPreferences(JabRefPreferences.getInstance(), mock(JournalAbbreviationLoader.class))));
+ FileUtil.createFileNameFromPattern(null, entry, fileNamePattern, JabRefPreferences.getInstance()
+ .getLayoutFormatterPreferences(mock(JournalAbbreviationLoader.class))));
}
@Test
@@ -45,6 +82,48 @@ public class FileUtilTest {
}
@Test
+ public void testGetLinkedFileNameNoPattern() {
+ String fileNamePattern = "";
+ BibEntry entry = new BibEntry();
+ entry.setCiteKey("1234");
+ entry.setField("title", "mytitle");
+
+ assertEquals("1234", FileUtil.createFileNameFromPattern(null, entry, fileNamePattern,
+ mock(LayoutFormatterPreferences.class)));
+ }
+
+ @Test
+ public void testGetDefaultFileNameNoPatternNoBibTeXKey() {
+ String fileNamePattern = "";
+ BibEntry entry = new BibEntry();
+ entry.setField("title", "mytitle");
+
+ assertEquals("default", FileUtil.createFileNameFromPattern(null, entry, fileNamePattern,
+ mock(LayoutFormatterPreferences.class)));
+ }
+
+ @Test
+ public void testGetLinkedFileNameGetKeyIfEmptyField() {
+ // bibkey - title
+ String fileNamePattern = "\\begin{title} - \\format[RemoveBrackets]{\\title}\\end{title}";
+ BibEntry entry = new BibEntry();
+ entry.setCiteKey("1234");
+
+ assertEquals("1234", FileUtil.createFileNameFromPattern(null, entry, fileNamePattern,
+ JabRefPreferences.getInstance().getLayoutFormatterPreferences(mock(JournalAbbreviationLoader.class))));
+ }
+
+ @Test
+ public void testGetLinkedFileNameGetDefaultIfEmptyFieldNoKey() {
+ // bibkey - title
+ String fileNamePattern = "\\begin{title} - \\format[RemoveBrackets]{\\title}\\end{title}";
+ BibEntry entry = new BibEntry();
+
+ assertEquals("default", FileUtil.createFileNameFromPattern(null, entry, fileNamePattern,
+ JabRefPreferences.getInstance().getLayoutFormatterPreferences(mock(JournalAbbreviationLoader.class))));
+ }
+
+ @Test
public void testGetFileExtensionSimpleFile() {
assertEquals("pdf", FileUtil.getFileExtension(new File("test.pdf")).get());
}
@@ -70,28 +149,38 @@ public class FileUtilTest {
}
@Test
- public void testGetFileExtensionSimpleString() {
+ public void getFileExtensionWithSimpleString() {
assertEquals("pdf", FileUtil.getFileExtension("test.pdf").get());
}
@Test
- public void testGetFileExtensionLowerCaseAndTrimmingString() {
+ public void getFileExtensionTrimsAndReturnsInLowercase() {
assertEquals("pdf", FileUtil.getFileExtension("test.PdF ").get());
}
@Test
- public void testGetFileExtensionMultipleDotsString() {
+ public void getFileExtensionWithMultipleDotsString() {
assertEquals("pdf", FileUtil.getFileExtension("te.st.PdF ").get());
}
@Test
- public void testGetFileExtensionNoExtensionString() {
- assertFalse(FileUtil.getFileExtension("JustTextNotASingleDot").isPresent());
+ public void getFileExtensionWithNoDotReturnsEmptyExtension() {
+ assertEquals(Optional.empty(), FileUtil.getFileExtension("JustTextNotASingleDot"));
+ }
+
+ @Test
+ public void getFileExtensionWithDotAtStartReturnsEmptyExtension() {
+ assertEquals(Optional.empty(), FileUtil.getFileExtension(".StartsWithADotIsNotAnExtension"));
+ }
+
+ @Test
+ public void getFileNameWithSimpleString() {
+ assertEquals("test", FileUtil.getFileName("test.pdf"));
}
@Test
- public void testGetFileExtensionNoExtension2String() {
- assertFalse(FileUtil.getFileExtension(".StartsWithADotIsNotAnExtension").isPresent());
+ public void getFileNameWithMultipleDotsString() {
+ assertEquals("te.st", FileUtil.getFileName("te.st.PdF "));
}
@Test
@@ -109,4 +198,112 @@ public class FileUtilTest {
assertEquals(uniqPath, result);
}
+ @Test
+ public void testCopyFileFromEmptySourcePathToEmptyDestinationPathWithOverrideExistFile(){
+ assertFalse(FileUtil.copyFile(nonExistingTestPath, nonExistingTestPath, true));
+ }
+
+ @Test
+ public void testCopyFileFromEmptySourcePathToEmptyDestinationPathWithoutOverrideExistFile(){
+ assertFalse(FileUtil.copyFile(nonExistingTestPath, nonExistingTestPath, false));
+ }
+
+ @Test
+ public void testCopyFileFromEmptySourcePathToExistDestinationPathWithOverrideExistFile(){
+ assertFalse(FileUtil.copyFile(nonExistingTestPath, existingTestFile, true));
+ }
+
+ @Test
+ public void testCopyFileFromEmptySourcePathToExistDestinationPathWithoutOverrideExistFile(){
+ assertFalse(FileUtil.copyFile(nonExistingTestPath, existingTestFile, false));
+ }
+
+ @Test
+ public void testCopyFileFromExistSourcePathToExistDestinationPathWithOverrideExistFile(){
+ assertTrue(FileUtil.copyFile(existingTestFile, existingTestFile, true));
+ }
+
+ @Test
+ public void testCopyFileFromExistSourcePathToExistDestinationPathWithoutOverrideExistFile(){
+ assertFalse(FileUtil.copyFile(existingTestFile, existingTestFile, false));
+ }
+
+ @Test
+ public void testCopyFileFromExistSourcePathToOtherExistDestinationPathWithOverrideExistFile(){
+ assertTrue(FileUtil.copyFile(existingTestFile, otherExistingTestFile, true));
+ }
+
+ @Test
+ public void testCopyFileFromExistSourcePathToOtherExistDestinationPathWithoutOverrideExistFile(){
+ assertFalse(FileUtil.copyFile(existingTestFile, otherExistingTestFile, false));
+ }
+
+ @Test
+ public void testCopyFileSuccessfulWithOverrideExistFile() throws IOException {
+ Path temp = otherTemporaryFolder.newFile("existingTestFile.txt").toPath();
+ FileUtil.copyFile(existingTestFile, temp, true);
+ assertEquals(Files.readAllLines(existingTestFile, StandardCharsets.UTF_8),Files.readAllLines(temp, StandardCharsets.UTF_8));
+ }
+
+ @Test
+ public void testCopyFileSuccessfulWithoutOverrideExistFile() throws IOException {
+ Path temp = otherTemporaryFolder.newFile("existingTestFile.txt").toPath();
+ FileUtil.copyFile(existingTestFile, temp, false);
+ assertNotEquals(Files.readAllLines(existingTestFile, StandardCharsets.UTF_8),Files.readAllLines(temp, StandardCharsets.UTF_8));
+ }
+
+ @Test (expected = NullPointerException.class)
+ public void testRenameFileWithFromFileIsNullAndToFileIsNull() {
+ FileUtil.renameFile(null, null);
+ }
+
+ @Test (expected = NullPointerException.class)
+ public void testRenameFileWithFromFileExistAndToFileIsNull() {
+ FileUtil.renameFile(existingTestFile, null);
+ }
+
+ @Test (expected = NullPointerException.class)
+ public void testRenameFileWithFromFileIsNullAndToFileExist() {
+ FileUtil.renameFile(null, existingTestFile);
+ }
+
+ @Test
+ public void testRenameFileWithFromFileNotExistAndToFileNotExist(){
+ assertFalse(FileUtil.renameFile(nonExistingTestPath, nonExistingTestPath));
+ }
+
+ @Test
+ public void testRenameFileWithFromFileNotExistAndToFileExist(){
+ assertFalse(FileUtil.renameFile(nonExistingTestPath, existingTestFile));
+ }
+
+ @Test
+ public void testRenameFileWithFromFileExistAndToFileNotExist(){
+ assertTrue(FileUtil.renameFile(existingTestFile, nonExistingTestPath));
+ }
+
+ @Test
+ public void testRenameFileWithFromFileExistAndToFileExist(){
+ assertTrue(FileUtil.renameFile(existingTestFile, existingTestFile));
+ }
+
+ @Test
+ public void testRenameFileWithFromFileExistAndOtherToFileExist(){
+ assertFalse(FileUtil.renameFile(existingTestFile, otherExistingTestFile));
+ }
+
+ @Test
+ public void testRenameFileSuccessful() {
+ Path temp = Paths.get(otherTemporaryFolder.toString());
+
+ System.out.println(temp);
+ FileUtil.renameFile(existingTestFile, temp);
+ assertFalse(Files.exists(existingTestFile));
+ }
+
+ private Path createTemporaryTestFile(String name) throws IOException {
+ File testFile = temporaryFolder.newFile(name);
+ Files.write(testFile.toPath(), name.getBytes(StandardCharsets.UTF_8), StandardOpenOption.APPEND);
+ return testFile.toPath();
+ }
}
diff --git a/src/test/java/net/sf/jabref/logic/util/io/RegExpFileSearchTests.java b/src/test/java/net/sf/jabref/logic/util/io/RegExpFileSearchTests.java
new file mode 100644
index 0000000..0e1da76
--- /dev/null
+++ b/src/test/java/net/sf/jabref/logic/util/io/RegExpFileSearchTests.java
@@ -0,0 +1,119 @@
+package net.sf.jabref.logic.util.io;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import net.sf.jabref.model.database.BibDatabase;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.BibtexEntryTypes;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class RegExpFileSearchTests {
+
+ private static final String filesDirectory = "src/test/resources/net/sf/jabref/imports/unlinkedFilesTestFolder";
+ private BibDatabase database;
+ private BibEntry entry;
+
+ @Before
+ public void setUp() {
+
+ entry = new BibEntry();
+ entry.setType(BibtexEntryTypes.ARTICLE);
+ entry.setCiteKey("HipKro03");
+ entry.setField("author", "Eric von Hippel and Georg von Krogh");
+ entry.setField("title", "Open Source Software and the \"Private-Collective\" Innovation Model: Issues for Organization Science");
+ entry.setField("journal", "Organization Science");
+ entry.setField("year", "2003");
+ entry.setField("volume", "14");
+ entry.setField("pages", "209--223");
+ entry.setField("number", "2");
+ entry.setField("address", "Institute for Operations Research and the Management Sciences (INFORMS), Linthicum, Maryland, USA");
+ entry.setField("doi", "http://dx.doi.org/10.1287/orsc.14.2.209.14992");
+ entry.setField("issn", "1526-5455");
+ entry.setField("publisher", "INFORMS");
+
+ database = new BibDatabase();
+ database.insertEntry(entry);
+ }
+
+ @Test
+ public void testFindFiles() {
+ //given
+ List<BibEntry> entries = new ArrayList<>();
+ BibEntry localEntry = new BibEntry("123", BibtexEntryTypes.ARTICLE.getName());
+ localEntry.setCiteKey("pdfInDatabase");
+ localEntry.setField("year", "2001");
+ entries.add(localEntry);
+
+ List<String> extensions = Arrays.asList("pdf");
+
+ List<File> dirs = Arrays.asList(new File(filesDirectory));
+
+ //when
+ Map<BibEntry, List<File>> result = RegExpFileSearch.findFilesForSet(entries, extensions, dirs,
+ "**/[bibtexkey].*\\\\.[extension]", ',');
+
+ //then
+ assertEquals(1, result.keySet().size());
+ }
+
+ @Test
+ public void testFieldAndFormat() {
+ assertEquals("Eric von Hippel and Georg von Krogh",
+ RegExpFileSearch.getFieldAndFormat("[author]", entry, database, ','));
+
+ assertEquals("Eric von Hippel and Georg von Krogh",
+ RegExpFileSearch.getFieldAndFormat("author", entry, database, ','));
+
+ assertEquals("", RegExpFileSearch.getFieldAndFormat("[unknownkey]", entry, database,
+ ','));
+
+ assertEquals("", RegExpFileSearch.getFieldAndFormat("[:]", entry, database, ','));
+
+ assertEquals("", RegExpFileSearch.getFieldAndFormat("[:lower]", entry, database,
+ ','));
+
+ assertEquals("eric von hippel and georg von krogh",
+ RegExpFileSearch.getFieldAndFormat("[author:lower]", entry, database,
+ ','));
+
+ assertEquals("HipKro03", RegExpFileSearch.getFieldAndFormat("[bibtexkey]", entry, database,
+ ','));
+
+ assertEquals("HipKro03", RegExpFileSearch.getFieldAndFormat("[bibtexkey:]", entry, database,
+ ','));
+ }
+
+ @Test
+ public void testExpandBrackets() {
+
+ assertEquals("", RegExpFileSearch.expandBrackets("", entry, database, ','));
+
+ assertEquals("dropped", RegExpFileSearch.expandBrackets("drop[unknownkey]ped", entry, database,
+ ','));
+
+ assertEquals("Eric von Hippel and Georg von Krogh",
+ RegExpFileSearch.expandBrackets("[author]", entry, database, ','));
+
+ assertEquals("Eric von Hippel and Georg von Krogh are two famous authors.",
+ RegExpFileSearch.expandBrackets("[author] are two famous authors.", entry, database,
+ ','));
+
+ assertEquals("Eric von Hippel and Georg von Krogh are two famous authors.",
+ RegExpFileSearch.expandBrackets("[author] are two famous authors.", entry, database,
+ ','));
+
+ assertEquals(
+ "Eric von Hippel and Georg von Krogh have published Open Source Software and the \"Private-Collective\" Innovation Model: Issues for Organization Science in Organization Science.",
+ RegExpFileSearch.expandBrackets("[author] have published [title] in [journal].", entry, database,
+ ','));
+ }
+
+}
diff --git a/src/test/java/net/sf/jabref/logic/util/strings/DiffHighlightingTest.java b/src/test/java/net/sf/jabref/logic/util/strings/DiffHighlightingTest.java
deleted file mode 100644
index 1ba9796..0000000
--- a/src/test/java/net/sf/jabref/logic/util/strings/DiffHighlightingTest.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package net.sf.jabref.logic.util.strings;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-
-
-public class DiffHighlightingTest {
-
- @Test
- public void testGenerateDiffHighlightingBothNullReturnsNull() {
- assertNull(DiffHighlighting.generateDiffHighlighting(null, null, ""));
- }
-
- @Test(expected = NullPointerException.class)
- public void testNullSeparatorThrowsNPE() {
- assertNull(DiffHighlighting.generateDiffHighlighting("", "", null));
- }
-
- @Test
- public void testGenerateDiffHighlightingNoDiff() {
- assertEquals("foo", DiffHighlighting.generateDiffHighlighting("foo", "foo", ""));
- }
-
- @Test
- public void testGenerateDiffHighlightingSingleWordAddTextWordDiff() {
- assertEquals("<span class=del>foo</span> <span class=add>foobar</span>",
- DiffHighlighting.generateDiffHighlighting("foo", "foobar", " "));
- }
-
- @Test
- public void testGenerateDiffHighlightingSingleWordAddTextCharacterDiff() {
- assertEquals("foo<span class=add>bar</span>", DiffHighlighting.generateDiffHighlighting("foo", "foobar", ""));
- }
-
- @Test
- public void testGenerateDiffHighlightingSingleWordDeleteTextWordDiff() {
- assertEquals("<span class=del>foobar</span> <span class=add>foo</span>",
- DiffHighlighting.generateDiffHighlighting("foobar", "foo", " "));
- }
-
- @Test
- public void testGenerateDiffHighlightingSingleWordDeleteTextCharacterDiff() {
- assertEquals("foo<span class=del>bar</span>", DiffHighlighting.generateDiffHighlighting("foobar", "foo", ""));
- }
-
- @Test
- public void generateSymmetricHighlightingSingleWordAddTextWordDiff() {
- assertEquals("<span class=change>foo</span>",
- DiffHighlighting.generateSymmetricHighlighting("foo", "foobar", " "));
- }
-
- @Test
- public void generateSymmetricHighlightingSingleWordAddTextCharacterDiff() {
- assertEquals("foo", DiffHighlighting.generateSymmetricHighlighting("foo", "foobar", ""));
- }
-
- @Test
- public void generateSymmetricHighlightingSingleWordDeleteTextWordDiff() {
- assertEquals("<span class=change>foobar</span>",
- DiffHighlighting.generateSymmetricHighlighting("foobar", "foo", " "));
- }
-
- @Test
- public void generateSymmetricHighlightingSingleWordDeleteTextCharacterDiff() {
- assertEquals("foo<span class=add>bar</span>", DiffHighlighting.generateSymmetricHighlighting("foobar", "foo", ""));
- }
-
- @Test
- public void generateSymmetricHighlightingMultipleWordsDeleteTextCharacterDiff() {
- assertEquals("foo<span class=add>bar</span> and <span class=add>some</span>thing",
- DiffHighlighting.generateSymmetricHighlighting("foobar and something", "foo and thing", ""));
- }
-
- @Test
- public void generateSymmetricHighlightingMultipleWordsDeleteTextWordDiff() {
- assertEquals("foo <span class=add>bar</span> and <span class=add>some</span> thing",
- DiffHighlighting.generateSymmetricHighlighting("foo bar and some thing", "foo and thing", " "));
- }
-}
diff --git a/src/test/java/net/sf/jabref/logic/util/strings/StringUtilTest.java b/src/test/java/net/sf/jabref/logic/util/strings/StringUtilTest.java
deleted file mode 100644
index 0865690..0000000
--- a/src/test/java/net/sf/jabref/logic/util/strings/StringUtilTest.java
+++ /dev/null
@@ -1,347 +0,0 @@
-package net.sf.jabref.logic.util.strings;
-
-import java.util.Optional;
-
-import net.sf.jabref.logic.util.OS;
-import net.sf.jabref.model.entry.FileField;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-public class StringUtilTest {
-
- private static final String[][] STRING_ARRAY_1 = {{"a", "b"}, {"c", "d"}};
- private static final String ENCODED_STRING_ARRAY_1 = "a:b;c:d";
- private static final String[][] STRING_ARRAY_2_WITH_NULL = {{"a", null}, {"c", "d"}};
- private static final String ENCODED_STRING_ARRAY_2_WITH_NULL = "a:" + null + ";c:d";
- private static final String[][] STRING_ARRAY_2 = {{"a", ""}, {"c", "d"}};
- private static final String ENCODED_STRING_ARRAY_2 = "a:;c:d";
- private static final String[][] STRING_ARRAY_3 = {{"a", ":b"}, {"c;", "d"}};
- private static final String ENCODED_STRING_ARRAY_3 = "a:\\:b;c\\;:d";
-
-
- @Test
- public void testUnifyLineBreaks() {
- // Mac < v9
- String result = StringUtil.unifyLineBreaksToConfiguredLineBreaks("\r");
- assertEquals(OS.NEWLINE, result);
- // Windows
- result = StringUtil.unifyLineBreaksToConfiguredLineBreaks("\r\n");
- assertEquals(OS.NEWLINE, result);
- // Unix
- result = StringUtil.unifyLineBreaksToConfiguredLineBreaks("\n");
- assertEquals(OS.NEWLINE, result);
- }
-
- @Test
- public void testGetCorrectFileName() {
- assertEquals("aa.bib", StringUtil.getCorrectFileName("aa", "bib"));
- assertEquals(".login.bib", StringUtil.getCorrectFileName(".login", "bib"));
- assertEquals("a.bib", StringUtil.getCorrectFileName("a.bib", "bib"));
- assertEquals("a.bib", StringUtil.getCorrectFileName("a.bib", "BIB"));
- assertEquals("a.bib", StringUtil.getCorrectFileName("a", "bib"));
- assertEquals("a.bb", StringUtil.getCorrectFileName("a.bb", "bib"));
- assertEquals("", StringUtil.getCorrectFileName(null, "bib"));
- }
-
- @Test
- public void testQuoteForHTML() {
- assertEquals("!", StringUtil.quoteForHTML("!"));
- assertEquals("!!!", StringUtil.quoteForHTML("!!!"));
- }
-
- @Test
- public void testRemoveBracesAroundCapitals() {
- assertEquals("ABC", StringUtil.removeBracesAroundCapitals("{ABC}"));
- assertEquals("ABC", StringUtil.removeBracesAroundCapitals("{{ABC}}"));
- assertEquals("{abc}", StringUtil.removeBracesAroundCapitals("{abc}"));
- assertEquals("ABCDEF", StringUtil.removeBracesAroundCapitals("{ABC}{DEF}"));
- }
-
- @Test
- public void testPutBracesAroundCapitals() {
- assertEquals("{ABC}", StringUtil.putBracesAroundCapitals("ABC"));
- assertEquals("{ABC}", StringUtil.putBracesAroundCapitals("{ABC}"));
- assertEquals("abc", StringUtil.putBracesAroundCapitals("abc"));
- assertEquals("#ABC#", StringUtil.putBracesAroundCapitals("#ABC#"));
- assertEquals("{ABC} def {EFG}", StringUtil.putBracesAroundCapitals("ABC def EFG"));
- }
-
- @Test
- public void testShaveString() {
-
- assertEquals("", StringUtil.shaveString(null));
- assertEquals("", StringUtil.shaveString(""));
- assertEquals("aaa", StringUtil.shaveString(" aaa\t\t\n\r"));
- assertEquals("a", StringUtil.shaveString(" {a} "));
- assertEquals("a", StringUtil.shaveString(" \"a\" "));
- assertEquals("{a}", StringUtil.shaveString(" {{a}} "));
- assertEquals("{a}", StringUtil.shaveString(" \"{a}\" "));
- assertEquals("\"{a\"}", StringUtil.shaveString(" \"{a\"} "));
- }
-
- @Test
- public void testJoin() {
- String[] s = "ab/cd/ed".split("/");
- assertEquals("ab\\cd\\ed", StringUtil.join(s, "\\", 0, s.length));
-
- assertEquals("cd\\ed", StringUtil.join(s, "\\", 1, s.length));
-
- assertEquals("ed", StringUtil.join(s, "\\", 2, s.length));
-
- assertEquals("", StringUtil.join(s, "\\", 3, s.length));
-
- assertEquals("", StringUtil.join(new String[] {}, "\\", 0, 0));
- }
-
- @Test
- public void testStripBrackets() {
- assertEquals("foo", StringUtil.stripBrackets("[foo]"));
- assertEquals("[foo]", StringUtil.stripBrackets("[[foo]]"));
- assertEquals("", StringUtil.stripBrackets(""));
- assertEquals("[foo", StringUtil.stripBrackets("[foo"));
- assertEquals("]", StringUtil.stripBrackets("]"));
- assertEquals("", StringUtil.stripBrackets("[]"));
- assertEquals("f[]f", StringUtil.stripBrackets("f[]f"));
- assertEquals(null, StringUtil.stripBrackets(null));
- }
-
- @Test
- public void testGetPart() {
- // Should be added
- }
-
- @Test
- public void testFindEncodingsForString() {
- // Unused in JabRef, but should be added in case it finds some use
- }
-
- @Test
- public void testWrap() {
- assertEquals("aaaaa" + OS.NEWLINE + "\tbbbbb" + OS.NEWLINE + "\tccccc",
- StringUtil.wrap("aaaaa bbbbb ccccc", 5));
- assertEquals("aaaaa bbbbb" + OS.NEWLINE + "\tccccc", StringUtil.wrap("aaaaa bbbbb ccccc", 8));
- assertEquals("aaaaa bbbbb" + OS.NEWLINE + "\tccccc", StringUtil.wrap("aaaaa bbbbb ccccc", 11));
- assertEquals("aaaaa bbbbb ccccc", StringUtil.wrap("aaaaa bbbbb ccccc", 12));
- assertEquals("aaaaa" + OS.NEWLINE + "\t" + OS.NEWLINE + "\tbbbbb" + OS.NEWLINE + "\t"
- + OS.NEWLINE + "\tccccc", StringUtil.wrap("aaaaa\nbbbbb\nccccc", 12));
- assertEquals(
- "aaaaa" + OS.NEWLINE + "\t" + OS.NEWLINE + "\t" + OS.NEWLINE + "\tbbbbb"
- + OS.NEWLINE + "\t" + OS.NEWLINE + "\tccccc",
- StringUtil.wrap("aaaaa\n\nbbbbb\nccccc", 12));
- assertEquals("aaaaa" + OS.NEWLINE + "\t" + OS.NEWLINE + "\tbbbbb" + OS.NEWLINE + "\t"
- + OS.NEWLINE + "\tccccc", StringUtil.wrap("aaaaa\r\nbbbbb\r\nccccc", 12));
- }
-
- @Test
- public void testUnquote() {
- assertEquals("a:", StringUtil.unquote("a::", ':'));
- assertEquals("a:;", StringUtil.unquote("a:::;", ':'));
- assertEquals("a:b%c;", StringUtil.unquote("a::b:%c:;", ':'));
- }
-
-
-
- @Test
- public void testEncodeStringArray() {
- assertEquals(ENCODED_STRING_ARRAY_1, FileField.encodeStringArray(STRING_ARRAY_1));
- assertEquals(ENCODED_STRING_ARRAY_2, FileField.encodeStringArray(STRING_ARRAY_2));
- assertEquals(ENCODED_STRING_ARRAY_2_WITH_NULL, FileField.encodeStringArray(STRING_ARRAY_2_WITH_NULL));
- assertEquals(ENCODED_STRING_ARRAY_3, FileField.encodeStringArray(STRING_ARRAY_3));
- }
-
- @Test
- public void testDecodeStringDoubleArray() {
- assertArrayEquals(STRING_ARRAY_1, StringUtil.decodeStringDoubleArray(ENCODED_STRING_ARRAY_1));
- assertArrayEquals(STRING_ARRAY_2, StringUtil.decodeStringDoubleArray(ENCODED_STRING_ARRAY_2));
- // arrays first differed at element [0][1]; expected: null<null> but was: java.lang.String<null>
- // assertArrayEquals(stringArray2res, StringUtil.decodeStringDoubleArray(encStringArray2));
- assertArrayEquals(STRING_ARRAY_3, StringUtil.decodeStringDoubleArray(ENCODED_STRING_ARRAY_3));
- }
-
- @Test
- public void testBooleanToBinaryString() {
- assertEquals("0", StringUtil.booleanToBinaryString(false));
- assertEquals("1", StringUtil.booleanToBinaryString(true));
- }
-
- @Test
- public void testIsInCurlyBrackets() {
- assertFalse(StringUtil.isInCurlyBrackets(""));
- assertFalse(StringUtil.isInCurlyBrackets(null));
- assertTrue(StringUtil.isInCurlyBrackets("{}"));
- assertTrue(StringUtil.isInCurlyBrackets("{a}"));
- assertTrue(StringUtil.isInCurlyBrackets("{a{a}}"));
- assertTrue(StringUtil.isInCurlyBrackets("{{\\AA}sa {\\AA}Stor{\\aa}}"));
- assertFalse(StringUtil.isInCurlyBrackets("{"));
- assertFalse(StringUtil.isInCurlyBrackets("}"));
- assertFalse(StringUtil.isInCurlyBrackets("a{}a"));
- assertFalse(StringUtil.isInCurlyBrackets("{\\AA}sa {\\AA}Stor{\\aa}"));
-
- }
-
- @Test
- public void testIsInSquareBrackets() {
- assertFalse(StringUtil.isInSquareBrackets(""));
- assertFalse(StringUtil.isInSquareBrackets(null));
- assertTrue(StringUtil.isInSquareBrackets("[]"));
- assertTrue(StringUtil.isInSquareBrackets("[a]"));
- assertFalse(StringUtil.isInSquareBrackets("["));
- assertFalse(StringUtil.isInSquareBrackets("]"));
- assertFalse(StringUtil.isInSquareBrackets("a[]a"));
- }
-
- @Test
- public void testIsInCitationMarks() {
- assertFalse(StringUtil.isInCitationMarks(""));
- assertFalse(StringUtil.isInCitationMarks(null));
- assertTrue(StringUtil.isInCitationMarks("\"\""));
- assertTrue(StringUtil.isInCitationMarks("\"a\""));
- assertFalse(StringUtil.isInCitationMarks("\""));
- assertFalse(StringUtil.isInCitationMarks("a\"\"a"));
- }
-
- @Test
- public void testIntValueOfSingleDigit() {
- assertEquals(1, StringUtil.intValueOf("1"));
- assertEquals(2, StringUtil.intValueOf("2"));
- assertEquals(8, StringUtil.intValueOf("8"));
- }
-
- @Test
- public void testIntValueOfLongString() {
- assertEquals(1234567890, StringUtil.intValueOf("1234567890"));
- }
-
- @Test
- public void testIntValueOfStartWithZeros() {
- assertEquals(1234, StringUtil.intValueOf("001234"));
- }
-
- @Test(expected = NumberFormatException.class)
- public void testIntValueOfExceptionIfStringContainsLetter() {
- StringUtil.intValueOf("12A2");
- }
-
- @Test(expected = NumberFormatException.class)
- public void testIntValueOfExceptionIfStringNull() {
- StringUtil.intValueOf(null);
- }
-
- @Test(expected = NumberFormatException.class)
- public void testIntValueOfExceptionfIfStringEmpty() {
- StringUtil.intValueOf("");
- }
-
- @Test
- public void testIntValueOfWithNullSingleDigit() {
- assertEquals(Optional.of(Integer.valueOf(1)), StringUtil.intValueOfOptional("1"));
- assertEquals(Optional.of(Integer.valueOf(2)), StringUtil.intValueOfOptional("2"));
- assertEquals(Optional.of(Integer.valueOf(8)), StringUtil.intValueOfOptional("8"));
- }
-
- @Test
- public void testIntValueOfWithNullLongString() {
- assertEquals(Optional.of(Integer.valueOf(1234567890)), StringUtil.intValueOfOptional("1234567890"));
- }
-
- @Test
- public void testIntValueOfWithNullStartWithZeros() {
- assertEquals(Optional.of(Integer.valueOf(1234)), StringUtil.intValueOfOptional("001234"));
- }
-
- @Test
- public void testIntValueOfWithNullExceptionIfStringContainsLetter() {
- assertEquals(Optional.empty(), StringUtil.intValueOfOptional("12A2"));
- }
-
- @Test
- public void testIntValueOfWithNullExceptionIfStringNull() {
- assertEquals(Optional.empty(), StringUtil.intValueOfOptional(null));
- }
-
- @Test
- public void testIntValueOfWithNullExceptionfIfStringEmpty() {
- assertEquals(Optional.empty(), StringUtil.intValueOfOptional(""));
- }
-
- @Test
- public void testQuoteSimple() {
- assertEquals("a::", StringUtil.quote("a:", "", ':'));
- }
-
- @Test
- public void testQuoteNullQuotation() {
- assertEquals("a::", StringUtil.quote("a:", null, ':'));
- }
-
- @Test
- public void testQuoteNullString() {
- assertEquals("", StringUtil.quote(null, ";", ':'));
- }
-
- @Test
- public void testQuoteQuotationCharacter() {
- assertEquals("a:::;", StringUtil.quote("a:;", ";", ':'));
- }
-
- @Test
- public void testQuoteMoreComplicated() {
- assertEquals("a::b:%c:;", StringUtil.quote("a:b%c;", "%;", ':'));
- }
-
- @Test
- public void testLimitStringLengthShort() {
- assertEquals("Test", StringUtil.limitStringLength("Test", 20));
- }
-
- @Test
- public void testLimitStringLengthLimiting() {
- assertEquals("TestTes...", StringUtil.limitStringLength("TestTestTestTestTest", 10));
- assertEquals(10, StringUtil.limitStringLength("TestTestTestTestTest", 10).length());
- }
-
- @Test
- public void testLimitStringLengthNullInput() {
- assertEquals("", StringUtil.limitStringLength(null, 10));
- }
-
- @Test
- public void testReplaceSpecialCharacters() {
- assertEquals("Hallo Arger", StringUtil.replaceSpecialCharacters("Hallo Arger"));
- assertEquals("aaAeoeeee", StringUtil.replaceSpecialCharacters("åÄöéèë"));
- }
-
- @Test
- public void testRepeatSpaces() {
- assertEquals("", StringUtil.repeatSpaces(0));
- assertEquals(" ", StringUtil.repeatSpaces(1));
- assertEquals(" ", StringUtil.repeatSpaces(7));
- }
-
- @Test
- public void testRepeat() {
- assertEquals("", StringUtil.repeat(0, 'a'));
- assertEquals("a", StringUtil.repeat(1, 'a'));
- assertEquals("aaaaaaa", StringUtil.repeat(7, 'a'));
- }
-
- @Test
- public void testBoldHTML() {
- assertEquals("<b>AA</b>", StringUtil.boldHTML("AA"));
- }
-
- @Test
- public void testBoldHTMLReturnsOriginalTextIfNonNull() {
- assertEquals("<b>AA</b>", StringUtil.boldHTML("AA", "BB"));
- }
-
- @Test
- public void testBoldHTMLReturnsAlternativeTextIfNull() {
- assertEquals("<b>BB</b>", StringUtil.boldHTML(null, "BB"));
- }
-}
diff --git a/src/test/java/net/sf/jabref/logic/util/version/VersionTest.java b/src/test/java/net/sf/jabref/logic/util/version/VersionTest.java
deleted file mode 100644
index be384f8..0000000
--- a/src/test/java/net/sf/jabref/logic/util/version/VersionTest.java
+++ /dev/null
@@ -1,216 +0,0 @@
-package net.sf.jabref.logic.util.version;
-
-
-import net.sf.jabref.logic.util.BuildInfo;
-import net.sf.jabref.logic.util.Version;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-public class VersionTest {
-
- @Test
- public void unknownVersionAsString() {
- Version version = new Version(BuildInfo.UNKNOWN_VERSION);
- assertEquals(BuildInfo.UNKNOWN_VERSION, version.getFullVersion());
- }
-
- @Test
- public void unknownVersionAsNull() {
- Version version = new Version(null);
- assertEquals(BuildInfo.UNKNOWN_VERSION, version.getFullVersion());
- }
-
- @Test
- public void unknownVersionAsEmptyString() {
- Version version = new Version("");
- assertEquals(BuildInfo.UNKNOWN_VERSION, version.getFullVersion());
- }
-
- @Test
- public void initVersionFromWrongStringResultsInUnknownVersion() {
- Version version = new Version("${version}");
- assertEquals(BuildInfo.UNKNOWN_VERSION, version.getFullVersion());
- }
-
- @Test
- public void versionOneDigit() {
- String versionText = "1";
- Version version = new Version(versionText);
- assertEquals(versionText, version.getFullVersion());
- assertEquals(1, version.getMajor());
- assertEquals(0, version.getMinor());
- assertEquals(0, version.getPatch());
- assertFalse(version.isDevelopmentVersion());
- }
-
- @Test
- public void versionTwoDigits() {
- String versionText = "1.2";
- Version version = new Version(versionText);
- assertEquals(versionText, version.getFullVersion());
- assertEquals(1, version.getMajor());
- assertEquals(2, version.getMinor());
- assertEquals(0, version.getPatch());
- assertFalse(version.isDevelopmentVersion());
- }
-
- @Test
- public void versionThreeDigits() {
- String versionText = "1.2.3";
- Version version = new Version(versionText);
- assertEquals(versionText, version.getFullVersion());
- assertEquals(1, version.getMajor());
- assertEquals(2, version.getMinor());
- assertEquals(3, version.getPatch());
- assertFalse(version.isDevelopmentVersion());
- }
-
- @Test
- public void versionOneDigitDevVersion() {
- String versionText = "1dev";
- Version version = new Version(versionText);
- assertEquals(versionText, version.getFullVersion());
- assertEquals(1, version.getMajor());
- assertEquals(0, version.getMinor());
- assertEquals(0, version.getPatch());
- assertTrue(version.isDevelopmentVersion());
- }
-
- @Test
- public void versionTwoDigitDevVersion() {
- String versionText = "1.2dev";
- Version version = new Version(versionText);
- assertEquals(versionText, version.getFullVersion());
- assertEquals(1, version.getMajor());
- assertEquals(2, version.getMinor());
- assertEquals(0, version.getPatch());
- assertTrue(version.isDevelopmentVersion());
- }
-
- @Test
- public void versionThreeDigitDevVersion() {
- String versionText = "1.2.3dev";
- Version version = new Version(versionText);
- assertEquals(versionText, version.getFullVersion());
- assertEquals(1, version.getMajor());
- assertEquals(2, version.getMinor());
- assertEquals(3, version.getPatch());
- assertTrue(version.isDevelopmentVersion());
- }
-
- @Test
- public void validVersionIsNotNewerThanUnknownVersion() {
- // Reason: unknown version should only happen for developer builds where we don't want an update notification
- Version unknownVersion = new Version(BuildInfo.UNKNOWN_VERSION);
- Version validVersion = new Version("4.2");
- assertFalse(validVersion.isNewerThan(unknownVersion));
- }
-
- @Test
- public void unknownVersionIsNotNewerThanvalidVersion() {
- Version unknownVersion = new Version(BuildInfo.UNKNOWN_VERSION);
- Version validVersion = new Version("4.2");
- assertFalse(unknownVersion.isNewerThan(validVersion));
- }
-
- @Test
- public void versionNewerThan() {
- Version olderVersion = new Version("2.4");
- Version newerVersion = new Version("4.2");
- assertTrue(newerVersion.isNewerThan(olderVersion));
- }
-
- @Test
- public void versionNotNewerThan() {
- Version olderVersion = new Version("2.4");
- Version newerVersion = new Version("4.2");
- assertFalse(olderVersion.isNewerThan(newerVersion));
- }
-
- @Test
- public void versionNotNewerThanSameVersion() {
- Version version1 = new Version("4.2");
- Version version2 = new Version("4.2");
- assertFalse(version1.isNewerThan(version2));
- }
-
- @Test
- public void versionNewerThanDevTwoDigits() {
- Version older = new Version("4.2");
- Version newer = new Version("4.3dev");
- assertTrue(newer.isNewerThan(older));
- }
-
- @Test
- public void versionNewerThanDevThreeDigits() {
- Version older = new Version("4.2.1");
- Version newer = new Version("4.3dev");
- assertTrue(newer.isNewerThan(older));
- }
-
- @Test
- public void versionNewerMinor() {
- Version older = new Version("4.1");
- Version newer = new Version("4.2.1");
- assertTrue(newer.isNewerThan(older));
- }
-
- @Test
- public void versionNotNewerMinor() {
- Version older = new Version("4.1");
- Version newer = new Version("4.2.1");
- assertFalse(older.isNewerThan(newer));
- }
-
- @Test
- public void versionNewerPatch() {
- Version older = new Version("4.2.1");
- Version newer = new Version("4.2.2");
- assertTrue(newer.isNewerThan(older));
- }
-
- @Test
- public void versionNotNewerPatch() {
- Version older = new Version("4.2.1");
- Version newer = new Version("4.2.2");
- assertFalse(older.isNewerThan(newer));
- }
-
- @Test
- public void equalVersionsNotNewer() {
- Version version1 = new Version("4.2.2");
- Version version2 = new Version("4.2.2");
- assertFalse(version1.isNewerThan(version2));
- }
-
- @Test
- public void changelogWithTwoDigits(){
- Version version = new Version("3.4");
- assertEquals("https://github.com/JabRef/jabref/blob/v3.4/CHANGELOG.md", version.getChangelogUrl());
- }
-
- @Test
- public void changelogWithThreeDigits(){
- Version version = new Version("3.4.1");
- assertEquals("https://github.com/JabRef/jabref/blob/v3.4.1/CHANGELOG.md", version.getChangelogUrl());
- }
-
- @Test
- public void versionNull() {
- String versionText = null;
- Version version = new Version(versionText);
- assertEquals(BuildInfo.UNKNOWN_VERSION, version.getFullVersion());
- }
-
- @Test
- public void versionEmpty() {
- String versionText = "";
- Version version = new Version(versionText);
- assertEquals(BuildInfo.UNKNOWN_VERSION, version.getFullVersion());
- }
-
-}
diff --git a/src/test/java/net/sf/jabref/logic/xmp/XMPSchemaBibtexTest.java b/src/test/java/net/sf/jabref/logic/xmp/XMPSchemaBibtexTest.java
index 839734d..e6522c9 100644
--- a/src/test/java/net/sf/jabref/logic/xmp/XMPSchemaBibtexTest.java
+++ b/src/test/java/net/sf/jabref/logic/xmp/XMPSchemaBibtexTest.java
@@ -43,7 +43,7 @@ public class XMPSchemaBibtexTest {
Assert.assertEquals(e.getFieldNames().size(), x.getFieldNames().size());
for (String name : e.getFieldNames()) {
- Assert.assertEquals(e.getFieldOptional(name), x.getFieldOptional(name));
+ Assert.assertEquals(e.getField(name), x.getField(name));
}
}
diff --git a/src/test/java/net/sf/jabref/logic/xmp/XMPUtilTest.java b/src/test/java/net/sf/jabref/logic/xmp/XMPUtilTest.java
index 2b08cbe..560139f 100644
--- a/src/test/java/net/sf/jabref/logic/xmp/XMPUtilTest.java
+++ b/src/test/java/net/sf/jabref/logic/xmp/XMPUtilTest.java
@@ -31,7 +31,6 @@ import javax.xml.transform.TransformerException;
import net.sf.jabref.cli.XMPUtilMain;
import net.sf.jabref.logic.bibtex.BibEntryWriter;
import net.sf.jabref.logic.bibtex.LatexFieldFormatter;
-import net.sf.jabref.logic.bibtex.LatexFieldFormatterPreferences;
import net.sf.jabref.logic.importer.ImportFormatPreferences;
import net.sf.jabref.logic.importer.ParserResult;
import net.sf.jabref.logic.importer.fileformat.BibtexParser;
@@ -149,7 +148,7 @@ public class XMPUtilTest {
public static String bibtexEntry2BibtexString(BibEntry e, JabRefPreferences preferences) throws IOException {
StringWriter sw = new StringWriter();
- new BibEntryWriter(new LatexFieldFormatter(LatexFieldFormatterPreferences.fromPreferences(preferences)),
+ new BibEntryWriter(new LatexFieldFormatter(preferences.getLatexFieldFormatterPreferences()),
false).write(e, sw, BibDatabaseMode.BIBTEX);
return sw.getBuffer().toString();
}
@@ -203,7 +202,7 @@ public class XMPUtilTest {
e.setField("year", "1982");
e.setField("month", "#jul#");
e.setField("abstract",
- "The success of the Linux operating system has demonstrated the viability of an alternative form of software development � open source software � that challenges traditional assumptions about software markets. Understanding what drives open source developers to participate in open source projects is crucial for assessing the impact of open source software. This article identifies two broad types of motivations that account for their participation in open source projects. [...]
+ "The success of the Linux operating system has demonstrated the viability of an alternative form of software development—open source software—that challenges traditional assumptions about software markets. Understanding what drives open source developers to participate in open source projects is crucial for assessing the impact of open source software. This article identifies two broad types of motivations that account for their participation in open source projects. The [...]
return e;
}
@@ -222,7 +221,7 @@ public class XMPUtilTest {
+ "<bibtex:keywords>peanut, butter, jelly</bibtex:keywords>"
+ "<bibtex:entrytype>Inproceedings</bibtex:entrytype>" + "<bibtex:year>1982</bibtex:year>"
+ "<bibtex:month>#jul#</bibtex:month>"
- + "<bibtex:abstract>The success of the Linux operating system has demonstrated the viability of an alternative form of software development � open source software � that challenges traditional assumptions about software markets. Understanding what drives open source developers to participate in open source projects is crucial for assessing the impact of open source software. This article identifies two broad types of motivations that account for their participation in ope [...]
+ + "<bibtex:abstract>The success of the Linux operating system has demonstrated the viability of an alternative form of software development—open source software—that challenges traditional assumptions about software markets. Understanding what drives open source developers to participate in open source projects is crucial for assessing the impact of open source software. This article identifies two broad types of motivations that account for their participation in open so [...]
}
/**
@@ -250,8 +249,8 @@ public class XMPUtilTest {
// The code assumes privacy filters to be off
prefs.putBoolean("useXmpPrivacyFilter", false);
- importFormatPreferences = ImportFormatPreferences.fromPreferences(prefs);
- xmpPreferences = XMPPreferences.fromPreferences(prefs);
+ importFormatPreferences = prefs.getImportFormatPreferences();
+ xmpPreferences = prefs.getXMPPreferences();
}
@After
@@ -280,9 +279,9 @@ public class XMPUtilTest {
Assert.assertNotNull(e);
Assert.assertEquals(Optional.of("OezbekC06"), e.getCiteKeyOptional());
- Assert.assertEquals(Optional.of("2003"), e.getFieldOptional("year"));
+ Assert.assertEquals(Optional.of("2003"), e.getField("year"));
Assert.assertEquals(Optional.of("Beach sand convolution by surf-wave optimzation"),
- e.getFieldOptional("title"));
+ e.getField("title"));
Assert.assertEquals("misc", e.getType());
}
@@ -305,8 +304,8 @@ public class XMPUtilTest {
Assert.assertNotNull(e);
Assert.assertEquals(Optional.of("OezbekC06"), e.getCiteKeyOptional());
- Assert.assertEquals(Optional.of("2003"), e.getFieldOptional("year"));
- Assert.assertEquals(Optional.of("�pt�mz�t��n"), e.getFieldOptional("title"));
+ Assert.assertEquals(Optional.of("2003"), e.getField("year"));
+ Assert.assertEquals(Optional.of("�pt�mz�t��n"), e.getField("title"));
Assert.assertEquals("misc", e.getType());
}
@@ -325,9 +324,9 @@ public class XMPUtilTest {
prefs.putBoolean("useXmpPrivacyFilter", true);
prefs.putStringList(JabRefPreferences.XMP_PRIVACY_FILTERS, Arrays.asList("author", "title", "note"));
- XMPUtil.writeXMP(pdfFile, e, null, XMPPreferences.fromPreferences(prefs));
+ XMPUtil.writeXMP(pdfFile, e, null, prefs.getXMPPreferences());
- List<BibEntry> l = XMPUtil.readXMP(pdfFile.getAbsoluteFile(), XMPPreferences.fromPreferences(prefs));
+ List<BibEntry> l = XMPUtil.readXMP(pdfFile.getAbsoluteFile(), prefs.getXMPPreferences());
Assert.assertEquals(1, l.size());
BibEntry x = l.get(0);
@@ -343,9 +342,9 @@ public class XMPUtilTest {
BibEntry e = t1BibtexEntry();
- XMPUtil.writeXMP(pdfFile, e, null, XMPPreferences.fromPreferences(prefs));
+ XMPUtil.writeXMP(pdfFile, e, null, prefs.getXMPPreferences());
- List<BibEntry> l = XMPUtil.readXMP(pdfFile.getAbsoluteFile(), XMPPreferences.fromPreferences(prefs));
+ List<BibEntry> l = XMPUtil.readXMP(pdfFile.getAbsoluteFile(), prefs.getXMPPreferences());
Assert.assertEquals(1, l.size());
BibEntry x = l.get(0);
Set<String> ts = x.getFieldNames();
@@ -379,8 +378,8 @@ public class XMPUtilTest {
Assert.assertNotNull(e);
Assert.assertEquals(Optional.of("Clarkson06"), e.getCiteKeyOptional());
- Assert.assertEquals("Kelly Clarkson and Ozzy Osbourne", e.getFieldOptional("author").get());
- Assert.assertEquals("Huey Duck and Dewey Duck and Louie Duck", e.getFieldOptional("editor").get());
+ Assert.assertEquals("Kelly Clarkson and Ozzy Osbourne", e.getField("author").get());
+ Assert.assertEquals("Huey Duck and Dewey Duck and Louie Duck", e.getField("editor").get());
Assert.assertEquals("misc", e.getType());
}
@@ -500,9 +499,9 @@ public class XMPUtilTest {
BibEntry e = l.get(0);
Assert.assertNotNull(e);
- Assert.assertEquals("Hallo World this is not an exercise .", e.getFieldOptional("title").get());
- Assert.assertEquals("Hallo World this is not an exercise .", e.getFieldOptional("tabs").get());
- Assert.assertEquals("\n\nAbstract preserve\n\t Whitespace\n\n", e.getFieldOptional("abstract").get());
+ Assert.assertEquals("Hallo World this is not an exercise .", e.getField("title").get());
+ Assert.assertEquals("Hallo World this is not an exercise .", e.getField("tabs").get());
+ Assert.assertEquals("\n\nAbstract preserve\n\t Whitespace\n\n", e.getField("abstract").get());
}
/**
@@ -768,12 +767,12 @@ public class XMPUtilTest {
if ("author".equalsIgnoreCase(field) || "editor".equalsIgnoreCase(field)) {
- AuthorList expectedAuthors = AuthorList.parse(expected.getFieldOptional(field).get());
- AuthorList actualAuthors = AuthorList.parse(actual.getFieldOptional(field).get());
+ AuthorList expectedAuthors = AuthorList.parse(expected.getField(field).get());
+ AuthorList actualAuthors = AuthorList.parse(actual.getField(field).get());
Assert.assertEquals(expectedAuthors, actualAuthors);
} else {
- Assert.assertEquals("comparing " + field, expected.getFieldOptional(field),
- actual.getFieldOptional(field));
+ Assert.assertEquals("comparing " + field, expected.getField(field),
+ actual.getField(field));
}
}
@@ -826,12 +825,12 @@ public class XMPUtilTest {
}
Assert.assertEquals(Optional.of("canh05"), a.getCiteKeyOptional());
- Assert.assertEquals("K. Crowston and H. Annabi", a.getFieldOptional("author").get());
- Assert.assertEquals("Title A", a.getFieldOptional("title").get());
+ Assert.assertEquals("K. Crowston and H. Annabi", a.getField("author").get());
+ Assert.assertEquals("Title A", a.getField("title").get());
Assert.assertEquals("article", a.getType());
Assert.assertEquals(Optional.of("foo"), b.getCiteKeyOptional());
- Assert.assertEquals("Norton Bar", b.getFieldOptional("author").get());
+ Assert.assertEquals("Norton Bar", b.getField("author").get());
Assert.assertEquals("inproceedings", b.getType());
}
@@ -1016,6 +1015,7 @@ public class XMPUtilTest {
if (metaRaw == null) {
Assert.fail();
+ return;
}
XMPMetadata meta = new XMPMetadata(XMLUtil.parse(metaRaw.createInputStream()));
@@ -1258,7 +1258,6 @@ public class XMPUtilTest {
* @throws TransformerException
*/
@Test
- @Ignore
public void testCommandLineSeveral() throws IOException, TransformerException {
File tempBib = File.createTempFile("JabRef", ".bib");
@@ -1335,7 +1334,7 @@ public class XMPUtilTest {
BibEntry x = l.get(0);
Assert.assertEquals(AuthorList.parse("Crowston, K. and Annabi, H. and Howison, J. and Masango, C."),
- AuthorList.parse(x.getFieldOptional("author").get()));
+ AuthorList.parse(x.getField("author").get()));
}
@Test(expected = EncryptedPdfsNotSupportedException.class)
@@ -1378,7 +1377,7 @@ public class XMPUtilTest {
// Test whether we the main function can load the bibtex correctly
BibEntry b = XMPUtil.readXMP(pdfFile, xmpPreferences).get(0);
Assert.assertNotNull(b);
- Assert.assertEquals(originalAuthors, AuthorList.parse(b.getFieldOptional("author").get()));
+ Assert.assertEquals(originalAuthors, AuthorList.parse(b.getField("author").get()));
// Next check from Document Information
try (PDDocument document = PDDocument.load(pdfFile.getAbsoluteFile())) {
@@ -1387,7 +1386,7 @@ public class XMPUtilTest {
AuthorList.parse(document.getDocumentInformation().getAuthor()));
b = XMPUtil.getBibtexEntryFromDocumentInformation(document.getDocumentInformation()).get();
- Assert.assertEquals(originalAuthors, AuthorList.parse(b.getFieldOptional("author").get()));
+ Assert.assertEquals(originalAuthors, AuthorList.parse(b.getField("author").get()));
// Now check from Dublin Core
PDDocumentCatalog catalog = document.getDocumentCatalog();
@@ -1395,6 +1394,7 @@ public class XMPUtilTest {
if (metaRaw == null) {
Assert.fail();
+ return; // To avoid warnings
}
XMPMetadata meta = new XMPMetadata(XMLUtil.parse(metaRaw.createInputStream()));
@@ -1413,7 +1413,7 @@ public class XMPUtilTest {
b = XMPUtil.getBibtexEntryFromDublinCore(dcSchema, xmpPreferences).get();
Assert.assertNotNull(b);
- Assert.assertEquals(originalAuthors, AuthorList.parse(b.getFieldOptional("author").get()));
+ Assert.assertEquals(originalAuthors, AuthorList.parse(b.getField("author").get()));
}
} finally {
if (!pdfFile.delete()) {
diff --git a/src/test/java/net/sf/jabref/model/BibDatabaseContextTest.java b/src/test/java/net/sf/jabref/model/BibDatabaseContextTest.java
new file mode 100644
index 0000000..da334b4
--- /dev/null
+++ b/src/test/java/net/sf/jabref/model/BibDatabaseContextTest.java
@@ -0,0 +1,51 @@
+package net.sf.jabref.model;
+
+import net.sf.jabref.model.database.BibDatabase;
+import net.sf.jabref.model.database.BibDatabaseContext;
+import net.sf.jabref.model.database.BibDatabaseMode;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.metadata.MetaData;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class BibDatabaseContextTest {
+ @Test
+ public void testTypeBasedOnDefaultBibtex() {
+ BibDatabaseContext bibDatabaseContext = new BibDatabaseContext(new BibDatabase(), new MetaData(), new Defaults(BibDatabaseMode.BIBTEX));
+ assertEquals(BibDatabaseMode.BIBTEX, bibDatabaseContext.getMode());
+
+ bibDatabaseContext.setMode(BibDatabaseMode.BIBLATEX);
+ assertEquals(BibDatabaseMode.BIBLATEX, bibDatabaseContext.getMode());
+ }
+
+ @Test
+ public void testTypeBasedOnDefaultBiblatex() {
+ BibDatabaseContext bibDatabaseContext = new BibDatabaseContext(new BibDatabase(), new MetaData(), new Defaults(BibDatabaseMode.BIBLATEX));
+ assertEquals(BibDatabaseMode.BIBLATEX, bibDatabaseContext.getMode());
+
+ bibDatabaseContext.setMode(BibDatabaseMode.BIBTEX);
+ assertEquals(BibDatabaseMode.BIBTEX, bibDatabaseContext.getMode());
+ }
+
+ @Test
+ public void testTypeBasedOnInferredModeBibTeX() {
+ BibDatabase db = new BibDatabase();
+ BibEntry e1 = new BibEntry("1");
+ db.insertEntry(e1);
+
+ BibDatabaseContext bibDatabaseContext = new BibDatabaseContext(db);
+ assertEquals(BibDatabaseMode.BIBTEX, bibDatabaseContext.getMode());
+ }
+
+ @Test
+ public void testTypeBasedOnInferredModeBiblatex() {
+ BibDatabase db = new BibDatabase();
+ BibEntry e1 = new BibEntry("1", "electronic");
+ db.insertEntry(e1);
+
+ BibDatabaseContext bibDatabaseContext = new BibDatabaseContext(db);
+ assertEquals(BibDatabaseMode.BIBLATEX, bibDatabaseContext.getMode());
+ }
+}
diff --git a/src/test/java/net/sf/jabref/model/database/BibDatabaseTest.java b/src/test/java/net/sf/jabref/model/database/BibDatabaseTest.java
index 536d781..002f714 100644
--- a/src/test/java/net/sf/jabref/model/database/BibDatabaseTest.java
+++ b/src/test/java/net/sf/jabref/model/database/BibDatabaseTest.java
@@ -178,7 +178,7 @@ public class BibDatabaseTest {
BibEntry entry = new BibEntry();
entry.setCiteKey("AAA");
database.insertEntry(entry);
- assertEquals(database.getNumberOfKeyOccurrences("AAA"), 1);
+ assertEquals(database.getDuplicationChecker().getNumberOfKeyOccurrences("AAA"), 1);
}
@Test
@@ -189,51 +189,7 @@ public class BibDatabaseTest {
entry = new BibEntry();
entry.setCiteKey("AAA");
database.insertEntry(entry);
- assertEquals(database.getNumberOfKeyOccurrences("AAA"), 2);
- }
-
- @Test
- public void setCiteKeySameKeySameEntry() {
- BibEntry entry = new BibEntry();
- entry.setCiteKey("AAA");
- database.insertEntry(entry);
- assertFalse(database.setCiteKeyForEntry(entry, "AAA"));
- assertEquals(database.getNumberOfKeyOccurrences("AAA"), 1);
- }
-
- @Test
- public void setCiteKeyRemoveKey() {
- BibEntry entry = new BibEntry();
- entry.setCiteKey("AAA");
- database.insertEntry(entry);
- assertFalse(database.setCiteKeyForEntry(entry, null));
- assertEquals(database.getNumberOfKeyOccurrences("AAA"), 0);
- assertEquals(Optional.empty(), entry.getCiteKeyOptional());
- }
-
- @Test
- public void setCiteKeyDifferentKeySameEntry() {
- BibEntry entry = new BibEntry();
- entry.setCiteKey("AAA");
- database.insertEntry(entry);
- assertFalse(database.setCiteKeyForEntry(entry, "BBB"));
- assertEquals(database.getNumberOfKeyOccurrences("AAA"), 0);
- assertEquals(database.getNumberOfKeyOccurrences("BBB"), 1);
- }
-
-
- @Test
- public void setCiteKeySameKeyDifferentEntries() {
- BibEntry entry = new BibEntry();
- entry.setCiteKey("AAA");
- database.insertEntry(entry);
- entry = new BibEntry();
- entry.setCiteKey("BBB");
- database.insertEntry(entry);
- assertTrue(database.setCiteKeyForEntry(entry, "AAA"));
- assertEquals(entry.getCiteKeyOptional(), Optional.of("AAA"));
- assertEquals(database.getNumberOfKeyOccurrences("AAA"), 2);
- assertEquals(database.getNumberOfKeyOccurrences("BBB"), 0);
+ assertEquals(database.getDuplicationChecker().getNumberOfKeyOccurrences("AAA"), 2);
}
@Test
@@ -245,7 +201,7 @@ public class BibDatabaseTest {
entry.setCiteKey("AAA");
database.insertEntry(entry);
database.removeEntry(entry);
- assertEquals(database.getNumberOfKeyOccurrences("AAA"), 1);
+ assertEquals(database.getDuplicationChecker().getNumberOfKeyOccurrences("AAA"), 1);
}
@Test
@@ -292,4 +248,16 @@ public class BibDatabaseTest {
database.addString(string);
assertEquals(database.resolveForStrings("AAA#AAA#AAA#"), "AAAaaaAAA#");
}
+
+ @Test
+ public void preambleIsEmptyIfNotSet() {
+ assertEquals(Optional.empty(), database.getPreamble());
+ }
+
+ @Test
+ public void setPreambleWorks() {
+ database.setPreamble("Oh yeah!");
+ assertEquals(Optional.of("Oh yeah!"), database.getPreamble());
+ }
+
}
diff --git a/src/test/java/net/sf/jabref/model/database/DuplicationCheckerTest.java b/src/test/java/net/sf/jabref/model/database/DuplicationCheckerTest.java
new file mode 100644
index 0000000..c2c4487
--- /dev/null
+++ b/src/test/java/net/sf/jabref/model/database/DuplicationCheckerTest.java
@@ -0,0 +1,111 @@
+package net.sf.jabref.model.database;
+
+import net.sf.jabref.model.entry.BibEntry;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+
+public class DuplicationCheckerTest {
+
+ private BibDatabase database;
+
+
+ @Before
+ public void setUp() {
+ database = new BibDatabase();
+ }
+
+ @Test
+ public void addEntry() {
+ BibEntry entry = new BibEntry();
+ entry.setCiteKey("AAA");
+ database.insertEntry(entry);
+ assertEquals(database.getDuplicationChecker().getNumberOfKeyOccurrences("AAA"), 1);
+ }
+
+ @Test
+ public void addAndRemoveEntry() {
+ BibEntry entry = new BibEntry();
+ entry.setCiteKey("AAA");
+ database.insertEntry(entry);
+ assertEquals(database.getDuplicationChecker().getNumberOfKeyOccurrences("AAA"), 1);
+ database.removeEntry(entry);
+ assertEquals(database.getDuplicationChecker().getNumberOfKeyOccurrences("AAA"), 0);
+ }
+
+ @Test
+ public void changeCiteKey() {
+ BibEntry entry = new BibEntry();
+ entry.setCiteKey("AAA");
+ database.insertEntry(entry);
+ assertEquals(database.getDuplicationChecker().getNumberOfKeyOccurrences("AAA"), 1);
+ entry.setCiteKey("BBB");
+ assertEquals(database.getDuplicationChecker().getNumberOfKeyOccurrences("AAA"), 0);
+ assertEquals(database.getDuplicationChecker().getNumberOfKeyOccurrences("BBB"), 1);
+ }
+
+
+ @Test
+ public void setCiteKeySameKeyDifferentEntries() {
+ BibEntry entry0 = new BibEntry();
+ entry0.setCiteKey("AAA");
+ database.insertEntry(entry0);
+ BibEntry entry1 = new BibEntry();
+ entry1.setCiteKey("BBB");
+ database.insertEntry(entry1);
+ assertEquals(database.getDuplicationChecker().getNumberOfKeyOccurrences("AAA"), 1);
+ assertEquals(database.getDuplicationChecker().getNumberOfKeyOccurrences("BBB"), 1);
+
+ entry1.setCiteKey("AAA");
+ assertEquals(database.getDuplicationChecker().getNumberOfKeyOccurrences("AAA"), 2);
+ assertEquals(database.getDuplicationChecker().getNumberOfKeyOccurrences("BBB"), 0);
+ }
+
+ @Test
+ public void removeMultipleCiteKeys(){
+ BibEntry entry0 = new BibEntry();
+ entry0.setCiteKey("AAA");
+ database.insertEntry(entry0);
+ BibEntry entry1 = new BibEntry();
+ entry1.setCiteKey("AAA");
+ database.insertEntry(entry1);
+ BibEntry entry2 = new BibEntry();
+ entry2.setCiteKey("AAA");
+ database.insertEntry(entry2);
+ assertEquals(database.getDuplicationChecker().getNumberOfKeyOccurrences("AAA"), 3);
+
+ database.removeEntry(entry2);
+ assertEquals(database.getDuplicationChecker().getNumberOfKeyOccurrences("AAA"), 2);
+
+ database.removeEntry(entry1);
+ assertEquals(database.getDuplicationChecker().getNumberOfKeyOccurrences("AAA"), 1);
+
+ database.removeEntry(entry0);
+ assertEquals(database.getDuplicationChecker().getNumberOfKeyOccurrences("AAA"), 0);
+ }
+
+ @Test
+ public void addEmptyCiteKey(){
+ BibEntry entry = new BibEntry();
+ entry.setCiteKey("");
+ database.insertEntry(entry);
+
+ assertEquals(database.getDuplicationChecker().getNumberOfKeyOccurrences(""), 0);
+ }
+
+ @Test
+ public void removeEmptyCiteKey(){
+ BibEntry entry = new BibEntry();
+ entry.setCiteKey("AAA");
+ database.insertEntry(entry);
+ assertEquals(database.getDuplicationChecker().getNumberOfKeyOccurrences("AAA"), 1);
+
+ entry.setCiteKey("");
+ database.removeEntry(entry);
+ assertEquals(database.getDuplicationChecker().getNumberOfKeyOccurrences("AAA"), 0);
+ }
+
+}
diff --git a/src/test/java/net/sf/jabref/model/database/KeyChangeListenerTest.java b/src/test/java/net/sf/jabref/model/database/KeyChangeListenerTest.java
index 976a9a6..d6e4de5 100644
--- a/src/test/java/net/sf/jabref/model/database/KeyChangeListenerTest.java
+++ b/src/test/java/net/sf/jabref/model/database/KeyChangeListenerTest.java
@@ -46,48 +46,48 @@ public class KeyChangeListenerTest {
@Test
public void testCrossrefChanged() {
- assertEquals(Optional.of("Entry4"), entry1.getFieldOptional("crossref"));
+ assertEquals(Optional.of("Entry4"), entry1.getField("crossref"));
entry4.setCiteKey("Banana");
- assertEquals(Optional.of("Banana"), entry1.getFieldOptional("crossref"));
+ assertEquals(Optional.of("Banana"), entry1.getField("crossref"));
}
@Test
public void testRelatedChanged() {
- assertEquals(Optional.of("Entry1,Entry3"), entry2.getFieldOptional("related"));
+ assertEquals(Optional.of("Entry1,Entry3"), entry2.getField("related"));
entry1.setCiteKey("Banana");
- assertEquals(Optional.of("Banana,Entry3"), entry2.getFieldOptional("related"));
+ assertEquals(Optional.of("Banana,Entry3"), entry2.getField("related"));
}
@Test
public void testRelatedChangedInSameEntry() {
- assertEquals(Optional.of("Entry1,Entry2,Entry3"), entry3.getFieldOptional("related"));
+ assertEquals(Optional.of("Entry1,Entry2,Entry3"), entry3.getField("related"));
entry3.setCiteKey("Banana");
- assertEquals(Optional.of("Entry1,Entry2,Banana"), entry3.getFieldOptional("related"));
+ assertEquals(Optional.of("Entry1,Entry2,Banana"), entry3.getField("related"));
}
@Test
public void testCrossrefRemoved() {
entry4.clearField(BibEntry.KEY_FIELD);
- assertEquals(Optional.empty(), entry1.getFieldOptional("crossref"));
+ assertEquals(Optional.empty(), entry1.getField("crossref"));
}
@Test
public void testCrossrefEntryRemoved() {
db.removeEntry(entry4);
- assertEquals(Optional.empty(), entry1.getFieldOptional("crossref"));
+ assertEquals(Optional.empty(), entry1.getField("crossref"));
}
@Test
public void testRelatedEntryRemoved() {
db.removeEntry(entry1);
- assertEquals(Optional.of("Entry3"), entry2.getFieldOptional("related"));
+ assertEquals(Optional.of("Entry3"), entry2.getField("related"));
}
@Test
public void testRelatedAllEntriesRemoved() {
db.removeEntry(entry1);
db.removeEntry(entry3);
- assertEquals(Optional.empty(), entry2.getFieldOptional("related"));
+ assertEquals(Optional.empty(), entry2.getField("related"));
}
}
diff --git a/src/test/java/net/sf/jabref/model/entry/AuthorListTest.java b/src/test/java/net/sf/jabref/model/entry/AuthorListTest.java
index b5aff0e..b470359 100644
--- a/src/test/java/net/sf/jabref/model/entry/AuthorListTest.java
+++ b/src/test/java/net/sf/jabref/model/entry/AuthorListTest.java
@@ -346,7 +346,7 @@ public class AuthorListTest {
Author author = AuthorList.parse("John Smith and von Neumann, Jr, John").getAuthor(0);
Assert.assertEquals(Optional.of("John"), author.getFirst());
- Assert.assertEquals("J.", author.getFirstAbbr());
+ Assert.assertEquals(Optional.of("J."), author.getFirstAbbr());
Assert.assertEquals("John Smith", author.getFirstLast(false));
Assert.assertEquals("J. Smith", author.getFirstLast(true));
Assert.assertEquals(Optional.empty(), author.getJr());
@@ -359,7 +359,7 @@ public class AuthorListTest {
author = AuthorList.parse("Peter Black Brown").getAuthor(0);
Assert.assertEquals(Optional.of("Peter Black"), author.getFirst());
- Assert.assertEquals("P. B.", author.getFirstAbbr());
+ Assert.assertEquals(Optional.of("P. B."), author.getFirstAbbr());
Assert.assertEquals("Peter Black Brown", author.getFirstLast(false));
Assert.assertEquals("P. B. Brown", author.getFirstLast(true));
Assert.assertEquals(Optional.empty(), author.getJr());
@@ -367,7 +367,7 @@ public class AuthorListTest {
author = AuthorList.parse("John Smith and von Neumann, Jr, John").getAuthor(1);
Assert.assertEquals(Optional.of("John"), author.getFirst());
- Assert.assertEquals("J.", author.getFirstAbbr());
+ Assert.assertEquals(Optional.of("J."), author.getFirstAbbr());
Assert.assertEquals("John von Neumann, Jr", author.getFirstLast(false));
Assert.assertEquals("J. von Neumann, Jr", author.getFirstLast(true));
Assert.assertEquals(Optional.of("Jr"), author.getJr());
@@ -525,6 +525,15 @@ public class AuthorListTest {
}
@Test
+ public void testGetAuthorsLastFirstAndsCaching() {
+ // getAsLastFirstNamesWithAnd caches its results, therefore we call the method twice using the same arguments
+ Assert.assertEquals("Smith, John", AuthorList.parse("John Smith").getAsLastFirstNamesWithAnd(false));
+ Assert.assertEquals("Smith, John", AuthorList.parse("John Smith").getAsLastFirstNamesWithAnd(false));
+ Assert.assertEquals("Smith, J.", AuthorList.parse("John Smith").getAsLastFirstNamesWithAnd(true));
+ Assert.assertEquals("Smith, J.", AuthorList.parse("John Smith").getAsLastFirstNamesWithAnd(true));
+ }
+
+ @Test
public void testGetAuthorsFirstFirst() {
AuthorList al;
@@ -602,7 +611,8 @@ public class AuthorListTest {
@Test
public void createCorrectInitials() {
- Assert.assertEquals("J. G.", AuthorList.parse("Hornberg, Johann Gottfried").getAuthor(0).getFirstAbbr());
+ Assert.assertEquals(Optional.of("J. G."),
+ AuthorList.parse("Hornberg, Johann Gottfried").getAuthor(0).getFirstAbbr());
}
@Test
@@ -635,4 +645,5 @@ public class AuthorListTest {
Author expected = new Author("H{e}lene", "H.", null, "Fiaux", null);
Assert.assertEquals(new AuthorList(expected), AuthorList.parse("H{e}lene Fiaux"));
}
+
}
diff --git a/src/test/java/net/sf/jabref/model/entry/BibEntryEqualityTest.java b/src/test/java/net/sf/jabref/model/entry/BibEntryEqualityTest.java
new file mode 100644
index 0000000..948e821
--- /dev/null
+++ b/src/test/java/net/sf/jabref/model/entry/BibEntryEqualityTest.java
@@ -0,0 +1,38 @@
+package net.sf.jabref.model.entry;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class BibEntryEqualityTest {
+ @Test
+ public void identicObjectsareEqual() throws Exception {
+ BibEntry e1 = new BibEntry();
+ BibEntry e2 = e1;
+ assertTrue(e1.equals(e2));
+ }
+
+ @Test
+ public void compareToNullObjectIsFalse() throws Exception {
+ BibEntry e1 = new BibEntry();
+ assertFalse(e1.equals(null));
+ }
+
+ @Test
+ public void compareToDifferentClassIsFalse() throws Exception {
+ BibEntry e1 = new BibEntry();
+ Object e2 = new Object();
+ assertFalse(e1.equals(e2));
+ }
+
+ @Test
+ public void compareIsTrueWhenIdAndFieldsAreEqual() throws Exception {
+ BibEntry e1 = new BibEntry("1");
+ e1.setField("key", "value");
+ BibEntry e2 = new BibEntry("1");
+ assertFalse(e1.equals(e2));
+ e2.setField("key", "value");
+ assertTrue(e1.equals(e2));
+ }
+}
diff --git a/src/test/java/net/sf/jabref/model/entry/BibEntryTest.java b/src/test/java/net/sf/jabref/model/entry/BibEntryTest.java
index d89ee60..8d03d79 100644
--- a/src/test/java/net/sf/jabref/model/entry/BibEntryTest.java
+++ b/src/test/java/net/sf/jabref/model/entry/BibEntryTest.java
@@ -34,6 +34,6 @@ public class BibEntryTest {
public void getFieldIsCaseInsensitive() throws Exception {
entry.setField("TeSt", "value");
- Assert.assertEquals(Optional.of("value"), entry.getFieldOptional("tEsT"));
+ Assert.assertEquals(Optional.of("value"), entry.getField("tEsT"));
}
}
diff --git a/src/test/java/net/sf/jabref/model/entry/BibEntryTests.java b/src/test/java/net/sf/jabref/model/entry/BibEntryTests.java
index 64257d6..208f3dd 100644
--- a/src/test/java/net/sf/jabref/model/entry/BibEntryTests.java
+++ b/src/test/java/net/sf/jabref/model/entry/BibEntryTests.java
@@ -1,6 +1,5 @@
package net.sf.jabref.model.entry;
-
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -13,6 +12,8 @@ import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+
public class BibEntryTests {
private BibEntry keywordEntry;
@@ -39,9 +40,9 @@ public class BibEntryTests {
public void testDefaultConstructor() {
BibEntry entry = new BibEntry();
// we have to use `getType("misc")` in the case of biblatex mode
- Assert.assertEquals("misc", entry.getType());
+ assertEquals("misc", entry.getType());
Assert.assertNotNull(entry.getId());
- Assert.assertFalse(entry.getFieldOptional("author").isPresent());
+ Assert.assertFalse(entry.getField("author").isPresent());
}
@Test
@@ -101,16 +102,16 @@ public class BibEntryTests {
@Test
public void typeOfBibEntryIsMiscAfterSettingToNullString() {
- Assert.assertEquals("article", keywordEntry.getType());
+ assertEquals("article", keywordEntry.getType());
keywordEntry.setType((String) null);
- Assert.assertEquals("misc", keywordEntry.getType());
+ assertEquals("misc", keywordEntry.getType());
}
@Test
public void typeOfBibEntryIsMiscAfterSettingToEmptyString() {
- Assert.assertEquals("article", keywordEntry.getType());
+ assertEquals("article", keywordEntry.getType());
keywordEntry.setType("");
- Assert.assertEquals("misc", keywordEntry.getType());
+ assertEquals("misc", keywordEntry.getType());
}
@@ -118,63 +119,99 @@ public class BibEntryTests {
public void getFieldOrAliasDateWithYearNumericalMonthString() {
emptyEntry.setField("year", "2003");
emptyEntry.setField("month", "3");
- Assert.assertEquals(Optional.of("2003-03"), emptyEntry.getFieldOrAlias("date"));
+ assertEquals(Optional.of("2003-03"), emptyEntry.getFieldOrAlias("date"));
}
@Test
public void getFieldOrAliasDateWithYearAbbreviatedMonth() {
emptyEntry.setField("year", "2003");
emptyEntry.setField("month", "#mar#");
- Assert.assertEquals(Optional.of("2003-03"), emptyEntry.getFieldOrAlias("date"));
+ assertEquals(Optional.of("2003-03"), emptyEntry.getFieldOrAlias("date"));
}
@Test
public void getFieldOrAliasDateWithYearAbbreviatedMonthString() {
emptyEntry.setField("year", "2003");
emptyEntry.setField("month", "mar");
- Assert.assertEquals(Optional.of("2003-03"), emptyEntry.getFieldOrAlias("date"));
+ assertEquals(Optional.of("2003-03"), emptyEntry.getFieldOrAlias("date"));
}
@Test
public void getFieldOrAliasDateWithOnlyYear() {
emptyEntry.setField("year", "2003");
- Assert.assertEquals(Optional.of("2003"), emptyEntry.getFieldOrAlias("date"));
+ assertEquals(Optional.of("2003"), emptyEntry.getFieldOrAlias("date"));
}
@Test
public void getFieldOrAliasYearWithDateYYYY() {
emptyEntry.setField("date", "2003");
- Assert.assertEquals(Optional.of("2003"), emptyEntry.getFieldOrAlias("year"));
+ assertEquals(Optional.of("2003"), emptyEntry.getFieldOrAlias("year"));
}
@Test
public void getFieldOrAliasYearWithDateYYYYMM() {
emptyEntry.setField("date", "2003-03");
- Assert.assertEquals(Optional.of("2003"), emptyEntry.getFieldOrAlias("year"));
+ assertEquals(Optional.of("2003"), emptyEntry.getFieldOrAlias("year"));
}
@Test
public void getFieldOrAliasYearWithDateYYYYMMDD() {
emptyEntry.setField("date", "2003-03-30");
- Assert.assertEquals(Optional.of("2003"), emptyEntry.getFieldOrAlias("year"));
+ assertEquals(Optional.of("2003"), emptyEntry.getFieldOrAlias("year"));
}
@Test
public void getFieldOrAliasMonthWithDateYYYYReturnsNull() {
emptyEntry.setField("date", "2003");
- Assert.assertEquals(Optional.empty(), emptyEntry.getFieldOrAlias("month"));
+ assertEquals(Optional.empty(), emptyEntry.getFieldOrAlias("month"));
}
@Test
public void getFieldOrAliasMonthWithDateYYYYMM() {
emptyEntry.setField("date", "2003-03");
- Assert.assertEquals(Optional.of("3"), emptyEntry.getFieldOrAlias("month"));
+ assertEquals(Optional.of("3"), emptyEntry.getFieldOrAlias("month"));
}
@Test
public void getFieldOrAliasMonthWithDateYYYYMMDD() {
emptyEntry.setField("date", "2003-03-30");
- Assert.assertEquals(Optional.of("3"), emptyEntry.getFieldOrAlias("month"));
+ assertEquals(Optional.of("3"), emptyEntry.getFieldOrAlias("month"));
+ }
+
+ @Test
+ public void getFieldOrAliasLatexFreeAlreadyFreeValueIsUnchanged() {
+ emptyEntry.setField("title", "A Title Without any LaTeX commands");
+ assertEquals(Optional.of("A Title Without any LaTeX commands"), emptyEntry.getFieldOrAliasLatexFree("title"));
+ }
+
+ @Test
+ public void getFieldOrAliasLatexFreeAlreadyFreeAliasValueIsUnchanged() {
+ emptyEntry.setField("journal", "A Title Without any LaTeX commands");
+ assertEquals(Optional.of("A Title Without any LaTeX commands"), emptyEntry.getFieldOrAliasLatexFree("journaltitle"));
+ }
+
+ @Test
+ public void getFieldOrAliasLatexFreeBracesAreRemoved() {
+ emptyEntry.setField("title", "{A Title with some {B}ra{C}es}");
+ assertEquals(Optional.of("A Title with some BraCes"), emptyEntry.getFieldOrAliasLatexFree("title"));
+ }
+
+ @Test
+ public void getFieldOrAliasLatexFreeBracesAreRemovedFromAlias() {
+ emptyEntry.setField("journal", "{A Title with some {B}ra{C}es}");
+ assertEquals(Optional.of("A Title with some BraCes"), emptyEntry.getFieldOrAliasLatexFree("journaltitle"));
+ }
+
+ @Test
+ public void getFieldOrAliasLatexFreeComplexConversionInAlias() {
+ emptyEntry.setField("journal", "A 32~{mA} {$\\Sigma\\Delta$}-modulator");
+ assertEquals(Optional.of("A 32\u00A0mA ΣΔ-modulator"), emptyEntry.getFieldOrAliasLatexFree("journaltitle"));
+ }
+
+ @Test
+ public void getFieldOrAliasLatexFreeDoesNotChangeDateSemantics() {
+ emptyEntry.setField("date", "2003-03-30");
+ assertEquals(Optional.of("3"), emptyEntry.getFieldOrAliasLatexFree("month"));
}
@Test(expected = NullPointerException.class)
@@ -185,161 +222,157 @@ public class BibEntryTests {
@Test(expected = NullPointerException.class)
public void addNullKeywordThrowsNPE() {
- keywordEntry.addKeyword(null, ", ");
+ keywordEntry.addKeyword((Keyword)null, ',');
Assert.fail();
}
@Test(expected = NullPointerException.class)
public void putNullKeywordListThrowsNPE() {
- keywordEntry.putKeywords(null, ", ");
+ keywordEntry.putKeywords((KeywordList)null, ',');
Assert.fail();
}
@Test(expected = NullPointerException.class)
public void putNullKeywordSeparatorThrowsNPE() {
keywordEntry.putKeywords(Arrays.asList("A", "B"), null);
- Assert.fail();
}
@Test
public void testGetSeparatedKeywordsAreCorrect() {
- String[] expected = {"Foo", "Bar"};
- Assert.assertArrayEquals(expected, keywordEntry.getKeywords().toArray());
+ assertEquals(new KeywordList("Foo", "Bar"), keywordEntry.getKeywords(','));
}
@Test
public void testAddKeywordIsCorrect() {
- keywordEntry.addKeyword("FooBar", ", ");
- String[] expected = {"Foo", "Bar", "FooBar"};
- Assert.assertArrayEquals(expected, keywordEntry.getKeywords().toArray());
+ keywordEntry.addKeyword("FooBar", ',');
+ assertEquals(new KeywordList("Foo", "Bar", "FooBar"), keywordEntry.getKeywords(','));
}
@Test
public void testAddKeywordHasChanged() {
- keywordEntry.addKeyword("FooBar", ", ");
+ keywordEntry.addKeyword("FooBar", ',');
Assert.assertTrue(keywordEntry.hasChanged());
}
@Test
public void testAddKeywordTwiceYiedsOnlyOne() {
- keywordEntry.addKeyword("FooBar", ", ");
- keywordEntry.addKeyword("FooBar", ", ");
- String[] expected = {"Foo", "Bar", "FooBar"};
- Assert.assertArrayEquals(expected, keywordEntry.getKeywords().toArray());
+ keywordEntry.addKeyword("FooBar", ',');
+ keywordEntry.addKeyword("FooBar", ',');
+ assertEquals(new KeywordList("Foo", "Bar", "FooBar"), keywordEntry.getKeywords(','));
}
@Test
public void addKeywordIsCaseSensitive() {
- keywordEntry.addKeyword("FOO", ", ");
- String[] expected = {"Foo", "Bar", "FOO"};
- Assert.assertArrayEquals(expected, keywordEntry.getKeywords().toArray());
+ keywordEntry.addKeyword("FOO", ',');
+ assertEquals(new KeywordList("Foo", "Bar", "FOO"), keywordEntry.getKeywords(','));
}
@Test
public void testAddKeywordWithDifferentCapitalizationChanges() {
- keywordEntry.addKeyword("FOO", ", ");
+ keywordEntry.addKeyword("FOO", ',');
Assert.assertTrue(keywordEntry.hasChanged());
}
@Test
public void testAddKeywordEmptyKeywordIsNotAdded() {
- keywordEntry.addKeyword("", ", ");
- String[] expected = {"Foo", "Bar"};
- Assert.assertArrayEquals(expected, keywordEntry.getKeywords().toArray());
+ keywordEntry.addKeyword("", ',');
+ assertEquals(new KeywordList("Foo", "Bar"), keywordEntry.getKeywords(','));
}
@Test
public void testAddKeywordEmptyKeywordNotChanged() {
- keywordEntry.addKeyword("", ", ");
+ keywordEntry.addKeyword("", ',');
Assert.assertFalse(keywordEntry.hasChanged());
}
@Test
public void texNewBibEntryHasNoKeywords() {
- Assert.assertTrue(emptyEntry.getKeywords().isEmpty());
+ Assert.assertTrue(emptyEntry.getKeywords(',').isEmpty());
}
@Test
public void texNewBibEntryHasNoKeywordsEvenAfterAddingEmptyKeyword() {
- emptyEntry.addKeyword("", ", ");
- Assert.assertTrue(emptyEntry.getKeywords().isEmpty());
+ emptyEntry.addKeyword("", ',');
+ Assert.assertTrue(emptyEntry.getKeywords(',').isEmpty());
}
@Test
public void texNewBibEntryAfterAddingEmptyKeywordNotChanged() {
- emptyEntry.addKeyword("", ", ");
+ emptyEntry.addKeyword("", ',');
Assert.assertFalse(emptyEntry.hasChanged());
}
@Test
public void testAddKeywordsWorksAsExpected() {
- String[] expected = {"Foo", "Bar"};
- emptyEntry.addKeywords(keywordEntry.getKeywords(), ", ");
- Assert.assertArrayEquals(expected, emptyEntry.getKeywords().toArray());
+ emptyEntry.addKeywords(Arrays.asList("Foo", "Bar"), ',');
+ assertEquals(new KeywordList("Foo", "Bar"), emptyEntry.getKeywords(','));
}
@Test
public void testPutKeywordsOverwritesOldKeywords() {
- keywordEntry.putKeywords(Arrays.asList("Yin", "Yang"), ", ");
- String[] expected = {"Yin", "Yang"};
- Assert.assertArrayEquals(expected, keywordEntry.getKeywords().toArray());
+ keywordEntry.putKeywords(Arrays.asList("Yin", "Yang"), ',');
+ assertEquals(new KeywordList("Yin", "Yang"), keywordEntry.getKeywords(','));
}
@Test
public void testPutKeywordsHasChanged() {
- keywordEntry.putKeywords(Arrays.asList("Yin", "Yang"), ", ");
+ keywordEntry.putKeywords(Arrays.asList("Yin", "Yang"), ',');
Assert.assertTrue(keywordEntry.hasChanged());
}
@Test
public void testPutKeywordsPutEmpyListErasesPreviousKeywords() {
- keywordEntry.putKeywords(Collections.emptyList(), ", ");
- Assert.assertTrue(keywordEntry.getKeywords().isEmpty());
+ keywordEntry.putKeywords(Collections.emptyList(), ',');
+ Assert.assertTrue(keywordEntry.getKeywords(',').isEmpty());
}
@Test
public void testPutKeywordsPutEmpyListHasChanged() {
- keywordEntry.putKeywords(Collections.emptyList(), ", ");
+ keywordEntry.putKeywords(Collections.emptyList(), ',');
Assert.assertTrue(keywordEntry.hasChanged());
}
@Test
public void testPutKeywordsPutEmpyListToEmptyBibentry() {
- emptyEntry.putKeywords(Collections.emptyList(), ", ");
- Assert.assertTrue(emptyEntry.getKeywords().isEmpty());
+ emptyEntry.putKeywords(Collections.emptyList(), ',');
+ Assert.assertTrue(emptyEntry.getKeywords(',').isEmpty());
}
@Test
public void testPutKeywordsPutEmpyListToEmptyBibentryNotChanged() {
- emptyEntry.putKeywords(Collections.emptyList(), ", ");
+ emptyEntry.putKeywords(Collections.emptyList(), ',');
Assert.assertFalse(emptyEntry.hasChanged());
}
@Test
public void putKeywordsToEmptyReturnsNoChange() {
- Optional<FieldChange> change = emptyEntry.putKeywords(Collections.emptyList(),
- ", ");
- Assert.assertEquals(Optional.empty(), change);
+ Optional<FieldChange> change = emptyEntry.putKeywords(Collections.emptyList(), ',');
+ assertEquals(Optional.empty(), change);
}
@Test
public void clearKeywordsReturnsChange() {
- Optional<FieldChange> change = keywordEntry.putKeywords(Collections.emptyList(),
- ", ");
- Assert.assertEquals(Optional.of(new FieldChange(keywordEntry, "keywords", "Foo, Bar", null)), change);
+ Optional<FieldChange> change = keywordEntry.putKeywords(Collections.emptyList(), ',');
+ assertEquals(Optional.of(new FieldChange(keywordEntry, "keywords", "Foo, Bar", null)), change);
}
@Test
public void changeKeywordsReturnsChange() {
- Optional<FieldChange> change = keywordEntry.putKeywords(Arrays.asList("Test", "FooTest"),
- ", ");
- Assert.assertEquals(Optional.of(new FieldChange(keywordEntry, "keywords", "Foo, Bar", "Test, FooTest")), change);
+ Optional<FieldChange> change = keywordEntry.putKeywords(Arrays.asList("Test", "FooTest"), ',');
+ assertEquals(Optional.of(new FieldChange(keywordEntry, "keywords", "Foo, Bar", "Test, FooTest")),
+ change);
}
@Test
public void putKeywordsToSameReturnsNoChange() {
- Optional<FieldChange> change = keywordEntry.putKeywords(Arrays.asList("Foo", "Bar"),
- ", ");
- Assert.assertEquals(Optional.empty(), change);
+ Optional<FieldChange> change = keywordEntry.putKeywords(Arrays.asList("Foo", "Bar"), ',');
+ assertEquals(Optional.empty(), change);
+ }
+
+ @Test
+ public void getKeywordsReturnsParsedKeywordListFromKeywordsField() {
+ BibEntry entry = new BibEntry();
+ entry.setField(FieldName.KEYWORDS, "w1, w2a w2b, w3");
+ assertEquals(new KeywordList("w1", "w2a w2b", "w3"), entry.getKeywords(','));
}
@Test
@@ -363,13 +396,13 @@ public class BibEntryTests {
be.setField("author", "Albert Einstein");
be.setCiteKey("Einstein1931");
Assert.assertTrue(be.hasCiteKey());
- Assert.assertEquals(Optional.of("Einstein1931"), be.getCiteKeyOptional());
- Assert.assertEquals(Optional.of("Albert Einstein"), be.getFieldOptional("author"));
+ assertEquals(Optional.of("Einstein1931"), be.getCiteKeyOptional());
+ assertEquals(Optional.of("Albert Einstein"), be.getField("author"));
be.clearField("author");
- Assert.assertEquals(Optional.empty(), be.getFieldOptional("author"));
+ assertEquals(Optional.empty(), be.getField("author"));
String id = IdGenerator.next();
be.setId(id);
- Assert.assertEquals(id, be.getId());
+ assertEquals(id, be.getId());
}
}
diff --git a/src/test/java/net/sf/jabref/model/entry/BibtexStringTest.java b/src/test/java/net/sf/jabref/model/entry/BibtexStringTest.java
index 26d565a..8cbfa8a 100644
--- a/src/test/java/net/sf/jabref/model/entry/BibtexStringTest.java
+++ b/src/test/java/net/sf/jabref/model/entry/BibtexStringTest.java
@@ -4,6 +4,7 @@ import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
public class BibtexStringTest {
@@ -36,4 +37,9 @@ public class BibtexStringTest {
}
+ @Test
+ public void getContentNeverReturnsNull() {
+ BibtexString bs = new BibtexString("ID", "SomeName", null);
+ assertNotNull(bs.getContent());
+ }
}
diff --git a/src/test/java/net/sf/jabref/model/entry/EntryUtilTest.java b/src/test/java/net/sf/jabref/model/entry/EntryUtilTest.java
deleted file mode 100644
index 2774968..0000000
--- a/src/test/java/net/sf/jabref/model/entry/EntryUtilTest.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package net.sf.jabref.model.entry;
-
-import java.util.Arrays;
-import java.util.LinkedHashSet;
-import java.util.Set;
-
-import org.junit.Assert;
-import org.junit.Test;
-
-public class EntryUtilTest {
-
- @Test
- public void testNCase() {
- Assert.assertEquals("", EntryUtil.capitalizeFirst(""));
- Assert.assertEquals("Hello world", EntryUtil.capitalizeFirst("Hello World"));
- Assert.assertEquals("A", EntryUtil.capitalizeFirst("a"));
- Assert.assertEquals("Aa", EntryUtil.capitalizeFirst("AA"));
- }
-
- @Test
- public void getSeparatedKeywords() {
- String keywords = "w1, w2a w2b, w3";
- Set<String> separatedKeywords = EntryUtil.getSeparatedKeywords(keywords);
- Assert.assertEquals(new LinkedHashSet<>(Arrays.asList("w1", "w2a w2b", "w3")), separatedKeywords);
- }
-
- @Test
- public void getSeparatedKeywordsEntry() {
- String keywords = "w1, w2a w2b, w3";
- BibEntry entry = new BibEntry();
- entry.setField(FieldName.KEYWORDS, keywords);
- Set<String> separatedKeywords = EntryUtil.getSeparatedKeywords(entry);
- Assert.assertEquals(new LinkedHashSet<>(Arrays.asList("w1", "w2a w2b", "w3")), separatedKeywords);
- }
-}
diff --git a/src/test/java/net/sf/jabref/model/entry/IEEETranEntryTypesTest.java b/src/test/java/net/sf/jabref/model/entry/IEEETranEntryTypesTest.java
index 6a162a5..36c93b3 100644
--- a/src/test/java/net/sf/jabref/model/entry/IEEETranEntryTypesTest.java
+++ b/src/test/java/net/sf/jabref/model/entry/IEEETranEntryTypesTest.java
@@ -10,7 +10,7 @@ public class IEEETranEntryTypesTest {
@Test
public void ctlTypeContainsYesNoFields() {
List<String> ctlFields = IEEETranEntryTypes.IEEETRANBSTCTL.getAllFields();
- List<String> ynFields = InternalBibtexFields.IEEETRANBSTCTL_YES_NO_FIELDS;
+ List<String> ynFields = InternalBibtexFields.getIEEETranBSTctlYesNoFields();
Assert.assertTrue(ctlFields.containsAll(ynFields));
}
diff --git a/src/test/java/net/sf/jabref/model/entry/KeywordListTest.java b/src/test/java/net/sf/jabref/model/entry/KeywordListTest.java
new file mode 100644
index 0000000..55b1f28
--- /dev/null
+++ b/src/test/java/net/sf/jabref/model/entry/KeywordListTest.java
@@ -0,0 +1,70 @@
+package net.sf.jabref.model.entry;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class KeywordListTest {
+
+ private KeywordList keywords;
+
+ @Before
+ public void setUp() throws Exception {
+ keywords = new KeywordList();
+ keywords.add("keywordOne");
+ keywords.add("keywordTwo");
+ }
+
+ @Test
+ public void parseEmptyStringReturnsEmptyList() throws Exception {
+ assertEquals(new KeywordList(), KeywordList.parse("", ','));
+ }
+
+ @Test
+ public void parseOneWordReturnsOneKeyword() throws Exception {
+ assertEquals(new KeywordList("keywordOne"),
+ KeywordList.parse("keywordOne", ','));
+ }
+
+ @Test
+ public void parseTwoWordReturnsTwoKeywords() throws Exception {
+ assertEquals(new KeywordList("keywordOne", "keywordTwo"),
+ KeywordList.parse("keywordOne, keywordTwo", ','));
+ }
+
+ @Test
+ public void parseTwoWordReturnsTwoKeywordsWithoutSpace() throws Exception {
+ assertEquals(new KeywordList("keywordOne", "keywordTwo"),
+ KeywordList.parse("keywordOne,keywordTwo", ','));
+ }
+
+ @Test
+ public void parseTwoWordReturnsTwoKeywordsWithDifferentDelimiter() throws Exception {
+ assertEquals(new KeywordList("keywordOne", "keywordTwo"),
+ KeywordList.parse("keywordOne| keywordTwo", '|'));
+ }
+
+ @Test
+ public void parseWordsWithWhitespaceReturnsOneKeyword() throws Exception {
+ assertEquals(new KeywordList("keyword and one"),
+ KeywordList.parse("keyword and one", ','));
+ }
+
+ @Test
+ public void parseWordsWithWhitespaceAndCommaReturnsTwoKeyword() throws Exception {
+ assertEquals(new KeywordList("keyword and one", "and two"),
+ KeywordList.parse("keyword and one, and two", ','));
+ }
+
+ @Test
+ public void parseIgnoresDuplicates() throws Exception {
+ assertEquals(new KeywordList("keywordOne", "keywordTwo"),
+ KeywordList.parse("keywordOne, keywordTwo, keywordOne", ','));
+ }
+
+ @Test
+ public void asStringAddsSpaceAfterDelimiter() throws Exception {
+ assertEquals("keywordOne, keywordTwo", keywords.getAsString(','));
+ }
+}
diff --git a/src/test/java/net/sf/jabref/model/entry/specialfields/SpecialFieldTest.java b/src/test/java/net/sf/jabref/model/entry/specialfields/SpecialFieldTest.java
new file mode 100644
index 0000000..0b866d0
--- /dev/null
+++ b/src/test/java/net/sf/jabref/model/entry/specialfields/SpecialFieldTest.java
@@ -0,0 +1,34 @@
+package net.sf.jabref.model.entry.specialfields;
+
+import java.util.Optional;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class SpecialFieldTest {
+
+
+ @Test
+ public void getSpecialFieldInstanceFromFieldNameValid() {
+ assertEquals(Optional.of(SpecialField.RANKING),
+ SpecialField.getSpecialFieldInstanceFromFieldName("ranking"));
+ }
+
+ @Test
+ public void getSpecialFieldInstanceFromFieldNameEmptyForInvalidField() {
+ assertEquals(Optional.empty(), SpecialField.getSpecialFieldInstanceFromFieldName("title"));
+ }
+
+ @Test
+ public void isSpecialFieldTrueForValidField() {
+ assertTrue(SpecialField.isSpecialField("ranking"));
+ }
+
+ @Test
+ public void isSpecialFieldFalseForInvalidField() {
+ assertFalse(SpecialField.isSpecialField("title"));
+ }
+}
diff --git a/src/test/java/net/sf/jabref/model/event/TestEventListener.java b/src/test/java/net/sf/jabref/model/event/TestEventListener.java
index 68a9f68..567a2e3 100644
--- a/src/test/java/net/sf/jabref/model/event/TestEventListener.java
+++ b/src/test/java/net/sf/jabref/model/event/TestEventListener.java
@@ -1,6 +1,9 @@
package net.sf.jabref.model.event;
+import net.sf.jabref.model.database.event.EntryAddedEvent;
+import net.sf.jabref.model.database.event.EntryRemovedEvent;
import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.event.EntryChangedEvent;
import com.google.common.eventbus.Subscribe;
diff --git a/src/test/java/net/sf/jabref/model/groups/AbstractGroupTest.java b/src/test/java/net/sf/jabref/model/groups/AbstractGroupTest.java
new file mode 100644
index 0000000..15a14f7
--- /dev/null
+++ b/src/test/java/net/sf/jabref/model/groups/AbstractGroupTest.java
@@ -0,0 +1,25 @@
+package net.sf.jabref.model.groups;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import net.sf.jabref.model.entry.BibEntry;
+
+import org.junit.Before;
+import org.mockito.Mockito;
+
+import static org.mockito.Mockito.mock;
+
+public class AbstractGroupTest {
+
+ private AbstractGroup group;
+ private final List<BibEntry> entries = new ArrayList<>();
+
+ @Before
+ public void setUp() throws Exception {
+ group = mock(AbstractGroup.class, Mockito.CALLS_REAL_METHODS);
+
+ entries.add(new BibEntry().withField("author", "author1 and author2"));
+ entries.add(new BibEntry().withField("author", "author1"));
+ }
+}
diff --git a/src/test/java/net/sf/jabref/model/groups/AllEntriesGroupTest.java b/src/test/java/net/sf/jabref/model/groups/AllEntriesGroupTest.java
new file mode 100644
index 0000000..978a220
--- /dev/null
+++ b/src/test/java/net/sf/jabref/model/groups/AllEntriesGroupTest.java
@@ -0,0 +1,14 @@
+package net.sf.jabref.model.groups;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class AllEntriesGroupTest {
+
+ @Test
+ public void testToString() {
+ assertEquals("AllEntriesGroup:", new AllEntriesGroup("").toString());
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/java/net/sf/jabref/model/groups/ExplicitGroupTest.java b/src/test/java/net/sf/jabref/model/groups/ExplicitGroupTest.java
new file mode 100644
index 0000000..5f141a4
--- /dev/null
+++ b/src/test/java/net/sf/jabref/model/groups/ExplicitGroupTest.java
@@ -0,0 +1,62 @@
+package net.sf.jabref.model.groups;
+
+import java.util.Optional;
+
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldName;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class ExplicitGroupTest {
+
+ private ExplicitGroup group;
+ private ExplicitGroup group2;
+
+ private BibEntry emptyEntry;
+
+ @Before
+ public void setUp() {
+ group = new ExplicitGroup("myExplicitGroup", GroupHierarchyType.INDEPENDENT, ',');
+ group2 = new ExplicitGroup("myExplicitGroup2", GroupHierarchyType.INCLUDING, ',');
+ emptyEntry = new BibEntry();
+ }
+
+ @Test
+ public void testToStringSimple() {
+ assertEquals("ExplicitGroup:myExplicitGroup;0;", group.toString());
+ }
+
+ @Test
+ public void toStringDoesNotWriteAssignedEntries() {
+ group.add(emptyEntry);
+
+ assertEquals("ExplicitGroup:myExplicitGroup;0;", group.toString());
+ }
+
+ @Test
+ public void addSingleGroupToBibEntrySuccessfullyIfEmptyBefore() {
+ group.add(emptyEntry);
+
+ assertEquals(Optional.of("myExplicitGroup"), emptyEntry.getField(FieldName.GROUPS));
+ }
+
+ @Test
+ public void addTwoGroupsToBibEntrySuccessfully() {
+ group.add(emptyEntry);
+ group2.add(emptyEntry);
+
+ assertEquals(Optional.of("myExplicitGroup, myExplicitGroup2"), emptyEntry.getField(FieldName.GROUPS));
+ }
+
+ @Test
+ public void noDuplicateStoredIfAlreadyInGroup() throws Exception {
+ emptyEntry.setField(FieldName.GROUPS, "myExplicitGroup");
+ group.add(emptyEntry);
+
+ assertEquals(Optional.of("myExplicitGroup"), emptyEntry.getField(FieldName.GROUPS));
+ }
+
+}
diff --git a/src/test/java/net/sf/jabref/model/groups/GroupTreeNodeTest.java b/src/test/java/net/sf/jabref/model/groups/GroupTreeNodeTest.java
new file mode 100644
index 0000000..97e8688
--- /dev/null
+++ b/src/test/java/net/sf/jabref/model/groups/GroupTreeNodeTest.java
@@ -0,0 +1,313 @@
+package net.sf.jabref.model.groups;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.search.matchers.AndMatcher;
+import net.sf.jabref.model.search.matchers.OrMatcher;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class GroupTreeNodeTest {
+
+ private final List<BibEntry> entries = new ArrayList<>();
+ private BibEntry entry;
+
+ @Before
+ public void setUp() throws Exception {
+ entries.clear();
+ entry = new BibEntry();
+ entries.add(entry);
+ entries.add(new BibEntry().withField("author", "author1 and author2"));
+ entries.add(new BibEntry().withField("author", "author1"));
+ }
+
+
+ /**
+ * Gets the marked node in the following tree of explicit groups:
+ * Root
+ * A ExplicitA, Including
+ * A ExplicitParent, Independent (= parent)
+ * B ExplicitNode, Refining (<-- this)
+ */
+ private GroupTreeNode getNodeInSimpleTree(GroupTreeNode root) {
+ root.addSubgroup(new ExplicitGroup("ExplicitA", GroupHierarchyType.INCLUDING, ','));
+ GroupTreeNode parent = root
+ .addSubgroup(new ExplicitGroup("ExplicitParent", GroupHierarchyType.INDEPENDENT, ','));
+ GroupTreeNode node = parent
+ .addSubgroup(new ExplicitGroup("ExplicitNode", GroupHierarchyType.REFINING, ','));
+ return node;
+ }
+
+ private GroupTreeNode getNodeInSimpleTree() {
+ return getNodeInSimpleTree(getRoot());
+ }
+
+ /**
+ * Gets the marked node in the following tree:
+ * Root
+ * A SearchA
+ * A ExplicitA, Including
+ * A ExplicitGrandParent (= grand parent)
+ * B ExplicitB
+ * B KeywordParent (= parent)
+ * C KeywordNode (<-- this)
+ * D ExplicitChild (= child)
+ * C SearchC
+ * C ExplicitC
+ * C KeywordC
+ * B SearchB
+ * B KeywordB
+ * A KeywordA
+ */
+ private GroupTreeNode getNodeInComplexTree(GroupTreeNode root) {
+ root.addSubgroup(getSearchGroup("SearchA"));
+ root.addSubgroup(new ExplicitGroup("ExplicitA", GroupHierarchyType.INCLUDING, ','));
+ GroupTreeNode grandParent = root
+ .addSubgroup(new ExplicitGroup("ExplicitGrandParent", GroupHierarchyType.INDEPENDENT, ','));
+ root.addSubgroup(getKeywordGroup("KeywordA"));
+
+ grandParent.addSubgroup(getExplict("ExplicitB"));
+ GroupTreeNode parent = grandParent.addSubgroup(getKeywordGroup("KeywordParent"));
+ grandParent.addSubgroup(getSearchGroup("SearchB"));
+ grandParent.addSubgroup(getKeywordGroup("KeywordB"));
+
+ GroupTreeNode node = parent.addSubgroup(getKeywordGroup("KeywordNode"));
+ parent.addSubgroup(getSearchGroup("SearchC"));
+ parent.addSubgroup(getExplict("ExplicitC"));
+ parent.addSubgroup(getKeywordGroup("KeywordC"));
+
+ node.addSubgroup(getExplict("ExplicitChild"));
+ return node;
+ }
+
+ private AbstractGroup getKeywordGroup(String name) {
+ return new KeywordGroup(name, "searchField", "searchExpression", true, false, GroupHierarchyType.INDEPENDENT,
+ ',');
+ }
+
+ private AbstractGroup getSearchGroup(String name) {
+ return new SearchGroup(name, "searchExpression", true, false, GroupHierarchyType.INCLUDING);
+ }
+
+ private AbstractGroup getExplict(String name) {
+ return new ExplicitGroup(name, GroupHierarchyType.REFINING, ',');
+ }
+
+ /*
+ public GroupTreeNode getNodeInComplexTree() {
+ return getNodeInComplexTree(new TreeNodeMock());
+ }
+ */
+
+ /**
+ * Gets the marked in the following tree:
+ * Root
+ * A
+ * A
+ * A (<- this)
+ * A
+ */
+ /*
+ public GroupTreeNode getNodeAsChild(TreeNodeMock root) {
+ root.addChild(new TreeNodeMock());
+ root.addChild(new TreeNodeMock());
+ TreeNodeMock node = new TreeNodeMock();
+ root.addChild(node);
+ root.addChild(new TreeNodeMock());
+ return node;
+ }
+ */
+ private GroupTreeNode getRoot() {
+ return GroupTreeNode.fromGroup(new AllEntriesGroup("All entries"));
+ }
+
+ @Test
+ public void getTreeAsStringInSimpleTree() throws Exception {
+ GroupTreeNode root = getRoot();
+ getNodeInSimpleTree(root);
+
+ List<String> expected = Arrays.asList(
+ "0 AllEntriesGroup:",
+ "1 ExplicitGroup:ExplicitA;2;",
+ "1 ExplicitGroup:ExplicitParent;0;",
+ "2 ExplicitGroup:ExplicitNode;1;"
+ );
+ assertEquals(expected, root.getTreeAsString());
+ }
+
+ @Test
+ public void getTreeAsStringInComplexTree() throws Exception {
+ GroupTreeNode root = getRoot();
+ getNodeInComplexTree(root);
+
+ List<String> expected = Arrays.asList(
+ "0 AllEntriesGroup:",
+ "1 SearchGroup:SearchA;2;searchExpression;1;0;",
+ "1 ExplicitGroup:ExplicitA;2;",
+ "1 ExplicitGroup:ExplicitGrandParent;0;",
+ "2 ExplicitGroup:ExplicitB;1;",
+ "2 KeywordGroup:KeywordParent;0;searchField;searchExpression;1;0;",
+ "3 KeywordGroup:KeywordNode;0;searchField;searchExpression;1;0;",
+ "4 ExplicitGroup:ExplicitChild;1;",
+ "3 SearchGroup:SearchC;2;searchExpression;1;0;",
+ "3 ExplicitGroup:ExplicitC;1;",
+ "3 KeywordGroup:KeywordC;0;searchField;searchExpression;1;0;",
+ "2 SearchGroup:SearchB;2;searchExpression;1;0;",
+ "2 KeywordGroup:KeywordB;0;searchField;searchExpression;1;0;",
+ "1 KeywordGroup:KeywordA;0;searchField;searchExpression;1;0;"
+ );
+ assertEquals(expected, root.getTreeAsString());
+ }
+
+ @Test
+ public void getSearchRuleForIndependentGroupReturnsGroupAsMatcher() {
+ GroupTreeNode node = GroupTreeNode
+ .fromGroup(new ExplicitGroup("node", GroupHierarchyType.INDEPENDENT, ','));
+ assertEquals(node.getGroup(), node.getSearchRule());
+ }
+
+ @Test
+ public void getSearchRuleForRefiningGroupReturnsParentAndGroupAsMatcher() {
+ GroupTreeNode parent = GroupTreeNode
+ .fromGroup(
+ new ExplicitGroup("parent", GroupHierarchyType.INDEPENDENT, ','));
+ GroupTreeNode node = parent
+ .addSubgroup(new ExplicitGroup("node", GroupHierarchyType.REFINING, ','));
+
+ AndMatcher matcher = new AndMatcher();
+ matcher.addRule(node.getGroup());
+ matcher.addRule(parent.getGroup());
+ assertEquals(matcher, node.getSearchRule());
+ }
+
+ @Test
+ public void getSearchRuleForIncludingGroupReturnsGroupOrSubgroupAsMatcher() {
+ GroupTreeNode node = GroupTreeNode.fromGroup(new ExplicitGroup("node", GroupHierarchyType.INCLUDING, ','));
+ GroupTreeNode child = node.addSubgroup(new ExplicitGroup("child", GroupHierarchyType.INDEPENDENT, ','));
+
+ OrMatcher matcher = new OrMatcher();
+ matcher.addRule(node.getGroup());
+ matcher.addRule(child.getGroup());
+ assertEquals(matcher, node.getSearchRule());
+ }
+
+ @Test
+ public void numberOfHitsReturnsZeroForEmptyList() throws Exception {
+ assertEquals(0, getNodeInSimpleTree().numberOfHits(Collections.emptyList()));
+ }
+
+ @Test
+ public void numberOfHitsMatchesOneEntry() throws Exception {
+ GroupTreeNode parent = getNodeInSimpleTree();
+ GroupTreeNode node = parent.addSubgroup(
+ new KeywordGroup("node", "author", "author2", true, false, GroupHierarchyType.INDEPENDENT, ','));
+ assertEquals(1, node.numberOfHits(entries));
+ }
+
+ @Test
+ public void numberOfHitsMatchesMultipleEntries() throws Exception {
+ GroupTreeNode parent = getNodeInSimpleTree();
+ GroupTreeNode node = parent.addSubgroup(
+ new KeywordGroup("node", "author", "author1", true, false, GroupHierarchyType.INDEPENDENT, ','));
+ assertEquals(2, node.numberOfHits(entries));
+ }
+
+ @Test
+ public void numberOfHitsWorksForRefiningGroups() throws Exception {
+ GroupTreeNode grandParent = getNodeInSimpleTree();
+ GroupTreeNode parent = grandParent.addSubgroup(
+ new KeywordGroup("node", "author", "author2", true, false, GroupHierarchyType.INDEPENDENT, ','));
+ GroupTreeNode node = parent.addSubgroup(
+ new KeywordGroup("node", "author", "author1", true, false, GroupHierarchyType.REFINING, ','));
+ assertEquals(1, node.numberOfHits(entries));
+ }
+
+ @Test
+ public void numberOfHitsWorksForHierarchyOfIndependentGroups() throws Exception {
+ GroupTreeNode grandParent = getNodeInSimpleTree();
+ GroupTreeNode parent = grandParent.addSubgroup(
+ new KeywordGroup("node", "author", "author2", true, false, GroupHierarchyType.INDEPENDENT, ','));
+ GroupTreeNode node = parent.addSubgroup(
+ new KeywordGroup("node", "author", "author1", true, false, GroupHierarchyType.INDEPENDENT, ','));
+ assertEquals(2, node.numberOfHits(entries));
+ }
+
+ @Test
+ public void setGroupChangesUnderlyingGroup() throws Exception {
+ GroupTreeNode node = getNodeInSimpleTree();
+ AbstractGroup newGroup = new ExplicitGroup("NewGroup", GroupHierarchyType.INDEPENDENT, ',');
+
+ node.setGroup(newGroup, true, entries);
+
+ assertEquals(newGroup, node.getGroup());
+ }
+
+ @Test
+ public void setGroupAddsPreviousAssignmentsExplicitToExplicit() throws Exception {
+ AbstractGroup oldGroup = new ExplicitGroup("OldGroup", GroupHierarchyType.INDEPENDENT, ',');
+ oldGroup.add(entry);
+ GroupTreeNode node = GroupTreeNode.fromGroup(oldGroup);
+ AbstractGroup newGroup = new ExplicitGroup("NewGroup", GroupHierarchyType.INDEPENDENT, ',');
+
+ node.setGroup(newGroup, true, entries);
+
+ assertTrue(newGroup.isMatch(entry));
+ }
+
+ @Test
+ public void setGroupWithFalseDoesNotAddsPreviousAssignments() throws Exception {
+ AbstractGroup oldGroup = new ExplicitGroup("OldGroup", GroupHierarchyType.INDEPENDENT, ',');
+ oldGroup.add(entry);
+ GroupTreeNode node = GroupTreeNode.fromGroup(oldGroup);
+ AbstractGroup newGroup = new ExplicitGroup("NewGroup", GroupHierarchyType.INDEPENDENT, ',');
+
+ node.setGroup(newGroup, false, entries);
+
+ assertFalse(newGroup.isMatch(entry));
+ }
+
+ @Test
+ public void setGroupAddsOnlyPreviousAssignments() throws Exception {
+ AbstractGroup oldGroup = new ExplicitGroup("OldGroup", GroupHierarchyType.INDEPENDENT, ',');
+ assertFalse(oldGroup.isMatch(entry));
+ GroupTreeNode node = GroupTreeNode.fromGroup(oldGroup);
+ AbstractGroup newGroup = new ExplicitGroup("NewGroup", GroupHierarchyType.INDEPENDENT, ',');
+
+ node.setGroup(newGroup, true, entries);
+
+ assertFalse(newGroup.isMatch(entry));
+ }
+
+ @Test
+ public void setGroupExplicitToSearchDoesNotKeepPreviousAssignments() throws Exception {
+ AbstractGroup oldGroup = new ExplicitGroup("OldGroup", GroupHierarchyType.INDEPENDENT, ',');
+ oldGroup.add(entry);
+ GroupTreeNode node = GroupTreeNode.fromGroup(oldGroup);
+ AbstractGroup newGroup = new SearchGroup("NewGroup", "test", false, false, GroupHierarchyType.INDEPENDENT);
+
+ node.setGroup(newGroup, true, entries);
+
+ assertFalse(newGroup.isMatch(entry));
+ }
+
+ @Test
+ public void setGroupExplicitToExplicitIsRenameAndSoRemovesPreviousAssignment() throws Exception {
+ AbstractGroup oldGroup = new ExplicitGroup("OldGroup", GroupHierarchyType.INDEPENDENT, ',');
+ oldGroup.add(entry);
+ GroupTreeNode node = GroupTreeNode.fromGroup(oldGroup);
+ AbstractGroup newGroup = new ExplicitGroup("NewGroup", GroupHierarchyType.INDEPENDENT, ',');
+
+ node.setGroup(newGroup, true, entries);
+
+ assertFalse(oldGroup.isMatch(entry));
+ }
+}
diff --git a/src/test/java/net/sf/jabref/model/groups/KeywordGroupTest.java b/src/test/java/net/sf/jabref/model/groups/KeywordGroupTest.java
new file mode 100644
index 0000000..6cec25e
--- /dev/null
+++ b/src/test/java/net/sf/jabref/model/groups/KeywordGroupTest.java
@@ -0,0 +1,110 @@
+package net.sf.jabref.model.groups;
+
+import java.util.Optional;
+
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.FieldName;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class KeywordGroupTest {
+
+ private KeywordGroup keywordTestGroup;
+ private KeywordGroup complexKeywordGroup;
+ private BibEntry emptyEntry;
+
+ @Before
+ public void setUp() {
+ keywordTestGroup = new KeywordGroup("name", "keywords", "test", false, false, GroupHierarchyType.INDEPENDENT, ',');
+ complexKeywordGroup = new KeywordGroup("name", "keywords", "\\H2O", false, false, GroupHierarchyType.INDEPENDENT, ',');
+ emptyEntry = new BibEntry();
+ }
+
+ @Test
+ public void testToString() {
+ assertEquals("KeywordGroup:name;0;keywords;test;0;0;", keywordTestGroup.toString());
+ }
+
+ @Test
+ public void testToString2() {
+ KeywordGroup anotherGroup = new KeywordGroup("myExplicitGroup", "author", "asdf", false, true,
+ GroupHierarchyType.REFINING, ',');
+ assertEquals("KeywordGroup:myExplicitGroup;1;author;asdf;0;1;", anotherGroup.toString());
+ }
+
+ @Test
+ public void containsSimpleWord() {
+ emptyEntry.setField("keywords", "test");
+
+ assertTrue(keywordTestGroup.isMatch(emptyEntry));
+ }
+
+ @Test
+ public void containsSimpleWordInSentence() throws Exception {
+ emptyEntry.setField("keywords", "Some sentence containing test word");
+
+ assertTrue(keywordTestGroup.isMatch(emptyEntry));
+ }
+
+ @Test
+ public void containsSimpleWordCommaSeparated() throws Exception {
+ emptyEntry.setField("keywords", "Some,list,containing,test,word");
+
+ assertTrue(keywordTestGroup.isMatch(emptyEntry));
+ }
+
+ @Test
+ public void containsSimpleWordSemicolonSeparated() throws Exception {
+ emptyEntry.setField("keywords", "Some;list;containing;test;word");
+
+ assertTrue(keywordTestGroup.isMatch(emptyEntry));
+ }
+
+ @Test
+ public void containsComplexWord() throws Exception {
+ emptyEntry.setField("keywords", "\\H2O");
+
+ assertTrue(complexKeywordGroup.isMatch(emptyEntry));
+ }
+
+ @Test
+ public void containsComplexWordInSentence() throws Exception {
+ emptyEntry.setField("keywords", "Some sentence containing \\H2O word");
+
+ assertTrue(complexKeywordGroup.isMatch(emptyEntry));
+ }
+
+ @Test
+ public void containsWordWithWhitespaceInSentence() throws Exception {
+ emptyEntry.setField("keywords", "Some sentence containing test word");
+
+ assertTrue(keywordTestGroup.isMatch(emptyEntry));
+ }
+
+ @Test
+ public void addGroupToBibEntrySuccessfullyIfEmptyBefore() throws Exception {
+ keywordTestGroup.add(emptyEntry);
+
+ assertEquals(Optional.of("test"), emptyEntry.getField(FieldName.KEYWORDS));
+ }
+
+ @Test
+ public void addGroupToBibEntrySuccessfullyIfNotEmptyBefore() throws Exception {
+ emptyEntry.setField(FieldName.KEYWORDS, "bla, blubb");
+ keywordTestGroup.add(emptyEntry);
+
+ assertEquals(Optional.of("bla, blubb, test"), emptyEntry.getField(FieldName.KEYWORDS));
+ }
+
+ @Test
+ public void noDuplicateStoredIfAlreadyInGroup() throws Exception {
+ emptyEntry.setField(FieldName.KEYWORDS, "test, blubb");
+ keywordTestGroup.add(emptyEntry);
+
+ assertEquals(Optional.of("test, blubb"), emptyEntry.getField(FieldName.KEYWORDS));
+ }
+}
diff --git a/src/test/java/net/sf/jabref/model/groups/SearchGroupTest.java b/src/test/java/net/sf/jabref/model/groups/SearchGroupTest.java
new file mode 100644
index 0000000..f39d9e8
--- /dev/null
+++ b/src/test/java/net/sf/jabref/model/groups/SearchGroupTest.java
@@ -0,0 +1,41 @@
+package net.sf.jabref.model.groups;
+
+import net.sf.jabref.model.entry.BibEntry;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class SearchGroupTest {
+
+
+ @Test
+ public void testContains() {
+ SearchGroup group = new SearchGroup("myExplicitGroup", "review",
+ true, true, GroupHierarchyType.INDEPENDENT);
+ assertEquals("SearchGroup:myExplicitGroup;0;review;1;1;", group.toString());
+
+ BibEntry entry = new BibEntry();
+ assertFalse(group.contains(entry));
+
+ entry.addKeyword("review", ',');
+ assertTrue(group.contains(entry));
+ }
+
+ @Test
+ public void testToStringSimple() {
+ SearchGroup group = new SearchGroup("myExplicitGroup", "author=harrer",
+ true, true, GroupHierarchyType.INDEPENDENT);
+ assertEquals("SearchGroup:myExplicitGroup;0;author=harrer;1;1;", group.toString());
+ }
+
+ @Test
+ public void testToStringComplex() {
+ SearchGroup group = new SearchGroup("myExplicitGroup", "author=\"harrer\"", true, false,
+ GroupHierarchyType.INCLUDING);
+ assertEquals("SearchGroup:myExplicitGroup;2;author=\"harrer\";1;0;", group.toString());
+ }
+
+}
diff --git a/src/test/java/net/sf/jabref/model/groups/TreeNodeTest.java b/src/test/java/net/sf/jabref/model/groups/TreeNodeTest.java
new file mode 100644
index 0000000..a68f2b7
--- /dev/null
+++ b/src/test/java/net/sf/jabref/model/groups/TreeNodeTest.java
@@ -0,0 +1,710 @@
+package net.sf.jabref.model.groups;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.function.Consumer;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.verify;
+
+ at RunWith(MockitoJUnitRunner.class)
+public class TreeNodeTest {
+
+ @Mock
+ Consumer<TreeNodeMock> subscriber;
+
+ /**
+ * Gets the marked node in the following tree:
+ * Root
+ * A
+ * A (= parent)
+ * B (<-- this)
+ */
+ private TreeNodeMock getNodeInSimpleTree(TreeNodeMock root) {
+ root.addChild(new TreeNodeMock());
+ TreeNodeMock parent = new TreeNodeMock();
+ root.addChild(parent);
+ TreeNodeMock node = new TreeNodeMock();
+ parent.addChild(node);
+ return node;
+ }
+
+ private TreeNodeMock getNodeInSimpleTree() {
+ return getNodeInSimpleTree(new TreeNodeMock());
+ }
+
+ /**
+ * Gets the marked node in the following tree:
+ * Root
+ * A
+ * A
+ * A (= grand parent)
+ * B
+ * B (= parent)
+ * C (<-- this)
+ * D (= child)
+ * C
+ * C
+ * C
+ * B
+ * B
+ * A
+ */
+ private TreeNodeMock getNodeInComplexTree(TreeNodeMock root) {
+ root.addChild(new TreeNodeMock());
+ root.addChild(new TreeNodeMock());
+ TreeNodeMock grandParent = new TreeNodeMock();
+ root.addChild(grandParent);
+ root.addChild(new TreeNodeMock());
+
+ grandParent.addChild(new TreeNodeMock());
+ TreeNodeMock parent = new TreeNodeMock();
+ grandParent.addChild(parent);
+ grandParent.addChild(new TreeNodeMock());
+ grandParent.addChild(new TreeNodeMock());
+
+ TreeNodeMock node = new TreeNodeMock();
+ parent.addChild(node);
+ parent.addChild(new TreeNodeMock());
+ parent.addChild(new TreeNodeMock());
+ parent.addChild(new TreeNodeMock());
+
+ node.addChild(new TreeNodeMock());
+ return node;
+ }
+
+ private TreeNodeMock getNodeInComplexTree() {
+ return getNodeInComplexTree(new TreeNodeMock());
+ }
+
+ /**
+ * Gets the marked in the following tree:
+ * Root
+ * A
+ * A
+ * A (<- this)
+ * A
+ */
+ private TreeNodeMock getNodeAsChild(TreeNodeMock root) {
+ root.addChild(new TreeNodeMock());
+ root.addChild(new TreeNodeMock());
+ TreeNodeMock node = new TreeNodeMock();
+ root.addChild(node);
+ root.addChild(new TreeNodeMock());
+ return node;
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void constructorChecksThatClassImplementsCorrectInterface() {
+ new WrongTreeNodeImplementation();
+ }
+
+ @Test
+ public void constructorExceptsCorrectImplementation() {
+ TreeNodeMock treeNode = new TreeNodeMock();
+ assertNotNull(treeNode);
+ }
+
+ @Test
+ public void newTreeNodeHasNoParentOrChildren() {
+ TreeNodeMock treeNode = new TreeNodeMock();
+ assertEquals(Optional.empty(), treeNode.getParent());
+ assertEquals(Collections.emptyList(), treeNode.getChildren());
+ assertNotNull(treeNode);
+ }
+
+ @Test
+ public void getIndexedPathFromRootReturnsEmptyListForRoot() {
+ TreeNodeMock root = new TreeNodeMock();
+ assertEquals(Collections.emptyList(), root.getIndexedPathFromRoot());
+ }
+
+ @Test
+ public void getIndexedPathFromRootSimplePath() {
+ assertEquals(Arrays.asList(1, 0), getNodeInSimpleTree().getIndexedPathFromRoot());
+ }
+
+ @Test
+ public void getIndexedPathFromRootComplexPath() {
+ assertEquals(Arrays.asList(2, 1, 0), getNodeInComplexTree().getIndexedPathFromRoot());
+ }
+
+ @Test
+ public void getDescendantSimplePath() {
+ TreeNodeMock root = new TreeNodeMock();
+ TreeNodeMock node = getNodeInSimpleTree(root);
+ assertEquals(node, root.getDescendant(Arrays.asList(1, 0)).get());
+ }
+
+ @Test
+ public void getDescendantComplexPath() {
+ TreeNodeMock root = new TreeNodeMock();
+ TreeNodeMock node = getNodeInComplexTree(root);
+ assertEquals(node, root.getDescendant(Arrays.asList(2, 1, 0)).get());
+ }
+
+ @Test
+ public void getDescendantNonExistentReturnsEmpty() {
+ TreeNodeMock root = new TreeNodeMock();
+ getNodeInComplexTree(root);
+ assertEquals(Optional.empty(), root.getDescendant(Arrays.asList(1, 100, 0)));
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void getPositionInParentForRootThrowsException() {
+ TreeNodeMock root = new TreeNodeMock();
+ root.getPositionInParent();
+ }
+
+ @Test
+ public void getPositionInParentSimpleTree() {
+ TreeNodeMock root = new TreeNodeMock();
+ TreeNodeMock node = getNodeAsChild(root);
+ assertEquals(2, node.getPositionInParent());
+ }
+
+ @Test
+ public void getIndexOfNonExistentChildReturnsEmpty() {
+ TreeNodeMock root = new TreeNodeMock();
+ assertEquals(Optional.empty(), root.getIndexOfChild(new TreeNodeMock()));
+ }
+
+ @Test
+ public void getIndexOfChild() {
+ TreeNodeMock root = new TreeNodeMock();
+ TreeNodeMock node = getNodeAsChild(root);
+ assertEquals((Integer)2, root.getIndexOfChild(node).get());
+ }
+
+ @Test
+ public void getLevelOfRoot() {
+ TreeNodeMock root = new TreeNodeMock();
+ assertEquals(0, root.getLevel());
+ }
+
+ @Test
+ public void getLevelInSimpleTree() {
+ assertEquals(2, getNodeInSimpleTree().getLevel());
+ }
+
+ @Test
+ public void getLevelInComplexTree() {
+ assertEquals(3, getNodeInComplexTree().getLevel());
+ }
+
+ @Test
+ public void getChildCountInSimpleTree() {
+ TreeNodeMock root = new TreeNodeMock();
+ getNodeInSimpleTree(root);
+ assertEquals(2, root.getNumberOfChildren());
+ }
+
+ @Test
+ public void getChildCountInComplexTree() {
+ TreeNodeMock root = new TreeNodeMock();
+ getNodeInComplexTree(root);
+ assertEquals(4, root.getNumberOfChildren());
+ }
+
+ @Test
+ public void moveToAddsAsLastChildInSimpleTree() {
+ TreeNodeMock root = new TreeNodeMock();
+ TreeNodeMock node = getNodeInSimpleTree(root);
+ node.moveTo(root);
+ assertEquals((Integer)2, root.getIndexOfChild(node).get());
+ }
+
+ @Test
+ public void moveToAddsAsLastChildInComplexTree() {
+ TreeNodeMock root = new TreeNodeMock();
+ TreeNodeMock node = getNodeInComplexTree(root);
+ node.moveTo(root);
+ assertEquals((Integer)4, root.getIndexOfChild(node).get());
+ }
+
+ @Test
+ public void moveToChangesParent() {
+ TreeNodeMock root = new TreeNodeMock();
+ TreeNodeMock node = getNodeInSimpleTree(root);
+ node.moveTo(root);
+ assertEquals(root, node.getParent().get());
+ }
+
+ @Test
+ public void moveToInSameLevelAddsAtEnd() {
+ TreeNodeMock root = new TreeNodeMock();
+ TreeNodeMock child1 = new TreeNodeMock();
+ TreeNodeMock child2 = new TreeNodeMock();
+ root.addChild(child1);
+ root.addChild(child2);
+
+ child1.moveTo(root);
+
+ assertEquals(Arrays.asList(child2, child1), root.getChildren());
+ }
+
+ @Test
+ public void getPathFromRootInSimpleTree() {
+ TreeNodeMock root = new TreeNodeMock();
+ TreeNodeMock node = getNodeInSimpleTree(root);
+
+ List<TreeNodeMock> path = node.getPathFromRoot();
+ assertEquals(3, path.size());
+ assertEquals(root, path.get(0));
+ assertEquals(node, path.get(2));
+ }
+
+ @Test
+ public void getPathFromRootInComplexTree() {
+ TreeNodeMock root = new TreeNodeMock();
+ TreeNodeMock node = getNodeInComplexTree(root);
+
+ List<TreeNodeMock> path = node.getPathFromRoot();
+ assertEquals(4, path.size());
+ assertEquals(root, path.get(0));
+ assertEquals(node, path.get(3));
+ }
+
+ @Test
+ public void getPreviousSiblingReturnsCorrect() {
+ TreeNodeMock root = new TreeNodeMock();
+ root.addChild(new TreeNodeMock());
+ TreeNodeMock previous = new TreeNodeMock();
+ root.addChild(previous);
+ TreeNodeMock node = new TreeNodeMock();
+ root.addChild(node);
+ root.addChild(new TreeNodeMock());
+
+ assertEquals(previous, node.getPreviousSibling().get());
+ }
+
+ @Test
+ public void getPreviousSiblingForRootReturnsEmpty() {
+ TreeNodeMock root = new TreeNodeMock();
+ assertEquals(Optional.empty(), root.getPreviousSibling());
+ }
+
+ @Test
+ public void getPreviousSiblingForNonexistentReturnsEmpty() {
+ TreeNodeMock root = new TreeNodeMock();
+ TreeNodeMock node = new TreeNodeMock();
+ root.addChild(node);
+ assertEquals(Optional.empty(), node.getPreviousSibling());
+ }
+
+ @Test
+ public void getNextSiblingReturnsCorrect() {
+ TreeNodeMock root = new TreeNodeMock();
+ root.addChild(new TreeNodeMock());
+ TreeNodeMock node = new TreeNodeMock();
+ root.addChild(node);
+ TreeNodeMock next = new TreeNodeMock();
+ root.addChild(next);
+ root.addChild(new TreeNodeMock());
+
+ assertEquals(next, node.getNextSibling().get());
+ }
+
+ @Test
+ public void getNextSiblingForRootReturnsEmpty() {
+ TreeNodeMock root = new TreeNodeMock();
+ assertEquals(Optional.empty(), root.getNextSibling());
+ }
+
+ @Test
+ public void getNextSiblingForNonexistentReturnsEmpty() {
+ TreeNodeMock root = new TreeNodeMock();
+ TreeNodeMock node = new TreeNodeMock();
+ root.addChild(node);
+ assertEquals(Optional.empty(), node.getPreviousSibling());
+ }
+
+ @Test
+ public void getParentReturnsCorrect() {
+ TreeNodeMock root = new TreeNodeMock();
+ TreeNodeMock node = getNodeAsChild(root);
+
+ assertEquals(root, node.getParent().get());
+ }
+
+ @Test
+ public void getParentForRootReturnsEmpty() {
+ TreeNodeMock root = new TreeNodeMock();
+ assertEquals(Optional.empty(), root.getParent());
+ }
+
+ @Test
+ public void getChildAtReturnsCorrect() {
+ TreeNodeMock root = new TreeNodeMock();
+ TreeNodeMock node = getNodeAsChild(root);
+
+ assertEquals(node, root.getChildAt(2).get());
+ }
+
+ @Test
+ public void getChildAtInvalidIndexReturnsEmpty() {
+ TreeNodeMock root = new TreeNodeMock();
+ root.addChild(new TreeNodeMock());
+ root.addChild(new TreeNodeMock());
+ assertEquals(Optional.empty(), root.getChildAt(10));
+ }
+
+ @Test
+ public void getRootReturnsTrueForRoot() {
+ TreeNodeMock root = new TreeNodeMock();
+ assertTrue(root.isRoot());
+ }
+
+ @Test
+ public void getRootReturnsFalseForChild() {
+ assertFalse(getNodeInSimpleTree().isRoot());
+ }
+
+ @Test
+ public void nodeIsAncestorOfItself() {
+ TreeNodeMock root = new TreeNodeMock();
+ assertTrue(root.isAncestorOf(root));
+ }
+
+ @Test
+ public void isAncestorOfInSimpleTree() {
+ TreeNodeMock root = new TreeNodeMock();
+ TreeNodeMock node = getNodeInSimpleTree(root);
+ assertTrue(root.isAncestorOf(node));
+ }
+
+ @Test
+ public void isAncestorOfInComplexTree() {
+ TreeNodeMock root = new TreeNodeMock();
+ TreeNodeMock node = getNodeInComplexTree(root);
+ assertTrue(root.isAncestorOf(node));
+ }
+
+ @Test
+ public void getRootOfSingleNode() {
+ TreeNodeMock root = new TreeNodeMock();
+ assertEquals(root, root.getRoot());
+ }
+
+ @Test
+ public void getRootInSimpleTree() {
+ TreeNodeMock root = new TreeNodeMock();
+ TreeNodeMock node = getNodeInSimpleTree(root);
+ assertEquals(root, node.getRoot());
+ }
+
+ @Test
+ public void getRootInComplexTree() {
+ TreeNodeMock root = new TreeNodeMock();
+ TreeNodeMock node = getNodeInComplexTree(root);
+ assertEquals(root, node.getRoot());
+ }
+
+ @Test
+ public void isLeafIsCorrectForRootWithoutChildren() {
+ TreeNodeMock root = new TreeNodeMock();
+ assertTrue(root.isLeaf());
+ }
+
+ @Test
+ public void removeFromParentSetsParentToEmpty() {
+ TreeNodeMock root = new TreeNodeMock();
+ TreeNodeMock node = getNodeAsChild(root);
+
+ node.removeFromParent();
+ assertEquals(Optional.empty(), node.getParent());
+ }
+
+ @Test
+ public void removeFromParentRemovesNodeFromChildrenCollection() {
+ TreeNodeMock root = new TreeNodeMock();
+ TreeNodeMock node = getNodeAsChild(root);
+
+ node.removeFromParent();
+ assertFalse(root.getChildren().contains(node));
+ }
+
+ @Test
+ public void removeAllChildrenSetsParentOfChildToEmpty() {
+ TreeNodeMock root = new TreeNodeMock();
+ TreeNodeMock node = getNodeAsChild(root);
+
+ root.removeAllChildren();
+ assertEquals(Optional.empty(), node.getParent());
+ }
+
+ @Test
+ public void removeAllChildrenRemovesAllNodesFromChildrenCollection() {
+ TreeNodeMock root = new TreeNodeMock();
+ getNodeAsChild(root);
+
+ root.removeAllChildren();
+ assertEquals(Collections.emptyList(), root.getChildren());
+ }
+
+ @Test
+ public void getFirstChildAtReturnsCorrect() {
+ TreeNodeMock root = new TreeNodeMock();
+ TreeNodeMock node = new TreeNodeMock();
+ root.addChild(node);
+
+ assertEquals(node, root.getFirstChild().get());
+ }
+
+ @Test
+ public void getFirstChildAtLeafReturnsEmpty() {
+ TreeNodeMock root = new TreeNodeMock();
+ TreeNodeMock leaf = getNodeAsChild(root);
+ assertEquals(Optional.empty(), leaf.getFirstChild());
+ }
+
+ @Test
+ public void isNodeDescendantInFirstLevel() {
+ TreeNodeMock root = new TreeNodeMock();
+ TreeNodeMock child = getNodeAsChild(root);
+ assertTrue(root.isNodeDescendant(child));
+ }
+
+ @Test
+ public void isNodeDescendantInComplex() {
+ TreeNodeMock root = new TreeNodeMock();
+ TreeNodeMock descendant = getNodeInComplexTree(root);
+ assertTrue(root.isNodeDescendant(descendant));
+ }
+
+ @Test
+ public void getChildrenReturnsAllChildren() {
+ TreeNodeMock root = new TreeNodeMock();
+ TreeNodeMock child1 = new TreeNodeMock();
+ TreeNodeMock child2 = new TreeNodeMock();
+ root.addChild(child1);
+ root.addChild(child2);
+
+ assertEquals(Arrays.asList(child1, child2), root.getChildren());
+ }
+
+ @Test
+ public void removeChildSetsParentToEmpty() {
+ TreeNodeMock root = new TreeNodeMock();
+ TreeNodeMock node = getNodeAsChild(root);
+
+ root.removeChild(node);
+ assertEquals(Optional.empty(), node.getParent());
+ }
+
+ @Test
+ public void removeChildRemovesNodeFromChildrenCollection() {
+ TreeNodeMock root = new TreeNodeMock();
+ TreeNodeMock node = getNodeAsChild(root);
+
+ root.removeChild(node);
+ assertFalse(root.getChildren().contains(node));
+ }
+
+ @Test
+ public void removeChildIndexSetsParentToEmpty() {
+ TreeNodeMock root = new TreeNodeMock();
+ TreeNodeMock node = getNodeAsChild(root);
+
+ root.removeChild(2);
+ assertEquals(Optional.empty(), node.getParent());
+ }
+
+ @Test
+ public void removeChildIndexRemovesNodeFromChildrenCollection() {
+ TreeNodeMock root = new TreeNodeMock();
+ TreeNodeMock node = getNodeAsChild(root);
+
+ root.removeChild(2);
+ assertFalse(root.getChildren().contains(node));
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void addThrowsExceptionIfNodeHasParent() {
+ TreeNodeMock root = new TreeNodeMock();
+ TreeNodeMock node = getNodeAsChild(root);
+ root.addChild(node);
+ }
+
+ @Test
+ public void moveAllChildrenToAddsAtSpecifiedPosition() {
+ TreeNodeMock root = new TreeNodeMock();
+ TreeNodeMock node = new TreeNodeMock();
+ root.addChild(node);
+ TreeNodeMock child1 = new TreeNodeMock();
+ TreeNodeMock child2 = new TreeNodeMock();
+ node.addChild(child1);
+ node.addChild(child2);
+
+ node.moveAllChildrenTo(root, 0);
+ assertEquals(Arrays.asList(child1, child2, node), root.getChildren());
+ }
+
+ @Test
+ public void moveAllChildrenToChangesParent() {
+ TreeNodeMock root = new TreeNodeMock();
+ TreeNodeMock node = new TreeNodeMock();
+ root.addChild(node);
+ TreeNodeMock child1 = new TreeNodeMock();
+ TreeNodeMock child2 = new TreeNodeMock();
+ node.addChild(child1);
+ node.addChild(child2);
+
+ node.moveAllChildrenTo(root, 0);
+ assertEquals(root, child1.getParent().get());
+ assertEquals(root, child2.getParent().get());
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void moveAllChildrenToDescendantThrowsException() {
+ TreeNodeMock root = new TreeNodeMock();
+ TreeNodeMock node = getNodeAsChild(root);
+
+ root.moveAllChildrenTo(node, 0);
+ }
+
+ @Test
+ public void sortChildrenSortsInFirstLevel() {
+ TreeNodeMock root = new TreeNodeMock();
+ TreeNodeMock child1 = new TreeNodeMock("a");
+ TreeNodeMock child2 = new TreeNodeMock("b");
+ TreeNodeMock child3 = new TreeNodeMock("c");
+ root.addChild(child2);
+ root.addChild(child3);
+ root.addChild(child1);
+
+ root.sortChildren((o1, o2) -> o1.getName().compareToIgnoreCase(o2.getName()), false);
+ assertEquals(Arrays.asList(child1, child2, child3), root.getChildren());
+ }
+
+ @Test
+ public void sortChildrenRecursiveSortsInDeeperLevel() {
+ TreeNodeMock root = new TreeNodeMock();
+ TreeNodeMock node = getNodeInSimpleTree(root);
+ TreeNodeMock child1 = new TreeNodeMock("a");
+ TreeNodeMock child2 = new TreeNodeMock("b");
+ TreeNodeMock child3 = new TreeNodeMock("c");
+ node.addChild(child2);
+ node.addChild(child3);
+ node.addChild(child1);
+
+ root.sortChildren((o1, o2) -> o1.getName().compareToIgnoreCase(o2.getName()), true);
+ assertEquals(Arrays.asList(child1, child2, child3), node.getChildren());
+ }
+
+ @Test
+ public void copySubtreeCopiesChildren() {
+ TreeNodeMock root = new TreeNodeMock();
+ TreeNodeMock node = getNodeAsChild(root);
+
+ TreeNodeMock copiedRoot = root.copySubtree();
+ assertEquals(Optional.empty(), copiedRoot.getParent());
+ assertFalse(copiedRoot.getChildren().contains(node));
+ assertEquals(root.getNumberOfChildren(), copiedRoot.getNumberOfChildren());
+ }
+
+ @Test
+ public void addChildSomewhereInTreeInvokesChangeEvent() {
+ TreeNodeMock root = new TreeNodeMock();
+ TreeNodeMock node = getNodeInComplexTree(root);
+
+ root.subscribeToDescendantChanged(subscriber);
+
+ node.addChild(new TreeNodeMock());
+ verify(subscriber).accept(node);
+ }
+
+ @Test
+ public void moveNodeSomewhereInTreeInvokesChangeEvent() {
+ TreeNodeMock root = new TreeNodeMock();
+ TreeNodeMock node = getNodeInComplexTree(root);
+ TreeNodeMock oldParent = node.getParent().get();
+
+ root.subscribeToDescendantChanged(subscriber);
+
+ node.moveTo(root);
+ verify(subscriber).accept(root);
+ verify(subscriber).accept(oldParent);
+ }
+
+ @Test
+ public void removeChildSomewhereInTreeInvokesChangeEvent() {
+ TreeNodeMock root = new TreeNodeMock();
+ TreeNodeMock node = getNodeInComplexTree(root);
+ TreeNodeMock child = node.addChild(new TreeNodeMock());
+
+ root.subscribeToDescendantChanged(subscriber);
+
+ node.removeChild(child);
+ verify(subscriber).accept(node);
+ }
+
+ @Test
+ public void removeChildIndexSomewhereInTreeInvokesChangeEvent() {
+ TreeNodeMock root = new TreeNodeMock();
+ TreeNodeMock node = getNodeInComplexTree(root);
+ node.addChild(new TreeNodeMock());
+
+ root.subscribeToDescendantChanged(subscriber);
+
+ node.removeChild(0);
+ verify(subscriber).accept(node);
+ }
+
+ /**
+ * This is just a dummy class deriving from TreeNode<T> so that we can test the generic class
+ */
+ private class TreeNodeMock extends TreeNode<TreeNodeMock> {
+
+ private final String name;
+
+ public TreeNodeMock() {
+ this("");
+ }
+
+ public TreeNodeMock(String name) {
+ super(TreeNodeMock.class);
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String toString() {
+ return "TreeNodeMock{" +
+ "name='" + name + '\'' +
+ '}';
+ }
+
+ @Override
+ public TreeNodeMock copyNode() {
+ return new TreeNodeMock(name);
+ }
+ }
+
+ private static class WrongTreeNodeImplementation extends TreeNode<TreeNodeMock> {
+ // This class is a wrong derived class of TreeNode<T>
+ // since it does not extends TreeNode<WrongTreeNodeImplementation>
+ // See test constructorChecksThatClassImplementsCorrectInterface
+ public WrongTreeNodeImplementation() {
+ super(TreeNodeMock.class);
+ }
+
+ @Override
+ public TreeNodeMock copyNode() {
+ return null;
+ }
+ }
+}
diff --git a/src/test/java/net/sf/jabref/model/search/matchers/MatcherSetsTest.java b/src/test/java/net/sf/jabref/model/search/matchers/MatcherSetsTest.java
new file mode 100644
index 0000000..6f0be29
--- /dev/null
+++ b/src/test/java/net/sf/jabref/model/search/matchers/MatcherSetsTest.java
@@ -0,0 +1,50 @@
+package net.sf.jabref.model.search.matchers;
+
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.search.rules.MockSearchMatcher;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+
+public class MatcherSetsTest {
+
+ @Test
+ public void testBuildAnd() {
+ MatcherSet matcherSet = MatcherSets.build(MatcherSets.MatcherType.AND);
+ assertTrue(matcherSet.isMatch(new BibEntry()));
+
+ matcherSet.addRule(new MockSearchMatcher(true));
+ assertTrue(matcherSet.isMatch(new BibEntry()));
+
+ matcherSet.addRule(new MockSearchMatcher(false));
+ assertFalse(matcherSet.isMatch(new BibEntry()));
+ }
+
+ @Test
+ public void testBuildOr() {
+ MatcherSet matcherSet = MatcherSets.build(MatcherSets.MatcherType.OR);
+ assertFalse(matcherSet.isMatch(new BibEntry()));
+
+ matcherSet.addRule(new MockSearchMatcher(true));
+ assertTrue(matcherSet.isMatch(new BibEntry()));
+
+ matcherSet.addRule(new MockSearchMatcher(false));
+ assertTrue(matcherSet.isMatch(new BibEntry()));
+ }
+
+ @Test
+ public void testBuildNotWithTrue() {
+ NotMatcher matcher = new NotMatcher(new MockSearchMatcher(true));
+ assertFalse(matcher.isMatch(new BibEntry()));
+ }
+
+ @Test
+ public void testBuildNotWithFalse() {
+ NotMatcher matcher = new NotMatcher(new MockSearchMatcher(false));
+ assertTrue(matcher.isMatch(new BibEntry()));
+ }
+
+}
diff --git a/src/test/java/net/sf/jabref/model/search/rules/ContainBasedSearchRuleTest.java b/src/test/java/net/sf/jabref/model/search/rules/ContainBasedSearchRuleTest.java
new file mode 100644
index 0000000..958de6f
--- /dev/null
+++ b/src/test/java/net/sf/jabref/model/search/rules/ContainBasedSearchRuleTest.java
@@ -0,0 +1,54 @@
+package net.sf.jabref.model.search.rules;
+
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.BibtexEntryTypes;
+import net.sf.jabref.model.entry.IdGenerator;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Test case for ContainBasedSearchRule.
+ */
+public class ContainBasedSearchRuleTest {
+
+ @Test
+ public void testBasicSearchParsing() {
+ BibEntry be = makeBibtexEntry();
+ ContainBasedSearchRule bsCaseSensitive = new ContainBasedSearchRule(true);
+ ContainBasedSearchRule bsCaseInsensitive = new ContainBasedSearchRule(false);
+ RegexBasedSearchRule bsCaseSensitiveRegexp = new RegexBasedSearchRule(true);
+ RegexBasedSearchRule bsCaseInsensitiveRegexp = new RegexBasedSearchRule(false);
+
+ String query = "marine 2001 shields";
+
+ Assert.assertEquals(false, bsCaseSensitive.applyRule(query, be));
+ Assert.assertEquals(true, bsCaseInsensitive.applyRule(query, be));
+ Assert.assertEquals(false, bsCaseSensitiveRegexp.applyRule(query, be));
+ Assert.assertEquals(false, bsCaseInsensitiveRegexp.applyRule(query, be));
+
+ query = "\"marine larviculture\"";
+
+ Assert.assertEquals(false, bsCaseSensitive.applyRule(query, be));
+ Assert.assertEquals(false, bsCaseInsensitive.applyRule(query, be));
+ Assert.assertEquals(false, bsCaseSensitiveRegexp.applyRule(query, be));
+ Assert.assertEquals(false, bsCaseInsensitiveRegexp.applyRule(query, be));
+
+ query = "marine [A-Za-z]* larviculture";
+
+ Assert.assertEquals(false, bsCaseSensitive.applyRule(query, be));
+ Assert.assertEquals(false, bsCaseInsensitive.applyRule(query, be));
+ Assert.assertEquals(false, bsCaseSensitiveRegexp.applyRule(query, be));
+ Assert.assertEquals(true, bsCaseInsensitiveRegexp.applyRule(query, be));
+
+ }
+
+ public BibEntry makeBibtexEntry() {
+ BibEntry e = new BibEntry(IdGenerator.next(), BibtexEntryTypes.INCOLLECTION.getName());
+ e.setField("title", "Marine finfish larviculture in Europe");
+ e.setField("bibtexkey", "shields01");
+ e.setField("year", "2001");
+ e.setField("author", "Kevin Shields");
+ return e;
+ }
+}
diff --git a/src/test/java/net/sf/jabref/model/search/rules/MockSearchMatcher.java b/src/test/java/net/sf/jabref/model/search/rules/MockSearchMatcher.java
new file mode 100644
index 0000000..3190450
--- /dev/null
+++ b/src/test/java/net/sf/jabref/model/search/rules/MockSearchMatcher.java
@@ -0,0 +1,21 @@
+package net.sf.jabref.model.search.rules;
+
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.search.SearchMatcher;
+
+/**
+ * Mock search rule that returns the values passed. Useful for testing.
+ */
+public class MockSearchMatcher implements SearchMatcher {
+
+ private final boolean result;
+
+ public MockSearchMatcher(boolean result) {
+ this.result = result;
+ }
+
+ @Override
+ public boolean isMatch(BibEntry entry) {
+ return result;
+ }
+}
diff --git a/src/test/java/net/sf/jabref/model/search/rules/SentenceAnalyzerTest.java b/src/test/java/net/sf/jabref/model/search/rules/SentenceAnalyzerTest.java
new file mode 100644
index 0000000..9cc2501
--- /dev/null
+++ b/src/test/java/net/sf/jabref/model/search/rules/SentenceAnalyzerTest.java
@@ -0,0 +1,20 @@
+package net.sf.jabref.model.search.rules;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class SentenceAnalyzerTest {
+
+ @Test
+ public void testGetWords() {
+ assertEquals(Arrays.asList("a","b"), new SentenceAnalyzer("a b").getWords());
+ assertEquals(Arrays.asList("a","b"), new SentenceAnalyzer(" a b ").getWords());
+ assertEquals(Collections.singletonList("b "), new SentenceAnalyzer("\"b \" ").getWords());
+ assertEquals(Collections.singletonList(" a"), new SentenceAnalyzer(" \\ a").getWords());
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/java/net/sf/jabref/model/strings/StringUtilTest.java b/src/test/java/net/sf/jabref/model/strings/StringUtilTest.java
new file mode 100644
index 0000000..a8d12d3
--- /dev/null
+++ b/src/test/java/net/sf/jabref/model/strings/StringUtilTest.java
@@ -0,0 +1,352 @@
+package net.sf.jabref.model.strings;
+
+import java.util.Optional;
+
+import net.sf.jabref.model.entry.FileField;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class StringUtilTest {
+
+ @Test
+ public void testBooleanToBinaryString() {
+ assertEquals("0", StringUtil.booleanToBinaryString(false));
+ assertEquals("1", StringUtil.booleanToBinaryString(true));
+ }
+
+ @Test
+ public void testQuoteSimple() {
+ assertEquals("a::", StringUtil.quote("a:", "", ':'));
+ }
+
+ @Test
+ public void testQuoteNullQuotation() {
+ assertEquals("a::", StringUtil.quote("a:", null, ':'));
+ }
+
+ @Test
+ public void testQuoteNullString() {
+ assertEquals("", StringUtil.quote(null, ";", ':'));
+ }
+
+ @Test
+ public void testQuoteQuotationCharacter() {
+ assertEquals("a:::;", StringUtil.quote("a:;", ";", ':'));
+ }
+
+ @Test
+ public void testQuoteMoreComplicated() {
+ assertEquals("a::b:%c:;", StringUtil.quote("a:b%c;", "%;", ':'));
+ }
+
+ private static final String[][] STRING_ARRAY_1 = {{"a", "b"}, {"c", "d"}};
+ private static final String ENCODED_STRING_ARRAY_1 = "a:b;c:d";
+ private static final String[][] STRING_ARRAY_2_WITH_NULL = {{"a", null}, {"c", "d"}};
+ private static final String ENCODED_STRING_ARRAY_2_WITH_NULL = "a:" + null + ";c:d";
+ private static final String[][] STRING_ARRAY_2 = {{"a", ""}, {"c", "d"}};
+ private static final String ENCODED_STRING_ARRAY_2 = "a:;c:d";
+ private static final String[][] STRING_ARRAY_3 = {{"a", ":b"}, {"c;", "d"}};
+ private static final String ENCODED_STRING_ARRAY_3 = "a:\\:b;c\\;:d";
+
+
+ @Test
+ public void testUnifyLineBreaks() {
+ // Mac < v9
+ String result = StringUtil.unifyLineBreaks("\r", "newline");
+ assertEquals("newline", result);
+ // Windows
+ result = StringUtil.unifyLineBreaks("\r\n", "newline");
+ assertEquals("newline", result);
+ // Unix
+ result = StringUtil.unifyLineBreaks("\n", "newline");
+ assertEquals("newline", result);
+ }
+
+ @Test
+ public void testGetCorrectFileName() {
+ assertEquals("aa.bib", StringUtil.getCorrectFileName("aa", "bib"));
+ assertEquals(".login.bib", StringUtil.getCorrectFileName(".login", "bib"));
+ assertEquals("a.bib", StringUtil.getCorrectFileName("a.bib", "bib"));
+ assertEquals("a.bib", StringUtil.getCorrectFileName("a.bib", "BIB"));
+ assertEquals("a.bib", StringUtil.getCorrectFileName("a", "bib"));
+ assertEquals("a.bb", StringUtil.getCorrectFileName("a.bb", "bib"));
+ assertEquals("", StringUtil.getCorrectFileName(null, "bib"));
+ }
+
+ @Test
+ public void testQuoteForHTML() {
+ assertEquals("!", StringUtil.quoteForHTML("!"));
+ assertEquals("!!!", StringUtil.quoteForHTML("!!!"));
+ }
+
+ @Test
+ public void testRemoveBracesAroundCapitals() {
+ assertEquals("ABC", StringUtil.removeBracesAroundCapitals("{ABC}"));
+ assertEquals("ABC", StringUtil.removeBracesAroundCapitals("{{ABC}}"));
+ assertEquals("{abc}", StringUtil.removeBracesAroundCapitals("{abc}"));
+ assertEquals("ABCDEF", StringUtil.removeBracesAroundCapitals("{ABC}{DEF}"));
+ }
+
+ @Test
+ public void testPutBracesAroundCapitals() {
+ assertEquals("{ABC}", StringUtil.putBracesAroundCapitals("ABC"));
+ assertEquals("{ABC}", StringUtil.putBracesAroundCapitals("{ABC}"));
+ assertEquals("abc", StringUtil.putBracesAroundCapitals("abc"));
+ assertEquals("#ABC#", StringUtil.putBracesAroundCapitals("#ABC#"));
+ assertEquals("{ABC} def {EFG}", StringUtil.putBracesAroundCapitals("ABC def EFG"));
+ }
+
+ @Test
+ public void testShaveString() {
+
+ assertEquals("", StringUtil.shaveString(null));
+ assertEquals("", StringUtil.shaveString(""));
+ assertEquals("aaa", StringUtil.shaveString(" aaa\t\t\n\r"));
+ assertEquals("a", StringUtil.shaveString(" {a} "));
+ assertEquals("a", StringUtil.shaveString(" \"a\" "));
+ assertEquals("{a}", StringUtil.shaveString(" {{a}} "));
+ assertEquals("{a}", StringUtil.shaveString(" \"{a}\" "));
+ assertEquals("\"{a\"}", StringUtil.shaveString(" \"{a\"} "));
+ }
+
+ @Test
+ public void testJoin() {
+ String[] s = "ab/cd/ed".split("/");
+ assertEquals("ab\\cd\\ed", StringUtil.join(s, "\\", 0, s.length));
+
+ assertEquals("cd\\ed", StringUtil.join(s, "\\", 1, s.length));
+
+ assertEquals("ed", StringUtil.join(s, "\\", 2, s.length));
+
+ assertEquals("", StringUtil.join(s, "\\", 3, s.length));
+
+ assertEquals("", StringUtil.join(new String[] {}, "\\", 0, 0));
+ }
+
+ @Test
+ public void testStripBrackets() {
+ assertEquals("foo", StringUtil.stripBrackets("[foo]"));
+ assertEquals("[foo]", StringUtil.stripBrackets("[[foo]]"));
+ assertEquals("", StringUtil.stripBrackets(""));
+ assertEquals("[foo", StringUtil.stripBrackets("[foo"));
+ assertEquals("]", StringUtil.stripBrackets("]"));
+ assertEquals("", StringUtil.stripBrackets("[]"));
+ assertEquals("f[]f", StringUtil.stripBrackets("f[]f"));
+ assertEquals(null, StringUtil.stripBrackets(null));
+ }
+
+ @Test
+ public void testGetPart() {
+ // Should be added
+ }
+
+ @Test
+ public void testFindEncodingsForString() {
+ // Unused in JabRef, but should be added in case it finds some use
+ }
+
+ @Test
+ public void testWrap() {
+ String newline = "newline";
+ assertEquals("aaaaa" + newline + "\tbbbbb" + newline + "\tccccc",
+ StringUtil.wrap("aaaaa bbbbb ccccc", 5, newline));
+ assertEquals("aaaaa bbbbb" + newline + "\tccccc", StringUtil.wrap("aaaaa bbbbb ccccc", 8, newline));
+ assertEquals("aaaaa bbbbb" + newline + "\tccccc", StringUtil.wrap("aaaaa bbbbb ccccc", 11, newline));
+ assertEquals("aaaaa bbbbb ccccc", StringUtil.wrap("aaaaa bbbbb ccccc", 12, newline));
+ assertEquals("aaaaa" + newline + "\t" + newline + "\tbbbbb" + newline + "\t" + newline + "\tccccc",
+ StringUtil.wrap("aaaaa\nbbbbb\nccccc", 12, newline));
+ assertEquals(
+ "aaaaa" + newline + "\t" + newline + "\t" + newline + "\tbbbbb" + newline + "\t" + newline + "\tccccc",
+ StringUtil.wrap("aaaaa\n\nbbbbb\nccccc", 12, newline));
+ assertEquals("aaaaa" + newline + "\t" + newline + "\tbbbbb" + newline + "\t" + newline + "\tccccc",
+ StringUtil.wrap("aaaaa\r\nbbbbb\r\nccccc", 12, newline));
+ }
+
+ @Test
+ public void testEncodeStringArray() {
+ assertEquals(ENCODED_STRING_ARRAY_1, FileField.encodeStringArray(STRING_ARRAY_1));
+ assertEquals(ENCODED_STRING_ARRAY_2, FileField.encodeStringArray(STRING_ARRAY_2));
+ assertEquals(ENCODED_STRING_ARRAY_2_WITH_NULL, FileField.encodeStringArray(STRING_ARRAY_2_WITH_NULL));
+ assertEquals(ENCODED_STRING_ARRAY_3, FileField.encodeStringArray(STRING_ARRAY_3));
+ }
+
+ @Test
+ public void testDecodeStringDoubleArray() {
+ assertArrayEquals(STRING_ARRAY_1, StringUtil.decodeStringDoubleArray(ENCODED_STRING_ARRAY_1));
+ assertArrayEquals(STRING_ARRAY_2, StringUtil.decodeStringDoubleArray(ENCODED_STRING_ARRAY_2));
+ // arrays first differed at element [0][1]; expected: null<null> but was: java.lang.String<null>
+ // assertArrayEquals(stringArray2res, StringUtil.decodeStringDoubleArray(encStringArray2));
+ assertArrayEquals(STRING_ARRAY_3, StringUtil.decodeStringDoubleArray(ENCODED_STRING_ARRAY_3));
+ }
+
+ @Test
+ public void testIsInCurlyBrackets() {
+ assertFalse(StringUtil.isInCurlyBrackets(""));
+ assertFalse(StringUtil.isInCurlyBrackets(null));
+ assertTrue(StringUtil.isInCurlyBrackets("{}"));
+ assertTrue(StringUtil.isInCurlyBrackets("{a}"));
+ assertTrue(StringUtil.isInCurlyBrackets("{a{a}}"));
+ assertTrue(StringUtil.isInCurlyBrackets("{{\\AA}sa {\\AA}Stor{\\aa}}"));
+ assertFalse(StringUtil.isInCurlyBrackets("{"));
+ assertFalse(StringUtil.isInCurlyBrackets("}"));
+ assertFalse(StringUtil.isInCurlyBrackets("a{}a"));
+ assertFalse(StringUtil.isInCurlyBrackets("{\\AA}sa {\\AA}Stor{\\aa}"));
+
+ }
+
+ @Test
+ public void testIsInSquareBrackets() {
+ assertFalse(StringUtil.isInSquareBrackets(""));
+ assertFalse(StringUtil.isInSquareBrackets(null));
+ assertTrue(StringUtil.isInSquareBrackets("[]"));
+ assertTrue(StringUtil.isInSquareBrackets("[a]"));
+ assertFalse(StringUtil.isInSquareBrackets("["));
+ assertFalse(StringUtil.isInSquareBrackets("]"));
+ assertFalse(StringUtil.isInSquareBrackets("a[]a"));
+ }
+
+ @Test
+ public void testIsInCitationMarks() {
+ assertFalse(StringUtil.isInCitationMarks(""));
+ assertFalse(StringUtil.isInCitationMarks(null));
+ assertTrue(StringUtil.isInCitationMarks("\"\""));
+ assertTrue(StringUtil.isInCitationMarks("\"a\""));
+ assertFalse(StringUtil.isInCitationMarks("\""));
+ assertFalse(StringUtil.isInCitationMarks("a\"\"a"));
+ }
+
+ @Test
+ public void testIntValueOfSingleDigit() {
+ assertEquals(1, StringUtil.intValueOf("1"));
+ assertEquals(2, StringUtil.intValueOf("2"));
+ assertEquals(8, StringUtil.intValueOf("8"));
+ }
+
+ @Test
+ public void testIntValueOfLongString() {
+ assertEquals(1234567890, StringUtil.intValueOf("1234567890"));
+ }
+
+ @Test
+ public void testIntValueOfStartWithZeros() {
+ assertEquals(1234, StringUtil.intValueOf("001234"));
+ }
+
+ @Test(expected = NumberFormatException.class)
+ public void testIntValueOfExceptionIfStringContainsLetter() {
+ StringUtil.intValueOf("12A2");
+ }
+
+ @Test(expected = NumberFormatException.class)
+ public void testIntValueOfExceptionIfStringNull() {
+ StringUtil.intValueOf(null);
+ }
+
+ @Test(expected = NumberFormatException.class)
+ public void testIntValueOfExceptionfIfStringEmpty() {
+ StringUtil.intValueOf("");
+ }
+
+ @Test
+ public void testIntValueOfWithNullSingleDigit() {
+ assertEquals(Optional.of(Integer.valueOf(1)), StringUtil.intValueOfOptional("1"));
+ assertEquals(Optional.of(Integer.valueOf(2)), StringUtil.intValueOfOptional("2"));
+ assertEquals(Optional.of(Integer.valueOf(8)), StringUtil.intValueOfOptional("8"));
+ }
+
+ @Test
+ public void testIntValueOfWithNullLongString() {
+ assertEquals(Optional.of(Integer.valueOf(1234567890)), StringUtil.intValueOfOptional("1234567890"));
+ }
+
+ @Test
+ public void testIntValueOfWithNullStartWithZeros() {
+ assertEquals(Optional.of(Integer.valueOf(1234)), StringUtil.intValueOfOptional("001234"));
+ }
+
+ @Test
+ public void testIntValueOfWithNullExceptionIfStringContainsLetter() {
+ assertEquals(Optional.empty(), StringUtil.intValueOfOptional("12A2"));
+ }
+
+ @Test
+ public void testIntValueOfWithNullExceptionIfStringNull() {
+ assertEquals(Optional.empty(), StringUtil.intValueOfOptional(null));
+ }
+
+ @Test
+ public void testIntValueOfWithNullExceptionfIfStringEmpty() {
+ assertEquals(Optional.empty(), StringUtil.intValueOfOptional(""));
+ }
+
+ @Test
+ public void testLimitStringLengthShort() {
+ assertEquals("Test", StringUtil.limitStringLength("Test", 20));
+ }
+
+ @Test
+ public void testLimitStringLengthLimiting() {
+ assertEquals("TestTes...", StringUtil.limitStringLength("TestTestTestTestTest", 10));
+ assertEquals(10, StringUtil.limitStringLength("TestTestTestTestTest", 10).length());
+ }
+
+ @Test
+ public void testLimitStringLengthNullInput() {
+ assertEquals("", StringUtil.limitStringLength(null, 10));
+ }
+
+ @Test
+ public void testReplaceSpecialCharacters() {
+ assertEquals("Hallo Arger", StringUtil.replaceSpecialCharacters("Hallo Arger"));
+ assertEquals("aaAeoeeee", StringUtil.replaceSpecialCharacters("åÄöéèë"));
+ }
+
+ @Test
+ public void testRepeatSpaces() {
+ assertEquals("", StringUtil.repeatSpaces(0));
+ assertEquals(" ", StringUtil.repeatSpaces(1));
+ assertEquals(" ", StringUtil.repeatSpaces(7));
+ }
+
+ @Test
+ public void testRepeat() {
+ assertEquals("", StringUtil.repeat(0, 'a'));
+ assertEquals("a", StringUtil.repeat(1, 'a'));
+ assertEquals("aaaaaaa", StringUtil.repeat(7, 'a'));
+ }
+
+ @Test
+ public void testBoldHTML() {
+ assertEquals("<b>AA</b>", StringUtil.boldHTML("AA"));
+ }
+
+ @Test
+ public void testBoldHTMLReturnsOriginalTextIfNonNull() {
+ assertEquals("<b>AA</b>", StringUtil.boldHTML("AA", "BB"));
+ }
+
+ @Test
+ public void testBoldHTMLReturnsAlternativeTextIfNull() {
+ assertEquals("<b>BB</b>", StringUtil.boldHTML(null, "BB"));
+ }
+
+ @Test
+ public void testUnquote() {
+ assertEquals("a:", StringUtil.unquote("a::", ':'));
+ assertEquals("a:;", StringUtil.unquote("a:::;", ':'));
+ assertEquals("a:b%c;", StringUtil.unquote("a::b:%c:;", ':'));
+ }
+
+ @Test
+ public void testCapitalizeFirst() {
+ assertEquals("", StringUtil.capitalizeFirst(""));
+ assertEquals("Hello world", StringUtil.capitalizeFirst("Hello World"));
+ assertEquals("A", StringUtil.capitalizeFirst("a"));
+ assertEquals("Aa", StringUtil.capitalizeFirst("AA"));
+ }
+}
diff --git a/src/test/java/net/sf/jabref/shared/DBMSConnectionTest.java b/src/test/java/net/sf/jabref/shared/DBMSConnectionTest.java
new file mode 100644
index 0000000..9ebf70a
--- /dev/null
+++ b/src/test/java/net/sf/jabref/shared/DBMSConnectionTest.java
@@ -0,0 +1,40 @@
+package net.sf.jabref.shared;
+
+import java.sql.SQLException;
+import java.util.Collection;
+
+import net.sf.jabref.shared.exception.InvalidDBMSConnectionPropertiesException;
+import net.sf.jabref.testutils.category.DatabaseTests;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+ at RunWith(Parameterized.class)
+ at Category(DatabaseTests.class)
+public class DBMSConnectionTest {
+
+ @Parameter
+ public DBMSType dbmsType;
+
+
+ @Parameters(name = "Test with {0} database system")
+ public static Collection<DBMSType> getTestingDatabaseSystems() {
+ return TestManager.getDBMSTypeTestParameter();
+ }
+
+ @Test
+ public void testGetConnection() throws SQLException, InvalidDBMSConnectionPropertiesException {
+ DBMSConnectionProperties properties = TestConnector.getTestConnectionProperties(dbmsType);
+ Assert.assertNotNull(new DBMSConnection(properties).getConnection());
+ }
+
+ @Test(expected = SQLException.class)
+ public void testGetConnectionFail() throws SQLException, InvalidDBMSConnectionPropertiesException {
+ new DBMSConnection(new DBMSConnectionProperties(dbmsType, "XXXX", 0, "XXXX", "XXXX", "XXXX")).getConnection();
+ }
+}
diff --git a/src/test/java/net/sf/jabref/shared/DBMSProcessorTest.java b/src/test/java/net/sf/jabref/shared/DBMSProcessorTest.java
new file mode 100644
index 0000000..c4336c2
--- /dev/null
+++ b/src/test/java/net/sf/jabref/shared/DBMSProcessorTest.java
@@ -0,0 +1,302 @@
+package net.sf.jabref.shared;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.shared.exception.InvalidDBMSConnectionPropertiesException;
+import net.sf.jabref.shared.exception.OfflineLockException;
+import net.sf.jabref.testutils.category.DatabaseTests;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+ at RunWith(Parameterized.class)
+ at Category(DatabaseTests.class)
+public class DBMSProcessorTest {
+
+ private DBMSConnection dbmsConnection;
+ private DBMSProcessor dbmsProcessor;
+
+ @Parameter
+ public DBMSType dbmsType;
+
+
+ @Before
+ public void setUp() throws SQLException, InvalidDBMSConnectionPropertiesException {
+ dbmsConnection = TestConnector.getTestDBMSConnection(dbmsType);
+ dbmsProcessor = DBMSProcessor.getProcessorInstance(dbmsConnection);
+ dbmsProcessor.setupSharedDatabase();
+ }
+
+ @Parameters(name = "Test with {0} database system")
+ public static Collection<DBMSType> getTestingDatabaseSystems() {
+ return TestManager.getDBMSTypeTestParameter();
+ }
+
+ @Test
+ public void testCheckBaseIntegrity() throws SQLException {
+ Assert.assertTrue(dbmsProcessor.checkBaseIntegrity());
+ clear();
+ Assert.assertFalse(dbmsProcessor.checkBaseIntegrity());
+ }
+
+ @Test
+ public void testSetUpSharedDatabase() throws SQLException {
+ clear();
+ dbmsProcessor.setupSharedDatabase();
+ Assert.assertTrue(dbmsProcessor.checkBaseIntegrity());
+ }
+
+ @Test
+ public void testInsertEntry() throws SQLException {
+ BibEntry expectedEntry = getBibEntryExample();
+
+ dbmsProcessor.insertEntry(expectedEntry);
+
+ BibEntry emptyEntry = new BibEntry();
+ emptyEntry.getSharedBibEntryData().setSharedID(1);
+ dbmsProcessor.insertEntry(emptyEntry); // does not insert, due to same sharedID.
+
+ Map<String, String> actualFieldMap = new HashMap<>();
+
+ try (ResultSet entryResultSet = selectFrom("ENTRY")) {
+ Assert.assertTrue(entryResultSet.next());
+ Assert.assertEquals(1, entryResultSet.getInt("SHARED_ID"));
+ Assert.assertEquals("inproceedings", entryResultSet.getString("TYPE"));
+ Assert.assertEquals(1, entryResultSet.getInt("VERSION"));
+ Assert.assertFalse(entryResultSet.next());
+
+ try (ResultSet fieldResultSet = selectFrom("FIELD")) {
+ while (fieldResultSet.next()) {
+ actualFieldMap.put(fieldResultSet.getString("NAME"), fieldResultSet.getString("VALUE"));
+ }
+ }
+ }
+
+ Map<String, String> expectedFieldMap = expectedEntry.getFieldMap();
+
+ Assert.assertEquals(expectedFieldMap, actualFieldMap);
+ }
+
+ @Test
+ public void testUpdateEntry() throws OfflineLockException, SQLException {
+ BibEntry expectedEntry = getBibEntryExample();
+
+ dbmsProcessor.insertEntry(expectedEntry);
+
+ expectedEntry.setType("book");
+ expectedEntry.setField("author", "Michael J and Hutchings");
+ expectedEntry.setField("customField", "custom value");
+ expectedEntry.clearField("booktitle");
+
+ dbmsProcessor.updateEntry(expectedEntry);
+
+ Optional<BibEntry> actualEntryOptional = dbmsProcessor
+ .getSharedEntry(expectedEntry.getSharedBibEntryData().getSharedID());
+
+ if (actualEntryOptional.isPresent()) {
+ Assert.assertEquals(expectedEntry, actualEntryOptional.get());
+ } else {
+ Assert.fail();
+ }
+ }
+
+ @Test(expected = OfflineLockException.class)
+ public void testUpdateNewerEntry() throws OfflineLockException, SQLException {
+ BibEntry bibEntry = getBibEntryExample();
+
+ dbmsProcessor.insertEntry(bibEntry);
+
+ bibEntry.getSharedBibEntryData().setVersion(0); // simulate older version
+ bibEntry.setField("year", "1993");
+
+ dbmsProcessor.updateEntry(bibEntry);
+ }
+
+ @Test
+ public void testUpdateEqualEntry() throws OfflineLockException, SQLException {
+ BibEntry expectedBibEntry = getBibEntryExample();
+
+ dbmsProcessor.insertEntry(expectedBibEntry);
+
+ expectedBibEntry.getSharedBibEntryData().setVersion(0); // simulate older version
+
+ dbmsProcessor.updateEntry(expectedBibEntry);
+
+ Optional<BibEntry> actualBibEntryOptional = dbmsProcessor
+ .getSharedEntry(expectedBibEntry.getSharedBibEntryData().getSharedID());
+
+ if (actualBibEntryOptional.isPresent()) {
+ Assert.assertEquals(expectedBibEntry, actualBibEntryOptional.get());
+ } else {
+ Assert.fail();
+ }
+ }
+
+ @Test
+ public void testRemoveEntry() throws SQLException {
+ BibEntry bibEntry = getBibEntryExample();
+ dbmsProcessor.insertEntry(bibEntry);
+ dbmsProcessor.removeEntry(bibEntry);
+
+ try (ResultSet resultSet = selectFrom("ENTRY")) {
+ Assert.assertFalse(resultSet.next());
+ }
+ }
+
+ @Test
+ public void testGetSharedEntries() {
+ BibEntry bibEntry = getBibEntryExampleWithEmptyFields();
+
+ dbmsProcessor.insertEntry(bibEntry);
+
+ List<BibEntry> expectedEntries = Arrays.asList(bibEntry);
+ List<BibEntry> actualEntries = dbmsProcessor.getSharedEntries();
+
+ Assert.assertEquals(expectedEntries, actualEntries);
+ }
+
+ @Test
+ public void testGetSharedEntry() {
+ BibEntry expectedBibEntry = getBibEntryExampleWithEmptyFields();
+
+ dbmsProcessor.insertEntry(expectedBibEntry);
+
+ Optional<BibEntry> actualBibEntryOptional = dbmsProcessor
+ .getSharedEntry(expectedBibEntry.getSharedBibEntryData().getSharedID());
+
+ if (actualBibEntryOptional.isPresent()) {
+ Assert.assertEquals(expectedBibEntry, actualBibEntryOptional.get());
+ } else {
+ Assert.fail();
+ }
+ }
+
+ @Test
+ public void testGetNotExistingSharedEntry() {
+ Optional<BibEntry> actualBibEntryOptional = dbmsProcessor.getSharedEntry(1);
+ Assert.assertFalse(actualBibEntryOptional.isPresent());
+ }
+
+ @Test
+ public void testGetSharedIDVersionMapping() throws OfflineLockException, SQLException {
+ BibEntry firstEntry = getBibEntryExample();
+ BibEntry secondEntry = getBibEntryExample();
+
+ dbmsProcessor.insertEntry(firstEntry);
+ dbmsProcessor.insertEntry(secondEntry);
+ dbmsProcessor.updateEntry(secondEntry);
+
+ Map<Integer, Integer> expectedIDVersionMap = new HashMap<>();
+ expectedIDVersionMap.put(firstEntry.getSharedBibEntryData().getSharedID(), 1);
+ expectedIDVersionMap.put(secondEntry.getSharedBibEntryData().getSharedID(), 2);
+
+ Map<Integer, Integer> actualIDVersionMap = dbmsProcessor.getSharedIDVersionMapping();
+
+ Assert.assertEquals(expectedIDVersionMap, actualIDVersionMap);
+
+ }
+
+ @Test
+ public void testGetSharedMetaData() {
+ insertMetaData("databaseType", "bibtex;");
+ insertMetaData("protectedFlag", "true;");
+ insertMetaData("saveActions", "enabled;\nauthor[capitalize,html_to_latex]\ntitle[title_case]\n;");
+ insertMetaData("saveOrderConfig", "specified;author;false;title;false;year;true;");
+
+ Map<String, String> expectedMetaData = getMetaDataExample();
+ Map<String, String> actualMetaData = dbmsProcessor.getSharedMetaData();
+
+ Assert.assertEquals(expectedMetaData, actualMetaData);
+
+ }
+
+ @Test
+ public void testSetSharedMetaData() throws SQLException {
+ Map<String, String> expectedMetaData = getMetaDataExample();
+ dbmsProcessor.setSharedMetaData(expectedMetaData);
+
+ Map<String, String> actualMetaData = dbmsProcessor.getSharedMetaData();
+
+ Assert.assertEquals(expectedMetaData, actualMetaData);
+ }
+
+ private Map<String, String> getMetaDataExample() {
+ Map<String, String> expectedMetaData = new HashMap<>();
+
+ expectedMetaData.put("databaseType", "bibtex;");
+ expectedMetaData.put("protectedFlag", "true;");
+ expectedMetaData.put("saveActions", "enabled;\nauthor[capitalize,html_to_latex]\ntitle[title_case]\n;");
+ expectedMetaData.put("saveOrderConfig", "specified;author;false;title;false;year;true;");
+
+ return expectedMetaData;
+ }
+
+ private BibEntry getBibEntryExampleWithEmptyFields() {
+ BibEntry bibEntry = new BibEntry();
+ bibEntry.setField("author", "Author");
+ bibEntry.setField("title", "");
+ bibEntry.setField("year", "");
+ bibEntry.getSharedBibEntryData().setSharedID(1);
+ return bibEntry;
+ }
+
+ private BibEntry getBibEntryExample() {
+ BibEntry bibEntry = new BibEntry();
+ bibEntry.setType("inproceedings");
+ bibEntry.setField("author", "Wirthlin, Michael J and Hutchings, Brad L and Gilson, Kent L");
+ bibEntry.setField("title", "The nano processor: a low resource reconfigurable processor");
+ bibEntry.setField("booktitle", "FPGAs for Custom Computing Machines, 1994. Proceedings. IEEE Workshop on");
+ bibEntry.setField("year", "1994");
+ bibEntry.setCiteKey("nanoproc1994");
+ return bibEntry;
+ }
+
+ private ResultSet selectFrom(String table) {
+ try {
+ return dbmsConnection.getConnection().createStatement().executeQuery("SELECT * FROM " + escape(table));
+ } catch (SQLException e) {
+ Assert.fail(e.getMessage());
+ return null;
+ }
+ }
+
+ // Oracle does not support multiple tuple insertion in one INSERT INTO command.
+ // Therefore this function was defined to improve the readability and to keep the code short.
+ private void insertMetaData(String key, String value) {
+ try {
+ dbmsConnection.getConnection().createStatement().executeUpdate("INSERT INTO " + escape("METADATA") + "("
+ + escape("KEY") + ", " + escape("VALUE") + ") VALUES("
+ + escapeValue(key) + ", " + escapeValue(value) + ")");
+ } catch (SQLException e) {
+ Assert.fail(e.getMessage());
+ }
+ }
+
+ private String escape(String expression) {
+ return dbmsProcessor.escape(expression);
+ }
+
+ private String escapeValue(String value) {
+ return "'" + value + "'";
+ }
+
+ @After
+ public void clear() throws SQLException {
+ TestManager.clearTables(dbmsConnection);
+ }
+}
diff --git a/src/test/java/net/sf/jabref/shared/DBMSSynchronizerTest.java b/src/test/java/net/sf/jabref/shared/DBMSSynchronizerTest.java
new file mode 100644
index 0000000..4e0f96a
--- /dev/null
+++ b/src/test/java/net/sf/jabref/shared/DBMSSynchronizerTest.java
@@ -0,0 +1,220 @@
+package net.sf.jabref.shared;
+
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import net.sf.jabref.logic.exporter.MetaDataSerializer;
+import net.sf.jabref.logic.formatter.casechanger.LowerCaseFormatter;
+import net.sf.jabref.model.bibtexkeypattern.GlobalBibtexKeyPattern;
+import net.sf.jabref.model.cleanup.FieldFormatterCleanup;
+import net.sf.jabref.model.cleanup.FieldFormatterCleanups;
+import net.sf.jabref.model.database.BibDatabase;
+import net.sf.jabref.model.database.BibDatabaseContext;
+import net.sf.jabref.model.database.BibDatabaseMode;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.model.entry.event.EntryEventSource;
+import net.sf.jabref.model.metadata.MetaData;
+import net.sf.jabref.shared.exception.DatabaseNotSupportedException;
+import net.sf.jabref.shared.exception.InvalidDBMSConnectionPropertiesException;
+import net.sf.jabref.shared.exception.OfflineLockException;
+import net.sf.jabref.testutils.category.DatabaseTests;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+ at RunWith(Parameterized.class)
+ at Category(DatabaseTests.class)
+public class DBMSSynchronizerTest {
+
+ private DBMSSynchronizer dbmsSynchronizer;
+ private DBMSConnection dbmsConnection;
+ private DBMSProcessor dbmsProcessor;
+ private BibDatabase bibDatabase;
+ private GlobalBibtexKeyPattern pattern;
+
+ @Parameter
+ public DBMSType dbmsType;
+
+ @Before
+ public void setUp() throws SQLException, DatabaseNotSupportedException, InvalidDBMSConnectionPropertiesException {
+
+ dbmsConnection = TestConnector.getTestDBMSConnection(dbmsType);
+
+ bibDatabase = new BibDatabase();
+ BibDatabaseContext context = new BibDatabaseContext(bibDatabase);
+
+ pattern = GlobalBibtexKeyPattern.fromPattern("[auth][year]");
+
+ dbmsSynchronizer = new DBMSSynchronizer(context, ',', pattern);
+ dbmsProcessor = DBMSProcessor.getProcessorInstance(dbmsConnection);
+
+ bibDatabase.registerListener(dbmsSynchronizer);
+
+ dbmsSynchronizer.openSharedDatabase(dbmsConnection);
+
+ }
+
+ @Parameters(name = "Test with {0} database system")
+ public static Collection<DBMSType> getTestingDatabaseSystems() {
+ return TestManager.getDBMSTypeTestParameter();
+ }
+
+ @Test
+ public void testEntryAddedEventListener() {
+ BibEntry expectedEntry = getBibEntryExample(1);
+ BibEntry furtherEntry = getBibEntryExample(1);
+
+ bibDatabase.insertEntry(expectedEntry);
+ // should not add into shared database.
+ bibDatabase.insertEntry(furtherEntry, EntryEventSource.SHARED);
+
+ List<BibEntry> actualEntries = dbmsProcessor.getSharedEntries();
+
+ Assert.assertEquals(1, actualEntries.size());
+ Assert.assertEquals(expectedEntry, actualEntries.get(0));
+ }
+
+ @Test
+ public void testFieldChangedEventListener() {
+ BibEntry expectedEntry = getBibEntryExample(1);
+ expectedEntry.registerListener(dbmsSynchronizer);
+
+ bibDatabase.insertEntry(expectedEntry);
+ expectedEntry.setField("author", "Brad L and Gilson");
+ expectedEntry.setField("title", "The micro multiplexer", EntryEventSource.SHARED);
+
+ List<BibEntry> actualEntries = dbmsProcessor.getSharedEntries();
+ Assert.assertEquals(1, actualEntries.size());
+ Assert.assertEquals(expectedEntry.getField("author"), actualEntries.get(0).getField("author"));
+ Assert.assertEquals("The nano processor1", actualEntries.get(0).getField("title").get());
+
+ }
+
+ @Test
+ public void testEntryRemovedEventListener() {
+ BibEntry bibEntry = getBibEntryExample(1);
+ bibDatabase.insertEntry(bibEntry);
+
+ List<BibEntry> actualEntries = dbmsProcessor.getSharedEntries();
+ Assert.assertEquals(1, actualEntries.size());
+ Assert.assertEquals(bibEntry, actualEntries.get(0));
+
+ bibDatabase.removeEntry(bibEntry);
+ actualEntries = dbmsProcessor.getSharedEntries();
+
+ Assert.assertEquals(0, actualEntries.size());
+
+ bibDatabase.insertEntry(bibEntry);
+ bibDatabase.removeEntry(bibEntry, EntryEventSource.SHARED);
+
+ actualEntries = dbmsProcessor.getSharedEntries();
+ Assert.assertEquals(1, actualEntries.size());
+ Assert.assertEquals(bibEntry, actualEntries.get(0));
+ }
+
+ @Test
+ public void testMetaDataChangedEventListener() {
+ MetaData testMetaData = new MetaData();
+ testMetaData.registerListener(dbmsSynchronizer);
+ dbmsSynchronizer.setMetaData(testMetaData);
+ testMetaData.setMode(BibDatabaseMode.BIBTEX);
+
+ Map<String, String> expectedMap = MetaDataSerializer.getSerializedStringMap(testMetaData, pattern);
+ Map<String, String> actualMap = dbmsProcessor.getSharedMetaData();
+
+ Assert.assertEquals(expectedMap, actualMap);
+ }
+
+ @Test
+ public void testInitializeDatabases() throws SQLException, DatabaseNotSupportedException {
+ clear();
+ dbmsSynchronizer.initializeDatabases();
+ Assert.assertTrue(dbmsProcessor.checkBaseIntegrity());
+ dbmsSynchronizer.initializeDatabases();
+ Assert.assertTrue(dbmsProcessor.checkBaseIntegrity());
+ }
+
+ @Test
+ public void testSynchronizeLocalDatabaseWithEntryRemoval() {
+ List<BibEntry> expectedBibEntries = Arrays.asList(getBibEntryExample(1), getBibEntryExample(2));
+
+ dbmsProcessor.insertEntry(expectedBibEntries.get(0));
+ dbmsProcessor.insertEntry(expectedBibEntries.get(1));
+
+ Assert.assertTrue(bibDatabase.getEntries().isEmpty());
+
+ dbmsSynchronizer.synchronizeLocalDatabase();
+
+ Assert.assertEquals(expectedBibEntries, bibDatabase.getEntries());
+
+ dbmsProcessor.removeEntry(expectedBibEntries.get(0));
+ dbmsProcessor.removeEntry(expectedBibEntries.get(1));
+
+ expectedBibEntries = new ArrayList<>();
+
+ dbmsSynchronizer.synchronizeLocalDatabase();
+
+ Assert.assertEquals(expectedBibEntries, bibDatabase.getEntries());
+ }
+
+ @Test
+ public void testSynchronizeLocalDatabaseWithEntryUpdate() throws OfflineLockException, SQLException {
+ BibEntry bibEntry = getBibEntryExample(1);
+ bibDatabase.insertEntry(bibEntry);
+ Assert.assertEquals(1, bibDatabase.getEntries().size());
+
+ BibEntry modifiedBibEntry = getBibEntryExample(1);
+ modifiedBibEntry.setField("custom", "custom value");
+ modifiedBibEntry.clearField("title");
+ modifiedBibEntry.setType("article");
+
+ dbmsProcessor.updateEntry(modifiedBibEntry);
+
+ dbmsSynchronizer.synchronizeLocalDatabase(); // testing point
+
+ Assert.assertEquals(bibDatabase.getEntries(), dbmsProcessor.getSharedEntries());
+ }
+
+ @Test
+ public void testApplyMetaData() {
+ BibEntry bibEntry = getBibEntryExample(1);
+ bibDatabase.insertEntry(bibEntry);
+
+ MetaData testMetaData = new MetaData();
+ testMetaData.setSaveActions(new FieldFormatterCleanups(true,
+ Collections.singletonList(new FieldFormatterCleanup("author", new LowerCaseFormatter()))));
+ dbmsSynchronizer.setMetaData(testMetaData);
+
+ dbmsSynchronizer.applyMetaData();
+
+ Assert.assertEquals("wirthlin, michael j1", bibEntry.getField("author").get());
+
+ }
+
+ private BibEntry getBibEntryExample(int index) {
+ BibEntry bibEntry = new BibEntry();
+ bibEntry.setType("book");
+ bibEntry.setField("author", "Wirthlin, Michael J" + index);
+ bibEntry.setField("title", "The nano processor" + index);
+ bibEntry.getSharedBibEntryData().setSharedID(index);
+ return bibEntry;
+ }
+
+ @After
+ public void clear() throws SQLException {
+ TestManager.clearTables(dbmsConnection);
+ }
+
+}
diff --git a/src/test/java/net/sf/jabref/shared/DBMSTypeTest.java b/src/test/java/net/sf/jabref/shared/DBMSTypeTest.java
new file mode 100644
index 0000000..bfe9c0c
--- /dev/null
+++ b/src/test/java/net/sf/jabref/shared/DBMSTypeTest.java
@@ -0,0 +1,48 @@
+package net.sf.jabref.shared;
+
+import net.sf.jabref.testutils.category.DatabaseTests;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+ at Category(DatabaseTests.class)
+public class DBMSTypeTest {
+
+ @Test
+ public void testToString() {
+ Assert.assertEquals("MySQL", DBMSType.MYSQL.toString());
+ Assert.assertEquals("Oracle", DBMSType.ORACLE.toString());
+ Assert.assertEquals("PostgreSQL", DBMSType.POSTGRESQL.toString());
+ }
+
+ @Test
+ public void testGetDriverClassPath() {
+ Assert.assertEquals("com.mysql.jdbc.Driver", DBMSType.MYSQL.getDriverClassPath());
+ Assert.assertEquals("oracle.jdbc.driver.OracleDriver", DBMSType.ORACLE.getDriverClassPath());
+ Assert.assertEquals("org.postgresql.Driver", DBMSType.POSTGRESQL.getDriverClassPath());
+ }
+
+ @Test
+ public void testFromString() {
+ Assert.assertEquals(DBMSType.MYSQL, DBMSType.fromString("MySQL").get());
+ Assert.assertEquals(DBMSType.ORACLE, DBMSType.fromString("Oracle").get());
+ Assert.assertEquals(DBMSType.POSTGRESQL, DBMSType.fromString("PostgreSQL").get());
+ Assert.assertFalse(DBMSType.fromString("XXX").isPresent());
+ }
+
+ @Test
+ public void testGetUrl() {
+ Assert.assertEquals("jdbc:mysql://localhost:3306/xe", DBMSType.MYSQL.getUrl("localhost", 3306, "xe"));
+ Assert.assertEquals("jdbc:oracle:thin:@localhost:1521:xe", DBMSType.ORACLE.getUrl("localhost", 1521, "xe"));
+ Assert.assertEquals("jdbc:postgresql://localhost:5432/xe", DBMSType.POSTGRESQL.getUrl("localhost", 5432, "xe"));
+ }
+
+ @Test
+ public void testGetDefaultPort() {
+ Assert.assertEquals(3306, DBMSType.MYSQL.getDefaultPort());
+ Assert.assertEquals(5432, DBMSType.POSTGRESQL.getDefaultPort());
+ Assert.assertEquals(1521, DBMSType.ORACLE.getDefaultPort());
+ }
+
+}
diff --git a/src/test/java/net/sf/jabref/shared/SynchronizationTestEventListener.java b/src/test/java/net/sf/jabref/shared/SynchronizationTestEventListener.java
new file mode 100644
index 0000000..60a9f85
--- /dev/null
+++ b/src/test/java/net/sf/jabref/shared/SynchronizationTestEventListener.java
@@ -0,0 +1,34 @@
+package net.sf.jabref.shared;
+
+import net.sf.jabref.shared.event.SharedEntryNotPresentEvent;
+import net.sf.jabref.shared.event.UpdateRefusedEvent;
+import net.sf.jabref.testutils.category.DatabaseTests;
+
+import com.google.common.eventbus.Subscribe;
+import org.junit.experimental.categories.Category;
+
+ at Category(DatabaseTests.class)
+public class SynchronizationTestEventListener {
+
+ private SharedEntryNotPresentEvent sharedEntryNotPresentEvent;
+ private UpdateRefusedEvent updateRefusedEvent;
+
+
+ @Subscribe
+ public void listen(SharedEntryNotPresentEvent event) {
+ this.sharedEntryNotPresentEvent = event;
+ }
+
+ @Subscribe
+ public void listen(UpdateRefusedEvent event) {
+ this.updateRefusedEvent = event;
+ }
+
+ public SharedEntryNotPresentEvent getSharedEntryNotPresentEvent() {
+ return sharedEntryNotPresentEvent;
+ }
+
+ public UpdateRefusedEvent getUpdateRefusedEvent() {
+ return updateRefusedEvent;
+ }
+}
diff --git a/src/test/java/net/sf/jabref/shared/SynchronizationTestSimulator.java b/src/test/java/net/sf/jabref/shared/SynchronizationTestSimulator.java
new file mode 100644
index 0000000..edd419f
--- /dev/null
+++ b/src/test/java/net/sf/jabref/shared/SynchronizationTestSimulator.java
@@ -0,0 +1,161 @@
+package net.sf.jabref.shared;
+
+import java.sql.SQLException;
+import java.util.Collection;
+
+import net.sf.jabref.model.Defaults;
+import net.sf.jabref.model.bibtexkeypattern.GlobalBibtexKeyPattern;
+import net.sf.jabref.model.database.BibDatabaseContext;
+import net.sf.jabref.model.database.BibDatabaseMode;
+import net.sf.jabref.model.database.DatabaseLocation;
+import net.sf.jabref.model.entry.BibEntry;
+import net.sf.jabref.shared.exception.DatabaseNotSupportedException;
+import net.sf.jabref.shared.exception.InvalidDBMSConnectionPropertiesException;
+import net.sf.jabref.testutils.category.DatabaseTests;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+ at RunWith(Parameterized.class)
+ at Category(DatabaseTests.class)
+public class SynchronizationTestSimulator {
+
+ private BibDatabaseContext clientContextA;
+ private BibDatabaseContext clientContextB;
+
+ private SynchronizationTestEventListener eventListenerB; // used to monitor occurring events
+
+ private DBMSConnection dbmsConnection;
+
+ @Parameter
+ public DBMSType dbmsType;
+
+
+ @Before
+ public void setUp() throws SQLException, DatabaseNotSupportedException, InvalidDBMSConnectionPropertiesException {
+ this.dbmsConnection = TestConnector.getTestDBMSConnection(dbmsType);
+
+ GlobalBibtexKeyPattern pattern = GlobalBibtexKeyPattern.fromPattern("[auth][year]");
+ clientContextA = new BibDatabaseContext(new Defaults(BibDatabaseMode.BIBTEX), DatabaseLocation.SHARED, ',',
+ pattern);
+ clientContextA.getDBMSSynchronizer().openSharedDatabase(dbmsConnection);
+
+ clientContextB = new BibDatabaseContext(new Defaults(BibDatabaseMode.BIBTEX), DatabaseLocation.SHARED, ',',
+ pattern);
+ clientContextB.getDBMSSynchronizer().openSharedDatabase(dbmsConnection);
+ eventListenerB = new SynchronizationTestEventListener();
+ clientContextB.getDBMSSynchronizer().registerListener(eventListenerB);
+ }
+
+ @Parameters(name = "Test with {0} database system")
+ public static Collection<DBMSType> getTestingDatabaseSystems() {
+ return TestManager.getDBMSTypeTestParameter();
+ }
+
+ @Test
+ public void simulateEntryInsertionAndManualPull() {
+ clientContextA.getDatabase().insertEntry(getBibEntryExample(1)); // client A inserts an entry
+ clientContextA.getDatabase().insertEntry(getBibEntryExample(2)); // client A inserts another entry
+ clientContextB.getDBMSSynchronizer().pullChanges(); // client B pulls the changes
+
+ Assert.assertEquals(clientContextA.getDatabase().getEntries(), clientContextB.getDatabase().getEntries());
+ }
+
+ @Test
+ public void simulateEntryUpdateAndManualPull() {
+ BibEntry bibEntry = getBibEntryExample(1);
+ clientContextA.getDatabase().insertEntry(bibEntry); // client A inserts an entry
+ bibEntry.setField("custom", "custom value"); // client A changes the entry
+ bibEntry.clearField("author");
+
+ clientContextB.getDBMSSynchronizer().pullChanges(); // client B pulls the changes
+
+ Assert.assertEquals(clientContextA.getDatabase().getEntries(), clientContextB.getDatabase().getEntries());
+ }
+
+ @Test
+ public void simulateEntryDelitionAndManualPull() {
+ BibEntry bibEntry = getBibEntryExample(1);
+ clientContextA.getDatabase().insertEntry(bibEntry); // client A inserts an entry
+ clientContextB.getDBMSSynchronizer().pullChanges(); // client B pulls the entry
+
+ Assert.assertFalse(clientContextA.getDatabase().getEntries().isEmpty());
+ Assert.assertFalse(clientContextB.getDatabase().getEntries().isEmpty());
+ Assert.assertEquals(clientContextA.getDatabase().getEntries(), clientContextB.getDatabase().getEntries());
+
+ clientContextA.getDatabase().removeEntry(bibEntry); // client A removes the entry
+ clientContextB.getDBMSSynchronizer().pullChanges(); // client B pulls the change
+
+ Assert.assertTrue(clientContextA.getDatabase().getEntries().isEmpty());
+ Assert.assertTrue(clientContextB.getDatabase().getEntries().isEmpty());
+ }
+
+ @Test
+ public void simulateUpdateOnNoLongerExistingEntry() {
+ BibEntry bibEntryOfClientA = getBibEntryExample(1);
+ clientContextA.getDatabase().insertEntry(bibEntryOfClientA); // client A inserts an entry
+ clientContextB.getDBMSSynchronizer().pullChanges(); // client B pulls the entry
+
+ Assert.assertFalse(clientContextA.getDatabase().getEntries().isEmpty());
+ Assert.assertFalse(clientContextB.getDatabase().getEntries().isEmpty());
+ Assert.assertEquals(clientContextA.getDatabase().getEntries(), clientContextB.getDatabase().getEntries());
+
+ clientContextA.getDatabase().removeEntry(bibEntryOfClientA); // client A removes the entry
+
+ Assert.assertFalse(clientContextB.getDatabase().getEntries().isEmpty());
+ Assert.assertNull(eventListenerB.getSharedEntryNotPresentEvent());
+
+ BibEntry bibEntryOfClientB = clientContextB.getDatabase().getEntries().get(0); // client B tries to update the entry
+ bibEntryOfClientB.setField("year", "2009");
+
+ // here a new SharedEntryNotPresentEvent has been thrown. In this case the user B would get an pop-up window.
+ Assert.assertNotNull(eventListenerB.getSharedEntryNotPresentEvent());
+ Assert.assertEquals(bibEntryOfClientB, eventListenerB.getSharedEntryNotPresentEvent().getBibEntry());
+ }
+
+ @Test
+ public void simulateEntryChangeConflicts() {
+ BibEntry bibEntryOfClientA = getBibEntryExample(1);
+ clientContextA.getDatabase().insertEntry(bibEntryOfClientA); // client A inserts an entry
+ clientContextB.getDBMSSynchronizer().pullChanges(); // client B pulls the entry
+
+ bibEntryOfClientA.setField("year", "2001"); // A now increases the version number
+
+ // B does nothing here, so there is no event occurrence
+
+ // B now tries to update the entry
+ Assert.assertFalse(clientContextB.getDatabase().getEntries().isEmpty());
+
+ Assert.assertNull(eventListenerB.getUpdateRefusedEvent());
+
+ BibEntry bibEntryOfClientB = clientContextB.getDatabase().getEntries().get(0);
+ bibEntryOfClientB.setField("year", "2016"); // B also tries to change something
+
+ // B now can not update the shared entry, due to optimistic offline lock.
+ // In this case an BibEntry merge dialog pops up.
+ Assert.assertNotNull(eventListenerB.getUpdateRefusedEvent());
+ }
+
+ private BibEntry getBibEntryExample(int index) {
+ BibEntry bibEntry = new BibEntry();
+ bibEntry.setType("inproceedings");
+ bibEntry.setField("author", "Wirthlin, Michael J and Hutchings, Brad L and Gilson, Kent L " + index);
+ bibEntry.setField("title", "The nano processor: a low resource reconfigurable processor " + index);
+ bibEntry.setField("booktitle", "FPGAs for Custom Computing Machines, 1994. Proceedings. IEEE Workshop on " + index);
+ bibEntry.setField("year", "199" + index);
+ bibEntry.setCiteKey("nanoproc199" + index);
+ return bibEntry;
+ }
+
+ @After
+ public void clear() throws SQLException {
+ TestManager.clearTables(dbmsConnection);
+ }
+}
diff --git a/src/test/java/net/sf/jabref/shared/TestConnector.java b/src/test/java/net/sf/jabref/shared/TestConnector.java
new file mode 100644
index 0000000..a623266
--- /dev/null
+++ b/src/test/java/net/sf/jabref/shared/TestConnector.java
@@ -0,0 +1,40 @@
+package net.sf.jabref.shared;
+
+import java.sql.SQLException;
+
+import net.sf.jabref.shared.exception.InvalidDBMSConnectionPropertiesException;
+import net.sf.jabref.testutils.category.DatabaseTests;
+
+import org.junit.experimental.categories.Category;
+
+ at Category(DatabaseTests.class)
+public class TestConnector {
+
+ public static DBMSType currentConnectionType;
+
+
+ public static DBMSConnection getTestDBMSConnection(DBMSType dbmsType) throws SQLException, InvalidDBMSConnectionPropertiesException {
+ currentConnectionType = dbmsType;
+
+ DBMSConnectionProperties properties = getTestConnectionProperties(dbmsType);
+
+ return new DBMSConnection(properties);
+ }
+
+ public static DBMSConnectionProperties getTestConnectionProperties(DBMSType dbmsType) {
+
+ if (dbmsType == DBMSType.MYSQL) {
+ return new DBMSConnectionProperties(dbmsType, "localhost", dbmsType.getDefaultPort(), "jabref", "root", "");
+ }
+
+ if (dbmsType == DBMSType.POSTGRESQL) {
+ return new DBMSConnectionProperties(dbmsType, "localhost", dbmsType.getDefaultPort(), "jabref", "postgres", "");
+ }
+
+ if (dbmsType == DBMSType.ORACLE) {
+ return new DBMSConnectionProperties(dbmsType, "localhost", dbmsType.getDefaultPort(), "xe", "travis", "travis");
+ }
+
+ return new DBMSConnectionProperties();
+ }
+}
diff --git a/src/test/java/net/sf/jabref/shared/TestManager.java b/src/test/java/net/sf/jabref/shared/TestManager.java
new file mode 100644
index 0000000..c8d6063
--- /dev/null
+++ b/src/test/java/net/sf/jabref/shared/TestManager.java
@@ -0,0 +1,50 @@
+package net.sf.jabref.shared;
+
+import java.sql.SQLException;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import net.sf.jabref.shared.exception.InvalidDBMSConnectionPropertiesException;
+
+/**
+ * This class provides helping methods for database tests.
+ * Furthermore it determines database systems which are ready to be used for tests.
+ */
+public class TestManager {
+
+ public static Collection<DBMSType> getDBMSTypeTestParameter() {
+
+ Set<DBMSType> dbmsTypes = new HashSet<>();
+ for (DBMSType dbmsType : DBMSType.values()) {
+ try {
+ TestConnector.getTestDBMSConnection(dbmsType);
+ dbmsTypes.add(dbmsType);
+ } catch (SQLException | InvalidDBMSConnectionPropertiesException e) {
+ // skip parameter
+ }
+ }
+ return dbmsTypes;
+ }
+
+ public static void clearTables(DBMSConnection dbmsConnection) throws SQLException {
+ DBMSType dbmsType = dbmsConnection.getProperties().getType();
+
+ if (dbmsType == DBMSType.MYSQL) {
+ dbmsConnection.getConnection().createStatement().executeUpdate("DROP TABLE IF EXISTS `FIELD`");
+ dbmsConnection.getConnection().createStatement().executeUpdate("DROP TABLE IF EXISTS `ENTRY`");
+ dbmsConnection.getConnection().createStatement().executeUpdate("DROP TABLE IF EXISTS `METADATA`");
+ } else if (dbmsType == DBMSType.POSTGRESQL) {
+ dbmsConnection.getConnection().createStatement().executeUpdate("DROP TABLE IF EXISTS \"FIELD\"");
+ dbmsConnection.getConnection().createStatement().executeUpdate("DROP TABLE IF EXISTS \"ENTRY\"");
+ dbmsConnection.getConnection().createStatement().executeUpdate("DROP TABLE IF EXISTS \"METADATA\"");
+ } else if (dbmsType == DBMSType.ORACLE) {
+ dbmsConnection.getConnection().createStatement()
+ .executeUpdate("BEGIN\n" + "EXECUTE IMMEDIATE 'DROP TABLE \"FIELD\"';\n"
+ + "EXECUTE IMMEDIATE 'DROP TABLE \"ENTRY\"';\n"
+ + "EXECUTE IMMEDIATE 'DROP TABLE \"METADATA\"';\n"
+ + "EXECUTE IMMEDIATE 'DROP SEQUENCE \"ENTRY_SEQ\"';\n" + "EXCEPTION\n" + "WHEN OTHERS THEN\n"
+ + "IF SQLCODE != -942 THEN\n" + "RAISE;\n" + "END IF;\n" + "END;");
+ }
+ }
+}
diff --git a/src/test/java/net/sf/jabref/specialfields/SpecialFieldsUtilsTest.java b/src/test/java/net/sf/jabref/specialfields/SpecialFieldsUtilsTest.java
deleted file mode 100644
index b08a501..0000000
--- a/src/test/java/net/sf/jabref/specialfields/SpecialFieldsUtilsTest.java
+++ /dev/null
@@ -1,122 +0,0 @@
-package net.sf.jabref.specialfields;
-
-import java.util.Optional;
-
-import net.sf.jabref.Globals;
-import net.sf.jabref.gui.undo.NamedCompound;
-import net.sf.jabref.model.entry.BibEntry;
-import net.sf.jabref.preferences.JabRefPreferences;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-
-public class SpecialFieldsUtilsTest {
-
- @Before
- public void setUp() {
- Globals.prefs = JabRefPreferences.getInstance();
- }
-
- @Test
- public void testSyncKeywordsFromSpecialFieldsBibEntry() {
- BibEntry entry = new BibEntry();
- entry.setField("ranking", "rank2");
- SpecialFieldsUtils.syncKeywordsFromSpecialFields(entry);
- assertEquals(Optional.of("rank2"), entry.getFieldOptional("keywords"));
- }
-
- @Test
- public void testSyncKeywordsFromSpecialFieldsBibEntryNamedCompoundHasEdits() {
- BibEntry entry = new BibEntry();
- NamedCompound nc = new NamedCompound("Test");
- entry.setField("ranking", "rank2");
- SpecialFieldsUtils.syncKeywordsFromSpecialFields(entry, nc);
- assertTrue(nc.hasEdits());
- }
-
- @Test
- public void testSyncKeywordsFromSpecialFieldsBibEntryExisitingKeyword() {
- BibEntry entry = new BibEntry();
- entry.setField("ranking", "rank2");
- entry.setField("keywords", "rank3");
- SpecialFieldsUtils.syncKeywordsFromSpecialFields(entry);
- assertEquals(Optional.of("rank2"), entry.getFieldOptional("keywords"));
- }
-
- @Test
- public void testSyncKeywordsFromSpecialFieldsBibEntryNamedCompoundCorrectContent() {
- BibEntry entry = new BibEntry();
- NamedCompound nc = new NamedCompound("Test");
- entry.setField("ranking", "rank2");
- SpecialFieldsUtils.syncKeywordsFromSpecialFields(entry, nc);
- assertEquals(Optional.of("rank2"), entry.getFieldOptional("keywords"));
- }
-
- @Test
- public void testSyncKeywordsFromSpecialFieldsBibEntryNamedCompoundNoEdits() {
- BibEntry entry = new BibEntry();
- NamedCompound nc = new NamedCompound("Test");
- SpecialFieldsUtils.syncKeywordsFromSpecialFields(entry, nc);
- assertFalse(nc.hasEdits());
- }
-
- @Test
- public void testSyncSpecialFieldsFromKeywordsBibEntry() {
- BibEntry entry = new BibEntry();
- entry.setField("keywords", "rank2");
- SpecialFieldsUtils.syncSpecialFieldsFromKeywords(entry);
- assertEquals(Optional.of("rank2"), entry.getFieldOptional("ranking"));
- }
-
- @Test
- public void testSyncSpecialFieldsFromKeywordsBibEntryNamedCompoundHasEdits() {
- BibEntry entry = new BibEntry();
- NamedCompound nc = new NamedCompound("Test");
- entry.setField("keywords", "rank2");
- SpecialFieldsUtils.syncSpecialFieldsFromKeywords(entry, nc);
- assertTrue(nc.hasEdits());
- }
-
- @Test
- public void testSyncSpecialFieldsFromKeywordsBibEntryNamedCompoundCorrectContent() {
- BibEntry entry = new BibEntry();
- NamedCompound nc = new NamedCompound("Test");
- entry.setField("keywords", "rank2");
- SpecialFieldsUtils.syncSpecialFieldsFromKeywords(entry, nc);
- assertEquals(Optional.of("rank2"), entry.getFieldOptional("ranking"));
- }
-
- @Test
- public void testSyncSpecialFieldsFromKeywordsBibEntryNamedCompoundNoEdit() {
- BibEntry entry = new BibEntry();
- NamedCompound nc = new NamedCompound("Test");
- SpecialFieldsUtils.syncSpecialFieldsFromKeywords(entry, nc);
- assertFalse(nc.hasEdits());
- }
-
- @Test
- public void testGetSpecialFieldInstanceFromFieldNameValid() {
- assertEquals(Optional.of(Rank.getInstance()),
- SpecialFieldsUtils.getSpecialFieldInstanceFromFieldName("ranking"));
- }
-
- @Test
- public void testGetSpecialFieldInstanceFromFieldNameInvalid() {
- assertEquals(Optional.empty(), SpecialFieldsUtils.getSpecialFieldInstanceFromFieldName("title"));
- }
-
- @Test
- public void testIsSpecialFieldTrue() {
- assertTrue(SpecialFieldsUtils.isSpecialField("ranking"));
- }
-
- @Test
- public void testIsSpecialFieldFalse() {
- assertFalse(SpecialFieldsUtils.isSpecialField("title"));
- }
-}
diff --git a/src/test/java/net/sf/jabref/support/DevEnvironment.java b/src/test/java/net/sf/jabref/support/DevEnvironment.java
index dbaa5ca..4fcc0d9 100644
--- a/src/test/java/net/sf/jabref/support/DevEnvironment.java
+++ b/src/test/java/net/sf/jabref/support/DevEnvironment.java
@@ -5,9 +5,22 @@ package net.sf.jabref.support;
* This is needed as some remote fetcher tests are blocked by Google when executed by CI servers.
*/
public class DevEnvironment {
+
public static boolean isCIServer() {
// See http://docs.travis-ci.com/user/environment-variables/#Default-Environment-Variables
// See https://circleci.com/docs/environment-variables
+ // See https://docs.snap-ci.com/environment-variables/
return Boolean.valueOf(System.getenv("CI"));
}
+
+ public static boolean isCircleCI() {
+ // See https://circleci.com/docs/environment-variables
+ return Boolean.valueOf(System.getenv("CIRCLECI"));
+ }
+
+ public static boolean isSnapCI() {
+ // See https://docs.snap-ci.com/environment-variables/
+ return Boolean.valueOf(System.getenv("SNAP_CI"));
+ }
+
}
diff --git a/src/test/java/net/sf/jabref/testutils/AssertUtil.java b/src/test/java/net/sf/jabref/testutils/AssertUtil.java
deleted file mode 100644
index 5b09333..0000000
--- a/src/test/java/net/sf/jabref/testutils/AssertUtil.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package net.sf.jabref.testutils;
-
-import org.junit.Assert;
-
-public class AssertUtil {
-
- /**
- * Will check if two paths are the same.
- */
- public static void assertEqualPaths(String path1, String path2) {
- Assert.assertNotNull("first path must not be null", path1);
- Assert.assertNotNull("second path must not be null", path2);
- Assert.assertEquals(path1.replaceAll("\\\\", "/"), path2.replaceAll("\\\\", "/"));
- }
-}
diff --git a/src/test/java/net/sf/jabref/testutils/GuiTestUtils.java b/src/test/java/net/sf/jabref/testutils/GuiTestUtils.java
deleted file mode 100644
index d341e4a..0000000
--- a/src/test/java/net/sf/jabref/testutils/GuiTestUtils.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package net.sf.jabref.testutils;
-
-import java.awt.Component;
-import java.awt.Container;
-
-/**
- * Provides helper methods for making testing of GUIs easier.
- *
- * @author Dennis Hartrampf, Ines Moosdorf
- */
-public class GuiTestUtils {
-
- /**
- * Get a Component by name.
- *
- * @param parent The parent Component, where to search in.
- * @param name The name of the Component to find.
- * @return The Component with the given name or null if no
- * such Component.
- */
- public static Component getChildNamed(Component parent, String name) {
- if (name.equals(parent.getName())) {
- return parent;
- }
-
- if (parent instanceof Container) {
- Component[] children = ((Container) parent).getComponents();
-
- for (Component aChildren : children) {
- Component child = GuiTestUtils.getChildNamed(aChildren, name);
- if (child != null) {
- return child;
- }
- }
- }
- return null;
- }
-}
diff --git a/src/test/java/net/sf/jabref/testutils/category/DatabaseTests.java b/src/test/java/net/sf/jabref/testutils/category/DatabaseTests.java
new file mode 100644
index 0000000..f763092
--- /dev/null
+++ b/src/test/java/net/sf/jabref/testutils/category/DatabaseTests.java
@@ -0,0 +1,4 @@
+package net.sf.jabref.testutils.category;
+
+public interface DatabaseTests {
+}
diff --git a/src/test/java/net/sf/jabref/testutils/category/FetcherTests.java b/src/test/java/net/sf/jabref/testutils/category/FetcherTests.java
new file mode 100644
index 0000000..c6923ae
--- /dev/null
+++ b/src/test/java/net/sf/jabref/testutils/category/FetcherTests.java
@@ -0,0 +1,4 @@
+package net.sf.jabref.testutils.category;
+
+public interface FetcherTests {
+}
diff --git a/src/test/java/net/sf/jabref/testutils/category/GUITests.java b/src/test/java/net/sf/jabref/testutils/category/GUITests.java
new file mode 100644
index 0000000..874ba08
--- /dev/null
+++ b/src/test/java/net/sf/jabref/testutils/category/GUITests.java
@@ -0,0 +1,4 @@
+package net.sf.jabref.testutils.category;
+
+public interface GUITests {
+}
diff --git a/src/test/resources/net/sf/jabref/customPreferences.xml b/src/test/resources/net/sf/jabref/customPreferences.xml
index cecad1b..78a1647 100644
--- a/src/test/resources/net/sf/jabref/customPreferences.xml
+++ b/src/test/resources/net/sf/jabref/customPreferences.xml
@@ -86,8 +86,6 @@
<entry key="resolveStringsAllFields" value="false"/>
<entry key="doNotResolveStringsFor" value="url"/>
<entry key="autoSave" value="true"/>
- <entry key="promptBeforeUsingAutosave" value="true"/>
- <entry key="autoSaveInterval" value="5"/>
<entry key="valueDelimiters" value="1"/>
<entry key="includeEmptyFields" value="false"/>
<entry key="writeFieldCamelCase" value="true"/>
diff --git a/src/test/resources/net/sf/jabref/logic/auxparser/crossref.aux b/src/test/resources/net/sf/jabref/logic/auxparser/crossref.aux
new file mode 100644
index 0000000..6fb30c9
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/auxparser/crossref.aux
@@ -0,0 +1,9 @@
+\relax
+\citation{Einstein1920a}
+\citation{Einstein1920b}
+\citation{Einstein1920c}
+\citation{UnresolvedKey}
+\bibstyle{plain}
+\bibdata{origin}
+\bibcite{Einstein1920a}{1}
+\@writefile{toc}{\contentsline {section}{\numberline {1}}{1}}
diff --git a/src/test/resources/net/sf/jabref/logic/auxparser/nested.aux b/src/test/resources/net/sf/jabref/logic/auxparser/nested.aux
index 8f29566..4322a63 100644
--- a/src/test/resources/net/sf/jabref/logic/auxparser/nested.aux
+++ b/src/test/resources/net/sf/jabref/logic/auxparser/nested.aux
@@ -2,4 +2,5 @@
\bibstyle{plain}
\bibdata{origin}
\@input{paper.aux}
+\@input{paper.aux}
\@writefile{toc}{\contentsline {section}{\numberline {1}}{1}}
diff --git a/src/test/resources/net/sf/jabref/logic/auxparser/origin.bib b/src/test/resources/net/sf/jabref/logic/auxparser/origin.bib
index 72fb3bc..fbea84e 100644
--- a/src/test/resources/net/sf/jabref/logic/auxparser/origin.bib
+++ b/src/test/resources/net/sf/jabref/logic/auxparser/origin.bib
@@ -21,4 +21,19 @@
author = {Einstein, Albert}
}
+ at InBook{Einstein1920a,
+ crossref = {Einstein1920},
+ pages = {22--23}
+}
+
+ at InBook{Einstein1920b,
+ crossref = {Einstein1921},
+ pages = {22--23}
+}
+
+ at InBook{Einstein1920c,
+ crossref = {Einstein1920},
+ pages = {25--33}
+}
+
@Comment{jabref-meta: databaseType:bibtex;}
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestArticle.bib b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestArticle.bib
new file mode 100644
index 0000000..f170c7f
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestArticle.bib
@@ -0,0 +1,11 @@
+% Encoding: UTF-8
+
+ at Article{Mustermann2016,
+ author = {Max Mustermann},
+ title = {Java tricks},
+ journal = {Java Journal},
+ year = {2016},
+ pages = {2},
+ month = {February},
+ keywords = {java}
+}
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestArticle.xml b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestArticle.xml
new file mode 100644
index 0000000..28010c4
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestArticle.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<file xmlns="http://bibtexml.sf.net/">
+ <entry id="Mustermann2016">
+ <article>
+ <author>Max Mustermann</author>
+ <title>Java tricks</title>
+ <journal>Java Journal</journal>
+ <year>2016</year>
+ <pages>2</pages>
+ <month>February</month>
+ <keywords>java</keywords>
+ </article>
+ </entry>
+</file>
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestArticleWithoutID.bib b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestArticleWithoutID.bib
new file mode 100644
index 0000000..b759fbe
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestArticleWithoutID.bib
@@ -0,0 +1,11 @@
+% Encoding: UTF-8
+
+ at Article{,
+ author = {Max Mustermann},
+ title = {Java tricks},
+ journal = {Java Journal},
+ year = {2016},
+ pages = {2},
+ month = {February},
+ keywords = {java}
+}
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestArticleWithoutID.xml b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestArticleWithoutID.xml
new file mode 100644
index 0000000..d1fbc68
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestArticleWithoutID.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<file xmlns="http://bibtexml.sf.net/">
+ <entry>
+ <article>
+ <author>Max Mustermann</author>
+ <title>Java tricks</title>
+ <journal>Java Journal</journal>
+ <year>2016</year>
+ <pages>2</pages>
+ <month>February</month>
+ <keywords>java</keywords>
+ </article>
+ </entry>
+</file>
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestAuthor.bib b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestAuthor.bib
new file mode 100644
index 0000000..f4cdac6
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestAuthor.bib
@@ -0,0 +1,5 @@
+% Encoding: UTF-8
+
+ at Misc{,
+ author = {Burri, Emanuel and Beglinger, Christoph and von Felten, Stefanie and Lehmann, Frank Serge}
+}
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestAuthor.xml b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestAuthor.xml
new file mode 100644
index 0000000..6a4e0c9
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestAuthor.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<file xmlns="http://bibtexml.sf.net/">
+ <entry>
+ <misc>
+ <author>Burri, Emanuel and Beglinger, Christoph and von Felten, Stefanie and Lehmann, Frank Serge</author>
+ </misc>
+ </entry>
+</file>
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestBook.bib b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestBook.bib
new file mode 100644
index 0000000..d4b21de
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestBook.bib
@@ -0,0 +1,11 @@
+% Encoding: UTF-8
+
+ at Book{Mustermann2016,
+ title = {Java Book},
+ publisher = {Java Book Publisher},
+ year = {2016},
+ author = {Max Mustermann},
+ volume = {1},
+ month = {February},
+ keywords = {java}
+}
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestBook.xml b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestBook.xml
new file mode 100644
index 0000000..4f167bd
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestBook.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<file xmlns="http://bibtexml.sf.net/">
+ <entry id="Mustermann2016">
+ <book>
+ <author>Max Mustermann</author>
+ <title>Java Book</title>
+ <publisher>Java Book Publisher</publisher>
+ <year>2016</year>
+ <volume>1</volume>
+ <month>February</month>
+ <keywords>java</keywords>
+ </book>
+ </entry>
+</file>
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestBooklet.bib b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestBooklet.bib
new file mode 100644
index 0000000..3dad334
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestBooklet.bib
@@ -0,0 +1,10 @@
+% Encoding: UTF-8
+
+ at Booklet{Mustermann2016,
+ title = {Java Booklet},
+ author = {Max Mustermann},
+ address = {Stuttgart},
+ month = {February},
+ year = {2016},
+ keywords = {java}
+}
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestBooklet.xml b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestBooklet.xml
new file mode 100644
index 0000000..f958037
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestBooklet.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<file xmlns="http://bibtexml.sf.net/">
+ <entry id="Mustermann2016">
+ <booklet>
+ <author>Max Mustermann</author>
+ <title>Java Booklet</title>
+ <address>Stuttgart</address>
+ <month>February</month>
+ <year>2016</year>
+ <keywords>java</keywords>
+ </booklet>
+ </entry>
+</file>
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestConference.bib b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestConference.bib
new file mode 100644
index 0000000..e7709ce
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestConference.bib
@@ -0,0 +1,18 @@
+% Encoding: UTF-8
+
+ at Conference{Mustermann2016,
+ author = {Max Mustermann},
+ title = {Java Conference},
+ booktitle = {Java Booktitle},
+ year = {2016},
+ editor = {Maxima Musterfrau},
+ volume = {1},
+ number = {1},
+ series = {1},
+ pages = {3-9},
+ address = {Stuttgart},
+ month = {February},
+ organization = {Java Org},
+ publisher = {Java Publisher},
+ keywords = {java}
+}
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestConference.xml b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestConference.xml
new file mode 100644
index 0000000..d363b41
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestConference.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<file xmlns="http://bibtexml.sf.net/">
+ <entry id="Mustermann2016">
+ <conference>
+ <author>Max Mustermann</author>
+ <title>Java Conference</title>
+ <booktitle>Java Booktitle</booktitle>
+ <year>2016</year>
+ <editor>Maxima Musterfrau</editor>
+ <volume>1</volume>
+ <number>1</number>
+ <series>1</series>
+ <pages>3-9</pages>
+ <address>Stuttgart</address>
+ <month>February</month>
+ <organization>Java Org</organization>
+ <publisher>Java Publisher</publisher>
+ <keywords>java</keywords>
+ </conference>
+ </entry>
+</file>
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestInBook.bib b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestInBook.bib
new file mode 100644
index 0000000..d0e1c4d
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestInBook.bib
@@ -0,0 +1,13 @@
+% Encoding: UTF-8
+
+ at InBook{Mustermann2016,
+ chapter = {8},
+ pages = {18-25},
+ title = {Java 8 Lambdas},
+ publisher = {Java Book Publisher},
+ year = {2016},
+ author = {Max Mustermann},
+ volume = {1},
+ month = {February},
+ keywords = {java}
+}
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestInBook.xml b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestInBook.xml
new file mode 100644
index 0000000..bfce988
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestInBook.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<file xmlns="http://bibtexml.sf.net/">
+ <entry id="Mustermann2016">
+ <inbook>
+ <volume>1</volume>
+ <chapter>8</chapter>
+ <pages>18-25</pages>
+ <month>February</month>
+ <keywords>java</keywords>
+ <year>2016</year>
+ <author>Max Mustermann</author>
+ <bibtexkey>Mustermann2016</bibtexkey>
+ <publisher>Java Book Publisher</publisher>
+ <title>Java 8 Lambdas</title>
+ </inbook>
+ </entry>
+</file>
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestInCollection.bib b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestInCollection.bib
new file mode 100644
index 0000000..9fa735a
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestInCollection.bib
@@ -0,0 +1,16 @@
+% Encoding: UTF-8
+
+ at InCollection{Mustermann2016,
+ author = {Max Mustermann},
+ title = {Java InCollection},
+ booktitle = {Java Testing},
+ publisher = {Java Publisher},
+ year = {2016},
+ editor = {Maxima Musterfrau},
+ volume = {1},
+ number = {1},
+ chapter = {3},
+ pages = {18-26},
+ month = {February},
+ keywords = {java}
+}
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestInCollection.xml b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestInCollection.xml
new file mode 100644
index 0000000..71a2ba4
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestInCollection.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<file xmlns="http://bibtexml.sf.net/">
+ <entry id="Mustermann2016">
+ <incollection>
+ <author>Max Mustermann</author>
+ <title>Java InCollection</title>
+ <booktitle>Java Testing</booktitle>
+ <publisher>Java Publisher</publisher>
+ <year>2016</year>
+ <editor>Maxima Musterfrau</editor>
+ <volume>1</volume>
+ <number>1</number>
+ <pages>18-26</pages>
+ <month>February</month>
+ <keywords>java</keywords>
+ </incollection>
+ </entry>
+</file>
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestInProceedings.bib b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestInProceedings.bib
new file mode 100644
index 0000000..0a95465
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestInProceedings.bib
@@ -0,0 +1,12 @@
+% Encoding: UTF-8
+
+ at InProceedings{Mustermann2016,
+ author = {Max Mustermann},
+ title = {Java InProceedings},
+ booktitle = {Java Book},
+ year = {2016},
+ month = {February},
+ organization = {Java Org},
+ publisher = {Java Publisher},
+ keywords = {java}
+}
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestInProceedings.xml b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestInProceedings.xml
new file mode 100644
index 0000000..e0dfe36
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestInProceedings.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<file xmlns="http://bibtexml.sf.net/">
+ <entry id="Mustermann2016">
+ <inproceedings>
+ <author>Max Mustermann</author>
+ <title>Java InProceedings</title>
+ <booktitle>Java Book</booktitle>
+ <year>2016</year>
+ <month>February</month>
+ <organization>Java Org</organization>
+ <publisher>Java Publisher</publisher>
+ <keywords>java</keywords>
+ </inproceedings>
+ </entry>
+</file>
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestInbookLessFields.bib b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestInbookLessFields.bib
new file mode 100644
index 0000000..4014194
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestInbookLessFields.bib
@@ -0,0 +1,15 @@
+ at InBook{Mustermann2016,
+ chapter = {10},
+ title = {Java Conference},
+ publisher = {Java Publisher},
+ author = {Max Mustermann},
+ editor = {Maxima Musterfrau},
+ volume = {1},
+ number = {1},
+ series = {1},
+ address = {Stuttgart},
+ edition = {10},
+ month = {February},
+ note = {some note},
+ keywords = {java},
+}
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestInbookLessFields.xml b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestInbookLessFields.xml
new file mode 100644
index 0000000..b45b557
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestInbookLessFields.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<file xmlns="http://bibtexml.sf.net/">
+ <entry id="Mustermann2016">
+ <inbook>
+ <editor>Maxima Musterfrau</editor>
+ <chapter>10</chapter>
+ <note>some note</note>
+ <address>Stuttgart</address>
+ <keywords>java</keywords>
+ <author>Max Mustermann</author>
+ <edition>10</edition>
+ <title>Java Conference</title>
+ <volume>1</volume>
+ <number>1</number>
+ <month>February</month>
+ <series>1</series>
+ <publisher>Java Publisher</publisher>
+ <bibtexkey>Mustermann2016</bibtexkey>
+ </inbook>
+ </entry>
+</file>
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestInvalidInbook.bib b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestInvalidInbook.bib
new file mode 100644
index 0000000..84b1642
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestInvalidInbook.bib
@@ -0,0 +1,3 @@
+ at inbook{Mustermann2016,
+
+}
\ No newline at end of file
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestInvalidInbook.xml b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestInvalidInbook.xml
new file mode 100644
index 0000000..964936a
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestInvalidInbook.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<file xmlns="http://bibtexml.sf.net/">
+ <entry id="Mustermann2016">
+ <inbook>
+ <bibtexkey>Mustermann2016</bibtexkey>
+ </inbook>
+ </entry>
+</file>
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestManual.bib b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestManual.bib
new file mode 100644
index 0000000..21a7961
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestManual.bib
@@ -0,0 +1,11 @@
+% Encoding: UTF-8
+
+ at Manual{Mustermann2016,
+ title = {How to install Java},
+ author = {Max Mustermann},
+ organization = {Java Users},
+ address = {Stuttgart},
+ month = {February},
+ year = {2016},
+ keywords = {java}
+}
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestManual.xml b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestManual.xml
new file mode 100644
index 0000000..876f8f7
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestManual.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<file xmlns="http://bibtexml.sf.net/">
+ <entry id="Mustermann2016">
+ <manual>
+ <author>Max Mustermann</author>
+ <title>How to install Java</title>
+ <organization>Java Users</organization>
+ <address>Stuttgart</address>
+ <month>February</month>
+ <year>2016</year>
+ <keywords>java</keywords>
+ </manual>
+ </entry>
+</file>
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestMasterThesis.bib b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestMasterThesis.bib
new file mode 100644
index 0000000..003c287
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestMasterThesis.bib
@@ -0,0 +1,12 @@
+% Encoding: UTF-8
+
+ at MastersThesis{Mustermann2016,
+ author = {Max Mustermann},
+ title = {Java MasterThesis},
+ school = {University},
+ year = {2016},
+ type = {Thesis},
+ address = {Stuttgart},
+ month = {February},
+ keywords = {java}
+}
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestMasterThesis.xml b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestMasterThesis.xml
new file mode 100644
index 0000000..6d7e0cf
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestMasterThesis.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<file xmlns="http://bibtexml.sf.net/">
+ <entry id="Mustermann2016">
+ <mastersthesis>
+ <author>Max Mustermann</author>
+ <title>Java MasterThesis</title>
+ <school>University</school>
+ <year>2016</year>
+ <type>Thesis</type>
+ <address>Stuttgart</address>
+ <month>February</month>
+ <keywords>java</keywords>
+ </mastersthesis>
+ </entry>
+</file>
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestMisc.bib b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestMisc.bib
new file mode 100644
index 0000000..9101bba
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestMisc.bib
@@ -0,0 +1,10 @@
+% Encoding: UTF-8
+
+ at Misc{Mustermann2016,
+ author = {Max Mustermann},
+ title = {Java Misc},
+ howpublished = {Internet},
+ month = {February},
+ year = {2016},
+ keywords = {java}
+}
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestMisc.xml b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestMisc.xml
new file mode 100644
index 0000000..8e84a02
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestMisc.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<file xmlns="http://bibtexml.sf.net/">
+ <entry id="Mustermann2016">
+ <misc>
+ <author>Max Mustermann</author>
+ <title>Java Misc</title>
+ <howpublished>Internet</howpublished>
+ <month>February</month>
+ <year>2016</year>
+ <keywords>java</keywords>
+ </misc>
+ </entry>
+</file>
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestPhdThesis.bib b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestPhdThesis.bib
new file mode 100644
index 0000000..6121bc3
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestPhdThesis.bib
@@ -0,0 +1,12 @@
+% Encoding: UTF-8
+
+ at PhdThesis{Mustermann2016,
+ author = {Max Mustermann},
+ title = {Java PhdThesis},
+ school = {University},
+ year = {2016},
+ type = {Thesis},
+ address = {Stuttgart},
+ month = {February},
+ keywords = {java}
+}
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestPhdThesis.xml b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestPhdThesis.xml
new file mode 100644
index 0000000..0712509
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestPhdThesis.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<file xmlns="http://bibtexml.sf.net/">
+ <entry id="Mustermann2016">
+ <phdthesis>
+ <author>Max Mustermann</author>
+ <title>Java PhdThesis</title>
+ <school>University</school>
+ <year>2016</year>
+ <type>Thesis</type>
+ <address>Stuttgart</address>
+ <month>February</month>
+ <keywords>java</keywords>
+ </phdthesis>
+ </entry>
+</file>
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestProceedings.bib b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestProceedings.bib
new file mode 100644
index 0000000..8d6cbe4
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestProceedings.bib
@@ -0,0 +1,11 @@
+% Encoding: UTF-8
+
+ at Proceedings{Musterfrau2016,
+ title = {Java Proceedings},
+ year = {2016},
+ editor = {Maxima Musterfrau},
+ address = {Stuttgart},
+ publisher = {Java Pub},
+ month = {February},
+ organization = {Java Org}
+}
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestProceedings.xml b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestProceedings.xml
new file mode 100644
index 0000000..143e178
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestProceedings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<file xmlns="http://bibtexml.sf.net/">
+ <entry id="Musterfrau2016">
+ <proceedings>
+ <editor>Maxima Musterfrau</editor>
+ <title>Java Proceedings</title>
+ <year>2016</year>
+ <address>Stuttgart</address>
+ <month>February</month>
+ <organization>Java Org</organization>
+ <publisher>Java Pub</publisher>
+ </proceedings>
+ </entry>
+</file>
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestTechReport.bib b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestTechReport.bib
new file mode 100644
index 0000000..1ab28ba
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestTechReport.bib
@@ -0,0 +1,11 @@
+ at TechReport{Mustermann2016,
+ author = {Max Mustermann},
+ title = {Java TechReport},
+ institution = {JIOT},
+ year = {2016},
+ type = {Report},
+ number = {1},
+ address = {Stuttgart},
+ month = {February},
+ keywords = {java},
+}
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestTechReport.xml b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestTechReport.xml
new file mode 100644
index 0000000..b9e7f2e
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestTechReport.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<file xmlns="http://bibtexml.sf.net/">
+ <entry id="Mustermann2016">
+ <techreport>
+ <author>Max Mustermann</author>
+ <title>Java TechReport</title>
+ <institution>JIOT</institution>
+ <year>2016</year>
+ <type>Report</type>
+ <number>1</number>
+ <address>Stuttgart</address>
+ <month>February</month>
+ <keywords>java</keywords>
+ </techreport>
+ </entry>
+</file>
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestUnpublished.bib b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestUnpublished.bib
new file mode 100644
index 0000000..f1720dd
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestUnpublished.bib
@@ -0,0 +1,9 @@
+% Encoding: UTF-8
+
+ at Unpublished{Mustermann2016,
+ author = {Max Mustermann},
+ title = {Java Unpublished},
+ month = {February},
+ year = {2016},
+ keywords = {java}
+}
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestUnpublished.xml b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestUnpublished.xml
new file mode 100644
index 0000000..37e7ebf
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/BibTeXMLExporterTestUnpublished.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<file xmlns="http://bibtexml.sf.net/">
+ <entry id="Mustermann2016">
+ <unpublished>
+ <author>Max Mustermann</author>
+ <title>Java Unpublished</title>
+ <month>February</month>
+ <year>2016</year>
+ <keywords>java</keywords>
+ </unpublished>
+ </entry>
+</file>
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/ModsExportFormatTestAllFields.bib b/src/test/resources/net/sf/jabref/logic/exporter/ModsExportFormatTestAllFields.bib
new file mode 100644
index 0000000..a151c7f
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/ModsExportFormatTestAllFields.bib
@@ -0,0 +1,29 @@
+% Encoding: UTF-8
+
+ at Article{,
+ author = {Don't, know and Realy, don't know},
+ title = {title},
+ journal = {Some journal},
+ year = {2000},
+ volume = {5},
+ pages = {67-68},
+ note = {a note, and another note},
+ abstract = {abstract},
+ address = {India},
+ affiliation = {an affiliation},
+ captured = {2000-11-11},
+ created = {2000-11-10},
+ doi = {someDoi},
+ edition = {2},
+ issuance = {monographic},
+ issue = {10},
+ keywords = {keyword, electrophoresis, neoplasia, spectrometry, translation},
+ language = {en},
+ location = {somewhere},
+ modified = {2000-12-10},
+ pmid = {123456789},
+ publisher = {Verlag verlag},
+ uri = {an uri},
+ url = {someWebSite},
+}
+
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/ModsExportFormatTestAllFields.xml b/src/test/resources/net/sf/jabref/logic/exporter/ModsExportFormatTestAllFields.xml
new file mode 100644
index 0000000..f446f13
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/ModsExportFormatTestAllFields.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<mods:modsCollection xmlns="http://www.w3.org/1999/xlink" xmlns:mods="http://www.loc.gov/mods/v3" xmlns:ns3="http://www.w3.org/2001/XMLSchema-instance" ns3:schemaLocation="http://www.loc.gov/standards/mods/v3/mods-3-6.xsd">
+ <mods:mods>
+ <mods:genre>article</mods:genre>
+ <mods:note>a note</mods:note>
+ <mods:note>and another note</mods:note>
+ <mods:subject>
+ <mods:topic>keyword</mods:topic>
+ </mods:subject>
+ <mods:subject>
+ <mods:topic>electrophoresis</mods:topic>
+ </mods:subject>
+ <mods:subject>
+ <mods:topic>neoplasia</mods:topic>
+ </mods:subject>
+ <mods:subject>
+ <mods:topic>spectrometry</mods:topic>
+ </mods:subject>
+ <mods:subject>
+ <mods:topic>translation</mods:topic>
+ </mods:subject>
+ <mods:language>
+ <mods:languageTerm>en</mods:languageTerm>
+ </mods:language>
+ <mods:titleInfo>
+ <mods:title>title</mods:title>
+ </mods:titleInfo>
+ <mods:name>
+ <mods:affiliation>an affiliation</mods:affiliation>
+ </mods:name>
+ <mods:name type="personal">
+ <mods:namePart type="family">Don't</mods:namePart>
+ <mods:namePart type="given">know</mods:namePart>
+ </mods:name>
+ <mods:name type="personal">
+ <mods:namePart type="family"> Realy</mods:namePart>
+ <mods:namePart type="given">don't</mods:namePart>
+ <mods:namePart type="given">know</mods:namePart>
+ </mods:name>
+ <mods:abstract>abstract</mods:abstract>
+ <mods:identifier type="pmid">123456789</mods:identifier>
+ <mods:identifier type="uri">an uri</mods:identifier>
+ <mods:location>
+ <mods:url>someWebSite</mods:url>
+ </mods:location>
+ <mods:location>
+ <mods:physicalLocation>somewhere</mods:physicalLocation>
+ </mods:location>
+ <mods:identifier type="doi">someDoi</mods:identifier>
+ <mods:originInfo>
+ <mods:dateIssued keyDate="yes">2000</mods:dateIssued>
+ <mods:edition>2</mods:edition>
+ <mods:dateCaptured keyDate="yes">2000-11-11</mods:dateCaptured>
+ <mods:dateModified keyDate="yes">2000-12-10</mods:dateModified>
+ <mods:place>
+ <mods:placeTerm type="text">India</mods:placeTerm>
+ </mods:place>
+ <mods:dateCreated keyDate="yes">2000-11-10</mods:dateCreated>
+ <mods:issuance>monographic</mods:issuance>
+ <mods:publisher>Verlag verlag</mods:publisher>
+ </mods:originInfo>
+ <mods:relatedItem type="host">
+ <mods:titleInfo>
+ <mods:title>Some journal</mods:title>
+ </mods:titleInfo>
+ <mods:part>
+ <mods:extent>
+ <mods:start>67</mods:start>
+ <mods:end>68</mods:end>
+ </mods:extent>
+ <mods:detail type="issue">
+ <mods:number>10</mods:number>
+ </mods:detail>
+ <mods:detail type="volume">
+ <mods:number>5</mods:number>
+ </mods:detail>
+ </mods:part>
+ </mods:relatedItem>
+ <mods:typeOfResource>text</mods:typeOfResource>
+ </mods:mods>
+</mods:modsCollection>
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/ModsExportFormatTestBook.bib b/src/test/resources/net/sf/jabref/logic/exporter/ModsExportFormatTestBook.bib
new file mode 100644
index 0000000..2743b9d
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/ModsExportFormatTestBook.bib
@@ -0,0 +1,9 @@
+% Encoding: UTF-8
+
+ at Book{,
+ isbn = {123456789},
+ issn = {987654321},
+ keywords = {note, and another note},
+ pages = {67-68},
+}
+
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/ModsExportFormatTestBook.xml b/src/test/resources/net/sf/jabref/logic/exporter/ModsExportFormatTestBook.xml
new file mode 100644
index 0000000..b7aa1f6
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/ModsExportFormatTestBook.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<mods:modsCollection xmlns="http://www.w3.org/1999/xlink" xmlns:mods="http://www.loc.gov/mods/v3" xmlns:ns3="http://www.w3.org/2001/XMLSchema-instance" ns3:schemaLocation="http://www.loc.gov/standards/mods/v3/mods-3-6.xsd">
+ <mods:mods>
+ <mods:genre>book</mods:genre>
+ <mods:identifier type="issn">987654321</mods:identifier>
+ <mods:subject>
+ <mods:topic>note</mods:topic>
+ </mods:subject>
+ <mods:subject>
+ <mods:topic>and another note</mods:topic>
+ </mods:subject>
+ <mods:identifier type="isbn">123456789</mods:identifier>
+ <mods:originInfo/>
+ <mods:relatedItem type="host">
+ <mods:part>
+ <mods:extent>
+ <mods:start>67</mods:start>
+ <mods:end>68</mods:end>
+ </mods:extent>
+ </mods:part>
+ </mods:relatedItem>
+ <mods:typeOfResource>text</mods:typeOfResource>
+ </mods:mods>
+</mods:modsCollection>
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/ModsExportFormatTestMultipleEntries.bib b/src/test/resources/net/sf/jabref/logic/exporter/ModsExportFormatTestMultipleEntries.bib
new file mode 100644
index 0000000..391c8a7
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/ModsExportFormatTestMultipleEntries.bib
@@ -0,0 +1,20 @@
+% Encoding: UTF-8
+
+ at Article{,
+ author = {Shruthi, Basavaradhya Sahukar and Vinodhkumar, Palani and Selvamani},
+ title = {Proteomics: A new perspective for cancer.},
+ journal = {Advanced biomedical research},
+ year = {2016},
+ volume = {5},
+ pages = {67},
+ address = {India},
+ keywords = {Biomarkers, electrophoresis, neoplasia, spectrometry, translation},
+}
+
+ at Inproceedings{ShruthiVinodhkumarSelvamani2016,
+ author = {Shruthi, Basavaradhya Sahukar and Vinodhkumar, Palani and Selvamani},
+ title = {Proteomics: A new perspective for cancer.},
+ journal = {Advanced biomedical research},
+ year = {2016},
+}
+
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/ModsExportFormatTestMultipleEntries.xml b/src/test/resources/net/sf/jabref/logic/exporter/ModsExportFormatTestMultipleEntries.xml
new file mode 100644
index 0000000..6cd2c06
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/ModsExportFormatTestMultipleEntries.xml
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<mods:modsCollection xmlns="http://www.w3.org/1999/xlink" xmlns:mods="http://www.loc.gov/mods/v3" xmlns:ns3="http://www.w3.org/2001/XMLSchema-instance" ns3:schemaLocation="http://www.loc.gov/standards/mods/v3/mods-3-6.xsd">
+ <mods:mods>
+ <mods:genre>article</mods:genre>
+ <mods:subject>
+ <mods:topic>Biomarkers</mods:topic>
+ </mods:subject>
+ <mods:subject>
+ <mods:topic>electrophoresis</mods:topic>
+ </mods:subject>
+ <mods:subject>
+ <mods:topic>neoplasia</mods:topic>
+ </mods:subject>
+ <mods:subject>
+ <mods:topic>spectrometry</mods:topic>
+ </mods:subject>
+ <mods:subject>
+ <mods:topic>translation</mods:topic>
+ </mods:subject>
+ <mods:name type="personal">
+ <mods:namePart type="family">Shruthi</mods:namePart>
+ <mods:namePart type="given">Basavaradhya</mods:namePart>
+ <mods:namePart type="given">Sahukar</mods:namePart>
+ </mods:name>
+ <mods:name type="personal">
+ <mods:namePart type="family"> Vinodhkumar</mods:namePart>
+ <mods:namePart type="given">Palani</mods:namePart>
+ </mods:name>
+ <mods:name type="personal">
+ <mods:namePart type="family"> Selvamani</mods:namePart>
+ </mods:name>
+ <mods:titleInfo>
+ <mods:title>Proteomics: A new perspective for cancer.</mods:title>
+ </mods:titleInfo>
+ <mods:originInfo>
+ <mods:place>
+ <mods:placeTerm type="text">India</mods:placeTerm>
+ </mods:place>
+ <mods:dateIssued keyDate="yes">2016</mods:dateIssued>
+ </mods:originInfo>
+ <mods:relatedItem type="host">
+ <mods:titleInfo>
+ <mods:title>Advanced biomedical research</mods:title>
+ </mods:titleInfo>
+ <mods:part>
+ <mods:detail type="volume">
+ <mods:number>5</mods:number>
+ </mods:detail>
+ <mods:extent>
+ <mods:total>67</mods:total>
+ </mods:extent>
+ </mods:part>
+ </mods:relatedItem>
+ <mods:typeOfResource>text</mods:typeOfResource>
+ </mods:mods>
+ <mods:mods ID="ShruthiVinodhkumarSelvamani2016">
+ <mods:identifier type="citekey">ShruthiVinodhkumarSelvamani2016</mods:identifier>
+ <mods:genre>inproceedings</mods:genre>
+ <mods:name type="personal">
+ <mods:namePart type="family">Shruthi</mods:namePart>
+ <mods:namePart type="given">Basavaradhya</mods:namePart>
+ <mods:namePart type="given">Sahukar</mods:namePart>
+ </mods:name>
+ <mods:name type="personal">
+ <mods:namePart type="family"> Vinodhkumar</mods:namePart>
+ <mods:namePart type="given">Palani</mods:namePart>
+ </mods:name>
+ <mods:name type="personal">
+ <mods:namePart type="family"> Selvamani</mods:namePart>
+ </mods:name>
+ <mods:titleInfo>
+ <mods:title>Proteomics: A new perspective for cancer.</mods:title>
+ </mods:titleInfo>
+ <mods:originInfo>
+ <mods:dateIssued keyDate="yes">2016</mods:dateIssued>
+ </mods:originInfo>
+ <mods:relatedItem type="host">
+ <mods:titleInfo>
+ <mods:title>Advanced biomedical research</mods:title>
+ </mods:titleInfo>
+ <mods:part/>
+ </mods:relatedItem>
+ <mods:typeOfResource>text</mods:typeOfResource>
+ </mods:mods>
+</mods:modsCollection>
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/ModsExportFormatTestOnlyRequiredFields.bib b/src/test/resources/net/sf/jabref/logic/exporter/ModsExportFormatTestOnlyRequiredFields.bib
new file mode 100644
index 0000000..3b9c8ac
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/ModsExportFormatTestOnlyRequiredFields.bib
@@ -0,0 +1,9 @@
+% Encoding: UTF-8
+
+ at Article{ShruthiVinodhkumarSelvamani2016,
+ author = {Shruthi, Basavaradhya Sahukar and Vinodhkumar, Palani and Selvamani},
+ title = {Proteomics: A new perspective for cancer.},
+ journal = {Advanced biomedical research},
+ year = {2016},
+}
+
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/ModsExportFormatTestOnlyRequiredFields.xml b/src/test/resources/net/sf/jabref/logic/exporter/ModsExportFormatTestOnlyRequiredFields.xml
new file mode 100644
index 0000000..60cc365
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/ModsExportFormatTestOnlyRequiredFields.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<mods:modsCollection xmlns="http://www.w3.org/1999/xlink" xmlns:mods="http://www.loc.gov/mods/v3" xmlns:ns3="http://www.w3.org/2001/XMLSchema-instance" ns3:schemaLocation="http://www.loc.gov/standards/mods/v3/mods-3-6.xsd">
+ <mods:mods ID="ShruthiVinodhkumarSelvamani2016">
+ <mods:identifier type="citekey">ShruthiVinodhkumarSelvamani2016</mods:identifier>
+ <mods:genre>article</mods:genre>
+ <mods:name type="personal">
+ <mods:namePart type="family">Shruthi</mods:namePart>
+ <mods:namePart type="given">Basavaradhya</mods:namePart>
+ <mods:namePart type="given">Sahukar</mods:namePart>
+ </mods:name>
+ <mods:name type="personal">
+ <mods:namePart type="family"> Vinodhkumar</mods:namePart>
+ <mods:namePart type="given">Palani</mods:namePart>
+ </mods:name>
+ <mods:name type="personal">
+ <mods:namePart type="family"> Selvamani</mods:namePart>
+ </mods:name>
+ <mods:titleInfo>
+ <mods:title>Proteomics: A new perspective for cancer.</mods:title>
+ </mods:titleInfo>
+ <mods:originInfo>
+ <mods:dateIssued keyDate="yes">2016</mods:dateIssued>
+ </mods:originInfo>
+ <mods:relatedItem type="host">
+ <mods:titleInfo>
+ <mods:title>Advanced biomedical research</mods:title>
+ </mods:titleInfo>
+ <mods:part/>
+ </mods:relatedItem>
+ <mods:typeOfResource>text</mods:typeOfResource>
+ </mods:mods>
+</mods:modsCollection>
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/ModsExportFormatTestTotalPages.bib b/src/test/resources/net/sf/jabref/logic/exporter/ModsExportFormatTestTotalPages.bib
new file mode 100644
index 0000000..3b9df84
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/ModsExportFormatTestTotalPages.bib
@@ -0,0 +1,8 @@
+% Encoding: UTF-8
+
+ at InBook{test,
+ pages = {1234},
+ author = {Mustermann},
+ keywords = {keyword}
+}
+
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/ModsExportFormatTestTotalPages.xml b/src/test/resources/net/sf/jabref/logic/exporter/ModsExportFormatTestTotalPages.xml
new file mode 100644
index 0000000..5b928be
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/ModsExportFormatTestTotalPages.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<mods:modsCollection xmlns="http://www.w3.org/1999/xlink" xmlns:mods="http://www.loc.gov/mods/v3" xmlns:ns3="http://www.w3.org/2001/XMLSchema-instance" ns3:schemaLocation="http://www.loc.gov/standards/mods/v3/mods-3-6.xsd">
+ <mods:mods ID="test">
+ <mods:identifier type="citekey">test</mods:identifier>
+ <mods:genre>inbook</mods:genre>
+ <mods:subject>
+ <mods:topic>keyword</mods:topic>
+ </mods:subject>
+ <mods:name type="personal">
+ <mods:namePart type="family">Mustermann</mods:namePart>
+ </mods:name>
+ <mods:originInfo/>
+ <mods:relatedItem type="host">
+ <mods:part>
+ <mods:extent>
+ <mods:total>1234</mods:total>
+ </mods:extent>
+ </mods:part>
+ </mods:relatedItem>
+ <mods:typeOfResource>text</mods:typeOfResource>
+ </mods:mods>
+</mods:modsCollection>
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/MsBibExportFormatTest2.xml b/src/test/resources/net/sf/jabref/logic/exporter/MsBibExportFormatTest2.xml
index 54b1476..81f235d 100644
--- a/src/test/resources/net/sf/jabref/logic/exporter/MsBibExportFormatTest2.xml
+++ b/src/test/resources/net/sf/jabref/logic/exporter/MsBibExportFormatTest2.xml
@@ -14,7 +14,10 @@
<b:Author/>
<b:Pages>237-248</b:Pages>
<b:JournalName>Wirtschaftsinformatik</b:JournalName>
+<b:Number>3</b:Number>
<b:City>a</b:City>
+<b:StateProvince/>
+<b:CountryRegion/>
<b:ThesisType>type</b:ThesisType>
</b:Source>
</b:Sources>
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/MsBibExportFormatTest3.xml b/src/test/resources/net/sf/jabref/logic/exporter/MsBibExportFormatTest3.xml
index b6855b7..703feb7 100644
--- a/src/test/resources/net/sf/jabref/logic/exporter/MsBibExportFormatTest3.xml
+++ b/src/test/resources/net/sf/jabref/logic/exporter/MsBibExportFormatTest3.xml
@@ -1,12 +1,16 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<b:Sources xmlns:b="http://schemas.openxmlformats.org/officeDocument/2006/bibliography" xmlns="http://schemas.openxmlformats.org/officeDocument/2006/bibliography" SelectedStyle="">
<b:Source>
-<b:SourceType>Report</b:SourceType>
-<b:BIBTEX_Entry>manual</b:BIBTEX_Entry>
-<b:Tag>raey</b:Tag>
<b:LCID>0</b:LCID>
-<b:Title>Agile Entwicklung Web-basierter Systeme</b:Title>
<b:Year>2002</b:Year>
+<b:Volume>44</b:Volume>
+<b:BIBTEX_Entry>manual</b:BIBTEX_Entry>
+<b:SourceType>Report</b:SourceType>
+<b:Title>Agile Entwicklung Web-basierter Systeme</b:Title>
+<b:Tag>raey</b:Tag>
+<b:Publisher>Gabler Verlag</b:Publisher>
+<b:BIBTEX_KeyWords>software development processes; agile software development environments; time-to-market; Extreme Programming; Crystal methods family; Adaptive Software Development</b:BIBTEX_KeyWords>
+<b:URL>http://dx.doi.org/10.1007/BF03250842</b:URL>
<b:Author>
<b:Author>
<b:NameList>
@@ -17,11 +21,8 @@
</b:Author>
</b:Author>
<b:Pages>237-248</b:Pages>
-<b:Volume>44</b:Volume>
-<b:StandardNumber> LCCN: 0937-6429</b:StandardNumber>
-<b:Publisher>Gabler Verlag</b:Publisher>
<b:JournalName>Wirtschaftsinformatik</b:JournalName>
-<b:URL>http://dx.doi.org/10.1007/BF03250842</b:URL>
-<b:BIBTEX_KeyWords>software development processes; agile software development environments; time-to-market; Extreme Programming; Crystal methods family; Adaptive Software Development</b:BIBTEX_KeyWords>
+<b:Number>3</b:Number>
+<b:StandardNumber>LCCN: 0937-6429</b:StandardNumber>
</b:Source>
</b:Sources>
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/MsBibExportFormatTest6.xml b/src/test/resources/net/sf/jabref/logic/exporter/MsBibExportFormatTest6.xml
index df5fc50..e750dd6 100644
--- a/src/test/resources/net/sf/jabref/logic/exporter/MsBibExportFormatTest6.xml
+++ b/src/test/resources/net/sf/jabref/logic/exporter/MsBibExportFormatTest6.xml
@@ -1,19 +1,20 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<b:Sources xmlns:b="http://schemas.openxmlformats.org/officeDocument/2006/bibliography" xmlns="http://schemas.openxmlformats.org/officeDocument/2006/bibliography" SelectedStyle="">
<b:Source>
-<b:SourceType>Report</b:SourceType>
-<b:BIBTEX_Entry>mastersthesis</b:BIBTEX_Entry>
<b:LCID>0</b:LCID>
-<b:Title>Agile Entwicklung Web-basierter Systeme</b:Title>
<b:Year>2002</b:Year>
-<b:Author/>
-<b:Pages>237-248</b:Pages>
<b:Volume>44</b:Volume>
-<b:StandardNumber> MRN: 0937-6429</b:StandardNumber>
+<b:BIBTEX_Entry>mastersthesis</b:BIBTEX_Entry>
+<b:SourceType>Report</b:SourceType>
+<b:Title>Agile Entwicklung Web-basierter Systeme</b:Title>
<b:Publisher>Gabler Verlag</b:Publisher>
+<b:BIBTEX_KeyWords>software development processes; agile software development environments; time-to-market; Extreme Programming; Crystal methods family; Adaptive Software Development</b:BIBTEX_KeyWords>
+<b:URL>http://dx.doi.org/10.1007/BF03250842</b:URL>
+<b:Author/>
+<b:Pages>237-248</b:Pages>
<b:JournalName>Wirtschaftsinformatik</b:JournalName>
+<b:Number>3</b:Number>
+<b:StandardNumber> MRN: 0937-6429</b:StandardNumber>
<b:ThesisType>Master's thesis</b:ThesisType>
-<b:URL>http://dx.doi.org/10.1007/BF03250842</b:URL>
-<b:BIBTEX_KeyWords>software development processes; agile software development environments; time-to-market; Extreme Programming; Crystal methods family; Adaptive Software Development</b:BIBTEX_KeyWords>
</b:Source>
</b:Sources>
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/MsBibKeyTest.bib b/src/test/resources/net/sf/jabref/logic/exporter/MsBibKeyTest.bib
new file mode 100644
index 0000000..aefe023
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/MsBibKeyTest.bib
@@ -0,0 +1,12 @@
+% Encoding: UTF-8
+
+ at Mycustomentrytype{SampleAuthor2012,
+ author = {SampleAuthor},
+ year = {2012},
+ date = {2012},
+ key = {MyStandardKey},
+}
+
+ at Comment{jabref-meta: databaseType:biblatex;}
+
+ at Comment{jabref-entrytype: Mycustomentrytype: req[author;year/date;key] opt[]}
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/MsBibKeyTest.xml b/src/test/resources/net/sf/jabref/logic/exporter/MsBibKeyTest.xml
new file mode 100644
index 0000000..ee1aaf9
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/MsBibKeyTest.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<b:Sources xmlns:b="http://schemas.openxmlformats.org/officeDocument/2006/bibliography" xmlns="http://schemas.openxmlformats.org/officeDocument/2006/bibliography" SelectedStyle="">
+<b:Source>
+<b:BIBTEX_Key>MyStandardKey</b:BIBTEX_Key>
+<b:Year>2012</b:Year>
+<b:BIBTEX_Entry>mycustomentrytype</b:BIBTEX_Entry>
+<b:SourceType>Misc</b:SourceType>
+<b:Tag>SampleAuthor2012</b:Tag>
+<b:Author>
+<b:Author>
+<b:NameList>
+<b:Person>
+<b:Last>SampleAuthor</b:Last>
+</b:Person>
+</b:NameList>
+</b:Author>
+</b:Author>
+</b:Source>
+</b:Sources>
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/MsBibLocationTest.bib b/src/test/resources/net/sf/jabref/logic/exporter/MsBibLocationTest.bib
new file mode 100644
index 0000000..c05724a
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/MsBibLocationTest.bib
@@ -0,0 +1,10 @@
+% Encoding: UTF-8
+
+ at InProceedings{LocationTest,
+ author = {LocationTest},
+ location = {Berlin},
+ owner = {Christoph Schwentker},
+ timestamp = {2016.09.04},
+}
+
+ at Comment{jabref-meta: databaseType:biblatex;}
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/MsBibLocationTest.xml b/src/test/resources/net/sf/jabref/logic/exporter/MsBibLocationTest.xml
new file mode 100644
index 0000000..e6c3485
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/MsBibLocationTest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<b:Sources xmlns:b="http://schemas.openxmlformats.org/officeDocument/2006/bibliography" xmlns="http://schemas.openxmlformats.org/officeDocument/2006/bibliography" SelectedStyle="">
+<b:Source>
+<b:BIBTEX_Entry>inproceedings</b:BIBTEX_Entry>
+<b:SourceType>ConferenceProceedings</b:SourceType>
+<b:Tag>LocationTest</b:Tag>
+<b:Author>
+<b:Author>
+<b:NameList>
+<b:Person>
+<b:Last>LocationTest</b:Last>
+</b:Person>
+</b:NameList>
+</b:Author>
+</b:Author>
+<b:City>Berlin</b:City>
+<b:StateProvince/>
+<b:CountryRegion/>
+</b:Source>
+</b:Sources>
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/MsBibMultiAddressTest.bib b/src/test/resources/net/sf/jabref/logic/exporter/MsBibMultiAddressTest.bib
new file mode 100644
index 0000000..c2b6a59
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/MsBibMultiAddressTest.bib
@@ -0,0 +1,11 @@
+% Encoding: UTF-8
+
+ at InProceedings{MultiAddressTest,
+ author = {MultiAddressTest},
+ location = {Berlin},
+ address = {Stroudsburg, PA, USA},
+ owner = {Christoph Schwentker},
+ timestamp = {2016.09.04},
+}
+
+ at Comment{jabref-meta: databaseType:biblatex;}
diff --git a/src/test/resources/net/sf/jabref/logic/exporter/MsBibMultiAddressTest.xml b/src/test/resources/net/sf/jabref/logic/exporter/MsBibMultiAddressTest.xml
new file mode 100644
index 0000000..bd817c1
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/exporter/MsBibMultiAddressTest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<b:Sources xmlns:b="http://schemas.openxmlformats.org/officeDocument/2006/bibliography" xmlns="http://schemas.openxmlformats.org/officeDocument/2006/bibliography" SelectedStyle="">
+<b:Source>
+<b:BIBTEX_Entry>inproceedings</b:BIBTEX_Entry>
+<b:SourceType>ConferenceProceedings</b:SourceType>
+<b:Tag>MultiAddressTest</b:Tag>
+<b:Author>
+<b:Author>
+<b:NameList>
+<b:Person>
+<b:Last>MultiAddressTest</b:Last>
+</b:Person>
+</b:NameList>
+</b:Author>
+</b:Author>
+<b:City>Stroudsburg</b:City>
+<b:StateProvince>PA</b:StateProvince>
+<b:CountryRegion>USA</b:CountryRegion>
+</b:Source>
+</b:Sources>
diff --git a/src/test/resources/net/sf/jabref/logic/importer/fetcher/gvk_empty_result_becaue_of_bad_query.xml b/src/test/resources/net/sf/jabref/logic/importer/fetcher/gvk_empty_result_because_of_bad_query.xml
similarity index 100%
rename from src/test/resources/net/sf/jabref/logic/importer/fetcher/gvk_empty_result_becaue_of_bad_query.xml
rename to src/test/resources/net/sf/jabref/logic/importer/fetcher/gvk_empty_result_because_of_bad_query.xml
diff --git a/src/test/resources/net/sf/jabref/logic/importer/fileformat/AutosavedSharedDatabase.bib b/src/test/resources/net/sf/jabref/logic/importer/fileformat/AutosavedSharedDatabase.bib
new file mode 100644
index 0000000..1e0881d
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/importer/fileformat/AutosavedSharedDatabase.bib
@@ -0,0 +1,6 @@
+% DBID: 13ceoc8dm42f5g1iitao3dj2ap
+% Encoding: UTF-8
+
+ at Book{test,
+ title = {title},
+}
diff --git a/src/test/resources/net/sf/jabref/logic/importer/fileformat/MODSImporterTestAllFields.bib b/src/test/resources/net/sf/jabref/logic/importer/fileformat/MODSImporterTestAllFields.bib
new file mode 100644
index 0000000..2e7c3ed
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/importer/fileformat/MODSImporterTestAllFields.bib
@@ -0,0 +1,17 @@
+ at article{TelPeak,
+ abstract = {an abstract},
+ affiliation = {an affiliation},
+ author = {Telescope},
+ captured = {1955-11-30},
+ city = {New York},
+ country = {United States},
+ created = {1955-03-22},
+ edition = {2},
+ journal = {Cell},
+ modified = {1970-12-01},
+ pages = {50},
+ source = {Indiana University Digital Library Program},
+ title = {Telescope PK from Zabriskie Pt.},
+ url = {http://purl.dlib.indiana.edu/iudl/archives/cushman/P07803, http://quod.lib.umich.edu/m/mods/thumbs/Indiana/oai.dlib.indiana.edu/ archives/cushman/oai_3Aoai.dlib.indiana.edu_3Aarchives_5Ccushman_5CP07803.png},
+ year = {1955}
+}
diff --git a/src/test/resources/net/sf/jabref/logic/importer/fileformat/MODSImporterTestAllFields.xml b/src/test/resources/net/sf/jabref/logic/importer/fileformat/MODSImporterTestAllFields.xml
new file mode 100644
index 0000000..0dc862f
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/importer/fileformat/MODSImporterTestAllFields.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<modsCollection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.loc.gov/mods/v3"
+ xsi:schemaLocation="http://www.loc.gov/mods/v3 http://www.loc.gov/standards/mods/v3/mods-3-3.xsd">
+<mods version="3.3">
+<titleInfo>
+<title>Telescope Peak from Zabriskie Point</title>
+</titleInfo>
+<titleInfo type="alternative" >
+<title>Telescope PK from Zabriskie Pt.</title>
+</titleInfo>
+<abstract>an abstract</abstract>
+<name>
+<namePart type="family">Telescope</namePart>
+<affiliation>an affiliation</affiliation>
+</name>
+<typeOfResource>still image</typeOfResource>
+<genre authority="gmgpc">Article</genre>
+<originInfo>
+<dateCreated encoding="w3cdtf" keyDate="yes">1955-03-22</dateCreated>
+<dateCaptured>1955-11-30</dateCaptured>
+<dateModified>1970-12-01</dateModified>
+<edition>2</edition>
+<copyrightDate encoding="w3cdtf">2003</copyrightDate>
+</originInfo>
+<physicalDescription>
+<internetMediaType>image/jpeg</internetMediaType>
+<digitalOrigin>reformatted digital</digitalOrigin>
+</physicalDescription>
+<subject authority="lctgm">
+</subject>
+<subject>
+<hierarchicalGeographic>
+<country>United States</country>
+<city>New York</city>
+</hierarchicalGeographic>
+</subject>
+<relatedItem type="host">
+<titleInfo>
+<title>Cell</title>
+</titleInfo>
+<part>
+<extent unit="page">
+<total>50</total>
+</extent>
+</part>
+</relatedItem>
+<identifier displayLabel="Cushman number" type="local">955.11</identifier>
+<identifier displayLabel="IU Archives number" type="local">P07803</identifier>
+<identifier type="citekey">TelPeak</identifier>
+<location>
+<url>http://purl.dlib.indiana.edu/iudl/archives/cushman/P07803</url>
+<url access="preview">http://quod.lib.umich.edu/m/mods/thumbs/Indiana/oai.dlib.indiana.edu/ archives/cushman/oai_3Aoai.dlib.indiana.edu_3Aarchives_5Ccushman_5CP07803.png</url>
+</location>
+<accessCondition>Copyright and reproduction rights for all Charles W. Cushman photographs are held by Indiana University and administered by the University Archives, Indiana University, Bloomington, IN 47405</accessCondition>
+<recordInfo>
+<recordContentSource>Indiana University Digital Library Program</recordContentSource>
+<recordCreationDate encoding="w3cdtf">2004-09-09</recordCreationDate>
+<recordIdentifier>archives/cushman/P07803</recordIdentifier>
+</recordInfo>
+</mods>
+</modsCollection>
diff --git a/src/test/resources/net/sf/jabref/logic/importer/fileformat/MODSImporterTestMinimal.bib b/src/test/resources/net/sf/jabref/logic/importer/fileformat/MODSImporterTestMinimal.bib
new file mode 100644
index 0000000..e69de29
diff --git a/src/test/resources/net/sf/jabref/logic/importer/fileformat/MODSImporterTestMinimal.xml b/src/test/resources/net/sf/jabref/logic/importer/fileformat/MODSImporterTestMinimal.xml
new file mode 100644
index 0000000..41a8a61
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/importer/fileformat/MODSImporterTestMinimal.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<modsCollection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.loc.gov/mods/v3"
+ xsi:schemaLocation="http://www.loc.gov/mods/v3 http://www.loc.gov/standards/mods/v3/mods-3-3.xsd">
+<mods version="3.6">
+<\mods>
+<\modsCollection>
diff --git a/src/test/resources/net/sf/jabref/logic/importer/fileformat/MODSImporterTestMods.bib b/src/test/resources/net/sf/jabref/logic/importer/fileformat/MODSImporterTestMods.bib
new file mode 100644
index 0000000..9cba645
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/importer/fileformat/MODSImporterTestMods.bib
@@ -0,0 +1,13 @@
+ at article{,
+ address = {New York},
+ author = {Alleman, Tillie Pierce},
+ journal = {A Celebration of Women Writers: Americana},
+ keywords = {Gettysburg, Battle of, Gettysburg, Pa., 1863, Gettysburg (Pa.) -- History -- Civil War, 1861-1865, United States -- History -- Civil War, 1861-1865 -- Campaigns},
+ language = {eng},
+ publisher = {W. Lake Borland},
+ source = {University of Pennsylvania Digital Library},
+ title = {At Gettysburg, or, What a Girl Saw and Heard of the Battle: A True Narrative},
+ url = { http://digital.library.upenn.edu/women/alleman/gettysburg/gettysburg.html},
+ year = {1889}
+}
+
diff --git a/src/test/resources/net/sf/jabref/logic/importer/fileformat/MODSImporterTestMods.xml b/src/test/resources/net/sf/jabref/logic/importer/fileformat/MODSImporterTestMods.xml
new file mode 100644
index 0000000..a9dcb39
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/importer/fileformat/MODSImporterTestMods.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<mods xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.loc.gov/mods/v3" version="3.4" xsi:schemaLocation="http://www.loc.gov/mods/v3 http://www.loc.gov/standards/mods/v3/mods-3-4.xsd">
+<genre>article</genre>
+<titleInfo>
+<title>At Gettysburg, or, What a Girl Saw and Heard of the Battle: A True Narrative</title>
+</titleInfo>
+<name type="personal">
+<namePart>Alleman, Tillie Pierce</namePart>
+<role>
+<roleTerm type="code" authority="marcrelator">aut</roleTerm>
+<roleTerm type="text" authority="marcrelator">Author</roleTerm>
+</role>
+</name>
+<typeOfResource>text</typeOfResource>
+<originInfo>
+<place>
+<placeTerm type="text">New York</placeTerm>
+</place>
+<publisher>W. Lake Borland</publisher>
+<dateIssued keyDate="yes" encoding="w3cdtf">1889</dateIssued>
+</originInfo>
+<language>
+<languageTerm authority="iso639-2b">eng</languageTerm>
+<languageTerm type="text">English</languageTerm>
+</language>
+<physicalDescription>
+<internetMediaType>text/html</internetMediaType>
+<digitalOrigin>reformatted digital</digitalOrigin>
+</physicalDescription>
+<subject authority="lcsh">
+<topic >Gettysburg, Battle of, Gettysburg, Pa., 1863</topic>
+</subject>
+<subject authority="lcsh">
+<topic>Gettysburg (Pa.) -- History -- Civil War, 1861-1865</topic>
+</subject>
+<subject authority="lcsh">
+<topic>United States -- History -- Civil War, 1861-1865 -- Campaigns</topic>
+</subject>
+<classification authority="lcc">E475.53 .A42</classification>
+<relatedItem type="host">
+<titleInfo type="uniform" authority="dlfaqcoll">
+<title>A Celebration of Women Writers: Americana</title>
+</titleInfo>
+</relatedItem>
+<location>
+<url usage="primary display" access="object in context"> http://digital.library.upenn.edu/women/alleman/gettysburg/gettysburg.html</url>
+</location>
+<accessCondition>Personal, noncommercial use of this item is permitted in the United States of America. Please see http://digital.library.upenn.edu/women/ for other rights and restrictions that may apply to this resource.
+</accessCondition>
+<recordInfo>
+<recordContentSource>University of Pennsylvania Digital Library</recordContentSource>
+<recordOrigin>MODS auto-converted from a simple Online Books Page metadata record. For details, see http://onlinebooks.library.upenn.edu/mods.html</recordOrigin>
+<languageOfCataloging>
+<languageTerm type="code" authority="iso639-2b">eng</languageTerm>
+</languageOfCataloging>
+</recordInfo>
+</mods>
diff --git a/src/test/resources/net/sf/jabref/logic/importer/fileformat/MODSImporterTestModsCollection.bib b/src/test/resources/net/sf/jabref/logic/importer/fileformat/MODSImporterTestModsCollection.bib
new file mode 100644
index 0000000..ee64bd4
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/importer/fileformat/MODSImporterTestModsCollection.bib
@@ -0,0 +1,33 @@
+ at misc{Mock++2003,
+ author = {Mock, T and Kruse, M and Dieckmann, GS},
+ issue = {2},
+ journal = {Aquat Microb Ecol},
+ keywords = {_Fragilariopsis cylindrus_, Methods, Microcosm, Micro-optodes, Oxygen exchange, Photosynthesis, Sea ice, Ice, Water, Diatoms, Epontic environment, Gas exchange, Diffusion, Boundary layers, Oxygen, Patchiness, Epontic organisms, Laminar boundary layer, Ice-water interface, Methodology, Bacillariophyceae},
+ location = {Indiana University, Bloomington. University Archives P07803},
+ note = {Marine},
+ pages = {197-205},
+ title = {A new microcosm to investigate oxygen dynamics at the sea ice water interface},
+ uri = {http://int-res.com/abstracts/ame/v30/n2/p197-205.html},
+ url = {http://int-res.com/abstracts/ame/v30/n2/p197-205.html},
+ volume = {30},
+ year = {2003}
+}, @misc{Schewe+Soltwedel2003,
+ author = {Schewe, I and Soltwedel, T},
+ doi = {10.1007/s00300-003-0526-8},
+ issue = {9},
+ journal = {Polar Biol},
+ pages = {610-620},
+ title = {Benthic response to ice-edge-induced particle flux in the Arctic Ocean},
+ volume = {26},
+ year = {2003}
+}, @book{Thomas+Dieckmann2003,
+ address = {Oxford},
+ author = {Thomas, DN and Dieckmann, GS},
+ isbn = {0-632-05808-0},
+ issuance = {monographic},
+ keywords = {zoology, sea ice},
+ publisher = {Blackwell Science Ltd},
+ title = {Sea ice - an introduction to its physics, chemistry, biology and geology},
+ year = {2003}
+}
+
diff --git a/src/test/resources/net/sf/jabref/logic/importer/fileformat/MODSImporterTestModsCollection.xml b/src/test/resources/net/sf/jabref/logic/importer/fileformat/MODSImporterTestModsCollection.xml
new file mode 100644
index 0000000..39c6065
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/importer/fileformat/MODSImporterTestModsCollection.xml
@@ -0,0 +1,240 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+
+<modsCollection xmlns="http://www.loc.gov/mods/v3">
+ <mods ID="Mock++2003">
+ <titleInfo>
+ <title>A new microcosm to investigate oxygen dynamics at the sea ice water interface</title>
+ </titleInfo>
+ <name type="personal">
+ <namePart type="family">Mock</namePart>
+ <namePart type="given">T</namePart>
+ <role>
+ <roleTerm authority="marcrelator" type="text">author</roleTerm>
+ </role>
+ </name>
+ <name type="personal">
+ <namePart type="family">Kruse</namePart>
+ <namePart type="given">M</namePart>
+ <role>
+ <roleTerm authority="marcrelator" type="text">author</roleTerm>
+ </role>
+ </name>
+ <name type="personal">
+ <namePart type="family">Dieckmann</namePart>
+ <namePart type="given">GS</namePart>
+ <role>
+ <roleTerm authority="marcrelator" type="text">author</roleTerm>
+ </role>
+ </name>
+ <originInfo>
+ <dateIssued>2003</dateIssued>
+ </originInfo>
+ <language>English</language>
+ <subject>
+ <topic>_Fragilariopsis cylindrus_</topic>
+ </subject>
+ <subject>
+ <topic>Methods</topic>
+ </subject>
+ <subject>
+ <topic>Microcosm</topic>
+ </subject>
+ <subject>
+ <topic>Micro-optodes</topic>
+ </subject>
+ <subject>
+ <topic>Oxygen exchange</topic>
+ </subject>
+ <subject>
+ <topic>Photosynthesis</topic>
+ </subject>
+ <subject>
+ <topic>Sea ice</topic>
+ </subject>
+ <subject>
+ <topic>Ice</topic>
+ </subject>
+ <subject>
+ <topic>Water</topic>
+ </subject>
+ <subject>
+ <topic>Diatoms</topic>
+ </subject>
+ <subject>
+ <topic>Epontic environment</topic>
+ </subject>
+ <subject>
+ <topic>Gas exchange</topic>
+ </subject>
+ <subject>
+ <topic>Diffusion</topic>
+ </subject>
+ <subject>
+ <topic>Boundary layers</topic>
+ </subject>
+ <subject>
+ <topic>Oxygen</topic>
+ </subject>
+ <subject>
+ <topic>Patchiness</topic>
+ </subject>
+ <subject>
+ <topic>Epontic organisms</topic>
+ </subject>
+ <subject>
+ <topic>Laminar boundary layer</topic>
+ </subject>
+ <subject>
+ <topic>Ice-water interface</topic>
+ </subject>
+ <subject>
+ <topic>Methodology</topic>
+ </subject>
+ <subject>
+ <topic>Bacillariophyceae</topic>
+ </subject>
+ <note>Marine</note>
+ <typeOfResource>text</typeOfResource>
+ <location>
+ <url>http://int-res.com/abstracts/ame/v30/n2/p197-205.html</url>
+ <physicalLocation>Indiana University, Bloomington. University Archives P07803</physicalLocation>
+ </location>
+ <identifier type="uri">http://int-res.com/abstracts/ame/v30/n2/p197-205.html</identifier>
+ <identifier type="citekey">Mock++2003</identifier>
+ <identifier type="local">IP� @ msteffens @ 713</identifier>
+ <relatedItem type="host">
+ <titleInfo>
+ <title>Aquatic Microbial Ecology</title>
+ </titleInfo>
+ <titleInfo type="abbreviated">
+ <title>Aquat Microb Ecol</title>
+ </titleInfo>
+ <originInfo>
+ <dateIssued>2003</dateIssued>
+ <publisher>Inter-Research</publisher>
+ <place>
+ <placeTerm type="text">Oldendorf/Luhe</placeTerm>
+ </place>
+ <issuance>continuing</issuance>
+ </originInfo>
+ <genre authority="marc">periodical</genre>
+ <genre>academic journal</genre>
+ <part>
+ <detail type="volume">
+ <number>30</number>
+ </detail>
+ <detail type="issue">
+ <number>2</number>
+ </detail>
+ <extent unit="page">
+ <start>197</start>
+ <end>205</end>
+ </extent>
+ </part>
+ <identifier type="issn">0948-3055</identifier>
+ </relatedItem>
+ </mods>
+ <mods ID="Schewe+Soltwedel2003">
+ <titleInfo>
+ <title>Benthic response to ice-edge-induced particle flux in the Arctic Ocean</title>
+ </titleInfo>
+ <name type="personal">
+ <namePart type="family">Schewe</namePart>
+ <namePart type="given">I</namePart>
+ <role>
+ <roleTerm authority="marcrelator" type="text">author</roleTerm>
+ </role>
+ </name>
+ <name type="personal">
+ <namePart type="family">Soltwedel</namePart>
+ <namePart type="given">T</namePart>
+ <role>
+ <roleTerm authority="marcrelator" type="text">author</roleTerm>
+ </role>
+ </name>
+ <originInfo>
+ <dateIssued>2003</dateIssued>
+ </originInfo>
+ <language>English</language>
+ <typeOfResource>text</typeOfResource>
+ <identifier type="doi">10.1007/s00300-003-0526-8</identifier>
+ <identifier type="citekey">Schewe+Soltwedel2003</identifier>
+ <identifier type="local">IP� @ msteffens @ 688</identifier>
+ <relatedItem type="host">
+ <titleInfo>
+ <title>Polar Biology</title>
+ </titleInfo>
+ <titleInfo type="abbreviated">
+ <title>Polar Biol</title>
+ </titleInfo>
+ <originInfo>
+ <dateIssued>2003</dateIssued>
+ <publisher>Springer-Verlag</publisher>
+ <place>
+ <placeTerm type="text">Heidelberg</placeTerm>
+ </place>
+ <issuance>continuing</issuance>
+ </originInfo>
+ <genre authority="marc">periodical</genre>
+ <genre>academic journal</genre>
+ <part>
+ <detail type="volume">
+ <number>26</number>
+ </detail>
+ <detail type="issue">
+ <number>9</number>
+ </detail>
+ <extent unit="page">
+ <start>610</start>
+ <end>620</end>
+ </extent>
+ </part>
+ <identifier type="issn">0722-4060</identifier>
+ </relatedItem>
+ </mods>
+ <mods ID="Thomas+Dieckmann2003">
+ <titleInfo>
+ <title>Sea ice - an introduction to its physics, chemistry, biology and geology</title>
+ </titleInfo>
+ <name type="personal">
+ <namePart type="family">Thomas</namePart>
+ <namePart type="given">DN</namePart>
+ <role>
+ <roleTerm authority="marcrelator" type="text">editor</roleTerm>
+ </role>
+ </name>
+ <name type="personal">
+ <namePart type="family">Dieckmann</namePart>
+ <namePart type="given">GS</namePart>
+ <role>
+ <roleTerm authority="marcrelator" type="text">editor</roleTerm>
+ </role>
+ </name>
+ <originInfo>
+ <dateIssued>2003</dateIssued>
+ <publisher>Blackwell Science Ltd</publisher>
+ <place>
+ <placeTerm type="text">Oxford</placeTerm>
+ </place>
+ <issuance>monographic</issuance>
+ </originInfo>
+ <language>English</language>
+ <subject>
+ <topic>zoology</topic>
+ </subject>
+ <subject>
+ <topic>sea ice</topic>
+ </subject>
+ <typeOfResource>text</typeOfResource>
+ <identifier type="citekey">Thomas+Dieckmann2003</identifier>
+ <identifier type="local">IP� @ library @ 34/436/1</identifier>
+ <identifier type="local">IP� @ msteffens @ IP�-34/436/1</identifier>
+ <genre authority="marc">book</genre>
+ <physicalDescription>
+ <extent unit="page">
+ <total>402</total>
+ </extent>
+ </physicalDescription>
+ <identifier type="isbn">0-632-05808-0</identifier>
+ </mods>
+</modsCollection>
\ No newline at end of file
diff --git a/src/test/resources/net/sf/jabref/logic/importer/fileformat/MedlineImporterTestArticleNoISSN.bib b/src/test/resources/net/sf/jabref/logic/importer/fileformat/MedlineImporterTestArticleNoISSN.bib
new file mode 100644
index 0000000..f7b2362
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/importer/fileformat/MedlineImporterTestArticleNoISSN.bib
@@ -0,0 +1,25 @@
+% Encoding: UTF-8
+
+ at Article{,
+ author = {Prichard, Eric C and Christman, Stephen D},
+ title = {Need for cognition moderates paranormal beliefs and magical ideation in inconsistent-handers.},
+ year = {2016},
+ volume = {21},
+ issue = {3},
+ pages = {228--242},
+ doi = {10.1080/1357650X.2015.1125914},
+ month = {May},
+ citation-subset = {IM},
+ country = {England},
+ created = {2016-03-10},
+ journal = {Laterality},
+ journal-abbreviation = {Laterality},
+ keywords = {Handedness; magical ideation; need for cognition; paranormal beliefs},
+ nlm-id = {9609064},
+ owner = {NLM},
+ pmid = {26886152},
+ pubmodel = {Print-Electronic},
+ status = {In-Data-Review},
+}
+
+ at Comment{jabref-meta: databaseType:biblatex;}
diff --git a/src/test/resources/net/sf/jabref/logic/importer/fileformat/MedlineImporterTestArticleNoISSN.xml b/src/test/resources/net/sf/jabref/logic/importer/fileformat/MedlineImporterTestArticleNoISSN.xml
new file mode 100644
index 0000000..1bdeef8
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/importer/fileformat/MedlineImporterTestArticleNoISSN.xml
@@ -0,0 +1,106 @@
+<PubmedArticle>
+ <MedlineCitation Owner="NLM" Status="In-Data-Review">
+ <PMID Version="1">26886152</PMID>
+ <DateCreated>
+ <Year>2016</Year>
+ <Month>03</Month>
+ <Day>10</Day>
+ </DateCreated>
+ <Article PubModel="Print-Electronic">
+ <Journal>
+ <JournalIssue CitedMedium="Internet">
+ <Volume>21</Volume>
+ <Issue>3</Issue>
+ <PubDate>
+ <Year>2016</Year>
+ <Month>May</Month>
+ </PubDate>
+ </JournalIssue>
+ <Title>Laterality</Title>
+ <ISOAbbreviation>Laterality</ISOAbbreviation>
+ </Journal>
+ <ArticleTitle>Need for cognition moderates paranormal beliefs and magical ideation in inconsistent-handers.</ArticleTitle>
+ <Pagination>
+ <MedlinePgn>228-42</MedlinePgn>
+ </Pagination>
+ <ELocationID EIdType="doi" ValidYN="Y">10.1080/1357650X.2015.1125914</ELocationID>
+ <Abstract>
+ <AbstractText></AbstractText>
+ </Abstract>
+ <AuthorList CompleteYN="Y">
+ <Author ValidYN="Y">
+ <LastName>Prichard</LastName>
+ <ForeName>Eric C</ForeName>
+ <Initials>EC</Initials>
+ <AffiliationInfo>
+ <Affiliation>a Department of Psychology , University of Toledo , Toledo , OH , USA.</Affiliation>
+ </AffiliationInfo>
+ </Author>
+ <Author ValidYN="Y">
+ <LastName>Christman</LastName>
+ <ForeName>Stephen D</ForeName>
+ <Initials>SD</Initials>
+ <AffiliationInfo>
+ <Affiliation>a Department of Psychology , University of Toledo , Toledo , OH , USA.</Affiliation>
+ </AffiliationInfo>
+ </Author>
+ </AuthorList>
+ <Language>eng</Language>
+ <PublicationTypeList>
+ <PublicationType UI="D016428">Journal Article</PublicationType>
+ </PublicationTypeList>
+ <ArticleDate DateType="Electronic">
+ <Year>2016</Year>
+ <Month>02</Month>
+ <Day>17</Day>
+ </ArticleDate>
+ </Article>
+ <MedlineJournalInfo>
+ <Country>England</Country>
+ <MedlineTA>Laterality</MedlineTA>
+ <NlmUniqueID>9609064</NlmUniqueID>
+ </MedlineJournalInfo>
+ <CitationSubset>IM</CitationSubset>
+ <KeywordList Owner="NOTNLM">
+ <Keyword MajorTopicYN="N">Handedness</Keyword>
+ <Keyword MajorTopicYN="N">magical ideation</Keyword>
+ <Keyword MajorTopicYN="N">need for cognition</Keyword>
+ <Keyword MajorTopicYN="N">paranormal beliefs</Keyword>
+ </KeywordList>
+ </MedlineCitation>
+ <PubmedData>
+ <History>
+ <PubMedPubDate PubStatus="aheadofprint">
+ <Year>2016</Year>
+ <Month>2</Month>
+ <Day>17</Day>
+ </PubMedPubDate>
+ <PubMedPubDate PubStatus="entrez">
+ <Year>2016</Year>
+ <Month>2</Month>
+ <Day>18</Day>
+ <Hour>6</Hour>
+ <Minute>0</Minute>
+ </PubMedPubDate>
+ <PubMedPubDate PubStatus="pubmed">
+ <Year>2016</Year>
+ <Month>2</Month>
+ <Day>18</Day>
+ <Hour>6</Hour>
+ <Minute>0</Minute>
+ </PubMedPubDate>
+ <PubMedPubDate PubStatus="medline">
+ <Year>2016</Year>
+ <Month>2</Month>
+ <Day>18</Day>
+ <Hour>6</Hour>
+ <Minute>0</Minute>
+ </PubMedPubDate>
+ </History>
+ <PublicationStatus>ppublish</PublicationStatus>
+ <ArticleIdList>
+ <ArticleId IdType="pubmed">26886152</ArticleId>
+ <ArticleId IdType="doi">10.1080/1357650X.2015.1125914</ArticleId>
+ </ArticleIdList>
+ </PubmedData>
+</PubmedArticle>
\ No newline at end of file
diff --git a/src/test/resources/net/sf/jabref/logic/importer/fileformat/MedlineImporterTestDOI.bib b/src/test/resources/net/sf/jabref/logic/importer/fileformat/MedlineImporterTestDOI.bib
new file mode 100644
index 0000000..30dc9e9
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/importer/fileformat/MedlineImporterTestDOI.bib
@@ -0,0 +1,26 @@
+% Encoding: UTF-8
+
+ at Article{,
+ author = {Trojan, Jörg and Waidmann, Oliver},
+ title = {Role of regorafenib as second-line therapy and landscape of investigational treatment options in advanced hepatocellular carcinoma.},
+ journal = {Journal of hepatocellular carcinoma},
+ year = {2016},
+ volume = {3},
+ pages = {31--36},
+ abstract = {Sorafenib is still the only systemic drug approved for the treatment of advanced hepatocellular carcinoma (HCC). In recent years, several investigational agents mainly targeting angiogenesis failed in late-phase clinical development due to either toxicity or lack of benefit. Recently, data of the RESORCE trial, a placebo-controlled Phase III study that evaluated the efficacy and safety of regorafenib in patients with HCC and documented disease progression after systemic [...]
+ country = {New Zealand},
+ created = {2016-10-5},
+ doi = {10.2147/JHC.S112537},
+ issn-linking = {2253-5969},
+ keywords = {anti-CTLA-4; anti-PD-1; cabozantinib; hepatocellular carcinoma; immunotherapy; lenvatinib; oncolytic virus; ramucirumab; receptor tyrosine kinase inhibitor; regorafenib; sorafenib; tivantinib},
+ nlm-id = {101674775},
+ owner = {NLM},
+ pii = {jhc-3-031},
+ pmc = {PMC5036543},
+ pmid = {27703962},
+ pubmodel = {Electronic-eCollection},
+ pubstatus = {epublish},
+ revised = {2016-10-11},
+}
+
+ at Comment{jabref-meta: databaseType:bibtex;}
diff --git a/src/test/resources/net/sf/jabref/logic/importer/fileformat/MedlineImporterTestDOI.xml b/src/test/resources/net/sf/jabref/logic/importer/fileformat/MedlineImporterTestDOI.xml
new file mode 100644
index 0000000..7676859
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/importer/fileformat/MedlineImporterTestDOI.xml
@@ -0,0 +1,112 @@
+<PubmedArticle>
+ <MedlineCitation Status="In-Data-Review" Owner="NLM">
+ <PMID Version="1">27703962</PMID>
+ <DateCreated>
+ <Year>2016</Year>
+ <Month>10</Month>
+ <Day>5</Day>
+ </DateCreated>
+ <DateRevised>
+ <Year>2016</Year>
+ <Month>10</Month>
+ <Day>11</Day>
+ </DateRevised>
+ <Article PubModel="Electronic-eCollection">
+ <Journal>
+ <JournalIssue CitedMedium="Print">
+ <Volume>3</Volume>
+ <PubDate>
+ <Year>2016</Year>
+ </PubDate>
+ </JournalIssue>
+ <Title>Journal of hepatocellular carcinoma</Title>
+ <ISOAbbreviation>J Hepatocell Carcinoma</ISOAbbreviation>
+ </Journal>
+ <ArticleTitle>Role of regorafenib as second-line therapy and landscape of investigational treatment options in advanced hepatocellular carcinoma.</ArticleTitle>
+ <Pagination>
+ <MedlinePgn>31-36</MedlinePgn>
+ </Pagination>
+ <AuthorList CompleteYN="Y">
+ <Author ValidYN="Y">
+ <LastName>Trojan</LastName>
+ <ForeName>Jörg</ForeName>
+ <Initials>J</Initials>
+ <AffiliationInfo>
+ <Affiliation>Medizinische Klinik 1, Universitätsklinikum Frankfurt, Germany.</Affiliation>
+ </AffiliationInfo>
+ </Author>
+ <Author ValidYN="Y">
+ <LastName>Waidmann</LastName>
+ <ForeName>Oliver</ForeName>
+ <Initials>O</Initials>
+ <AffiliationInfo>
+ <Affiliation>Medizinische Klinik 1, Universitätsklinikum Frankfurt, Germany.</Affiliation>
+ </AffiliationInfo>
+ </Author>
+ </AuthorList>
+ <Language>ENG</Language>
+ <PublicationTypeList>
+ <PublicationType UI="">REVIEW</PublicationType>
+ <PublicationType UI="">JOURNAL ARTICLE</PublicationType>
+ </PublicationTypeList>
+ <ArticleDate DateType="Electronic">
+ <Year>2016</Year>
+ <Month>Sep</Month>
+ <Day>21</Day>
+ </ArticleDate>
+ </Article>
+ <MedlineJournalInfo>
+ <Country>New Zealand</Country>
+ <MedlineTA>J Hepatocell Carcinoma</MedlineTA>
+ <NlmUniqueID>101674775</NlmUniqueID>
+ <ISSNLinking>2253-5969</ISSNLinking>
+ </MedlineJournalInfo>
+ <KeywordList Owner="NOTNLM">
+ <Keyword MajorTopicYN="N">anti-CTLA-4</Keyword>
+ <Keyword MajorTopicYN="N">anti-PD-1</Keyword>
+ <Keyword MajorTopicYN="N">cabozantinib</Keyword>
+ <Keyword MajorTopicYN="N">hepatocellular carcinoma</Keyword>
+ <Keyword MajorTopicYN="N">immunotherapy</Keyword>
+ <Keyword MajorTopicYN="N">lenvatinib</Keyword>
+ <Keyword MajorTopicYN="N">oncolytic virus</Keyword>
+ <Keyword MajorTopicYN="N">ramucirumab</Keyword>
+ <Keyword MajorTopicYN="N">receptor tyrosine kinase inhibitor</Keyword>
+ <Keyword MajorTopicYN="N">regorafenib</Keyword>
+ <Keyword MajorTopicYN="N">sorafenib</Keyword>
+ <Keyword MajorTopicYN="N">tivantinib</Keyword>
+ </KeywordList>
+ </MedlineCitation>
+ <PubmedData>
+ <History>
+ <PubMedPubDate PubStatus="entrez">
+ <Year>2016</Year>
+ <Month>10</Month>
+ <Day>6</Day>
+ <Hour>6</Hour>
+ <Minute>0</Minute>
+ </PubMedPubDate>
+ <PubMedPubDate PubStatus="pubmed">
+ <Year>2016</Year>
+ <Month>10</Month>
+ <Day>6</Day>
+ <Hour>6</Hour>
+ <Minute>0</Minute>
+ </PubMedPubDate>
+ <PubMedPubDate PubStatus="medline">
+ <Year>2016</Year>
+ <Month>10</Month>
+ <Day>6</Day>
+ <Hour>6</Hour>
+ <Minute>0</Minute>
+ </PubMedPubDate>
+ </History>
+ <PublicationStatus>epublish</PublicationStatus>
+ <ArticleIdList>
+ <ArticleId IdType="pubmed">27703962</ArticleId>
+ <ArticleId IdType="pmc">PMC5036543</ArticleId>
+ <ArticleId IdType="doi">10.2147/JHC.S112537</ArticleId>
+ <ArticleId IdType="pii">jhc-3-031</ArticleId>
+ </ArticleIdList>
+ </PubmedData>
+</PubmedArticle>
+
diff --git a/src/test/resources/net/sf/jabref/logic/importer/fileformat/MsBibLocationTest.bib b/src/test/resources/net/sf/jabref/logic/importer/fileformat/MsBibLocationTest.bib
new file mode 100644
index 0000000..b84d408
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/importer/fileformat/MsBibLocationTest.bib
@@ -0,0 +1,8 @@
+% Encoding: UTF-8
+
+ at InProceedings{LocationTest,
+ author = {LocationTest},
+ location = {Berlin},
+}
+
+ at Comment{jabref-meta: databaseType:biblatex;}
diff --git a/src/test/resources/net/sf/jabref/logic/importer/fileformat/MsBibLocationTest.xml b/src/test/resources/net/sf/jabref/logic/importer/fileformat/MsBibLocationTest.xml
new file mode 100644
index 0000000..e6c3485
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/importer/fileformat/MsBibLocationTest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<b:Sources xmlns:b="http://schemas.openxmlformats.org/officeDocument/2006/bibliography" xmlns="http://schemas.openxmlformats.org/officeDocument/2006/bibliography" SelectedStyle="">
+<b:Source>
+<b:BIBTEX_Entry>inproceedings</b:BIBTEX_Entry>
+<b:SourceType>ConferenceProceedings</b:SourceType>
+<b:Tag>LocationTest</b:Tag>
+<b:Author>
+<b:Author>
+<b:NameList>
+<b:Person>
+<b:Last>LocationTest</b:Last>
+</b:Person>
+</b:NameList>
+</b:Author>
+</b:Author>
+<b:City>Berlin</b:City>
+<b:StateProvince/>
+<b:CountryRegion/>
+</b:Source>
+</b:Sources>
diff --git a/src/test/resources/net/sf/jabref/logic/importer/fileformat/MsBibMultiLocationAddressTest.bib b/src/test/resources/net/sf/jabref/logic/importer/fileformat/MsBibMultiLocationAddressTest.bib
new file mode 100644
index 0000000..d1a912a
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/importer/fileformat/MsBibMultiLocationAddressTest.bib
@@ -0,0 +1,8 @@
+% Encoding: UTF-8
+
+ at InProceedings{LocationTest,
+ author = {LocationTest},
+ location = {Stroudsburg, PA, USA},
+}
+
+ at Comment{jabref-meta: databaseType:biblatex;}
diff --git a/src/test/resources/net/sf/jabref/logic/importer/fileformat/MsBibMultiLocationAddressTest.xml b/src/test/resources/net/sf/jabref/logic/importer/fileformat/MsBibMultiLocationAddressTest.xml
new file mode 100644
index 0000000..3453b38
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/importer/fileformat/MsBibMultiLocationAddressTest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<b:Sources xmlns:b="http://schemas.openxmlformats.org/officeDocument/2006/bibliography" xmlns="http://schemas.openxmlformats.org/officeDocument/2006/bibliography" SelectedStyle="">
+<b:Source>
+<b:BIBTEX_Entry>inproceedings</b:BIBTEX_Entry>
+<b:SourceType>ConferenceProceedings</b:SourceType>
+<b:Tag>LocationTest</b:Tag>
+<b:Author>
+<b:Author>
+<b:NameList>
+<b:Person>
+<b:Last>LocationTest</b:Last>
+</b:Person>
+</b:NameList>
+</b:Author>
+</b:Author>
+<b:City>Stroudsburg</b:City>
+<b:StateProvince>PA</b:StateProvince>
+<b:CountryRegion>USA</b:CountryRegion>
+</b:Source>
+</b:Sources>
diff --git a/src/test/resources/net/sf/jabref/logic/importer/fileformat/RisImporterTest3.bib b/src/test/resources/net/sf/jabref/logic/importer/fileformat/RisImporterTest3.bib
index 91789c9..d40bd1c 100644
--- a/src/test/resources/net/sf/jabref/logic/importer/fileformat/RisImporterTest3.bib
+++ b/src/test/resources/net/sf/jabref/logic/importer/fileformat/RisImporterTest3.bib
@@ -1,14 +1,14 @@
@incollection{,
author = {Barata, Catarina and Celebi, MEmre and Marques, JorgeS},
- booktitle = {Dermoscopy Image Analysis},
comment = {doi:10.1201/b19107-2},
doi = {10.1201/b19107-2},
issn = {978-1-4822-5326-9},
+ journal = {Dermoscopy Image Analysis},
month = {#sep#},
pages = {1-22},
publisher = {CRC Press},
series = {Digital Imaging and Computer Vision},
- title = {Toward a Robust Analysis of Dermoscopy Images Acquired under Different Conditions},
+ title = {Toward a Robust Analysis of Dermoscopy Images Acquired under Different Conditions},
url = {http://dx.doi.org/10.1201/b19107-2},
year = {2015}
}
diff --git a/src/test/resources/net/sf/jabref/logic/importer/fileformat/RisImporterTest3.ris b/src/test/resources/net/sf/jabref/logic/importer/fileformat/RisImporterTest3.ris
index cd2d6c1..6e88a59 100644
--- a/src/test/resources/net/sf/jabref/logic/importer/fileformat/RisImporterTest3.ris
+++ b/src/test/resources/net/sf/jabref/logic/importer/fileformat/RisImporterTest3.ris
@@ -6,7 +6,6 @@ M1 - 0
DO - doi:10.1201/b19107-2
UR - http://dx.doi.org/10.1201/b19107-2
N1 - doi:10.1201/b19107-2
-M3 - doi:10.1201/b19107-2
AU - Catarina Barata
AU - MEmre Celebi
AU - JorgeS Marques
diff --git a/src/test/resources/net/sf/jabref/logic/importer/fileformat/RisImporterTest6.bib b/src/test/resources/net/sf/jabref/logic/importer/fileformat/RisImporterTest6.bib
index 9c78389..0bf8147 100644
--- a/src/test/resources/net/sf/jabref/logic/importer/fileformat/RisImporterTest6.bib
+++ b/src/test/resources/net/sf/jabref/logic/importer/fileformat/RisImporterTest6.bib
@@ -1,7 +1,7 @@
@article{,
- abstract = {Toxic metals such as arsenic, cadmium, lead, and mercury are ubiquitous, have no beneficial role in human homeostasis, and contribute to noncommunicable chronic diseases. While novel drug targets for chronic disease are eagerly sought, potentially helpful agents that aid in detoxification of toxic elements, chelators, have largely been restricted to overt acute poisoning. Chelation, that is multiple coordination bonds between organic molecules and metals, is very common in [...]
author = {Sears, Margaret E.},
comment = {23690738[pmid]},
+ database = {PMC},
issn = {1537-744X},
journal = {The Scientific World Journal},
month = {#mar#},
diff --git a/src/test/resources/net/sf/jabref/logic/importer/fileformat/RisImporterTest6.ris b/src/test/resources/net/sf/jabref/logic/importer/fileformat/RisImporterTest6.ris
index fdcf18e..bedb102 100644
--- a/src/test/resources/net/sf/jabref/logic/importer/fileformat/RisImporterTest6.ris
+++ b/src/test/resources/net/sf/jabref/logic/importer/fileformat/RisImporterTest6.ris
@@ -7,7 +7,6 @@ Y1 - 2013
PY - 2013/04/18
PY - 2013/02/15/received
PY - 2013/03/14/accepted
-AB - Toxic metals such as arsenic, cadmium, lead, and mercury are ubiquitous, have no beneficial role in human homeostasis, and contribute to noncommunicable chronic diseases. While novel drug targets for chronic disease are eagerly sought, potentially helpful agents that aid in detoxification of toxic elements, chelators, have largely been restricted to overt acute poisoning. Chelation, that is multiple coordination bonds between organic molecules and metals, is very common in the body [...]
SP - 219840
VL - 2013
DO - 10.1155/2013/219840
diff --git a/src/test/resources/net/sf/jabref/logic/importer/fileformat/RisImporterTestDoiAndJournalTitle.bib b/src/test/resources/net/sf/jabref/logic/importer/fileformat/RisImporterTestDoiAndJournalTitle.bib
new file mode 100644
index 0000000..5b66e51
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/importer/fileformat/RisImporterTestDoiAndJournalTitle.bib
@@ -0,0 +1,12 @@
+ at patent{,
+ author = {some author},
+ month = dec,
+ year = {2014},
+ doi = {10.1201/b19107-2},
+ journal = {Journal},
+ caption = {254},
+ edition = {5},
+ editor = {some editor},
+ language = {eng},
+ number = {25},
+}
diff --git a/src/test/resources/net/sf/jabref/logic/importer/fileformat/RisImporterTestDoiAndJournalTitle.ris b/src/test/resources/net/sf/jabref/logic/importer/fileformat/RisImporterTestDoiAndJournalTitle.ris
new file mode 100644
index 0000000..93fe6b3
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/importer/fileformat/RisImporterTestDoiAndJournalTitle.ris
@@ -0,0 +1,12 @@
+TY - PAT
+T2 - Journal
+AU - some author
+DO - doi:10.1201/b19107-2
+A4 - some editor
+LA - eng
+CA - 254
+ET - 5
+IS - 25
+DA - 2014/12/12
+ER - dsfd
+
diff --git a/src/test/resources/net/sf/jabref/logic/importer/fileformat/RisImporterTestScopus.bib b/src/test/resources/net/sf/jabref/logic/importer/fileformat/RisImporterTestScopus.bib
new file mode 100644
index 0000000..ab14c21
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/importer/fileformat/RisImporterTestScopus.bib
@@ -0,0 +1,17 @@
+% Encoding: UTF-8
+
+ at Article{,
+ author = {Federico, S. and Grillo, A. and Herzog, W.},
+ title = {A transversely isotropic composite with a statistical distribution of spheroidal inclusions: A geometrical approach to overall properties},
+ journal = {Journal of the Mechanics and Physics of Solids},
+ year = {2004},
+ volume = {52},
+ number = {10},
+ pages = {2309--2327},
+ address = {Dipartimento di Metodologie Fisiche, Facoltà di Ingegneria, Univ. degli Studi di Catania, Catania, Italy},
+ comment = {Cited By :44 Export Date: 1 April 2016},
+ database = {Scopus},
+ keywords = {Composite, Inclusions, Statistical distribution, Transverse isotropy},
+ url = {http://www.scopus.com/inward/record.url?eid=2-s2.0-4544289390&partnerID=40&md5=ad1a4baab95650b103a3467b787b83aa},
+}
+
diff --git a/src/test/resources/net/sf/jabref/logic/importer/fileformat/RisImporterTestScopus.ris b/src/test/resources/net/sf/jabref/logic/importer/fileformat/RisImporterTestScopus.ris
new file mode 100644
index 0000000..c888381
--- /dev/null
+++ b/src/test/resources/net/sf/jabref/logic/importer/fileformat/RisImporterTestScopus.ris
@@ -0,0 +1,26 @@
+TY - JOUR
+TI - A transversely isotropic composite with a statistical distribution of spheroidal inclusions: A geometrical approach to overall properties
+T2 - Journal of the Mechanics and Physics of Solids
+VL - 52
+IS - 10
+SP - 2309
+EP - 2327
+PY - 2004
+DO - 10.1016/j.jmps.2004.03.010
+AU - Federico, S.
+AU - Grillo, A.
+AU - Herzog, W.
+AD - Dipto. di Ingegneria Industriale, Facoltà di Ingegneria, Univ. degli Studi di Catania, Catania, Italy
+AD - Human Performance Laboratory, Faculty of Kinesiology, University of Calgary, 2500 University Drive NW, Calgary, Alta. T2N 1N4, Canada
+AD - Dipartimento di Metodologie Fisiche, Facoltà di Ingegneria, Univ. degli Studi di Catania, Catania, Italy
+KW - Composite
+KW - Inclusions
+KW - Statistical distribution
+KW - Transverse isotropy
+N1 - Cited By :44
+N1 - Export Date: 1 April 2016
+M3 - Article
+DB - Scopus
+UR - http://www.scopus.com/inward/record.url?eid=2-s2.0-4544289390&partnerID=40&md5=ad1a4baab95650b103a3467b787b83aa
+ER -
+
diff --git a/src/test/resources/testbib/complex.bib b/src/test/resources/testbib/complex.bib
index 80e1831..769c196 100644
--- a/src/test/resources/testbib/complex.bib
+++ b/src/test/resources/testbib/complex.bib
@@ -182,7 +182,7 @@ This is some user comment in front of a string, should also be preserved.
publisher = {ACM},
bdsk-url-1 = {http://doi.acm.org/10.1145/1358628.1358810},
doi = {http://doi.acm.org/10.1145/1358628.1358810},
- isbn = {978-1-60558-012-X},
+ isbn = {978-1-60558-012-8},
location = {Florence, Italy}
}
@@ -296,8 +296,6 @@ This is some user comment in front of a string, should also be preserved.
1 KeywordGroup:DynamicGroup\;0\;author\;Churchill\;0\;0\;;
}
- at Comment{jabref-meta: groupsversion:3;}
-
@Comment{jabref-meta: keypattern_article:articleTest;}
@Comment{jabref-meta: keypatterndefault:[authors3][year];}
@@ -306,6 +304,4 @@ This is some user comment in front of a string, should also be preserved.
@Comment{jabref-meta: saveOrderConfig:specified;author;false;address;false;bibtexkey;false;}
- at Comment{jabref-meta: selector_title:testWord;word2;}
-
Some trailing text
diff --git a/src/test/resources/testbib/crossref.bib b/src/test/resources/testbib/crossref.bib
new file mode 100644
index 0000000..c80aa99
--- /dev/null
+++ b/src/test/resources/testbib/crossref.bib
@@ -0,0 +1,45 @@
+% Encoding: UTF-8
+
+ at InProceedings{DBLP:conf/wicsa/ZimmermannWKG15,
+ author = {Olaf Zimmermann and Lukas Wegmann and Heiko Koziolek and Thomas Goldschmidt},
+ title = {Architectural Decision Guidance Across Projects - Problem Space Modeling, Decision Backlog Management and Cloud Computing Knowledge},
+ booktitle = {12th Working {IEEE/IFIP} Conference on Software Architecture, {WICSA} 2015, Montreal, QC, Canada, May 4-8, 2015},
+ year = {2015},
+ pages = {85--94},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/wicsa/ZimmermannWKG15},
+ crossref = {DBLP:conf/wicsa/2015},
+ doi = {10.1109/WICSA.2015.29},
+ timestamp = {Mon, 27 Jul 2015 18:21:36 +0200},
+ url = {http://dx.doi.org/10.1109/WICSA.2015.29},
+}
+
+ at Article{Article2016,
+ author = {Hans Mustermann},
+ title = {Title of the article},
+ journal = {Journal},
+ year = {2016},
+ related = {InProceedings2015},
+ test = {xy},
+}
+
+ at InProceedings{InProceedings2015,
+ author = {Anna Musterfrau},
+ title = {Paper title},
+ booktitle = {Book title},
+ year = {2015},
+}
+
+ at Proceedings{DBLP:conf/wicsa/2015,
+ title = {12th Working {IEEE/IFIP} Conference on Software Architecture, {WICSA} 2015, Montreal, QC, Canada, May 4-8, 2015},
+ year = {2015},
+ editor = {Len Bass and Patricia Lago and Philippe Kruchten},
+ publisher = {{IEEE} Computer Society},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/wicsa/2015},
+ isbn = {978-1-4799-1922-2},
+ timestamp = {Fri, 24 Jul 2015 13:18:35 +0200},
+ url = {http://ieeexplore.ieee.org/xpl/mostRecentIssue.jsp?punumber=7158223},
+}
+
+ at Comment{jabref-meta: databaseType:bibtex;}
diff --git a/src/test/resources/testbib/jabref-authors.bib b/src/test/resources/testbib/jabref-authors.bib
new file mode 100644
index 0000000..74ccdc5
--- /dev/null
+++ b/src/test/resources/testbib/jabref-authors.bib
@@ -0,0 +1,2920 @@
+% Encoding: UTF-8
+
+ at Article{GarridoKallstromKummEtAl2016,
+ author = {Mario Garrido and Petter Kallstrom and Martin Kumm and Oscar Gustafsson},
+ title = {{CORDIC} {II:} {A} New Improved {CORDIC} Algorithm},
+ journal = {{IEEE} Trans. on Circuits and Systems},
+ year = {2016},
+ volume = {63-II},
+ number = {2},
+ pages = {186--190},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/journals/tcas/GarridoKKG16},
+ doi = {10.1109/TCSII.2015.2483422},
+ timestamp = {Mon, 08 Feb 2016 00:00:00 +0100},
+}
+
+ at InProceedings{GustafssonJohansson2015,
+ author = {Oscar Gustafsson and H{\aa}kan Johansson},
+ title = {Decimation filters for high-speed delta-sigma modulators with passband constraints: General versus CIC-based {FIR} filters},
+ booktitle = {2015 {IEEE} International Symposium on Circuits and Systems, {ISCAS} 2015, Lisbon, Portugal, May 24-27, 2015},
+ year = {2015},
+ pages = {2205--2208},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/iscas/GustafssonJ15},
+ doi = {10.1109/ISCAS.2015.7169119},
+ timestamp = {Wed, 05 Aug 2015 09:08:53 +0200},
+}
+
+ at InProceedings{JohanssonGustafsson2015,
+ author = {H{\aa}kan Johansson and Oscar Gustafsson},
+ title = {Filter-bank based all-digital channelizers and aggregators for multi-standard video distribution},
+ booktitle = {2015 {IEEE} International Conference on Digital Signal Processing, {DSP} 2015, Singapore, July 21-24, 2015},
+ year = {2015},
+ pages = {1117--1120},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/icdsp/JohanssonG15a},
+ doi = {10.1109/ICDSP.2015.7252052},
+ keywords = {rank4},
+ timestamp = {Tue, 22 Sep 2015 18:08:19 +0200},
+ url = {http://dx.doi.org/10.1109/ICDSP.2015.7252052},
+}
+
+ at InProceedings{AlamGustafsson2015,
+ author = {Syed Asad Alam and Oscar Gustafsson},
+ title = {Generalized division-free architecture and compact memory structure for resampling in particle filters},
+ booktitle = {European Conference on Circuit Theory and Design, {ECCTD} 2015, Trondheim, Norway, August 24-26, 2015},
+ year = {2015},
+ pages = {1--4},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/ecctd/AlamG15},
+ doi = {10.1109/ECCTD.2015.7300060},
+ timestamp = {Thu, 22 Oct 2015 09:49:02 +0200},
+ url = {http://dx.doi.org/10.1109/ECCTD.2015.7300060},
+}
+
+ at InProceedings{IngemarssonGustafsson2015,
+ author = {Carl Ingemarsson and Oscar Gustafsson},
+ title = {On fixed-point implementation of symmetric matrix inversion},
+ booktitle = {European Conference on Circuit Theory and Design, {ECCTD} 2015, Trondheim, Norway, August 24-26, 2015},
+ year = {2015},
+ pages = {1--4},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/ecctd/IngemarssonG15},
+ doi = {10.1109/ECCTD.2015.7300068},
+ timestamp = {Thu, 22 Oct 2015 09:49:02 +0200},
+ url = {http://dx.doi.org/10.1109/ECCTD.2015.7300068},
+}
+
+ at InProceedings{JohanssonGustafsson2015a,
+ author = {H{\aa}kan Johansson and Oscar Gustafsson},
+ title = {On frequency-domain implementation of digital {FIR} filters},
+ booktitle = {2015 {IEEE} International Conference on Digital Signal Processing, {DSP} 2015, Singapore, July 21-24, 2015},
+ year = {2015},
+ pages = {315--318},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/icdsp/JohanssonG15},
+ doi = {10.1109/ICDSP.2015.7251883},
+ timestamp = {Tue, 22 Sep 2015 18:08:19 +0200},
+ url = {http://dx.doi.org/10.1109/ICDSP.2015.7251883},
+}
+
+ at Article{AlamGustafsson2014,
+ author = {Syed Asad Alam and Oscar Gustafsson},
+ title = {Design of Finite Word Length Linear-Phase {FIR} Filters in the Logarithmic Number System Domain},
+ journal = {{VLSI} Design},
+ year = {2014},
+ volume = {2014},
+ pages = {217495:1--217495:14},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/journals/vlsi/AlamG14},
+ doi = {10.1155/2014/217495},
+ timestamp = {Mon, 01 Jun 2015 01:00:00 +0200},
+ url = {http://dx.doi.org/10.1155/2014/217495},
+}
+
+ at InProceedings{SadeghifarWiknerGustafsson2014,
+ author = {Mohammad Reza Sadeghifar and J. Jacob Wikner and Oscar Gustafsson},
+ title = {Linear programming design of semi-digital {FIR} filter and {\(\Sigma\)}{\(\Delta\)} modulator for {VDSL2} transmitter},
+ booktitle = {{IEEE} International Symposium on Circuits and Systemss, {ISCAS} 2014, Melbourne, Victoria, Australia, June 1-5, 2014},
+ year = {2014},
+ pages = {2465--2468},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/iscas/SadeghifarWG14},
+ doi = {10.1109/ISCAS.2014.6865672},
+ timestamp = {Fri, 20 May 2016 09:19:46 +0200},
+ url = {http://dx.doi.org/10.1109/ISCAS.2014.6865672},
+}
+
+ at Article{GarridoQureshiGustafsson2014,
+ author = {Mario Garrido and Fahad Qureshi and Oscar Gustafsson},
+ title = {Low-Complexity Multiplierless Constant Rotators Based on Combined Coefficient Selection and Shift-and-Add Implementation {(CCSSI)}},
+ journal = {{IEEE} Trans. on Circuits and Systems},
+ year = {2014},
+ volume = {61-I},
+ number = {7},
+ pages = {2002--2012},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/journals/tcas/GarridoQG14},
+ doi = {10.1109/TCSI.2014.2304664},
+ timestamp = {Thu, 18 Sep 2014 01:00:00 +0200},
+ url = {http://dx.doi.org/10.1109/TCSI.2014.2304664},
+}
+
+ at Article{AfzalWiknerGustafsson2014,
+ author = {Nadeem Afzal and J. Jacob Wikner and Oscar Gustafsson},
+ title = {Reducing Complexity and Power of Digital Multibit Error-Feedback {\(\Delta\)}{\(\Sigma\)} Modulators},
+ journal = {{IEEE} Trans. on Circuits and Systems},
+ year = {2014},
+ volume = {61-II},
+ number = {9},
+ pages = {641--645},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/journals/tcas/AfzalWG14},
+ doi = {10.1109/TCSII.2014.2331105},
+ timestamp = {Thu, 18 Sep 2014 01:00:00 +0200},
+ url = {http://dx.doi.org/10.1109/TCSII.2014.2331105},
+}
+
+ at InProceedings{BoopalGarridoGustafsson2013,
+ author = {Padma Prasad Boopal and Mario Garrido and Oscar Gustafsson},
+ title = {A reconfigurable {FFT} architecture for variable-length and multi-streaming {OFDM} standards},
+ booktitle = {2013 {IEEE} International Symposium on Circuits and Systems (ISCAS2013), Beijing, China, May 19-23, 2013},
+ year = {2013},
+ pages = {2066--2070},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/iscas/BoopalGG13},
+ doi = {10.1109/ISCAS.2013.6572279},
+ timestamp = {Mon, 26 Aug 2013 07:33:58 +0200},
+ url = {http://dx.doi.org/10.1109/ISCAS.2013.6572279},
+}
+
+ at InCollection{GustafssonWanhammar2013,
+ author = {Oscar Gustafsson and Lars Wanhammar},
+ title = {Arithmetic},
+ booktitle = {Handbook of Signal Processing Systems},
+ publisher = {Springer},
+ year = {2013},
+ editor = {Shuvra S. Bhattacharyya and Ed F. Deprettere and Rainer Leupers and Jarmo Takala},
+ pages = {593--637},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/reference/sps/GustafssonW13},
+ doi = {10.1007/978-1-4614-6859-2_19},
+ timestamp = {Wed, 11 Dec 2013 13:59:28 +0100},
+ url = {http://dx.doi.org/10.1007/978-1-4614-6859-2_19},
+}
+
+ at Article{AshrafiStrolloGustafsson2013,
+ author = {Ashkan Ashrafi and Antonio G. M. Strollo and Oscar Gustafsson},
+ title = {Hardware Implementation of Digital Signal Processing Algorithms},
+ journal = {J. Electrical and Computer Engineering},
+ year = {2013},
+ volume = {2013},
+ pages = {782575:1--782575:2},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/journals/jece/AshrafiSG13},
+ doi = {10.1155/2013/782575},
+ timestamp = {Fri, 29 May 2015 01:00:00 +0200},
+ url = {http://dx.doi.org/10.1155/2013/782575},
+}
+
+ at InProceedings{GustafssonEhliar2013,
+ author = {Oscar Gustafsson and Andreas Ehliar},
+ title = {Low-complexity general {FIR} filters based on Winograd's inner product algorithm},
+ booktitle = {2013 {IEEE} International Symposium on Circuits and Systems (ISCAS2013), Beijing, China, May 19-23, 2013},
+ year = {2013},
+ pages = {93--96},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/iscas/GustafssonE13},
+ doi = {10.1109/ISCAS.2013.6571790},
+ timestamp = {Mon, 26 Aug 2013 07:33:58 +0200},
+ url = {http://dx.doi.org/10.1109/ISCAS.2013.6571790},
+}
+
+ at Article{AbbasGustafssonJohansson2013,
+ author = {Muhammad Abbas and Oscar Gustafsson and H{\aa}kan Johansson},
+ title = {On the Fixed-Point Implementation of Fractional-Delay Filters Based on the Farrow Structure},
+ journal = {{IEEE} Trans. on Circuits and Systems},
+ year = {2013},
+ volume = {60-I},
+ number = {4},
+ pages = {926--937},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/journals/tcas/AbbasGJ13},
+ doi = {10.1109/TCSI.2013.2244272},
+ timestamp = {Wed, 10 Apr 2013 01:00:00 +0200},
+ url = {http://dx.doi.org/10.1109/TCSI.2013.2244272},
+}
+
+ at Article{GarridoGrajalMarcosEtAl2013,
+ author = {Mario Garrido and Jes{\'{u}}s Grajal and Miguel A. S{\'{a}}nchez Marcos and Oscar Gustafsson},
+ title = {Pipelined Radix-2\({}^{\mbox{k}}\) Feedforward {FFT} Architectures},
+ journal = {{IEEE} Trans. {VLSI} Syst.},
+ year = {2013},
+ volume = {21},
+ number = {1},
+ pages = {23--32},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/journals/tvlsi/GarridoGSG13},
+ doi = {10.1109/TVLSI.2011.2178275},
+ timestamp = {Sat, 10 Jan 2015 00:00:00 +0100},
+ url = {http://dx.doi.org/10.1109/TVLSI.2011.2178275},
+}
+
+ at Article{SheikhGustafsson2012,
+ author = {Zaka Ullah Sheikh and Oscar Gustafsson},
+ title = {Linear Programming Design of Coefficient Decimation {FIR} Filters},
+ journal = {{IEEE} Trans. on Circuits and Systems},
+ year = {2012},
+ volume = {59-II},
+ number = {1},
+ pages = {60--64},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/journals/tcas/SheikhG12},
+ doi = {10.1109/TCSII.2011.2173965},
+ timestamp = {Mon, 23 Jan 2012 00:00:00 +0100},
+ url = {http://dx.doi.org/10.1109/TCSII.2011.2173965},
+}
+
+ at InProceedings{KallstromGarridoGustafsson2012,
+ author = {Petter Kallstrom and Mario Garrido and Oscar Gustafsson},
+ title = {Low-complexity rotators for the {FFT} using base-3 signed stages},
+ booktitle = {{IEEE} Asia Pacific Conference on Circuits and Systems, {APCCAS} 2012, Kaohsiung, Taiwan, December 2-5, 2012},
+ year = {2012},
+ pages = {519--522},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/apccas/KallstromGG12},
+ doi = {10.1109/APCCAS.2012.6419086},
+ timestamp = {Fri, 08 May 2015 15:30:14 +0200},
+ url = {http://dx.doi.org/10.1109/APCCAS.2012.6419086},
+}
+
+ at InProceedings{IngemarssonKallstromGustafsson2012,
+ author = {Carl Ingemarsson and Petter Kallstrom and Oscar Gustafsson},
+ title = {Using {DSP} block pre-adders in pipeline {SDF} {FFT} implementations in contemporary FPGAs},
+ booktitle = {22nd International Conference on Field Programmable Logic and Applications (FPL), Oslo, Norway, August 29-31, 2012},
+ year = {2012},
+ editor = {Dirk Koch and Satnam Singh and Jim T{\o}rresen},
+ pages = {71--74},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/fpl/IngemarssonKG12},
+ doi = {10.1109/FPL.2012.6339243},
+ timestamp = {Mon, 12 Nov 2012 15:25:30 +0100},
+ url = {http://dx.doi.org/10.1109/FPL.2012.6339243},
+}
+
+ at InProceedings{BladGustafsson2011,
+ author = {Anton Blad and Oscar Gustafsson},
+ title = {{FPGA} implementation of rate-compatible {QC-LDPC} code decoder},
+ booktitle = {20th European Conference on Circuit Theory and Design, {ECCTD} 2011, Linkoping, Sweden, Aug. 29-31, 2011},
+ year = {2011},
+ pages = {777--780},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/ecctd/BladG11},
+ doi = {10.1109/ECCTD.2011.6043844},
+ timestamp = {Mon, 31 Oct 2011 11:49:23 +0100},
+ url = {http://dx.doi.org/10.1109/ECCTD.2011.6043844},
+}
+
+ at InProceedings{AhmedGarridoGustafsson2011,
+ author = {Tanvir Ahmed and Mario Garrido and Oscar Gustafsson},
+ title = {A 512-point 8-parallel pipelined feedforward {FFT} for {WPAN}},
+ booktitle = {Conference Record of the Forty Fifth Asilomar Conference on Signals, Systems and Computers, {ACSCC} 2011, Pacific Grove, CA, USA, November 6-9, 2011},
+ year = {2011},
+ editor = {Michael B. Matthews},
+ pages = {981--984},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/acssc/AhmedGG11},
+ doi = {10.1109/ACSSC.2011.6190157},
+ timestamp = {Tue, 28 Apr 2015 17:32:17 +0200},
+ url = {http://dx.doi.org/10.1109/ACSSC.2011.6190157},
+}
+
+ at Article{GarridoGustafssonGrajal2011,
+ author = {Mario Garrido and Oscar Gustafsson and Jes{\'{u}}s Grajal},
+ title = {Accurate Rotations Based on Coefficient Scaling},
+ journal = {{IEEE} Trans. on Circuits and Systems},
+ year = {2011},
+ volume = {58-II},
+ number = {10},
+ pages = {662--666},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/journals/tcas/GarridoGG11a},
+ doi = {10.1109/TCSII.2011.2164144},
+ timestamp = {Mon, 24 Oct 2011 01:00:00 +0200},
+ url = {http://dx.doi.org/10.1109/TCSII.2011.2164144},
+}
+
+ at InProceedings{AbbasGustafsson2011,
+ author = {Muhammad Abbas and Oscar Gustafsson},
+ title = {Computational and implementation complexity of polynomial evaluation schemes},
+ booktitle = {2011 NORCHIP, Lund, Sweden, November 14-15, 2011},
+ year = {2011},
+ pages = {1--6},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/norchip/AbbasG11},
+ doi = {10.1109/NORCHP.2011.6126735},
+ timestamp = {Wed, 11 Feb 2015 10:01:32 +0100},
+ url = {http://dx.doi.org/10.1109/NORCHP.2011.6126735},
+}
+
+ at InProceedings{IngemarssonGustafsson2011,
+ author = {Carl Ingemarsson and Oscar Gustafsson},
+ title = {Finite wordlength properties of matrix inversion algorithms in fixed-point and logarithmic number systems},
+ booktitle = {20th European Conference on Circuit Theory and Design, {ECCTD} 2011, Linkoping, Sweden, Aug. 29-31, 2011},
+ year = {2011},
+ pages = {673--676},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/ecctd/IngemarssonG11},
+ doi = {10.1109/ECCTD.2011.6043633},
+ timestamp = {Mon, 31 Oct 2011 11:49:23 +0100},
+ url = {http://dx.doi.org/10.1109/ECCTD.2011.6043633},
+}
+
+ at InProceedings{QureshiGustafsson2011,
+ author = {Fahad Qureshi and Oscar Gustafsson},
+ title = {Generation of all radix-2 fast Fourier transform algorithms using binary trees},
+ booktitle = {20th European Conference on Circuit Theory and Design, {ECCTD} 2011, Linkoping, Sweden, Aug. 29-31, 2011},
+ year = {2011},
+ pages = {677--680},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/ecctd/QureshiG11},
+ doi = {10.1109/ECCTD.2011.6043634},
+ timestamp = {Mon, 31 Oct 2011 11:49:23 +0100},
+ url = {http://dx.doi.org/10.1109/ECCTD.2011.6043634},
+}
+
+ at InProceedings{AlamGustafsson2011,
+ author = {Syed Asad Alam and Oscar Gustafsson},
+ title = {Implementation of narrow-band frequency-response masking for efficient narrow transition band {FIR} filters on FPGAs},
+ booktitle = {2011 NORCHIP, Lund, Sweden, November 14-15, 2011},
+ year = {2011},
+ pages = {1--4},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/norchip/AlamG11},
+ doi = {10.1109/NORCHP.2011.6126702},
+ timestamp = {Wed, 11 Feb 2015 10:01:32 +0100},
+ url = {http://dx.doi.org/10.1109/NORCHP.2011.6126702},
+}
+
+ at InProceedings{AlamGustafsson2011a,
+ author = {Syed Asad Alam and Oscar Gustafsson},
+ title = {Implementation of time-multiplexed sparse periodic {FIR} filters for {FRM} on FPGAs},
+ booktitle = {International Symposium on Circuits and Systems {(ISCAS} 2011), May 15-19 2011, Rio de Janeiro, Brazil},
+ year = {2011},
+ pages = {661--664},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/iscas/AlamG11},
+ doi = {10.1109/ISCAS.2011.5937652},
+ timestamp = {Fri, 20 May 2016 09:36:47 +0200},
+ url = {http://dx.doi.org/10.1109/ISCAS.2011.5937652},
+}
+
+ at Article{QureshiGustafsson2011a,
+ author = {Fahad Qureshi and Oscar Gustafsson},
+ title = {Low-Complexity Constant Multiplication Based on Trigonometric Identities with Applications to FFTs},
+ journal = {{IEICE} Transactions},
+ year = {2011},
+ volume = {94-A},
+ number = {11},
+ pages = {2361--2368},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/journals/ieicet/QureshiG11},
+ timestamp = {Fri, 04 Nov 2011 00:00:00 +0100},
+ url = {http://search.ieice.org/bin/summary.php?id=e94-a_11_2361},
+}
+
+ at InProceedings{KallstromGustafsson2011,
+ author = {Petter Kallstrom and Oscar Gustafsson},
+ title = {Magnitude scaling for increased {SFDR} in {DDFS}},
+ booktitle = {2011 NORCHIP, Lund, Sweden, November 14-15, 2011},
+ year = {2011},
+ pages = {1--4},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/norchip/KallstromG11},
+ doi = {10.1109/NORCHP.2011.6126708},
+ timestamp = {Wed, 11 Feb 2015 10:01:32 +0100},
+ url = {http://dx.doi.org/10.1109/NORCHP.2011.6126708},
+}
+
+ at InProceedings{JohanssonGustafssonDeBrunnerEtAl2011,
+ author = {Kenny Johansson and Oscar Gustafsson and Linda DeBrunner and Lars Wanhammar},
+ title = {Minimum adder depth multiple constant multiplication algorithm for low power {FIR} filters},
+ booktitle = {International Symposium on Circuits and Systems {(ISCAS} 2011), May 15-19 2011, Rio de Janeiro, Brazil},
+ year = {2011},
+ pages = {1439--1442},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/iscas/JohanssonGDW11},
+ doi = {10.1109/ISCAS.2011.5937844},
+ timestamp = {Fri, 20 May 2016 09:36:47 +0200},
+ url = {http://dx.doi.org/10.1109/ISCAS.2011.5937844},
+}
+
+ at Article{AtharGustafssonQureshiEtAl2011,
+ author = {Saima Athar and Oscar Gustafsson and Fahad Qureshi and Izzet Kale},
+ title = {On the efficient computation of single-bit input word length pipelined FFTs},
+ journal = {{IEICE} Electronic Express},
+ year = {2011},
+ volume = {8},
+ number = {17},
+ pages = {1437--1443},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/journals/ieiceee/AtharGQK11},
+ doi = {10.1587/elex.8.1437},
+ timestamp = {Mon, 26 May 2014 01:00:00 +0200},
+ url = {http://dx.doi.org/10.1587/elex.8.1437},
+}
+
+ at InProceedings{AtharGustafsson2011,
+ author = {Saima Athar and Oscar Gustafsson},
+ title = {Optimization of {AIQ} representations for low complexity wavelet transforms},
+ booktitle = {20th European Conference on Circuit Theory and Design, {ECCTD} 2011, Linkoping, Sweden, Aug. 29-31, 2011},
+ year = {2011},
+ pages = {314--317},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/ecctd/AtharG11},
+ doi = {10.1109/ECCTD.2011.6043349},
+ timestamp = {Mon, 31 Oct 2011 11:49:23 +0100},
+ url = {http://dx.doi.org/10.1109/ECCTD.2011.6043349},
+}
+
+ at Article{GarridoGrajalGustafsson2011,
+ author = {Mario Garrido and Jes{\'{u}}s Grajal and Oscar Gustafsson},
+ title = {Optimum Circuits for Bit Reversal},
+ journal = {{IEEE} Trans. on Circuits and Systems},
+ year = {2011},
+ volume = {58-II},
+ number = {10},
+ pages = {657--661},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/journals/tcas/GarridoGG11},
+ doi = {10.1109/TCSII.2011.2164141},
+ timestamp = {Mon, 24 Oct 2011 01:00:00 +0200},
+ url = {http://dx.doi.org/10.1109/TCSII.2011.2164141},
+}
+
+ at Article{LarssonGustafsson2011,
+ author = {Erik G. Larsson and Oscar Gustafsson},
+ title = {The Impact of Dynamic Voltage and Frequency Scaling on Multicore {DSP} Algorithm Design [Exploratory {DSP]}},
+ journal = {{IEEE} Signal Process. Mag.},
+ year = {2011},
+ volume = {28},
+ number = {3},
+ pages = {127--144},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/journals/spm/LarssonG11},
+ doi = {10.1109/MSP.2011.940410},
+ timestamp = {Tue, 27 Mar 2012 01:00:00 +0200},
+ url = {http://dx.doi.org/10.1109/MSP.2011.940410},
+}
+
+ at Article{GustafssonQureshi2010,
+ author = {Oscar Gustafsson and Fahad Qureshi},
+ title = {Addition Aware Quantization for Low Complexity and High Precision Constant Multiplication},
+ journal = {{IEEE} Signal Process. Lett.},
+ year = {2010},
+ volume = {17},
+ number = {2},
+ pages = {173--176},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/journals/spl/GustafssonQ10},
+ doi = {10.1109/LSP.2009.2036384},
+ timestamp = {Thu, 13 Jun 2013 01:00:00 +0200},
+ url = {http://dx.doi.org/10.1109/LSP.2009.2036384},
+}
+
+ at InProceedings{QureshiGarridoGustafsson2010,
+ author = {Fahad Qureshi and Mario Garrido and Oscar Gustafsson},
+ title = {Alternatives for low-complexity complex rotators},
+ booktitle = {17th {IEEE} International Conference on Electronics, Circuits, and Systems, {ICECS} 2010, Athens, Greece, 12-15 December, 2010},
+ year = {2010},
+ pages = {17--20},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/icecsys/QureshiGG10},
+ doi = {10.1109/ICECS.2010.5724443},
+ timestamp = {Tue, 29 Nov 2011 15:56:51 +0100},
+ url = {http://dx.doi.org/10.1109/ICECS.2010.5724443},
+}
+
+ at InProceedings{GustafssonAmiriAnderssonEtAl2010,
+ author = {Oscar Gustafsson and Kiarash Amiri and Dennis Andersson and Anton Blad and Christian Bonnet and Joseph R. Cavallaro and Jeroen Declerck and Antoine Dejonghe and Patrik Eliardsson and Miguel Glassee and Aawatif Hayar and Lieven Hollevoet and Christopher Hunter and Madhura Joshi and Florian Kaltenberger and Raymond Knopp and Khanh Le and Zoran Miljanic and Patrick Murphy and Frederik Naessens and Navid Nikaein and Dominique Nussbaum and Renaud Pacalet and Praveen Raghavan an [...]
+ title = {Architectures for cognitive radio testbeds and demonstrators - An overview},
+ booktitle = {5th International {ICST} Conference on Cognitive Radio Oriented Wireless Networks and Communications, {CROWNCOM} 2010, Cannes, France, June 9-11, 2010},
+ year = {2010},
+ editor = {Erik Larsson and Aawatif Hayar},
+ pages = {1--6},
+ publisher = {{ICST} / {IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/crowncom/GustafssonAABBC10},
+ doi = {10.4108/ICST.CROWNCOM2010.9290},
+ timestamp = {Thu, 19 Mar 2015 16:19:52 +0100},
+ url = {http://dx.doi.org/10.4108/ICST.CROWNCOM2010.9290},
+}
+
+ at InCollection{GustafssonWanhammar2010,
+ author = {Oscar Gustafsson and Lars Wanhammar},
+ title = {Arithmetic},
+ booktitle = {Handbook of Signal Processing Systems},
+ publisher = {Springer},
+ year = {2010},
+ editor = {Shuvra S. Bhattacharyya and Ed F. Deprettere and Rainer Leupers and Jarmo Takala},
+ pages = {283--327},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/books/daglib/p/GustafssonW10},
+ doi = {10.1007/978-1-4419-6345-1_12},
+ timestamp = {Thu, 25 Feb 2016 14:11:59 +0100},
+ url = {http://dx.doi.org/10.1007/978-1-4419-6345-1_12},
+}
+
+ at InProceedings{SheikhGustafsson2010,
+ author = {Zaka Ullah Sheikh and Oscar Gustafsson},
+ title = {Design of narrow-band and wide-band frequency-response masking filters using sparse non-periodic sub-filters},
+ booktitle = {18th European Signal Processing Conference, {EUSIPCO} 2010, Aalborg, Denmark, August 23-27, 2010},
+ year = {2010},
+ pages = {1704--1707},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/eusipco/SheikhG10},
+ timestamp = {Mon, 05 Oct 2015 10:46:48 +0200},
+ url = {http://ieeexplore.ieee.org/xpl/freeabs_all.jsp?arnumber=7096541},
+}
+
+ at Article{BladGustafsson2010,
+ author = {Anton Blad and Oscar Gustafsson},
+ title = {Integer Linear Programming-Based Bit-Level Optimization for High-Speed {FIR} Decimation Filter Architectures},
+ journal = {{CSSP}},
+ year = {2010},
+ volume = {29},
+ number = {1},
+ pages = {81--101},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/journals/cssp/BladG10},
+ doi = {10.1007/s00034-009-9116-5},
+ timestamp = {Fri, 15 May 2015 01:00:00 +0200},
+ url = {http://dx.doi.org/10.1007/s00034-009-9116-5},
+}
+
+ at InProceedings{BladGustafsson2010a,
+ author = {Anton Blad and Oscar Gustafsson},
+ title = {Redundancy reduction for high-speed fir filter architectures based on carry-save adder trees},
+ booktitle = {International Symposium on Circuits and Systems {(ISCAS} 2010), May 30 - June 2, 2010, Paris, France},
+ year = {2010},
+ pages = {181--184},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/iscas/BladG10},
+ doi = {10.1109/ISCAS.2010.5537997},
+ timestamp = {Fri, 20 May 2016 09:38:10 +0200},
+ url = {http://dx.doi.org/10.1109/ISCAS.2010.5537997},
+}
+
+ at InProceedings{QureshiGustafsson2010,
+ author = {Fahad Qureshi and Oscar Gustafsson},
+ title = {Twiddle factor memory switching activity analysis of radix-2\({}^{\mbox{2}}\) and equivalent {FFT} algorithms},
+ booktitle = {International Symposium on Circuits and Systems {(ISCAS} 2010), May 30 - June 2, 2010, Paris, France},
+ year = {2010},
+ pages = {4145--4148},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/iscas/QureshiG10},
+ doi = {10.1109/ISCAS.2010.5537605},
+ timestamp = {Fri, 20 May 2016 09:38:10 +0200},
+ url = {http://dx.doi.org/10.1109/ISCAS.2010.5537605},
+}
+
+ at InProceedings{JohanssonGustafssonDeBrunner2009,
+ author = {Kenny Johansson and Oscar Gustafsson and Linda DeBrunner},
+ title = {Estimation of the Switching Activity in Shift-and-add based Computations},
+ booktitle = {International Symposium on Circuits and Systems {(ISCAS} 2009), 24-17 May 2009, Taipei, Taiwan},
+ year = {2009},
+ pages = {3054--3057},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/iscas/JohanssonGD09},
+ doi = {10.1109/ISCAS.2009.5118447},
+ timestamp = {Fri, 20 May 2016 09:39:07 +0200},
+ url = {http://dx.doi.org/10.1109/ISCAS.2009.5118447},
+}
+
+ at InProceedings{QureshiGustafsson2009,
+ author = {Fahad Qureshi and Oscar Gustafsson},
+ title = {Low-complexity Reconfigurable Complex Constant Multiplication for FFTs},
+ booktitle = {International Symposium on Circuits and Systems {(ISCAS} 2009), 24-17 May 2009, Taipei, Taiwan},
+ year = {2009},
+ pages = {1137--1140},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/iscas/QureshiG09},
+ doi = {10.1109/ISCAS.2009.5117961},
+ timestamp = {Fri, 20 May 2016 09:39:07 +0200},
+ url = {http://dx.doi.org/10.1109/ISCAS.2009.5117961},
+}
+
+ at InProceedings{KhanGustafssonJohansson2009,
+ author = {Tahir Abbas Khan and Oscar Gustafsson and H{\aa}kan Johansson},
+ title = {Scaling of Fractional Delay Filters based on the Farrow Structure},
+ booktitle = {International Symposium on Circuits and Systems {(ISCAS} 2009), 24-17 May 2009, Taipei, Taiwan},
+ year = {2009},
+ pages = {489--492},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/iscas/KhanGJ09},
+ doi = {10.1109/ISCAS.2009.5117792},
+ timestamp = {Fri, 20 May 2016 09:39:07 +0200},
+ url = {http://dx.doi.org/10.1109/ISCAS.2009.5117792},
+}
+
+ at InProceedings{BladGustafsson2008,
+ author = {Anton Blad and Oscar Gustafsson},
+ title = {Bit-level optimized {FIR} filter architectures for high-speed decimation applications},
+ booktitle = {International Symposium on Circuits and Systems {(ISCAS} 2008), 18-21 May 2008, Sheraton Seattle Hotel, Seattle, Washington, {USA}},
+ year = {2008},
+ pages = {1914--1917},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/iscas/BladG08},
+ doi = {10.1109/ISCAS.2008.4541817},
+ timestamp = {Fri, 20 May 2016 09:40:26 +0200},
+ url = {http://dx.doi.org/10.1109/ISCAS.2008.4541817},
+}
+
+ at Article{Gustafsson2008,
+ author = {Oscar Gustafsson},
+ title = {Comments on 'A 70 MHz Multiplierless {FIR} Hilbert Transformer in 0.35 {\(\mathrm{\mu}\)}m Standard {CMOS} Library'},
+ journal = {{IEICE} Transactions},
+ year = {2008},
+ volume = {91-A},
+ number = {3},
+ pages = {899--900},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/journals/ieicet/Gustafsson08},
+ doi = {10.1093/ietfec/e91-a.3.899},
+ timestamp = {Tue, 16 Sep 2008 01:00:00 +0200},
+ url = {http://dx.doi.org/10.1093/ietfec/e91-a.3.899},
+}
+
+ at Article{JohanssonGustafssonWanhammar2008,
+ author = {Kenny Johansson and Oscar Gustafsson and Lars Wanhammar},
+ title = {Implementation of elementary functions for logarithmic number systems},
+ journal = {{IET} Computers {\&} Digital Techniques},
+ year = {2008},
+ volume = {2},
+ number = {4},
+ pages = {295--304},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/journals/iet-cdt/JohanssonGW08},
+ doi = {10.1049/iet-cdt:20070080},
+ timestamp = {Wed, 22 Jun 2011 01:00:00 +0200},
+ url = {http://dx.doi.org/10.1049/iet-cdt:20070080},
+}
+
+ at InProceedings{OskuiiJohanssonGustafssonEtAl2008,
+ author = {Saeeid Tahmasbi Oskuii and Kenny Johansson and Oscar Gustafsson and Per Gunnar Kjeldsberg},
+ title = {Power optimization of weighted bit-product summation tree for elementary function generator},
+ booktitle = {International Symposium on Circuits and Systems {(ISCAS} 2008), 18-21 May 2008, Sheraton Seattle Hotel, Seattle, Washington, {USA}},
+ year = {2008},
+ pages = {1240--1243},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/iscas/OskuiiJGK08},
+ doi = {10.1109/ISCAS.2008.4541649},
+ timestamp = {Fri, 20 May 2016 09:40:26 +0200},
+ url = {http://dx.doi.org/10.1109/ISCAS.2008.4541649},
+}
+
+ at InProceedings{JohanssonGustafssonWanhammar2008a,
+ author = {Kenny Johansson and Oscar Gustafsson and Lars Wanhammar},
+ title = {Switching activity estimation for shift-and-add based constant multipliers},
+ booktitle = {International Symposium on Circuits and Systems {(ISCAS} 2008), 18-21 May 2008, Sheraton Seattle Hotel, Seattle, Washington, {USA}},
+ year = {2008},
+ pages = {676--679},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/iscas/JohanssonGW08},
+ doi = {10.1109/ISCAS.2008.4541508},
+ timestamp = {Fri, 20 May 2016 09:40:26 +0200},
+ url = {http://dx.doi.org/10.1109/ISCAS.2008.4541508},
+}
+
+ at InProceedings{WanhammarSoltanianGustafssonEtAl2008,
+ author = {Lars Wanhammar and Baharak Soltanian and Oscar Gustafsson and Kenny Johansson},
+ title = {Synthesis of bandpass circulator-tree wave digital filters},
+ booktitle = {15th {IEEE} International Conference on Electronics, Circuits and Systems, {ICECS} 2008, St. Julien's, Malta, August 31 2008-September 3, 2008},
+ year = {2008},
+ pages = {834--837},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/icecsys/WanhammarSGJ08},
+ doi = {10.1109/ICECS.2008.4674983},
+ timestamp = {Tue, 22 Apr 2014 15:56:46 +0200},
+ url = {http://dx.doi.org/10.1109/ICECS.2008.4674983},
+}
+
+ at InProceedings{Gustafsson2007,
+ author = {Oscar Gustafsson},
+ title = {A Difference Based Adder Graph Heuristic for Multiple Constant Multiplication Problems},
+ booktitle = {International Symposium on Circuits and Systems {(ISCAS} 2007), 27-20 May 2007, New Orleans, Louisiana, {USA}},
+ year = {2007},
+ pages = {1097--1100},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/iscas/Gustafsson07},
+ doi = {10.1109/ISCAS.2007.378201},
+ timestamp = {Fri, 20 May 2016 09:41:11 +0200},
+ url = {http://dx.doi.org/10.1109/ISCAS.2007.378201},
+}
+
+ at InProceedings{JohanssonGustafssonWanhammar2007,
+ author = {Kenny Johansson and Oscar Gustafsson and Lars Wanhammar},
+ title = {Bit-Level Optimization of Shift-and-Add Based {FIR} Filters},
+ booktitle = {14th {IEEE} International Conference on Electronics, Circuits, and Systems, {ICECS} 2007, Marrakech, Morocco, December 11-14, 2007},
+ year = {2007},
+ pages = {713--716},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/icecsys/JohanssonGW07},
+ doi = {10.1109/ICECS.2007.4511091},
+ timestamp = {Tue, 26 Nov 2013 20:43:23 +0100},
+ url = {http://dx.doi.org/10.1109/ICECS.2007.4511091},
+}
+
+ at InProceedings{GustafssonJohansson2007,
+ author = {Oscar Gustafsson and H{\aa}kan Johansson},
+ title = {Complexity Comparison of Linear-Phase Mth-Band and General {FIR} Filters},
+ booktitle = {International Symposium on Circuits and Systems {(ISCAS} 2007), 27-20 May 2007, New Orleans, Louisiana, {USA}},
+ year = {2007},
+ pages = {2335--2338},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/iscas/GustafssonJ07},
+ doi = {10.1109/ISCAS.2007.378856},
+ timestamp = {Fri, 20 May 2016 09:41:11 +0200},
+ url = {http://dx.doi.org/10.1109/ISCAS.2007.378856},
+}
+
+ at InProceedings{GustafssonOlofsson2007,
+ author = {Oscar Gustafsson and Mikael Olofsson},
+ title = {Complexity Reduction of Constant Matrix Computations over the Binary Field},
+ booktitle = {Arithmetic of Finite Fields, First International Workshop, {WAIFI} 2007, Madrid, Spain, June 21-22, 2007, Proceedings},
+ year = {2007},
+ editor = {Claude Carlet and Berk Sunar},
+ volume = {4547},
+ series = {Lecture Notes in Computer Science},
+ pages = {103--115},
+ publisher = {Springer},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/waifi/GustafssonO07},
+ doi = {10.1007/978-3-540-73074-3_9},
+ timestamp = {Tue, 02 Oct 2007 09:38:31 +0200},
+ url = {http://dx.doi.org/10.1007/978-3-540-73074-3_9},
+}
+
+ at Article{Gustafsson2007a,
+ author = {Oscar Gustafsson},
+ title = {Lower Bounds for Constant Multiplication Problems},
+ journal = {{IEEE} Trans. on Circuits and Systems},
+ year = {2007},
+ volume = {54-II},
+ number = {11},
+ pages = {974--978},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/journals/tcas/Gustafsson07},
+ doi = {10.1109/TCSII.2007.903212},
+ timestamp = {Fri, 25 Oct 2013 01:00:00 +0200},
+ url = {http://dx.doi.org/10.1109/TCSII.2007.903212},
+}
+
+ at InProceedings{GustafssonOskuiiJohanssonEtAl2007,
+ author = {Oscar Gustafsson and Saeeid Tahmasbi Oskuii and Kenny Johansson and Per Gunnar Kjeldsberg},
+ title = {Switching Activity Reduction of MAC-Based {FIR} Filters with Correlated Input Data},
+ booktitle = {Integrated Circuit and System Design. Power and Timing Modeling, Optimization and Simulation, 17th International Workshop, {PATMOS} 2007, Gothenburg, Sweden, September 3-5, 2007, Proceedings},
+ year = {2007},
+ editor = {Nadine Az{\'{e}}mard and Lars J. Svensson},
+ volume = {4644},
+ series = {Lecture Notes in Computer Science},
+ pages = {526--535},
+ publisher = {Springer},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/patmos/GustafssonOJK07},
+ doi = {10.1007/978-3-540-74442-9_51},
+ timestamp = {Thu, 23 Aug 2007 14:55:51 +0200},
+ url = {http://dx.doi.org/10.1007/978-3-540-74442-9_51},
+}
+
+ at InProceedings{OskuiiKjeldsbergGustafsson2007,
+ author = {Saeeid Tahmasbi Oskuii and Per Gunnar Kjeldsberg and Oscar Gustafsson},
+ title = {Transition-activity aware design of reduction-stages for parallel multipliers},
+ booktitle = {Proceedings of the 17th {ACM} Great Lakes Symposium on {VLSI} 2007, Stresa, Lago Maggiore, Italy, March 11-13, 2007},
+ year = {2007},
+ editor = {Hai Zhou and Enrico Macii and Zhiyuan Yan and Yehia Massoud},
+ pages = {120--125},
+ publisher = {{ACM}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/glvlsi/OskuiiKG07},
+ doi = {10.1145/1228784.1228817},
+ timestamp = {Mon, 29 Sep 2014 17:13:50 +0200},
+ url = {http://doi.acm.org/10.1145/1228784.1228817},
+}
+
+ at InProceedings{JohanssonGustafssonJohanssonEtAl2006,
+ author = {H{\aa}kan Johansson and Oscar Gustafsson and J. Johansson and Lars Wanhammar},
+ title = {Adjustable Fractional-Delay {FIR} Filters Using the Farrow Structure and Multirate Techniques},
+ booktitle = {{IEEE} Asia Pacific Conference on Circuits and Systems 2006, {APCCAS} 2006, Singapore, 4-7 December 2006},
+ year = {2006},
+ pages = {1055--1058},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/apccas/JohanssonGJW06},
+ doi = {10.1109/APCCAS.2006.342270},
+ timestamp = {Fri, 08 May 2015 15:30:14 +0200},
+ url = {http://dx.doi.org/10.1109/APCCAS.2006.342270},
+}
+
+ at InProceedings{JohanssonGustafssonWanhammar2006,
+ author = {Kenny Johansson and Oscar Gustafsson and Lars Wanhammar},
+ title = {Approximation of elementary functions using a weighted sum of bit-products},
+ booktitle = {International Symposium on Circuits and Systems {(ISCAS} 2006), 21-24 May 2006, Island of Kos, Greece},
+ year = {2006},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/iscas/JohanssonGW06},
+ doi = {10.1109/ISCAS.2006.1692705},
+ timestamp = {Fri, 20 May 2016 09:41:50 +0200},
+ url = {http://dx.doi.org/10.1109/ISCAS.2006.1692705},
+}
+
+ at InProceedings{BackeniusSallGustafsson2006,
+ author = {Erik Backenius and Erik Sall and Oscar Gustafsson},
+ title = {Bidirectional conversion to minimum signed-digit representation},
+ booktitle = {International Symposium on Circuits and Systems {(ISCAS} 2006), 21-24 May 2006, Island of Kos, Greece},
+ year = {2006},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/iscas/BackeniusSG06},
+ doi = {10.1109/ISCAS.2006.1693109},
+ timestamp = {Fri, 20 May 2016 09:41:50 +0200},
+ url = {http://dx.doi.org/10.1109/ISCAS.2006.1693109},
+}
+
+ at InProceedings{GustafssonJohanssonJohanssonEtAl2006,
+ author = {Oscar Gustafsson and Kenny Johansson and H{\aa}kan Johansson and Lars Wanhammar},
+ title = {Implementation of Polyphase Decomposed {FIR} Filters for Interpolation and Decimation Using Multiple Constant Multiplication Techniques},
+ booktitle = {{IEEE} Asia Pacific Conference on Circuits and Systems 2006, {APCCAS} 2006, Singapore, 4-7 December 2006},
+ year = {2006},
+ pages = {924--927},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/apccas/GustafssonJJW06},
+ doi = {10.1109/APCCAS.2006.342212},
+ timestamp = {Fri, 08 May 2015 15:30:14 +0200},
+ url = {http://dx.doi.org/10.1109/APCCAS.2006.342212},
+}
+
+ at InProceedings{GustafssonOhlsson2005,
+ author = {Oscar Gustafsson and Henrik Ohlsson},
+ title = {A low power decimation filter architecture for high-speed single-bit sigma-delta modulation},
+ booktitle = {International Symposium on Circuits and Systems {(ISCAS} 2005), 23-26 May 2005, Kobe, Japan},
+ year = {2005},
+ pages = {1453--1456},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/iscas/GustafssonO05},
+ doi = {10.1109/ISCAS.2005.1464872},
+ timestamp = {Fri, 20 May 2016 09:46:35 +0200},
+ url = {http://dx.doi.org/10.1109/ISCAS.2005.1464872},
+}
+
+ at InProceedings{JohanssonGustafssonWanhammar2005,
+ author = {Kenny Johansson and Oscar Gustafsson and Lars Wanhammar},
+ title = {Implementation of low-complexity {FIR} filters using serial arithmetic},
+ booktitle = {International Symposium on Circuits and Systems {(ISCAS} 2005), 23-26 May 2005, Kobe, Japan},
+ year = {2005},
+ pages = {1449--1452},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/iscas/JohanssonGW05},
+ doi = {10.1109/ISCAS.2005.1464871},
+ timestamp = {Fri, 20 May 2016 09:46:35 +0200},
+ url = {http://dx.doi.org/10.1109/ISCAS.2005.1464871},
+}
+
+ at Article{JohanssonGustafsson2005,
+ author = {H{\aa}kan Johansson and Oscar Gustafsson},
+ title = {Linear-phase {FIR} interpolation, decimation, and mth-band filters utilizing the farrow structure},
+ journal = {{IEEE} Trans. on Circuits and Systems},
+ year = {2005},
+ volume = {52-I},
+ number = {10},
+ pages = {2197--2207},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/journals/tcas/JohanssonG05},
+ doi = {10.1109/TCSI.2005.853264},
+ timestamp = {Mon, 13 Apr 2015 01:00:00 +0200},
+ url = {http://dx.doi.org/10.1109/TCSI.2005.853264},
+}
+
+ at InProceedings{OhlssonGustafssonWanhammar2004,
+ author = {Henrik Ohlsson and Oscar Gustafsson and Lars Wanhammar},
+ title = {A shifted permuted difference coefficient method},
+ booktitle = {Proceedings of the 2004 International Symposium on Circuits and Systems, {ISCAS} 2004, Vancouver, BC, Canada, May 23-26, 2004},
+ year = {2004},
+ pages = {161--164},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/iscas/OhlssonGW04},
+ doi = {10.1109/ISCAS.2004.1328708},
+ timestamp = {Fri, 20 May 2016 09:53:46 +0200},
+ url = {http://dx.doi.org/10.1109/ISCAS.2004.1328708},
+}
+
+ at InProceedings{JohanssonGustafssonWanhammar2004,
+ author = {Kenny Johansson and Oscar Gustafsson and Lars Wanhammar},
+ title = {Low-complexity bit-serial constant-coefficient multipliers},
+ booktitle = {Proceedings of the 2004 International Symposium on Circuits and Systems, {ISCAS} 2004, Vancouver, BC, Canada, May 23-26, 2004},
+ year = {2004},
+ pages = {649--652},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/iscas/JohanssonGW04},
+ doi = {10.1109/ISCAS.2004.1328830},
+ timestamp = {Fri, 20 May 2016 09:53:46 +0200},
+ url = {http://dx.doi.org/10.1109/ISCAS.2004.1328830},
+}
+
+ at InProceedings{JohanssonGustafsson2004,
+ author = {H{\aa}kan Johansson and Oscar Gustafsson},
+ title = {Mth-band linear-phase {FIR} filter interpolators and decimators utilizing the Farrow structure},
+ booktitle = {Proceedings of the 2004 International Symposium on Circuits and Systems, {ISCAS} 2004, Vancouver, BC, Canada, May 23-26, 2004},
+ year = {2004},
+ pages = {129--132},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/iscas/JohanssonG04},
+ doi = {10.1109/ISCAS.2004.1328700},
+ timestamp = {Fri, 20 May 2016 09:53:46 +0200},
+ url = {http://dx.doi.org/10.1109/ISCAS.2004.1328700},
+}
+
+ at InProceedings{GustafssonDempsterWanhammar2004,
+ author = {Oscar Gustafsson and Andrew G. Dempster and Lars Wanhammar},
+ title = {Multiplier blocks using carry-save adders},
+ booktitle = {Proceedings of the 2004 International Symposium on Circuits and Systems, {ISCAS} 2004, Vancouver, BC, Canada, May 23-26, 2004},
+ year = {2004},
+ pages = {473--476},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/iscas/GustafssonDW04},
+ timestamp = {Fri, 20 May 2016 09:53:46 +0200},
+}
+
+ at InProceedings{JohanssonGustafssonWanhammar2004a,
+ author = {Kenny Johansson and Oscar Gustafsson and Lars Wanhammar},
+ title = {Power Estimation for Ripple-Carry Adders with Correlated Input Data},
+ booktitle = {Integrated Circuit and System Design, Power and Timing Modeling, Optimization and Simulation; 14th International Workshop, {PATMOS} 2004, Santorini, Greece, September 15-17, 2004, Proceedings},
+ year = {2004},
+ editor = {Enrico Macii and Odysseas G. Koufopavlou and Vassilis Paliouras},
+ volume = {3254},
+ series = {Lecture Notes in Computer Science},
+ pages = {662--674},
+ publisher = {Springer},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/patmos/JohanssonGW04},
+ doi = {10.1007/978-3-540-30205-6_68},
+ timestamp = {Wed, 10 Aug 2011 01:00:00 +0200},
+ url = {http://dx.doi.org/10.1007/978-3-540-30205-6_68},
+}
+
+ at InProceedings{JohanssonGustafssonWanhammar2004b,
+ author = {Kenny Johansson and Oscar Gustafsson and Lars Wanhammar},
+ title = {Switching activity in bit-serial constant-coefficient multipliers},
+ booktitle = {Proceedings of the 2004 International Symposium on Circuits and Systems, {ISCAS} 2004, Vancouver, BC, Canada, May 23-26, 2004},
+ year = {2004},
+ pages = {469--472},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/iscas/JohanssonGW04a},
+ timestamp = {Fri, 20 May 2016 09:53:46 +0200},
+}
+
+ at Article{GustafssonJohanssonWanhammar2003,
+ author = {Oscar Gustafsson and H{\aa}kan Johansson and Lars Wanhammar},
+ title = {Single Filter Frequency-Response Masking Fir Filters},
+ journal = {Journal of Circuits, Systems, and Computers},
+ year = {2003},
+ volume = {12},
+ number = {5},
+ pages = {601--630},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/journals/jcsc/GustafssonJW03},
+ doi = {10.1142/S0218126603001094},
+ timestamp = {Fri, 08 Apr 2005 01:00:00 +0200},
+ url = {http://dx.doi.org/10.1142/S0218126603001094},
+}
+
+ at InProceedings{GustafssonDempsterWanhammar2002,
+ author = {Oscar Gustafsson and Andrew G. Dempster and Lars Wanhammar},
+ title = {Extended results for minimum-adder constant integer multipliers},
+ booktitle = {Proceedings of the 2002 International Symposium on Circuits and Systems, {ISCAS} 2002, Scottsdale, Arizona, USA, May 26-29, 2002},
+ year = {2002},
+ pages = {73--76},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/iscas/GustafssonDW02},
+ doi = {10.1109/ISCAS.2002.1009780},
+ timestamp = {Fri, 20 May 2016 10:09:31 +0200},
+ url = {http://dx.doi.org/10.1109/ISCAS.2002.1009780},
+}
+
+ at InProceedings{OhlssonGustafssonWanhammar2001,
+ author = {Henrik Ohlsson and Oscar Gustafsson and Lars Wanhammar},
+ title = {Arithmetic transformations for increased maximal sample rate of bit-parallel bireciprocal lattice wave digital filters},
+ booktitle = {Proceedings of the 2001 International Symposium on Circuits and Systems, {ISCAS} 2001, Sydney, Australia, May 6-9, 2001},
+ year = {2001},
+ pages = {825--828},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/iscas/OhlssonGW01},
+ doi = {10.1109/ISCAS.2001.921198},
+ timestamp = {Fri, 20 May 2016 10:15:21 +0200},
+ url = {http://dx.doi.org/10.1109/ISCAS.2001.921198},
+}
+
+ at InProceedings{GustafssonOhlssonWanhammar2001,
+ author = {Oscar Gustafsson and Henrik Ohlsson and Lars Wanhammar},
+ title = {Minimum-adder integer multipliers using carry-save adders},
+ booktitle = {Proceedings of the 2001 International Symposium on Circuits and Systems, {ISCAS} 2001, Sydney, Australia, May 6-9, 2001},
+ year = {2001},
+ pages = {709--712},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/iscas/GustafssonOW01},
+ doi = {10.1109/ISCAS.2001.921169},
+ timestamp = {Fri, 20 May 2016 10:15:21 +0200},
+ url = {http://dx.doi.org/10.1109/ISCAS.2001.921169},
+}
+
+ at InProceedings{GustafssonJohanssonWanhammar2001,
+ author = {Oscar Gustafsson and H{\aa}kan Johansson and Lars Wanhammar},
+ title = {Narrow-band and wide-band high-speed recursive digital filters using single filter frequency masking techniques},
+ booktitle = {Proceedings of the Sixth International Symposium on Signal Processing and its Applications, {ISSPA} 2001, August 13-16 2001, Shmgri-La Hotel, Kuala Lumpur, Malaysia},
+ year = {2001},
+ pages = {36--39},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/isspa/GustafssonJW01},
+ doi = {10.1109/ISSPA.2001.949769},
+ timestamp = {Wed, 08 Jan 2014 08:33:42 +0100},
+ url = {http://dx.doi.org/10.1109/ISSPA.2001.949769},
+}
+
+ at InProceedings{GustafssonJohanssonWanhammar2001a,
+ author = {Oscar Gustafsson and H{\aa}kan Johansson and Lars Wanhammar},
+ title = {Narrow-band and wide-band single filter frequency masking {FIR} filters},
+ booktitle = {Proceedings of the 2001 International Symposium on Circuits and Systems, {ISCAS} 2001, Sydney, Australia, May 6-9, 2001},
+ year = {2001},
+ pages = {181--184},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/iscas/GustafssonJW01},
+ doi = {10.1109/ISCAS.2001.921037},
+ timestamp = {Fri, 20 May 2016 10:15:21 +0200},
+ url = {http://dx.doi.org/10.1109/ISCAS.2001.921037},
+}
+
+ at InProceedings{GustafssonJohanssonWanhammar2000,
+ author = {Oscar Gustafsson and H{\aa}kan Johansson and Lars Wanhammar},
+ title = {Design and efficient implementation of narrow-band single filter frequency masking {FIR} filters},
+ booktitle = {10th European Signal Processing Conference, {EUSIPCO} 2000, Tampere, Finland, September 4-8, 2000},
+ year = {2000},
+ pages = {1--4},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/eusipco/GustafssonJW00},
+ timestamp = {Fri, 06 May 2016 11:05:57 +0200},
+ url = {http://ieeexplore.ieee.org/xpl/freeabs_all.jsp?arnumber=7075430},
+}
+
+ at InProceedings{GustafssonWanhammar1999,
+ author = {Oscar Gustafsson and Lars Wanhammar},
+ title = {Implementation of maximally fast ladder wave digital filters using a numerically equivalent state-space representation},
+ booktitle = {Proceedings of the 1999 International Symposium on Circuits and Systems, {ISCAS} 1999, Orlando, Florida, USA, May 30 - June 2, 1999},
+ year = {1999},
+ pages = {419--422},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/iscas/GustafssonW99},
+ doi = {10.1109/ISCAS.1999.778874},
+ timestamp = {Fri, 20 May 2016 10:19:45 +0200},
+ url = {http://dx.doi.org/10.1109/ISCAS.1999.778874},
+}
+
+ at InProceedings{GeigerHarrerLenhardEtAl2016,
+ author = {Matthias Geiger and Simon Harrer and J\"org Lenhard and Guido Wirtz},
+ title = {{On the Evolution of BPMN 2.0 Support and Implementation}},
+ booktitle = {10th International IEEE Symposium on Service-Oriented System Engineering (SOSE)},
+ year = {2016},
+ pages = {120--128},
+ address = {Oxford, UK},
+ month = {March/April},
+ doi = {10.1109/sose.2016.39},
+ file = {:geiger2016evolution.pdf:PDF},
+ keywords = {rank4},
+}
+
+ at InProceedings{GeigerHarrerLenhard2016,
+ author = {Matthias Geiger and Simon Harrer and J\"org Lenhard},
+ title = {{P}rocess {E}ngine {B}enchmarking with {B}etsy -- {C}urrent {S}tatus and {F}uture {D}irections},
+ booktitle = {Proceedings of the 8th Central-European Workshop on Services and their Composition (ZEUS), January 27-28, Vienna, Austria},
+ year = {2016},
+ pages = {37--44},
+ month = {jan},
+ file = {:Geiger2016ProcessEngineBenchmarking.pdf:PDF},
+}
+
+ at InProceedings{NikolTraegerHarrerEtAl2016,
+ author = {Gabriel Nikol and Michael Tr\"ager and Simon Harrer and Guido Wirtz},
+ title = {{Service-oriented Multi-tenancy (SO-MT): Enabling Multi-tenancy for Existing Service Composition Engines with Docker}},
+ year = {2016},
+ doi = {10.1109/sose.2016.40},
+ file = {:Nikol2016.pdf:PDF},
+}
+
+ at InProceedings{GeigerHarrerLenhardEtAl2015,
+ author = {Matthias Geiger and Simon Harrer and J{\"{o}}rg Lenhard and Mathias Casar and Andreas Vorndran and Guido Wirtz},
+ title = {{BPMN Conformance in Open Source Engines}},
+ booktitle = {{Proceedings of the 9\textsuperscript{th} IEEE International Symposium on Service-Oriented System Engineering (SOSE)}},
+ year = {2015},
+ address = {San Francisco Bay, CA, USA},
+ month = mar,
+ organization = {IEEE},
+ publisher = {Institute of Electrical {\&} Electronics Engineers ({IEEE})},
+ doi = {10.1109/SOSE.2015.22},
+ file = {:Geiger2015BPMNConformanceIn.pdf:PDF},
+}
+
+ at InProceedings{HarrerGeigerPreisingerEtAl2015,
+ author = {Simon Harrer and Matthias Geiger and Christian R. Prei{\ss}inger and David Bimamisa and Stephan J.A. Schuberth and Guido Wirtz},
+ title = {{Improving the Static Analysis Conformance of BPEL Engines with BPELlint}},
+ booktitle = {{Proceedings of the 9\textsuperscript{th} IEEE International Symposium on Service-Oriented System Engineering (SOSE)}},
+ year = {2015},
+ address = {San Francisco Bay, CA, USA},
+ month = mar,
+ organization = {IEEE},
+ publisher = {Institute of Electrical {\&} Electronics Engineers ({IEEE})},
+ doi = {10.1109/SOSE.2015.21},
+ file = {:Harrer2015ImprovingStaticAnalysis.pdf:PDF},
+ keywords = {rank5},
+}
+
+ at InProceedings{HarrerRoeckWirtz2014,
+ author = {Simon Harrer and Cedric R\"ock and Guido Wirtz},
+ title = {{Automated and Isolated Tests for Complex Middleware Products: The Case of BPEL Engines}},
+ booktitle = {Proceedings of the 7\textsuperscript{th} IEEE International Conference on Software Testing, Verification and Validation Workshops (ICSTW'14)},
+ year = {2014},
+ pages = {390--398},
+ address = {Cleveland, Ohio, USA},
+ month = apr,
+ note = {Testing Tools Track},
+ doi = {10.1109/ICSTW.2014.45},
+ file = {:Harrer2014AutomatedandIsolated.pdf:PDF},
+ keywords = {rank2},
+}
+
+ at InProceedings{HarrerPreisingerWirtz2014,
+ author = {Simon Harrer and Christian Prei{\ss}inger and Guido Wirtz},
+ title = {{BPEL Conformance in Open Source Engines: The Case of Static Analysis}},
+ booktitle = {Proceedings of the 7\textsuperscript{th} {IEEE} International Conference on Service-Oriented Computing and Applications {(SOCA'14)}},
+ year = {2014},
+ pages = {33--40},
+ address = {Matsue, Japan},
+ month = nov,
+ organization = {IEEE},
+ doi = {10.1109/SOCA.2014.49},
+ file = {:Harrer2014BPELConformancein.pdf:PDF},
+}
+
+ at InProceedings{RoeckHarrerWirtz2014,
+ author = {Cedric R\"ock and Simon Harrer and Guido Wirtz},
+ title = {{Performance Benchmarking of BPEL Engines: A Comparison Framework, Status Quo Evaluation and Challenges}},
+ booktitle = {Proceedings of the 26\textsuperscript{th} International Conference on Software Engineering and Knowledge Engineering (SEKE'14)},
+ year = {2014},
+ pages = {31--34},
+ address = {Vancouver, Canada},
+ month = jul,
+ file = {:Roeck2014PerformanceBenchmarkingBPEL.pdf:PDF},
+}
+
+ at InCollection{Harrer2014,
+ author = {Harrer, Simon},
+ title = {{Process Engine Selection Support}},
+ booktitle = {On the Move to Meaningful Internet Systems: {OTM} 2014 Workshops},
+ publisher = {Springer Berlin Heidelberg},
+ year = {2014},
+ volume = {8842},
+ series = {Lecture Notes in Computer Science},
+ pages = {18--22},
+ month = oct,
+ doi = {10.1007/978-3-662-45550-0_3},
+ file = {:Harrer2014ProcessEngineSelection.pdf:PDF},
+ keywords = {BPMS selection, evaluation},
+}
+
+ at TechReport{PreisingerHarrer2014,
+ author = {Christian Roland Prei{\ss}inger and Simon Harrer},
+ title = {{Static Analysis Rules of the BPEL Specification: Tagging, Formalization and Tests}},
+ institution = {Otto-Friedrich Universit\"at Bamberg},
+ year = {2014},
+ type = {Bamberger Beitr\"age zur Wirtschaftsinformatik und Angewandten Informatik},
+ number = {no. 99},
+ month = aug,
+ file = {:Preissinger2014StaticAnalysisRules.pdf:PDF},
+}
+
+ at TechReport{RoeckHarrer2014,
+ author = {Cedric R\"ock and Simon Harrer},
+ title = {{Testing BPEL Engine Performance: A Survey}},
+ institution = {Otto-Friedrich Universit\"at Bamberg},
+ year = {2014},
+ type = {Bamberger Beitr\"age zur Wirtschaftsinformatik und Angewandten Informatik},
+ number = {no. 93},
+ month = may,
+ file = {:Roeck2014TestingBPELEngine.pdf:PDF},
+}
+
+ at InProceedings{HarrerNizamicWirtzEtAl2014,
+ author = {Simon Harrer and Faris Nizamic and Guido Wirtz and Alexander Lazovik},
+ title = {{Towards a Robustness Evaluation Framework for BPEL Engines}},
+ booktitle = {Proceedings of the 7\textsuperscript{th} {IEEE} International Conference on Service-Oriented Computing and Applications {(SOCA'14)}},
+ year = {2014},
+ pages = {199--206},
+ address = {Matsue, Japan},
+ month = nov,
+ organization = {IEEE},
+ doi = {10.1109/SOCA.2014.40},
+ file = {:Harrer2014TowardsRobustnessEvaluation.pdf:PDF},
+}
+
+ at InProceedings{KolbWirtz2014,
+ author = {Stefan Kolb and Guido Wirtz},
+ title = {{Towards Application Portability in Platform as a Service}},
+ booktitle = {{Proceedings of the 8\textsuperscript{th} IEEE International Symposium on Service-Oriented System Engineering (SOSE)}},
+ year = {2014},
+ address = {Oxford, United Kingdom},
+ month = apr,
+ organization = {IEEE},
+ file = {:Kolb2014TowardsApplicationPortability.pdf:PDF},
+}
+
+ at InProceedings{PreisingerHarrerSchuberthEtAl2014,
+ author = {Prei{\ss}inger, Christian R and Harrer, Simon and Schuberth, Stephan JA and Bimamisa, David and Wirtz, Guido},
+ title = {{Towards Standard Conformant BPEL Engines: The Case of Static Analysis}},
+ booktitle = {Proceedings of the 6\textsuperscript{th} Central-European Workshop on Services and their Composition (ZEUS'14)},
+ year = {2014},
+ pages = {60--63},
+ address = {Potsdam, Germany},
+ month = feb,
+ file = {:Preissinger2014BPELStaticAnalysisProposal.pdf:PDF},
+}
+
+ at InProceedings{HarrerLenhardWirtzEtAl2014,
+ author = {Simon Harrer and J\"org Lenhard and Guido Wirtz and Tammo van Lessen},
+ title = {{Towards Uniform BPEL Engine Management in the Cloud}},
+ booktitle = {Proceedings des CloudCycle14 Workshops auf der 44. Jahrestagung der Gesellschaft f\"ur Informatik e.V. (GI)},
+ year = {2014},
+ series = {LNI},
+ month = sep,
+ publisher = {Gesellschaft f\"ur Informatik e.V. (GI)},
+ file = {:Harrer2014TowardsUniformBPEL.pdf:PDF},
+}
+
+ at TechReport{Geiger2013,
+ author = {Matthias Geiger},
+ title = {{BPMN 2.0 Process Model Serialization Constraints}},
+ institution = {Otto-Friedrich Universit\"at Bamberg},
+ year = {2013},
+ type = {Bamberger Beitr\"age zur Wirtschaftsinformatik und Angewandten Informatik,},
+ number = {no. 92},
+ month = {May},
+ file = {:Geiger2013BPMN20Process.pdf:PDF},
+}
+
+ at InProceedings{GeigerWirtz2013,
+ author = {Matthias Geiger and Guido Wirtz},
+ title = {{BPMN 2.0 Serialization - Standard Compliance Issues and Evaluation of Modeling Tools}},
+ booktitle = {5\textsuperscript{th} International Workshop on Enterprise Modelling and Information Systems Architectures},
+ year = {2013},
+ address = {St. Gallen, Switzerland},
+ month = sep,
+ file = {:Geiger2013BPMN20Serialization.pdf:PDF},
+}
+
+ at InProceedings{GeigerWirtz2013a,
+ author = {Matthias Geiger and Guido Wirtz},
+ title = {{Detecting Interoperability and Correctness Issues in BPMN 2.0 Process Models}},
+ booktitle = {ZEUS, Rostock, Germany, February 21-22, 2013},
+ year = {2013},
+ series = {CEUR Workshop Proceedings},
+ pages = {39--42},
+ month = feb,
+ publisher = {CEUR-WS.org},
+ file = {:Geiger2013DetectingInteroperabilityand.pdf:PDF},
+}
+
+ at InProceedings{LenhardWirtz2013,
+ author = {J\"org Lenhard and Guido Wirtz},
+ title = {{Detecting Portability Issues in Model-Driven BPEL Mappings}},
+ booktitle = {SEKE},
+ year = {2013},
+ address = {Boston, Massachusetts, USA},
+ month = jun,
+ file = {:Lenhard2013DetectingPortabilityIssues.pdf:PDF},
+}
+
+ at InProceedings{LenhardHarrerWirtz2013,
+ author = {J{\"{o}}rg Lenhard and Simon Harrer and Guido Wirtz},
+ title = {{Measuring the Installability of Service Orchestrations Using the SQuaRE Method}},
+ booktitle = {{Proceedings of the 6\textsuperscript{th} IEEE International Conference on Service-Oriented Computing and Applications (SOCA'13)}},
+ year = {2013},
+ address = {Kauai, Hawaii, USA},
+ month = dec,
+ organization = {IEEE},
+ doi = {10.1109/SOCA.2013.30},
+ file = {:Lenhard2013MeasuringInstallabilityService.pdf:PDF},
+}
+
+ at InProceedings{LenhardWirtz2013a,
+ author = {J\"org Lenhard and Guido Wirtz},
+ title = {{Measuring the Portability of Executable Service-Oriented Processes}},
+ booktitle = {Proceedings of the 17\textsuperscript{th} IEEE International EDOC Conference},
+ year = {2013},
+ pages = {117--126},
+ address = {Vancouver, Canada},
+ month = sep,
+ publisher = {IEEE},
+ file = {:Lenhard2013MeasuringPortabilityof.pdf:PDF},
+}
+
+ at InProceedings{HarrerLenhardWirtz2013,
+ author = {Simon Harrer and J\"org Lenhard and Guido Wirtz},
+ title = {{Open Source versus Proprietary Software in Service-Orientation: The Case of BPEL Engines}},
+ booktitle = {Proceedings of the 11\textsuperscript{th} International Conference on Service-Oriented Computing {(ICSOC'13)}},
+ year = {2013},
+ volume = {8274},
+ series = {Lecture Notes in Computer Science},
+ pages = {99--113},
+ address = {Berlin, Germany},
+ month = dec,
+ publisher = {Springer Berlin Heidelberg},
+ doi = {10.1007/978-3-642-45005-1_8},
+ file = {:Harrer2013OpenSourceversus.pdf:PDF},
+}
+
+ at TechReport{HarrerLenhard2012,
+ author = {Harrer, Simon and Lenhard, J\"org},
+ title = {{Betsy--A BPEL Engine Test System}},
+ institution = {Otto-Friedrich Universit\"at Bamberg},
+ year = {2012},
+ number = {90},
+ month = jul,
+ file = {:Harrer2012BetsyBPELEngine.pdf:PDF},
+}
+
+ at InProceedings{HarrerLenhardWirtz2012,
+ author = {Simon Harrer and J\"org Lenhard and Guido Wirtz},
+ title = {{BPEL Conformance in Open Source Engines}},
+ booktitle = {Proceedings of the 5\textsuperscript{th} {IEEE} International Conference on Service-Oriented Computing and Applications {(SOCA'12)}, Taipei, Taiwan},
+ year = {2012},
+ pages = {237--244},
+ month = dec,
+ organization = {IEEE},
+ publisher = {Institute of Electrical {\&} Electronics Engineers ({IEEE})},
+ doi = {10.1109/SOCA.2012.6449467},
+ file = {:Harrer2012BPELconformancein.pdf:PDF},
+}
+
+ at InProceedings{KolbLenhardWirtz2012,
+ author = {Stefan Kolb and J\"org Lenhard and Guido Wirtz},
+ title = {{Bridging the Heterogeneity of Orchestrations - A Petri Net-based Integration of BPEL and Windows Workflow}},
+ booktitle = {Proceedings of the 5\textsuperscript{th} {IEEE} International Conference on Service-Oriented Computing and Applications {(SOCA'12)}, Taipei, Taiwan},
+ year = {2012},
+ pages = {1--8},
+ month = dec,
+ organization = {IEEE},
+ file = {:Kolb2012BridgingHeterogeneityOrchestrations.pdf:PDF},
+}
+
+ at Article{SchoenbergerSchwalbWirtz2012,
+ author = {Andreas Sch\"onberger and Johannes Schwalb and Guido Wirtz},
+ title = {{Interoperability and Functionality of WS-* Implementations}},
+ journal = {International Journal of Web Services Research},
+ year = {2012},
+ volume = {9},
+ number = {3},
+ pages = {1--22},
+}
+
+ at TechReport{Lenhard2011,
+ author = {J\"org Lenhard},
+ title = {{A Pattern-based Analysis of WS-BPEL and Windows Workflow}},
+ institution = {Otto-Friedrich Universit\"at Bamberg},
+ year = {2011},
+ type = {Bamberger Beitr\"age zur Wirtschaftsinformatik und Angewandten Informatik,},
+ number = {no. 88},
+ month = mar,
+}
+
+ at InProceedings{GeigerSchoenbergerWirtz2011,
+ author = {Matthias Geiger and Andreas Sch\"onberger and Guido Wirtz},
+ title = {{A} {P}roposal for {C}hecking the {C}onformance of eb{BP}-{ST} {C}horeographies and {WS}-{BPEL} {O}rchestrations},
+ booktitle = {Proceedings of the 3rd Central-European Workshop on Services and their Composition (ZEUS), Karlsruhe, Germany, February 21-22, 2011},
+ year = {2011},
+ series = {CEUR Workshop Proceedings},
+ pages = {24--25},
+ month = {Feb},
+ publisher = {CEUR-WS.org},
+ file = {:Geiger2011ProposalCheckingConformance.pdf:PDF},
+}
+
+ at InProceedings{LenhardSchoenbergerWirtz2011,
+ author = {J\"org Lenhard and Andreas Sch\"onberger and Guido Wirtz},
+ title = {{Edit Distance-Based Pattern Support Assessment of Orchestration Languages}},
+ booktitle = {On the Move 2011 Confederated International Conferences: CoopIS, IS, DOA and ODBASE,},
+ year = {2011},
+ address = {Hersonissos},
+ file = {:Lenhard2011EditDistanceBased.pdf:PDF},
+}
+
+ at InProceedings{SchoenbergerSchwalbWirtz2011,
+ author = {Andreas Sch\"onberger and Johannes Schwalb and Guido Wirtz},
+ title = {{Has {WS-I}'s Work Resulted in {WS-*} Interoperability?}},
+ booktitle = {Proceedings of the 9\textsuperscript{th} International Conference on Web Services (ICWS 2011)},
+ year = {2011},
+ address = {Washington, D.C., USA},
+ month = jul,
+ organization = {IEEE},
+ file = {:Schoenberger2011HasWSIs.pdf:PDF},
+ keywords = {Web Services Interoperability, Interoperability Testing, WS-Security, WS-ReliableMessaging},
+}
+
+ at InProceedings{GeigerSchoenbergerWirtz2011a,
+ author = {Matthias Geiger and Andreas Sch\"onberger and Guido Wirtz},
+ title = {{Towards Automated Conformance Checking of {ebBP-ST} Choreographies and Corresponding {WS-BPEL} Based Orchestrations}},
+ booktitle = {Conference on Software Engineering and Knowledge Engineering (SEKE), Miami, Florida, USA},
+ year = {2011},
+ month = {7.-9. July},
+ publisher = {Knowledge Systems Institute},
+ file = {:Geiger2011TowardsAutomatedConformance.pdf:PDF},
+}
+
+ at InProceedings{SchoenbergerWirtz2010,
+ author = {Andreas Sch\"onberger and Guido Wirtz},
+ title = {{Towards Executing ebBP-Reg B2Bi Choreographies}},
+ booktitle = {Proceedings of the 12\textsuperscript{th} IEEE Conference on Commerce and Enterprise Computing (CEC 2010), Shanghai, China},
+ year = {2010},
+ month = nov,
+ organization = {IEEE},
+}
+
+ at InProceedings{SchoenbergerBenkerFritzemeierEtAl2009,
+ author = {Andreas Sch\"onberger and Thomas Benker and Stefan Fritzemeier and Matthias Geiger and Simon Harrer and Tristan Kessner and Johannes Schwalb and Guido Wirtz},
+ title = {{QoS}-{E}nabled {B}usiness-to-{B}usiness {I}ntegration {U}sing {ebBP} to {WS-BPEL} {T}ranslations},
+ booktitle = {Proceedings of the IEEE SCC 2009 International Conference on Services Computing, Bangalore, India},
+ year = {2009},
+ month = {September},
+ organization = {IEEE},
+ doi = {10.1109/scc.2009.56},
+ keywords = {B2Bi, ebXML BPSS, WS-BPEL, Quality of Service, NES, conformance},
+}
+
+ at TechReport{BenkerFritzemeierGeigerEtAl2009,
+ author = {Thomas Benker and Stefan Fritzemeier and Matthias Geiger and Simon Harrer and Tristan Kessner and Johannes Schwalb and Andreas Schoenberger and Guido Wirtz},
+ title = {{QoS-Enabled B2B Integration}},
+ institution = {Otto-Friedrich Universit\"at Bamberg},
+ year = {2009},
+ type = {Bamberger Beitr\"age zur Wirtschaftsinformatik und Angewandten Informatik},
+ number = {no. 80},
+ month = may,
+ file = {:Benker2009.pdf:PDF},
+ series = {Bamberger Beitr{\"a}ge zur Wirtschaftsinformatik und Angewandten Informatik},
+}
+
+ at PhdThesis{Kopp2016,
+ author = {Oliver Kopp},
+ title = {Partner{\"{u}}bergreifende Gesch{\"{a}}ftsprozesse und ihre Realisierung in {BPEL}},
+ school = {University of Stuttgart},
+ year = {2016},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/phd/de/Kopp16},
+ timestamp = {Thu, 17 Mar 2016 00:00:00 +0100},
+ url = {http://nbn-resolving.de/urn:nbn:de:bsz:93-opus-105304},
+}
+
+ at Article{WettingerBreitenbuecherKoppEtAl2016,
+ author = {Johannes Wettinger and Uwe Breitenb{\"{u}}cher and Oliver Kopp and Frank Leymann},
+ title = {Streamlining DevOps automation for Cloud applications using {TOSCA} as standardized metamodel},
+ journal = {Future Generation Comp. Syst.},
+ year = {2016},
+ volume = {56},
+ pages = {317--332},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/journals/fgcs/WettingerBKL16},
+ doi = {10.1016/j.future.2015.07.017},
+ keywords = {rank4},
+ timestamp = {Thu, 31 Mar 2016 01:00:00 +0200},
+}
+
+ at InProceedings{KoppBinzBreitenbuecherEtAl2015,
+ author = {Oliver Kopp and Tobias Binz and Uwe Breitenb{\"{u}}cher and Frank Leymann and Thomas Michelbach},
+ title = {A Domain-Specific Modeling Tool to Model Management Plans for Composite Applications},
+ booktitle = {Proceedings of the 7th Central European Workshop on Services and their Composition, {ZEUS} 2015, Jena, Germany, February 19-20, 2015.},
+ year = {2015},
+ editor = {Thomas S. Heinze and Thomas M. Prinz},
+ volume = {1360},
+ series = {{CEUR} Workshop Proceedings},
+ pages = {51--54},
+ publisher = {CEUR-WS.org},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/zeus/KoppBBLM15},
+ timestamp = {Mon, 30 May 2016 16:28:37 +0200},
+ url = {http://ceur-ws.org/Vol-1360/paper9.pdf},
+}
+
+ at InProceedings{BreitenbuecherBinzKoppEtAl2015,
+ author = {Uwe Breitenb{\"{u}}cher and Tobias Binz and Oliver Kopp and Frank Leymann and Johannes Wettinger},
+ title = {A Modelling Concept to Integrate Declarative and Imperative Cloud Application Provisioning Technologies},
+ booktitle = {{CLOSER} 2015 - Proceedings of the 5th International Conference on Cloud Computing and Services Science, Lisbon, Portugal, 20-22 May, 2015.},
+ year = {2015},
+ editor = {Markus Helfert and Donald Ferguson and V{\'{\i}}ctor M{\'{e}}ndez Mu{\~{n}}oz},
+ pages = {487--496},
+ publisher = {SciTePress},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/closer/BreitenbucherBK15},
+ doi = {10.5220/0005495104870496},
+ keywords = {rank3},
+ timestamp = {Tue, 04 Aug 2015 09:17:34 +0200},
+ url = {http://dx.doi.org/10.5220/0005495104870496},
+}
+
+ at InProceedings{BreitenbuecherHirmerKepesEtAl2015,
+ author = {Uwe Breitenb{\"{u}}cher and Pascal Hirmer and K{\'{a}}lm{\'{a}}n K{\'{e}}pes and Oliver Kopp and Frank Leymann and Matthias Wieland},
+ title = {A situation-aware workflow modelling extension},
+ booktitle = {Proceedings of the 17th International Conference on Information Integration and Web-based Applications {\&} Services, iiWAS 2015, Brussels, Belgium, December 11-13, 2015},
+ year = {2015},
+ editor = {Gabriele Anderst{-}Kotsis and Maria Indrawan{-}Santiago},
+ pages = {64:1--64:7},
+ publisher = {{ACM}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/iiwas/BreitenbucherHK15},
+ doi = {10.1145/2837185.2837248},
+ timestamp = {Mon, 23 May 2016 01:00:00 +0200},
+ url = {http://doi.acm.org/10.1145/2837185.2837248},
+}
+
+ at InProceedings{WagnerKoppLeymann2015,
+ author = {Sebastian Wagner and Oliver Kopp and Frank Leymann},
+ title = {Choreography-based Consolidation of Interacting Processes Having Activity-based Loops},
+ booktitle = {{CLOSER} 2015 - Proceedings of the 5th International Conference on Cloud Computing and Services Science, Lisbon, Portugal, 20-22 May, 2015.},
+ year = {2015},
+ editor = {Markus Helfert and Donald Ferguson and V{\'{\i}}ctor M{\'{e}}ndez Mu{\~{n}}oz},
+ pages = {284--296},
+ publisher = {SciTePress},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/closer/WagnerKL15},
+ doi = {10.5220/0005443802840296},
+ timestamp = {Mon, 15 Feb 2016 00:00:00 +0100},
+ url = {http://dx.doi.org/10.5220/0005443802840296},
+}
+
+ at InProceedings{ThomsenHartmannKlumppEtAl2015,
+ author = {Jessica Thomsen and Niklas Hartmann and Florian Klumpp and Thomas Erge and Michael Falkenthal and Oliver Kopp and Frank Leymann and Sven Stando and Nino Turek and Christoph Schlenzig and Holger Schwarz},
+ title = {Darstellung des Konzeptes - {DMA} Decentralised Market Agent - zur Bew{\"{a}}ltigung zuk{\"{u}}nftiger Herausforderungen in Verteilnetzen},
+ booktitle = {45. Jahrestagung der Gesellschaft f{\"{u}}r Informatik, Informatik 2015, Informatik, Energie und Umwelt, 28. September - 2. Oktober 2015 in Cottbus, Deutschland},
+ year = {2015},
+ editor = {Douglas W. Cunningham and Petra Hofstedt and Klaus Meer and Ingo Schmitt},
+ volume = {246},
+ series = {{LNI}},
+ pages = {53--67},
+ publisher = {{GI}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/gi/ThomsenHKEFKLST15},
+ timestamp = {Tue, 15 Mar 2016 10:22:59 +0100},
+ url = {http://subs.emis.de/LNI/Proceedings/Proceedings246/article75.html},
+}
+
+ at InProceedings{BreitenbuecherBinzKoppEtAl2015a,
+ author = {Uwe Breitenb{\"{u}}cher and Tobias Binz and Oliver Kopp and K{\'{a}}lm{\'{a}}n K{\'{e}}pes and Frank Leymann and Johannes Wettinger},
+ title = {Hybrid {TOSCA} Provisioning Plans: Integrating Declarative and Imperative Cloud Application Provisioning Technologies},
+ booktitle = {Cloud Computing and Services Science - 5th International Conference, {CLOSER} 2015, Lisbon, Portugal, May 20-22, 2015, Revised Selected Papers},
+ year = {2015},
+ editor = {Markus Helfert and V{\'{\i}}ctor M{\'{e}}ndez Mu{\~{n}}oz and Donald Ferguson},
+ volume = {581},
+ series = {Communications in Computer and Information Science},
+ pages = {239--262},
+ publisher = {Springer},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/closer/BreitenbucherBK15a},
+ doi = {10.1007/978-3-319-29582-4_13},
+ timestamp = {Thu, 03 Mar 2016 18:52:40 +0100},
+ url = {http://dx.doi.org/10.1007/978-3-319-29582-4_13},
+}
+
+ at Article{EshuisNortaKoppEtAl2015,
+ author = {Rik Eshuis and Alex Norta and Oliver Kopp and Esa Pitkanen},
+ title = {Service Outsourcing with Process Views},
+ journal = {{IEEE} Trans. Services Computing},
+ year = {2015},
+ volume = {8},
+ number = {1},
+ pages = {136--154},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/journals/tsc/EshuisNKP15},
+ doi = {10.1109/TSC.2013.51},
+ keywords = {rank2},
+ timestamp = {Wed, 09 Mar 2016 00:00:00 +0100},
+ url = {http://dx.doi.org/10.1109/TSC.2013.51},
+}
+
+ at InProceedings{KoppFalkenthalHartmannEtAl2015,
+ author = {Oliver Kopp and Michael Falkenthal and Niklas Hartmann and Frank Leymann and Holger Schwarz and Jessica Thomsen},
+ title = {Towards a Cloud-based Platform Architecture for a Decentralized Market Agent},
+ booktitle = {45. Jahrestagung der Gesellschaft f{\"{u}}r Informatik, Informatik 2015, Informatik, Energie und Umwelt, 28. September - 2. Oktober 2015 in Cottbus, Deutschland},
+ year = {2015},
+ editor = {Douglas W. Cunningham and Petra Hofstedt and Klaus Meer and Ingo Schmitt},
+ volume = {246},
+ series = {{LNI}},
+ pages = {69--80},
+ publisher = {{GI}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/gi/KoppFHLST15},
+ timestamp = {Tue, 15 Mar 2016 10:22:59 +0100},
+ url = {http://subs.emis.de/LNI/Proceedings/Proceedings246/article98.html},
+}
+
+ at InCollection{BinzBreitenbuecherKoppEtAl2014,
+ author = {Tobias Binz and Uwe Breitenb{\"{u}}cher and Oliver Kopp and Frank Leymann},
+ title = {{TOSCA:} Portable Automated Deployment and Management of Cloud Applications},
+ booktitle = {Advanced Web Services},
+ publisher = {Springer},
+ year = {2014},
+ editor = {Athman Bouguettaya and Quan Z. Sheng and Florian Daniel},
+ pages = {527--549},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/books/sp/aws14/BinzBKL14},
+ doi = {10.1007/978-1-4614-7535-4_22},
+ timestamp = {Thu, 16 Apr 2015 19:09:16 +0200},
+ url = {http://dx.doi.org/10.1007/978-1-4614-7535-4_22},
+}
+
+ at InProceedings{WagnerKoppLeymann2014,
+ author = {Sebastian Wagner and Oliver Kopp and Frank Leymann},
+ title = {Choreography-based Consolidation of Multi-instance {BPEL} Processes},
+ booktitle = {{CLOSER} 2014 - Proceedings of the 4th International Conference on Cloud Computing and Services Science, Barcelona, Spain, April 3-5, 2014.},
+ year = {2014},
+ editor = {Markus Helfert and Fr{\'{e}}d{\'{e}}ric Desprez and Donald Ferguson and Frank Leymann and V{\'{\i}}ctor M{\'{e}}ndez Mu{\~{n}}oz},
+ pages = {287--298},
+ publisher = {SciTePress},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/closer/WagnerKL14},
+ doi = {10.5220/0004857902870298},
+ timestamp = {Mon, 15 Feb 2016 00:00:00 +0100},
+ url = {http://dx.doi.org/10.5220/0004857902870298},
+}
+
+ at InProceedings{BreitenbuecherBinzKepesEtAl2014,
+ author = {Uwe Breitenb{\"{u}}cher and Tobias Binz and Kalman Kepes and Oliver Kopp and Frank Leymann and Johannes Wettinger},
+ title = {Combining Declarative and Imperative Cloud Application Provisioning Based on {TOSCA}},
+ booktitle = {2014 {IEEE} International Conference on Cloud Engineering, Boston, MA, USA, March 11-14, 2014},
+ year = {2014},
+ pages = {87--96},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/ic2e/BreitenbucherBKKLW14},
+ doi = {10.1109/IC2E.2014.56},
+ timestamp = {Tue, 28 Apr 2015 17:32:17 +0200},
+ url = {http://dx.doi.org/10.1109/IC2E.2014.56},
+}
+
+ at InProceedings{BreitenbuecherBinzKoppEtAl2014,
+ author = {Uwe Breitenb{\"{u}}cher and Tobias Binz and Oliver Kopp and Frank Leymann and Matthias Wieland},
+ title = {Context-aware Cloud Application Management},
+ booktitle = {{CLOSER} 2014 - Proceedings of the 4th International Conference on Cloud Computing and Services Science, Barcelona, Spain, April 3-5, 2014.},
+ year = {2014},
+ editor = {Markus Helfert and Fr{\'{e}}d{\'{e}}ric Desprez and Donald Ferguson and Frank Leymann and V{\'{\i}}ctor M{\'{e}}ndez Mu{\~{n}}oz},
+ pages = {499--509},
+ publisher = {SciTePress},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/closer/BreitenbucherBKLW14},
+ doi = {10.5220/0004949204990509},
+ timestamp = {Fri, 12 Sep 2014 14:58:05 +0200},
+ url = {http://dx.doi.org/10.5220/0004949204990509},
+}
+
+ at InProceedings{BreitenbuecherBinzKoppEtAl2014a,
+ author = {Uwe Breitenb{\"{u}}cher and Tobias Binz and Oliver Kopp and Frank Leymann and Matthias Wieland},
+ title = {Context-Aware Provisioning and Management of Cloud Applications},
+ booktitle = {Cloud Computing and Services Sciences - International Conference in Cloud Computing and Services Sciences, {CLOSER} 2014, Barcelona Spain, April 3-5, 2014, Revised Selected Papers},
+ year = {2014},
+ editor = {Markus Helfert and Fr{\'{e}}d{\'{e}}ric Desprez and Donald Ferguson and Frank Leymann and V{\'{\i}}ctor M{\'{e}}ndez Mu{\~{n}}oz},
+ volume = {512},
+ series = {Communications in Computer and Information Science},
+ pages = {151--168},
+ publisher = {Springer},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/closer/BreitenbucherBK14},
+ doi = {10.1007/978-3-319-25414-2_10},
+ timestamp = {Fri, 06 May 2016 14:21:50 +0200},
+ url = {http://dx.doi.org/10.1007/978-3-319-25414-2_10},
+}
+
+ at Article{BinzBreitenbuecherKoppEtAl2014a,
+ author = {Tobias Binz and Uwe Breitenb{\"{u}}cher and Oliver Kopp and Frank Leymann},
+ title = {Migration of enterprise applications to the cloud},
+ journal = {it - Information Technology},
+ year = {2014},
+ volume = {56},
+ number = {3},
+ pages = {106--111},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/journals/it/BinzBKL14},
+ doi = {10.1515/itit-2013-1032},
+ timestamp = {Tue, 17 Jun 2014 01:00:00 +0200},
+ url = {http://dx.doi.org/10.1515/itit-2013-1032},
+}
+
+ at Article{WettingerBinzBreitenbuecherEtAl2014,
+ author = {Johannes Wettinger and Tobias Binz and Uwe Breitenb{\"{u}}cher and Oliver Kopp and Frank Leymann},
+ title = {Streamlining Cloud Management Automation by Unifying the Invocation of Scripts and Services Based on {TOSCA}},
+ journal = {{IJOCI}},
+ year = {2014},
+ volume = {4},
+ number = {2},
+ pages = {45--63},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/journals/ijoci/WettingerBBKL14},
+ doi = {10.4018/ijoci.2014040103},
+ timestamp = {Fri, 16 Jan 2015 00:00:00 +0100},
+ url = {http://dx.doi.org/10.4018/ijoci.2014040103},
+}
+
+ at InProceedings{SungurKoppLeymann2014,
+ author = {C. Timurhan Sungur and Oliver Kopp and Frank Leymann},
+ title = {Supporting Informal Processes},
+ booktitle = {Proceedings of the 6th Central-European Workshop on Services and their Composition, {ZEUS} 2014, Potsdam, Germany, February 20-21, 2014.},
+ year = {2014},
+ editor = {Nico Herzberg and Matthias Kunze},
+ volume = {1140},
+ series = {{CEUR} Workshop Proceedings},
+ pages = {49--56},
+ publisher = {CEUR-WS.org},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/zeus/SungurKL14},
+ timestamp = {Mon, 30 May 2016 16:28:37 +0200},
+ url = {http://ceur-ws.org/Vol-1140/paper8.pdf},
+}
+
+ at InProceedings{WettingerBinzBreitenbuecherEtAl2014a,
+ author = {Johannes Wettinger and Tobias Binz and Uwe Breitenb{\"{u}}cher and Oliver Kopp and Frank Leymann and Michael Zimmermann},
+ title = {Unified Invocation of Scripts and Services for Provisioning, Deployment, and Management of Cloud Applications Based on {TOSCA}},
+ booktitle = {{CLOSER} 2014 - Proceedings of the 4th International Conference on Cloud Computing and Services Science, Barcelona, Spain, April 3-5, 2014.},
+ year = {2014},
+ editor = {Markus Helfert and Fr{\'{e}}d{\'{e}}ric Desprez and Donald Ferguson and Frank Leymann and V{\'{\i}}ctor M{\'{e}}ndez Mu{\~{n}}oz},
+ pages = {559--568},
+ publisher = {SciTePress},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/closer/WettingerBBKLZ14},
+ doi = {10.5220/0004859005590568},
+ timestamp = {Fri, 12 Sep 2014 14:58:05 +0200},
+ url = {http://dx.doi.org/10.5220/0004859005590568},
+}
+
+ at InProceedings{BreitenbuecherBinzKoppEtAl2014b,
+ author = {Uwe Breitenb{\"{u}}cher and Tobias Binz and Oliver Kopp and Frank Leymann},
+ title = {Vinothek - {A} Self-Service Portal for {TOSCA}},
+ booktitle = {Proceedings of the 6th Central-European Workshop on Services and their Composition, {ZEUS} 2014, Potsdam, Germany, February 20-21, 2014.},
+ year = {2014},
+ editor = {Nico Herzberg and Matthias Kunze},
+ volume = {1140},
+ series = {{CEUR} Workshop Proceedings},
+ pages = {69--72},
+ publisher = {CEUR-WS.org},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/zeus/BreitenbucherBKL14},
+ timestamp = {Mon, 30 May 2016 16:28:37 +0200},
+ url = {http://ceur-ws.org/Vol-1140/paper11.pdf},
+}
+
+ at InProceedings{BinzBreitenbuecherKoppEtAl2013,
+ author = {Tobias Binz and Uwe Breitenb{\"{u}}cher and Oliver Kopp and Frank Leymann},
+ title = {Automated Discovery and Maintenance of Enterprise Topology Graphs},
+ booktitle = {2013 {IEEE} 6th International Conference on Service-Oriented Computing and Applications, Koloa, HI, USA, December 16-18, 2013},
+ year = {2013},
+ pages = {126--134},
+ publisher = {{IEEE} Computer Society},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/soca/BinzBKL13},
+ doi = {10.1109/SOCA.2013.29},
+ timestamp = {Fri, 10 Jul 2015 14:02:01 +0200},
+ url = {http://dx.doi.org/10.1109/SOCA.2013.29},
+}
+
+ at InProceedings{CardosoBinzBreitenbuecherEtAl2013,
+ author = {Jorge Cardoso and Tobias Binz and Uwe Breitenb{\"{u}}cher and Oliver Kopp and Frank Leymann},
+ title = {Cloud Computing Automation: Integrating {USDL} and {TOSCA}},
+ booktitle = {Advanced Information Systems Engineering - 25th International Conference, CAiSE 2013, Valencia, Spain, June 17-21, 2013. Proceedings},
+ year = {2013},
+ editor = {Camille Salinesi and Moira C. Norrie and Oscar Pastor},
+ volume = {7908},
+ series = {Lecture Notes in Computer Science},
+ pages = {1--16},
+ publisher = {Springer},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/caise/CardosoBBKL13},
+ doi = {10.1007/978-3-642-38709-8_1},
+ timestamp = {Tue, 25 Jun 2013 10:22:54 +0200},
+ url = {http://dx.doi.org/10.1007/978-3-642-38709-8_1},
+}
+
+ at InProceedings{WagnerKoppLeymann2013,
+ author = {Sebastian Wagner and Oliver Kopp and Frank Leymann},
+ title = {Consolidation of Interacting {BPEL} Process Models with Fault Handlers},
+ booktitle = {Proceedings of the 5\({}^{\mbox{th}}\) Central-European Workshop on Services and their Composition, Rostock, Germany, February 21-22, 2013},
+ year = {2013},
+ editor = {Oliver Kopp and Niels Lohmann},
+ volume = {1029},
+ series = {{CEUR} Workshop Proceedings},
+ pages = {9--16},
+ publisher = {CEUR-WS.org},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/zeus/WagnerKL13},
+ timestamp = {Mon, 30 May 2016 16:28:37 +0200},
+ url = {http://ceur-ws.org/Vol-1029/paper2.pdf},
+}
+
+ at InProceedings{SungurSpiessOertelEtAl2013,
+ author = {C. Timurhan Sungur and Patrik Spiess and Nina Oertel and Oliver Kopp},
+ title = {Extending {BPMN} for Wireless Sensor Networks},
+ booktitle = {{IEEE} 15th Conference on Business Informatics, {CBI} 2013, Vienna, Austria, July 15-18, 2013},
+ year = {2013},
+ pages = {109--116},
+ publisher = {{IEEE} Computer Society},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/wecwis/SungurSOK13},
+ doi = {10.1109/CBI.2013.24},
+ timestamp = {Wed, 11 May 2016 10:54:36 +0200},
+ url = {http://dx.doi.org/10.1109/CBI.2013.24},
+}
+
+ at InProceedings{BinzBreitenbuecherKoppEtAl2013a,
+ author = {Tobias Binz and Uwe Breitenb{\"{u}}cher and Oliver Kopp and Frank Leymann and Andreas Wei{\ss}},
+ title = {Improve Resource-sharing through Functionality-preserving Merge of Cloud Application Topologies},
+ booktitle = {{CLOSER} 2013 - Proceedings of the 3rd International Conference on Cloud Computing and Services Science, Aachen, Germany, 8-10 May, 2013},
+ year = {2013},
+ editor = {Fr{\'{e}}d{\'{e}}ric Desprez and Donald Ferguson and Ethan Hadar and Frank Leymann and Matthias Jarke and Markus Helfert},
+ pages = {96--103},
+ publisher = {SciTePress},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/closer/BinzBKLW13},
+ timestamp = {Tue, 01 Oct 2013 14:38:38 +0200},
+}
+
+ at InProceedings{WettingerKoppLeymann2013,
+ author = {Johannes Wettinger and Oliver Kopp and Frank Leymann},
+ title = {Improving Portability of Cloud Service Topology Models Relying on Script-Based Deployment},
+ booktitle = {Proceedings of the 5\({}^{\mbox{th}}\) Central-European Workshop on Services and their Composition, Rostock, Germany, February 21-22, 2013},
+ year = {2013},
+ editor = {Oliver Kopp and Niels Lohmann},
+ volume = {1029},
+ series = {{CEUR} Workshop Proceedings},
+ pages = {24--27},
+ publisher = {CEUR-WS.org},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/zeus/WettingerKL13},
+ timestamp = {Mon, 30 May 2016 16:28:37 +0200},
+ url = {http://ceur-ws.org/Vol-1029/paper5.pdf},
+}
+
+ at InProceedings{BreitenbuecherBinzKoppEtAl2013,
+ author = {Uwe Breitenb{\"{u}}cher and Tobias Binz and Oliver Kopp and Frank Leymann and Johannes Wettinger},
+ title = {Integrated Cloud Application Provisioning: Interconnecting Service-Centric and Script-Centric Management Technologies},
+ booktitle = {On the Move to Meaningful Internet Systems: {OTM} 2013 Conferences - Confederated International Conferences: CoopIS, DOA-Trusted Cloud, and {ODBASE} 2013, Graz, Austria, September 9-13, 2013. Proceedings},
+ year = {2013},
+ editor = {Robert Meersman and Herv{\'{e}} Panetto and Tharam S. Dillon and Johann Eder and Zohra Bellahsene and Norbert Ritter and Pieter De Leenheer and Dejing Dou},
+ volume = {8185},
+ series = {Lecture Notes in Computer Science},
+ pages = {130--148},
+ publisher = {Springer},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/otm/BreitenbucherBKLW13},
+ doi = {10.1007/978-3-642-41030-7_9},
+ timestamp = {Sun, 23 Mar 2014 11:49:46 +0100},
+ url = {http://dx.doi.org/10.1007/978-3-642-41030-7_9},
+}
+
+ at InProceedings{BinzBreitenbuecherHauptEtAl2013,
+ author = {Tobias Binz and Uwe Breitenb{\"{u}}cher and Florian Haupt and Oliver Kopp and Frank Leymann and Alexander Nowak and Sebastian Wagner},
+ title = {OpenTOSCA - {A} Runtime for TOSCA-Based Cloud Applications},
+ booktitle = {Service-Oriented Computing - 11th International Conference, {ICSOC} 2013, Berlin, Germany, December 2-5, 2013, Proceedings},
+ year = {2013},
+ editor = {Samik Basu and Cesare Pautasso and Liang Zhang and Xiang Fu},
+ volume = {8274},
+ series = {Lecture Notes in Computer Science},
+ pages = {692--695},
+ publisher = {Springer},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/icsoc/BinzBHKLNW13},
+ doi = {10.1007/978-3-642-45005-1_62},
+ timestamp = {Mon, 15 Feb 2016 00:00:00 +0100},
+ url = {http://dx.doi.org/10.1007/978-3-642-45005-1_62},
+}
+
+ at InProceedings{BreitenbuecherBinzKoppEtAl2013a,
+ author = {Uwe Breitenb{\"{u}}cher and Tobias Binz and Oliver Kopp and Frank Leymann},
+ title = {Pattern-based Runtime Management of Composite Cloud Applications},
+ booktitle = {{CLOSER} 2013 - Proceedings of the 3rd International Conference on Cloud Computing and Services Science, Aachen, Germany, 8-10 May, 2013},
+ year = {2013},
+ editor = {Fr{\'{e}}d{\'{e}}ric Desprez and Donald Ferguson and Ethan Hadar and Frank Leymann and Matthias Jarke and Markus Helfert},
+ pages = {475--482},
+ publisher = {SciTePress},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/closer/BreitenbucherBKL13},
+ timestamp = {Tue, 01 Oct 2013 14:38:38 +0200},
+}
+
+ at InProceedings{WagnerRollerKoppEtAl2013,
+ author = {Sebastian Wagner and Dieter Roller and Oliver Kopp and Tobias Unger and Frank Leymann},
+ title = {Performance Optimizations for Interacting Business Processes},
+ booktitle = {2013 {IEEE} International Conference on Cloud Engineering, {IC2E} 2013, San Francisco, CA, USA, March 25-27, 2013},
+ year = {2013},
+ pages = {210--216},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/ic2e/WagnerRKUL13},
+ doi = {10.1109/IC2E.2013.34},
+ timestamp = {Mon, 15 Feb 2016 00:00:00 +0100},
+ url = {http://dx.doi.org/10.1109/IC2E.2013.34},
+}
+
+ at InProceedings{WaizeneggerWielandBinzEtAl2013,
+ author = {Tim Waizenegger and Matthias Wieland and Tobias Binz and Uwe Breitenb{\"{u}}cher and Florian Haupt and Oliver Kopp and Frank Leymann and Bernhard Mitschang and Alexander Nowak and Sebastian Wagner},
+ title = {Policy4TOSCA: {A} Policy-Aware Cloud Service Provisioning Approach to Enable Secure Cloud Computing},
+ booktitle = {On the Move to Meaningful Internet Systems: {OTM} 2013 Conferences - Confederated International Conferences: CoopIS, DOA-Trusted Cloud, and {ODBASE} 2013, Graz, Austria, September 9-13, 2013. Proceedings},
+ year = {2013},
+ editor = {Robert Meersman and Herv{\'{e}} Panetto and Tharam S. Dillon and Johann Eder and Zohra Bellahsene and Norbert Ritter and Pieter De Leenheer and Dejing Dou},
+ volume = {8185},
+ series = {Lecture Notes in Computer Science},
+ pages = {360--376},
+ publisher = {Springer},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/otm/WaizeneggerWBBHKLMNW13},
+ doi = {10.1007/978-3-642-41030-7_26},
+ timestamp = {Mon, 15 Feb 2016 00:00:00 +0100},
+ url = {http://dx.doi.org/10.1007/978-3-642-41030-7_26},
+}
+
+ at Proceedings{KoppLohmann2013,
+ title = {Proceedings of the 5\({}^{\mbox{th}}\) Central-European Workshop on Services and their Composition, Rostock, Germany, February 21-22, 2013},
+ year = {2013},
+ editor = {Oliver Kopp and Niels Lohmann},
+ volume = {1029},
+ series = {{CEUR} Workshop Proceedings},
+ publisher = {CEUR-WS.org},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/zeus/2013},
+ timestamp = {Mon, 30 May 2016 01:00:00 +0200},
+ url = {http://ceur-ws.org/Vol-1029},
+}
+
+ at InProceedings{DemontBreitenbuecherKoppEtAl2013,
+ author = {Christoph Demont and Uwe Breitenb{\"{u}}cher and Oliver Kopp and Frank Leymann and Johannes Wettinger},
+ title = {Towards Integrating {TOSCA} and {ITIL}},
+ booktitle = {Proceedings of the 5\({}^{\mbox{th}}\) Central-European Workshop on Services and their Composition, Rostock, Germany, February 21-22, 2013},
+ year = {2013},
+ editor = {Oliver Kopp and Niels Lohmann},
+ volume = {1029},
+ series = {{CEUR} Workshop Proceedings},
+ pages = {28--31},
+ publisher = {CEUR-WS.org},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/zeus/DemontBKLW13},
+ timestamp = {Mon, 30 May 2016 16:28:37 +0200},
+ url = {http://ceur-ws.org/Vol-1029/paper6.pdf},
+}
+
+ at InProceedings{KoppBinzBreitenbuecherEtAl2013,
+ author = {Oliver Kopp and Tobias Binz and Uwe Breitenb{\"{u}}cher and Frank Leymann},
+ title = {Winery - {A} Modeling Tool for TOSCA-Based Cloud Applications},
+ booktitle = {Service-Oriented Computing - 11th International Conference, {ICSOC} 2013, Berlin, Germany, December 2-5, 2013, Proceedings},
+ year = {2013},
+ editor = {Samik Basu and Cesare Pautasso and Liang Zhang and Xiang Fu},
+ volume = {8274},
+ series = {Lecture Notes in Computer Science},
+ pages = {700--704},
+ publisher = {Springer},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/icsoc/KoppBBL13},
+ doi = {10.1007/978-3-642-45005-1_64},
+ timestamp = {Thu, 12 Dec 2013 14:25:10 +0100},
+ url = {http://dx.doi.org/10.1007/978-3-642-45005-1_64},
+}
+
+ at InProceedings{KoppBinzBreitenbuecherEtAl2012,
+ author = {Oliver Kopp and Tobias Binz and Uwe Breitenb{\"{u}}cher and Frank Leymann},
+ title = {{BPMN4TOSCA:} {A} Domain-Specific Language to Model Management Plans for Composite Applications},
+ booktitle = {Business Process Model and Notation - 4th International Workshop, {BPMN} 2012, Vienna, Austria, September 12-13, 2012. Proceedings},
+ year = {2012},
+ editor = {Jan Mendling and Matthias Weidlich},
+ volume = {125},
+ series = {Lecture Notes in Business Information Processing},
+ pages = {38--52},
+ publisher = {Springer},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/bpmn/KoppBBL12},
+ doi = {10.1007/978-3-642-33155-8_4},
+ timestamp = {Tue, 18 Sep 2012 15:54:08 +0200},
+ url = {http://dx.doi.org/10.1007/978-3-642-33155-8_4},
+}
+
+ at InProceedings{StrauchBreitenbuecherKoppEtAl2012,
+ author = {Steve Strauch and Uwe Breitenb{\"{u}}cher and Oliver Kopp and Frank Leymann and Tobias Unger},
+ title = {Cloud Data Patterns for Confidentiality},
+ booktitle = {{CLOSER} 2012 - Proceedings of the 2nd International Conference on Cloud Computing and Services Science, Porto, Portugal, 18 - 21 April, 2012},
+ year = {2012},
+ editor = {Frank Leymann and Ivan I. Ivanov and Marten van Sinderen and Tony Shan},
+ pages = {387--394},
+ publisher = {SciTePress},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/closer/StrauchBKLU12},
+ timestamp = {Thu, 03 Mar 2016 19:04:32 +0100},
+}
+
+ at InProceedings{StrauchAndrikopoulosBreitenbuecherEtAl2012,
+ author = {Steve Strauch and Vasilios Andrikopoulos and Uwe Breitenb{\"{u}}cher and Oliver Kopp and Frank Leyrnann},
+ title = {Non-functional data layer patterns for Cloud applications},
+ booktitle = {4th {IEEE} International Conference on Cloud Computing Technology and Science Proceedings, CloudCom 2012, Taipei, Taiwan, December 3-6, 2012},
+ year = {2012},
+ pages = {601--605},
+ publisher = {{IEEE} Computer Society},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/cloudcom/StrauchABKL12},
+ doi = {10.1109/CloudCom.2012.6427478},
+ timestamp = {Tue, 02 Jun 2015 18:34:42 +0200},
+ url = {http://dx.doi.org/10.1109/CloudCom.2012.6427478},
+}
+
+ at Article{NowakBinzFehlingEtAl2012,
+ author = {Alexander Nowak and Tobias Binz and Christoph Fehling and Oliver Kopp and Frank Leymann and Sebastian Wagner},
+ title = {Pattern-driven green adaptation of process-based applications and their runtime infrastructure},
+ journal = {Computing},
+ year = {2012},
+ volume = {94},
+ number = {6},
+ pages = {463--487},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/journals/computing/NowakBFKLW12},
+ doi = {10.1007/s00607-012-0188-x},
+ timestamp = {Mon, 15 Feb 2016 00:00:00 +0100},
+ url = {http://dx.doi.org/10.1007/s00607-012-0188-x},
+}
+
+ at Proceedings{SchoenbergerKoppLohmann2012,
+ title = {Proceedings of the 4\({}^{\mbox{th}}\) Central-European Workshop on Services and their Composition, ZEUS-2012, Bamberg, Germany, February 23-24, 2012},
+ year = {2012},
+ editor = {Andreas Sch{\"{o}}nberger and Oliver Kopp and Niels Lohmann},
+ volume = {847},
+ series = {{CEUR} Workshop Proceedings},
+ publisher = {CEUR-WS.org},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/zeus/2012},
+ timestamp = {Mon, 30 May 2016 01:00:00 +0200},
+ url = {http://ceur-ws.org/Vol-847},
+}
+
+ at InProceedings{ReiterBreitenbuecherKoppEtAl2012,
+ author = {Michael Reiter and Uwe Breitenb{\"{u}}cher and Oliver Kopp and Dimka Karastoyanova},
+ title = {Quality of data driven simulation workflows},
+ booktitle = {8th {IEEE} International Conference on E-Science, e-Science 2012, Chicago, IL, USA, October 8-12, 2012},
+ year = {2012},
+ pages = {1--8},
+ publisher = {{IEEE} Computer Society},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/eScience/ReiterBKK12},
+ doi = {10.1109/eScience.2012.6404417},
+ timestamp = {Fri, 07 Nov 2014 00:00:00 +0100},
+ url = {http://dx.doi.org/10.1109/eScience.2012.6404417},
+}
+
+ at InProceedings{BreitenbuecherKoppLeymannEtAl2012,
+ author = {Uwe Breitenb{\"{u}}cher and Oliver Kopp and Frank Leymann and Michael Reiter and Dieter Roller and Tobias Unger},
+ title = {Six Strategies for Building High Performance {SOA} Applications},
+ booktitle = {Proceedings of the 4\({}^{\mbox{th}}\) Central-European Workshop on Services and their Composition, ZEUS-2012, Bamberg, Germany, February 23-24, 2012},
+ year = {2012},
+ editor = {Andreas Sch{\"{o}}nberger and Oliver Kopp and Niels Lohmann},
+ volume = {847},
+ series = {{CEUR} Workshop Proceedings},
+ pages = {120--127},
+ publisher = {CEUR-WS.org},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/zeus/BreitenbucherKLRRU12},
+ timestamp = {Mon, 30 May 2016 16:43:12 +0200},
+ url = {http://ceur-ws.org/Vol-847/paper16.pdf},
+}
+
+ at InProceedings{WagnerKoppLeymann2012,
+ author = {Sebastian Wagner and Oliver Kopp and Frank Leymann},
+ title = {Towards Verification of Process Merge Patterns with Allen's Interval Algebra},
+ booktitle = {Proceedings of the 4\({}^{\mbox{th}}\) Central-European Workshop on Services and their Composition, ZEUS-2012, Bamberg, Germany, February 23-24, 2012},
+ year = {2012},
+ editor = {Andreas Sch{\"{o}}nberger and Oliver Kopp and Niels Lohmann},
+ volume = {847},
+ series = {{CEUR} Workshop Proceedings},
+ pages = {81--88},
+ publisher = {CEUR-WS.org},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/zeus/WagnerKL12},
+ timestamp = {Mon, 30 May 2016 16:43:12 +0200},
+ url = {http://ceur-ws.org/Vol-847/paper11.pdf},
+}
+
+ at InProceedings{BreitenbuecherBinzKoppEtAl2012,
+ author = {Uwe Breitenb{\"{u}}cher and Tobias Binz and Oliver Kopp and Frank Leymann and David Schumm},
+ title = {Vino4TOSCA: {A} Visual Notation for Application Topologies Based on {TOSCA}},
+ booktitle = {On the Move to Meaningful Internet Systems: {OTM} 2012, Confederated International Conferences: CoopIS, DOA-SVI, and {ODBASE} 2012, Rome, Italy, September 10-14, 2012. Proceedings, Part {I}},
+ year = {2012},
+ editor = {Robert Meersman and Herv{\'{e}} Panetto and Tharam S. Dillon and Stefanie Rinderle{-}Ma and Peter Dadam and Xiaofang Zhou and Siani Pearson and Alois Ferscha and Sonia Bergamaschi and Isabel F. Cruz},
+ volume = {7565},
+ series = {Lecture Notes in Computer Science},
+ pages = {416--424},
+ publisher = {Springer},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/otm/BreitenbucherBKLS12},
+ doi = {10.1007/978-3-642-33606-5_25},
+ timestamp = {Sun, 27 Jan 2013 17:45:33 +0100},
+ url = {http://dx.doi.org/10.1007/978-3-642-33606-5_25},
+}
+
+ at InProceedings{StrauchKoppLeymannEtAl2011,
+ author = {Steve Strauch and Oliver Kopp and Frank Leymann and Tobias Unger},
+ title = {A Taxonomy for Cloud Data Hosting Solutions},
+ booktitle = {{IEEE} Ninth International Conference on Dependable, Autonomic and Secure Computing, {DASC} 2011, 12-14 December 2011, Sydney, Australia},
+ year = {2011},
+ pages = {577--584},
+ publisher = {{IEEE} Computer Society},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/dasc/StrauchKLU11},
+ doi = {10.1109/DASC.2011.106},
+ timestamp = {Tue, 18 Aug 2015 20:06:19 +0200},
+ url = {http://dx.doi.org/10.1109/DASC.2011.106},
+}
+
+ at InProceedings{KoppLeymannWagner2011,
+ author = {Oliver Kopp and Frank Leymann and Sebastian Wagner},
+ title = {Modeling Choreographies: {BPMN} 2.0 versus BPEL-based Approaches},
+ booktitle = {Enterprise Modelling and Information Systems Architectures: Proceedings of the 4th International Workshop on Enterprise Modelling and Information Systems Architectures, {EMISA} 2011, Hamburg, Germany, September 22-23, 2011},
+ year = {2011},
+ editor = {Markus N{\"{u}}ttgens and Oliver Thomas and Barbara Weber},
+ volume = {190},
+ series = {{LNI}},
+ pages = {225--230},
+ publisher = {{GI}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/emisa/KoppLW11},
+ timestamp = {Tue, 15 Mar 2016 11:26:11 +0100},
+ url = {http://subs.emis.de/LNI/Proceedings/Proceedings190/article6448.html},
+}
+
+ at InProceedings{KoppLeymannSchummEtAl2011,
+ author = {Oliver Kopp and Frank Leymann and David Schumm and Tobias Unger},
+ title = {On {BPMN} Process Fragment Auto-Completion},
+ booktitle = {3rd Central-European Workshop on Services and their Composition, Services und ihre Komposition, {ZEUS} 2011, Karlsruhe, Germany, February 21-22, 2011. Proceedings},
+ year = {2011},
+ editor = {Daniel Eichhorn and Agnes Koschmider and Huayu Zhang},
+ volume = {705},
+ series = {{CEUR} Workshop Proceedings},
+ pages = {58--64},
+ publisher = {CEUR-WS.org},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/zeus/KoppLSU11},
+ timestamp = {Mon, 30 May 2016 16:43:12 +0200},
+ url = {http://ceur-ws.org/Vol-705/paper8.pdf},
+}
+
+ at InProceedings{KoppLeymannUngerEtAl2011,
+ author = {Oliver Kopp and Frank Leymann and Tobias Unger and Sebastian Wagner},
+ title = {Towards The Essential Flow Model},
+ booktitle = {3rd Central-European Workshop on Services and their Composition, Services und ihre Komposition, {ZEUS} 2011, Karlsruhe, Germany, February 21-22, 2011. Proceedings},
+ year = {2011},
+ editor = {Daniel Eichhorn and Agnes Koschmider and Huayu Zhang},
+ volume = {705},
+ series = {{CEUR} Workshop Proceedings},
+ pages = {26--33},
+ publisher = {CEUR-WS.org},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/zeus/KoppLUW11},
+ timestamp = {Mon, 30 May 2016 16:43:12 +0200},
+ url = {http://ceur-ws.org/Vol-705/paper4.pdf},
+}
+
+ at InProceedings{WetzsteinKarastoyanovaKoppEtAl2010,
+ author = {Branimir Wetzstein and Dimka Karastoyanova and Oliver Kopp and Frank Leymann and Daniel Zwink},
+ title = {Cross-organizational process monitoring based on service choreographies},
+ booktitle = {Proceedings of the 2010 {ACM} Symposium on Applied Computing (SAC), Sierre, Switzerland, March 22-26, 2010},
+ year = {2010},
+ editor = {Sung Y. Shin and Sascha Ossowski and Michael Schumacher and Mathew J. Palakal and Chih{-}Cheng Hung},
+ pages = {2485--2490},
+ publisher = {{ACM}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/sac/WetzsteinKKLZ10},
+ doi = {10.1145/1774088.1774601},
+ timestamp = {Tue, 03 Nov 2015 12:36:38 +0100},
+ url = {http://doi.acm.org/10.1145/1774088.1774601},
+}
+
+ at InProceedings{KoppGoerlachLeymann2010,
+ author = {Oliver Kopp and Katharina G{\"{o}}rlach and Frank Leymann},
+ title = {Extending choreography spheres to improve simulations},
+ booktitle = {iiWAS'2010 - The 12th International Conference on Information Integration and Web-based Applications and Services, 8-10 November 2010, Paris, France},
+ year = {2010},
+ editor = {Gabriele Kotsis and David Taniar and Eric Pardede and Imad Saleh and Ismail Khalil},
+ pages = {696--699},
+ publisher = {{ACM}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/iiwas/KoppGL10},
+ doi = {10.1145/1967486.1967598},
+ timestamp = {Tue, 03 May 2011 20:12:09 +0200},
+ url = {http://doi.acm.org/10.1145/1967486.1967598},
+}
+
+ at InProceedings{KoppLeymannWutke2010,
+ author = {Oliver Kopp and Frank Leymann and Daniel Wutke},
+ title = {Fault Handling in the Web Service Stack},
+ booktitle = {Service-Oriented Computing - 8th International Conference, {ICSOC} 2010, San Francisco, CA, USA, December 7-10, 2010. Proceedings},
+ year = {2010},
+ editor = {Paul P. Maglio and Mathias Weske and Jian Yang and Marcelo Fantinato},
+ volume = {6470},
+ series = {Lecture Notes in Computer Science},
+ pages = {303--317},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/icsoc/KoppLW10},
+ doi = {10.1007/978-3-642-17358-5_21},
+ timestamp = {Mon, 09 May 2011 13:28:38 +0200},
+ url = {http://dx.doi.org/10.1007/978-3-642-17358-5_21},
+}
+
+ at InProceedings{KoppEnglerLessenEtAl2010,
+ author = {Oliver Kopp and Lasse Engler and Tammo van Lessen and Frank Leymann and J{\"{o}}rg Nitzsche},
+ title = {Interaction Choreography Models in {BPEL:} Choreographies on the Enterprise Service Bus},
+ booktitle = {Subject-Oriented Business Process Management - Second International Conference, {S-BPM} {ONE} 2010, Karlsruhe, Germany, October 14, 2010. Selected Papers},
+ year = {2010},
+ editor = {Albert Fleischmann and Werner Schmidt and Robert Singer and Detlef Seese},
+ volume = {138},
+ series = {Communications in Computer and Information Science},
+ pages = {36--53},
+ publisher = {Springer},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/s-bpm-one/KoppELLN10},
+ doi = {10.1007/978-3-642-23135-3_3},
+ timestamp = {Sat, 05 May 2012 12:36:21 +0200},
+ url = {http://dx.doi.org/10.1007/978-3-642-23135-3_3},
+}
+
+ at InProceedings{KoppLeymannWu2010,
+ author = {Oliver Kopp and Frank Leymann and Fei Wu},
+ title = {Mapping interconnection choreography models to interaction choreography models},
+ booktitle = {2nd Central-European Workshop on Services and their Composition, Services und ihre Komposition, {ZEUS} 2010, Berlin, Germany, February 25-26, 2010. Proceedings},
+ year = {2010},
+ editor = {Christian Gierds and Jan S{\"{u}}rmeli},
+ volume = {563},
+ series = {{CEUR} Workshop Proceedings},
+ pages = {81--88},
+ publisher = {CEUR-WS.org},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/zeus/KoppLW10},
+ timestamp = {Mon, 30 May 2016 16:43:12 +0200},
+ url = {http://ceur-ws.org/Vol-563/paper10.pdf},
+}
+
+ at InProceedings{KoppEberleLeymannEtAl2010,
+ author = {Oliver Kopp and Hanna Eberle and Frank Leymann and Tobias Unger},
+ title = {The Subprocess Spectrum},
+ booktitle = {{INFORMATIK} 2010 - Business Process and Service Science - Proceedings of {ISSS} and BPSC, September 27 - October 1, 2010 in Leipzig, Germany},
+ year = {2010},
+ editor = {Witold Abramowicz and Rainer Alt and Klaus{-}Peter F{\"{a}}hnrich and Bogdan Franczyk and Leszek A. Maciaszek},
+ volume = {177},
+ series = {{LNI}},
+ pages = {267--279},
+ publisher = {{GI}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/bpsc/KoppELU10},
+ timestamp = {Tue, 15 Mar 2016 11:26:11 +0100},
+ url = {http://subs.emis.de/LNI/Proceedings/Proceedings177/article6191.html},
+}
+
+ at InProceedings{WielandMartinKoppEtAl2009,
+ author = {Matthias Wieland and Daniel Martin and Oliver Kopp and Frank Leymann},
+ title = {{SOEDA:} {A} Method for Specification and Implementation of Applications on a Service-Oriented Event-Driven Architecture},
+ booktitle = {Business Information Systems, 12th International Conference, {BIS} 2009, Poznan, Poland, April 27-29, 2009. Proceedings},
+ year = {2009},
+ editor = {Witold Abramowicz},
+ volume = {21},
+ series = {Lecture Notes in Business Information Processing},
+ pages = {193--204},
+ publisher = {Springer},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/bis/WielandMKL09},
+ doi = {10.1007/978-3-642-01190-0_17},
+ timestamp = {Mon, 11 May 2009 22:46:43 +0200},
+ url = {http://dx.doi.org/10.1007/978-3-642-01190-0_17},
+}
+
+ at Proceedings{KoppLohmann2009,
+ title = {1st Central-European Workshop on Services and their Composition, {ZEUS} 2009, Stuttgart, Germany, March 2-3, 2009. Proceedings},
+ year = {2009},
+ editor = {Oliver Kopp and Niels Lohmann},
+ volume = {438},
+ series = {{CEUR} Workshop Proceedings},
+ publisher = {CEUR-WS.org},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/zeus/2009},
+ timestamp = {Mon, 30 May 2016 01:00:00 +0200},
+ url = {http://ceur-ws.org/Vol-438},
+}
+
+ at InProceedings{BischofKoppLessenEtAl2009,
+ author = {Marc Bischof and Oliver Kopp and Tammo van Lessen and Frank Leymann},
+ title = {BPELscript: {A} Simplified Script Syntax for {WS-BPEL} 2.0},
+ booktitle = {35th Euromicro Conference on Software Engineering and Advanced Applications, {SEAA} 2009, Patras, Greece, August 27-29, 2009, Proceedings},
+ year = {2009},
+ pages = {39--46},
+ publisher = {{IEEE} Computer Society},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/euromicro/BischofKLL09},
+ doi = {10.1109/SEAA.2009.21},
+ timestamp = {Wed, 17 Feb 2016 00:00:00 +0100},
+ url = {http://dx.doi.org/10.1109/SEAA.2009.21},
+}
+
+ at InProceedings{KoppLeymann2009,
+ author = {Oliver Kopp and Frank Leymann},
+ title = {Do we need internal behavior in choreography models?},
+ booktitle = {1st Central-European Workshop on Services and their Composition, {ZEUS} 2009, Stuttgart, Germany, March 2-3, 2009. Proceedings},
+ year = {2009},
+ editor = {Oliver Kopp and Niels Lohmann},
+ volume = {438},
+ series = {{CEUR} Workshop Proceedings},
+ pages = {68--73},
+ publisher = {CEUR-WS.org},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/zeus/KoppL09},
+ timestamp = {Mon, 30 May 2016 16:57:34 +0200},
+ url = {http://ceur-ws.org/Vol-438/paper11.pdf},
+}
+
+ at InProceedings{KoppWielandLeymann2009,
+ author = {Oliver Kopp and Matthias Wieland and Frank Leymann},
+ title = {External and Internal Events in EPCs: e\({}^{\mbox{2}}\)EPCs},
+ booktitle = {Business Process Management Workshops, {BPM} 2009 International Workshops, Ulm, Germany, September 7, 2009. Revised Papers},
+ year = {2009},
+ editor = {Stefanie Rinderle{-}Ma and Shazia Wasim Sadiq and Frank Leymann},
+ volume = {43},
+ series = {Lecture Notes in Business Information Processing},
+ pages = {381--392},
+ publisher = {Springer},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/bpm/KoppWL09},
+ doi = {10.1007/978-3-642-12186-9_36},
+ timestamp = {Wed, 14 Apr 2010 15:27:11 +0200},
+ url = {http://dx.doi.org/10.1007/978-3-642-12186-9_36},
+}
+
+ at InProceedings{MonakovaKoppLeymann2009,
+ author = {Ganna Monakova and Oliver Kopp and Frank Leymann},
+ title = {Improving control flow verification in a business process using an extended Petri net},
+ booktitle = {1st Central-European Workshop on Services and their Composition, {ZEUS} 2009, Stuttgart, Germany, March 2-3, 2009. Proceedings},
+ year = {2009},
+ editor = {Oliver Kopp and Niels Lohmann},
+ volume = {438},
+ series = {{CEUR} Workshop Proceedings},
+ pages = {95--101},
+ publisher = {CEUR-WS.org},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/zeus/MonakovaKL09},
+ timestamp = {Mon, 30 May 2016 16:57:34 +0200},
+ url = {http://ceur-ws.org/Vol-438/paper15.pdf},
+}
+
+ at Article{DeckerKoppLeymannEtAl2009,
+ author = {Gero Decker and Oliver Kopp and Frank Leymann and Mathias Weske},
+ title = {Interacting services: From specification to execution},
+ journal = {Data Knowl. Eng.},
+ year = {2009},
+ volume = {68},
+ number = {10},
+ pages = {946--972},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/journals/dke/DeckerKLW09},
+ doi = {10.1016/j.datak.2009.04.003},
+ timestamp = {Thu, 03 Sep 2009 01:00:00 +0200},
+ url = {http://dx.doi.org/10.1016/j.datak.2009.04.003},
+}
+
+ at InProceedings{EberleKoppUngerEtAl2009,
+ author = {Hanna Eberle and Oliver Kopp and Tobias Unger and Frank Leymann},
+ title = {Retry Scopes to Enable Robust Workflow Execution in Pervasive Environments},
+ booktitle = {Service-Oriented Computing. ICSOC/ServiceWave 2009 Workshops - International Workshops, ICSOC/ServiceWave 2009, Stockholm, Sweden, November 23-27, 2009, Revised Selected Papers},
+ year = {2009},
+ editor = {Asit Dan and Frederic Gittler and Farouk Toumani},
+ volume = {6275},
+ series = {Lecture Notes in Computer Science},
+ pages = {358--369},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/icsoc/EberleKUL09},
+ doi = {10.1007/978-3-642-16132-2_34},
+ timestamp = {Fri, 24 Sep 2010 12:57:23 +0200},
+ url = {http://dx.doi.org/10.1007/978-3-642-16132-2_34},
+}
+
+ at Article{KoppMartinWutkeEtAl2009,
+ author = {Oliver Kopp and Daniel Martin and Daniel Wutke and Frank Leymann},
+ title = {The Difference Between Graph-Based and Block-Structured Business Process Modelling Languages},
+ journal = {Enterprise Modelling and Information Systems Architectures},
+ year = {2009},
+ volume = {4},
+ number = {1},
+ pages = {3--13},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/journals/emisaij/KoppMWL09},
+ timestamp = {Thu, 17 Mar 2016 00:00:00 +0100},
+ url = {https://www.emisa-journal.org/emisa/article/view/54},
+}
+
+ at InProceedings{KoppMietznerLeymann2009,
+ author = {Oliver Kopp and Ralph Mietzner and Frank Leymann},
+ title = {The Influence of an External Transaction on a {BPEL} Scope},
+ booktitle = {On the Move to Meaningful Internet Systems: {OTM} 2009, Confederated International Conferences, CoopIS, DOA, IS, and {ODBASE} 2009, Vilamoura, Portugal, November 1-6, 2009, Proceedings, Part {I}},
+ year = {2009},
+ editor = {Robert Meersman and Tharam S. Dillon and Pilar Herrero},
+ volume = {5870},
+ series = {Lecture Notes in Computer Science},
+ pages = {381--388},
+ publisher = {Springer},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/otm/KoppML09},
+ doi = {10.1007/978-3-642-05148-7_27},
+ timestamp = {Sun, 08 Nov 2009 21:19:42 +0100},
+ url = {http://dx.doi.org/10.1007/978-3-642-05148-7_27},
+}
+
+ at InProceedings{KoppWielandLeymann2009a,
+ author = {Oliver Kopp and Matthias Wieland and Frank Leymann},
+ title = {Towards choreography transactions},
+ booktitle = {1st Central-European Workshop on Services and their Composition, {ZEUS} 2009, Stuttgart, Germany, March 2-3, 2009. Proceedings},
+ year = {2009},
+ editor = {Oliver Kopp and Niels Lohmann},
+ volume = {438},
+ series = {{CEUR} Workshop Proceedings},
+ pages = {49--54},
+ publisher = {CEUR-WS.org},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/zeus/KoppWL09},
+ timestamp = {Mon, 30 May 2016 16:57:34 +0200},
+ url = {http://ceur-ws.org/Vol-438/paper8.pdf},
+}
+
+ at InProceedings{MonakovaKoppLeymannEtAl2009,
+ author = {Ganna Monakova and Oliver Kopp and Frank Leymann and Simon Moser and Klaus Sch{\"{a}}fers},
+ title = {Verifying Business Rules Using an {SMT} Solver for {BPEL} Processes},
+ booktitle = {Business Process, Services Computing and Intelligent Service Management, Leipzig, Germany, March 23-25, 2009},
+ year = {2009},
+ editor = {Witold Abramowicz and Leszek A. Maciaszek and Ryszard Kowalczyk and Andreas Speck},
+ volume = {147},
+ series = {{LNI}},
+ pages = {81--94},
+ publisher = {{GI}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/bpsc/MonakovaKLMS09},
+ timestamp = {Tue, 31 May 2011 01:00:00 +0200},
+ url = {http://subs.emis.de/LNI/Proceedings/Proceedings147/article2475.html},
+}
+
+ at InProceedings{KoppWetzsteinMietznerEtAl2008,
+ author = {Oliver Kopp and Branimir Wetzstein and Ralph Mietzner and Stefan Pottinger and Dimka Karastoyanova and Frank Leymann},
+ title = {A Model-Driven Approach to Implementing Coordination Protocols in {BPEL}},
+ booktitle = {Business Process Management Workshops, {BPM} 2008 International Workshops, Milano, Italy, September 1-4, 2008. Revised Papers},
+ year = {2008},
+ editor = {Danilo Ardagna and Massimo Mecella and Jian Yang},
+ volume = {17},
+ series = {Lecture Notes in Business Information Processing},
+ pages = {188--199},
+ publisher = {Springer},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/bpm/KoppWMPKL08},
+ doi = {10.1007/978-3-642-00328-8_19},
+ timestamp = {Mon, 17 Aug 2009 15:36:13 +0200},
+ url = {http://dx.doi.org/10.1007/978-3-642-00328-8_19},
+}
+
+ at Article{DeckerKoppBarros2008,
+ author = {Gero Decker and Oliver Kopp and Alistair P. Barros},
+ title = {An Introduction to Service Choreographies (Servicechoreographien - eine Einf{\"{u}}hrung)},
+ journal = {it - Information Technology},
+ year = {2008},
+ volume = {50},
+ number = {2},
+ pages = {122--127},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/journals/it/DeckerKB08},
+ doi = {10.1524/itit.2008.0473},
+ timestamp = {Sat, 11 Dec 2010 00:00:00 +0100},
+ url = {http://dx.doi.org/10.1524/itit.2008.0473},
+}
+
+ at Article{KoppLeymann2008,
+ author = {Oliver Kopp and Frank Leymann},
+ title = {Choreography Design Using {WS-BPEL}},
+ journal = {{IEEE} Data Eng. Bull.},
+ year = {2008},
+ volume = {31},
+ number = {3},
+ pages = {31--34},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/journals/debu/KoppL08},
+ timestamp = {Fri, 26 Sep 2008 01:00:00 +0200},
+ url = {http://sites.computer.org/debull/A08Sept/kopp.pdf},
+}
+
+ at InProceedings{KoppKhalafLeymann2008,
+ author = {Oliver Kopp and Rania Khalaf and Frank Leymann},
+ title = {Deriving Explicit Data Links in {WS-BPEL} Processes},
+ booktitle = {2008 {IEEE} International Conference on Services Computing {(SCC} 2008), 8-11 July 2008, Honolulu, Hawaii, {USA}},
+ year = {2008},
+ pages = {367--376},
+ publisher = {{IEEE} Computer Society},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/IEEEscc/KoppKL08},
+ doi = {10.1109/SCC.2008.122},
+ timestamp = {Wed, 02 Dec 2015 00:00:00 +0100},
+ url = {http://dx.doi.org/10.1109/SCC.2008.122},
+}
+
+ at Article{KhalafKoppLeymann2008,
+ author = {Rania Khalaf and Oliver Kopp and Frank Leymann},
+ title = {Maintaining Data Dependencies across {BPEL} Process Fragments},
+ journal = {Int. J. Cooperative Inf. Syst.},
+ year = {2008},
+ volume = {17},
+ number = {3},
+ pages = {259--282},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/journals/ijcis/KhalafKL08},
+ doi = {10.1142/S0218843008001828},
+ timestamp = {Wed, 05 Nov 2008 00:00:00 +0100},
+ url = {http://dx.doi.org/10.1142/S0218843008001828},
+}
+
+ at InProceedings{DeckerKoppLeymannEtAl2008,
+ author = {Gero Decker and Oliver Kopp and Frank Leymann and Kerstin Pfitzner and Mathias Weske},
+ title = {Modeling Service Choreographies Using {BPMN} and BPEL4Chor},
+ booktitle = {Advanced Information Systems Engineering, 20th International Conference, CAiSE 2008, Montpellier, France, June 16-20, 2008, Proceedings},
+ year = {2008},
+ editor = {Zohra Bellahsene and Michel L{\'{e}}onard},
+ volume = {5074},
+ series = {Lecture Notes in Computer Science},
+ pages = {79--93},
+ publisher = {Springer},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/caise/DeckerKLPW08},
+ doi = {10.1007/978-3-540-69534-9_6},
+ timestamp = {Wed, 11 Jun 2008 11:38:30 +0200},
+ url = {http://dx.doi.org/10.1007/978-3-540-69534-9_6},
+}
+
+ at InProceedings{KoppMartinWutkeEtAl2008,
+ author = {Oliver Kopp and Daniel Martin and Daniel Wutke and Frank Leymann},
+ title = {On the Choice Between Graph-Based and Block-Structured Business Process Modeling Languages},
+ booktitle = {Modellierung betrieblicher Informationssysteme - Modellierung zwischen {SOA} und Compliance Management - 27.-28. November 2008 Saarbr{\"{u}}cken, Germany},
+ year = {2008},
+ editor = {Peter Loos and Markus N{\"{u}}ttgens and Klaus Turowski and Dirk Werth},
+ volume = {141},
+ series = {{LNI}},
+ pages = {59--72},
+ publisher = {{GI}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/mobis/KoppMWL08},
+ timestamp = {Tue, 31 May 2011 01:00:00 +0200},
+ url = {http://subs.emis.de/LNI/Proceedings/Proceedings141/article2307.html},
+}
+
+ at InProceedings{LohmannKoppLeymannEtAl2007,
+ author = {Niels Lohmann and Oliver Kopp and Frank Leymann and Wolfgang Reisig},
+ title = {Analyzing BPEL4Chor: Verification and Participant Synthesis},
+ booktitle = {Web Services and Formal Methods, 4th International Workshop, {WS-FM} 2007, Brisbane, Australia, September 28-29, 2007. Proceedings},
+ year = {2007},
+ editor = {Marlon Dumas and Reiko Heckel},
+ volume = {4937},
+ series = {Lecture Notes in Computer Science},
+ pages = {46--60},
+ publisher = {Springer},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/wsfm/LohmannKLR07},
+ doi = {10.1007/978-3-540-79230-7_4},
+ timestamp = {Tue, 15 Apr 2008 11:12:04 +0200},
+ url = {http://dx.doi.org/10.1007/978-3-540-79230-7_4},
+}
+
+ at InProceedings{DeckerKoppLeymannEtAl2007,
+ author = {Gero Decker and Oliver Kopp and Frank Leymann and Mathias Weske},
+ title = {BPEL4Chor: Extending {BPEL} for Modeling Choreographies},
+ booktitle = {2007 {IEEE} International Conference on Web Services {(ICWS} 2007), July 9-13, 2007, Salt Lake City, Utah, {USA}},
+ year = {2007},
+ pages = {296--303},
+ publisher = {{IEEE} Computer Society},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/icws/DeckerKLW07},
+ doi = {10.1109/ICWS.2007.59},
+ timestamp = {Thu, 20 Aug 2015 01:00:00 +0200},
+ url = {http://dx.doi.org/10.1109/ICWS.2007.59},
+}
+
+ at InProceedings{KoppEberleUngerEtAl2007,
+ author = {Oliver Kopp and Hanna Eberle and Tobias Unger and Frank Leymann},
+ title = {From Process Models to Business Landscapes},
+ booktitle = {6. Workshop der Gesellschaft f{\"{u}}r Informatik e.V. {(GI)} und Treffen ihres Arbeitskreises "Gesch{\"{a}}ftsprozessmanagement mit Ereignisgesteuerten Prozessketten (WI-EPK)" St. Augustin, 29. November - 30. November 2007},
+ year = {2007},
+ editor = {Markus N{\"{u}}ttgens and Frank J. Rump and Andreas Gadatsch},
+ volume = {303},
+ series = {{CEUR} Workshop Proceedings},
+ pages = {7--22},
+ publisher = {CEUR-WS.org},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/epk/KoppEUL07},
+ timestamp = {Mon, 30 May 2016 16:57:35 +0200},
+ url = {http://ceur-ws.org/Vol-303/epk2007-paper1.pdf},
+}
+
+ at InProceedings{KhalafKoppLeymann2007,
+ author = {Rania Khalaf and Oliver Kopp and Frank Leymann},
+ title = {Maintaining Data Dependencies Across {BPEL} Process Fragments},
+ booktitle = {Service-Oriented Computing - {ICSOC} 2007, Fifth International Conference, Vienna, Austria, September 17-20, 2007, Proceedings},
+ year = {2007},
+ editor = {Bernd J. Kr{\"{a}}mer and Kwei{-}Jay Lin and Priya Narasimhan},
+ volume = {4749},
+ series = {Lecture Notes in Computer Science},
+ pages = {207--219},
+ publisher = {Springer},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/icsoc/KhalafKL07},
+ doi = {10.1007/978-3-540-74974-5_17},
+ timestamp = {Fri, 31 Aug 2007 12:13:15 +0200},
+ url = {http://dx.doi.org/10.1007/978-3-540-74974-5_17},
+}
+
+ at InProceedings{PfitznerDeckerKoppEtAl2007,
+ author = {Kerstin Pfitzner and Gero Decker and Oliver Kopp and Frank Leymann},
+ title = {Web Service Choreography Configurations for {BPMN}},
+ booktitle = {Service-Oriented Computing - {ICSOC} 2007 Workshops, International Workshops, Vienna, Austria, September 17, 2007, Revised Selected Papers},
+ year = {2007},
+ editor = {Elisabetta Di Nitto and Matei Ripeanu},
+ volume = {4907},
+ series = {Lecture Notes in Computer Science},
+ pages = {401--412},
+ publisher = {Springer},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/icsoc/PfitznerDKL07},
+ doi = {10.1007/978-3-540-93851-4_39},
+ timestamp = {Fri, 16 Jan 2009 14:26:18 +0100},
+ url = {http://dx.doi.org/10.1007/978-3-540-93851-4_39},
+}
+
+ at InProceedings{KoppUngerLeymann2006,
+ author = {Oliver Kopp and Tobias Unger and Frank Leymann},
+ title = {Nautilus Event-driven Process Chains: Syntax, Semantics, and their Mapping to {BPEL}},
+ booktitle = {5. Workshop der Gesellschaft f{\"{u}}r Informatik e.V. {(GI)} und Treffen ihres Arbeitskreises "Gesch{\"{a}}ftsprozessmanagement mit Ereignisgesteuerten Prozessketten (WI-EPK)", Wien, 30. November - 01. Dezember 2006},
+ year = {2006},
+ editor = {Markus N{\"{u}}ttgens and Frank J. Rump and Jan Mendling},
+ volume = {224},
+ series = {{CEUR} Workshop Proceedings},
+ pages = {85--104},
+ publisher = {CEUR-WS.org},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/epk/KoppUL06},
+ timestamp = {Mon, 30 May 2016 16:57:35 +0200},
+ url = {http://ceur-ws.org/Vol-224/epk2006-paper5.pdf},
+}
+
+ at InCollection{FrenzelLorenzScheinEtAl2012,
+ author = {Frenzel, Heiko and Lorenz, Michael and Schein, Friedrich-L and Lajn, Alexander and Kl{\"u}pfel, Fabian J and Diez, Tobias and von Wenckstern, Holger and Grundmann, Marius},
+ title = {Metal-Semiconductor Field-Effect Transistors and Integrated Circuits Based on ZnO and Related Oxides},
+ booktitle = {Handbook of Zinc Oxide and Related Materials: Devices and Nano-Engineering},
+ publisher = {CRC Press},
+ year = {2012},
+ volume = {2},
+ pages = {369--434},
+}
+
+ at Article{LajnDiezScheinEtAl2011,
+ author = {Lajn, A and Diez, T and Schein, F and Frenzel, H and von Wenckstern, H and Grundmann, M},
+ title = {Light and temperature stability of fully transparent ZnO-based inverter circuits},
+ journal = {Electron Device Letters, IEEE},
+ year = {2011},
+ volume = {32},
+ number = {4},
+ pages = {515--517},
+ publisher = {IEEE},
+}
+
+ at InProceedings{SkoienAlverAlfredsen2014,
+ author = {Kristoffer Rist Skoien and Morten Omholt Alver and Jo Arve Alfredsen},
+ title = {A computer vision approach for detection and quantification of feed particles in marine fish farms},
+ booktitle = {2014 {IEEE} International Conference on Image Processing, {ICIP} 2014, Paris, France, October 27-30, 2014},
+ year = {2014},
+ pages = {1648--1652},
+ publisher = {{IEEE}},
+ bibsource = {dblp computer science bibliography, http://dblp.org},
+ biburl = {http://dblp.uni-trier.de/rec/bib/conf/icip/SkoienAA14},
+ doi = {10.1109/ICIP.2014.7025330},
+ timestamp = {Thu, 26 Feb 2015 13:54:18 +0100},
+ url = {http://dx.doi.org/10.1109/ICIP.2014.7025330},
+}
+
+ at Article{AttramadalOieStorsethEtAl2012,
+ author = {Attramadal, Kari JK and {\O}ie, Gunvor and St{\o}rseth, Trond R and Alver, Morten O and Vadstein, Olav and Olsen, Yngvar},
+ title = {The effects of moderate ozonation or high intensity UV-irradiation on the microbial environment in RAS for marine larvae},
+ journal = {Aquaculture},
+ year = {2012},
+ volume = {330},
+ pages = {121--129},
+ publisher = {Elsevier},
+}
+
+ at Article{AlverTennoyAlfredsenEtAl2007,
+ author = {Alver, Morten Omholt and Tenn{\o}y, Torodd and Alfredsen, Jo Arve and {\O}ie, Gunvor},
+ title = {Automatic measurement of rotifer Brachionus plicatilis densities in first feeding tanks},
+ journal = {Aquacultural engineering},
+ year = {2007},
+ volume = {36},
+ number = {2},
+ pages = {115--121},
+ publisher = {Elsevier},
+}
+
+ at Article{BrochEllingsenForbordEtAl2013,
+ author = {Broch, Ole Jacob and Ellingsen, Ingrid Helene and Forbord, Silje and Wang, Xinxin and Volent, Zsolt and Alver, Morten Omholt and Hand{\aa}, Aleksander and Andresen, Kjersti and Slagstad, Dag and Reitan, KIR and others},
+ title = {Modelling the cultivation and bioremediation potential of the kelp Saccharina latissima in close proximity to an exposed salmon farm in Norway},
+ journal = {Aquaculture Environment Interactions},
+ year = {2013},
+ volume = {4},
+ number = {2},
+ pages = {187--206},
+}
+
+ at Article{AlverHanckeSakshaugEtAl2014,
+ author = {Alver, Morten O and Hancke, Kasper and Sakshaug, Egil and Slagstad, Dag},
+ title = {A spectrally-resolved light propagation model for aquatic systems: Steps toward parameterizing primary production},
+ journal = {Journal of Marine Systems},
+ year = {2014},
+ volume = {130},
+ pages = {134--146},
+ publisher = {Elsevier},
+}
+
+ at Article{AlverAlfredsenSigholt2004,
+ author = {Alver, Morten Omholt and Alfredsen, Jo Arve and Sigholt, Trygve},
+ title = {Dynamic modelling of pellet distribution in Atlantic salmon (Salmo salar L.) cages},
+ journal = {Aquacultural engineering},
+ year = {2004},
+ volume = {31},
+ number = {1},
+ pages = {51--72},
+ publisher = {Elsevier},
+}
+
+ at Article{AlverAlfredsenOlsen2006,
+ author = {Alver, Morten Omholt and Alfredsen, Jo Arve and Olsen, Yngvar},
+ title = {An individual-based population model for rotifer (Brachionus plicatilis) cultures},
+ journal = {Hydrobiologia},
+ year = {2006},
+ volume = {560},
+ number = {1},
+ pages = {93--108},
+ publisher = {Springer},
+}
+
+ at Article{LoiselMorel1998,
+ author = {Loisel, Hubert and Morel, Andre},
+ title = {Light scattering and chlorophyll concentration in case 1 waters: A reexamination},
+ journal = {Limnology and Oceanography},
+ year = {1998},
+ volume = {43},
+ number = {5},
+ pages = {847--858},
+ publisher = {Wiley Online Library},
+}
+
+ at Article{AlverStoroyBardalEtAl2011,
+ author = {Alver, Morten Omholt and Stor{\o}y, Werner and Bardal, Tora and Overrein, Ingrid and Ons{\o}yen, Mathias Karlsen and Tenn{\o}y, Torodd and {\O}ie, Gunvor},
+ title = {Automatic measurement of Acartia tonsa nauplii density, and estimation of stage distribution},
+ journal = {Aquaculture},
+ year = {2011},
+ volume = {313},
+ number = {1},
+ pages = {100--106},
+ publisher = {Elsevier},
+}
+
+ at Article{AlverAlfredsenOie2007,
+ author = {Alver, Morten Omholt and Alfredsen, Jo Arve and {\O}ie, Gunvor},
+ title = {Estimating larval density in cod (Gadus morhua) first feeding tanks using measurements of feed density and larval growth rates},
+ journal = {Aquaculture},
+ year = {2007},
+ volume = {268},
+ number = {1},
+ pages = {216--226},
+ publisher = {Elsevier},
+}
+
+ at Article{HovlandHanckeAlverEtAl2014,
+ author = {Hovland, Erlend Kjeldsberg and Hancke, Kasper and Alver, Morten Omholt and Drinkwater, Ken and H{\o}kedal, Jo and Johnsen, Geir and Moline, Mark and Sakshaug, Egil},
+ title = {Optical impact of an Emiliania huxleyi bloom in the frontal region of the Barents Sea},
+ journal = {Journal of Marine Systems},
+ year = {2014},
+ volume = {130},
+ pages = {228--240},
+ publisher = {Elsevier},
+}
+
+ at Article{Kirk1989,
+ author = {Kirk, JTO},
+ title = {The upwelling light stream in natural waters},
+ journal = {Limnology and Oceanography},
+ year = {1989},
+ volume = {34},
+ number = {8},
+ pages = {1410--1425},
+ publisher = {Wiley Online Library},
+}
+
+ at Article{AlverAlfredsenOieEtAl2010,
+ author = {Alver, Morten Omholt and Alfredsen, Jo Arve and {\O}ie, Gunvor and Stor{\o}y, Werner and Olsen, Yngvar},
+ title = {Automatic control of growth and density in rotifer cultures},
+ journal = {Aquacultural engineering},
+ year = {2010},
+ volume = {43},
+ number = {1},
+ pages = {6--13},
+ publisher = {Elsevier},
+}
+
+ at Article{MiljeteigOlsenBatnesEtAl2014,
+ author = {Miljeteig, Cecilie and Olsen, Anders Johny and B{\aa}tnes, Anna S and Altin, Dag and Nordtug, Trond and Alver, Morten O and Speed, James DM and Jenssen, Bj{\o}rn Munro},
+ title = {Sex and life stage dependent phototactic response of the marine copepod Calanus finmarchicus (Copepoda: Calanoida)},
+ journal = {Journal of Experimental Marine Biology and Ecology},
+ year = {2014},
+ volume = {451},
+ pages = {16--24},
+ publisher = {Elsevier},
+}
+
+ at Article{AlverAlfredsenOie2005,
+ author = {Alver, Morten O and Alfredsen, Jo A and {\O}ie, Gunvor},
+ title = {A system for model-based biomass estimation of larvae in intensive cod larvicultures},
+ journal = {Aquaculture International},
+ year = {2005},
+ volume = {13},
+ number = {6},
+ pages = {519--541},
+ publisher = {Springer},
+}
+
+ at Article{AlverTennoyAlfredsenEtAl2008,
+ author = {Alver, Morten Omholt and Tenn{\o}y, Torodd and Alfredsen, Jo Arve and {\O}ie, Gunvor and Olsen, Yngvar},
+ title = {Automatic control of rotifer density in larval first feeding tanks},
+ journal = {Control Engineering Practice},
+ year = {2008},
+ volume = {16},
+ number = {3},
+ pages = {347--355},
+ publisher = {Elsevier},
+}
+
+ at Comment{jabref-meta: databaseType:bibtex;}
diff --git a/xjc.gradle b/xjc.gradle
index 3f2c773..9ae589e 100644
--- a/xjc.gradle
+++ b/xjc.gradle
@@ -9,8 +9,10 @@ dependencies {
task xjc {
inputs.dir "src/main/resources/xjc/medline/"
inputs.dir "src/main/resources/xjc/bibtexml/"
+ inputs.dir "src/main/resources/xjc/mods/"
outputs.dir "src/main/gen/net/sf/jabref/logic/importer/fileformat/medline"
outputs.dir "src/main/gen/net/sf/jabref/logic/importer/fileformat/bibtexml"
+ outputs.dir "src/main/gen/net/sf/jabref/logic/importer/fileformat/mods"
ant.taskdef(name: 'xjc', classname: 'com.sun.tools.xjc.XJCTask', classpath: configurations.xjc.asPath)
@@ -21,6 +23,11 @@ task xjc {
ant.xjc(destdir: 'src/main/gen/', package: 'net.sf.jabref.logic.importer.fileformat.bibtexml') {
schema(dir: 'src/main/resources/xjc/bibtexml', includes: 'bibtexml.xsd')
}
+ ant.xjc(destdir: 'src/main/gen/', package: 'net.sf.jabref.logic.importer.fileformat.mods') {
+ arg(value: '-npa') //don't create package-info.java because it was manually added in src/main/java to ensure the namespace prefix mapping
+ schema(dir: 'src/main/resources/xjc/mods', includes: 'mods-3-6.xsd')
+ binding(dir: 'src/main/resources/xjc/mods', includes: 'mods-binding.xjb')
+ }
}
}
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-java/jabref.git
More information about the pkg-java-commits
mailing list