Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » Eclipse Scout » Tri-state Checkboxes
Tri-state Checkboxes [message #1061827] Tue, 04 June 2013 09:42 Go to next message
Urs Beeli is currently offline Urs BeeliFriend
Messages: 573
Registered: October 2012
Location: Bern, Switzerland
Senior Member
In our project we have certain objects that collate information of various sub-objects. This means that we can have the following situation for boolean values:
- the value is "true" for all sub-objects
- the value is "false" for all sub-objects
- the value is "true" for some sub-objects and "false" for others

We would like to display this situation using a tri-state checkbox.
index.php/fa/15136/0/

However, looking through the properties of the CheckboxField and BooleanField I didn't find anything that looked like it would let me do that.

Is there no support for tri-state checkboxes in Scout?
  • Attachment: tristate.png
    (Size: 0.91KB, Downloaded 1416 times)
Re: Tri-state Checkboxes [message #1061859 is a reply to message #1061827] Tue, 04 June 2013 12:00 Go to previous messageGo to next message
Jeremie Bresson is currently offline Jeremie BressonFriend
Messages: 1252
Registered: October 2011
Senior Member
Hi,

There is a TriState Object (based on Boolean): org.eclipse.scout.commons.TriState.

But I am afraid, there is no Field for this Object.
Re: Tri-state Checkboxes [message #1061898 is a reply to message #1061859] Tue, 04 June 2013 15:02 Go to previous messageGo to next message
Urs Beeli is currently offline Urs BeeliFriend
Messages: 573
Registered: October 2012
Location: Bern, Switzerland
Senior Member
Thanks Jeremie

So I guess I could start creating an AbstractTristateField which extends AbstractValueField<TriState> and write SwtScoutTristate by peeking at SwtScoutCheckbox and handling the special icon for the "undefined" case... That doesn't look so daunting at first (thought I might be terribly wrong Smile

I'll get back to you if I succeed or get stuck.
Re: Tri-state Checkboxes [message #1061988 is a reply to message #1061898] Wed, 05 June 2013 09:28 Go to previous messageGo to next message
Urs Beeli is currently offline Urs BeeliFriend
Messages: 573
Registered: October 2012
Location: Bern, Switzerland
Senior Member
Ok, I can report success Smile

I've put together a custom field (with heavy inspiration from AbstractBooleanField/SwtScoutCheckbox) which works.

index.php/fa/15142/0/

AbstractTristateField takes one of the three possible values of TriState (TRUE, FALSE, UNDEFINED), if the initial value is TRUE or FALSE it will behave like a normal checkbox (toggle between true/false). If the value is set to UNDEFINED (at any time in its life cycle) it will behave like a tri-state checkbox (true->false->undefined->true). You can force it to tri-state behaviour even when your initial value is true/false by using setTristateMode(true) or by using the "Default Tristate Mode" advanced property.

Feel free to integrate this into the Scout framework if you think it will be useful for other people (after all, most of the code is pinched from existing scout classes Smile (I realise you might not want to do that while there is only a SWT implementation, see below).

Here are the necessary classes:

Client

ITristateField
import org.eclipse.scout.commons.TriState;
import org.eclipse.scout.rt.client.ui.form.fields.IValueField;

public interface ITristateField extends IValueField<TriState> {

  /**
   * Sets the value of the tri-state field. If this is the first assignment to this field, no matter which method (setChecked(Boolean), setChecked(TriState), setValue()) is used, the tri-state mode
   * will be updated (turned off for true/false, turned on for null)
   * 
   * @param b
   *          true/false/null
   */
  void setChecked(Boolean b);

  /**
   * Sets the value of the tri-state field. If this is the first assignment to this field, no matter which method (setChecked(Boolean), setChecked(TriState), setValue()) is used, the tri-state mode
   * will be updated (turned off for true/false, turned on for null)
   * 
   * @param b
   *          TriState.TRUE, TriState.FALSE, TriState.UNDEFINED
   */
  void setChecked(TriState t);

  /**
   * Returns the value of this tri-state field
   * 
   * @return true for TriState.TRUE false for TriState.FALSE or TriState.UNDEFINED
   */
  Boolean isChecked();

  /**
   * Returns the value of this field
   * 
   * @return TriState.TRUE, TriState.FALSE or TriState.UNDEFINED
   */
  TriState getChecked();

  /**
   * Explicitely set the tri-state mode of the field
   * 
   * This can be useful if you want to force the field into tri-state mode with an inital value other than TriState.UNDEFINED (i.e. with TRUE/FALSE)
   * 
   * NOTE: even if you turn tri-state mode off, when you later set the field value to TriState.UNDEFINED, the tri-state mode will be re-enabled implicitely
   * 
   * @param b
   */
  void setTristateMode(boolean b);

  boolean isTristateMode();

  ITristateFieldUIFacade getUIFacade();

}


ITristateFieldUIFacade
public interface ITristateFieldUIFacade {

  void toggle();
}


AbstractTristateField
import org.eclipse.scout.commons.TriState;
import org.eclipse.scout.commons.exception.ProcessingException;
import org.eclipse.scout.commons.logger.IScoutLogger;
import org.eclipse.scout.commons.logger.ScoutLogManager;
import org.eclipse.scout.rt.client.ui.form.fields.AbstractValueField;
import org.eclipse.scout.rt.client.ui.form.fields.booleanfield.AbstractBooleanField;
import org.eclipse.scout.rt.shared.ScoutTexts;
import org.eclipse.scout.rt.shared.TEXTS;

public abstract class AbstractTristateField extends AbstractValueField<TriState> implements ITristateField {
  private static final IScoutLogger LOG = ScoutLogManager.getLogger(AbstractBooleanField.class);

  private ITristateFieldUIFacade m_uiFacade;
  private TriState m_tristateMode = TriState.UNDEFINED;

  public AbstractTristateField() {
    this(true);
  }

  public AbstractTristateField(boolean callInitializer) {
    super(callInitializer);
  }

  @Override
  protected void initConfig() {
    m_uiFacade = new P_UIFacade();
    super.initConfig();
    setTristateMode(getConfiguredDefaultTristateMode());
    propertySupport.setProperty(PROP_VALUE, TriState.FALSE);
    propertySupport.setProperty(PROP_DISPLAY_TEXT, execFormatValue(getValue()));
  }

  @Override
  public void setChecked(Boolean b) {
    setChecked(b == null ? TriState.UNDEFINED : b ? TriState.TRUE : TriState.FALSE);
  }

  @Override
  public void setChecked(TriState t) {
    updateTristateMode(t);
    setValue(t);
  }

  @Override
  public Boolean isChecked() {
    return getValue() != null && getValue().getBooleanValue();
  }

  @Override
  public TriState getChecked() {
    return getValue();
  }

  // format value for display
  @Override
  protected String formatValueInternal(TriState validValue) {
    if (validValue == null) {
      return "";
    }
    return validValue.getBooleanValue() == null ? TEXTS.get("Indeterminate") : validValue.getBooleanValue() ? ScoutTexts.get("Yes") : ScoutTexts.get("No");
  }

  // convert string to a boolean
  @Override
  protected TriState parseValueInternal(String text) throws ProcessingException {
    TriState retVal = null;
    if (text != null && text.length() == 0) {
      text = null;
    }
    if (text != null) {
      if (text.equals("1") || text.equalsIgnoreCase("true") || text.equalsIgnoreCase("yes") || text.equalsIgnoreCase("on")) {
        retVal = TriState.TRUE;
      } else if (text.equals("1") || text.equalsIgnoreCase("false") || text.equalsIgnoreCase("no") || text.equalsIgnoreCase("off")) {
        retVal = TriState.FALSE;
      } else {
        retVal = TriState.UNDEFINED;
      }
    }
    return retVal;
  }

  @Override
  public ITristateFieldUIFacade getUIFacade() {
    return m_uiFacade;
  }

  private class P_UIFacade implements ITristateFieldUIFacade {
    @Override
    public void toggle() {
      if (isEnabled() && isVisible()) {
        TriState oldValue = getValue();
        if (TriState.TRUE.equals(oldValue)) {
          setChecked(TriState.FALSE);
        } else if (TriState.FALSE.equals(oldValue)) {
          if (isTristateMode()) {
            setChecked(TriState.UNDEFINED);
          } else {
            setChecked(TriState.TRUE);
          }
        } else {
          setChecked(TriState.TRUE);
        }
      }
    }

  }

  /**
   * This property will define the default tri-state mode of this control.
   * 
   * The default is <code>false</code> which indicates "bi-state" behaviour (true/false) toggle
   * 
   * The TristateField will automatically change to tri-state behaviour if an "indeterminate" value is set on it.
   * However, you can use this method with value <code>true</code> to force tri-state behaviour from the start,
   * independent of the values that are set on the field.
   * 
   * @return
   */
  @ConfigProperty(ConfigProperty.BOOLEAN)
  @Order(500)
  @ConfigPropertyValue("false")
  protected boolean getConfiguredDefaultTristateMode() {
    return false;
  }

  @Override
  public void setTristateMode(boolean b) {
    m_tristateMode = (b ? TriState.TRUE : TriState.FALSE);
  }

  @Override
  public boolean isTristateMode() {
    updateTristateMode(getValue());
    boolean result = !TriState.FALSE.equals(m_tristateMode);
    return result;
  }

  private void updateTristateMode(TriState t) {
    if (TriState.UNDEFINED.equals(m_tristateMode)) {
      // this is out initial set: if the value is UNDEFINED, set mode to tristate, else set it to bistate
      if (TriState.UNDEFINED.equals(t)) {
        m_tristateMode = TriState.TRUE;
      } else {
        m_tristateMode = TriState.FALSE;
      }
    }
    // if the value is set to UNDEFINED (even later on) -> enable tristate mode
    if (TriState.UNDEFINED.equals(t)) {
      m_tristateMode = TriState.TRUE;
    }
  }
}


SWT

ISwtScoutTristateField
import org.eclipse.minicrm.client.ui.form.fields.ext.ITristateField;
import org.eclipse.scout.rt.ui.swt.ext.ILabelComposite;
import org.eclipse.scout.rt.ui.swt.form.fields.ISwtScoutFormField;
import org.eclipse.swt.widgets.Button;

public interface ISwtScoutTristateField extends ISwtScoutFormField<ITristateField> {
  @Override
  Button getSwtField();

  ILabelComposite getPlaceholderLabel();

}


SwtScoutTristateField
import org.eclipse.minicrm.client.ui.form.fields.ext.ITristateField;
import org.eclipse.scout.commons.TriState;
import org.eclipse.scout.commons.exception.IProcessingStatus;
import org.eclipse.scout.rt.ui.swt.LogicalGridData;
import org.eclipse.scout.rt.ui.swt.LogicalGridLayout;
import org.eclipse.scout.rt.ui.swt.ext.ILabelComposite;
import org.eclipse.scout.rt.ui.swt.ext.StatusLabelEx;
import org.eclipse.scout.rt.ui.swt.form.fields.LogicalGridDataBuilder;
import org.eclipse.scout.rt.ui.swt.form.fields.SwtScoutValueFieldComposite;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;

public class SwtScoutTristateField extends SwtScoutValueFieldComposite<ITristateField> implements ISwtScoutTristateField {
  private P_SwtButtonListener m_swtButtonListener;
  private boolean m_mandatoryCached;
  private StatusLabelEx m_labelPlaceholder;
  // ticket 86811: avoid double-action in queue
  private boolean m_handleActionPending;

  @Override
  protected void initializeSwt(Composite parent) {
    super.initializeSwt(parent);
    Composite container = getEnvironment().getFormToolkit().createComposite(parent);
    m_labelPlaceholder = new StatusLabelEx(container, SWT.NONE, getEnvironment());
    getEnvironment().getFormToolkit().getFormToolkit().adapt(m_labelPlaceholder, false, false);
    m_labelPlaceholder.setLayoutData(LogicalGridDataBuilder.createLabel(getScoutObject().getGridData()));

    Button checkbox = getEnvironment().getFormToolkit().createButton(container, "", SWT.CHECK);

    LogicalGridData checkboxData = LogicalGridDataBuilder.createField(getScoutObject().getGridData());
    checkboxData.fillHorizontal = false;
    checkboxData.useUiWidth = true;
    checkboxData.weightx = 0;
    checkbox.setLayoutData(checkboxData);

    // This label is only used to dispatch some properties to the checkbox label (see updateLabel)
    // So it has to be invisible.
    StatusLabelEx dispatcherLabel = new StatusLabelEx(container, SWT.NONE, getEnvironment());
    dispatcherLabel.setVisible(false);
    setSwtLabel(dispatcherLabel);

    setSwtContainer(container);
    setSwtField(checkbox);

    // layout
    container.setLayout(new LogicalGridLayout(1, 0));
  }

  @Override
  protected void attachScout() {
    super.attachScout();
    if (m_swtButtonListener == null) {
      m_swtButtonListener = new P_SwtButtonListener();
    }
    getSwtField().addListener(SWT.Selection, m_swtButtonListener);
  }

  @Override
  protected void setErrorStatusFromScout(IProcessingStatus s) {
    // Update the status of the labelPlaceholder and not the dispatcherLabel
    m_labelPlaceholder.setStatus(s);
  }

  @Override
  protected void setMandatoryFromScout(boolean b) {
    super.setMandatoryFromScout(b);

    updateLabel();
  }

  /**
   * Updates the label of the checkbox with the properties of the dispatcher label. This makes sure that the mandatory appearance is reflected correctly.
   */
  protected void updateLabel() {
    if (getSwtLabel() instanceof StatusLabelEx) {
      StatusLabelEx swtLabel = (StatusLabelEx) getSwtLabel();

      if (swtLabel.getText() != null) {
        getSwtField().setText(swtLabel.getText());
      }

      getSwtField().setFont(swtLabel.getFont());
      getSwtField().setForeground(swtLabel.getForeground());
      getSwtField().setBackground(swtLabel.getBackground());
    }
  }

  @Override
  protected void detachScout() {
    super.detachScout();
    getSwtField().removeListener(SWT.Selection, m_swtButtonListener);
  }

  @Override
  public Button getSwtField() {
    return (Button) super.getSwtField();
  }

  @Override
  public ILabelComposite getPlaceholderLabel() {
    return m_labelPlaceholder;
  }

  @Override
  protected void setLabelVisibleFromScout() {
    boolean b = getScoutObject().isLabelVisible();
    if (m_labelPlaceholder != null && b != m_labelPlaceholder.getVisible()) {
      m_labelPlaceholder.setVisible(b);
      if (getSwtContainer() != null && isConnectedToScout()) {
        getSwtContainer().layout(true, true);
      }
    }
  }

  @Override
  protected void setLabelFromScout(String s) {
    super.setLabelFromScout(s);
    updateLabel();
  }

  @Override
  protected void setValueFromScout() {
    TriState value = getScoutObject() == null ? TriState.FALSE : getScoutObject().getValue();

    // isTristateMode() *must* be called, to make sure the mode flag is initialised on the model!
    @SuppressWarnings("unused")
    boolean mode = getScoutObject() == null ? false : getScoutObject().isTristateMode();

    if (TriState.TRUE.equals(value)) {
      getSwtField().setSelection(true);
      getSwtField().setGrayed(false);
    } else if (TriState.FALSE.equals(value)) {
      getSwtField().setSelection(false);
      getSwtField().setGrayed(false);
    } else {
      getSwtField().setSelection(true);
      getSwtField().setGrayed(true);
    }

  }

  protected void handleSwtAction() {
    if (getSwtField().isEnabled()) {
      if (!m_handleActionPending) {
        m_handleActionPending = true;
        // notify Scout
        Runnable t = new Runnable() {
          @Override
          public void run() {
            try {
              getScoutObject().getUIFacade().toggle();
            } finally {
              m_handleActionPending = false;
            }
          }
        };
        getEnvironment().invokeScoutLater(t, 0);
        // end notify
      }
    }
  }

  private class P_SwtButtonListener implements Listener {
    @Override
    public void handleEvent(Event event) {
      switch (event.type) {
      case SWT.Selection:
        handleSwtAction();
        break;
      }
    }
  } // end class P_SwtButtonListener

}


plugin.xml
   <extension
         point="org.eclipse.scout.rt.ui.swt.formfields">
     <formField
           active="true"
           modelClass="org.eclipse.minicrm.client.ui.form.fields.ext.ITristateField"
           name="Tristate Field"
           scope="default">
        <uiClass
              class="org.eclipse.minicrm.ui.swt.form.fields.ext.SwtScoutTristateField">
        </uiClass>
     </formField>
   </extension>


Swing

Our immediate need is for SWT, so I haven't bothered with a Swing renderer yet. Looking at this link, tt shouldn't be too hard, I'll see if I can make the time to come up with something.

RAP

I haven't even looked at this yet. I might or might not get around to it.

Server

ProcessService
    formData.getTristate().setValue(TriState.TRUE);        // start in state "true", has bi-state behaviour
    formData.getTristate2().setValue(TriState.FALSE);      // start in state "false", has bi-state behaviour
    formData.getTristate3().setValue(TriState.UNDEFINED);  // start in state "undefined", has tri-state behaviour

  • Attachment: tristate.png
    (Size: 1.41KB, Downloaded 1163 times)
Re: Tri-state Checkboxes [message #1061997 is a reply to message #1061988] Wed, 05 June 2013 10:30 Go to previous messageGo to next message
Urs Beeli is currently offline Urs BeeliFriend
Messages: 573
Registered: October 2012
Location: Bern, Switzerland
Senior Member
Ok, now I also have a working implementation for Swing and a semi-working one for RAP (it seems RAP has no separate icon for "undefined", even though it goes into tri-state when using setGrayed(true)).

Swing

index.php/fa/15143/0/

ISwingScoutTristateField
import org.eclipse.minicrm.client.ui.form.fields.ext.ITristateField;
import org.eclipse.scout.rt.ui.swing.ext.JCheckBoxEx;
import org.eclipse.scout.rt.ui.swing.form.fields.ISwingScoutFormField;

public interface ISwingScoutTristateField extends ISwingScoutFormField<ITristateField> {
  JCheckBoxEx getSwingCheckBox();

}


SwingScoutTristateField
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.Icon;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.SwingConstants;

import org.eclipse.minicrm.client.ui.form.fields.ext.ITristateField;
import org.eclipse.scout.commons.TriState;
import org.eclipse.scout.rt.ui.swing.LogicalGridData;
import org.eclipse.scout.rt.ui.swing.LogicalGridLayout;
import org.eclipse.scout.rt.ui.swing.SwingUtility;
import org.eclipse.scout.rt.ui.swing.ext.JCheckBoxEx;
import org.eclipse.scout.rt.ui.swing.ext.JPanelEx;
import org.eclipse.scout.rt.ui.swing.ext.JStatusLabelEx;
import org.eclipse.scout.rt.ui.swing.form.fields.SwingScoutValueFieldComposite;

public class SwingScoutTristateField extends SwingScoutValueFieldComposite<ITristateField> implements ISwingScoutTristateField {
  private static final long serialVersionUID = 1L;

  private boolean m_mandatoryCached;
  private boolean m_handleActionPending;
  private Icon m_tristateIcon;

  @Override
  protected void initializeSwing() {
    JPanelEx container = new JPanelEx();
    container.setOpaque(false);
    JStatusLabelEx label = getSwingEnvironment().createStatusLabel(getScoutObject());
    container.add(label);
    JCheckBox swingCheckBox = createCheckBox(container);
    container.add(swingCheckBox);
    swingCheckBox.setVerifyInputWhenFocusTarget(true);
    swingCheckBox.setAlignmentX(0);
    swingCheckBox.setVerticalAlignment(SwingConstants.TOP);
    // attach swing listeners
    swingCheckBox.addActionListener(new P_SwingActionListener());

    setSwingLabel(label);
    setSwingField(swingCheckBox);
    setSwingContainer(container);

    LogicalGridData gd = (LogicalGridData) swingCheckBox.getClientProperty(LogicalGridData.CLIENT_PROPERTY_NAME);
    gd.fillHorizontal = false; // must be false to be only as wide as the label. This avoids that clicking in white space area toggles the value (BSI ticket 101344)

    getSwingContainer().setLayout(new LogicalGridLayout(getSwingEnvironment(), 1, 0));
  }

  protected JCheckBox createCheckBox(JComponent container) {
    JCheckBoxEx swingCheckBox = new JCheckBoxEx();
    swingCheckBox.setOpaque(false);

    m_tristateIcon = getSwingEnvironment().getIcon("checkbox_tristate");

    return swingCheckBox;
  }

  @Override
  public JCheckBoxEx getSwingCheckBox() {
    return (JCheckBoxEx) getSwingField();
  }

  @Override
  protected void setHorizontalAlignmentFromScout(int scoutAlign) {
    if (getSwingCheckBox() != null) {
      getSwingCheckBox().setHorizontalAlignment(SwingUtility.createHorizontalAlignment(scoutAlign));
    }
  }

  @Override
  protected void setLabelFromScout(String s) {
    getSwingCheckBox().setText(s);
  }

  @Override
  protected void setValueFromScout(Object o) {
    TriState value = (TriState) o;

    // isTristateMode() *must* be called, to make sure the mode flag is initialised on the model!
    @SuppressWarnings("unused")
    boolean mode = getScoutObject() == null ? false : getScoutObject().isTristateMode();

    if (TriState.TRUE.equals(value)) {
      getSwingCheckBox().setSelected(true);
      getSwingCheckBox().setIcon(null);
    } else if (TriState.FALSE.equals(value)) {
      getSwingCheckBox().setSelected(false);
      getSwingCheckBox().setIcon(null);
    } else {
      getSwingCheckBox().setSelected(true);
      getSwingCheckBox().setIcon(m_tristateIcon);
    }
  }

  @Override
  protected void setMandatoryFromScout(boolean b) {
    if (b != m_mandatoryCached) {
      m_mandatoryCached = b;
      getSwingCheckBox().setMandatory(b);
      getSwingLabel().setMandatory(b); // bsh 2010-10-01: inform the label - some GUIs (e.g. Rayo) might use this information
    }
  }

  protected void handleSwingAction(ActionEvent e) {
    if (getSwingCheckBox().isEnabled()) {

      if (!m_handleActionPending) {
        m_handleActionPending = true;
        // notify Scout
        Runnable t = new Runnable() {
          @Override
          public void run() {
            try {
              getScoutObject().getUIFacade().toggle();
            } finally {
              m_handleActionPending = false;
            }
          }
        };
        getSwingEnvironment().invokeScoutLater(t, 0);
        // end notify
      }
    }
  }

  /*
   * Listeners
   */
  private class P_SwingActionListener implements ActionListener {
    @Override
    public void actionPerformed(ActionEvent e) {
      handleSwingAction(e);
    }
  }// end class

}


plugin.xml
  <extension
        point="org.eclipse.scout.rt.ui.swing.formfields">
     <formField
           active="true"
           modelClass="org.eclipse.minicrm.client.ui.form.fields.ext.ITristateField"
           name="Tristate Field"
           scope="default">
        <uiClass
              class="org.eclipse.minicrm.ui.swing.form.fields.ext.SwingScoutTristateField">
        </uiClass>
     </formField>
  </extension>


In addition, you need to place the attached file checkbox_tristate.png into client/resources/icons.


RAP

IRwtScoutTristateField
import org.eclipse.minicrm.client.ui.form.fields.ext.ITristateField;
import org.eclipse.scout.rt.ui.rap.ext.ILabelComposite;
import org.eclipse.scout.rt.ui.rap.form.fields.IRwtScoutFormField;
import org.eclipse.swt.widgets.Button;

public interface IRwtScoutTristateField extends IRwtScoutFormField<ITristateField> {

  @Override
  Button getUiField();

  ILabelComposite getPlaceholderLabel();
}


RwtScoutTristateField
import org.eclipse.minicrm.client.ui.form.fields.ext.ITristateField;
import org.eclipse.scout.commons.TriState;
import org.eclipse.scout.commons.exception.IProcessingStatus;
import org.eclipse.scout.rt.ui.rap.LogicalGridData;
import org.eclipse.scout.rt.ui.rap.LogicalGridLayout;
import org.eclipse.scout.rt.ui.rap.ext.StatusLabelEx;
import org.eclipse.scout.rt.ui.rap.form.fields.LogicalGridDataBuilder;
import org.eclipse.scout.rt.ui.rap.form.fields.RwtScoutValueFieldComposite;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;

public class RwtScoutTristateField extends RwtScoutValueFieldComposite<ITristateField> implements IRwtScoutTristateField {

  private P_RwtButtonListener m_uiButtonListener;
  private boolean m_mandatoryCached;
  private StatusLabelEx m_labelPlaceholder;
  private boolean m_handleActionPending;

  @Override
  protected void initializeUi(Composite parent) {
    super.initializeUi(parent);
    Composite container = getUiEnvironment().getFormToolkit().createComposite(parent);
    m_labelPlaceholder = new StatusLabelEx(container, SWT.NONE);
    getUiEnvironment().getFormToolkit().getFormToolkit().adapt(m_labelPlaceholder, false, false);
    m_labelPlaceholder.setLayoutData(LogicalGridDataBuilder.createLabel(getScoutObject().getGridData()));

    Button checkbox = getUiEnvironment().getFormToolkit().createButton(container, "", SWT.CHECK);

    LogicalGridData checkboxData = LogicalGridDataBuilder.createField(getScoutObject().getGridData());
    checkboxData.fillHorizontal = false;
    checkboxData.useUiWidth = true;
    checkboxData.weightx = 0;
    checkbox.setLayoutData(checkboxData);

    // This label is only used to dispatch some properties to the checkbox label (see updateLabel)
    // So it has to be invisible.
    StatusLabelEx dispatcherLabel = new StatusLabelEx(container, SWT.NONE);
    dispatcherLabel.setVisible(false);
    setUiLabel(dispatcherLabel);

    //
    setUiContainer(container);
    setUiField(checkbox);

    // layout
    container.setLayout(new LogicalGridLayout(1, 0));
  }

  @Override
  protected void attachScout() {
    super.attachScout();
    if (m_uiButtonListener == null) {
      m_uiButtonListener = new P_RwtButtonListener();
    }
    getUiField().addListener(SWT.Selection, m_uiButtonListener);
  }

  /*
   * (non-Javadoc)
   * 
   * @see org.eclipse.scout.rt.ui.rap.form.fields.RwtScoutValueFieldComposite#setErrorStatusFromScout(org.eclipse.scout.commons.exception.IProcessingStatus)
   */
  @Override
  protected void setErrorStatusFromScout(IProcessingStatus s) {
    // Update the status of the labelPlaceholder and not the dispatcherLabel
    m_labelPlaceholder.setStatus(s);
  }

  /*
   * (non-Javadoc)
   * 
   * @see org.eclipse.scout.rt.ui.rap.form.fields.RwtScoutFieldComposite#setMandatoryFromScout(boolean)
   */
  @Override
  protected void setMandatoryFromScout(boolean b) {
    super.setMandatoryFromScout(b);
    // if (b != m_mandatoryCached) {
    // m_mandatoryCached = b;
    // getUiLabel().setMandatory(b); // bsh 2010-10-01: inform the label - some GUIs (e.g. Rayo) might use this information
    // }

    updateLabel();
  }

  /**
   * Updates the label of the checkbox with the properties of the dispatcher label. This makes sure that the mandatory appearance is reflected correctly.
   */
  protected void updateLabel() {
    if (getUiLabel() instanceof StatusLabelEx) {
      StatusLabelEx uiLabel = getUiLabel();

      if (uiLabel.getText() != null) {
        getUiField().setText(uiLabel.getText());
      }

      getUiField().setFont(uiLabel.getFont());
      getUiField().setForeground(uiLabel.getForeground());
      getUiField().setBackground(uiLabel.getBackground());
    }
  }

  @Override
  protected void detachScout() {
    super.detachScout();
    getUiField().removeListener(SWT.Selection, m_uiButtonListener);
  }

  @Override
  public Button getUiField() {
    return (Button) super.getUiField();
  }

  @Override
  public StatusLabelEx getUiLabel() {
    return (StatusLabelEx) super.getUiLabel();
  }

  @Override
  public StatusLabelEx getPlaceholderLabel() {
    return m_labelPlaceholder;
  }

  @Override
  protected void setLabelVisibleFromScout() {
    boolean b = getScoutObject().isLabelVisible();
    if (m_labelPlaceholder != null && b != m_labelPlaceholder.getVisible()) {
      m_labelPlaceholder.setVisible(b);
      if (getUiContainer() != null && isCreated()) {
        getUiContainer().layout(true, true);
      }
    }
  }

  @Override
  protected void setLabelFromScout(String s) {
    super.setLabelFromScout(s);
    updateLabel();
  }

  @Override
  protected void setValueFromScout() {
    TriState value = getScoutObject() == null ? TriState.FALSE : getScoutObject().getValue();

    // isTristateMode() *must* be called, to make sure the mode flag is initialised on the model!
    @SuppressWarnings("unused")
    boolean mode = getScoutObject() == null ? false : getScoutObject().isTristateMode();

    if (TriState.TRUE.equals(value)) {
      getUiField().setSelection(true);
      getUiField().setGrayed(false);
    } else if (TriState.FALSE.equals(value)) {
      getUiField().setSelection(false);
      getUiField().setGrayed(false);
    } else {
      getUiField().setSelection(true);
      getUiField().setGrayed(true);
    }
  }

  protected void handleUiAction() {
    if (getUiField().isEnabled()) {
      if (!m_handleActionPending) {
        m_handleActionPending = true;
        // notify Scout
        Runnable t = new Runnable() {
          @Override
          public void run() {
            try {
              getScoutObject().getUIFacade().toggle();
            } finally {
              m_handleActionPending = false;
            }
          }
        };
        getUiEnvironment().invokeScoutLater(t, 0);
        // end notify
      }
    }
  }

  private class P_RwtButtonListener implements Listener {
    private static final long serialVersionUID = 1L;

    @Override
    public void handleEvent(Event event) {
      switch (event.type) {
      case SWT.Selection:
        handleUiAction();
        break;
      }
    }
  } // end class P_RwtButtonListener

}


plugin.xml
   <extension
         point="org.eclipse.scout.rt.ui.rap.formfields">
     <formField
           active="true"
           modelClass="org.eclipse.minicrm.client.ui.form.fields.ext.ITristateField"
           name="Draw Line Field"
           scope="default">
        <uiClass
              class="org.eclipse.minicrm.ui.rap.form.fields.ext.RwtScoutTristateField">
        </uiClass>
     </formField>
   </extension>

[Updated on: Wed, 05 June 2013 10:32]

Report message to a moderator

Re: Tri-state Checkboxes [message #1062168 is a reply to message #1061997] Thu, 06 June 2013 11:23 Go to previous messageGo to next message
Urs Beeli is currently offline Urs BeeliFriend
Messages: 573
Registered: October 2012
Location: Bern, Switzerland
Senior Member
A followup question:
m_tristateIcon = getSwingEnvironment().getIcon("checkbox_tristate");


does not find icons in org.eclipse.minicrm.ui.swt/resources/icons but it does find those under org.eclipse.minicrm.client/resources/icons.

What would I need to change so that the icons from my swt resources are used?
Re: Tri-state Checkboxes [message #1062181 is a reply to message #1061997] Thu, 06 June 2013 12:08 Go to previous messageGo to next message
Jeremie Bresson is currently offline Jeremie BressonFriend
Messages: 1252
Registered: October 2011
Senior Member
Urs Beeli wrote on Wed, 05 June 2013 12:30
(it seems RAP has no separate icon for "undefined", even though it goes into tri-state when using setGrayed(true)).

Have you checked this discussion:
Change Icon of checkable Table. It gives some highlight on where the icons are located in the RAP code.

Glad you got it working. It demonstrates that Scout widgets concept is extendible.
Re: Tri-state Checkboxes [message #1062182 is a reply to message #1062181] Thu, 06 June 2013 12:15 Go to previous messageGo to next message
Urs Beeli is currently offline Urs BeeliFriend
Messages: 573
Registered: October 2012
Location: Bern, Switzerland
Senior Member
Jeremie

I had only briefly looked at it and hadn't followed it far enough down to find the post about the icon provider. I'll try this out. However, the post by claudio only mentions the file names for the "bi-state" checkbox. Do you know what name the file for the third "indeterminate" state has?

Edit: Ok, after trying things with the icon provider in rap and not seeing any difference I have now gone back to the two intertwined threads and it seems that this would need to be done in the CSS files. I have not really understood how that needs to be done and will go and ask my questions in those two threads.

If anyone can give me a hint on how to pick the icons out of Swing/resources/icons instead of Client/resources/icons I think I can wrap up this topic.

[Updated on: Thu, 06 June 2013 13:16]

Report message to a moderator

Re: Tri-state Checkboxes [message #1062212 is a reply to message #1062182] Thu, 06 June 2013 14:19 Go to previous messageGo to next message
Urs Beeli is currently offline Urs BeeliFriend
Messages: 573
Registered: October 2012
Location: Bern, Switzerland
Senior Member
Ok, I have my RAP icon working, will post an update with all needed steps next week.
Re: Tri-state Checkboxes [message #1072657 is a reply to message #1062168] Tue, 23 July 2013 08:16 Go to previous messageGo to next message
Eclipse UserFriend
Hi Urs

To ensure icons gets resolved from any diffrent bundle than *.client. Register a org.eclipse.scout.rt.client.services.common.icon.IconProviderService to the desired bundle.
In your case add the following extension to the *.ui.swt bundle's plugin.xml. So icons will be resolved in the *.ui.swt/resources/icons folder.

 <extension
         point="org.eclipse.scout.service.services">
      <service
            class="org.eclipse.scout.rt.client.services.common.icon.IconProviderService"
            createImmediately="false"
            factory="org.eclipse.scout.rt.client.services.ClientServiceFactory">
      </service>
   </extension>


-andreas
Re: Tri-state Checkboxes [message #1072670 is a reply to message #1072657] Tue, 23 July 2013 08:40 Go to previous messageGo to next message
Urs Beeli is currently offline Urs BeeliFriend
Messages: 573
Registered: October 2012
Location: Bern, Switzerland
Senior Member
Do I understand this correctly, that if I define IconProviderServices in the client's plugin.xml (there are currently two of them) *and* in the swt's plugin.xml (the one above), the icon resolution will work as follows:

- in the client code using the two registered providers, according to priority (is it correct, that this will never fall back to the swt provider?)
- in the swt code using the registered for swt (what if that fails, will it fall back to the client providers?)
Re: Tri-state Checkboxes [message #1072706 is a reply to message #1072670] Tue, 23 July 2013 10:32 Go to previous message
Eclipse UserFriend
Have a look at org.eclipse.scout.rt.client.ui.IconLocator the lookup for IconProviderServices is done with SERVICES.getServices(IIconProviderService.class) which returns a ranking sorted list of all registered services. An IconProviderService for the client bundle registered in the IconLocator's constructor.

- andreas
Previous Topic:Open Forms list?
Next Topic:Detect timeout
Goto Forum:
  


Current Time: Tue Apr 16 19:53:12 GMT 2024

Powered by FUDForum. Page generated in 1.76787 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top