001package org.vishia.gral.widget;
002
003import java.util.List;
004import java.util.Map;
005
006import org.vishia.gral.base.GralTable;
007import org.vishia.gral.base.GralWidget;
008import org.vishia.gral.ifc.GralMngBuild_ifc;
009import org.vishia.gral.ifc.GralMng_ifc;
010import org.vishia.gral.ifc.GralUserAction;
011import org.vishia.gral.ifc.GralTableLine_ifc;
012import org.vishia.util.Assert;
013import org.vishia.util.KeyCode;
014import org.vishia.util.Removeable;
015
016/**The base class for lists which supports nested selections. The associated widget is a table.
017 * The action listener {@link #actionTable} captures all key and mouse activities on the table-widget.
018 * It is the base class for file selection and command selection.
019 * The base idea is, left and right keys navigates in a tree to outer and deeper nodes. The table
020 * shows only members of the current node. A text line shows the current node path.
021 * It may be possible to switch to a tree presentation (TODO). But this complex widget should occupy
022 * only a simple rectangle of a GUI, not some windows etc. It may be less in spread too if necessary.
023 * <br><br>
024 * Note: this class should not be a derived class of {@link GralTable}, because instances of derived classes
025 * should be created as final compositions in the main thread before the table can be presented 
026 * in the graphic thread. Therefore the aggregation {@link #wdgdTable} cannot be final. It is set 
027 * only when {@link #setToPanel(GralMngBuild_ifc, String, int, int[], char)} is called.  
028 * <pre>
029 *  GralSelectList
030 *        |--{@link #wdgdTable}--->GralTable         TableLineData
031 *                                     |---idxLine------*>|
032 *                                     |---tableLines---*>|
033 * </pre>
034 * @author Hartmut Schorrig
035 *
036 */
037public abstract class GralSelectList<UserData> implements Removeable //extends GralWidget
038{
039  /**Version and history:
040   * <ul>
041   * <li>2018-10-28 Hartmut chg: {@link #createImplWidget_Gthread()} instead setToPanel(mng)
042   * <li>2011-11-18 chg: This class does not inherit from GralWidget now. The GralWidget, which represents this class,
043   *   is referenced with the public aggregation {@link #wdgdTable}. Only this instance is registered on a panel
044   *   calling {@link #setToPanel(GralMngBuild_ifc, String, int, int[], char)}. 
045   * <li>2011-10-02 chg: Uses keycodes from {@link KeyCode} now,
046   * <li>2011-10-02 chg: {@link #actionOk(Object, GralTableLine_ifc)} returns boolean now, false if no action is done.
047   * <li>older- TODO
048   * </ul>
049   * <b>Copyright/Copyleft</b>:
050   * For this source the LGPL Lesser General Public License,
051   * published by the Free Software Foundation is valid.
052   * It means:
053   * <ol>
054   * <li> You can use this source without any restriction for any desired purpose.
055   * <li> You can redistribute copies of this source to everybody.
056   * <li> Every user of this source, also the user of redistribute copies
057   *    with or without payment, must accept this license for further using.
058   * <li> But the LPGL ist not appropriate for a whole software product,
059   *    if this source is only a part of them. It means, the user
060   *    must publish this part of source,
061   *    but don't need to publish the whole source of the own product.
062   * <li> You can study and modify (improve) this source
063   *    for own using or for redistribution, but you have to license the
064   *    modified sources likewise under this LGPL Lesser General Public License.
065   *    You mustn't delete this Copyright/Copyleft inscription in this source file.
066   * </ol>
067   * If you are indent to use this sources without publishing its usage, you can get
068   * a second license subscribing a special contract with the author. 
069   * 
070   * @author Hartmut Schorrig = hartmut.schorrig@vishia.de
071   * 
072   */
073  public static final String version = "2018-10-28";
074  
075
076  /**The table which is showing in the widget. */
077  public GralTable<UserData> wdgdTable;
078  
079
080  /**The keys for left and right navigation. Default it is shift + left and right arrow key.
081   * 
082   */
083  protected int keyLeft = KeyCode.alt + KeyCode.left, keyRight = KeyCode.alt + KeyCode.right;
084  
085  
086  
087  /**Not used yet, register actions? */
088  protected Map<String, GralUserAction> actions;
089  
090  protected GralSelectList(String posName, int rows, int[] columns, char size) //String name, GralWidgetMng mng)
091  {
092    if(posName == null){
093      Assert.stop();
094    }
095    wdgdTable = new GralTable<UserData>(posName, rows, columns);
096    wdgdTable.setVisible(true);
097  }
098
099  
100  /**The left and right key codes for selection left and right can be changed.
101   * The key code is a number maybe in combination with alt, ctrl, shift see {@link KeyCode}.
102   * @param keyLeft Key code for outer selection
103   * @param keyRight KeyCode for deeper selection
104   */
105  public final void setLeftRightKeys(int keyLeft, int keyRight){
106    this.keyLeft = keyLeft; this.keyRight = keyRight;
107  }
108
109  //public SelectList()
110  //{
111  //  super('l');
112  //}
113
114
115  /**
116   * @param panel
117   * @param identArgJbat
118   * @param rows
119   * @param columns
120   * @param size
121   */
122  public void XXXsetToPanel(GralMngBuild_ifc gralMng)
123  {
124    wdgdTable.setToPanel(gralMng);
125    //wdgdTable = gralMng.addTable(name, rows, columns);
126    wdgdTable.setActionChange(actionTable);
127  }
128  
129 
130  
131  /**
132   */
133  public void createImplWidget_Gthread()
134  {
135    wdgdTable.createImplWidget_Gthread();
136    wdgdTable.setActionChange(actionTable);
137  }
138  
139 
140  
141  public void set(List<String[]> listData)
142  {
143    for(String[] data: listData){
144      wdgdTable.setValue(GralMng_ifc.cmdInsert, 0, data[0]);
145    }
146  }
147  
148  
149  /**Sets the focus of the associated table widget.
150   * @return true if focused.
151   */
152  public boolean setFocus(){ wdgdTable.setFocus(); return true; }
153  
154  /**Removes all data and all widgets of this class. */
155  @Override public boolean remove(){
156    wdgdTable.remove();
157    return true;
158  }
159  
160  /**Action if a table line is selected and entered. Its either a double click with the mouse
161   * or click of OK (Enter) button.
162   * @param userData The user data stored in the line of table.
163   */
164  protected abstract boolean actionOk(Object userData, GralTableLine_ifc<UserData> line);
165  
166  /**Action if a table line is selected and ctrl-left is pressed or the release button is pressed.
167   * @param userData The user data stored in the line of table.
168   */
169  protected abstract void actionLeft(Object userData, GralTableLine_ifc<UserData> line);
170  
171  /**Action if a table line is selected and ctrl-right is pressed or the release button is pressed.
172   * @param userData The user data stored in the line of table.
173   */
174  protected abstract void actionRight(Object userData, GralTableLine_ifc<UserData> line);
175  
176  
177  /**Action if a table line is selected and any other key is pressed or the context menu is invoked.
178   * @param key code or mouse code, one of constans from {@link KeyCode}.
179   * @param userData The user data stored in the line of table.
180   * @param line The table line.
181   * @return true if is was relevant for the key.
182   */
183  protected abstract boolean actionUserKey(int key, Object userData, GralTableLine_ifc<UserData> line);
184  
185  
186  private final GralUserAction actionTable = new GralUserAction("actionTable")
187  {
188
189    @Override public boolean userActionGui(int keyCode, GralWidget widgdTable, Object... params)
190    {
191      //assert(sIntension.equals("table-key"));
192      @SuppressWarnings("unchecked")
193      GralTableLine_ifc<UserData> line = (GralTableLine_ifc<UserData>)params[0];
194      Object data = line == null ? null : line.getUserData();
195      //int keyCode = (Integer)params[1];
196      boolean done = true;
197      if(data !=null) {
198        if(keyCode == keyLeft){ actionLeft(data, line); }
199        else if(keyCode == keyRight){ actionRight(data, line); }
200        else if(keyCode == KeyCode.enter){ done = actionOk(data, line); }
201        else if(keyCode == KeyCode.mouse1Double){ done = actionOk(data, line); }
202        else { done = actionUserKey(keyCode, data, line); }
203      } else {
204        done = false;
205      }
206      return done;
207    }
208    
209    
210  };
211
212
213  
214  void stop(){}
215  
216}