package org.geogebra.web.web.gui.layout; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.TreeSet; import org.geogebra.common.gui.layout.DockComponent; import org.geogebra.common.gui.layout.DockManager; import org.geogebra.common.gui.layout.DockPanel; import org.geogebra.common.io.layout.DockPanelData; import org.geogebra.common.io.layout.DockSplitPaneData; import org.geogebra.common.io.layout.PerspectiveDecoder; import org.geogebra.common.io.layout.ShowDockPanelListener; import org.geogebra.common.javax.swing.SwingConstants; import org.geogebra.common.main.App; import org.geogebra.common.main.Feature; import org.geogebra.common.util.debug.Log; import org.geogebra.ggbjdk.java.awt.geom.Rectangle; import org.geogebra.web.html5.awt.GDimensionW; import org.geogebra.web.html5.euclidian.EuclidianPanelWAbstract; import org.geogebra.web.html5.gui.GuiManagerInterfaceW; import org.geogebra.web.html5.main.AppW; import org.geogebra.web.web.gui.layout.panels.Euclidian2DockPanelW; import org.geogebra.web.web.gui.layout.panels.EuclidianDockPanelW; import org.geogebra.web.web.gui.layout.panels.EuclidianDockPanelWAbstract; import org.geogebra.web.web.gui.view.algebra.AlgebraViewW; import org.geogebra.web.web.main.AppWFull; import org.geogebra.web.web.main.AppWapplet; import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.ui.DockLayoutPanel; import com.google.gwt.user.client.ui.Panel; import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.user.client.ui.Widget; /** * Class responsible to manage the whole docking area of the window. * * @author Florian Sonner */ public class DockManagerW extends DockManager { private static final int DEFAULT_KEYBOARD_HEIGHT = 186; AppW app; private LayoutW layout; /** * False if the application is running in unsigned mode. We can only listen to * euclidian view focus changes in this case. */ private boolean hasFullFocusSystem; /** * The root split pane. */ private DockSplitPaneW rootPane; /** * The dock panel which has the focus at the moment. */ private DockPanelW focusedDockPanel; /** * The euclidian dock panel which had the focus the last. */ private EuclidianDockPanelWAbstract focusedEuclidianDockPanel; /** * A list with all registered dock panels. */ private ArrayList<DockPanelW> dockPanels; /** * List of DockPanelListeners, informed when some dockpanel is shown. */ private List<ShowDockPanelListener> showDockPanelListener; private boolean panelsMoved; /** * @param layout */ public DockManagerW(LayoutW layout) { this.layout = layout; this.app = layout.getApplication(); dockPanels = new ArrayList<DockPanelW>(); showDockPanelListener=new ArrayList<ShowDockPanelListener>(); //if(!app.isApplet()) { // app.setGlassPane(glassPane); //} // register focus changes // try { // Toolkit.getDefaultToolkit().addAWTEventListener(this , AWTEvent.MOUSE_EVENT_MASK); // hasFullFocusSystem = true; // } catch(Exception e) { // hasFullFocusSystem = false; // } } /** * Register a new dock panel. Use Layout::registerPanel() as public interface. * * @param dockPanel */ public void registerPanel(DockPanelW dockPanel) { dockPanels.add(dockPanel); dockPanel.register(this); } /** * remove panel for the dock panels list * @param dockPanel panel */ @Override public void unRegisterPanel(DockPanel dockPanel) { dockPanels.remove(dockPanel); } /** * Apply a certain perspective by arranging the dock panels in the requested order. * * @param spData * @param dpData * * @see LayoutD#applyPerspective(geogebra.io.layout.Perspective) */ public void applyPerspective(DockSplitPaneData[] spData, DockPanelData[] dpData) { if(dockPanels != null) { // hide existing external windows for(DockPanelW panel : dockPanels) { if(panel.isOpenInFrame() && panel.isVisible()) { hide(panel); } panel.setAlone(false); } TreeSet<Integer> updated = new TreeSet<Integer>(); // copy dock panel info settings for(int i = 0; i < dpData.length; ++i) { updated.add(dpData[i].getViewId()); DockPanelW panel = getPanel(dpData[i]); if(panel == null) { // TODO insert error panel }else{ panel.setToolbarString(dpData[i].getToolbarString()); panel.setFrameBounds((Rectangle) dpData[i].getFrameBounds()); panel.setEmbeddedDef(dpData[i].getEmbeddedDef()); panel.setEmbeddedSize(dpData[i].getEmbeddedSize()); panel.setShowStyleBar(dpData[i].showStyleBar()); panel.setOpenInFrame(dpData[i].isOpenInFrame()); // detach views which were visible, but are not in the new perspective if(panel.isVisible() && (!dpData[i].isVisible() || dpData[i].isOpenInFrame())) { app.getGuiManager().detachView(panel.getViewId()); } panel.setVisible(dpData[i].isVisible() && !dpData[i].isOpenInFrame()); if (dpData[i].getViewId() == App.VIEW_EUCLIDIAN) { ((EuclidianDockPanelW)panel).reset(); } else if (dpData[i].getViewId() == App.VIEW_EUCLIDIAN2) { ((Euclidian2DockPanelW)panel).reset(); } } } for (DockPanelW dockPanel : dockPanels) { if (!dockPanel.hasPlane() && !updated.contains(dockPanel.getViewId())) { dockPanel.setVisible(false); } } } // int panelDim; if(spData.length > 0) { DockSplitPaneW[] splitPanes = new DockSplitPaneW[spData.length]; // hm should mean HashMap<DockSplitPaneW, Integer> spw = new HashMap<DockSplitPaneW, Integer>(); HashMap<DockSplitPaneW, Integer> sph = new HashMap<DockSplitPaneW, Integer>(); // construct the split panes for(int i = 0; i < spData.length; ++i) { splitPanes[i] = new DockSplitPaneW(spData[i].getOrientation(), app); spw.put(splitPanes[i], 0); sph.put(splitPanes[i], 0); } // cascade the split panes if (rootPane != null) { Widget rootPaneParent = rootPane.getParent(); if (rootPaneParent != null) { if (rootPaneParent instanceof VerticalPanel) { rootPane.clear(); rootPane.removeFromParent(); rootPane = splitPanes[0]; ((VerticalPanel)rootPaneParent).add(rootPane); } else if (rootPaneParent instanceof DockLayoutPanel) { rootPane.clear(); rootPane.removeFromParent(); rootPane = splitPanes[0]; ((DockLayoutPanel)rootPaneParent).add(rootPane); } else { rootPane.clear(); rootPane = splitPanes[0]; } } else { rootPane.clear(); rootPane = splitPanes[0]; } } else { rootPane = splitPanes[0]; } // loop through every but the first split pane for(int i = 1; i < spData.length; ++i) { DockSplitPaneW currentParent = rootPane; // a similar system as it's used to determine the position of the dock panels (see comment in DockManager::show()) // 0: turn left/up, 1: turn right/down String[] directions = spData[i].getLocation().split(","); // get the parent split pane, the last position is reserved for the location // of the current split pane and therefore ignored here for(int j = 0; j < directions.length - 1; ++j) { if(directions[j].equals("0")) { currentParent = (DockSplitPaneW)currentParent.getLeftComponent(); } else { currentParent = (DockSplitPaneW)currentParent.getRightComponent(); } } // insert the split pane if(directions[directions.length - 1].equals("0")) { currentParent.setLeftComponentCheckEmpty(splitPanes[i]); } else { currentParent.setRightComponentCheckEmpty(splitPanes[i]); } } // now insert the dock panels for(int i = 0; i < dpData.length; ++i) { DockPanelW panel = getPanel(dpData[i].getViewId()); // skip panels which will not be drawn in the main window if(!dpData[i].isVisible() || dpData[i].isOpenInFrame() // eg run "no 3D" with 3D View open in saved settings || panel == null){ continue; } // attach view to kernel (being attached multiple times is ignored) app.getGuiManager().attachView(panel.getViewId()); //if(dpData[i].isOpenInFrame()) { // show(panel); // continue; //} DockSplitPaneW currentParent = rootPane; String[] directions = dpData[i].getEmbeddedDef().split(","); /* * Get the parent split pane of this dock panel and ignore the last * direction as its reserved for the position of the dock panel itself. * * In contrast to the algorithm used in the show() method we'll not take care * of invalid positions as the data should not be corrupted. */ for(int j = 0; j < directions.length - 1; ++j) { if(directions[j].equals("0") || directions[j].equals("3")) { currentParent = (DockSplitPaneW)currentParent.getLeftComponent(); } else { currentParent = (DockSplitPaneW)currentParent.getRightComponent(); } } if(currentParent==null){ Log.error("Invalid perspective"); currentParent = rootPane; } else if(directions[directions.length - 1].equals("0") || directions[directions.length - 1].equals("3")) { currentParent.setLeftComponentCheckEmpty(panel); } else { currentParent.setRightComponentCheckEmpty(panel); } panel.setEmbeddedSize(dpData[i].getEmbeddedSize()); panel.updatePanel(true); // this might have to belong to panel.updatePanel // maybe not needed if updatePanel is right // maybe wrong if onResize makes things wrong if (currentParent .getOrientation() == SwingConstants.VERTICAL_SPLIT) { panel.setHeight(dpData[i].getEmbeddedSize()+"px"); } else { panel.setWidth(dpData[i].getEmbeddedSize()+"px"); } if (currentParent .getOrientation() == SwingConstants.VERTICAL_SPLIT) { int panelDim = panel.getEstimatedSize().getWidth(); sph.put(currentParent, sph.get(currentParent) + dpData[i].getEmbeddedSize()); spw.put(currentParent, Math.max(spw.get(currentParent), panelDim)); } else { int panelDim = panel.getEstimatedSize().getHeight(); spw.put(currentParent, spw.get(currentParent) + dpData[i].getEmbeddedSize()); sph.put(currentParent, Math.max(sph.get(currentParent), panelDim)); } DockSplitPaneW oldParent = currentParent; while (oldParent != rootPane) { if (oldParent.getParent() instanceof DockSplitPaneW) { DockSplitPaneW otherParent = oldParent; oldParent = (DockSplitPaneW)oldParent.getParent(); if (oldParent .getOrientation() == SwingConstants.VERTICAL_SPLIT) { sph.put(oldParent, sph.get(oldParent) + dpData[i].getEmbeddedSize()); spw.put(oldParent, Math.max(spw.get(oldParent), spw.get(otherParent))); } else { spw.put(oldParent, spw.get(oldParent) + dpData[i].getEmbeddedSize()); sph.put(oldParent, Math.max(sph.get(oldParent), spw.get(otherParent))); } } else { break; } } // move toolbar to main container // if(panel.hasToolbar()) { // ToolbarContainer mainContainer = ((GuiManagerD) app.getGuiManager()).getToolbarPanel(); // mainContainer.addToolbar(getPanel(dpData[i].getViewId()).getToolbar()); // } } //recursive update resize weights for giving new space to euclidian views updateSplitPanesResizeWeight(); int windowWidth; int windowHeight; // TODO this is how the layout should work in all cases, only the // old AppWApplication needs the other way if (app instanceof AppWapplet) { // Emulate the way split panes in Java applets are sized: // 2) Use the ggb xml window size to set dividers // 1) Resize the applet to the data-param dimensions // Now find the correct applet window dimensions and resize the rootPane. windowWidth = app .getWidthForSplitPanel(spw.get(rootPane) <= 0 ? app .getPreferredSize().getWidth() : spw .get(rootPane)); // this is applet window height. Priority: applet params > split // pane sizes > guess based on overall window size (assumes // desktop toolbar) windowHeight = app .getHeightForSplitPanel(sph.get(rootPane) <= 0 ? app .getPreferredSize().getHeight() : sph .get(rootPane)); rootPane.clear(); rootPane.setPixelSize(windowWidth, windowHeight); // Set the window dimensions to the ggb xml <window> tag size. int windowWidth2 = app.getPreferredSize().getWidth(); int windowHeight2 = app.getPreferredSize().getHeight(); // Set the split pane dividers if(windowWidth2 == 0){ windowWidth2 = windowWidth; windowHeight2 = windowHeight; app.setPreferredSize(new GDimensionW(windowWidth2, windowHeight2)); } setSplitPaneDividers(spData, splitPanes, windowHeight2, windowWidth2, windowHeight, windowWidth); // for debugging // rootPane.setPixelSize(spw.get(rootPane), sph.get(rootPane)); } markAlonePanel(); setActiveToolBarDefault(dpData); // is focused dock panel not visible anymore => reset if (focusedDockPanel != null && !focusedDockPanel.isVisible()) { focusedDockPanel = null; if (focusedEuclidianDockPanel != null) { focusedEuclidianDockPanel.setEuclidianFocus(false); } focusedEuclidianDockPanel = null; } } panelsMoved = false; // update all labels at once setLabels(); } private void setPreferredSizes(DockSplitPaneW pane, int h, int w) { pane.setPreferredWidth(w, h); if (pane.getOrientation() == SwingConstants.VERTICAL_SPLIT) { if (pane.getLeftComponent() instanceof DockSplitPaneW) { setPreferredSizes((DockSplitPaneW) pane.getLeftComponent(), h, w); } if (pane.getRightComponent() instanceof DockSplitPaneW) { setPreferredSizes((DockSplitPaneW) pane.getRightComponent(), h - pane.getDividerLocation() - pane.getSplitterSize(), w); } } else { // horizontal if (pane.getLeftComponent() instanceof DockSplitPaneW) { setPreferredSizes((DockSplitPaneW) pane.getLeftComponent(), h, pane.getDividerLocation()); } if (pane.getRightComponent() instanceof DockSplitPaneW) { setPreferredSizes((DockSplitPaneW) pane.getRightComponent(), h, w - pane.getDividerLocation() - pane.getSplitterSize()); } } } @Override public void ensureFocus() { if (this.focusedDockPanel != null) { return; } boolean focusDone = false; for (int i = 0; i < dockPanels.size() && !focusDone; ++i) { if (!dockPanels.get(i).hasPlane()) { // we can't focus on // view for plane // otherwise we will // recreate it if (dockPanels.get(i) != null && dockPanels.get(i).isVisible()) { setFocusedPanel(dockPanels.get(i)); // don't like algebra view as focused view if (dockPanels.get(i).getViewId() != App.VIEW_ALGEBRA && dockPanels.get(i).getViewId() != App.VIEW_PROPERTIES) { focusDone = true; } } } } } /** * Sets split pane divider locations * * @param spData * split pane sizes * @param splitPanes * actual split panes * @param windowHeight * center pane width of original file * @param windowWidth * center pane height of original file * @param theRealWindowHeight * target center pane height (might be affected by data param) * @param theRealWindowWidth * target center pane width (might be affected by data param) */ protected void setSplitPaneDividers(DockSplitPaneData[] spData, DockSplitPaneW[] splitPanes, int windowHeight, int windowWidth, int theRealWindowHeight, int theRealWindowWidth) { double sdl = 0; int divLoc = 0; // set the dividers of the split panes for (int i = 0; i < spData.length; ++i) { splitPanes[i].clear(); // don't set splitpane width/height here, because that would call onResize sdl = spData[i].getDividerLocation(); if (Double.isNaN(sdl) || Double.isInfinite(sdl)) { // if omitted, divider locations should be computed (fixing problems in most cases, but maybe not in all) // sdl should be x that 0 <= x <= 1 sdl = splitPanes[i].computeDividerLocationRecursive(); } if (spData[i].getOrientation() == SwingConstants.VERTICAL_SPLIT) { divLoc = (int)(sdl * windowHeight); if (divLoc <= theRealWindowHeight - splitPanes[i].getSplitterSize()) { splitPanes[i].setDividerLocationSilent(divLoc); } else { splitPanes[i].setDividerLocationSilent(theRealWindowHeight - splitPanes[i].getSplitterSize()); } } else { divLoc = (int)(sdl * windowWidth); if (divLoc <= theRealWindowWidth - splitPanes[i].getSplitterSize()) { splitPanes[i].setDividerLocationSilent(divLoc); } else { splitPanes[i].setDividerLocationSilent(theRealWindowWidth - splitPanes[i].getSplitterSize()); } } } setPreferredSizes(rootPane, windowHeight, windowWidth); rootPane.setComponentsSilentRecursive(); } /** * update dispatching of new space with split panes */ private void updateSplitPanesResizeWeight(){ rootPane.updateResizeWeight(); } /** * Start the drag'n'drop process of a DockPanel. * * @param panel */ public void drag(DockPanelW panel) { // Do not allow docking in case this is the last view if(panel.getParentSplitPane() == rootPane) { if(rootPane.getOpposite(panel) == null) { return; } } if (app.getArticleElement().getDataParamShowMenuBar(false)) { DockGlassPaneW glassPane = ((AppWFull) app).getGlassPane(); if (glassPane.getArticleElement() == null) { glassPane.setArticleElement(app .getArticleElement()); } glassPane.attach(this); glassPane.startDrag(new DnDState(panel)); } } /** * Stop the drag'n'drop procedure and drop the component to the the defined * location. * * @param dndState */ public void drop(DnDState dndState) { DockPanelW source = dndState.getSource(); DockSplitPaneW sourceParent = source.getParentSplitPane(); DockPanelW target = dndState.getTarget(); Widget opposite = sourceParent.getOpposite(source); // No action required if(target == null || target == source && !dndState.isRegionOut()) { return; } // Hide the source first hide(source, false, true); source.setVisible(true); // Add the source panel at the new position DockSplitPaneW newSplitPane = new DockSplitPaneW(app); int dndRegion = dndState.getRegion(); // Determine the orientation of the new split pane if(dndRegion == DnDState.LEFT || dndRegion == DnDState.LEFT_OUT || dndRegion == DnDState.RIGHT || dndRegion == DnDState.RIGHT_OUT) { newSplitPane.setOrientation(SwingConstants.HORIZONTAL_SPLIT); } else { newSplitPane.setOrientation(SwingConstants.VERTICAL_SPLIT); } if(dndState.isRegionOut() && (target.getParent() == sourceParent || target == source)) { dndRegion >>= 4; dndState.setRegion(dndRegion); } boolean updatedRootPane = false; if(dndState.isRegionOut()) { DockSplitPaneW targetParent = target.getParentSplitPane(); if(targetParent == rootPane) { rootPane = newSplitPane; } else { ((DockSplitPaneW)targetParent.getParent()).replaceComponent(targetParent, newSplitPane); } if(dndRegion == DnDState.LEFT_OUT || dndRegion == DnDState.TOP_OUT) { newSplitPane.setRightComponent(targetParent); newSplitPane.setLeftComponent(source); } else { newSplitPane.setRightComponent(source); newSplitPane.setLeftComponent(targetParent); } } else { if(source == target) { if(opposite instanceof DockPanel) { if(((DockPanelW) opposite).getParentSplitPane().getOpposite(opposite) == null) { rootPane = newSplitPane; } else { ((DockPanelW) opposite).getParentSplitPane().replaceComponent(opposite, newSplitPane); } } else { if(opposite == rootPane) { rootPane = newSplitPane; } else { ((DockSplitPaneW)opposite.getParent()).replaceComponent(opposite, newSplitPane); } } if(dndRegion == DnDState.LEFT || dndRegion == DnDState.TOP) { newSplitPane.setRightComponent(opposite); newSplitPane.setLeftComponent(source); } else { newSplitPane.setRightComponent(source); newSplitPane.setLeftComponent(opposite); } } else if(target.getParentSplitPane().getOpposite(target) == null && target.getParentSplitPane() == rootPane) { rootPane.clear(); if(dndRegion == DnDState.LEFT || dndRegion == DnDState.TOP) { rootPane.setLeftComponent(source); rootPane.setRightComponent(target); } else { rootPane.setLeftComponent(target); rootPane.setRightComponent(source); } updatedRootPane = true; rootPane.setOrientation(newSplitPane.getOrientation()); } else { target.getParentSplitPane().replaceComponent(target, newSplitPane); if(dndRegion == DnDState.LEFT || dndRegion == DnDState.TOP) { newSplitPane.setRightComponent(target); newSplitPane.setLeftComponent(source); } else { newSplitPane.setRightComponent(source); newSplitPane.setLeftComponent(target); } } } app.updateCenterPanel(); //updatePanels(); double dividerLocation = 0; if(dndRegion == DnDState.LEFT || dndRegion == DnDState.LEFT_OUT || dndRegion == DnDState.TOP || dndRegion == DnDState.TOP_OUT) { dividerLocation = 0.4; } else { dividerLocation = 0.6; } if(updatedRootPane) { setDividerLocation(rootPane, dividerLocation); } else { setDividerLocation(newSplitPane,dividerLocation); } //update new space dispatching updateSplitPanesResizeWeight(); // add toolbar to main toolbar container if necessary if(source.hasToolbar()) { //ToolbarContainer mainContainer = ((GuiManagerW) app.getGuiManager()).getToolbarPanel(); // mainContainer.addToolbar(source.getToolbar()); // mainContainer.updateToolbarPanel(); } // has to be called *after* the toolbar was added to the container setFocusedPanel(source); unmarkAlonePanels(); markAlonePanel(); panelsMoved = true; // Manually dispatch a resize event as the size of the // euclidian view isn't updated all the time. // TODO What does the resize do which will update the component ?! //app.repaintEuclidianViews(rootPane); //rootPane.onResize(); Timer timer = new Timer() { @Override public void run() { //true, because this can only be executed, if menu is open app.getGuiManager().updateStyleBarPositions(true); } }; timer.schedule(0); } private void setDividerLocation(DockSplitPaneW splitPane, double dividerLocation) { final double dividerLoc = dividerLocation; final DockSplitPaneW sp = splitPane; Scheduler.get().scheduleDeferred(new ScheduledCommand() { @Override public void execute() { sp.setDividerLocation(dividerLoc); rootPane.deferredOnResize(); } }); } /** * Show a DockPanel identified by its ID. * * @param viewId */ public void show(int viewId) { show(getPanel(viewId)); } /** * Show a DockPanel where it was displayed the last time - either in the main window * or in a separate frame. * * The location of the DockPanel in the main window is given by the definition string * stored in DockPanelInfo.getEmbeddedDef(). * A definition string can be read like a list of directions, where numbers * represents the four directions we can go: * * 0: Top * 1: Right * 2: Bottom * 3: Left * * A definition string like "0,3,2" is read by the program this way: * - Go to the top (=0) container of the root pane. * - Go to the container at the left (=3) of the current container. * - Insert the DockPanel at the bottom (=2) of the current container. * * Note that the program differs between the top & left and bottom & right * position while the DockSplitPane just differs between a left and right * component and the orientation of the split pane. * * As the layout of the panels is changed frequently and may be completely * different if the DockPanel is inserted again, the algorithm ignores all * directions which are not existing anymore in order to get the best possible * result. * Using the example from above, the second direction ("3") may be * ignored if the top container of the root pane isn't divided anymore or the * orientation of the container was changed. The algorithm will continue with * "2" and will insert the DockPanel at the bottom of the top container * of the root pane. * * @param panel */ public void show(DockPanelW panel) { panel.setVisible(true); panel.setHidden(false); // TODO causes any problems? app.getGuiManager().attachView(panel.getViewId()); if(panel.isOpenInFrame()) { //panel.createFrame(); } else { app.persistWidthAndHeight(); // Transform the definition into an array of integers String[] def = panel.getEmbeddedDef().split(","); int[] locations = new int[def.length]; for(int i = 0; i < def.length; ++i) { if(def[i].length() == 0) { def[i] = "1"; } locations[i] = Integer.parseInt(def[i]); if(locations[i] > 3 || locations[i] < 0) { locations[i] = 3; // left as default direction } } // We insert this panel at the left by default if(locations.length == 0) { locations = new int[] { 3 }; } DockSplitPaneW currentPane = rootPane; int secondLastPos = -1; // Get the location of our new DockPanel (ignore last entry) for(int i = 0; i < locations.length - 1; ++i) { // The orientation of the current pane does not match the stored orientation, skip this if (currentPane .getOrientation() == SwingConstants.HORIZONTAL_SPLIT && (locations[i] == 0 || locations[i] == 2)) { continue; } else if (currentPane .getOrientation() == SwingConstants.VERTICAL_SPLIT && (locations[i] == 1 || locations[i] == 3)) { continue; } Widget component; if(locations[i] == 0 || locations[i] == 3) { component = currentPane.getLeftComponent(); } else { component = currentPane.getRightComponent(); } if(!(component instanceof DockSplitPaneW)) { secondLastPos = locations[i]; break; } // else currentPane = (DockSplitPaneW)component; } int size = panel.getEmbeddedSize(); int lastPos = locations[locations.length - 1]; DockSplitPaneW newSplitPane = new DockSplitPaneW(app); if(lastPos == 0 || lastPos == 2) { newSplitPane.setOrientation(SwingConstants.VERTICAL_SPLIT); } else { newSplitPane.setOrientation(SwingConstants.HORIZONTAL_SPLIT); } // the size (height / width depending upon lastPos) of the parent element, // this value is necessary to prevent panels which completely hide // their opposite element // the component opposite to the current component Widget opposite; int oppositeWidth = 0; int oppositeHeight = 0; //==================== // TODO temporary fix: //newSplitPane.setDividerLocation(size); if(secondLastPos == -1) { opposite = rootPane; oppositeWidth = opposite.getOffsetWidth(); oppositeHeight = opposite.getOffsetHeight(); rootPane = newSplitPane; // in root pane, the opposite may be null if(lastPos == 0 || lastPos == 3) { if(((DockSplitPaneW)opposite).getLeftComponent() == null) { opposite = ((DockSplitPaneW)opposite).getRightComponent(); } } else { if (((DockSplitPaneW) opposite) .getRightComponent() == null) { opposite = ((DockSplitPaneW)opposite).getLeftComponent(); } } } else { if (secondLastPos == 0 || secondLastPos == 3) { opposite = currentPane.getLeftComponent(); } else { opposite = currentPane.getRightComponent(); } // in root pane, the opposite may be null if (opposite == null) { opposite = currentPane.getOpposite(null); oppositeWidth = opposite.getOffsetWidth(); oppositeHeight = opposite.getOffsetHeight(); rootPane = newSplitPane; } else if(opposite.getParent() == rootPane && rootPane.getOpposite(opposite) == null) { oppositeWidth = opposite.getOffsetWidth(); oppositeHeight = opposite.getOffsetHeight(); rootPane = newSplitPane; } else { oppositeWidth = opposite.getOffsetWidth(); oppositeHeight = opposite.getOffsetHeight(); currentPane.replaceComponent(opposite, newSplitPane); } } newSplitPane.setPreferredWidth(oppositeWidth, oppositeHeight); //App.debug("\n"+((DockComponent) opposite).toString("opposite")); //save divider locations to prevent not visible views if (opposite != null) { ((DockComponent) opposite).saveDividerLocation(); } if(lastPos == 0 || lastPos == 3) { newSplitPane.setLeftComponent(panel); newSplitPane.setRightComponent(opposite); } else { newSplitPane.setLeftComponent(opposite); newSplitPane.setRightComponent(panel); } if(!app.isIniting()) { app.updateCenterPanel(); } //check new split pane size regarding orientation int newSplitPaneSize; if (newSplitPane .getOrientation() == SwingConstants.HORIZONTAL_SPLIT) { newSplitPaneSize=//newSplitPane.getOffsetWidth(); oppositeWidth; } else { newSplitPaneSize=//newSplitPane.getOffsetHeight(); oppositeHeight; } //check if panel size is not too large if (size+DockComponent.MIN_SIZE>newSplitPaneSize) { size = newSplitPaneSize/2; //set the divider location } //---------------- // TODO turned this off for now ... need to fix for web //--------------- if(lastPos == 0 || lastPos == 3) { newSplitPane.setDividerLocation(size); } else { newSplitPane.setDividerLocation(newSplitPaneSize - size); } //App.debug("\nnewSplitPaneSize = "+newSplitPaneSize+"\nsize = "+size); //App.debug("\n======\n"+((DockComponent) opposite).toString("")); //re dispatch divider locations to prevent not visible views if (opposite != null) { ((DockComponent) opposite).updateDividerLocation(newSplitPaneSize-size,newSplitPane.getOrientation()); } } panel.updatePanel(false); // here we need to resize both panel and opposite panel.getParentSplitPane().deferredOnResize(); //update dispatching of new space updateSplitPanesResizeWeight(); // add toolbar to main toolbar container if necessary, *has* to be called after // DockPanel::updatePanel() as the toolbar is initialized there if(!panel.isOpenInFrame() && app.isShowToolbar()) { // original // ToolbarContainer mainContainer = ((GuiManagerD) app.getGuiManager()).getToolbarPanel(); // mainContainer.addToolbar(panel.getToolbar()); // mainContainer.updateToolbarPanel(); app.setShowToolBar(true, true); app.getGuiManager().setActivePanelAndToolbar(panel.getViewId()); } // has to be called *after* the toolbar was added to the container setFocusedPanel(panel); unmarkAlonePanels(); markAlonePanel(); for (ShowDockPanelListener l:showDockPanelListener){ l.showDockPanel(panel); } } /** * Hide a dock panel identified by the view ID. * * @param viewId * @return true if succeeded to hide the panel */ public boolean hide(int viewId, boolean isPermanent) { return hide(getPanel(viewId), isPermanent, false); } /** * Hide a dock panel permanently. * * @param panel * @return true if succeeded to hide the panel */ public boolean hide(DockPanelW panel) { return hide(panel, true, false); } /** * close the dock panel * @param viewId id of the dock panel * @param isPermanent says if the close is permanent */ public void closePanel(int viewId, boolean isPermanent){ closePanel(getPanel(viewId), isPermanent); } /** * close the dock panel * @param panel dock panel * @param isPermanent says if the close is permanent */ public void closePanel(DockPanelW panel, boolean isPermanent){ if (hide(panel, isPermanent, false)){ app.updateMenubar(); if(getFocusedPanel() == panel) { setFocusedPanel(null); } } } /** * * @return true if the layout contains less than two panels */ private boolean containsLessThanTwoPanels(){ return (rootPane==null) || (rootPane.getLeftComponent()==null) || (rootPane.getRightComponent()==null); } /** * Hide a dock panel. * * @param panel * @param isPermanent If this change is permanent. * @return true if it succeeded to hide the panel */ public boolean hide(DockPanelW panel, boolean isPermanent, boolean fromDrop) { if(!panel.isVisible()) { // some views (especially CAS) will close so slowly that the user is able // to issue another "close" call, therefore we quit quietly return false; } //if panel is open in frame, check if it's not the last one if (!panel.isOpenInFrame() && containsLessThanTwoPanels()) { return false; } // do in the end, because we need to calculate width/height //panel.setHidden(!isPermanent); //panel.setVisible(false); setFocusedPanel(null); if(isPermanent) { app.getGuiManager().detachView(panel.getViewId()); } if(panel.isOpenInFrame()) { // TODO: deal with remove // panel.removeFrame(); panel.setOpenInFrame(true); // open in frame the next time } else { DockSplitPaneW parent = panel.getParentSplitPane(); int parentOffsetWidth = parent.getOffsetWidth(); int parentOffsetHeight = parent.getOffsetHeight(); app.persistWidthAndHeight(); // Save settings if (parent.getOrientation() == SwingConstants.HORIZONTAL_SPLIT) { panel.setEmbeddedSize(panel.getOffsetWidth()); } else { panel.setEmbeddedSize(panel.getOffsetHeight()); } panel.setEmbeddedDef(panel.calculateEmbeddedDef()); panel.setOpenInFrame(false); Widget opposite = parent.getOpposite(panel); //save divider location and size (if DockSplitPane) if (opposite!=null){ ((DockComponent) opposite).saveDividerLocation(); } int orientation = parent.getOrientation(); int size = 0; if (orientation == SwingConstants.VERTICAL_SPLIT) { size = parentOffsetHeight; } else { size = parentOffsetWidth; } if(parent == rootPane) { if(opposite instanceof DockSplitPaneW) { rootPane = (DockSplitPaneW) opposite; } else { parent.replaceComponent(panel, null); } app.updateCenterPanel(); } else { DockSplitPaneW grandParent = (DockSplitPaneW)parent.getParent(); int dividerLoc = grandParent.getDividerLocation(); grandParent.replaceComponent(parent, opposite); grandParent.setDividerLocation(dividerLoc); grandParent.forceLayout(); } //re dispatch divider location if (opposite!=null) { ((DockComponent) opposite).updateDividerLocation(size,orientation); } // TODO: resize here? // if(isPermanent) { // app.validateComponent(); // } if (fromDrop) { if (opposite.getParent() instanceof DockSplitPaneW) { ((DockSplitPaneW)opposite.getParent()).onResize(); } else if (opposite instanceof DockSplitPaneW) { ((DockSplitPaneW)opposite).onResize(); } } else if(opposite !=null) { if (opposite.getParent() instanceof DockSplitPaneW) { ((DockSplitPaneW)opposite.getParent()).deferredOnResize(); } else if (opposite instanceof DockSplitPaneW) { ((DockSplitPaneW)opposite).deferredOnResize(); } } if(panel.hasToolbar()) { // ToolbarContainer mainContainer = ((GuiManagerD) app.getGuiManager()).getToolbarPanel(); // mainContainer.removeToolbar(panel.getToolbar()); // mainContainer.updateToolbarPanel(); app.setShowToolBar(true, true); // active toolbar should not be the panel's any more if (app.getGuiManager().getActiveToolbarId() == panel.getViewId()) { setActiveToolBarDefault(null); } } app.getGuiManager().refreshCustomToolsInToolBar(); app.updateToolBar(); } panel.setHidden(!isPermanent); panel.setVisible(false); markAlonePanel(); return true; } private TreeSet<Integer> viewsInPerspective = new TreeSet<Integer>(); /** * set active toolbar to default */ private void setActiveToolBarDefault(DockPanelData[] dpData) { GuiManagerInterfaceW guiManager = app.getGuiManager(); // default int toolbarID = App.VIEW_EUCLIDIAN; if (dpData != null) { viewsInPerspective.clear(); for (int i = 0; i < dpData.length; i++) { if (dpData[i].isVisible() && !dpData[i].isOpenInFrame()) { viewsInPerspective.add(dpData[i].getViewId()); } } if (viewsInPerspective.contains(App.VIEW_CAS)) { toolbarID = App.VIEW_CAS; } else if (viewsInPerspective.contains(App.VIEW_SPREADSHEET)) { toolbarID = App.VIEW_SPREADSHEET; } else if (viewsInPerspective.contains(App.VIEW_EUCLIDIAN)) { toolbarID = App.VIEW_EUCLIDIAN; } else if (viewsInPerspective.contains(App.VIEW_EUCLIDIAN2)) { toolbarID = App.VIEW_EUCLIDIAN2; } else if (viewsInPerspective.contains(App.VIEW_EUCLIDIAN3D)) { toolbarID = App.VIEW_EUCLIDIAN3D; } else if (viewsInPerspective .contains(App.VIEW_PROBABILITY_CALCULATOR)) { toolbarID = App.VIEW_PROBABILITY_CALCULATOR; } } // show CAS-toolbar in CAS-perspective (same for Spreadsheet) // in the other perspectives use Euclidian-toolbar (if available) else if (guiManager.hasCasView() && getPanel(App.VIEW_CAS) != null && getPanel(App.VIEW_CAS).isVisible()) { toolbarID = App.VIEW_CAS; } else if (guiManager.hasSpreadsheetView() && getPanel(App.VIEW_SPREADSHEET) != null && getPanel(App.VIEW_SPREADSHEET).isVisible()) { toolbarID = App.VIEW_SPREADSHEET; } else if (app.getEuclidianView1().isShowing()) { toolbarID = App.VIEW_EUCLIDIAN; } else if (app.hasEuclidianView2(1) && app.getEuclidianView2(1).isShowing()) { toolbarID = App.VIEW_EUCLIDIAN2; } else if (app.hasEuclidianView3D() && app.showView(App.VIEW_EUCLIDIAN3D)) { toolbarID = App.VIEW_EUCLIDIAN3D; // what else can it be?? } else if (guiManager.hasProbabilityCalculator() && app.getGuiManager().getProbabilityCalculator().isShowing()) { toolbarID = App.VIEW_PROBABILITY_CALCULATOR; } else if (guiManager.hasAlgebraView() && app.getGuiManager().getAlgebraView().isShowing()) { // algebra view has no toolbar! toolbarID = App.VIEW_ALGEBRA; } guiManager.setActivePanelAndToolbar(toolbarID); } /** * Listen to mouse clicks and determine if the view focus changed. Just * used in case the full focus system is active. * * Euclidian views always inform the dock manager about focus changes using * their own mouse click events (see EuclidianController:mouseClicked()) because * 1) This AWT event cannot be used for unsigned applets but we need euclidian * view focus changes for new object placement * 2) An own mouse listener may be called *after* the euclidian controller * mouse listener was called, therefore new objects may be created in the wrong * euclidian view as the focus was not changed at the time of object creation. */ /* public void eventDispatched(AWTEvent event) { // we also get notified about other mouse events, but we want to ignore them if(event.getID() != MouseEvent.MOUSE_CLICKED) { // App.debug(event); return; } // determine ancestor element of the event source which is of type // dock panel Component source = (Component)event.getSource(); //App.debug(" source: " + source); DockPanel dp = (DockPanel)SwingUtilities.getAncestorOfClass(DockPanel.class, source); // ignore this if we didn't hit a dock panel at all or if we hit the euclidian // view, they are always handled by their own mouse event (see doc comment above) if(dp != null && !(dp.getComponent() instanceof EuclidianViewJPanel)) { //updates the properties view only if source is not the euclidian style bar boolean updatePropertiesView = true; if (source instanceof EuclidianStyleBar) updatePropertiesView=false; else if (SwingUtilities.getAncestorOfClass(EuclidianStyleBar.class, source)!=null) updatePropertiesView=false; setFocusedPanel(dp, updatePropertiesView); } } */ /** * Change the focused panel to "panel". * * @param panel panel */ public void setFocusedPanel(DockPanel panel) { setFocusedPanel(panel, true); } /** * Change the focused panel to "panel". TODO: partly unimplemented * * @param panel panel * @param updatePropertiesView update the properties view */ public void setFocusedPanel(DockPanel panel, boolean updatePropertiesView) { if(focusedDockPanel == panel) { return; } // euclidian focus // in case there is no focused panel there is also no focused euclidian // dock panel if(panel == null) { if(focusedEuclidianDockPanel != null) { focusedEuclidianDockPanel.setEuclidianFocus(false); // if (focusedEuclidianDockPanel != focusedDockPanel) // focusedEuclidianDockPanel.setTitleLabelFocus(); focusedEuclidianDockPanel = null; } }else{ if(panel instanceof EuclidianDockPanelWAbstract && focusedEuclidianDockPanel != panel) { // remove focus from previously focused dock panel if(focusedEuclidianDockPanel != null) { focusedEuclidianDockPanel.setEuclidianFocus(false); // if (focusedEuclidianDockPanel != focusedDockPanel) // focusedEuclidianDockPanel.setTitleLabelFocus(); } // if a panel has focus and that panel is a euclidian dock panel // change the focused euclidian dock panel to that panel focusedEuclidianDockPanel = (EuclidianDockPanelWAbstract) panel; focusedEuclidianDockPanel.setEuclidianFocus(true); // (panels which are not euclidian dock panels do not change the focused // euclidian dock panel (ie the old is kept)) } } // remove focus from previously focused dock panel if(focusedDockPanel != null) { focusedDockPanel.setFocus(false, false); } focusedDockPanel = (DockPanelW)panel; if(focusedDockPanel != null) { focusedDockPanel.setFocus(true, updatePropertiesView); Log.debug("FOCUSCHANGE: " + focusedDockPanel.getViewId()); } app.getGuiManager().updateMenubarSelection(); //if(focusedDockPanel != null && panel.isInFrame()){ // panel.getFrame().toFront(); //} } /** * Changes the focused panel to the dock panel with ID viewId. * Uses {@link DockManagerW#setFocusedPanel(DockPanel)} internally * but adds some validation checks. * * @param viewId * @return true if focus was changed, false if the requested dock panel does * not exist or is invisible at the moment */ @Override public boolean setFocusedPanel(int viewId) { DockPanelW dockPanel = getPanel(viewId); if(dockPanel != null && dockPanel.isVisible()) { setFocusedPanel(dockPanel); return true; } // else return false; } /** * @return The dock panel which has focus at the moment. */ public DockPanelW getFocusedPanel() { return focusedDockPanel; } /** * @return The viewId of the dock panel which has focus at the moment. */ @Override public int getFocusedViewId() { if (focusedDockPanel == null) { return -1; } return focusedDockPanel.getViewId(); } /** * @return The dock euclidian panel which had focus the last. */ @Override public EuclidianDockPanelWAbstract getFocusedEuclidianPanel() { return focusedEuclidianDockPanel; } /** * Moves the focus between visible panels. Just the register order is taken * into consideration here, so the focus changing order does not depend upon * the visual order. * * @param forward If the next or previous panel should be focused, * calling this method once with both possibilities will cancel out * the effect so to say. */ public void moveFocus(boolean forward) { if(focusedDockPanel == null) { return; } // to follow the DRY principle we'll use a single iterator for both // forward and backward iteration Iterator<DockPanelW> it = getForwardBackwardIterator(forward); // if the focused dock panel was found already boolean foundFocused = false; boolean changedFocus = false; while(it.hasNext()) { DockPanelW panel = it.next(); // all we do for now on just takes visible dock panels // into consideration if(panel.isVisible()) { // we already found the focused dock panel, so this is the // new panel to focus if(foundFocused) { setFocusedPanel(panel); changedFocus = true; break; } // is this the focused dock panel? else if(panel == focusedDockPanel) { foundFocused = true; } else { // we have not reached the focused dock panel, therefore // we do nothing } } } // if just invisible dock panels (or none) followed the focused dock panel we have // not changed the focus so far, so we go through our list from the beginning if(!changedFocus) { // recreate our iterator as we can't reset it it = getForwardBackwardIterator(forward); while(it.hasNext()) { DockPanelW panel = it.next(); if(panel.isVisible()) { // quit if we reached the focused panel until we found another // visible panel if(panel == focusedDockPanel) { break; } // change panel // else setFocusedPanel(panel); changedFocus = true; break; } } } } /** * If just one panel is visible in the main frame, mark him as 'alone'. */ private void markAlonePanel() { // determine if such a panel exists DockPanelW singlePanel = null; if(rootPane.getRightComponent() == null) { Widget leftComponent = rootPane.getLeftComponent(); if (leftComponent instanceof DockPanel) { singlePanel = (DockPanelW)leftComponent; } } if(rootPane.getLeftComponent() == null) { Widget rightComponent = rootPane.getRightComponent(); if (rightComponent instanceof DockPanel) { singlePanel = (DockPanelW)rightComponent; } } // mark the found panel as 'alone' if(singlePanel != null) { singlePanel.setAlone(true); } } /** * Remove marks from any panel, that it might be alone. */ private void unmarkAlonePanels() { for(DockPanelW panel : dockPanels) { if(panel.isAlone()) { panel.setAlone(false); } } } /** * Helper method to create an iterator which either iterates forward or * backward through the dock panel list. * * @param forward If the returned iterator should return forward or backward * @return The iterator */ private Iterator<DockPanelW> getForwardBackwardIterator(boolean forward) { if(forward) { return dockPanels.iterator(); } final ListIterator<DockPanelW> original = dockPanels.listIterator(dockPanels.size()); // we create our own iterator which iterates through our list in // reversed order return new Iterator<DockPanelW>() { @Override public void remove() { original.remove(); } @Override public DockPanelW next() { return original.previous(); } @Override public boolean hasNext() { return original.hasPrevious(); } }; } /** * Update the labels of all DockPanels. */ @Override public void setLabels() { for(DockPanelW panel : dockPanels) { panel.updateLabels(); } for(DockPanelW panel : dockPanels) { panel.buildToolbarGui(); } } /** * Update the glass pane */ public void updateGlassPane() { // if(!app.isApplet() && glassPane.getParent() != null) { // app.setGlassPane(glassPane); // } } /** * Update the titles of the frames as they contain the file name of the current * document. */ public void updateTitles() { // for(DockPanel panel : dockPanels) { //panel.updateTitle(); // } } /** * Update all DockPanels. * * This is required if the user changed whether the title bar should be displayed or not. * * @see #setLabels() */ public void updatePanels() { for(DockPanelW panel : dockPanels) { panel.updatePanel(false); } } /** * Change the toolbar mode for all toolbars in external frames. * * @param mode */ public void setToolbarMode(int mode) { // for(DockPanelW panel : dockPanels) { // panel.setToolbarMode(mode); // } } /** * Update the fonts in all dock panels. */ public void updateFonts() { for(DockPanelW panel : dockPanels) { panel.updateFonts(); } for(DockPanelW panel : dockPanels) { panel.buildToolbarGui(); } } /** * Scale the split panes based upon the given X and Y scale. This is used to keep relative * dimensions of the split panes if the user is switching between applet and frame mode. * * @param scaleX * @param scaleY */ public void scale(double scaleX, double scaleY) { scale(scaleX, scaleY, rootPane); } private void scale(double scaleX, double scaleY, DockSplitPaneW splitPane) { splitPane.setDividerLocation((int) (splitPane.getDividerLocation() * (splitPane.getOrientation() == SwingConstants.VERTICAL_SPLIT ? scaleX : scaleY))); if(splitPane.getLeftComponent() != null && splitPane.getLeftComponent() instanceof DockSplitPaneW) { scale(scaleX, scaleY, (DockSplitPaneW)splitPane.getLeftComponent()); } if(splitPane.getRightComponent() != null && splitPane.getRightComponent() instanceof DockSplitPaneW) { scale(scaleX, scaleY, (DockSplitPaneW)splitPane.getRightComponent()); } } /** * @return GeoGebraLayout instance */ public LayoutW getLayout() { return layout; } /** * @return The glass pane which is used to draw the preview rectangle if the user dragged * a DockPanel. */ //public DockGlassPane getGlassPane() { // return glassPane; // } /** * * @param viewId constant VIEW_EUCLIDIAN, VIEW_ALGEBRA, or VIEW_FOR_PLANE * @param plane plane when for euclidian view for plane * @return a DockPanel */ public DockPanelW getPanel(DockPanelData dpData) { if (dpData.getPlane()==null) { return getPanel(dpData.getViewId()); } //euclidian view for plane case DockPanelW panel = (DockPanelW) app.getCompanion().createEuclidianDockPanelForPlane(dpData.getViewId(), dpData.getPlane()); if (panel==null){ Log.error("panel==null"); return null; } //set the view id of the dock panel data for apply perspective dpData.setViewId(panel.getViewId()); return panel; } /** * Returns a specific DockPanel. * * Use the constants VIEW_EUCLIDIAN, VIEW_ALGEBRA etc. as viewId. * * @param viewId * @return The panel associated to the viewId */ @Override public DockPanelW getPanel(int viewId) { DockPanelW panel = null; for(DockPanelW dockPanel : dockPanels) { if(dockPanel.getViewId() == viewId) { panel = dockPanel; break; } } return panel; } /** * @return All dock panels */ public DockPanelW[] getPanels() { return dockPanels.toArray(new DockPanelW[0]); } /** * @return The root split pane which contains all other elements like DockPanels or * DockSplitPanes. */ public DockSplitPaneW getRoot() { return rootPane; } /** * re-initializes root panel if needed * * @param panel * The app frame */ public void init(Panel panel) { if (rootPane == null) { rootPane = new DockSplitPaneW(app); } if (rootPane.getParent() == null) { panel.add(rootPane); } panelsMoved = false; } /** * @return True if all focus may change between all views, false if just * the euclidian views are affected by this. */ public boolean hasFullFocusSystem() { return hasFullFocusSystem; } private double kbHeight = 0; public void addShowDockPanelListener(ShowDockPanelListener l){ showDockPanelListener.add(l); } public void enableDragging(boolean drag) { for (int i = 0; i < getPanels().length; i++) { getPanels()[i].enableDragging(drag); } } @Override public void resizePanels() { for (int i = 0; i < getPanels().length; i++) { getPanels()[i].onResize(); } } public DockPanelW getPanelForKeyboard() { DockPanelW panel = getFocusedPanel(); if (panel == null || (panel.getViewId() != App.VIEW_ALGEBRA && panel.getViewId() != App.VIEW_CAS && (!app.has(Feature.SHOW_ONE_KEYBOARD_BUTTON_IN_FRAME) || (panel.getViewId() != App.VIEW_SPREADSHEET && panel .getViewId() != App.VIEW_PROBABILITY_CALCULATOR)))) { panel = getPanel(App.VIEW_ALGEBRA); if (!panel.isVisible()) { panel = getPanel(App.VIEW_CAS); if (!panel.isVisible()) { panel = getPanel(App.VIEW_ALGEBRA); } } } return panel; } @Override public int getNumberOfOpenViews() { int num = 0; for (DockPanelW d : this.dockPanels) { if (d.isVisible()) { num++; } } return num; } public AppW getApp() { return app; } @Override public void adjustViews() { DockPanelW avPanel = getPanel(App.VIEW_ALGEBRA); if (avPanel != null) { avPanel.onResize(); } if (!app.canResize() || panelsMoved) { return; } calculateKeyboardHeight(); final boolean portrait = app.getWidth() < app.getHeight(); final double landscape = PerspectiveDecoder .landscapeRatio(app.getWidth()); Scheduler.get().scheduleDeferred(new ScheduledCommand() { @Override public void execute() { adjustViews(portrait, landscape); } }); } /** * @param portrait * whether the format is portrait * @param landscapeRatio * preferred landscape ratio */ protected void adjustViews(boolean portrait, double landscapeRatio) { if (!app.has(Feature.ADJUST_VIEWS)) { return; } DockPanelW avPanel = getPanel(App.VIEW_ALGEBRA); if (avPanel == null) { Log.debug("[WGT] No AV panel to flip."); return; } DockSplitPaneW split = avPanel.getParentSplitPane(); if (split == null || split != getRoot()) { Log.debug("[WGT] No opposite"); return; } Widget opposite = split.getOpposite(avPanel); if (!(opposite instanceof EuclidianPanelWAbstract)) { return; } AlgebraViewW av = ((AlgebraViewW) app.getAlgebraView()); double avHeight = kbHeight; if (!app.has(Feature.NEW_TOOLBAR)) { avHeight += av.getInputTreeItem().getOffsetHeight(); } double portraitDivider = avHeight / app.getHeight(); split.clear(); setDividerLocation(split, portrait ? 1 - portraitDivider : landscapeRatio); split.setOrientation(portrait ? SwingConstants.VERTICAL_SPLIT : SwingConstants.HORIZONTAL_SPLIT); if (portrait) { split.setRightComponent(avPanel); split.setLeftComponent(opposite); } else { split.setLeftComponent(avPanel); split.setRightComponent(opposite); } } private void calculateKeyboardHeight() { double kh = app.getAppletFrame().getKeyboardHeight(); if (kh == 0) { kh = DEFAULT_KEYBOARD_HEIGHT; } if (kbHeight < kh) { kbHeight = kh; } } }