    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}