blob: 2b2dc6ad3e3e10e23cb7f964fb4a13f7e7727434 [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 org.openide.windows.Mode;
import org.openide.windows.TopComponent;
import org.openide.windows.Workspace;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.swing.SwingUtilities;
import java.awt.Image;
import java.awt.Rectangle;
import java.io.IOException;
import java.util.Collection;
import org.netbeans.core.windows.persistence.ModeConfig;
import org.netbeans.core.windows.persistence.PersistenceManager;
import org.openide.util.Exceptions;
/** This class is an implementation of Mode interface.
* It designates 'place' on screen, at wich TopComponent can occure.
*
* @author Peter Zavadsky
*/
public final class ModeImpl implements Mode.Xml {
/** Name constant as a base for nonamed modes. */
private static final String MODE_ANONYMOUS_NAME = "anonymousMode"; // NOI18N
/** asociated property change support for firing property changes */
private final PropertyChangeSupport changeSupport = new PropertyChangeSupport(this);
/** Debugging flag. */
private static final boolean DEBUG = Debug.isLoggable(ModeImpl.class);
/** Construct new mode with given properties */
private ModeImpl(String name, int state, int kind, boolean permanent) {
getCentral().createModeModel(this, name, state, kind, permanent);
}
/** Factory method which creates <code>ModeImpl</code> instances. */
public static ModeImpl createModeImpl(String name, int state, int kind, boolean permanent) {
return new ModeImpl(name, state, kind, permanent);
}
///////////////////////////////////////////////////////////////////
// Start of org.openide.windows.Mode interface implementation.
///////////////////////////////////////////////////////////////////
/** Gets the programmatic name of this mode.
* This name should be unique, as it is used to find modes etc.
* Implements <code>Mode</code> interface method.
* @return programmatic name of this mode */
@Override
public String getName () {
WindowManagerImpl.warnIfNotInEDT();
return getCentral().getModeName(this);
}
/**
* @return A list of Mode's additional names.
* @since 2.30
*/
Collection<String> getOtherNames() {
WindowManagerImpl.warnIfNotInEDT();
return getCentral().getModeOtherNames(this);
}
/**
* Add another mode name.
* @param modeOtherName
* @since 2.30
*/
void addOtherName( String modeOtherName ) {
WindowManagerImpl.warnIfNotInEDT();
getCentral().addModeOtherName(this, modeOtherName);
}
/** Gets display name of this mode.
** Implements <code>Mode</code> interface method.
* @return Human presentable name of this mode implementation
* @deprecated It is not used anymore. This impl delegated to {@link #getName} method. */
@Override
public String getDisplayName () {
WindowManagerImpl.warnIfNotInEDT();
return getName();
}
/** Gets icon for this mode.
* Implements <code>Mode</code> interface method.
* @return null
* @deprecated It is not used anymore. */
@Override
public Image getIcon () {
WindowManagerImpl.warnIfNotInEDT();
return null;
}
/** Indicates whether specified <code>TopComponent</code> can be docked
* into this <code>Mode</code>.
* Implements <code>Mode</code> interface method.
* @return <code>true</code> */
@Override
public boolean canDock(TopComponent tc) {
WindowManagerImpl.warnIfNotInEDT();
return true;
}
/** Attaches a component to a mode for this workspace.
* If the component is in different mode on this desktop, it is
* removed from the original and moved to this one.
* Implements <code>Mode</code> interface method.
*
* @param tc top component to dock into this mode
* @return true if top component was succesfully docked to this
* mode, false otherwise */
@Override
public boolean dockInto(TopComponent tc) {
WindowManagerImpl.warnIfNotInEDT();
return dockIntoImpl(tc, true);
}
/** Sets bounds of this mode.
* Implements <code>Mode</code> interface method.
* @param rect bounds for the mode */
@Override
public void setBounds (Rectangle bounds) {
WindowManagerImpl.warnIfNotInEDT();
getCentral().setModeBounds(this, bounds);
}
/** Getter for current bounds of the mode.
* Implements <code>Mode</code> interface method.
* @return the bounds of the mode
*/
@Override
public Rectangle getBounds () {
WindowManagerImpl.warnIfNotInEDT();
return getCentral().getModeBounds(this);
}
/** Getter for asociated workspace.
* Implements <code>Mode</code> interface method.
* @return The workspace instance to which is this mode asociated.
* @deprecated XXX Don't use anymore.
*/
@Override
public Workspace getWorkspace () {
WindowManagerImpl.warnIfNotInEDT();
// Here is the only fake workspace.
return WindowManagerImpl.getInstance();
}
/** Gets array of <code>TopComponent</code>S in this mode.
* Implements <code>Mode</code> interface method.
* @return array of top components which are currently
* docked in this mode. May return empty array if no top component
* is docked in this mode.
*/
@Override
public TopComponent[] getTopComponents() {
WindowManagerImpl.warnIfNotInEDT();
return getCentral().getModeTopComponents(this).toArray(new TopComponent[0]);
}
/** Adds listener to the property changes.
* Implements <code>Mode</code> interface support. */
@Override
public void addPropertyChangeListener (PropertyChangeListener pchl) {
changeSupport.addPropertyChangeListener(pchl);
}
/** Removes listener to the property changes.
* Implements <code>Mode</code> interface method. */
@Override
public void removePropertyChangeListener (PropertyChangeListener pchl) {
changeSupport.removePropertyChangeListener(pchl);
}
///////////////////////////////////////////////////////////////////
// End of org.openide.windows.Mode interface implementation.
///////////////////////////////////////////////////////////////////
/** Actually performs the docking operation.
* @param tc top component to dock into this mode
* @param orderWeight weight for ordering. Smaller weight number means
* smaller position index, which means closer to the top or start in
* visual representations
* @param select <code>true</code> if the docked <code>TopComponent</code>
* will be selected afterwards
* @return true if top component was succesfully docked to this */
private boolean dockIntoImpl(final TopComponent tc, final boolean select) {
if(DEBUG) {
Debug.log(ModeImpl.class, "Docking tc=" + tc.getName() + " into mode=" + this); // NOI18N
Debug.dumpStack(ModeImpl.class);
}
boolean opened = false;
// PENDING
// Preferably all in one step.
ModeImpl mode = (ModeImpl)WindowManagerImpl.getInstance().findMode(tc);
if(mode != null && mode != this) {
// XXX if only closin (mode.close(tc)) there could happen,
// there is the same TopComponent as closed in two modes. Revise.
opened = tc.isOpened();
mode.removeTopComponent(tc);
}
if( opened ) {
//don't close the TopComponent if it was opened in the previous mode
addOpenedTopComponent( tc );
} else {
addClosedTopComponent(tc);
}
return true;
}
/** Closes given top component. */
public void close(TopComponent tc) {
if(!getOpenedTopComponents().contains(tc)) {
return;
}
if (PersistenceHandler.isTopComponentPersistentWhenClosed(tc)) {
addClosedTopComponent(tc);
} else {
if (Boolean.TRUE.equals(tc.getClientProperty(Constants.KEEP_NON_PERSISTENT_TC_IN_MODEL_WHEN_CLOSED))) {
addClosedTopComponent(tc);
} else {
removeTopComponent(tc);
}
}
}
/** Gets list of opened TopComponentS. */
public List<TopComponent> getOpenedTopComponents() {
return getCentral().getModeOpenedTopComponents(this);
}
/** Sets selected TopComponent. */
public void setSelectedTopComponent(TopComponent tc) {
if(!getOpenedTopComponents().contains(tc)) {
return;
}
TopComponent old = getSelectedTopComponent();
if(tc == old) {
return;
}
getCentral().setModeSelectedTopComponent(this, tc);
}
/** Gets selected TopComponent. */
public TopComponent getSelectedTopComponent() {
WindowManagerImpl.assertEventDispatchThread();
return getCentral().getModeSelectedTopComponent(this);
}
/**
* Remember which top component was previously the selected one.
* Used when switching to/from maximized mode.
*/
public void setPreviousSelectedTopComponentID(String tcId) {
String old = getPreviousSelectedTopComponentID();
if(null != tcId && tcId.equals(old)) {
return;
}
getCentral().setModePreviousSelectedTopComponentID(this, tcId);
}
/**
* @return The top component that was the selected one before switching to/from
* the maximized mode.
*/
public TopComponent getPreviousSelectedTopComponent() {
String tcId = getPreviousSelectedTopComponentID();
TopComponent res = null;
if( null != tcId )
res = WindowManagerImpl.getInstance().findTopComponent(tcId);
WindowManagerImpl.assertEventDispatchThread();
return res;
}
/**
* @return The ID top component that was the selected one before switching to/from
* the maximized mode.
*/
public String getPreviousSelectedTopComponentID() {
WindowManagerImpl.assertEventDispatchThread();
return getCentral().getModePreviousSelectedTopComponentID(this);
}
public void addOpenedTopComponent(TopComponent tc) {
getCentral().addModeOpenedTopComponent(this, tc);
}
public void addOpenedTopComponentNoNotify(TopComponent tc) {
getCentral().addModeOpenedTopComponentNoNotify(this, tc);
}
public void addOpenedTopComponent(TopComponent tc, int index) {
getCentral().insertModeOpenedTopComponent( this, tc, index );
}
public void addClosedTopComponent(TopComponent tc) {
getCentral().addModeClosedTopComponent(this, tc);
}
public void addUnloadedTopComponent(String tcID) {
addUnloadedTopComponent( tcID, -1 );
}
public void addUnloadedTopComponent(String tcID, int index) {
getCentral().addModeUnloadedTopComponent(this, tcID, index);
}
public void setUnloadedSelectedTopComponent(String tcID) {
getCentral().setUnloadedSelectedTopComponent(this, tcID);
}
public void setUnloadedPreviousSelectedTopComponent(String tcID) {
getCentral().setUnloadedPreviousSelectedTopComponent(this, tcID);
}
public List<String> getOpenedTopComponentsIDs() {
return getCentral().getModeOpenedTopComponentsIDs(this);
}
public List<String> getClosedTopComponentsIDs() {
return getCentral().getModeClosedTopComponentsIDs(this);
}
public List<String> getTopComponentsIDs() {
return getCentral().getModeTopComponentsIDs(this);
}
/** Gets opened top component position in the mode */
public int getTopComponentTabPosition(TopComponent tc) {
return getCentral().getModeTopComponentTabPosition(this, tc);
}
/** Sets and updates the state of associated frame, if frame exists.
* Otherwise remembers state for futher use
*/
public void setFrameState(int state) {
getCentral().setModeFrameState(this, state);
}
/** @return state of the frame
* If frame exists, its real state is returned.
* Last remembered frame state is returned if frame currently
* doesn't exist. FrameType.NORMAL is returned as default if state cannot be
* obtained by mentioned procedures.
*/
public int getFrameState () {
return getCentral().getModeFrameState(this);
}
/** Indicates whether this mode is permanent, it means it is kept in model
* even in case it becomes empty. */
public boolean isPermanent () {
return getCentral().isModePermanent(this);
}
/** Indicates whether this mode has no TopComponents. */
public boolean isEmpty() {
return getCentral().isModeEmpty(this);
}
public boolean containsTopComponent(TopComponent tc) {
return getCentral().containsModeTopComponent(this, tc);
}
/** Gets state of mode. Either split or separate. */
public int getState() {
return getCentral().getModeState(this);
}
/** Gets kind, either editor or view. */
public int getKind() {
return getCentral().getModeKind(this);
}
/** Gets side, either null for view and editor kinds, a side constant for sliding kind.. */
public String getSide() {
return getCentral().getModeSide(this);
}
// Contstraints and split weights are saved in split structure at wm model level.
/** Sets constraints for mode. */
public void setConstraints(SplitConstraint[] constraints) {
WindowManagerImpl.getInstance().setModeConstraints(this, constraints);
}
/** @return Current constraints of this mode, null by default */
public SplitConstraint[] getConstraints() {
return WindowManagerImpl.getInstance().getModeConstraints(this);
}
/**
* @return True if this mode is minimized.
* @since 2.30
*/
public boolean isMinimized() {
return getCentral().isModeMinimized( this );
}
/**
* Mark this mode as minimized or docked.
* @param minimized
* @since 2.30
*/
public void setMinimized( boolean minimized ) {
getCentral().setModeMinimized( this, minimized );
}
/** Removes TopComponent from this mode. */
public void removeTopComponent(TopComponent tc) {
getCentral().removeModeTopComponent(this, tc);
}
public void removeTopComponents(Set topComponentSet) {
for(Iterator it = topComponentSet.iterator(); it.hasNext(); ) {
TopComponent tc = (TopComponent)it.next();
removeTopComponent(tc);
}
}
// XXX Only use for yet unloaded components, for PersistenceHandler only.
public void removeClosedTopComponentID(String tcID) {
getCentral().removeModeClosedTopComponentID(this, tcID);
}
// XXX It is used for user actions only, to prohibit mixing
// of view and editor components.
/** Indicates whether this mode can contain specified TopComponent. */
public boolean canContain(TopComponent tc) {
if(Constants.SWITCH_MODE_ADD_NO_RESTRICT
|| WindowManagerImpl.getInstance().isTopComponentAllowedToMoveAnywhere(tc)
|| Switches.isMixingOfEditorsAndViewsEnabled()) {
return true;
}
ModeImpl mode = (ModeImpl)WindowManagerImpl.getInstance().findMode(tc);
if(mode == null) {
return true;
}
// allow mixing of view and sliding modes
int myKind = getKind();
int otherKind = mode.getKind();
return (myKind == otherKind) ||
(myKind != Constants.MODE_KIND_EDITOR && otherKind != Constants.MODE_KIND_EDITOR);
}
void doFirePropertyChange(final String propName,
final Object oldValue, final Object newValue) {
// PENDING When #37529 finished, then uncomment the next row and move the
// checks of AWT thread away.
// WindowManagerImpl.assertEventDispatchThread();
if(SwingUtilities.isEventDispatchThread()) {
changeSupport.firePropertyChange(propName, oldValue, newValue);
} else {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
changeSupport.firePropertyChange(propName, oldValue, newValue);
}
});
}
}
/** @return string description of this mode */
@Override
public String toString () {
// #42995 - don't scream when toString called from non-AWT thread
return super.toString () + "[" + getCentral().getModeName(this) + "]"; // NOI18N
}
/** Accessor to central unit. Helper method. */
private static Central getCentral() {
return WindowManagerImpl.getInstance().getCentral();
}
////////////////////
// Utility methods>>
/*private*/ static String getUnusedModeName() {
String base = MODE_ANONYMOUS_NAME;
// don't allow base to be too long, because will act as file name too
// PENDING Maximal length is 20.
if (base.length() > 20) {
base = base.substring(0, 20);
}
// add numbers to the name
String result;
int modeNumber = 1;
WindowManagerImpl wm = WindowManagerImpl.getInstance();
while(wm.findMode(result = base + "_" + modeNumber) != null) { // NOI18N
modeNumber++;
}
return result;
}
// Utility methods<<
////////////////////
public void setModeName(String text) {
getCentral().setModeName(this, text);
}
@Override
public String toXml() {
ModeConfig config = PersistenceHandler.getDefault().getConfigFromMode(this);
try {
return PersistenceManager.getDefault().createXmlFromMode(config);
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
return "";
}
}
}