summaryrefslogtreecommitdiff
path: root/platform/platform-impl/src/com/intellij/util/ui/SwingHelper.java
diff options
context:
space:
mode:
Diffstat (limited to 'platform/platform-impl/src/com/intellij/util/ui/SwingHelper.java')
-rw-r--r--platform/platform-impl/src/com/intellij/util/ui/SwingHelper.java465
1 files changed, 465 insertions, 0 deletions
diff --git a/platform/platform-impl/src/com/intellij/util/ui/SwingHelper.java b/platform/platform-impl/src/com/intellij/util/ui/SwingHelper.java
new file mode 100644
index 000000000000..ac4c1b12373c
--- /dev/null
+++ b/platform/platform-impl/src/com/intellij/util/ui/SwingHelper.java
@@ -0,0 +1,465 @@
+package com.intellij.util.ui;
+
+import com.intellij.ide.BrowserUtil;
+import com.intellij.openapi.actionSystem.ActionManager;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.DefaultActionGroup;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.fileChooser.FileChooserDescriptor;
+import com.intellij.openapi.fileChooser.FileChooserFactory;
+import com.intellij.openapi.ide.CopyPasteManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.ComponentWithBrowseButton;
+import com.intellij.openapi.ui.DialogWrapper;
+import com.intellij.openapi.ui.TextComponentAccessor;
+import com.intellij.openapi.ui.TextFieldWithBrowseButton;
+import com.intellij.openapi.util.SystemInfo;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.ui.HyperlinkLabel;
+import com.intellij.ui.TextFieldWithHistory;
+import com.intellij.ui.TextFieldWithHistoryWithBrowseButton;
+import com.intellij.util.NotNullProducer;
+import com.intellij.util.PlatformIcons;
+import com.intellij.util.containers.ComparatorUtil;
+import com.intellij.util.containers.ContainerUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import javax.swing.event.PopupMenuEvent;
+import javax.swing.event.PopupMenuListener;
+import javax.swing.table.DefaultTableCellRenderer;
+import javax.swing.table.TableCellRenderer;
+import javax.swing.table.TableColumn;
+import java.awt.*;
+import java.awt.datatransfer.StringSelection;
+import java.awt.datatransfer.Transferable;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+public class SwingHelper {
+
+ private static final Logger LOG = Logger.getInstance(SwingHelper.class);
+
+ /**
+ * Creates panel whose content consists of given {@code children} components
+ * stacked vertically each on another in a given order.
+ *
+ * @param childAlignmentX Component.LEFT_ALIGNMENT, Component.CENTER_ALIGNMENT or Component.RIGHT_ALIGNMENT
+ * @param children children components
+ * @return created panel
+ */
+ @NotNull
+ public static JPanel newVerticalPanel(float childAlignmentX, Component... children) {
+ return newGenericBoxPanel(true, childAlignmentX, children);
+ }
+
+ @NotNull
+ public static JPanel newLeftAlignedVerticalPanel(Component... children) {
+ return newVerticalPanel(Component.LEFT_ALIGNMENT, children);
+ }
+
+ @NotNull
+ public static JPanel newLeftAlignedVerticalPanel(@NotNull Collection<Component> children) {
+ return newVerticalPanel(Component.LEFT_ALIGNMENT, children);
+ }
+
+ @NotNull
+ public static JPanel newVerticalPanel(float childAlignmentX, @NotNull Collection<Component> children) {
+ return newVerticalPanel(childAlignmentX, children.toArray(new Component[children.size()]));
+ }
+
+ /**
+ * Creates panel whose content consists of given {@code children} components horizontally
+ * stacked each on another in a given order.
+ *
+ * @param childAlignmentY Component.TOP_ALIGNMENT, Component.CENTER_ALIGNMENT or Component.BOTTOM_ALIGNMENT
+ * @param children children components
+ * @return created panel
+ */
+ @NotNull
+ public static JPanel newHorizontalPanel(float childAlignmentY, Component... children) {
+ return newGenericBoxPanel(false, childAlignmentY, children);
+ }
+
+ @NotNull
+ public static JPanel newHorizontalPanel(float childAlignmentY, @NotNull Collection<Component> children) {
+ return newHorizontalPanel(childAlignmentY, children.toArray(new Component[children.size()]));
+ }
+
+ private static JPanel newGenericBoxPanel(boolean verticalOrientation,
+ float childAlignment,
+ Component... children) {
+ JPanel panel = new JPanel();
+ int axis = verticalOrientation ? BoxLayout.Y_AXIS : BoxLayout.X_AXIS;
+ panel.setLayout(new BoxLayout(panel, axis));
+ for (Component child : children) {
+ panel.add(child, childAlignment);
+ if (child instanceof JComponent) {
+ JComponent jChild = (JComponent) child;
+ if (verticalOrientation) {
+ jChild.setAlignmentX(childAlignment);
+ } else {
+ jChild.setAlignmentY(childAlignment);
+ }
+ }
+ }
+ return panel;
+ }
+
+ @NotNull
+ public static JPanel wrapWithoutStretch(@NotNull JComponent component) {
+ JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
+ panel.add(component);
+ return panel;
+ }
+
+ @NotNull
+ public static JPanel wrapWithHorizontalStretch(@NotNull JComponent component) {
+ JPanel panel = new JPanel(new BorderLayout(0, 0));
+ panel.add(component, BorderLayout.NORTH);
+ return panel;
+ }
+
+ public static void setPreferredWidthToFitText(@NotNull TextFieldWithHistoryWithBrowseButton component) {
+ int childWidth = calcWidthToFitText(component.getChildComponent().getTextEditor(), 35);
+ setPreferredWidthForComponentWithBrowseButton(component, childWidth);
+ }
+
+ public static void setPreferredWidthToFitText(@NotNull TextFieldWithBrowseButton component) {
+ int childWidth = calcWidthToFitText(component.getChildComponent(), 20);
+ setPreferredWidthForComponentWithBrowseButton(component, childWidth);
+ }
+
+ private static <T extends JComponent> void setPreferredWidthForComponentWithBrowseButton(@NotNull ComponentWithBrowseButton<T> component,
+ int childPrefWidth) {
+ Dimension buttonPrefSize = component.getButton().getPreferredSize();
+ setPreferredWidth(component, childPrefWidth + buttonPrefSize.width);
+ }
+
+ public static void setPreferredWidthToFitText(@NotNull JTextField textField) {
+ setPreferredWidthToFitText(textField, 15);
+ }
+
+ public static void setPreferredWidthToFitText(@NotNull JTextField textField, int additionalWidth) {
+ setPreferredSizeToFitText(textField, StringUtil.notNullize(textField.getText()), additionalWidth);
+ }
+
+ public static void setPreferredWidthToFitText(@NotNull JTextField textField, @NotNull String text) {
+ setPreferredSizeToFitText(textField, text, 15);
+ }
+
+ private static void setPreferredSizeToFitText(@NotNull JTextField textField, @NotNull String text, int additionalWidth) {
+ int width = calcWidthToFitText(textField, text, additionalWidth);
+ setPreferredWidth(textField, width);
+ }
+
+ private static int calcWidthToFitText(@NotNull JTextField textField, int additionalWidth) {
+ return calcWidthToFitText(textField, textField.getText(), additionalWidth);
+ }
+
+ private static int calcWidthToFitText(@NotNull JTextField textField, @NotNull String text, int additionalWidth) {
+ return textField.getFontMetrics(textField.getFont()).stringWidth(text) + additionalWidth;
+ }
+
+ public static void adjustDialogSizeToFitPreferredSize(@NotNull DialogWrapper dialogWrapper) {
+ JRootPane rootPane = dialogWrapper.getRootPane();
+ Dimension componentSize = rootPane.getSize();
+ Dimension componentPreferredSize = rootPane.getPreferredSize();
+ if (componentPreferredSize.width <= componentSize.width && componentPreferredSize.height <= componentSize.height) {
+ return;
+ }
+ int dw = Math.max(0, componentPreferredSize.width - componentSize.width);
+ int dh = Math.max(0, componentPreferredSize.height - componentSize.height);
+
+ Dimension oldDialogSize = dialogWrapper.getSize();
+ Dimension newDialogSize = new Dimension(oldDialogSize.width + dw, oldDialogSize.height + dh);
+
+ dialogWrapper.setSize(newDialogSize.width, newDialogSize.height);
+ rootPane.revalidate();
+ rootPane.repaint();
+
+ LOG.info("DialogWrapper '" + dialogWrapper.getTitle() + "' has been resized (added width: " + dw + ", added height: " + dh + ")");
+ }
+
+ public static <T> void updateItems(@NotNull JComboBox comboBox,
+ @NotNull List<T> newItems,
+ @Nullable T newSelectedItemIfSelectionCannotBePreserved) {
+ if (!shouldUpdate(comboBox, newItems)) {
+ return;
+ }
+ Object selectedItem = comboBox.getSelectedItem();
+ //noinspection SuspiciousMethodCalls
+ if (selectedItem != null && !newItems.contains(selectedItem)) {
+ selectedItem = null;
+ }
+ if (selectedItem == null && newItems.contains(newSelectedItemIfSelectionCannotBePreserved)) {
+ selectedItem = newSelectedItemIfSelectionCannotBePreserved;
+ }
+ comboBox.removeAllItems();
+ for (T newItem : newItems) {
+ comboBox.addItem(newItem);
+ }
+ if (selectedItem != null) {
+ int count = comboBox.getItemCount();
+ for (int i = 0; i < count; i++) {
+ Object item = comboBox.getItemAt(i);
+ if (selectedItem.equals(item)) {
+ comboBox.setSelectedIndex(i);
+ break;
+ }
+ }
+ }
+ }
+
+ private static <T> boolean shouldUpdate(@NotNull JComboBox comboBox, @NotNull List<T> newItems) {
+ int count = comboBox.getItemCount();
+ if (newItems.size() != count) {
+ return true;
+ }
+ for (int i = 0; i < count; i++) {
+ Object oldItem = comboBox.getItemAt(i);
+ T newItem = newItems.get(i);
+ if (!ComparatorUtil.equalsNullable(oldItem, newItem)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static void setNoBorderCellRendererFor(@NotNull TableColumn column) {
+ final TableCellRenderer previous = column.getCellRenderer();
+ column.setCellRenderer(new DefaultTableCellRenderer() {
+ @Override
+ public Component getTableCellRendererComponent(JTable table,
+ Object value,
+ boolean isSelected,
+ boolean hasFocus,
+ int row,
+ int column) {
+ Component component;
+ if (previous != null) {
+ component = previous.getTableCellRendererComponent(table, value, isSelected, false, row, column);
+ }
+ else {
+ component = super.getTableCellRendererComponent(table, value, isSelected, false, row, column);
+ }
+ if (component instanceof JComponent) {
+ ((JComponent)component).setBorder(null);
+ }
+ return component;
+ }
+ });
+ }
+
+ public static void addHistoryOnExpansion(@NotNull final TextFieldWithHistory textFieldWithHistory,
+ @NotNull final NotNullProducer<List<String>> historyProvider) {
+ textFieldWithHistory.addPopupMenuListener(new PopupMenuListener() {
+ @Override
+ public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
+ List<String> newHistory = historyProvider.produce();
+ Set<String> newHistorySet = ContainerUtil.newHashSet(newHistory);
+ List<String> oldHistory = textFieldWithHistory.getHistory();
+ List<String> mergedHistory = ContainerUtil.newArrayList();
+ for (String item : oldHistory) {
+ if (!newHistorySet.contains(item)) {
+ mergedHistory.add(item);
+ }
+ }
+ mergedHistory.addAll(newHistory);
+ textFieldWithHistory.setHistory(mergedHistory);
+
+ setLongestAsPrototype(textFieldWithHistory, mergedHistory);
+
+ // one-time initialization
+ textFieldWithHistory.removePopupMenuListener(this);
+ }
+
+ @Override
+ public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
+ }
+
+ @Override
+ public void popupMenuCanceled(PopupMenuEvent e) {
+ }
+ });
+ }
+
+ private static void setLongestAsPrototype(@NotNull JComboBox comboBox, @NotNull List<String> variants) {
+ Object prototypeDisplayValue = comboBox.getPrototypeDisplayValue();
+ String prototypeDisplayValueStr = null;
+ if (prototypeDisplayValue instanceof String) {
+ prototypeDisplayValueStr = (String) prototypeDisplayValue;
+ }
+ else if (prototypeDisplayValue != null) {
+ return;
+ }
+ String longest = StringUtil.notNullize(prototypeDisplayValueStr);
+ boolean updated = false;
+ for (String s : variants) {
+ if (longest.length() < s.length()) {
+ longest = s;
+ updated = true;
+ }
+ }
+ if (updated) {
+ comboBox.setPrototypeDisplayValue(longest);
+ }
+ }
+
+ public static void installFileCompletionAndBrowseDialog(@Nullable Project project,
+ @NotNull TextFieldWithHistoryWithBrowseButton textFieldWithHistoryWithBrowseButton,
+ @NotNull String browseDialogTitle,
+ @NotNull FileChooserDescriptor fileChooserDescriptor) {
+ doInstall(project,
+ textFieldWithHistoryWithBrowseButton,
+ textFieldWithHistoryWithBrowseButton.getChildComponent().getTextEditor(),
+ browseDialogTitle,
+ fileChooserDescriptor,
+ TextComponentAccessor.TEXT_FIELD_WITH_HISTORY_WHOLE_TEXT);
+ }
+
+ public static void installFileCompletionAndBrowseDialog(@Nullable Project project,
+ @NotNull TextFieldWithBrowseButton textFieldWithBrowseButton,
+ @NotNull String browseDialogTitle,
+ @NotNull FileChooserDescriptor fileChooserDescriptor) {
+ doInstall(project,
+ textFieldWithBrowseButton,
+ textFieldWithBrowseButton.getTextField(),
+ browseDialogTitle,
+ fileChooserDescriptor,
+ TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT);
+ }
+
+ private static <T extends JComponent> void doInstall(@Nullable Project project,
+ @NotNull ComponentWithBrowseButton<T> componentWithBrowseButton,
+ @NotNull JTextField textField,
+ @NotNull String browseDialogTitle,
+ @NotNull FileChooserDescriptor fileChooserDescriptor,
+ @NotNull TextComponentAccessor<T> textComponentAccessor) {
+ fileChooserDescriptor = fileChooserDescriptor.withShowHiddenFiles(SystemInfo.isUnix);
+ componentWithBrowseButton.addBrowseFolderListener(
+ project,
+ new ComponentWithBrowseButton.BrowseFolderActionListener<T>(
+ browseDialogTitle,
+ null,
+ componentWithBrowseButton,
+ project,
+ fileChooserDescriptor,
+ textComponentAccessor
+ ),
+ true
+ );
+ FileChooserFactory.getInstance().installFileCompletion(
+ textField,
+ fileChooserDescriptor,
+ true,
+ project
+ );
+ }
+
+ @NotNull
+ public static HyperlinkLabel createWebHyperlink(@NotNull String url) {
+ return createWebHyperlink(url, url);
+ }
+
+ @NotNull
+ public static HyperlinkLabel createWebHyperlink(@NotNull String text, @NotNull String url) {
+ HyperlinkLabel hyperlink = new HyperlinkLabel(text);
+ hyperlink.setHyperlinkTarget(url);
+
+ DefaultActionGroup actionGroup = new DefaultActionGroup();
+ actionGroup.add(new OpenLinkInBrowser(url));
+ actionGroup.add(new CopyLinkAction(url));
+
+ hyperlink.setComponentPopupMenu(ActionManager.getInstance().createActionPopupMenu("web hyperlink", actionGroup).getComponent());
+ return hyperlink;
+ }
+
+ public static void setPreferredWidth(@NotNull JComponent component, int width) {
+ Dimension preferredSize = component.getPreferredSize();
+ preferredSize.width = width;
+ component.setPreferredSize(preferredSize);
+ }
+
+ @NotNull
+ public static JEditorPane createHtmlViewer(boolean carryTextOver,
+ @Nullable Font font,
+ @Nullable Color background,
+ @Nullable Color foreground) {
+ final JEditorPane textPane;
+ if (carryTextOver) {
+ textPane = new JEditorPane() {
+ @Override
+ public Dimension getPreferredSize() {
+ // This trick makes text component to carry text over to the next line
+ // if the text line width exceeds parent's width
+ Dimension dimension = super.getPreferredSize();
+ dimension.width = 0;
+ return dimension;
+ }
+ };
+ }
+ else {
+ textPane = new JEditorPane();
+ }
+ textPane.setFont(font != null ? font : UIUtil.getLabelFont());
+ textPane.setContentType(UIUtil.HTML_MIME);
+ textPane.setEditable(false);
+ textPane.setBackground(background != null ? background : UIUtil.getLabelBackground());
+ textPane.setForeground(foreground != null ? foreground : UIUtil.getLabelForeground());
+ return textPane;
+ }
+
+ public static void setHtml(@NotNull JEditorPane editorPane, @NotNull String bodyInnerHtml) {
+ String html = String.format(
+ "<html><head>%s</head><body>%s</body></html>",
+ UIUtil.getCssFontDeclaration(editorPane.getFont(), null, null, null),
+ bodyInnerHtml
+ );
+ editorPane.setText(html);
+ }
+
+ private static class CopyLinkAction extends AnAction {
+
+ private final String myUrl;
+
+ private CopyLinkAction(@NotNull String url) {
+ super("Copy Link Address", null, PlatformIcons.COPY_ICON);
+ myUrl = url;
+ }
+
+ @Override
+ public void update(AnActionEvent e) {
+ e.getPresentation().setEnabled(true);
+ }
+
+ @Override
+ public void actionPerformed(AnActionEvent e) {
+ Transferable content = new StringSelection(myUrl);
+ CopyPasteManager.getInstance().setContents(content);
+ }
+ }
+
+ private static class OpenLinkInBrowser extends AnAction {
+
+ private final String myUrl;
+
+ private OpenLinkInBrowser(@NotNull String url) {
+ super("Open Link in Browser", null, PlatformIcons.WEB_ICON);
+ myUrl = url;
+ }
+
+ @Override
+ public void update(AnActionEvent e) {
+ e.getPresentation().setEnabled(true);
+ }
+
+ @Override
+ public void actionPerformed(AnActionEvent e) {
+ BrowserUtil.browse(myUrl);
+ }
+ }
+} \ No newline at end of file