/*******************************************************************************
* Copyright (c) 2009 Florian Pirchner 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:
* Florian Pirchner � initial API and implementation (based on other ridgets of
* compeople AG)
* compeople AG - adjustments for Riena v1.2
*******************************************************************************/
package org.eclipse.riena.internal.ui.ridgets.swt;
import java.util.Arrays;
import java.util.Collections;
import org.eclipse.core.databinding.beans.BeansObservables;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Link;
import org.eclipse.riena.core.util.ListenerList;
import org.eclipse.riena.core.util.StringUtils;
import org.eclipse.riena.ui.ridgets.AbstractMarkerSupport;
import org.eclipse.riena.ui.ridgets.ILinkRidget;
import org.eclipse.riena.ui.ridgets.IRidget;
import org.eclipse.riena.ui.ridgets.listener.ISelectionListener;
import org.eclipse.riena.ui.ridgets.swt.AbstractValueRidget;
import org.eclipse.riena.ui.ridgets.swt.BasicMarkerSupport;
/**
* Ridget for an SWT {@link Link} widget.
*
* @since 1.2
*/
public class LinkRidget extends AbstractValueRidget implements ILinkRidget {
/**
* This property is used by the databinding to sync ridget and model. It is
* always fired before its sibling {@link ILinkRidget#PROPERTY_TEXT} to
* ensure that the model is updated before any listeners try accessing it.
* <p>
* This property is not API. Do not use in client code.
*/
private static final String PROPERTY_TEXT_INTERNAL = "textInternal"; //$NON-NLS-1$
private final LinkSelectionObserver selectionObserver;
private String text;
private boolean textAlreadyInitialized;
public LinkRidget() {
selectionObserver = new LinkSelectionObserver(this);
}
@Override
protected void checkUIControl(final Object uiControl) {
checkType(uiControl, Link.class);
}
@Override
protected void bindUIControl() {
final Link control = getUIControl();
if (control != null) {
control.addSelectionListener(selectionObserver);
initText();
updateUIText();
}
}
@Override
protected void unbindUIControl() {
super.unbindUIControl();
final Link control = getUIControl();
if (control != null) {
control.removeSelectionListener(selectionObserver);
}
}
@Override
protected AbstractMarkerSupport createMarkerSupport() {
return new BasicMarkerSupport(this, propertyChangeSupport);
}
@Override
protected IObservableValue getRidgetObservable() {
return BeansObservables.observeValue(this, PROPERTY_TEXT_INTERNAL);
}
public void addSelectionListener(final ISelectionListener listener) {
selectionObserver.addListener(listener);
}
@Override
public Link getUIControl() {
return (Link) super.getUIControl();
}
public String getText() {
return text;
}
/**
* This method is not API. Do not use in client code.
*
* @noreference This method is not intended to be referenced by clients.
*/
public final String getTextInternal() {
return getText();
}
/**
* Always returns true because mandatory markers do not make sense for this
* ridget.
*/
@Override
public boolean isDisableMandatoryMarker() {
return true;
}
public void removeSelectionListener(final ISelectionListener listener) {
selectionObserver.removeListener(listener);
}
public void setText(final String text) {
final String oldText = this.text;
this.text = text;
updateUIText();
firePropertyChange(PROPERTY_TEXT_INTERNAL, oldText, this.text);
firePropertyChange(ILinkRidget.PROPERTY_TEXT, oldText, this.text);
}
public void setText(final String text, final String link) {
String mergedText;
if (StringUtils.isDeepEmpty(text) && StringUtils.isDeepEmpty(link)) {
mergedText = ""; //$NON-NLS-1$
} else if (StringUtils.isDeepEmpty(link)) {
mergedText = String.format("<a>%s</a>", convertNullToEmpty(text)); //$NON-NLS-1$
} else {
mergedText = String.format("<a href=\"%s\">%s</a>", convertNullToEmpty(link), convertNullToEmpty(text)); //$NON-NLS-1$
}
setText(mergedText);
}
/**
* This method is not API. Do not use in client code.
*
* @noreference This method is not intended to be referenced by clients.
*/
public final void setTextInternal(final String text) {
setText(text);
}
// helping methods
//////////////////
private String convertNullToEmpty(final String value) {
return StringUtils.isDeepEmpty(value) ? "" : value; //$NON-NLS-1$
}
private void updateUIText() {
final Link control = getUIControl();
if (control != null) {
control.setText(convertNullToEmpty(text));
}
}
/**
* If the text of the ridget has no value, initialize it with the text of
* the UI control.
*/
private void initText() {
if (text == null && !textAlreadyInitialized) {
final Link control = getUIControl();
if (control != null && !control.isDisposed()) {
text = control.getText();
textAlreadyInitialized = true;
}
}
}
// helping classes
//////////////////
/**
* Forwards selection events from the Link widget to a collection of
* ISelectionListeners.
*/
private static final class LinkSelectionObserver extends AbstractObserver<ISelectionListener> {
public LinkSelectionObserver(final IRidget source) {
super(source);
}
@Override
protected ListenerList<ISelectionListener> createList() {
return new ListenerList<ISelectionListener>(ISelectionListener.class);
}
@Override
protected void fireAction(final SelectionEvent evt) {
final ListenerList<ISelectionListener> listeners = getListeners();
if (listeners != null) {
final org.eclipse.riena.ui.ridgets.listener.SelectionEvent event = new org.eclipse.riena.ui.ridgets.listener.SelectionEvent(
getSource(), Collections.EMPTY_LIST, Arrays.asList(evt.text));
for (final ISelectionListener listener : listeners.getListeners()) {
listener.ridgetSelected(event);
}
}
}
}
}