diff --git a/src/main/java/org/jabref/JabRefGUI.java b/src/main/java/org/jabref/JabRefGUI.java index 57214d9ef9f..203dcf03386 100644 --- a/src/main/java/org/jabref/JabRefGUI.java +++ b/src/main/java/org/jabref/JabRefGUI.java @@ -65,17 +65,7 @@ public JabRefGUI(Stage mainStage, List argsDatabases, boolean isBl } private void openWindow(Stage mainStage) { - // Set antialiasing on everywhere. This only works in JRE >= 1.5. - // Or... it doesn't work, period. - // TODO test and maybe remove this! I found this commented out with no additional info ( payload@lavabit.com ) - // Enabled since JabRef 2.11 beta 4 - System.setProperty("swing.aatext", "true"); - // Default is "on". - // "lcd" instead of "on" because of http://wiki.netbeans.org/FaqFontRendering and http://docs.oracle.com/javase/6/docs/technotes/guides/2d/flags.html#aaFonts - System.setProperty("awt.useSystemAAFontSettings", "lcd"); - - // look and feel. This MUST be the first thing to do before loading any Swing-specific code! - setLookAndFeel(); + applyFontRenderingTweak(); // If the option is enabled, open the last edited libraries, if any. if (!isBlank && Globals.prefs.getBoolean(JabRefPreferences.OPEN_LAST_EDITED)) { @@ -242,9 +232,9 @@ private boolean isLoaded(File fileToOpen) { return false; } - private void setLookAndFeel() { - // On Linux, Java FX fonts look blurry per default. This can be improved by using a non-default rendering - // setting. See https://github.com/woky/javafx-hates-linux + private void applyFontRenderingTweak() { + // On Linux, Java FX fonts look blurry per default. This can be improved by using a non-default rendering setting. + // See https://github.com/woky/javafx-hates-linux if (Globals.prefs.getBoolean(JabRefPreferences.FX_FONT_RENDERING_TWEAK)) { System.setProperty("prism.text", "t2k"); System.setProperty("prism.lcdtext", "true"); @@ -254,9 +244,4 @@ private void setLookAndFeel() { public static JabRefFrame getMainFrame() { return mainFrame; } - - // Only used for testing, other than that do NOT set the mainFrame... - public static void setMainFrame(JabRefFrame mainFrame) { - JabRefGUI.mainFrame = mainFrame; - } } diff --git a/src/main/java/org/jabref/gui/BasePanel.java b/src/main/java/org/jabref/gui/BasePanel.java index ea88315f304..be3afdff2fa 100644 --- a/src/main/java/org/jabref/gui/BasePanel.java +++ b/src/main/java/org/jabref/gui/BasePanel.java @@ -65,7 +65,6 @@ import org.jabref.gui.specialfields.SpecialFieldViewModel; import org.jabref.gui.undo.CountingUndoManager; import org.jabref.gui.undo.NamedCompound; -import org.jabref.gui.undo.UndoableChangeType; import org.jabref.gui.undo.UndoableFieldChange; import org.jabref.gui.undo.UndoableInsertEntry; import org.jabref.gui.undo.UndoableRemoveEntry; @@ -1021,39 +1020,6 @@ public BibDatabase getDatabase() { return bibDatabaseContext.getDatabase(); } - public void changeTypeOfSelectedEntries(String newType) { - List bes = mainTable.getSelectedEntries(); - changeType(bes, newType); - } - - private void changeType(List entries, String newType) { - if ((entries == null) || (entries.isEmpty())) { - LOGGER.error("At least one entry must be selected to be able to change the type."); - return; - } - - if (entries.size() > 1) { - boolean proceed = dialogService.showConfirmationDialogAndWait(Localization.lang("Change entry type"), Localization.lang("Multiple entries selected. Do you want to change the type of all these to '%0'?")); - if (!proceed) { - return; - } - } - - NamedCompound compound = new NamedCompound(Localization.lang("Change entry type")); - for (BibEntry entry : entries) { - compound.addEdit(new UndoableChangeType(entry, entry.getType(), newType)); - DefaultTaskExecutor.runInJavaFXThread(() -> { - entry.setType(newType); - }); - } - - output(formatOutputMessage(Localization.lang("Changed type to '%0' for", newType), entries.size())); - compound.end(); - getUndoManager().addEdit(compound); - markBaseChanged(); - updateEntryEditorIfShowing(); - } - public boolean showDeleteConfirmationDialog(int numberOfEntries) { if (Globals.prefs.getBoolean(JabRefPreferences.CONFIRM_DELETE)) { String title = Localization.lang("Delete entry"); diff --git a/src/main/java/org/jabref/gui/DuplicateResolverDialog.java b/src/main/java/org/jabref/gui/DuplicateResolverDialog.java index 858a7c7e7f2..d9f65a22f83 100644 --- a/src/main/java/org/jabref/gui/DuplicateResolverDialog.java +++ b/src/main/java/org/jabref/gui/DuplicateResolverDialog.java @@ -116,7 +116,7 @@ private void init(BibEntry one, BibEntry two, DuplicateResolverType type) { getDialogPane().setContent(borderPane); Button helpButton = (Button) this.getDialogPane().lookupButton(help); - helpButton.setOnAction(evt -> helpCommand.getCommand().execute()); + helpButton.setOnAction(evt -> helpCommand.execute()); } public BibEntry getMergedEntry() { diff --git a/src/main/java/org/jabref/gui/GUIGlobals.java b/src/main/java/org/jabref/gui/GUIGlobals.java index e1f145054ff..12d55f69bbe 100644 --- a/src/main/java/org/jabref/gui/GUIGlobals.java +++ b/src/main/java/org/jabref/gui/GUIGlobals.java @@ -10,9 +10,6 @@ import org.jabref.logic.l10n.Localization; import org.jabref.preferences.JabRefPreferences; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - /** * Static variables for graphics files and keyboard shortcuts. */ @@ -32,11 +29,6 @@ public class GUIGlobals { public static final String UNTITLED_TITLE = Localization.lang("untitled"); - // Colors. - public static final Color ENTRY_EDITOR_LABEL_COLOR = new Color(100, 100, 150); // Empty field, blue. - - private static final Logger LOGGER = LoggerFactory.getLogger(GUIGlobals.class); - private GUIGlobals() { } diff --git a/src/main/java/org/jabref/gui/JEditorPaneWithHighlighting.java b/src/main/java/org/jabref/gui/JEditorPaneWithHighlighting.java deleted file mode 100644 index 71235c5d08e..00000000000 --- a/src/main/java/org/jabref/gui/JEditorPaneWithHighlighting.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.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 org.jabref.gui.fieldeditors.JTextAreaWithHighlighting; -import org.jabref.logic.search.SearchQueryHighlightListener; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class JEditorPaneWithHighlighting extends JEditorPane implements SearchQueryHighlightListener { - - private static final Logger LOGGER = LoggerFactory.getLogger(JTextAreaWithHighlighting.class); - - public void highlightPattern(Optional 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/org/jabref/gui/JabRefFrame.java b/src/main/java/org/jabref/gui/JabRefFrame.java index ff496a25e09..cb6775bebaf 100644 --- a/src/main/java/org/jabref/gui/JabRefFrame.java +++ b/src/main/java/org/jabref/gui/JabRefFrame.java @@ -550,32 +550,6 @@ public void changed(ObservableValue observable, Boolean oldVa }); setCenter(splitPane); - - /* - 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; - con.weightx = 0; - con.gridwidth = 1; - con.insets = new Insets(0, 2, 0, 0); - gbl.setConstraints(statusLabel, con); - status.add(statusLabel); - con.weightx = 1; - con.insets = new Insets(0, 4, 0, 0); - con.gridwidth = 1; - gbl.setConstraints(statusLine, con); - status.add(statusLine); - con.weightx = 0; - con.gridwidth = GridBagConstraints.REMAINDER; - con.insets = new Insets(2, 4, 2, 2); - gbl.setConstraints(progressBar, con); - status.add(progressBar); - statusLabel.setForeground(GUIGlobals.ENTRY_EDITOR_LABEL_COLOR.darker()); - */ } private void setDividerPosition() { diff --git a/src/main/java/org/jabref/gui/actions/ChangeTypeAction.java b/src/main/java/org/jabref/gui/actions/ChangeTypeAction.java deleted file mode 100644 index b7b907a662c..00000000000 --- a/src/main/java/org/jabref/gui/actions/ChangeTypeAction.java +++ /dev/null @@ -1,52 +0,0 @@ -package org.jabref.gui.actions; - -import java.awt.event.ActionEvent; -import java.util.Collections; -import java.util.List; - -import javax.swing.AbstractAction; -import javax.swing.undo.UndoManager; - -import javafx.scene.control.MenuItem; - -import org.jabref.gui.BasePanel; -import org.jabref.gui.undo.NamedCompound; -import org.jabref.gui.undo.UndoableChangeType; -import org.jabref.logic.l10n.Localization; -import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.EntryType; - -public class ChangeTypeAction extends AbstractAction { - - private final String type; - private final BasePanel panel; - - public ChangeTypeAction(EntryType type, BasePanel bp) { - super(type.getName()); - this.type = type.getName(); - panel = bp; - } - - @Override - public void actionPerformed(ActionEvent evt) { - panel.changeTypeOfSelectedEntries(type); - } - - public static MenuItem as(EntryType type, BibEntry entry, UndoManager undoManager) { - return as(type, Collections.singletonList(entry), undoManager); - } - - public static MenuItem as(EntryType type, List entries, UndoManager undoManager) { - MenuItem menuItem = new MenuItem(type.getName()); - menuItem.setOnAction(event -> { - NamedCompound compound = new NamedCompound(Localization.lang("Change entry type")); - for (BibEntry entry : entries) { - entry.setType(type) - .ifPresent(change -> compound.addEdit(new UndoableChangeType(change))); - } - - undoManager.addEdit(compound); - }); - return menuItem; - } -} diff --git a/src/main/java/org/jabref/gui/actions/CopyDoiUrlAction.java b/src/main/java/org/jabref/gui/actions/CopyDoiUrlAction.java index aa8ee344abe..51adf9ba8b3 100644 --- a/src/main/java/org/jabref/gui/actions/CopyDoiUrlAction.java +++ b/src/main/java/org/jabref/gui/actions/CopyDoiUrlAction.java @@ -1,10 +1,7 @@ package org.jabref.gui.actions; -import java.awt.event.ActionEvent; import java.util.Optional; -import javax.swing.AbstractAction; - import javafx.scene.control.TextArea; import org.jabref.Globals; @@ -15,24 +12,17 @@ /** * Copies the doi url to the clipboard */ -public class CopyDoiUrlAction extends AbstractAction { - - private TextArea component = null; - private String identifier; +public class CopyDoiUrlAction extends SimpleCommand { - public CopyDoiUrlAction(String identifier) { - super(Localization.lang("Copy DOI url")); - this.identifier = identifier; - } + private TextArea component; public CopyDoiUrlAction(TextArea component) { - this(component.getText()); this.component = component; } @Override - public void actionPerformed(ActionEvent e) { - identifier = component == null ? identifier : component.getText(); + public void execute() { + String identifier = component.getText(); Optional urlOptional = DOI.parse(identifier).map(DOI::getURIAsASCIIString); if (urlOptional.isPresent()) { diff --git a/src/main/java/org/jabref/gui/actions/MnemonicAwareAction.java b/src/main/java/org/jabref/gui/actions/MnemonicAwareAction.java deleted file mode 100644 index b1bfa9f87d5..00000000000 --- a/src/main/java/org/jabref/gui/actions/MnemonicAwareAction.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.jabref.gui.actions; - -import javax.swing.AbstractAction; -import javax.swing.Action; -import javax.swing.Icon; - -import org.jabref.gui.icon.IconTheme; - -/** - * This class extends {@link AbstractAction} with the ability to set - * the mnemonic key based on a '&' character inserted in front of - * the desired mnemonic letter. This is done by setting the action's - * name using putValue(NAME, actionname). - * This facilitates localized mnemonics. - */ -public abstract class MnemonicAwareAction extends AbstractAction { - - public MnemonicAwareAction() { } - - public MnemonicAwareAction(Icon icon) { - if (icon instanceof IconTheme.FontBasedIcon) { - putValue(Action.SMALL_ICON, ((IconTheme.FontBasedIcon) icon).createSmallIcon()); - putValue(Action.LARGE_ICON_KEY, icon); - } else { - putValue(Action.SMALL_ICON, icon); - } - } - - @Override - public void putValue(String key, Object value) { - if (key.equals(Action.NAME)) { - String name = value.toString(); - int i = name.indexOf('&'); - if (i >= 0) { - char mnemonic = Character.toUpperCase(name.charAt(i + 1)); - putValue(Action.MNEMONIC_KEY, (int) mnemonic); - value = name.substring(0, i) + name.substring(i + 1); - } else { - value = name; - } - } - super.putValue(key, value); - } -} diff --git a/src/main/java/org/jabref/gui/actions/StandardActions.java b/src/main/java/org/jabref/gui/actions/StandardActions.java index 6e7493f32d7..2c91ff5c4b5 100644 --- a/src/main/java/org/jabref/gui/actions/StandardActions.java +++ b/src/main/java/org/jabref/gui/actions/StandardActions.java @@ -91,6 +91,7 @@ public enum StandardActions implements Action { OPEN_FILE(Localization.lang("Open file"), Localization.lang("Open file"), IconTheme.JabRefIcons.FILE, KeyBinding.OPEN_FILE), OPEN_CONSOLE(Localization.lang("Open terminal here"), Localization.lang("Open terminal here"), IconTheme.JabRefIcons.CONSOLE, KeyBinding.OPEN_CONSOLE), COPY_LINKED_FILES(Localization.lang("Copy linked files to folder...")), + COPY_DOI(Localization.lang("Copy DOI url")), ABBREVIATE(Localization.lang("Abbreviate journal names")), ABBREVIATE_ISO("ISO", Localization.lang("Abbreviate journal names of the selected entries (ISO abbreviation)"), KeyBinding.ABBREVIATE), ABBREVIATE_MEDLINE("MEDLINE", Localization.lang("Abbreviate journal names of the selected entries (MEDLINE abbreviation)")), @@ -138,6 +139,10 @@ public enum StandardActions implements Action { SET_FILE_LINKS(Localization.lang("Automatically set file links"), KeyBinding.AUTOMATICALLY_LINK_FILES), HELP(Localization.lang("Online help"), IconTheme.JabRefIcons.HELP, KeyBinding.HELP), + HELP_KEY_PATTERNS(Localization.lang("Help on key patterns"), IconTheme.JabRefIcons.HELP, KeyBinding.HELP), + HELP_REGEX_SEARCH(Localization.lang("Help on regular expression search"), IconTheme.JabRefIcons.HELP, KeyBinding.HELP), + HELP_NAME_FORMATTER(Localization.lang("Help on Name Formatting"), IconTheme.JabRefIcons.HELP, KeyBinding.HELP), + HELP_SPECIAL_FIELDS(Localization.lang("Help on special fields"), IconTheme.JabRefIcons.HELP, KeyBinding.HELP), WEB_MENU(Localization.lang("JabRef resources")), OPEN_WEBPAGE(Localization.lang("Website"), Localization.lang("Opens JabRef's website")), OPEN_FACEBOOK("Facebook", Localization.lang("Opens JabRef's Facebook page"), IconTheme.JabRefIcons.FACEBOOK), diff --git a/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternPanel.java b/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternPanel.java index e3796c623ee..e1e81d2bc03 100644 --- a/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternPanel.java +++ b/src/main/java/org/jabref/gui/bibtexkeypattern/BibtexKeyPatternPanel.java @@ -1,7 +1,5 @@ package org.jabref.gui.bibtexkeypattern; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; import java.util.HashMap; import java.util.Locale; import java.util.Map; @@ -30,15 +28,9 @@ public class BibtexKeyPatternPanel extends Pane { - // used by both BibtexKeyPatternPanel and TabLabelPAttern - protected final GridBagLayout gbl = new GridBagLayout(); - protected final GridBagConstraints con = new GridBagConstraints(); - // default pattern protected final TextField defaultPat = new TextField(); - private final int COLUMNS = 2; - // one field for each type private final Map textFields = new HashMap<>(); private final BasePanel panel; @@ -64,7 +56,8 @@ private void buildGUI() { int rowIndex = 1; int columnIndex = 0; // The header - can be removed - for (int i = 0; i < COLUMNS; i++) { + int columnsNumber = 2; + for (int i = 0; i < columnsNumber; i++) { Label label = new Label(Localization.lang("Entry type")); Label keyPattern = new Label(Localization.lang("Key pattern")); gridPane.add(label, ++columnIndex, rowIndex); @@ -93,7 +86,7 @@ private void buildGUI() { textFields.put(type.getName().toLowerCase(Locale.ROOT), textField); - if (columnIndex == (COLUMNS - 1)) { + if (columnIndex == (columnsNumber - 1)) { columnIndex = 0; rowIndex++; } else { @@ -104,7 +97,7 @@ private void buildGUI() { rowIndex++; ActionFactory factory = new ActionFactory(Globals.prefs.getKeyBindingRepository()); - Button help = factory.createIconButton(StandardActions.HELP, new HelpAction(Localization.lang("Help on key patterns"), HelpFile.BIBTEX_KEY_PATTERN).getCommand()); + Button help = factory.createIconButton(StandardActions.HELP_KEY_PATTERNS, new HelpAction(HelpFile.BIBTEX_KEY_PATTERN)); gridPane.add(help, 1, rowIndex); Button btnDefaultAll1 = new Button(Localization.lang("Reset all")); @@ -138,8 +131,7 @@ private void fillPatternUsingPanelData(AbstractBibtexKeyPattern keypatterns) { } protected GlobalBibtexKeyPattern getKeyPatternAsGlobalBibtexKeyPattern() { - GlobalBibtexKeyPattern res = GlobalBibtexKeyPattern.fromPattern( - JabRefPreferences.getInstance().get(JabRefPreferences.DEFAULT_BIBTEX_KEY_PATTERN)); + GlobalBibtexKeyPattern res = GlobalBibtexKeyPattern.fromPattern(Globals.prefs.get(JabRefPreferences.DEFAULT_BIBTEX_KEY_PATTERN)); fillPatternUsingPanelData(res); return res; } diff --git a/src/main/java/org/jabref/gui/cleanup/CleanupActionsListModel.java b/src/main/java/org/jabref/gui/cleanup/CleanupActionsListModel.java deleted file mode 100644 index f7bf8a5e463..00000000000 --- a/src/main/java/org/jabref/gui/cleanup/CleanupActionsListModel.java +++ /dev/null @@ -1,81 +0,0 @@ -package org.jabref.gui.cleanup; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -import javax.swing.ListModel; -import javax.swing.event.ListDataEvent; -import javax.swing.event.ListDataListener; - -import org.jabref.model.cleanup.FieldFormatterCleanup; -import org.jabref.model.cleanup.FieldFormatterCleanups; - -public class CleanupActionsListModel implements ListModel { - - private List cleanupActions; - private final List listeners = new ArrayList<>(); - - - public CleanupActionsListModel(List cleanupAction) { - Objects.requireNonNull(cleanupAction); - this.cleanupActions = cleanupAction; - - } - - public void addCleanupAction(FieldFormatterCleanup action) { - if (!cleanupActions.contains(action)) { - cleanupActions.add(action); - for (ListDataListener listener : listeners) { - listener.intervalAdded(new ListDataEvent(action, ListDataEvent.INTERVAL_ADDED, cleanupActions.size(), - cleanupActions.size())); - } - } - } - - /** - * Removes the action at the specified index from the list. - * Removal is only done when index {@code >=0} and index {@code<=} list size - * @param index The index to remove - */ - public void removeAtIndex(int index) { - - if ((index >= 0) && (index < cleanupActions.size())) { - FieldFormatterCleanup action = cleanupActions.remove(index); - for (ListDataListener listener : listeners) { - listener.intervalRemoved(new ListDataEvent(action, ListDataEvent.INTERVAL_REMOVED, index, index)); - } - } - } - - public List getAllActions() { - return cleanupActions; - } - - @Override - public int getSize() { - return cleanupActions.size(); - } - - @Override - public FieldFormatterCleanup getElementAt(int index) { - return cleanupActions.get(index); - } - - @Override - public void addListDataListener(ListDataListener l) { - listeners.add(l); - } - - @Override - public void removeListDataListener(ListDataListener l) { - listeners.remove(l); - } - - public void reset(FieldFormatterCleanups defaultFormatters) { - cleanupActions = new ArrayList<>(defaultFormatters.getConfiguredActions()); - for (ListDataListener listener : listeners) { - listener.contentsChanged(new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, 0, cleanupActions.size())); - } - } -} diff --git a/src/main/java/org/jabref/gui/customizefields/CustomizeGeneralFieldsDialogView.java b/src/main/java/org/jabref/gui/customizefields/CustomizeGeneralFieldsDialogView.java index a36f44bb86d..e2e6fe781fb 100644 --- a/src/main/java/org/jabref/gui/customizefields/CustomizeGeneralFieldsDialogView.java +++ b/src/main/java/org/jabref/gui/customizefields/CustomizeGeneralFieldsDialogView.java @@ -36,11 +36,7 @@ public CustomizeGeneralFieldsDialogView() { .load() .setAsDialogPane(this); - HelpAction helpCommand = new HelpAction(HelpFile.GENERAL_FIELDS); - //HelpAction is written with Swing, not JavaFX, so runCommand() cannot be used normally. Here I am reaching into - //the command and running execute. When HelpAction is converted to JavaFX, - //the following will need to be changed. - ControlHelper.setAction(helpButton, getDialogPane(), event -> helpCommand.getCommand().execute()); + ControlHelper.setAction(helpButton, getDialogPane(), event -> new HelpAction(HelpFile.GENERAL_FIELDS).execute()); ControlHelper.setAction(resetButton, getDialogPane(), event -> resetFields()); ControlHelper.setAction(okButton, getDialogPane(), event -> saveFieldsAndCloseDialog()); diff --git a/src/main/java/org/jabref/gui/entryeditor/EntryEditor.java b/src/main/java/org/jabref/gui/entryeditor/EntryEditor.java index 450da9e98d9..4ebdb2b1b72 100644 --- a/src/main/java/org/jabref/gui/entryeditor/EntryEditor.java +++ b/src/main/java/org/jabref/gui/entryeditor/EntryEditor.java @@ -376,7 +376,7 @@ private void setupToolBar() { typeLabel.setText(typedEntry.getTypeForDisplay()); // Add type change menu - ContextMenu typeMenu = new ChangeEntryTypeMenu(preferences.getKeyBindings()).getChangeEntryTypePopupMenu(entry, databaseContext, undoManager); + ContextMenu typeMenu = new ChangeEntryTypeMenu().getChangeEntryTypePopupMenu(entry, databaseContext, undoManager); typeLabel.setOnMouseClicked(event -> typeMenu.show(typeLabel, Side.RIGHT, 0, 0)); typeChangeButton.setOnMouseClicked(event -> typeMenu.show(typeChangeButton, Side.RIGHT, 0, 0)); // Add menu for fetching bibliographic information diff --git a/src/main/java/org/jabref/gui/externalfiles/DownloadExternalFile.java b/src/main/java/org/jabref/gui/externalfiles/DownloadExternalFile.java deleted file mode 100644 index b4e1ad794db..00000000000 --- a/src/main/java/org/jabref/gui/externalfiles/DownloadExternalFile.java +++ /dev/null @@ -1,345 +0,0 @@ -package org.jabref.gui.externalfiles; - -import java.io.File; -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URL; -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.SwingUtilities; - -import org.jabref.Globals; -import org.jabref.JabRefExecutorService; -import org.jabref.gui.DialogService; -import org.jabref.gui.externalfiletype.ExternalFileType; -import org.jabref.gui.externalfiletype.ExternalFileTypes; -import org.jabref.gui.filelist.FileListEntryEditor; -import org.jabref.logic.l10n.Localization; -import org.jabref.logic.net.URLDownload; -import org.jabref.logic.util.OS; -import org.jabref.logic.util.io.FileUtil; -import org.jabref.model.database.BibDatabaseContext; -import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.LinkedFile; -import org.jabref.preferences.JabRefPreferences; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * 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. - *

- * 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. - *

- * If the download is canceled, or failed, the user is informed. The callback is never called. - */ -public class DownloadExternalFile { - - private static final Logger LOGGER = LoggerFactory.getLogger(DownloadExternalFile.class); - - private final BibDatabaseContext databaseContext; - private final BibEntry entry; - private final DialogService dialogService; - - private FileListEntryEditor editor; - private boolean downloadFinished; - private boolean dontShowDialog; - - public DownloadExternalFile(DialogService dialogService, BibDatabaseContext databaseContext, BibEntry entry) { - this.dialogService = dialogService; - this.databaseContext = databaseContext; - this.entry = entry; - } - - /** - * 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") - */ - public static 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; - } - } - - /** - * 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; - - Optional res = dialogService.showInputDialogAndWait(Localization.lang("Download file"), Localization.lang("Enter URL to download")); - - if (res.isPresent()) { - URL url; - try { - url = new URL(res.get()); - } catch (MalformedURLException ex1) { - dialogService.showErrorDialogAndWait(Localization.lang("Download file"), - Localization.lang("Invalid URL")); - - return; - } - download(url, callback); - } - } - - public void download(URL url, final DownloadCallback callback) throws IOException { - // TODO: what if this takes long time? - // TODO: stop editor dialog if this results in an error? - String mimeType = new URLDownload(url).getMimeType(); - download(url, mimeType, callback); - } - - private Optional getExternalFileType(String mimeType) { - Optional suggestedType = Optional.empty(); - if (mimeType != null) { - LOGGER.debug("MIME Type suggested: " + mimeType); - suggestedType = ExternalFileTypes.getInstance().getExternalFileTypeByMimeType(mimeType); - } - return suggestedType; - } - - /** - * Start a download. - * - * @param callback The object to which the filename should be reported when download - * is complete. - */ - public void download(URL url, String mimeType, final DownloadCallback callback) throws IOException { - Optional fileType = getExternalFileType(mimeType); - - // First of all, start the download itself in the background to a temporary file: - final Path tempFile = Files.createTempFile("jabref_download", "tmp"); - tempFile.toFile().deleteOnExit(); - - final URLDownload fileDownload = new URLDownload(url); - - JabRefExecutorService.INSTANCE.execute(() -> { - try { - fileDownload.toFile(tempFile); - } catch (IOException e) { - dontShowDialog = true; - if ((editor != null) && editor.isVisible()) { - editor.setVisible(false, false); - } - - LOGGER.info("Error while downloading " + "'" + url + "'", e); - - dialogService.showErrorDialogAndWait(Localization.lang("Download file"), Localization.lang("Invalid URL") + ": " + e.getMessage()); - - return; - } - // Download finished: call the method that stops the progress bar etc.: - SwingUtilities.invokeLater(DownloadExternalFile.this::downloadFinished); - }); - - // Then, while the download is proceeding, let the user choose the details of the file: - String suffix; - if (fileType.isPresent()) { - suffix = fileType.get().getExtension(); - } else { - // If we did not find a file type from the MIME type, try based on extension: - suffix = getSuffix(url.toString()); - if (suffix == null) { - suffix = ""; - } - fileType = ExternalFileTypes.getInstance().getExternalFileTypeByExt(suffix); - } - String suggestedName = getSuggestedFileName(suffix); - List fDirectory = databaseContext.getFileDirectories(Globals.prefs.getFilePreferences()); - 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); - LinkedFile fileListEntry = new LinkedFile("", file.getCanonicalPath(), fileType.map(ExternalFileType::getName).orElse("")); - editor = new FileListEntryEditor(fileListEntry, true, false, databaseContext, true); - editor.getProgressBar().setIndeterminate(true); - editor.setOkEnabled(false); - editor.setExternalConfirm(closeEntry -> { - File f = directory == null ? new File(closeEntry.getLink()) : expandFilename(directory, closeEntry.getLink()); - if (f.isDirectory()) { - dialogService.showErrorDialogAndWait(Localization.lang("Download file"), - Localization.lang("Target file cannot be a directory.")); - - return false; - } - if (f.exists()) { - return dialogService.showConfirmationDialogAndWait(Localization.lang("Download file"), - Localization.lang("'%0' exists. Overwrite file?", f.getName()), Localization.lang("Overwrite file"), - Localization.lang("Cancel")); - - } 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.getLink()) : expandFilename(directory, - fileListEntry.getLink()); - 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(tempFile, 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.getLink().startsWith(directory) - && (fileListEntry.getLink().length() > dirPrefix.length())) { - fileListEntry = new LinkedFile(fileListEntry.getDescription(), - fileListEntry.getLink().substring(dirPrefix.length()), fileListEntry.getFileType()); - } - callback.downloadComplete(fileListEntry); - - if (!Files.deleteIfExists(tempFile)) { - LOGGER.info("Cannot delete temporary file"); - } - } else { - // Canceled. Just delete the temp file: - if (downloadFinished && !Files.deleteIfExists(tempFile)) { - 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)); - - 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; - } - - /** - * Callback interface that users of this class must implement in order to receive - * notification when download is complete. - */ - @FunctionalInterface - public interface DownloadCallback { - - void downloadComplete(LinkedFile file); - } -} diff --git a/src/main/java/org/jabref/gui/fieldeditors/JTextAreaWithHighlighting.java b/src/main/java/org/jabref/gui/fieldeditors/JTextAreaWithHighlighting.java deleted file mode 100644 index 05bb4c791b4..00000000000 --- a/src/main/java/org/jabref/gui/fieldeditors/JTextAreaWithHighlighting.java +++ /dev/null @@ -1,173 +0,0 @@ -package org.jabref.gui.fieldeditors; - -import java.awt.event.ActionEvent; -import java.util.Optional; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import javax.swing.AbstractAction; -import javax.swing.KeyStroke; -import javax.swing.text.BadLocationException; -import javax.swing.text.DefaultHighlighter; -import javax.swing.text.Document; -import javax.swing.text.Highlighter; -import javax.swing.text.Keymap; -import javax.swing.undo.CannotRedoException; -import javax.swing.undo.CannotUndoException; -import javax.swing.undo.UndoManager; - -import org.jabref.Globals; -import org.jabref.gui.actions.Actions; -import org.jabref.gui.util.component.JTextAreaWithPlaceholder; -import org.jabref.logic.search.SearchQueryHighlightListener; -import org.jabref.preferences.JabRefPreferences; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class JTextAreaWithHighlighting extends JTextAreaWithPlaceholder implements SearchQueryHighlightListener { - - private static final Logger LOGGER = LoggerFactory.getLogger(JTextAreaWithHighlighting.class); - - private Optional highlightPattern = Optional.empty(); - - private UndoManager undo; - - public JTextAreaWithHighlighting() { - this(""); - } - - public JTextAreaWithHighlighting(String text) { - this(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(); - } - - private void setupPasteListener() { - // Bind paste command to KeyBinds.PASTE - getInputMap().put(Globals.getKeyPrefs().getKey(org.jabref.gui.keyboard.KeyBinding.PASTE), Actions.PASTE); - } - - private void setupUndoRedo() { - undo = new UndoManager(); - Document doc = getDocument(); - - // Listen for undo and redo events - doc.addUndoableEditListener(evt -> undo.addEdit(evt.getEdit())); - - // Create an undo action and add it to the text component - getActionMap().put("Undo", new AbstractAction("Undo") { - - @Override - public void actionPerformed(ActionEvent evt) { - try { - if (undo.canUndo()) { - undo.undo(); - } - } catch (CannotUndoException ignored) { - // Ignored - } - } - }); - - // Bind the undo action to ctl-Z - getInputMap().put(Globals.getKeyPrefs().getKey(org.jabref.gui.keyboard.KeyBinding.UNDO), "Undo"); - - // Create a redo action and add it to the text component - getActionMap().put("Redo", new AbstractAction(Actions.REDO.name()) { - - @Override - public void actionPerformed(ActionEvent evt) { - try { - if (undo.canRedo()) { - undo.redo(); - } - } catch (CannotRedoException ignored) { - // Ignored - } - } - }); - - // Bind the redo action to ctrl-Y - boolean bind = true; - KeyStroke redoKey = Globals.getKeyPrefs().getKey(org.jabref.gui.keyboard.KeyBinding.REDO); - if (Globals.prefs.getBoolean(JabRefPreferences.EDITOR_EMACS_KEYBINDINGS)) { - // If emacs is enabled, check if we have a conflict at keys - // If yes, do not bind - // Typically, we have: CTRL+y is "yank" in emacs and REDO in 'normal' settings - // The Emacs key bindings are stored in the keymap, not in the input map. - Keymap keymap = getKeymap(); - KeyStroke[] keys = keymap.getBoundKeyStrokes(); - int i = 0; - while ((i < keys.length) && !keys[i].equals(redoKey)) { - i++; - } - if (i < keys.length) { - // conflict found -> do not bind - bind = false; - } - } - if (bind) { - getInputMap().put(redoKey, "Redo"); - } - } - - /** - * Highlight words in the Textarea - * - * @param words to highlight - */ - private void highLight() { - // highlight all characters that appear in charsToHighlight - Highlighter highlighter = getHighlighter(); - highlighter.removeAllHighlights(); - - if ((highlightPattern == null) || !highlightPattern.isPresent()) { - return; - } - String content = getText(); - if (content.isEmpty()) { - return; - } - - highlightPattern.ifPresent(pattern -> { - Matcher matcher = pattern.matcher(content); - while (matcher.find()) { - try { - highlighter.addHighlight(matcher.start(), matcher.end(), DefaultHighlighter.DefaultPainter); - } catch (BadLocationException ble) { - // should not occur if matcher works right - LOGGER.warn("Highlighting not possible, bad location", ble); - } - } - }); - - } - - @Override - public void setText(String text) { - super.setText(text); - highLight(); - if (undo != null) { - undo.discardAllEdits(); - } - } - - @Override - public void highlightPattern(Optional highlightPattern) { - this.highlightPattern = highlightPattern; - highLight(); - } - -} diff --git a/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java index 68da8aec6f5..c4f11bb73b3 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java @@ -26,7 +26,6 @@ import org.jabref.gui.AbstractViewModel; import org.jabref.gui.DialogService; import org.jabref.gui.desktop.JabRefDesktop; -import org.jabref.gui.externalfiles.DownloadExternalFile; import org.jabref.gui.externalfiles.FileDownloadTask; import org.jabref.gui.externalfiletype.ExternalFileType; import org.jabref.gui.externalfiletype.ExternalFileTypes; @@ -38,6 +37,7 @@ import org.jabref.logic.externalfiles.LinkedFileHandler; import org.jabref.logic.l10n.Localization; import org.jabref.logic.net.URLDownload; +import org.jabref.logic.net.URLUtil; import org.jabref.logic.xmp.XmpPreferences; import org.jabref.logic.xmp.XmpUtilWriter; import org.jabref.model.database.BibDatabaseContext; @@ -439,12 +439,8 @@ private Optional inferFileTypeFromMimeType(URLDownload urlDown } private Optional inferFileTypeFromURL(String url) { - String extension = DownloadExternalFile.getSuffix(url); - if (extension != null) { - return ExternalFileTypes.getInstance().getExternalFileTypeByExt(extension); - } else { - return Optional.empty(); - } + return URLUtil.getSuffix(url) + .flatMap(extension -> ExternalFileTypes.getInstance().getExternalFileTypeByExt(extension)); } public LinkedFile getFile() { diff --git a/src/main/java/org/jabref/gui/fieldeditors/contextmenu/EditorMenus.java b/src/main/java/org/jabref/gui/fieldeditors/contextmenu/EditorMenus.java index 575403025f0..baaabbe8f93 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/contextmenu/EditorMenus.java +++ b/src/main/java/org/jabref/gui/fieldeditors/contextmenu/EditorMenus.java @@ -4,9 +4,6 @@ import java.util.List; import java.util.function.Supplier; -import javax.swing.AbstractAction; -import javax.swing.Action; - import javafx.scene.control.CustomMenuItem; import javafx.scene.control.Label; import javafx.scene.control.MenuItem; @@ -15,7 +12,10 @@ import javafx.scene.control.TextInputControl; import javafx.scene.control.Tooltip; +import org.jabref.Globals; +import org.jabref.gui.actions.ActionFactory; import org.jabref.gui.actions.CopyDoiUrlAction; +import org.jabref.gui.actions.StandardActions; import org.jabref.logic.formatter.bibtexfields.CleanupURLFormatter; import org.jabref.logic.formatter.bibtexfields.NormalizeNamesFormatter; import org.jabref.logic.l10n.Localization; @@ -74,9 +74,8 @@ public static Supplier> getNameMenu(final TextInputControl textIn */ public static Supplier> getDOIMenu(TextArea textArea) { return () -> { - AbstractAction copyDoiUrlAction = new CopyDoiUrlAction(textArea); - MenuItem copyDoiUrlMenuItem = new MenuItem((String) copyDoiUrlAction.getValue(Action.NAME)); - copyDoiUrlMenuItem.setOnAction(event -> copyDoiUrlAction.actionPerformed(null)); + ActionFactory factory = new ActionFactory(Globals.getKeyPrefs()); + MenuItem copyDoiUrlMenuItem = factory.createMenuItem(StandardActions.COPY_DOI, new CopyDoiUrlAction(textArea)); List menuItems = new ArrayList<>(); menuItems.add(copyDoiUrlMenuItem); diff --git a/src/main/java/org/jabref/gui/filelist/ConfirmCloseFileListEntryEditor.java b/src/main/java/org/jabref/gui/filelist/ConfirmCloseFileListEntryEditor.java deleted file mode 100644 index 92e92a8eaa9..00000000000 --- a/src/main/java/org/jabref/gui/filelist/ConfirmCloseFileListEntryEditor.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.jabref.gui.filelist; - -import org.jabref.model.entry.LinkedFile; - -/** - * 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. - */ -@FunctionalInterface -public interface ConfirmCloseFileListEntryEditor { - - boolean confirmClose(LinkedFile entry); -} diff --git a/src/main/java/org/jabref/gui/filelist/FileListEntryEditor.java b/src/main/java/org/jabref/gui/filelist/FileListEntryEditor.java deleted file mode 100644 index fc590f146e2..00000000000 --- a/src/main/java/org/jabref/gui/filelist/FileListEntryEditor.java +++ /dev/null @@ -1,386 +0,0 @@ -package org.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.nio.file.Paths; -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 org.jabref.Globals; -import org.jabref.gui.JabRefFrame; -import org.jabref.gui.desktop.JabRefDesktop; -import org.jabref.gui.externalfiletype.ExternalFileType; -import org.jabref.gui.externalfiletype.ExternalFileTypes; -import org.jabref.gui.externalfiletype.UnknownExternalFileType; -import org.jabref.gui.keyboard.KeyBinding; -import org.jabref.gui.util.DefaultTaskExecutor; -import org.jabref.gui.util.FileDialogConfiguration; -import org.jabref.logic.l10n.Localization; -import org.jabref.logic.util.io.FileUtil; -import org.jabref.model.database.BibDatabaseContext; -import org.jabref.model.entry.LinkedFile; -import org.jabref.model.util.FileHelper; -import org.jabref.preferences.JabRefPreferences; - -import com.jgoodies.forms.builder.ButtonBarBuilder; -import com.jgoodies.forms.builder.FormBuilder; -import com.jgoodies.forms.layout.FormLayout; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * 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. - * @deprecated Use {@link LinkedFileEditDialogView} - */ -@Deprecated -public class FileListEntryEditor { - - private static final Pattern REMOTE_LINK_PATTERN = Pattern.compile("[a-z]+://.*"); - - private static final Logger LOGGER = LoggerFactory.getLogger(FileListEntryEditor.class); - private final JTextField link = new JTextField(); - private final JTextField description = new JTextField(); - private final JButton ok = new JButton(Localization.lang("OK")); - private final JComboBox types; - private final JProgressBar prog = new JProgressBar(SwingConstants.HORIZONTAL); - private final JLabel downloadLabel = new JLabel(Localization.lang("Downloading...")); - private JDialog dialog; - //Do not make this variable final, as then the lambda action listener will fail on compile - private JabRefFrame frame; - private boolean showSaveDialog; - private ConfirmCloseFileListEntryEditor externalConfirm; - private LinkedFile entry; - //Do not make this variable final, as then the lambda action listener will fail on compiƶe - private BibDatabaseContext databaseContext; - private final ActionListener browsePressed = e -> { - String fileText = link.getText().trim(); - Optional file = FileHelper.expandFilename(this.databaseContext, fileText, - Globals.prefs.getFilePreferences()); - - Path workingDir = file.orElse(Paths.get(Globals.prefs.get(JabRefPreferences.WORKING_DIRECTORY))); - String fileName = Paths.get(fileText).getFileName().toString(); - - FileDialogConfiguration fileDialogConfiguration = new FileDialogConfiguration.Builder() - .withInitialDirectory(workingDir) - .withInitialFileName(fileName).build(); - - Optional path; - if (showSaveDialog) { - path = DefaultTaskExecutor.runInJavaFXThread(() -> frame.getDialogService().showFileSaveDialog(fileDialogConfiguration)); - } else { - path = DefaultTaskExecutor.runInJavaFXThread(() -> frame.getDialogService().showFileOpenDialog(fileDialogConfiguration)); - } - - path.ifPresent(newFile -> { - // Store the directory for next time: - Globals.prefs.put(JabRefPreferences.WORKING_DIRECTORY, newFile.toString()); - - // If the file is below the file directory, make the path relative: - List fileDirectories = this.databaseContext - .getFileDirectoriesAsPaths(Globals.prefs.getFilePreferences()); - newFile = FileUtil.relativize(newFile, fileDirectories); - - link.setText(newFile.toString()); - link.requestFocus(); - }); - }; - private boolean okPressed; - - private boolean okDisabledExternally; - private boolean openBrowseWhenShown; - - private boolean dontOpenBrowseUntilDisposed; - - public FileListEntryEditor(LinkedFile entry, boolean showProgressBar, boolean showOpenButton, BibDatabaseContext databaseContext, boolean showSaveDialog) { - this(entry, showProgressBar, showOpenButton, databaseContext); - this.showSaveDialog = showSaveDialog; - } - - public FileListEntryEditor(LinkedFile entry, boolean showProgressBar, boolean showOpenButton, BibDatabaseContext databaseContext) { - this.entry = entry; - this.databaseContext = databaseContext; - - 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; - } - } - dialog.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) { - dialog.dispose(); - } - }; - cancel.addActionListener(cancelAction); - - // Key bindings: - ActionMap am = builder.getPanel().getActionMap(); - InputMap im = builder.getPanel().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); - im.put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE), "close"); - am.put("close", cancelAction); - - 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(); - } - - }); - - dialog = new JDialog(); - dialog.setTitle(Localization.lang("Select files")); - dialog.setModal(true); - dialog.getContentPane().add(builder.getPanel(), BorderLayout.CENTER); - dialog.getContentPane().add(bb.getPanel(), BorderLayout.SOUTH); - dialog.pack(); - dialog.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 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(LinkedFile 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; - } - String title; - if (showSaveDialog) { - title = Localization.lang("Save file"); - } else { - title = Localization.lang("Select files"); - } - dialog.setTitle(title); - dialog.setVisible(visible); - } - - public boolean isVisible() { - return (dialog != null) && dialog.isVisible(); - } - - private void setValues(LinkedFile entry) { - description.setText(entry.getDescription()); - link.setText(entry.getLink()); - - Collection 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: - Optional fileType = ExternalFileTypes.getInstance().fromLinkedFile(entry, false); - if (fileType.isPresent() && !(fileType.get() instanceof UnknownExternalFileType)) { - types.setSelectedItem(fileType.get()); - } else if ((entry.getLink() != null) && (!entry.getLink().isEmpty())) { - checkExtension(); - } - } - - private void storeSettings(LinkedFile 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 dirs = databaseContext.getFileDirectories(Globals.prefs.getFilePreferences()); - 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.setDescription(descriptionText); - listEntry.setFileType(type.getName()); - listEntry.setLink(fileLink); - } - - public boolean okPressed() { - return okPressed; - } - -} diff --git a/src/main/java/org/jabref/gui/groups/GroupTreeCellRenderer.java b/src/main/java/org/jabref/gui/groups/GroupTreeCellRenderer.java deleted file mode 100644 index 4b128b2593d..00000000000 --- a/src/main/java/org/jabref/gui/groups/GroupTreeCellRenderer.java +++ /dev/null @@ -1,114 +0,0 @@ -package org.jabref.gui.groups; - -import java.awt.Color; -import java.awt.Component; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -import javax.swing.BorderFactory; -import javax.swing.JLabel; -import javax.swing.JTree; -import javax.swing.border.Border; -import javax.swing.tree.DefaultTreeCellRenderer; - -import org.jabref.model.groups.GroupTreeNode; - -/** - * Renders a GroupTreeNode using its group's getName() method, rather that its toString() method. - */ -public class GroupTreeCellRenderer extends DefaultTreeCellRenderer { - - /** The cell over which the user is currently dragging */ - private Object highlight1Cell; - private List overlappingGroups = new ArrayList<>(); - private List matchingGroups = new ArrayList<>(); - private Object highlightBorderCell; - - @Override - public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, - int row, boolean tmpHasFocus) { - // show as selected - selected = (Objects.equals(highlight1Cell, value)) || sel; - Component c = super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, tmpHasFocus); - // this is sometimes called from deep within somewhere, with a dummy - // value (probably for layout etc.), so we've got to check here! - if (!(value instanceof GroupTreeNodeViewModel)) { - return c; - } - if (!(c instanceof JLabel)) { - return c; // sanity check - } - - GroupTreeNodeViewModel viewModel = (GroupTreeNodeViewModel) value; - JLabel label = (JLabel) c; - - Border border; - if (Objects.equals(highlightBorderCell, value)) { - border = BorderFactory.createLineBorder(Color.BLACK); - } else { - border = BorderFactory.createEmptyBorder(); - } - if (label.getBorder() != border) { - label.setBorder(border); - } - - Boolean red = printInRed(viewModel) && !selected; // do not print currently selected node in red - Boolean underlined = printUnderlined(viewModel); - StringBuilder sb = new StringBuilder(60); - sb.append(""); - if (red) { - sb.append(""); - } - if (underlined) { - sb.append(""); - } - if (viewModel.printInItalics()) { - sb.append(""); - } - sb.append(viewModel.getName()); - if (viewModel.printInItalics()) { - sb.append(""); - } - if (underlined) { - sb.append(""); - } - if (red) { - sb.append(""); - } - sb.append(""); - - String text = sb.toString(); - if (!label.getText().equals(text)) { - label.setText(text); - } - label.setToolTipText(viewModel.getDescription()); - - return c; - } - - private boolean printInRed(GroupTreeNodeViewModel viewModel) { - if (viewModel.isAllEntriesGroup()) { - // Do not print all entries group in red - return false; - } - - return overlappingGroups.contains(viewModel.getNode()); - } - - private boolean printUnderlined(GroupTreeNodeViewModel viewModel) { - if (viewModel.isAllEntriesGroup()) { - // Do not underline all entries group - return false; - } - return matchingGroups.contains(viewModel.getNode()); - } - - /** - * Highlights the specified cells (by drawing a border around it), or disables highlight if highlightBorderCell == - * null. - */ - public void setHighlightBorderCell(Object highlightBorderCell) { - this.highlightBorderCell = highlightBorderCell; - } -} diff --git a/src/main/java/org/jabref/gui/help/HelpAction.java b/src/main/java/org/jabref/gui/help/HelpAction.java index d18d3f0b34b..603e055abaf 100644 --- a/src/main/java/org/jabref/gui/help/HelpAction.java +++ b/src/main/java/org/jabref/gui/help/HelpAction.java @@ -1,68 +1,39 @@ package org.jabref.gui.help; -import java.awt.event.ActionEvent; 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; -import javax.swing.KeyStroke; - import org.jabref.Globals; -import org.jabref.gui.actions.MnemonicAwareAction; import org.jabref.gui.actions.SimpleCommand; import org.jabref.gui.desktop.JabRefDesktop; -import org.jabref.gui.icon.IconTheme; import org.jabref.logic.help.HelpFile; -import org.jabref.logic.l10n.Localization; import org.jabref.preferences.JabRefPreferences; /** * This Action keeps a reference to a URL. When activated, it shows the help * Dialog unless it is already visible, and shows the URL in it. */ -public class HelpAction extends MnemonicAwareAction { +public class HelpAction extends SimpleCommand { /** * New languages of the help have to be added here */ - private static final Set AVAIABLE_LANG_FILES = Stream.of("en", "de", "fr", "in", "ja") - .collect(Collectors.toCollection(HashSet::new)); + private static final Set AVAILABLE_LANG_FILES = Stream.of("en", "de", "fr", "in", "ja") + .collect(Collectors.toCollection(HashSet::new)); private HelpFile helpPage; - - public HelpAction(String title, String tooltip, HelpFile helpPage, KeyStroke key) { - this(title, tooltip, helpPage, IconTheme.JabRefIcons.HELP.getSmallIcon()); - putValue(Action.ACCELERATOR_KEY, key); - } - - private HelpAction(String title, String tooltip, HelpFile helpPage, Icon icon) { - super(icon); - this.helpPage = helpPage; - putValue(Action.NAME, title); - putValue(Action.SHORT_DESCRIPTION, tooltip); - } - - public HelpAction(String tooltip, HelpFile helpPage) { - this(Localization.lang("Help"), tooltip, helpPage, IconTheme.JabRefIcons.HELP.getSmallIcon()); - } - - public HelpAction(HelpFile helpPage, Icon icon) { - this(Localization.lang("Help"), Localization.lang("Help"), helpPage, icon); - } - public HelpAction(HelpFile helpPage) { - this(Localization.lang("Help"), Localization.lang("Help"), helpPage, IconTheme.JabRefIcons.HELP.getSmallIcon()); + this.helpPage = helpPage; } public static void openHelpPage(HelpFile helpPage) { String lang = Globals.prefs.get(JabRefPreferences.LANGUAGE); StringBuilder sb = new StringBuilder("https://help.jabref.org/"); - if (AVAIABLE_LANG_FILES.contains(lang)) { + if (AVAILABLE_LANG_FILES.contains(lang)) { sb.append(lang); sb.append("/"); } else { @@ -72,15 +43,6 @@ public static void openHelpPage(HelpFile helpPage) { JabRefDesktop.openBrowserShowPopup(sb.toString()); } - public void setHelpFile(HelpFile urlPart) { - this.helpPage = urlPart; - } - - @Override - public void actionPerformed(ActionEvent e) { - openHelpPage(helpPage); - } - public static SimpleCommand getMainHelpPageCommand() { return new SimpleCommand() { @Override @@ -90,12 +52,8 @@ public void execute() { }; } - public SimpleCommand getCommand() { - return new SimpleCommand() { - @Override - public void execute() { - openHelpPage(helpPage); - } - }; + @Override + public void execute() { + openHelpPage(helpPage); } } diff --git a/src/main/java/org/jabref/gui/importer/fetcher/WebSearchPane.java b/src/main/java/org/jabref/gui/importer/fetcher/WebSearchPane.java index 30ee0635043..b3851939465 100644 --- a/src/main/java/org/jabref/gui/importer/fetcher/WebSearchPane.java +++ b/src/main/java/org/jabref/gui/importer/fetcher/WebSearchPane.java @@ -59,8 +59,7 @@ protected Node createContentPane() { ActionFactory factory = new ActionFactory(preferences.getKeyBindingRepository()); EasyBind.subscribe(viewModel.selectedFetcherProperty(), fetcher -> { if ((fetcher != null) && fetcher.getHelpPage().isPresent()) { - HelpAction helpCommand = new HelpAction(fetcher.getHelpPage().get()); - Button helpButton = factory.createIconButton(StandardActions.HELP, helpCommand.getCommand()); + Button helpButton = factory.createIconButton(StandardActions.HELP, new HelpAction(fetcher.getHelpPage().get())); helpButtonContainer.getChildren().setAll(helpButton); } else { helpButtonContainer.getChildren().clear(); diff --git a/src/main/java/org/jabref/gui/keyboard/KeyBinder.java b/src/main/java/org/jabref/gui/keyboard/KeyBinder.java deleted file mode 100644 index 1944bd038cd..00000000000 --- a/src/main/java/org/jabref/gui/keyboard/KeyBinder.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.jabref.gui.keyboard; - -import javax.swing.Action; -import javax.swing.ActionMap; -import javax.swing.InputMap; -import javax.swing.JComponent; -import javax.swing.JRootPane; - -import org.jabref.Globals; - -public class KeyBinder { - - private KeyBinder() { - } - - /** - * Binds ESC-Key to cancel button - * - * @param rootPane the pane to bind the action to. Typically, this variable is retrieved by this.getRootPane(); - * @param cancelAction the action to bind - */ - public static void bindCloseDialogKeyToCancelAction(JRootPane rootPane, Action cancelAction) { - InputMap im = rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); - ActionMap am = rootPane.getActionMap(); - im.put(Globals.getKeyPrefs().getKey(KeyBinding.CLOSE), "close"); - am.put("close", cancelAction); - } - -} diff --git a/src/main/java/org/jabref/gui/maintable/MainTable.java b/src/main/java/org/jabref/gui/maintable/MainTable.java index d852104c1fd..892116fb337 100644 --- a/src/main/java/org/jabref/gui/maintable/MainTable.java +++ b/src/main/java/org/jabref/gui/maintable/MainTable.java @@ -83,17 +83,17 @@ public MainTable(MainTableDataModel model, JabRefFrame frame, this.getColumns().addAll(new MainTableColumnFactory(database, preferences.getColumnPreferences(), externalFileTypes, panel.getUndoManager(), frame.getDialogService()).createColumns()); new ViewModelTableRowFactory() - .withOnMouseClickedEvent((entry, event) -> { + .withOnMouseClickedEvent((entry, event) -> { if (event.getClickCount() == 2) { panel.showAndEdit(entry.getEntry()); } }) - .withContextMenu(entry -> RightClickMenu.create(entry, keyBindingRepository, panel, Globals.getKeyPrefs(), frame.getDialogService())) - .setOnDragDetected(this::handleOnDragDetected) - .setOnDragDropped(this::handleOnDragDropped) - .setOnDragOver(this::handleOnDragOver) - .setOnMouseDragEntered(this::handleOnDragEntered) - .install(this); + .withContextMenu(entry -> RightClickMenu.create(entry, keyBindingRepository, panel, frame.getDialogService())) + .setOnDragDetected(this::handleOnDragDetected) + .setOnDragDropped(this::handleOnDragDropped) + .setOnDragOver(this::handleOnDragOver) + .setOnMouseDragEntered(this::handleOnDragEntered) + .install(this); /*for (Entry entries : preferences.getColumnPreferences().getSortTypesForColumns().entrySet()) { Optional> column = this.getColumns().stream().filter(col -> entries.getKey().equals(col.getText())).findFirst(); diff --git a/src/main/java/org/jabref/gui/maintable/RightClickMenu.java b/src/main/java/org/jabref/gui/maintable/RightClickMenu.java index 3070a50a2b7..66b1c5c3765 100644 --- a/src/main/java/org/jabref/gui/maintable/RightClickMenu.java +++ b/src/main/java/org/jabref/gui/maintable/RightClickMenu.java @@ -29,7 +29,7 @@ public class RightClickMenu { - public static ContextMenu create(BibEntryTableViewModel entry, KeyBindingRepository keyBindingRepository, BasePanel panel, KeyBindingRepository keyBindings, DialogService dialogService) { + public static ContextMenu create(BibEntryTableViewModel entry, KeyBindingRepository keyBindingRepository, BasePanel panel, DialogService dialogService) { ContextMenu contextMenu = new ContextMenu(); ActionFactory factory = new ActionFactory(keyBindingRepository); @@ -79,7 +79,7 @@ public static ContextMenu create(BibEntryTableViewModel entry, KeyBindingReposit contextMenu.getItems().add(new SeparatorMenuItem()); - contextMenu.getItems().add(new ChangeEntryTypeMenu(keyBindings).getChangeEntryTypeMenu(entry.getEntry(), panel.getBibDatabaseContext(), panel.getUndoManager())); + contextMenu.getItems().add(new ChangeEntryTypeMenu().getChangeEntryTypeMenu(entry.getEntry(), panel.getBibDatabaseContext(), panel.getUndoManager())); contextMenu.getItems().add(factory.createMenuItem(StandardActions.MERGE_WITH_FETCHED_ENTRY, getFetchEntryData(panel))); contextMenu.getItems().add(factory.createMenuItem(StandardActions.ATTACH_FILE, new AttachFileAction(panel, dialogService))); contextMenu.getItems().add(factory.createMenuItem(StandardActions.MERGE_ENTRIES, mergeEntries(panel))); diff --git a/src/main/java/org/jabref/gui/menus/ChangeEntryTypeMenu.java b/src/main/java/org/jabref/gui/menus/ChangeEntryTypeMenu.java index f65f4517030..eb7ca539262 100644 --- a/src/main/java/org/jabref/gui/menus/ChangeEntryTypeMenu.java +++ b/src/main/java/org/jabref/gui/menus/ChangeEntryTypeMenu.java @@ -1,14 +1,8 @@ package org.jabref.gui.menus; -import java.awt.Font; import java.util.Collection; -import java.util.HashMap; import java.util.List; -import java.util.Map; -import javax.swing.JMenu; -import javax.swing.JMenuItem; -import javax.swing.KeyStroke; import javax.swing.undo.UndoManager; import javafx.collections.ObservableList; @@ -17,11 +11,9 @@ import javafx.scene.control.MenuItem; import javafx.scene.control.SeparatorMenuItem; -import org.jabref.gui.BasePanel; -import org.jabref.gui.actions.ChangeTypeAction; -import org.jabref.gui.keyboard.KeyBinding; -import org.jabref.gui.keyboard.KeyBindingRepository; import org.jabref.gui.undo.CountingUndoManager; +import org.jabref.gui.undo.NamedCompound; +import org.jabref.gui.undo.UndoableChangeType; import org.jabref.logic.l10n.Localization; import org.jabref.model.EntryTypes; import org.jabref.model.database.BibDatabaseContext; @@ -32,23 +24,20 @@ import org.jabref.model.entry.IEEETranEntryTypes; public class ChangeEntryTypeMenu { - public final Map entryShortCuts = new HashMap<>(); - - public ChangeEntryTypeMenu(KeyBindingRepository keyBindings) { - entryShortCuts.put(BibtexEntryTypes.ARTICLE.getName(), keyBindings.getKey(KeyBinding.NEW_ARTICLE)); - entryShortCuts.put(BibtexEntryTypes.BOOK.getName(), keyBindings.getKey(KeyBinding.NEW_BOOK)); - entryShortCuts.put(BibtexEntryTypes.PHDTHESIS.getName(), keyBindings.getKey(KeyBinding.NEW_PHDTHESIS)); - entryShortCuts.put(BibtexEntryTypes.INBOOK.getName(), keyBindings.getKey(KeyBinding.NEW_MASTERSTHESIS)); - entryShortCuts.put(BibtexEntryTypes.INBOOK.getName(), keyBindings.getKey(KeyBinding.NEW_INBOOK)); - entryShortCuts.put(BibtexEntryTypes.PROCEEDINGS.getName(), keyBindings.getKey(KeyBinding.NEW_PROCEEDINGS)); - entryShortCuts.put(BibtexEntryTypes.UNPUBLISHED.getName(), keyBindings.getKey(KeyBinding.NEW_UNPUBLISHED)); - entryShortCuts.put(BibtexEntryTypes.TECHREPORT.getName(), keyBindings.getKey(KeyBinding.NEW_TECHREPORT)); + + public ChangeEntryTypeMenu() { + } - public JMenu getChangeEntryTypeMenu(BasePanel panel) { - JMenu menu = new JMenu(Localization.lang("Change entry type")); - populateChangeEntryTypeMenu(menu, panel); - return menu; + public static MenuItem createMenuItem(EntryType type, BibEntry entry, UndoManager undoManager) { + MenuItem menuItem = new MenuItem(type.getName()); + menuItem.setOnAction(event -> { + NamedCompound compound = new NamedCompound(Localization.lang("Change entry type")); + entry.setType(type) + .ifPresent(change -> compound.addEdit(new UndoableChangeType(change))); + undoManager.addEdit(compound); + }); + return menuItem; } public ContextMenu getChangeEntryTypePopupMenu(BibEntry entry, BibDatabaseContext bibDatabaseContext, CountingUndoManager undoManager) { @@ -95,61 +84,11 @@ private void populateSubMenu(ObservableList items, String text, List items, Collection types, BibEntry entry, UndoManager undoManager) { for (EntryType type : types) { - items.add(ChangeTypeAction.as(type, entry, undoManager)); + items.add(createMenuItem(type, entry, undoManager)); } } private void populate(Menu menu, Collection types, BibEntry entry, UndoManager undoManager) { populate(menu.getItems(), types, entry, undoManager); } - - /** - * Remove all types from the menu. Then cycle through all available - * types, and add them. - */ - private void populateChangeEntryTypeMenu(JMenu menu, BasePanel panel) { - menu.removeAll(); - - // biblatex? - if (panel.getBibDatabaseContext().isBiblatexMode()) { - for (EntryType type : EntryTypes.getAllValues(BibDatabaseMode.BIBLATEX)) { - menu.add(new ChangeTypeAction(type, panel)); - } - - List customTypes = EntryTypes.getAllCustomTypes(BibDatabaseMode.BIBLATEX); - if (!customTypes.isEmpty()) { - menu.addSeparator(); - // custom types - createEntryTypeSection(panel, menu, "Custom Entries", customTypes); - } - } else { - // Bibtex - createEntryTypeSection(panel, menu, "BibTeX Entries", BibtexEntryTypes.ALL); - menu.addSeparator(); - // ieeetran - createEntryTypeSection(panel, menu, "IEEETran Entries", IEEETranEntryTypes.ALL); - - List customTypes = EntryTypes.getAllCustomTypes(BibDatabaseMode.BIBTEX); - if (!customTypes.isEmpty()) { - menu.addSeparator(); - // custom types - createEntryTypeSection(panel, menu, "Custom Entries", customTypes); - } - } - } - - private void createEntryTypeSection(BasePanel panel, JMenu menu, String title, List types) { - // bibtex - JMenuItem header = new JMenuItem(title); - Font font = new Font(menu.getFont().getName(), Font.ITALIC, menu.getFont().getSize()); - header.setFont(font); - header.setEnabled(false); - if (!types.isEmpty()) { - menu.add(header); - } - - for (EntryType type : types) { - menu.add(new ChangeTypeAction(type, panel)); - } - } } diff --git a/src/main/java/org/jabref/gui/openoffice/OpenOfficePanel.java b/src/main/java/org/jabref/gui/openoffice/OpenOfficePanel.java index 7d2c1c20e70..c56e7606c29 100644 --- a/src/main/java/org/jabref/gui/openoffice/OpenOfficePanel.java +++ b/src/main/java/org/jabref/gui/openoffice/OpenOfficePanel.java @@ -117,9 +117,7 @@ public OpenOfficePanel(JabRefFrame frame, JabRefPreferences jabRefPreferences, O manualConnect.setTooltip(new Tooltip(Localization.lang("Manual connect"))); manualConnect.setMaxWidth(Double.MAX_VALUE); - HelpAction helpCommand = new HelpAction(HelpFile.OPENOFFICE_LIBREOFFICE); - - help = factory.createIconButton(StandardActions.HELP, helpCommand.getCommand()); + help = factory.createIconButton(StandardActions.HELP, new HelpAction(HelpFile.OPENOFFICE_LIBREOFFICE)); help.setMaxWidth(Double.MAX_VALUE); selectDocument = new Button(); diff --git a/src/main/java/org/jabref/gui/preferences/AdvancedTab.java b/src/main/java/org/jabref/gui/preferences/AdvancedTab.java index 4a8dbf0a075..03f67d319cb 100644 --- a/src/main/java/org/jabref/gui/preferences/AdvancedTab.java +++ b/src/main/java/org/jabref/gui/preferences/AdvancedTab.java @@ -80,7 +80,7 @@ public AdvancedTab(DialogService dialogService, JabRefPreferences prefs) { p.getChildren().add(remoteServerPort); ActionFactory factory = new ActionFactory(preferences.getKeyBindingRepository()); - Button help = factory.createIconButton(StandardActions.HELP, new HelpAction(HelpFile.REMOTE).getCommand()); + Button help = factory.createIconButton(StandardActions.HELP, new HelpAction(HelpFile.REMOTE)); help.setMaxWidth(Double.MAX_VALUE); p.getChildren().add(help); diff --git a/src/main/java/org/jabref/gui/preferences/FileTab.java b/src/main/java/org/jabref/gui/preferences/FileTab.java index 4067cf08751..060afb272cd 100644 --- a/src/main/java/org/jabref/gui/preferences/FileTab.java +++ b/src/main/java/org/jabref/gui/preferences/FileTab.java @@ -143,8 +143,7 @@ public FileTab(DialogService dialogService, JabRefPreferences prefs) { matchExactKeyOnly.setToggleGroup(autolinkGroup); useRegExpComboBox.setToggleGroup(autolinkGroup); - Button help = factory.createIconButton(StandardActions.HELP, new HelpAction(Localization.lang("Help on regular expression search"), - HelpFile.REGEX_SEARCH).getCommand()); + Button help = factory.createIconButton(StandardActions.HELP_REGEX_SEARCH, new HelpAction(HelpFile.REGEX_SEARCH)); builder.add(help, 3, 16); builder.add(runAutoFileSearch, 1, 17); builder.add(allowFileAutoOpenBrowse, 1, 18); @@ -157,7 +156,7 @@ public FileTab(DialogService dialogService, JabRefPreferences prefs) { builder.add(autosave, 1, 20); builder.add(localAutoSave, 1, 21); - Button helpAutosave = factory.createIconButton(StandardActions.HELP, new HelpAction(HelpFile.AUTOSAVE).getCommand()); + Button helpAutosave = factory.createIconButton(StandardActions.HELP, new HelpAction(HelpFile.AUTOSAVE)); builder.add(helpAutosave, 2, 21); } diff --git a/src/main/java/org/jabref/gui/preferences/GeneralTab.java b/src/main/java/org/jabref/gui/preferences/GeneralTab.java index c7f3759755d..4dacdd38e8a 100644 --- a/src/main/java/org/jabref/gui/preferences/GeneralTab.java +++ b/src/main/java/org/jabref/gui/preferences/GeneralTab.java @@ -95,7 +95,7 @@ public GeneralTab(DialogService dialogService, JabRefPreferences prefs) { builder.add(defOwnerField, 2, 10); builder.add(overwriteOwner, 3, 10); - Button helpOwner = factory.createIconButton(StandardActions.HELP, new HelpAction(HelpFile.OWNER).getCommand()); + Button helpOwner = factory.createIconButton(StandardActions.HELP, new HelpAction(HelpFile.OWNER)); builder.add(helpOwner, 4, 10); builder.add(useTimeStamp, 1, 13); @@ -105,7 +105,7 @@ public GeneralTab(DialogService dialogService, JabRefPreferences prefs) { builder.add(fieldName, 3, 13); builder.add(timeStampField, 4, 13); - Button helpTimestamp = factory.createIconButton(StandardActions.HELP, new HelpAction(HelpFile.TIMESTAMP).getCommand()); + Button helpTimestamp = factory.createIconButton(StandardActions.HELP, new HelpAction(HelpFile.TIMESTAMP)); builder.add(helpTimestamp, 6, 13); builder.add(updateTimeStamp, 1, 14); diff --git a/src/main/java/org/jabref/gui/preferences/NameFormatterTab.java b/src/main/java/org/jabref/gui/preferences/NameFormatterTab.java index da1f649fb2c..bfc0de4fbfd 100644 --- a/src/main/java/org/jabref/gui/preferences/NameFormatterTab.java +++ b/src/main/java/org/jabref/gui/preferences/NameFormatterTab.java @@ -151,8 +151,7 @@ public NameFormatterTab(JabRefPreferences prefs) { } }); - Button help = factory.createIconButton(StandardActions.HELP, new HelpAction(Localization.lang("Help on Name Formatting"), - HelpFile.CUSTOM_EXPORTS_NAME_FORMATTER).getCommand()); + Button help = factory.createIconButton(StandardActions.HELP_NAME_FORMATTER, new HelpAction(HelpFile.CUSTOM_EXPORTS_NAME_FORMATTER)); HBox toolbar = new HBox(); toolbar.getChildren().addAll(addName, addLast, add, delete, help); tabPanel.setBottom(toolbar); diff --git a/src/main/java/org/jabref/gui/preferences/TableColumnsTab.java b/src/main/java/org/jabref/gui/preferences/TableColumnsTab.java index fe9dd582df7..38c252b642c 100644 --- a/src/main/java/org/jabref/gui/preferences/TableColumnsTab.java +++ b/src/main/java/org/jabref/gui/preferences/TableColumnsTab.java @@ -1,15 +1,11 @@ package org.jabref.gui.preferences; -import java.awt.event.ActionEvent; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Locale; -import javax.swing.AbstractAction; - import javafx.beans.property.SimpleDoubleProperty; import javafx.beans.property.SimpleStringProperty; import javafx.collections.FXCollections; @@ -50,7 +46,7 @@ class TableColumnsTab extends Pane implements PrefsTab { private final JabRefPreferences prefs; private boolean tableChanged; - private final TableView colSetup; + private final TableView colSetup; private final JabRefFrame frame; private final CheckBox urlColumn; @@ -229,8 +225,7 @@ public TableColumnsTab(JabRefPreferences prefs, JabRefFrame frame) { ActionFactory factory = new ActionFactory(prefs.getKeyBindingRepository()); - Button helpButton = factory.createIconButton(StandardActions.HELP, new HelpAction(Localization.lang("Help on special fields"), - HelpFile.SPECIAL_FIELDS).getCommand()); + Button helpButton = factory.createIconButton(StandardActions.HELP_SPECIAL_FIELDS, new HelpAction(HelpFile.SPECIAL_FIELDS)); rankingColumn = new CheckBox(Localization.lang("Show rank")); qualityColumn = new CheckBox(Localization.lang("Show quality")); @@ -299,7 +294,7 @@ public TableColumnsTab(JabRefPreferences prefs, JabRefFrame frame) { builder.add(tabPanel, 1, 5); Button buttonOrder = new Button("Update to current column order"); buttonOrder.setPrefSize(300, 30); - buttonOrder.setOnAction(e -> new UpdateOrderAction()); + buttonOrder.setOnAction(e -> updateOrderAction()); builder.add(buttonOrder, 1, 7); } @@ -517,23 +512,16 @@ public void storeSettings() { } - class UpdateOrderAction extends AbstractAction { - - public UpdateOrderAction() { - super(Localization.lang("Update to current column order")); + private void updateOrderAction() { + BasePanel panel = frame.getCurrentBasePanel(); + if (panel == null) { + return; } + // idea: sort elements according to value stored in hash, keep + // everything not inside hash/mainTable as it was + final HashMap map = new HashMap<>(); - @Override - public void actionPerformed(ActionEvent e) { - BasePanel panel = frame.getCurrentBasePanel(); - if (panel == null) { - return; - } - // idea: sort elements according to value stored in hash, keep - // everything not inside hash/mainTable as it was - final HashMap map = new HashMap<>(); - - // first element (#) not inside data + // first element (#) not inside data /* for (TableColumn column : panel.getMainTable().getColumns()) { String name = column.getText(); @@ -542,19 +530,18 @@ public void actionPerformed(ActionEvent e) { } } */ - Collections.sort(data, (o1, o2) -> { - Integer n1 = map.get(o1.getName()); - Integer n2 = map.get(o2.getName()); - if ((n1 == null) || (n2 == null)) { - return 0; - } - return n1.compareTo(n2); - }); + data.sort((o1, o2) -> { + Integer n1 = map.get(o1.getName()); + Integer n2 = map.get(o2.getName()); + if ((n1 == null) || (n2 == null)) { + return 0; + } + return n1.compareTo(n2); + }); - colSetup.setItems(data); - colSetup.refresh(); - tableChanged = true; - } + colSetup.setItems(data); + colSetup.refresh(); + tableChanged = true; } @Override diff --git a/src/main/java/org/jabref/gui/util/ControlHelper.java b/src/main/java/org/jabref/gui/util/ControlHelper.java index b5d139b338a..ca9b703880a 100644 --- a/src/main/java/org/jabref/gui/util/ControlHelper.java +++ b/src/main/java/org/jabref/gui/util/ControlHelper.java @@ -3,9 +3,6 @@ import java.util.function.Consumer; import java.util.function.UnaryOperator; -import javax.swing.JComponent; - -import javafx.embed.swing.SwingNode; import javafx.event.ActionEvent; import javafx.event.Event; import javafx.scene.Parent; @@ -24,13 +21,6 @@ public static void setAction(ButtonType buttonType, DialogPane dialogPane, Consu })); } - public static void setSwingContent(DialogPane dialogPane, JComponent content) { - SwingNode node = new SwingNode(); - node.setContent(content); - node.setVisible(true); - dialogPane.setContent(node); - } - public static boolean childIsFocused(Parent node) { return node.isFocused() || node.getChildrenUnmodifiable().stream().anyMatch(child -> { if (child instanceof Parent) { diff --git a/src/main/java/org/jabref/gui/util/component/CheckBoxMessage.java b/src/main/java/org/jabref/gui/util/component/CheckBoxMessage.java deleted file mode 100644 index 99aa890ca7d..00000000000 --- a/src/main/java/org/jabref/gui/util/component/CheckBoxMessage.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.jabref.gui.util.component; - -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.awt.Insets; - -import javax.swing.JCheckBox; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.SwingConstants; - -public class CheckBoxMessage extends JPanel { - - private final JCheckBox cb; - - - public CheckBoxMessage(String message, String cbText, boolean defaultValue) { - cb = new JCheckBox(cbText, defaultValue); - GridBagLayout gbl = new GridBagLayout(); - setLayout(gbl); - GridBagConstraints con = new GridBagConstraints(); - con.gridwidth = GridBagConstraints.REMAINDER; - - JLabel lab = new JLabel(message + '\n'); - cb.setHorizontalAlignment(SwingConstants.LEFT); - gbl.setConstraints(lab, con); - add(lab); - con.anchor = GridBagConstraints.WEST; - con.insets = new Insets(10, 0, 0, 0); - gbl.setConstraints(cb, con); - add(cb); - } - - public boolean isSelected() { - return cb.isSelected(); - } -} diff --git a/src/main/java/org/jabref/gui/util/component/JTextAreaWithPlaceholder.java b/src/main/java/org/jabref/gui/util/component/JTextAreaWithPlaceholder.java deleted file mode 100644 index 0c0c0b06acb..00000000000 --- a/src/main/java/org/jabref/gui/util/component/JTextAreaWithPlaceholder.java +++ /dev/null @@ -1,90 +0,0 @@ -package org.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/org/jabref/gui/util/component/JTextFieldWithPlaceholder.java b/src/main/java/org/jabref/gui/util/component/JTextFieldWithPlaceholder.java deleted file mode 100644 index b676b20adb4..00000000000 --- a/src/main/java/org/jabref/gui/util/component/JTextFieldWithPlaceholder.java +++ /dev/null @@ -1,91 +0,0 @@ -package org.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(); - } - } - -} diff --git a/src/main/java/org/jabref/gui/worker/CallBack.java b/src/main/java/org/jabref/gui/worker/CallBack.java deleted file mode 100644 index 4fa4c6eb60e..00000000000 --- a/src/main/java/org/jabref/gui/worker/CallBack.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.jabref.gui.worker; - -/** - * Represents a task that is to be executed on the GUI thread - */ -@FunctionalInterface -public interface CallBack { - - void update(); - -} diff --git a/src/main/java/org/jabref/logic/net/URLUtil.java b/src/main/java/org/jabref/logic/net/URLUtil.java index 05644fd4a18..e927d6933ff 100644 --- a/src/main/java/org/jabref/logic/net/URLUtil.java +++ b/src/main/java/org/jabref/logic/net/URLUtil.java @@ -6,7 +6,9 @@ import java.net.URLDecoder; import java.nio.charset.StandardCharsets; import java.util.Objects; +import java.util.Optional; +import org.jabref.gui.externalfiletype.ExternalFileTypes; import org.jabref.model.strings.StringUtil; import org.apache.http.client.utils.URIBuilder; @@ -52,7 +54,7 @@ public static String cleanGoogleSearchURL(String url) { for (String pair: pairs) { // "clean" url is decoded value of "url" parameter if (pair.startsWith("url=")) { - String value = pair.substring(pair.indexOf('=') + 1, pair.length()); + String value = pair.substring(pair.indexOf('=') + 1); String decode = URLDecoder.decode(value, StandardCharsets.UTF_8.name()); // url? @@ -102,4 +104,57 @@ private static String appendSegmentToPath(String path, String segment) { return path + "/" + segment; } + /** + * 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") + */ + public static Optional 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 Optional.empty(); + } else { + return Optional.of(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 Optional.empty(); + } else { + return Optional.of(link.substring(index + 1)); + } + } + } else { + return Optional.ofNullable(suffix); + } + } } diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index 6f889dd0133..c553d2896fa 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -280,9 +280,6 @@ Donate\ to\ JabRef=Donate to JabRef Down=Down Download\ file=Download file - -Downloading...=Downloading... - duplicate\ removal=duplicate removal Duplicate\ string\ name=Duplicate string name @@ -300,7 +297,6 @@ Each\ line\ must\ be\ of\ the\ following\ form=Each line must be of the followin Edit=Edit Edit\ entry=Edit entry -Save\ file=Save file Edit\ file\ type=Edit file type Edit\ group=Edit group @@ -390,7 +386,6 @@ File\ directory\ is\ not\ set\ or\ does\ not\ exist\!=File directory is not set File\ exists=File exists File\ not\ found=File not found -File\ type=File type filename=filename Files\ opened=Files opened @@ -927,8 +922,6 @@ Sublibrary\ from\ AUX=Sublibrary from AUX Switches\ between\ full\ and\ abbreviated\ journal\ name\ if\ the\ journal\ name\ is\ known.=Switches between full and abbreviated journal name if the journal name is known. Tabname=Tabname -Target\ file\ cannot\ be\ a\ directory.=Target file cannot be a directory. - Tertiary\ sort\ criterion=Tertiary sort criterion Test=Test @@ -1097,7 +1090,6 @@ Line\ %0\:\ Found\ corrupted\ BibTeX\ key\ %1.=Line %0: Found corrupted BibTeX k Line\ %0\:\ Found\ corrupted\ BibTeX\ key\ %1\ (contains\ whitespaces).=Line %0: Found corrupted BibTeX key %1 (contains whitespaces). Line\ %0\:\ Found\ corrupted\ BibTeX\ key\ %1\ (comma\ missing).=Line %0: Found corrupted BibTeX key %1 (comma missing). No\ full\ text\ document\ found=No full text document found -Update\ to\ current\ column\ order=Update to current column order Download\ from\ URL=Download from URL Rename\ field=Rename field Append\ field=Append field @@ -1451,8 +1443,6 @@ Could\ not\ connect\ to\ %0=Could not connect to %0 Warning\:\ %0\ out\ of\ %1\ entries\ have\ undefined\ title.=Warning: %0 out of %1 entries have undefined title. Warning\:\ %0\ out\ of\ %1\ entries\ have\ undefined\ BibTeX\ key.=Warning: %0 out of %1 entries have undefined BibTeX key. Added\ new\ '%0'\ entry.=Added new '%0' entry. -Multiple\ entries\ selected.\ Do\ you\ want\ to\ change\ the\ type\ of\ all\ these\ to\ '%0'?=Multiple entries selected. Do you want to change the type of all these to '%0'? -Changed\ type\ to\ '%0'\ for=Changed type to '%0' for Really\ delete\ the\ selected\ entry?=Really delete the selected entry? Really\ delete\ the\ %0\ selected\ entries?=Really delete the %0 selected entries? Keep\ merged\ entry\ only=Keep merged entry only diff --git a/src/test/java/org/jabref/cleanup/CleanupActionsListModelTest.java b/src/test/java/org/jabref/cleanup/CleanupActionsListModelTest.java deleted file mode 100644 index b44b0c572aa..00000000000 --- a/src/test/java/org/jabref/cleanup/CleanupActionsListModelTest.java +++ /dev/null @@ -1,94 +0,0 @@ -package org.jabref.cleanup; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import javax.swing.event.ListDataEvent; -import javax.swing.event.ListDataListener; - -import org.jabref.gui.cleanup.CleanupActionsListModel; -import org.jabref.logic.cleanup.Cleanups; -import org.jabref.logic.formatter.bibtexfields.ClearFormatter; -import org.jabref.model.cleanup.FieldFormatterCleanup; -import org.jabref.model.cleanup.FieldFormatterCleanups; - -import org.junit.jupiter.api.Test; -import org.mockito.ArgumentCaptor; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; -import static org.mockito.Mockito.when; - -public class CleanupActionsListModelTest { - - @Test - public void resetFiresItemsChanged() throws Exception { - CleanupActionsListModel model = new CleanupActionsListModel(Collections.emptyList()); - ListDataListener listener = mock(ListDataListener.class); - model.addListDataListener(listener); - FieldFormatterCleanups defaultFormatters = mock(FieldFormatterCleanups.class); - - model.reset(defaultFormatters); - - ArgumentCaptor argument = ArgumentCaptor.forClass(ListDataEvent.class); - verify(listener).contentsChanged(argument.capture()); - assertEquals(ListDataEvent.CONTENTS_CHANGED, argument.getValue().getType()); - } - - @Test - public void resetSetsFormattersToPassedList() throws Exception { - CleanupActionsListModel model = new CleanupActionsListModel(Collections.emptyList()); - FieldFormatterCleanups defaultFormatters = mock(FieldFormatterCleanups.class); - List formatters = Arrays.asList(new FieldFormatterCleanup("test", new ClearFormatter())); - when(defaultFormatters.getConfiguredActions()).thenReturn(formatters); - - model.reset(defaultFormatters); - - assertEquals(formatters, model.getAllActions()); - } - - public List getDefaultFieldFormatterCleanups() { - FieldFormatterCleanups formatters = Cleanups.DEFAULT_SAVE_ACTIONS; - //new ArrayList because configured actions is an unmodifiable collection - return new ArrayList<>(formatters.getConfiguredActions()); - } - - @Test - public void removedAtIndexOkay() { - - CleanupActionsListModel model = new CleanupActionsListModel(getDefaultFieldFormatterCleanups()); - ListDataListener listener = mock(ListDataListener.class); - model.addListDataListener(listener); - model.removeAtIndex(0); - - ArgumentCaptor argument = ArgumentCaptor.forClass(ListDataEvent.class); - verify(listener).intervalRemoved(argument.capture()); - assertEquals(ListDataEvent.INTERVAL_REMOVED, argument.getValue().getType()); - } - - @Test - public void removedAtIndexMinus1DoesNothing() { - - CleanupActionsListModel model = new CleanupActionsListModel(getDefaultFieldFormatterCleanups()); - ListDataListener listener = mock(ListDataListener.class); - model.addListDataListener(listener); - model.removeAtIndex(-1); - - verifyZeroInteractions(listener); - } - - @Test - public void removedAtIndexgreaterListSizeDoesNothing() { - - CleanupActionsListModel model = new CleanupActionsListModel(getDefaultFieldFormatterCleanups()); - ListDataListener listener = mock(ListDataListener.class); - model.addListDataListener(listener); - model.removeAtIndex((getDefaultFieldFormatterCleanups().size() + 1)); - - verifyZeroInteractions(listener); - } -}