001package org.vishia.gral.swt;
002
003import org.eclipse.swt.SWT;
004import org.eclipse.swt.events.KeyListener;
005import org.eclipse.swt.events.KeyEvent;
006import org.eclipse.swt.events.ShellListener;
007import org.eclipse.swt.events.ShellEvent;
008import org.eclipse.swt.events.TraverseEvent;
009import org.eclipse.swt.events.TraverseListener;
010import org.eclipse.swt.widgets.Display;
011import org.eclipse.swt.widgets.Event;
012import org.eclipse.swt.widgets.Listener;
013import org.eclipse.swt.widgets.Menu;
014import org.eclipse.swt.widgets.Shell;
015import org.vishia.gral.base.GralGraphicThread;
016import org.vishia.gral.base.GralGraphicThread.ImplAccess;
017import org.vishia.gral.base.GralMng;
018import org.vishia.gral.base.GralPos;
019import org.vishia.gral.base.GralWindow;
020import org.vishia.gral.ifc.GralWindow_ifc;
021import org.vishia.msgDispatch.LogMessage;
022
023/**This class is the implementation class of a simple graphic implementation for SWT.
024 * It doesn't depend of complex functionality of the org.vishia.gral. But that implementations based on this.
025 * This class can be used for a simple SWT graphic implementation.
026 */
027class SwtGraphicThread extends GralGraphicThread.ImplAccess //implements Runnable
028{
029  /**Version, history and license.
030   * <ul>
031   * <li>2016-07-16 Hartmut chg: The main window will be created with same methods like all other windows. 
032   * <li>2015-01-17 Hartmut chg: Now {@link GralGraphicThread} is an own instance able to create before the graphic is established.
033   *   This graphical implementation extends the {@link ImplAccess}. 
034   * <li<2012-07-14 Hartmut chg: {@link #traverseKeyFilter} now excludes [ctrl-tab]. Only [tab] is a traversal key.
035   * <li>2012-04-16 Hartmut chg: {@link #initGraphic()} now creates the main window, creates the
036   *   {@link SwtMng} instead it is doing in the non-graphic thread. 
037   * <li>2012-04-10 Hartmut chg: Now the traversal keys ctrl-Pgdn/up are disabled.
038   * <li>2011-11-12 Hartmut chg: Now the primary window has a menu bar anyway. 
039   * </ul>
040   * <b>Copyright/Copyleft</b>:
041   * For this source the LGPL Lesser General Public License,
042   * published by the Free Software Foundation is valid.
043   * It means:
044   * <ol>
045   * <li> You can use this source without any restriction for any desired purpose.
046   * <li> You can redistribute copies of this source to everybody.
047   * <li> Every user of this source, also the user of redistribute copies
048   *    with or without payment, must accept this license for further using.
049   * <li> But the LPGL is not appropriate for a whole software product,
050   *    if this source is only a part of them. It means, the user
051   *    must publish this part of source,
052   *    but don't need to publish the whole source of the own product.
053   * <li> You can study and modify (improve) this source
054   *    for own using or for redistribution, but you have to license the
055   *    modified sources likewise under this LGPL Lesser General Public License.
056   *    You mustn't delete this Copyright/Copyleft inscription in this source file.
057   * </ol>
058   * If you are intent to use this sources without publishing its usage, you can get
059   * a second license subscribing a special contract with the author. 
060   * 
061   * @author Hartmut Schorrig = hartmut.schorrig@vishia.de
062   * 
063   */
064  //@SuppressWarnings("hiding")
065  public final static String version = "2015-01-17";
066
067  /**The graphical device for the application for all windows of this application. */
068  Display displaySwt;
069  
070  /**The main window. SWT: named as Shell. */
071  Shell windowSwt;
072  
073  //SwtPrimaryWindow instance;
074  
075  SwtMng gralMng;
076  
077  /**The windows-closing event handler. It is used private only, but public set because documentation. 
078   * The close event will be fired also when a SubWindow is closed. Therefore test the Shell instance.
079   * Only if the main window is closed, bExit should be set to true.
080   * */
081  public final class WindowsCloseListener implements Listener{
082    /**Invoked when the window is closed; it sets {@link #bExit}, able to get with {@link #isRunning()}.
083     * @see org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets.Event)
084     */
085    @Override public void handleEvent(Event event) {
086      setClosed( event.widget == windowSwt); //close if the main window was closed.
087    }
088  }
089
090  /**Instance of windowsCloseHandler. */
091  private final WindowsCloseListener windowsCloseListener = new WindowsCloseListener(); 
092  
093  
094  
095  KeyListener keyListener = new KeyListener()
096  {
097    @Override public void keyPressed(KeyEvent key)
098    {
099      // TODO Auto-generated method stub
100      stop();
101    }
102
103    @Override public void keyReleased(KeyEvent e)
104    {
105      // TODO Auto-generated method stub
106      
107    }
108    
109  };
110  
111  
112  
113  /**Disables the ctrl-pgUp and ctrl-Pgdn as traversal key listener. It should be able to use
114   * by the application. Only Tab and sh-Tab are usual. */
115  TraverseListener XXXkeyTraverse = new TraverseListener(){
116    @Override public void keyTraversed(TraverseEvent e) {
117      stop();
118      if(  e.detail == SWT.TRAVERSE_PAGE_NEXT //|| e.keyCode == SWT.PAGE_DOWN){
119        || e.detail == SWT.TRAVERSE_PAGE_PREVIOUS
120         ) {
121        e.doit = true;
122  } } };
123  
124  
125  /**This interface routine is invoked on any key which is used as 'traverse' key to switch
126   * between widgets, panels etc. SWT uses the ctrl-pgup and ctrl-pgdn to switch between the
127   * tab cards on a TabbedPanel. This is not a standard behavior for all graphic systems.
128   * That keys should be able to use in the application. Therefore they are disabled as traversal keys.
129   * To switch between the tabs - it may be application specific to do it with keys - or the mouse
130   * can be used. 
131   * 
132   */
133  Listener traverseKeyFilter = new Listener(){
134    @Override public void handleEvent(Event event) {
135      int traverseIdent = event.detail; 
136      int key = event.keyCode;
137      int keyModifier = event.stateMask;
138      if(  traverseIdent == SWT.TRAVERSE_PAGE_NEXT         //the pg-dn key in SWT
139        || traverseIdent == SWT.TRAVERSE_PAGE_PREVIOUS   //the pg-up key in SWT
140        || key == '\t' && keyModifier == SWT.CTRL
141        ) {
142        event.doit = false;
143      }
144      stop();
145    }
146    
147  };
148  
149  
150  ShellListener mainComponentListerner = new ShellListener()
151  {
152
153        
154    @Override
155    public void shellActivated(ShellEvent e) {
156      // TODO Auto-generated method stub
157      
158    }
159
160    @Override
161    public void shellClosed(ShellEvent e) {
162      // TODO Auto-generated method stub
163      
164    }
165
166    @Override
167    public void shellDeactivated(ShellEvent e) {
168      // TODO Auto-generated method stub
169      
170    }
171
172    @Override
173    public void shellDeiconified(ShellEvent e) {
174      // TODO Auto-generated method stub
175      
176    }
177
178    @Override
179    public void shellIconified(ShellEvent e) {
180      // TODO Auto-generated method stub
181      
182    }
183    
184  };
185  
186  
187  
188  
189  //final String sTitle; 
190  //final int xPos, yPos, xSize, ySize;
191  
192  SwtGraphicThread(GralWindow windowGral, char sizeShow, LogMessage log)
193  { super(sizeShow, windowGral, log);
194    startThread();
195    //this.sTitle = sTitle; 
196    //this.xPos = left; this.yPos = top; this.xSize = xSize; this.ySize = ySize; 
197  }
198  
199  
200  
201  
202  
203  
204  /**
205   * @see org.vishia.gral.base.GralGraphicThread#initGraphic()
206   */
207  @Override protected void initGraphic(){
208    displaySwt = new Display();  //The organization class of the whole graphic independent of a concrete window.
209    displaySwt.addFilter(SWT.Close, windowsCloseListener);
210    displaySwt.addFilter(SWT.Traverse, traverseKeyFilter);
211    SwtProperties propertiesGui = new SwtProperties(this.displaySwt, sizeCharProperties);
212    gralMng = new SwtMng(displaySwt, propertiesGui, log);
213    
214  }
215
216  void XXX_Old_createWindow__(){
217  
218    SwtSubWindow windSwt = new SwtSubWindow(gralMng, mainWindow);
219    
220    gralMng.mng.registerPanel(mainWindow);
221    
222    windowSwt = windSwt.window; //, SWT.ON_TOP | SWT.MAX | SWT.TITLE);
223    //windowSwt.addKeyListener(keyListener);
224    //windowSwt.addTraverseListener(keyTraverse);
225    
226    //graphicFramePos = new Position(graphicFrame.getContentPane());
227    //graphicFramePos.set(0,0,xSize,ySize);
228    // main = this;
229    //windowSwt.setText(mainWindow.getText());
230    //
231    //set a menu bar anyway. Otherwise the calculation of used area of the window may be faulty
232    //if it is calculated first, and after them menu items are added.
233    //It isn't able to expected that the user won't have a menu bar in a primary window.
234    Menu menuBar = new Menu(windowSwt, SWT.BAR);
235    windowSwt.setMenuBar(menuBar);
236    //graphicFrame.getContentPane().setLayout(new BorderLayout());
237    //graphicFrame.addWindowListener(new WindowClosingAdapter(true));
238    //graphicFrame.setSize( xSize, ySize );
239    //if(xSize == -1 || ySize == -1){
240      //windowSwt.setMaximized(true);
241    //} else {
242      //windowSwt.setBounds(xPos,yPos, xSize, ySize );  //Start position.
243    //}
244    windowSwt.open();
245
246    //graphicFrame.getContentPane().setLayout(new FlowLayout());
247    windowSwt.setLayout(null);
248    windowSwt.addShellListener(mainComponentListerner);
249
250    
251    //The propertiesGuiSwt needs the Display instance for Font and Color. Therefore the graphic thread with creation of Display should be executed before. 
252    //mainWindow.setPanelMng(gralMng);
253    //int windProps = GralWindow_ifc.windResizeable;
254    //GralWindow windowGral = new GralWindow("main", sTitle, windProps, gralMng, null );
255    
256    //The PrimaryWindowSwt is a derivation of the GralPrimaryWindow. It is more as only a SWT Shell.
257    //instance = new SwtPrimaryWindow(windowGral, gralMng, this, this.displaySwt);
258    ///
259  
260  }
261
262  
263  @Override
264  protected boolean dispatchOsEvents()
265  { return displaySwt.readAndDispatch();
266  }
267
268  @Override
269  protected void graphicThreadSleep()
270  {
271    displaySwt.sleep ();
272  }
273  
274  
275  /**Yet Experience: SWT knows the {@link Display#asyncExec(Runnable)}.
276   * @param exec
277   */
278  protected void addToGraphicImplThread(Runnable exec){
279    displaySwt.asyncExec(exec);
280  }
281  
282  @Override
283  public void wakeup(){
284    if(displaySwt == null){
285      
286    }
287    displaySwt.wake();
288    //extEventSet.set(true);
289    //isWakedUpOnly = true;
290  }
291
292  
293  
294  void stop(){}
295  
296}