    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}