Browse Source

Further text ui refactoring.

pull/170/head
weisj 5 years ago
parent
commit
13fc51e35d
  1. 245
      core/src/main/java/com/github/weisj/darklaf/ui/text/DarkTextUI.java
  2. 120
      core/src/main/java/com/github/weisj/darklaf/ui/text/bridge/DarkEditorPaneUIBridge.java
  3. 5
      core/src/main/java/com/github/weisj/darklaf/ui/text/bridge/DarkTextAreaUIBridge.java
  4. 14
      core/src/main/java/com/github/weisj/darklaf/ui/text/dummy/DummyEditorPane.java

245
core/src/main/java/com/github/weisj/darklaf/ui/text/DarkTextUI.java

@ -25,23 +25,17 @@
package com.github.weisj.darklaf.ui.text;
import java.awt.*;
import java.awt.event.*;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.HashSet;
import java.util.Set;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.plaf.ActionMapUIResource;
import javax.swing.plaf.ComponentInputMapUIResource;
import javax.swing.plaf.InputMapUIResource;
import javax.swing.plaf.basic.BasicTextUI;
import javax.swing.text.*;
import sun.awt.SunToolkit;
import sun.swing.DefaultLookup;
import com.github.weisj.darklaf.components.border.MarginBorderWrapper;
import com.github.weisj.darklaf.graphics.GraphicsContext;
import com.github.weisj.darklaf.graphics.GraphicsUtil;
@ -58,7 +52,7 @@ import com.github.weisj.darklaf.util.PropertyUtil;
/**
* @author Jannis Weis
*/
public abstract class DarkTextUI extends BasicTextUI implements PropertyChangeListener {
public abstract class DarkTextUI extends BasicTextUI implements PropertyChangeListener, FocusListener {
protected static final String KEY_PREFIX = "JTextComponent.";
public static final String KEY_ROUNDED_SELECTION = KEY_PREFIX + "roundedSelection";
@ -72,25 +66,6 @@ public abstract class DarkTextUI extends BasicTextUI implements PropertyChangeLi
protected static final String TOGGLE_INSERT = "toggle_insert";
protected JTextComponent editor;
private FocusListener focusListener = new FocusListener() {
@Override
public void focusGained(final FocusEvent e) {
Caret caret = editor.getCaret();
if (caret instanceof DarkCaret) {
((DarkCaret) caret).setPaintSelectionHighlight(true);
}
editor.repaint();
}
@Override
public void focusLost(final FocusEvent e) {
Caret caret = editor.getCaret();
if (caret instanceof DarkCaret) {
((DarkCaret) caret).setPaintSelectionHighlight(false);
}
editor.repaint();
}
};
protected DefaultTextRenderer defaultTextRenderer;
protected DarkCaret darkCaret;
@ -164,6 +139,7 @@ public abstract class DarkTextUI extends BasicTextUI implements PropertyChangeLi
@Override
public void propertyChange(final PropertyChangeEvent evt) {
super.propertyChange(evt);
String key = evt.getPropertyName();
if (KEY_ROUNDED_SELECTION.equals(key)) {
boolean rounded = PropertyUtil.getBooleanProperty(editor, DarkTextUI.KEY_ROUNDED_SELECTION);
@ -183,14 +159,13 @@ public abstract class DarkTextUI extends BasicTextUI implements PropertyChangeLi
@Override
protected void installListeners() {
super.installListeners();
editor.addFocusListener(focusListener);
editor.addFocusListener(this);
}
@Override
protected void uninstallListeners() {
super.uninstallListeners();
editor.removeFocusListener(focusListener);
focusListener = null;
editor.removeFocusListener(this);
}
protected Color getBackground(final JTextComponent c) {
@ -360,23 +335,11 @@ public abstract class DarkTextUI extends BasicTextUI implements PropertyChangeLi
return 0;
}
protected void installKeyboardActions() {
// backward compatibility support... keymaps for the UI
// are now installed in the more friendly input map.
editor.setKeymap(createKeymap());
InputMap km = getInputMap();
if (km != null) {
SwingUtilities.replaceUIInputMap(editor, JComponent.WHEN_FOCUSED,
km);
}
ActionMap map = getActionMap();
if (map != null) {
SwingUtilities.replaceUIActionMap(editor, map);
}
updateFocusAcceleratorBinding(false);
protected void installDarkKeyBoardActions() {
ActionMap actionMap = SwingUtilities.getUIActionMap(getComponent());
actionMap.put(TOGGLE_INSERT, new ToggleInsertAction());
InputMap inputMap = SwingUtilities.getUIInputMap(getComponent(), JComponent.WHEN_FOCUSED);
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, 0), TOGGLE_INSERT);
}
@Override
@ -385,6 +348,7 @@ public abstract class DarkTextUI extends BasicTextUI implements PropertyChangeLi
editor = (JTextComponent) c;
}
super.installUI(c);
installDarkKeyBoardActions();
}
@Override
@ -392,62 +356,6 @@ public abstract class DarkTextUI extends BasicTextUI implements PropertyChangeLi
return new DarkHighlighter();
}
/*
* Implementation of BasicTextUI.
*/
/**
* Get the InputMap to use for the UI.
*
* @return the input map
*/
protected InputMap getInputMap() {
InputMap map = new InputMapUIResource();
InputMap shared = (InputMap) DefaultLookup.get(editor, this, getPropertyPrefix() + ".focusInputMap");
if (shared != null) {
map.setParent(shared);
}
map.put(KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, 0), TOGGLE_INSERT);
return map;
}
protected ActionMap getActionMap() {
String mapName = getPropertyPrefix() + ".actionMap";
ActionMap map = (ActionMap) UIManager.get(mapName);
if (map == null) {
map = createActionMap();
if (map != null) {
UIManager.getLookAndFeelDefaults().put(mapName, map);
}
}
ActionMap componentMap = new ActionMapUIResource();
componentMap.put("requestFocus", new FocusAction());
/*
* fix for bug 4515750
* JTextField & non-editable JTextArea bind return key - default btn not accessible
*
* Wrap the return action so that it is only enabled when the
* component is editable. This allows the default button to be
* processed when the text component has focus and isn't editable.
*
*/
if (getEditorKit(editor) instanceof DefaultEditorKit) {
if (map != null) {
Object obj = map.get(DefaultEditorKit.insertBreakAction);
if (obj instanceof DefaultEditorKit.InsertBreakAction) {
Action action = new TextActionWrapper((TextAction) obj);
componentMap.put(action.getValue(Action.NAME), action);
}
map.put(TOGGLE_INSERT, new ToggleInsertAction());
}
}
if (map != null) {
componentMap.setParent(map);
}
return componentMap;
}
@Override
protected Keymap createKeymap() {
Keymap km = super.createKeymap();
@ -455,124 +363,21 @@ public abstract class DarkTextUI extends BasicTextUI implements PropertyChangeLi
return km;
}
/**
* Invoked when the focus accelerator changes, this will update the key bindings as necessary.
*
* @param changed the changed
*/
@SuppressWarnings("MagicConstant")
protected void updateFocusAcceleratorBinding(final boolean changed) {
char accelerator = editor.getFocusAccelerator();
if (changed || accelerator != '\0') {
InputMap km = SwingUtilities.getUIInputMap(editor, JComponent.WHEN_IN_FOCUSED_WINDOW);
if (km == null && accelerator != '\0') {
km = new ComponentInputMapUIResource(editor);
SwingUtilities.replaceUIInputMap(editor, JComponent.WHEN_IN_FOCUSED_WINDOW, km);
ActionMap am = getActionMap();
SwingUtilities.replaceUIActionMap(editor, am);
}
if (km != null) {
km.clear();
if (accelerator != '\0') {
km.put(KeyStroke.getKeyStroke(accelerator, getFocusAcceleratorKeyMask()), "requestFocus");
km.put(KeyStroke.getKeyStroke(accelerator,
DarkUIUtil.setAltGraphMask(getFocusAcceleratorKeyMask())),
"requestFocus");
}
}
}
}
/**
* Create a default action map. This is basically the set of actions found exported by the component.
*
* @return the action map
*/
public ActionMap createActionMap() {
ActionMap map = new ActionMapUIResource();
Action[] actions = editor.getActions();
for (Action a : actions) {
map.put(a.getValue(Action.NAME), a);
}
map.put(TransferHandler.getCutAction().getValue(Action.NAME), TransferHandler.getCutAction());
map.put(TransferHandler.getCopyAction().getValue(Action.NAME), TransferHandler.getCopyAction());
map.put(TransferHandler.getPasteAction().getValue(Action.NAME), TransferHandler.getPasteAction());
return map;
}
protected static int getFocusAcceleratorKeyMask() {
Toolkit tk = Toolkit.getDefaultToolkit();
if (tk instanceof SunToolkit) {
return ((SunToolkit) tk).getFocusAcceleratorKeyMask();
}
return ActionEvent.ALT_MASK;
}
/**
* Invoked when editable property is changed.
* <p>
* removing 'TAB' and 'SHIFT-TAB' from traversalKeysSet in case editor is editable adding 'TAB' and 'SHIFT-TAB' to
* traversalKeysSet in case editor is non editable
*/
@SuppressWarnings("deprecation")
protected void updateFocusTraversalKeys() {
/*
* Fix for 4514331 Non-editable JTextArea and similar
* should allow Tab to keyboard - accessibility
*/
EditorKit editorKit = getEditorKit(editor);
if (editorKit instanceof DefaultEditorKit) {
Set<AWTKeyStroke> storedForwardTraversalKeys = editor.getFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
Set<AWTKeyStroke> storedBackwardTraversalKeys = editor.getFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS);
Set<AWTKeyStroke> forwardTraversalKeys = new HashSet<>(storedForwardTraversalKeys);
Set<AWTKeyStroke> backwardTraversalKeys = new HashSet<>(storedBackwardTraversalKeys);
if (editor.isEditable()) {
forwardTraversalKeys.remove(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0));
backwardTraversalKeys.remove(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, InputEvent.SHIFT_MASK));
} else {
forwardTraversalKeys.add(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0));
backwardTraversalKeys.add(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, InputEvent.SHIFT_MASK));
}
LookAndFeel.installProperty(editor, "focusTraversalKeysForward", forwardTraversalKeys);
LookAndFeel.installProperty(editor, "focusTraversalKeysBackward", backwardTraversalKeys);
}
}
public class FocusAction extends AbstractAction {
public void actionPerformed(final ActionEvent e) {
editor.requestFocus();
}
public boolean isEnabled() {
return editor.isEditable();
@Override
public void focusGained(final FocusEvent e) {
Caret caret = editor.getCaret();
if (caret instanceof DarkCaret) {
((DarkCaret) caret).setPaintSelectionHighlight(true);
}
editor.repaint();
}
/**
* Wrapper for text actions to return isEnabled false in case editor is non editable
*/
public class TextActionWrapper extends TextAction {
final TextAction action;
public TextActionWrapper(final TextAction action) {
super((String) action.getValue(Action.NAME));
this.action = action;
}
/**
* The operation to perform when this action is triggered.
*
* @param e the action event
*/
public void actionPerformed(final ActionEvent e) {
action.actionPerformed(e);
}
public boolean isEnabled() {
return (editor == null || editor.isEditable()) && action.isEnabled();
@Override
public void focusLost(final FocusEvent e) {
Caret caret = editor.getCaret();
if (caret instanceof DarkCaret) {
((DarkCaret) caret).setPaintSelectionHighlight(false);
}
editor.repaint();
}
}

120
core/src/main/java/com/github/weisj/darklaf/ui/text/bridge/DarkEditorPaneUIBridge.java

@ -25,19 +25,16 @@
package com.github.weisj.darklaf.ui.text.bridge;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.*;
import javax.swing.plaf.basic.BasicEditorPaneUI;
import javax.swing.text.DefaultEditorKit;
import javax.swing.text.EditorKit;
import javax.swing.text.JTextComponent;
import com.github.weisj.darklaf.ui.text.DarkTextUI;
import com.github.weisj.darklaf.ui.text.action.ToggleInsertAction;
import com.github.weisj.darklaf.ui.text.dummy.DummyEditorPane;
import com.github.weisj.darklaf.ui.text.dummy.DummyEditorPaneUI;
import com.github.weisj.darklaf.util.PropertyKey;
import com.github.weisj.darklaf.util.PropertyUtil;
/**
* @author Jannis Weis
@ -45,103 +42,86 @@ import com.github.weisj.darklaf.util.PropertyUtil;
public abstract class DarkEditorPaneUIBridge extends DarkTextUI {
private static final DummyEditorPane editorPane = new DummyEditorPane();
private static final BasicEditorPaneUI basicEditorPaneUI = new DummyEditorPaneUI();
private static final DummyEditorPaneUI basicEditorPaneUI = new DummyEditorPaneUI();
static {
basicEditorPaneUI.installUI(editorPane);
}
private PropertyChangeListener propertyChangeListener;
@Override
public void installUI(final JComponent c) {
editorPane.setEditorPane((JEditorPane) c);
basicEditorPaneUI.installUI(editorPane);
super.installUI(c);
updateDisplayProperties(c);
updateDisplayProperties();
}
@Override
protected void installListeners() {
propertyChangeListener = editorPane.getPropertyChangeListener();
super.installListeners();
}
@Override
public void uninstallUI(final JComponent c) {
cleanDisplayProperties(c);
super.uninstallUI(c);
editorPane.setEditorPane(null);
editorPane.addPropertyChangeListener(null);
}
protected void updateDisplayProperties(final JComponent c) {
if (c instanceof JEditorPane) {
editorPane.setEditorPane((JEditorPane) c);
basicEditorPaneUI.installUI(editorPane);
}
protected void updateDisplayProperties() {
updateDisplayProperties((JEditorPane) getComponent(),
new PropertyChangeEvent(editorPane, PropertyKey.FONT,
editorPane.getFont(), editorPane.getFont()));
}
protected void updateDisplayProperties(final JEditorPane c, final PropertyChangeEvent event) {
editorPane.setEditorPane(c);
basicEditorPaneUI.propertyChange(event);
}
protected void cleanDisplayProperties(final JComponent c) {
if (c instanceof JEditorPane) {
editorPane.setEditorPane((JEditorPane) c);
basicEditorPaneUI.uninstallUI(editorPane);
}
editorPane.setEditorPane((JEditorPane) c);
basicEditorPaneUI.uninstallUI(editorPane);
}
@Override
public ActionMap getActionMap() {
protected void installKeyboardActions() {
super.installKeyboardActions();
updateActionMap();
}
protected void updateFocusAcceleratorBinding(final PropertyChangeEvent event) {
/*
* This invokes the UpdateHandler propertyChange event which in turn invokes
* #updateFocusAcceleratorBinding
*/
propertyChangeListener.propertyChange(event);
}
protected void updateActionMap() {
editorPane.setActionMap(new ActionMap());
editorPane.setEditorPane((JEditorPane) getComponent());
ActionMap am = editorPane.getActionMap();
EditorKit editorKit = getEditorKit(getComponent());
if (editorKit instanceof DefaultEditorKit) {
am.put(TOGGLE_INSERT, new ToggleInsertAction());
}
return am;
basicEditorPaneUI.installKeyBoardActionsReal();
ActionMap map = editorPane.getActionMap();
SwingUtilities.replaceUIActionMap(getComponent(), map);
installDarkKeyBoardActions();
}
@Override
public void propertyChange(final PropertyChangeEvent evt) {
super.propertyChange(evt);
String name = evt.getPropertyName();
if ("editorKit".equals(name)) {
ActionMap map = SwingUtilities.getUIActionMap(getComponent());
if (map != null) {
Object oldValue = evt.getOldValue();
if (oldValue instanceof EditorKit) {
Action[] actions = ((EditorKit) oldValue).getActions();
if (actions != null) {
removeActions(map, actions);
}
}
Object newValue = evt.getNewValue();
if (newValue instanceof EditorKit) {
Action[] actions = ((EditorKit) newValue).getActions();
if (actions != null) {
addActions(map, actions);
}
}
}
updateFocusTraversalKeys();
} else if (PropertyKey.EDITABLE.equals(name)) {
updateFocusTraversalKeys();
if ("editorKit".equals(name) || PropertyKey.EDITABLE.equals(name)) {
editorPane.setEditorPane((JEditorPane) getComponent());
basicEditorPaneUI.propertyChange(evt);
} else if (PropertyKey.FOREGROUND.equals(name)
|| PropertyKey.FONT.equals(name)
|| PropertyKey.DOCUMENT.equals(name)
|| JEditorPane.W3C_LENGTH_UNITS.equals(name)
|| JEditorPane.HONOR_DISPLAY_PROPERTIES.equals(name)) {
JComponent c = getComponent();
updateDisplayProperties(getComponent());
if (JEditorPane.W3C_LENGTH_UNITS.equals(name)
|| JEditorPane.HONOR_DISPLAY_PROPERTIES.equals(name)) {
modelChanged();
}
if (PropertyKey.FOREGROUND.equals(name)) {
if (PropertyUtil.getBooleanProperty(c, JEditorPane.HONOR_DISPLAY_PROPERTIES)) {
modelChanged();
}
}
}
}
protected void addActions(final ActionMap map, final Action[] actions) {
for (Action a : actions) {
map.put(a.getValue(Action.NAME), a);
}
}
protected void removeActions(final ActionMap map, final Action[] actions) {
for (Action a : actions) {
map.remove(a.getValue(Action.NAME));
updateDisplayProperties((JEditorPane) getComponent(), evt);
} else if ("focusAccelerator".equals(name)) {
updateFocusAcceleratorBinding(evt);
}
}

5
core/src/main/java/com/github/weisj/darklaf/ui/text/bridge/DarkTextAreaUIBridge.java

@ -28,7 +28,6 @@ import java.awt.*;
import java.beans.PropertyChangeEvent;
import javax.swing.*;
import javax.swing.plaf.basic.BasicTextAreaUI;
import javax.swing.text.Element;
import javax.swing.text.JTextComponent;
import javax.swing.text.View;
@ -44,7 +43,7 @@ import com.github.weisj.darklaf.util.PropertyKey;
public abstract class DarkTextAreaUIBridge extends DarkTextUI {
private static final JTextArea area = new DummyTextArea();
private static final BasicTextAreaUI basicTextAreaUI = new DummyTextAreaUI();
private static final DummyTextAreaUI basicTextAreaUI = new DummyTextAreaUI();
/*
* Implementation of BasicTextAreaUI
@ -58,7 +57,7 @@ public abstract class DarkTextAreaUIBridge extends DarkTextUI {
// rebuild the view
modelChanged();
} else if (PropertyKey.EDITABLE.equals(evt.getPropertyName())) {
updateFocusTraversalKeys();
basicTextAreaUI.propertyChange(evt);
}
}

14
core/src/main/java/com/github/weisj/darklaf/ui/text/dummy/DummyEditorPane.java

@ -42,11 +42,16 @@ import javax.swing.text.Highlighter;
public class DummyEditorPane extends JEditorPane {
private JEditorPane editorPane;
private PropertyChangeListener propertyChangeListener;
public void setEditorPane(final JEditorPane editorPane) {
this.editorPane = editorPane;
}
public PropertyChangeListener getPropertyChangeListener() {
return propertyChangeListener;
}
@Override
public Document getDocument() {
if (editorPane == null) return super.getDocument();
@ -71,6 +76,11 @@ public class DummyEditorPane extends JEditorPane {
return editorPane.getBackground();
}
@Override
public boolean isEditable() {
return editorPane.isEditable();
}
@Override
protected void setUI(final ComponentUI newUI) {}
@ -81,7 +91,9 @@ public class DummyEditorPane extends JEditorPane {
public void updateUI() {}
@Override
public void addPropertyChangeListener(final PropertyChangeListener listener) {}
public void addPropertyChangeListener(final PropertyChangeListener listener) {
propertyChangeListener = listener;
}
@Override
public synchronized void addMouseListener(final MouseListener l) {}

Loading…
Cancel
Save