From 13fc51e35d838a2a9b6052de938ef7f47559a2db Mon Sep 17 00:00:00 2001 From: weisj Date: Thu, 21 May 2020 09:26:35 +0200 Subject: [PATCH] Further text ui refactoring. --- .../weisj/darklaf/ui/text/DarkTextUI.java | 245 ++---------------- .../text/bridge/DarkEditorPaneUIBridge.java | 120 ++++----- .../ui/text/bridge/DarkTextAreaUIBridge.java | 5 +- .../ui/text/dummy/DummyEditorPane.java | 14 +- 4 files changed, 90 insertions(+), 294 deletions(-) diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/text/DarkTextUI.java b/core/src/main/java/com/github/weisj/darklaf/ui/text/DarkTextUI.java index 4e083370..1878801f 100644 --- a/core/src/main/java/com/github/weisj/darklaf/ui/text/DarkTextUI.java +++ b/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. - *

- * 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 storedForwardTraversalKeys = editor.getFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); - Set storedBackwardTraversalKeys = editor.getFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); - Set forwardTraversalKeys = new HashSet<>(storedForwardTraversalKeys); - Set 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(); } } diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/text/bridge/DarkEditorPaneUIBridge.java b/core/src/main/java/com/github/weisj/darklaf/ui/text/bridge/DarkEditorPaneUIBridge.java index 3adde4e1..a52ca557 100644 --- a/core/src/main/java/com/github/weisj/darklaf/ui/text/bridge/DarkEditorPaneUIBridge.java +++ b/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); } } diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/text/bridge/DarkTextAreaUIBridge.java b/core/src/main/java/com/github/weisj/darklaf/ui/text/bridge/DarkTextAreaUIBridge.java index 7b7233e7..8c99d069 100644 --- a/core/src/main/java/com/github/weisj/darklaf/ui/text/bridge/DarkTextAreaUIBridge.java +++ b/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); } } diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/text/dummy/DummyEditorPane.java b/core/src/main/java/com/github/weisj/darklaf/ui/text/dummy/DummyEditorPane.java index 314ae19c..60c25fdf 100644 --- a/core/src/main/java/com/github/weisj/darklaf/ui/text/dummy/DummyEditorPane.java +++ b/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) {}