001package org.vishia.gral.swt;
002
003import java.util.Map;
004import java.util.TreeMap;
005
006import org.eclipse.swt.SWT;
007import org.eclipse.swt.events.ControlEvent;
008import org.eclipse.swt.events.ControlListener;
009import org.eclipse.swt.events.DisposeEvent;
010import org.eclipse.swt.events.DisposeListener;
011import org.eclipse.swt.events.MouseEvent;
012import org.eclipse.swt.events.MouseListener;
013import org.eclipse.swt.events.SelectionEvent;
014import org.eclipse.swt.events.SelectionListener;
015import org.eclipse.swt.events.ShellEvent;
016import org.eclipse.swt.events.ShellListener;
017import org.eclipse.swt.graphics.Point;
018import org.eclipse.swt.graphics.Rectangle;
019import org.eclipse.swt.widgets.Composite;
020import org.eclipse.swt.widgets.Display;
021import org.eclipse.swt.widgets.Label;
022import org.eclipse.swt.widgets.Menu;
023import org.eclipse.swt.widgets.MenuItem;
024import org.eclipse.swt.widgets.Shell;
025import org.eclipse.swt.widgets.Widget;
026import org.vishia.gral.base.GralPanelContent;
027import org.vishia.gral.base.GralWidgImpl_ifc;
028import org.vishia.gral.base.GralWidget;
029import org.vishia.gral.base.GralMng;
030import org.vishia.gral.base.GralWindow;
031import org.vishia.gral.base.GralWindow_setifc;
032import org.vishia.gral.ifc.GralColor;
033import org.vishia.gral.ifc.GralRectangle;
034import org.vishia.gral.ifc.GralUserAction;
035import org.vishia.gral.ifc.GralWindow_ifc;
036import org.vishia.util.KeyCode;
037
038//public class SubWindowSwt extends GralPanelContent implements WidgetCmpnifc
039//public class SwtSubWindow extends GralWindow implements SwtSetValue_ifc
040public class SwtSubWindow extends GralWindow.GraphicImplAccess implements GralWidgImpl_ifc
041{
042
043  
044  /**Version, history and license:
045   * <ul>
046   * <li>2016-08-31 Hartmut chg: Now disposes the window in {@link #shellListener} 
047   * <li>2015-05-31 Hartmut {@link #setFocusGThread()} now regards the {@link GralPanelContent#setPrimaryWidget(GralWidget)}.
048   * <li>2015-04-27 Hartmut new {@link #windRemoveOnClose}
049   * <li>2012-07-13 Hartmut new:  {@link #getPixelSize()}, chg: {@link #getPixelPositionSize()} in all implementations. 
050   *   A swt.widget.Shell now returns the absolute position and the real size of its client area without menu and title bar.
051   * <li>2012-06-29 Hartmut new: {@link #setResizeAction(GralUserAction)} now for both ctors, resize on subwindow works.
052   * <li>2012-03-10 Hartmut new: calls invisibleSetAction.userActionGui if the window is set invisible by pressing the X closing icon.
053   * <li>2012-02-11 Hartmut chg: The menu of the window is managed now in {@link SwtMenu}. Instance refered with {@link #menuBar}
054   * <li>2011-11-27 Hartmut chg: {@link #addMenuBarArea9ItemGThread(String, String, GralUserAction)} moved from
055   *   {@link SwtPrimaryWindow} to this, because the capability to have a menu bar may needed on a sub-window too.
056   * <li>2011-11-18 Hartmut chg: {@link SwtSubWindow#SwtSubWindow(String, Display, String, int, GralMng)}
057   *   now gets an int-property instead boolean 'exclusive'. A window has more as one property. Constants
058   *   are defined in {@link GralWindow#windExclusive} etc.
059   * <li>2011-11-10 Hartmut chg:  move all files from mainGuiSwt to gral.swt, dissolve of package mainGuiSwt
060   * <li>2011-11-09 Hartmut chg: renamed from SubWindowSwt to SwtSubWindow
061   * <li>2011-11-01 Hartmut new: {@link #shellListener} and {@link #disposeListener} added, but empty yet.
062   * <li>2011-10-31 Hartmut new: {@link #mouseListener} and {@link #setMouseAction(GralUserAction)}.
063   * <li>2011-10-30 Hartmut new: {@link #resizeListener}, {@link #setResizeAction(GralUserAction)} etc:
064   *   Not this class is base of {@link SwtPrimaryWindow} and contains this capabilities yet.
065   * <li>2011-10-30 Hartmut new: {@link #getPixelPositionSize()} and {@link #setBoundsPixel(int, int, int, int)}
066   *   to support pixel-orientation too. Note it isn't a concept of GRAL anyway, but it is needed.
067   * <li>2011-10-20 Hartmut chg: {@link GralMng} as parameter of constructor: The {@link GralWidget}
068   *   refers it, it should be initialized.
069   * <li>2011-10-15 Hartmut new: {@link #removeWidgetImplementation()}.
070   * <li>2011-09-23 Hartmut bugfix: setFocus() called in {@link #setWindowVisible(boolean)}, it hasn't
071   *   the focus automatically.
072   * <li>2011-09-18 Hartmut chg: Now it is a SubWindowSwt and inherits from the new {@link GralWindow}.
073   *   Some methods {@link #setBackColor(GralColor, int)}, {@link #setWindowVisible(boolean)} etc added
074   *   to comply the interface and super class definitions.
075   * <li>2011-09-03 Hartmut creation as wrapper arround a SWT.Shell inherits {@link org.vishia.gral.base.GralPanelContent}.
076   * </ul>
077   * <br><br> 
078   * <b>Copyright/Copyleft</b>:
079   * For this source the LGPL Lesser General Public License,
080   * published by the Free Software Foundation is valid.
081   * It means:
082   * <ol>
083   * <li> You can use this source without any restriction for any desired purpose.
084   * <li> You can redistribute copies of this source to everybody.
085   * <li> Every user of this source, also the user of redistribute copies
086   *    with or without payment, must accept this license for further using.
087   * <li> But the LPGL is not appropriate for a whole software product,
088   *    if this source is only a part of them. It means, the user
089   *    must publish this part of source,
090   *    but doesn't need to publish the whole source of the own product.
091   * <li> You can study and modify (improve) this source
092   *    for own using or for redistribution, but you have to license the
093   *    modified sources likewise under this LGPL Lesser General Public License.
094   *    You mustn't delete this Copyright/Copyleft inscription in this source file.
095   * </ol>
096   * If you intent to use this source without publishing its usage, you can get
097   * a second license subscribing a special contract with the author. 
098   * 
099   * @author Hartmut Schorrig = hartmut.schorrig@vishia.de
100   * 
101   */
102  @SuppressWarnings("hiding")
103  public static final String sVersion = "2016-08-31";
104  
105  /**It contains the association to the swt widget (Control) and the {@link SwtMng}
106   * and implements some methods of {@link GralWidgImpl_ifc} which are delegate from this.
107   */
108  SwtWidgetHelper swtWidgWrapper;
109
110  protected Shell window;
111  
112  
113  protected SwtMenu menuBar;
114  
115  /**State of the window in swt. */
116  protected boolean bFullScreen;
117  
118  /**Some flags to set an action listener a first time if the action is given. */
119  private boolean bHasResizeAction, bHasMouseAction;
120  
121  /**The resizeListener will be activated if {@link #setResizeAction(GralUserAction)} will be called.
122   * It calls this user action on resize. */
123  private final ControlListener resizeListener = new ControlListener()
124  { @Override public void controlMoved(ControlEvent e) 
125    { //do nothing if moved.
126    }
127
128    @Override public void controlResized(ControlEvent e) 
129    { if(resizeAction() !=null){
130        resizeAction().exec(0, SwtSubWindow.super.gralWindow);
131      }
132    }
133  };
134  
135  
136
137  
138  /**Constructs a window (primary or sub window maybe for dialog etc.).
139   * @param name
140   * @param display
141   * @param title
142   * @param windProps
143   * @param gralMng
144   */
145  SwtSubWindow(SwtMng mng, GralWindow wdgGral)
146  //SwtSubWindow(String name, Display display, String title, int windProps, GralMng gralMng)
147  { //super(name, windProps, gralMng, null);
148    super(wdgGral);  //Invoke constructor of the super class, with knowledge of its outer class.
149    int props = 0; ////|SWT.CLOSE;
150    String sTitle = super.getTitle();
151    int windProps = super.getWindowProps();
152    if(sTitle !=null){ 
153      props |= SWT.TITLE | SWT.BORDER | SWT.CLOSE | SWT.MIN | SWT.MAX; 
154    } else {
155      if((windProps & GralWindow.windHasMenu) !=0) throw new IllegalArgumentException("Window without title but with menu is not supported");
156    }
157    //if(exclusive){ props |= SWT.PRIMARY_MODAL | SWT.SYSTEM_MODAL | SWT.APPLICATION_MODAL; }
158    if((windProps & GralWindow.windExclusive) !=0){ 
159      assert((windProps & GralWindow.windConcurrently) ==0);
160      props |= SWT.APPLICATION_MODAL; 
161    } else {
162      assert((windProps & GralWindow.windExclusive) ==0);
163    }
164    if((windProps & GralWindow.windOnTop) !=0){ props |= SWT.ON_TOP; }
165    if((windProps & GralWindow.windResizeable) !=0){ props |= SWT.RESIZE; }
166    //
167    //create the window:
168    window = new Shell(mng.displaySwt, props);
169    window.setData(wdgGral);
170    super.wdgimpl = this.swtWidgWrapper = new SwtWidgetHelper(window, mng);
171    GralRectangle rect = mng.calcPositionOfWindow(wdgGral.pos());
172    window.setBounds(rect.x, rect.y, rect.dx, rect.dy );
173    if(rect.dx == -1)  { //TODO
174      window.setMaximized(true);
175    }    
176    window.addShellListener(shellListener);
177    if((windProps & GralWindow.windIsMain)!=0) {
178      window.addDisposeListener(disposeListenerMainWindow);
179    } else {
180      window.addDisposeListener(disposeListener);
181    }
182    window.addFocusListener(mng.focusListener);
183    //window.add
184    if((windProps & GralWindow.windHasMenu) !=0){
185      Menu menuBarSwt = new Menu(window, SWT.BAR);
186      window.setMenuBar(menuBarSwt);
187    }
188    //super.panelComposite = window;
189    if(sTitle !=null){ window.setText(sTitle); }
190    if(!bHasResizeAction && resizeAction() != null){
191      window.addControlListener(resizeListener);  //This listener calls the resizeAction
192    }
193    /* test
194    Label testLabel = new Label(window, 0);
195    testLabel.setText("T");
196    testLabel.setBounds(0,0,10,10);
197    Rectangle bounds = testLabel.getBounds();
198    Point size = window.getSize();
199    Rectangle windowPos = window.getBounds();
200    Rectangle clientAread = window.getClientArea();
201    */
202  }
203  
204  /*
205  SwtSubWindow(String name, int windProps, Shell shell, GralMng gralMng)
206  { super(name, windProps, gralMng, shell);
207    this.window = shell;
208    setResizeAction(actionResizeOnePanel);
209    
210  }
211  */
212  
213  
214  @Override public Object getWidgetImplementation(){ return window; }
215  
216  
217  
218  
219  
220  
221  @Override
222  public void removeWidgetImplementation()
223  {
224    window.dispose();
225    window = null;
226  }
227
228  
229  @Override public GralRectangle getPixelPositionSize(){
230    return swtWidgWrapper.getPixelPositionSize();
231  }
232
233  @Override public GralRectangle getPixelSize(){
234    Point size = window.getSize();
235    return new GralRectangle(0,0,size.x, size.y);
236  }
237
238
239  /**Returns the size of the working area without border, menu and title of the window.
240   * Uses {@link org.eclipse.swt.widgets.Scrollable#getClientArea()}  to get the size.
241   */
242
243  @Override public void setBoundsPixel(int x, int y, int dx, int dy)
244  { window.setBounds(x,y,dx,dy);
245  }
246  
247  
248  
249  
250  @SuppressWarnings("synthetic-access") 
251  protected ShellListener shellListener = new ShellListener(){
252
253    @Override
254    public void shellActivated(ShellEvent e)
255    {
256      stop();
257      
258    }
259
260    /**Sets the Window invisible instead dispose it. Note that all sub windows should be build 
261     * as static instances. They should be set visible and invisible instead remove and build new.
262     * @see org.eclipse.swt.events.ShellListener#shellClosed(org.eclipse.swt.events.ShellEvent)
263     */
264    @Override public void shellClosed(ShellEvent e) ////
265    { int windProps = getWindowProps();
266      if(actionOnCloseWindow() !=null){
267        actionOnCloseWindow().exec(KeyCode.menuEntered, SwtSubWindow.this.gralWindow);
268      }
269      setVisibleState(false);
270      if((windProps & GralWindow_ifc.windRemoveOnClose)!=0) {
271        window.dispose();
272        window = null;
273        menuBar = null;
274        SwtSubWindow.this.widgg._wdgImpl = null;  //therewith garbage this class.
275
276        gralWindow.remove();  //remove the window as widget.
277        e.doit = true;
278      } else {
279        e.doit = false;
280        ((Shell)e.widget).setVisible(false);
281      }
282    }
283
284    @Override
285    public void shellDeactivated(ShellEvent e)
286    {
287      if((SwtSubWindow.this.getWindowProps() & GralWindow_ifc.windRemoveOnClose) !=0) {
288      }
289    }
290
291    @Override
292    public void shellDeiconified(ShellEvent e)
293    {
294      setVisibleState(true);
295    }
296
297    @Override
298    public void shellIconified(ShellEvent e)
299    {
300      setVisibleState(false);
301    }
302    
303  };
304  
305  
306  
307  private final DisposeListener disposeListener = new DisposeListener(){
308    
309    
310    @Override
311    public void widgetDisposed(DisposeEvent e)
312    {
313    }
314  };
315  
316  
317  private final DisposeListener disposeListenerMainWindow = new DisposeListener(){
318    @Override
319    public void widgetDisposed(DisposeEvent e)
320    {
321      GralMng.closeGral();
322    }
323  };
324  
325  
326  /**The mouseListener will be activated if {@link #setMouseAction(GralUserAction)} will be called.
327   * It calls this user action on resize. */
328  MouseListener mouseListener = new MouseListener()
329  {
330    int captureAreaDivider;
331    
332    @Override public void mouseDoubleClick(MouseEvent e) 
333    { GralRectangle pos = new GralRectangle(e.x, e.y, 0,0);
334      int key = KeyCode.mouse1Double;  //TODO select key, alt, ctrl etc.
335      SwtSubWindow.this.mouseAction().exec(key, SwtSubWindow.this.gralWindow, pos);
336    }
337
338    @Override public void mouseDown(MouseEvent e) 
339    { GralRectangle pos = new GralRectangle(e.x, e.y, 0,0);
340      int key = KeyCode.mouse1Down;  //TODO select key, alt, ctrl etc.
341      SwtSubWindow.this.mouseAction().exec(key, SwtSubWindow.this.gralWindow, pos);
342    }
343
344    @Override public void mouseUp(MouseEvent e) 
345    { GralRectangle pos = new GralRectangle(e.x, e.y, 0,0);
346      int key = KeyCode.mouse1Up;  //TODO select key, alt, ctrl etc.
347      SwtSubWindow.this.mouseAction().exec(key, SwtSubWindow.this.gralWindow, pos);
348    }
349    
350  };
351  
352  
353  class ActionUserMenuItem implements SelectionListener
354  { 
355    final GralUserAction action;
356    
357    public ActionUserMenuItem(GralUserAction action)
358    { this.action = action;
359    }
360
361    @Override
362    public void widgetDefaultSelected(SelectionEvent e) {
363      // TODO Auto-generated method stub
364      
365    }
366  
367    @Override
368    public void widgetSelected(SelectionEvent e)
369    { Object oWidgSwt = e.getSource();
370      final GralWidget widgg;
371      if(oWidgSwt instanceof Widget){
372        Widget widgSwt = (Widget)oWidgSwt;
373        Object oGralWidg = widgSwt.getData();
374        if(oGralWidg instanceof GralWidget){
375          widgg = (GralWidget)oGralWidg;
376        } else { widgg = null; }
377      } else { widgg = null; }
378      action.userActionGui(KeyCode.menuEntered, widgg);
379    }
380  }
381  
382  
383
384
385  
386  void stop(){}
387
388  @Override
389  public boolean setFocusGThread()
390  { 
391    setVisibleState(true);  //has focus, 
392    window.setVisible(true);
393    //if(gralPanel().setFocusGThread()){   //sets the focus of the primary widget.
394      //return true;  //if any element of the panel was set to focus, the window has the focus already.
395      //Especially the primaryWidget should be focused.
396    //} else {
397      //no primary window etc.
398      return window.setFocus();  
399    //}
400  }
401
402
403  @Override public void setVisibleGThread(boolean bVisible) { super.setVisibleState(bVisible); window.setVisible(bVisible); }
404
405
406
407  @Override public void repaintGthread() {
408    int chg = getChanged();
409    int acknChg = 0;
410    if(!bHasResizeAction && resizeAction() != null){
411      window.addControlListener(resizeListener);
412    }
413    if(!bHasMouseAction && mouseAction() != null){
414      window.addControlListener(resizeListener);
415    }
416    if(super.shouldClose()){
417      window.close();
418    } 
419    if((chg & chgText)!=0){
420      acknChg |= chgText;   //sets the title of the window
421      window.setText(dyda().displayedText);;
422    }
423    if((chg & chgVisible)!=0){
424      acknChg |= chgVisible;
425      setFocusGThread();
426    }
427    if((chg & chgInvisible)!=0){
428      acknChg |= chgInvisible;
429      window.setVisible(false);
430    }
431    if(bFullScreen != super.isFullScreen()){
432      window.setFullScreen(bFullScreen = super.isFullScreen());
433    }
434    acknChanged(acknChg);
435    window.update();
436    window.redraw();
437    //swtWindow_setifc.repaintGthread(); 
438  }
439  
440
441}