[autocomplete] 126/143: Adding support for using fancy smancy Substance renderers if a Substance Look and Feel is installed. We don't want a compile time dependency so everything is done by reflection and delegation. This means we don't get Substance's rollover effects, but that's a minor issue.
Benjamin Mesing
ben at alioth.debian.org
Sat Oct 19 12:53:30 UTC 2013
This is an automated email from the git hooks/post-receive script.
ben pushed a commit to branch master
in repository autocomplete.
commit 1f665e5c2d4dc68407d5b8944690170876b9c803
Author: bobbylight <robert at fifesoft.com>
Date: Sun Jan 20 07:30:01 2013 +0000
Adding support for using fancy smancy Substance renderers if a Substance Look and Feel is installed. We don't want a compile time dependency so everything is done by reflection and delegation. This means we don't get Substance's rollover effects, but that's a minor issue.
---
.../ui/autocomplete/AutoCompletePopupWindow.java | 49 +++++-
.../ui/autocomplete/CompletionCellRenderer.java | 161 ++++++++++++++++++--
src/org/fife/ui/autocomplete/TipUtil.java | 8 +
src/org/fife/ui/autocomplete/Util.java | 83 ++++++++++
4 files changed, 285 insertions(+), 16 deletions(-)
diff --git a/src/org/fife/ui/autocomplete/AutoCompletePopupWindow.java b/src/org/fife/ui/autocomplete/AutoCompletePopupWindow.java
index 4d22903..0956704 100644
--- a/src/org/fife/ui/autocomplete/AutoCompletePopupWindow.java
+++ b/src/org/fife/ui/autocomplete/AutoCompletePopupWindow.java
@@ -123,6 +123,12 @@ class AutoCompletePopupWindow extends JWindow implements CaretListener,
*/
private static final int VERTICAL_SPACE = 1;
+ /**
+ * The class name of the Substance List UI.
+ */
+ private static final String SUBSTANCE_LIST_UI =
+ "org.pushingpixels.substance.internal.ui.SubstanceListUI";
+
/**
* Constructor.
@@ -130,19 +136,14 @@ class AutoCompletePopupWindow extends JWindow implements CaretListener,
* @param parent The parent window (hosting the text component).
* @param ac The auto-completion instance.
*/
- public AutoCompletePopupWindow(Window parent, AutoCompletion ac) {
+ public AutoCompletePopupWindow(Window parent, final AutoCompletion ac) {
super(parent);
ComponentOrientation o = ac.getTextComponentOrientation();
this.ac = ac;
model = new CompletionListModel();
- list = new JList(model) {
- public void setUI(ListUI ui) {
- // Keep our special UI, no matter what
- super.setUI(new FastListUI());
- }
- };
+ list = new PopupList(model);
list.setCellRenderer(new DelegatingCellRenderer());
list.addListSelectionListener(this);
@@ -920,6 +921,40 @@ class AutoCompletePopupWindow extends JWindow implements CaretListener,
}
+ /**
+ * The actual list of completion choices in this popup window.
+ */
+ private class PopupList extends JList {
+
+ public PopupList(CompletionListModel model) {
+ super(model);
+ }
+
+ public void setUI(ListUI ui) {
+ if (Util.getUseSubstanceRenderers() &&
+ SUBSTANCE_LIST_UI.equals(ui.getClass().getName())) {
+ // Substance requires its special ListUI be installed for
+ // its renderers to actually render (!), but long completion
+ // lists (e.g. PHPCompletionProvider in RSTALanguageSupport)
+ // will simply populate too slowly on initial display (when
+ // calculating preferred size of all items), so in this case
+ // we give a prototype cell value.
+ CompletionProvider p = ac.getCompletionProvider();
+ BasicCompletion bc = new BasicCompletion(p, "Hello world");
+ setPrototypeCellValue(bc);
+ }
+ else {
+ // Our custom UI that is faster for long HTML completion
+ // lists.
+ ui = new FastListUI();
+ setPrototypeCellValue(null);
+ }
+ super.setUI(ui);
+ }
+
+ }
+
+
class RightAction extends AbstractAction {
public void actionPerformed(ActionEvent e) {
diff --git a/src/org/fife/ui/autocomplete/CompletionCellRenderer.java b/src/org/fife/ui/autocomplete/CompletionCellRenderer.java
index 5a82a25..af6365a 100644
--- a/src/org/fife/ui/autocomplete/CompletionCellRenderer.java
+++ b/src/org/fife/ui/autocomplete/CompletionCellRenderer.java
@@ -17,6 +17,7 @@ import java.awt.Rectangle;
import javax.swing.DefaultListCellRenderer;
import javax.swing.Icon;
import javax.swing.JList;
+import javax.swing.SwingUtilities;
import javax.swing.plaf.basic.BasicHTML;
import javax.swing.text.View;
@@ -58,6 +59,11 @@ public class CompletionCellRenderer extends DefaultListCellRenderer {
private boolean showTypes;
/**
+ * The color to use when rendering types in completion text.
+ */
+ private String typeColor;
+
+ /**
* During rendering, whether the item being rendered is selected.
*/
private boolean selected;
@@ -79,6 +85,14 @@ public class CompletionCellRenderer extends DefaultListCellRenderer {
private Rectangle paintTextR;
/**
+ * An optional delegate renderer (primarily for Substance).
+ */
+ private DefaultListCellRenderer delegate;
+
+ private static final String SUBSTANCE_RENDERER_CLASS_NAME =
+ "org.pushingpixels.substance.api.renderers.SubstanceDefaultListCellRenderer";
+
+ /**
* Keeps the HTML descriptions from "wrapping" in the list, which cuts off
* words.
*/
@@ -89,10 +103,63 @@ public class CompletionCellRenderer extends DefaultListCellRenderer {
* Constructor.
*/
public CompletionCellRenderer() {
- //setDisplayFont(new Font("Monospaced", Font.PLAIN, 12));
- setShowTypes(true);
- paramColor = "#aa0077";
- paintTextR = new Rectangle();
+ init();
+ }
+
+
+ /**
+ * Constructor. This is primarily a hook for Substance, or any other
+ * Look and Feel whose renderers look drastically different than standard
+ * <code>DefaultListCellRenderer</code>s. Everything except for the text
+ * rendering will be done by the delegate. In almost all scenarios, you
+ * will want to use the no-argument constructor instead of this one.
+ *
+ * @param delegate The delegate renderer.
+ * @see #delegateToSubstanceRenderer()
+ */
+ public CompletionCellRenderer(DefaultListCellRenderer delegate) {
+ setDelegateRenderer(delegate);
+ init();
+ }
+
+
+ /**
+ * Returns a decent "parameter" color based on the current default
+ * foreground color.
+ *
+ * @return The parameter color to use.
+ */
+ private String createParamColor() {
+ return Util.isLightForeground(getForeground()) ?
+ Util.getHexString(Util.getHyperlinkForeground()): "#aa0077";
+ }
+
+
+ /**
+ * Returns a decent "type" color based on the current default foreground
+ * color.
+ *
+ * @return The type color to use.
+ */
+ private String createTypeColor() {
+ return "#808080";
+ }
+
+
+ /**
+ * Attempts to delegate rendering to a Substance cell renderer. This
+ * should only be called if Substance is known to be on the classpath.
+ *
+ * @throws Exception If Substance is not on the classpath, or some other
+ * error occurs creating the Substance cell renderer.
+ * @see Util#getUseSubstanceRenderers()
+ * @see #setDelegateRenderer(DefaultListCellRenderer)
+ */
+ public void delegateToSubstanceRenderer() throws Exception {
+ Class clazz = Class.forName(SUBSTANCE_RENDERER_CLASS_NAME);
+ DefaultListCellRenderer delegate =
+ (DefaultListCellRenderer)clazz.newInstance();
+ setDelegateRenderer(delegate);
}
@@ -109,6 +176,17 @@ public class CompletionCellRenderer extends DefaultListCellRenderer {
/**
+ * Returns the delegate renderer, or <code>null</code> if there is none.
+ *
+ * @return The delegate renderer.
+ * @see #setDelegateRenderer(DefaultListCellRenderer)
+ */
+ public DefaultListCellRenderer getDelegateRenderer() {
+ return delegate;
+ }
+
+
+ /**
* Returns the font used when rendering completions.
*
* @return The font. If this is <code>null</code>, then the default list
@@ -137,7 +215,7 @@ public class CompletionCellRenderer extends DefaultListCellRenderer {
setFont(font); // Overrides super's setFont(list.getFont()).
}
this.selected = selected;
- this.realBG = altBG!=null && (index&1)==0 ? altBG : list.getBackground();
+ this.realBG = altBG!=null && (index&1)==1 ? altBG : list.getBackground();
Completion c = (Completion)value;
setIcon(c.getIcon());
@@ -162,7 +240,17 @@ public class CompletionCellRenderer extends DefaultListCellRenderer {
prepareForOtherCompletion(list, c, index, selected, hasFocus);
}
- if (!selected && (index&1)==0 && altBG!=null) {
+ // A delegate renderer might do its own alternate row striping
+ // (Substance does).
+ if (delegate!=null) {
+ delegate.getListCellRendererComponent(list, getText(), index,
+ selected, hasFocus);
+ delegate.setFont(getFont());
+ delegate.setIcon(getIcon());
+ return delegate;
+ }
+
+ if (!selected && (index&1)==1 && altBG!=null) {
setBackground(altBG);
}
@@ -183,6 +271,15 @@ public class CompletionCellRenderer extends DefaultListCellRenderer {
}
+ private void init() {
+ //setDisplayFont(new Font("Monospaced", Font.PLAIN, 12));
+ setShowTypes(true);
+ typeColor = createTypeColor();
+ paramColor = createParamColor();
+ paintTextR = new Rectangle();
+ }
+
+
protected void paintComponent(Graphics g) {
//super.paintComponent(g);
@@ -282,7 +379,7 @@ public class CompletionCellRenderer extends DefaultListCellRenderer {
if (getShowTypes() && fc.getType()!=null) {
sb.append(" : ");
if (!selected) {
- sb.append("<font color='#808080'>");
+ sb.append("<font color='").append(typeColor).append("'>");
}
sb.append(fc.getType());
if (!selected) {
@@ -355,7 +452,7 @@ public class CompletionCellRenderer extends DefaultListCellRenderer {
if (definition!=null) {
sb.append(" - ");
if (!selected) {
- sb.append("<font color='#808080'>");
+ sb.append("<font color='").append(typeColor).append("'>");
}
sb.append(definition);
if (!selected) {
@@ -386,7 +483,7 @@ public class CompletionCellRenderer extends DefaultListCellRenderer {
if (getShowTypes() && vc.getType()!=null) {
sb.append(" : ");
if (!selected) {
- sb.append("<font color='#808080'>");
+ sb.append("<font color='").append(typeColor).append("'>");
}
sb.append(vc.getType());
if (!selected) {
@@ -413,6 +510,22 @@ public class CompletionCellRenderer extends DefaultListCellRenderer {
/**
+ * Sets the delegate renderer. Most users will never use this method; it
+ * is primarily a hook for Substance and other Look and Feels whose
+ * renderers look drastically different from the standard
+ * <code>DefaultListCellRenderer</code>.
+ *
+ * @param delegate The new delegate renderer. If this is <code>null</code>,
+ * the default rendering of this component is used.
+ * @see #getDelegateRenderer()
+ * @see #delegateToSubstanceRenderer()
+ */
+ public void setDelegateRenderer(DefaultListCellRenderer delegate) {
+ this.delegate = delegate;
+ }
+
+
+ /**
* Sets the font to use when rendering completion items.
*
* @param font The font to use. If this is <code>null</code>, then
@@ -442,6 +555,7 @@ public class CompletionCellRenderer extends DefaultListCellRenderer {
* Sets the color to use for function arguments.
*
* @param color The color to use. This is ignored if <code>null</code>.
+ * @see #setTypeColor(Color)
*/
public void setParamColor(Color color) {
if (color!=null) {
@@ -462,4 +576,33 @@ public class CompletionCellRenderer extends DefaultListCellRenderer {
}
+ /**
+ * Sets the color to use for function/field types. Note that if
+ * {@link #getShowTypes()} returns <code>false</code>, this property
+ * effectively does nothing.
+ *
+ * @param color The color to use for types. This is ignored if
+ * <code>null</code>.
+ * @see #setShowTypes(boolean)
+ * @see #setParamColor(Color)
+ */
+ public void setTypeColor(Color color) {
+ if (color!=null) {
+ typeColor = Util.getHexString(color);
+ }
+ }
+
+
+ /**
+ * Overridden to update our delegate, if necessary.
+ */
+ public void updateUI() {
+ super.updateUI();
+ if (delegate!=null) {
+ SwingUtilities.updateComponentTreeUI(delegate);
+ }
+ paramColor = createParamColor();
+ }
+
+
}
\ No newline at end of file
diff --git a/src/org/fife/ui/autocomplete/TipUtil.java b/src/org/fife/ui/autocomplete/TipUtil.java
index 2caa0d4..7ee8664 100644
--- a/src/org/fife/ui/autocomplete/TipUtil.java
+++ b/src/org/fife/ui/autocomplete/TipUtil.java
@@ -159,6 +159,14 @@ class TipUtil {
"body { font-family: " + font.getFamily() +
"; font-size: " + font.getSize() + "pt" +
"; color: " + Util.getHexString(fg) + "; }");
+
+ // Always add link foreground rule. Unfortunately these CSS rules
+ // stack each time the LaF is changed (how can we overwrite them
+ // without clearing out the important "standard" ones?).
+ Color linkFG = Util.getHyperlinkForeground();
+ doc.getStyleSheet().addRule(
+ "a { color: " + Util.getHexString(linkFG) + "; }");
+
URL url = TipUtil.class.getResource("bullet_black.png");
if (url!=null) {
doc.getStyleSheet().addRule(
diff --git a/src/org/fife/ui/autocomplete/Util.java b/src/org/fife/ui/autocomplete/Util.java
index ceab7f5..c994b60 100644
--- a/src/org/fife/ui/autocomplete/Util.java
+++ b/src/org/fife/ui/autocomplete/Util.java
@@ -16,6 +16,8 @@ import java.awt.Rectangle;
import java.lang.reflect.Method;
import java.net.URI;
import java.security.AccessControlException;
+import javax.swing.JLabel;
+import javax.swing.UIManager;
import org.fife.ui.rsyntaxtextarea.PopupWindowDecorator;
@@ -29,6 +31,19 @@ import org.fife.ui.rsyntaxtextarea.PopupWindowDecorator;
public class Util {
/**
+ * If a system property is defined with this name and set, ignoring case,
+ * to <code>true</code>, this library will not attempt to use Substance
+ * renderers. Otherwise, if a Substance Look and Feel is installed, we
+ * will attempt to use Substance cell renderers in all of our dropdowns.<p>
+ *
+ * Note that we do not have a build dependency on Substance, so all access
+ * to Substance stuff is done via reflection. We will fall back onto
+ * default renderers if something goes horribly wrong.
+ */
+ public static final String PROPERTY_DONT_USE_SUBSTANCE_RENDERERS =
+ "org.fife.ui.autocomplete.DontUseSubstanceRenderers";
+
+ /**
* If this system property is <code>true</code>, then even the "main" two
* auto-complete windows will allow window decorations via
* {@link PopupWindowDecorator}. If this property is undefined or
@@ -39,6 +54,13 @@ public class Util {
public static final String PROPERTY_ALLOW_DECORATED_AUTOCOMPLETE_WINDOWS =
"org.fife.ui.autocomplete.allowDecoratedAutoCompleteWindows";
+ /**
+ * Used for the color of hyperlinks when a LookAndFeel uses light text
+ * against a dark background.
+ */
+ private static final Color LIGHT_HYPERLINK_FG = new Color(0xd8ffff);
+
+ private static final boolean useSubstanceRenderers;
private static boolean desktopCreationAttempted;
private static Object desktop;
private static final Object LOCK_DESKTOP_CREATION = new Object();
@@ -158,6 +180,28 @@ public class Util {
/**
+ * Returns the color to use for hyperlink-style components. This method
+ * will return <code>Color.blue</code> unless it appears that the current
+ * LookAndFeel uses light text on a dark background, in which case a
+ * brighter alternative is returned.
+ *
+ * @return The color to use for hyperlinks.
+ */
+ static final Color getHyperlinkForeground() {
+
+ // This property is defined by all standard LaFs, even Nimbus (!),
+ // but you never know what crazy LaFs there are...
+ Color fg = UIManager.getColor("Label.foreground");
+ if (fg==null) {
+ fg = new JLabel().getForeground();
+ }
+
+ return isLightForeground(fg) ? LIGHT_HYPERLINK_FG : Color.blue;
+
+ }
+
+
+ /**
* Returns the screen coordinates for the monitor that contains the
* specified point. This is useful for setups with multiple monitors,
* to ensure that popup windows are positioned properly.
@@ -202,6 +246,32 @@ public class Util {
/**
+ * Returns whether we should attempt to use Substance cell renderers and
+ * styles for things such as completion choices, if a Substance Look and
+ * Feel is installed. If this is <code>false</code>, we'll use our
+ * standard rendering for completions, even when Substance is being used.
+ *
+ * @return Whether to use Substance renderers if Substance is installed.
+ */
+ public static boolean getUseSubstanceRenderers() {
+ return useSubstanceRenderers;
+ }
+
+
+ /**
+ * Returns whether the specified color is "light" to use as a foreground.
+ * Colors that return <code>true</code> indicate that the current Look and
+ * Feel probably uses light text colors on a dark background.
+ *
+ * @param fg The foreground color.
+ * @return Whether it is a "light" foreground color.
+ */
+ public static final boolean isLightForeground(Color fg) {
+ return fg.getRed()>0xa0 && fg.getGreen()>0xa0 && fg.getBlue()>0xa0;
+ }
+
+
+ /**
* Returns whether <code>str</code> starts with <code>start</code>,
* ignoring case.
*
@@ -226,4 +296,17 @@ public class Util {
}
+ static {
+
+ boolean use = true;
+ try {
+ use = !Boolean.getBoolean(PROPERTY_DONT_USE_SUBSTANCE_RENDERERS);
+ } catch (AccessControlException ace) { // We're in an applet.
+ use = true;
+ }
+ useSubstanceRenderers = use;
+
+ }
+
+
}
\ No newline at end of file
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-java/autocomplete.git
More information about the pkg-java-commits
mailing list