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}