tmf: Add collapsible event table header bar with applied filter labels
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.ui / src / org / eclipse / tracecompass / tmf / ui / viewers / events / TmfEventsTableHeader.java
1 /*******************************************************************************
2 * Copyright (c) 2016 Ericsson
3 *
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *
9 * Contributors:
10 * Patrick Tasse - Initial API and implementation
11 *******************************************************************************/
12
13 package org.eclipse.tracecompass.tmf.ui.viewers.events;
14
15 import org.eclipse.swt.SWT;
16 import org.eclipse.swt.custom.CLabel;
17 import org.eclipse.swt.events.ControlAdapter;
18 import org.eclipse.swt.events.ControlEvent;
19 import org.eclipse.swt.events.MouseAdapter;
20 import org.eclipse.swt.events.MouseEvent;
21 import org.eclipse.swt.graphics.Color;
22 import org.eclipse.swt.graphics.Image;
23 import org.eclipse.swt.graphics.Point;
24 import org.eclipse.swt.graphics.RGB;
25 import org.eclipse.swt.graphics.Rectangle;
26 import org.eclipse.swt.layout.RowLayout;
27 import org.eclipse.swt.widgets.Composite;
28 import org.eclipse.swt.widgets.Control;
29 import org.eclipse.tracecompass.internal.tmf.ui.Activator;
30 import org.eclipse.tracecompass.tmf.core.filter.ITmfFilter;
31 import org.eclipse.tracecompass.tmf.core.filter.model.ITmfFilterTreeNode;
32 import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterNode;
33 import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterRootNode;
34
35 /**
36 * Header bar for the events table.
37 *
38 * @since 2.0
39 */
40 public class TmfEventsTableHeader extends Composite {
41
42 private static final Image COLLAPSED = Activator.getDefault().getImageFromPath("icons/ovr16/collapsed_ovr.gif"); //$NON-NLS-1$
43 private static final Image EXPANDED = Activator.getDefault().getImageFromPath("icons/ovr16/expanded_ovr.gif"); //$NON-NLS-1$
44 private static final Image DELETE = Activator.getDefault().getImageFromPath("icons/elcl16/delete_button.gif"); //$NON-NLS-1$
45 private static final Image DELETE_SMALL = Activator.getDefault().getImageFromPath("icons/ovr16/delete_ovr.gif"); //$NON-NLS-1$
46 private static final int DEFAULT_MARGIN = 3;
47 private static final int COLLAPSED_IMAGE_MARGIN = 2;
48 private static final int COLLAPSED_RIGHT_MARGIN = 32;
49 private static final RGB LABEL_BACKGROUND = new RGB(255, 255, 192);
50 private static final String TOOLTIP_KEY = "toolTip"; //$NON-NLS-1$
51
52 /**
53 * Interface for header bar call-backs.
54 */
55 public interface IEventsTableHeaderListener {
56 /**
57 * A filter has been selected.
58 *
59 * @param filter
60 * the selected filter
61 */
62 void filterSelected(ITmfFilter filter);
63
64 /**
65 * A filter has been removed.
66 *
67 * @param filter
68 * the removed filter
69 */
70 void filterRemoved(ITmfFilter filter);
71 }
72
73 private final IEventsTableHeaderListener fListener;
74 private final RowLayout fLayout;
75 private final Color fLabelBackground;
76 private boolean fCollapsed = false;
77
78 /**
79 * Constructor
80 *
81 * @param parent
82 * the parent composite
83 * @param style
84 * the style of widget to construct
85 * @param listener
86 * the listener to the header bar events
87 */
88 public TmfEventsTableHeader(Composite parent, int style, IEventsTableHeaderListener listener) {
89 super(parent, style);
90 fListener = listener;
91 fLayout = new RowLayout();
92 fLayout.marginTop = 0;
93 fLayout.marginBottom = 0;
94 fLayout.marginLeft = EXPANDED.getBounds().width;
95 setLayout(fLayout);
96 fLabelBackground = new Color(getDisplay(), LABEL_BACKGROUND);
97 getParent().addControlListener(new ControlAdapter() {
98 @Override
99 public void controlResized(ControlEvent e) {
100 getParent().layout();
101 }
102 });
103 addPaintListener(e -> {
104 if (fCollapsed) {
105 e.gc.drawImage(COLLAPSED, 0, 0);
106 } else {
107 e.gc.drawImage(EXPANDED, 0, 0);
108 }
109 });
110 addMouseListener(new MouseAdapter() {
111 @Override
112 public void mouseDown(MouseEvent e) {
113 toggle();
114 }
115 });
116 }
117
118 @Override
119 public void dispose() {
120 super.dispose();
121 fLabelBackground.dispose();
122 }
123
124 @Override
125 public Point computeSize(int wHint, int hHint, boolean changed) {
126 int height = fCollapsed && getChildren().length > 0 ? EXPANDED.getBounds().height : hHint;
127 return super.computeSize(getParent().getSize().x, height, changed);
128 }
129
130 /**
131 * Add a filter to the header.
132 *
133 * @param filter
134 * the filter to add
135 */
136 public void addFilter(ITmfFilter filter) {
137 if (filter instanceof TmfFilterRootNode) {
138 TmfFilterRootNode parentFilter = (TmfFilterRootNode) filter;
139 for (ITmfFilterTreeNode childFilter : parentFilter.getChildren()) {
140 addNewFilter(childFilter);
141 }
142 } else {
143 addNewFilter(filter);
144 }
145 fLayout.marginTop = 1;
146 fLayout.marginBottom = 1;
147 getParent().layout(true, true);
148 }
149
150 /**
151 * Remove a filter from the header.
152 *
153 * @param filter
154 * the filter to remove
155 */
156 public void removeFilter(ITmfFilter filter) {
157 for (Control control : getChildren()) {
158 if (filter.equals(control.getData())) {
159 control.dispose();
160 break;
161 }
162 }
163 if (getChildren().length == 0) {
164 fLayout.marginTop = 0;
165 fLayout.marginBottom = 0;
166 }
167 getParent().layout(true, true);
168 }
169
170 /**
171 * Clear all filters in the header.
172 */
173 public void clearFilters() {
174 for (Control control : getChildren()) {
175 control.dispose();
176 }
177 fLayout.marginTop = 0;
178 fLayout.marginBottom = 0;
179 getParent().layout(true, true);
180 }
181
182 private void addNewFilter(ITmfFilter filter) {
183 CLabel label = new CLabel(this, SWT.SHADOW_OUT);
184 label.setBackground(fLabelBackground);
185 String text;
186 if (filter instanceof TmfFilterNode) {
187 text = ((TmfFilterNode) filter).getFilterName();
188 label.setData(TOOLTIP_KEY, filter.toString());
189 } else {
190 text = filter.toString();
191 }
192 if (fCollapsed) {
193 label.setToolTipText(text);
194 label.setTopMargin(0);
195 label.setBottomMargin(0);
196 label.setRightMargin(COLLAPSED_RIGHT_MARGIN);
197 } else {
198 label.setImage(DELETE);
199 label.setText(text);
200 label.setToolTipText((String) label.getData(TOOLTIP_KEY));
201 }
202 label.setData(filter);
203 label.addMouseListener(new MouseAdapter() {
204 @Override
205 public void mouseDown(MouseEvent e) {
206 Rectangle bounds;
207 if (fCollapsed) {
208 bounds = new Rectangle(0, 0, 2 * COLLAPSED_IMAGE_MARGIN + DELETE_SMALL.getBounds().width, label.getBounds().height);
209 } else {
210 bounds = DELETE.getBounds();
211 bounds.x += label.getLeftMargin();
212 bounds.y = (label.getSize().y - bounds.height) / 2;
213 }
214 if (bounds.contains(e.x, e.y)) {
215 fListener.filterRemoved((ITmfFilter) label.getData());
216 } else {
217 fListener.filterSelected((ITmfFilter) label.getData());
218 getParent().layout(true, true);
219 }
220 }
221 });
222 label.addPaintListener(e -> {
223 if (fCollapsed) {
224 e.gc.drawImage(DELETE_SMALL, COLLAPSED_IMAGE_MARGIN, COLLAPSED_IMAGE_MARGIN);
225 }
226 });
227 }
228
229 private void toggle() {
230 fCollapsed = !fCollapsed;
231 for (Control child : getChildren()) {
232 if (child instanceof CLabel) {
233 CLabel label = (CLabel) child;
234 if (fCollapsed) {
235 label.setImage(null);
236 label.setToolTipText(label.getText());
237 label.setText(null);
238 label.setMargins(DEFAULT_MARGIN, 0, COLLAPSED_RIGHT_MARGIN, 0);
239 } else {
240 label.setImage(DELETE);
241 label.setText(label.getToolTipText());
242 label.setToolTipText((String) label.getData(TOOLTIP_KEY));
243 label.setMargins(DEFAULT_MARGIN, DEFAULT_MARGIN, DEFAULT_MARGIN, DEFAULT_MARGIN);
244 }
245 }
246 }
247 getParent().layout();
248 }
249 }
This page took 0.03985 seconds and 5 git commands to generate.