avoid NPE if project frame is not yet set

GitOrigin-RevId: db67484a2e317d111c9d5c5c0730b19154c4efdb
This commit is contained in:
Vladimir Krivosheev
2020-10-21 05:56:39 +00:00
committed by intellij-monorepo-bot
parent b8987fdeaa
commit e88ef6402a
7 changed files with 65 additions and 67 deletions
@@ -96,4 +96,7 @@ public abstract class WindowManager {
public abstract boolean isFullScreenSupportedInCurrentOS();
public abstract void requestUserAttention(@NotNull IdeFrame frame, boolean critical);
public void updateDefaultFrameInfoOnProjectClose(@NotNull Project project) {
}
}
@@ -16,7 +16,9 @@ import com.intellij.openapi.project.Project
import com.intellij.openapi.project.ProjectManager
import com.intellij.openapi.project.ProjectManagerListener
import com.intellij.openapi.project.ex.ProjectManagerEx
import com.intellij.openapi.project.impl.*
import com.intellij.openapi.project.impl.ProjectUiFrameAllocator
import com.intellij.openapi.project.impl.ProjectUiFrameManager
import com.intellij.openapi.project.impl.createNewProjectFrame
import com.intellij.openapi.startup.StartupManager
import com.intellij.openapi.util.ModificationTracker
import com.intellij.openapi.util.SystemInfo
@@ -275,7 +277,9 @@ open class RecentProjectsManagerBase : RecentProjectsManager(), PersistentStateC
val appInfo = ApplicationInfoEx.getInstanceEx()
info.displayName = getProjectDisplayName(project)
info.projectWorkspaceId = project.stateStore.projectWorkspaceId
info.frame = ProjectFrameBounds.getInstance(project).frameInfoHelper.info
ProjectFrameBounds.getInstance(project).frameInfoHelper.info?.let {
info.frame = it
}
info.build = appInfo!!.build.asString()
info.productionCode = appInfo.build.productCode
info.eap = appInfo.isEAP
@@ -538,11 +542,15 @@ open class RecentProjectsManagerBase : RecentProjectsManager(), PersistentStateC
LOG.warn("Cannot find frameHelper for ${project.name} to update frame info")
return
}
val frame = frameHelper.frame
if (frame == null) {
LOG.warn("frameHelper.frame is null, cannot ${project.name} to update frame info")
return
}
val workspaceId = project.stateStore.projectWorkspaceId
// ensure that last closed project frame bounds will be used as newly created project frame bounds (if will be no another focused opened project)
val frameInfo = ProjectFrameBounds.getInstance(project).getActualFrameInfoInDeviceSpace(frameHelper, windowManager)
val frameInfo = ProjectFrameBounds.getInstance(project).getActualFrameInfoInDeviceSpace(frameHelper, frame, windowManager)
val path = getProjectPath(project)
synchronized(stateLock) {
val info = state.additionalInfo.get(path)
@@ -554,13 +562,13 @@ open class RecentProjectsManagerBase : RecentProjectsManager(), PersistentStateC
info.frame = frameInfo
}
info.projectWorkspaceId = workspaceId
info.frameTitle = frameHelper.frame?.title
info.frameTitle = frame.title
}
}
LOG.runAndLogException {
if (writLastProjectInfo) {
writeInfoFile(frameInfo, frameHelper.frame ?: return@runAndLogException)
writeInfoFile(frameInfo, frame)
}
if (workspaceId != null && Registry.`is`("ide.project.loading.show.last.state")) {
@@ -1,4 +1,4 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.ide.actions;
import com.intellij.ide.IdeBundle;
@@ -11,7 +11,7 @@ import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ex.ProjectManagerEx;
import com.intellij.openapi.wm.impl.ProjectFrameBounds;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.openapi.wm.impl.welcomeScreen.WelcomeFrame;
import com.intellij.projectImport.ProjectAttachProcessor;
import com.intellij.ui.IdeUICustomization;
@@ -28,7 +28,7 @@ public final class CloseProjectAction extends AnAction implements DumbAware {
assert project != null;
// ensure that last closed project frame bounds will be used as newly created project frame bounds (if will be no another focused opened project)
ProjectFrameBounds.getInstance(project).updateDefaultFrameInfoOnProjectClose();
WindowManager.getInstance().updateDefaultFrameInfoOnProjectClose(project);
ProjectManagerEx.getInstanceEx().closeAndDispose(project);
// RecentProjectsManager cannot distinguish close as part of exit (no need to remove project),
@@ -14,6 +14,7 @@ import java.awt.Point
import java.awt.Rectangle
import java.awt.peer.ComponentPeer
import java.awt.peer.FramePeer
import javax.swing.JFrame
internal class FrameInfoHelper {
companion object {
@@ -43,26 +44,28 @@ internal class FrameInfoHelper {
this.info = info
}
fun updateFrameInfo(frame: ProjectFrameHelper) {
info = updateFrameInfo(frame, null, info)
fun updateFrameInfo(frameHelper: ProjectFrameHelper, frame: JFrame) {
info = updateFrameInfo(frameHelper, frame, null, info)
}
fun getModificationCount(): Long {
return info?.modificationCount ?: 0
}
fun updateAndGetModificationCount(project: Project, lastNormalFrameBounds: Rectangle?, windowManager: WindowManagerImpl): Long {
val frame = windowManager.getFrameHelper(project) ?: return getModificationCount()
return updateAndGetModificationCount(frame, lastNormalFrameBounds, windowManager)
fun update(project: Project, lastNormalFrameBounds: Rectangle?, windowManager: WindowManagerImpl) {
val frameHelper = windowManager.getFrameHelper(project) ?: return
updateAndGetInfo(frameHelper, frameHelper.frame ?: return, lastNormalFrameBounds, windowManager)
}
fun updateAndGetModificationCount(frame: ProjectFrameHelper, lastNormalFrameBounds: Rectangle?, windowManager: WindowManagerImpl): Long {
val newInfo = updateFrameInfo(frame, lastNormalFrameBounds, info)
updateDefaultFrameInfoInDeviceSpace(windowManager, newInfo)
fun updateAndGetInfo(frameHelper: ProjectFrameHelper,
frame: JFrame,
lastNormalFrameBounds: Rectangle?,
windowManager: WindowManagerImpl): FrameInfo {
val newInfo = updateFrameInfo(frameHelper, frame, lastNormalFrameBounds, info)
windowManager.defaultFrameInfoHelper.copyFrom(newInfo)
info = newInfo
isDirty = false
return getModificationCount()
return newInfo
}
fun copyFrom(newInfo: FrameInfo) {
@@ -74,8 +77,7 @@ internal class FrameInfoHelper {
}
}
private fun updateFrameInfo(frameHelper: ProjectFrameHelper, lastNormalFrameBounds: Rectangle?, oldFrameInfo: FrameInfo?): FrameInfo {
val frame = frameHelper.frame!!
internal fun updateFrameInfo(frameHelper: ProjectFrameHelper, frame: JFrame, lastNormalFrameBounds: Rectangle?, oldFrameInfo: FrameInfo?): FrameInfo {
var extendedState = frame.extendedState
if (SystemInfoRt.isMac) {
// java 11
@@ -112,9 +114,4 @@ private fun updateFrameInfo(frameHelper: ProjectFrameHelper, lastNormalFrameBoun
frameInfo.fullScreen = isInFullScreen
}
return frameInfo
}
internal fun updateDefaultFrameInfoInDeviceSpace(windowManager: WindowManagerImpl, newInfo: FrameInfo) {
// see comment in the myFrameStateListener about chicken and egg problem
windowManager.defaultFrameInfoHelper.copyFrom(newInfo)
}
@@ -5,14 +5,14 @@ import com.intellij.openapi.components.BaseState
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.service
import com.intellij.openapi.project.Project
import com.intellij.openapi.wm.WindowManager
import com.intellij.util.xmlb.annotations.Property
import com.intellij.util.xmlb.annotations.Tag
import java.awt.Frame
import java.awt.Rectangle
import javax.swing.JFrame
@Service
class ProjectFrameBounds(private val project: Project) {
internal class ProjectFrameBounds {
companion object {
@JvmStatic
fun getInstance(project: Project) = project.service<ProjectFrameBounds>()
@@ -21,29 +21,8 @@ class ProjectFrameBounds(private val project: Project) {
internal val frameInfoHelper = FrameInfoHelper()
private var pendingBounds: Rectangle? = null
/**
* Maybe outdated. You must always check isDirty if you need actual info.
*/
internal fun getFrameInfoInDeviceSpace() = frameInfoHelper.info
internal fun getActualFrameInfoInDeviceSpace(frame: ProjectFrameHelper, windowManager: WindowManagerImpl): FrameInfo {
val result = frameInfoHelper.info
if (frameInfoHelper.isDirty || result == null) {
frameInfoHelper.updateAndGetModificationCount(frame, pendingBounds, windowManager)
return frameInfoHelper.info!!
}
return result
}
fun updateDefaultFrameInfoOnProjectClose() {
val windowManager = WindowManager.getInstance() as WindowManagerImpl
if (frameInfoHelper.isDirty || frameInfoHelper.info == null) {
// not really required, because will be applied during project save on close
frameInfoHelper.updateAndGetModificationCount(project, pendingBounds, windowManager)
}
else {
updateDefaultFrameInfoInDeviceSpace(windowManager, frameInfoHelper.info ?: return)
}
internal fun getActualFrameInfoInDeviceSpace(frameHelper: ProjectFrameHelper, frame: JFrame, windowManager: WindowManagerImpl): FrameInfo {
return frameInfoHelper.updateAndGetInfo(frameHelper, frame, pendingBounds, windowManager)
}
fun markDirty(bounds: Rectangle?) {
@@ -411,7 +411,7 @@ open class ToolWindowManagerImpl(val project: Project) : ToolWindowManagerEx(),
if (toolWindowPane == null) {
if (!ApplicationManager.getApplication().isUnitTestMode) {
LOG.warn("ProjectFrameAllocator is not used - use ProjectManager.openProject to open project in a correct way")
LOG.error("ProjectFrameAllocator is not used - use ProjectManager.openProject to open project in a correct way")
}
val toolWindowsPane = init((WindowManager.getInstance() as WindowManagerImpl).allocateFrame(project))
@@ -93,7 +93,7 @@ class WindowManagerImpl : WindowManagerEx(), PersistentStateComponentWithModific
// Cannot mark as dirty and compute later, because to convert user space info to device space,
// we need graphicsConfiguration, but we can get graphicsConfiguration only from frame,
// but later, when getStateModificationCount or getState is called, may be no frame at all.
defaultFrameInfoHelper.updateFrameInfo(frameHelper)
defaultFrameInfoHelper.updateFrameInfo(frameHelper, frame)
}
else if (!project.isDisposed) {
ProjectFrameBounds.getInstance(project).markDirty(if (isMaximized(extendedState)) null else bounds)
@@ -302,6 +302,9 @@ class WindowManagerImpl : WindowManagerEx(), PersistentStateComponentWithModific
frame.addComponentListener(frameStateListener)
}
/**
* This method is not used in a normal conditions. Only in case of violation and early access to ToolWindowManager.
*/
fun allocateFrame(project: Project,
projectFrameHelperFactory: Supplier<out ProjectFrameHelper> = Supplier {
ProjectFrameHelper(createNewProjectFrame(forceDisableAutoRequestFocus = false, frameInfo = null), null)
@@ -323,15 +326,13 @@ class WindowManagerImpl : WindowManagerEx(), PersistentStateComponentWithModific
return frame
}
private fun allocateNewFrame(project: Project, frame: ProjectFrameHelper) {
frame.init()
private fun allocateNewFrame(project: Project, frameHelper: ProjectFrameHelper) {
frameHelper.init()
var frameInfo = ProjectFrameBounds.getInstance(project).getFrameInfoInDeviceSpace()
if (frameInfo?.bounds == null) {
val lastFocusedProject = IdeFocusManager.getGlobalInstance().lastFocusedFrame?.project
if (lastFocusedProject != null) {
frameInfo = ProjectFrameBounds.getInstance(lastFocusedProject).getActualFrameInfoInDeviceSpace(frame, this)
}
var frameInfo: FrameInfo? = null
val lastFocusedProjectFrame = IdeFocusManager.getGlobalInstance().lastFocusedFrame?.project?.let { getFrameHelper(it) }
if (lastFocusedProjectFrame != null) {
frameInfo = getFrameInfoByFrameHelper(lastFocusedProjectFrame)
if (frameInfo?.bounds == null) {
frameInfo = defaultFrameInfoHelper.info
}
@@ -344,19 +345,19 @@ class WindowManagerImpl : WindowManagerEx(), PersistentStateComponentWithModific
}
val bounds = frameInfo.bounds
if (bounds != null) {
frame.frame!!.bounds = FrameBoundsConverter.convertFromDeviceSpaceAndFitToScreen(bounds)
frameHelper.frame!!.bounds = FrameBoundsConverter.convertFromDeviceSpaceAndFitToScreen(bounds)
}
}
frame.setProject(project)
projectToFrame.put(project, frame)
val uiFrame = frame.frame!!
frameHelper.setProject(project)
projectToFrame.put(project, frameHelper)
val uiFrame = frameHelper.frame!!
if (frameInfo != null) {
uiFrame.extendedState = frameInfo.extendedState
}
uiFrame.isVisible = true
if (isFullScreenSupportedInCurrentOs() && frameInfo != null && frameInfo.fullScreen) {
frame.toggleFullScreen(true)
frameHelper.toggleFullScreen(true)
}
uiFrame.addComponentListener(frameStateListener)
@@ -476,6 +477,12 @@ class WindowManagerImpl : WindowManagerEx(), PersistentStateComponentWithModific
}
override fun isFullScreenSupportedInCurrentOS() = isFullScreenSupportedInCurrentOs()
override fun updateDefaultFrameInfoOnProjectClose(project: Project) {
val frameHelper = getFrameHelper(project) ?: return
val frameInfo = getFrameInfoByFrameHelper(frameHelper) ?: return
defaultFrameInfoHelper.copyFrom(frameInfo)
}
}
private fun calcAlphaModelSupported(): Boolean {
@@ -544,4 +551,8 @@ private fun getIdeFrame(component: Component): IdeFrame? {
is IdeFrame -> component
else -> null
}
}
}
private fun getFrameInfoByFrameHelper(frameHelper: ProjectFrameHelper): FrameInfo? {
return updateFrameInfo(frameHelper, frameHelper.frame ?: return null, null, null)
}