From ef475ea3b5fab5506da932f3f53ef8b2db2bbcfd Mon Sep 17 00:00:00 2001 From: Vassiliy Date: Wed, 20 Nov 2013 10:31:32 +0400 Subject: [PATCH] IDEA-97696 Custom tool windows layout is lost on exiting IDE with closed projects (cherry picked from commit 984cdfb) --- .../impl/stores/FileBasedStorage.java | 7 +- .../impl/stores/XmlElementStorage.java | 11 +- .../openapi/wm/impl/WindowManagerImpl.java | 110 ++++++++++-------- 3 files changed, 75 insertions(+), 53 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/FileBasedStorage.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/FileBasedStorage.java index 75b0999c66ae..874790f0c6df 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/FileBasedStorage.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/FileBasedStorage.java @@ -163,7 +163,7 @@ public class FileBasedStorage extends XmlElementStorage { @Override protected void doSave() throws StateStorageException { - if (myBlockSavingTheContent) { + if (myBlockSavingTheContentCausedByRead || myBlockSavingTheContentCausedByWrite) { return; } if (ApplicationManager.getApplication().isUnitTestMode() && myFile != null && StringUtil.startsWithChar(myFile.getPath(), '$')) { @@ -248,7 +248,8 @@ public class FileBasedStorage extends XmlElementStorage { @Override @Nullable protected Document loadDocument() throws StateStorageException { - myBlockSavingTheContent = false; + myBlockSavingTheContentCausedByRead = false; + myBlockSavingTheContentCausedByWrite = false; try { VirtualFile file = getVirtualFile(); if (file == null || file.isDirectory() || !file.isValid()) { @@ -271,7 +272,7 @@ public class FileBasedStorage extends XmlElementStorage { @Nullable private Document processReadException(@Nullable final Exception e) { boolean contentTruncated = e == null; - myBlockSavingTheContent = isProjectOrModuleFile() && !contentTruncated; + myBlockSavingTheContentCausedByRead = isProjectOrModuleFile() && !contentTruncated; if (!ApplicationManager.getApplication().isUnitTestMode() && !ApplicationManager.getApplication().isHeadlessEnvironment()) { if (e != null) { LOG.info(e); diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/XmlElementStorage.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/XmlElementStorage.java index 650419f6381a..93992e36f0f6 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/XmlElementStorage.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/XmlElementStorage.java @@ -51,7 +51,8 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { protected final StreamProvider myStreamProvider; protected final String myFileSpec; private final ComponentRoamingManager myComponentRoamingManager; - protected boolean myBlockSavingTheContent = false; + protected boolean myBlockSavingTheContentCausedByRead = false; + protected boolean myBlockSavingTheContentCausedByWrite = false; protected int myUpToDateHash = -1; protected int myProviderUpToDateHash = -1; private boolean mySavingDisabled = false; @@ -270,13 +271,15 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { try { setState(componentName, DefaultStateSerializer.serializeState(state, storageSpec)); + myBlockSavingTheContentCausedByWrite = false; } catch (WriteExternalException e) { + myBlockSavingTheContentCausedByWrite = true; LOG.debug(e); } } - private synchronized void setState(final String componentName, final Element element) { + private synchronized void setState(@NotNull String componentName, @NotNull Element element) { if (element.getAttributes().isEmpty() && element.getChildren().isEmpty()) { return; } @@ -325,7 +328,7 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { } private boolean _needsSave(int hash) { - if (myBlockSavingTheContent) { + if (myBlockSavingTheContentCausedByRead || myBlockSavingTheContentCausedByWrite) { return false; } @@ -374,7 +377,7 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { public final void save() throws StateStorageException { assert mySession == this; - if (myBlockSavingTheContent) { + if (myBlockSavingTheContentCausedByRead || myBlockSavingTheContentCausedByWrite) { return; } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/WindowManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/WindowManagerImpl.java index 8a59c04b2ab4..984b6551cb82 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/WindowManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/WindowManagerImpl.java @@ -27,13 +27,12 @@ import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationInfo; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ex.ApplicationInfoEx; -import com.intellij.openapi.components.ApplicationComponent; +import com.intellij.openapi.components.*; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.ui.popup.JBPopup; import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.util.NamedJDOMExternalizable; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.wm.IdeFrame; import com.intellij.openapi.wm.StatusBar; @@ -67,7 +66,11 @@ import java.util.Set; * @author Anton Katilin * @author Vladimir Kondratyev */ -public final class WindowManagerImpl extends WindowManagerEx implements ApplicationComponent, NamedJDOMExternalizable { +@State( + name = "WindowManager", + roamingType = RoamingType.GLOBAL, + storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/window.manager.xml")}) +public final class WindowManagerImpl extends WindowManagerEx implements ApplicationComponent, PersistentStateComponent { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.wm.impl.WindowManagerImpl"); @NonNls public static final String FULL_SCREEN = "ide.frame.full.screen"; @@ -689,12 +692,9 @@ public final class WindowManagerImpl extends WindowManagerEx implements Applicat return myCommandProcessor; } - public final String getExternalFileName() { - return "window.manager"; - } - - public final void readExternal(final Element element) { - final Element frameElement = element.getChild(FRAME_ELEMENT); + @Override + public void loadState(Element state) { + final Element frameElement = state.getChild(FRAME_ELEMENT); if (frameElement != null) { myFrameBounds = loadFrameBounds(frameElement); try { @@ -708,7 +708,7 @@ public final class WindowManagerImpl extends WindowManagerEx implements Applicat } } - final Element desktopElement = element.getChild(DesktopLayout.TAG); + final Element desktopElement = state.getChild(DesktopLayout.TAG); if (desktopElement != null) { myLayout.readExternal(desktopElement); } @@ -743,43 +743,61 @@ public final class WindowManagerImpl extends WindowManagerEx implements Applicat return bounds; } - public final void writeExternal(final Element element) { - // Save frame bounds - final Element frameElement = new Element(FRAME_ELEMENT); - element.addContent(frameElement); - final Project[] projects = ProjectManager.getInstance().getOpenProjects(); - final Project project = projects.length > 0 ? projects[0] : null; - - final IdeFrameImpl frame = getFrame(project); - if (frame != null) { - int extendedState = frame.getExtendedState(); - if (SystemInfo.isMacOSLion) { - @SuppressWarnings("deprecation") ComponentPeer peer = frame.getPeer(); - if (peer instanceof FramePeer) { - // frame.state is not updated by jdk so get it directly from peer - extendedState = ((FramePeer)peer).getState(); - } - } - boolean isMaximized = extendedState == Frame.MAXIMIZED_BOTH || - isFullScreenSupportedInCurrentOS() && frame.isInFullScreen(); - boolean usePreviousBounds = isMaximized && - myFrameBounds != null && - frame.getBounds().contains(new Point((int)myFrameBounds.getCenterX(), (int)myFrameBounds.getCenterY())); - Rectangle rectangle = usePreviousBounds ? myFrameBounds : frame.getBounds(); - frameElement.setAttribute(X_ATTR, Integer.toString(rectangle.x)); - frameElement.setAttribute(Y_ATTR, Integer.toString(rectangle.y)); - frameElement.setAttribute(WIDTH_ATTR, Integer.toString(rectangle.width)); - frameElement.setAttribute(HEIGHT_ATTR, Integer.toString(rectangle.height)); - - if (!(frame.isInFullScreen() && SystemInfo.isAppleJvm)) { - frameElement.setAttribute(EXTENDED_STATE_ATTR, Integer.toString(extendedState)); - } - - // Save default layout - final Element layoutElement = new Element(DesktopLayout.TAG); - element.addContent(layoutElement); - myLayout.writeExternal(layoutElement); + @Nullable + @Override + public Element getState() { + Element frameState = getFrameState(); + if (frameState == null) { + return null; } + + Element state = new Element("state"); + state.addContent(frameState); + + // Save default layout + Element layoutElement = new Element(DesktopLayout.TAG); + state.addContent(layoutElement); + myLayout.writeExternal(layoutElement); + return state; + } + + private Element getFrameState() { + // Save frame bounds + final Project[] projects = ProjectManager.getInstance().getOpenProjects(); + if (projects.length == 0) { + return null; + } + + Project project = projects[0]; + final IdeFrameImpl frame = getFrame(project); + if (frame == null) { + return null; + } + + final Element frameElement = new Element(FRAME_ELEMENT); + int extendedState = frame.getExtendedState(); + if (SystemInfo.isMacOSLion) { + @SuppressWarnings("deprecation") ComponentPeer peer = frame.getPeer(); + if (peer instanceof FramePeer) { + // frame.state is not updated by jdk so get it directly from peer + extendedState = ((FramePeer)peer).getState(); + } + } + boolean isMaximized = extendedState == Frame.MAXIMIZED_BOTH || + isFullScreenSupportedInCurrentOS() && frame.isInFullScreen(); + boolean usePreviousBounds = isMaximized && + myFrameBounds != null && + frame.getBounds().contains(new Point((int)myFrameBounds.getCenterX(), (int)myFrameBounds.getCenterY())); + Rectangle rectangle = usePreviousBounds ? myFrameBounds : frame.getBounds(); + frameElement.setAttribute(X_ATTR, Integer.toString(rectangle.x)); + frameElement.setAttribute(Y_ATTR, Integer.toString(rectangle.y)); + frameElement.setAttribute(WIDTH_ATTR, Integer.toString(rectangle.width)); + frameElement.setAttribute(HEIGHT_ATTR, Integer.toString(rectangle.height)); + + if (!(frame.isInFullScreen() && SystemInfo.isAppleJvm)) { + frameElement.setAttribute(EXTENDED_STATE_ATTR, Integer.toString(extendedState)); + } + return frameElement; } public final DesktopLayout getLayout() {