View Javadoc

1   /**
2    * Copyright (C) 2008 Atlassian
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *    http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
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) { // on double click, just open the issue
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 		//contentPanel.setPreferredSize(getCustomPreferredSize());
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 }