1 /*
   2  * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package test.com.sun.javafx.pgstub;
  27 
  28 import java.security.AccessControlContext;
  29 import java.util.LinkedList;
  30 import java.util.List;
  31 import java.util.Queue;
  32 
  33 import com.sun.javafx.tk.FocusCause;
  34 import com.sun.javafx.tk.TKScene;
  35 import com.sun.javafx.tk.TKStage;
  36 import com.sun.javafx.tk.TKStageListener;
  37 
  38 /**
  39  * @author Richard Bair
  40  */
  41 public class StubStage implements TKStage {
  42 
  43     private NotificationSender notificationSender = new NotificationSender();
  44 
  45     @Override
  46     public void setTKStageListener(TKStageListener listener) {
  47         notificationSender.setListener(listener);
  48     }
  49 
  50     @Override
  51     public TKScene createTKScene(boolean depthBuffer, boolean msaa, AccessControlContext acc) {
  52         return new StubScene();
  53     }
  54 
  55     @Override
  56     public void setScene(TKScene scene) {
  57         if (scene != null) {
  58             StubScene s = (StubScene) scene;
  59             s.stage = this;
  60             notificationSender.setScene(s);
  61             if (visible && width != -1 && height != -1)
  62                 s.getListener().changedSize(width, height);
  63         }
  64     }
  65 
  66     public int numTimesSetSizeAndLocation;
  67 
  68     // Platform place/resize the window with some
  69     // "default" value. Pretending that the values
  70     // below are those platform defaults.
  71     public float x = 16;
  72     public float y = 12;
  73     public float width = 256;
  74     public float height = 192;
  75     public float renderScaleX = 1.0f;
  76     public float renderScaleY = 1.0f;
  77 
  78     public boolean visible;
  79     public float opacity;
  80 
  81     @Override
  82     public void setBounds(float x, float y, boolean xSet, boolean ySet,
  83                           float width, float height,
  84                           float contentWidth, float contentHeight,
  85                           float xGravity, float yGravity,
  86                           float renderScaleX, float renderScaleY)
  87     {
  88         numTimesSetSizeAndLocation++;
  89 
  90         boolean locationChanged = false;
  91 
  92         if (xSet && (this.x != x)) {
  93             this.x = x;
  94             locationChanged = true;
  95         }
  96 
  97         if (ySet && (this.y != y)) {
  98             this.y = y;
  99             locationChanged = true;
 100         }
 101 
 102         if (locationChanged) {
 103             notificationSender.changedLocation(x, y);
 104         }
 105 
 106         boolean sizeChanged = false;
 107 
 108         if (width > 0) {
 109             if (this.width != width) {
 110                 this.width = width;
 111                 sizeChanged = true;
 112             }
 113         } else if (contentWidth > 0) {
 114             if (this.width != contentWidth) {
 115                 this.width = contentWidth;
 116                 sizeChanged = true;
 117             }
 118         }
 119 
 120         if (height > 0) {
 121             if (this.height != height) {
 122                 this.height = height;
 123                 sizeChanged = true;
 124             }
 125         } else if (contentHeight > 0) {
 126             if (this.height != contentHeight) {
 127                 this.height = contentHeight;
 128                 sizeChanged = true;
 129             }
 130         }
 131 
 132         if (sizeChanged) {
 133             notificationSender.changedSize(width, height);
 134         }
 135         if (renderScaleX > 0.0) this.renderScaleX = renderScaleX;
 136         if (renderScaleY > 0.0) this.renderScaleY = renderScaleY;
 137     }
 138 
 139     @Override
 140     public float getPlatformScaleX() {
 141         return 1.0f;
 142     }
 143 
 144     @Override
 145     public float getPlatformScaleY() {
 146         return 1.0f;
 147     }
 148 
 149     @Override
 150     public float getOutputScaleX() {
 151         return 1.0f;
 152     }
 153 
 154     @Override
 155     public float getOutputScaleY() {
 156         return 1.0f;
 157     }
 158 
 159     // Just a helper method
 160     public void setSize(float w, float h) {
 161         setBounds(0, 0, false, false, w, h, 0, 0, 0, 0, 0, 0);
 162     }
 163 
 164     // Just a helper method
 165     public void setLocation(float x, float y) {
 166         setBounds(x, y, true, true, 0, 0, 0, 0, 0, 0, 0, 0);
 167     }
 168 
 169     @Override
 170     public void setIcons(List icons) {
 171     }
 172 
 173     @Override
 174     public void setTitle(String title) {
 175     }
 176 
 177     @Override
 178     public void setVisible(boolean visible) {
 179         this.visible = visible;
 180 
 181         if (!visible) {
 182             notificationSender.changedFocused(false, FocusCause.DEACTIVATED);
 183         }
 184 
 185         notificationSender.changedLocation(x, y);
 186         notificationSender.changedSize(width, height);
 187     }
 188 
 189     @Override
 190     public void setOpacity(float opacity) {
 191         this.opacity = opacity;
 192     }
 193 
 194     @Override
 195     public void setIconified(boolean iconified) {
 196         notificationSender.changedIconified(iconified);
 197     }
 198 
 199     @Override
 200     public void setMaximized(boolean maximized) {
 201         notificationSender.changedMaximized(maximized);
 202     }
 203 
 204     @Override
 205     public void setAlwaysOnTop(boolean alwaysOnTop) {
 206         notificationSender.changedAlwaysOnTop(alwaysOnTop);
 207     }
 208 
 209     @Override
 210     public void setResizable(boolean resizable) {
 211         notificationSender.changedResizable(resizable);
 212     }
 213 
 214     @Override
 215     public void setImportant(boolean important) {
 216     }
 217 
 218     @Override
 219     public void setFullScreen(boolean fullScreen) {
 220         notificationSender.changedFullscreen(fullScreen);
 221     }
 222 
 223     @Override
 224     public void requestFocus() {
 225         notificationSender.changedFocused(true, FocusCause.ACTIVATED);
 226     }
 227 
 228     @Override
 229     public void requestFocus(FocusCause cause) {
 230         notificationSender.changedFocused(true, cause);
 231     }
 232 
 233     @Override
 234     public void toBack() {
 235     }
 236 
 237     @Override
 238     public void toFront() {
 239     }
 240 
 241     @Override
 242     public void close() {
 243     }
 244 
 245     private boolean focusGrabbed;
 246 
 247     @Override
 248     public boolean grabFocus() {
 249         focusGrabbed = true;
 250         return true;
 251     }
 252 
 253     @Override
 254     public void ungrabFocus() {
 255         focusGrabbed = false;
 256     }
 257 
 258     public boolean isFocusGrabbed() {
 259         return focusGrabbed;
 260     }
 261 
 262     @Override
 263     public void setMinimumSize(int minWidth, int minHeight) {
 264     }
 265 
 266     @Override
 267     public void setMaximumSize(int maxWidth, int maxHeight) {
 268     }
 269 
 270     public void holdNotifications() {
 271         notificationSender.holdNotifications();
 272     }
 273 
 274     public void releaseNotifications() {
 275         notificationSender.releaseNotifications();
 276     }
 277 
 278     public void releaseSingleNotification() {
 279         notificationSender.releaseSingleNotification();
 280     }
 281 
 282     protected final TKStageListener getNotificationSender() {
 283         return notificationSender;
 284     }
 285 
 286     @Override
 287     public void requestInput(String text, int type, double width, double height,
 288                                 double Mxx, double Mxy, double Mxz, double Mxt,
 289                                 double Myx, double Myy, double Myz, double Myt,
 290                                 double Mzx, double Mzy, double Mzz, double Mzt) {
 291         throw new UnsupportedOperationException("Not supported yet.");
 292     }
 293 
 294     @Override
 295     public void releaseInput() {
 296         throw new UnsupportedOperationException("Not supported yet.");
 297     }
 298 
 299     private interface Notification {
 300         void execute(TKStageListener listener);
 301     }
 302 
 303     private static final class NotificationSender implements TKStageListener {
 304         private final Queue<Notification> queue =
 305                 new LinkedList<Notification>();
 306 
 307         private boolean hold;
 308         private TKStageListener listener;
 309         private StubScene scene;
 310 
 311         public void setListener(final TKStageListener listener) {
 312             this.listener = listener;
 313         }
 314 
 315         public void setScene(final StubScene scene) {
 316             this.scene = scene;
 317         }
 318 
 319         public void holdNotifications() {
 320             hold = true;
 321         }
 322 
 323         public void releaseNotifications() {
 324             hold = false;
 325             flush();
 326         }
 327 
 328         private void releaseSingleNotification() {
 329             queue.poll().execute(listener);
 330         }
 331 
 332         @Override
 333         public void changedLocation(final float x, final float y) {
 334             process(listener1 -> listener1.changedLocation(x, y));
 335         }
 336 
 337         @Override
 338         public void changedSize(final float width, final float height) {
 339             process(listener1 -> {
 340                 listener1.changedSize(width, height);
 341                 if (scene != null && width != -1 && height != -1) {
 342                     scene.getListener().changedSize(width, height);
 343                 }
 344             });
 345         }
 346 
 347         @Override
 348         public void changedScale(float xScale, float yScale) {
 349             process(listener1 -> listener1.changedScale(xScale, yScale));
 350         }
 351 
 352         @Override
 353         public void changedFocused(final boolean focused,
 354                                    final FocusCause cause) {
 355             process(listener1 -> listener1.changedFocused(focused, cause));
 356         }
 357 
 358         @Override
 359         public void changedIconified(final boolean iconified) {
 360             process(listener1 -> listener1.changedIconified(iconified));
 361         }
 362 
 363         @Override
 364         public void changedMaximized(final boolean maximized) {
 365             process(listener1 -> listener1.changedMaximized(maximized));
 366         }
 367 
 368         @Override
 369         public void changedAlwaysOnTop(boolean alwaysOnTop) {
 370             process(listener1 -> listener1.changedAlwaysOnTop(alwaysOnTop));
 371         }
 372 
 373 
 374         @Override
 375         public void changedResizable(final boolean resizable) {
 376             process(listener1 -> listener1.changedResizable(resizable));
 377         }
 378 
 379         @Override
 380         public void changedFullscreen(final boolean fs) {
 381             process(listener1 -> listener1.changedFullscreen(fs));
 382         }
 383 
 384         @Override
 385         public void closing() {
 386             process(listener1 -> listener1.closing());
 387         }
 388 
 389         @Override
 390         public void closed() {
 391             process(listener1 -> listener1.closed());
 392         }
 393 
 394         @Override
 395         public void focusUngrab() {
 396             process(listener1 -> listener1.focusUngrab());
 397         }
 398 
 399         private void process(final Notification notification) {
 400             if (hold) {
 401                 queue.offer(notification);
 402                 return;
 403             }
 404 
 405             if (listener != null) {
 406                 notification.execute(listener);
 407             }
 408         }
 409 
 410         private void flush() {
 411             if (listener == null) {
 412                 queue.clear();
 413                 return;
 414             }
 415 
 416             Notification nextNotification = queue.poll();
 417             while (nextNotification != null) {
 418                 nextNotification.execute(listener);
 419                 nextNotification = queue.poll();
 420             }
 421         }
 422 
 423         /**
 424         * Initialize accessibility
 425         */
 426         public void initAccessibleTKStageListener() {
 427             // TODO: Add code later
 428         }
 429 
 430         @Override
 431         public void changedScreen(Object from, Object to) {
 432             // TODO: Add code later
 433         }
 434 
 435     }
 436 
 437     @Override
 438     public void setRTL(boolean b) {
 439     }
 440 }