1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.atlassian.theplugin.idea.ui;
18
19 import com.intellij.openapi.util.IconLoader;
20 import com.intellij.util.ui.UIUtil;
21 import org.jetbrains.annotations.NonNls;
22
23 import javax.swing.*;
24 import java.awt.*;
25 import java.awt.event.*;
26 import java.util.ArrayList;
27 import java.util.Collection;
28
29 public class CollapsiblePanel extends JPanel {
30 private JButton myToggleCollapseButton;
31 private JComponent myContent;
32 private boolean myIsCollapsed;
33 private final Collection<CollapsingListener> myListeners = new ArrayList<CollapsingListener>();
34 private boolean myIsInitialized = false;
35 private Icon myExpandIcon;
36 private Icon myCollapseIcon;
37 private JLabel myTitleLabel;
38 private JPanel contentPanel;
39 private JPanel labelPanel;
40
41 public static final KeyStroke LEFT_KEY_STROKE = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0);
42 public static final KeyStroke RIGHT_KEY_STROKE = KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0);
43 @NonNls
44 public static final String EXPAND = "expand";
45 @NonNls
46 public static final String COLLAPSE = "collapse";
47
48
49 public CollapsiblePanel(boolean collapseButtonAtLeft,
50 boolean isCollapsed, Icon collapseIcon, Icon expandIcon,
51 String title) {
52 super(new GridBagLayout());
53 setupComponents(expandIcon, collapseIcon, title, collapseButtonAtLeft, isCollapsed);
54 }
55
56 public CollapsiblePanel(JComponent content, boolean collapseButtonAtLeft,
57 boolean isCollapsed, Icon collapseIcon, Icon expandIcon,
58 String title) {
59 super(new GridBagLayout());
60 setupComponents(expandIcon, collapseIcon, title, collapseButtonAtLeft, isCollapsed);
61 setContent(content);
62 }
63
64
65 public CollapsiblePanel(boolean collapseButtonAtLeft,
66 boolean isCollapsed, String title) {
67 super(new GridBagLayout());
68 Icon collapseIcon = IconLoader.findIcon("/icons/navigate_down_10.gif");
69 Icon expandIcon = IconLoader.findIcon("/icons/navigate_right_10.gif");
70 setupComponents(expandIcon, collapseIcon, title, collapseButtonAtLeft, isCollapsed);
71 }
72
73 public void setTitle(String title) {
74 myTitleLabel.setText(title);
75 }
76
77
78 private Dimension getButtonDimension() {
79 if (myExpandIcon == null) {
80 return new Dimension(9, 9);
81 } else {
82 return new Dimension((myExpandIcon.getIconWidth() > myCollapseIcon.getIconWidth() ? myExpandIcon.getIconWidth() : myCollapseIcon.getIconWidth()),
83 myExpandIcon.getIconHeight() > myCollapseIcon.getIconHeight() ? myExpandIcon.getIconHeight() : myCollapseIcon.getIconHeight());
84 }
85 }
86
87 public CollapsiblePanel(JComponent content, boolean collapseButtonAtLeft) {
88 this(content, collapseButtonAtLeft, false, null, null, null);
89 }
90
91 protected void setCollapsed(boolean collapse) {
92 try {
93
94 if (collapse) {
95 if (myIsInitialized) {
96 remove(contentPanel);
97
98
99 if (contentPanel != null) {
100 contentPanel.setVisible(false);
101 myContent.setVisible(false);
102 }
103 labelPanel.requestFocusInWindow();
104 }
105
106 } else {
107 if (myContent != null) {
108 add(contentPanel,
109 new GridBagConstraints(0, 1, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH,
110 new Insets(3, 0, 0, 0), 0, 0));
111 contentPanel.setVisible(true);
112 myContent.setVisible(true);
113
114 }
115
116 }
117 myIsCollapsed = collapse;
118
119
120 revalidate();
121 repaint();
122
123 Icon icon = getIcon();
124 if (icon != null) {
125
126 myToggleCollapseButton.setIcon(icon);
127 myToggleCollapseButton.setBorder(null);
128 myToggleCollapseButton.setBorderPainted(false);
129 myToggleCollapseButton.setToolTipText(getToggleButtonToolTipText());
130 }
131
132
133 if (collapse) {
134 setFocused(true);
135 setSelected(true);
136
137 } else if (myContent != null) {
138 myContent.requestFocusInWindow();
139 }
140
141
142 notifyListners();
143
144 revalidate();
145 repaint();
146 } finally {
147 myIsInitialized = true;
148 }
149 }
150
151 private String getToggleButtonToolTipText() {
152 if (myIsCollapsed) {
153 return "Collapsed";
154 } else {
155 return "Expanded";
156 }
157 }
158
159 private Icon getIcon() {
160 if (myIsCollapsed) {
161 return myExpandIcon;
162 } else {
163 return myCollapseIcon;
164 }
165 }
166
167 private void notifyListners() {
168 CollapsingListener[] listeners = myListeners.toArray(new CollapsingListener[myListeners.size()]);
169 for (CollapsingListener listener : listeners) {
170 listener.onCollapsingChanged(this, isCollapsed());
171 }
172 }
173
174 public JComponent getContent() {
175 return myContent;
176 }
177
178 public void setContent(JComponent content) {
179 setBackground(content.getBackground());
180 this.myContent = content;
181 contentPanel.setBackground(content.getBackground());
182 contentPanel.add(content, BorderLayout.CENTER);
183 }
184
185 private void setupComponents(Icon expandIcon, Icon collapseIcon,
186 String title, boolean collapseButtonAtLeft,
187 boolean isCollapsed) {
188
189 contentPanel = new JPanel(new BorderLayout());
190
191 this.myToggleCollapseButton = new JButton();
192 this.myExpandIcon = expandIcon;
193 this.myCollapseIcon = collapseIcon;
194
195 final Dimension buttonDimension = getButtonDimension();
196
197
198 myToggleCollapseButton.setOpaque(false);
199 myToggleCollapseButton.setBorderPainted(false);
200
201 myToggleCollapseButton.setSize(buttonDimension);
202 myToggleCollapseButton.setPreferredSize(buttonDimension);
203 myToggleCollapseButton.setMinimumSize(buttonDimension);
204 myToggleCollapseButton.setMaximumSize(buttonDimension);
205
206 myToggleCollapseButton.setFocusable(true);
207
208
209 myToggleCollapseButton.getActionMap().put(COLLAPSE, new AbstractAction() {
210 public void actionPerformed(ActionEvent e) {
211 collapse();
212 }
213 });
214
215 myToggleCollapseButton.getActionMap().put(EXPAND, new AbstractAction() {
216 public void actionPerformed(ActionEvent e) {
217 expand();
218 }
219 });
220
221 myToggleCollapseButton.getInputMap().put(LEFT_KEY_STROKE, COLLAPSE);
222 myToggleCollapseButton.getInputMap().put(RIGHT_KEY_STROKE, EXPAND);
223
224 myToggleCollapseButton.addActionListener(new ActionListener() {
225 public void actionPerformed(ActionEvent e) {
226 setCollapsed(!myIsCollapsed);
227 }
228 });
229
230 final int iconAnchor = collapseButtonAtLeft ? GridBagConstraints.WEST : GridBagConstraints.EAST;
231 labelPanel = new JPanel(new BorderLayout(20, 0));
232
233 labelPanel.add(myToggleCollapseButton, BorderLayout.LINE_START);
234 labelPanel.setBackground(UIUtil.getTableSelectionBackground());
235 if (title != null) {
236
237 myTitleLabel = new JLabel(title);
238 myTitleLabel.setFont(UIUtil.getLabelFont().deriveFont(Font.BOLD));
239
240 labelPanel.add(myTitleLabel, BorderLayout.CENTER);
241 revalidate();
242 repaint();
243
244 myTitleLabel.addMouseListener(new MouseAdapter() {
245 public void mouseClicked(MouseEvent e) {
246 if (myIsCollapsed) {
247 expand();
248 } else {
249 collapse();
250 }
251 }
252 });
253
254 }
255
256
257 add(labelPanel,
258 new GridBagConstraints(0, 0, 1, 1, 1, 0.0,
259 iconAnchor,
260 GridBagConstraints.HORIZONTAL,
261 new Insets(1, collapseButtonAtLeft ? 0 : 1, 0, collapseButtonAtLeft ? 1 : 0), 0,
262 0));
263
264 myIsCollapsed = isCollapsed;
265 setCollapsed(isCollapsed);
266
267 }
268
269
270 public void addCollapsingListener(CollapsingListener listener) {
271 myListeners.add(listener);
272 }
273
274 public void removeCollapsingListener(CollapsingListener listener) {
275 myListeners.remove(listener);
276 }
277
278 public boolean isCollapsed() {
279 return myIsCollapsed;
280 }
281
282 public void expand() {
283 if (myIsCollapsed) {
284 setCollapsed(false);
285 }
286 }
287
288 public void collapse() {
289 if (!myIsCollapsed) {
290 setCollapsed(true);
291 }
292 }
293
294 public void setFocused(boolean focused) {
295 myToggleCollapseButton.requestFocusInWindow();
296 }
297
298 public void setSelected(boolean selected) {
299 myToggleCollapseButton.setSelected(selected);
300 }
301
302 public ActionMap getCollapsibleActionMap() {
303 return myToggleCollapseButton.getActionMap();
304 }
305
306 public InputMap getCollapsibleInputMap() {
307 return myToggleCollapseButton.getInputMap();
308 }
309
310 protected void paintComponent(Graphics g) {
311 updatePanel();
312 super.paintComponent(g);
313 }
314
315 private void updatePanel() {
316 setBackground(UIUtil.getTableSelectionBackground());
317
318
319 }
320
321 protected void paintChildren(Graphics g) {
322 if (myTitleLabel != null) {
323 updateTitle();
324 }
325
326
327 updateToggleButton();
328
329 super.paintChildren(g);
330 }
331
332 private void updateToggleButton() {
333 myToggleCollapseButton.setBackground(UIUtil.getTableSelectionBackground());
334
335 }
336
337 private void updateTitle() {
338
339 myTitleLabel.setForeground(UIUtil.getTableSelectionForeground());
340 myTitleLabel.setBackground(UIUtil.getTableSelectionBackground());
341 }
342
343 private boolean paintAsSelected() {
344 return myToggleCollapseButton.hasFocus() && isCollapsed();
345 }
346
347 }