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}