Spec-Zone .ru
спецификации, руководства, описания, API
001/*
002 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.  Oracle designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Oracle in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
022 * or visit www.oracle.com if you need additional information or have any
023 * questions.
024 */
025
026package javafx.stage;
027
028import java.util.ArrayList;
029import java.util.List;
030
031import javafx.beans.property.BooleanProperty;
032import javafx.beans.property.BooleanPropertyBase;
033import javafx.beans.property.SimpleBooleanProperty;
034import javafx.beans.property.StringProperty;
035import javafx.beans.property.StringPropertyBase;
036import javafx.collections.FXCollections;
037import javafx.collections.ListChangeListener.Change;
038import javafx.collections.ObservableList;
039import javafx.geometry.NodeOrientation;
040import javafx.scene.Scene;
041import javafx.scene.image.Image;
042
043import com.sun.javafx.beans.annotations.Default;
044import com.sun.javafx.collections.TrackableObservableList;
045import com.sun.javafx.robot.impl.FXRobotHelper;
046import com.sun.javafx.scene.SceneHelper;
047import com.sun.javafx.stage.StageHelper;
048import com.sun.javafx.stage.StagePeerListener;
049import com.sun.javafx.tk.TKPulseListener;
050import com.sun.javafx.tk.TKStage;
051import com.sun.javafx.tk.Toolkit;
052import javafx.beans.property.DoubleProperty;
053import javafx.beans.property.DoublePropertyBase;
054import javafx.beans.property.Property;
055import javafx.beans.property.ReadOnlyBooleanProperty;
056import javafx.beans.property.ReadOnlyBooleanWrapper;
057import javafx.beans.value.ObservableValue;
058
059/**
060 * The JavaFX {@code Stage} class is the top level JavaFX container.
061 * The primary Stage is constructed by the platform. Additional Stage
062 * objects may be constructed by the application.
063 *
064 * <p>
065 * Stage objects must be constructed and modified on the
066 * JavaFX Application Thread.
067 * </p>
068 * <p>
069 * Many of the {@code Stage} properties are read only because they can
070 * be changed externally by the underlying platform and therefore must
071 * not be bindable.
072 * </p>
073 * 
074 * <p><b>Style</b></p>
075 * <p>
076 * A stage has one of the following styles:
077 * <ul>
078 * <li>{@link StageStyle#DECORATED} - a stage with a solid white background and
079 * platform decorations.</li>
080 * <li>{@link StageStyle#UNDECORATED} - a stage with a solid white background
081 * and no decorations.</li>
082 * <li>{@link StageStyle#TRANSPARENT} - a stage with a transparent background
083 * and no decorations.</li>
084 * <li>{@link StageStyle#UTILITY} - a stage with a solid white background and
085 * minimal platform decorations.</li>
086 * </ul>
087 * <p>The style must be initialized before the stage is made visible.</p>
088 * <p>On some platforms decorations might not be available. For example, on
089 * some mobile or embedded devices. In these cases a request for a DECORATED or
090 * UTILITY window will be accepted, but no decorations will be shown. </p>
091 * 
092 * <p><b>Owner</b></p>
093 * <p>
094 * A stage can optionally have an owner Window.
095 * When a window is a stage's owner, it is said to be the parent of that stage.
096 * When a parent window is closed, all its descendant windows are closed. 
097 * The same chained behavior applied for a parent window that is iconified. 
098 * A stage will always be on top of its parent window.
099 * The owner must be initialized before the stage is made visible.
100 *
101 * <p><b>Modality</b></p>
102 * <p>
103 * A stage has one of the following modalities:
104 * <ul>
105 * <li>{@link Modality#NONE} - a stage that does not block any other window.</li>
106 * <li>{@link Modality#WINDOW_MODAL} - a stage that blocks input events from 
107 * being delivered to all windows from its owner (parent) to its root.
108 * Its root is the closest ancestor window without an owner.</li>
109 * <li>{@link Modality#APPLICATION_MODAL} - a stage that blocks input events from 
110 * being delivered to all windows from the same application, except for those
111 * from its child hierarchy.</li>
112 * </ul> 
113 * 
114 * <p>When a window is blocked by a modal stage its Z-order relative to its ancestors
115 * is preserved, and it receives no input events and no window activation events,
116 * but continues to animate and render normally.
117 * Note that showing a modal stage does not necessarily block the caller. The
118 * {@link #show} method returns immediately regardless of the modality of the stage.
119 * Use the {@link #showAndWait} method if you need to block the caller until
120 * the modal stage is hidden (closed).
121 * The modality must be initialized before the stage is made visible.</p> 
122 *
123 * <p><b>Example:</b></p>
124 *
125 *
126<pre><code>
127import javafx.application.Application;
128import javafx.scene.Group;
129import javafx.scene.Scene;
130import javafx.scene.text.Font;
131import javafx.scene.text.Text;
132import javafx.stage.Stage;
133
134public class HelloWorld extends Application {
135
136    &#64;Override public void start(Stage stage) {
137        Text text = new Text(10, 40, "Hello World!");
138        text.setFont(new Font(40));
139        Scene scene = new Scene(new Group(text));
140
141        stage.setTitle("Welcome to JavaFX!"); 
142        stage.setScene(scene); 
143        stage.sizeToScene(); 
144        stage.show(); 
145    }
146
147    public static void main(String[] args) {
148        Application.launch(args);
149    }
150}
151
152 * </code></pre>
153 * <p>produces the following on Windows:</p>
154 * <p><img src="doc-files/Stage-win.png"/></p>
155 *
156 * <p>produces the following on Mac OSX:</p>
157 * <p><img src="doc-files/Stage-mac.png"/></p>
158 *
159 * <p>produces the following on Linux:</p>
160 * <p><img src="doc-files/Stage-linux.png"/></p>
161 */
162public class Stage extends Window {
163
164    private boolean inNestedEventLoop = false;
165
166    private static ObservableList<Stage> stages = FXCollections.<Stage>observableArrayList();
167
168    static {
169        FXRobotHelper.setStageAccessor(new FXRobotHelper.FXRobotStageAccessor() {
170            @Override public ObservableList<Stage> getStages() {
171                return stages;
172            }
173        });
174        StageHelper.setStageAccessor(new StageHelper.StageAccessor() {
175            @Override public ObservableList<Stage> getStages() {
176                return stages;
177            }
178        });
179    }
180    
181    private static final StagePeerListener.StageAccessor STAGE_ACCESSOR = new StagePeerListener.StageAccessor() {
182
183        @Override
184        public void setIconified(Stage stage, boolean iconified) {
185            stage.iconifiedPropertyImpl().set(iconified);
186        }
187
188        @Override
189        public void setMaximized(Stage stage, boolean maximized) {
190            stage.maximizedPropertyImpl().set(maximized);
191        }
192
193        @Override
194        public void setResizable(Stage stage, boolean resizable) {
195            ((ResizableProperty)stage.resizableProperty()).setNoInvalidate(resizable);
196        }
197
198        @Override
199        public void setFullScreen(Stage stage, boolean fs) {
200            stage.fullScreenPropertyImpl().set(fs);
201        }
202    };
203
204    /**
205     * Creates a new instance of decorated {@code Stage}.
206     *
207     * @throws IllegalStateException if this constructor is called on a thread
208     * other than the JavaFX Application Thread.
209     */
210    public Stage() {
211        this(StageStyle.DECORATED);
212    }
213
214    /**
215     * Creates a new instance of {@code Stage}.
216     *
217     * @param style The style of the {@code Stage}
218     *
219     * @throws IllegalStateException if this constructor is called on a thread
220     * other than the JavaFX Application Thread.
221     */
222    public Stage(@Default("javafx.stage.StageStyle.DECORATED") StageStyle style) {
223        super();
224
225        Toolkit.getToolkit().checkFxUserThread();
226
227        // Set the style
228        initStyle(style);
229    }
230    
231    /**
232     * Specify the scene to be used on this stage.
233     */
234    @Override final public void setScene(Scene value) {
235        super.setScene(value);
236    }
237    
238    /**
239     * @inheritDoc
240     */
241    @Override public final void show() {
242        super.show();
243    }
244    
245    private boolean primary = false;
246
247    /**
248     * sets this stage to be the primary stage.
249     * When run as an applet, this stage will appear in the broswer
250     * @treatAsPrivate implementation detail
251     * @deprecated This is an internal API that is not intended for use and will be removed in the next version
252     */
253    @Deprecated
254    public void impl_setPrimary(boolean primary) {
255        this.primary = primary;
256    }
257
258    /**
259     * Returns whether this stage is the primary stage.
260     * When run as an applet, the primary stage will appear in the broswer
261     *
262     * @return true if this stage is the primary stage for the application.
263     */
264    boolean isPrimary() {
265        return primary;
266    }
267    
268    /**
269     * @treatAsPrivate implementation detail
270     * @deprecated This is an internal API that is not intended for use and will be removed in the next version
271     */
272    @Deprecated
273    @Override
274    public String impl_getMXWindowType() {
275        return (primary) ? "PrimaryStage" : getClass().getSimpleName();
276    }
277
278    private boolean important = true;
279
280    /**
281     * Sets a flag indicating whether this stage is an "important" window for
282     * the purpose of determining whether the application is idle and should
283     * exit. The application is considered finished when the last important
284     * window is closed.
285     * @treatAsPrivate implementation detail
286     * @deprecated This is an internal API that is not intended for use and will be removed in the next version
287     */
288    @Deprecated
289    public void impl_setImportant(boolean important) {
290        this.important = important;
291    }
292
293    private boolean isImportant() {
294        return important;
295    }
296
297    /**
298     * Shows this stage and waits for it to be hidden (closed) before returning
299     * to the caller. This method temporarily blocks processing of the current
300     * event, and starts a nested event loop to handle other events.
301     * This method must be called on the FX Application thread.
302     * <p>
303     * A Stage is hidden (closed) by one of the following means:
304     * <ul>
305     * <li>the application calls the {@link #hide} or {@link #close} method on
306     * this stage</li>
307     * <li>this stage has a non-null owner window, and its owner is closed</li>
308     * <li>the user closes the window via the window system (for example,
309     * by pressing the close button in the window decoration)</li>
310     * </ul>
311     * </p>
312     *
313     * <p>
314     * After the Stage is hidden, and the application has returned from the
315     * event handler to the event loop, the nested event loop terminates
316     * and this method returns to the caller.
317     * </p>
318     * <p>
319     * For example, consider the following sequence of operations for different
320     * event handlers, assumed to execute in the order shown below:
321     * <pre>void evtHander1(...) {
322     *     stage1.showAndWait();
323     *     doSomethingAfterStage1Closed(...)
324     * }
325     *
326     * void evtHander2(...) {
327     *     stage1.hide();
328     *     doSomethingElseHere(...)
329     * }</pre>
330     * evtHandler1 will block at the call to showAndWait. It will resume execution
331     * after stage1 is hidden and the current event handler, in this case evtHandler2,
332     * returns to the event loop. This means that doSomethingElseHere will
333     * execute before doSomethingAfterStage1Closed.
334     * </p>
335     *
336     * <p>
337     * More than one stage may be shown with showAndWait. Each call
338     * will start a new nested event loop. The stages may be hidden in any order,
339     * but a particular nested event loop (and thus the showAndWait method
340     * for the associated stage) will only terminate after all inner event loops
341     * have also terminated.
342     * </p>
343     * <p>
344     * For example, consider the following sequence of operations for different
345     * event handlers, assumed to execute in the order shown below:
346     * <ul>
347     * <pre>void evtHander1() {
348     *     stage1.showAndWait();
349     *     doSomethingAfterStage1Closed(...)
350     * }
351     *
352     * void evtHander2() {
353     *     stage2.showAndWait();
354     *     doSomethingAfterStage2Closed(...)
355     * }
356     *
357     * void evtHander3() {
358     *     stage1.hide();
359     *     doSomethingElseHere(...)
360     * }
361     *
362     * void evtHander4() {
363     *     stage2.hide();
364     *     doSomethingElseHereToo(...)
365     * }</pre>
366     * </ul>
367     * evtHandler1 will block at the call to stage1.showAndWait, starting up
368     * a nested event loop just like in the previous example. evtHandler2 will
369     * then block at the call to stage2.showAndWait, starting up another (inner)
370     * nested event loop. The first call to stage1.showAndWait will resume execution
371     * after stage1 is hidden, but only after the inner nested event loop started
372     * by stage2.showAndWait has terminated. This means that the call to
373     * stage1.showAndWait won't return until after evtHandler2 has returned.
374     * The order of execution is: stage1.showAndWait, stage2.showAndWait,
375     * stage1.hide, doSomethingElseHere, stage2.hide, doSomethingElseHereToo,
376     * doSomethingAfterStage2Closed, doSomethingAfterStage1Closed.
377     * </p>
378     *
379     * <p>
380     * This method must not be called on the primary stage or on a stage that
381     * is already visible.
382     * </p>
383     *
384     * @throws IllegalStateException if this method is called on a thread
385     *     other than the JavaFX Application Thread.
386     * @throws IllegalStateException if this method is called on the
387     *     primary stage.
388     * @throws IllegalStateException if this stage is already showing.
389     * @since 2.2
390     */
391    public void showAndWait() {
392
393        Toolkit.getToolkit().checkFxUserThread();
394
395        if (isPrimary()) {
396            throw new IllegalStateException("Cannot call this method on primary stage");
397        }
398
399        if (isShowing()) {
400            throw new IllegalStateException("Stage already visible");
401        }
402
403        // TODO: file a new bug; the following assertion can fail if this
404        // method is called from an event handler that is listening to a
405        // WindowEvent.WINDOW_HIDING event.
406        assert !inNestedEventLoop;
407
408        show();
409        inNestedEventLoop = true;
410        Toolkit.getToolkit().enterNestedEventLoop(this);
411    }
412
413    private StageStyle style; // default is set in constructor
414
415    /**
416     * Specifies the style for this stage. This must be done prior to making
417     * the stage visible. The style is one of: StageStyle.DECORATED,
418     * StageStyle.UNDECORATED, StageStyle.TRANSPARENT, or StageStyle.UTILITY.
419     *
420     * @param style the style for this stage.
421     *
422     * @throws IllegalStateException if this property is set after the stage
423     * has ever been made visible.
424     *
425     * @defaultValue StageStyle.DECORATED
426     */
427    public final void initStyle(StageStyle style) {
428        if (hasBeenVisible) {
429            throw new IllegalStateException("Cannot set style once stage has been set visible");
430        }
431        this.style = style;
432    }
433
434    /**
435     * Retrieves the style attribute for this stage.
436     *
437     * @return the stage style.
438     */
439    public final StageStyle getStyle() {
440        return style;
441    }
442
443    private Modality modality = Modality.NONE;
444
445    /**
446     * Specifies the modality for this stage. This must be done prior to making
447     * the stage visible. The modality is one of: Modality.NONE,
448     * Modality.WINDOW_MODAL, or Modality.APPLICATION_MODAL.
449     *
450     * @param modality the modality for this stage.
451     *
452     * @throws IllegalStateException if this property is set after the stage
453     * has ever been made visible.
454     *
455     * @throws IllegalStateException if this stage is the primary stage.
456     *
457     * @defaultValue Modality.NONE
458     */
459    public final void initModality(Modality modality) {
460        if (hasBeenVisible) {
461            throw new IllegalStateException("Cannot set modality once stage has been set visible");
462        }
463
464        if (isPrimary()) {
465            throw new IllegalStateException("Cannot set modality for the primary stage");
466        }
467
468        this.modality = modality;
469    }
470
471    /**
472     * Retrieves the modality attribute for this stage.
473     *
474     * @return the modality.
475     */
476    public final Modality getModality() {
477        return modality;
478    }
479
480    private Window owner = null;
481
482    /**
483     * Specifies the owner Window for this stage, or null for a top-level,
484     * unowned stage. This must be done prior to making the stage visible.
485     *
486     * @param owner the owner for this stage.
487     *
488     * @throws IllegalStateException if this property is set after the stage
489     * has ever been made visible.
490     *
491     * @throws IllegalStateException if this stage is the primary stage.
492     *
493     * @defaultValue null
494     */
495    public final void initOwner(Window owner) {
496        if (hasBeenVisible) {
497            throw new IllegalStateException("Cannot set owner once stage has been set visible");
498        }
499
500        if (isPrimary()) {
501            throw new IllegalStateException("Cannot set owner for the primary stage");
502        }
503
504        this.owner = owner;
505        
506        final Scene sceneValue = getScene();
507        if (sceneValue != null) {
508            SceneHelper.parentEffectiveOrientationInvalidated(sceneValue);
509        }
510    }
511
512    /**
513     * Retrieves the owner Window for this stage, or null for an unowned stage.
514     *
515     * @return the owner Window.
516     */
517    public final Window getOwner() {
518        return owner;
519    }
520
521    /**
522     * Specifies whether this {@code Stage} should be a full-screen,
523     * undecorated window.
524     * <p>
525     * The implementation of full-screen mode is platform and profile-dependent.
526     * </p>
527     * <p>
528     * When set to {@code true}, the {@code Stage} will attempt to enter
529     * full-screen mode when visible. Set to {@code false} to return {@code Stage}
530     * to windowed mode.
531     * An {@link IllegalStateException} is thrown if this property is set
532     * on a thread other than the JavaFX Application Thread.
533     * </p>
534     * <p>
535     * The full-screen mode will be exited (and the {@code fullScreen} attribute
536     * will be set to {@code false}) if the full-screen
537     * {@code Stage} loses focus or if another {@code Stage} enters
538     * full-screen mode on the same {@link Screen}. Note that a {@code Stage}
539     * in full-screen mode can become invisible without losing its
540     * full-screen status and will again enter full-screen mode when the
541     * {@code Stage} becomes visible.
542     * </p>
543     * If the platform supports multiple screens an application can control
544     * which {@code Screen} the Stage will enter full-screen mode on by
545     * setting its position to be within the bounds of that {@code Screen}
546     * prior to entering full-screen mode.
547     * <p>
548     * However once in full-screen mode, {@code Stage}'s {@code x}, {@code y},
549     * {@code width}, and {@code height} variables will continue to represent
550     * the non-full-screen position and size of the window; the same for
551     * {@code iconified}, {@code resizable}, {@code style}, and {@code
552     * opacity}. If changes are made to any of these attributes while in
553     * full-screen mode, upon exiting full-screen mode the {@code Stage} will
554     * assume those attributes.
555     * </p>
556     * <p>
557     * In case that more {@code Stage} modes are set simultaneously their order
558     * of importance is {@code iconified}, fullScreen, {@code maximized} (from
559     * strongest to weakest).
560     * </p>
561     * <p>
562     * The property is read only because it can be changed externally
563     * by the underlying platform and therefore must not be bindable.
564     * </p>
565     *
566     * Notes regarding desktop profile implementation.
567     * <p>
568     * For desktop profile the runtime will attempt to enter full-screen
569     * exclusive mode (FSEM) if such is supported by the platform and it is
570     * allowed for this application. If either is not the case a
571     * simulated full-screen window will be used instead; the window will be
572     * maximized, made undecorated if possible, and moved to the front.
573     * </p>
574     * For desktop profile the user can unconditionally exit full-screen mode
575     * at any time by pressing {@code ESC}.
576     * <p>
577     * There are differences in behavior between signed and unsigned
578     * applications. Signed applications are allowed to enter full-screen
579     * exclusive mode unrestricted while unsigned applications will
580     * have the following restrictions:
581     * </p>
582     * <ul>
583     *  <li>Applications can only enter FSEM in response
584     *   to user input. More specifically, entering is allowed from mouse
585     *   ({@code Node.mousePressed/mouseReleased/mouseClicked}) or keyboard
586     *   ({@code Node.keyPressed/keyReleased/keyTyped}) event handlers. It is
587     *   not allowed to enter FSEM in response to {@code ESC}
588     *   key. Attempting to enter FSEM from any other context will result in
589     *   emulated full-screen mode.
590     *   <p>
591     *   If {@code Stage} was constructed as full-screen but not visible
592     *   it will enter full-screen mode upon becoming visible, with the same
593     *   limitations to when this is allowed to happen as when setting
594     *   {@code fullScreen} to {@code true}.
595     *   </p>
596     *  </li>
597     *  <li> If the application was allowed to enter FSEM
598     *   it will have limited keyboard input. It will only receive KEY_PRESSED
599     *   and KEY_RELEASED events from the following keys:
600     *   {@code UP, DOWN, LEFT, RIGHT, SPACE, TAB, PAGE_UP, PAGE_DOWN, HOME, END, ENTER}
601     *  </li>
602     * </ul>
603     * @defaultValue false
604     */
605    private ReadOnlyBooleanWrapper fullScreen;
606
607    public final void setFullScreen(boolean value) {
608        Toolkit.getToolkit().checkFxUserThread();
609        fullScreenPropertyImpl().set(value);
610        if (impl_peer != null)
611            impl_peer.setFullScreen(value);
612    }
613
614    public final boolean isFullScreen() {
615        return fullScreen == null ? false : fullScreen.get();
616    }
617
618    public final ReadOnlyBooleanProperty fullScreenProperty() {
619        return fullScreenPropertyImpl().getReadOnlyProperty();
620    }
621
622    private ReadOnlyBooleanWrapper fullScreenPropertyImpl () {
623        if (fullScreen == null) {
624            fullScreen = new ReadOnlyBooleanWrapper(Stage.this, "fullScreen");
625        }
626        return fullScreen;
627    }
628
629    /**
630     * Defines the icon images to be used in the window decorations and when
631     * minimized. The images should be different sizes of the same image and
632     * the best size will be chosen, eg. 16x16, 32,32.
633     *
634     * @defaultValue empty
635     */
636    private ObservableList<Image> icons = new TrackableObservableList<Image>() {
637        @Override protected void onChanged(Change<Image> c) {
638            List<Object> platformImages = new ArrayList<Object>();
639            for (Image icon : icons) {
640                platformImages.add(icon.impl_getPlatformImage());
641            }
642            if (impl_peer != null) {
643                impl_peer.setIcons(platformImages);
644            }
645        }
646    };
647
648    /**
649     * Gets the icon images to be used in the window decorations and when
650     * minimized. The images should be different sizes of the same image and
651     * the best size will be chosen, eg. 16x16, 32,32.
652     * @return An observable list of icons of this window
653     */
654    public final ObservableList<Image> getIcons() {
655        return icons;
656    }
657
658    /**
659     * Defines the title of the {@code Stage}.
660     *
661     * @defaultValue empty string
662     */
663    private StringProperty title;
664
665    public final void setTitle(String value) {
666        titleProperty().set(value);
667    }
668
669    public final String getTitle() {
670        return title == null ? null : title.get();
671    }
672
673    public final StringProperty titleProperty() {
674        if (title == null) {
675            title = new StringPropertyBase() {
676
677                @Override
678                protected void invalidated() {
679                    if (impl_peer != null) {
680                        impl_peer.setTitle(get());
681                    }
682                }
683
684                @Override
685                public Object getBean() {
686                    return Stage.this;
687                }
688
689                @Override
690                public String getName() {
691                    return "title";
692                }
693            };
694        }
695        return title;
696    }
697
698    /**
699     * Defines whether the {@code Stage} is iconified or not.
700     * <p>
701     * In case that more {@code Stage} modes are set simultaneously their order
702     * of importance is iconified} {@code fullScreen}, {@code maximized} (from
703     * strongest to weakest).
704     * </p>
705     * <p>
706     * On some mobile and embedded platforms setting this property to true will
707     * hide the {@code Stage} but not show an icon for it.
708     * </p>
709     * <p>
710     * The property is read only because it can be changed externally
711     * by the underlying platform and therefore must not be bindable.
712     * </p>
713     *
714     * @defaultValue false
715     */
716    private ReadOnlyBooleanWrapper iconified;
717
718    public final void setIconified(boolean value) {
719        iconifiedPropertyImpl().set(value);
720        if (impl_peer != null)
721            impl_peer.setIconified(value);
722    }
723
724    public final boolean isIconified() {
725        return iconified == null ? false : iconified.get();
726    }
727
728    public final ReadOnlyBooleanProperty iconifiedProperty() {
729        return iconifiedPropertyImpl().getReadOnlyProperty();
730    }
731
732    private final ReadOnlyBooleanWrapper iconifiedPropertyImpl() {
733        if (iconified == null) {
734            iconified = new ReadOnlyBooleanWrapper(Stage.this, "iconified");
735        }
736        return iconified;
737    }
738
739    /**
740     * Defines whether the {@code Stage} is maximized or not.
741     * <p>
742     * In case that more {@code Stage} modes are set simultaneously their order
743     * of importance is {@code iconified}, {@code fullScreen}, maximized (from
744     * strongest to weakest).
745     * </p>
746     * <p>
747     * The property is read only because it can be changed externally
748     * by the underlying platform and therefore must not be bindable.
749     * </p>
750     *
751     * @defaultValue false
752     */
753    private ReadOnlyBooleanWrapper maximized;
754
755    public final void setMaximized(boolean value) {
756        maximizedPropertyImpl().set(value);
757        if (impl_peer != null)
758            impl_peer.setMaximized(value);
759    }
760
761    public final boolean isMaximized() {
762        return maximized == null ? false : maximized.get();
763    }
764
765    public final ReadOnlyBooleanProperty maximizedProperty() {
766        return maximizedPropertyImpl().getReadOnlyProperty();
767    }
768
769    private final ReadOnlyBooleanWrapper maximizedPropertyImpl() {
770        if (maximized == null) {
771            maximized = new ReadOnlyBooleanWrapper(Stage.this, "maximized");
772        }
773        return maximized;
774    }
775
776    /**
777     * Defines whether the {@code Stage} is resizable or not by the user.
778     * Programatically you may still change the size of the Stage. This is
779     * a hint which allows the implementation to optionally make the Stage
780     * resizable by the user.
781     * <p>
782     * <b>Warning:</b> Since 8.0 the property cannot be bound and will throw
783     * {@code RuntimeException} on an attempt to do so. This is because
784     * the setting of resizable is asynchronous on some systems or generally
785     * might be set by the system / window manager.
786     * <br>
787     * Bidirectional binds are still allowed, as they don't block setting of the
788     * property by the system.
789     * 
790     * @defaultValue true
791     */
792    private BooleanProperty resizable;
793
794    public final void setResizable(boolean value) {
795        resizableProperty().set(value);
796    }
797
798    public final boolean isResizable() {
799        return resizable == null ? true : resizable.get();
800    }
801
802    public final BooleanProperty resizableProperty() {
803        if (resizable == null) {
804            resizable = new ResizableProperty();
805        }
806        return resizable;
807    }
808
809    //We cannot return ReadOnlyProperty in resizable, as this would be
810    // backward incompatible. All we can do is to create this custom property
811    // implementation that disallows binds
812    private class ResizableProperty extends SimpleBooleanProperty {
813        private boolean noInvalidate;
814
815        public ResizableProperty() {
816            super(Stage.this, "resizable", true);
817        }
818
819        void setNoInvalidate(boolean value) {
820            noInvalidate = true;
821            set(value);
822            noInvalidate = false;
823        }
824
825        @Override
826        protected void invalidated() {
827            if (noInvalidate) {
828                return;
829            }
830            if (impl_peer != null) {
831                applyBounds();
832                impl_peer.setResizable(get());
833            }
834        }
835
836        @Override
837        public void bind(ObservableValue<? extends Boolean> rawObservable) {
838            throw new RuntimeException("Resizable property cannot be bound");
839        }
840
841    }
842
843    /**
844     * Defines the minimum width of this {@code Stage}.
845     *
846     * @defaultValue 0
847     */
848    private DoubleProperty minWidth;
849
850    public final void setMinWidth(double value) {
851        minWidthProperty().set(value);
852    }
853
854    public final double getMinWidth() {
855        return minWidth == null ? 0 : minWidth.get();
856    }
857
858    public final DoubleProperty minWidthProperty() {
859        if (minWidth == null) {
860            minWidth = new DoublePropertyBase(0) {
861
862                @Override
863                protected void invalidated() {
864                    if (impl_peer != null) {
865                        impl_peer.setMinimumSize((int) Math.ceil(get()),
866                                (int) Math.ceil(getMinHeight()));
867                    }
868                    if (getWidth() < getMinWidth()) {
869                        setWidth(getMinWidth());
870                    }
871                }
872
873                @Override
874                public Object getBean() {
875                    return Stage.this;
876                }
877
878                @Override
879                public String getName() {
880                    return "minWidth";
881                }
882            };
883        }
884        return minWidth;
885    }
886
887    /**
888     * Defines the minimum height of this {@code Stage}.
889     *
890     * @defaultValue 0
891     */
892    private DoubleProperty minHeight;
893
894    public final void setMinHeight(double value) {
895        minHeightProperty().set(value);
896    }
897
898    public final double getMinHeight() {
899        return minHeight == null ? 0 : minHeight.get();
900    }
901
902    public final DoubleProperty minHeightProperty() {
903        if (minHeight == null) {
904            minHeight = new DoublePropertyBase(0) {
905
906                @Override
907                protected void invalidated() {
908                    if (impl_peer != null) {
909                        impl_peer.setMinimumSize(
910                                (int) Math.ceil(getMinWidth()),
911                                (int) Math.ceil(get()));
912                    }
913                    if (getHeight() < getMinHeight()) {
914                        setHeight(getMinHeight());
915                    }
916                }
917
918                @Override
919                public Object getBean() {
920                    return Stage.this;
921                }
922
923                @Override
924                public String getName() {
925                    return "minHeight";
926                }
927            };
928        }
929        return minHeight;
930    }
931
932    /**
933     * Defines the maximum width of this {@code Stage}.
934     *
935     * @defaultValue Double.MAX_VALUE
936     */
937    private DoubleProperty maxWidth;
938
939    public final void setMaxWidth(double value) {
940        maxWidthProperty().set(value);
941    }
942
943    public final double getMaxWidth() {
944        return maxWidth == null ? Double.MAX_VALUE : maxWidth.get();
945    }
946
947    public final DoubleProperty maxWidthProperty() {
948        if (maxWidth == null) {
949            maxWidth = new DoublePropertyBase(Double.MAX_VALUE) {
950
951                @Override
952                protected void invalidated() {
953                    if (impl_peer != null) {
954                        impl_peer.setMaximumSize((int) Math.floor(get()),
955                                (int) Math.floor(getMaxHeight()));
956                    }
957                    if (getWidth() > getMaxWidth()) {
958                        setWidth(getMaxWidth());
959                    }
960                }
961
962                @Override
963                public Object getBean() {
964                    return Stage.this;
965                }
966
967                @Override
968                public String getName() {
969                    return "maxWidth";
970                }
971            };
972        }
973        return maxWidth;
974    }
975
976    /**
977     * Defines the maximum height of this {@code Stage}.
978     *
979     * @defaultValue Double.MAX_VALUE
980     */
981    private DoubleProperty maxHeight;
982
983    public final void setMaxHeight(double value) {
984        maxHeightProperty().set(value);
985    }
986
987    public final double getMaxHeight() {
988        return maxHeight == null ? Double.MAX_VALUE : maxHeight.get();
989    }
990
991    public final DoubleProperty maxHeightProperty() {
992        if (maxHeight == null) {
993            maxHeight = new DoublePropertyBase(Double.MAX_VALUE) {
994
995                @Override
996                protected void invalidated() {
997                    if (impl_peer != null) {
998                        impl_peer.setMaximumSize(
999                                (int) Math.floor(getMaxWidth()),
1000                                (int) Math.floor(get()));
1001                    }
1002                    if (getHeight() > getMaxHeight()) {
1003                        setHeight(getMaxHeight());
1004                    }
1005                }
1006
1007                @Override
1008                public Object getBean() {
1009                    return Stage.this;
1010                }
1011
1012                @Override
1013                public String getName() {
1014                    return "maxHeight";
1015                }
1016            };
1017        }
1018        return maxHeight;
1019    }
1020
1021    
1022    /**
1023     * @treatAsPrivate implementation detail
1024     * @deprecated This is an internal API that is not intended for use and will be removed in the next version
1025     */
1026    @Deprecated
1027    @Override protected void impl_visibleChanging(boolean value) {
1028        super.impl_visibleChanging(value);
1029        Toolkit toolkit = Toolkit.getToolkit();
1030        if (value && (impl_peer == null)) {
1031            // Setup the peer
1032            Window window = getOwner();
1033            TKStage tkStage = (window == null ? null : window.impl_getPeer());
1034            Scene scene = getScene();
1035            boolean rtl = scene != null && scene.getEffectiveNodeOrientation() == NodeOrientation.RIGHT_TO_LEFT;
1036
1037            impl_peer = toolkit.createTKStage(getStyle(), isPrimary(), getModality(), tkStage, rtl);
1038            peerListener = new StagePeerListener(this, STAGE_ACCESSOR);
1039            
1040           // Insert this into stages so we have a references to all created stages
1041            stages.add(this);
1042        }
1043    }
1044
1045    
1046    /**
1047     * @treatAsPrivate implementation detail
1048     * @deprecated This is an internal API that is not intended for use and will be removed in the next version
1049     */
1050    @Deprecated
1051    @Override protected void impl_visibleChanged(boolean value) {
1052        super.impl_visibleChanged(value);
1053
1054        if (value) {
1055            // Finish initialization
1056            impl_peer.setImportant(isImportant());
1057            impl_peer.setResizable(isResizable());
1058            impl_peer.setFullScreen(isFullScreen());
1059            impl_peer.setIconified(isIconified());
1060            impl_peer.setMaximized(isMaximized());
1061            impl_peer.setTitle(getTitle());
1062            impl_peer.setMinimumSize((int) Math.ceil(getMinWidth()),
1063                    (int) Math.ceil(getMinHeight()));
1064            impl_peer.setMaximumSize((int) Math.floor(getMaxWidth()),
1065                    (int) Math.floor(getMaxHeight()));
1066
1067            List<Object> platformImages = new ArrayList<Object>();
1068            for (Image icon : icons) {
1069                platformImages.add(icon.impl_getPlatformImage());
1070            }
1071            if (impl_peer != null) {
1072                impl_peer.setIcons(platformImages);
1073            }
1074        }
1075
1076        if (!value) {
1077            // Remove form active stage list
1078            stages.remove(this);
1079        }
1080
1081        if (!value && inNestedEventLoop) {
1082            inNestedEventLoop = false;
1083            Toolkit.getToolkit().exitNestedEventLoop(this, null);
1084        }
1085    }
1086
1087    /**
1088     * Bring the {@code Window} to the foreground.  If the {@code Window} is
1089     * already in the foreground there is no visible difference.
1090     */
1091    public void toFront() {
1092        if (impl_peer != null) {
1093            impl_peer.toFront();
1094        }
1095    }
1096
1097    /**
1098     * Send the {@code Window} to the background.  If the {@code Window} is
1099     * already in the background there is no visible difference.  This action
1100     * places this {@code Window} at the bottom of the stacking order on
1101     * platforms that support stacking.
1102     */
1103    public void toBack() {
1104        if (impl_peer != null) {
1105            impl_peer.toBack();
1106        }
1107    }
1108
1109    /**
1110     * Closes this {@code Stage}.
1111     * This call is equivalent to {@code hide()}.
1112     */
1113    public void close() {
1114        hide();
1115    }
1116
1117    @Override
1118    Window getWindowOwner() {
1119        return getOwner();
1120    }
1121}