1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
| package net.zephyr.graphicInterface.ressources;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import org.eclipse.core.databinding.beans.BeanProperties;
import org.eclipse.core.databinding.observable.list.IObservableList;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.widgets.Composite;
/**
* Extension of <i>org.eclipse.jface.viewers.ComboViewer</i> which support data binding for the list of choice and the selected element.
* The class is generic
*
* @author kase74
*
* @param <T> Type of the elements the combo must display.
*/
public class MyComboViewerDataBinded<T> extends ComboViewer
{
private final ViewModel _viewModel = new ViewModel();
private List<T> _originalListOfChoices;
private final String _attributesAccessors;
/**
* Data model to store the list of choice elements and the selected elements by user
* @author kase74
*
* @param <T> Generic support
*/
private class ViewModel extends AbstractModelObjectData4JavaBeanSupport
{
private List<T> _listOfChoices;
private T _selectedElement;
@SuppressWarnings("unused")
public List<T> get_listOfChoices() {
return _listOfChoices;
}
@SuppressWarnings("unused")
public void set_listOfChoices(List<T> listOfChoices) {
if(this._listOfChoices==null)
{
MyComboViewerDataBinded.this.setInput(listOfChoices); // To set the real content of the comboviewer
firePropertyChange("_listOfChoices", _listOfChoices, _listOfChoices = listOfChoices);
}
else if (! this._listOfChoices.equals(listOfChoices))
{
MyComboViewerDataBinded.this.setInput(listOfChoices); // To set the real content of the comboviewer
firePropertyChange("_listOfChoices", _listOfChoices, _listOfChoices = listOfChoices);
}
}
public T get_selectedElement() {
return _selectedElement;
}
public void set_selectedElement(T selectedElement) {
if( (this._selectedElement == null) || (! this._selectedElement.equals(selectedElement)) )
firePropertyChange("_selectedElement", _selectedElement, _selectedElement = selectedElement);
}
}
/**
* Label provider adapted to support generic and several label for each element in the list of choice.
* @author kase74
*
*/
private class MyLabelProvider extends LabelProvider
{
private final String[] _stringTab;
private final String _attributesSeparator = " - "; // represents the separator of attributes for each items string representation
@SuppressWarnings("unused")
private MyLabelProvider()
{ // Private constructor to avoid instantiation with no parameter
_stringTab = null; // never execute ! Just to avoid the compilation message "The blank final field _stringTab may not have been initialized"
}
protected MyLabelProvider(String attributesAccessors) {
super();
_stringTab = attributesAccessors.split(" ");
}
@SuppressWarnings("unchecked")
@Override
public String getText(Object element) {
Method method=null;
StringBuilder stringbuilder = new StringBuilder();
try {
for(String s : _stringTab)
{
if(stringbuilder.length()>0)
stringbuilder.append(_attributesSeparator); // Separator if more than one attribute
method = ((T)element).getClass().getMethod(s); // Call the corresponding methods in the T instance object
stringbuilder.append((String) method.invoke(element)); // append of the result to construct the final presentation string to add in the list of choice
}
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
| NoSuchMethodException | SecurityException e) {
e.printStackTrace();
}
return stringbuilder.toString();
}
}
/**
* Object permitting Java bean data binding to populate items in a combo box and retrieve
* the corresponding object of the source list.
* An IObservableList object can be bind with the widget combo box.
*
* @param parent as org.eclipse.jface.viewers.ComboViewer
* @param style as org.eclipse.jface.viewers.ComboViewer
* @param listOfChoices is the list of object the combo box must propose.
* @param attributesAccessors is a string which enumerate accessors of attributes the items must display.<br>
* Each accessor must corresponds to the getter method name of the corresponding field (e.g. <i>getIndex</i>) and must be
* separated by a space character (e.g. <i>getIndex getName</i>).<br>
* Of course, getters must exists in the class of the object, <U>and be careful to syntax and uppercase characters in the string.</U>
* <p>
* usage example :
* <p><code>// Creation of the object combo viewer :<br>
* combo = new MyComboViewerDataBinded<Type of the object to list>(widgetParent, SWT.READ_ONLY,
TheList, "getIndex getName");</code><br>
(...)<br>
* <code>
* // Make binding of the combo box with a jet fan element list and the selection of one of them.<br>
IObservableList<JetFan> jetFanListInModel = PojoProperties.list("jetFan").observe(_scenario.getResources());<br>
bindingContext.bindList(combo.getIObservableList(), jetFanListInModel, null, null);<br>
<br>
IObservableValue<JetFan> jetFanSelectedInModel = PojoProperties.value("fan").observe(_jetFanElement);<br>
bindingContext.bindValue(combo.getIObservableValue(), jetFanSelectedInModel, null, null);<br>
</code>
<p><B>/!\ Be careful : if the model list is changed, the combo doesn't see this change automatically.<br>
You have to update the content list with call to :</B><br>
<li>combo.refreshListOfChoices(), if the original list is the same object and just elements insides was updated.</li>
<li>combo.changeListOfChoices(List<T> newList), if the object representing the list change.</li><br>
<B>otherwise, MyComboViewerDataBinded doesn't work properly. Unfortunately the method comboviewer.setInput() of the mother class is not "overidable" and so impossible to hide.</B>
*/
public MyComboViewerDataBinded(Composite parent, int style,
List<T> listOfChoices, String attributesAccessors)
{
super(parent, style);
this._originalListOfChoices = listOfChoices;
this.setContentProvider(ArrayContentProvider.getInstance());
this._attributesAccessors = attributesAccessors;
this.setLabelProvider(new MyLabelProvider(attributesAccessors));
this.addSelectionChangedListener(new ISelectionChangedListener() {
@SuppressWarnings("unchecked")
@Override
public void selectionChanged(SelectionChangedEvent event) {
IStructuredSelection selection = (IStructuredSelection) event.getSelection();
if(selection.size()>0)
_viewModel.set_selectedElement((T) selection.getFirstElement());
}
});
}
/**
* refresh the content list of choices with the original object list passed on creation.
* The content of the list should have been changed before. <br>
* If an item is selected before, the method try to select again the same item after refresh. Tests of equality of items is done on combination of attributes equality.
*/
public void refreshListOfChoices()
{
T selectedElement = this._viewModel.get_selectedElement();
this.setInput(_originalListOfChoices);
MyComboViewerDataBinded.this.setSelection(null);
this.refresh();
String[] tab = this._attributesAccessors.split(" ");
Method method=null;
boolean testEqual = false;
for(T element : _originalListOfChoices)
{ // tests equality on combination of attributes equality.
testEqual = true;
for(String s : tab)
{ // Scan all attributes
try
{
method = ((T)element).getClass().getMethod(s); // Call the corresponding methods in the T instance object
if(!method.invoke(element).equals(method.invoke(selectedElement)))
{
testEqual = false;
break; // Exit from for(String s : tab)
}
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
| NoSuchMethodException | SecurityException e) {
e.printStackTrace();
}
}
if(testEqual)
{
MyComboViewerDataBinded.this.setSelection(new StructuredSelection(selectedElement)); // To select the real element into the comboviewer
break; // Exit from for(T element : _originalListOfChoices)
}
}
}
/**
* Change the object list on which the list of choices is based on. The combo lost its selection.
* @param newList replace the old list.
*/
public void changeListOfChoices(List<T> newList)
{
this.setInput(newList);
MyComboViewerDataBinded.this.setSelection(null);
_originalListOfChoices = newList;
this.refresh();
}
/**
* @return a bean IObservableList to binding the list of choice of the combo viewer with a data model.<br>
* <br>
* usage :<br>
* <code>bindingContext.bindList(combo.getIObservableList(), <i>DataModelListOfElement</i>, null, null);</code><br>
*/
@SuppressWarnings("unchecked")
public IObservableList<List<T>> getIObservableList()
{
return BeanProperties.list("_listOfChoices").observe(this._viewModel);
}
/**
* @return a bean IObservableValue to binding the selected item of the combo viewer with a data model.<br>
* <br>
* usage :<br>
* <code>bindingContext.bindList(combo.getIObservableValue(), <i>DataModelElementToUpdate</i>, null, null);</code><br>
*/
@SuppressWarnings("unchecked")
public IObservableValue<T> getIObservableValue()
{
return BeanProperties.value("_selectedElement").observe(this._viewModel);
}
} |
Partager