blob: 811d05b0e55ba7597316a2956e9b2f33f90562f8 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011,2012 Laurent CARON
* 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:
* Laurent CARON (laurent.caron at gmail dot com) - Initial implementation and API
* Marnix van Bochove (mgvanbochove at gmail dot com) - Enhancements and bug fixes
*******************************************************************************/
package org.mihalis.opal.checkBoxGroup;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Layout;
import org.eclipse.swt.widgets.Widget;
import org.mihalis.opal.utils.SWTGraphicUtil;
/**
* Instances of this class provide an etched border with a title and a checkbox. If the checkbox is checked, the content of the composite is enabled. If the checkbox is unchecked, the content of the composite is disabled, thus not editable.
* <p>
* <dl>
* <dt><b>Styles:</b></dt>
* <dd>BORDER</dd>
* <dt><b>Events:</b></dt>
* <dd>(none)</dd>
* </dl>
*/
public class CheckBoxGroup extends Canvas implements PaintListener {
/** The button. */
protected Button button;
/** The content. */
private final Composite content;
/** The selection listeners. */
private final List<SelectionListener> selectionListeners;
/** The transparent. */
private boolean transparent = false;
/**
* 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 widget which will be the parent of the new instance
* (cannot be null)
* @param style the style of widget to construct
* @see Composite#Composite(Composite, int)
* @see SWT#BORDER
* @see Widget#getStyle
* @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>
* </ul>
*/
public CheckBoxGroup(final Composite parent, final int style) {
super(parent, style);
super.setLayout(new GridLayout());
this.selectionListeners = new ArrayList<SelectionListener>();
createCheckBoxButton();
this.content = new Composite(this, style);
this.content.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true));
this.addPaintListener(this);
}
/**
* Creates the check box button.
*/
private void createCheckBoxButton() {
this.button = new Button(this, SWT.CHECK);
final GridData gdButton = new GridData(GridData.BEGINNING, GridData.CENTER, true, false);
gdButton.horizontalIndent = 15;
this.button.setLayoutData(gdButton);
this.button.setSelection(true);
this.button.pack();
this.button.addSelectionListener(new SelectionAdapter() {
/**
* @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
*/
@Override
public void widgetSelected(final SelectionEvent e) {
e.doit = fireSelectionListeners(e);
if (!e.doit) {
return;
}
if (CheckBoxGroup.this.button.getSelection()) {
CheckBoxGroup.this.activate();
} else {
CheckBoxGroup.this.deactivate();
}
}
});
}
/**
* Fire the selection listeners.
*
* @param selectionEvent mouse event
* @return true if the selection could be changed, false otherwise
*/
private boolean fireSelectionListeners(final SelectionEvent selectionEvent) {
selectionEvent.widget = this;
for (final SelectionListener listener : this.selectionListeners) {
listener.widgetSelected(selectionEvent);
if (!selectionEvent.doit) {
return false;
}
}
return true;
}
/**
* Activate the content.
*/
public void activate() {
this.button.setSelection(true);
SWTGraphicUtil.enableAllChildrenWidgets(this.content);
}
/**
* Adds the listener to the collection of listeners who will be notified
* when the user changes the receiver's selection, by sending it one of the
* messages defined in the <code>SelectionListener</code> interface.
* <p>
* When <code>widgetSelected</code> is called, the item field of the event
* object is valid. If the receiver has the <code>SWT.CHECK</code> style and
* the check selection changes, the event object detail field contains the
* value <code>SWT.CHECK</code>. <code>widgetDefaultSelected</code> is
* typically called when an item is double-clicked. The item field of the
* event object is valid for default selection, but the detail field is not
* used.
* </p>
*
* @param listener the listener which should be notified when the user
* changes the receiver's selection
* @see SelectionListener
* @see #removeSelectionListener
* @see SelectionEvent
* @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>
*/
public void addSelectionListener(final SelectionListener listener) {
checkWidget();
this.selectionListeners.add(listener);
}
/**
* Deactivate the content.
*/
public void deactivate() {
this.button.setSelection(false);
SWTGraphicUtil.disableAllChildrenWidgets(this.content);
}
/**
* Checks if is activated.
*
* @return <code>true</code> if the content is activated, <code>false</code>
* otherwise
*/
public boolean isActivated() {
return this.button.getSelection();
}
/**
* Gets the layout.
*
* @return the layout
* @see org.eclipse.swt.widgets.Composite#getLayout()
*/
@Override
public Layout getLayout() {
return this.content.getLayout();
}
/**
* Removes the listener from the collection of listeners who will be
* notified when the user changes the receiver's selection.
*
* @param listener the listener which should no longer be notified
* @see SelectionListener
* @see #addSelectionListener
* @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>
*/
public void removeSelectionListener(final SelectionListener listener) {
checkWidget();
this.selectionListeners.remove(listener);
}
/**
* Sets the focus.
*
* @return true, if successful
* @see org.eclipse.swt.widgets.Composite#setFocus()
*/
@Override
public boolean setFocus() {
return this.content.setFocus();
}
/**
* Sets the layout.
*
* @param layout the new layout
* @see org.eclipse.swt.widgets.Composite#setLayout(org.eclipse.swt.widgets.Layout)
*/
@Override
public void setLayout(final Layout layout) {
this.content.setLayout(layout);
}
// ------------------------------------ Getters and Setters
/**
* Gets the text.
*
* @return the text of the button
*/
public String getText() {
return this.button.getText();
}
/**
* Sets the text.
*
* @param text the text of the button to set
*/
public void setText(final String text) {
this.button.setText(text);
}
/**
* Gets the font.
*
* @return the font of the button
*/
@Override
public Font getFont() {
return this.button.getFont();
}
/**
* Sets the font.
*
* @param font the font to set
*/
@Override
public void setFont(final Font font) {
this.button.setFont(font);
}
/**
* Gets the content.
*
* @return the content of the group
*/
public Composite getContent() {
return this.content;
}
/**
* Checks if is transparent.
*
* @return true, if is transparent
*/
public boolean isTransparent() {
return this.transparent;
}
/**
* Sets the transparent.
*
* @param transparent the new transparent
*/
public void setTransparent(final boolean transparent) {
this.transparent = transparent;
if (transparent) {
setBackgroundMode(SWT.INHERIT_DEFAULT);
this.content.setBackgroundMode(SWT.INHERIT_DEFAULT);
}
}
/* (non-Javadoc)
* @see org.eclipse.swt.events.PaintListener#paintControl(org.eclipse.swt.events.PaintEvent)
*/
@Override
public void paintControl(final PaintEvent paintEvent) {
if (paintEvent.widget == this) {
drawWidget(paintEvent.gc);
}
}
/**
* Draws the widget.
*
* @param gc the gc
*/
private void drawWidget(final GC gc) {
final Rectangle rect = this.getClientArea();
final int margin = (int) (this.button.getSize().y * 1.5);
final int startY = margin / 2;
gc.setForeground(this.getDisplay().getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW));
gc.drawRoundRectangle(1, startY, rect.width - 2, rect.height - startY - 2, 2, 2);
gc.setForeground(this.getDisplay().getSystemColor(SWT.COLOR_WIDGET_LIGHT_SHADOW));
gc.drawRoundRectangle(2, startY + 1, rect.width - 4, rect.height - startY - 4, 2, 2);
}
}