| /* |
| * Copyright 2000-2014 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.ui; |
| |
| import com.intellij.openapi.application.Application; |
| import com.intellij.openapi.application.ApplicationManager; |
| import com.intellij.openapi.fileChooser.FileChooser; |
| import com.intellij.openapi.fileChooser.FileChooserDescriptor; |
| import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; |
| import com.intellij.openapi.ui.FixedSizeButton; |
| import com.intellij.openapi.ui.Splitter; |
| import com.intellij.openapi.ui.TextFieldWithBrowseButton; |
| import com.intellij.openapi.util.io.FileUtil; |
| import com.intellij.openapi.util.text.CharFilter; |
| import com.intellij.openapi.util.text.StringUtil; |
| import com.intellij.openapi.vfs.VfsUtilCore; |
| import com.intellij.openapi.vfs.VirtualFile; |
| import com.intellij.util.ArrayUtil; |
| import com.intellij.util.Consumer; |
| import com.intellij.util.ui.UIUtil; |
| import org.intellij.lang.annotations.JdkConstants; |
| import org.jetbrains.annotations.NonNls; |
| import org.jetbrains.annotations.NotNull; |
| |
| import javax.swing.*; |
| import javax.swing.border.Border; |
| import javax.swing.border.TitledBorder; |
| import javax.swing.table.TableCellRenderer; |
| import javax.swing.table.TableColumnModel; |
| import java.awt.*; |
| import java.awt.event.ActionEvent; |
| import java.awt.event.ActionListener; |
| import java.lang.reflect.InvocationTargetException; |
| import java.net.MalformedURLException; |
| |
| public class GuiUtils { |
| private static final Insets paddingFromDialogBoundaries = new Insets(7, 5, 7, 5); |
| private static final Insets paddingInsideDialog = new Insets(5, 5, 5, 5); |
| |
| private static final CharFilter NOT_MNEMONIC_CHAR_FILTER = new CharFilter() { |
| @Override |
| public boolean accept(char ch) { |
| return ch != '&' && ch != UIUtil.MNEMONIC; |
| } |
| }; |
| |
| public static JPanel constructFieldWithBrowseButton(JComponent aComponent, ActionListener aActionListener) { |
| return constructFieldWithBrowseButton(aComponent, aActionListener, 0); |
| } |
| |
| public static JPanel constructFieldWithBrowseButton(TextFieldWithHistory aComponent, ActionListener aActionListener) { |
| return constructFieldWithBrowseButton(aComponent, aActionListener, 0); |
| } |
| |
| private static JPanel constructFieldWithBrowseButton(final JComponent aComponent, final ActionListener aActionListener, int delta) { |
| JPanel result = new JPanel(new GridBagLayout()); |
| result.add(aComponent, new GridBagConstraints(0, 0, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0,0)); |
| FixedSizeButton browseButton = new FixedSizeButton(aComponent.getPreferredSize().height - delta);//ignore border in case of browse button |
| TextFieldWithBrowseButton.MyDoClickAction.addTo(browseButton, aComponent); |
| result.add(browseButton, new GridBagConstraints(1, 0, 1, 1, 0, 1, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0,0,0,0), 0,0)); |
| browseButton.addActionListener(aActionListener); |
| |
| return result; |
| } |
| |
| public static JPanel constructDirectoryBrowserField(final JTextField field, final String objectName) { |
| return constructFieldWithBrowseButton(field, new ActionListener() { |
| @Override |
| public void actionPerformed(ActionEvent e) { |
| FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor().withTitle("Select " + objectName); |
| VirtualFile file = FileChooser.chooseFile(descriptor, field, null, null); |
| if (file != null) { |
| field.setText(FileUtil.toSystemDependentName(file.getPath())); |
| field.postActionEvent(); |
| } |
| } |
| }); |
| } |
| |
| public static JPanel constructFileURLBrowserField(final TextFieldWithHistory field, final String objectName) { |
| return constructFieldWithBrowseButton(field, new ActionListener() { |
| @Override |
| public void actionPerformed(ActionEvent e) { |
| FileChooserDescriptor descriptor = |
| FileChooserDescriptorFactory.createSingleFileNoJarsDescriptor().withTitle("Select " + objectName); |
| VirtualFile file = FileChooser.chooseFile(descriptor, field, null, null); |
| if (file != null) { |
| try { |
| field.setText(VfsUtilCore.virtualToIoFile(file).toURI().toURL().toString()); |
| } |
| catch (MalformedURLException e1) { |
| field.setText(""); |
| } |
| } |
| } |
| }); |
| } |
| |
| public static JComponent constructLabeledComponent(String aLabelText, JComponent aComponent, @JdkConstants.BoxLayoutAxis int aAxis) { |
| JPanel result = new JPanel(); |
| BoxLayout boxLayout = new BoxLayout(result, aAxis); |
| result.setLayout(boxLayout); |
| |
| result.add(new JLabel(aLabelText)); |
| result.add(aComponent); |
| |
| return result; |
| } |
| |
| public static JPanel makeDialogPanel(JPanel aPanel) { |
| JPanel emptyBordered = makePaddedPanel(aPanel, paddingFromDialogBoundaries); |
| return wrapWithBorder(emptyBordered, IdeBorderFactory.createRoundedBorder()); |
| } |
| |
| public static JPanel makeTitledPanel(JComponent aComponent, String aTitle) { |
| JPanel result = makePaddedPanel(aComponent, false, true, false, true); |
| return wrapWithBorder(result, IdeBorderFactory.createTitledBorder(aTitle, true)); |
| } |
| |
| |
| private static JPanel wrapWithBorder(JComponent aPanel, Border aBorder) { |
| JPanel wrapper = new JPanel(new BorderLayout()); |
| wrapper.add(aPanel, BorderLayout.CENTER); |
| wrapper.setBorder(aBorder); |
| return wrapper; |
| } |
| |
| |
| public static BorderLayout createBorderLayout() { |
| return new BorderLayout(paddingInsideDialog.left, paddingInsideDialog.top); |
| } |
| |
| public static GridLayout createGridLayout(int aRows, int aColumns) { |
| return new GridLayout(aRows, aColumns, paddingInsideDialog.left, paddingInsideDialog.top); |
| } |
| |
| public static Component createVerticalStrut() { |
| return Box.createRigidArea(new Dimension(0, paddingInsideDialog.top)); |
| } |
| |
| public static Component createHorisontalStrut() { |
| return Box.createRigidArea(new Dimension(paddingInsideDialog.left, 0)); |
| } |
| |
| private static JPanel makePaddedPanel(JComponent aComponent, Insets aInsets) { |
| return wrapWithBorder(aComponent, BorderFactory.createEmptyBorder( |
| aInsets.top, |
| aInsets.left, |
| aInsets.bottom, |
| aInsets.right |
| )); |
| } |
| |
| private static JPanel makePaddedPanel(JComponent aComponent, |
| boolean aTop, |
| boolean aLeft, |
| boolean aBottom, |
| boolean aRight) { |
| return wrapWithBorder(aComponent, BorderFactory.createEmptyBorder( |
| aTop ? paddingInsideDialog.top : 0, |
| aLeft ? paddingInsideDialog.left : 0, |
| aBottom ? paddingInsideDialog.bottom : 0, |
| aRight ? paddingInsideDialog.right : 0)); |
| } |
| |
| public static void setAdditionalIcon(JRadioButton button, Icon icon) { |
| final Icon defaultIcon = UIUtil.getRadioButtonIcon(); |
| LayeredIcon deficon = new LayeredIcon(2); |
| deficon.setIcon(defaultIcon, 0); |
| deficon.setIcon(icon, 1, defaultIcon.getIconWidth() + 5, 0); |
| button.setIcon(deficon); |
| |
| LayeredIcon pressed = new LayeredIcon(2); |
| pressed.setIcon(defaultIcon, 0); |
| pressed.setIcon(icon, 1, defaultIcon.getIconWidth() + 5, 0); |
| button.setPressedIcon(pressed); |
| |
| LayeredIcon selected = new LayeredIcon(2); |
| selected.setIcon(defaultIcon, 0); |
| selected.setIcon(icon, 1, defaultIcon.getIconWidth() + 5, 0); |
| button.setSelectedIcon(selected); |
| } |
| |
| public static String getTextWithoutMnemonicEscaping(String text) { |
| return StringUtil.strip(text, NOT_MNEMONIC_CHAR_FILTER); |
| } |
| |
| public static char getDisplayedMnemonic(String text) { |
| final int i = getDisplayedMnemonicIndex(text); |
| return i == -1 ? (char)-1 : text.charAt(i + 1); |
| } |
| |
| public static int getDisplayedMnemonicIndex(String text) { |
| return text.indexOf("&"); |
| } |
| |
| public static void packParentDialog(Component component) { |
| while (component != null) { |
| if (component instanceof JDialog) { |
| component.setVisible(true); |
| break; |
| } |
| component = component.getParent(); |
| } |
| } |
| |
| public static void replaceJSplitPaneWithIDEASplitter(JComponent root) { |
| final Container parent = root.getParent(); |
| if (root instanceof JSplitPane) { |
| // we can painlessly replace only splitter which is the only child in container |
| if (parent.getComponents().length != 1 && !(parent instanceof Splitter)) { |
| return; |
| } |
| final JSplitPane pane = (JSplitPane)root; |
| final Component component1 = pane.getTopComponent(); |
| final Component component2 = pane.getBottomComponent(); |
| final int orientation = pane.getOrientation(); |
| final Splitter splitter = new JBSplitter(orientation == JSplitPane.VERTICAL_SPLIT); |
| splitter.setFirstComponent((JComponent) component1); |
| splitter.setSecondComponent((JComponent) component2); |
| splitter.setShowDividerControls(pane.isOneTouchExpandable()); |
| splitter.setHonorComponentsMinimumSize(true); |
| |
| if (pane.getDividerLocation() > 0) { |
| // let the component chance to resize itself |
| SwingUtilities.invokeLater(new Runnable() { |
| @Override |
| public void run() { |
| double proportion; |
| if (pane.getOrientation() == JSplitPane.VERTICAL_SPLIT) { |
| proportion = pane.getDividerLocation() / (double)(parent.getHeight() - pane.getDividerSize()); |
| } |
| else { |
| proportion = pane.getDividerLocation() / (double)(parent.getWidth() - pane.getDividerSize()); |
| } |
| if (proportion > 0 && proportion < 1) { |
| splitter.setProportion((float)proportion); |
| } |
| } |
| }); |
| } |
| |
| if (parent instanceof Splitter) { |
| final Splitter psplitter = (Splitter) parent; |
| if (psplitter.getFirstComponent() == root) |
| psplitter.setFirstComponent(splitter); |
| else |
| psplitter.setSecondComponent(splitter); |
| } |
| else { |
| parent.remove(0); |
| parent.setLayout(new BorderLayout()); |
| parent.add(splitter, BorderLayout.CENTER); |
| } |
| replaceJSplitPaneWithIDEASplitter((JComponent) component1); |
| replaceJSplitPaneWithIDEASplitter((JComponent) component2); |
| } |
| else { |
| final Component[] components = root.getComponents(); |
| for (Component component : components) { |
| if (component instanceof JComponent) { |
| replaceJSplitPaneWithIDEASplitter((JComponent)component); |
| } |
| } |
| } |
| } |
| |
| public static void iterateChildren(Component container, Consumer<Component> consumer, JComponent... excludeComponents) { |
| if (excludeComponents != null && ArrayUtil.find(excludeComponents, container) != -1) return; |
| consumer.consume(container); |
| if (container instanceof Container) { |
| final Component[] components = ((Container)container).getComponents(); |
| for (Component child : components) { |
| iterateChildren(child, consumer, excludeComponents); |
| } |
| } |
| } |
| |
| public static void iterateChildren(Consumer<Component> consumer, Component... components) { |
| for (final Component component : components) { |
| iterateChildren(component, consumer); |
| } |
| } |
| |
| public static void enableChildren(final boolean enabled, Component... components) { |
| for (final Component component : components) { |
| enableChildren(component, enabled); |
| } |
| } |
| |
| public static void showComponents(final boolean visible, Component... components) { |
| for (final Component component : components) { |
| component.setVisible(visible); |
| } |
| } |
| |
| public static void enableChildren(Component container, final boolean enabled, JComponent... excludeComponents) { |
| iterateChildren(container, new Consumer<Component>() { |
| @Override |
| public void consume(final Component t) { |
| enableComponent(t, enabled); |
| } |
| }, excludeComponents); |
| } |
| |
| private static void enableComponent(Component component, boolean enabled) { |
| if (component.isEnabled() == enabled) return; |
| component.setEnabled(enabled); |
| if (component instanceof JPanel) { |
| final Border border = ((JPanel)component).getBorder(); |
| if (border instanceof TitledBorder) { |
| Color color = enabled ? component.getForeground() : UIUtil.getInactiveTextColor(); |
| ((TitledBorder)border).setTitleColor(color); |
| } |
| } |
| else if (component instanceof JLabel) { |
| Color color = UIUtil.getInactiveTextColor(); |
| if (color == null) color = component.getForeground(); |
| @NonNls String changeColorString = "<font color=#" + colorToHex(color) +">"; |
| final JLabel label = (JLabel)component; |
| @NonNls String text = label.getText(); |
| if (text != null && text.startsWith("<html>")) { |
| if (StringUtil.startsWithConcatenation(text, "<html>", changeColorString) && enabled) { |
| text = "<html>"+text.substring(("<html>"+changeColorString).length()); |
| } |
| else if (!StringUtil.startsWithConcatenation(text, "<html>", changeColorString) && !enabled) { |
| text = "<html>"+changeColorString+text.substring("<html>".length()); |
| } |
| label.setText(text); |
| } |
| } |
| else if (component instanceof JTable) { |
| TableColumnModel columnModel = ((JTable)component).getColumnModel(); |
| for (int i=0; i<columnModel.getColumnCount();i++) { |
| TableCellRenderer cellRenderer = columnModel.getColumn(0).getCellRenderer(); |
| if (cellRenderer instanceof Component) { |
| enableComponent((Component)cellRenderer, enabled); |
| } |
| } |
| } |
| } |
| |
| public static String colorToHex(final Color color) { |
| return to2DigitsHex(color.getRed()) |
| +to2DigitsHex(color.getGreen()) |
| +to2DigitsHex(color.getBlue()); |
| } |
| |
| private static String to2DigitsHex(int i) { |
| String s = Integer.toHexString(i); |
| if (s.length() < 2) s = "0" + s; |
| return s; |
| } |
| |
| public static void invokeAndWait(@NotNull Runnable runnable) throws InvocationTargetException, InterruptedException { |
| Application application = ApplicationManager.getApplication(); |
| assert !application.isDispatchThread() : "Must not be invoked from AWT dispatch thread"; |
| if (application.isReadAccessAllowed()) { |
| // make ApplicationImpl catch deadlock situation with readLock held |
| application.invokeAndWait(runnable, application.getDefaultModalityState()); |
| return; |
| } |
| SwingUtilities.invokeAndWait(runnable); |
| } |
| |
| public static void runOrInvokeAndWait(@NotNull Runnable runnable) throws InvocationTargetException, InterruptedException { |
| Application application = ApplicationManager.getApplication(); |
| if (application.isDispatchThread()) { |
| runnable.run(); |
| } |
| else { |
| invokeAndWait(runnable); |
| } |
| } |
| |
| public static JTextField createUndoableTextField() { |
| JTextField field = new JTextField(); |
| if (ApplicationManager.getApplication() != null) { |
| new TextComponentUndoProvider(field); |
| } |
| return field; |
| } |
| } |