001package org.vishia.gral.base;
002
003import java.lang.reflect.Array;
004import java.util.Iterator;
005import java.util.LinkedList;
006import java.util.List;
007import java.util.concurrent.atomic.AtomicInteger;
008
009import org.vishia.byteData.VariableContainer_ifc;
010import org.vishia.fileRemote.FileMark;
011import org.vishia.gral.ifc.GralColor;
012import org.vishia.gral.ifc.GralMngBuild_ifc;
013import org.vishia.gral.ifc.GralRectangle;
014import org.vishia.gral.ifc.GralTableLine_ifc;
015import org.vishia.gral.ifc.GralTable_ifc;
016import org.vishia.gral.ifc.GralUserAction;
017import org.vishia.gral.ifc.GralWidget_ifc;
018import org.vishia.util.Assert;
019import org.vishia.util.Debugutil;
020import org.vishia.util.Docu_UML_simpleNotation;
021import org.vishia.util.IterableIterator;
022import org.vishia.util.KeyCode;
023import org.vishia.util.Removeable;
024import org.vishia.util.SelectMask;
025import org.vishia.util.MarkMask_ifc;
026import org.vishia.util.TreeNodeBase;
027import org.vishia.util.TreeNode_ifc;
028
029
030/**This is the Gral class for a table. Its usage is independent of a graphical implementation layer.
031 * A table consists of some text fields which are arranged in columns and lines. The lines can be associated
032 * to any user data.
033 * <br><br>
034 * <b>Data, text and graphic architecture of the table</b>:<br>
035 * All data which are managed in this table are contained in an Tree node {@link #rootLine} with a unlimited size. 
036 * That container references instances of {@link TableLineData}. 
037 * Each of that table line contains the texts which are displayed in the cells,
038 * the color etc., a key for searching and a reference to any user data. In that kind a table is a container class
039 * with a graphical touch.
040 * <br>
041 * For presenting the table in a graphic implementation some text fields are arranged in a line and column structure
042 * in any panel or canvas. The number of such fields for the lines is limited, only the maximal number of viewable 
043 * lines should be present (about 20 to 50), independent of the length of the table. 
044 * If any part of the table will be shown, that fields
045 * will be filled with the texts from the {@link TableLineData#cellTexts} of the corresponding line.
046 * If the table content will be shifted in the visible area, the text content of the fields are replaced. 
047 * <br><br>
048 * Each text field refers an instance of {@link CellData} as its
049 * 'user data'. The CellData refers via {@link CellData#tableItem} the line.
050 * 
051 * <pre>
052 *   Graphic representation     GralTable        {@link TableLineData}
053 *             |                   |<--------------<#>|           
054 *    |<*------+                   |                  |<>--userData--->User's data                    
055 *   TextField                     |---rootLine-----*>|
056 *    |<>------>CellData           |---lineSelected-->|-->cellTexts
057 *                 |                                  |-->colors
058 *                 |---tableItem--------------------->|
059 * </pre>
060 * UML presentation, see {@link Docu_UML_simpleNotation}.
061 * <br><br>
062 * A {@link TableLineData} refers any aggregated user data, associated with {@link #insertLine(String, int, String[], Object)}
063 * or {@link NodeTableLine#addChildLine(String, String[], Object)} etc. The user data can be gotten with {@link TableLineData#getUserData()}.
064 * The user data are not part of the graphical presentation by automatism. They can be used for graphical implementation
065 * by the application, especially to provide the texts or maybe colors for the table line cells. 
066 * <br><br>
067 * <b>Keyboard handling in a table</b>: <br>
068 * The table has its own {@link GraphicImplAccess#processKeys(int)} method which is called 
069 * from the graphical implementation layer in an key event handler.
070 * This method processes some keys for navigation and selection in the table. If the key is not
071 * used for that, first the action of {@link GralWidget#setActionChange(GralUserAction)}
072 * will be invoked with the key. If that method returns false,
073 * the key will be offer the {@link GralMng#userMainKeyAction} for a global key usage.
074 * <br>
075 * Especially Mouse double click etc. can be handled in the change action.
076 * 
077 * <br><br>
078 * <b>Focus handling in a table</b>: <br>
079 * <ul>
080 * <li>If a cell gets the focus by mouse click, whereby another cell of the table has lost the focus before,
081 *   the focus state of the table is not changed. Only the {@link #specifyActionOnLineSelected(GralUserAction)}
082 *   is called.
083 * <li>If a cell gets the focus by mouse click, whereby the table has not the focus before,
084 *   the {@link GralWidget#setActionFocused(GralUserAction)} is called from the focus action of the presentation graphic layer.
085 * <li>If {@link #setFocus()} is called from outside, the selected cell is marked with 
086 *   {@link GraphicImplAccess.CellData#bSetFocus}. The following repaint sets the focus for that cell.  
087 * </ul>
088 * 
089 * <br><br>
090 * <b>Adding an context menu</b>: <br>
091 * The {@link #addContextMenuEntryGthread(int, String, String, GralUserAction)} can be invoked for the table only in the graphic thread. 
092 * Use any {@link GralGraphicTimeOrder} to do that, use a callback with this time order on the creation of the table. 
093 * 
094 * @author Hartmut Schorrig
095 *
096 */
097@SuppressWarnings("synthetic-access") 
098public final class GralTable<UserData> extends GralWidget implements GralTable_ifc<UserData> {
099
100  /**Version, history and license.
101   * <ul>
102   * <li>2018-10-28 Hartmut chg: Now uses argument zLineMax from {@link #GralTable(String, int, int[])} instead constant 50 for number of showed lines.
103   * <li>2018-01-07 Hartmut new: {@link #getCellTextFocus()}  
104   * <li>2016-09-17 Hartmut new: in {@link #mouseDouble(int, CellData)} the <code>getActionChangeStrict(ActionChangeWhen.onMouse1Double, true)</code>
105   *   is checked. Therewith the new concept of {@link #specifyActionChange(String, GralUserAction, String[], org.vishia.gral.ifc.GralWidget_ifc.ActionChangeWhen...)}
106   *   for specific actions is used here now. Firstly only for the mouse double click action. TODO: for all specific actions. 
107   * <li>2016-09-01 Hartmut new: {@link #getIxLine(GralTableLine_ifc)} to determine the current position of a given table line.
108   * <li>2016-08-28 Hartmut chg: {@link GraphicImplAccess#setBoundsCells(int, int)} now gets the zLineVisible.
109   *   The {@link org.vishia.gral.swt.SwtTable#setBoundsCells(int, int)} sets the rest of texts invisible. Therewith the phenomena of ghost lines
110   *   on resizing are removed. 
111   * <li>2016-08-28 Hartmut chg:  Bugfix: In {@link org.vishia.gral.swt.SwtTable#resizeTable(GralRectangle)}: 
112   *   The {@link GralWidget#pos()} should not be used because the Composite is resized with it already. Instead the number of lines
113   *   is correctly calculated now and {@link GraphicImplAccess#setBoundsCells(int, int)} is invoked with that {@link #zLineVisible}.  
114   * <li>2015-11-19 Hartmut chg: Some changes for future: The cells should be managed in the GralTable, not in SwtTable. Adaption for AwtTable 
115   * <li>2015-10-29 Hartmut chg: {@link TableLineData#bChangedSet}, the content will be written in {@link org.vishia.gral.swt.SwtTable}
116   *   or another graphic implementation only if the text is changed. Therewith editing a table is possible while the other cells
117   *   are updated frequently. That can be used for tables which shows a current state, and a column is editable.
118   *   See {@link org.vishia.guiInspc.InspcViewTargetComm}.
119   * <li>2015-08-28 Hartmut chg: {@link #processKeys(int)}: Use tab and sh-tab to switch between the columns. 
120   *   This keys are used as 'traverse key' normally, but they are ignored for that now by a proper TraverseListener
121   *   in {@link org.vishia.gral.swt.SwtTable}. The standard traverse listener which is active for traversing between the
122   *   text fields of the table does not set the correct {@link #colSelectedixCellC} which is necessary for accept the column.
123   * <li>2015-08-28 Hartmut new: Search in columns:
124   *   <ul><li>Use the keys without shiftDigit-designation if it is a text key. It is not possible to use elsewhere.
125   *       <li>{@link #searchContent(boolean)}: If the search string starts with '*' it searches 'contains(...)'.
126   *   </ul>    
127   * <li>2015-07-12 Hartmut new: {@link TableLineData#setBackColor} with colorSelect etc. for content-depending table presentation. 
128   * <li>2015-06-21 Hartmut chg: Implementation of {@link TableLineData#setBackColor(GralColor, int}} 
129   *   now regards the ix-argument as cell index, like defined in comment.
130   * <li>2015-05-31 Hartmut chg: {@link GraphicImplAccess#processKeys(int}} updates the cell text in the line firstly
131   *  if it is an editing cell. It helps to get the correct text in the graphic thread.  
132   * <li>2014-12-26 Hartmut chg: {@link #colorBackSelectSomeMarked} etc.  
133   * <li>2013-12-23 Hartmut chg: Rename {@link #setColorBackSelectedLine(GralColor)} instead setColorCurrLine(): 
134   *   It is not the current line which is changed but the color setting for all current (= selected) lines. 
135   * <li>2013-12-23 Hartmut chg: {@link #checkAndUpdateText(String, CellData)} supports update text on edit cells.
136   * <li>2013-12-18 Hartmut chg: {@link CellData} is defined now public and as part of GralTable. There were a problem
137   *   using the Java7-Compiler with difficult Generic parameter mismatches. The CellData is a simple data class without
138   *   generic, but the compiler has interpreted a generic parameter. May the compiler wrong? The structure of a program
139   *   should be simple! The only one disadvantage is, {@link CellData} has to be public, not protected,
140   *   because it is not seen from the implementation class of {@link GraphicImplAccess}. Another problem was
141   *   {@link GraphicImplAccess#mouseDownGral()} etc. The compiler has a problem it was named 'mouseDown'
142   *   and 'super.mouseDown(ev)' was called from the derivated class. Keep it simple. It does not need the same name. 
143   * <li>2013-12-06 Hartmut new: {@link #setColumnEditable(int, boolean)}, supports editing in cells. 
144   * <li>2013-11-24 Hartmut chg: {@link GralTable.GraphicImplAccess#focusGained()} etc. refactored. 
145   * <li>2013-11-23 Hartmut chg: use {@link KeyCode#userSelect} etc. for calling {@link #actionOnLineSelected(int, GralTableLine_ifc)}
146   * <li>2013-11-16 Hartmut chg: setCurrentCell(int, int) removed because the line number without respect to a line
147   *   is not able to handle. Only a line is given. New method {@link #setCurrentLine(GralTableLine_ifc, int, int)}
148   *   can set the given line to any location in the visible area of table.  
149   * <li>2013-11-15 Hartmut new: {@link TableLineData} and {@link GraphicImplAccess} are non-static yet
150   *   because the generic type should be the same without additional effort. This is the reason.
151   *   Nevertheless the non-static property was given already, but deployed by the outer aggregation 
152   *   of the static one.
153   * <li>2013-10-03 Hartmut new: {@link TableLineData} now extends {@link TreeNodeBase}. It is a tree.
154   * <li>2013-10-03 Hartmut new: {@link GraphicImplAccess#cells}, the {@link GraphicImplAccess.CellData} are able to access
155   *   elsewhere only in the implementation layer via the text widget.
156   * <li>2013-11-02 Hartmut chg: {@link GralTable.TableLineData} is static now with outer reference, more transparent
157   * <li>2013-11-02 Hartmut chg: {@link GralTable.GraphicImplAccess#resizeTable(GralRectangle)} moved from SWT implementation,
158   *   preparing tree view. {@link GralTable.TableLineData#treeDepth}, {@link GralTable.TableLineData#childLines} for tree view.
159   * <li>2013-11-02 Hartmut chg: {@link GralTable.TableLineData} is static now with outer reference, more transparent
160   * <li>2013-10-06 Hartmut chg: call {@link #actionOnLineSelected(int, GralTableLine_ifc)} only if the line is changed, 
161   *   not on focus without changed line.
162   * <li>2013-09-15 Hartmut new: Implementation of {@link #setBackColor(GralColor, int)}  
163   *   with special comments for usage of the int parameter.
164   *   See {@link GralTable_ifc#setBackColor(GralColor, int)}, Adequate {@link #getBackColor(int)}. 
165   * <li>2013-09-14 Hartmut chg: {@link GraphicImplAccess} implements now {@link GralWidgImpl_ifc} without any other
166   *   changes (was proper) and sets {@link GralWidget#_wdgImpl}. Therefore all routines which works from the
167   *   GralWidget calls the methods of the implement of the GralTable immediately without special overridden methods
168   *   in this class. It is the concept.
169   * <li>2013-09-14 Hartmut chg: uses the {@link GralWidget.DynamicData#backColor} etc.
170   * <li>2013-08-11 Hartmut chg: {@link #getMarkedLines()} now checkes the {@link TableLineData#userData}
171   *   whether that is instanceof {@link MarkMask_ifc}. If true then uses its selection state
172   *   instead the selection state of the {@link TableLineData}.
173   * <li>2013-06-29 Hartmut chg: refactoring. Now a GralTable<generic> can be created before the graphic is build. It is the new schema of GralWidget.
174   *   The inner class {@link GraphicImplAccess} is provided as super class for the graphic implementation class,
175   *   for example {@link org.vishia.gral.swt.SwtTable}.
176   * <li>2013-06-12 Hartmut chg: On right mouse pressing the current line will be selected, because
177   *   the context menu should have an association to that line.
178   * <li>2013-06-12 Hartmut chg: A marked line is now designated with a background color. 
179   *   A selected marked line has another background than a selected non marked line (to see it).
180   * <li>2013-06-11 Hartmut new: Now the {@link GralTable}, the {@link GralTable.TableLineData} and this
181   *   interface are marked with the generic type UserData.
182   * <li>2013-05-22 Hartmut new: {@link TableLineData#lineInGraphic} not used yet, but for further usage.
183   *   Maybe for refresh data only if they are in the visible range. 2013-10-03 removed, too many effort on tree view.
184   *   To detect visible lines iterate over {@link GraphicImplAccess#cells}
185   * <li>2013-05-11 Hartmut chg: {@link #deleteLine(GralTableLine_ifc)} was not ready, now tested
186   * <li>2013-05-11 Hartmut chg: {@link TableLineData} instead TableItemWidget.
187   * <li>2013-04-28 Hartmut new: {@link #specifyKeysMarkUpDn(int, int)}
188   * <li>2013-04-28 Hartmut new: {@link #specifyActionOnLineMarked(MarkMask_ifc)}
189   * <li>2013-04-28 Hartmut renamed: {@link #actionOnLineSelected(int, GralTableLine_ifc)}
190   * <li>2013-04-21 Hartmut chg: {@link #processKeys(int)}: input of a text key starts searching for a line with this key
191   *   immediately, better handling for usage.
192   * <li>2012-08-22 Hartmut new {@link #setCurrentLine(int)} with int, it isn't new because it was able to set with
193   *   {@link #setCurrentCell(int, int)} with -1 as second parameter.
194   * <li>2012-07-15 Hartmut new: search functionality: The implementation should/may have a text field 
195   *   which shows the search string. While up and down keys the that lines are selected which text in the {@link #ixColumn}
196   *   starts with the search string.
197   * <li>2012-03-09 Hartmut bugfix: The {@link #idxLine} was not cleared if the table was cleared.
198   * <li>2012-02-19 Hartmut new: mouseWheel and double click
199   * <li>2012-01-30 Hartmut new: {@link #setColorCurrLine(GralColor)}
200   * <li>2012-01-15 Hartmut new: {@link #setCurrentLine(String)}, {@link #insertLine(String, int, String[], Object)}:
201   *    the key is supported now. 
202   * <li>2012-01-06 Hartmut new: concept of a table which is independent of the table implementation 
203   *   of the table implementations in the graphic system layer or in operation system: 
204   *   The capability  of a SWT-table is not sufficient, for example the color of the selection bar
205   *   is not able to change. Other reason: Implementation of table in SWT, AWT, Swing is different.
206   *   It seems better to have one table concept with independent features, which based on simple widgets.
207   *   is not  
208   * <li>2011-12-30 Hartmut chg {@link #procStandardKeys(int, GralTableLine_ifc, int)} returns true if standard keys are used. 
209   * <li>2011-11-27 Hartmut new {@link #actionOnLineSelected(int, GralTableLine_ifc)}: The user action is called
210   *   anytime if a line is selected by user operation. It can be show any associated content anywhere
211   *   additionally. It is used for example in "The.file.Commander" to show date, time and maybe content 
212   *   while the user selects any files. The graphical implementation should be call {@link #actionOnLineSelected(int, GralTableLine_ifc)}
213   *   in its Selection listener. 
214   * <li>2011-11-20 Hartmut new The capability of selection of lines is moved from the 
215   *   {@link org.vishia.gral.widget.GralSelectList} to this class. It means any table has the capability
216   *   of selection of multiple lines. This capability is supported with a extension of the
217   *   {@link GralTableLine_ifc} with {@link org.vishia.util.MarkMask_ifc}. The selection of a line
218   *   is notificated in the users data which are associated with the table line, not in the graphic
219   *   representation of the table. This is differenced to SWT Table implementation. The capability
220   *   of selection in an SWT table isn't used. The selection is done by default with shift-key up/down
221   *   or with mouse selection ctrl-click, shift-click like usual.
222   *   The selection is not missed if the up/down keys are pressed furthermore. More as that,
223   *   more as one ranges of lines can be selected. That is a better capability than in SWT.
224   * </ul>
225   * 
226   * <b>Copyright/Copyleft</b>:
227   * For this source the LGPL Lesser General Public License,
228   * published by the Free Software Foundation is valid.
229   * It means:
230   * <ol>
231   * <li> You can use this source without any restriction for any desired purpose.
232   * <li> You can redistribute copies of this source to everybody.
233   * <li> Every user of this source, also the user of redistribute copies
234   *    with or without payment, must accept this license for further using.
235   * <li> But the LPGL is not appropriate for a whole software product,
236   *    if this source is only a part of them. It means, the user
237   *    must publish this part of source,
238   *    but don't need to publish the whole source of the own product.
239   * <li> You can study and modify (improve) this source
240   *    for own using or for redistribution, but you have to license the
241   *    modified sources likewise under this LGPL Lesser General Public License.
242   *    You mustn't delete this Copyright/Copyleft inscription in this source file.
243   * </ol>
244   * If you are intent to use this sources without publishing its usage, you can get
245   * a second license subscribing a special contract with the author. 
246   * 
247   * @author Hartmut Schorrig = hartmut.schorrig@vishia.de
248   * 
249   */
250  protected final static String sVersion = "2018-10-28";
251
252  
253  protected int keyMarkUp = KeyCode.shift + KeyCode.up, keyMarkDn = KeyCode.shift + KeyCode.dn;
254  
255  protected int keyOpenChild = KeyCode.right, keyCloseChild = KeyCode.left;
256  
257  protected String keySeparator = "/";
258  
259  //protected final Map<String, TableLineData> idxLine = new TreeMap<String, TableLineData>();
260  
261  /**This action will be called any time when the selection of the current line is changed. 
262   * The {@link GralUserAction#exec(int, GralWidget_ifc, Object...)} will be called
263   * with the line as Object. */
264  GralUserAction actionOnLineSelected;
265  
266  /**This action will be called any time when children of a tree node line should be refreshed. 
267   * The {@link GralUserAction#exec(int, GralWidget_ifc, Object...)} will be called
268   * with the line as Object. */
269  GralUserAction actionOnRefreshChildren;
270  
271  /**Width of each column in GralUnits. */
272  protected int[] columnWidthsGral;
273  
274  protected boolean[] bColumnEditable;
275  
276  protected GralMenu[] menuColumns;
277  
278
279  
280  GraphicImplAccess gi;
281
282  
283  /**The currently selected cell. */
284  protected int lineSelectedixCell, colSelectedixCellC;
285  
286  protected int lineSelectedNewixCell;
287  
288  /**Array of lines which are currently associated to the cells of the implementation layer.
289   * It means they are the showing lines. Note that the TableLineData referred with the {@link #rootLine}
290   * are all of the lines of the table. They are not associated to any graphic widget any time.
291   * Whether they are associated to a graphic widget or not is able to evaluate with this array.
292   * The cellLines[0] is the TableLineData of the first visible line in any case etc.
293   */
294  protected TableLineData[] linesForCell;
295  
296  boolean bChangedLinesForCell;
297
298  /**The current line. */
299  protected TableLineData lineSelected;
300  
301  
302  /**The line which is selected by mouse pressing, for right mouse menu. */
303  protected TableLineData lineSelectedNew;
304  
305  
306  /**Number of lines and columns of data. */
307  protected int zLine, zColumn;
308  
309  /**Current number of visible lines in the view. */
310  protected int zLineVisible;
311  
312  protected int zLineVisibleMax;
313  
314  /**Number of lines and number of the current line. It is -1 if this numbers should be evaluated from {@link #rootLine}
315   */
316  private int zLineCurr = 0, nLineFirst = -1;
317  
318  
319  protected final StringBuilder searchChars = new StringBuilder(20);
320  
321  /**Any line of the table has one TableItemWidget, a long table has some more.
322   * Contains content, color, selection etc. of the lines with there cells.
323   * 
324   */
325  //protected ArrayList<TableLineData> tableLines = new ArrayList<TableLineData>();
326  
327  
328  /**The root for all lines of the table. It may be a tree. The lines are the nodes of the tree which are shown.
329   */
330  NodeTableLine rootLine;
331  
332  
333  /**True if a line or a column is marked. */
334  //protected boolean[] markedLines, markedColumns;
335  
336  /**If true then the graphic implementation fields for cells should be filled newly with the text. */
337  protected boolean bPrepareVisibleArea;
338  
339  
340  /**Difference of changing ixLine for cells. 0: Assignment not changed.
341   * It is used in {@link #redrawTableWithFocusedCell(CellData)}
342   */
343  protected int XXXdLineForCells;
344  
345  /**Check the last time of redrawing. */
346  protected long timeLastRedraw;
347  
348  /**If set, then a next key will be processed. It is set to false if a key event is executed
349   * and it is set to true in {@link #keyActionDone}. */
350  protected boolean keyDone = true;
351  
352  /**The last key which was pressed  */
353  private int lastKey;
354  
355  /**Number of key repetitions if a key was not used because the redraw was pending yet. */
356  private int keyRepetition;
357  
358  
359
360  
361  /**Data of that cell which was pointered while any mouse button is pressed. */
362  //protected CellData cellDataOnMousePressed;
363  
364  /**The color of the current line. It is the selected line */
365  protected GralColor colorBackSelect;
366  /**The color of that lines which are marked. */
367  protected GralColor colorBackMarked;
368  /**The color of the current, the selected line if it is marked. */
369  protected GralColor colorBackSelectMarked;
370  /**The color of that lines which's some children are marked. */
371  protected GralColor colorBackSomeMarked;
372  /**The color of the current selected line if some children of it are marked. */
373  protected GralColor colorBackSelectSomeMarked;
374  
375  protected GralColor colorBackSelectNew;
376  protected GralColor colorBackSelectNewMarked;
377  
378  protected GralColor colorTextSelect;
379  protected GralColor colorTextMarked;
380  
381  
382  protected GralColor colorSelectCharsBack;
383  protected GralColor colorSelectChars;
384
385  /**Background of VscrollBar. */
386  protected GralColor colorBackVscrollbar;
387  
388  /**20 nuances of color for the slider of the vertical scrollBar. The nuances depends on the pixel size. */
389  protected final GralColor[] colorSliderVscrollbar = new GralColor[10];
390  
391  
392  /**This action will be called if any line is marked. It may be null, see 
393   * 
394   */
395  protected MarkMask_ifc actionMarkOnLine;
396  
397
398  /**Constructs a table which should be positioned on {@link #setToPanel(GralMngBuild_ifc)}
399   * see {@link #GralTable(String, int, int[])}, zLineMax is 50. 
400   */
401  public GralTable(String posName, int[] columnWidths) {
402    this(posName, 50, columnWidths);
403  }
404  
405  
406  
407  
408  /**Constructs a table which should be positioned on {@link #setToPanel(GralMngBuild_ifc)}
409   * @param pos String given position in GralPos units.
410   * @param zLineMax maximal number of lines managed for content. It should be related to the size of viewing. 10..50 is proper.
411   * @param name to register for symbolic access
412   * @param columnWidths positive value from left: width, negative value from right: width. 
413   *   The last column with a positive width is used for sizeable. 
414   */
415  public GralTable(String posName, int zLineMax, int[] columnWidths) {
416    super(posName, 'L');
417    this.columnWidthsGral = columnWidths;
418    this.zColumn = columnWidths.length;
419    this.bColumnEditable = new boolean[this.zColumn];  //all false.
420    
421    rootLine = new NodeTableLine("", null);
422    rootLine.showChildren = true;
423    rootLine.treeDepth = -1; //children of rootline are level 0
424    rootLine.zLineUnfolded = 0;  //count added line.
425    
426    @SuppressWarnings("unchecked")
427    TableLineData[] linesForCell1 = (TableLineData[])Array.newInstance( TableLineData.class, zLineMax );
428    linesForCell = linesForCell1; //Hint: linesForCell = new GralTable<UserData>.TableLineData[50]; does not work because TableLineData is generic.
429    zLineVisibleMax = linesForCell.length;
430    setColors();
431  }
432
433  
434  
435  
436  /**Constructs a table with position
437   * @param pos String given position in GralPos units.
438   * @param name to registrate
439   * @param columnWidths positive value from left: width, negative value from right: width. 
440   *   The last column with a positive width is used for sizeable. 
441   */
442  public GralTable(String pos, String name, int[] columnWidths) 
443  { this(pos !=null ? ((pos.startsWith("@") ? "" : "@") + pos + "=" + name) : name, columnWidths); }
444  
445  
446  
447  public int nrofLinesVisibleMax(){ return zLineVisibleMax; }
448  
449  /**Sets an action which is called any time when another line is selected.
450   * This action will be called any time when the selection of the current line is changed. 
451   * The {@link GralUserAction#userActionGui(int, GralWidget, Object...)} will be called
452   * with the line as Object and the following keys:
453   * <ul>
454   * <li>{@link KeyCode#removed} if the table was cleard.
455   * <li>{@link KeyCode#defaultSelect} if the table was filled and firstly the {@link #lineSelected} is set.
456   * <li>{@link KeyCode#userSelect} if the user acts with keyboard or mouse
457   * </ul>
458   * @param actionOnLineSelected The action, null to switch off this functionality.
459   */
460  public void specifyActionOnLineSelected(GralUserAction action){
461    this.actionOnLineSelected = action;
462  }
463  
464  
465  public void specifyActionOnLineMarked(MarkMask_ifc action){
466    actionMarkOnLine = action;
467  }
468  
469  /**Sets an action which is called any time when another line is selected.
470   * This action will be called any time when the selection of the current line is changed. 
471   * The {@link GralUserAction#userActionGui(int, GralWidget, Object...)} will be called
472   * with the line as Object.
473   * @param actionOnLineSelected The action, null to switch off this functionality.
474   */
475  public void specifyActionOnRefreshChildren(GralUserAction action){
476    this.actionOnRefreshChildren = action;
477  }
478  
479  
480  /**Specifies the keys to mark lines in the table.
481   * Without invocation of this method the keys {@link KeyCode#shift} + {@link KeyCode#up}
482   * respectively shift+dn are specified.
483   * @param up Any code defined in {@link KeyCode} which marks a line and selects the next line after them.
484   * @param dn Any code defined in {@link KeyCode} which marks a line and selects the previous line after them.
485   */
486  public void specifyKeysMarkUpDn(int up, int dn){
487    keyMarkUp = up; keyMarkDn = dn;
488  }
489  
490  
491  
492
493  
494  /**Adds a context menu entry for the given column.
495   * It is an abbreviation for {@link #getContextMenuColumn(int)} 
496   * and {@link GralMenu#addMenuItem(String, String, GralUserAction)}.
497   * The context menu is valid for the column of the whole table independent of the line. In the 
498   * {@link GralUserAction#exec(int, GralWidget_ifc, Object...)} method (param action) the given widget
499   * is the whole table. To get the line where the mouse was pressed:
500   * <ul>
501   * <li>{@link #getLineMousePressed()} returns the line where the mouse was pressed to open the context menu
502   * <li>{@link #getCurrentLine()} returns the line which was selected before. It is possible especially to work with both lines.
503   *   The mouse button for the context menu does not change the current line of the table.
504   * </ul>
505   *  
506   * @param col The column, see {@link #getContextMenuColumn(int)}
507   * @param identArgJbat The name of the entry, see {@link GralMenu#addMenuItem(String, String, GralUserAction)}
508   * @param sMenuPath same like {@link GralMenu#addMenuItem(String, String, GralUserAction)}
509   * @param action the action invoked on menu entered.
510   */
511  public void addContextMenuEntryGthread(int col, String menuname, String sMenuPath, GralUserAction action){
512    GralMenu menu = getContextMenuColumn(col);
513    menu.addMenuItem(this, menuname, sMenuPath, action);
514  }
515  
516
517  /**Returns the same context menu for all cells of the designated column. Each cells of the column gets the same context menu.
518   * It means the action has not any knowledge about the cell which has used to start the context menu.
519   * Only the whole table is associated. The advantage of this in comparison to {@link #getContextMenuColumnCells(int)}
520   * is: Some resources are saved, because there is only one menu item instance in the implementation layer
521   * of the graphic for all cells.<br>
522   * See {@link #getContextMenuColumnCells(int)}. Note that the {@link GralWidget_ifc}-parameter of the 
523   *   {@link GralUserAction#exec(int, GralWidget_ifc, Object...)} methods of all added menu entries
524   *   are given with the whole table, instance of this {@link GralTable}.
525   *
526   *  
527   * @param col The column of the table, count from 0,1,...
528   * @return The menu to add {@link GralMenu#addMenuItem(String, String, GralUserAction)}.
529   */
530  public GralMenu getContextMenuColumn(int col){
531    if(menuColumns == null){
532      menuColumns = new GralMenu[zColumn];
533    }
534    if(menuColumns[col] == null){
535      menuColumns[col] = gi.createColumnMenu(col); //for all cells of this column
536    }
537    return menuColumns[col];
538  }
539  
540  
541  /**Adds a context menu entries to all cells of the designated column. This method can't be used 
542   * if either {@link #getContextMenuColumn(int)} or {@link #addContextMenuEntryGthread(int, String, String, GralUserAction)}
543   * are called before. That is because either only one context menu can be added to all cells of a column
544   * (saves resources) or internal an extra context menu with the same appearance can be addes to all cells
545   * of the column. Using this method creates a context menu and its entry for all cells of the column
546   * with an extra menu instance. The reason of the extra instance is: The menu instance associates the cell, 
547   * and the cell associates the table line via {@link GralTableLine_ifc}. Because that the 
548   * {@link GralWidget_ifc}-parameter of the {@link GralUserAction#exec(int, GralWidget_ifc, Object...)}
549   * of the action parameter refers the cell. Use the following template for the action:
550   * <pre>
551   * </pre>
552   *  
553   * @param col The column of the table, count from 0,1,...
554   * @return The menu to add {@link GralMenu#addMenuItem(String, String, GralUserAction)}.
555   */
556  public GralMenu getContextMenuColumnCells(int col, String name, String sMenuPath, GralUserAction action){
557    return null;
558  }
559  
560  
561  public void setColumnWidth(int width, int[] columnWidths){
562    columnWidthsGral = columnWidths;
563  }
564  
565  
566  /**Sets the specified column to edit-able or not. This routine can be invoked before the graphic implementation
567   * is created (before {@link #setToPanel(GralMngBuild_ifc)} or after them in running mode. 
568   * 
569   * @param column the number, starting by 0. 
570   * @param val true then edit-able, false then read only.
571   * @throws IndexOutOfBoundsException on faulty column.
572   */
573  public void setColumnEditable(int column, boolean val){
574    bColumnEditable[column] = val;
575    if(((GralWidget)this)._wdgImpl !=null){
576      dyda.setChanged(GraphicImplAccess.chgEditableColumn);
577      repaint(repaintDelay, repaintDelayMax);
578    }
579  }
580  
581  @Override public boolean setCurrentLine(String key){
582    Object oLine = rootLine.getNode(key, keySeparator);
583    if(oLine instanceof GralTableLine_ifc) {
584      @SuppressWarnings("unchecked") 
585      GralTableLine_ifc<UserData> line = (GralTableLine_ifc<UserData>)oLine;
586      setCurrentLine(line, lineSelectedixCell, -1);
587      return true;
588    } else return false;
589  }
590  
591  //@Override public boolean setCurrentLine(int nLine){ return setCurrentCell(nLine, -1); }
592
593  
594  void setColors(){
595    colorBackSelect = GralColor.getColor("lam");
596    colorBackSelectNew = GralColor.getColor("lbl");
597    
598    colorBackMarked = GralColor.getColor("lrd");
599    colorBackSelectMarked = GralColor.getColor("rd");
600    
601    colorBackSomeMarked = GralColor.getColor("pma");
602    colorBackSelectSomeMarked = GralColor.getColor("lma");
603    
604    colorBackSelectNewMarked = GralColor.getColor("lpu");
605    dyda.backColor = GralColor.getColor("wh");
606    dyda.backColorNoFocus = GralColor.getColor("pgr");
607    //colorBackSelectNonFocused = GralColor.getColor("am");
608    //colorBackMarkedNonFocused = GralColor.getColor("lrd");
609    //colorBackTableNonFocused = GralColor.getColor("gr");
610    dyda.textColor = GralColor.getColor("bk");
611    colorSelectCharsBack = GralColor.getColor("lgr");
612    colorSelectChars = GralColor.getColor("wh");
613    colorBackVscrollbar = GralColor.getColor("lgr");
614    int rd1,gn1, bl1, rd2, gn2, bl2;
615    bl1 = colorBackVscrollbar.getColorValue();
616    rd1 = (bl1 >>16) & 0xff;
617    gn1 = (bl1 >>8) & 0xff;
618    bl1 = bl1 & 0xff;
619    colorSliderVscrollbar[0] = GralColor.getColor("bl");
620    bl2 = colorSliderVscrollbar[0].getColorValue();
621    rd2 = (bl1 >>16) & 0xff;
622    gn2 = (bl1 >>8) & 0xff;
623    bl2 = bl1 & 0xff;
624    
625    for(int ix=1; ix < colorSliderVscrollbar.length; ++ix){
626      float r = 0.8f * ((float)(ix)) / (colorSliderVscrollbar.length);  //max. 0.8
627      int rd = rd2 + (int)((rd1 - rd2) * r);
628      int gn = gn2 + (int)((gn1 - gn2) * r);
629      int bl = bl2 + (int)((bl1 - bl2) * r);
630      colorSliderVscrollbar[ix] = GralColor.getColor(rd, gn, bl);
631    }
632  }
633  
634  
635  
636  
637  /**Sets the focus of the table.
638   * It sets an information that the selected cell should focused while drawing ({@link GraphicImplAccess.CellData#bSetFocus}).
639   * Than it invokes the overridden super.{@link GralWidget#setFocus(int, int)}. 
640   * That method asserts the visibility of the table and calls {@link GralWidgImpl_ifc#setFocusGThread()}
641   * That method is implemented in the implementation widget layer and causes a redraw which focused
642   * the correct cell. 
643   * @see org.vishia.gral.base.GralWidget#setFocus(int, int)
644   */
645  @Override public void setFocus(int delay, int latest){
646    if(gi !=null){
647      gi.cells[lineSelectedixCell][colSelectedixCellC].bSetFocus = true;  //will be processed on redraw
648      super.setFocus(delay, latest);
649    }
650  }
651  
652  
653
654  
655  
656  @Override
657  public void setCurrentLine(GralTableLine_ifc<UserData> line, int ixline, int ixcolumn) {
658    int ixline1 = ixline >= 0 ? ixline: zLineVisible + ixline;  //negative: -1 is the last line.
659    if(ixline1 < 0) { ixline1 = 0;}
660    if(ixline1 >= zLineVisible) { ixline1 = zLineVisible-1; }
661    assert(zLineVisible >0);
662    assert(ixcolumn < gi.cells[0].length);
663    lineSelected = (TableLineData)line;
664    nLineFirst = -1;  //get new, undefined elsewhere.
665    actionOnLineSelected(KeyCode.userSelect, lineSelected);
666    lineSelectedixCell = ixline1;
667    if(lineSelectedixCell >= zLineVisible){
668      lineSelectedixCell = zLineVisible -1;
669    }
670    if(ixcolumn >=0){
671      this.colSelectedixCellC = ixcolumn;
672    }
673    bPrepareVisibleArea = true;
674    repaint();
675  }
676
677  
678  
679  /**Sets the color of the currently selected line. 
680   * @param color
681   */
682  public void setColorBackSelectedLine(GralColor color){ 
683    colorBackSelect = color; 
684    repaint(100, 0);
685  }
686
687  
688
689  
690  /**Returns the current selected line. */
691  @Override
692  public TableLineData getCurrentLine() {
693    return lineSelected;
694  }
695
696  
697  /**Returns the temporary selected line while pressing the mouse button.
698   * This method is able to use especially in mouse actions of user level.
699   * On pressing any mouse button the line on mouse position is set independent of the current line.
700   * The {@link #lineSelected()} is unchanged in this moment. 
701   * @return The line where the mouse button is pressed.
702   */
703  public TableLineData getLineMousePressed(){ return lineSelectedNew; }
704  
705  
706  
707
708  @SuppressWarnings("unchecked") @Override
709  public GralTableLine_ifc<UserData> getLine(String key) {
710    Object oRootline = rootLine.getNode(key, keySeparator);
711    if(oRootline instanceof GralTableLine_ifc){ return (GralTableLine_ifc<UserData>) oRootline; }
712    else return null;
713  }
714
715
716  
717  /**Gets the text of any cell which is in focus. 
718   * This is a special routine: If no line is selected, it is possible that a text in a cell were written which is not assiciated to a line.
719   * @return
720   */
721  public String getCellTextFocus() {
722    if(gi !=null) return gi.getCellTextFocus();
723    else return null;
724  }
725  
726
727  /**Gets the index in the visual presentation of the given line.
728   * @param line any line of this table, maybe null, maybe a line from any other table
729   * @return 0 for the first line, 1..., -1 if not found respectively the line is not in the visible area. 
730   *  Return index of the first not defined line (current length of table) if line==null
731   */
732  public int getIxLine(GralTableLine_ifc<UserData> line) {
733    for(int ix = 0; ix < linesForCell.length; ++ix) {
734      TableLineData line1 = linesForCell[ix];
735      if(line1 == line) return ix;
736    }
737    return -1; //not found;
738  }
739  
740  
741  @Override public TableLineData insertLine(String lineKey, int row, String[] lineTexts, UserData userData) {
742    if(row ==0){
743      //insert on top
744      TableLineData lineBehind = rootLine.firstChild();
745      if(lineBehind ==null){
746        return rootLine.addChildLine(lineKey, lineTexts, userData);
747      } else {
748        return lineBehind.addPrevLine(lineKey, lineTexts, userData);
749      }
750    } else if(row < 0) {
751      return addLine(lineKey, lineTexts, userData);
752    } else {
753      throw new IllegalArgumentException("GralTable.insertLine - row not supported,row= " + row);
754    }
755  }
756  
757  
758  
759  public TableLineData XXXinsertLine(String key, int row, String[] cellTexts, UserData userData) {
760    TableLineData line = this.new TableLineData(key, userData);
761    
762    if(row > zLine || row < 0){
763      row = zLine;
764    }
765    if(row == 0){
766      rootLine.addNodeFirst(line);  //addOnTop
767    }
768    if(lineSelected == null){ 
769      lineSelected = line;
770      actionOnLineSelected(KeyCode.defaultSelect, lineSelected);
771    }
772    zLine +=1;
773    if(zLineCurr >= 0){ 
774      zLineCurr +=1;
775    }
776    if(cellTexts !=null){
777      for(int ixCol = 0; ixCol < cellTexts.length && ixCol < line.cellTexts.length; ++ixCol){
778        line.cellTexts[ixCol] = cellTexts[ixCol];
779      }
780    }
781    bPrepareVisibleArea = true;
782    repaint(100, 0);
783    return line;
784  }
785
786  
787  
788  /* (non-Javadoc)
789   * @see org.vishia.gral.ifc.GralTable_ifc#addLine(java.lang.String, java.lang.String[], java.lang.Object)
790   */
791  @Override public TableLineData addLine(String lineKey, String[] lineTexts, UserData userData) {
792    return rootLine.addChildLine(lineKey, lineTexts, userData);
793  }
794    
795    
796  public TableLineData XXXaddLine(String key, String[] cellTexts, UserData userData) {
797    
798    TableLineData line = this.new TableLineData(key, userData);
799    if(lineSelected == null){ //// 
800      lineSelected = line;
801      actionOnLineSelected(KeyCode.defaultSelect, lineSelected);
802      if(zLineCurr == -1){ 
803        zLineCurr = 0;
804        nLineFirst = 0;
805      }
806    }
807    if(zLineCurr >= 0){
808      zLineCurr +=1;
809    }
810    zLine += 1;
811    rootLine.addNode(line);
812    if(cellTexts !=null){
813      for(int ixCol = 0; ixCol < cellTexts.length && ixCol < line.cellTexts.length; ++ixCol){
814        line.cellTexts[ixCol] = cellTexts[ixCol];
815      }
816    }
817    bPrepareVisibleArea = true;
818    repaint();
819    return line;
820  }
821
822  
823  
824  
825  @Override public void deleteLine(GralTableLine_ifc<UserData> line) {
826    line.deleteLine();
827  }
828  
829  
830  /**Returns in iterable object for the lines which can used in a for-element expression
831   * or in a {@link Iterator} usage.
832   * Because the class {@link TableLineData} implements the {@link GralTableLine_ifc}
833   * the user can write for example: <pre>
834   * for(GralTableLine_ifc<MyData> line: widgTableVariables.iterLines()) {
835   *    MyData data = line.getUserData();
836   *    line.setBackColor(colorXY, 0);
837   *  }
838   * </pre>
839   * @return
840   */
841  public IterableIterator<TableLineData> iterLines(){
842    return rootLine.iterator();
843  }
844  
845  
846  
847  @Override public int size(){ 
848    if(zLineCurr < 0) {
849      //TODO count
850    }
851    return zLine; 
852  }
853  
854
855  @Override public void clearTable() {
856    colSelectedixCellC = 0;
857    zLine = 0;
858    zLineCurr = 0;
859    nLineFirst = -1;
860    lineSelected = null;
861    actionOnLineSelected(KeyCode.removed, lineSelected);
862    searchChars.setLength(0);
863    for(int ix = 0; ix < linesForCell.length; ++ix){
864      linesForCell[ix] = null;
865    }
866    bChangedLinesForCell = true;
867    rootLine.clear();
868    bPrepareVisibleArea = true;
869    repaint(200,200);
870  }
871
872  
873  
874  
875  
876  @Override public List<GralTableLine_ifc<UserData>> getMarkedLines(int mask) {
877    List<GralTableLine_ifc<UserData>> list = new LinkedList<GralTableLine_ifc<UserData>>();
878    
879    for(TableLineData item: rootLine.iterator()){
880      if(item.data instanceof MarkMask_ifc){
881        if((((MarkMask_ifc)item.data).getMark() & mask) !=0){
882          list.add(item);
883        }
884      }
885      else if((item.getMark() & mask) !=0){
886        list.add(item);
887      }
888    }
889    return list;
890  }
891
892  
893  @Override public TreeNode_ifc<?, UserData> getAllLines() { return rootLine; }
894  
895  
896  @Override public List<UserData> getListContent() {
897    List<UserData> list = new LinkedList<UserData>();
898    for(TableLineData item: rootLine.iterator()){
899      list.add(item.getUserData());
900    }
901    return list;
902  }
903
904  
905  @Override public GralTableLine_ifc<UserData> getFirstMarkedLine(int mask) {
906    for(TableLineData item: rootLine.iterator()){
907      if((item.getMark() & mask) !=0){
908        return item;
909      }
910    }
911    return null;
912  }
913
914  
915  
916  
917  
918  private void fillVisibleArea(){
919    TableLineData line = lineSelected;
920    int ix = lineSelectedixCell;
921    while(ix >0 && line !=null){
922      line = prevLine(line);
923      if(line !=null){
924        linesForCell[--ix] = line;
925      }
926    }
927    int nLinesBefore = lineSelectedixCell - ix;  //==lineStart if all lines are present.
928    if(ix > 0){
929      System.arraycopy(linesForCell, ix, linesForCell, 0, nLinesBefore);
930      lineSelectedixCell = nLinesBefore;
931    }
932    bChangedLinesForCell = true;
933    fillVisibleAreaBehind(lineSelected, nLinesBefore);
934  }
935  
936  
937  
938  private void fillVisibleAreaBehind(TableLineData lineStart, int ixStart){
939    int ix = ixStart;
940    TableLineData line = lineStart;
941    while(line !=null && ix < zLineVisible) {
942      linesForCell[ix] = line;
943      line = nextLine(line);
944      ix +=1;
945    } 
946    while(ix < zLineVisible){
947      linesForCell[ix++] = null;
948    }
949    bChangedLinesForCell = true;
950    
951  }
952  
953
954  
955  /**Shifts the content in {@link #linesForCell} to show the appropriate part of data 
956   * (e.g. lines of {@link #rootLine})in the table.
957   * @param dLine >0 shift up to get next lines, <0 shift down to get previous lines
958   * @return nr of lines shifted
959   */
960  protected int shiftVisibleArea(int dLine){
961    int dLine1 = dLine;
962    if(dLine >0){ //forward in lines
963      TableLineData line = linesForCell[zLineVisible -1];  //the last line
964      while(line !=null && dLine1 >0){
965        line = nextLine(line);
966        if(line !=null){
967          System.arraycopy(linesForCell, 1, linesForCell, 0, zLineVisible-1);
968          linesForCell[zLineVisible-1] = line;
969          dLine1 -=1;
970          bChangedLinesForCell = true;
971        }
972      }
973    } else if(dLine < 0){ //backward in lines
974      TableLineData line;
975      line = linesForCell[0];  //the new start line
976      if(line == null){
977        line = rootLine.firstChild(); //outer.tableLines.size() ==0 ? null : outer.tableLines.get(0);  //on init
978      }
979      while(line !=null && dLine1 < 0){
980        line = prevLine(line);
981        if(line !=null){
982          System.arraycopy(linesForCell, 0, linesForCell, 1, zLineVisible-1);
983          linesForCell[0] = line;
984          dLine1 +=1;
985          bChangedLinesForCell = true;
986        }
987      }
988    }
989    int nLineShift = dLine - dLine1;
990    if(nLineShift !=0){
991      nLineFirst += nLineShift;
992    }
993    return nLineShift;
994  }
995  
996  
997  TableLineData nextLine(TableLineData lineP){
998    TableLineData line = lineP;
999    TableLineData linenext = null;
1000    if(line.showChildren){
1001      linenext = line.firstChild();         //deeper to any children
1002    }
1003    if(linenext == null){ //no children found
1004      linenext = line.nextSibling();  //may go to next root
1005    }
1006    while(linenext == null //no sibling found
1007      && line.parent() !=null  
1008      && !line.parentEquals(rootLine)) 
1009    {
1010      line = line.parent();
1011      if(line !=null){
1012        linenext = line.nextSibling();  //may null, then repeat for next parent
1013      }
1014    }
1015    return linenext;  //maybe null
1016  }
1017  
1018  
1019  TableLineData prevLine(TableLineData lineP){
1020    TableLineData line2 = lineP, line = lineP;
1021    line2 = line.prevSibling();
1022    if(line2 == null){
1023      //check parent
1024      if(!line.parentEquals(rootLine)){
1025        line = line.parent();
1026      } else {
1027        line = null;  //on root as first entry
1028      }
1029    } else {
1030      //if(line2 !=null){ line2 = line2.prevSibling(); } //the parent is the current parent, use previous.
1031      while(line2 !=null && line2.showChildren){
1032        //it has children
1033        line2 = line2.lastChild();  //last of all showing levels
1034      }
1035      line = line2;
1036    }
1037    return line;
1038  }  
1039  
1040  
1041  /**Invoked in the graphic thread from mouse listener in {@link GraphicImplAccess#mouseDownGral(int, CellData)}
1042   * @param key
1043   * @param cell
1044   */
1045  protected void mouseDown(int key, CellData cell){
1046    lineSelectedNew = linesForCell[cell.ixCellLine]; 
1047    repaint(0,0);  //immediately, it is in the graphic thread.
1048  }
1049
1050
1051  /**Invoked in the graphic thread from mouse listener in {@link GraphicImplAccess#mouseUpGral(int, CellData)}
1052   * @param key
1053   * @param cell
1054   */
1055  protected void mouseUp(int key, CellData cell){
1056    if(key == KeyCode.mouse1Up){
1057      lineSelected = lineSelectedNew;
1058      nLineFirst = -1;  //get new
1059      lineSelectedNew = null;
1060      lineSelectedixCell = cell.ixCellLine;  //used for key handling.
1061      colSelectedixCellC = cell.ixCellColumn;
1062      actionOnLineSelected(KeyCode.userSelect, lineSelected);
1063      repaint();
1064    }
1065  }
1066
1067
1068
1069  /**Invoked in the graphic thread from mouse listener in {@link GraphicImplAccess#mouseDoubleGral(int, CellData)}
1070   * @param key
1071   * @param cell
1072   */
1073  protected void mouseDouble(int key, CellData cell){
1074    ActionChange action1 = getActionChangeStrict(ActionChangeWhen.onMouse1Double, true);
1075    if(action1 !=null
1076      && action1.action().exec(KeyCode.mouse1Double, linesForCell[cell.ixCellLine])  //executes the action.
1077      ) {
1078        //it is sufficient.
1079    } else {
1080      processKeys(KeyCode.mouse1Double);
1081    }
1082  }
1083
1084
1085
1086  
1087  
1088  /**Increments or decrements ixLineNew in [up] or [dn] situation until the {@link #searchChars} are found
1089   * or one time if searchChars are not given.
1090   * If the searchChars are not found, either the first or last line will be selected. It is because
1091   * any key operation should have an effect for the user. Paradigm: Not the search and found is prior,
1092   * the response of operation is prior. The user may see whether anything is found. 
1093   * @param bUp direction
1094   * @return true if found
1095   */
1096  protected boolean searchContent(boolean bUp){
1097    String search = searchChars.toString();
1098    boolean found = false;
1099    if(search != null && search.length() !=0) { // return false;
1100      boolean contSearch = true;
1101      TableLineData line2, line = lineSelected;
1102      do{
1103        if(bUp && line !=null){        //up
1104          line2 = prevLine(line);
1105        } else if(!bUp && line !=null){ //down
1106          line2 = nextLine(line);
1107        } else {
1108          //ixLineNew = ixLineNewAct;
1109          line2 = null;                 //eand reached
1110        }
1111        if(line2 ==null){ //end of search
1112          contSearch = false;  //without change the lineSelected
1113          lineSelected = line;  //show the first or last line
1114          nLineFirst = -1;  //get new, undefined elsewhere.
1115          found = search.length() >0;
1116        } else {
1117          line = line2;
1118          String sTextLo = line.getCellText(colSelectedixCellC).toLowerCase();
1119          String sText = line.getCellText(colSelectedixCellC);
1120          if( search.length() == 0 || search.equals('*')){   //always found if no searchchar is given.
1121            found = false;
1122            contSearch = false;
1123          } else if(  sTextLo.startsWith(search)
1124                   || search.charAt(0)== '*' && sText.contains(search.substring(1))
1125            ){  //found
1126            found = true;
1127            lineSelected = line;
1128            nLineFirst = -1;  //get new, undefined elsewhere.
1129            bPrepareVisibleArea = true;
1130            contSearch = false;                   //found
1131          } else {
1132            found = false;
1133          }
1134        }
1135      } while(contSearch);
1136    }
1137    return found;
1138  }
1139  
1140  
1141  
1142  
1143  /**Invoked from focus lost of any table cell implementation, checks whether the line is changed.
1144   * @param sText The text in the cell from the implementation widget.
1145   * @param celldata The cell, the line is gotten from {@link #linesForCell}[{@link CellData#ixCellLine}].
1146   */
1147  protected void checkAndUpdateText(String sText, CellData celldata){
1148    TableLineData line = linesForCell[celldata.ixCellLine];
1149    if(line !=null && !sText.equals(line.cellTexts[celldata.ixCellColumn])){
1150      line.cellTexts[celldata.ixCellColumn] = sText;
1151      line.bChangedEdit[celldata.ixCellColumn] = true;
1152    }
1153  }  
1154  
1155      /**Handle all standard keys of table. 
1156     * It should call in the key event handler from the implementation class.
1157     * <br>Keys:
1158     * <ul>
1159     * <li>pgup: 
1160     * <li>up
1161     * <li>dn
1162     * <li>pgdn
1163     * <li>{@link #keyMarkUp}
1164     * <li>{@link #keyMarkDn}
1165     * <li>calls {@link GralMng#getRegisteredUserAction(String what)} with what="KeyAction"
1166     *   and invokes the returned action method. With them all standard key actions of this application
1167     *   may be done if a {@link GralUserAction} is registered for that.  
1168     * </ul>
1169     * @param keyCode Encoding see {@link KeyCode}.
1170     * @return true if the key is processed, false if the key is not processed here. Maybe processed after them.
1171     */
1172    protected boolean processKeys(int keyCode){
1173      if(keyCode == KeyCode.enter)
1174        Debugutil.stop();
1175      boolean done = true;
1176      long time = System.currentTimeMillis();
1177      lineSelectedNew = null;  //on any key, clear highlighted mouse down cell, if it is set yet.
1178      if(lastKey == keyCode){ keyRepetition +=1;  //same key
1179      } else {
1180        keyRepetition = 1; //other key.
1181      }
1182      //NOTE: prevent to fast key action if the last redraw is yet finished.
1183      //The draw needs to much time in Linux-GTK with an Atom processor (Lenovo)
1184      long timeDiff = time - timeLastRedraw;
1185      if( keyDone || keyCode == KeyCode.mouse1Double || timeDiff > -11110){  //use 50 ms for timeout if keyDone isn't set.  
1186        keyDone = false;
1187        switch(keyCode){
1188        case KeyCode.tab: {
1189          if(colSelectedixCellC < columnWidthsGral.length-1) { 
1190            colSelectedixCellC +=1; 
1191          }
1192        } break;
1193        case KeyCode.shift + KeyCode.tab: {
1194          if(colSelectedixCellC >= 1) { 
1195            colSelectedixCellC -=1; 
1196          }
1197        } break;
1198        case KeyCode.pgup: {
1199          if(lineSelectedixCell > 2){
1200            lineSelectedixCell = 2;
1201          } else {
1202            int shifted = shiftVisibleArea(-zLineVisible);  //shifted = -1 if all shifted
1203            lineSelectedixCell -= zLineVisible + shifted;
1204            if(lineSelectedixCell <0){
1205              lineSelectedixCell = 0;  //limit it on top.
1206            }
1207          }
1208          lineSelected = linesForCell[lineSelectedixCell];
1209          nLineFirst = -1;  //get new, undefined elsewhere.
1210          //the table has the focus, because the key action is done only if it is so.
1211          //set the new cell focused, in the paint routine.
1212          gi.cells[lineSelectedixCell][colSelectedixCellC].bSetFocus = true; 
1213          actionOnLineSelected(KeyCode.userSelect, lineSelected);
1214          keyActionDone.activate();
1215        } break;
1216        case KeyCode.mouseWheelUp:
1217        case KeyCode.up: {
1218          if(!searchContent(true)) {
1219            if(lineSelectedixCell > 2){
1220              lineSelectedixCell -=1;
1221            } else {
1222              int shifted = shiftVisibleArea(-1);  //shifted = -1 if all shifted
1223              lineSelectedixCell -= 1 + shifted;
1224              if(lineSelectedixCell <0){
1225                lineSelectedixCell = 0;  //limit it on top.
1226              }
1227            }
1228            lineSelected = linesForCell[lineSelectedixCell];
1229            
1230          }
1231          //the table has the focus, because the key action is done only if it is so.
1232          //set the new cell focused, in the paint routine.
1233          gi.cells[lineSelectedixCell][colSelectedixCellC].bSetFocus = true; 
1234          actionOnLineSelected(KeyCode.userSelect, lineSelected);
1235          keyActionDone.activate();
1236        } break;
1237        case KeyCode.pgdn: {
1238          if(lineSelectedixCell < zLineVisible -3){
1239            lineSelectedixCell = zLineVisible -3;
1240          } else {
1241            int shifted = shiftVisibleArea(zLineVisible);
1242            lineSelectedixCell += zLineVisible - shifted;
1243            if(lineSelectedixCell >= zLineVisible){
1244              lineSelectedixCell = zLineVisible -1;  //limit it on top.
1245            }
1246          }
1247          while( (lineSelected = linesForCell[lineSelectedixCell]) ==null
1248               && lineSelectedixCell >0    
1249            ){
1250            lineSelectedixCell -=1;
1251          }
1252          nLineFirst = -1;  //get new, undefined elsewhere.
1253          //the table has the focus, because the key action is done only if it is so.
1254          //set the new cell focused, in the paint routine.
1255          gi.cells[lineSelectedixCell][colSelectedixCellC].bSetFocus = true; 
1256          actionOnLineSelected(KeyCode.userSelect, lineSelected);
1257          keyActionDone.activate();
1258        } break;
1259        default:
1260          if(keyCode == KeyCode.dn || keyCode == keyMarkDn || keyCode == KeyCode.mouseWheelDn
1261            ) {
1262            if(keyCode == keyMarkDn && lineSelected !=null){
1263              GralTableLine_ifc<?> line = lineSelected; //tableLines.get(ixLine);
1264              if((line.getMark() & FileMark.select)!=0){
1265                //it is selected yet
1266                line.setNonMarked(FileMark.select, line.getUserData());
1267              } else {
1268                line.setMarked(FileMark.select, line.getUserData());
1269              }
1270            }
1271            if(!searchContent(false)) {
1272              if(lineSelectedixCell < zLineVisible -3){
1273                lineSelectedixCell +=1;
1274              } else {
1275                int shifted = shiftVisibleArea(1);
1276                lineSelectedixCell += 1 - shifted;
1277                if(lineSelectedixCell >= zLineVisible){
1278                  lineSelectedixCell = zLineVisible -1;  //limit it on top.
1279                }
1280              }
1281              while( (lineSelected = linesForCell[lineSelectedixCell]) ==null
1282                   && lineSelectedixCell >0    
1283                ){
1284                lineSelectedixCell -=1;
1285              }
1286              nLineFirst = -1;  //get new, undefined elsewhere.
1287            }
1288            //the table has the focus, because the key action is done only if it is so.
1289            //set the new cell focused, in the paint routine.
1290            gi.cells[lineSelectedixCell][colSelectedixCellC].bSetFocus = true; 
1291            actionOnLineSelected(KeyCode.userSelect, lineSelected);
1292            
1293            keyActionDone.activate();
1294          } else if(KeyCode.isTextKey(keyCode) && !bColumnEditable[colSelectedixCellC]){
1295            keyCode &= ~KeyCode.shiftDigit;  //The keycode is valid without shift-designation.
1296            searchChars.appendCodePoint(keyCode);
1297            searchContent(false);
1298            repaint();
1299          } else if(keyCode == KeyCode.esc){
1300            searchChars.setLength(0);
1301            repaint();
1302          } else if(keyCode == KeyCode.back && searchChars.length() >0){
1303            searchChars.setLength(searchChars.length()-1);
1304            repaint();
1305          } else if(lineSelected !=null && keyCode == keyOpenChild){
1306            if(lineSelected.lineCanHaveChildren){
1307              actionOnRefreshChildren(lineSelected);  //may get or refresh children, callback in user.
1308            }
1309            if(lineSelected.hasChildren()){           //only if it has children currently really.
1310              lineSelected.showChildren(true, true, true);
1311              //lineSelected.countChildren(true, nLineFirst);  //count the children.
1312              //fillVisibleAreaBehind(lineSelected, lineSelectedixCell);
1313              //repaint();
1314            }
1315          } else if(lineSelected !=null && keyCode == keyCloseChild){
1316            if(lineSelected !=null && lineSelected.showChildren){
1317              lineSelected.showChildren(false, false);
1318              fillVisibleAreaBehind(lineSelected, lineSelectedixCell);
1319              repaint();
1320            }
1321          } else {
1322            done = false;
1323          }
1324        }//switch
1325        if(done == false && keyCode == keyMarkDn && lineSelected !=null){
1326          GralTableLine_ifc<?> line = lineSelected; //tableLines.get(ixLine);
1327          if((line.getMark() & 1)!=0){
1328            //it is selected yet
1329            line.setNonMarked(1, line.getUserData());
1330          } else {
1331            line.setMarked(1, line.getUserData());
1332          }
1333          
1334          keyActionDone.activate();
1335          done = true;
1336        }
1337        if(!done /*&& lineSelected !=null*/){
1338          GralWidget_ifc.ActionChange action = getActionChange(GralWidget_ifc.ActionChangeWhen.onEnter);
1339          if(action !=null){
1340            Object[] args = action.args();
1341            if(args == null){ done = action.action().exec(keyCode, this, lineSelected); }
1342            else { done = action.action().exec(keyCode, this, args, lineSelected); }
1343          }
1344        } //if(table.)
1345        if(!done && itsMng.userMainKeyAction() !=null){
1346          done = itsMng.userMainKeyAction().exec(keyCode, getCurrentLine());
1347        }
1348        if(!done){
1349          //if actionChanging.userAction() returns false 
1350          GralUserAction mainKeyAction = itsMng.getRegisteredUserAction("KeyAction");
1351          if(mainKeyAction !=null){
1352            //old form called because compatibility, if new for with int-parameter returns false.
1353            if(!mainKeyAction.exec(keyCode, this)){
1354              done = mainKeyAction.exec(keyCode, this, new Integer(keyCode));
1355            }
1356          }
1357        }
1358        keyRepetition = 0;  //because it was done.
1359      }//if not redraw pending.
1360      lastKey = keyCode;
1361      return done;
1362    }
1363
1364  
1365  
1366  
1367  
1368  /**This callback is need because the paint of a table needs more time if a slow processor is used
1369   * and the key repeat rate is higher than the calculation time. After finishing all paint requests
1370   * in the graphic thread this action was called. It sets {@link #keyDone} = true, then the next key
1371   * is processed immediately. Elsewhere, if the graphic thread is busy in the graphic os dispatching
1372   * and a new key event is received there, the key action won't be executed.
1373   * <br>
1374   * It helps for a run-after effect if the key are released already but some key events are stored.
1375   * If a navigation key is released, the table navigation should be stopped immediately.
1376   * 
1377   */
1378  protected final GralGraphicTimeOrder keyActionDone = new GralGraphicTimeOrder("GralTableKeyDone") {
1379    @Override
1380    public void executeOrder() {
1381      gi.bFocused = true;  //to focus while repainting
1382      _wdgImpl.repaintGthread();
1383      keyDone = true;
1384      //System.out.println("Key done");
1385    }
1386  };
1387
1388  /**It is called whenever another line is selected, if the focus is gotten by mouse click
1389   * or a navigation key is pressed. 
1390   * This method calls the {@link GralUserAction#userActionGui(int, GralWidget, Object...)}.
1391   * The {@link #specifyActionOnLineSelected(GralUserAction)} can be set with any user instantiation
1392   * of that interface. The params[0] of that routine are filled with the {@link GralTableLine_ifc}
1393   * of the selected line.
1394   *  
1395   * @param line
1396   */
1397  private void actionOnLineSelected(int key, GralTableLine_ifc<?> line){
1398    itsMng.setLastClickedWidget(lineSelected);
1399    if(actionOnLineSelected !=null){
1400      actionOnLineSelected.exec(key, this, line);
1401    }
1402  }
1403  
1404  
1405  /**It is called whenever another line is selected, if the focus is gotten by mouse click
1406   * or a navigation key is pressed. 
1407   * This method calls the {@link GralUserAction#userActionGui(int, GralWidget, Object...)}.
1408   * The {@link #specifyActionOnLineSelected(GralUserAction)} can be set with any user instantiation
1409   * of that interface. The params[0] of that routine are filled with the {@link GralTableLine_ifc}
1410   * of the selected line.
1411   *  
1412   * @param line
1413   */
1414  protected void actionOnRefreshChildren(GralTableLine_ifc<?> line){
1415    if(actionOnRefreshChildren !=null){
1416      actionOnRefreshChildren.exec(KeyCode.userSelect, this, line);
1417    }
1418  }
1419  
1420  /**Only used on invocation of {@link GraphicImplAccess#drawCellContent}. It is not defined there but here because it is static. */
1421  public final static class LinePresentation
1422  {
1423    public GralColor colorBack, colorText;
1424    
1425    public GralColor[] cellsColorBack;
1426  }
1427  
1428  
1429  /**This is the super class for all implementers. It has protected access to all elements in the 
1430   * environment class. Via access methods the implementor class has protected access to all of it.
1431   * 
1432   */
1433  public abstract class GraphicImplAccess extends GralWidget.ImplAccess
1434  implements GralWidgImpl_ifc, Removeable
1435  {
1436    
1437    public static final int chgEditableColumn = 0x00100000;
1438
1439    /**Only used on invocation of {@link #drawCellContent}
1440     * 
1441     */
1442    private final LinePresentation linePresentation = new LinePresentation();
1443    
1444    protected final GralTable<UserData> outer;
1445    
1446    //protected GralWidgImpl_ifc implWidgWrapper;
1447
1448    
1449    protected CellData[][] cells;
1450    
1451    
1452    
1453    /**Set to true while {@link #table}.{@link Table#redrawGthread()} is running.
1454     * It prevents recursive invocation of redraw() while setFocus() is invoked. */
1455    protected boolean bRedrawPending;
1456
1457    
1458    
1459    
1460    /**Pixel per line. */
1461    protected int linePixel;
1462    
1463    /**Column position for the cells in pixel from 0 (left) calculated from the pixel size of the table. 
1464     * This values are calculated on setToPanel and after resize with {@link #resizeTable(GralRectangle)}. 
1465     */
1466    protected final int[] xpixelCell;
1467
1468    /**Pixel position of the vertical scroll bar. */
1469    protected final GralRectangle xyVscrollbar = new GralRectangle(0,0,0,0);
1470    
1471    /**Position of vScrollBar calculated from {@link GralTable#rootLine}. {@link NodeTableLine#zLineUnfolded} and {@link GralTable#nLineCurr}
1472     * written in {@link #determineSizeAndPosition()} used for painting vScrollBar. */
1473    protected int y1Scrollbar, y2Scrollbar;
1474    
1475    protected boolean bVscrollbarChanged;
1476    
1477    /**New and last index of the sliderColor. The last index is stored by the implementation and compared with the new one
1478     * to desire whether a new implementation color should be gotten. */
1479    protected int ixColorScrollbar, ixColorScrollbarLast = -1;
1480    
1481    /**Start position of each column in pixel. 
1482     * @deprecated only used in org.vishia.gral.swt.SwtTable#initSwtTable(...) */
1483    protected int[] columnPixel;
1484    
1485    protected final int xPixelUnit;
1486        
1487    /**number of columns which should be shift to rigth on tree indent. 0. don't shift. Usual 1 */
1488    protected int nrofColumnTreeShift;
1489
1490    /**Index (subscript) of the graphical line (not lines of the table)
1491     * which has the selection color and which should be gotten the selection color.
1492     */
1493    //protected int ixGlineSelected = -1, ixGlineSelectedNew = -1;
1494    
1495    /**Set true if the focus is gained by mouse click. It causes color set and 
1496     * invocation of {@link #actionOnLineSelected(GralTableLine_ifc)}. 
1497     */
1498    protected boolean bFocused;
1499    
1500    
1501    /**Sets temporary between focus lost and redraw. It is reset if the focus is gained for another cell
1502     * of the same table. */
1503    protected boolean bFocusLost;
1504    
1505    /**Set to true if the table has the focus in window.
1506     */
1507    protected boolean XXXhasFocus;
1508    
1509
1510    protected long mousetime, redrawtime, mousect, redrawct;
1511    
1512    private boolean mouseDoubleClick;
1513    
1514    
1515
1516    protected GraphicImplAccess(GralTable<UserData> outer, GralMng mng){ 
1517      super(outer, mng);
1518      this.outer = outer;
1519      this.cells = new GralTable.CellData[zLineVisibleMax][zColumn()];
1520      xPixelUnit = mng.propertiesGui.xPixelUnit();
1521      outer.gi = this; 
1522      int xdPix = outer.itsMng.propertiesGui().xPixelUnit();
1523      columnPixel = new int[outer.columnWidthsGral.length+1];
1524      int xPix = 0;
1525      columnPixel[0] = xPix;
1526      for(int iCol = 0; iCol < outer.columnWidthsGral.length; ++iCol){
1527        xPix += outer.columnWidthsGral[iCol] * xdPix;
1528        columnPixel[iCol+1] = xPix;
1529      }
1530
1531      this.xpixelCell = new int[outer.columnWidthsGral.length+1];
1532      int ydPix = outer.itsMng.propertiesGui().yPixelUnit();
1533      linePixel = 2 * ydPix;
1534    }
1535    
1536    protected GralMng itsMng(){ return outer.itsMng; }
1537    
1538    protected boolean bColumnEditable(int ix){ return GralTable.this.bColumnEditable[ix]; }
1539    
1540    
1541    protected void checkAndUpdateText(String sText, CellData celldata){
1542      GralTable.this.checkAndUpdateText(sText, celldata);
1543    }
1544    
1545    protected int ixColumn(){ return outer.colSelectedixCellC; }
1546    
1547    //protected int ixLine(){ return outer.ixLine; }
1548    
1549    protected int[] columnWidthsGral(){ return outer.columnWidthsGral; }
1550    
1551    
1552    
1553    protected int zColumn(){ return outer.zColumn; }
1554    
1555    protected GralColor colorSelectCharsBack(){ return outer.colorSelectCharsBack; }
1556    
1557    protected boolean bChangedLinesForCell(){ return outer.bChangedLinesForCell; }
1558    
1559    protected void bChangedLinesForCell(boolean val){ outer.bChangedLinesForCell = val; }
1560    
1561    
1562    
1563    protected GralColor colorSelectChars(){ return outer.colorSelectChars; }
1564    
1565    protected GralColor colorBackTable(){ return outer.dyda.backColor; }
1566    
1567    protected GralColor colorBackVscrollbar(){ return outer.colorBackVscrollbar; }
1568    
1569    protected GralColor colorLineVscrollbar(){ return outer.colorSliderVscrollbar[ixColorScrollbar]; }
1570    
1571    protected StringBuilder searchChars(){ return outer.searchChars; }
1572    
1573    
1574    /**Returns the line on that any mouse button was pressed. It is either the left, mid or right button.
1575     * Able to use for context menu (right button).
1576     * @return
1577     */
1578    //public TableLineData getLineOnMousePressed(){ return cellDataOnMousePressed.tableItem; }
1579    
1580
1581    
1582    /**Handle all standard keys of table. 
1583     * It should call in the key event handler from the implementation class.
1584     * <br>Keys:
1585     * <ul>
1586     * <li>pgup: 
1587     * <li>up
1588     * <li>dn
1589     * <li>pgdn
1590     * <li>{@link #keyMarkUp}
1591     * <li>{@link #keyMarkDn}
1592     * <li>calls {@link GralMng#getRegisteredUserAction(String what)} with what="KeyAction"
1593     *   and invokes the returned action method. With them all standard key actions of this application
1594     *   may be done if a {@link GralUserAction} is registered for that.  
1595     * </ul>
1596     * @param keyCode Encoding see {@link KeyCode}.
1597     * @return true if the key is processed, false if the key is not processed here. Maybe processed after them.
1598     */
1599    protected boolean processKeys(int keyCode){ 
1600      //GralTable widgt = (GralTable)widgg;
1601      if(lineSelected !=null && bColumnEditable(colSelectedixCellC)) {
1602        //update the text of the cell from the implementation layer:
1603        CellData cell = cells[lineSelectedixCell][colSelectedixCellC];
1604        String sContent = getCellText(cell);
1605        lineSelected.cellTexts[colSelectedixCellC] = sContent;
1606        //setCellText(cell, sContent);
1607      }
1608      return outer.processKeys(keyCode); 
1609    }
1610/*
1611    boolean done = true;
1612      long time = System.currentTimeMillis();
1613      if(lastKey == keyCode){ keyRepetition +=1;  //same key
1614      } else {
1615        keyRepetition = 1; //other key.
1616      }
1617      //NOTE: prevent to fast key action if the last redraw is yet finished.
1618      //The draw needs to much time in Linux-GTK with an Atom processor (Lenovo)
1619      if( keyDone || keyCode == KeyCode.mouse1Double || (time - timeLastRedraw) > 350){  //use 350 ms for timeout if keyDone isn't set.  
1620        keyDone = false;
1621        switch(keyCode){
1622        case KeyCode.pgup: {
1623          if(outer.ixLine > zLineVisible){
1624            outer.ixLineNew = outer.ixLine - zLineVisible;
1625          } else {
1626            outer.ixLineNew = 0;
1627          }
1628          outer.keyActionDone.addToGraphicThread(outer.itsMng.gralDevice(), 0);
1629        } break;
1630        case KeyCode.mouseWheelUp:
1631        case KeyCode.up: {
1632          if(outer.ixLine > 0){
1633            //ixLineNew = ixLine - keyRepetition;
1634            outer.searchContent(true);
1635            if(outer.ixLineNew <0){ outer.ixLineNew = 0; }
1636          }
1637          
1638          if(outer.ixCellLineSelect > 3){
1639            outer.ixCellLineSelect -=1;
1640          } else {
1641            dLineForCells = -1;  
1642          }
1643
1644          outer.keyActionDone.addToGraphicThread(outer.itsMng.gralDevice(), 0);
1645        } break;
1646        case KeyCode.mouseWheelDn:
1647        case KeyCode.dn: {
1648          if(outer.ixLine < outer.zLine -1){
1649            //ixLineNew = ixLine + keyRepetition;
1650            outer.searchContent(false);
1651            if(outer.ixLineNew >= outer.zLine ){ outer.ixLineNew = outer.zLine -1; }
1652          }
1653          
1654          if(outer.ixCellLineSelect < zLineVisible -3){
1655            outer.ixCellLineSelect +=1;
1656            outer.selectLine = outer.cellLines[outer.ixCellLineSelect];
1657          } else {
1658            dLineForCells =1;  
1659          }
1660          
1661          outer.keyActionDone.addToGraphicThread(outer.itsMng.gralDevice(), 0);
1662        } break;
1663        case KeyCode.pgdn: {
1664          if(outer.ixLine < outer.zLine - zLineVisible){
1665            outer.ixLineNew = outer.ixLine + zLineVisible;
1666          } else {
1667            outer.ixLineNew = outer.zLine -1;
1668          }
1669          outer.keyActionDone.addToGraphicThread(outer.itsMng.gralDevice(), 0);
1670        } break;
1671        default:
1672          if(KeyCode.isTextKey(keyCode)){
1673            outer.searchChars.appendCodePoint(keyCode);
1674            outer.searchContent(false);
1675            outer.repaint();
1676          } else if(keyCode == KeyCode.esc){
1677            outer.searchChars.setLength(0);
1678            outer.repaint();
1679          } else if(keyCode == KeyCode.back && outer.searchChars.length() >0){
1680            outer.searchChars.setLength(outer.searchChars.length()-1);
1681            outer.repaint();
1682          } else {
1683            done = false;
1684          }
1685        }//switch
1686        if(done == false && keyCode == outer.keyMarkDn && outer.ixLine >=0){
1687          GralTableLine_ifc<?> line = outer.tableLines.get(outer.ixLine);
1688          if((line.getMark() & 1)!=0){
1689            //it is selected yet
1690            line.setNonMarked(1, line.getUserData());
1691          } else {
1692            line.setMarked(1, line.getUserData());
1693          }
1694          if(outer.ixLine < outer.zLine -1){
1695            outer.ixLineNew = outer.ixLine + 1;
1696          }
1697          outer.keyActionDone.addToGraphicThread(outer.itsMng.gralDevice(), 0);
1698          done = true;
1699        }
1700        if(!done && outer.ixLine >=0){
1701          GralTableLine_ifc<?> lineGral = outer.tableLines.get(outer.ixLine);
1702          if(outer.actionChanging !=null){
1703            //all other keys: call actionChanging.
1704            done = outer.actionChanging.exec(keyCode, outer, lineGral);
1705          }
1706        } //if(table.)
1707        if(!done && outer.itsMng.userMainKeyAction() !=null){
1708          done = outer.itsMng.userMainKeyAction().exec(keyCode, outer.getCurrentLine());
1709        }
1710        if(!done){
1711          //if actionChanging.userAction() returns false 
1712          GralUserAction mainKeyAction = outer.itsMng.getRegisteredUserAction("KeyAction");
1713          if(mainKeyAction !=null){
1714            //old form called because compatibility, if new for with int-parameter returns false.
1715            if(!mainKeyAction.exec(keyCode, outer)){
1716              done = mainKeyAction.exec(keyCode, outer, new Integer(keyCode));
1717            }
1718          }
1719        }
1720        keyRepetition = 0;  //because it was done.
1721      }//if not redraw pending.
1722      lastKey = keyCode;
1723      return done;
1724    }
1725*/
1726    
1727    
1728    
1729    protected void setFocusCellMousePressed(){
1730     
1731    }
1732
1733    
1734    /**Invoked on editing a text field
1735     * @param cell
1736     * @param text
1737     */
1738    protected void setCellText(CellData cell, String text){
1739      TableLineData line = GralTable.this.linesForCell[cell.ixCellLine];
1740      if(line != null){
1741        line.setCellText(text, cell.ixCellColumn);
1742      }
1743    }
1744    
1745    
1746    /**Gets the current text of the given cell from the graphic implementation.
1747     * @param cell
1748     * @return
1749     */
1750    protected abstract String getCellText(CellData cell);
1751    
1752    
1753    /**Gets the cell text from the focused cell in the implementation. */
1754    protected abstract String getCellTextFocus();
1755    
1756    /**Updates the cell text fields which presents the content of the table.
1757     * After them update() of the graphic level should be called.
1758     * To execute the update of the cells in the graphic layer the {@link #drawCellContent(int, CellData[], TableLineData, LinePresentation)}
1759     * is called inside for any cell. This method is implemented in the implementation layer.
1760     */
1761    protected void updateGraphicCellContent(){
1762      long dbgtime = System.currentTimeMillis();
1763      bRedrawPending = true;
1764
1765      Assert.check(outer.itsMng.currThreadIsGraphic());
1766      GralTable<UserData>.TableLineData/*<?>*/ line;
1767      
1768      if(outer.bPrepareVisibleArea){
1769        outer.fillVisibleArea();  //show the selected line at line 3 in graphic or before 0..2
1770        outer.bPrepareVisibleArea = false;
1771      }
1772      
1773      //Now draw:
1774      //
1775      int ix = -1;
1776      while(++ix < outer.zLineVisible) {
1777        line = outer.linesForCell[ix];
1778        setLinePresentation(line);
1779        drawCellContent(ix, cells[ix], line, linePresentation);
1780      }
1781      if(++ix < outer.zLineVisibleMax){  //a half visible line
1782        drawCellContent(ix, cells[ix], null, linePresentation);
1783      }
1784      outer.timeLastRedraw = System.currentTimeMillis();
1785      //System.out.println("GralTable - redraw;" + timeLastRedraw - dbgTime);
1786    }
1787
1788    
1789    
1790    private void setLinePresentation(TableLineData/*<?>*/ line){
1791      boolean marked = line !=null && (line.getMark() & 1)!=0;
1792      boolean childrenMarked = line !=null && (line.getMark() & 2)!=0;
1793      if(line == outer.lineSelected){
1794        if(marked){
1795          linePresentation.colorBack = line.colorBackSelectMarked !=null ? line.colorBackSelectMarked : outer.colorBackSelectMarked;
1796        } else if(childrenMarked){
1797          linePresentation.colorBack = line.colorBackSelectSomeMarked !=null ? line.colorBackSelectSomeMarked : outer.colorBackSelectSomeMarked;
1798        } else {
1799          linePresentation.colorBack = line !=null && line.colorBackSelect !=null ? line.colorBackSelect : outer.colorBackSelect;
1800        }
1801      } else if(line == outer.lineSelectedNew){
1802        linePresentation.colorBack = marked ? outer.colorBackSelectNewMarked : outer.colorBackSelectNew;
1803      } else {
1804        if(marked){
1805          linePresentation.colorBack = line.colorBackMarked !=null ? line.colorBackMarked : outer.colorBackMarked;
1806        } else if(childrenMarked){
1807          linePresentation.colorBack = line.colorBackSomeMarked !=null ? line.colorBackSomeMarked : outer.colorBackSomeMarked;
1808        } else if(!bFocused){
1809          linePresentation.colorBack = dyda.backColorNoFocus;
1810        } else {
1811          linePresentation.colorBack = line !=null && line.colorBackground !=null ? line.colorBackground : outer.dyda.backColor;
1812        }
1813      }
1814      linePresentation.colorText = line !=null && line.colorForeground !=null ? line.colorForeground : outer.dyda.textColor;
1815      linePresentation.cellsColorBack = line !=null ? line.cellColorBack : null; //maybe null or can contain null elements.
1816    }
1817    
1818
1819    /**This method have to be called before the vertical scroll bar is painted
1820     * in the {@link GralWidgImpl_ifc#repaintGthread()} routine..
1821     * It checks whether the {@link GralTable#nLineCurr} and the shown number of lines
1822     * in {@link GralTable#rootLine}. {@link GralTable.NodeTableLine#zLineUnfolded}
1823     * is given, e.g. >=0. If one of them is <0 or lines are countered
1824     * calling {@link NodeTableLine#countChildren(boolean, int)}. 
1825     * Therewith the {@link GralTable#nLineCurr} is set too. Anytime if the situation is not specified
1826     * the {@link GralTable#nLineCurr} can be set to -1. This forces new calculation.
1827     */
1828    protected void determineSizeAndPositionScrollbar(int yPixel)
1829    { if(GralTable.this.nLineFirst <0 || GralTable.this.rootLine.zLineUnfolded <0) {
1830        GralTable.this.rootLine.countChildren(true, 0);
1831      }
1832      int zLine = Math.max(1, rootLine.zLineUnfolded);
1833      int y1 = yPixel * nLineFirst / zLine;
1834      int zLineShow = Math.min(zLineVisible, zLine);  //less if table is shorter than visible area
1835      int yd = yPixel * zLineShow / zLine;   //it is <= yPixel
1836      if(yd < 5){
1837        yd = 5;
1838      }
1839      int y2 = y1 + yd;
1840      if(y2 > yPixel) {
1841        y2 = yPixel;
1842        y1 = y2 - yd;
1843      }
1844      if(y1 != y1Scrollbar || y2 != y2Scrollbar){ 
1845        y1Scrollbar = y1;
1846        y2Scrollbar = y2;
1847        bVscrollbarChanged = true;
1848        ixColorScrollbar = (y2Scrollbar - y1Scrollbar) / 15;
1849        if(ixColorScrollbar >= outer.colorSliderVscrollbar.length){ ixColorScrollbar = outer.colorSliderVscrollbar.length -1; }
1850      }
1851
1852    }
1853
1854    /**This routine will be called inside a resize listener of the implementation graphic.
1855     * It calculates the width of the columns with the given width of the table's canvas.
1856     * Then {@link #setBoundsCells()} will be called. 
1857     * That is implemented in the underlying graphic layer and sets the bounds for each cell.
1858     * @param pixTable Size of the table area.
1859     */
1860    protected void resizeTable(GralRectangle pixTable) {
1861      int xPixelUnit = itsMng().propertiesGui().xPixelUnit();
1862      int yPixelUnit = itsMng().propertiesGui().yPixelUnit();
1863      outer.zLineVisible = pixTable.dy / yPixelUnit / 2;
1864      if(outer.zLineVisible > outer.zLineVisibleMax){ outer.zLineVisible = outer.zLineVisibleMax; }
1865      xyVscrollbar.x = pixTable.dx - xPixelUnit;
1866      xyVscrollbar.dx = xPixelUnit;
1867      xyVscrollbar.y = 0;
1868      xyVscrollbar.dy = pixTable.dy;
1869      int xPixel1 = 0;
1870      xpixelCell[0] = xPixel1;
1871      int ixPixelCell;
1872      int xPos;
1873      //Columns from left with positive width
1874      for(ixPixelCell = 0; ixPixelCell < columnWidthsGral().length && (xPos = columnWidthsGral()[ixPixelCell]) > 0; ++ixPixelCell){
1875        xPixel1 += xPos * xPixelUnit;
1876        xpixelCell[ixPixelCell+1] = xPixel1;
1877      }
1878      nrofColumnTreeShift = ixPixelCell +1;
1879      System.out.println("GralTable - resizeTable; nrofColumnTreeShift =" + nrofColumnTreeShift);
1880      xPixel1 = pixTable.dx - xPixelUnit;
1881      xpixelCell[columnWidthsGral().length] = xPixel1;  //right position.
1882      for(ixPixelCell = columnWidthsGral().length-1; ixPixelCell >=0  && (xPos = columnWidthsGral()[ixPixelCell]) < 0; --ixPixelCell){
1883        xPixel1 += xPos * xPixelUnit;
1884        xpixelCell[ixPixelCell] = xPixel1;
1885      }
1886      setBoundsCells(0, outer.zLineVisible);
1887
1888    }
1889    
1890    
1891    /**Invoked in {@link #resizeTable(GralRectangle)} as action which should be implemented in the implementation layer.
1892     * The {@link #xpixelCell} was set before.
1893     * @param treeDepthBase
1894     */
1895    abstract protected void setBoundsCells(int treeDepthBase, int zLineVisible);
1896
1897    @Override public boolean remove(){
1898      outer.rootLine.removeChildren();
1899      return true;
1900    }
1901
1902    
1903    /**Sets the current cell as focused with the focus color. It causes
1904     * a redraw of the whole table because the cell may be shifted in table position.
1905     * TODO this method must call in the graphic thread yet, queue it with {@link GralMng#setInfo(GralWidget, int, int, Object, Object)}.
1906     * @param cell The cell 
1907     */
1908    protected boolean redrawTableWithFocusedCell(CellData data){
1909      if(bPrepareVisibleArea){
1910        fillVisibleArea();  //show the selected line at line 3 in graphic or before 0..2
1911        bPrepareVisibleArea = false;
1912      }
1913      TableLineData line = outer.linesForCell[data.ixCellLine];
1914      if( line !=null){ //don't do any action if the cell isn't use.
1915        outer.lineSelectedNewixCell = data.ixCellLine;
1916        lineSelectedNew = line;
1917        //TODO outer.selectLine = data.tableItem;
1918        outer.colSelectedixCellC = data.ixCellColumn;
1919        bFocused = true;
1920        return true;
1921      }
1922      else return false;
1923    }
1924
1925
1926    
1927    /**This routine is invoked if any cell of the table gets the focus. It is if the window gets the focus
1928     * from view of the whole operation system, if the mouse is landing on a cell Text-field with click
1929     * or if setFocus() for the graphic presentation layer was called. 
1930     * <ul>
1931     * <li>If {@link #bFocusLost} is true, another cell of this table has lost the focus
1932     *   in the last 50 ms before the repaint() was invoked. Then the super.{@link GralWidget#setFocus()}
1933     *   will not be called.
1934     * <li>If {@link #bRedrawPending} is set, it means that the focus gained is invoked by a setFocus()-call
1935     *   of the graphic representation layer. Then the {@link GralWidget#setFocus()} will not be called.  
1936     * <li>If both conditions are false, it is a focusGained either by mouse click, whereby this table 
1937     *   has not have the focus before, or by any other action of focusing. 
1938     *   Then {@link GralWidget#setFocus()} is called to designate, that the table is focused.   
1939     * </ul>
1940     */
1941    public void focusGainedTable(){ 
1942      if(bFocusLost){  
1943        //focus is lost from another cell of this table yet now, repaint is not invoked,
1944        bFocusLost = false;  //ignore focus lost.
1945      } else {
1946        //Any cell has got the focus, it means the table has gotten the focus.
1947        bFocused = true; 
1948        if(!bRedrawPending){
1949          itsMng.gralFocusListener.focusGainedGral(GralTable.this);
1950          //super.focusGained();
1951          System.out.println("GralTable - debugInfo; focusGained " + GralTable.this.toString() );
1952          repaint(50,100);
1953        }
1954      }
1955    }
1956    
1957    /**Invoked if any cell has lost the focus.
1958     * If the table has lost the focus, the repaint will established this state after 50 milliseconds
1959     * because the flag {@link #bFocused} = false.
1960     * But if another cell of the table has gotten the focus in this time, the bFocus = true is set. 
1961     * 
1962     */
1963    protected void focusLostTable(){ 
1964      bFocusLost = true;
1965      repaint(50,100);  //NOTE: bFocusLost =false will be set in repaint.
1966    }
1967    
1968
1969    
1970    
1971    
1972    
1973    protected void mouseDownGral(int key, CellData cell){
1974      mousetime = System.currentTimeMillis();
1975      outer.mouseDown(key, cell);
1976    }
1977
1978
1979    protected void mouseUpGral(int key, CellData cell){
1980      if(mouseDoubleClick){
1981        mouseDoubleClick = false;
1982      } else {
1983        outer.mouseUp(key, cell);
1984      }
1985    }
1986
1987
1988    protected void mouseDoubleGral(int key, CellData cell){
1989      mousetime = System.currentTimeMillis();
1990      mouseDoubleClick = true;
1991      outer.mouseDouble(key, cell);
1992    }
1993
1994
1995    protected abstract void drawCellContent(int iCellLine, CellData[] cellData, GralTable<?>.TableLineData line, LinePresentation linePresentationP);
1996
1997    protected abstract CellData drawCellInvisible(int iCellLine, int iCellCol);
1998
1999    protected abstract int getVisibleLinesTableImpl();
2000    
2001    /**Should be implemented by the implementation class.
2002     * @param column The column
2003     * @return The menu.
2004     */
2005    protected abstract GralMenu createColumnMenu(int column);
2006    
2007    
2008    //protected void setCellDataOnMousePressed(CellData data){ cellDataOnMousePressed = data; } 
2009    
2010
2011    
2012
2013 
2014  }
2015
2016  
2017  /**This class is the super class of {@link TableLineData} which presents a line as a node in a tree. 
2018   * Therefore it implements the {@link TreeNodeBase} interface. A line as parent node can be presented folded (default)
2019   * or unfolded in several levels to present a tree instead a simple table. 
2020   * <br><br>
2021   * Only the {@link GralTable#rootLine} is a pure instance of this class The root line is never visible. It is the root. 
2022   * All other lines are instances of {@link TableLineData} derived from this class. 
2023   */
2024  public class NodeTableLine 
2025  extends TreeNodeBase<TableLineData, UserData, GralTableLine_ifc<UserData>>
2026  {
2027    /**Number of lines for this line and all visible children.
2028     * 
2029     */
2030    int zLineUnfolded;
2031    
2032    /**The deepness in the tree presentation of the data.
2033     * 
2034     */
2035    int treeDepth;
2036
2037    /**Lines of a children, a tree structure. null for a non-treed table.
2038     * null it the children are unknown or there are not children.
2039     */
2040    //protected ArrayList<TableLineData> childLines;
2041    
2042    //protected TableLineData parentLine;
2043    
2044    /**True if it is known that the node has children. They may be unknown, then {@link #childLines} are null. */
2045    boolean lineCanHaveChildren;
2046
2047    /**True if the children are shown in representation. */
2048    boolean showChildren;
2049
2050    NodeTableLine(String key, UserData data){ super(key, data); }
2051    
2052    
2053    void clear() {
2054      rootLine.removeChildren();
2055      rootLine.zLineUnfolded = 0;
2056    }
2057    
2058    
2059    /**Inserts a line as child of this. This method should be used if no child line exists yet.
2060     * It adds as last line of children. If child lines are existent, one can use {@link #addPrevLine(String, String[], Object)}
2061     * or {@link #addNextLine(String, String[], Object)} in respect to a given child line too.
2062     * @param lineKey The key for the line
2063     * @param lineTexts maybe null, elsewhere texts for the cells (column texts) of the line.
2064     * @param userDataP
2065     * @return the added line.
2066     */
2067    public TableLineData addChildLine(String lineKey, String[] lineTexts, UserData userDataP){
2068      lineCanHaveChildren = true; //hasChildren();
2069      TableLineData line = GralTable.this.new TableLineData(lineKey, userDataP);
2070      super.addNode(line);
2071      line.treeDepth = this.treeDepth +1;
2072      line.prepareAddedLine(lineTexts);
2073      return line;
2074
2075    }
2076    
2077    
2078    /**Inserts a line before the current line.
2079     * @param lineKey The key for the line
2080     * @param lineTexts maybe null, elsewhere texts for the cells (column texts) of the line.
2081     * @param userDataP
2082     * @return the added line.
2083     */
2084    public TableLineData addPrevLine(String lineKey, String[] lineTexts, UserData userDataP){
2085      lineCanHaveChildren = true; //hasChildren();
2086      TableLineData line = GralTable.this.new TableLineData(lineKey, userDataP);
2087      super.addSiblingPrev(line);  
2088      line.prepareAddedLine(lineTexts);
2089      return line;
2090
2091    }
2092    
2093    
2094    
2095    /**Inserts a line behind the current line.
2096     * @param lineKey The key for the line
2097     * @param lineTexts maybe null, elsewhere texts for the cells (column texts) of the line.
2098     * @param userDataP
2099     * @return the added line.
2100     */
2101    public TableLineData addNextLine(String lineKey, String[] lineTexts, UserData userDataP){
2102      lineCanHaveChildren = true; //hasChildren();
2103      TableLineData line = GralTable.this.new TableLineData(lineKey, userDataP);
2104      super.addSiblingNext(line);
2105      line.prepareAddedLine(lineTexts);
2106      return line;
2107
2108    }
2109
2110    public void deleteLine() {
2111      zLine -=1;
2112      nLineFirst = -1;
2113      adjCountChildrenInParent(-1);
2114      final TableLineData line1 = (TableLineData)this;
2115      bPrepareVisibleArea = true;
2116      if(lineSelected == this){
2117        TableLineData line2 = prevLine(line1);
2118        if(line2 == null){
2119          lineSelected = nextLine(line1); 
2120        } else {
2121          lineSelected = line2;
2122          //nLineCurr left unchanged.
2123        }
2124      } else {
2125        nLineFirst = -1;  //get new, undefined elsewhere.
2126      }
2127      line1.detach();
2128      repaint();
2129    }
2130    
2131    
2132
2133    
2134    void countChildren(boolean bLeftGrandChildrenOpen, int nrParent){
2135      countChildren(bLeftGrandChildrenOpen, nrParent, 0);
2136      adjCountChildrenInParent(this.zLineUnfolded);
2137    }
2138    
2139    
2140    /**Counts the children and checks whether their childs should be shown.
2141     * It checks and sets {@link TableLineData#showChildren}
2142     * @param lineParent
2143     * @param bLeftGrandChildrenOpen false then set {@link TableLineData#showChildren} = false, true: count the grand children.  
2144     * @param recurs more than 100 - prevent it.
2145     */
2146    void countChildren(boolean bLeftGrandChildrenOpen, int nrParent, int recurs){
2147      if(recurs >100) return;
2148      this.zLineUnfolded = 0;
2149      int ctParent = nrParent;
2150      TableLineData child = this.firstChild();
2151      while(child !=null) {
2152        this.zLineUnfolded +=1;
2153        ctParent +=1;
2154        if(zLineCurr >=0){ 
2155          zLineCurr +=1; 
2156          if(child == linesForCell[0]) {
2157            nLineFirst = ctParent;
2158          }
2159        }
2160        if(child.showChildren && bLeftGrandChildrenOpen) {
2161          child.countChildren(true, ctParent, recurs+1);
2162          this.zLineUnfolded += child.zLineUnfolded;
2163        } else {
2164          child.showChildren = false; //close it.
2165          child.zLineUnfolded = 0;
2166        }
2167        child = child.nextSibling();
2168      }
2169    }
2170    
2171    
2172    
2173    void adjCountChildrenInParent(int nCorr) {
2174      ////
2175      NodeTableLine parent1 = parent();
2176      boolean showChildren1 = showChildren;
2177      while(parent1 !=null   //stop on root node. 
2178          && (showChildren1 &= parent1.showChildren)   //stop count zLineUnfolded on nonvisible children.
2179        ) {
2180        zLineUnfolded += nCorr;
2181        parent1 = parent1.parent();   
2182      }
2183    }
2184
2185    
2186
2187    
2188  }
2189  
2190  
2191  /**An instance of this class presents a line in a table or a node or leaf in a tree.
2192   * It is not associated with a graphical representation primary, it is a container element only.
2193   * The graphical representation refers this class.
2194   * A table line contains:
2195   * <ul>
2196   * <li>Association to user data for application usage, unused in graphic: {@link TreeNodeBase#data}
2197   * <li>Texts for all cells of the table: {@link TableLineData#cellTexts}
2198   * <li>background and text color for the line (all cells) {@link TableLineData#colorBackground}, {@link TableLineData#colorForeground}
2199   * <li>Maybe background colors for all or some cells, null if the cell have the line back color
2200   * <li>Information about marking: {@link TableLineData#markMask}
2201   * <li>Information whether the line was changed (any cell): {@link TableLineData#bChanged}.  
2202   * </ul>
2203   */
2204  public final class TableLineData
2205  extends NodeTableLine 
2206  implements MarkMask_ifc, GralTableLine_ifc<UserData>
2207  {
2208
2209    SelectMask markMask;
2210    
2211    
2212    /**If a repaint is necessary, it is changed by increment by 1. If the redraw is executed
2213     * and no other redraw is requested, it is set to 0. If another redraw is requested while the
2214     * redraw runs but isn't finished, it should be executed a second time. Therefore it isn't reset to 0. 
2215     */
2216    public AtomicInteger ctRepaintLine = new AtomicInteger();  //NOTE should be public to see it from derived outer class
2217    
2218    public final String[] cellTexts;
2219
2220    /**If not null, then a special background color for the cell. Elsewhere the cell will be shown in the {@link #colorBackground} of the line
2221     * or the {@link GralTable#colorBackMarked} etc. of the table.
2222     * 
2223     */
2224    public GralColor[] cellColorBack;
2225    
2226    /**A line may have its datapath adequate a {@link GralWidget}, only used for
2227     * {@link #getDataPath()} and {@link #setDataPath(String)}.
2228     */
2229    private String sDataPath;
2230    
2231    /**True if any of a cell text was changed by manual edit. */
2232    protected final boolean[] bChangedEdit;
2233    
2234    /**True if any of a cell text was changed by manual edit. */
2235    protected final boolean[] bChangedSet;
2236    
2237    public GralColor colorForeground, colorBackground, colorBackSelect, colorBackSelectMarked, colorBackSelectSomeMarked, colorBackMarked, colorBackSomeMarked;
2238    
2239    //protected UserData userData;
2240    
2241    //TODO GralColor colorBack, colorText;
2242    
2243    TableLineData(String key, UserData data){
2244      super(key, data);  //key, data
2245      cellTexts = new String[GralTable.this.zColumn];
2246      bChangedEdit = new boolean[GralTable.this.zColumn];
2247      bChangedSet = new boolean[GralTable.this.zColumn];
2248    }
2249    
2250    
2251    
2252    
2253    /**Gets the table where this line is member of. 
2254     */
2255    @Override public GralTable<UserData> getTable() { return GralTable.this; }
2256    
2257    
2258    
2259    
2260    private void prepareAddedLine(String[] lineTexts) {
2261      nLineFirst = -1;  //get new, undefined elsewhere.
2262      if(lineTexts !=null){
2263        for(int ixCol = 0; ixCol < lineTexts.length && ixCol < cellTexts.length; ++ixCol){
2264          cellTexts[ixCol] = lineTexts[ixCol];
2265          bChangedSet[ixCol] = true;
2266        }
2267      } ////
2268      if(lineSelected == null){ //// 
2269        lineSelected = this;
2270        actionOnLineSelected(KeyCode.defaultSelect, lineSelected);
2271      }
2272      adjCountChildrenInParent(1);
2273      zLine += 1;
2274      GralTable.this.bPrepareVisibleArea = true;
2275      boolean showChildren1 = this.showChildren; 
2276      if(zLineUnfolded == -1){ 
2277        zLineUnfolded = 0;
2278      }
2279      if(showChildren) {
2280        zLineUnfolded +=1;
2281        adjCountChildrenInParent(1);
2282      }
2283      if(this == linesForCell[0]) {
2284        nLineFirst = rootLine.zLineUnfolded;  //store the number of current line if given.
2285      }
2286      if(showChildren1) {
2287        repaint();
2288      }
2289    }
2290    
2291
2292    
2293    
2294    /*
2295    @Override
2296    public void removeChildren(){
2297      if(childLines !=null){
2298        childLines = null;
2299      }
2300    }
2301    */
2302    
2303    
2304    @Override public void setEditable(boolean editable){
2305      throw new IllegalArgumentException("a table line can't be set edit able");
2306      //TODO set a table line to able to edit?
2307    }
2308
2309    /**Query whether the table line is able to edit: Return from the whole table.
2310     * @see org.vishia.gral.ifc.GralWidget_ifc#isEditable()
2311     */
2312    @Override public boolean isEditable(){ 
2313      return GralTable.this.bEditable; 
2314    }
2315    
2316    
2317    @Override public boolean isNotEditableOrShouldInitialize(){ return GralTable.this.isNotEditableOrShouldInitialize(); }
2318
2319    
2320    @Override public boolean isGraphicDisposed(){ return GralTable.this.isGraphicDisposed(); }
2321    
2322    
2323    @Override public boolean isChanged(boolean setUnchanged){ 
2324      boolean ret = false;
2325      for(int ix = 0; ix < bChangedEdit.length; ++ix) {
2326        ret |= bChangedEdit[ix];
2327        if(setUnchanged){
2328          bChangedEdit[ix] = false;
2329        }
2330      }
2331      return ret; 
2332    }
2333
2334
2335    public boolean wasCelltextSet(int column){
2336      boolean ret = bChangedSet[column];
2337      if(ret){
2338        bChangedSet[ column] = false;
2339      }
2340      return ret;
2341    }
2342    
2343    
2344    @Override public TableLineData parentNode(){ return (TableLineData)super.getParent(); }
2345    
2346    @Override public String getName(){ return GralTable.this.name; }
2347    
2348    @Override public void setCmd(String cmd){ GralTable.this.setCmd(cmd); }
2349    
2350    @Override public String getCmd(){ return GralTable.this.getCmd(); }
2351    
2352
2353    @Override public String getCellText(int column) { 
2354      String text = cellTexts[column]; 
2355      return text == null ? "" : text;
2356    }
2357
2358    @Override public String[] getCellTexts() { return cellTexts; }
2359
2360    
2361    public int treeDepth(){ return treeDepth; }
2362    
2363    @Override
2364    public String setCellText(String text, int column) {
2365      String oldText = cellTexts[column];
2366      if(oldText ==null || !oldText.equals(text)) {
2367        cellTexts[column] = text;
2368        bChangedSet[column] = true;
2369        GralTable.this.repaint();
2370      }
2371      return oldText;
2372    }
2373
2374    
2375    
2376    
2377    @Override public UserData getUserData() { return data;  }
2378
2379    //@Override public void setUserData(UserData data) {this.userData = data; }
2380
2381    @Override public long setContentIdent(long date){ long last = GralTable.this.dateUser; GralTable.this.dateUser = date; return last; }
2382    
2383    @Override public long getContentIdent(){ return GralTable.this.dateUser; }
2384
2385    @Override
2386    public int getSelectedColumn()
2387    { return GralTable.this.colSelectedixCellC;
2388    }
2389
2390    @Override public boolean setVisible(boolean visible) 
2391    { return false;  //TODO line visible. 
2392    }
2393
2394    
2395    
2396    @Override public void setFocus() { GralTable.this.setFocus(); }
2397
2398    @Override public void setFocus(int delay, int latest) { GralTable.this.setFocus(delay, latest); }
2399
2400    @Override public boolean isInFocus(){ return GralTable.this.isInFocus(); } 
2401
2402    @Override public boolean isVisible(){ return GralTable.this.isVisible(); }
2403    
2404
2405    @Override @Deprecated public GralColor setBackgroundColor(GralColor color) {
2406      GralColor ret = colorBackground;
2407      colorBackground = color;
2408      repaint(50, 50);
2409      return ret;
2410    }
2411
2412    @Override @Deprecated public GralColor setForegroundColor(GralColor color) {
2413      GralColor ret = colorForeground;
2414      colorForeground = color;
2415      repaint(50, 50);
2416      return ret;
2417    }
2418
2419    
2420    /**Sets the background color of the whole line or one cell.
2421     * @param ix -1 for the whole line, >=0 for one cell.
2422     */
2423    @Override public void setBackColor(GralColor color, int ix)
2424    { 
2425      if(color !=null && color.getColorName().equals("pma"))
2426        Assert.stop();
2427      if(ix <0){
2428        colorBackground = color;
2429      } else {
2430        if(ix >= cellTexts.length) throw new IndexOutOfBoundsException("faulty index " + ix);
2431        if(cellColorBack == null){ cellColorBack = new GralColor[cellTexts.length]; }
2432        cellColorBack[ix] = color;
2433      }
2434      repaint();
2435    }
2436    
2437    @Override public GralColor getBackColor(int ix)
2438    { 
2439      if(ix <0 || cellColorBack == null) {
2440        return colorBackground;
2441      } else {
2442        if(ix >= cellTexts.length) throw new IndexOutOfBoundsException("faulty index " + ix);
2443        return cellColorBack[ix] !=null ? cellColorBack[ix] : colorBackground;
2444      }
2445    }
2446    
2447    
2448
2449    /**Sets the background color for a special cell of line or for all cells of this line 
2450     *   which has not a special cell color for the several states of the line.
2451     * @param colorNormal non selected, non marked
2452     * @param colorSelected non marked, the selected line.
2453     * @param colorMarked marked, not the selected line
2454     * @param colorSomeMarked some marked, not the selected line
2455     * @param colorSelectMarked marked or some marked, the selected line.
2456     * @param ix -1 for the line, 0... for one cell of the line. 
2457     */
2458    public void setBackColor(GralColor colorNormal, GralColor colorSelected, GralColor colorMarked, GralColor colorSomeMarked, GralColor colorSelectMarked, int ix)
2459    { 
2460      if(ix <0){
2461        this.colorBackground = colorNormal;
2462        this.colorBackSelect = colorSelected;
2463        this.colorBackMarked = colorMarked;
2464        this.colorBackSelectSomeMarked = colorSomeMarked;
2465        this.colorBackSelectMarked = colorSelectMarked;
2466      } else {
2467        if(ix >= cellTexts.length) throw new IndexOutOfBoundsException("faulty index " + ix);
2468        if(cellColorBack == null){ cellColorBack = new GralColor[cellTexts.length]; }
2469        cellColorBack[ix] = colorNormal;
2470        //TODO cell colors state specific.
2471        this.colorBackSelect = colorSelected;
2472        this.colorBackMarked = colorMarked;
2473        this.colorBackSelectSomeMarked = colorSomeMarked;
2474        this.colorBackSelectMarked = colorSelectMarked;
2475      }
2476      repaint();
2477    }
2478    
2479    @Override public void setLineColor(GralColor color, int ix)
2480    { 
2481      colorForeground = color;
2482      repaint(50, 50);
2483    }
2484
2485    @Override public void setTextColor(GralColor color)
2486    { 
2487      colorForeground = color;
2488      repaint(50, 50);
2489    }
2490
2491    @Override public void setText(CharSequence text){
2492      throw new IllegalArgumentException("GralTable-TableLineData - setText is not implemented;");
2493    }
2494    
2495    
2496    @Override public void showChildren(boolean show, boolean bLeftGrandChildrenOpen) {
2497      if(show) {
2498        if(bLeftGrandChildrenOpen && showChildren) return;  //do nothing because no change
2499        else {
2500          if(showChildren) {  //it is shown already
2501          }
2502          showChildren = true;
2503          //children are closed yet, open and count it.
2504          countChildren(bLeftGrandChildrenOpen, nLineFirst);
2505        }
2506      } else { //switch off children
2507        if(showChildren) {
2508          adjCountChildrenInParent(-zLineUnfolded);  //firstly subtract because children are open
2509          showChildren = false;
2510        }
2511        //else: don't change anything.
2512      }
2513    }
2514
2515    
2516    
2517    
2518    public void showChildren(boolean show, boolean bLeftGrandChildrenOpen, boolean showReally) {
2519      showChildren(show, bLeftGrandChildrenOpen);
2520      countChildren(bLeftGrandChildrenOpen, nLineFirst);  //count the children.
2521      fillVisibleAreaBehind(this, lineSelectedixCell);
2522      repaint();
2523    }      
2524    
2525    
2526    @Override
2527    public void repaint() {
2528      ctRepaintLine.addAndGet(1);
2529      GralTable.this.repaint(); 
2530    }
2531
2532    @Override public void repaint(int delay, int latest){
2533      ctRepaintLine.addAndGet(1);
2534      GralTable.this.repaint(delay, latest); 
2535      //itsMng.setInfoDelayed(this, GralPanelMngWorking_ifc.cmdRedraw, 0, null, null, delay);
2536    }
2537    
2538
2539    
2540
2541    
2542    @Override
2543    public void setBoundsPixel(int x, int y, int dx, int dy) {
2544      // TODO Auto-generated method stub
2545      
2546    }
2547
2548    @Override public void refreshFromVariable(VariableContainer_ifc container){
2549      GralTable.this.refreshFromVariable(container);
2550    }
2551
2552    @Override public void refreshFromVariable(VariableContainer_ifc container, long timeAtleast, GralColor colorRefreshed, GralColor colorOld){
2553      GralTable.this.refreshFromVariable(container, timeAtleast, colorRefreshed, colorOld);
2554    }
2555
2556
2557    
2558    @Override public void setDataPath(String sDataPath){
2559      this.sDataPath = sDataPath;
2560    }
2561
2562    
2563    
2564    @Override public String getDataPath(){ return this.sDataPath; }
2565
2566    @Override public ActionChange getActionChange(ActionChangeWhen when){ return GralTable.this.getActionChange(when); }
2567
2568    
2569
2570    //@Override public Object[] getWidgetMultiImplementations(){ return null; }
2571
2572    
2573    @Override
2574    public boolean remove()
2575    { return GralTable.this.gi.remove();
2576    }
2577
2578    
2579    
2580    
2581    @Override public void setHtmlHelp(String url) { GralTable.this.setHtmlHelp(url); }
2582    
2583    
2584    @Override public Object getContentInfo(){ return data; }
2585
2586    
2587    
2588    @Override public int getMark(){
2589      if(data instanceof MarkMask_ifc){
2590        return ((MarkMask_ifc)data).getMark();
2591      } else if(markMask == null){
2592        return 0;
2593      } else {
2594        return markMask.getMark();
2595      }
2596
2597    }
2598    
2599
2600    /**Sets the mark status of the line.
2601     * It invokes the method given with {@link GralTable#specifyActionOnLineMarked(MarkMask_ifc)}
2602     * with the given {@link #setUserData(Object)} of this line. It means a selection with the user data
2603     * may be done too. This method will be called especially on pressing the mark key specified with  
2604     * {@link GralTable#specifyKeysMarkUpDn(int, int)}
2605     * @param mask This bits of the {@link SelectMask#selectMask} will be reseted.
2606     * @param data if null then don't invoke {@link GralTable#specifyActionOnLineMarked(MarkMask_ifc)}
2607     * @see org.vishia.util.SelectMask#setNonMarked(int, java.lang.Object)
2608     */
2609    @Override public int setNonMarked(int mask, Object data)
2610    { if(GralTable.this.actionMarkOnLine !=null && data !=null){ GralTable.this.actionMarkOnLine.setNonMarked(mask, data); }
2611      if(data instanceof MarkMask_ifc){
2612        ((MarkMask_ifc)data).setNonMarked(mask, data);
2613      }
2614      if(markMask ==null) return 0;
2615      else return markMask.setNonMarked(mask, data);
2616    }
2617    
2618    /**Sets the mark status of the line.
2619     * It invokes the method given with {@link GralTable#specifyActionOnLineMarked(MarkMask_ifc)}
2620     * with the given {@link #getUserData()} of this line. It means a selection with the user data
2621     * may be done too. This method will be called especially on pressing the mark key specified with  
2622     * {@link GralTable#specifyKeysMarkUpDn(int, int)}
2623     * @param mask This bits of the {@link SelectMask#selectMask} will be set.
2624     * @param data if null then don't invoke {@link GralTable#specifyActionOnLineMarked(MarkMask_ifc)}
2625     * @see org.vishia.util.SelectMask#setNonMarked(int, java.lang.Object)
2626     */
2627    @Override public int setMarked(int mask, Object data)
2628    { if(GralTable.this.actionMarkOnLine !=null && data !=null){ GralTable.this.actionMarkOnLine.setMarked(mask, data); }
2629      if(data instanceof MarkMask_ifc){
2630        ((MarkMask_ifc)data).setMarked(mask, data);
2631      }
2632      if(markMask ==null){ markMask = new SelectMask(); }
2633      return markMask.setMarked(mask, data);
2634    }
2635
2636    @Override public GralMng gralMng(){ return GralTable.this.gralMng(); }
2637    
2638    @Override public void setToPanel(GralMngBuild_ifc mng){
2639      throw new IllegalArgumentException("GralTableLine.setToPanel - is illegal; Use GralTable.setToPanel(...)");
2640    }
2641
2642    @Override public void createImplWidget_Gthread(){
2643      throw new IllegalArgumentException("GralTableLine.setToPanel - is illegal; Use GralTable.setToPanel(...)");
2644    }
2645
2646    @Override public String toString(){ 
2647      StringBuilder u = new StringBuilder();
2648      for(int ii = 0; ii < cellTexts.length; ++ii){
2649        u.append(cellTexts[ii]).append('|');
2650      }
2651      return u.toString(); 
2652    }
2653
2654
2655
2656    @Override public void setData(Object data)
2657    { throw new IllegalArgumentException("not supported, only final data on construction.");
2658    }
2659
2660
2661
2662    @Override public UserData getData()
2663    { return data;
2664    }
2665  }
2666  
2667  /**Data for each Text widget of the graphical implementation layer.
2668   * An instance is created on creating the text field for the cell in the implementation layer.
2669   * The instance is referenced only by the text field,
2670   * It refers the data of the {@link GralTable#tableLines}.
2671   * <pre>
2672   * swt.Canvas
2673   *      |--*>swt.Text
2674   *               |--data-->CellData
2675   *                           -ixCellLine
2676   *                           -ixCellColumn
2677   * 
2678   * </pre>
2679   * 
2680   * Note: The class should be used  only in the graphic implementation layer. It is public only to allow access from several implementations.
2681   * It is not public to offer it for applications.
2682   */
2683  public static class CellData
2684  {
2685    
2686    /**The row and column in the graphical presentation. With the information about the row, the
2687     * associated {@link TableLineData} can be found via the {@link GralTable#linesForCell}. */
2688    public final int ixCellLine, ixCellColumn;
2689    
2690    /**The color in the graphical presentation. It is the color of the text field. 
2691     * Note that the color of the text field is only changed if this colors and the 
2692     * {@link TableLineData#colorBackground} and {@link TableLineData#colorForeground} are different. 
2693     * It saves some calculation time if the color of the text field is set only if it is necessary. */
2694    public GralColor colorBack, colorText;
2695    
2696    
2697    /**temporary set to true to set the focus of this cell.
2698     * 
2699     */
2700    public boolean bSetFocus;
2701    
2702    /**The currently tree depth of this cell. Invoke setBounds if it is different of line. */
2703    public int treeDepth;
2704    
2705    
2706    /**The widget for a cell is a GralTextField. @since 2015-11-09 for AWT-adaption*/
2707    //public GralTextField wdgCell;
2708    
2709    public CellData(int ixCellLine, int ixCellColumn){
2710      this.ixCellLine = ixCellLine; 
2711      this.ixCellColumn = ixCellColumn;
2712      //this.wdgCell = new GralTextField(null);
2713    }
2714  }
2715  
2716
2717  
2718  
2719}