From 9dc94f7d6e882ddee5633c683b8fd7f3274580d1 Mon Sep 17 00:00:00 2001 From: weisj Date: Wed, 20 May 2020 23:27:49 +0200 Subject: [PATCH] Refactored text ui classes. Added bidi text hint. --- .../weisj/darklaf/ui/text/DarkCaret.java | 82 +++- .../darklaf/ui/text/DarkEditorPaneUI.java | 319 +-------------- .../darklaf/ui/text/DarkPasswordFieldUI.java | 3 +- .../weisj/darklaf/ui/text/DarkTextAreaUI.java | 94 +---- .../darklaf/ui/text/DarkTextFieldUI.java | 1 + .../ui/text/DarkTextFieldUIBridge.java | 370 ------------------ .../weisj/darklaf/ui/text/DarkTextUI.java | 2 +- .../text/bridge/DarkEditorPaneUIBridge.java | 153 ++++++++ .../DarkPasswordFieldUIBridge.java | 30 +- .../ui/text/bridge/DarkTextAreaUIBridge.java | 86 ++++ .../ui/text/bridge/DarkTextFieldUIBridge.java | 65 +++ .../ui/text/dummy/DummyEditorPane.java | 128 ++++++ .../ui/text/dummy/DummyEditorPaneUI.java | 39 ++ .../darklaf/ui/text/dummy/DummyTextArea.java | 98 +++++ .../ui/text/dummy/DummyTextAreaUI.java | 48 +++ .../ui/text/dummy/DummyTextComponent.java | 99 +++++ 16 files changed, 809 insertions(+), 808 deletions(-) delete mode 100644 core/src/main/java/com/github/weisj/darklaf/ui/text/DarkTextFieldUIBridge.java create mode 100644 core/src/main/java/com/github/weisj/darklaf/ui/text/bridge/DarkEditorPaneUIBridge.java rename core/src/main/java/com/github/weisj/darklaf/ui/text/{ => bridge}/DarkPasswordFieldUIBridge.java (80%) create mode 100644 core/src/main/java/com/github/weisj/darklaf/ui/text/bridge/DarkTextAreaUIBridge.java create mode 100644 core/src/main/java/com/github/weisj/darklaf/ui/text/bridge/DarkTextFieldUIBridge.java create mode 100644 core/src/main/java/com/github/weisj/darklaf/ui/text/dummy/DummyEditorPane.java create mode 100644 core/src/main/java/com/github/weisj/darklaf/ui/text/dummy/DummyEditorPaneUI.java create mode 100644 core/src/main/java/com/github/weisj/darklaf/ui/text/dummy/DummyTextArea.java create mode 100644 core/src/main/java/com/github/weisj/darklaf/ui/text/dummy/DummyTextAreaUI.java create mode 100644 core/src/main/java/com/github/weisj/darklaf/ui/text/dummy/DummyTextComponent.java diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/text/DarkCaret.java b/core/src/main/java/com/github/weisj/darklaf/ui/text/DarkCaret.java index fae800f8..1fd77547 100644 --- a/core/src/main/java/com/github/weisj/darklaf/ui/text/DarkCaret.java +++ b/core/src/main/java/com/github/weisj/darklaf/ui/text/DarkCaret.java @@ -45,6 +45,8 @@ import com.github.weisj.darklaf.ui.text.action.SelectWordAction; */ public class DarkCaret extends DefaultCaret implements UIResource { + private static final int FLAG_SIZE = 3; + private static Action selectWord; private static Action selectLine; private final Segment seg; @@ -58,6 +60,10 @@ public class DarkCaret extends DefaultCaret implements UIResource { private boolean insertMode; private boolean expandMode; + private boolean dotLtr = true; + private final int[] flagXPoints = new int[3]; + private final int[] flagYPoints = new int[3]; + public DarkCaret() { this(null, null); } @@ -290,6 +296,12 @@ public class DarkCaret extends DefaultCaret implements UIResource { y = r.y; width = r.width + 4; height = r.height; + + if (isBidiText() && !dotLtr) { + x -= FLAG_SIZE; + width += FLAG_SIZE; + } + repaint(); } } @@ -381,11 +393,51 @@ public class DarkCaret extends DefaultCaret implements UIResource { case THICK_VERTICAL_LINE_STYLE : case VERTICAL_LINE_STYLE : g.fillRect(r.x, r.y, style.getSize(), r.height); + if (isBidiText()) { + flagXPoints[0] = r.x + (dotLtr ? style.getSize() : 0); + flagYPoints[0] = r.y; + flagXPoints[1] = flagXPoints[0]; + flagYPoints[1] = flagYPoints[0] + FLAG_SIZE; + flagXPoints[2] = flagXPoints[0] + ((dotLtr) ? FLAG_SIZE : -FLAG_SIZE); + flagYPoints[2] = flagYPoints[0]; + g.fillPolygon(flagXPoints, flagYPoints, 3); + } break; } } } + protected boolean isBidiText() { + Document doc = getComponent().getDocument(); + if (doc instanceof AbstractDocument) { + Element bidi = ((AbstractDocument) doc).getBidiRootElement(); + return (bidi != null) && (bidi.getElementCount() > 1); + } + return false; + } + + protected boolean isPositionLTR(int position, final Position.Bias bias) { + Document doc = getComponent().getDocument(); + if (bias == Position.Bias.Backward && --position < 0) position = 0; + return isLeftToRight(doc, position, position); + } + + protected static boolean isLeftToRight(final Document doc, final int p0, final int p1) { + if (Boolean.TRUE.equals(doc.getProperty("i18n"))) { + if (doc instanceof AbstractDocument) { + AbstractDocument adoc = (AbstractDocument) doc; + Element bidiRoot = adoc.getBidiRootElement(); + int index = bidiRoot.getElementIndex(p0); + Element bidiElem = bidiRoot.getElement(index); + if (bidiElem.getEndOffset() >= p1) { + AttributeSet bidiAttrs = bidiElem.getAttributes(); + return ((StyleConstants.getBidiLevel(bidiAttrs) % 2) == 0); + } + } + } + return true; + } + /** * Selects word based on a mouse event. */ @@ -431,13 +483,29 @@ public class DarkCaret extends DefaultCaret implements UIResource { } } - private char getCharAtCaret() { - JTextComponent textArea = getComponent(); - try { - textArea.getDocument().getText(getDot(), 1, seg); - } catch (BadLocationException e) { - return ' '; + @Override + public void setDot(final int d, final Position.Bias bias) { + super.setDot(d, bias); + updateDot(d, bias); + } + + public void updateDot(final int d, final Position.Bias bias) { + Document doc = getComponent().getDocument(); + int dot = d; + Position.Bias dotBias = bias; + if (doc != null) { + dot = Math.min(dot, doc.getLength()); } - return seg.array[seg.offset]; + dot = Math.max(dot, 0); + + // The position (0,Backward) is out of range so disallow it. + if (dot == 0) dotBias = Position.Bias.Forward; + dotLtr = isPositionLTR(d, dotBias); + } + + @Override + public void moveDot(final int dot, final Position.Bias dotBias) { + super.moveDot(dot, dotBias); + updateDot(dot, dotBias); } } diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/text/DarkEditorPaneUI.java b/core/src/main/java/com/github/weisj/darklaf/ui/text/DarkEditorPaneUI.java index 822b2271..5f3ac0de 100644 --- a/core/src/main/java/com/github/weisj/darklaf/ui/text/DarkEditorPaneUI.java +++ b/core/src/main/java/com/github/weisj/darklaf/ui/text/DarkEditorPaneUI.java @@ -24,42 +24,16 @@ */ package com.github.weisj.darklaf.ui.text; -import java.awt.*; -import java.beans.PropertyChangeEvent; - import javax.swing.*; -import javax.swing.plaf.ActionMapUIResource; import javax.swing.plaf.ComponentUI; -import javax.swing.plaf.UIResource; -import javax.swing.text.*; -import javax.swing.text.html.HTMLDocument; -import javax.swing.text.html.StyleSheet; -import com.github.weisj.darklaf.ui.text.action.ToggleInsertAction; -import com.github.weisj.darklaf.util.PropertyKey; -import com.github.weisj.darklaf.util.PropertyUtil; +import com.github.weisj.darklaf.ui.text.bridge.DarkEditorPaneUIBridge; /** * @author Jannis Weis */ -public class DarkEditorPaneUI extends DarkTextUI { - - /** - * Attribute key to reference the default font. used in javax.swing.text.StyleContext.getFont to resolve the default - * font. - */ - private static final String FONT_ATTRIBUTE_KEY = "FONT_ATTRIBUTE_KEY"; +public class DarkEditorPaneUI extends DarkEditorPaneUIBridge { - /** - * Creates a new BasicEditorPaneUI. - */ - public DarkEditorPaneUI() { - super(); - } - - /* - * Implementation of DarkEditorPaneUI - */ public static ComponentUI createUI(final JComponent c) { return new DarkEditorPaneUI(); } @@ -69,295 +43,8 @@ public class DarkEditorPaneUI extends DarkTextUI { return DarkCaret.CaretStyle.THICK_VERTICAL_LINE_STYLE; } - /** - * {@inheritDoc} - * - * @since 1.5 - */ - public void installUI(final JComponent c) { - super.installUI(c); - updateDisplayProperties(c.getFont(), c.getForeground()); - } - - void updateDisplayProperties(final Font font, final Color fg) { - JComponent c = getComponent(); - boolean honorDisplayProperties = PropertyUtil.getBooleanProperty(c, JEditorPane.HONOR_DISPLAY_PROPERTIES); - boolean w3cLengthUnits = PropertyUtil.getBooleanProperty(c, JEditorPane.W3C_LENGTH_UNITS); - if (this instanceof DarkTextPaneUI || honorDisplayProperties) { - // using equals because can not use UIResource for Boolean - Document doc = getComponent().getDocument(); - if (doc instanceof StyledDocument) { - if (doc instanceof HTMLDocument && honorDisplayProperties) { - updateCSS(font, fg); - } else { - updateStyle(font, fg); - } - } - } else { - cleanDisplayProperties(); - } - if (w3cLengthUnits) { - Document doc = getComponent().getDocument(); - if (doc instanceof HTMLDocument) { - StyleSheet documentStyleSheet = ((HTMLDocument) doc).getStyleSheet(); - documentStyleSheet.addRule("W3C_LENGTH_UNITS_ENABLE"); - } - } else { - Document doc = getComponent().getDocument(); - if (doc instanceof HTMLDocument) { - StyleSheet documentStyleSheet = ((HTMLDocument) doc).getStyleSheet(); - documentStyleSheet.addRule("W3C_LENGTH_UNITS_DISABLE"); - } - - } - } - - private void updateCSS(final Font font, final Color fg) { - JTextComponent component = getComponent(); - Document document = component.getDocument(); - if (document instanceof HTMLDocument) { - StyleSheet styleSheet = new StyleSheetUIResource(); - StyleSheet documentStyleSheet = ((HTMLDocument) document).getStyleSheet(); - StyleSheet[] styleSheets = documentStyleSheet.getStyleSheets(); - if (styleSheets != null) { - for (StyleSheet s : styleSheets) { - if (s instanceof StyleSheetUIResource) { - documentStyleSheet.removeStyleSheet(s); - } - } - } - String cssRule = sun.swing.SwingUtilities2.displayPropertiesToCSS(font, fg); - styleSheet.addRule(cssRule); - documentStyleSheet.addStyleSheet(styleSheet); - documentStyleSheet.addRule("BASE_SIZE " + component.getFont().getSize()); - Style style = ((StyledDocument) document).getStyle(StyleContext.DEFAULT_STYLE); - if (!font.equals(style.getAttribute(FONT_ATTRIBUTE_KEY))) { - style.addAttribute(FONT_ATTRIBUTE_KEY, font); - } - } - } - - private void updateStyle(final Font font, final Color fg) { - updateFont(font); - updateForeground(fg); - } - - void cleanDisplayProperties() { - Document document = getComponent().getDocument(); - if (document instanceof HTMLDocument) { - StyleSheet documentStyleSheet = ((HTMLDocument) document).getStyleSheet(); - StyleSheet[] styleSheets = documentStyleSheet.getStyleSheets(); - if (styleSheets != null) { - for (StyleSheet s : styleSheets) { - if (s instanceof StyleSheetUIResource) { - documentStyleSheet.removeStyleSheet(s); - documentStyleSheet.addRule("BASE_SIZE_DISABLE"); - break; - } - } - } - Style style = ((StyledDocument) document).getStyle(StyleContext.DEFAULT_STYLE); - if (style.getAttribute(FONT_ATTRIBUTE_KEY) != null) { - style.removeAttribute(FONT_ATTRIBUTE_KEY); - } - } - } - - /** - * Update the font in the default style of the document. - * - * @param font the new font to use or null to remove the font attribute from the document's style - */ - private void updateFont(final Font font) { - StyledDocument doc = (StyledDocument) getComponent().getDocument(); - Style style = doc.getStyle(StyleContext.DEFAULT_STYLE); - - if (style == null) { - return; - } - - String fontFamily = (String) style.getAttribute(StyleConstants.FontFamily); - Integer fontSize = (Integer) style.getAttribute(StyleConstants.FontSize); - Boolean isBold = (Boolean) style.getAttribute(StyleConstants.Bold); - Boolean isItalic = (Boolean) style.getAttribute(StyleConstants.Italic); - Font fontAttribute = (Font) style.getAttribute(FONT_ATTRIBUTE_KEY); - if (font == null) { - if (fontFamily != null) { - style.removeAttribute(StyleConstants.FontFamily); - } - if (fontSize != null) { - style.removeAttribute(StyleConstants.FontSize); - } - if (isBold != null) { - style.removeAttribute(StyleConstants.Bold); - } - if (isItalic != null) { - style.removeAttribute(StyleConstants.Italic); - } - if (fontAttribute != null) { - style.removeAttribute(FONT_ATTRIBUTE_KEY); - } - } else { - if (!font.getName().equals(fontFamily)) { - StyleConstants.setFontFamily(style, font.getName()); - } - if (fontSize == null || fontSize != font.getSize()) { - StyleConstants.setFontSize(style, font.getSize()); - } - if (isBold == null || isBold != font.isBold()) { - StyleConstants.setBold(style, font.isBold()); - } - if (isItalic == null || isItalic != font.isItalic()) { - StyleConstants.setItalic(style, font.isItalic()); - } - if (!font.equals(fontAttribute)) { - style.addAttribute(FONT_ATTRIBUTE_KEY, font); - } - } - } - - /** - * Update the color in the default style of the document. - * - * @param color the new color to use or null to remove the color attribute from the document's style - */ - private void updateForeground(final Color color) { - StyledDocument doc = (StyledDocument) getComponent().getDocument(); - Style style = doc.getStyle(StyleContext.DEFAULT_STYLE); - - if (style == null) { - return; - } - - if (color == null) { - if (style.getAttribute(StyleConstants.Foreground) != null) { - style.removeAttribute(StyleConstants.Foreground); - } - } else { - if (!color.equals(StyleConstants.getForeground(style))) { - StyleConstants.setForeground(style, color); - } - } - } - - /** - * Fetch an action map to use. The map for a JEditorPane is not shared because it changes with the EditorKit. - */ - public ActionMap getActionMap() { - ActionMap am = new ActionMapUIResource(); - am.put("requestFocus", new FocusAction()); - EditorKit editorKit = getEditorKit(getComponent()); - if (editorKit != null) { - Action[] actions = editorKit.getActions(); - if (actions != null) { - addActions(am, actions); - } - } - am.put(TransferHandler.getCutAction().getValue(Action.NAME), - TransferHandler.getCutAction()); - am.put(TransferHandler.getCopyAction().getValue(Action.NAME), - TransferHandler.getCopyAction()); - am.put(TransferHandler.getPasteAction().getValue(Action.NAME), - TransferHandler.getPasteAction()); - if (editorKit instanceof DefaultEditorKit) { - am.put(TOGGLE_INSERT, new ToggleInsertAction()); - } - return am; - } - - void addActions(final ActionMap map, final Action[] actions) { - int n = actions.length; - for (Action a : actions) { - map.put(a.getValue(Action.NAME), a); - } - } - - /** - * This method gets called when a bound property is changed on the associated JTextComponent. This is a hook which - * UI implementations may change to reflect how the UI displays bound properties of JTextComponent subclasses. This - * is implemented to rebuild the ActionMap based upon an EditorKit change. - * - * @param evt the property change event - */ - 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(); - } 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(c.getFont(), c.getForeground()); - 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(); - } - } - - } - } - - /** - * Fetches the name used as a key to lookup properties through the UIManager. This is used as a prefix to all the - * standard text properties. - * - * @return the name ("EditorPane") - */ + @Override protected String getPropertyPrefix() { return "EditorPane"; } - - /** - * {@inheritDoc} - * - * @since 1.5 - */ - public void uninstallUI(final JComponent c) { - cleanDisplayProperties(); - super.uninstallUI(c); - } - - /** - * Fetches the EditorKit for the UI. This is whatever is currently set in the associated JEditorPane. - * - * @return the editor capabilities - */ - public EditorKit getEditorKit(final JTextComponent tc) { - JEditorPane pane = (JEditorPane) getComponent(); - return pane.getEditorKit(); - } - - void removeActions(final ActionMap map, final Action[] actions) { - for (Action a : actions) { - map.remove(a.getValue(Action.NAME)); - } - } - - protected static class StyleSheetUIResource extends StyleSheet implements UIResource {} } diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/text/DarkPasswordFieldUI.java b/core/src/main/java/com/github/weisj/darklaf/ui/text/DarkPasswordFieldUI.java index a8eee614..695b68fc 100644 --- a/core/src/main/java/com/github/weisj/darklaf/ui/text/DarkPasswordFieldUI.java +++ b/core/src/main/java/com/github/weisj/darklaf/ui/text/DarkPasswordFieldUI.java @@ -37,6 +37,7 @@ import javax.swing.text.JTextComponent; import com.github.weisj.darklaf.graphics.GraphicsContext; import com.github.weisj.darklaf.graphics.PaintUtil; import com.github.weisj.darklaf.icons.EmptyIcon; +import com.github.weisj.darklaf.ui.text.bridge.DarkPasswordFieldUIBridge; import com.github.weisj.darklaf.util.PropertyUtil; /** @@ -46,7 +47,7 @@ import com.github.weisj.darklaf.util.PropertyUtil; public class DarkPasswordFieldUI extends DarkPasswordFieldUIBridge { protected static final String KEY_PREFIX = "JPasswordField."; - public static final String KEY_SHOW_VIEW_BUTTON = "JPasswordField.showViewIcon"; + public static final String KEY_SHOW_VIEW_BUTTON = KEY_PREFIX + "showViewIcon"; protected Icon show; protected Icon showPressed; protected int borderSize; diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/text/DarkTextAreaUI.java b/core/src/main/java/com/github/weisj/darklaf/ui/text/DarkTextAreaUI.java index 5892e778..2c3d0701 100644 --- a/core/src/main/java/com/github/weisj/darklaf/ui/text/DarkTextAreaUI.java +++ b/core/src/main/java/com/github/weisj/darklaf/ui/text/DarkTextAreaUI.java @@ -24,115 +24,27 @@ */ package com.github.weisj.darklaf.ui.text; -import java.awt.*; -import java.beans.PropertyChangeEvent; - import javax.swing.*; import javax.swing.plaf.ComponentUI; -import javax.swing.plaf.TextUI; -import javax.swing.plaf.basic.BasicTextAreaUI; -import javax.swing.text.*; -import com.github.weisj.darklaf.util.PropertyKey; +import com.github.weisj.darklaf.ui.text.bridge.DarkTextAreaUIBridge; /** * @author Jannis Weis */ -public class DarkTextAreaUI extends DarkTextUI { - - private static final JTextArea area = new JTextArea() { - @Override - public void setUI(final TextUI ui) {} - }; - private static final BasicTextAreaUI basicTextAreaUI = new BasicTextAreaUIWrapper(); +public class DarkTextAreaUI extends DarkTextAreaUIBridge { public static ComponentUI createUI(final JComponent ta) { return new DarkTextAreaUI(); } - /* - * Implementation of BasicTextAreaUI - */ - /** - * This method gets called when a bound property is changed on the associated JTextComponent. This is a hook which - * UI implementations may change to reflect how the UI displays bound properties of JTextComponent subclasses. This - * is implemented to rebuild the View when the - * WrapLine or the WrapStyleWord property changes. - * - * @param evt the property change event - */ - public void propertyChange(final PropertyChangeEvent evt) { - super.propertyChange(evt); - if (evt.getPropertyName().equals("lineWrap") || - evt.getPropertyName().equals("wrapStyleWord") || - evt.getPropertyName().equals("tabSize")) { - // rebuild the view - modelChanged(); - } else if (PropertyKey.EDITABLE.equals(evt.getPropertyName())) { - updateFocusTraversalKeys(); - } - } - + @Override protected String getPropertyPrefix() { return "TextArea"; } - /** - * Creates the view for an element. Returns a WrappedPlainView or PlainView. - * - * @param elem the element - * @return the view - */ - public View create(final Element elem) { - JTextComponent editor = getComponent(); - if (editor instanceof JTextArea) { - JTextArea c = (JTextArea) editor; - area.setLineWrap(c.getLineWrap()); - area.setWrapStyleWord(c.getWrapStyleWord()); - basicTextAreaUI.installUI(area); - } - return basicTextAreaUI.create(elem); - } - - /** - * Returns the baseline. - * - * @see javax.swing.JComponent#getBaseline(int, int) - * @since 1.6 - */ - public int getBaseline(final JComponent c, final int width, final int height) { - return basicTextAreaUI.getBaseline(c, width, height); - } - - /** - * Returns an enum indicating how the baseline of the component changes as the size changes. - * - * @see javax.swing.JComponent#getBaseline(int, int) - * @since 1.6 - */ - public Component.BaselineResizeBehavior getBaselineResizeBehavior(final JComponent c) { - return basicTextAreaUI.getBaselineResizeBehavior(c); - } - @Override protected DarkCaret.CaretStyle getDefaultCaretStyle() { return DarkCaret.CaretStyle.VERTICAL_LINE_STYLE; } - - protected static class BasicTextAreaUIWrapper extends BasicTextAreaUI { - - @Override - public void installUI(final JComponent c) { - super.installUI(c); - } - - @Override - protected void installDefaults() {} - - @Override - protected void installKeyboardActions() {} - - @Override - protected void installListeners() {} - } } diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/text/DarkTextFieldUI.java b/core/src/main/java/com/github/weisj/darklaf/ui/text/DarkTextFieldUI.java index 3c6f3fba..b99bc1dc 100644 --- a/core/src/main/java/com/github/weisj/darklaf/ui/text/DarkTextFieldUI.java +++ b/core/src/main/java/com/github/weisj/darklaf/ui/text/DarkTextFieldUI.java @@ -39,6 +39,7 @@ import com.github.weisj.darklaf.graphics.GraphicsContext; import com.github.weisj.darklaf.listener.MouseClickListener; import com.github.weisj.darklaf.listener.MouseMovementListener; import com.github.weisj.darklaf.listener.PopupMenuAdapter; +import com.github.weisj.darklaf.ui.text.bridge.DarkTextFieldUIBridge; import com.github.weisj.darklaf.util.DarkUIUtil; import com.github.weisj.darklaf.util.PropertyUtil; diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/text/DarkTextFieldUIBridge.java b/core/src/main/java/com/github/weisj/darklaf/ui/text/DarkTextFieldUIBridge.java deleted file mode 100644 index 472e415c..00000000 --- a/core/src/main/java/com/github/weisj/darklaf/ui/text/DarkTextFieldUIBridge.java +++ /dev/null @@ -1,370 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2020 Jannis Weis - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - */ -package com.github.weisj.darklaf.ui.text; - -import java.awt.*; - -import javax.swing.*; -import javax.swing.event.DocumentEvent; -import javax.swing.plaf.basic.BasicTextFieldUI; -import javax.swing.text.*; - -import com.github.weisj.darklaf.ui.html.DarkHTML; - -/** - * This class is an exact copy of the implementation of {@link BasicTextFieldUI}. In this way it is possible to contain - * all Laf specific methods in {@link DarkTextFieldUI}, without having to extends {@link BasicTextFieldUI} directly and - * instead extend the {@link DarkTextUI} base class. - * - * @author Jannis Weis - */ -public abstract class DarkTextFieldUIBridge extends DarkTextUI { - - /** - * Fetches the name used as a key to lookup properties through the UIManager. This is used as a prefix to all the - * standard text properties. - * - * @return the name ("TextField") - */ - protected String getPropertyPrefix() { - return "TextField"; - } - - /** - * Creates a view (FieldView) based on an element. - * - * @param elem the element - * @return the view - */ - public View create(final Element elem) { - Document doc = elem.getDocument(); - Object i18nFlag = doc.getProperty("i18n"/* AbstractDocument.I18NProperty */); - if (Boolean.TRUE.equals(i18nFlag)) { - // To support bidirectional text, we build a more heavyweight - // representation of the field. - String kind = elem.getName(); - if (kind != null) { - if (kind.equals(AbstractDocument.ContentElementName)) { - return new GlyphView(elem) { - @Override - public float getMinimumSpan(final int axis) { - // no wrap - return getPreferredSpan(axis); - } - }; - } else if (kind.equals(AbstractDocument.ParagraphElementName)) { - return new I18nFieldView(elem); - } - } - // this shouldn't happen, should probably throw in this case. - } - return new FieldView(elem); - } - - /** - * Returns the baseline. - * - * @throws NullPointerException {@inheritDoc} - * @throws IllegalArgumentException {@inheritDoc} - * @see javax.swing.JComponent#getBaseline(int, int) - * @since 1.6 - */ - public int getBaseline(final JComponent c, final int width, int height) { - super.getBaseline(c, width, height); - View rootView = getRootView((JTextComponent) c); - if (rootView.getViewCount() > 0) { - Insets insets = c.getInsets(); - height = height - insets.top - insets.bottom; - if (height > 0) { - int baseline = insets.top; - View fieldView = rootView.getView(0); - int vspan = (int) fieldView.getPreferredSpan(View.Y_AXIS); - if (height != vspan) { - int slop = height - vspan; - baseline += slop / 2; - } - if (fieldView instanceof I18nFieldView) { - int fieldBaseline = DarkHTML.getBaseline(fieldView, width - insets.left - insets.right, - height); - if (fieldBaseline < 0) { - return -1; - } - baseline += fieldBaseline; - } else { - FontMetrics fm = c.getFontMetrics(c.getFont()); - baseline += fm.getAscent(); - } - return baseline; - } - } - return -1; - } - - /** - * Returns an enum indicating how the baseline of the component changes as the size changes. - * - * @throws NullPointerException {@inheritDoc} - * @see javax.swing.JComponent#getBaseline(int, int) - * @since 1.6 - */ - public Component.BaselineResizeBehavior getBaselineResizeBehavior(final JComponent c) { - super.getBaselineResizeBehavior(c); - return Component.BaselineResizeBehavior.CENTER_OFFSET; - } - - /** - * A field view that support bidirectional text via the support provided by ParagraphView. - */ - static class I18nFieldView extends ParagraphView { - - I18nFieldView(final Element elem) { - super(elem); - } - - protected void setJustification(final int j) { - // Justification is done in adjustAllocation(), so disable - // ParagraphView's justification handling by doing nothing here. - } - - /** - * Fetch the constraining span to flow against for the given child index. There is no limit for a field since - * it scrolls, so this is implemented to return Integer.MAX_VALUE. - */ - public int getFlowSpan(final int index) { - return Integer.MAX_VALUE; - } - - /** - * Renders using the given rendering surface and area on that surface. The view may need to do layout and create - * child views to enable itself to render into the given allocation. - * - * @param g the rendering surface to use - * @param a the allocated region to render into - * @see View#paint - */ - public void paint(final Graphics g, final Shape a) { - Rectangle r = (Rectangle) a; - g.clipRect(r.x, r.y, r.width, r.height); - super.paint(g, adjustAllocation(a)); - } - - /** - * Adjusts the allocation given to the view to be a suitable allocation for a text field. If the view has been - * allocated more than the preferred span vertically, the allocation is changed to be centered vertically. - * Horizontally the view is adjusted according to the horizontal alignment property set on the associated - * JTextField (if that is the type of the hosting component). - * - * @param a the allocation given to the view, which may need to be adjusted. - * @return the allocation that the superclass should use. - */ - Shape adjustAllocation(final Shape a) { - if (a != null) { - Rectangle bounds = a.getBounds(); - int vspan = (int) getPreferredSpan(Y_AXIS); - int hspan = (int) getPreferredSpan(X_AXIS); - if (bounds.height != vspan) { - int slop = bounds.height - vspan; - bounds.y += slop / 2; - bounds.height -= slop; - } - - // horizontal adjustments - Component c = getContainer(); - if (c instanceof JTextField) { - JTextField field = (JTextField) c; - BoundedRangeModel vis = field.getHorizontalVisibility(); - int max = Math.max(hspan, bounds.width); - int value = vis.getValue(); - int extent = Math.min(max, bounds.width - 1); - if ((value + extent) > max) { - value = max - extent; - } - vis.setRangeProperties(value, extent, vis.getMinimum(), - max, false); - if (hspan < bounds.width) { - // horizontally align the interior - int slop = bounds.width - 1 - hspan; - - int align = ((JTextField) c).getHorizontalAlignment(); - if (isLeftToRight(c)) { - if (align == LEADING) { - align = LEFT; - } else if (align == TRAILING) { - align = RIGHT; - } - } else { - if (align == LEADING) { - align = RIGHT; - } else if (align == TRAILING) { - align = LEFT; - } - } - - switch (align) { - case SwingConstants.CENTER : - bounds.x += slop / 2; - bounds.width -= slop; - break; - case SwingConstants.RIGHT : - bounds.x += slop; - bounds.width -= slop; - break; - } - } else { - // adjust the allocation to match the bounded range. - bounds.width = hspan; - bounds.x -= vis.getValue(); - } - } - return bounds; - } - return null; - } - - static boolean isLeftToRight(final java.awt.Component c) { - return c.getComponentOrientation().isLeftToRight(); - } - - // --- View methods ------------------------------------------- - - /** - * Determines the resizability of the view along the given axis. A value of 0 or less is not resizable. - * - * @param axis View.X_AXIS or View.Y_AXIS - * @return the weight -> 1 for View.X_AXIS, else 0 - */ - public int getResizeWeight(final int axis) { - if (axis == View.X_AXIS) { - return 1; - } - return 0; - } - - /** - * Provides a mapping from the document model coordinate space to the coordinate space of the view mapped to - * it. - * - * @param pos the position to convert >= 0 - * @param a the allocated region to render into - * @return the bounding box of the given position - * @throws BadLocationException if the given position does not represent a valid location in the associated - * document - * @see View#modelToView - */ - public Shape modelToView(final int pos, final Shape a, final Position.Bias b) throws BadLocationException { - return super.modelToView(pos, adjustAllocation(a), b); - } - - /** - * Provides a mapping from the view coordinate space to the logical coordinate space of the model. - * - * @param fx the X coordinate >= 0.0f - * @param fy the Y coordinate >= 0.0f - * @param a the allocated region to render into - * @return the location within the model that best represents the given point in the view - * @see View#viewToModel - */ - public int viewToModel(final float fx, final float fy, final Shape a, final Position.Bias[] bias) { - return super.viewToModel(fx, fy, adjustAllocation(a), bias); - } - - /** - * Provides a mapping from the document model coordinate space to the coordinate space of the view mapped to - * it. - * - * @param p0 the position to convert >= 0 - * @param b0 the bias toward the previous character or the next character represented by - * p0, in case the - * position is a boundary of two views. - * @param p1 the position to convert >= 0 - * @param b1 the bias toward the previous character or the next character represented by - * p1, in case the - * position is a boundary of two views. - * @param a the allocated region to render into - * @return the bounding box of the given position is returned - * @throws BadLocationException if the given position does not represent a valid location in the associated - * document - * @throws IllegalArgumentException for an invalid bias argument - * @see View#viewToModel - */ - public Shape modelToView(final int p0, final Position.Bias b0, - final int p1, final Position.Bias b1, final Shape a) - throws BadLocationException { - return super.modelToView(p0, b0, p1, b1, adjustAllocation(a)); - } - - /** - * Gives notification that something was inserted into the document in a location that this view is responsible - * for. - * - * @param changes the change information from the associated document - * @param a the current allocation of the view - * @param f the factory to use to rebuild if the view has children - * @see View#insertUpdate - */ - public void insertUpdate(final DocumentEvent changes, final Shape a, final ViewFactory f) { - super.insertUpdate(changes, adjustAllocation(a), f); - updateVisibilityModel(); - } - - /** - * Update the visibility model with the associated JTextField (if there is one) to reflect the current - * visibility as a result of changes to the document model. The bounded range properties are updated. If the - * view hasn't yet been shown the extent will be zero and we just set it to be full until determined otherwise. - */ - void updateVisibilityModel() { - Component c = getContainer(); - if (c instanceof JTextField) { - JTextField field = (JTextField) c; - BoundedRangeModel vis = field.getHorizontalVisibility(); - int hspan = (int) getPreferredSpan(X_AXIS); - int extent = vis.getExtent(); - int maximum = Math.max(hspan, extent); - extent = (extent == 0) ? maximum : extent; - int value = maximum - extent; - int oldValue = vis.getValue(); - if ((oldValue + extent) > maximum) { - oldValue = maximum - extent; - } - value = Math.max(0, Math.min(value, oldValue)); - vis.setRangeProperties(value, extent, 0, maximum, false); - } - } - - /** - * Gives notification that something was removed from the document in a location that this view is responsible - * for. - * - * @param changes the change information from the associated document - * @param a the current allocation of the view - * @param f the factory to use to rebuild if the view has children - * @see View#removeUpdate - */ - public void removeUpdate(final DocumentEvent changes, final Shape a, final ViewFactory f) { - super.removeUpdate(changes, adjustAllocation(a), f); - updateVisibilityModel(); - } - } -} 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 b786617f..4e083370 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 @@ -517,7 +517,7 @@ public abstract class DarkTextUI extends BasicTextUI implements PropertyChangeLi * traversalKeysSet in case editor is non editable */ @SuppressWarnings("deprecation") - void updateFocusTraversalKeys() { + protected void updateFocusTraversalKeys() { /* * Fix for 4514331 Non-editable JTextArea and similar * should allow Tab to keyboard - accessibility 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 new file mode 100644 index 00000000..3adde4e1 --- /dev/null +++ b/core/src/main/java/com/github/weisj/darklaf/ui/text/bridge/DarkEditorPaneUIBridge.java @@ -0,0 +1,153 @@ +/* + * MIT License + * + * Copyright (c) 2020 Jannis Weis + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ +package com.github.weisj.darklaf.ui.text.bridge; + +import java.beans.PropertyChangeEvent; + +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 + */ +public abstract class DarkEditorPaneUIBridge extends DarkTextUI { + + private static final DummyEditorPane editorPane = new DummyEditorPane(); + private static final BasicEditorPaneUI basicEditorPaneUI = new DummyEditorPaneUI(); + + static { + basicEditorPaneUI.installUI(editorPane); + } + + @Override + public void installUI(final JComponent c) { + super.installUI(c); + updateDisplayProperties(c); + } + + @Override + public void uninstallUI(final JComponent c) { + cleanDisplayProperties(c); + super.uninstallUI(c); + } + + protected void updateDisplayProperties(final JComponent c) { + if (c instanceof JEditorPane) { + editorPane.setEditorPane((JEditorPane) c); + basicEditorPaneUI.installUI(editorPane); + } + } + + protected void cleanDisplayProperties(final JComponent c) { + if (c instanceof JEditorPane) { + editorPane.setEditorPane((JEditorPane) c); + basicEditorPaneUI.uninstallUI(editorPane); + } + } + + @Override + public ActionMap getActionMap() { + editorPane.setEditorPane((JEditorPane) getComponent()); + ActionMap am = editorPane.getActionMap(); + EditorKit editorKit = getEditorKit(getComponent()); + if (editorKit instanceof DefaultEditorKit) { + am.put(TOGGLE_INSERT, new ToggleInsertAction()); + } + return am; + } + + @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(); + } 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)); + } + } + + @Override + public EditorKit getEditorKit(final JTextComponent tc) { + JEditorPane pane = (JEditorPane) getComponent(); + return pane.getEditorKit(); + } +} diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/text/DarkPasswordFieldUIBridge.java b/core/src/main/java/com/github/weisj/darklaf/ui/text/bridge/DarkPasswordFieldUIBridge.java similarity index 80% rename from core/src/main/java/com/github/weisj/darklaf/ui/text/DarkPasswordFieldUIBridge.java rename to core/src/main/java/com/github/weisj/darklaf/ui/text/bridge/DarkPasswordFieldUIBridge.java index ae883fb9..b6bab17b 100644 --- a/core/src/main/java/com/github/weisj/darklaf/ui/text/DarkPasswordFieldUIBridge.java +++ b/core/src/main/java/com/github/weisj/darklaf/ui/text/bridge/DarkPasswordFieldUIBridge.java @@ -22,7 +22,7 @@ * SOFTWARE. * */ -package com.github.weisj.darklaf.ui.text; +package com.github.weisj.darklaf.ui.text.bridge; import javax.swing.*; import javax.swing.plaf.basic.BasicPasswordFieldUI; @@ -31,6 +31,9 @@ import javax.swing.text.Element; import javax.swing.text.PasswordView; import javax.swing.text.View; +import com.github.weisj.darklaf.ui.text.DarkPasswordFieldUI; +import com.github.weisj.darklaf.ui.text.DarkTextFieldUI; + /** * This class is an exact copy of the implementation of {@link BasicPasswordFieldUI}. In this way it is possible to * contain all Laf specific methods in {@link DarkPasswordFieldUI}, without having to extends {@link @@ -40,11 +43,7 @@ import javax.swing.text.View; */ public abstract class DarkPasswordFieldUIBridge extends DarkTextFieldUI { - /** - * Installs the necessary properties on the JPasswordField. - * - * @since 1.6 - */ + @Override protected void installDefaults() { super.installDefaults(); String prefix = getPropertyPrefix(); @@ -54,30 +53,17 @@ public abstract class DarkPasswordFieldUIBridge extends DarkTextFieldUI { } } - /** - * Fetches the name used as a key to look up properties through the UIManager. This is used as a prefix to all the - * standard text properties. - * - * @return the name ("PasswordField") - */ + @Override protected String getPropertyPrefix() { return "PasswordField"; } - /** - * Creates a view (PasswordView) for an element. - * - * @param elem the element - * @return the view - */ + @Override public View create(final Element elem) { return new PasswordView(elem); } - /** - * Create the action map for Password Field. This map provides same actions for double mouse click and and for - * triple mouse click (see bug 4231444). - */ + @Override public ActionMap createActionMap() { ActionMap map = super.createActionMap(); if (map.get(DefaultEditorKit.selectWordAction) != null) { 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 new file mode 100644 index 00000000..7b7233e7 --- /dev/null +++ b/core/src/main/java/com/github/weisj/darklaf/ui/text/bridge/DarkTextAreaUIBridge.java @@ -0,0 +1,86 @@ +/* + * MIT License + * + * Copyright (c) 2020 Jannis Weis + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ +package com.github.weisj.darklaf.ui.text.bridge; + +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; + +import com.github.weisj.darklaf.ui.text.DarkTextUI; +import com.github.weisj.darklaf.ui.text.dummy.DummyTextArea; +import com.github.weisj.darklaf.ui.text.dummy.DummyTextAreaUI; +import com.github.weisj.darklaf.util.PropertyKey; + +/** + * @author Jannis Weis + */ +public abstract class DarkTextAreaUIBridge extends DarkTextUI { + + private static final JTextArea area = new DummyTextArea(); + private static final BasicTextAreaUI basicTextAreaUI = new DummyTextAreaUI(); + + /* + * Implementation of BasicTextAreaUI + */ + @Override + public void propertyChange(final PropertyChangeEvent evt) { + super.propertyChange(evt); + if (evt.getPropertyName().equals("lineWrap") || + evt.getPropertyName().equals("wrapStyleWord") || + evt.getPropertyName().equals("tabSize")) { + // rebuild the view + modelChanged(); + } else if (PropertyKey.EDITABLE.equals(evt.getPropertyName())) { + updateFocusTraversalKeys(); + } + } + + @Override + public View create(final Element elem) { + JTextComponent editor = getComponent(); + if (editor instanceof JTextArea) { + JTextArea c = (JTextArea) editor; + area.setLineWrap(c.getLineWrap()); + area.setWrapStyleWord(c.getWrapStyleWord()); + basicTextAreaUI.installUI(area); + } + return basicTextAreaUI.create(elem); + } + + @Override + public int getBaseline(final JComponent c, final int width, final int height) { + return basicTextAreaUI.getBaseline(c, width, height); + } + + @Override + public Component.BaselineResizeBehavior getBaselineResizeBehavior(final JComponent c) { + return basicTextAreaUI.getBaselineResizeBehavior(c); + } +} diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/text/bridge/DarkTextFieldUIBridge.java b/core/src/main/java/com/github/weisj/darklaf/ui/text/bridge/DarkTextFieldUIBridge.java new file mode 100644 index 00000000..1b92427f --- /dev/null +++ b/core/src/main/java/com/github/weisj/darklaf/ui/text/bridge/DarkTextFieldUIBridge.java @@ -0,0 +1,65 @@ +/* + * MIT License + * + * Copyright (c) 2020 Jannis Weis + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ +package com.github.weisj.darklaf.ui.text.bridge; + +import java.awt.*; + +import javax.swing.*; +import javax.swing.plaf.basic.BasicTextFieldUI; +import javax.swing.text.*; + +import com.github.weisj.darklaf.ui.text.DarkTextFieldUI; +import com.github.weisj.darklaf.ui.text.DarkTextUI; + +/** + * This class is an exact copy of the implementation of {@link BasicTextFieldUI}. In this way it is possible to contain + * all Laf specific methods in {@link DarkTextFieldUI}, without having to extends {@link BasicTextFieldUI} directly and + * instead extend the {@link DarkTextUI} base class. + * + * @author Jannis Weis + */ +public abstract class DarkTextFieldUIBridge extends DarkTextUI { + + private static final BasicTextFieldUI basicTextFieldUI = new BasicTextFieldUI(); + + protected String getPropertyPrefix() { + return "TextField"; + } + + @Override + public View create(final Element elem) { + return basicTextFieldUI.create(elem); + } + + @Override + public int getBaseline(final JComponent c, final int width, final int height) { + return basicTextFieldUI.getBaseline(c, width, height); + } + + @Override + public Component.BaselineResizeBehavior getBaselineResizeBehavior(final JComponent c) { + return basicTextFieldUI.getBaselineResizeBehavior(c); + } +} 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 new file mode 100644 index 00000000..314ae19c --- /dev/null +++ b/core/src/main/java/com/github/weisj/darklaf/ui/text/dummy/DummyEditorPane.java @@ -0,0 +1,128 @@ +/* + * MIT License + * + * Copyright (c) 2020 Jannis Weis + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ +package com.github.weisj.darklaf.ui.text.dummy; + +import java.awt.*; +import java.awt.event.InputMethodListener; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import java.awt.event.MouseWheelListener; +import java.beans.PropertyChangeListener; + +import javax.swing.*; +import javax.swing.event.DocumentListener; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.TextUI; +import javax.swing.text.Caret; +import javax.swing.text.Document; +import javax.swing.text.Highlighter; + +public class DummyEditorPane extends JEditorPane { + + private JEditorPane editorPane; + + public void setEditorPane(final JEditorPane editorPane) { + this.editorPane = editorPane; + } + + @Override + public Document getDocument() { + if (editorPane == null) return super.getDocument(); + return editorPane.getDocument(); + } + + @Override + public Font getFont() { + if (editorPane == null) return null; + return editorPane.getFont(); + } + + @Override + public Color getForeground() { + if (editorPane == null) return null; + return editorPane.getForeground(); + } + + @Override + public Color getBackground() { + if (editorPane == null) return null; + return editorPane.getBackground(); + } + + @Override + protected void setUI(final ComponentUI newUI) {} + + @Override + public void setUI(final TextUI ui) {} + + @Override + public void updateUI() {} + + @Override + public void addPropertyChangeListener(final PropertyChangeListener listener) {} + + @Override + public synchronized void addMouseListener(final MouseListener l) {} + + @Override + public synchronized void addMouseMotionListener(final MouseMotionListener l) {} + + @Override + public synchronized void addMouseWheelListener(final MouseWheelListener l) {} + + @Override + public void addInputMethodListener(final InputMethodListener l) {} + + @Override + public void setHighlighter(final Highlighter h) {} + + @Override + public void setTransferHandler(final TransferHandler newHandler) {} + + @Override + public void setCaret(final Caret c) {} + + @Override + public void setDocument(final Document doc) {} + + @Override + public void setDisabledTextColor(final Color c) {} + + @Override + public void setDragEnabled(final boolean b) {} + + @Override + public LayoutManager getLayout() { + return null; + } + + @Override + public void setLayout(final LayoutManager mgr) { + if (mgr instanceof DocumentListener) { + Document doc = getDocument(); + if (doc != null) doc.removeDocumentListener((DocumentListener) mgr); + } + } +} diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/text/dummy/DummyEditorPaneUI.java b/core/src/main/java/com/github/weisj/darklaf/ui/text/dummy/DummyEditorPaneUI.java new file mode 100644 index 00000000..88b1f800 --- /dev/null +++ b/core/src/main/java/com/github/weisj/darklaf/ui/text/dummy/DummyEditorPaneUI.java @@ -0,0 +1,39 @@ +/* + * MIT License + * + * Copyright (c) 2020 Jannis Weis + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ +package com.github.weisj.darklaf.ui.text.dummy; + +import javax.swing.plaf.basic.BasicEditorPaneUI; + +public class DummyEditorPaneUI extends BasicEditorPaneUI { + + @Override + protected void installDefaults() {} + + @Override + protected void installListeners() {} + + @Override + protected void modelChanged() {} +} diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/text/dummy/DummyTextArea.java b/core/src/main/java/com/github/weisj/darklaf/ui/text/dummy/DummyTextArea.java new file mode 100644 index 00000000..67b0315f --- /dev/null +++ b/core/src/main/java/com/github/weisj/darklaf/ui/text/dummy/DummyTextArea.java @@ -0,0 +1,98 @@ +/* + * MIT License + * + * Copyright (c) 2020 Jannis Weis + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ +package com.github.weisj.darklaf.ui.text.dummy; + +import java.awt.*; +import java.awt.event.InputMethodListener; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import java.awt.event.MouseWheelListener; +import java.beans.PropertyChangeListener; + +import javax.swing.*; +import javax.swing.event.DocumentListener; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.TextUI; +import javax.swing.text.Caret; +import javax.swing.text.Document; +import javax.swing.text.Highlighter; + +public class DummyTextArea extends JTextArea { + + @Override + protected void setUI(final ComponentUI newUI) {} + + @Override + public void setUI(final TextUI ui) {} + + @Override + public void updateUI() {} + + @Override + public void addPropertyChangeListener(final PropertyChangeListener listener) {} + + @Override + public synchronized void addMouseListener(final MouseListener l) {} + + @Override + public synchronized void addMouseMotionListener(final MouseMotionListener l) {} + + @Override + public synchronized void addMouseWheelListener(final MouseWheelListener l) {} + + @Override + public void addInputMethodListener(final InputMethodListener l) {} + + @Override + public void setHighlighter(final Highlighter h) {} + + @Override + public void setTransferHandler(final TransferHandler newHandler) {} + + @Override + public void setCaret(final Caret c) {} + + @Override + public void setDocument(final Document doc) {} + + @Override + public void setDisabledTextColor(final Color c) {} + + @Override + public void setDragEnabled(final boolean b) {} + + @Override + public LayoutManager getLayout() { + return null; + } + + @Override + public void setLayout(final LayoutManager mgr) { + if (mgr instanceof DocumentListener) { + Document doc = getDocument(); + if (doc != null) doc.removeDocumentListener((DocumentListener) mgr); + } + } +} diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/text/dummy/DummyTextAreaUI.java b/core/src/main/java/com/github/weisj/darklaf/ui/text/dummy/DummyTextAreaUI.java new file mode 100644 index 00000000..95ec891c --- /dev/null +++ b/core/src/main/java/com/github/weisj/darklaf/ui/text/dummy/DummyTextAreaUI.java @@ -0,0 +1,48 @@ +/* + * MIT License + * + * Copyright (c) 2020 Jannis Weis + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ +package com.github.weisj.darklaf.ui.text.dummy; + +import javax.swing.*; +import javax.swing.plaf.basic.BasicTextAreaUI; + +public class DummyTextAreaUI extends BasicTextAreaUI { + + @Override + public void installUI(final JComponent c) { + super.installUI(c); + } + + @Override + protected void installDefaults() {} + + @Override + protected void installKeyboardActions() {} + + @Override + protected void installListeners() {} + + @Override + protected void modelChanged() {} +} diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/text/dummy/DummyTextComponent.java b/core/src/main/java/com/github/weisj/darklaf/ui/text/dummy/DummyTextComponent.java new file mode 100644 index 00000000..7c503b09 --- /dev/null +++ b/core/src/main/java/com/github/weisj/darklaf/ui/text/dummy/DummyTextComponent.java @@ -0,0 +1,99 @@ +/* + * MIT License + * + * Copyright (c) 2020 Jannis Weis + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ +package com.github.weisj.darklaf.ui.text.dummy; + +import java.awt.*; +import java.awt.event.InputMethodListener; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import java.awt.event.MouseWheelListener; +import java.beans.PropertyChangeListener; + +import javax.swing.*; +import javax.swing.event.DocumentListener; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.TextUI; +import javax.swing.text.Caret; +import javax.swing.text.Document; +import javax.swing.text.Highlighter; +import javax.swing.text.JTextComponent; + +public class DummyTextComponent extends JTextComponent { + + @Override + protected void setUI(final ComponentUI newUI) {} + + @Override + public void setUI(final TextUI ui) {} + + @Override + public void updateUI() {} + + @Override + public void addPropertyChangeListener(final PropertyChangeListener listener) {} + + @Override + public synchronized void addMouseListener(final MouseListener l) {} + + @Override + public synchronized void addMouseMotionListener(final MouseMotionListener l) {} + + @Override + public synchronized void addMouseWheelListener(final MouseWheelListener l) {} + + @Override + public void addInputMethodListener(final InputMethodListener l) {} + + @Override + public void setHighlighter(final Highlighter h) {} + + @Override + public void setTransferHandler(final TransferHandler newHandler) {} + + @Override + public void setCaret(final Caret c) {} + + @Override + public void setDocument(final Document doc) {} + + @Override + public void setDisabledTextColor(final Color c) {} + + @Override + public void setDragEnabled(final boolean b) {} + + @Override + public LayoutManager getLayout() { + return null; + } + + @Override + public void setLayout(final LayoutManager mgr) { + if (mgr instanceof DocumentListener) { + Document doc = getDocument(); + if (doc != null) doc.removeDocumentListener((DocumentListener) mgr); + } + } +}