IDEA-162025 Unexpected focus-effect painting in ComboBox with custom JPanel-based...
authorDenis Fokin <Denis.Fokin@jetbrains.com>
Tue, 4 Oct 2016 12:58:11 +0000 (15:58 +0300)
committerDenis Fokin <Denis.Fokin@jetbrains.com>
Tue, 4 Oct 2016 12:58:53 +0000 (15:58 +0300)
platform/util/src/com/intellij/util/ui/JBUI.java
platform/util/src/com/intellij/util/ui/components/ComboBoxCompositeEditor.java [new file with mode: 0644]

index e14f67b8289c267375bfcd280873656db8773c10..5daf3ef06d4af96296319ebd30a21e71df136c0a 100644 (file)
@@ -22,6 +22,7 @@ import com.intellij.openapi.util.SystemInfo;
 import com.intellij.ui.border.CustomLineBorder;
 import com.intellij.util.SystemProperties;
 import com.intellij.util.ui.components.BorderLayoutPanel;
+import com.intellij.util.ui.components.ComboBoxCompositeEditor;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -263,4 +264,15 @@ public class JBUI {
       return new BorderLayoutPanel(hgap, vgap);
     }
   }
+
+  /**
+   *    JComboBox<String> comboBox = new ComboBox<>();
+   *    comboBox.setEditable(true);
+   *    comboBox.setEditor(JBUI.ComboBox.compositeComboboxEditor(new JTextField("Text Field")));
+   */
+  public static class ComboBox {
+    public static ComboBoxCompositeEditor compositeComboboxEditor  (JComponent ... components) {
+      return new ComboBoxCompositeEditor(components);
+    }
+  }
 }
diff --git a/platform/util/src/com/intellij/util/ui/components/ComboBoxCompositeEditor.java b/platform/util/src/com/intellij/util/ui/components/ComboBoxCompositeEditor.java
new file mode 100644 (file)
index 0000000..e4f1ae0
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2000-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.util.ui.components;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ActionListener;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+
+/**
+ * @author Denis Fokin
+ */
+
+public class ComboBoxCompositeEditor extends JComponent implements ComboBoxEditor {
+
+  public interface EditorComponent {
+    void setItem(String anObject);
+    String getItem();
+    void selectAll();
+    void addActionListener(ActionListener l);
+    void removeActionListener(ActionListener l);
+    JComponent getDelegate();
+
+  }
+
+  private final EditorComponent[] myComponents;
+  private String myItem = null;
+  private int focusableComponentIndex;
+
+  public ComboBoxCompositeEditor(final JComponent ... components) {
+    assert components.length > 0;
+    setLayout(new GridLayout(1, 0));
+    setFocusable(false);
+    myComponents = new EditorComponent[components.length];
+
+    for (int i = 0; i < components.length; i ++) {
+      final int index = i;
+      myComponents[i] = new ComboBoxCompositeEditor.EditorComponent () {
+        public void setItem(String anObject) {
+          if (components[index] instanceof JTextField) {
+            JTextField component = (JTextField)components[index];
+            component.setText((anObject == null) ? "" : anObject);
+          }
+        }
+
+        public String getItem() {
+          if (components[index] instanceof JTextField) {
+            JTextField component = (JTextField)components[index];
+            return component.getText();
+          }
+          return "";
+        }
+
+        @Override
+        public void selectAll() {
+          if (components[index] instanceof JTextField) {
+            JTextField component = (JTextField)components[index];
+            component.selectAll();
+          }
+        }
+
+        @Override
+        public void addActionListener(ActionListener l) {
+          if (components[index] instanceof JTextField) {
+            JTextField component = (JTextField)components[index];
+            component.addActionListener(l);
+          }
+        }
+
+        @Override
+        public void removeActionListener(ActionListener l) {
+          if (components[index] instanceof JTextField) {
+            JTextField component = (JTextField)components[index];
+            component.removeActionListener(l);
+          }
+        }
+
+        @Override
+        public JComponent getDelegate() {
+          return components[index];
+        }
+      };
+    }
+
+    focusableComponentIndex = 0;
+    final JComponent component = myComponents[focusableComponentIndex].getDelegate();
+    component.setBorder(null);
+    component.addFocusListener(new FocusListener() {
+
+      Component parent = null;
+
+      @Override
+      public void focusGained(FocusEvent e) {
+        parent = component.getParent();
+        parent.repaint();
+      }
+
+      @Override
+      public void focusLost(FocusEvent e) {
+        parent.repaint();
+      }
+    });
+  }
+
+  @Override
+  public Component getEditorComponent() {
+    return myComponents[focusableComponentIndex].getDelegate();
+  }
+
+  @Override
+  public void setItem(Object anObject) {
+      myItem = (String)anObject;
+      for (EditorComponent editorComponent : myComponents) {
+        editorComponent.setItem(myItem);
+      }
+  }
+
+  @Override
+  public Object getItem() {
+    return myItem;
+  }
+
+  @Override
+  public void selectAll() {
+    myComponents[focusableComponentIndex].selectAll();
+  }
+
+  @Override
+  public void addActionListener(ActionListener l) {
+    for (EditorComponent editorComponent : myComponents) {
+      editorComponent.addActionListener(l);
+    }
+  }
+
+  @Override
+  public void removeActionListener(ActionListener l) {
+    for (EditorComponent editorComponent : myComponents) {
+      editorComponent.removeActionListener(l);
+    }
+  }
+
+  @Override
+  public void setFocusable(boolean focusable) {}
+
+  @Override
+  public boolean isFocusable() {
+    return false;
+  }
+}