• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 package ohos.devtools.views.trace;
17 
18 import com.intellij.ui.JBColor;
19 import com.intellij.ui.UtilUiBundle;
20 import com.intellij.util.containers.ContainerUtil;
21 import com.intellij.util.ui.StartupUiUtil;
22 import com.intellij.util.ui.UIUtil;
23 import org.jetbrains.annotations.Nls;
24 import org.jetbrains.annotations.NonNls;
25 import org.jetbrains.annotations.NotNull;
26 
27 import javax.swing.AbstractAction;
28 import javax.swing.ActionMap;
29 import javax.swing.Icon;
30 import javax.swing.InputMap;
31 import javax.swing.JButton;
32 import javax.swing.JComponent;
33 import javax.swing.JPanel;
34 import javax.swing.KeyStroke;
35 import java.awt.Color;
36 import java.awt.Dimension;
37 import java.awt.Font;
38 import java.awt.Graphics;
39 import java.awt.GridBagConstraints;
40 import java.awt.GridBagLayout;
41 import java.awt.Insets;
42 import java.awt.Label;
43 import java.awt.event.ActionEvent;
44 import java.awt.event.ActionListener;
45 import java.awt.event.KeyEvent;
46 import java.util.Collection;
47 
48 /**
49  * FolderPanel
50  *
51  * @since 2021/5/18 23:18
52  */
53 public class FolderPanel extends JPanel {
54     /**
55      * LEFT_KEY_STROKE
56      */
57     public static final KeyStroke LEFT_KEY_STROKE = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0);
58 
59     /**
60      * LEFT_KEY_STROKE
61      */
62     public static final KeyStroke RIGHT_KEY_STROKE = KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0);
63 
64     /**
65      * expand word
66      */
67     @NonNls
68     public static final String EXPAND = "expand";
69 
70     /**
71      * collapse word
72      */
73     @NonNls
74     public static final String COLLAPSE = "collapse";
75 
76     private final JButton myToggleCollapseButton;
77     private final JComponent myContent;
78     private final Collection<CollapsingListener> myListeners = ContainerUtil.createLockFreeCopyOnWriteList();
79     private final Icon myExpandIcon;
80     private final Icon myCollapseIcon;
81     private boolean myIsCollapsed;
82     private boolean myIsInitialized = false;
83     private Label myTitleLabel;
84 
85     /**
86      * structure
87      *
88      * @param content content
89      * @param collapseButtonAtLeft collapseButtonAtLeft
90      * @param isCollapsed isCollapsed
91      * @param collapseIcon collapseIcon
92      * @param expandIcon expandIcon
93      * @param title title
94      */
FolderPanel(JComponent content, boolean collapseButtonAtLeft, boolean isCollapsed, Icon collapseIcon, Icon expandIcon, String title)95     public FolderPanel(JComponent content, boolean collapseButtonAtLeft, boolean isCollapsed, Icon collapseIcon,
96         Icon expandIcon, String title) {
97         super(new GridBagLayout());
98         myContent = content;
99         setBackground(content.getBackground());
100         myExpandIcon = expandIcon;
101         myCollapseIcon = collapseIcon;
102         myToggleCollapseButton = new JButton();
103         myToggleCollapseButton.setOpaque(false);
104         myToggleCollapseButton.setBorderPainted(false);
105         myToggleCollapseButton.setBackground(new Color(0, 0, 0, 0));
106         final Dimension buttonDimension = getButtonDimension();
107         myToggleCollapseButton.setSize(buttonDimension);
108         myToggleCollapseButton.setPreferredSize(buttonDimension);
109         myToggleCollapseButton.setMinimumSize(buttonDimension);
110         myToggleCollapseButton.setMaximumSize(buttonDimension);
111         myToggleCollapseButton.setFocusable(true);
112         myToggleCollapseButton.getActionMap().put(COLLAPSE, new AbstractAction() {
113             @Override
114             public void actionPerformed(ActionEvent event) {
115                 collapse();
116             }
117         });
118         myToggleCollapseButton.getActionMap().put(EXPAND, new AbstractAction() {
119             @Override
120             public void actionPerformed(ActionEvent event) {
121                 expand();
122             }
123         });
124         myToggleCollapseButton.getInputMap().put(LEFT_KEY_STROKE, COLLAPSE);
125         myToggleCollapseButton.getInputMap().put(RIGHT_KEY_STROKE, EXPAND);
126         final int iconAnchor = collapseButtonAtLeft ? GridBagConstraints.WEST : GridBagConstraints.EAST;
127         add(myToggleCollapseButton, new GridBagConstraints(0, 0, 1, 1, 1.0, 0.0, iconAnchor, GridBagConstraints.CENTER,
128             new Insets(0, collapseButtonAtLeft ? 0 : 5, 0, collapseButtonAtLeft ? 0 : 0), 0, 0));
129         if (title != null) {
130             myTitleLabel = new Label(title);
131             myTitleLabel.setFont(StartupUiUtil.getLabelFont().deriveFont(Font.BOLD));
132             myTitleLabel.setBackground(content.getBackground());
133             add(myTitleLabel,
134                 new GridBagConstraints(0, 0, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE,
135                     new Insets(0, 20, 0, 0), 0, 0));
136         }
137         myToggleCollapseButton.addActionListener(new ActionListener() {
138             @Override
139             public void actionPerformed(ActionEvent event) {
140                 setCollapsed(!myIsCollapsed);
141             }
142         });
143         setCollapsed(isCollapsed);
144     }
145 
146     /**
147      * structure
148      *
149      * @param content content
150      * @param collapseButtonAtLeft collapseButtonAtLeft
151      */
FolderPanel(JComponent content, boolean collapseButtonAtLeft)152     public FolderPanel(JComponent content, boolean collapseButtonAtLeft) {
153         this(content, collapseButtonAtLeft, false, null, null, null);
154     }
155 
getButtonDimension()156     private Dimension getButtonDimension() {
157         if (myExpandIcon == null) {
158             return new Dimension(7, 7);
159         } else {
160             return new Dimension(myExpandIcon.getIconWidth(), myExpandIcon.getIconHeight());
161         }
162     }
163 
164     @Nls
getToggleButtonToolTipText()165     private String getToggleButtonToolTipText() {
166         if (myIsCollapsed) {
167             return UtilUiBundle.message("collapsible.panel.collapsed.state.tooltip.text");
168         } else {
169             return UtilUiBundle.message("collapsible.panel.expanded.state.tooltip.text");
170         }
171     }
172 
getIcon()173     private Icon getIcon() {
174         if (myIsCollapsed) {
175             return myExpandIcon;
176         } else {
177             return myCollapseIcon;
178         }
179     }
180 
notifyListeners()181     private void notifyListeners() {
182         for (CollapsingListener listener : myListeners) {
183             listener.onCollapsingChanged(this, isCollapsed());
184         }
185     }
186 
187     /**
188      * addCollapsingListener
189      *
190      * @param listener listener
191      */
addCollapsingListener(CollapsingListener listener)192     public void addCollapsingListener(CollapsingListener listener) {
193         myListeners.add(listener);
194     }
195 
196     /**
197      * removeCollapsingListener
198      *
199      * @param listener listener
200      */
removeCollapsingListener(CollapsingListener listener)201     public void removeCollapsingListener(CollapsingListener listener) {
202         myListeners.remove(listener);
203     }
204 
205     /**
206      * get myIsCollapsed
207      *
208      * @return isCollapsed
209      */
isCollapsed()210     public boolean isCollapsed() {
211         return myIsCollapsed;
212     }
213 
214     /**
215      * set the collapse
216      *
217      * @param collapse collapse
218      */
setCollapsed(boolean collapse)219     protected void setCollapsed(boolean collapse) {
220         try {
221             if (collapse) {
222                 if (myIsInitialized) {
223                     remove(myContent);
224                 }
225             } else {
226                 add(myContent,
227                     new GridBagConstraints(0, 1, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH,
228                         new Insets(0, 0, 0, 0), 0, 0));
229             }
230             myIsCollapsed = collapse;
231             Icon icon = getIcon();
232             if (icon != null) {
233                 myToggleCollapseButton.setIcon(icon);
234                 myToggleCollapseButton.setBorder(null);
235                 myToggleCollapseButton.setBorderPainted(false);
236                 myToggleCollapseButton.setToolTipText(getToggleButtonToolTipText());
237             }
238             if (collapse) {
239                 setFocused(true);
240                 setSelected(true);
241             } else {
242                 myContent.requestFocusInWindow();
243             }
244             notifyListeners();
245             revalidate();
246             repaint();
247         } finally {
248             myIsInitialized = true;
249         }
250     }
251 
252     /**
253      * expand
254      */
expand()255     public void expand() {
256         if (myIsCollapsed) {
257             setCollapsed(false);
258         }
259     }
260 
261     /**
262      * collapse
263      */
collapse()264     public void collapse() {
265         if (!myIsCollapsed) {
266             setCollapsed(true);
267         }
268     }
269 
270     /**
271      * setFocused
272      *
273      * @param focused focused
274      */
setFocused(boolean focused)275     public void setFocused(boolean focused) {
276         myToggleCollapseButton.requestFocusInWindow();
277     }
278 
279     /**
280      * setSelected
281      *
282      * @param selected selected
283      */
setSelected(boolean selected)284     public void setSelected(boolean selected) {
285         myToggleCollapseButton.setSelected(selected);
286     }
287 
288     /**
289      * getCollapsibleActionMap
290      *
291      * @return InputMap
292      */
getCollapsibleActionMap()293     public ActionMap getCollapsibleActionMap() {
294         return myToggleCollapseButton.getActionMap();
295     }
296 
297     /**
298      * getCollapsibleInputMap
299      *
300      * @return InputMap
301      */
getCollapsibleInputMap()302     public InputMap getCollapsibleInputMap() {
303         return myToggleCollapseButton.getInputMap();
304     }
305 
306     @Override
paintComponent(Graphics graphics)307     protected void paintComponent(Graphics graphics) {
308         updatePanel();
309         super.paintComponent(graphics);
310     }
311 
updatePanel()312     private void updatePanel() {
313         if (paintAsSelected()) {
314             setBackground(UIUtil.getTableSelectionBackground(true));
315         } else {
316             setBackground(myContent.getBackground());
317         }
318     }
319 
320     @Override
paintChildren(Graphics graphics)321     protected void paintChildren(Graphics graphics) {
322         if (myTitleLabel != null) {
323             updateTitle();
324         }
325         updateToggleButton();
326         super.paintChildren(graphics);
327     }
328 
updateToggleButton()329     private void updateToggleButton() {
330         if (paintAsSelected()) {
331             myToggleCollapseButton.setBackground(JBColor.background().brighter());
332         } else {
333             myToggleCollapseButton.setBackground(myContent.getBackground());
334         }
335     }
336 
updateTitle()337     private void updateTitle() {
338         if (paintAsSelected()) {
339             myTitleLabel.setForeground(JBColor.foreground());
340             myTitleLabel.setBackground(JBColor.background().brighter());
341         } else {
342             myTitleLabel.setForeground(JBColor.foreground());
343             myTitleLabel.setBackground(JBColor.background().brighter());
344         }
345     }
346 
paintAsSelected()347     private boolean paintAsSelected() {
348         return myToggleCollapseButton.hasFocus() && isCollapsed();
349     }
350 
351     /**
352      * CollapsingListener
353      *
354      * @since 2021/5/18 23:18
355      */
356     public interface CollapsingListener {
357         /**
358          * onCollapsingChanged
359          *
360          * @param panel panel
361          * @param newValue newValue
362          */
onCollapsingChanged(@otNull FolderPanel panel, boolean newValue)363         void onCollapsingChanged(@NotNull FolderPanel panel, boolean newValue);
364     }
365 
366 }
367