use of org.phoebus.ui.docking.DockPane in project phoebus by ControlSystemStudio.
the class MementoHelper method closePaneOrSplit.
/**
* Close a DockPane or SplitDock and all tabs held within.
*
* <p>Dock items must have been prepared to close.
*
* @param node Node, either a dock item or split pane, that will be closed.
* @return boolean <code>true</code> if all the tabs close successfully.
*/
public static boolean closePaneOrSplit(final Node node) {
if (node instanceof DockPane) {
// Close every dock item in the dock pane.
final DockPane pane = (DockPane) node;
final List<DockItem> items = pane.getDockItems();
for (final DockItem item : items) item.close();
} else if (node instanceof SplitDock) {
final SplitDock split = (SplitDock) node;
// We are altering the size of the list we are iterating over...
final List<Node> items = new ArrayList<>(split.getItems());
// If a node fails to close, return false.
for (Node item : items) if (!closePaneOrSplit(item))
return false;
// and thus not triggering a merge..
if (split.getItems().size() > 0)
split.merge();
} else {
logger.log(Level.WARNING, "Cannot close " + node);
return false;
}
return true;
}
use of org.phoebus.ui.docking.DockPane in project phoebus by ControlSystemStudio.
the class MementoHelper method savePaneOrSplit.
/**
* @param memento
* @param item DockPane or SplitDock
*/
private static void savePaneOrSplit(final MementoTree memento, final Node node) {
if (node instanceof DockPane) {
final DockPane pane = (DockPane) node;
final MementoTree pane_memento = memento.createChild(PANE);
if (pane.isFixed())
pane_memento.setBoolean(FIXED, true);
if (pane.getName().length() > 0)
pane_memento.setString(NAME, pane.getName());
pane_memento.setNumber(SELECTED, pane.getSelectionModel().getSelectedIndex());
for (DockItem item : pane.getDockItems()) saveDockItem(pane_memento, item);
} else if (node instanceof SplitDock) {
final SplitDock split = (SplitDock) node;
final MementoTree split_memento = memento.createChild(SPLIT);
split_memento.setNumber(POS, split.getDividerPosition());
if (!split.isHorizontal())
split_memento.setBoolean(HORIZONTAL, false);
for (Node sub : split.getItems()) savePaneOrSplit(split_memento, sub);
} else
logger.log(Level.WARNING, "Cannot persist " + node);
}
use of org.phoebus.ui.docking.DockPane in project phoebus by ControlSystemStudio.
the class MementoHelper method restorePaneOrSplit.
/**
* @param pane Initial, empty pane that might be filled with items or split
* @param children
* @return <code>true</code> if any tab item was restored
*/
private static boolean restorePaneOrSplit(final DockPane pane, final MementoTree content) {
boolean any = false;
if (content.getName().equals(PANE)) {
// Fill given pane with tabs
for (MementoTree item_memento : content.getChildren()) any |= restoreDockItem(item_memento, pane);
// Maybe select a specific tab
// If the new tab is inside a SplitDock,
// it won't actually exist until the content of the SplitDock's SplitPane
// is rendered on the next UI tick, resulting in a NullPointerException
// deep inside JFX calling TabPane$TabPaneSelectionModel.select
// By deferring to a later UI tick, the tab selection succeeds
content.getNumber(SELECTED).ifPresent(index -> Platform.runLater(() -> {
// so check once more
if (index.intValue() < pane.getTabs().size())
pane.getSelectionModel().select(index.intValue());
}));
content.getString(NAME).ifPresent(pane::setName);
// If pane is 'fixed', mark as such _after_ all items have been restored
// to prevent changes from now on
content.getBoolean(FIXED).ifPresent(fixed -> {
// then wait another tick
if (fixed)
Platform.runLater(() -> pane.deferUntilInScene(scene -> Platform.runLater(() -> pane.setFixed(true))));
});
} else if (content.getName().equals(SPLIT)) {
// Split the original pane
final SplitDock split = pane.split(content.getBoolean(HORIZONTAL).orElse(true));
// Fill split's items
final List<Node> first_second_pane = split.getItems();
final List<MementoTree> first_second_mememto = content.getChildren();
any |= restorePaneOrSplit((DockPane) first_second_pane.get(0), first_second_mememto.get(0));
any |= restorePaneOrSplit((DockPane) first_second_pane.get(1), first_second_mememto.get(1));
// The divider position needs to be set at the end, after the complete scene has been restored.
// Otherwise the SplitPane self-adjusts the position when the sub-elements are rendered,
// replacing a position set now.
content.getNumber(POS).ifPresent(num -> {
UpdateThrottle.TIMER.schedule(() -> Platform.runLater(() -> split.setDividerPosition(num.doubleValue())), 300, TimeUnit.MILLISECONDS);
});
} else
logger.log(Level.WARNING, "Expect <pane> or <split>, got " + content);
return any;
}
use of org.phoebus.ui.docking.DockPane in project phoebus by ControlSystemStudio.
the class MementoHelper method restoreStage.
/**
* Restore state of Stage from memento
* @param memento
* @param stage
* @return <code>true</code> if any tab item was restored
*/
public static boolean restoreStage(final MementoTree stage_memento, final Stage stage) {
// Closest to atomically setting size and location with minimal flicker: hide, update, show
stage.hide();
stage_memento.getNumber(X).ifPresent(num -> stage.setX(num.doubleValue()));
stage_memento.getNumber(Y).ifPresent(num -> stage.setY(num.doubleValue()));
stage_memento.getNumber(WIDTH).ifPresent(num -> stage.setWidth(num.doubleValue()));
stage_memento.getNumber(HEIGHT).ifPresent(num -> stage.setHeight(num.doubleValue()));
// Check if stage is visible.
// Memento might have been stored when a secondary monitor was connected
// or on a different host with larger display, but saved location is outside
// of currently connected displays.
// Mac OS might relocate them on its own,
// but at least in Windows 10 such stages are then off-screen and hard to get.
final List<Screen> match = Screen.getScreensForRectangle(stage.getX(), stage.getY(), stage.getWidth(), stage.getHeight());
if (match.isEmpty()) {
logger.log(Level.WARNING, "Relocating restored stage from X=" + stage.getX() + " Y=" + stage.getY() + " to primary screen");
final Rectangle2D relocate = Screen.getPrimary().getVisualBounds();
// Move to top-left corner of primary screen so it's visible.
// Keep size to minimize impact on saved layout.
stage.setX(relocate.getMinX());
stage.setY(relocate.getMinY());
}
stage.show();
stage_memento.getBoolean(FULLSCREEN).ifPresent(flag -> stage.setFullScreen(flag));
stage_memento.getBoolean(MAXIMIZED).ifPresent(flag -> stage.setMaximized(flag));
stage_memento.getBoolean(MINIMIZED).ifPresent(flag -> stage.setIconified(flag));
// Initial pane of the new stage
final DockPane pane = DockStage.getDockPanes(stage).get(0);
// <pane> content or <split>
final List<MementoTree> children = stage_memento.getChildren();
if (children.size() != 1) {
logger.log(Level.WARNING, "Expect single <pane> or <split>, got " + children);
return false;
}
return restorePaneOrSplit(pane, children.get(0));
}
Aggregations