Source code: org/eclipse/swt/widgets/ToolBar.java
1 /*******************************************************************************
2 * Copyright (c) 2000, 2004 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
7 *
8 * Contributors:
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.swt.widgets;
12
13
14 import org.eclipse.swt.*;
15 import org.eclipse.swt.internal.*;
16 import org.eclipse.swt.internal.gtk.*;
17 import org.eclipse.swt.graphics.*;
18
19 /**
20 * Instances of this class support the layout of selectable
21 * tool bar items.
22 * <p>
23 * The item children that may be added to instances of this class
24 * must be of type <code>ToolItem</code>.
25 * </p><p>
26 * Note that although this class is a subclass of <code>Composite</code>,
27 * it does not make sense to add <code>Control</code> children to it,
28 * or set a layout on it.
29 * </p><p>
30 * <dl>
31 * <dt><b>Styles:</b></dt>
32 * <dd>FLAT, WRAP, RIGHT, HORIZONTAL, VERTICAL, SHADOW_OUT</dd>
33 * <dt><b>Events:</b></dt>
34 * <dd>(none)</dd>
35 * </dl>
36 * <p>
37 * Note: Only one of the styles HORIZONTAL and VERTICAL may be specified.
38 * </p><p>
39 * IMPORTANT: This class is <em>not</em> intended to be subclassed.
40 * </p>
41 */
42 public class ToolBar extends Composite {
43 ToolItem lastFocus;
44
45 /**
46 * Constructs a new instance of this class given its parent
47 * and a style value describing its behavior and appearance.
48 * <p>
49 * The style value is either one of the style constants defined in
50 * class <code>SWT</code> which is applicable to instances of this
51 * class, or must be built by <em>bitwise OR</em>'ing together
52 * (that is, using the <code>int</code> "|" operator) two or more
53 * of those <code>SWT</code> style constants. The class description
54 * lists the style constants that are applicable to the class.
55 * Style bits are also inherited from superclasses.
56 * </p>
57 *
58 * @param parent a composite control which will be the parent of the new instance (cannot be null)
59 * @param style the style of control to construct
60 *
61 * @exception IllegalArgumentException <ul>
62 * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
63 * </ul>
64 * @exception SWTException <ul>
65 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
66 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
67 * </ul>
68 *
69 * @see SWT#FLAT
70 * @see SWT#WRAP
71 * @see SWT#RIGHT
72 * @see SWT#HORIZONTAL
73 * @see SWT#SHADOW_OUT
74 * @see SWT#VERTICAL
75 * @see Widget#checkSubclass()
76 * @see Widget#getStyle()
77 */
78 public ToolBar (Composite parent, int style) {
79 super (parent, checkStyle (style));
80 /*
81 * Ensure that either of HORIZONTAL or VERTICAL is set.
82 * NOTE: HORIZONTAL and VERTICAL have the same values
83 * as H_SCROLL and V_SCROLL so it is necessary to first
84 * clear these bits to avoid scroll bars and then reset
85 * the bits using the original style supplied by the
86 * programmer.
87 */
88 if ((style & SWT.VERTICAL) != 0) {
89 this.style |= SWT.VERTICAL;
90 } else {
91 this.style |= SWT.HORIZONTAL;
92 }
93 int orientation = (style & SWT.VERTICAL) != 0 ? OS.GTK_ORIENTATION_VERTICAL : OS.GTK_ORIENTATION_HORIZONTAL;
94 OS.gtk_toolbar_set_orientation (handle, orientation);
95 }
96
97 Control [] _getChildren () {
98 Control [] children = super._getChildren ();
99 int count = 0;
100 ToolItem [] items = getItems ();
101 for (int i=0; i<items.length; i++) {
102 ToolItem item = items [i];
103 if (item != null && item.control != null) count++;
104 }
105 if (count == 0) return children;
106 Control [] newChildren = new Control [children.length + count];
107 System.arraycopy (children, 0, newChildren, 0, children.length);
108 int index = children.length;
109 for (int i=0; i<items.length; i++) {
110 ToolItem item = items [i];
111 if (item != null && item.control != null) newChildren [index++] = item.control;
112 }
113 return newChildren;
114 }
115
116 static int checkStyle (int style) {
117 /*
118 * Feature in GTK. It is not possible to create
119 * a toolbar that wraps. Therefore, no matter what
120 * style bits are specified, clear the WRAP bits so
121 * that the style matches the behavior.
122 */
123 if ((style & SWT.WRAP) != 0) style &= ~SWT.WRAP;
124 /*
125 * Even though it is legal to create this widget
126 * with scroll bars, they serve no useful purpose
127 * because they do not automatically scroll the
128 * widget's client area. The fix is to clear
129 * the SWT style.
130 */
131 return style & ~(SWT.H_SCROLL | SWT.V_SCROLL);
132 }
133
134 void createHandle (int index) {
135 state |= HANDLE;
136 fixedHandle = OS.gtk_fixed_new ();
137 if (fixedHandle == 0) error (SWT.ERROR_NO_HANDLES);
138 OS.gtk_fixed_set_has_window (fixedHandle, true);
139 handle = OS.gtk_toolbar_new ();
140 if (handle == 0) error (SWT.ERROR_NO_HANDLES);
141 long /*int*/ parentHandle = parent.parentingHandle ();
142 OS.gtk_container_add (parentHandle, fixedHandle);
143 OS.gtk_container_add (fixedHandle, handle);
144 OS.gtk_widget_show (fixedHandle);
145 OS.gtk_widget_show (handle);
146 if ((style & SWT.FLAT) != 0) {
147 byte [] swt_toolbar_flat = Converter.wcsToMbcs (null, "swt-toolbar-flat", true);
148 OS.gtk_widget_set_name (handle, swt_toolbar_flat);
149 }
150 }
151
152 public Point computeSize (int wHint, int hHint, boolean changed) {
153 checkWidget ();
154 if (wHint != SWT.DEFAULT && wHint < 0) wHint = 0;
155 if (hHint != SWT.DEFAULT && hHint < 0) hHint = 0;
156 if (layout != null) super.computeSize(wHint, hHint, changed);
157 return computeNativeSize(handle, wHint, hHint, changed);
158 }
159
160 long /*int*/ eventHandle () {
161 return fixedHandle;
162 }
163
164 boolean forceFocus (long /*int*/ focusHandle) {
165 if (lastFocus != null && lastFocus.setFocus ()) return true;
166 ToolItem [] items = getItems ();
167 for (int i = 0; i < items.length; i++) {
168 ToolItem item = items [i];
169 if (item.setFocus ()) return true;
170 }
171 return super.forceFocus (focusHandle);
172 }
173
174 /**
175 * Returns the item at the given, zero-relative index in the
176 * receiver. Throws an exception if the index is out of range.
177 *
178 * @param index the index of the item to return
179 * @return the item at the given index
180 *
181 * @exception IllegalArgumentException <ul>
182 * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
183 * </ul>
184 * @exception SWTException <ul>
185 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
186 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
187 * </ul>
188 */
189 public ToolItem getItem (int index) {
190 checkWidget();
191 if (!(0 <= index && index < getItemCount())) error (SWT.ERROR_INVALID_RANGE);
192 return getItems()[index];
193 }
194
195 /**
196 * Returns the item at the given point in the receiver
197 * or null if no such item exists. The point is in the
198 * coordinate system of the receiver.
199 *
200 * @param point the point used to locate the item
201 * @return the item at the given point
202 *
203 * @exception IllegalArgumentException <ul>
204 * <li>ERROR_NULL_ARGUMENT - if the point is null</li>
205 * </ul>
206 * @exception SWTException <ul>
207 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
208 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
209 * </ul>
210 */
211 public ToolItem getItem (Point point) {
212 checkWidget();
213 if (point == null) error (SWT.ERROR_NULL_ARGUMENT);
214 ToolItem[] items = getItems();
215 for (int i=0; i<items.length; i++) {
216 if (items[i].getBounds().contains(point)) return items[i];
217 }
218 return null;
219 }
220
221 /**
222 * Returns the number of items contained in the receiver.
223 *
224 * @return the number of items
225 *
226 * @exception SWTException <ul>
227 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
228 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
229 * </ul>
230 */
231 public int getItemCount () {
232 checkWidget();
233 long /*int*/ list = OS.gtk_container_get_children (handle);
234 if (list == 0) return 0;
235 int itemCount = OS.g_list_length (list);
236 OS.g_list_free (list);
237 return itemCount;
238 }
239
240 /**
241 * Returns an array of <code>ToolItem</code>s which are the items
242 * in the receiver.
243 * <p>
244 * Note: This is not the actual structure used by the receiver
245 * to maintain its list of items, so modifying the array will
246 * not affect the receiver.
247 * </p>
248 *
249 * @return the items in the receiver
250 *
251 * @exception SWTException <ul>
252 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
253 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
254 * </ul>
255 */
256 public ToolItem [] getItems () {
257 checkWidget();
258 long /*int*/ list = OS.gtk_container_get_children (handle);
259 if (list == 0) return new ToolItem [0];
260 int count = OS.g_list_length (list);
261 ToolItem [] result = new ToolItem [count];
262 for (int i=0; i<count; i++) {
263 long /*int*/ data = OS.g_list_nth_data (list, i);
264 Widget widget = display.getWidget (data);
265 result [i] = (ToolItem) widget;
266 }
267 OS.g_list_free (list);
268 return result;
269 }
270
271 /**
272 * Returns the number of rows in the receiver. When
273 * the receiver has the <code>WRAP</code> style, the
274 * number of rows can be greater than one. Otherwise,
275 * the number of rows is always one.
276 *
277 * @return the number of items
278 *
279 * @exception SWTException <ul>
280 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
281 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
282 * </ul>
283 */
284 public int getRowCount () {
285 checkWidget();
286 /* On GTK, toolbars cannot wrap */
287 return 1;
288 }
289
290 long /*int*/ gtk_key_press_event (long /*int*/ widget, long /*int*/ eventPtr) {
291 if (!hasFocus ()) return 0;
292 long /*int*/ result = super.gtk_key_press_event (widget, eventPtr);
293 if (result != 0) return result;
294 ToolItem [] items = getItems ();
295 int length = items.length;
296 int index = 0;
297 while (index < length) {
298 if (items [index].hasFocus ()) break;
299 index++;
300 }
301 GdkEventKey gdkEvent = new GdkEventKey ();
302 OS.memmove (gdkEvent, eventPtr, GdkEventKey.sizeof);
303 boolean next = false;
304 switch (gdkEvent.keyval) {
305 case OS.GDK_Up:
306 case OS.GDK_Left: next = false; break;
307 case OS.GDK_Down: {
308 if (0 <= index && index < length) {
309 ToolItem item = items [index];
310 if ((item.style & SWT.DROP_DOWN) != 0) {
311 Event event = new Event ();
312 event.detail = SWT.ARROW;
313 long /*int*/ topHandle = item.topHandle ();
314 event.x = OS.GTK_WIDGET_X (topHandle);
315 event.y = OS.GTK_WIDGET_Y (topHandle) + OS.GTK_WIDGET_HEIGHT (topHandle);
316 item.postEvent (SWT.Selection, event);
317 return result;
318 }
319 }
320 //FALL THROUGH
321 }
322 case OS.GDK_Right: next = true; break;
323 default: return result;
324 }
325 int start = index, offset = next ? 1 : -1;
326 while ((index = (index + offset + length) % length) != start) {
327 ToolItem item = items [index];
328 if (item.setFocus ()) return result;
329 }
330 return result;
331 }
332
333 boolean hasFocus () {
334 ToolItem [] items = getItems ();
335 for (int i=0; i<items.length; i++) {
336 ToolItem item = items [i];
337 if (item.hasFocus ()) return true;
338 }
339 return super.hasFocus();
340 }
341
342 /**
343 * Searches the receiver's list starting at the first item
344 * (index 0) until an item is found that is equal to the
345 * argument, and returns the index of that item. If no item
346 * is found, returns -1.
347 *
348 * @param item the search item
349 * @return the index of the item
350 *
351 * @exception IllegalArgumentException <ul>
352 * <li>ERROR_NULL_ARGUMENT - if the tool item is null</li>
353 * <li>ERROR_INVALID_ARGUMENT - if the tool item has been disposed</li>
354 * </ul>
355 * @exception SWTException <ul>
356 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
357 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
358 * </ul>
359 */
360 public int indexOf (ToolItem item) {
361 checkWidget();
362 if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
363 // TEMPORARY CODE
364 ToolItem [] items = getItems ();
365 for (int i=0; i<items.length; i++) {
366 if (item == items[i]) return i;
367 }
368 return -1;
369 }
370
371 boolean mnemonicHit (char key) {
372 ToolItem [] items = getItems ();
373 for (int i=0; i<items.length; i++) {
374 long /*int*/ labelHandle = items [i].labelHandle;
375 if (labelHandle != 0 && mnemonicHit (labelHandle, key)) return true;
376 }
377 return false;
378 }
379
380 boolean mnemonicMatch (char key) {
381 ToolItem [] items = getItems ();
382 for (int i=0; i<items.length; i++) {
383 long /*int*/ labelHandle = items [i].labelHandle;
384 if (labelHandle != 0 && mnemonicMatch (labelHandle, key)) return true;
385 }
386 return false;
387 }
388
389 void releaseWidget () {
390 ToolItem [] items = getItems ();
391 for (int i=0; i<items.length; i++) {
392 ToolItem item = items [i];
393 if (!item.isDisposed ()) item.releaseResources ();
394 }
395 items = null;
396 super.releaseWidget ();
397 }
398
399 void removeControl (Control control) {
400 super.removeControl (control);
401 ToolItem [] items = getItems ();
402 for (int i=0; i<items.length; i++) {
403 ToolItem item = items [i];
404 if (item != null && item.control == control) {
405 item.setControl (null);
406 }
407 }
408 }
409
410 void setFontDescription (long /*int*/ font) {
411 super.setFontDescription (font);
412 ToolItem [] items = getItems ();
413 for (int i = 0; i < items.length; i++) {
414 if (items[i] != null) {
415 items[i].setFontDescription (font);
416 }
417 }
418 }
419
420 void setForegroundColor (GdkColor color) {
421 super.setForegroundColor (color);
422 ToolItem [] items = getItems ();
423 for (int i = 0; i < items.length; i++) {
424 if (items[i] != null) {
425 items[i].setForegroundColor (color);
426 }
427 }
428 }
429
430 public void setToolTipText (String string) {
431 checkWidget();
432 super.setToolTipText (string);
433 Shell shell = _getShell ();
434 ToolItem [] items = getItems ();
435 for (int i = 0; i < items.length; i++) {
436 shell.setToolTipText (items [i].handle, string != null ? null : items [i].toolTipText);
437 }
438 }
439
440 }