# HG changeset patch # Parent bae64ac16e127c7dcc0b1661671e5946a5f780d1 # User Jesse Glick #212297: display combo boxes with custom renderers properly in GTK L&F. diff --git a/java.api.common/src/org/netbeans/modules/java/api/common/project/ui/customizer/MainClassChooser.java b/java.api.common/src/org/netbeans/modules/java/api/common/project/ui/customizer/MainClassChooser.java --- a/java.api.common/src/org/netbeans/modules/java/api/common/project/ui/customizer/MainClassChooser.java +++ b/java.api.common/src/org/netbeans/modules/java/api/common/project/ui/customizer/MainClassChooser.java @@ -58,9 +58,9 @@ import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicBoolean; import javax.lang.model.element.TypeElement; -import javax.swing.DefaultListCellRenderer; import javax.swing.JList; import javax.swing.JPanel; +import javax.swing.ListCellRenderer; import javax.swing.ListSelectionModel; import javax.swing.SwingUtilities; import javax.swing.event.ChangeEvent; @@ -79,6 +79,7 @@ import org.netbeans.spi.java.classpath.support.ClassPathSupport; import org.openide.awt.Mnemonics; import org.openide.awt.MouseUtils; +import org.openide.awt.Renderers; import org.openide.filesystems.FileObject; import org.openide.util.Exceptions; import org.openide.util.NbBundle; @@ -392,7 +393,8 @@ return 0; } - private static final class MainClassRenderer extends DefaultListCellRenderer { + private static final class MainClassRenderer implements ListCellRenderer { + private final ListCellRenderer orig = Renderers.defaultComboBoxRenderer(); @Override public Component getListCellRendererComponent (JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { String displayName; @@ -403,7 +405,7 @@ } else { displayName = value.toString (); } - return super.getListCellRendererComponent (list, displayName, index, isSelected, cellHasFocus); + return orig.getListCellRendererComponent (list, displayName, index, isSelected, cellHasFocus); } } diff --git a/java.api.common/src/org/netbeans/modules/java/api/common/project/ui/customizer/SourceRootsUi.java b/java.api.common/src/org/netbeans/modules/java/api/common/project/ui/customizer/SourceRootsUi.java --- a/java.api.common/src/org/netbeans/modules/java/api/common/project/ui/customizer/SourceRootsUi.java +++ b/java.api.common/src/org/netbeans/modules/java/api/common/project/ui/customizer/SourceRootsUi.java @@ -60,7 +60,6 @@ import java.text.MessageFormat; import javax.swing.CellEditor; import javax.swing.DefaultCellEditor; -import javax.swing.DefaultListCellRenderer; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JFileChooser; @@ -71,6 +70,7 @@ import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JTextField; +import javax.swing.ListCellRenderer; import javax.swing.ListSelectionModel; import javax.swing.SwingUtilities; import javax.swing.event.ListSelectionEvent; @@ -89,6 +89,7 @@ import org.netbeans.modules.java.api.common.SourceRoots; import org.openide.DialogDisplayer; import org.openide.DialogDescriptor; +import org.openide.awt.Renderers; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileUtil; import org.openide.util.NbBundle; @@ -606,9 +607,10 @@ this.add (label2); } - private static class InvalidRootRenderer extends DefaultListCellRenderer { + private static class InvalidRootRenderer implements ListCellRenderer { private static final long serialVersionUID = 194496879246810209L; + private final ListCellRenderer orig = Renderers.defaultComboBoxRenderer(); private boolean projectConflict; public InvalidRootRenderer (boolean projectConflict) { @@ -617,7 +619,7 @@ public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { if (" ".equals(value)) { // NOI18N - return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + return orig.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); } File f = (File) value; String message = f.getAbsolutePath(); @@ -631,7 +633,7 @@ projectName}); } } - return super.getListCellRendererComponent(list, message, index, isSelected, cellHasFocus); + return orig.getListCellRendererComponent(list, message, index, isSelected, cellHasFocus); } } } diff --git a/java.api.common/src/org/netbeans/modules/java/api/common/project/ui/wizards/FolderList.java b/java.api.common/src/org/netbeans/modules/java/api/common/project/ui/wizards/FolderList.java --- a/java.api.common/src/org/netbeans/modules/java/api/common/project/ui/wizards/FolderList.java +++ b/java.api.common/src/org/netbeans/modules/java/api/common/project/ui/wizards/FolderList.java @@ -64,11 +64,11 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.regex.Pattern; import javax.swing.DefaultListModel; -import javax.swing.DefaultListCellRenderer; import javax.swing.DropMode; import javax.swing.JComponent; import javax.swing.JFileChooser; import javax.swing.JList; +import javax.swing.ListCellRenderer; import javax.swing.TransferHandler; import javax.swing.event.ListSelectionListener; import javax.swing.event.ListSelectionEvent; @@ -82,6 +82,7 @@ import org.netbeans.api.project.Sources; import org.netbeans.modules.java.api.common.project.ui.customizer.SourceRootsUi; import org.netbeans.spi.java.project.support.JavadocAndSourceRootDetection; +import org.openide.awt.Renderers; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileUtil; import org.openide.util.Cancellable; @@ -458,14 +459,15 @@ return false; } - private static class Renderer extends DefaultListCellRenderer { + private static class Renderer implements ListCellRenderer { + private final ListCellRenderer orig = Renderers.defaultComboBoxRenderer(); public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { if (" ".equals(value)) { // NOI18N - return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + return orig.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); } File f = (File) value; String message = f.getAbsolutePath(); - Component result = super.getListCellRendererComponent(list, message, index, isSelected, cellHasFocus); + Component result = orig.getListCellRendererComponent(list, message, index, isSelected, cellHasFocus); return result; } } diff --git a/java.api.common/src/org/netbeans/modules/java/api/common/ui/PlatformUiSupport.java b/java.api.common/src/org/netbeans/modules/java/api/common/ui/PlatformUiSupport.java --- a/java.api.common/src/org/netbeans/modules/java/api/common/ui/PlatformUiSupport.java +++ b/java.api.common/src/org/netbeans/modules/java/api/common/ui/PlatformUiSupport.java @@ -64,6 +64,7 @@ import org.openide.DialogDisplayer; import org.openide.NotifyDescriptor; import org.openide.awt.HtmlRenderer; +import org.openide.awt.Renderers; import org.openide.modules.SpecificationVersion; import org.openide.util.NbBundle; import org.openide.util.Parameters; @@ -552,6 +553,7 @@ private static final class PlatformListCellRenderer implements ListCellRenderer { private final ListCellRenderer delegate; + private final ListCellRenderer orig = Renderers.defaultComboBoxRenderer(); public PlatformListCellRenderer() { delegate = HtmlRenderer.createRenderer(); @@ -569,11 +571,12 @@ name = "" //NOI18N + NbBundle.getMessage( PlatformUiSupport.class, "TXT_BrokenPlatformFmt", key.getDisplayName()); + return delegate.getListCellRendererComponent(list, name, index, isSelected, cellHasFocus); } else { name = key.getDisplayName(); } } - return delegate.getListCellRendererComponent(list, name, index, isSelected, cellHasFocus); + return orig.getListCellRendererComponent(list, name, index, isSelected, cellHasFocus); } } @@ -759,6 +762,7 @@ private static final class SourceLevelListCellRenderer implements ListCellRenderer { private ListCellRenderer delegate; + private final ListCellRenderer orig = Renderers.defaultComboBoxRenderer(); public SourceLevelListCellRenderer() { delegate = HtmlRenderer.createRenderer(); @@ -776,11 +780,12 @@ message = "" //NOI18N + NbBundle.getMessage( PlatformUiSupport.class, "TXT_InvalidSourceLevel", key.getDisplayName()); + return delegate.getListCellRendererComponent(list, message, index, isSelected, cellHasFocus); } else { message = key.getDisplayName(); } } - return delegate.getListCellRendererComponent(list, message, index, isSelected, cellHasFocus); + return orig.getListCellRendererComponent(list, message, index, isSelected, cellHasFocus); } } diff --git a/java.j2seproject/src/org/netbeans/modules/java/j2seproject/ui/customizer/CustomizerRun.java b/java.j2seproject/src/org/netbeans/modules/java/j2seproject/ui/customizer/CustomizerRun.java --- a/java.j2seproject/src/org/netbeans/modules/java/j2seproject/ui/customizer/CustomizerRun.java +++ b/java.j2seproject/src/org/netbeans/modules/java/j2seproject/ui/customizer/CustomizerRun.java @@ -67,7 +67,6 @@ import javax.swing.event.ChangeListener; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; -import javax.swing.plaf.UIResource; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -77,6 +76,7 @@ import java.util.*; import java.util.logging.Level; import java.util.logging.Logger; +import org.openide.awt.Renderers; public class CustomizerRun extends JPanel implements HelpCtx.Provider { public static final Logger log = Logger.getLogger(CustomizerRun.class.getName()); @@ -683,16 +683,11 @@ } - private final class ConfigListCellRenderer extends JLabel implements ListCellRenderer, UIResource { + private final class ConfigListCellRenderer implements ListCellRenderer { - public ConfigListCellRenderer () { - setOpaque(true); - } + private final ListCellRenderer orig = Renderers.defaultComboBoxRenderer(); public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { - // #93658: GTK needs name to render cell renderer "natively" - setName("ComboBox.listRenderer"); // NOI18N - String config = (String) value; String label; if (config == null) { @@ -707,24 +702,7 @@ } else { label = NbBundle.getBundle("org.netbeans.modules.java.j2seproject.Bundle").getString("J2SEConfigurationProvider.default.label"); // NOI18N } - setText(label); - - if ( isSelected ) { - setBackground(list.getSelectionBackground()); - setForeground(list.getSelectionForeground()); - } - else { - setBackground(list.getBackground()); - setForeground(list.getForeground()); - } - - return this; - } - - // #93658: GTK needs name to render cell renderer "natively" - public String getName() { - String name = super.getName(); - return name == null ? "ComboBox.renderer" : name; // NOI18N + return orig.getListCellRendererComponent(list, label, index, isSelected, cellHasFocus); } } diff --git a/openide.awt/src/org/openide/awt/Renderers.java b/openide.awt/src/org/openide/awt/Renderers.java new file mode 100644 --- /dev/null +++ b/openide.awt/src/org/openide/awt/Renderers.java @@ -0,0 +1,115 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2012 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2012 Sun Microsystems, Inc. + */ + +package org.openide.awt; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.ListCellRenderer; +import javax.swing.UIManager; +import javax.swing.plaf.basic.BasicComboBoxRenderer; +import javax.swing.plaf.basic.BasicComboBoxUI; +import javax.swing.plaf.synth.SynthLookAndFeel; + +/** + * Utilities for creating L&F-aware cell renderers. + * @since XXX + */ +public class Renderers { + + private static final Logger LOG = Logger.getLogger(Renderers.class.getName()); + + /** + * Creates a combo box renderer appropriate to the current L&F. + * This will look nicer in some L&Fs than subclassing {@link BasicComboBoxRenderer}. + *

Usage: + *

+    MyModelType[] data = ...;
+    JComboBox combo = new JComboBox(data);
+    combo.setRenderer(new ListCellRenderer() {
+        final ListCellRenderer orig = Renderers.defaultComboBoxRenderer();
+        @Override public Component getListCellRendererComponent(
+                JList l, Object v, int i, boolean sel, boolean foc) {
+            return orig.getListCellRendererComponent(
+                l, ((MyModelType) v).getDisplayName(), i, sel, foc);
+        }
+    });
+     * 
+ * @return a renderer + */ + public static ListCellRenderer defaultComboBoxRenderer() { + // XXX consider also handling " " as a value specially (workaround for another Swing bug) + Class clazz = UIManager.getDefaults().getUIClass("ComboBoxUI"); + if (clazz != null) { + Constructor ctor = null; + if (clazz == SynthLookAndFeel.class) { // #7168287 + try { // only public in JDK 7 + clazz = Class.forName("javax.swing.plaf.synth.SynthComboBoxUI"); + ctor = clazz.getDeclaredConstructor(); + ctor.setAccessible(true); + ctor.newInstance(); + } catch (Exception x) { + LOG.log(Level.WARNING, null, x); + } + } + if (BasicComboBoxUI.class.isAssignableFrom(clazz)) { + try { + Method createRenderer = BasicComboBoxUI.class.getDeclaredMethod("createRenderer"); + createRenderer.setAccessible(true); + return (ListCellRenderer) createRenderer.invoke(ctor != null ? ctor.newInstance() : clazz.newInstance()); + } catch (Exception x) { + LOG.log(Level.WARNING, null, x); + } + } else { + LOG.log(Level.WARNING, "unknown UI class: {0}", clazz); + } + } else { + LOG.warning("no UI class"); + } + return new BasicComboBoxRenderer.UIResource(); + } + + private Renderers() {} + +} diff --git a/openide.awt/test/unit/src/org/openide/awt/RenderersTest.java b/openide.awt/test/unit/src/org/openide/awt/RenderersTest.java new file mode 100644 --- /dev/null +++ b/openide.awt/test/unit/src/org/openide/awt/RenderersTest.java @@ -0,0 +1,71 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2012 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2012 Sun Microsystems, Inc. + */ + +package org.openide.awt; + +import java.util.logging.Level; +import javax.swing.ListCellRenderer; +import javax.swing.UIManager; +import javax.swing.plaf.synth.SynthLookAndFeel; +import junit.framework.Test; +import org.netbeans.junit.NbModuleSuite; +import org.netbeans.junit.NbTestCase; + +public class RenderersTest extends NbTestCase { + + public RenderersTest(String name) { + super(name); + } + + public static Test suite() throws Exception { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + return NbModuleSuite.createConfiguration(RenderersTest.class).failOnException(Level.INFO).failOnMessage(Level.WARNING).gui(false).enableModules("-", "-").suite(); + } + + public void testDefaultComboBoxRenderer() throws Exception { + ListCellRenderer renderer = Renderers.defaultComboBoxRenderer(); + if (UIManager.getLookAndFeel() instanceof SynthLookAndFeel) { + assertEquals("SynthComboBoxRenderer", renderer.getClass().getSimpleName()); + } + } + +} diff --git a/options.editor/src/org/netbeans/modules/options/indentation/FormattingPanel.java b/options.editor/src/org/netbeans/modules/options/indentation/FormattingPanel.java --- a/options.editor/src/org/netbeans/modules/options/indentation/FormattingPanel.java +++ b/options.editor/src/org/netbeans/modules/options/indentation/FormattingPanel.java @@ -53,14 +53,13 @@ import java.util.Comparator; import java.util.List; import javax.swing.DefaultComboBoxModel; -import javax.swing.DefaultListCellRenderer; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JPanel; +import javax.swing.ListCellRenderer; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; -import javax.swing.UIManager; import javax.swing.border.EmptyBorder; import javax.swing.text.Document; import javax.swing.text.JTextComponent; @@ -68,6 +67,7 @@ import org.netbeans.modules.editor.settings.storage.api.EditorSettings; import org.netbeans.modules.options.editor.spi.PreferencesCustomizer; import org.netbeans.modules.options.editor.spi.PreviewProvider; +import org.openide.awt.Renderers; import org.openide.util.NbBundle; import org.openide.util.WeakListeners; @@ -86,7 +86,8 @@ // } // Languages combobox renderer - languageCombo.setRenderer(new DefaultListCellRenderer() { + languageCombo.setRenderer(new ListCellRenderer() { + final ListCellRenderer orig = Renderers.defaultComboBoxRenderer(); @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { if (value instanceof String) { @@ -94,18 +95,19 @@ ? EditorSettings.getDefault().getLanguageName((String)value) : org.openide.util.NbBundle.getMessage(FormattingPanel.class, "LBL_AllLanguages"); //NOI18N } - return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + return orig.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); } }); // Category combobox renderer - categoryCombo.setRenderer(new DefaultListCellRenderer() { + categoryCombo.setRenderer(new ListCellRenderer() { + final ListCellRenderer orig = Renderers.defaultComboBoxRenderer(); @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { if (value instanceof PreferencesCustomizer) { value = ((PreferencesCustomizer) value).getDisplayName(); } - return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + return orig.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); } }); diff --git a/projectuiapi/src/org/netbeans/spi/project/ui/support/ProjectCustomizer.java b/projectuiapi/src/org/netbeans/spi/project/ui/support/ProjectCustomizer.java --- a/projectuiapi/src/org/netbeans/spi/project/ui/support/ProjectCustomizer.java +++ b/projectuiapi/src/org/netbeans/spi/project/ui/support/ProjectCustomizer.java @@ -67,7 +67,6 @@ import java.util.logging.Logger; import javax.swing.ComboBoxModel; import javax.swing.DefaultComboBoxModel; -import javax.swing.DefaultListCellRenderer; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JList; @@ -82,6 +81,7 @@ import org.netbeans.modules.project.uiapi.CustomizerPane; import org.netbeans.modules.project.uiapi.Utilities; import org.netbeans.spi.project.ui.support.ProjectCustomizer.Category; +import org.openide.awt.Renderers; import org.openide.cookies.InstanceCookie; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileStateInvalidException; @@ -826,11 +826,8 @@ return new EncodingModel(initialCharset); } - private static final class EncodingRenderer extends DefaultListCellRenderer { - EncodingRenderer() { - //Needed for synth? - setName ("ComboBox.listRenderer"); //NOI18N - } + private static final class EncodingRenderer implements ListCellRenderer { + final ListCellRenderer orig = Renderers.defaultComboBoxRenderer(); @Override public Component getListCellRendererComponent(JList list, Object value, @@ -838,7 +835,7 @@ if (value instanceof Charset) { value = ((Charset) value).displayName(); } - return super.getListCellRendererComponent(list, value, index, + return orig.getListCellRendererComponent(list, value, index, isSelected, isLeadSelection); } }