1 /*******************************************************************************
2 * Copyright (c) 2009 Ericsson
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
10 * Francois Chouinard - Initial API and implementation
11 *******************************************************************************/
13 package org
.eclipse
.linuxtools
.lttng
.ui
.views
.histogram
;
15 import org
.eclipse
.swt
.SWT
;
16 import org
.eclipse
.swt
.events
.FocusEvent
;
17 import org
.eclipse
.swt
.events
.FocusListener
;
18 import org
.eclipse
.swt
.events
.KeyEvent
;
19 import org
.eclipse
.swt
.events
.KeyListener
;
20 import org
.eclipse
.swt
.graphics
.Font
;
21 import org
.eclipse
.swt
.graphics
.FontData
;
22 import org
.eclipse
.swt
.layout
.GridData
;
23 import org
.eclipse
.swt
.layout
.GridLayout
;
24 import org
.eclipse
.swt
.widgets
.Composite
;
25 import org
.eclipse
.swt
.widgets
.Display
;
26 import org
.eclipse
.swt
.widgets
.Group
;
27 import org
.eclipse
.swt
.widgets
.Label
;
28 import org
.eclipse
.swt
.widgets
.Text
;
31 * <b><u>TimeTextGroup</u></b>
33 * Special control for HistogramView
35 * This control will give you a group, a text box and a label at once.
37 public class TimeTextGroup
implements FocusListener
, KeyListener
{
40 // 2010-06-10 Yuriy: Has been moved to header into HistogramView.java
41 protected static final String NANOSEC_LABEL = "sec";
43 private static final String LONGEST_STRING_VALUE
= "." + Long
.MAX_VALUE
;
44 private static final int MAX_CHAR_IN_TEXTBOX
= LONGEST_STRING_VALUE
.length();
46 // The "small font" height used to display time will be "default font" minus this constant
47 private static final int VERY_SMALL_FONT_MODIFIER
= 2;
48 private static final int SMALL_FONT_MODIFIER
= 1;
51 // private static final int DEFAULT_INDENT_SIZE = 10;
53 private HistogramView parentView
= null;
54 private AsyncTimeTextGroupRedrawer asyncRedrawer
= null;
56 private Group grpName
= null;
57 private Text txtNanosec
= null;
58 private Label lblNanosec
= null;
60 private long timeValue
= 0L;
63 * Default Constructor.<p>
65 * @param newParentView Parent HistogramView
66 * @param parent Parent Composite, used to position the inner controls.
67 * @param textStyle Style of the textbox. Usually SWT.BORDER or SWT.NONE (or anything that suit a Text)
68 * @param groupStyle Style of the group. Anything that suite a Text
70 public TimeTextGroup(HistogramView newParentView
, Composite parent
, int textStyle
, int groupStyle
) {
71 this(newParentView
, parent
, textStyle
, groupStyle
, "", HistogramConstant
.formatNanoSecondsTime(0L), false);
75 * Default Constructor with adjustement for small screen.<p>
77 * @param newParentView Parent HistogramView
78 * @param parent Parent Composite, used to position the inner controls.
79 * @param textStyle Style of the textbox. Usually SWT.BORDER or SWT.NONE (or anything that suit a Text)
80 * @param groupStyle Style of the group. Anything that suite a Text
81 * @param isSpaceSaverNeeded Value that tell if we try to save some space in the control.
83 public TimeTextGroup(HistogramView newParentView
, Composite parent
, int textStyle
, int groupStyle
, boolean isSpaceSaverNeeded
) {
84 this(newParentView
, parent
, textStyle
, groupStyle
, "", HistogramConstant
.formatNanoSecondsTime(0L), isSpaceSaverNeeded
);
88 * Default Constructor, allow you to give the groupname and the textbox value.<p>
90 * @param newParentView Parent HistogramView
91 * @param parent Parent Composite, used to position the inner controls.
92 * @param textStyle Style of the textbox. Usually SWT.BORDER or SWT.NONE (or anything that suit a Text)
93 * @param groupStyle Style of the group. Anything that suite a Text
94 * @param groupValue Value (label) of the group.
95 * @param textValue Value of the textbox.
97 public TimeTextGroup(HistogramView newParentView
, Composite parent
, int textStyle
, int groupStyle
, String groupValue
, String textValue
) {
98 this(newParentView
, parent
, textStyle
, groupStyle
, groupValue
, textValue
, false);
102 * Default Constructor with adjustment for small screen, allow you to give the group name and the text box value.<p>
104 * @param newParentView Parent HistogramView
105 * @param parent Parent Composite, used to position the inner controls.
106 * @param textStyle Style of the text box. Usually SWT.BORDER or SWT.NONE (or anything that suit a Text)
107 * @param groupStyle Style of the group. Anything that suite a Text
108 * @param groupValue Value (label) of the group.
109 * @param textValue Value of the text box.
110 * @param isSpaceSaverNeeded Value that tell if we try to save some space in the control.
112 public TimeTextGroup(HistogramView newParentView
, Composite parent
, int textStyle
, int groupStyle
, String groupValue
, String textValue
, boolean isSpaceSaverNeeded
) {
113 Font font
= parent
.getFont();
114 FontData tmpFontData
= font
.getFontData()[0];
116 Font smallFont
= null;
117 int textBoxSize
= -1;
118 // int indentSize = -1;
120 // If we were asked to save size, calculate the correct value here
121 if ( isSpaceSaverNeeded
== true ) {
122 smallFont
= new Font(font
.getDevice(), tmpFontData
.getName(), tmpFontData
.getHeight()-VERY_SMALL_FONT_MODIFIER
, tmpFontData
.getStyle());
124 // No minimum textBoxSize and no indent size
129 // We use only a slightly smaller font
130 smallFont
= new Font(font
.getDevice(), tmpFontData
.getName(), tmpFontData
.getHeight()-SMALL_FONT_MODIFIER
, tmpFontData
.getStyle());
132 // ** Creation of the textbox
133 // Calculate the optimal size of the textbox already
134 // This will avoid the control to move around and resize when bigger value are given
135 textBoxSize
= HistogramConstant
.getTextSizeInControl(parent
, LONGEST_STRING_VALUE
);
138 // indentSize = DEFAULT_INDENT_SIZE;
141 parentView
= newParentView
;
143 // ** Creation of the group
144 // GridLayout gridLayoutgroup = new GridLayout(2, false);
145 GridLayout gridLayoutgroup
= new GridLayout(1, false);
146 gridLayoutgroup
.horizontalSpacing
= 0;
147 gridLayoutgroup
.verticalSpacing
= 0;
148 grpName
= new Group(parent
, groupStyle
);
149 grpName
.setText(groupValue
);
150 grpName
.setFont(smallFont
);
151 grpName
.setLayout(gridLayoutgroup
);
153 txtNanosec
= new Text(grpName
, textStyle
);
154 txtNanosec
.setTextLimit( MAX_CHAR_IN_TEXTBOX
);
155 txtNanosec
.setText(textValue
);
156 txtNanosec
.setFont(smallFont
);
157 GridData gridDataTextBox
= new GridData(SWT
.LEFT
, SWT
.CENTER
, true, false);
158 gridDataTextBox
.horizontalIndent
= 0; // indentSize;
159 gridDataTextBox
.verticalIndent
= 0;
160 gridDataTextBox
.minimumWidth
= textBoxSize
;
161 txtNanosec
.setLayoutData(gridDataTextBox
);
163 // ** Creation of the label
165 lblNanosec = new Label(grpName, SWT.LEFT);
166 lblNanosec.setText(NANOSEC_LABEL);
167 lblNanosec.setFont(smallFont);
168 GridData gridDataLabel = new GridData(SWT.LEFT, SWT.CENTER, false, false);
169 gridDataLabel.horizontalIndent = indentSize;
170 gridDataLabel.verticalIndent = 0;
171 lblNanosec.setLayoutData(gridDataLabel);
175 addNeededListeners();
179 * Create and add all listeners needed by our control.<p>
181 protected void addNeededListeners() {
183 // AsyncCanvasRedrawer is an internal class
184 // This is used to redraw the canvas without danger from a different thread
185 asyncRedrawer
= new AsyncTimeTextGroupRedrawer(this);
187 txtNanosec
.addFocusListener(this);
188 txtNanosec
.addKeyListener(this);
192 * Getter for the layout data currently in use.<p>
196 public Object
getLayoutData() {
197 return grpName
.getLayoutData();
201 * Set a new layoutData for our control.<p>
203 * @param layoutData the new layout data
205 public void setLayoutData(Object layoutData
) {
206 grpName
.setLayoutData(layoutData
);
210 * Get the control's parent.<p>
212 * @return Currently used parent
214 public Composite
getParent() {
215 return grpName
.getParent();
219 * Set a new parent for the control.<p>
221 * @return Currently used parent
223 public void setParent(Composite newParent
) {
224 grpName
.setParent(newParent
);
225 txtNanosec
.setParent(newParent
);
226 lblNanosec
.setParent(newParent
);
230 public boolean isDisposed() {
231 return grpName
.isDisposed();
235 * Getter for the time value of the control.<p>
237 * @return The nanoseconds time value
239 public long getValue() {
244 * Set a new String value to the control.<p>
245 * Note : The String value will be converted in long before being applied;
246 * if any conversion error occur, 0 will be used. <p>
248 * @param newTimeAsString The value to convert and set.
250 public void setValue(String newTimeAsString
) {
251 long timeAsLong
= HistogramConstant
.convertStringToNanoseconds(newTimeAsString
);
252 setValue( timeAsLong
);
256 * Set a new value to the control.<p>
257 * Note : The value will be formatted as nanosecond value,
258 * missing zero will be added if needed.<p>
260 * @param newTime The value to set.
262 public void setValue(long newTime
) {
264 txtNanosec
.setText( HistogramConstant
.formatNanoSecondsTime(newTime
) );
268 * Set a new String value, asynchronously.<p>
269 * This will call setValue(String) in async.Exec to avoid Thread Access problem to UI.<p>
271 * @param newTimeAsString The value to convert and set.
273 public void setValueAsynchronously(String newTimeAsString
) {
274 long timeAsLong
= HistogramConstant
.convertStringToNanoseconds(newTimeAsString
);
275 setValueAsynchronously( timeAsLong
);
279 * Set a new String value, asynchronously.<p>
280 * This will call setValue(long) in async.Exec to avoid Thread Access problem to UI.<p>
282 * @param newTimeAsString The value to set.
284 public void setValueAsynchronously(long newTime
) {
285 // Set the correct value ASAP
288 // Create a new redrawer in case it doesn't exist yet (we never know with thread!)
289 if ( asyncRedrawer
== null ) {
290 asyncRedrawer
= new AsyncTimeTextGroupRedrawer(this);
293 asyncRedrawer
.asynchronousSetValue(newTime
);
297 * Set a new group name (label) for this control.<p>
299 * @param newName The new name to set.
301 public void setGroupName(String newName
) {
302 grpName
.setText(newName
);
306 * Set a new group name (label) for this control, asynchronously.<p>
307 * This will call setValue(long) in async.Exec to avoid Thread Access problem to UI.<p>
309 * @param newName The new name to set.
311 public void setGroupNameAsynchronously(String newGroupName
) {
312 // Create a new redrawer in case it doesn't exist yet (we never know with thread!)
313 if ( asyncRedrawer
== null ) {
314 asyncRedrawer
= new AsyncTimeTextGroupRedrawer(this);
317 asyncRedrawer
.asynchronousSetGroupName(newGroupName
);
322 * Method to call the "Asynchronous redrawer" for this time text group<p>
323 * This allow safe redraw from different threads.
325 public void redrawAsynchronously() {
326 // Create a new redrawer in case it doesn't exist yet (we never know with thread!)
327 if ( asyncRedrawer
== null ) {
328 asyncRedrawer
= new AsyncTimeTextGroupRedrawer(this);
331 asyncRedrawer
.asynchronousRedraw();
337 public void redraw () {
344 * This function is called when an user enter a new string in the control by hand.<p>
345 * It will ensure the format of the String is valid.
347 protected void handleNewStringValue() {
348 String valueInText
= txtNanosec
.getText();
349 long valueAsLong
= HistogramConstant
.convertStringToNanoseconds(valueInText
);
351 if ( getValue() != valueAsLong
) {
352 setValue(valueAsLong
);
353 // Notify our parent that the control was updated
354 notifyParentUpdatedTextGroupValue();
359 * This function notify our parent HistogramView that our value changed.
361 public void notifyParentUpdatedTextGroupValue() {
362 parentView
.timeTextGroupChangeNotification();
366 * Function that is called when the canvas get focus.<p>
368 * Doesn't do anything yet...
370 * @param event The focus event generated.
373 public void focusGained(FocusEvent event
) {
378 * Function that is called when the canvas loose focus.<p>
379 * It will validate that the String entered by the user (if any) is valid.<p>
381 * @param event The focus event generated.
384 public void focusLost(FocusEvent event
) {
385 handleNewStringValue();
389 * Function that is called when a key is pressed.<p>
391 * - Enter (CR) : Validate the entered String.<p>
393 * @param event The KeyEvent generated when the key was pressed.
396 public void keyPressed(KeyEvent event
) {
397 switch (event
.keyCode
) {
398 // SWT.CR is "ENTER" Key
400 handleNewStringValue();
408 * Function that is called when a key is released.<p>
412 * @param event The KeyEvent generated when the key was pressed.
415 public void keyReleased(KeyEvent e
) {
421 * <b><u>AsyncTimeTextGroupRedrawer Inner Class</u></b>
423 * Asynchronous redrawer for the TimeTextGroup
425 * This class role is to call method that update the UI on asynchronously.
426 * This should prevent any "invalid thread access" exception when trying to update UI from a different thread.
428 class AsyncTimeTextGroupRedrawer
{
430 private TimeTextGroup parentTimeTextGroup
= null;
433 * AsyncTimeTextGroupRedrawer constructor.
435 * @param newParent Related time text group.
437 public AsyncTimeTextGroupRedrawer(TimeTextGroup newParent
) {
438 parentTimeTextGroup
= newParent
;
442 * Asynchronous SetValue for time text group.
444 * Basically, it just run "getParent().setValue(time)" in asyncExec.
446 * @param newTime The new time to set
448 public void asynchronousSetValue(final long newTime
) {
449 // Ignore setting of value if widget is disposed
450 if (parentTimeTextGroup
.isDisposed()) return;
452 Display display
= parentTimeTextGroup
.getParent().getDisplay();
453 display
.asyncExec(new Runnable() {
456 if (!parentTimeTextGroup
.isDisposed()) {
457 parentTimeTextGroup
.setValue(newTime
);
464 * Asynchronous SetGroupName for time text group.
466 * Basically, it just run "getParent().setGroupName(name)" in asyncExec.
468 * @param newGroupName The new group name to set
470 public void asynchronousSetGroupName(String newGroupName
) {
471 // Ignore setting of name if widget is disposed
472 if (parentTimeTextGroup
.isDisposed()) return;
474 final String tmpName
= newGroupName
;
475 Display display
= parentTimeTextGroup
.getParent().getDisplay();
476 display
.asyncExec(new Runnable() {
479 if (!parentTimeTextGroup
.isDisposed()) {
480 parentTimeTextGroup
.setGroupName(tmpName
);
487 * Function to redraw the related time text group asynchonously.<p>
489 * Basically, it just run "getParent().redraw()" in asyncExec.
492 public void asynchronousRedraw() {
493 // Ignore redraw if widget is disposed
494 if (parentTimeTextGroup
.isDisposed()) return;
496 Display display
= parentTimeTextGroup
.getParent().getDisplay();
497 display
.asyncExec(new Runnable() {
500 if (!parentTimeTextGroup
.isDisposed()) {
501 parentTimeTextGroup
.getParent().redraw();