PageRenderTime 53ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 0ms

/src/fwt/java/WindowPeer.java

https://bitbucket.org/bedlaczech/fan-1.0
Java | 303 lines | 195 code | 50 blank | 58 comment | 39 complexity | cd98622153b2e36a9ac583c7afcd4849 MD5 | raw file
Possible License(s): CC-BY-SA-3.0
  1. //
  2. // Copyright (c) 2008, Brian Frank and Andy Frank
  3. // Licensed under the Academic Free License version 3.0
  4. //
  5. // History:
  6. // 12 Jun 08 Brian Frank Creation
  7. //
  8. package fan.fwt;
  9. import fan.sys.*;
  10. import org.eclipse.swt.*;
  11. import org.eclipse.swt.events.*;
  12. import org.eclipse.swt.graphics.Image;
  13. import org.eclipse.swt.graphics.Point;
  14. import org.eclipse.swt.graphics.Rectangle;
  15. import org.eclipse.swt.widgets.*;
  16. import org.eclipse.swt.widgets.Widget;
  17. import org.eclipse.swt.layout.*;
  18. import org.eclipse.swt.dnd.*;
  19. public class WindowPeer
  20. extends PanePeer
  21. implements ShellListener
  22. {
  23. //////////////////////////////////////////////////////////////////////////
  24. // Construction
  25. //////////////////////////////////////////////////////////////////////////
  26. public static WindowPeer make(fan.fwt.Window self)
  27. throws Exception
  28. {
  29. WindowPeer peer = new WindowPeer();
  30. ((fan.fwt.Pane)self).peer = peer;
  31. ((fan.fwt.Widget)self).peer = peer;
  32. peer.self = self;
  33. return peer;
  34. }
  35. public final Widget create(Widget parent)
  36. {
  37. // window uses open, not normal attach process
  38. throw new IllegalStateException();
  39. }
  40. //////////////////////////////////////////////////////////////////////////
  41. // Fields
  42. //////////////////////////////////////////////////////////////////////////
  43. // Str title := ""
  44. public String title(Window self) { return title.get(); }
  45. public void title(Window self, String v) { title.set(v); }
  46. public final Prop.StrProp title = new Prop.StrProp(this, "")
  47. {
  48. public String get(Widget w) { return ((Shell)w).getText(); }
  49. public void set(Widget w, String v) { ((Shell)w).setText(v); }
  50. };
  51. // Image icon := null
  52. public fan.gfx.Image icon(Window self) { return icon.get(); }
  53. public void icon(Window self, fan.gfx.Image v) { icon.set(v); }
  54. public final Prop.ImageProp icon = new Prop.ImageProp(this)
  55. {
  56. public void set(Widget w, Image v) { ((Shell)w).setImage(v); }
  57. };
  58. //////////////////////////////////////////////////////////////////////////
  59. // Sizing
  60. //////////////////////////////////////////////////////////////////////////
  61. void onPosChange() { explicitPos = true; }
  62. void onSizeChange() { explicitSize = true; }
  63. void layout()
  64. {
  65. try { ((Window)self).onLayout(); }
  66. catch (Exception e) { e.printStackTrace(); }
  67. }
  68. //////////////////////////////////////////////////////////////////////////
  69. // Eventing
  70. //////////////////////////////////////////////////////////////////////////
  71. public void shellClosed(ShellEvent se)
  72. {
  73. Window self = (Window)this.self;
  74. fan.fwt.Event fe = event(EventId.close);
  75. self.onClose().fire(fe);
  76. if (fe.consumed) se.doit = false;
  77. }
  78. public void shellActivated(ShellEvent se)
  79. {
  80. Window self = (Window)this.self;
  81. self.onActive().fire(event(EventId.active));
  82. }
  83. public void shellDeactivated(ShellEvent se)
  84. {
  85. Window self = (Window)this.self;
  86. self.onInactive().fire(event(EventId.inactive));
  87. }
  88. public void shellDeiconified(ShellEvent se)
  89. {
  90. Window self = (Window)this.self;
  91. self.onDeiconified().fire(event(EventId.deiconified));
  92. }
  93. public void shellIconified(ShellEvent se)
  94. {
  95. Window self = (Window)this.self;
  96. self.onIconified().fire(event(EventId.iconified));
  97. }
  98. //////////////////////////////////////////////////////////////////////////
  99. // Lifecycle
  100. //////////////////////////////////////////////////////////////////////////
  101. int style(Window self)
  102. {
  103. int style = defaultStyle();
  104. if (self.mode == WindowMode.modeless) style |= SWT.MODELESS;
  105. else if (self.mode == WindowMode.windowModal) style |= SWT.PRIMARY_MODAL;
  106. else if (self.mode == WindowMode.appModal) style |= SWT.APPLICATION_MODAL;
  107. else if (self.mode == WindowMode.sysModal) style |= SWT.SYSTEM_MODAL;
  108. if (self.alwaysOnTop) style |= SWT.ON_TOP;
  109. if (self.resizable) style |= SWT.RESIZE;
  110. if (!self.showTrim) style |= SWT.NO_TRIM;
  111. return style;
  112. }
  113. int defaultStyle() { return SWT.CLOSE | SWT.TITLE | SWT.MIN | SWT.MAX; }
  114. public Object open(Window self)
  115. {
  116. // if already open
  117. if (control != null) throw Err.make("Window already open");
  118. // initialize with clean slate
  119. result = null;
  120. // create SWT shell
  121. Fwt fwt = Fwt.get();
  122. Shell shell;
  123. fan.fwt.Widget parent = self.parent();
  124. Shell parentShell = parent == null ? null : (Shell)parent.peer.control;
  125. if (parentShell == null)
  126. {
  127. shell = new Shell(fwt.display, style(self));
  128. }
  129. else
  130. {
  131. shell = new Shell(parentShell, style(self));
  132. }
  133. shell.setLayout(new FillLayout());
  134. shell.addShellListener(this);
  135. attachTo(shell);
  136. // setup drag and drop
  137. initDrop(shell);
  138. // if not explicitly sized, then use prefSize - but
  139. // make sure not bigger than monitor (at this point we
  140. // don't know which monitor so assume primary monitor)
  141. if (!explicitSize)
  142. {
  143. shell.pack();
  144. Rectangle mb = shell.getBounds();
  145. Rectangle pb = fwt.display.getPrimaryMonitor().getClientArea();
  146. int pw = Math.min(mb.width, pb.width-50);
  147. int ph = Math.min(mb.height, pb.height-50);
  148. self.size(size(pw, ph));
  149. }
  150. // if not explicitly positioned, then center on
  151. // parent shell (or primary monitor)
  152. if (!explicitPos)
  153. {
  154. Rectangle pb = parentShell == null ?
  155. fwt.display.getPrimaryMonitor().getClientArea() :
  156. parentShell.getBounds();
  157. Rectangle mb = shell.getBounds();
  158. int cx = pb.x + (pb.width - mb.width)/2;
  159. int cy = pb.y + (pb.height - mb.height)/2;
  160. self.pos(point(cx, cy));
  161. }
  162. // ensure that window isn't off the display; this
  163. // still might cover multiple monitors though, but
  164. // provides a safe sanity check
  165. Rectangle mb = shell.getBounds();
  166. Rectangle db = fwt.display.getClientArea();
  167. if (mb.width > db.width) mb.width = db.width;
  168. if (mb.height > db.height) mb.height = db.height;
  169. if (mb.x + mb.width > db.x + db.width) mb.x = db.x + db.width - mb.width;
  170. if (mb.x < db.x) mb.x = db.x;
  171. if (mb.y + mb.height > db.y + db.height) mb.y = db.y + db.height - mb.height;
  172. if (mb.y < db.y) mb.y = db.y;
  173. self.bounds(rect(mb));
  174. // set default button
  175. if (defButton != null)
  176. shell.setDefaultButton((org.eclipse.swt.widgets.Button)defButton.peer.control);
  177. // open
  178. shell.open();
  179. // TODO FIXIT: we actually want to fire this after the event
  180. // loop is entered, so SWT is "active" - for now we can use
  181. // Desktop.callLater(~10ms) as a workaround
  182. self.onOpen().fire(event(EventId.open));
  183. // block until dialog is closed
  184. fwt.eventLoop(shell);
  185. // cleanup
  186. detach(self);
  187. explicitPos = explicitSize = false;
  188. return result;
  189. }
  190. public void activate(Window self)
  191. {
  192. if (control == null) return;
  193. Shell shell = (Shell)control;
  194. shell.setActive();
  195. }
  196. public void close(Window self, Object result)
  197. {
  198. if (control == null) return;
  199. this.result = result;
  200. Shell shell = (Shell)control;
  201. shell.close();
  202. detach(self);
  203. }
  204. //////////////////////////////////////////////////////////////////////////
  205. // Drag and Drop
  206. //////////////////////////////////////////////////////////////////////////
  207. /**
  208. * The FWT doesn't officially support drag and drop. However as a
  209. * temp solution we provide a back-door hook to drop files onto a
  210. * Window for flux.
  211. */
  212. void initDrop(Shell shell)
  213. {
  214. DropTarget t = new DropTarget(shell, DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_DEFAULT);
  215. t.setTransfer(new Transfer[] { FileTransfer.getInstance() });
  216. t.addDropListener(new DropTargetAdapter()
  217. {
  218. public void dragEnter(DropTargetEvent event)
  219. {
  220. }
  221. public void dragOver(DropTargetEvent event)
  222. {
  223. event.feedback = DND.FEEDBACK_SELECT | DND.FEEDBACK_SCROLL;
  224. }
  225. public void drop(DropTargetEvent event)
  226. {
  227. Window window = (Window)self;
  228. if (window.onDrop == null) return;
  229. FileTransfer ft = FileTransfer.getInstance();
  230. if (!ft.isSupportedType(event.currentDataType)) return;
  231. fan.sys.List data = new fan.sys.List(Sys.FileType, 0);
  232. String[] paths = (String[])ft.nativeToJava(event.currentDataType);
  233. for (int i=0; i<paths.length; ++i)
  234. data.add(File.os(paths[i]));
  235. window.onDrop().call(data);
  236. }
  237. });
  238. }
  239. //////////////////////////////////////////////////////////////////////////
  240. // NoDoc
  241. //////////////////////////////////////////////////////////////////////////
  242. public void setOverlayText(Window self, String text)
  243. {
  244. Fwt.get().display.getSystemTaskBar().getItem(0).setOverlayText(text);
  245. }
  246. //////////////////////////////////////////////////////////////////////////
  247. // Fields
  248. //////////////////////////////////////////////////////////////////////////
  249. boolean explicitPos; // has pos been explicitly configured?
  250. boolean explicitSize; // has size been explicitly configured?
  251. Button defButton;
  252. Object result;
  253. }