blob: fe5e34709695623aeed6ef22b87cce056efa560a [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2004 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.swt.widgets;
import org.eclipse.swt.*;
import org.eclipse.swt.internal.*;
import org.eclipse.swt.internal.gtk.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.events.*;
/**
* Instances of this class are selectable user interface
* objects that allow the user to enter and modify numeric
* values.
* <p>
* <dl>
* <dt><b>Styles:</b></dt>
* <dd>READ_ONLY</dd>
* <dt><b>Events:</b></dt>
* <dd>Selection, Modify</dd>
* </dl>
* <p>
* IMPORTANT: This class is <em>not</em> intended to be subclassed.
* </p>
*
* @since 3.1
*/
public class Spinner extends Composite {
static final int INNER_BORDER = 2;
static final int MIN_ARROW_WIDTH = 6;
int lastEventTime = 0;
int /*long*/ gdkEventKey = 0;
/**
* Constructs a new instance of this class given its parent
* and a style value describing its behavior and appearance.
* <p>
* The style value is either one of the style constants defined in
* class <code>SWT</code> which is applicable to instances of this
* class, or must be built by <em>bitwise OR</em>'ing together
* (that is, using the <code>int</code> "|" operator) two or more
* of those <code>SWT</code> style constants. The class description
* lists the style constants that are applicable to the class.
* Style bits are also inherited from superclasses.
* </p>
*
* @param parent a composite control which will be the parent of the new instance (cannot be null)
* @param style the style of control to construct
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
* </ul>
* @exception SWTException <ul>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
* <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
* </ul>
*
* @see SWT#READ_ONLY
* @see Widget#checkSubclass
* @see Widget#getStyle
*/
public Spinner (Composite parent, int style) {
super (parent, checkStyle (style));
}
/**
* Adds the listener to the collection of listeners who will
* be notified when the receiver's text is modified, by sending
* it one of the messages defined in the <code>ModifyListener</code>
* interface.
*
* @param listener the listener which should be notified
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
* </ul>
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*
* @see ModifyListener
* @see #removeModifyListener
*/
public void addModifyListener (ModifyListener listener) {
checkWidget ();
if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
TypedListener typedListener = new TypedListener (listener);
addListener (SWT.Modify, typedListener);
}
/**
* Adds the listener to the collection of listeners who will
* be notified when the control is selected, by sending
* it one of the messages defined in the <code>SelectionListener</code>
* interface.
* <p>
* <code>widgetSelected</code> is not called for texts.
* <code>widgetDefaultSelected</code> is typically called when ENTER is pressed in a single-line text.
* </p>
*
* @param listener the listener which should be notified
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
* </ul>
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*
* @see SelectionListener
* @see #removeSelectionListener
* @see SelectionEvent
*/
public void addSelectionListener(SelectionListener listener) {
checkWidget ();
if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
TypedListener typedListener = new TypedListener(listener);
addListener(SWT.Selection,typedListener);
addListener(SWT.DefaultSelection,typedListener);
}
/**
* Adds the listener to the collection of listeners who will
* be notified when the receiver's text is verified, by sending
* it one of the messages defined in the <code>VerifyListener</code>
* interface.
*
* @param listener the listener which should be notified
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
* </ul>
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*
* @see VerifyListener
* @see #removeVerifyListener
*/
void addVerifyListener (VerifyListener listener) {
checkWidget();
if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
TypedListener typedListener = new TypedListener (listener);
addListener (SWT.Verify, typedListener);
}
static int checkStyle (int style) {
/*
* Even though it is legal to create this widget
* with scroll bars, they serve no useful purpose
* because they do not automatically scroll the
* widget's client area. The fix is to clear
* the SWT style.
*/
return style & ~(SWT.H_SCROLL | SWT.V_SCROLL);
}
protected void checkSubclass () {
if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
}
public Point computeSize (int wHint, int hHint, boolean changed) {
checkWidget ();
if (wHint != SWT.DEFAULT && wHint < 0) wHint = 0;
if (hHint != SWT.DEFAULT && hHint < 0) hHint = 0;
int[] w = new int [1], h = new int [1];
int /*long*/ layout = OS.gtk_entry_get_layout (handle);
int /*long*/ hAdjustment = OS.gtk_spin_button_get_adjustment (handle);
GtkAdjustment adjustment = new GtkAdjustment ();
OS.memmove (adjustment, hAdjustment);
int digits = OS.gtk_spin_button_get_digits (handle);
for (int i = 0; i < digits; i++) adjustment.upper *= 10;
String string = String.valueOf ((int) adjustment.upper);
if (digits > 0) {
StringBuffer buffer = new StringBuffer ();
buffer.append (string);
buffer.append (getDecimalSeparator ());
int count = digits - string.length ();
while (count >= 0) {
buffer.append ("0");
count--;
}
string = buffer.toString ();
}
byte [] buffer1 = Converter.wcsToMbcs (null, string, false);
int /*long*/ ptr = OS.pango_layout_get_text (layout);
int length = OS.strlen (ptr);
byte [] buffer2 = new byte [length];
OS.memmove (buffer2, ptr, length);
OS.pango_layout_set_text (layout, buffer1, buffer1.length);
OS.pango_layout_get_size (layout, w, h);
OS.pango_layout_set_text (layout, buffer2, buffer2.length);
int width = OS.PANGO_PIXELS (w [0]);
int height = OS.PANGO_PIXELS (h [0]);
width = wHint == SWT.DEFAULT ? width : wHint;
height = hHint == SWT.DEFAULT ? height : hHint;
Rectangle trim = computeTrim (0, 0, width, height);
return new Point (trim.width, trim.height);
}
public Rectangle computeTrim (int x, int y, int width, int height) {
checkWidget ();
int xborder = 0, yborder = 0;
int /*long*/ style = OS.gtk_widget_get_style (handle);
if ((this.style & SWT.BORDER) != 0) {
xborder += OS.gtk_style_get_xthickness (style);
yborder += OS.gtk_style_get_ythickness (style);
}
xborder += INNER_BORDER;
yborder += INNER_BORDER;
int [] property = new int [1];
OS.gtk_widget_style_get (handle, OS.interior_focus, property, 0);
if (property [0] == 0) {
OS.gtk_widget_style_get (handle, OS.focus_line_width, property, 0);
xborder += property [0];
yborder += property [0];
}
int /*long*/ fontDesc = OS.gtk_style_get_font_desc (style);
int fontSize = OS.pango_font_description_get_size (fontDesc);
int arrowSize = Math.max (OS.PANGO_PIXELS (fontSize), MIN_ARROW_WIDTH);
arrowSize = arrowSize - arrowSize % 2;
Rectangle trim = super.computeTrim (x, y, width, height);
trim.x -= xborder;
trim.y -= yborder;
trim.width += 2 * xborder;
trim.height += 2 * yborder;
trim.width += arrowSize + (2 * OS.gtk_style_get_xthickness (style));
return new Rectangle (trim.x, trim.y, trim.width, trim.height);
}
/**
* Copies the selected text.
* <p>
* The current selection is copied to the clipboard.
* </p>
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*/
public void copy () {
checkWidget ();
OS.gtk_editable_copy_clipboard (handle);
}
void createHandle (int index) {
state |= HANDLE | MENU;
fixedHandle = OS.g_object_new (display.gtk_fixed_get_type (), 0);
if (fixedHandle == 0) error (SWT.ERROR_NO_HANDLES);
OS.gtk_fixed_set_has_window (fixedHandle, true);
int /*long*/ adjustment = OS.gtk_adjustment_new (0, 0, 100, 1, 10, 0);
if (adjustment == 0) error (SWT.ERROR_NO_HANDLES);
handle = OS.gtk_spin_button_new (adjustment, 1, 0);
if (handle == 0) error (SWT.ERROR_NO_HANDLES);
OS.gtk_container_add (fixedHandle, handle);
OS.gtk_editable_set_editable (handle, (style & SWT.READ_ONLY) == 0);
OS.gtk_entry_set_has_frame (handle, (style & SWT.BORDER) != 0);
OS.gtk_spin_button_set_wrap (handle, (style & SWT.WRAP) != 0);
}
/**
* Cuts the selected text.
* <p>
* The current selection is first copied to the
* clipboard and then deleted from the widget.
* </p>
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*/
public void cut () {
checkWidget ();
OS.gtk_editable_cut_clipboard (handle);
}
void deregister () {
super.deregister ();
int /*long*/ imContext = imContext ();
if (imContext != 0) display.removeWidget (imContext);
}
boolean filterKey (int keyval, int /*long*/ event) {
int time = OS.gdk_event_get_time (event);
if (time != lastEventTime) {
lastEventTime = time;
int /*long*/ imContext = imContext ();
if (imContext != 0) {
return OS.gtk_im_context_filter_keypress (imContext, event);
}
}
gdkEventKey = event;
return false;
}
void fixIM () {
/*
* The IM filter has to be called one time for each key press event.
* When the IM is open the key events are duplicated. The first event
* is filtered by SWT and the second event is filtered by GTK. In some
* cases the GTK handler does not run (the widget is destroyed, the
* application code consumes the event, etc), for these cases the IM
* filter has to be called by SWT.
*/
if (gdkEventKey != 0 && gdkEventKey != -1) {
int /*long*/ imContext = imContext ();
if (imContext != 0) {
OS.gtk_im_context_filter_keypress (imContext, gdkEventKey);
gdkEventKey = -1;
return;
}
}
gdkEventKey = 0;
}
GdkColor getBackgroundColor () {
return getBaseColor ();
}
public int getBorderWidth () {
checkWidget();
int /*long*/ style = OS.gtk_widget_get_style (handle);
if ((this.style & SWT.BORDER) != 0) {
return OS.gtk_style_get_xthickness (style);
}
return 0;
}
GdkColor getForegroundColor () {
return getTextColor ();
}
/**
* Returns the amount that the receiver's value will be
* modified by when the up/down arrows are pressed.
*
* @return the increment
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*/
public int getIncrement () {
checkWidget ();
int /*long*/ hAdjustment = OS.gtk_spin_button_get_adjustment (handle);
GtkAdjustment adjustment = new GtkAdjustment ();
OS.memmove (adjustment, hAdjustment);
int digits = OS.gtk_spin_button_get_digits (handle);
for (int i = 0; i < digits; i++) adjustment.step_increment *= 10;
return (int) adjustment.step_increment;
}
/**
* Returns the maximum value which the receiver will allow.
*
* @return the maximum
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*/
public int getMaximum () {
checkWidget ();
int /*long*/ hAdjustment = OS.gtk_spin_button_get_adjustment (handle);
GtkAdjustment adjustment = new GtkAdjustment ();
OS.memmove (adjustment, hAdjustment);
int digits = OS.gtk_spin_button_get_digits (handle);
for (int i = 0; i < digits; i++) adjustment.upper *= 10;
return (int) adjustment.upper;
}
/**
* Returns the minimum value which the receiver will allow.
*
* @return the minimum
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*/
public int getMinimum () {
checkWidget ();
int /*long*/ hAdjustment = OS.gtk_spin_button_get_adjustment (handle);
GtkAdjustment adjustment = new GtkAdjustment ();
OS.memmove (adjustment, hAdjustment);
int digits = OS.gtk_spin_button_get_digits (handle);
for (int i = 0; i < digits; i++) adjustment.lower *= 10;
return (int) adjustment.lower;
}
/**
* Returns the amount that the receiver's position will be
* modified by when the page up/down keys are pressed.
*
* @return the page increment
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*/
public int getPageIncrement () {
checkWidget ();
int /*long*/ hAdjustment = OS.gtk_spin_button_get_adjustment (handle);
GtkAdjustment adjustment = new GtkAdjustment ();
OS.memmove (adjustment, hAdjustment);
int digits = OS.gtk_spin_button_get_digits (handle);
for (int i = 0; i < digits; i++) adjustment.page_increment *= 10;
return (int) adjustment.page_increment;
}
/**
* Returns the <em>selection</em>, which is the receiver's position.
*
* @return the selection
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*/
public int getSelection () {
checkWidget ();
int /*long*/ hAdjustment = OS.gtk_spin_button_get_adjustment (handle);
GtkAdjustment adjustment = new GtkAdjustment ();
OS.memmove (adjustment, hAdjustment);
int digits = OS.gtk_spin_button_get_digits (handle);
for (int i = 0; i < digits; i++) adjustment.value *= 10;
return (int) adjustment.value;
}
public int getDigits () {
checkWidget ();
return OS.gtk_spin_button_get_digits (handle);
}
String getDecimalSeparator () {
int /*long*/ ptr = OS.localeconv_decimal_point ();
int length = OS.strlen (ptr);
byte [] buffer = new byte [length];
OS.memmove (buffer, ptr, length);
return new String (Converter.mbcsToWcs (null, buffer));
}
int gtk_activate (int widget) {
postEvent (SWT.DefaultSelection);
return 0;
}
int /*long*/ gtk_changed (int /*long*/ widget) {
sendEvent (SWT.Modify);
return 0;
}
int /*long*/ gtk_commit (int /*long*/ imContext, int /*long*/ text) {
if (text == 0) return 0;
if (!OS.gtk_editable_get_editable (handle)) return 0;
int length = OS.strlen (text);
if (length == 0) return 0;
byte [] buffer = new byte [length];
OS.memmove (buffer, text, length);
char [] chars = Converter.mbcsToWcs (null, buffer);
char [] newChars = sendIMKeyEvent (SWT.KeyDown, null, chars);
if (newChars == null) return 0;
OS.g_signal_handlers_block_matched (imContext, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, COMMIT);
int id = OS.g_signal_lookup (OS.commit, OS.gtk_im_context_get_type ());
int mask = OS.G_SIGNAL_MATCH_DATA | OS.G_SIGNAL_MATCH_ID;
OS.g_signal_handlers_unblock_matched (imContext, mask, id, 0, 0, 0, handle);
if (newChars == chars) {
OS.g_signal_emit_by_name (imContext, OS.commit, text);
} else {
buffer = Converter.wcsToMbcs (null, newChars, true);
OS.g_signal_emit_by_name (imContext, OS.commit, buffer);
}
OS.g_signal_handlers_unblock_matched (imContext, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, COMMIT);
OS.g_signal_handlers_block_matched (imContext, mask, id, 0, 0, 0, handle);
return 0;
}
int /*long*/ gtk_delete_text (int /*long*/ widget, int /*long*/ start_pos, int /*long*/ end_pos) {
if (!hooks (SWT.Verify) && !filters (SWT.Verify)) return 0;
String newText = verifyText ("", (int)/*64*/start_pos, (int)/*64*/end_pos);
if (newText == null) {
OS.g_signal_stop_emission_by_name (handle, OS.delete_text);
} else {
if (newText.length () > 0) {
int [] pos = new int [1];
pos [0] = (int)/*64*/end_pos;
byte [] buffer = Converter.wcsToMbcs (null, newText, false);
OS.g_signal_handlers_block_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
OS.g_signal_handlers_block_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, INSERT_TEXT);
OS.gtk_editable_insert_text (handle, buffer, buffer.length, pos);
OS.g_signal_handlers_unblock_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, INSERT_TEXT);
OS.g_signal_handlers_unblock_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
OS.gtk_editable_set_position (handle, pos [0]);
}
}
return 0;
}
int /*long*/ gtk_event_after (int /*long*/ widget, int /*long*/ gdkEvent) {
if (cursor != null) setCursor (cursor.handle);
return super.gtk_event_after (widget, gdkEvent);
}
int /*long*/ gtk_focus_out_event (int /*long*/ widget, int /*long*/ event) {
fixIM ();
return super.gtk_focus_out_event (widget, event);
}
int /*long*/ gtk_insert_text (int /*long*/ widget, int /*long*/ new_text, int /*long*/ new_text_length, int /*long*/ position) {
// if (!hooks (SWT.Verify) && !filters (SWT.Verify)) return 0;
if (new_text == 0 || new_text_length == 0) return 0;
byte [] buffer = new byte [(int)/*64*/new_text_length];
OS.memmove (buffer, new_text, buffer.length);
String oldText = new String (Converter.mbcsToWcs (null, buffer));
int [] pos = new int [1];
OS.memmove (pos, position, 4);
if (pos [0] == -1) {
int /*long*/ ptr = OS.gtk_entry_get_text (handle);
pos [0] = (int)/*64*/OS.g_utf8_strlen (ptr, -1);
}
int [] oldStart = new int [1], oldEnd = new int [1];
OS.gtk_editable_get_selection_bounds (handle, oldStart, oldEnd);
String newText = verifyText (oldText, pos [0], pos [0]);
final int [] newStart = new int [1], newEnd = new int [1];
OS.gtk_editable_get_selection_bounds (handle, newStart, newEnd);
boolean newSelection = oldStart [0] != newStart [0] || oldEnd [0] != newEnd [0];
if (newSelection) {
if (newText == null) newText = "";
pos [0] = newEnd [0];
}
if (newText == null) {
OS.g_signal_stop_emission_by_name (handle, OS.insert_text);
} else {
if (newText != oldText || newSelection) {
byte [] buffer2 = Converter.wcsToMbcs (null, newText, false);
OS.g_signal_handlers_block_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, INSERT_TEXT);
if (newSelection) {
OS.g_signal_handlers_block_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
OS.gtk_editable_delete_selection (handle);
OS.g_signal_handlers_unblock_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
}
OS.gtk_editable_insert_text (handle, buffer2, buffer2.length, pos);
OS.g_signal_handlers_unblock_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, INSERT_TEXT);
OS.g_signal_stop_emission_by_name (handle, OS.insert_text);
OS.memmove (position, pos, 4);
}
}
return 0;
}
int /*long*/ gtk_key_press_event (int /*long*/ widget, int /*long*/ event) {
int /*long*/ result = super.gtk_key_press_event (widget, event);
if (result != 0) fixIM ();
if (gdkEventKey == -1) result = 1;
gdkEventKey = 0;
return result;
}
int /*long*/ gtk_popup_menu (int /*long*/ widget) {
int [] x = new int [1], y = new int [1];
OS.gdk_window_get_pointer (0, x, y, null);
return showMenu (x [0], y [0]) ? 1 : 0;
}
int /*long*/ gtk_value_changed (int /*long*/ widget) {
postEvent (SWT.Selection);
return 0;
}
void hookEvents () {
super.hookEvents();
int /*long*/ windowProc2 = display.windowProc2;
int /*long*/ windowProc3 = display.windowProc3;
int /*long*/ windowProc4 = display.windowProc4;
int /*long*/ windowProc5 = display.windowProc5;
OS.g_signal_connect_after (handle, OS.changed, windowProc2, CHANGED);
OS.g_signal_connect (handle, OS.insert_text, windowProc5, INSERT_TEXT);
OS.g_signal_connect (handle, OS.delete_text, windowProc4, DELETE_TEXT);
OS.g_signal_connect (handle, OS.value_changed, windowProc2, VALUE_CHANGED);
OS.g_signal_connect (handle, OS.activate, windowProc2, ACTIVATE);
int /*long*/ imContext = imContext ();
if (imContext != 0) {
OS.g_signal_connect (imContext, OS.commit, windowProc3, COMMIT);
int id = OS.g_signal_lookup (OS.commit, OS.gtk_im_context_get_type ());
int mask = OS.G_SIGNAL_MATCH_DATA | OS.G_SIGNAL_MATCH_ID;
OS.g_signal_handlers_block_matched (imContext, mask, id, 0, 0, 0, handle);
}
}
int /*long*/ imContext () {
return OS.GTK_ENTRY_IM_CONTEXT (handle);
}
int /*long*/ paintWindow () {
int /*long*/ window = super.paintWindow ();
int /*long*/ children = OS.gdk_window_get_children (window);
if (children != 0) window = OS.g_list_data (children);
OS.g_list_free (children);
return window;
}
/**
* Pastes text from clipboard.
* <p>
* The selected text is deleted from the widget
* and new text inserted from the clipboard.
* </p>
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*/
public void paste () {
checkWidget ();
OS.gtk_editable_paste_clipboard (handle);
}
void register () {
super.register ();
int /*long*/ imContext = imContext ();
if (imContext != 0) display.addWidget (imContext, this);
}
void releaseWidget () {
fixIM ();
super.releaseWidget ();
}
/**
* Removes the listener from the collection of listeners who will
* be notified when the receiver's text is modified.
*
* @param listener the listener which should no longer be notified
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
* </ul>
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*
* @see ModifyListener
* @see #addModifyListener
*/
public void removeModifyListener (ModifyListener listener) {
checkWidget ();
if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
if (eventTable == null) return;
eventTable.unhook (SWT.Modify, listener);
}
/**
* Removes the listener from the collection of listeners who will
* be notified when the control is selected.
*
* @param listener the listener which should no longer be notified
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
* </ul>
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*
* @see SelectionListener
* @see #addSelectionListener
*/
public void removeSelectionListener(SelectionListener listener) {
checkWidget ();
if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
if (eventTable == null) return;
eventTable.unhook(SWT.Selection, listener);
eventTable.unhook(SWT.DefaultSelection,listener);
}
/**
* Removes the listener from the collection of listeners who will
* be notified when the control is verified.
*
* @param listener the listener which should be notified
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
* </ul>
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*
* @see VerifyListener
* @see #addVerifyListener
*/
void removeVerifyListener (VerifyListener listener) {
checkWidget ();
if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
if (eventTable == null) return;
eventTable.unhook (SWT.Verify, listener);
}
void setBackgroundColor (GdkColor color) {
super.setBackgroundColor (color);
OS.gtk_widget_modify_base (handle, 0, color);
}
void setCursor (int /*long*/ cursor) {
int /*long*/ defaultCursor = 0;
if (cursor == 0) defaultCursor = OS.gdk_cursor_new (OS.GDK_XTERM);
super.setCursor (cursor != 0 ? cursor : defaultCursor);
if (cursor == 0) OS.gdk_cursor_destroy (defaultCursor);
}
void setFontDescription (int /*long*/ font) {
super.setFontDescription (font);
}
void setForegroundColor (GdkColor color) {
super.setForegroundColor (color);
OS.gtk_widget_modify_text (handle, 0, color);
}
/**
* Sets the amount that the receiver's value will be
* modified by when the up/down arrows are pressed to
* the argument, which must be at least one.
*
* @param value the new increment (must be greater than zero)
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*/
public void setIncrement (int value) {
checkWidget ();
if (value < 1) return;
int /*long*/ hAdjustment = OS.gtk_spin_button_get_adjustment (handle);
GtkAdjustment adjustment = new GtkAdjustment ();
OS.memmove (adjustment, hAdjustment);
double newValue = value;
int digits = OS.gtk_spin_button_get_digits (handle);
for (int i = 0; i < digits; i++) newValue /= 10;
OS.g_signal_handlers_block_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, VALUE_CHANGED);
OS.gtk_spin_button_set_increments (handle, newValue, adjustment.page_increment);
OS.g_signal_handlers_unblock_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, VALUE_CHANGED);
}
/**
* Sets the maximum value that the receiver will allow. This new
* value will be ignored if it is not greater than the receiver's current
* minimum value. If the new maximum is applied then the receiver's
* selection value will be adjusted if necessary to fall within its new range.
*
* @param value the new maximum, which must be greater than the current minimum
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*/
public void setMaximum (int value) {
checkWidget ();
if (value < 0) return;
int /*long*/ hAdjustment = OS.gtk_spin_button_get_adjustment (handle);
GtkAdjustment adjustment = new GtkAdjustment ();
OS.memmove (adjustment, hAdjustment);
double newValue = value;
int digits = OS.gtk_spin_button_get_digits (handle);
for (int i = 0; i < digits; i++) newValue /= 10;
if (newValue <= adjustment.lower) return;
OS.g_signal_handlers_block_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, VALUE_CHANGED);
OS.gtk_spin_button_set_range (handle, adjustment.lower, newValue);
OS.g_signal_handlers_unblock_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, VALUE_CHANGED);
}
/**
* Sets the minimum value that the receiver will allow. This new
* value will be ignored if it is negative or is not less than the receiver's
* current maximum value. If the new minimum is applied then the receiver's
* selection value will be adjusted if necessary to fall within its new range.
*
* @param value the new minimum, which must be nonnegative and less than the current maximum
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*/
public void setMinimum (int value) {
checkWidget ();
if (value < 0) return;
int /*long*/ hAdjustment = OS.gtk_spin_button_get_adjustment (handle);
GtkAdjustment adjustment = new GtkAdjustment ();
OS.memmove (adjustment, hAdjustment);
double newValue = value;
int digits = OS.gtk_spin_button_get_digits (handle);
for (int i = 0; i < digits; i++) newValue /= 10;
if (newValue >= adjustment.upper) return;
OS.g_signal_handlers_block_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, VALUE_CHANGED);
OS.gtk_spin_button_set_range (handle, newValue, adjustment.upper);
OS.g_signal_handlers_unblock_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, VALUE_CHANGED);
}
/**
* Sets the amount that the receiver's position will be
* modified by when the page up/down keys are pressed
* to the argument, which must be at least one.
*
* @param value the page increment (must be greater than zero)
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*/
public void setPageIncrement (int value) {
checkWidget ();
if (value < 1) return;
int /*long*/ hAdjustment = OS.gtk_spin_button_get_adjustment (handle);
GtkAdjustment adjustment = new GtkAdjustment ();
OS.memmove (adjustment, hAdjustment);
double newValue = value;
int digits = OS.gtk_spin_button_get_digits (handle);
for (int i = 0; i < digits; i++) newValue /= 10;
OS.g_signal_handlers_block_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, VALUE_CHANGED);
OS.gtk_spin_button_set_increments (handle, adjustment.step_increment, newValue);
OS.g_signal_handlers_unblock_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, VALUE_CHANGED);
}
/**
* Sets the <em>selection</em>, which is the receiver's
* position, to the argument. If the argument is not within
* the range specified by minimum and maximum, it will be
* adjusted to fall within this range.
*
* @param value the new selection (must be zero or greater)
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*/
public void setSelection (int value) {
checkWidget ();
double newValue = value;
int digits = OS.gtk_spin_button_get_digits (handle);
for (int i = 0; i < digits; i++) newValue /= 10;
OS.g_signal_handlers_block_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, VALUE_CHANGED);
OS.gtk_spin_button_set_value (handle, newValue);
OS.g_signal_handlers_unblock_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, VALUE_CHANGED);
}
public void setDigits (int value) {
checkWidget ();
if (value < 0) error (SWT.ERROR_INVALID_ARGUMENT);
int digits = OS.gtk_spin_button_get_digits (handle);
if (value == digits) return;
int /*long*/ hAdjustment = OS.gtk_spin_button_get_adjustment (handle);
GtkAdjustment adjustment = new GtkAdjustment ();
OS.memmove (adjustment, hAdjustment);
int diff = Math.abs (value - digits);
int factor = 1;
for (int i = 0; i < diff; i++) factor *= 10;
if (digits > value) {
adjustment.value *= factor;
adjustment.upper *= factor;
adjustment.lower *= factor;
adjustment.step_increment *= factor;
adjustment.page_increment *= factor;
} else {
adjustment.value /= factor;
adjustment.upper /= factor;
adjustment.lower /= factor;
adjustment.step_increment /= factor;
adjustment.page_increment /= factor;
}
OS.memmove (hAdjustment, adjustment);
OS.gtk_spin_button_set_digits (handle, value);
}
boolean translateTraversal (GdkEventKey keyEvent) {
int key = keyEvent.keyval;
switch (key) {
case OS.GDK_KP_Enter:
case OS.GDK_Return: {
int /*long*/ imContext = imContext ();
if (imContext != 0) {
int /*long*/ [] preeditString = new int /*long*/ [1];
OS.gtk_im_context_get_preedit_string (imContext, preeditString, null, null);
if (preeditString [0] != 0) {
int length = OS.strlen (preeditString [0]);
OS.g_free (preeditString [0]);
if (length != 0) return false;
}
}
}
}
return super.translateTraversal (keyEvent);
}
String verifyText (String string, int start, int end) {
if (string.length () == 0 && start == end) return null;
Event event = new Event ();
event.text = string;
event.start = start;
event.end = end;
int /*long*/ eventPtr = OS.gtk_get_current_event ();
if (eventPtr != 0) {
GdkEventKey gdkEvent = new GdkEventKey ();
OS.memmove (gdkEvent, eventPtr, GdkEventKey.sizeof);
switch (gdkEvent.type) {
case OS.GDK_KEY_PRESS:
setKeyState (event, gdkEvent);
break;
}
OS.gdk_event_free (eventPtr);
}
int index = 0;
if (OS.gtk_spin_button_get_digits (handle) > 0) {
String decimalSeparator = getDecimalSeparator ();
index = string.indexOf (decimalSeparator);
if (index != -1) {
string = string.substring (0, index) + string.substring (index + 1);
}
index = 0;
}
while (index < string.length ()) {
if (!Character.isDigit (string.charAt (index))) break;
index++;
}
event.doit = index == string.length ();
/*
* It is possible (but unlikely), that application
* code could have disposed the widget in the verify
* event. If this happens, answer null to cancel
* the operation.
*/
sendEvent (SWT.Verify, event);
if (!event.doit || isDisposed ()) return null;
return event.text;
}
}