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}