blob: cb42062333bce8de3bf37f9b638fb2b048d49a45 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.core.windows;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.KeyboardFocusManager;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.SwingUtilities;
import org.netbeans.core.windows.model.DockingStatus;
import org.netbeans.core.windows.model.Model;
import org.netbeans.core.windows.model.ModelElement;
import org.netbeans.core.windows.model.ModelFactory;
import org.netbeans.core.windows.options.WinSysPrefs;
import org.netbeans.core.windows.view.ControllerHandler;
import org.netbeans.core.windows.view.View;
import org.netbeans.core.windows.view.dnd.TopComponentDraggable;
import org.openide.windows.Mode;
import org.openide.windows.TopComponent;
import org.openide.windows.WindowManager;
/**
* This class is a central unit of window system. It controls communication
* flows to model, to view, from controller and from API calls.
*
* @author Peter Zavadsky
*/
final class Central implements ControllerHandler {
/** Model of window system. */
private final Model model = ModelFactory.createWindowSystemModel();
/** Helper class for managing requests to view. */
private final ViewRequestor viewRequestor = new ViewRequestor(this);
private ModeImpl modeBeingMaximized = null;
/** Constructor. */
public Central() {
}
public void topComponentRequestAttention (ModeImpl mode, TopComponent tc) {
String modeName = getModeName(mode);
viewRequestor.scheduleRequest (
new ViewRequest(modeName, View.TOPCOMPONENT_REQUEST_ATTENTION, tc, tc));
}
public void topComponentCancelRequestAttention (ModeImpl mode, TopComponent tc) {
String modeName = getModeName(mode);
viewRequestor.scheduleRequest (
new ViewRequest(modeName, View.TOPCOMPONENT_CANCEL_REQUEST_ATTENTION, tc, tc));
}
/**
* Turns tab highlight on/off
* @param mode
* @param tc
* @param highlight
* @since 2.54
*/
public void topComponentAttentionHighlight (ModeImpl mode, TopComponent tc, boolean highlight) {
String modeName = getModeName(mode);
viewRequestor.scheduleRequest (
new ViewRequest(modeName, highlight ? View.TOPCOMPONENT_ATTENTION_HIGHLIGHT_ON
: View.TOPCOMPONENT_ATTENTION_HIGHLIGHT_OFF, tc, tc));
}
/////////////////////
// Mutators >>
/** Sets visible or invisible window system and requests view accordingly. */
public void setVisible(boolean visible) {
if(isVisible() == visible) {
return;
}
model.setVisible(visible);
viewRequestor.scheduleRequest(
new ViewRequest(null, View.CHANGE_VISIBILITY_CHANGED, null, Boolean.valueOf(visible)));
}
/** Sets main window bounds (joined[tiled] state) into model and requests view (if needed). */
public void setMainWindowBoundsJoined(Rectangle mainWindowBoundsJoined) {
if(mainWindowBoundsJoined == null) {
return;
}
Rectangle old = getMainWindowBoundsJoined();
if(old.equals(mainWindowBoundsJoined)) {
return;
}
model.setMainWindowBoundsJoined(mainWindowBoundsJoined);
if(isVisible()) {
viewRequestor.scheduleRequest(
new ViewRequest(null, View.CHANGE_MAIN_WINDOW_BOUNDS_JOINED_CHANGED,
old, mainWindowBoundsJoined));
}
}
/** Sets main window bounds (separated state) into model and requests view (if needed). */
public void setMainWindowBoundsSeparated(Rectangle mainWindowBoundsSeparated) {
if(mainWindowBoundsSeparated == null) {
return;
}
Rectangle old = getMainWindowBoundsSeparated();
if(old.equals(mainWindowBoundsSeparated)) {
return;
}
model.setMainWindowBoundsSeparated(mainWindowBoundsSeparated);
if(isVisible()) {
viewRequestor.scheduleRequest(
new ViewRequest(null, View.CHANGE_MAIN_WINDOW_BOUNDS_SEPARATED_CHANGED,
old, mainWindowBoundsSeparated));
}
}
public void setMainWindowFrameStateJoined(int frameState) {
int old = getMainWindowFrameStateJoined();
if(old == frameState) {
return;
}
model.setMainWindowFrameStateJoined(frameState);
if(isVisible()) {
viewRequestor.scheduleRequest(new ViewRequest(null, View.CHANGE_MAIN_WINDOW_FRAME_STATE_JOINED_CHANGED,
Integer.valueOf(old), Integer.valueOf(frameState)));
}
}
public void setMainWindowFrameStateSeparated(int frameState) {
int old = getMainWindowFrameStateSeparated();
if(old == frameState) {
return;
}
model.setMainWindowFrameStateSeparated(frameState);
if(isVisible()) {
viewRequestor.scheduleRequest(new ViewRequest(null, View.CHANGE_MAIN_WINDOW_FRAME_STATE_SEPARATED_CHANGED,
Integer.valueOf(old), Integer.valueOf(frameState)));
}
}
/** Sets active mode into model and requests view (if needed). */
public void setActiveMode(final ModeImpl activeMode) {
//#87843: Do not activate mode when it does not contain any opened TC
if (activeMode != null) {
List<TopComponent> l = activeMode.getOpenedTopComponents();
if (l.isEmpty()) {
return;
}
}
final ModeImpl old = getActiveMode();
if(activeMode == old) {
// kind of workaround to the scenario when a window slides out automatically
// and user clicks in the currently active mode, not allow to exit in such case and fire changes to
// force the slided-out window to disappear.
ModeImpl impl = model.getSlidingMode(Constants.BOTTOM);
boolean bottom = (impl == null || impl.getSelectedTopComponent() == null);
impl = model.getSlidingMode(Constants.LEFT);
boolean left = (impl == null || impl.getSelectedTopComponent() == null);
impl = model.getSlidingMode(Constants.RIGHT);
boolean right = (impl == null || impl.getSelectedTopComponent() == null);
impl = model.getSlidingMode(Constants.TOP);
boolean top = (impl == null || impl.getSelectedTopComponent() == null);
if (bottom && left && right && top) {
return;
}
}
model.setActiveMode(activeMode);
if(isVisible()) {
viewRequestor.scheduleRequest(
new ViewRequest(null, View.CHANGE_ACTIVE_MODE_CHANGED,
old, activeMode));
}
WindowManagerImpl.getInstance().doFirePropertyChange(
WindowManagerImpl.PROP_ACTIVE_MODE, old, activeMode);
// Notify registry.
// active mode can be null, Active mode info is stored in winsys config (system layer) and modes in
// project layer, that can cause out of synch state when switching projects.
// all subsequent calls should handle the null value correctly.
if (activeMode != null) {
WindowManagerImpl.notifyRegistryTopComponentActivated(
activeMode.getSelectedTopComponent());
} else {
WindowManagerImpl.notifyRegistryTopComponentActivated(null);
}
}
/** Sets editor area bounds into model and requests view (if needed). */
public void setEditorAreaBounds(Rectangle editorAreaBounds) {
if(editorAreaBounds == null) {
return;
}
Rectangle old = getEditorAreaBounds();
if(old.equals(editorAreaBounds)) {
return;
}
model.setEditorAreaBounds(editorAreaBounds);
if(isVisible()) {
viewRequestor.scheduleRequest(
new ViewRequest(null, View.CHANGE_EDITOR_AREA_BOUNDS_CHANGED,
old, editorAreaBounds));
}
}
/** Sets editor area constraints into model and requests view (if needed). */
public void setEditorAreaConstraints(SplitConstraint[] editorAreaConstraints) {
SplitConstraint[] old = getEditorAreaConstraints();
if(Arrays.equals(old, editorAreaConstraints)) {
return;
}
model.setEditorAreaConstraints(editorAreaConstraints);
if(isVisible()) {
viewRequestor.scheduleRequest(
new ViewRequest(null, View.CHANGE_EDITOR_AREA_CONSTRAINTS_CHANGED,
old, editorAreaConstraints));
}
}
/** Sets editor area state into model and requests view (if needed). */
public void setEditorAreaState(int editorAreaState) {
int old = getEditorAreaState();
if(editorAreaState == old) {
return;
}
int requiredState = editorAreaState == Constants.EDITOR_AREA_JOINED
? Constants.MODE_STATE_JOINED
: Constants.MODE_STATE_SEPARATED;
for(Iterator it = getModes().iterator(); it.hasNext(); ) {
ModeImpl mode = (ModeImpl)it.next();
if(mode.getKind() == Constants.MODE_KIND_VIEW
&& mode.getState() != requiredState) {
model.setModeState(mode, requiredState);
// Adjust bounds if necessary.
if(editorAreaState == Constants.EDITOR_AREA_SEPARATED) {
Rectangle bounds = model.getModeBounds(mode);
if(bounds.isEmpty()) {
model.setModeBounds(mode, model.getModeBoundsSeparatedHelp(mode));
}
}
}
// when switching to SDI, undock sliding windows
// #51992 -start
if (mode.getKind() == Constants.MODE_KIND_SLIDING && editorAreaState == Constants.EDITOR_AREA_SEPARATED) {
TopComponent[] tcs = mode.getTopComponents();
for (int i = 0; i < tcs.length;i++) {
String tcID = WindowManagerImpl.getInstance().findTopComponentID(tcs[i]);
ModeImpl targetMode = model.getModeTopComponentPreviousMode(mode, tcID);
if ((targetMode == null) || !model.getModes().contains(targetMode)) {
SplitConstraint[] constraints = model.getModeTopComponentPreviousConstraints(mode, tcID);
constraints = constraints == null ? new SplitConstraint[0] : constraints;
// create mode to dock topcomponent back into
targetMode = WindowManagerImpl.getInstance().createModeImpl(
ModeImpl.getUnusedModeName(), Constants.MODE_KIND_VIEW, false);
model.setModeState(targetMode, requiredState);
model.addMode(targetMode, constraints);
}
moveTopComponentIntoMode(targetMode, tcs[i] );
}
}
// #51992 - end
}
if(editorAreaState == Constants.EDITOR_AREA_SEPARATED) {
Rectangle editorAreaBounds = model.getEditorAreaBounds();
// Adjust bounds if necessary.
if(editorAreaBounds.isEmpty()) {
model.setEditorAreaBounds(model.getEditorAreaBoundsHelp());
}
// Adjust bounds if necessary.
Rectangle mainWindowBoundsSeparated = model.getMainWindowBoundsSeparated();
if(mainWindowBoundsSeparated.isEmpty()) {
model.setMainWindowBoundsSeparated(model.getMainWindowBoundsSeparatedHelp());
}
}
model.setEditorAreaState(editorAreaState);
if(isVisible()) {
viewRequestor.scheduleRequest(
new ViewRequest(null, View.CHANGE_EDITOR_AREA_STATE_CHANGED,
Integer.valueOf(old), Integer.valueOf(editorAreaState)));
}
WindowManagerImpl.getInstance().doFirePropertyChange(
WindowManagerImpl.PROP_EDITOR_AREA_STATE, Integer.valueOf(old), Integer.valueOf(editorAreaState));
}
public void setEditorAreaFrameState(int frameState) {
int old = getEditorAreaFrameState();
if(old == frameState) {
return;
}
model.setEditorAreaFrameState(frameState);
if(isVisible()) {
viewRequestor.scheduleRequest(new ViewRequest(null, View.CHANGE_EDITOR_AREA_FRAME_STATE_CHANGED,
Integer.valueOf(old), Integer.valueOf(frameState)));
}
}
/** Sets new maximized mode into model and requests view update (if needed). */
void switchMaximizedMode(ModeImpl newMaximizedMode) {
ModeImpl old = getCurrentMaximizedMode();
if(newMaximizedMode == old) {
return;
}
WindowManagerImpl wm = WindowManagerImpl.getInstance();
if( null == newMaximizedMode ) {
//cancel current maximized mode
if( isViewMaximized() ) {
//some non-editor TopComponent is currently maximized
//restore docking status of other components
if( isEditorMaximized() ) {
restoreViews( model.getMaximizedDockingStatus() );
} else {
restoreViews( model.getDefaultDockingStatus() );
}
//return the maximized TopComponent to its original mode
ModeImpl currentMaximizedMode = getViewMaximizedMode();
if( currentMaximizedMode.getTopComponents().length == 1 ) {
TopComponent maximizedTC = currentMaximizedMode.getTopComponents()[0];
String tcID = wm.findTopComponentID( maximizedTC );
//find the mode where the TopComponent was before its maximization
ModeImpl prevMode = getModeTopComponentPreviousMode( tcID, currentMaximizedMode );
int prevIndex = model.getModeTopComponentPreviousIndex( currentMaximizedMode, tcID );
if( null == prevMode ) {
//TODO log a warning here because we somehow lost the previous mode
if ((prevMode == null) || !model.getModes().contains(prevMode)) {
// mode to return to isn't valid anymore, try constraints
SplitConstraint[] constraints = model.getModeTopComponentPreviousConstraints(currentMaximizedMode, tcID);
if (constraints != null) {
// create mode with the same constraints to dock topcomponent back into
prevMode = WindowManagerImpl.getInstance().createModeImpl(
ModeImpl.getUnusedModeName(), Constants.MODE_KIND_VIEW, false);
model.addMode(prevMode, constraints);
}
}
if (prevMode == null) {
// fallback, previous saved mode not found somehow, use default modes
prevMode = WindowManagerImpl.getInstance().getDefaultViewMode();
}
}
prevMode.addOpenedTopComponent( maximizedTC, prevIndex );
prevMode.setSelectedTopComponent( maximizedTC );
setActiveMode(prevMode);
model.removeMode( currentMaximizedMode );
} else {
Logger.getLogger( Central.class.getName() ).log( Level.WARNING,
"A 'view' mode is maximized but it has wrong number of TopComponents, Mode=["
+ currentMaximizedMode.getName() + "], TC count=" + currentMaximizedMode.getTopComponents().length );
}
//cancel the maximized mode
setViewMaximizedMode( null );
} else if( isEditorMaximized() ) {
//an editor TopComponent is maximized
model.getMaximizedDockingStatus().mark();
ModeImpl prevActiveMode = getActiveMode();
//restore the docking status of other components
restoreViews( model.getDefaultDockingStatus() );
//cancel the maximized mode
setEditorMaximizedMode( null );
setActiveMode( prevActiveMode );
}
} else {
assert !isViewMaximized();
//set new maximized mode
if( newMaximizedMode.getKind() == Constants.MODE_KIND_EDITOR ) {
//the new maximized mode is an editor TopComponent
//remember the current docking status of opened TopComponents
model.getDefaultDockingStatus().mark();
//slide-out/dock some TopComponents according to their previous state in maximized mode
restoreViews( model.getMaximizedDockingStatus() );
setEditorMaximizedMode( newMaximizedMode );
} else if( newMaximizedMode.getKind() == Constants.MODE_KIND_VIEW ) {
//the new maximized mode is non-editor TopComponent
//get the TopComponent that will be maximized
TopComponent tcToMaximize = newMaximizedMode.getSelectedTopComponent();
if( null == tcToMaximize ) {
if( newMaximizedMode.getOpenedTopComponents().isEmpty() ) {
return;
}
tcToMaximize = newMaximizedMode.getOpenedTopComponents().get(0);
}
//remember the docking status of opened components
if( isEditorMaximized() ) {
model.getMaximizedDockingStatus().mark();
} else {
model.getDefaultDockingStatus().mark();
}
modeBeingMaximized = newMaximizedMode;
String tcID = wm.findTopComponentID( tcToMaximize );
int prevIndex = newMaximizedMode.getOpenedTopComponents().indexOf( tcToMaximize );
//create a new mode for the maximization
ModeImpl mode = WindowManagerImpl.getInstance().createModeImpl(ModeImpl.getUnusedModeName(), Constants.MODE_KIND_VIEW, true);
model.addMode(mode, new SplitConstraint[0]);
//the mode has just one TopComponent
mode.addOpenedTopComponent( tcToMaximize );
mode.setSelectedTopComponent( tcToMaximize );
//remember where to put the TopComponent back when un-maximizing
setModeTopComponentPreviousMode( tcID, mode, newMaximizedMode, prevIndex );
setViewMaximizedMode( mode );
//slide-out all other TopComponents (the editor area won't be visible)
slideAllViews();
setActiveMode( mode );
modeBeingMaximized = null;
} else {
throw new IllegalArgumentException( "Cannot maximize a sliding view" );
}
}
if(isVisible()) {
viewRequestor.scheduleRequest(
new ViewRequest(null, View.CHANGE_MAXIMIZED_MODE_CHANGED,
old, getCurrentMaximizedMode()));
}
WindowManagerImpl.getInstance().doFirePropertyChange(
WindowManagerImpl.PROP_MAXIMIZED_MODE, old, getCurrentMaximizedMode());
}
/** Sets editor mode that is currenlty maximized (used when the window system loads) */
void setEditorMaximizedMode(ModeImpl editorMaximizedMode) {
model.setEditorMaximizedMode( editorMaximizedMode );
}
/** Sets view mode that is currenlty maximized (used when the window system loads) */
void setViewMaximizedMode(ModeImpl viewMaximizedMode) {
model.setViewMaximizedMode( viewMaximizedMode );
}
/** Sets constraints for mode into model and requests view (if needed). */
public void setModeConstraints(ModeImpl mode, SplitConstraint[] modeConstraints) {
SplitConstraint[] old = getModeConstraints(mode);
if(Arrays.equals(modeConstraints, old)) {
return;
}
model.setModeConstraints(mode, modeConstraints);
if(isVisible()) {
viewRequestor.scheduleRequest(
new ViewRequest(null, View.CHANGE_MODE_CONSTRAINTS_CHANGED,
old, modeConstraints));
}
}
/** Adds mode into model and requests view (if needed). */
public void addMode(ModeImpl mode, SplitConstraint[] modeConstraints) {
// PENDING which one to use?
// if(getModes().contains(mode)) {
// return;
// }
SplitConstraint[] old = getModeConstraints(mode);
if(modeConstraints == old) {
return;
}
model.addMode(mode, modeConstraints);
if(isVisible()) {
viewRequestor.scheduleRequest(
new ViewRequest(null, View.CHANGE_MODE_ADDED, null, mode));
}
WindowManagerImpl.getInstance().doFirePropertyChange(
WindowManager.PROP_MODES, null, null);
}
final void setModeName(ModeImpl mode, String text) {
model.setModeName(mode, text);
}
/** Removes mode from model and requests view (if needed). */
public void removeMode(ModeImpl mode) {
if(!getModes().contains(mode)) {
return;
}
// debugLog("removeMode()=" + mode.getDisplayName());
model.removeMode(mode);
if(isVisible()) {
viewRequestor.scheduleRequest(
new ViewRequest(null, View.CHANGE_MODE_REMOVED, null, mode));
}
WindowManagerImpl.getInstance().doFirePropertyChange(
WindowManager.PROP_MODES, null, null);
}
/** Sets toolbar configuration name and requests view (if needed). */
public void setToolbarConfigName(String toolbarConfigName) {
String old = getToolbarConfigName();
if(old.equals(toolbarConfigName)) {
return;
}
model.setToolbarConfigName(toolbarConfigName);
if(isVisible()) {
viewRequestor.scheduleRequest(
new ViewRequest(null, View.CHANGE_TOOLBAR_CONFIGURATION_CHANGED,
old, toolbarConfigName));
}
}
/** Updates UI. */
public void updateUI() {
// Pure request, no model change.
if(isVisible()) {
viewRequestor.scheduleRequest(new ViewRequest(null, View.CHANGE_UI_UPDATE, null, null));
}
}
////////////////////////////
// Mode specific >>
private void closeMode(ModeImpl mode) {
if(mode == null) {
return;
}
TopComponent[] tcs = getModeOpenedTopComponents(mode).toArray(new TopComponent[0]);
for (int i = 0; i < tcs.length; i++) {
if (PersistenceHandler.isTopComponentPersistentWhenClosed(tcs[i])) {
model.addModeClosedTopComponent(mode, tcs[i]);
} else {
if (Boolean.TRUE.equals(tcs[i].getClientProperty(Constants.KEEP_NON_PERSISTENT_TC_IN_MODEL_WHEN_CLOSED))) {
model.addModeClosedTopComponent(mode, tcs[i]);
} else {
model.removeModeTopComponent(mode, tcs[i], null);
}
}
}
ModeImpl oldActive = getActiveMode();
ModeImpl newActive;
if(mode == oldActive) {
newActive = setSomeModeActive();
} else {
newActive = oldActive;
}
// debugLog("closeMode()");
// Remove mode from model if is not permanennt and emptied.
boolean modeRemoved = false;
if(!mode.isPermanent() && model.getModeTopComponents(mode).isEmpty()) {
// only if no sliding modes' tc points to this mode, then it's ok to remove it.
if (doCheckSlidingModes(mode)) {
// debugLog("do close mode=" + mode.getDisplayName());
model.removeMode(mode);
modeRemoved = true;
}
}
if(isVisible()) {
viewRequestor.scheduleRequest(new ViewRequest(mode, View.CHANGE_MODE_CLOSED, null, null));
}
// Notify closed.
for(int i = 0; i < tcs.length; i++) {
// Notify TopComponent was closed.
WindowManagerImpl.getInstance().notifyTopComponentClosed(tcs[i]);
}
if(oldActive != newActive) {
WindowManagerImpl.getInstance().doFirePropertyChange(
WindowManagerImpl.PROP_ACTIVE_MODE, oldActive, newActive);
}
if(modeRemoved) {
WindowManagerImpl.getInstance().doFirePropertyChange(
WindowManager.PROP_MODES, null, null);
}
// Notify new active.
if(newActive != null) {
// Notify registry.
WindowManagerImpl.notifyRegistryTopComponentActivated(
newActive.getSelectedTopComponent());
} else {
WindowManagerImpl.notifyRegistryTopComponentActivated(null);
}
}
// XXX TODO Model should handle this on its own.
private ModeImpl setSomeModeActive() {
for(Iterator it = getModes().iterator(); it.hasNext(); ) {
ModeImpl mode = (ModeImpl)it.next();
if(!mode.getOpenedTopComponents().isEmpty() && Constants.MODE_KIND_SLIDING != mode.getKind()) {
model.setActiveMode(mode);
return mode;
}
}
model.setActiveMode(null);
return model.getActiveMode();
}
/** Sets bounds into model and requests view (if needed). */
public void setModeBounds(ModeImpl mode, Rectangle bounds) {
if(bounds == null) {
return;
}
Rectangle old = getModeBounds(mode);
if(old.equals(bounds)) {
return;
}
model.setModeBounds(mode, bounds);
if(isVisible() && getEditorAreaState() == Constants.EDITOR_AREA_SEPARATED) {
viewRequestor.scheduleRequest(new ViewRequest(
mode, View.CHANGE_MODE_BOUNDS_CHANGED, old, bounds));
}
mode.doFirePropertyChange(ModeImpl.PROP_BOUNDS, old, bounds);
}
/** Sets frame state. */
public void setModeFrameState(ModeImpl mode, int frameState) {
int old = getModeFrameState(mode);
if(frameState == old) {
return;
}
model.setModeFrameState(mode, frameState);
if(isVisible()) {
viewRequestor.scheduleRequest(new ViewRequest(
mode, View.CHANGE_MODE_FRAME_STATE_CHANGED,
Integer.valueOf(old), Integer.valueOf(frameState)));
}
}
/** Sets seleted TopComponent into model and requests view (if needed). */
public void setModeSelectedTopComponent(ModeImpl mode, TopComponent selected) {
// don't apply check for sliding kind when clearing selection to null
if (mode.getKind() != Constants.MODE_KIND_SLIDING || selected != null) {
if(!getModeOpenedTopComponents(mode).contains(selected)) {
return;
}
}
TopComponent old = getModeSelectedTopComponent(mode);
if(selected == old) {
return;
}
model.setModeSelectedTopComponent(mode, selected);
if(isVisible()) {
viewRequestor.scheduleRequest(
new ViewRequest(mode, View.CHANGE_MODE_SELECTED_TOPCOMPONENT_CHANGED,
old, selected));
}
// Notify registry.
if(mode == getActiveMode()) {
WindowManagerImpl.notifyRegistryTopComponentActivated(selected);
}
}
/**
* Remember which TopComponent was previously the selected one, used when switching to/from maximized mode.
*
* @param mode
* @param tcId ID of TopComponent that was previously selected.
*/
public void setModePreviousSelectedTopComponentID(ModeImpl mode, String tcId) {
model.setModePreviousSelectedTopComponentID( mode, tcId );
}
/** Adds opened TopComponent into model and requests view (if needed). */
public void addModeOpenedTopComponent(ModeImpl mode, TopComponent tc) {
boolean wasOpened = tc.isOpened();
if(getModeOpenedTopComponents(mode).contains(tc)) {
return;
}
// Validate the TopComponent was removed from other modes.
removeTopComponentFromOtherModes(mode, tc);
model.addModeOpenedTopComponent(mode, tc);
if(isVisible()) {
viewRequestor.scheduleRequest(
new ViewRequest(mode, View.CHANGE_MODE_TOPCOMPONENT_ADDED,
null, tc));
}
if( !wasOpened ) { //make sure componentOpened() is called just once
// Notify opened.
WindowManagerImpl.getInstance().notifyTopComponentOpened(tc);
}
}
/** Adds opened TopComponent into model and requests view (if needed). */
void addModeOpenedTopComponentNoNotify(ModeImpl mode, TopComponent tc) {
if(getModeOpenedTopComponents(mode).contains(tc)) {
return;
}
// Validate the TopComponent was removed from other modes.
removeTopComponentFromOtherModes(mode, tc);
model.addModeOpenedTopComponent(mode, tc);
if(isVisible()) {
viewRequestor.scheduleRequest(
new ViewRequest(mode, View.CHANGE_MODE_TOPCOMPONENT_ADDED,
null, tc));
}
}
public void insertModeOpenedTopComponent(ModeImpl mode, TopComponent tc, int index) {
boolean wasOpened = tc.isOpened();
List openedTcs = getModeOpenedTopComponents(mode);
if(index >= 0 && !openedTcs.isEmpty()
&& openedTcs.size() > index && openedTcs.get(index) == tc) {
return;
}
// Validate the TopComponent was removed from other modes.
removeTopComponentFromOtherModes(mode, tc);
model.insertModeOpenedTopComponent(mode, tc, index);
if(isVisible()) {
viewRequestor.scheduleRequest(
new ViewRequest(mode, View.CHANGE_MODE_TOPCOMPONENT_ADDED, // PENDING inserted?
null, tc));
}
if( !wasOpened ) { //make sure componentOpened() is called just once
// #102258: Notify opened when opened through openAtTabPosition as well
WindowManagerImpl.getInstance().notifyTopComponentOpened(tc);
}
}
public boolean addModeClosedTopComponent(ModeImpl mode, TopComponent tc) {
boolean opened = getModeOpenedTopComponents(mode).contains(tc);
if(opened && !tc.canClose()) {
return false;
}
if(containsModeTopComponent(mode,tc) && !opened) {
return false;
}
if( isViewMaximized() && mode.getKind() == Constants.MODE_KIND_SLIDING ) {
//134622 - unslide first if some other view is maximized, otherwise
//the view being closed will reopen in slidebar after restoring from maximized mode
mode = unSlide(tc, mode);
}
// Validate the TopComponent was removed from other modes.
removeTopComponentFromOtherModes(mode, tc);
model.addModeClosedTopComponent(mode, tc);
ModeImpl oldActive = getActiveMode();
ModeImpl newActive;
if(model.getModeOpenedTopComponents(mode).isEmpty() && mode == oldActive) {
newActive = setSomeModeActive();
} else {
newActive = oldActive;
}
// Unmaximize mode if necessary.
if(getCurrentMaximizedMode() == mode && model.getModeOpenedTopComponents(mode).isEmpty()) {
switchMaximizedMode(null);
}
if(isVisible() && opened) {
viewRequestor.scheduleRequest(
new ViewRequest(mode, View.CHANGE_MODE_TOPCOMPONENT_REMOVED,
null, tc));
}
if(oldActive != newActive) {
WindowManagerImpl.getInstance().doFirePropertyChange(
WindowManagerImpl.PROP_ACTIVE_MODE, oldActive, newActive);
}
if(newActive != null) {
// Notify registry.
WindowManagerImpl.notifyRegistryTopComponentActivated(
newActive.getSelectedTopComponent());
} else {
WindowManagerImpl.notifyRegistryTopComponentActivated(null);
}
// Notify closed.
if(opened) {
WindowManagerImpl.getInstance().notifyTopComponentClosed(tc);
}
return true;
}
// XXX Could be called only during load phase of window system.
public void addModeUnloadedTopComponent(ModeImpl mode, String tcID, int index) {
TopComponentTracker.getDefault().add( tcID, mode );
model.addModeUnloadedTopComponent(mode, tcID, index);
}
// XXX
public void setUnloadedSelectedTopComponent(ModeImpl mode, String tcID) {
model.setModeUnloadedSelectedTopComponent(mode, tcID);
}
public void setUnloadedPreviousSelectedTopComponent(ModeImpl mode, String tcID) {
model.setModeUnloadedPreviousSelectedTopComponent(mode, tcID);
}
// XXX
public List<String> getModeOpenedTopComponentsIDs(ModeImpl mode) {
return model.getModeOpenedTopComponentsIDs(mode);
}
// XXX
public List getModeClosedTopComponentsIDs(ModeImpl mode) {
return model.getModeClosedTopComponentsIDs(mode);
}
// XXX
public List<String> getModeTopComponentsIDs(ModeImpl mode) {
return model.getModeTopComponentsIDs(mode);
}
/** Helper validation. */
private boolean removeTopComponentFromOtherModes(ModeImpl mode, TopComponent tc) {
boolean tcRemoved = false;
for(Iterator it = model.getModes().iterator(); it.hasNext(); ) {
ModeImpl m = (ModeImpl)it.next();
if(m == mode) {
continue;
}
if(model.containsModeTopComponent(m, tc)) {
tcRemoved = true;
model.removeModeTopComponent(m, tc, null);
// debugLog("removeTopComponentFromOtherModes()");
// Remove mode from model if is not permanennt and emptied.
boolean modeRemoved = false;
if(!m.isPermanent() && m.isEmpty() && doCheckSlidingModes(m)
// now the tc is not added to the sliding mode yet, but is *somehow* expected to be..
// maybe needs redesign..
&& mode.getKind() != Constants.MODE_KIND_SLIDING
//do not let remove a mode whose only TC is just being maximized
&& m != modeBeingMaximized ) {
// debugLog("removeTopComponentFromOtherModes() - really removing=" + m.getDisplayName());
model.removeMode(m);
modeRemoved = true;
}
if(modeRemoved) {
WindowManagerImpl.getInstance().doFirePropertyChange(
WindowManager.PROP_MODES, null, null);
}
}
}
return tcRemoved;
}
/** Removed top component from model and requests view (if needed). */
public boolean removeModeTopComponent(ModeImpl mode, TopComponent tc) {
if(!containsModeTopComponent(mode, tc)) {
return false;
}
boolean viewChange = getModeOpenedTopComponents(mode).contains(tc);
if(viewChange && !tc.canClose()) {
return false;
}
TopComponent recentTc = null;
if( mode.getKind() == Constants.MODE_KIND_EDITOR ) {
//an editor document is being closed so let's find the most recent editor to select
recentTc = getRecentTopComponent( mode, tc );
}
model.removeModeTopComponent(mode, tc, recentTc);
ModeImpl oldActive = getActiveMode();
ModeImpl newActive;
if(model.getModeOpenedTopComponents(mode).isEmpty() && mode == oldActive) {
newActive = setSomeModeActive();
} else {
newActive = oldActive;
}
// Unmaximize mode if necessary.
if(getCurrentMaximizedMode() == mode && model.getModeOpenedTopComponents(mode).isEmpty()) {
switchMaximizedMode(null);
}
// debugLog("removeModeTopComponent()");
// Remove mode from model if is not permanennt and emptied.
boolean modeRemoved = false;
if(!mode.isPermanent() && model.getModeTopComponents(mode).isEmpty()) {
// remove only if there's no other component in sliding modes that has this one as the previous mode.
//TODO
if (doCheckSlidingModes(mode)) {
// debugLog("removeModeTopComponent() -removing " + mode.getDisplayName());
model.removeMode(mode);
modeRemoved = true;
}
}
if(viewChange && isVisible()) {
viewRequestor.scheduleRequest(new ViewRequest(
mode, View.CHANGE_MODE_TOPCOMPONENT_REMOVED,
null, tc));
}
// Notify closed.
if(viewChange) {
WindowManagerImpl.getInstance().notifyTopComponentClosed(tc);
}
if(oldActive != newActive) {
WindowManagerImpl.getInstance().doFirePropertyChange(
WindowManagerImpl.PROP_ACTIVE_MODE, oldActive, newActive);
}
if(modeRemoved) {
WindowManagerImpl.getInstance().doFirePropertyChange(
WindowManager.PROP_MODES, null, null);
}
if(newActive != null) {
// Notify registry.
WindowManagerImpl.notifyRegistryTopComponentActivated(
newActive.getSelectedTopComponent());
} else {
WindowManagerImpl.notifyRegistryTopComponentActivated(
null);
}
return true;
}
/**
* Find TopComponent to be selected when the currently selected TC is closed
* in the given mode.
* @param editorMode Editor mode
* @param closedTc TopComponent which is being closed in the given mode.
* @return TopComponent to select or null (e.g. the mode will be empty after close)
*/
TopComponent getRecentTopComponent( ModeImpl editorMode, TopComponent closedTc ) {
WindowManagerImpl wm = WindowManagerImpl.getInstance();
if (!WinSysPrefs.HANDLER.getBoolean(WinSysPrefs.EDITOR_CLOSE_ACTIVATES_RECENT, true)) {
List<TopComponent> open = editorMode.getOpenedTopComponents();
int pos = open.indexOf(closedTc);
if (open.size() > 1 && pos >= 0) {
if (pos > 0) { // select previous one
return open.get(pos - 1);
} else { // this was first, so select next one
return open.get(1);
}
}
}
String[] ids = wm.getRecentViewIDList();
for( String tcId : ids ) {
ModeImpl mode = findMode(tcId);
if (mode == null
|| mode != editorMode) {
continue;
}
TopComponent tc = wm.findTopComponent( tcId );
if( tc == closedTc )
continue;
return tc;
}
return null;
}
private ModeImpl findMode( String tcId ) {
for( ModeImpl mode : getModes() ) {
if( mode.getTopComponentsIDs().contains( tcId ) )
return mode;
}
return null;
}
// remove the mode only if there's no other component in sliding modes that has this one as the previous mode.
boolean doCheckSlidingModes(ModeImpl mode) {
ModeImpl slid = model.getSlidingMode(Constants.BOTTOM);
if (slid != null) {
TopComponent[] tcs = slid.getTopComponents();
for (int i = 0; i < tcs.length; i++) {
String tcID = WindowManagerImpl.getInstance().findTopComponentID(tcs[i]);
ModeImpl impl = model.getModeTopComponentPreviousMode(slid, tcID);
if (impl == mode) {
return false;
}
}
}
slid = model.getSlidingMode(Constants.LEFT);
if (slid != null) {
TopComponent[] tcs = slid.getTopComponents();
for (int i = 0; i < tcs.length; i++) {
String tcID = WindowManagerImpl.getInstance().findTopComponentID(tcs[i]);
ModeImpl impl = model.getModeTopComponentPreviousMode(slid, tcID);
if (impl == mode) {
return false;
}
}
}
slid = model.getSlidingMode(Constants.RIGHT);
if (slid != null) {
TopComponent[] tcs = slid.getTopComponents();
for (int i = 0; i < tcs.length; i++) {
String tcID = WindowManagerImpl.getInstance().findTopComponentID(tcs[i]);
ModeImpl impl = model.getModeTopComponentPreviousMode(slid, tcID);
if (impl == mode) {
return false;
}
}
}
slid = model.getSlidingMode(Constants.TOP);
if (slid != null) {
TopComponent[] tcs = slid.getTopComponents();
for (int i = 0; i < tcs.length; i++) {
String tcID = WindowManagerImpl.getInstance().findTopComponentID(tcs[i]);
ModeImpl impl = model.getModeTopComponentPreviousMode(slid, tcID);
if (impl == mode) {
return false;
}
}
}
return true;
}
// XXX
public void removeModeClosedTopComponentID(ModeImpl mode, String tcID) {
// It is silent now, has to be used only for closed yet unloaded components!
model.removeModeClosedTopComponentID(mode, tcID);
}
/// << Mode specific
//////////////////////////////
// TopComponentGroup>>
public boolean isGroupOpened(TopComponentGroupImpl tcGroup) {
return model.isGroupOpened(tcGroup);
}
/** Opens TopComponentGroup. */
public void openGroup(TopComponentGroupImpl tcGroup) {
if(isGroupOpened(tcGroup)) {
return;
}
if( isEditorMaximized() && isViewMaximized() )
switchMaximizedMode( null );
Set<TopComponent> openedBeforeTopComponents = new HashSet<TopComponent>();
Set<TopComponent> tcs = tcGroup.getTopComponents();
for(Iterator<TopComponent> it = tcs.iterator(); it.hasNext(); ) {
TopComponent tc = it.next();
if( tc.isOpened() ) {
openedBeforeTopComponents.add( tc );
}
}
tcs = tcGroup.getOpeningSet();
HashSet<ModeImpl> openedModes = new HashSet<ModeImpl>( tcs.size() );
List<TopComponent> openedTcs = new ArrayList<TopComponent>();
for(Iterator<TopComponent> it = tcs.iterator(); it.hasNext(); ) {
TopComponent tc = it.next();
if(!tc.isOpened()) {
WindowManagerImpl wm = WindowManagerImpl.getInstance();
ModeImpl mode = (ModeImpl)wm.findMode(tc);
if(mode == null) {
// Only view TopComponent is in group.
mode = wm.getDefaultViewMode();
} else {
if( mode.getOpenedTopComponentsIDs().isEmpty() ) {
openedModes.add( mode );
}
}
model.addModeOpenedTopComponent(mode, tc);
if (tc.getClientProperty(GROUP_SELECTED) != null) {
tc.requestVisible();
}
if( isEditorMaximized() && mode.getState() != Constants.MODE_STATE_SEPARATED ) {
String tcID = wm.findTopComponentID( tc );
if( !isTopComponentDockedInMaximizedMode( tcID ) && mode.getKind() != Constants.MODE_KIND_SLIDING ) {
//slide the TopComponent to edgebar and slide it out
slide( tc, mode, getSlideSideForMode( mode ) );
}
}
openedTcs.add(tc);
}
}
model.openGroup(tcGroup, new HashSet<TopComponent>(openedTcs), openedBeforeTopComponents);
//restore selected TopComponents
for( ModeImpl mode : openedModes ) {
TopComponent prevSelTC = mode.getPreviousSelectedTopComponent();
if( null != prevSelTC )
mode.setSelectedTopComponent( prevSelTC );
}
if(isVisible()) {
viewRequestor.scheduleRequest(new ViewRequest(tcGroup,
View.CHANGE_TOPCOMPONENT_ARRAY_ADDED, null,
openedTcs.toArray(new TopComponent[0])));
}
// Notify oepned.
for(TopComponent tc: openedTcs) {
WindowManagerImpl.getInstance().notifyTopComponentOpened(tc);
}
}
/** Used to remember selected group member TC in mode so that it can be
* selected when group is opened.
*/
private static final Object GROUP_SELECTED = new Object();
/** Closes TopComponentGroup. */
public void closeGroup(TopComponentGroupImpl tcGroup) {
if(!isGroupOpened(tcGroup)) {
return;
}
if( isViewMaximized() ) {
//#222210
switchMaximizedMode( null );
}
Set tcs = tcGroup.getClosingSet();
List<TopComponent> closedTcs = new ArrayList<TopComponent>();
Set<TopComponent> openedTcsByGroup = model.getGroupOpenedTopComponents(tcGroup);
// Find out TC which were opened before the group was opened.
Set<TopComponent> openedTcsBefore = model.getGroupOpenedBeforeTopComponents(tcGroup);
// Adjust opening flags.
for(Iterator<TopComponent> it = model.getGroupTopComponents(tcGroup).iterator(); it.hasNext(); ) {
TopComponent tc = it.next();
boolean wasOpenedBefore = openedTcsBefore.contains(tc);
boolean openedByGroup = openedTcsByGroup.contains(tc);
if(tc.isOpened()) {
if(!wasOpenedBefore && !openedByGroup) {
// Open by group next time, user opened it while group was opened.
model.addGroupOpeningTopComponent(tcGroup, tc);
}
} else {
if(wasOpenedBefore || openedByGroup) {
// Don't open by group next time, user closed it while group was opened.
model.removeGroupOpeningTopComponent(tcGroup, tc);
}
}
}
ArrayList<ModeImpl> groupModes = new ArrayList<ModeImpl>( tcs.size() );
//remember which TCs are active
for(Iterator it = tcs.iterator(); it.hasNext(); ) {
TopComponent tc = (TopComponent)it.next();
if( !tc.isOpened() || openedTcsBefore.contains(tc)) {
continue;
}
ModeImpl mode = (ModeImpl)WindowManagerImpl.getInstance().findMode(tc);
if( null != mode )
groupModes.add( mode );
}
for( ModeImpl mode : groupModes ) {
TopComponent selTC = mode.getSelectedTopComponent();
if( null != selTC ) {
String tcId = WindowManagerImpl.getInstance().findTopComponentID(selTC);
if( null != tcId )
setModePreviousSelectedTopComponentID( mode, tcId );
}
}
WindowManagerImpl wmi = WindowManagerImpl.getInstance();
// Now close those which needed.
for(Iterator it = tcs.iterator(); it.hasNext(); ) {
TopComponent tc = (TopComponent)it.next();
if(tc.isOpened()) {
// Whether to ignore closing flag.
if(openedTcsBefore.contains(tc)) {
continue;
}
//#202131 - avoid endless opening and closing of window groups
//when non-document window from a TC group is dropped into editor area
if( wmi.isEditorTopComponent( tc ) ) {
continue;
}
boolean ignore = false;
for(Iterator it2 = model.getTopComponentGroups().iterator(); it2.hasNext(); ) {
TopComponentGroupImpl group = (TopComponentGroupImpl)it2.next();
if(group == tcGroup) {
continue;
}
if(group.isOpened() && group.getOpeningSet().contains(tc)) {
ignore = true;
break;
}
}
if(ignore) {
continue;
}
// Now you can close it.
ModeImpl mode = (ModeImpl)WindowManagerImpl.getInstance().findMode(tc);
if(mode != null) {
if (mode.getSelectedTopComponent() == tc) {
tc.putClientProperty(GROUP_SELECTED, Boolean.TRUE);
} else {
tc.putClientProperty(GROUP_SELECTED, null);
}
if (PersistenceHandler.isTopComponentPersistentWhenClosed(tc)) {
model.addModeClosedTopComponent(mode, tc);
} else {
if (Boolean.TRUE.equals(tc.getClientProperty(Constants.KEEP_NON_PERSISTENT_TC_IN_MODEL_WHEN_CLOSED))) {
model.addModeClosedTopComponent(mode, tc);
} else {
model.removeModeTopComponent(mode, tc, null);
}
}
closedTcs.add(tc);
}
}
}
model.closeGroup(tcGroup);
if(isVisible()) {
viewRequestor.scheduleRequest(new ViewRequest(tcGroup,
View.CHANGE_TOPCOMPONENT_ARRAY_REMOVED, null,
closedTcs.toArray(new TopComponent[0])));
}
// Notify closed.
for(TopComponent tc: closedTcs) {
WindowManagerImpl.getInstance().notifyTopComponentClosed(tc);
}
}
/** Adds TopComponentGroup into model. */
public void addTopComponentGroup(TopComponentGroupImpl tcGroup) {
model.addTopComponentGroup(tcGroup);
}
/** Removes TopComponentGroup from model. */
public void removeTopComponentGroup(TopComponentGroupImpl tcGroup) {
model.removeTopComponentGroup(tcGroup);
}
public boolean addGroupUnloadedTopComponent(TopComponentGroupImpl tcGroup, String tcID) {
return model.addGroupUnloadedTopComponent(tcGroup, tcID);
}
public boolean removeGroupUnloadedTopComponent(TopComponentGroupImpl tcGroup, String tcID) {
return model.removeGroupUnloadedTopComponent(tcGroup, tcID);
}
/** Adds opening top component for set into model. */
public boolean addGroupUnloadedOpeningTopComponent(TopComponentGroupImpl tcGroup, String tcID) {
return model.addGroupUnloadedOpeningTopComponent(tcGroup, tcID);
}
/** Removes opening top component from model. */
public boolean removeGroupUnloadedOpeningTopComponent(TopComponentGroupImpl tcGroup, String tcID) {
return model.removeGroupUnloadedOpeningTopComponent(tcGroup, tcID);
}
/** Adds closing top component for set into model. */
public boolean addGroupUnloadedClosingTopComponent(TopComponentGroupImpl tcGroup, String tcID) {
return model.addGroupUnloadedClosingTopComponent(tcGroup, tcID);
}
/** Removes closing top component for set from model. */
public boolean removeGroupUnloadedClosingTopComponent(TopComponentGroupImpl tcGroup, String tcID) {
return model.removeGroupUnloadedClosingTopComponent(tcGroup, tcID);
}
// XXX Just helper for persistence.
public boolean addGroupUnloadedOpenedTopComponent(TopComponentGroupImpl tcGroup, String tcID) {
if(!isGroupOpened(tcGroup)) {
return false;
}
return model.addGroupUnloadedOpenedTopComponent(tcGroup, tcID);
}
// XXX Just helper for persistence
public Set getGroupOpenedTopComponents(TopComponentGroupImpl tcGroup) {
return model.getGroupOpenedTopComponents(tcGroup);
}
// XXX>>
public Set<String> getGroupTopComponentsIDs(TopComponentGroupImpl tcGroup) {
return model.getGroupTopComponentsIDs(tcGroup);
}
public Set<String> getGroupOpeningSetIDs(TopComponentGroupImpl tcGroup) {
return model.getGroupOpeningSetIDs(tcGroup);
}
public Set<String> getGroupClosingSetIDs(TopComponentGroupImpl tcGroup) {
return model.getGroupClosingSetIDs(tcGroup);
}
public Set<String> getGroupOpenedTopComponentsIDs(TopComponentGroupImpl tcGroup) {
return model.getGroupOpenedTopComponentsIDs(tcGroup);
}
// XXX<<
// TopComponentGroup<<
//////////////////////////////
// Mutators <<
/////////////////////
/////////////////////
// Accessors>>
/** Indicates whether windows system shows GUI. */
public boolean isVisible() {
return model.isVisible();
}
/** Gets <code>Set</code> of all <code>Mode</code>'s. */
public Set<? extends ModeImpl> getModes () {
return model.getModes();
}
/** Gets main window bounds for joined(tiled) state. */
public Rectangle getMainWindowBoundsJoined() {
return model.getMainWindowBoundsJoined();
}
/** Gets main window bounds for separated state. */
public Rectangle getMainWindowBoundsSeparated() {
return model.getMainWindowBoundsSeparated();
}
public int getMainWindowFrameStateJoined() {
return model.getMainWindowFrameStateJoined();
}
public int getMainWindowFrameStateSeparated() {
return model.getMainWindowFrameStateSeparated();
}
/** Gets active mode from model. */
public ModeImpl getActiveMode () {
return model.getActiveMode();
}
/** Gets last active editor mode from model. */
public ModeImpl getLastActiveEditorMode () {
return model.getLastActiveEditorMode();
}
/** Gets editor area bounds from model. */
public Rectangle getEditorAreaBounds() {
return model.getEditorAreaBounds();
}
/** Gets editor area constraints from model. */
public SplitConstraint[] getEditorAreaConstraints() {
return model.getEditorAreaConstraints();
}
/** Gets editor area state from model. */
public int getEditorAreaState() {
return model.getEditorAreaState();
}
public int getEditorAreaFrameState() {
return model.getEditorAreaFrameState();
}
public Component getEditorAreaComponent() {
return viewRequestor.getEditorAreaComponent();
}
/** Gets mode that is currently maximized (can be an editor or view component). */
ModeImpl getCurrentMaximizedMode() {
if( isViewMaximized() )
return model.getViewMaximizedMode();
if( isEditorMaximized() )
return model.getEditorMaximizedMode();
return null;
}
/** Gets editor maximized mode. */
ModeImpl getEditorMaximizedMode() {
return model.getEditorMaximizedMode();
}
/** Gets view maximized mode. */
ModeImpl getViewMaximizedMode() {
return model.getViewMaximizedMode();
}
/** Gets constraints for mode from model. */
public SplitConstraint[] getModeConstraints(ModeImpl mode) {
return model.getModeConstraints(mode);
}
/** Gets toolbar configuration name from model. */
public String getToolbarConfigName () {
return model.getToolbarConfigName();
}
////////////////////////////////
/// >> Mode specific
/** Gets programatic name of mode. */
public String getModeName(ModeImpl mode) {
return model.getModeName(mode);
}
/** Gets bounds. */
public Rectangle getModeBounds(ModeImpl mode) {
return model.getModeBounds(mode);
}
/** Gets State. */
public int getModeState(ModeImpl mode) {
return model.getModeState(mode);
}
/** Gets kind. */
public int getModeKind(ModeImpl mode) {
return model.getModeKind(mode);
}
/** Gets side. */
public String getModeSide(ModeImpl mode) {
return model.getModeSide(mode);
}
/** Gets frame state. */
public int getModeFrameState(ModeImpl mode) {
return model.getModeFrameState(mode);
}
/** Gets used defined. */
public boolean isModePermanent(ModeImpl mode) {
return model.isModePermanent(mode);
}
public boolean isModeEmpty(ModeImpl mode) {
return model.isModeEmpty(mode);
}
/** */
public boolean containsModeTopComponent(ModeImpl mode, TopComponent tc) {
return model.containsModeTopComponent(mode, tc);
}
/** Gets selected TopComponent. */
public TopComponent getModeSelectedTopComponent(ModeImpl mode) {
return model.getModeSelectedTopComponent(mode);
}
/**
* @return ID of TopComponent that was previously selected in the given mode or null.
*/
public String getModePreviousSelectedTopComponentID(ModeImpl mode) {
return model.getModePreviousSelectedTopComponentID( mode );
}
/** Gets list of top components in this workspace. */
public List<TopComponent> getModeTopComponents(ModeImpl mode) {
return model.getModeTopComponents(mode);
}
/** Gets list of top components in this workspace. */
public List<TopComponent> getModeOpenedTopComponents(ModeImpl mode) {
return model.getModeOpenedTopComponents(mode);
}
/** Gets position of top component in given mode. */
public int getModeTopComponentTabPosition(ModeImpl mode, TopComponent tc) {
return model.getModeOpenedTopComponentTabPosition(mode, tc);
}
/**
*
* @param mode
* @return True if the given mode is minimized.
* @since 2.30
*/
boolean isModeMinimized( ModeImpl mode ) {
return model.isModeMinimized( mode );
}
/**
* Mark the given mode as minimized or docked.
* @param mode
* @param minimized True if the mode is minimized, false if docked.
* @since 2.30
*/
void setModeMinimized( ModeImpl mode, boolean minimized ) {
model.setModeMinimized( mode, minimized );
}
/**
* @param mode
* @return List of Mode's additional names.
* @since 2.30
*/
Collection<String> getModeOtherNames( ModeImpl mode ) {
return model.getModeOtherNames( mode );
}
/**
* Add another mode name.
* @param mode
* @param modeOtherName
* @since 2.30
*/
void addModeOtherName( ModeImpl mode, String modeOtherName ) {
model.addModeOtherName( mode, modeOtherName );
}
/// << Mode specific
////////////////////////////////
////////////////////////////////////
// TopComponentGroup specific >>
public Set<TopComponentGroupImpl> getTopComponentGroups() {
return model.getTopComponentGroups();
}
public String getGroupName(TopComponentGroupImpl tcGroup) {
return model.getGroupName(tcGroup);
}
public Set<TopComponent> getGroupTopComponents(TopComponentGroupImpl tcGroup) {
return model.getGroupTopComponents(tcGroup);
}
/** Gets opening top components for group from model. */
public Set<TopComponent> getGroupOpeningTopComponents(TopComponentGroupImpl tcGroup) {
return model.getGroupOpeningTopComponents(tcGroup);
}
/** Gets closing top components for group from model. */
public Set getGroupClosingTopComponents(TopComponentGroupImpl tcGroup) {
return model.getGroupClosingTopComponents(tcGroup);
}
// TopComponentGroup specific <<
////////////////////////////////////
// Accessors<<
/////////////////////
// Others>>
// PENDING>>
public void topComponentDisplayNameChanged(ModeImpl mode, TopComponent tc) {
if(isVisible()) {
viewRequestor.scheduleRequest(new ViewRequest(
mode, View.CHANGE_TOPCOMPONENT_DISPLAY_NAME_CHANGED, null, tc));
}
}
public void topComponentDisplayNameAnnotation(ModeImpl mode, TopComponent tc) {
if(isVisible()) {
viewRequestor.scheduleRequest(new ViewRequest(
mode, View.CHANGE_TOPCOMPONENT_DISPLAY_NAME_ANNOTATION_CHANGED, null, tc));
}
}
// PENDING<<
public void topComponentToolTipChanged(ModeImpl mode, TopComponent tc) {
if(isVisible()) {
viewRequestor.scheduleRequest(new ViewRequest(
mode, View.CHANGE_TOPCOMPONENT_TOOLTIP_CHANGED, null, tc));
}
}
public void topComponentIconChanged(ModeImpl mode, TopComponent tc) {
if(isVisible()) {
viewRequestor.scheduleRequest(new ViewRequest(
mode, View.CHANGE_TOPCOMPONENT_ICON_CHANGED, null, tc));
}
}
/**
*
* @param mode
* @param tc
* @param busy
* @since 2.45
*/
public void topComponentMakeBusy( ModeImpl mode, TopComponent tc, boolean busy ) {
String modeName = getModeName(mode);
viewRequestor.scheduleRequest (
new ViewRequest(modeName, busy ? View.TOPCOMPONENT_SHOW_BUSY : View.TOPCOMPONENT_HIDE_BUSY, tc, tc));
}
public void resetModel() {
model.reset();
}
// Others<<
// Compound ones>>
/**
* Creates a new mode on the side of the reference mode.
* @param referenceMode
* @param side
* @param modeName
* @param modeKind
* @param permanent
* @return
*/
ModeImpl attachModeToSide( ModeImpl referenceMode, String side, String modeName, int modeKind, boolean permanent ) {
ModeImpl newMode = WindowManagerImpl.getInstance().createModeImpl(modeName, modeKind, permanent);
model.addModeToSide(newMode, referenceMode, side);
return newMode;
}
/** Creates new mode on side of specified one and puts there the TopComponentS. */
private ModeImpl attachModeToSide(ModeImpl attachMode, String side, int modeKind) {
return attachModeToSide( attachMode, side, ModeImpl.getUnusedModeName(), modeKind, false);
}
/** Creates new mode on side of desktop */
private ModeImpl attachModeAroundDesktop(String side) {
// New mode. It is necessary to add it yet.
ModeImpl newMode = WindowManagerImpl.getInstance().createModeImpl(
ModeImpl.getUnusedModeName(), Constants.MODE_KIND_VIEW, false);
model.addModeAround(newMode, side);
return newMode;
}
/** Creates new mode on side of editor area and puts there the TopComponentS. */
private ModeImpl attachModeAroundEditor(String side, int modeKind) {
// New mode. It is necessary to add it yet.
ModeImpl newMode = WindowManagerImpl.getInstance().createModeImpl(
ModeImpl.getUnusedModeName(), modeKind, false);
model.addModeAroundEditor(newMode, side);
return newMode;
}
private ModeImpl createFloatingMode(Rectangle bounds, int modeKind) {
WindowManagerImpl wmi = WindowManagerImpl.getInstance();
// New mode. It is necessary to add it yet.
ModeImpl newMode = wmi.createModeImpl(
ModeImpl.getUnusedModeName(), modeKind, Constants.MODE_STATE_SEPARATED, false);
newMode.setBounds(bounds);
model.addMode(newMode, new SplitConstraint[] {new SplitConstraint(Constants.HORIZONTAL, 100, 0.5f)});
return newMode;
}
/** */
public void activateModeTopComponent(ModeImpl mode, TopComponent tc) {
if(!getModeOpenedTopComponents(mode).contains(tc)) {
return;
}
ModeImpl oldActiveMode = getActiveMode();
//#45650 -some API users call the activation all over again all the time on one item.
// improve performance for such cases.
if (oldActiveMode != null && oldActiveMode.equals(mode)) {
if (tc != null && tc.equals(model.getModeSelectedTopComponent(mode))) {
// #82385, #139319 do repeat activation if focus is not
// owned by tc to be activated
Component fOwn = KeyboardFocusManager.getCurrentKeyboardFocusManager().
getFocusOwner();
if (fOwn != null && SwingUtilities.isDescendingFrom(fOwn, tc)) {
//#70173 - activation request came probably from a sliding
//window in 'hover' mode, so let's hide it
slideOutSlidingWindows( mode );
return;
}
}
}
model.setActiveMode(mode);
model.setModeSelectedTopComponent(mode, tc);
if(isVisible()) {
viewRequestor.scheduleRequest(new ViewRequest(mode,
View.CHANGE_TOPCOMPONENT_ACTIVATED, null, tc));
//restore floating windows if iconified
if( mode.getState() == Constants.MODE_STATE_SEPARATED ) {
Frame frame = (Frame) SwingUtilities.getAncestorOfClass(Frame.class, tc);
if( null != frame && frame != WindowManagerImpl.getInstance().getMainWindow()
&& (frame.getExtendedState() & Frame.ICONIFIED) > 0 ) {
frame.setExtendedState(frame.getExtendedState() - Frame.ICONIFIED );
}
}
}
// Notify registry.
WindowManagerImpl.notifyRegistryTopComponentActivated(tc);
if(oldActiveMode != mode) {
WindowManagerImpl.getInstance().doFirePropertyChange(
WindowManagerImpl.PROP_ACTIVE_MODE, oldActiveMode, mode);
}
}
// Compound ones<<
/**
* Make sure no sliding window is slided-in.
*/
protected void slideOutSlidingWindows( ModeImpl newActiveMode ) {
for( ModeImpl mode : getModes() ) {
if( !newActiveMode.equals(mode)
&& mode.getKind() == Constants.MODE_KIND_SLIDING
&& null != mode.getSelectedTopComponent() ) {
setModeSelectedTopComponent( mode, null );
}
}
}
// Other >>
public boolean isDragInProgress() {
// XXX
return viewRequestor.isDragInProgress();
}
public Frame getMainWindow() {
// XXX
return viewRequestor.getMainWindow();
}
public String guessSlideSide(TopComponent tc) {
return viewRequestor.guessSlideSide(tc);
}
/**
* Find the side (LEFT/RIGHT/BOTTOM) where the TopComponent from the given
* mode should slide to.
*
* @param mode Mode
* @return The slide side for TopComponents from the given mode.
*/
String getSlideSideForMode(ModeImpl mode) {
return model.getSlideSideForMode( mode );
}
/** Tells whether given top component is inside joined mode (in main window)
* or inside separate mode (separate window).
*
* @param the component in question
* @return True when given component is docked, which means lives now
* inside main window. False if component lives inside separate window.
*/
public boolean isDocked (TopComponent comp) {
ModeImpl mode = (ModeImpl)WindowManagerImpl.getInstance().findMode(comp);
return mode != null && mode.getState() == Constants.MODE_STATE_JOINED;
}
// Other <<
// Helper methods
/** Creates model for mode, used internally. */
public void createModeModel(ModeImpl mode, String name, int state, int kind, boolean permanent) {
model.createModeModel(mode, name, state, kind, permanent);
}
/** Creates model for top component group, used internally. */
public void createGroupModel(TopComponentGroupImpl tcGroup, String name, boolean opened) {
model.createGroupModel(tcGroup, name, opened);
}
// snapshot
/** Creates window system model snapshot, used for requesting view. */
public WindowSystemSnapshot createWindowSystemSnapshot() {
return model.createWindowSystemSnapshot();
}
///////////////////////////
// ControllerHandler>>
@Override
public void userActivatedMode(ModeImpl mode) {
if(mode != null) {
setActiveMode(mode);
}
}
@Override
public void userActivatedModeWindow(ModeImpl mode) {
if(mode != null) {
setActiveMode(mode);
}
}
@Override
public void userActivatedEditorWindow() {
WindowManagerImpl wm = WindowManagerImpl.getInstance();
TopComponent[] tcs = wm.getRecentViewList();
for(int i = 0; i < tcs.length; i++) {
TopComponent tc = tcs[i];
ModeImpl mode = (ModeImpl)wm.findMode(tc);
if(mode != null
&& mode.getKind() == Constants.MODE_KIND_EDITOR
&& !mode.getOpenedTopComponents().isEmpty()) {
setActiveMode(mode);
return;
}
}
ModeImpl mode = wm.getDefaultEditorMode();
if(mode != null && !mode.getOpenedTopComponents().isEmpty()) {
setActiveMode(mode);
} else {
// when someone calls this as a matter of activating editor mode as a fallback, but none is opened,
// do unactivate the current selection.
// #44389
setActiveMode(null);
}
}
@Override
public void userActivatedTopComponent(ModeImpl mode, TopComponent selected) {
if(mode != null) {
setModeSelectedTopComponent(mode, selected);
}
}
@Override
public void userResizedMainWindow(Rectangle bounds) {
if(getEditorAreaState() == Constants.EDITOR_AREA_JOINED) {
model.setMainWindowBoundsJoined(bounds);
} else {
model.setMainWindowBoundsSeparated(bounds);
}
}
@Override
public void userResizedMainWindowBoundsSeparatedHelp(Rectangle bounds) {
if(getEditorAreaState() == Constants.EDITOR_AREA_JOINED
&& getMainWindowBoundsSeparated().isEmpty()) {
model.setMainWindowBoundsUserSeparatedHelp(bounds);
}
}
@Override
public void userResizedEditorArea(Rectangle bounds) {
model.setEditorAreaBounds(bounds);
}
@Override
public void userResizedEditorAreaBoundsHelp(Rectangle bounds) {
if(getEditorAreaState() == Constants.EDITOR_AREA_JOINED
&& getEditorAreaBounds().isEmpty()) {
model.setEditorAreaBoundsUserHelp(bounds);
}
}
@Override
public void userResizedModeBounds(ModeImpl mode, Rectangle bounds) {
Rectangle old = model.getModeBounds(mode);
model.setModeBounds(mode, bounds);
mode.doFirePropertyChange(ModeImpl.PROP_BOUNDS, old, bounds);
}
@Override
public void userResizedModeBoundsSeparatedHelp(ModeImpl mode, Rectangle bounds) {
model.setModeBoundsSeparatedHelp(mode, bounds);
}
@Override
public void userChangedFrameStateMainWindow(int frameState) {
if(getEditorAreaState() == Constants.EDITOR_AREA_JOINED) {
model.setMainWindowFrameStateJoined(frameState);
} else {
model.setMainWindowFrameStateSeparated(frameState);
}
}
@Override
public void userChangedFrameStateEditorArea(int frameState) {
model.setEditorAreaFrameState(frameState);
}
@Override
public void userChangedFrameStateMode(ModeImpl mode, int frameState) {
model.setModeFrameState(mode, frameState);
}
@Override
public void userChangedSplit( ModelElement[] snapshots, double[] splitWeights ) {
model.setSplitWeights( snapshots, splitWeights );
}
@Override
public void userClosedTopComponent(ModeImpl mode, TopComponent tc) {
if( mode == getCurrentMaximizedMode() && isViewMaximized() ) {
switchMaximizedMode( null );
for(Iterator it = getModes().iterator(); it.hasNext(); ) {
ModeImpl newMode = (ModeImpl)it.next();
if(newMode.containsTopComponent(tc)) {
userClosedTopComponent( newMode, tc );
return;
}
}
}
TopComponent recentTc = null;
if( mode.getKind() == Constants.MODE_KIND_EDITOR ) {
//an editor document is being closed so let's find the most recent editor to select
recentTc = getRecentTopComponent( mode, tc );
}
boolean wasTcClosed = false;
if (PersistenceHandler.isTopComponentPersistentWhenClosed(tc)) {
wasTcClosed = addModeClosedTopComponent(mode, tc);
} else {
if (Boolean.TRUE.equals(tc.getClientProperty(Constants.KEEP_NON_PERSISTENT_TC_IN_MODEL_WHEN_CLOSED))) {
wasTcClosed = addModeClosedTopComponent(mode, tc);
} else {
wasTcClosed = removeModeTopComponent(mode, tc);
}
}
if( wasTcClosed
&& mode.getKind() == Constants.MODE_KIND_EDITOR
&& "editor".equals(mode.getName()) //NOI18N
&& mode.getOpenedTopComponentsIDs().isEmpty() ) {
//134945 - if user just closed the last topcomponent in the default
//and permanent "editor" mode then pick some other arbitrary editor mode
//and move its topcomponents to the default editor mode. otherwise opening
//of a new editor window will cause a split in the editor area.
ModeImpl otherEditorMode = findSomeOtherEditorModeImpl();
if( null != otherEditorMode ) {
for( String closedTcId : otherEditorMode.getClosedTopComponentsIDs() ) {
mode.addUnloadedTopComponent(closedTcId);
}
List<TopComponent> tcs = otherEditorMode.getOpenedTopComponents();
for( TopComponent t : tcs ) {
int index = otherEditorMode.getTopComponentTabPosition(t);
mode.addOpenedTopComponent(t, index);
}
removeMode(otherEditorMode);
}
}
if ((recentTc != null) && wasTcClosed) {
recentTc.requestActive();
}
//#177986 - repaint the main window when closing the last tc
if( TopComponent.getRegistry().getOpened().isEmpty() ) {
SwingUtilities.invokeLater( new Runnable() {
@Override
public void run() {
java.awt.Frame f = getMainWindow();
if( null != f && f.isVisible() ) {
f.invalidate();
f.repaint();
}
}
});
}
}
/**
* @return ModeImpl with opened TopComponents which is 'editor' kind but
* not the default and permanent one. Returns null if there is no such mode.
*/
private ModeImpl findSomeOtherEditorModeImpl() {
for( ModeImpl m : getModes() ) {
if( m.getKind() == Constants.MODE_KIND_EDITOR
&& !"editor".equals(m.getName()) //NOI18N
&& !m.getOpenedTopComponentsIDs().isEmpty()
&& !m.isPermanent()
&& m.getState() != Constants.MODE_STATE_SEPARATED )
return m;
}
return null;
}
@Override
public void userClosedMode(ModeImpl mode) {
if(mode != null) {
boolean allAreClosable = true;
for( TopComponent tc : mode.getOpenedTopComponents() ) {
if( !Switches.isClosingEnabled(tc) ) {
allAreClosable = false;
break;
}
}
if( allAreClosable ) {
closeMode(mode);
} else {
ArrayList<TopComponent> tcs = new ArrayList<>(mode.getOpenedTopComponents());
for( TopComponent tc : tcs ) {
if( Switches.isClosingEnabled(tc) ) {
userClosedTopComponent(mode, tc);
}
}
}
// Unmaximize if necessary.
if(mode.getOpenedTopComponents().isEmpty()
&& mode == getCurrentMaximizedMode())
{
switchMaximizedMode(null);
}
}
}
// DnD
@Override
public void userDroppedTopComponents(ModeImpl mode, TopComponentDraggable draggable) {
boolean unmaximize = false;
if( draggable.isTopComponentTransfer() ) {
unmaximize = moveTopComponentIntoMode( mode, draggable.getTopComponent() );
} else {
TopComponent selTC = draggable.getMode().getSelectedTopComponent();
mergeModes( draggable.getMode(), mode, -1 );
if( null != selTC )
mode.setSelectedTopComponent( selTC );
}
updateViewAfterDnD(unmaximize);
}
@Override
public void userDroppedTopComponents(ModeImpl mode, TopComponentDraggable draggable, int index) {
boolean unmaximize = false;
if( draggable.isTopComponentTransfer() ) {
unmaximize = moveTopComponentIntoMode( mode, draggable.getTopComponent(), index );
} else {
TopComponent selTC = draggable.getMode().getSelectedTopComponent();
mergeModes( draggable.getMode(), mode, index );
if( null != selTC )
mode.setSelectedTopComponent( selTC );
}
updateViewAfterDnD(unmaximize);
}
@Override
public void userDroppedTopComponents(ModeImpl mode, TopComponentDraggable draggable, String side) {
ModeImpl newMode = attachModeToSide( mode, side, mode.getKind() );
if( draggable.isTopComponentTransfer() ) {
moveTopComponentIntoMode( newMode, draggable.getTopComponent() );
} else {
if( newMode.getKind() != draggable.getKind() ) {
mergeModes( draggable.getMode(), newMode, -1 );
} else {
dockMode( newMode, draggable.getMode() );
}
}
updateViewAfterDnD(true);
}
@Override
public void userDroppedTopComponentsIntoEmptyEditor(TopComponentDraggable draggable) {
// PENDING
ModeImpl mode = (ModeImpl)WindowManagerImpl.getInstance().findMode("editor"); // NOI18N
if( null == mode || mode.getState() == Constants.MODE_STATE_SEPARATED ) {
for( ModeImpl m : getModes() ) {
if( m.getKind() == Constants.MODE_KIND_EDITOR && m.getState() == Constants.MODE_STATE_JOINED ) {
mode = m;
break;
}
}
}
if( null == mode || mode == draggable.getMode() ) {
if( draggable.isModeTransfer() && draggable.getMode().getKind() == Constants.MODE_KIND_EDITOR ) {
userDockedMode( draggable.getMode() );
}
return;
}
if( draggable.isTopComponentTransfer() ) {
moveTopComponentIntoMode(mode, draggable.getTopComponent());
} else {
if( mode.getKind() != draggable.getKind() ) {
mergeModes( draggable.getMode(), mode, 0 );
} else {
dockMode( mode, draggable.getMode() );
}
}
updateViewAfterDnD(true);
}
@Override
public void userDroppedTopComponentsAround(TopComponentDraggable draggable, String side) {
ModeImpl newMode = attachModeAroundDesktop( side );
if( draggable.isTopComponentTransfer() ) {
moveTopComponentIntoMode( newMode, draggable.getTopComponent() );
} else {
dockMode( newMode, draggable.getMode() );
}
updateViewAfterDnD(true);
}
@Override
public void userDroppedTopComponentsAroundEditor(TopComponentDraggable draggable, String side) {
ModeImpl newMode = attachModeAroundEditor( side, draggable.getKind() );
if( draggable.isTopComponentTransfer() ) {
moveTopComponentIntoMode( newMode, draggable.getTopComponent() );
} else {
dockMode( newMode, draggable.getMode() );
}
updateViewAfterDnD(true);
}
@Override
public void userDroppedTopComponentsIntoFreeArea(TopComponentDraggable draggable, Rectangle bounds) {
if( draggable.isTopComponentTransfer() ) {
ModeImpl newMode = createFloatingMode( bounds, draggable.getKind() );
moveTopComponentIntoMode( newMode, draggable.getTopComponent() );
newMode.setSelectedTopComponent( draggable.getTopComponent() );
} else {
userUndockedMode( draggable.getMode(), bounds );
}
updateViewAfterDnD(false);
}
/**
* User made the given Mode floating.
* @param mode
* @since 2.30
*/
public void userUndockedMode( ModeImpl mode ) {
if (getCurrentMaximizedMode() == mode) {
switchMaximizedMode(null);
}
Rectangle modeBounds = null;
TopComponent tc = mode.getSelectedTopComponent();
if( null != tc ) {
Point tcLoc = tc.getLocation();
Dimension tcSize = tc.getSize();
SwingUtilities.convertPointToScreen(tcLoc, tc);
modeBounds = new Rectangle(tcLoc, tcSize);
}
userUndockedMode( mode, modeBounds );
}
private void userUndockedMode( ModeImpl mode, Rectangle modeBounds ) {
int modeKind = mode.getKind();
if (modeKind == Constants.MODE_KIND_SLIDING) {
modeKind = Constants.MODE_KIND_VIEW;
}
if (getCurrentMaximizedMode() == mode) {
switchMaximizedMode(null);
}
if( null != modeBounds ) {
model.setModeBounds( mode, modeBounds );
}
SplitConstraint[] constraints = mode.getConstraints();
model.setModeState( mode, Constants.MODE_STATE_SEPARATED );
ModeImpl previousMode = WindowManagerImpl.getInstance().createMode( null, mode.getKind(), Constants.MODE_STATE_JOINED, true, constraints);
constraints = previousMode.getConstraints();
List<String> openedIDs = mode.getOpenedTopComponentsIDs();
for( String tcID : getModeTopComponentsIDs( mode ) ) {
model.setModeTopComponentPreviousMode(mode, tcID, previousMode, openedIDs.indexOf( tcID ));
model.setModeTopComponentPreviousConstraints(mode, tcID, constraints);
}
model.setModeConstraints( mode, new SplitConstraint[0] );
updateViewAfterDnD(false);
WindowManagerImpl.getInstance().doFirePropertyChange(
WindowManager.PROP_MODES, null, null);
}
/**
* User docked the given mode (from floating state).
* @param mode
* @since 2.30
*/
public void userDockedMode( ModeImpl mode ) {
int modeKind = mode.getKind();
if (modeKind == Constants.MODE_KIND_SLIDING) {
modeKind = Constants.MODE_KIND_VIEW;
}
switchMaximizedMode(null);
TopComponent selectedTC = mode.getSelectedTopComponent();
if( !mode.isPermanent() ) {
for( TopComponent tc : mode.getOpenedTopComponents() ) {
userDockedTopComponent( tc, mode );
}
} else {
List<String> ids = mode.getTopComponentsIDs();
if( !ids.isEmpty() ) {
String tcID = ids.get( 0 );
ModeImpl previousMode = model.getModeTopComponentPreviousMode( mode, tcID );
if( null == previousMode || !model.getModes().contains(previousMode) ) {
SplitConstraint[] constraints = model.getModeTopComponentPreviousConstraints( mode, tcID );
if( null != constraints ) {
previousMode = findJoinedMode( modeKind, constraints);
}
}
if( null == previousMode ) {
SplitConstraint[] constraints = model.getModeTopComponentPreviousConstraints( mode, tcID );
if( null != constraints )
model.setModeConstraints( mode, constraints );
model.setModeState( mode, Constants.MODE_STATE_JOINED );
} else {
if( previousMode.isPermanent() && !previousMode.getTopComponentsIDs().isEmpty() ) {
List<String> opened = mode.getOpenedTopComponentsIDs();
for( String id : opened ) {
int prevIndex = model.getModeTopComponentPreviousIndex( mode, id );
TopComponent tc = WindowManagerImpl.getInstance().findTopComponent( id );
previousMode.addOpenedTopComponent( tc, prevIndex );
}
mergeModes( mode, previousMode, -1 );
mode = null;
} else {
dockMode( previousMode, mode );
}
}
}
if( null != mode ) {
SplitConstraint[] constraints = mode.getConstraints();
if( null == constraints || constraints.length == 0 ) {
//just a fallback, it shouldn't really happen
model.setModeConstraints( mode, new SplitConstraint[] { new SplitConstraint( Constants.HORIZONTAL, 0, 0.2) } );
}
model.setModeState( mode, Constants.MODE_STATE_JOINED );
}
}
updateViewAfterDnD(false);
if( null != selectedTC )
selectedTC.requestActive();
WindowManagerImpl.getInstance().doFirePropertyChange(
WindowManager.PROP_MODES, null, null);
}
/**
* Merge the given Modes into a single name.
* @param source Mode which will disappear after the merge.
* @param target Mode which will receive all TopComponents from the source
* mode.
* @since 2.30
*/
private void mergeModes( ModeImpl source, ModeImpl target, int index ) {
ModeImpl prevMode = null;
SplitConstraint[] prevConstraints = null;
if( source.isPermanent() && !target.isPermanent() ) {
prevMode = getPreviousMode( source );
prevConstraints = getPreviousConstraints( source );
} else {
prevMode = getPreviousMode( target );
prevConstraints = getPreviousConstraints( target );
}
int tmpIndex = index;
for( String tcID: source.getTopComponentsIDs() ) {
target.addUnloadedTopComponent( tcID, tmpIndex );
if( tmpIndex >= 0 )
tmpIndex++;
}
tmpIndex = index;
List<TopComponent> opened = source.getOpenedTopComponents();
for( TopComponent tc : opened ) {
target.addOpenedTopComponent( tc, tmpIndex );
if( tmpIndex >= 0 )
tmpIndex++;
TopComponentTracker.getDefault().add( tc, target );
}
if( source.isPermanent() ) {
target.addOtherName( source.getName() );
for( String otherName : source.getOtherNames() ) {
target.addOtherName( otherName );
}
}
if( source.isPermanent() )
model.makeModePermanent( target );
if( target.getState() == Constants.MODE_STATE_SEPARATED ) {
setPreviousMode( target, prevMode );
setPreviousConstraints( target, prevConstraints );
}
model.removeMode( source );
}
/**
* Find the mode which the TopComponents of the given mode were in before.
* @param mode
* @return
* @since 2.30
*/
private ModeImpl getPreviousMode( ModeImpl mode ) {
ModeImpl prevMode = null;
if( mode.getState() == Constants.MODE_STATE_JOINED ) {
prevMode = mode;
} else {
List<String> ids = mode.getTopComponentsIDs();
if( !ids.isEmpty() )
prevMode = model.getModeTopComponentPreviousMode( mode, ids.get( 0 ) );
}
if( prevMode != null && !getModes().contains( prevMode ) )
prevMode = null;
return prevMode;
}
/**
* Find previous split constraints of TopComponents in the given mode.
* @param mode
* @return
* @since 2.30
*/
private SplitConstraint[] getPreviousConstraints( ModeImpl mode ) {
ModeImpl prevMode = getPreviousMode( mode );
if( null != prevMode )
return mode.getConstraints();
List<String> ids = mode.getTopComponentsIDs();
if( !ids.isEmpty() )
return model.getModeTopComponentPreviousConstraints( mode, ids.get( 0 ) );
return null;
}
/**
* Set previous mode for all TopComponents in given mode.
* @param mode Mode to adjust
* @param prevMode Previous mode
* @since 2.30
*/
private void setPreviousMode( ModeImpl mode, ModeImpl prevMode ) {
for( String tcId : mode.getTopComponentsIDs() ) {
int prevIndex = model.getModeTopComponentPreviousIndex( mode, tcId );
model.setModeTopComponentPreviousMode( mode, tcId, prevMode, prevIndex );
}
}
/**
* Set previous split constraints for all TopComponents in given mode.
* @param mode
* @param prevConstraints
* @since 2.30
*/
private void setPreviousConstraints( ModeImpl mode, SplitConstraint[] prevConstraints ) {
for( String tcId : mode.getTopComponentsIDs() ) {
model.setModeTopComponentPreviousConstraints( mode, tcId, prevConstraints );
}
}
private void dockMode( ModeImpl prevMode, ModeImpl floatingMode ) {
ModeImpl floatingPrevMode = getPreviousMode( floatingMode );
List<TopComponent> opened = prevMode.getOpenedTopComponents();
for( TopComponent tc : opened ) {
floatingMode.addOpenedTopComponent( tc );
}
for( String tcID: prevMode.getClosedTopComponentsIDs() ) {
floatingMode.addUnloadedTopComponent( tcID );
}
model.dockMode( prevMode, floatingMode );
setPreviousMode( floatingMode, null );
setPreviousConstraints( floatingMode, null );
if( null != floatingPrevMode && floatingPrevMode.getTopComponentsIDs().isEmpty() ) {
model.removeMode( floatingPrevMode );
}
}
/**
* User minimized the whole Mode
* @param mode
* @since 2.30
*/
void userMinimizedMode( ModeImpl mode ) {
List<TopComponent> opened = mode.getOpenedTopComponents();
TopComponent selTc = mode.getSelectedTopComponent();
String side = getSlideSideForMode( mode );
for( TopComponent tc : opened ) {
slide( tc, mode, side );
}
WindowManagerImpl wm = WindowManagerImpl.getInstance();
int index = 0;
for( TopComponent tc : opened ) {
ModeImpl newMode = ( ModeImpl ) wm.findMode( tc );
if( null == newMode )
continue;
String tcId = wm.findTopComponentID( tc );
model.setModeTopComponentPreviousMode(newMode, tcId, mode, index++);
}
setModeMinimized( mode, true );
if( null != selTc ) {
mode.setPreviousSelectedTopComponentID( wm.findTopComponentID(selTc) );
}
}
/**
* User restored a Mode from minimized state in given sliding Mode.
* @param slidingMode
* @param modeToRestore
* @since 2.35
*/
void userRestoredMode( ModeImpl slidingMode, ModeImpl modeToRestore ) {
TopComponent tcToSelect = modeToRestore.getPreviousSelectedTopComponent();
setModeMinimized( modeToRestore, false );
WindowManagerImpl wm = WindowManagerImpl.getInstance();
for( TopComponent tc : slidingMode.getOpenedTopComponents() ) {
String id = wm.findTopComponentID( tc );
ModeImpl prevMode = model.getModeTopComponentPreviousMode( slidingMode, id );
if( null != prevMode && prevMode.equals( modeToRestore ) ) {
int prevIndex = model.getModeTopComponentPreviousIndex(slidingMode, id);
moveTopComponentIntoMode(prevMode, tc, prevIndex);
}
}
if( null != tcToSelect )
modeToRestore.setSelectedTopComponent( tcToSelect );
if(isVisible()) {
viewRequestor.scheduleRequest(
new ViewRequest(null, View.CHANGE_TOPCOMPONENT_AUTO_HIDE_DISABLED, null, null));
}
setActiveMode( modeToRestore );
}
@Override
public void userUndockedTopComponent(TopComponent tc, ModeImpl mode) {
Point tcLoc = tc.getLocation();
Dimension tcSize = tc.getSize();
SwingUtilities.convertPointToScreen(tcLoc, tc);
Rectangle bounds = new Rectangle(tcLoc, tcSize);
// #89100: update mode kind when undocking view in sliding mode
int modeKind = mode.getKind();
if (modeKind == Constants.MODE_KIND_SLIDING) {
modeKind = Constants.MODE_KIND_VIEW;
}
// #81479: unmaximize only if desirable
if (getCurrentMaximizedMode() == mode &&
mode.getOpenedTopComponents().size() == 1 &&
mode.getOpenedTopComponents().get(0) == tc) {
switchMaximizedMode(null);
}
ModeImpl newMode = createFloatingMode( bounds, modeKind );
moveTopComponentIntoMode( newMode, tc );
updateViewAfterDnD(false);
WindowManagerImpl.getInstance().doFirePropertyChange(
WindowManager.PROP_MODES, null, null);
}
@Override
public void userDockedTopComponent(TopComponent tc, ModeImpl mode) {
ModeImpl dockTo = null;
// find saved previous mode or at least constraints (=the place) to dock back into
String tcID = WindowManagerImpl.getInstance().findTopComponentID(tc);
ModeImpl source = (ModeImpl) WindowManagerImpl.getInstance().findMode(tc);
dockTo = model.getModeTopComponentPreviousMode(source, tcID);
int dockIndex = model.getModeTopComponentPreviousIndex(source, tcID);
int modeKind = mode.getKind();
if ((dockTo == null) || !model.getModes().contains(dockTo) || dockTo.getState() == Constants.MODE_STATE_SEPARATED) {
// mode to dock to back isn't valid anymore, try constraints
SplitConstraint[] constraints = model.getModeTopComponentPreviousConstraints(source, tcID);
if (constraints != null) {
//there might be some mode with the same constraints already
dockTo = findJoinedMode( modeKind, constraints );
if( null == dockTo ) {
// create mode with the same constraints to dock topcomponent back into
dockTo = WindowManagerImpl.getInstance().createModeImpl(
ModeImpl.getUnusedModeName(), modeKind, false);
model.addMode(dockTo, constraints);
}
}
}
if (dockTo == null) {
// fallback, previous saved mode not found somehow, use default modes
dockTo = modeKind == Constants.MODE_KIND_EDITOR
? WindowManagerImpl.getInstance().getDefaultEditorMode()
: WindowManagerImpl.getInstance().getDefaultViewMode();
}
moveTopComponentIntoMode(dockTo, tc, dockIndex);
updateViewAfterDnD(false);
WindowManagerImpl.getInstance().doFirePropertyChange(
WindowManager.PROP_MODES, null, null);
}
/**
*
* @param draggable
* @since 2.37
*/
void userStartedKeyboardDragAndDrop( TopComponentDraggable draggable ) {
viewRequestor.userStartedKeyboardDragAndDrop( draggable );
}
private ModeImpl findJoinedMode( int modeKind, SplitConstraint[] constraints ) {
for( ModeImpl m : getModes() ) {
if( m.getKind() != modeKind || m.getState() != Constants.MODE_STATE_JOINED )
continue;
SplitConstraint[] modeConstraints = m.getConstraints();
if( modeConstraints.length != constraints.length )
continue;
boolean match = true;
for( int i=0; i<constraints.length; i++ ) {
if( constraints[i].orientation != modeConstraints[i].orientation
|| constraints[i].index != modeConstraints[i].index ) {
match = false;
break;
}
}
if( match )
return m;
}
return null;
}
private boolean moveTopComponentIntoMode(ModeImpl mode, TopComponent tc) {
return moveTopComponentIntoMode(mode, tc, -1);
}
private boolean moveTopComponentIntoMode(ModeImpl mode, TopComponent tc, int index) {
boolean moved = false;
boolean intoSliding = mode.getKind() == Constants.MODE_KIND_SLIDING;
boolean intoSeparate = mode.getState() == Constants.MODE_STATE_SEPARATED;
ModeImpl prevMode = null;
String tcID = WindowManagerImpl.getInstance().findTopComponentID(tc);
// XXX
if(!mode.canContain(tc)) {
return false;
}
TopComponentTracker.getDefault().add( tc, mode );
for(Iterator it = model.getModes().iterator(); it.hasNext(); ) {
ModeImpl m = (ModeImpl)it.next();
if(model.containsModeTopComponent(m, tc)) {
if (m.getKind() == Constants.MODE_KIND_SLIDING ||
m.getState() == Constants.MODE_STATE_SEPARATED) {
prevMode = model.getModeTopComponentPreviousMode(m, tcID);
} else {
prevMode = m;
}
break;
}
}
int prevIndex = prevMode != null && (intoSliding || intoSeparate) ? prevMode.getOpenedTopComponentsIDs().indexOf( tcID ) : -1;
if(removeTopComponentFromOtherModes(mode, tc)) {
moved = true;
}
if (index > -1) {
model.insertModeOpenedTopComponent(mode, tc, index);
} else {
model.addModeOpenedTopComponent(mode, tc);
}
if (prevMode != null && (intoSliding || intoSeparate)) {
if( intoSeparate && mode.isPermanent() ) {
//TC is being moved to a undocked mode so from now it will be
//groupped with other TCs in that mode
//so change the previous mode to ensure it docks back into
//the same mode as other TCs in this mode
List<String> ids = mode.getTopComponentsIDs();
if( !ids.isEmpty() ) {
ModeImpl groupPrevMode = model.getModeTopComponentPreviousMode( mode, ids.get( 0 ) );
if( null != groupPrevMode ) {
prevMode = groupPrevMode;
}
}
}
// remember previous mode and constraints for precise de-auto-hide
model.setModeTopComponentPreviousMode(mode, tcID, prevMode, prevIndex);
model.setModeTopComponentPreviousConstraints(mode, tcID, model.getModeConstraints(prevMode));
}
if (!intoSliding) {
// make the target mode active after dragging..
model.setActiveMode(mode);
model.setModeSelectedTopComponent(mode, tc);
} else {
sortSlidedOutTopComponentsByPrevModes( mode );
// don't activate sliding modes, it means the component slides out, that's a bad thing..
// make some other desktop mode active
if(prevMode != null && prevMode == getActiveMode()
&& prevMode.getOpenedTopComponents().isEmpty()) {
setSomeModeActive();
}
// check the drop mode if it was already used, if not, assign it some reasonable size,
// according to the current component.
if (mode.getBounds().width == 0 && mode.getBounds().height == 0) {
// now we have the sliding mode in initial state
mode.setBounds(tc.getBounds());
}
}
//#232061
if( null != tc.getClientProperty("windnd_cloned_tc")) {
tc.putClientProperty("windnd_cloned_tc", null);
WindowManagerImpl.getInstance().notifyTopComponentOpened(tc);
}
return moved;
}
private void sortSlidedOutTopComponentsByPrevModes( ModeImpl slidingMode ) {
if( !Switches.isModeSlidingEnabled() )
return;
List<String> opened = slidingMode.getOpenedTopComponentsIDs();
}
private void updateViewAfterDnD(boolean unmaximize) {
if( unmaximize ) {
switchMaximizedMode(null);
}
if(isVisible()) {
viewRequestor.scheduleRequest(
new ViewRequest(null, View.CHANGE_DND_PERFORMED, null, null));
FloatingWindowTransparencyManager.getDefault().update();
}
}
// Sliding
/** Adds mode into model and requests view (if needed). */
public void addSlidingMode(ModeImpl mode, ModeImpl original, String side, Map<String,Integer> slideInSizes) {
ModeImpl targetMode = model.getSlidingMode(side);
if (targetMode != null) {
//TODO what to do here.. something there already
return;
}
targetMode = WindowManagerImpl.getInstance().createModeImpl(
ModeImpl.getUnusedModeName(), Constants.MODE_KIND_SLIDING, false);
model.addSlidingMode(mode, side, slideInSizes);
if(isVisible()) {
viewRequestor.scheduleRequest(
new ViewRequest(null, View.CHANGE_MODE_ADDED, null, mode));
}
WindowManagerImpl.getInstance().doFirePropertyChange(
WindowManager.PROP_MODES, null, null);
}
@Override
public void userEnabledAutoHide(TopComponent tc, ModeImpl source, String targetSide) {
if( isViewMaximized() )
switchMaximizedMode( null );
String tcID = WindowManagerImpl.getInstance().findTopComponentID(tc);
if( isEditorMaximized() )
setTopComponentDockedInMaximizedMode( tcID, false );
slide( tc, source, targetSide );
}
/**
* Slide out the given TopComponent
*/
void slide(TopComponent tc, ModeImpl source, String targetSide) {
ModeImpl targetMode = model.getSlidingMode(targetSide);
if (targetMode == null) {
targetMode = WindowManagerImpl.getInstance().createModeImpl(
ModeImpl.getUnusedModeName(), Constants.MODE_KIND_SLIDING, false);
model.addSlidingMode(targetMode, targetSide, null);
model.setModeBounds(targetMode, new Rectangle(tc.getBounds()));
}
ModeImpl oldActive = getActiveMode();
moveTopComponentIntoMode(targetMode, tc);
ModeImpl newActive = getActiveMode();
if(isVisible()) {
viewRequestor.scheduleRequest(
new ViewRequest(null, View.CHANGE_TOPCOMPONENT_AUTO_HIDE_ENABLED, null, null));
}
if(oldActive != newActive) {
WindowManagerImpl.getInstance().doFirePropertyChange(
WindowManagerImpl.PROP_ACTIVE_MODE, oldActive, newActive);
}
// Notify new active.
if(newActive != null) {
// Notify registry.
WindowManagerImpl.notifyRegistryTopComponentActivated(
newActive.getSelectedTopComponent());
} else {
WindowManagerImpl.notifyRegistryTopComponentActivated(null);
}
}
@Override
public void userResizedSlidingMode(ModeImpl mode, Rectangle rect) {
model.setModeBounds(mode, new Rectangle(rect));
//remember user's settings for the slided-in TopComponent size
String side = model.getSlidingModeConstraints( mode );
model.setSlideInSize( side,
mode.getSelectedTopComponent(),
Constants.BOTTOM.equals( side ) || Constants.TOP.equals(side) ? rect.height : rect.width );
if( null != mode.getSelectedTopComponent() ) {
String tcID = WindowManagerImpl.getInstance().findTopComponentID( mode.getSelectedTopComponent() );
model.setTopComponentMaximizedWhenSlidedIn( tcID, false );
}
}
@Override
public void userDisabledAutoHide(TopComponent tc, ModeImpl source) {
// unmaximize if needed
if( isViewMaximized() ) {
switchMaximizedMode(null);
}
String tcID = WindowManagerImpl.getInstance().findTopComponentID(tc);
if( isEditorMaximized() )
setTopComponentDockedInMaximizedMode( tcID, true );
unSlide( tc, source );
}
/**
* Cancel the sliding mode of the given TopComponent.
*/
private ModeImpl unSlide(TopComponent tc, ModeImpl source) {
String tcID = WindowManagerImpl.getInstance().findTopComponentID(tc);
ModeImpl targetMode = model.getModeTopComponentPreviousMode(source, tcID);
int targetIndex = model.getModeTopComponentPreviousIndex(source, tcID);
if ((targetMode == null) || !model.getModes().contains(targetMode)) {
// mode to return to isn't valid anymore, try constraints
SplitConstraint[] constraints = model.getModeTopComponentPreviousConstraints(source, tcID);
if (constraints != null) {
// create mode with the same constraints to dock topcomponent back into
targetMode = WindowManagerImpl.getInstance().createModeImpl(
ModeImpl.getUnusedModeName(), source.getKind(), false);
model.addMode(targetMode, constraints);
}
}
if (targetMode == null) {
// fallback, previous saved mode not found somehow, use default modes
targetMode = source.getKind() == Constants.MODE_KIND_EDITOR
? WindowManagerImpl.getInstance().getDefaultEditorMode()
: WindowManagerImpl.getInstance().getDefaultViewMode();
}
moveTopComponentIntoMode(targetMode, tc, targetIndex);
targetMode.setMinimized( false );
if (source.isEmpty()) {
model.removeMode(source);
}
if(isVisible()) {
viewRequestor.scheduleRequest(
new ViewRequest(null, View.CHANGE_TOPCOMPONENT_AUTO_HIDE_DISABLED, null, null));
}
WindowManagerImpl.getInstance().doFirePropertyChange(
WindowManagerImpl.PROP_ACTIVE_MODE, null, getActiveMode());
return targetMode;
}
void setTopComponentMinimized( TopComponent tc, boolean minimized ) {
if( !tc.isOpened() ) {
return;
}
if( isTopComponentMinimized( tc ) == minimized ) {
return; //nothing todo
}
ModeImpl mode = ( ModeImpl ) WindowManagerImpl.getInstance().findMode( tc );
if( null == mode || mode.getState() != Constants.MODE_STATE_JOINED ) {
return;
}
if( minimized ) {
slide( tc, mode, guessSlideSide( tc ) );
} else {
unSlide( tc, mode );
}
//#207438 - make sure global minimize/dock actions get updated
WindowManagerImpl.getInstance().doFirePropertyChange(
WindowManager.PROP_MODES, null, null);
}
boolean isTopComponentMinimized( TopComponent tc ) {
if( !tc.isOpened() ) {
return false;
}
ModeImpl mode = ( ModeImpl ) WindowManagerImpl.getInstance().findMode( tc );
return null != mode && mode.getKind() == Constants.MODE_KIND_SLIDING;
}
/**
* @return The mode where the given TopComponent had been before it was moved to sliding or separate mode.
*/
public ModeImpl getModeTopComponentPreviousMode(String tcID, ModeImpl currentSlidingMode) {
return model.getModeTopComponentPreviousMode(currentSlidingMode, tcID);
}
/**
* @return The position (tab index) of the given TopComponent before it was moved to sliding or separate mode.
*/
public int getModeTopComponentPreviousIndex(String tcID, ModeImpl currentSlidingMode) {
return model.getModeTopComponentPreviousIndex(currentSlidingMode, tcID);
}
/**
* Remember the mode and position where the given TopComponent was before moving into sliding or separate mode.
*
* @param tcID TopComponent's id
* @param currentSlidingMode The mode where the TopComponent is at the moment.
* @param prevMode The mode where the TopComponent had been before it was moved to the sliding mode.
* @param prevIndex Tab index of the TopComponent before it was moved to the new mode.
*/
public void setModeTopComponentPreviousMode(String tcID, ModeImpl currentSlidingMode, ModeImpl prevMode, int prevIndex) {
model.setModeTopComponentPreviousMode(currentSlidingMode, tcID, prevMode, prevIndex);
}
Map<String,Integer> getSlideInSizes( String side ) {
return model.getSlideInSizes( side );
}
/**
* Set the state of the TopComponent when the editor is maximized.
*
* @param tcID TopComponent id
* @param docked True if the TopComponent should stay docked in maximized editor mode,
* false if it should slide out when the editor is maximized.
*/
void setTopComponentDockedInMaximizedMode( String tcID, boolean docked ) {
if( docked )
model.getMaximizedDockingStatus().addDocked( tcID );
else
model.getMaximizedDockingStatus().addSlided( tcID );
}
/**
* Get the state of the TopComponent when the editor is maximized.
*
* @param tcID TopComponent id.
* @return True if the TopComponent should stay docked in maximized editor mode,
* false if it should slide out when the editor is maximized.
*/
boolean isTopComponentDockedInMaximizedMode( String tcID ) {
return model.getMaximizedDockingStatus().isDocked( tcID );
}
/**
* Set the state of the TopComponent when no mode is maximized.
*
* @param tcID TopComponent id
* @param slided True if the TopComponent is slided in the default mode,
* false if it is docked.
*/
void setTopComponentSlidedInDefaultMode( String tcID, boolean slided ) {
if( slided )
model.getDefaultDockingStatus().addSlided( tcID );
else
model.getDefaultDockingStatus().addDocked( tcID );
}
/**
* Get the state of the TopComponent when it is slided-in.
*
* @param tcID TopComponent id.
* @return true if the TopComponent is maximized when slided-in.
*/
boolean isTopComponentMaximizedWhenSlidedIn( String tcID ) {
return model.isTopComponentMaximizedWhenSlidedIn( tcID );
}
/**
* Set the state of the TopComponent when it is slided-in.
*
* @param tcID TopComponent id.
* @param maximized true if the TopComponent is maximized when slided-in.
*/
void setTopComponentMaximizedWhenSlidedIn( String tcID, boolean maximized ) {
model.setTopComponentMaximizedWhenSlidedIn( tcID, maximized );
}
void userToggledTopComponentSlideInMaximize( String tcID ) {
setTopComponentMaximizedWhenSlidedIn( tcID, !isTopComponentMaximizedWhenSlidedIn( tcID ) );
if( isVisible() ) {
TopComponent tc = WindowManagerImpl.getInstance().findTopComponent( tcID );
ModeImpl mode = WindowManagerImpl.getInstance().findModeForOpenedID( tcID );
if( null != tc && null != mode && null != mode.getSide() ) {
viewRequestor.scheduleRequest (
new ViewRequest(tc, View.CHANGE_MAXIMIZE_TOPCOMPONENT_SLIDE_IN, null, mode.getSide()));
}
}
}
/**
* Get the state of the TopComponent when no mode is maximized.
*
* @param tcID TopComponent id.
* @return True if the TopComponent is slided in the default mode,
* false if it is docked.
*/
boolean isTopComponentSlidedInDefaultMode( String tcID ) {
return model.getDefaultDockingStatus().isSlided( tcID );
}
boolean isEditorMaximized() {
return null != model.getEditorMaximizedMode();
}
boolean isViewMaximized() {
return null != model.getViewMaximizedMode();
}
/**
* Slide-out or dock opened TopComponent according to their previous state.
*/
private void restoreViews( DockingStatus viewStatus ) {
WindowManagerImpl wm = WindowManagerImpl.getInstance();
Set<? extends Mode> modes = getModes();
for( Iterator<? extends Mode> i=modes.iterator(); i.hasNext(); ) {
ModeImpl modeImpl = (ModeImpl)i.next();
if( modeImpl.getState() == Constants.MODE_STATE_SEPARATED )
continue;
if( modeImpl.getKind() == Constants.MODE_KIND_VIEW ) {
List<TopComponent> views = getModeOpenedTopComponents( modeImpl );
Collections.reverse( views );
for( Iterator<TopComponent> j=views.iterator(); j.hasNext(); ) {
TopComponent tc = j.next();
String tcID = wm.findTopComponentID( tc );
if( viewStatus.shouldSlide( tcID ) ) {
slide( tc, modeImpl, guessSlideSide( tc ) );
}
}
} else if( modeImpl.getKind() == Constants.MODE_KIND_SLIDING ) {
List<TopComponent> views = getModeOpenedTopComponents( modeImpl );
Collections.reverse( views );
for( Iterator<TopComponent> j=views.iterator(); j.hasNext(); ) {
TopComponent tc = j.next();
String tcID = wm.findTopComponentID( tc );
if( viewStatus.shouldDock( tcID ) ) {
unSlide( tc, modeImpl );
}
}
}
}
//now that all views are slided/restore make sure the right views are selected in each mode
for( Iterator<? extends Mode> i=modes.iterator(); i.hasNext(); ) {
ModeImpl modeImpl = (ModeImpl)i.next();
if( modeImpl.getState() == Constants.MODE_STATE_SEPARATED )
continue;
if( modeImpl.getKind() == Constants.MODE_KIND_VIEW ) {
//make sure that the same view is selected as before
TopComponent prevActiveTc = modeImpl.getPreviousSelectedTopComponent();
if( null != prevActiveTc ) {
setModeSelectedTopComponent( modeImpl, prevActiveTc );
}
}
}
}
/**
* Slide out all non-editor TopComponents.
*/
private void slideAllViews() {
//find appropriate sliding bars first, otherwise the split hierarchy
//will change while sliding some windows so the sliding positions would be wrong
Map<TopComponent, String> tc2slideSide = new HashMap<TopComponent, String>(30);
Set<? extends Mode> modes = getModes();
for( Iterator<? extends Mode> i=modes.iterator(); i.hasNext(); ) {
ModeImpl modeImpl = (ModeImpl)i.next();
if( modeImpl.getKind() == Constants.MODE_KIND_VIEW
&& modeImpl != getViewMaximizedMode()
&& modeImpl.getState() != Constants.MODE_STATE_SEPARATED ) {
List<TopComponent> views = getModeOpenedTopComponents( modeImpl );
for( Iterator<TopComponent> j=views.iterator(); j.hasNext(); ) {
TopComponent tc = j.next();
tc2slideSide.put( tc, guessSlideSide( tc ) );
}
}
}
for( Iterator<? extends Mode> i=modes.iterator(); i.hasNext(); ) {
ModeImpl modeImpl = (ModeImpl)i.next();
if( modeImpl.getKind() == Constants.MODE_KIND_VIEW
&& modeImpl != getViewMaximizedMode()
&& modeImpl.getState() != Constants.MODE_STATE_SEPARATED ) {
List<TopComponent> views = getModeOpenedTopComponents( modeImpl );
Collections.reverse( views );
for( Iterator<TopComponent> j=views.iterator(); j.hasNext(); ) {
TopComponent tc = j.next();
slide( tc, modeImpl, tc2slideSide.get( tc ) );
}
}
}
}
// ControllerHandler <<
////////////////////////////
/**
* Creates a new mode and moves the given TopComponent into it.
* @param tc
*/
void newTabGroup( TopComponent tc ) {
ModeImpl currentMode = ( ModeImpl ) WindowManagerImpl.getInstance().findMode( tc );
if( null == currentMode )
return;
ModeImpl newMode = attachModeToSide( currentMode, null, currentMode.getKind() );
moveTopComponentIntoMode( newMode, tc );
updateViewAfterDnD( true );
tc.requestActive();
WindowManagerImpl.getInstance().doFirePropertyChange(
WindowManager.PROP_MODES, null, null);
}
/**
* Removes the given mode and moves all its TopComponents to some other mode.
* @param mode
*/
void collapseTabGroup( ModeImpl mode ) {
ModeImpl neighbor = findClosestNeighbor( mode );
if( null == neighbor )
return;
TopComponent selTC = mode.getSelectedTopComponent();
mergeModes( mode, neighbor, -1 );
if( null != selTC )
selTC.requestActive();
updateViewAfterDnD( true );
WindowManagerImpl.getInstance().doFirePropertyChange(
WindowManager.PROP_MODES, null, null);
}
/**
* Find mode that is closest to the given mode. Usually it's a neighbor at the
* same level in the split hierarchy.
* @param mode
* @return Closest neighbor to the given mode or null.
*/
private ModeImpl findClosestNeighbor( ModeImpl mode ) {
ArrayList<ModeImpl> modes = new ArrayList<ModeImpl>( model.getModes().size() );
ModeImpl inSplitLeftNeighbor = null;
ModeImpl inSplitRightNeighbor = null;
SplitConstraint[] sc = mode.getConstraints();
int index = sc[sc.length-1].index;
for( ModeImpl m : model.getModes() ) {
if( mode == m || m.getKind() != mode.getKind() || m.getState() != mode.getState() )
continue;
SplitConstraint[] otherSc = m.getConstraints();
if( sameSplit( sc, otherSc) ) {
int otherIndex = otherSc[sc.length-1].index;
if( index < otherIndex ) {
if( null == inSplitLeftNeighbor || otherIndex > inSplitLeftNeighbor.getConstraints()[sc.length-1].index )
inSplitLeftNeighbor = m;
} else {
if( null == inSplitRightNeighbor || otherIndex < inSplitRightNeighbor.getConstraints()[sc.length-1].index )
inSplitRightNeighbor = m;
}
}
modes.add( m );
}
if( modes.isEmpty() )
return null;
if( null != inSplitLeftNeighbor )
return inSplitLeftNeighbor;
if( null != inSplitRightNeighbor )
return inSplitRightNeighbor;
Collections.sort( modes, new Comparator<ModeImpl>() {
@Override
public int compare( ModeImpl o1, ModeImpl o2 ) {
SplitConstraint[] sc1 = o1.getConstraints();
SplitConstraint[] sc2 = o2.getConstraints();
return sc1.length - sc2.length;
}
});
return modes.get( 0 );
}
/**
* Check if the given constraints point to docking areas at the same level
* in the split hierarchy.
* @param sc1
* @param sc2
* @return
*/
private boolean sameSplit( SplitConstraint[] sc1, SplitConstraint[] sc2 ) {
if( sc1.length != sc2.length )
return false;
for( int i=0; i<sc1.length-1; i++ ) {
if( sc1[i].orientation != sc2[i].orientation || sc1[i].index != sc2[i].index )
return false;
}
return sc1[sc1.length-1].orientation == sc2[sc2.length-1].orientation;
}
}