All Classes Namespaces Files Functions Variables
BaseBoxChooser.java
Go to the documentation of this file.
1 package fi.jyu.mit.fxgui;
2 
3 import java.util.ArrayList;
4 import java.util.List;
5 import java.util.function.Consumer;
6 
7 import javafx.beans.property.BooleanProperty;
8 import javafx.beans.property.SimpleBooleanProperty;
9 import javafx.beans.property.SimpleStringProperty;
10 import javafx.beans.property.StringProperty;
11 import javafx.beans.value.ChangeListener;
12 import javafx.beans.value.ObservableValue;
13 import javafx.collections.FXCollections;
14 import javafx.collections.ListChangeListener;
15 import javafx.collections.ObservableList;
16 import javafx.geometry.Insets;
17 import javafx.scene.Node;
18 import javafx.scene.layout.VBox;
19 
20 /**
21  * Base class for any single object that want to be added in multiples and then selected
22  * @author terop
23  * @version 13.1.2017
24  * @param <TO> Type of objects to be stored.
25  * @param <TC> Type of components to be used
26  */
27 public abstract class BaseBoxChooser<TO, TC extends Node> extends VBox implements MultipleChooser<TO> {
28  /**
29  * StringProperty for asking the example data from the scenebuilder
30  */
31  protected StringProperty rivit = new SimpleStringProperty("\n");
32  /**
33  * Should the components example data be reset at start
34  */
35  protected BooleanProperty nollataanko = new SimpleBooleanProperty(false);
36  /**
37  * All of the components that were created
38  */
39  protected ArrayList<TC> boxes = new ArrayList<TC>();
40  /**
41  * The stored items inside this system
42  */
43  protected ObservableList<StringAndObject<TO>> items = FXCollections.observableArrayList();
44  /**
45  * Listeners for everyone who registered to any kind of changes for this object
46  */
47  protected ArrayList<Consumer<TO>> lambdaListeners = new ArrayList<Consumer<TO>>();
48  /**
49  * Stored listeners for easy removal
50  */
51  protected ArrayList<ChangeListener<Boolean>> changeListenersForRemoval = new ArrayList<>();
52 
53 
54  /**
55  * Initializes the control.
56  */
57  public BaseBoxChooser() {
58  super();
59  items.addListener(new ListChangeListener<StringAndObject<TO>>() {
60 
61  @Override
62  public void onChanged(Change<? extends StringAndObject<TO>> c) {
63  //TODO: change the components according to these changes
64  while (c.next()) {
65  if (c.wasPermutated()) {
66  /* for (int i = c.getFrom(); i < c.getTo(); ++i) {
67  //permutate
68  }*/
69  //UpdateComponents(items);
70  } else if (c.wasUpdated()) {
71  //update item
72  } else {
73  /* for (StringAndObject<TO> remitem : c.getRemoved()) {
74 
75  }
76  for (StringAndObject<TO> additem : c.getAddedSubList()) {
77  //additem.add(Outer.this);
78  }*/
79  //UpdateComponents(items);
80  }
81  }
82 
83  }
84  });
85  this.setSpacing(10.0);
86  this.setPadding(new Insets(10, 0, 10, 20));
87 
88  }
89 
90 
91  /**
92  * Adds a selection listener to the base component so when someone does selection this event is called
93  * @param event what to do when event happens
94  */
95  @Override
96  public void addSelectionListener(Consumer<TO> event){
97  this.lambdaListeners.add(event);
98  }
99 
100 
101  /**
102  * Adds the given object with given name
103  * @param name objektin kohdalla näkyvä teksti
104  * @param object tallennettava olio
105  */
106  @Override
107  public void add(String name, TO object){
108  add(new StringAndObject<TO>(name, object));
109  }
110 
111 
112  /**
113  * Adds the StringAndObject to the system and creates components necessary
114  * @param so object to add
115  */
116  public void add(StringAndObject<TO> so) {
117  getItems().add(so);
118 
119  //Create a new component and combine all the listeners to it
120  final TC box = addCorrectComponent(so.getName(), so.getObject()); //must be effectively final for the changed
121 
122  ChangeListener<Boolean> listener = new ChangeListener<Boolean>() {
123  @Override
124  public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
125 
126  selectedChanged();
127  }
128  };
129  changeListenersForRemoval.add(listener);
130 
131  addChangeListener(box, listener);
132  this.getChildren().add(box);
133  boxes.add(box);
134  }
135 
136 
137  /**
138  * This calls the listeners in the class! Probably not useful elsewhere
139  * We scope this into the class for easier access to the baseClass instead of every this pointing to the ChangeListener-anonymous class
140  * The visibility of this should be package. NOT public or private. Java seems to do this by not having a keyword at all! We don't what this definitely as public but nor do we want to create synthetic accessor(which might be preferred over public still)
141  * @param box the box that was selected
142  */
144  for (Consumer<TO> checkBoxListener : lambdaListeners) {
145  TO selected = getSelectedObject();
146  checkBoxListener.accept(selected);
147  }
148  }
149 
150 
151  /**
152  * Adds to the component a listener when its state is changed. Base cannot know which property is to be cared about
153  * @param box componetn to use
154  * @param listener function listen
155  */
156  protected abstract void addChangeListener(TC box, ChangeListener<Boolean> listener);
157 
158 
159  /**
160  * Will give the created new component to this class so no reflection is needed.
161  * Since the class is abstract anyways
162  * @param name ???
163  * @param object ???
164  * @return ??
165  */
166  protected abstract TC addCorrectComponent(String name, TO object);
167 
168 
169  /**
170  * Returns the inner ObservableList. Will break functionality. You have been warned
171  * @return the inner observableList
172  */
173  public ObservableList<StringAndObject<TO>> getItems() {
174  return items;
175  }
176 
177 
178  /**
179  * Updates the components to match given list
180  * @param list the objects to make the gui look like
181  */
182  public void UpdateComponents(ObservableList<StringAndObject<TO>> list){
183  clear();
184  for (StringAndObject<TO> stringAndObject : list) {
185  add(stringAndObject);
186  }
187  }
188 
189 
190  /**
191  * Addes the given object to the list
192  * @param object tallennettava olio
193  */
194  @Override
195  public void add(TO object){
196  add(null, object);
197  }
198 
199 
200  /**
201  * Adds example text to the list
202  * @param text teksti joka näytetään
203  */
204  @Override
205  public void addExample(String text){
206  add(text, null);
207  }
208 
209 
210  /**
211  * Clears the ObservableList that holds the objects
212  */
213  @Override
214  public void clear(){
215  getItems().clear();
216  ObservableList<Node> children = this.getChildren(); //Only removes the comboboxes added with the inner workings
217  for (TC node : boxes) {
218  children.remove(node);
219 
220  removeListener(node, changeListenersForRemoval);
221  /*for (ChangeListener<Boolean> listener : changeListenersForRemoval) {//Extra work to remove all of the listeners
222  //node.selectedProperty().removeListener(listener);
223  }*/
224  }
225  changeListenersForRemoval.clear();
226  boxes.clear();
227  }
228 
229 
230  /**
231  * Removes all the listeners from the node from the property they may be linked to
232  * @param node ???
233  * @param list ???
234  */
235  protected abstract void removeListener(TC node, ArrayList<ChangeListener<Boolean>> list);
236 
237 
238  private void setRows(String[] strings) {
239  ObservableList<StringAndObject<TO>> objects = getItems();
240  objects.clear();
241  for (String string : strings) {
242  add(string, null);
243  }
244  }
245 
246 
247  /**
248  * Sets the rows.
249  *
250  * @param jono
251  * A multiline string, each line representing a single row.
252  */
253  @Override
254  public void setRivit(String jono) {
255  this.rivit.set(jono);
256  String[] strings = jono.split("\n"); // erotinMerkki.get());
257  setRows(strings);
258  }
259 
260 
261  /**
262  * Sets the rows.
263  *
264  * @param rivit
265  * A string arrays, each line representing a single row.
266  */
267  @Override
268  public void setRivit(String[] rivit) {
269  StringBuilder sb = new StringBuilder();
270  String sep = "";
271  for (String s: rivit) { sb.append(sep).append(s); sep = "\n"; }
272  this.rivit.set(sb.toString());
273  setRows(rivit);
274  }
275 
276 
277  /**
278  * Palauttaa valitun olion tai null
279  * @return valittu olio tai null
280  */
281  @Override
282  public TO getSelectedObject() {
283  for (int i = 0; i < boxes.size(); i++) {
284  if(isComponentSelected(boxes.get(i)))
285  {
286  return items.get(i).getObject();
287  }
288  }
289  return null;
290  }
291 
292 
293  /**
294  * Returns the first selected text component
295  */
296  @Override
297  public String getSelectedText() {
298  for (int i = 0; i < boxes.size(); i++) {
299  if(isComponentSelected(boxes.get(i)))
300  {
301  return removeMnemonic(items.get(i).getName());
302  }
303  }
304  return null;
305  }
306 
307 
308  /**
309  * Returns the first selected index
310  */
311  @Override
312  public int getSelectedIndex() {
313  for (int i = 0; i < boxes.size(); i++) {
314  if(isComponentSelected(boxes.get(i)))
315  {
316  return i;
317  }
318  }
319  return -1;
320  }
321 
322 
323  @Override
324  public int setSelectedIndex(int index) {
325  int oldIndex = getSelectedIndex();
326  if ( index < 0 || boxes.size() <= index )
327  return oldIndex;
328  setComponentSelected(boxes.get(index), true);
329  return oldIndex;
330  }
331 
332 
333  /**
334  * Returns if the component should be selected by the baseboxchooser for getItems
335  * @param component the generic component that we want to know if is selected
336  * @return if the component is selected or not
337  */
338  protected abstract boolean isComponentSelected(TC component);
339 
340  /**
341  * Sets component selected
342  * @param component the generic component that we want to know if is selected
343  * @param value value to set for component
344  * @return if the component was selected or not
345  */
346  protected abstract boolean setComponentSelected(TC component, boolean value);
347 
348 
349  @Override
350  public List<TO> getSelectedObjects() {
351  List<TO> objects = new ArrayList<TO>();
352  for (int i = 0; i < boxes.size(); i++) {
353  if(isComponentSelected(boxes.get(i))){
354  objects.add(items.get(i).getObject());
355  }
356 
357  }
358  return objects;
359  }
360 
361 
362  @Override
363  public List<String> getSelectedTexts() {
364  List<String> objects = new ArrayList<String>();
365  for (int i = 0; i < boxes.size(); i++) {
366  if(isComponentSelected(boxes.get(i))){
367  objects.add(removeMnemonic(items.get(i).getName()));
368  }
369 
370  }
371  return objects;
372  }
373 
374 
375  @Override
376  public List<Integer> getSelectedIndices() {
377  List<Integer> objects = new ArrayList<Integer>();
378  for (int i = 0; i < boxes.size(); i++) {
379  if(isComponentSelected(boxes.get(i))){
380  objects.add(i);
381  }
382 
383  }
384  return objects;
385  }
386 
387 
388  /**
389  * Returns the contents of the ListChooser as a multiline string.
390  *
391  * @return The contents of the ListChooser as a multiline string.
392  */
393  public String getRivit() {
394  return rivit.get();
395  }
396 
397 
398  /**
399  * Sets the value if the component should be reset after the original example data
400  * @param reset should it be reset
401  */
402  public void setNollataanko(boolean reset){
403  nollataanko.set(reset);
404  }
405 
406 
407  /**
408  * Returns if the component was selected to be cleared
409  * @return should it be cleared
410  */
411  public boolean getNollataanko(){
412  return nollataanko.get();
413  }
414 
415 
416  /**
417  * Poistetaan alleviiva
418  * @param item mistä poistetaan
419  * @return ilman 1. alleviivaa
420  */
421  @Override
422  public String removeMnemonic(String item) {
423  return item.replaceFirst("_", "");
424  }
425 
426 }