001package org.vishia.gral.swt; 002 003 004 005 006import org.eclipse.swt.SWT; 007import org.eclipse.swt.events.ControlEvent; 008import org.eclipse.swt.events.ControlListener; 009import org.eclipse.swt.events.FocusEvent; 010import org.eclipse.swt.events.FocusListener; 011import org.eclipse.swt.events.KeyEvent; 012import org.eclipse.swt.events.KeyListener; 013import org.eclipse.swt.events.MouseEvent; 014import org.eclipse.swt.events.MouseListener; 015import org.eclipse.swt.events.MouseWheelListener; 016import org.eclipse.swt.events.PaintEvent; 017import org.eclipse.swt.events.PaintListener; 018import org.eclipse.swt.events.SelectionEvent; 019import org.eclipse.swt.events.SelectionListener; 020import org.eclipse.swt.events.TraverseEvent; 021import org.eclipse.swt.events.TraverseListener; 022import org.eclipse.swt.graphics.Color; 023import org.eclipse.swt.graphics.Font; 024import org.eclipse.swt.graphics.GC; 025import org.eclipse.swt.graphics.Point; 026import org.eclipse.swt.graphics.Rectangle; 027import org.eclipse.swt.widgets.Canvas; 028import org.eclipse.swt.widgets.Composite; 029import org.eclipse.swt.widgets.Control; 030import org.eclipse.swt.widgets.Menu; 031import org.eclipse.swt.widgets.Text; 032import org.eclipse.swt.widgets.Widget; 033import org.vishia.gral.base.GralMenu; 034import org.vishia.gral.base.GralTable; 035import org.vishia.gral.base.GralWidgImpl_ifc; 036import org.vishia.gral.base.GralWidget; 037import org.vishia.gral.base.GralMng; 038import org.vishia.gral.ifc.GralColor; 039import org.vishia.gral.ifc.GralRectangle; 040import org.vishia.gral.ifc.GralTableLine_ifc; 041import org.vishia.gral.ifc.GralUserAction; 042import org.vishia.gral.ifc.GralWidget_ifc; 043import org.vishia.util.Assert; 044import org.vishia.util.Debugutil; 045import org.vishia.util.KeyCode; 046 047/**Implementation of the GralTable for Swt graphic. 048 * The following schema shows the aggregation relations, see {@link org.vishia.util.Docu_UML_simpleNotation}: 049 * <pre> 050 * |--widgg----------------->GralWidget<|-------+ 051 * | | | 052 * +--|>GralWidget.ImplAccess<--widgImpl---| | 053 * | | 054 * | | 055 * +-|>GralTable.GraphicImplAccess | 056 * | | | 057 * SwtTable | GralTable 058 * | | | 059 * | |<-------------------------------------gi--| 060 * | | | 061 * | |<&>-------------------------------------&>| 062 * | access to all protected methods and fields of GralTable 063 * | 064 * | 065 * | 066 * |---swtWidg----->SwtWidgetHelper 067 * | | 068 * | | 069 * | |--widgetSwt--->Control<|---Composite<|---SwtTable.Table 070 * | | | 071 * |---cellsSwt--------------*>Text<*---------------------| some Listener 072 * | 073 * | 074 * </pre> 075 * <ul> 076 * <li>The {@link GralTable} contains some implementation-non-specific things, most of table structure. 077 * <li>To access from this class to the GralTable, the inner class {@link GralTable.GraphicImplAccess} 078 * is used as super class of SwtTable with protected access. 079 * <li>The GralTable knows this class via the interface {@link GralWidgImpl_ifc} in its superclass 080 * association {@link GralWidget#_wdgImpl}. 081 * <li>The GralTable knows this class via {@link GralTable#gi} association with the proper type. 082 * <li>The {@link GralTable.GraphicImplAccess} defines some abstract methods which are implemented here. 083 * <li>But some implementations of {@link GralWidgImpl_ifc} is found in {@link SwtWidgetHelper}. 084 * That are unique implementations, reuse it! 085 * <li>Therefore for reused implementations this class delegates the interface to {@link #swtWidgHelper}. 086 * <li>The Swt widget core implementation is {@link Table} which is derived from 087 * {@link org.eclipse.swt.widgets.Composite}. That Composite contains some text fields 088 * which are the visible rows and columns of the table. 089 * <li>The text fields are created as children of the swt.widgets.Composite but associated 090 * in this class: {@link #cellsSwt}. Therefore this class can access the visible rows and columns 091 * directly, using as {@link org.eclipse.swt.widgets.Text}. 092 * <li>The inner class {@link Table} is necessary only as implementor of {@link GralWidgetGthreadSet_ifc}. 093 * But that is an {@link Deprecated} interface. It is possible to replace it later with an simple 094 * instance of Composite. 095 * <li>The content of the table itself is stored in an array of {@link GralTable#tableLines}, 096 * see description of {@link GralTable}. 097 * </ul> 098 * @author Hartmut Schorrig 099 * 100 */ 101public class SwtTable extends GralTable<?>.GraphicImplAccess implements GralWidgImpl_ifc 102, FocusListener //for the cells 103//public class SwtTable implements GralWidgImpl_ifc 104{ 105 106 /**Version and history 107 * <ul> 108 * <li>2018-01-07 Hartmut new: {@link #getCellTextFocus()} 109 * <li>2015-08-29 Hartmut chg: It has a {@link #traverseListenerTable} now to accept 'tab' and 'sh-tab' as normal key 110 * instead usage to traverse between the text fields of a table. TODO: What traversing functions are missing yet? 111 * They should not any traverse function between the cells. 112 * <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. 113 * The inner class {@link GraphicImplAccess} is provided as super class for the graphic implementation class, 114 * for example {@link org.vishia.gral.swt.SwtTable}. 115 * <li>2013-10-08 Hartmut chg: 116 * <li>2012-07-15 Hartmut new: search functionality: This implementation have a text field 117 * which shows the search string. While up and down keys the that lines are selected which text in the {@link #ixColumn()} 118 * starts whith the search string. 119 * <li>2012-01-06 Hartmut new: concept of a table which is independent of the table implementation 120 * of the table implementations in the graphic system layer or in operation system: 121 * The capability of a SWT-table is not sufficient, for example the color of the selection bar 122 * is not able to change. Other reason: Implementation of table in SWT, AWT, Swing is different. 123 * It seems better to have one table concept with independent features, which based on simple widgets. 124 * is not 125 * </ul> 126 * 127 * <b>Copyright/Copyleft</b>: 128 * For this source the LGPL Lesser General Public License, 129 * published by the Free Software Foundation is valid. 130 * It means: 131 * <ol> 132 * <li> You can use this source without any restriction for any desired purpose. 133 * <li> You can redistribute copies of this source to everybody. 134 * <li> Every user of this source, also the user of redistribute copies 135 * with or without payment, must accept this license for further using. 136 * <li> But the LPGL ist not appropriate for a whole software product, 137 * if this source is only a part of them. It means, the user 138 * must publish this part of source, 139 * but don't need to publish the whole source of the own product. 140 * <li> You can study and modify (improve) this source 141 * for own using or for redistribution, but you have to license the 142 * modified sources likewise under this LGPL Lesser General Public License. 143 * You mustn't delete this Copyright/Copyleft inscription in this source file. 144 * </ol> 145 * If you are intent to use this sources without publishing its usage, you can get 146 * a second license subscribing a special contract with the author. 147 * 148 * @author Hartmut Schorrig = hartmut.schorrig@vishia.de 149 * 150 */ 151 public final static String version = "2015-08-29"; 152 153 /**It contains the association to the swt widget (Control) and the {@link SwtMng} 154 * and implements some methods of {@link GralWidgImpl_ifc} which are delegate from this. 155 */ 156 private final SwtWidgetHelper swtWidgHelper; 157 158 /**Some SWT Text Control fields. There are the visible cells of the table. They are children 159 * of the Composite in {@link SwtWidgetHelper#widgetSwt}. */ 160 private final Text[][] cellsSwt; 161 162 private Canvas vScrollBar; 163 164 private Text cellInFocus; 165 166 Color colorBackVscrollbar, colorSliderVscrollbar; 167 168 /**SWT Text Control which contains a search text. It is only visible if need. */ 169 protected Text swtSearchText; 170 171 //private final SwtTable.Table table; 172 173 private final FocusListener focusListenerTable; 174 175 //private final FocusListener focusListenerCell; 176 177 private final MousePressedListenerTable mousePressedListener = new MousePressedListenerTable(); 178 179 private final MouseWheelListenerTable mouseWheelListener = new MouseWheelListenerTable(); 180 181 private final TableKeyListerner myKeyListener; 182 183 public SwtTable(GralTable<?> gralTable, SwtMng mng, Composite parent) 184 { gralTable.super(gralTable, mng.mng); 185 //super(name, mng, columnWidths); 186 this.myKeyListener = this.new TableKeyListerner(null); 187 focusListenerTable = this.new FocusListenerTable(mng); 188 //focusListenerCell = this; 189 setColorsSwt(); 190 int zLineVisibleMax = gralTable.nrofLinesVisibleMax(); 191 this.cellsSwt = new Text[zLineVisibleMax][zColumn()]; 192 int zColumn = zColumn(); 193 Composite swtTable = new SwtTable.Table(parent, zColumn, mng); 194 initSwtTable(swtTable, zColumn, mng); 195 vScrollBar = new Vscrollbar(swtTable); 196 super.wdgimpl = this.swtWidgHelper = new SwtWidgetHelper(swtTable, mng); 197 //gralTable.implMethodWidget_.setWidgetImpl(this); 198 //this.menuColumns = new SwtMenu[zColumn]; 199 swtWidgHelper.widgetSwt.addKeyListener(myKeyListener); 200 //table.addSelectionListener(selectionListener); 201 swtWidgHelper.widgetSwt.addControlListener(resizeListener); 202 swtWidgHelper.widgetSwt.addFocusListener(focusListenerTable); 203 204 swtWidgHelper.widgetSwt.setFont(mng.propertiesGuiSwt.stdInputFont); 205 GralRectangle pixTable = swtWidgHelper.mng.setBounds_(widgg.pos(), swtWidgHelper.widgetSwt); 206 SwtTable.this.resizeTable(pixTable); 207 } 208 209 210 211 212 /** 213 * @param gralTable 214 * @param mng 215 * @param sName 216 * @param height 217 * @param columnWidths 218 * @return 219 * @deprecated Create an instance of {@link GralTable} and call 220 */ 221 @Deprecated 222 public static GralTable addTable(GralTable gralTable, SwtMng mng, String sName, int height, int[] columnWidths 223 //, int selectionColumn, CharSequence selectionText 224 ) { 225 226 boolean TEST = false; 227 final SwtTable table; 228 Composite parent = mng.getCurrentPanel(); 229 table = new SwtTable(gralTable, mng, parent); //, selectionColumn, selectionText); 230 table.outer.setDataPath(sName); 231 table.swtWidgHelper.widgetSwt.setData(table); 232 mng.mng.registerWidget(gralTable); 233 //NOTE done in SwtTable.resize() ((SwtMng)mng).setPosAndSize_(table.table); 234 return gralTable; 235 236 } 237 238 239 /*package private*/ 240 static void createTable(GralTable<?> gralTable, SwtMng mng) { 241 242 Composite parent = mng.getWidgetsPanel(gralTable); 243 @SuppressWarnings("unchecked") 244 final SwtTable table = new SwtTable(gralTable, mng, parent); //, selectionColumn, selectionText); 245 table.swtWidgHelper.widgetSwt.setData(table); 246 mng.mng.registerWidget(gralTable); 247 //NOTE done in SwtTable.resize() ((SwtMng)mng).setPosAndSize_(table.table); 248 249 } 250 251 252 private void setColorsSwt(){ 253 //colorBackSelectSwt = mng.getColorImpl(colorBackSelect); 254 //colorBackMarkedSwt = mng.getColorImpl(colorBackMarked); 255 //colorBackTableSwt = mng.getColorImpl(colorBackTable); 256 //colorBackSelectNonFocusedSwt = mng.getColorImpl(colorBackSelectNonFocused); 257 //colorBackMarkedNonFocusedSwt = mng.getColorImpl(colorBackMarkedNonFocused); 258 //colorBackTableNonFocusedSwt = mng.getColorImpl(colorBackTableNonFocused); 259 } 260 261 262 263 264 @Override public Object getWidgetImplementation() { 265 return swtWidgHelper.widgetSwt; 266 } 267 268 //@Override 269 public GralColor setBackgroundColor(GralColor color) { 270 // TODO Auto-generated method stub 271 return null; 272 } 273 274 //@Override 275 public GralColor setForegroundColor(GralColor color) { 276 // TODO Auto-generated method stub 277 return null; 278 } 279 280 @Override 281 public void setBoundsPixel(int x, int y, int dx, int dy) { 282 // TODO Auto-generated method stub 283 284 } 285 286 287 288 @Override public GralRectangle getPixelPositionSize(){ return swtWidgHelper.getPixelPositionSize(); } 289 290 291 //@Override 292 public boolean XXXsetVisible(boolean visible){ 293 boolean ret = swtWidgHelper.widgetSwt.isVisible(); 294 swtWidgHelper.widgetSwt.setVisible(visible); 295 ((GralWidget.ImplAccess)this).setVisibleState(visible); 296 return ret; 297 } 298 299 300 301 /** TODO implement in {@link GralTable.GraphicImplAccess} 302 * @see org.vishia.gral.base.GralWidgImpl_ifc#repaintGthread() 303 */ 304 @Override public void repaintGthread(){ 305 if(bFocusLost){ 306 //this is about 50 ms after focus lost, the focus has lost really. 307 bFocused = false; 308 bFocusLost = false; 309 setFocused(widgg, false); 310 } 311 if(swtWidgHelper.widgetSwt !=null && !swtWidgHelper.widgetSwt.isDisposed()){ 312 int chg = getChanged(); 313 int acknChg = 0; 314 if((chg & chgVisible)!=0){ 315 acknChg |= chgVisible; 316 setVisibleState(true); 317 swtWidgHelper.widgetSwt.setVisible(true); //the composite. 318 //for(Text[] lines: cellsSwt){ 319 // for(Text cell: lines){ cell.setVisible(true); } 320 //} 321 } 322 if((chg & chgInvisible)!=0){ 323 acknChg |= chgInvisible; 324 setVisibleState(false); 325 swtWidgHelper.widgetSwt.setVisible(false); //the composite. 326 //for(Text[] lines: cellsSwt){ 327 // for(Text cell: lines){ cell.setVisible(false); } 328 //} 329 } 330 acknChanged(acknChg); 331 if(widgg.isVisible()){ 332 // 333 updateGraphicCellContent(); //invokes drawCellContent(...) with the correct lines. 334 //^^^^^^^^^^^^^^^^^ 335 //setAllCellContentGthread(); 336 Color colorSelectBack = swtWidgHelper.mng.getColorImpl(super.colorSelectCharsBack()); 337 Color colorSelect = swtWidgHelper.mng.getColorImpl(super.colorSelectChars()); 338 if(super.searchChars().length() >0){ 339 swtSearchText.setBackground(colorSelectBack); 340 swtSearchText.setForeground(colorSelect); 341 //swtSearchText. 342 swtSearchText.setText(searchChars().toString()); 343 Point tabSize = swtWidgHelper.widgetSwt.getSize(); 344 swtSearchText.setBounds(xpixelCell[ixColumn()] + 10, tabSize.y - linePixel, xpixelCell[ixColumn()+1] - xpixelCell[ixColumn()] - 10, linePixel); 345 swtSearchText.setVisible(true); 346 347 } else { 348 swtSearchText.setVisible(false); 349 } 350 //System.out.println("swtTable redrawed"); 351 //see redrawChildren. This redraw don't influences the vScrollbar: 352 //swtWidgHelper.widgetSwt.redraw(); 353 //swtWidgHelper.widgetSwt.update(); //this is the core-redraw 354 //redraw command for the: 355 if(bVscrollbarChanged){ 356 vScrollBar.update(); 357 vScrollBar.redraw(); 358 } 359 } 360 //((Table)swtWidg.widgetSwt).super.redraw(); 361 redrawtime = System.currentTimeMillis(); 362 super.bChangedLinesForCell(false); 363 //System.out.println("test SwtTable redraw " + ++redrawct); 364 } else { 365 System.out.println("test SwtTable redraw disposed" + ++redrawct); 366 } 367 bRedrawPending = false; 368 369 } 370 371 372 /**Sets the focus to the current cell of the tab 373 * @see org.vishia.gral.base.GralWidget#setFocusGThread() 374 * TODO this method must call in the graphic thread yet, queue it with {@link GralMng#setInfo(GralWidget, int, int, Object, Object)}. 375 */ 376 @Override public boolean setFocusGThread() 377 { repaintGthread(); //to set the focus of the cell 378 return true; 379 } 380 381 382 @Override public void setVisibleGThread(boolean bVisible) { 383 swtWidgHelper.setVisibleGThread(bVisible); 384 super.setVisibleState(bVisible); 385 for(Text[] cell1 : cellsSwt) for(Text cell: cell1){ 386 if(cell !=null) { 387 cell.setVisible(bVisible); 388 } 389 } 390 repaintGthread(); 391 } 392 393 394 @Override 395 protected void setDragEnable(int dragType) 396 { throw new IllegalArgumentException("drag not supported for this widget type"); 397 } 398 399 400 /**Removes the graphical widgets. 401 * @see org.vishia.gral.base.GralWidget#removeWidgetImplementation() 402 */ 403 @Override public void removeWidgetImplementation() { 404 // TODO Auto-generated method stub 405 if(!swtWidgHelper.widgetSwt.isDisposed()){ 406 for(int iRow = 0; iRow < cellsSwt.length; ++iRow){ 407 for(int iCol = 0; iCol < zColumn(); ++iCol){ 408 Text cell = cellsSwt[iRow][iCol]; 409 cell.dispose(); 410 cellsSwt[iRow][iCol] = null; 411 } 412 } 413 swtWidgHelper.widgetSwt.dispose(); //it may be sufficient to dispose table only becaust it is the container.... 414 } 415 } 416 417 @Override public boolean remove(){ 418 super.remove(); //removes the widget implementation. 419 return true; 420 } 421 422 423 /**Sets the current cell as focused with the focus color. It causes 424 * a redraw of the whole table because the cell may be shifted in table position. 425 * TODO this method must call in the graphic thread yet, queue it with {@link GralMng#setInfo(GralWidget, int, int, Object, Object)}. 426 * @param cell The cell 427 */ 428 private void redrawTableWithFocusedCell(Widget cell){ 429 GralTable.CellData data = (GralTable.CellData)cell.getData(); 430 data.bSetFocus = true; 431 if(super.redrawTableWithFocusedCell(data)){ 432 repaintGthread(); 433 //((Table)swtWidgWrapper.widgetSwt).redrawGthread(); 434 } 435 } 436 437 438 439 @Override protected int getVisibleLinesTableImpl(){ 440 Rectangle size = swtWidgHelper.widgetSwt.getBounds(); 441 return size.height / linePixel; 442 } 443 444 445 /**This routine implements all things to set the content of any table cell to show it. 446 * @see org.vishia.gral.base.GralTable#drawCellContent(int, int, org.vishia.gral.base.GralTable.TableLineData) 447 */ 448 @Override protected void drawCellContent(int iCellLine, GralTable.CellData[] cellLine, GralTable<?>.TableLineData line, GralTable.LinePresentation linePresentationP){ 449 Text[] textlineSwt = cellsSwt[iCellLine]; 450 int treeDepth = -1; 451 if(line !=null && line.treeDepth() != cellLine[0].treeDepth){ 452 treeDepth = cellLine[0].treeDepth = line.treeDepth(); 453 } 454 if(line !=null){ 455 for(int col=0; col < cells[0].length; ++col){ 456 Text cellSwt = textlineSwt[col]; 457 GralTable.CellData cellData = cellLine[col]; //(GralTable.CellData)cellSwt.getData(); 458 if(treeDepth >=0 && col < super.nrofColumnTreeShift){ 459 int xleft = xpixelCell[col] + treeDepth * xPixelUnit; 460 int xRight = xpixelCell[col+1] + (col < (super.nrofColumnTreeShift-1) ? treeDepth * xPixelUnit : 0); 461 int yTop = cellData.ixCellLine * linePixel; 462 cellSwt.setBounds(xleft, yTop, xRight - xleft, linePixel); 463 } 464 // 465 if(line.wasCelltextSet(col) || bChangedLinesForCell()) { 466 String text = line.cellTexts[col]; 467 if(text == null){ text = ""; } 468 // 469 cellSwt.setText(text); 470 } 471 if(cellData.bSetFocus){ 472 cellSwt.setFocus(); 473 cellData.bSetFocus = false; 474 } 475 GralColor colorBackCell = linePresentationP.cellsColorBack !=null && linePresentationP.cellsColorBack[col] !=null 476 ? linePresentationP.cellsColorBack[col] : linePresentationP.colorBack; 477 if(cellData.colorBack != colorBackCell){ 478 //only change color of the SWT Text field if it is necessary, comparison set color with cellData.color. 479 Color colorSwt = swtWidgHelper.mng.getColorImpl(colorBackCell); 480 cellSwt.setBackground(colorSwt); 481 cellData.colorBack = colorBackCell; //for the visible cell swt widget, not for the table line! 482 } 483 if(cellData.colorText != linePresentationP.colorText){ 484 //only change color of the SWT Text field if it is necessary, comparison set color with cellData.color. 485 cellSwt.setForeground(swtWidgHelper.mng.getColorImpl(linePresentationP.colorText)); 486 cellData.colorText = linePresentationP.colorText; 487 } 488 cellSwt.setVisible(true); 489 cellSwt.redraw(); 490 } 491 } else { 492 //empty line: 493 GralColor colorBack = colorBackTable(); 494 for(int col=0; col < cells[0].length; ++col){ 495 Text cellSwt = textlineSwt[col]; 496 GralTable.CellData cellData = cellLine[col]; //(GralTable.CellData)cellSwt.getData(); 497 cellSwt.setText(""); 498 if(cellData.colorBack != colorBack){ 499 Color colorSwt = swtWidgHelper.mng.getColorImpl(colorBack); 500 cellSwt.setBackground(colorSwt); 501 cellData.colorBack = colorBack; //for the visible cell swt widget, not for the table line! 502 } 503 } 504 } 505 } 506 507 508 509 510 511 @Override protected GralTable.CellData drawCellInvisible(int iCellLine, int iCellCol){ 512 Text cellSwt = cellsSwt[iCellLine][iCellCol]; 513 GralTable.CellData cellData = (GralTable.CellData)cellSwt.getData(); 514 cellSwt.setText(""); 515 if(cellData.colorBack != colorBackTable()){ 516 Color colorSwt = swtWidgHelper.mng.getColorImpl(colorBackTable()); 517 cellSwt.setBackground(colorSwt); 518 cellData.colorBack = colorBackTable(); 519 } 520 cellSwt.setVisible(true); 521 return (cellData); 522 } 523 524 525 526 527 private void paintVscrollbar(GC gc, Canvas canvas) 528 { 529 530 if(ixColorScrollbar != ixColorScrollbarLast) { 531 //only get a new color if necessary. 532 colorBackVscrollbar = swtWidgHelper.mng.getColorImpl(colorBackVscrollbar()); 533 colorSliderVscrollbar = swtWidgHelper.mng.getColorImpl(colorLineVscrollbar()); 534 ixColorScrollbarLast = ixColorScrollbar; 535 } 536 Rectangle dim = canvas.getBounds(); 537 determineSizeAndPositionScrollbar(dim.height); 538 gc.setForeground(colorBackVscrollbar); 539 gc.fillRectangle(1, dim.y, dim.width, dim.height); 540 gc.setForeground(colorSliderVscrollbar); 541 gc.setBackground(colorSliderVscrollbar); 542 //Note: relative coordinates inside the canvas area: 543 gc.fillRectangle(1, y1Scrollbar, dim.width-1, y2Scrollbar - y1Scrollbar); 544 //gc.drawLine(1, y1Scrollbar+1, dim.width-1, y2Scrollbar); // - y1Scrollbar-1); 545 546 //gc.drawLine(1,1, dim.width-1, dim.height-1); 547 548 } 549 550 551 552 553 @Override protected GralMenu createColumnMenu(int column){ 554 //GralMenu menuColumn = new SwtMenu(outer, swtWidgWrapper.widgetSwt, itsMng()); 555 GralMenu menuColumn = new GralMenu(); 556 new SwtMenu(menuColumn, null, cellsSwt[0][column]); 557 for(int iRow = 1; iRow < cellsSwt.length; ++iRow){ 558 //uses the same menu instance in all cells of the column. 559 cellsSwt[iRow][column].setMenu((Menu)menuColumn.getMenuImpl()); 560 } 561 return menuColumn; 562 } 563 564 565 /**Called internal from mouse event only. 566 * @param ev 567 */ 568 protected void mouseDown(MouseEvent ev){ 569 Text widgSwt = (Text)ev.widget; //it is only associated to a cell. 570 GralTable.CellData cell = (GralTable.CellData)widgSwt.getData(); 571 int key = SwtGralKey.convertMouseKey(ev.button, SwtGralKey.MouseAction.down, ev.stateMask); 572 super.mouseDownGral(key, cell); //To independent GRAL layer 573 } 574 575 576 577 /**Called internal from mouse event only. 578 * @param ev 579 */ 580 protected void mouseUp(MouseEvent ev){ 581 Text widgSwt = (Text)ev.widget; //it is only associated to a cell. 582 GralTable.CellData cell = (GralTable.CellData)widgSwt.getData(); 583 int key = SwtGralKey.convertMouseKey(ev.button, SwtGralKey.MouseAction.up, ev.stateMask); 584 super.mouseUpGral(key, cell); //To independent GRAL layer 585 } 586 587 588 589 /**Called internal from mouse event only. 590 * @param ev 591 */ 592 protected void mouseDouble(MouseEvent ev){ 593 Text widgSwt = (Text)ev.widget; //it is only associated to a cell. 594 GralTable.CellData cell = (GralTable.CellData)widgSwt.getData(); 595 int key = SwtGralKey.convertMouseKey(ev.button, SwtGralKey.MouseAction.down, ev.stateMask); 596 super.mouseDoubleGral(key, cell); //To independent GRAL layer 597 } 598 599 600 601 @Override protected void setBoundsCells(int treeDepthBase, int zLineVisible){ 602 int yPix = 0; 603 //int xPixelUnit = swtWidgHelper.mng.mng.propertiesGui.xPixelUnit(); 604 int ixrow = 0; 605 for(Text[] row: cellsSwt){ 606 if(ixrow < zLineVisible) { 607 int ixColumn = 0; 608 for(Text cell: row){ 609 cell.setVisible(true); 610 int xleft = 0; 611 cell.setBounds(xleft + xpixelCell[ixColumn], yPix, xpixelCell[ixColumn+1] - xpixelCell[ixColumn], linePixel); 612 ixColumn +=1; 613 } 614 yPix += linePixel; 615 } else { 616 //invisible cells: 617 for(Text cell: row){ 618 cell.setVisible(false); 619 } 620 } 621 ixrow +=1; 622 } 623 vScrollBar.setBounds(xyVscrollbar.x, xyVscrollbar.y, xyVscrollbar.dx, xyVscrollbar.dy); 624 } 625 626 /**Invoked on {@link #swtKeyListener} if enter. */ 627 void setTextToLine(Text widgSwt){ 628 String text = widgSwt.getText(); 629 GralTable.CellData data = (GralTable.CellData)widgSwt.getData(); 630 SwtTable.this.setCellText(data, text); 631 } 632 633 634 protected String getCellText(GralTable.CellData cell){ 635 return cellsSwt[cell.ixCellLine][cell.ixCellColumn].getText(); 636 } 637 638 639 @Override protected String getCellTextFocus(){ 640 if(cellInFocus == null) return null; 641 else return cellInFocus.getText(); 642 } 643 644 645 646 647 648 649 /**Focus listener implementation for all cells. 650 * This routine is invoked whenever the focus of any Text field of the table will be lost the focus. 651 * It invokes {@link GralTable.GraphicImplAccess#focusLostTable()} but only if 652 * {@link GralTable.GraphicImplAccess#bRedrawPending} is not set. That prevents invocation while 653 * {@link GralTable.GraphicImplAccess#updateGraphicCellContent()} sets the focus while updating the graphic cells. 654 * 655 */ 656 @Override public void focusLost(FocusEvent ev){ 657 //System.out.println("Cell focus lost"); 658 super.focusLostTable(); 659 if(!bRedrawPending){ 660 //System.out.println("SwtTable - cell focus lost;" + (SwtTable.this).outer.toString()); 661 GralTable.CellData celldata = (GralTable.CellData)ev.widget.getData(); 662 Text widgSwt = (Text)ev.widget; 663 if(super.bColumnEditable(celldata.ixCellColumn)){ 664 String sText = widgSwt.getText(); 665 super.checkAndUpdateText(sText, celldata); 666 } 667 //widgSwt.setBackground(colorBackSelectNonFocusedSwt); 668 System.out.println("SwtTableCell - focus lost;"); 669 //int iCellLine = data.ixCellLine; //ixLineNew - ixLine1; 670 //for(int iCellCol = 0; iCellCol < zColumn(); ++iCellCol){ 671 672 //cellSwt.setBackground(colorBackSelectNonFocusedSwt); 673 //} 674 } 675 } 676 677 /**Focus listener implementation for all cells. 678 * This routine is invoked especially if the mouse is landing 679 * on a Text-field with click. Then this table line and column 680 * should be selected as currently. <br> 681 * This routine is invoked on setFocus()-call too. In this case 682 * it should not done anything. The variable #bRedrawPending guards it. 683 * @see org.eclipse.swt.events.FocusListener#focusGained(org.eclipse.swt.events.FocusEvent) 684 */ 685 @Override public void focusGained(FocusEvent ev) { 686 SwtTable.this.focusGainedTable(); 687 setFocused(widgg, true); 688 cellInFocus = (Text)ev.getSource(); 689 //System.out.println("SwtTableCell - focus gained;"); 690 } 691 692 693 694 695 696 protected void initSwtTable(Composite swtTable, int zColumns, SwtMng mng){ 697 int yPix = 0; 698 Font font = mng.propertiesGuiSwt.getTextFontSwt(2, outer.whatIs, outer.whatIs); 699 Color colorBackTableSwt = mng.getColorImpl(colorBackTable()); 700 for(int iCol = 0; iCol < zColumns; ++iCol){ 701 //menuColumns[iCol] = new SwtMenu(name + "_menu" + iCol, this, itsMng()); 702 } 703 //NOTE: only if the swtSelectText is created first, it will drawn in in the foreground of the other cells. 704 swtSearchText = new Text(swtTable, SWT.LEFT | SWT.SINGLE | SWT.READ_ONLY); 705 swtSearchText.setFont(font); 706 swtSearchText.setVisible(false); 707 for(int iRow = 0; iRow < cellsSwt.length; ++iRow){ 708 for(int iCol = 0; iCol < zColumns; ++iCol){ 709 boolean editable = super.bColumnEditable(iCol); 710 Text cell = new Text(swtTable, SWT.LEFT | SWT.SINGLE | (editable ? 0 : SWT.READ_ONLY)); 711 if(editable){ 712 cell.addKeyListener(swtKeyListener); 713 } 714 cell.setFont(font); 715 cell.addKeyListener(myKeyListener); 716 cell.addFocusListener(this); 717 cell.addMouseListener(mousePressedListener); 718 cell.addMouseWheelListener(mouseWheelListener); 719 cell.addTraverseListener(traverseListenerTable); 720 GralTable.CellData cellData = new GralTable.CellData(iRow, iCol); 721 cell.setData(cellData); 722 cells[iRow][iCol] = cellData; 723 int xdPixCol = super.columnPixel[iCol+1] - columnPixel[iCol]; 724 cell.setBounds(columnPixel[iCol], yPix, xdPixCol, linePixel); 725 cell.setBackground(colorBackTableSwt); 726 //cell.setMenu((Menu)menuColumns[iCol].getMenuImpl()); 727 cellsSwt[iRow][iCol] = cell; 728 } 729 yPix += linePixel; 730 } 731 //The text field for selection string 732 733 734 735 } 736 737 738 739 740 /**The widget for the vertical scroll bar is a canvas with a special paint routine. 741 * In the paint routine {@link SwtTable#paintVscrollbar(PaintEvent, Canvas)} is called. 742 */ 743 @SuppressWarnings("synthetic-access") 744 private class Vscrollbar extends Canvas 745 { 746 Vscrollbar(Composite parent) { 747 super(parent, 0); 748 addPaintListener(vScrollbarPainter); 749 750 } 751 752 @Override 753 public void drawBackground(GC g, int x, int y, int dx, int dy) { 754 System.out.println("VScrollbar - draw"); 755 //SwtTable.this.paintVscrollbar(g, Vscrollbar.this); 756 } 757 758 private PaintListener vScrollbarPainter = new PaintListener(){ 759 @Override public void paintControl(PaintEvent e) { 760 //System.out.println("VScrollbar - paintlistener"); 761 SwtTable.this.paintVscrollbar(e.gc, Vscrollbar.this); 762 } 763 }; 764 765 } 766 767 768 769 /**The SWT-Composite for the cell texts and the scroll bar. */ 770 private class Table extends Composite { 771 772 public Table(Composite parent, int zColumns, SwtMng mng) { 773 super(parent, 0); 774 } 775 776 777 //@Override public void drawBackground (GC gc, int x, int y, int width, int height, int offsetX, int offsetY) { 778 // redrawGthread(); 779 //} 780 781 782 783 784 785 } 786 787 788 789 protected void keyPressed(KeyEvent keyEv){ 790 try{ 791 if((keyEv.keyCode & 0xffff) !=0){ 792 final int keyCode = SwtGralKey.convertFromSwt(keyEv.keyCode, keyEv.stateMask, keyEv.character); 793 processKeys(keyCode); 794 } 795 } catch(Exception exc){ 796 String txt = Assert.exceptionInfo("SwtTable - keyPressed Exception", exc, 0, 20, true).toString(); 797 swtWidgHelper.mng.mng.log.sendMsg(0, txt); 798 //CharSequence stackInfo = Assert.exceptionInfo("Gral - SwtTable;", exc, 1, 5); 799 //System.err.append(stackInfo); 800 //exc.printStackTrace(System.out); 801 } 802 803 } 804 805 806 807 808 /**A Table is completed with a special key listener. On all keys 809 * the {@link GralUserAction} given in the {@link GralWidget#getActionChange()} is called 810 * <ul> 811 * <li> with given command "table-key". 812 * <li>params[0] is the selected line referenced with {@link GralTableLine_ifc} 813 * <li>params[1] is the key code described in {@link KeyCode} 814 * </ul> 815 * If the method returns false, the central key action given in {@link GralMng#getRegisteredUserAction(String)} 816 * for "keyAction" is tried to get and then invoked with cmd = "key" and the key code in params[0]. 817 * This central keyAction may be used for application centralized keys without association to the table itself. 818 */ 819 class TableKeyListerner implements KeyListener 820 { 821 final KeyListener basicListener; 822 823 824 825 public TableKeyListerner(KeyListener basicListener) 826 { 827 this.basicListener = basicListener; 828 } 829 830 @Override 831 public void keyPressed(KeyEvent keyEv) 832 { SwtTable.this.keyPressed(keyEv); 833 } 834 835 @Override 836 public void keyReleased(KeyEvent arg0) 837 { 838 //basicListener.keyReleased(arg0); 839 840 } 841 842 }; 843 844 ControlListener resizeListener = new ControlListener() 845 { @Override public void controlMoved(ControlEvent e) 846 { //do nothing if moved. 847 stop(); 848 } 849 850 /**The Composite for the whole table is resized already. This routine should determine which Text fields are visible and used. 851 * @see org.eclipse.swt.events.ControlListener#controlResized(org.eclipse.swt.events.ControlEvent) 852 */ 853 @Override public void controlResized(ControlEvent e) 854 { 855 stop(); 856 Rectangle boundsTable = ((Control)e.widget).getBounds(); 857 int borderTable = ((Control)e.widget).getBorderWidth(); 858 //the pixTable is given already with the Composite of the whole table. 859 GralRectangle pixTable = new GralRectangle(boundsTable.x, boundsTable.y, boundsTable.width, boundsTable.height); 860 //it calls repaint with delay. 861 //Composite parent = ((Control)e.widget).getParent(); 862 //Rectangle parentBounds = parent.getBounds(); 863 //GralRectangle pixTable = outer.pos().calcWidgetPosAndSize(itsMng().propertiesGui(), parentBounds.width, parentBounds.height, 0, 0); 864 //GralRectangle pixTable = outer.pos().calcWidgetPosAndSize(itsMng().propertiesGui(), boundsTable.width, boundsTable.height, 0, 0); 865 SwtTable.this.resizeTable(pixTable); 866 } 867 868 }; 869 870 871 private final class MousePressedListenerTable implements MouseListener{ 872 873 protected MousePressedListenerTable(){} 874 875 876 @Override 877 public void mouseDoubleClick(MouseEvent ev) 878 { //Note: redirect to environment class to prevent usage of synthetic accessor 879 SwtTable.this.mouseDouble(ev); 880 //System.out.println("SwtTable-mouse-double"); 881 882 } 883 884 @Override 885 public void mouseDown(MouseEvent ev) 886 { //Note: redirect to environment class to prevent usage of synthetic accessor 887 SwtTable.this.mouseDown(ev); 888 } 889 890 @Override 891 public void mouseUp(MouseEvent ev) 892 { //Note: redirect to environment class to prevent usage of synthetic accessor 893 SwtTable.this.mouseUp(ev); 894 } 895 896 } 897 898 899 class MouseWheelListenerTable implements MouseWheelListener{ 900 901 @Override 902 public void mouseScrolled(MouseEvent e) { 903 //System.out.println("SwtTable mouseWheel " + e.count); 904 if(e.count >0){ 905 processKeys(KeyCode.mouseWheelUp); 906 } else { 907 processKeys(KeyCode.mouseWheelDn); 908 } 909 } 910 911 } 912 913 914 /**Debug: this focus listener is not invoked any time. It is associated to a swt.Composite. 915 * 916 */ 917 private class FocusListenerTable implements FocusListener //extends SwtWidgetMng.SwtMngFocusListener 918 { 919 FocusListenerTable(SwtMng mng){ 920 //mng.super(); 921 } 922 923 @Override public void focusLost(FocusEvent e){ 924 System.out.println("SwtTable - debug;table composite focus lost. "); 925 } 926 927 @Override public void focusGained(FocusEvent ev) 928 { System.out.println("SwtTable - debug;table composite focus gained. "); 929 } 930 931 }; 932 933 TraverseListener traverseListenerTable = new TraverseListener() { 934 935 @Override public void keyTraversed(TraverseEvent ev) 936 { 937 Debugutil.stop(); 938 final int keyCode = SwtGralKey.convertFromSwt(ev.keyCode, ev.stateMask, ev.character); 939 if(keyCode == KeyCode.tab) { // || keyCode == KeyCode.ctrl+KeyCode.tab) { 940 //if(e.character == '\t'){ 941 //only the tab key should be handled because up and down are received by the key handler 942 SwtTable.this.keyPressed(ev); 943 } 944 } 945 }; 946 947 948 949 /**An instance of this is associated to any cell of the table. 950 * The focus gained method is used to set the current cell of the table and to invoke redraw 951 * to show the new selection. That focus event is invoked if the mouse button is pressed on that cell. 952 */ 953 private class XXXFocusListenerCell implements FocusListener 954 { 955 956 /**This method does nothing. A lost focus color showing may be forced from redraw of another 957 * table. Think about: maybe any action? 958 * Old: This routine is invoked whenever the focus of any Text field of the table will be lost 959 * the focus. Before that occurs, the field is the selected line, because it has had the focus. 960 * Therefore the {@link GralTable#colorBackSelectNonFocused} is set. 961 * @deprecated unnecessary yet. 962 */ 963 @Deprecated 964 @Override public void focusLost(FocusEvent ev){ 965 //System.out.println("Cell focus lost"); 966 SwtTable.this.focusLostTable(); 967 if(!bRedrawPending){ 968 //System.out.println("SwtTable - cell focus lost;" + (SwtTable.this).outer.toString()); 969 GralTable.CellData data = (GralTable.CellData)ev.widget.getData(); 970 Control widgSwt = (Control)ev.widget; 971 //widgSwt.setBackground(colorBackSelectNonFocusedSwt); 972 System.out.println("SwtTableCell - focus lost;"); 973 int iCellLine = data.ixCellLine; //ixLineNew - ixLine1; 974 for(int iCellCol = 0; iCellCol < zColumn(); ++iCellCol){ 975 Text cellSwt = cellsSwt[iCellLine][iCellCol]; 976 977 //cellSwt.setBackground(colorBackSelectNonFocusedSwt); 978 } 979 } 980 } 981 982 /**This routine is invoked especially if the mouse is landing 983 * on a Text-field with click. Then this table line and column 984 * should be selected as currently. <br> 985 * This routine is invoked on setFocus()-call too. In this case 986 * it should not done anything. The variable #bRedrawPending guards it. 987 * @see org.eclipse.swt.events.FocusListener#focusGained(org.eclipse.swt.events.FocusEvent) 988 */ 989 @Override public void focusGained(FocusEvent ev) { 990 SwtTable.this.focusGainedTable(); 991 //System.out.println("SwtTableCell - focus gained;"); 992 } 993 994 }; 995 996 997 998 /**This class wraps the {@link GralUserAction} for a menu action for the table. 999 */ 1000 static class ActionUserMenuItem implements SelectionListener 1001 { 1002 final GralUserAction action; 1003 1004 public ActionUserMenuItem(GralUserAction action) 1005 { this.action = action; 1006 } 1007 1008 @Override 1009 public void widgetDefaultSelected(SelectionEvent e) { 1010 // TODO Auto-generated method stub 1011 1012 } 1013 1014 @Override 1015 public void widgetSelected(SelectionEvent e) 1016 { Object oWidgSwt = e.getSource(); 1017 final GralWidget widgg; 1018 if(oWidgSwt instanceof Widget){ 1019 Widget widgSwt = (Widget)oWidgSwt; 1020 Object oGralWidg = widgSwt.getData(); 1021 if(oGralWidg instanceof GralWidget){ 1022 widgg = (GralWidget)oGralWidg; 1023 } else { widgg = null; } 1024 } else { widgg = null; } 1025 action.userActionGui(KeyCode.menuEntered, widgg); 1026 } 1027 } 1028 1029 1030 1031 protected SwtKeyListener swtKeyListener = new SwtKeyListener(widgg.gralMng()._impl.gralKeyListener) 1032 { 1033 1034 @Override public final boolean specialKeysOfWidgetType(int key, GralWidget_ifc widgg, Object widgImpl){ 1035 boolean bDone = true; 1036 if(KeyCode.isWritingKey(key)){ 1037 //bTextChanged = true; 1038 } 1039 if(key == KeyCode.enter) { // && KeyCode.isWritingOrTextNavigationKey(key)){ 1040 bDone = true; 1041 assert(widgImpl instanceof Text); 1042 Text widgSwt = (Text)widgImpl; 1043 setTextToLine(widgSwt); 1044 } else { 1045 /* 1046 boolean bUserOk; 1047 if(user !=null){ 1048 Point selection = textFieldSwt.getSelection(); 1049 bUserOk = user.userKey(key 1050 , textFieldSwt.getText() 1051 , textFieldSwt.getCaretPosition() 1052 , selection.x, selection.y); 1053 } else bUserOk = false; 1054 if(!bUserOk ){ 1055 switch(key){ 1056 case KeyCode.ctrl + 'a': { 1057 textFieldSwt.selectAll(); 1058 } break; 1059 default: bDone = false; 1060 } 1061 } 1062 */ 1063 } 1064 return bDone; 1065 } 1066 }; 1067 1068 1069 1070 void stop(){} 1071 1072 1073 1074 1075}