package org.jabref.gui.fieldeditors;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.lang.reflect.InvocationTargetException;
import javax.swing.AbstractAction;
import javax.swing.JComponent;
import javax.swing.SwingUtilities;
import javax.swing.text.Document;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoManager;
import org.jabref.Globals;
import org.jabref.gui.GUIGlobals;
import org.jabref.gui.actions.Actions;
import org.jabref.gui.autocompleter.AutoCompleteListener;
import org.jabref.gui.util.component.JTextFieldWithPlaceholder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* An implementation of the FieldEditor backed by a JTextField. Used for single-line input, only BibTex key at the
* moment?!
*/
public class TextField extends JTextFieldWithPlaceholder implements FieldEditor {
private static final Log LOGGER = LogFactory.getLog(TextField.class);
private final String fieldName;
private UndoManager undo;
private AutoCompleteListener autoCompleteListener;
public TextField(String fieldName, String content, boolean changeColorOnFocus) {
this(fieldName, content, changeColorOnFocus, "");
}
public TextField(String fieldName, String content, boolean changeColorOnFocus, String title) {
super(content, title);
setupPasteListener();
setupUndoRedo();
updateFont();
// Add the global focus listener, so a menu item can see if this field
// was focused when
// an action was called.
addFocusListener(Globals.getFocusListener());
if (changeColorOnFocus) {
addFocusListener(new FieldEditorFocusListener());
}
this.fieldName = fieldName;
setBackground(GUIGlobals.validFieldBackgroundColor);
setForeground(GUIGlobals.editorTextColor);
}
@Override
public void setText(String t) {
super.setText(t);
if (undo != null) {
undo.discardAllEdits();
}
}
@Override
public void append(String text) {
setText(getText() + text);
}
@Override
public String getFieldName() {
return fieldName;
}
@Override
public JComponent getPane() {
return this;
}
@Override
public JComponent getTextComponent() {
return this;
}
@Override
public void setActiveBackgroundColor() {
setBackgroundColor(GUIGlobals.activeBackgroundColor);
}
@Override
public void setValidBackgroundColor() {
setBackgroundColor(GUIGlobals.validFieldBackgroundColor);
}
@Override
public void setInvalidBackgroundColor() {
setBackgroundColor(GUIGlobals.invalidFieldBackgroundColor);
}
private void setBackgroundColor(Color color) {
if (SwingUtilities.isEventDispatchThread()) {
setBackground(color);
} else {
try {
SwingUtilities.invokeAndWait(() -> setBackground(color));
} catch (InvocationTargetException | InterruptedException e) {
LOGGER.info("Problem setting background color", e);
}
}
}
private void updateFont() {
setFont(GUIGlobals.currentFont);
}
@Override
// Only replaces selected text if found
public void paste(String textToInsert) {
replaceSelection(textToInsert);
}
@Override
public void undo() {
// Nothing
}
@Override
public void redo() {
// Nothing
}
@Override
public void setAutoCompleteListener(AutoCompleteListener listener) {
autoCompleteListener = listener;
}
@Override
public void clearAutoCompleteSuggestion() {
if (autoCompleteListener != null) {
autoCompleteListener.clearCurrentSuggestion(this);
}
}
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) {
@Override
public void actionPerformed(ActionEvent evt) {
try {
if (undo.canRedo()) {
undo.redo();
}
} catch (CannotRedoException ignored) {
// Ignored
}
}
});
// Bind the redo action to ctl-Y
getInputMap().put(Globals.getKeyPrefs().getKey(org.jabref.gui.keyboard.KeyBinding.REDO), "Redo");
}
}