From 859b0b20d11a62cb39ed963308d12521b6164996 Mon Sep 17 00:00:00 2001 From: VISTALL Date: Sat, 25 Dec 2021 15:40:30 +0300 Subject: [PATCH 1/6] introduce welcome project, for new ui of welcome --- .../src/main/resources/META-INF/plugin.xml | 3 + .../TranslatingCompilerFilesMonitorImpl.java | 8 + .../compiler/CompilerConfigurationImpl.java | 5 +- ...lationCompilerFilesMonitorVfsListener.java | 2 +- .../project/DefaultProjectFactory.java | 7 +- .../com/intellij/openapi/project/Project.java | 4 + .../impl/ProjectRootManagerComponent.java | 12 +- .../project/WelcomeProjectFactory.java | 29 +++ .../ide/actions/CloseProjectAction.java | 11 +- .../ide/actions/RecentProjectsGroup.java | 8 +- .../module/impl/ModuleManagerComponent.java | 2 +- .../impl/DefaultProjectFactoryImpl.java | 83 +------ .../project/impl/DefaultProjectImpl.java | 28 +-- .../openapi/project/impl/ProjectImpl.java | 11 +- .../impl/stores/DefaultProjectStoreImpl.java | 170 +-------------- .../impl/stores/ProjectStoreImpl.java | 23 +- .../stores/SingleFileProjectStoreImpl.java | 202 ++++++++++++++++++ .../whatsNew/WhatsNewVirtualFileEditor.java | 3 + .../impl/SingleFileProjectFactoryImpl.java | 114 ++++++++++ .../project/impl/SingleFileProjectImpl.java | 55 +++++ .../welcome/WelcomeProjectFactoryImpl.java | 51 +++++ .../impl/welcome/WelcomeProjectImpl.java | 46 ++++ .../impl/welcome/WelcomeProjectStoreImpl.java | 44 ++++ .../consulo/start/WelcomeFrameManager.java | 16 +- 24 files changed, 643 insertions(+), 294 deletions(-) create mode 100644 modules/base/platform-api/src/main/java/consulo/project/WelcomeProjectFactory.java create mode 100644 modules/base/platform-impl/src/main/java/consulo/components/impl/stores/SingleFileProjectStoreImpl.java create mode 100644 modules/base/platform-impl/src/main/java/consulo/project/impl/SingleFileProjectFactoryImpl.java create mode 100644 modules/base/platform-impl/src/main/java/consulo/project/impl/SingleFileProjectImpl.java create mode 100644 modules/base/platform-impl/src/main/java/consulo/project/impl/welcome/WelcomeProjectFactoryImpl.java create mode 100644 modules/base/platform-impl/src/main/java/consulo/project/impl/welcome/WelcomeProjectImpl.java create mode 100644 modules/base/platform-impl/src/main/java/consulo/project/impl/welcome/WelcomeProjectStoreImpl.java diff --git a/modules/base/base-plugin/src/main/resources/META-INF/plugin.xml b/modules/base/base-plugin/src/main/resources/META-INF/plugin.xml index 8376cc6751e5..9d65e10c4b2a 100644 --- a/modules/base/base-plugin/src/main/resources/META-INF/plugin.xml +++ b/modules/base/base-plugin/src/main/resources/META-INF/plugin.xml @@ -1250,6 +1250,9 @@ + + diff --git a/modules/base/compiler-impl/src/main/java/com/intellij/compiler/impl/TranslatingCompilerFilesMonitorImpl.java b/modules/base/compiler-impl/src/main/java/com/intellij/compiler/impl/TranslatingCompilerFilesMonitorImpl.java index 9a17f845cdd0..7c442c09881e 100644 --- a/modules/base/compiler-impl/src/main/java/com/intellij/compiler/impl/TranslatingCompilerFilesMonitorImpl.java +++ b/modules/base/compiler-impl/src/main/java/com/intellij/compiler/impl/TranslatingCompilerFilesMonitorImpl.java @@ -100,6 +100,10 @@ static class ProjectListener implements ProjectManagerListener { @Override public void projectOpened(@Nonnull Project project, @Nonnull UIAccess uiAccess) { + if (project.isWelcome()) { + return; + } + TranslatingCompilerFilesMonitorImpl monitor = getMonitor(); final MessageBusConnection conn = project.getMessageBus().connect(); @@ -205,6 +209,10 @@ public void run(@Nonnull final ProgressIndicator indicator) { @Override public void projectClosed(@Nonnull Project project, @Nonnull UIAccess uiAccess) { + if (project.isWelcome()) { + return; + } + TranslatingCompilerFilesMonitorImpl monitor = getMonitor(); final int projectId = monitor.getProjectId(project); diff --git a/modules/base/compiler-impl/src/main/java/consulo/compiler/CompilerConfigurationImpl.java b/modules/base/compiler-impl/src/main/java/consulo/compiler/CompilerConfigurationImpl.java index 6d6ab46d9f2e..732869bce4e3 100644 --- a/modules/base/compiler-impl/src/main/java/consulo/compiler/CompilerConfigurationImpl.java +++ b/modules/base/compiler-impl/src/main/java/consulo/compiler/CompilerConfigurationImpl.java @@ -36,7 +36,6 @@ import jakarta.inject.Inject; import jakarta.inject.Singleton; import org.jdom.Element; -import org.jetbrains.annotations.NonNls; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -60,6 +59,10 @@ public MyWatchedRootsProvider(final Project project) { @Nonnull @Override public Set getRootsToWatch() { + if (myProject.isWelcome()) { + return Set.of(); + } + return ((CompilerConfigurationImpl)CompilerConfiguration.getInstance(myProject)).getRootsToWatch(); } } diff --git a/modules/base/compiler-impl/src/main/java/consulo/compiler/impl/TranslationCompilerFilesMonitorVfsListener.java b/modules/base/compiler-impl/src/main/java/consulo/compiler/impl/TranslationCompilerFilesMonitorVfsListener.java index 93486b4573a6..814b44cae97f 100644 --- a/modules/base/compiler-impl/src/main/java/consulo/compiler/impl/TranslationCompilerFilesMonitorVfsListener.java +++ b/modules/base/compiler-impl/src/main/java/consulo/compiler/impl/TranslationCompilerFilesMonitorVfsListener.java @@ -327,7 +327,7 @@ private void processNewFile(final VirtualFile file, final boolean notifyServer) // need read action to ensure that the project was not disposed during the iteration over the project list ApplicationManager.getApplication().runReadAction(() -> { for (final Project project : projectManager.getOpenProjects()) { - if (!project.isInitialized()) { + if (!project.isInitialized() || project.isWelcome()) { continue; // the content of this project will be scanned during its post-startup activities } final int projectId = monitor.getProjectId(project); diff --git a/modules/base/core-api/src/main/java/com/intellij/openapi/project/DefaultProjectFactory.java b/modules/base/core-api/src/main/java/com/intellij/openapi/project/DefaultProjectFactory.java index add803ef2bf2..ab9e0c08689e 100644 --- a/modules/base/core-api/src/main/java/com/intellij/openapi/project/DefaultProjectFactory.java +++ b/modules/base/core-api/src/main/java/com/intellij/openapi/project/DefaultProjectFactory.java @@ -16,17 +16,18 @@ package com.intellij.openapi.project; import com.intellij.openapi.components.ServiceManager; + import javax.annotation.Nonnull; /** * @author yole */ -public abstract class DefaultProjectFactory { +public interface DefaultProjectFactory { @Nonnull - public static DefaultProjectFactory getInstance() { + static DefaultProjectFactory getInstance() { return ServiceManager.getService(DefaultProjectFactory.class); } @Nonnull - public abstract Project getDefaultProject(); + Project getDefaultProject(); } diff --git a/modules/base/core-api/src/main/java/com/intellij/openapi/project/Project.java b/modules/base/core-api/src/main/java/com/intellij/openapi/project/Project.java index bb5136e8c7e4..2ab036ceddb6 100644 --- a/modules/base/core-api/src/main/java/com/intellij/openapi/project/Project.java +++ b/modules/base/core-api/src/main/java/com/intellij/openapi/project/Project.java @@ -128,4 +128,8 @@ default boolean isModulesReady() { default boolean isDefault() { return false; } + + default boolean isWelcome() { + return false; + } } diff --git a/modules/base/lang-impl/src/main/java/com/intellij/openapi/roots/impl/ProjectRootManagerComponent.java b/modules/base/lang-impl/src/main/java/com/intellij/openapi/roots/impl/ProjectRootManagerComponent.java index 11b15df1a5a7..ad30066ac477 100644 --- a/modules/base/lang-impl/src/main/java/com/intellij/openapi/roots/impl/ProjectRootManagerComponent.java +++ b/modules/base/lang-impl/src/main/java/com/intellij/openapi/roots/impl/ProjectRootManagerComponent.java @@ -76,7 +76,7 @@ public class ProjectRootManagerComponent extends ProjectRootManagerImpl implemen private final BatchUpdateListener myHandler; private final MessageBusConnection myConnection; - private Set myRootsToWatch = new HashSet(); + private Set myRootsToWatch = new HashSet<>(); private final boolean myDoLogCachesUpdate; @Inject @@ -103,7 +103,7 @@ public void afterRefreshFinish(boolean asynchronous) { } }, project); - if (!project.isDefault()) { + if (!project.isDefault() && !myProject.isWelcome()) { startupManager.registerStartupActivity(() -> myStartupActivityPerformed = true); } @@ -161,7 +161,7 @@ private void doUpdateOnRefresh() { if (ApplicationManager.getApplication().isUnitTestMode() && (!myStartupActivityPerformed || myProject.isDisposed())) { return; // in test mode suppress addition to a queue unless project is properly initialized } - if (myProject.isDefault()) { + if (myProject.isDefault() || myProject.isWelcome()) { return; } @@ -217,10 +217,10 @@ private static String url2path(String url) { @Nullable private Pair, Set> getAllRoots(boolean includeSourceRoots) { - if (myProject.isDefault()) return null; + if (myProject.isDefault() || myProject.isWelcome()) return null; - final Set recursive = new HashSet(); - final Set flat = new HashSet(); + final Set recursive = new HashSet<>(); + final Set flat = new HashSet<>(); final String projectFilePath = myProject.getProjectFilePath(); final File projectDirFile = projectFilePath == null ? null : new File(projectFilePath).getParentFile(); diff --git a/modules/base/platform-api/src/main/java/consulo/project/WelcomeProjectFactory.java b/modules/base/platform-api/src/main/java/consulo/project/WelcomeProjectFactory.java new file mode 100644 index 000000000000..d596cd3a0674 --- /dev/null +++ b/modules/base/platform-api/src/main/java/consulo/project/WelcomeProjectFactory.java @@ -0,0 +1,29 @@ +/* + * Copyright 2013-2021 consulo.io + * + * Licensed 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 consulo.project; + +import com.intellij.openapi.project.Project; + +import javax.annotation.Nonnull; + +/** + * @author VISTALL + * @since 25/12/2021 + */ +public interface WelcomeProjectFactory { + @Nonnull + Project getWelcomeProject(); +} diff --git a/modules/base/platform-impl/src/main/java/com/intellij/ide/actions/CloseProjectAction.java b/modules/base/platform-impl/src/main/java/com/intellij/ide/actions/CloseProjectAction.java index d62ecdc8a452..65718b8ebefa 100644 --- a/modules/base/platform-impl/src/main/java/com/intellij/ide/actions/CloseProjectAction.java +++ b/modules/base/platform-impl/src/main/java/com/intellij/ide/actions/CloseProjectAction.java @@ -24,11 +24,11 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import consulo.start.WelcomeFrameManager; -import consulo.ui.annotation.RequiredUIAccess; import consulo.ui.UIAccess; +import consulo.ui.annotation.RequiredUIAccess; +import jakarta.inject.Inject; import javax.annotation.Nonnull; -import jakarta.inject.Inject; public class CloseProjectAction extends AnAction implements DumbAware { private WelcomeFrameManager myWelcomeFrameManager; @@ -58,6 +58,11 @@ public void actionPerformed(@Nonnull AnActionEvent event) { public void update(@Nonnull AnActionEvent event) { Presentation presentation = event.getPresentation(); Project project = event.getData(CommonDataKeys.PROJECT); - presentation.setEnabled(project != null); + if (project != null && project.isWelcome()) { + presentation.setEnabledAndVisible(false); + } + else { + presentation.setEnabled(project != null && !project.isWelcome()); + } } } diff --git a/modules/base/platform-impl/src/main/java/com/intellij/ide/actions/RecentProjectsGroup.java b/modules/base/platform-impl/src/main/java/com/intellij/ide/actions/RecentProjectsGroup.java index 77a56ccd589d..f3ab6888f704 100644 --- a/modules/base/platform-impl/src/main/java/com/intellij/ide/actions/RecentProjectsGroup.java +++ b/modules/base/platform-impl/src/main/java/com/intellij/ide/actions/RecentProjectsGroup.java @@ -23,6 +23,8 @@ import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.util.SystemInfo; +import consulo.ui.annotation.RequiredUIAccess; + import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -34,16 +36,20 @@ public RecentProjectsGroup() { // Let's make tile more macish if (SystemInfo.isMac) { templatePresentation.setText(ActionsBundle.message("group.reopen.mac.text")); - } else { + } + else { templatePresentation.setText(ActionsBundle.message("group.reopen.win.text")); } } + @Override @Nonnull public AnAction[] getChildren(@Nullable AnActionEvent e) { return RecentProjectsManagerBase.getInstance().getRecentProjectsActions(true); } + @RequiredUIAccess + @Override public void update(AnActionEvent event) { Presentation presentation = event.getPresentation(); presentation.setEnabled(RecentProjectsManagerBase.getInstance().getRecentProjectsActions(true).length > 0); diff --git a/modules/base/platform-impl/src/main/java/com/intellij/openapi/module/impl/ModuleManagerComponent.java b/modules/base/platform-impl/src/main/java/com/intellij/openapi/module/impl/ModuleManagerComponent.java index 7293582a0fd0..7b0fbeae8dd2 100644 --- a/modules/base/platform-impl/src/main/java/com/intellij/openapi/module/impl/ModuleManagerComponent.java +++ b/modules/base/platform-impl/src/main/java/com/intellij/openapi/module/impl/ModuleManagerComponent.java @@ -55,7 +55,7 @@ public ModuleManagerComponent(Project project, ProgressManager progressManager) myConnection.subscribe(ProjectTopics.PROJECT_ROOTS); - if(project.isDefault()) { + if(project.isDefault() || project.isWelcome()) { myReady = true; } } diff --git a/modules/base/platform-impl/src/main/java/com/intellij/openapi/project/impl/DefaultProjectFactoryImpl.java b/modules/base/platform-impl/src/main/java/com/intellij/openapi/project/impl/DefaultProjectFactoryImpl.java index aabe89aaf03f..1d4cc97c278f 100644 --- a/modules/base/platform-impl/src/main/java/com/intellij/openapi/project/impl/DefaultProjectFactoryImpl.java +++ b/modules/base/platform-impl/src/main/java/com/intellij/openapi/project/impl/DefaultProjectFactoryImpl.java @@ -22,99 +22,34 @@ import com.intellij.openapi.project.DefaultProjectFactory; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; -import consulo.annotation.access.RequiredReadAction; -import consulo.annotation.access.RequiredWriteAction; +import consulo.components.impl.stores.DefaultProjectStoreImpl; import consulo.disposer.Disposable; -import consulo.disposer.Disposer; -import consulo.logging.Logger; +import consulo.project.impl.SingleFileProjectFactoryImpl; import jakarta.inject.Inject; import jakarta.inject.Singleton; import org.jdom.Element; -import org.jetbrains.annotations.TestOnly; import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.io.IOException; /** * @author yole */ @State(name = "ProjectManager", storages = @Storage("project.default.xml")) @Singleton -public class DefaultProjectFactoryImpl extends DefaultProjectFactory implements PersistentStateComponent, Disposable { - private static final Logger LOG = Logger.getInstance(DefaultProjectFactoryImpl.class); - - private DefaultProjectImpl myDefaultProject; - private boolean myDefaultProjectWasDisposed = false; - +public class DefaultProjectFactoryImpl extends SingleFileProjectFactoryImpl implements DefaultProjectFactory, PersistentStateComponent, Disposable { @Inject public DefaultProjectFactoryImpl(@Nonnull Application application, @Nonnull ProjectManager projectManager) { - myDefaultProject = new DefaultProjectImpl(application, projectManager, "", application.isUnitTestMode()); - myDefaultProject.initNotLazyServices(null); - myDefaultProject.setInitialized(); - } - - @TestOnly - public boolean isDefaultProjectInitialized() { - return myDefaultProject != null; + super(new DefaultProjectImpl(application, projectManager, "", application.isUnitTestMode()), DefaultProjectStoreImpl.ROOT_TAG_NAME); } - @Override @Nonnull - public Project getDefaultProject() { - LOG.assertTrue(!myDefaultProjectWasDisposed, "Default project has been already disposed!"); - return myDefaultProject; - } - - @RequiredWriteAction - @Nullable - @Override - public Element getState() { - assert myDefaultProject != null; - - myDefaultProject.save(); - - Element stateElement = myDefaultProject.getStateElement(); - - if (stateElement == null) { - // we are not ready to save - return null; - } - - Element element = new Element("state"); - stateElement.detach(); - element.addContent(stateElement); - return element; - } - - @RequiredReadAction - @Override - public void loadState(Element state) { - Element defaultProjectElement = state.getChild("defaultProject"); - if (defaultProjectElement != null) { - defaultProjectElement.detach(); - - myDefaultProject.setStateElement(defaultProjectElement); - } - } - @Override - public void afterLoadState() { - try { - myDefaultProject.getStateStore().load(); - } - catch (IOException e) { - LOG.error(e); - } + public Project getDefaultProject() { + return getProject(); } - @Override - public void dispose() { - if (myDefaultProject != null) { - Disposer.dispose(myDefaultProject); - - myDefaultProject = null; - myDefaultProjectWasDisposed = true; - } + @Deprecated + public boolean isDefaultProjectInitialized() { + return isProjectInitialized(); } } \ No newline at end of file diff --git a/modules/base/platform-impl/src/main/java/com/intellij/openapi/project/impl/DefaultProjectImpl.java b/modules/base/platform-impl/src/main/java/com/intellij/openapi/project/impl/DefaultProjectImpl.java index 027f707b78cb..afad19ba1b95 100644 --- a/modules/base/platform-impl/src/main/java/com/intellij/openapi/project/impl/DefaultProjectImpl.java +++ b/modules/base/platform-impl/src/main/java/com/intellij/openapi/project/impl/DefaultProjectImpl.java @@ -17,40 +17,26 @@ import com.intellij.openapi.application.Application; import com.intellij.openapi.project.ProjectManager; -import org.jdom.Element; +import consulo.components.impl.stores.DefaultProjectStoreImpl; +import consulo.components.impl.stores.IProjectStore; +import consulo.project.impl.SingleFileProjectImpl; import javax.annotation.Nonnull; -import javax.annotation.Nullable; /** * @author peter */ -public class DefaultProjectImpl extends ProjectImpl { +public class DefaultProjectImpl extends SingleFileProjectImpl { private static final String TEMPLATE_PROJECT_NAME = "Default (Template) Project"; - private Element myStateElement; - private boolean myInitialized; - DefaultProjectImpl(@Nonnull Application application, @Nonnull ProjectManager manager, @Nonnull String filePath, boolean optimiseTestLoadSpeed) { super(application, manager, filePath, optimiseTestLoadSpeed, TEMPLATE_PROJECT_NAME, false); } - @Nullable - public Element getStateElement() { - return myStateElement; - } - - public void setStateElement(@Nullable Element stateElement) { - myStateElement = stateElement; - } - - public void setInitialized() { - myInitialized = true; - } - @Override - public boolean isInitialized() { - return myInitialized; + @Nonnull + protected Class getStoreImplClass() { + return DefaultProjectStoreImpl.class; } @Override diff --git a/modules/base/platform-impl/src/main/java/com/intellij/openapi/project/impl/ProjectImpl.java b/modules/base/platform-impl/src/main/java/com/intellij/openapi/project/impl/ProjectImpl.java index e2a0c440a84d..efa8fc6ce413 100644 --- a/modules/base/platform-impl/src/main/java/com/intellij/openapi/project/impl/ProjectImpl.java +++ b/modules/base/platform-impl/src/main/java/com/intellij/openapi/project/impl/ProjectImpl.java @@ -41,7 +41,6 @@ import com.intellij.util.TimedReference; import consulo.application.AccessRule; import consulo.components.impl.PlatformComponentManagerImpl; -import consulo.components.impl.stores.DefaultProjectStoreImpl; import consulo.components.impl.stores.IProjectStore; import consulo.components.impl.stores.ProjectStoreImpl; import consulo.components.impl.stores.StoreUtil; @@ -99,7 +98,7 @@ protected ProjectImpl(@Nonnull Application application, @Nonnull ProjectManager putUserData(CREATION_TRACE, DebugUtil.currentStackTrace()); } - if (!isDefault()) { + if (!isDefault() && !isWelcome()) { if (noUIThread) { getStateStore().setProjectFilePathNoUI(dirPath); } @@ -173,8 +172,12 @@ protected void bootstrapInjectingContainer(@Nonnull InjectingContainerBuilder bu builder.bind(ProjectEx.class).to(this); builder.bind(ProjectPathMacroManager.class).to(ProjectPathMacroManager.class).forceSingleton(); - final Class storeClass = isDefault() ? DefaultProjectStoreImpl.class : ProjectStoreImpl.class; - builder.bind(IProjectStore.class).to(storeClass).forceSingleton(); + builder.bind(IProjectStore.class).to(getStoreImplClass()).forceSingleton(); + } + + @Nonnull + protected Class getStoreImplClass() { + return ProjectStoreImpl.class; } @Nonnull diff --git a/modules/base/platform-impl/src/main/java/consulo/components/impl/stores/DefaultProjectStoreImpl.java b/modules/base/platform-impl/src/main/java/consulo/components/impl/stores/DefaultProjectStoreImpl.java index 75f6c5981739..4cd7b42482a3 100644 --- a/modules/base/platform-impl/src/main/java/consulo/components/impl/stores/DefaultProjectStoreImpl.java +++ b/modules/base/platform-impl/src/main/java/consulo/components/impl/stores/DefaultProjectStoreImpl.java @@ -15,188 +15,26 @@ */ package consulo.components.impl.stores; -import com.intellij.openapi.components.*; -import com.intellij.openapi.components.StateStorage.SaveSession; import com.intellij.openapi.components.impl.ProjectPathMacroManager; import com.intellij.openapi.project.Project; -import com.intellij.openapi.project.impl.DefaultProjectImpl; -import com.intellij.openapi.util.Couple; -import com.intellij.util.containers.ContainerUtil; -import consulo.components.impl.stores.storage.StateStorageManager; -import consulo.components.impl.stores.storage.StorageData; -import consulo.components.impl.stores.storage.VfsFileBasedStorage; -import consulo.components.impl.stores.storage.XmlElementStorage; import jakarta.inject.Inject; import jakarta.inject.Provider; import jakarta.inject.Singleton; -import org.jdom.Element; -import org.jetbrains.annotations.NonNls; import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.io.IOException; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; @Singleton -public class DefaultProjectStoreImpl extends ProjectStoreImpl { - @NonNls - private static final String ROOT_TAG_NAME = "defaultProject"; +public class DefaultProjectStoreImpl extends SingleFileProjectStoreImpl { + public static final String ROOT_TAG_NAME = "defaultProject"; @Inject public DefaultProjectStoreImpl(@Nonnull Project project, @Nonnull ProjectPathMacroManager pathMacroManager, @Nonnull Provider applicationDefaultStoreCache) { super(project, pathMacroManager, applicationDefaultStoreCache); } - @Nullable - Element getStateCopy() { - final Element element = getProject().getStateElement(); - return element != null ? element.clone() : null; - } - - @Override - @Nonnull - protected DefaultProjectImpl getProject() { - return (DefaultProjectImpl)super.getProject(); - } - @Nonnull @Override - protected StateStorageManager createStateStorageManager() { - final XmlElementStorage storage = new XmlElementStorage("", RoamingType.DISABLED, myPathMacroManager.createTrackingSubstitutor(), ROOT_TAG_NAME, null) { - @Override - @Nullable - protected Element loadLocalData() { - return getStateCopy(); - } - - @Override - protected XmlElementStorageSaveSession createSaveSession(@Nonnull StorageData storageData) { - return new XmlElementStorageSaveSession(storageData) { - @Override - protected void doSave(@Nullable Element element) { - // we must set empty element instead of null as indicator - ProjectManager state is ready to save - getProject().setStateElement(element == null ? new Element("empty") : element); - } - - // we must not collapse paths here, because our solution is just a big hack - // by default, getElementToSave() returns collapsed paths -> setDefaultProjectRootElement -> project manager writeExternal -> save -> compare old and new - diff because old has expanded, but new collapsed - // -> needless save - @Override - protected boolean isCollapsePathsOnSave() { - return false; - } - }; - } - }; - - //noinspection deprecation - return new StateStorageManager() { - @Override - public void addMacro(@Nonnull String macro, @Nonnull String expansion) { - throw new UnsupportedOperationException("Method addMacro not implemented in " + getClass()); - } - - @Nonnull - @Override - public String buildFileSpec(@Nonnull Storage storage) { - throw new UnsupportedOperationException("Method buildFileSpec not implemented in " + getClass()); - } - - @Override - @Nullable - public TrackingPathMacroSubstitutor getMacroSubstitutor() { - return null; - } - - @Override - @Nullable - public StateStorage getStateStorage(@Nonnull Storage storageSpec) throws StateStorageException { - return storage; - } - - @Nullable - @Override - public StateStorage getStateStorage(@Nonnull String fileSpec, @Nonnull RoamingType roamingType) { - return storage; - } - - @Nonnull - @Override - public Couple> getCachedFileStateStorages(@Nonnull Collection changed, @Nonnull Collection deleted) { - return new Couple<>(Collections.emptyList(), Collections.emptyList()); - } - - @Override - public void clearStateStorage(@Nonnull String file) { - } - - @Nullable - @Override - public ExternalizationSession startExternalization() { - StateStorage.ExternalizationSession externalizationSession = storage.startExternalization(); - return externalizationSession == null ? null : new MyExternalizationSession(externalizationSession); - } - - @Nonnull - @Override - public String expandMacros(@Nonnull String file) { - throw new UnsupportedOperationException("Method expandMacros not implemented in " + getClass()); - } - - @Nonnull - @Override - public String collapseMacros(@Nonnull String path) { - throw new UnsupportedOperationException("Method collapseMacros not implemented in " + getClass()); - } - - @Override - public void setStreamProvider(@Nullable StreamProvider streamProvider) { - throw new UnsupportedOperationException("Method setStreamProvider not implemented in " + getClass()); - } - - @Nullable - @Override - public StreamProvider getStreamProvider() { - throw new UnsupportedOperationException("Method getStreamProviders not implemented in " + getClass()); - } - - @Nonnull - @Override - public Collection getStorageFileNames() { - throw new UnsupportedOperationException("Method getStorageFileNames not implemented in " + getClass()); - } - }; - } - - @Override - public void load() throws IOException { - Element stateElement = getProject().getStateElement(); - if (stateElement != null) { - // reload storage - since initNotLazyService called before #loadState() - reload(Arrays.asList(getMainStorage())); - } - } - - private static class MyExternalizationSession implements StateStorageManager.ExternalizationSession { - @Nonnull - final StateStorage.ExternalizationSession externalizationSession; - - public MyExternalizationSession(@Nonnull StateStorage.ExternalizationSession externalizationSession) { - this.externalizationSession = externalizationSession; - } - - @Override - public void setState(@Nonnull Storage[] storageSpecs, @Nonnull Object component, @Nonnull String componentName, @Nonnull Object state) { - externalizationSession.setState(component, componentName, state, null); - } - - @Nonnull - @Override - public List createSaveSessions(boolean force) { - return ContainerUtil.createMaybeSingletonList(externalizationSession.createSaveSession(false)); - } + protected String getRootTagName() { + return ROOT_TAG_NAME; } } \ No newline at end of file diff --git a/modules/base/platform-impl/src/main/java/consulo/components/impl/stores/ProjectStoreImpl.java b/modules/base/platform-impl/src/main/java/consulo/components/impl/stores/ProjectStoreImpl.java index 0974743a604e..d87260404001 100644 --- a/modules/base/platform-impl/src/main/java/consulo/components/impl/stores/ProjectStoreImpl.java +++ b/modules/base/platform-impl/src/main/java/consulo/components/impl/stores/ProjectStoreImpl.java @@ -125,7 +125,7 @@ public void setProjectFilePathNoUI(@Nonnull final String filePath) { @Override @Nullable public VirtualFile getProjectBaseDir() { - if (myProject.isDefault()) return null; + if (myProject.isDefault() || myProject.isWelcome()) return null; final String path = getProjectBasePath(); if (path == null) return null; @@ -135,7 +135,7 @@ public VirtualFile getProjectBaseDir() { @Override public String getProjectBasePath() { - if (myProject.isDefault()) return null; + if (myProject.isDefault() || myProject.isWelcome()) return null; final String path = getProjectFilePath(); if (!StringUtil.isEmptyOrSpaces(path)) { @@ -152,7 +152,7 @@ public String getProjectBasePath() { } private String getBasePath(@Nonnull File file) { - if (myProject.isDefault()) { + if (myProject.isDefault() || myProject.isWelcome()) { return file.getParent(); } else { @@ -185,7 +185,7 @@ public static String readProjectName(@Nonnull File file) { @Override public String getPresentableUrl() { - if (myProject.isDefault()) { + if (myProject.isDefault() || myProject.isWelcome()) { return null; } if (myPresentableUrl == null) { @@ -199,7 +199,10 @@ public String getPresentableUrl() { @Override public VirtualFile getProjectFile() { - return myProject.isDefault() ? null : ((VfsFileBasedStorage)getDefaultFileStorage()).getVirtualFile(); + if (myProject.isDefault() || myProject.isWelcome()) { + return null; + } + return ((VfsFileBasedStorage)getDefaultFileStorage()).getVirtualFile(); } @Nonnull @@ -212,7 +215,10 @@ private XmlElementStorage getDefaultFileStorage() { @Override public VirtualFile getWorkspaceFile() { - if (myProject.isDefault()) return null; + if (myProject.isDefault() || myProject.isWelcome()) { + return null; + } + final VfsFileBasedStorage storage = (VfsFileBasedStorage)getStateStorageManager().getStateStorage(StoragePathMacros.WORKSPACE_FILE, RoamingType.DISABLED); assert storage != null; return storage.getVirtualFile(); @@ -231,7 +237,10 @@ public void loadProjectFromTemplate(@Nonnull ProjectImpl defaultProject) { @Nonnull @Override public String getProjectFilePath() { - return myProject.isDefault() ? "" : ((VfsFileBasedStorage)getDefaultFileStorage()).getFilePath(); + if (myProject.isDefault() || myProject.isWelcome()) { + return ""; + } + return ((VfsFileBasedStorage)getDefaultFileStorage()).getFilePath(); } @Nonnull diff --git a/modules/base/platform-impl/src/main/java/consulo/components/impl/stores/SingleFileProjectStoreImpl.java b/modules/base/platform-impl/src/main/java/consulo/components/impl/stores/SingleFileProjectStoreImpl.java new file mode 100644 index 000000000000..0b9b9050ff6a --- /dev/null +++ b/modules/base/platform-impl/src/main/java/consulo/components/impl/stores/SingleFileProjectStoreImpl.java @@ -0,0 +1,202 @@ +/* + * Copyright 2013-2021 consulo.io + * + * Licensed 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 consulo.components.impl.stores; + +import com.intellij.openapi.components.*; +import com.intellij.openapi.components.impl.ProjectPathMacroManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Couple; +import com.intellij.util.containers.ContainerUtil; +import consulo.components.impl.stores.storage.StateStorageManager; +import consulo.components.impl.stores.storage.StorageData; +import consulo.components.impl.stores.storage.VfsFileBasedStorage; +import consulo.components.impl.stores.storage.XmlElementStorage; +import consulo.project.impl.SingleFileProjectImpl; +import jakarta.inject.Inject; +import jakarta.inject.Provider; +import org.jdom.Element; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.io.IOException; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +/** + * @author VISTALL + * @since 25/12/2021 + */ +public abstract class SingleFileProjectStoreImpl extends ProjectStoreImpl { + @Inject + public SingleFileProjectStoreImpl(@Nonnull Project project, @Nonnull ProjectPathMacroManager pathMacroManager, @Nonnull Provider applicationDefaultStoreCache) { + super(project, pathMacroManager, applicationDefaultStoreCache); + } + + @Nullable + Element getStateCopy() { + final Element element = getProject().getStateElement(); + return element != null ? element.clone() : null; + } + + @Nonnull + protected abstract String getRootTagName(); + + @Override + @Nonnull + protected SingleFileProjectImpl getProject() { + return (SingleFileProjectImpl)super.getProject(); + } + + @Nonnull + @Override + protected StateStorageManager createStateStorageManager() { + final XmlElementStorage storage = new XmlElementStorage("", RoamingType.DISABLED, myPathMacroManager.createTrackingSubstitutor(), getRootTagName(), null) { + @Override + @Nullable + protected Element loadLocalData() { + return getStateCopy(); + } + + @Override + protected XmlElementStorageSaveSession createSaveSession(@Nonnull StorageData storageData) { + return new XmlElementStorageSaveSession(storageData) { + @Override + protected void doSave(@Nullable Element element) { + // we must set empty element instead of null as indicator - ProjectManager state is ready to save + getProject().setStateElement(element == null ? new Element("empty") : element); + } + + // we must not collapse paths here, because our solution is just a big hack + // by default, getElementToSave() returns collapsed paths -> setDefaultProjectRootElement -> project manager writeExternal -> save -> compare old and new - diff because old has expanded, but new collapsed + // -> needless save + @Override + protected boolean isCollapsePathsOnSave() { + return false; + } + }; + } + }; + + //noinspection deprecation + return new StateStorageManager() { + @Override + public void addMacro(@Nonnull String macro, @Nonnull String expansion) { + throw new UnsupportedOperationException("Method addMacro not implemented in " + getClass()); + } + + @Nonnull + @Override + public String buildFileSpec(@Nonnull Storage storage) { + throw new UnsupportedOperationException("Method buildFileSpec not implemented in " + getClass()); + } + + @Override + @Nullable + public TrackingPathMacroSubstitutor getMacroSubstitutor() { + return null; + } + + @Override + @Nullable + public StateStorage getStateStorage(@Nonnull Storage storageSpec) throws StateStorageException { + return storage; + } + + @Nullable + @Override + public StateStorage getStateStorage(@Nonnull String fileSpec, @Nonnull RoamingType roamingType) { + return storage; + } + + @Nonnull + @Override + public Couple> getCachedFileStateStorages(@Nonnull Collection changed, @Nonnull Collection deleted) { + return new Couple<>(Collections.emptyList(), Collections.emptyList()); + } + + @Override + public void clearStateStorage(@Nonnull String file) { + } + + @Nullable + @Override + public ExternalizationSession startExternalization() { + StateStorage.ExternalizationSession externalizationSession = storage.startExternalization(); + return externalizationSession == null ? null : new MyExternalizationSession(externalizationSession); + } + + @Nonnull + @Override + public String expandMacros(@Nonnull String file) { + throw new UnsupportedOperationException("Method expandMacros not implemented in " + getClass()); + } + + @Nonnull + @Override + public String collapseMacros(@Nonnull String path) { + throw new UnsupportedOperationException("Method collapseMacros not implemented in " + getClass()); + } + + @Override + public void setStreamProvider(@Nullable StreamProvider streamProvider) { + throw new UnsupportedOperationException("Method setStreamProvider not implemented in " + getClass()); + } + + @Nullable + @Override + public StreamProvider getStreamProvider() { + throw new UnsupportedOperationException("Method getStreamProviders not implemented in " + getClass()); + } + + @Nonnull + @Override + public Collection getStorageFileNames() { + throw new UnsupportedOperationException("Method getStorageFileNames not implemented in " + getClass()); + } + }; + } + + @Override + public void load() throws IOException { + Element stateElement = getProject().getStateElement(); + if (stateElement != null) { + // reload storage - since initNotLazyService called before #loadState() + reload(Arrays.asList(getMainStorage())); + } + } + + private static class MyExternalizationSession implements StateStorageManager.ExternalizationSession { + @Nonnull + final StateStorage.ExternalizationSession externalizationSession; + + public MyExternalizationSession(@Nonnull StateStorage.ExternalizationSession externalizationSession) { + this.externalizationSession = externalizationSession; + } + + @Override + public void setState(@Nonnull Storage[] storageSpecs, @Nonnull Object component, @Nonnull String componentName, @Nonnull Object state) { + externalizationSession.setState(component, componentName, state, null); + } + + @Nonnull + @Override + public List createSaveSessions(boolean force) { + return ContainerUtil.createMaybeSingletonList(externalizationSession.createSaveSession(false)); + } + } +} \ No newline at end of file diff --git a/modules/base/platform-impl/src/main/java/consulo/ide/plugins/whatsNew/WhatsNewVirtualFileEditor.java b/modules/base/platform-impl/src/main/java/consulo/ide/plugins/whatsNew/WhatsNewVirtualFileEditor.java index 143827106f6e..15a999d6c925 100644 --- a/modules/base/platform-impl/src/main/java/consulo/ide/plugins/whatsNew/WhatsNewVirtualFileEditor.java +++ b/modules/base/platform-impl/src/main/java/consulo/ide/plugins/whatsNew/WhatsNewVirtualFileEditor.java @@ -149,6 +149,9 @@ private void fetchData() { myLoadingPanel.add(ScrollPaneFactory.createScrollPane(myEditorPanel, true), BorderLayout.CENTER); myLoadingPanel.stopLoading(); + + myLoadingPanel.invalidate(); + myLoadingPanel.repaint(); }); }); } diff --git a/modules/base/platform-impl/src/main/java/consulo/project/impl/SingleFileProjectFactoryImpl.java b/modules/base/platform-impl/src/main/java/consulo/project/impl/SingleFileProjectFactoryImpl.java new file mode 100644 index 000000000000..f34e83bc0f10 --- /dev/null +++ b/modules/base/platform-impl/src/main/java/consulo/project/impl/SingleFileProjectFactoryImpl.java @@ -0,0 +1,114 @@ +/* + * Copyright 2013-2021 consulo.io + * + * Licensed 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 consulo.project.impl; + +import com.intellij.openapi.components.PersistentStateComponent; +import consulo.annotation.access.RequiredReadAction; +import consulo.annotation.access.RequiredWriteAction; +import consulo.disposer.Disposable; +import consulo.disposer.Disposer; +import consulo.logging.Logger; +import jakarta.inject.Inject; +import org.jdom.Element; +import org.jetbrains.annotations.TestOnly; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.io.IOException; + +/** + * @author VISTALL + * @since 25/12/2021 + */ +public class SingleFileProjectFactoryImpl

implements PersistentStateComponent, Disposable { + private static final Logger LOG = Logger.getInstance(SingleFileProjectFactoryImpl.class); + @Nonnull + private final String myRootTagName; + + private P myProject; + private boolean myProjectWasDisposed = false; + + @Inject + public SingleFileProjectFactoryImpl(@Nonnull P project, @Nonnull String rootTagName) { + myRootTagName = rootTagName; + myProject = project; + myProject.initNotLazyServices(null); + myProject.setInitialized(); + } + + @TestOnly + public boolean isProjectInitialized() { + return myProject != null; + } + + @Nonnull + public P getProject() { + LOG.assertTrue(!myProjectWasDisposed, "Project has been already disposed!"); + return myProject; + } + + @RequiredWriteAction + @Nullable + @Override + public Element getState() { + assert myProject != null; + + myProject.save(); + + Element stateElement = myProject.getStateElement(); + + if (stateElement == null) { + // we are not ready to save + return null; + } + + Element element = new Element("state"); + stateElement.detach(); + element.addContent(stateElement); + return element; + } + + @RequiredReadAction + @Override + public void loadState(Element state) { + Element defaultProjectElement = state.getChild(myRootTagName); + if (defaultProjectElement != null) { + defaultProjectElement.detach(); + + myProject.setStateElement(defaultProjectElement); + } + } + + @Override + public void afterLoadState() { + try { + myProject.getStateStore().load(); + } + catch (IOException e) { + LOG.error(e); + } + } + + @Override + public void dispose() { + if (myProject != null) { + Disposer.dispose(myProject); + + myProject = null; + myProjectWasDisposed = true; + } + } +} \ No newline at end of file diff --git a/modules/base/platform-impl/src/main/java/consulo/project/impl/SingleFileProjectImpl.java b/modules/base/platform-impl/src/main/java/consulo/project/impl/SingleFileProjectImpl.java new file mode 100644 index 000000000000..3930a08d0827 --- /dev/null +++ b/modules/base/platform-impl/src/main/java/consulo/project/impl/SingleFileProjectImpl.java @@ -0,0 +1,55 @@ +/* + * Copyright 2013-2021 consulo.io + * + * Licensed 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 consulo.project.impl; + +import com.intellij.openapi.application.Application; +import com.intellij.openapi.project.ProjectManager; +import com.intellij.openapi.project.impl.ProjectImpl; +import org.jdom.Element; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * @author VISTALL + * @since 25/12/2021 + */ +public class SingleFileProjectImpl extends ProjectImpl { + private Element myStateElement; + private boolean myInitialized; + + protected SingleFileProjectImpl(@Nonnull Application application, @Nonnull ProjectManager manager, @Nonnull String dirPath, boolean isOptimiseTestLoadSpeed, String projectName, boolean noUIThread) { + super(application, manager, dirPath, isOptimiseTestLoadSpeed, projectName, noUIThread); + } + + @Nullable + public Element getStateElement() { + return myStateElement; + } + + public void setStateElement(@Nullable Element stateElement) { + myStateElement = stateElement; + } + + public void setInitialized() { + myInitialized = true; + } + + @Override + public boolean isInitialized() { + return myInitialized; + } +} diff --git a/modules/base/platform-impl/src/main/java/consulo/project/impl/welcome/WelcomeProjectFactoryImpl.java b/modules/base/platform-impl/src/main/java/consulo/project/impl/welcome/WelcomeProjectFactoryImpl.java new file mode 100644 index 000000000000..0cd9e1e4cb51 --- /dev/null +++ b/modules/base/platform-impl/src/main/java/consulo/project/impl/welcome/WelcomeProjectFactoryImpl.java @@ -0,0 +1,51 @@ +/* + * Copyright 2013-2021 consulo.io + * + * Licensed 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 consulo.project.impl.welcome; + +import com.intellij.openapi.application.Application; +import com.intellij.openapi.components.PersistentStateComponent; +import com.intellij.openapi.components.State; +import com.intellij.openapi.components.Storage; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.project.ProjectManager; +import consulo.components.impl.stores.DefaultProjectStoreImpl; +import consulo.disposer.Disposable; +import consulo.project.WelcomeProjectFactory; +import consulo.project.impl.SingleFileProjectFactoryImpl; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; +import org.jdom.Element; + +import javax.annotation.Nonnull; + +/** + * @author VISTALL + * @since 25/12/2021 + */ +@State(name = "ProjectManager", storages = @Storage("welcome.project.xml")) +@Singleton +public class WelcomeProjectFactoryImpl extends SingleFileProjectFactoryImpl implements WelcomeProjectFactory, PersistentStateComponent, Disposable { + @Inject + public WelcomeProjectFactoryImpl(@Nonnull Application application, @Nonnull ProjectManager projectManager) { + super(new WelcomeProjectImpl(application, projectManager, "", application.isUnitTestMode()), DefaultProjectStoreImpl.ROOT_TAG_NAME); + } + + @Nonnull + @Override + public Project getWelcomeProject() { + return getProject(); + } +} \ No newline at end of file diff --git a/modules/base/platform-impl/src/main/java/consulo/project/impl/welcome/WelcomeProjectImpl.java b/modules/base/platform-impl/src/main/java/consulo/project/impl/welcome/WelcomeProjectImpl.java new file mode 100644 index 000000000000..391ea5ee63c9 --- /dev/null +++ b/modules/base/platform-impl/src/main/java/consulo/project/impl/welcome/WelcomeProjectImpl.java @@ -0,0 +1,46 @@ +/* + * Copyright 2013-2021 consulo.io + * + * Licensed 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 consulo.project.impl.welcome; + +import com.intellij.openapi.application.Application; +import com.intellij.openapi.project.ProjectManager; +import consulo.components.impl.stores.IProjectStore; +import consulo.project.impl.SingleFileProjectImpl; + +import javax.annotation.Nonnull; + +/** + * @author VISTALL + * @since 25/12/2021 + */ +public class WelcomeProjectImpl extends SingleFileProjectImpl { + private static final String NAME = "Welcome"; + + WelcomeProjectImpl(@Nonnull Application application, @Nonnull ProjectManager manager, @Nonnull String filePath, boolean optimiseTestLoadSpeed) { + super(application, manager, filePath, optimiseTestLoadSpeed, NAME, false); + } + + @Nonnull + @Override + protected Class getStoreImplClass() { + return WelcomeProjectStoreImpl.class; + } + + @Override + public boolean isWelcome() { + return true; + } +} diff --git a/modules/base/platform-impl/src/main/java/consulo/project/impl/welcome/WelcomeProjectStoreImpl.java b/modules/base/platform-impl/src/main/java/consulo/project/impl/welcome/WelcomeProjectStoreImpl.java new file mode 100644 index 000000000000..291f6f5f4413 --- /dev/null +++ b/modules/base/platform-impl/src/main/java/consulo/project/impl/welcome/WelcomeProjectStoreImpl.java @@ -0,0 +1,44 @@ +/* + * Copyright 2013-2021 consulo.io + * + * Licensed 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 consulo.project.impl.welcome; + +import com.intellij.openapi.components.impl.ProjectPathMacroManager; +import com.intellij.openapi.project.Project; +import consulo.components.impl.stores.ApplicationDefaultStoreCache; +import consulo.components.impl.stores.SingleFileProjectStoreImpl; +import jakarta.inject.Inject; +import jakarta.inject.Provider; + +import javax.annotation.Nonnull; + +/** + * @author VISTALL + * @since 25/12/2021 + */ +public class WelcomeProjectStoreImpl extends SingleFileProjectStoreImpl { + public static final String ROOT_TAG_NAME = "welcomeProject"; + + @Inject + public WelcomeProjectStoreImpl(@Nonnull Project project, @Nonnull ProjectPathMacroManager pathMacroManager, @Nonnull Provider applicationDefaultStoreCache) { + super(project, pathMacroManager, applicationDefaultStoreCache); + } + + @Nonnull + @Override + protected String getRootTagName() { + return ROOT_TAG_NAME; + } +} \ No newline at end of file diff --git a/modules/base/platform-impl/src/main/java/consulo/start/WelcomeFrameManager.java b/modules/base/platform-impl/src/main/java/consulo/start/WelcomeFrameManager.java index 7cf835ee00ad..87c7d7d76512 100644 --- a/modules/base/platform-impl/src/main/java/consulo/start/WelcomeFrameManager.java +++ b/modules/base/platform-impl/src/main/java/consulo/start/WelcomeFrameManager.java @@ -27,9 +27,10 @@ import com.intellij.openapi.wm.IdeFrame; import com.intellij.openapi.wm.WindowManager; import com.intellij.openapi.wm.ex.WindowManagerEx; -import consulo.ui.annotation.RequiredUIAccess; -import consulo.ui.UIAccess; +import consulo.project.WelcomeProjectFactory; import consulo.ui.Size; +import consulo.ui.UIAccess; +import consulo.ui.annotation.RequiredUIAccess; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -85,10 +86,13 @@ protected void frameClosed() { public void showFrame() { UIAccess.assertIsUIThread(); - if (myFrameInstance == null) { - myFrameInstance = createFrame(); - myFrameInstance.getWindow().show(); - } + WelcomeProjectFactory welcomeProjectFactory = Application.get().getInstance(WelcomeProjectFactory.class); + + ProjectManager.getInstance().openProjectAsync(welcomeProjectFactory.getWelcomeProject(), UIAccess.current()); + //if (myFrameInstance == null) { + // myFrameInstance = createFrame(); + // myFrameInstance.getWindow().show(); + //} } @RequiredUIAccess From 4b667e260d9e5702d4f4bd7559876b14a17d3ea0 Mon Sep 17 00:00:00 2001 From: VISTALL Date: Sat, 25 Dec 2021 17:04:55 +0300 Subject: [PATCH 2/6] intro welcome editor for recent projects, etc --- .../src/main/resources/META-INF/plugin.xml | 5 +- .../fileEditor/impl/UnifiedEditorWindow.java | 12 ++- .../com/intellij/ui/tabs/impl/TabLabel.java | 5 + .../internal/NotClosableFileMarker.java | 25 +++++ .../com/intellij/ide/actions/CloseAction.java | 6 +- .../ide/actions/CloseAllEditorsAction.java | 7 +- .../impl/EditorTabbedContainer.java | 32 +++++-- .../impl/FileEditorManagerImpl.java | 5 + .../impl/WelcomeVirtualFile.java | 41 +++++++++ .../impl/WelcomeVirtualFileEditor.java | 92 +++++++++++++++++++ .../WelcomeVirtualFileEditorProvider.java | 49 ++++++++++ .../WelcomeVirtualFileStartupActivity.java | 36 ++++++++ .../impl/ReopenProjectToolWindowActivity.java | 4 +- 13 files changed, 303 insertions(+), 16 deletions(-) create mode 100644 modules/base/platform-api/src/main/java/consulo/fileEditor/internal/NotClosableFileMarker.java create mode 100644 modules/base/platform-impl/src/main/java/consulo/ide/welcomeScreen/impl/WelcomeVirtualFile.java create mode 100644 modules/base/platform-impl/src/main/java/consulo/ide/welcomeScreen/impl/WelcomeVirtualFileEditor.java create mode 100644 modules/base/platform-impl/src/main/java/consulo/ide/welcomeScreen/impl/WelcomeVirtualFileEditorProvider.java create mode 100644 modules/base/platform-impl/src/main/java/consulo/ide/welcomeScreen/impl/WelcomeVirtualFileStartupActivity.java diff --git a/modules/base/base-plugin/src/main/resources/META-INF/plugin.xml b/modules/base/base-plugin/src/main/resources/META-INF/plugin.xml index 9d65e10c4b2a..2fda91f509a3 100644 --- a/modules/base/base-plugin/src/main/resources/META-INF/plugin.xml +++ b/modules/base/base-plugin/src/main/resources/META-INF/plugin.xml @@ -2518,7 +2518,7 @@ - + @@ -2803,6 +2803,9 @@ + + + diff --git a/modules/base/lang-impl/src/main/java/consulo/fileEditor/impl/UnifiedEditorWindow.java b/modules/base/lang-impl/src/main/java/consulo/fileEditor/impl/UnifiedEditorWindow.java index 5670bd12bd1c..ed09476cce69 100644 --- a/modules/base/lang-impl/src/main/java/consulo/fileEditor/impl/UnifiedEditorWindow.java +++ b/modules/base/lang-impl/src/main/java/consulo/fileEditor/impl/UnifiedEditorWindow.java @@ -24,6 +24,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import consulo.disposer.Disposable; +import consulo.fileEditor.internal.NotClosableFileMarker; import consulo.fileTypes.impl.VfsIconUtil; import consulo.ui.Component; import consulo.ui.Tab; @@ -285,14 +286,17 @@ public void setEditor(@Nullable EditorWithProviderComposite editor, boolean sele } else { - EditorWithProviderComposite fileComposite = findFileComposite(editor.getFile()); + VirtualFile file = editor.getFile(); + EditorWithProviderComposite fileComposite = findFileComposite(file); if (fileComposite == null) { - Tab tab = myTabbedLayout.addTab(editor.getFile().getName(), editor.getUIComponent()); + Tab tab = myTabbedLayout.addTab(file.getName(), editor.getUIComponent()); tab.setCloseHandler((thisTab, component) -> { DataContext dataContext = DataManager.getInstance().getDataContext(); - new CloseTab(myTabbedLayout, myProject, editor.getFile(), this).actionPerformed(AnActionEvent.createFromInputEvent(null, "Test", null, dataContext)); + if (!(file instanceof NotClosableFileMarker)) { + new CloseTab(myTabbedLayout, myProject, file, this).actionPerformed(AnActionEvent.createFromInputEvent(null, "Test", null, dataContext)); + } }); - tab.withIcon(VfsIconUtil.getIcon(editor.getFile(), 0, myManager.getProject())); + tab.withIcon(VfsIconUtil.getIcon(file, 0, myManager.getProject())); myEditors.put(editor, tab); } else { diff --git a/modules/base/platform-api/src/main/java/com/intellij/ui/tabs/impl/TabLabel.java b/modules/base/platform-api/src/main/java/com/intellij/ui/tabs/impl/TabLabel.java index e132fa8a2fcd..3dc715002247 100644 --- a/modules/base/platform-api/src/main/java/com/intellij/ui/tabs/impl/TabLabel.java +++ b/modules/base/platform-api/src/main/java/com/intellij/ui/tabs/impl/TabLabel.java @@ -32,6 +32,7 @@ import com.intellij.util.ui.UIUtil; import com.intellij.util.ui.accessibility.ScreenReader; import consulo.awt.TargetAWT; +import consulo.fileEditor.internal.NotClosableFileMarker; import consulo.ui.image.Image; import consulo.ui.image.ImageEffects; @@ -167,6 +168,10 @@ public Insets getInsets() { if (UISettings.getInstance().SHOW_CLOSE_BUTTON) { insets.right = JBUI.scale(3); } + + if (myInfo.getObject() instanceof NotClosableFileMarker) { + insets.right = JBUI.scale(8); + } return insets; } diff --git a/modules/base/platform-api/src/main/java/consulo/fileEditor/internal/NotClosableFileMarker.java b/modules/base/platform-api/src/main/java/consulo/fileEditor/internal/NotClosableFileMarker.java new file mode 100644 index 000000000000..ff4da94d7b21 --- /dev/null +++ b/modules/base/platform-api/src/main/java/consulo/fileEditor/internal/NotClosableFileMarker.java @@ -0,0 +1,25 @@ +/* + * Copyright 2013-2021 consulo.io + * + * Licensed 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 consulo.fileEditor.internal; + +/** + * Interface for disabling close action if file is opened in editor + * + * @author VISTALL + * @since 25/12/2021 + */ +public interface NotClosableFileMarker { +} diff --git a/modules/base/platform-impl/src/main/java/com/intellij/ide/actions/CloseAction.java b/modules/base/platform-impl/src/main/java/com/intellij/ide/actions/CloseAction.java index febbbc9c66d6..83125a1f50c4 100644 --- a/modules/base/platform-impl/src/main/java/com/intellij/ide/actions/CloseAction.java +++ b/modules/base/platform-impl/src/main/java/com/intellij/ide/actions/CloseAction.java @@ -32,7 +32,7 @@ public void update(@Nonnull AnActionEvent e) { e.getPresentation().setIcon(ActionPlaces.isToolbarPlace(e.getPlace()) ? AllIcons.Actions.Cancel : null); CloseTarget closeTarget = e.getData(CloseTarget.KEY); - e.getPresentation().setEnabled(closeTarget != null); + e.getPresentation().setEnabled(closeTarget != null && closeTarget.isCloseActionEnabled()); } @RequiredUIAccess @@ -45,5 +45,9 @@ public interface CloseTarget { Key KEY = Key.create("GenericClosable"); void close(); + + default boolean isCloseActionEnabled() { + return true; + } } } diff --git a/modules/base/platform-impl/src/main/java/com/intellij/ide/actions/CloseAllEditorsAction.java b/modules/base/platform-impl/src/main/java/com/intellij/ide/actions/CloseAllEditorsAction.java index 6fa0557d538e..58084cc624dc 100644 --- a/modules/base/platform-impl/src/main/java/com/intellij/ide/actions/CloseAllEditorsAction.java +++ b/modules/base/platform-impl/src/main/java/com/intellij/ide/actions/CloseAllEditorsAction.java @@ -27,8 +27,11 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import consulo.fileEditor.impl.EditorWindow; +import consulo.fileEditor.internal.NotClosableFileMarker; +import consulo.ui.annotation.RequiredUIAccess; public class CloseAllEditorsAction extends AnAction implements DumbAware { + @RequiredUIAccess @Override public void actionPerformed(final AnActionEvent e) { final Project project = e.getData(CommonDataKeys.PROJECT); @@ -38,7 +41,9 @@ public void actionPerformed(final AnActionEvent e) { if (window != null) { final VirtualFile[] files = window.getFiles(); for (final VirtualFile file : files) { - window.closeFile(file); + if (!(file instanceof NotClosableFileMarker)) { + window.closeFile(file); + } } return; } diff --git a/modules/base/platform-impl/src/main/java/com/intellij/openapi/fileEditor/impl/EditorTabbedContainer.java b/modules/base/platform-impl/src/main/java/com/intellij/openapi/fileEditor/impl/EditorTabbedContainer.java index 83e3d4b1488e..e263ebd9947b 100644 --- a/modules/base/platform-impl/src/main/java/com/intellij/openapi/fileEditor/impl/EditorTabbedContainer.java +++ b/modules/base/platform-impl/src/main/java/com/intellij/openapi/fileEditor/impl/EditorTabbedContainer.java @@ -59,6 +59,7 @@ import consulo.disposer.Disposable; import consulo.disposer.Disposer; import consulo.fileEditor.impl.EditorWindow; +import consulo.fileEditor.internal.NotClosableFileMarker; import consulo.util.dataholder.Key; import org.jetbrains.annotations.NonNls; @@ -334,7 +335,9 @@ public void insertTab(final VirtualFile file, final consulo.ui.image.Image icon, tab.setTestableUi(new MyQueryable(tab)); final ActionGroup.Builder tabActions = ActionGroup.newImmutableBuilder(); - tabActions.add(new CloseTab(comp, myProject, file, myWindow)); + if (!(file instanceof NotClosableFileMarker)) { + tabActions.add(new CloseTab(comp, myProject, file, myWindow)); + } tab.setTabLabelActions(tabActions.build(), ActionPlaces.EDITOR_TAB); myTabs.addTabSilently(tab, indexToInsert); @@ -419,7 +422,7 @@ public Object getData(@Nonnull Key dataId) { final VirtualFile selectedFile = myWindow.getSelectedFile(); return selectedFile != null && selectedFile.isValid() ? selectedFile : null; } - if (DesktopEditorWindow.DATA_KEY == dataId) { + if (EditorWindow.DATA_KEY == dataId) { return myWindow; } if (PlatformDataKeys.HELP_ID == dataId) { @@ -433,10 +436,6 @@ public Object getData(@Nonnull Key dataId) { } } - if (DesktopEditorWindow.DATA_KEY == dataId) { - return myWindow; - } - return null; } } @@ -459,6 +458,19 @@ public void close() { }); } + @Override + public boolean isCloseActionEnabled() { + TabInfo selected = myTabs.getTargetInfo(); + if (selected == null) return true; + + final VirtualFile file = (VirtualFile)selected.getObject(); + + if (file instanceof NotClosableFileMarker) { + return false; + } + return true; + } + private boolean isFloating() { return myWindow.getOwner().isFloating(); } @@ -471,12 +483,18 @@ public void mouseReleased(MouseEvent e) { if (UIUtil.isCloseClick(e, MouseEvent.MOUSE_RELEASED)) { final TabInfo info = myTabs.findInfo(e); if (info != null) { + Object selectedFile = info.getObject(); + if (selectedFile instanceof NotClosableFileMarker) { + return; + } + IdeEventQueue.getInstance().blockNextEvents(e); if (e.isAltDown() && e.getButton() == MouseEvent.BUTTON1) {//close others List allTabInfos = myTabs.getTabs(); for (TabInfo tabInfo : allTabInfos) { + VirtualFile object = (VirtualFile)tabInfo.getObject(); if (tabInfo == info) continue; - FileEditorManagerEx.getInstanceEx(myProject).closeFile((VirtualFile)tabInfo.getObject(), myWindow); + FileEditorManagerEx.getInstanceEx(myProject).closeFile(object, myWindow); } } else { diff --git a/modules/base/platform-impl/src/main/java/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java b/modules/base/platform-impl/src/main/java/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java index cf72e9dc451b..c5a4cad97d6f 100644 --- a/modules/base/platform-impl/src/main/java/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java +++ b/modules/base/platform-impl/src/main/java/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java @@ -79,6 +79,7 @@ import consulo.disposer.Disposer; import consulo.fileEditor.impl.*; import consulo.fileEditor.impl.text.TextEditorProvider; +import consulo.fileEditor.internal.NotClosableFileMarker; import consulo.logging.Logger; import consulo.ui.UIAccess; import consulo.ui.annotation.RequiredUIAccess; @@ -570,6 +571,10 @@ public void closeFile(@Nonnull final VirtualFile file) { public void closeFile(@Nonnull final VirtualFile file, final boolean moveFocus, final boolean closeAllCopies) { assertDispatchThread(); + if (file instanceof NotClosableFileMarker) { + return; + } + CommandProcessor.getInstance().executeCommand(myProject, () -> closeFileImpl(file, moveFocus, closeAllCopies), "", null); } diff --git a/modules/base/platform-impl/src/main/java/consulo/ide/welcomeScreen/impl/WelcomeVirtualFile.java b/modules/base/platform-impl/src/main/java/consulo/ide/welcomeScreen/impl/WelcomeVirtualFile.java new file mode 100644 index 000000000000..04ce5ffdbfed --- /dev/null +++ b/modules/base/platform-impl/src/main/java/consulo/ide/welcomeScreen/impl/WelcomeVirtualFile.java @@ -0,0 +1,41 @@ +/* + * Copyright 2013-2021 consulo.io + * + * Licensed 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 consulo.ide.welcomeScreen.impl; + +import com.intellij.openapi.fileEditor.impl.IdeDocumentHistoryImpl; +import com.intellij.openapi.vfs.VirtualFileWithoutContent; +import com.intellij.testFramework.LightVirtualFile; +import consulo.fileEditor.internal.NotClosableFileMarker; + +/** + * @author VISTALL + * @since 25/12/2021 + */ +public class WelcomeVirtualFile extends LightVirtualFile implements VirtualFileWithoutContent, IdeDocumentHistoryImpl.SkipFromDocumentHistory, NotClosableFileMarker { + public WelcomeVirtualFile() { + super("Welcome"); + } + + @Override + public boolean isValid() { + return true; + } + + @Override + public boolean equals(Object obj) { + return obj instanceof WelcomeVirtualFile; + } +} diff --git a/modules/base/platform-impl/src/main/java/consulo/ide/welcomeScreen/impl/WelcomeVirtualFileEditor.java b/modules/base/platform-impl/src/main/java/consulo/ide/welcomeScreen/impl/WelcomeVirtualFileEditor.java new file mode 100644 index 000000000000..591a7081274f --- /dev/null +++ b/modules/base/platform-impl/src/main/java/consulo/ide/welcomeScreen/impl/WelcomeVirtualFileEditor.java @@ -0,0 +1,92 @@ +/* + * Copyright 2013-2021 consulo.io + * + * Licensed 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 consulo.ide.welcomeScreen.impl; + +import com.intellij.openapi.fileEditor.FileEditor; +import com.intellij.openapi.project.Project; +import consulo.util.dataholder.UserDataHolderBase; +import kava.beans.PropertyChangeListener; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import javax.swing.*; + +/** + * @author VISTALL + * @since 25/12/2021 + */ +public class WelcomeVirtualFileEditor extends UserDataHolderBase implements FileEditor { + private final Project myProject; + + private JComponent myComponent; + + public WelcomeVirtualFileEditor(Project project) { + myProject = project; + } + + @Nonnull + @Override + public JComponent getComponent() { + if (myComponent != null) { + return myComponent; + } + + myComponent = new JPanel(); + return myComponent; + } + + @Nullable + @Override + public JComponent getPreferredFocusedComponent() { + return null; + } + + @Nonnull + @Override + public String getName() { + return "welcome"; + } + + @Override + public boolean isModified() { + return false; + } + + @Override + public void selectNotify() { + + } + + @Override + public void deselectNotify() { + + } + + @Override + public void addPropertyChangeListener(@Nonnull PropertyChangeListener listener) { + + } + + @Override + public void removePropertyChangeListener(@Nonnull PropertyChangeListener listener) { + + } + + @Override + public void dispose() { + + } +} diff --git a/modules/base/platform-impl/src/main/java/consulo/ide/welcomeScreen/impl/WelcomeVirtualFileEditorProvider.java b/modules/base/platform-impl/src/main/java/consulo/ide/welcomeScreen/impl/WelcomeVirtualFileEditorProvider.java new file mode 100644 index 000000000000..5f04c37ea3ee --- /dev/null +++ b/modules/base/platform-impl/src/main/java/consulo/ide/welcomeScreen/impl/WelcomeVirtualFileEditorProvider.java @@ -0,0 +1,49 @@ +/* + * Copyright 2013-2021 consulo.io + * + * Licensed 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 consulo.ide.welcomeScreen.impl; + +import com.intellij.openapi.fileEditor.FileEditor; +import com.intellij.openapi.fileEditor.FileEditorProvider; +import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import consulo.ui.annotation.RequiredUIAccess; + +import javax.annotation.Nonnull; + +/** + * @author VISTALL + * @since 25/12/2021 + */ +public class WelcomeVirtualFileEditorProvider implements FileEditorProvider, DumbAware { + @Override + public boolean accept(@Nonnull Project project, @Nonnull VirtualFile file) { + return file instanceof WelcomeVirtualFile; + } + + @RequiredUIAccess + @Nonnull + @Override + public FileEditor createEditor(@Nonnull Project project, @Nonnull VirtualFile file) { + return new WelcomeVirtualFileEditor(project); + } + + @Nonnull + @Override + public String getEditorTypeId() { + return "welcome"; + } +} diff --git a/modules/base/platform-impl/src/main/java/consulo/ide/welcomeScreen/impl/WelcomeVirtualFileStartupActivity.java b/modules/base/platform-impl/src/main/java/consulo/ide/welcomeScreen/impl/WelcomeVirtualFileStartupActivity.java new file mode 100644 index 000000000000..b5440beed670 --- /dev/null +++ b/modules/base/platform-impl/src/main/java/consulo/ide/welcomeScreen/impl/WelcomeVirtualFileStartupActivity.java @@ -0,0 +1,36 @@ +/* + * Copyright 2013-2021 consulo.io + * + * Licensed 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 consulo.ide.welcomeScreen.impl; + +import com.intellij.openapi.fileEditor.FileEditorManager; +import com.intellij.openapi.project.Project; +import consulo.project.startup.StartupActivity; +import consulo.ui.UIAccess; + +import javax.annotation.Nonnull; + +/** + * @author VISTALL + * @since 25/12/2021 + */ +public class WelcomeVirtualFileStartupActivity implements StartupActivity.DumbAware { + @Override + public void runActivity(@Nonnull Project project, @Nonnull UIAccess uiAccess) { + if (project.isWelcome()) { + uiAccess.give(() -> FileEditorManager.getInstance(project).openFile(new WelcomeVirtualFile(), true)); + } + } +} diff --git a/modules/base/platform-impl/src/main/java/consulo/project/impl/ReopenProjectToolWindowActivity.java b/modules/base/platform-impl/src/main/java/consulo/project/impl/ReopenProjectToolWindowActivity.java index bb32749d4176..12e95f47087a 100644 --- a/modules/base/platform-impl/src/main/java/consulo/project/impl/ReopenProjectToolWindowActivity.java +++ b/modules/base/platform-impl/src/main/java/consulo/project/impl/ReopenProjectToolWindowActivity.java @@ -17,11 +17,11 @@ import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; -import com.intellij.openapi.startup.StartupActivity; import com.intellij.openapi.util.EmptyRunnable; import com.intellij.openapi.wm.ToolWindow; import com.intellij.openapi.wm.ToolWindowId; import com.intellij.openapi.wm.ToolWindowManager; +import consulo.project.startup.StartupActivity; import consulo.ui.UIAccess; import javax.annotation.Nonnull; @@ -32,7 +32,7 @@ */ public class ReopenProjectToolWindowActivity implements StartupActivity.Background, DumbAware { @Override - public void runActivity(@Nonnull UIAccess uiAccess, @Nonnull Project project) { + public void runActivity(@Nonnull Project project, @Nonnull UIAccess uiAccess) { ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(project); ToolWindow toolWindow = toolWindowManager.getToolWindow(ToolWindowId.PROJECT_VIEW); From 8fad3f51d1d0f9ea6a65ba536c64a33d4d5afc5e Mon Sep 17 00:00:00 2001 From: VISTALL Date: Sat, 25 Dec 2021 17:09:33 +0300 Subject: [PATCH 3/6] do not traverse ui for replacing splitter --- .../java/com/intellij/ide/projectView/impl/ProjectViewImpl.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/modules/base/lang-impl/src/main/java/com/intellij/ide/projectView/impl/ProjectViewImpl.java b/modules/base/lang-impl/src/main/java/com/intellij/ide/projectView/impl/ProjectViewImpl.java index c36abcbcf057..6f85b262e8e1 100644 --- a/modules/base/lang-impl/src/main/java/com/intellij/ide/projectView/impl/ProjectViewImpl.java +++ b/modules/base/lang-impl/src/main/java/com/intellij/ide/projectView/impl/ProjectViewImpl.java @@ -70,7 +70,6 @@ import com.intellij.psi.util.PsiUtilCore; import com.intellij.ui.AutoScrollFromSourceHandler; import com.intellij.ui.AutoScrollToSourceHandler; -import com.intellij.ui.GuiUtils; import com.intellij.ui.components.JBList; import com.intellij.ui.content.Content; import com.intellij.ui.content.ContentManager; @@ -555,7 +554,6 @@ public void setupToolWindow(@Nonnull ToolWindow toolWindow, final boolean loadPa toolWindow.getComponent().putClientProperty(ToolWindowContentUI.HIDE_ID_LABEL, "true"); } - GuiUtils.replaceJSplitPaneWithIDEASplitter(myPanel); SwingUtilities.invokeLater(() -> splitterProportions.restoreSplitterProportions(myPanel)); if (loadPaneExtensions) { From 6bac2b35b88d5ced7b08afcc41287979abaf8907 Mon Sep 17 00:00:00 2001 From: VISTALL Date: Sat, 25 Dec 2021 17:36:50 +0300 Subject: [PATCH 4/6] scope cleanup --- .../DependencyValidationManagerImpl.java | 26 +++-------------- .../ide/scopeView/ScopeTreeViewPanel.java | 29 +++++++++---------- .../intellij/ide/scopeView/ScopeViewPane.java | 10 +++---- .../ide/scratch/ScratchesNamedScope.java | 4 ++- 4 files changed, 25 insertions(+), 44 deletions(-) diff --git a/modules/base/analysis-impl/src/main/java/com/intellij/packageDependencies/DependencyValidationManagerImpl.java b/modules/base/analysis-impl/src/main/java/com/intellij/packageDependencies/DependencyValidationManagerImpl.java index 07bd5c72e589..62b47af27682 100644 --- a/modules/base/analysis-impl/src/main/java/com/intellij/packageDependencies/DependencyValidationManagerImpl.java +++ b/modules/base/analysis-impl/src/main/java/com/intellij/packageDependencies/DependencyValidationManagerImpl.java @@ -22,7 +22,6 @@ import com.intellij.openapi.components.Storage; import com.intellij.openapi.components.StoragePathMacros; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Pair; import com.intellij.psi.PsiFile; import com.intellij.psi.search.scope.packageSet.*; @@ -82,7 +81,7 @@ public void scopesChanged() { @Nonnull public List getPredefinedScopes() { final List predefinedScopes = new ArrayList(); - final CustomScopesProvider[] scopesProviders = CustomScopesProvider.CUSTOM_SCOPES_PROVIDER.getExtensions(myProject); + final List scopesProviders = CustomScopesProvider.CUSTOM_SCOPES_PROVIDER.getExtensionList(myProject); for (CustomScopesProvider scopesProvider : scopesProviders) { predefinedScopes.addAll(scopesProvider.getCustomScopes()); } @@ -91,7 +90,7 @@ public List getPredefinedScopes() { @Override public NamedScope getPredefinedScope(@Nonnull String name) { - final CustomScopesProvider[] scopesProviders = CustomScopesProvider.CUSTOM_SCOPES_PROVIDER.getExtensions(myProject); + final List scopesProviders = CustomScopesProvider.CUSTOM_SCOPES_PROVIDER.getExtensionList(myProject); for (CustomScopesProvider scopesProvider : scopesProviders) { final NamedScope scope = scopesProvider instanceof CustomScopesProviderEx ? ((CustomScopesProviderEx)scopesProvider).getCustomScope(name) @@ -109,7 +108,7 @@ public boolean hasRules() { } @Override - @javax.annotation.Nullable + @Nullable public DependencyRule getViolatorDependencyRule(@Nonnull PsiFile from, @Nonnull PsiFile to) { for (DependencyRule dependencyRule : myRules) { if (dependencyRule.isForbiddenToUse(from, to)) return dependencyRule; @@ -267,24 +266,7 @@ private void writeRules(Element element) { } } - @Override - @javax.annotation.Nullable - public NamedScope getScope(@javax.annotation.Nullable final String name) { - final NamedScope scope = super.getScope(name); - if (scope == null) { - final PackageSet packageSet = myUnnamedScopes.get(name); - if (packageSet != null) { - return new NamedScope.UnnamedScope(packageSet); - } - } - //compatibility for predefined scopes: rename Project -> All - if (scope == null && Comparing.strEqual(name, "Project")) { - return super.getScope("All"); - } - return scope; - } - - @javax.annotation.Nullable + @Nullable private static Element writeRule(DependencyRule rule) { NamedScope fromScope = rule.getFromScope(); NamedScope toScope = rule.getToScope(); diff --git a/modules/base/lang-impl/src/main/java/com/intellij/ide/scopeView/ScopeTreeViewPanel.java b/modules/base/lang-impl/src/main/java/com/intellij/ide/scopeView/ScopeTreeViewPanel.java index 729cccfcf5d7..a654019037d9 100644 --- a/modules/base/lang-impl/src/main/java/com/intellij/ide/scopeView/ScopeTreeViewPanel.java +++ b/modules/base/lang-impl/src/main/java/com/intellij/ide/scopeView/ScopeTreeViewPanel.java @@ -247,7 +247,7 @@ private void doWhenDone(Runnable runnable) { public void selectScope(final NamedScope scope) { refreshScope(scope); if (scope != DefaultScopesProvider.getAllScope() && scope != null) { - CURRENT_SCOPE_NAME = scope.getName(); + CURRENT_SCOPE_NAME = scope.getScopeId(); } } @@ -299,7 +299,7 @@ public void keyPressed(KeyEvent e) { private PsiElement[] getSelectedPsiElements() { final TreePath[] treePaths = myTree.getSelectionPaths(); if (treePaths != null) { - Set result = new HashSet(); + Set result = new HashSet<>(); for (TreePath path : treePaths) { PackageDependenciesNode node = (PackageDependenciesNode)path.getLastPathComponent(); final PsiElement psiElement = node.getPsiElement(); @@ -341,13 +341,10 @@ public boolean isMarked(VirtualFile file) { myTree.getEmptyText().setText("Loading..."); myActionCallback = new AsyncResult<>(); myTree.putClientProperty(TreeState.CALLBACK, new WeakReference(myActionCallback)); - myTree.setModel(myBuilder.build(myProject, true, new Runnable() { - @Override - public void run() { - myTree.setPaintBusy(false); - myTree.getEmptyText().setText(UIBundle.message("message.nothingToShow")); - myActionCallback.setDone(); - } + myTree.setModel(myBuilder.build(myProject, true, () -> { + myTree.setPaintBusy(false); + myTree.getEmptyText().setText(UIBundle.message("message.nothingToShow")); + myActionCallback.setDone(); })); ((PackageDependenciesNode)myTree.getModel().getRoot()).sortChildren(); ((DefaultTreeModel)myTree.getModel()).reload(); @@ -384,7 +381,7 @@ public Object getData(Key dataId) { final TreePath[] treePaths = myTree.getSelectionPaths(); if (treePaths != null) { if (LangDataKeys.PSI_ELEMENT_ARRAY == dataId) { - Set psiElements = new HashSet(); + Set psiElements = new HashSet<>(); for (TreePath treePath : treePaths) { final PackageDependenciesNode node = (PackageDependenciesNode)treePath.getLastPathComponent(); if (node.isValid()) { @@ -431,7 +428,7 @@ public Object getData(Key dataId) { private Module[] getSelectedModules() { final TreePath[] treePaths = myTree.getSelectionPaths(); if (treePaths != null) { - Set result = new HashSet(); + Set result = new HashSet<>(); for (TreePath path : treePaths) { PackageDependenciesNode node = (PackageDependenciesNode)path.getLastPathComponent(); if (node instanceof ModuleNode) { @@ -870,7 +867,7 @@ public boolean canDeleteElement(@Nonnull DataContext dataContext) { @Override public void deleteElement(@Nonnull DataContext dataContext) { List allElements = Arrays.asList(getSelectedPsiElements()); - ArrayList validElements = new ArrayList(); + ArrayList validElements = new ArrayList<>(); for (PsiElement psiElement : allElements) { if (psiElement != null && psiElement.isValid()) validElements.add(psiElement); } @@ -903,7 +900,7 @@ public void problemsDisappeared(@Nonnull VirtualFile file) { } private void addNode(VirtualFile file, final String scopeName) { - queueUpdate(file, new Function() { + queueUpdate(file, new Function<>() { @Override @Nullable public DefaultMutableTreeNode fun(final PsiFile psiFile) { @@ -913,7 +910,7 @@ public DefaultMutableTreeNode fun(final PsiFile psiFile) { } private void removeNode(VirtualFile file, final String scopeName) { - queueUpdate(file, new Function() { + queueUpdate(file, new Function<>() { @Override @Nullable public DefaultMutableTreeNode fun(final PsiFile psiFile) { @@ -985,7 +982,7 @@ public void run() { @Override public void changesRemoved(Collection changes, ChangeList fromList) { final String name = fromList.getName(); - final Set files = new HashSet(); + final Set files = new HashSet<>(); collectFiles(changes, files); for (VirtualFile file : files) { removeNode(file, name); @@ -995,7 +992,7 @@ public void changesRemoved(Collection changes, ChangeList fromList) { @Override public void changesAdded(Collection changes, ChangeList toList) { final String name = toList.getName(); - final Set files = new HashSet(); + final Set files = new HashSet<>(); collectFiles(changes, files); for (VirtualFile file : files) { addNode(file, name); diff --git a/modules/base/lang-impl/src/main/java/com/intellij/ide/scopeView/ScopeViewPane.java b/modules/base/lang-impl/src/main/java/com/intellij/ide/scopeView/ScopeViewPane.java index 71df29518d06..e76f63e56832 100644 --- a/modules/base/lang-impl/src/main/java/com/intellij/ide/scopeView/ScopeViewPane.java +++ b/modules/base/lang-impl/src/main/java/com/intellij/ide/scopeView/ScopeViewPane.java @@ -148,7 +148,7 @@ public JComponent createComponent() { myViewPanel = new ScopeTreeViewPanel(myProject); Disposer.register(this, myViewPanel); myViewPanel.initListeners(); - myViewPanel.selectScope(NamedScopesHolder.getScope(myProject, getSubId())); + myViewPanel.selectScope(getSelectedScope()); myTree = myViewPanel.getTree(); PopupHandler.installPopupHandler(myTree, IdeActions.GROUP_SCOPE_VIEW_POPUP, ActionPlaces.SCOPE_VIEW_POPUP); enableDnD(); @@ -207,7 +207,7 @@ protected String getId() { @Override public ActionCallback updateFromRoot(boolean restoreExpandedPaths) { saveExpandedPaths(); - myViewPanel.selectScope(NamedScopesHolder.getScope(myProject, getSubId())); + myViewPanel.selectScope(getSelectedScope()); restoreExpandedPaths(); return new ActionCallback.Done(); } @@ -219,12 +219,12 @@ public void select(Object element, VirtualFile file, boolean requestFocus) { if (psiFile == null) return; if (!(element instanceof PsiElement)) return; - List allScopes = new ArrayList(); + List allScopes = new ArrayList<>(); ContainerUtil.addAll(allScopes, myDependencyValidationManager.getScopes()); ContainerUtil.addAll(allScopes, myNamedScopeManager.getScopes()); for (int i = 0; i < allScopes.size(); i++) { final NamedScope scope = allScopes.get(i); - String name = scope.getName(); + String name = scope.getScopeId(); if (name.equals(getSubId())) { allScopes.set(i, allScopes.get(0)); allScopes.set(0, scope); @@ -232,7 +232,7 @@ public void select(Object element, VirtualFile file, boolean requestFocus) { } } for (NamedScope scope : allScopes) { - String name = scope.getName(); + String name = scope.getScopeId(); PackageSet packageSet = scope.getValue(); if (packageSet == null) continue; if (changeView(packageSet, ((PsiElement)element), psiFile, name, myNamedScopeManager, requestFocus)) break; diff --git a/modules/base/lang-impl/src/main/java/com/intellij/ide/scratch/ScratchesNamedScope.java b/modules/base/lang-impl/src/main/java/com/intellij/ide/scratch/ScratchesNamedScope.java index a349ec715e03..2ed14bfdcfa3 100644 --- a/modules/base/lang-impl/src/main/java/com/intellij/ide/scratch/ScratchesNamedScope.java +++ b/modules/base/lang-impl/src/main/java/com/intellij/ide/scratch/ScratchesNamedScope.java @@ -13,12 +13,14 @@ import javax.annotation.Nullable; public class ScratchesNamedScope extends NamedScope { + public static final String ID = "Scratches and Consoles"; + public static String scratchesAndConsoles() { return IdeBundle.message("scratches.and.consoles"); } public ScratchesNamedScope() { - super(scratchesAndConsoles(), PlatformIconGroup.scopeScratches(), new AbstractPackageSet(scratchesAndConsoles()) { + super(ID, PlatformIconGroup.scopeScratches(), new AbstractPackageSet(scratchesAndConsoles()) { @Override public boolean contains(@Nonnull VirtualFile file, @Nonnull Project project, @Nullable NamedScopesHolder holder) { return ScratchesNamedScope.contains(project, file); From e0fd4107dfda98a306372657f2b3d37602375cca Mon Sep 17 00:00:00 2001 From: VISTALL Date: Sat, 25 Dec 2021 18:12:54 +0300 Subject: [PATCH 5/6] welcome project next --- .../impl/FavoritesViewToolWindowFactory.java | 5 ++ .../impl/StructureViewToolWindowFactory.java | 7 +++ .../java/com/intellij/ide/todo/TodoPanel.java | 5 +- .../ide/todo/TodoToolWindowFactory.java | 5 ++ .../com/intellij/ide/impl/ProjectUtil.java | 5 +- .../impl/FileEditorManagerImpl.java | 5 -- .../welcomeScreen/NewRecentProjectPanel.java | 0 .../welcomeScreen/RecentProjectPanel.java | 2 +- .../impl/WelcomeVirtualFile.java | 2 +- .../impl/WelcomeVirtualFileEditor.java | 12 ++++- .../impl/WelcomeVirtualFileType.java | 54 +++++++++++++++++++ .../openapi/project/ProjectManager.java | 9 ++-- .../openapi/wm/impl/DesktopIdeFrameImpl.java | 12 ++--- .../wm/impl/DesktopWindowManagerImpl.java | 13 +++++ 14 files changed, 114 insertions(+), 22 deletions(-) rename modules/{desktop-awt/desktop-platform-impl => base/platform-impl}/src/main/java/com/intellij/openapi/wm/impl/welcomeScreen/NewRecentProjectPanel.java (100%) rename modules/{desktop-awt/desktop-platform-impl => base/platform-impl}/src/main/java/com/intellij/openapi/wm/impl/welcomeScreen/RecentProjectPanel.java (99%) create mode 100644 modules/base/platform-impl/src/main/java/consulo/ide/welcomeScreen/impl/WelcomeVirtualFileType.java diff --git a/modules/base/lang-impl/src/main/java/com/intellij/ide/projectView/impl/FavoritesViewToolWindowFactory.java b/modules/base/lang-impl/src/main/java/com/intellij/ide/projectView/impl/FavoritesViewToolWindowFactory.java index d8d4cfb3d1e1..1f964a379fca 100644 --- a/modules/base/lang-impl/src/main/java/com/intellij/ide/projectView/impl/FavoritesViewToolWindowFactory.java +++ b/modules/base/lang-impl/src/main/java/com/intellij/ide/projectView/impl/FavoritesViewToolWindowFactory.java @@ -41,4 +41,9 @@ public void createToolWindowContent(@Nonnull Project project, ToolWindow toolWin final Content content = contentManager.getFactory().createContent(panel, null, false); contentManager.addContent(content); } + + @Override + public boolean shouldBeAvailable(@Nonnull Project project) { + return !project.isWelcome(); + } } diff --git a/modules/base/lang-impl/src/main/java/com/intellij/ide/structureView/impl/StructureViewToolWindowFactory.java b/modules/base/lang-impl/src/main/java/com/intellij/ide/structureView/impl/StructureViewToolWindowFactory.java index eb93755a1563..3a6cef6ce6e2 100644 --- a/modules/base/lang-impl/src/main/java/com/intellij/ide/structureView/impl/StructureViewToolWindowFactory.java +++ b/modules/base/lang-impl/src/main/java/com/intellij/ide/structureView/impl/StructureViewToolWindowFactory.java @@ -24,6 +24,8 @@ import com.intellij.openapi.wm.ex.ToolWindowEx; import consulo.ui.annotation.RequiredUIAccess; +import javax.annotation.Nonnull; + /** * @author yole */ @@ -34,4 +36,9 @@ public void createToolWindowContent(Project project, ToolWindow toolWindow) { StructureViewFactoryImpl factory = (StructureViewFactoryImpl)StructureViewFactory.getInstance(project); factory.initToolWindow((ToolWindowEx)toolWindow); } + + @Override + public boolean shouldBeAvailable(@Nonnull Project project) { + return !project.isWelcome(); + } } diff --git a/modules/base/lang-impl/src/main/java/com/intellij/ide/todo/TodoPanel.java b/modules/base/lang-impl/src/main/java/com/intellij/ide/todo/TodoPanel.java index cc8385d692a9..bffe2304616b 100644 --- a/modules/base/lang-impl/src/main/java/com/intellij/ide/todo/TodoPanel.java +++ b/modules/base/lang-impl/src/main/java/com/intellij/ide/todo/TodoPanel.java @@ -232,7 +232,10 @@ public void valueChanged(final TreeSelectionEvent e) { toolbarGroup.add(new MyPreviewAction()); - setToolbar(ActionManager.getInstance().createActionToolbar(ActionPlaces.TODO_VIEW_TOOLBAR, toolbarGroup, false).getComponent()); + ActionToolbar toolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.TODO_VIEW_TOOLBAR, toolbarGroup, false); + toolbar.setTargetComponent(this); + + setToolbar(toolbar.getComponent()); } @Nonnull diff --git a/modules/base/lang-impl/src/main/java/com/intellij/ide/todo/TodoToolWindowFactory.java b/modules/base/lang-impl/src/main/java/com/intellij/ide/todo/TodoToolWindowFactory.java index e36b5cfb2f1f..d7e7ea6a1e74 100644 --- a/modules/base/lang-impl/src/main/java/com/intellij/ide/todo/TodoToolWindowFactory.java +++ b/modules/base/lang-impl/src/main/java/com/intellij/ide/todo/TodoToolWindowFactory.java @@ -34,4 +34,9 @@ public class TodoToolWindowFactory implements ToolWindowFactory, DumbAware { public void createToolWindowContent(@Nonnull Project project, @Nonnull ToolWindow toolWindow) { ServiceManager.getService(project, TodoView.class).initToolWindow(toolWindow); } + + @Override + public boolean shouldBeAvailable(@Nonnull Project project) { + return !project.isWelcome(); + } } diff --git a/modules/base/platform-impl/src/main/java/com/intellij/ide/impl/ProjectUtil.java b/modules/base/platform-impl/src/main/java/com/intellij/ide/impl/ProjectUtil.java index bc38a3975abf..c84fb94f890b 100644 --- a/modules/base/platform-impl/src/main/java/com/intellij/ide/impl/ProjectUtil.java +++ b/modules/base/platform-impl/src/main/java/com/intellij/ide/impl/ProjectUtil.java @@ -184,8 +184,9 @@ public static AsyncResult openAsync(@Nonnull String path, @Nullable fin AsyncResult reopenAsync = AsyncResult.undefined(); Project projectToClose = projectToCloseFinal; - Project[] openProjects = ProjectManager.getInstance().getOpenProjects(); - if (!forceOpenInNewFrame && openProjects.length > 0) { + ProjectManager projectManager = ProjectManager.getInstance(); + Project[] openProjects = projectManager.getOpenProjects(); + if (!forceOpenInNewFrame && openProjects.length > 0 && !projectManager.isWelcomeOnlyProjectOpened()) { if (projectToClose == null) { projectToClose = openProjects[openProjects.length - 1]; } diff --git a/modules/base/platform-impl/src/main/java/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java b/modules/base/platform-impl/src/main/java/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java index c5a4cad97d6f..cf72e9dc451b 100644 --- a/modules/base/platform-impl/src/main/java/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java +++ b/modules/base/platform-impl/src/main/java/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java @@ -79,7 +79,6 @@ import consulo.disposer.Disposer; import consulo.fileEditor.impl.*; import consulo.fileEditor.impl.text.TextEditorProvider; -import consulo.fileEditor.internal.NotClosableFileMarker; import consulo.logging.Logger; import consulo.ui.UIAccess; import consulo.ui.annotation.RequiredUIAccess; @@ -571,10 +570,6 @@ public void closeFile(@Nonnull final VirtualFile file) { public void closeFile(@Nonnull final VirtualFile file, final boolean moveFocus, final boolean closeAllCopies) { assertDispatchThread(); - if (file instanceof NotClosableFileMarker) { - return; - } - CommandProcessor.getInstance().executeCommand(myProject, () -> closeFileImpl(file, moveFocus, closeAllCopies), "", null); } diff --git a/modules/desktop-awt/desktop-platform-impl/src/main/java/com/intellij/openapi/wm/impl/welcomeScreen/NewRecentProjectPanel.java b/modules/base/platform-impl/src/main/java/com/intellij/openapi/wm/impl/welcomeScreen/NewRecentProjectPanel.java similarity index 100% rename from modules/desktop-awt/desktop-platform-impl/src/main/java/com/intellij/openapi/wm/impl/welcomeScreen/NewRecentProjectPanel.java rename to modules/base/platform-impl/src/main/java/com/intellij/openapi/wm/impl/welcomeScreen/NewRecentProjectPanel.java diff --git a/modules/desktop-awt/desktop-platform-impl/src/main/java/com/intellij/openapi/wm/impl/welcomeScreen/RecentProjectPanel.java b/modules/base/platform-impl/src/main/java/com/intellij/openapi/wm/impl/welcomeScreen/RecentProjectPanel.java similarity index 99% rename from modules/desktop-awt/desktop-platform-impl/src/main/java/com/intellij/openapi/wm/impl/welcomeScreen/RecentProjectPanel.java rename to modules/base/platform-impl/src/main/java/com/intellij/openapi/wm/impl/welcomeScreen/RecentProjectPanel.java index 741882ed6cec..09022106683c 100644 --- a/modules/desktop-awt/desktop-platform-impl/src/main/java/com/intellij/openapi/wm/impl/welcomeScreen/RecentProjectPanel.java +++ b/modules/base/platform-impl/src/main/java/com/intellij/openapi/wm/impl/welcomeScreen/RecentProjectPanel.java @@ -236,7 +236,7 @@ public JBList getList() { @Nonnull private AnAction performSelectedAction(@Nonnull InputEvent event, AnAction selection) { - String actionPlace = UIUtil.uiParents(myList, true).filter(FlatWelcomeFrame.class).isEmpty() ? ActionPlaces.POPUP : ActionPlaces.WELCOME_SCREEN; + String actionPlace = /*UIUtil.uiParents(myList, true).filter(FlatWelcomeFrame.class).isEmpty() ? ActionPlaces.POPUP : */ActionPlaces.WELCOME_SCREEN; AnActionEvent actionEvent = AnActionEvent.createFromInputEvent(event, actionPlace, selection.getTemplatePresentation(), DataManager.getInstance().getDataContext(myList), false, false); ActionUtil.performActionDumbAwareWithCallbacks(selection, actionEvent, actionEvent.getDataContext()); return selection; diff --git a/modules/base/platform-impl/src/main/java/consulo/ide/welcomeScreen/impl/WelcomeVirtualFile.java b/modules/base/platform-impl/src/main/java/consulo/ide/welcomeScreen/impl/WelcomeVirtualFile.java index 04ce5ffdbfed..ac3a85fd04ef 100644 --- a/modules/base/platform-impl/src/main/java/consulo/ide/welcomeScreen/impl/WelcomeVirtualFile.java +++ b/modules/base/platform-impl/src/main/java/consulo/ide/welcomeScreen/impl/WelcomeVirtualFile.java @@ -26,7 +26,7 @@ */ public class WelcomeVirtualFile extends LightVirtualFile implements VirtualFileWithoutContent, IdeDocumentHistoryImpl.SkipFromDocumentHistory, NotClosableFileMarker { public WelcomeVirtualFile() { - super("Welcome"); + super("Welcome", WelcomeVirtualFileType.INSTANCE, ""); } @Override diff --git a/modules/base/platform-impl/src/main/java/consulo/ide/welcomeScreen/impl/WelcomeVirtualFileEditor.java b/modules/base/platform-impl/src/main/java/consulo/ide/welcomeScreen/impl/WelcomeVirtualFileEditor.java index 591a7081274f..46471ca6460e 100644 --- a/modules/base/platform-impl/src/main/java/consulo/ide/welcomeScreen/impl/WelcomeVirtualFileEditor.java +++ b/modules/base/platform-impl/src/main/java/consulo/ide/welcomeScreen/impl/WelcomeVirtualFileEditor.java @@ -17,6 +17,8 @@ import com.intellij.openapi.fileEditor.FileEditor; import com.intellij.openapi.project.Project; +import com.intellij.openapi.wm.impl.welcomeScreen.NewRecentProjectPanel; +import com.intellij.ui.OnePixelSplitter; import consulo.util.dataholder.UserDataHolderBase; import kava.beans.PropertyChangeListener; @@ -31,7 +33,7 @@ public class WelcomeVirtualFileEditor extends UserDataHolderBase implements FileEditor { private final Project myProject; - private JComponent myComponent; + private OnePixelSplitter myComponent; public WelcomeVirtualFileEditor(Project project) { myProject = project; @@ -44,7 +46,13 @@ public JComponent getComponent() { return myComponent; } - myComponent = new JPanel(); + myComponent = new OnePixelSplitter(); + myComponent.setProportion(0.3f); + + NewRecentProjectPanel panel = new NewRecentProjectPanel(this, false); + myComponent.setFirstComponent(panel.getRootPanel()); + myComponent.setSecondComponent(new JPanel()); + return myComponent; } diff --git a/modules/base/platform-impl/src/main/java/consulo/ide/welcomeScreen/impl/WelcomeVirtualFileType.java b/modules/base/platform-impl/src/main/java/consulo/ide/welcomeScreen/impl/WelcomeVirtualFileType.java new file mode 100644 index 000000000000..f5e949631378 --- /dev/null +++ b/modules/base/platform-impl/src/main/java/consulo/ide/welcomeScreen/impl/WelcomeVirtualFileType.java @@ -0,0 +1,54 @@ +/* + * Copyright 2013-2021 consulo.io + * + * Licensed 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 consulo.ide.welcomeScreen.impl; + +import com.intellij.openapi.fileTypes.FileType; +import consulo.localize.LocalizeValue; +import consulo.platform.base.icon.PlatformIconGroup; +import consulo.ui.image.Image; + +import javax.annotation.Nonnull; + +/** + * @author VISTALL + * @since 25/12/2021 + */ +public class WelcomeVirtualFileType implements FileType { + public static final WelcomeVirtualFileType INSTANCE = new WelcomeVirtualFileType(); + + @Override + public boolean isReadOnly() { + return true; + } + + @Nonnull + @Override + public String getId() { + return "_WELCOME"; + } + + @Nonnull + @Override + public LocalizeValue getDescription() { + return LocalizeValue.of(); + } + + @Nonnull + @Override + public Image getIcon() { + return PlatformIconGroup.vcsHistory(); + } +} diff --git a/modules/base/project-model-api/src/main/java/com/intellij/openapi/project/ProjectManager.java b/modules/base/project-model-api/src/main/java/com/intellij/openapi/project/ProjectManager.java index eacae4132f9c..680ca3e3b3cd 100644 --- a/modules/base/project-model-api/src/main/java/com/intellij/openapi/project/ProjectManager.java +++ b/modules/base/project-model-api/src/main/java/com/intellij/openapi/project/ProjectManager.java @@ -16,8 +16,6 @@ package com.intellij.openapi.project; import com.intellij.openapi.application.Application; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.messages.Topic; import consulo.annotation.DeprecationInfo; @@ -25,11 +23,9 @@ import consulo.ui.UIAccess; import consulo.ui.annotation.RequiredUIAccess; import consulo.util.concurrent.AsyncResult; -import org.jdom.JDOMException; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import java.io.IOException; /** * Provides project management. @@ -85,6 +81,11 @@ public AsyncResult closeAndDisposeAsync(@Nonnull Project project, @Nonnull @Nonnull public abstract Project[] getOpenProjects(); + public boolean isWelcomeOnlyProjectOpened() { + Project[] openProjects = getOpenProjects(); + return openProjects.length == 1 && openProjects[0].isWelcome(); + } + /** * Returns the project which is used as a template for new projects. The template project * is always available, even when no other project is open. diff --git a/modules/desktop-awt/desktop-platform-impl/src/main/java/com/intellij/openapi/wm/impl/DesktopIdeFrameImpl.java b/modules/desktop-awt/desktop-platform-impl/src/main/java/com/intellij/openapi/wm/impl/DesktopIdeFrameImpl.java index 7ad334e0b6db..05c3a1f45199 100644 --- a/modules/desktop-awt/desktop-platform-impl/src/main/java/com/intellij/openapi/wm/impl/DesktopIdeFrameImpl.java +++ b/modules/desktop-awt/desktop-platform-impl/src/main/java/com/intellij/openapi/wm/impl/DesktopIdeFrameImpl.java @@ -33,7 +33,6 @@ import com.intellij.openapi.util.ActionCallback; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.SystemInfo; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.wm.IdeFrame; import com.intellij.openapi.wm.IdeRootPaneNorthExtension; import com.intellij.openapi.wm.StatusBar; @@ -413,12 +412,13 @@ public static void updateTitle(JFrame frame, final String title, final String fi frame.getRootPane().putClientProperty("Window.documentFile", currentFile); final String applicationName = FrameTitleUtil.buildTitle(); + ProjectManager projectManager = ProjectManager.getInstance(); + final TitleBuilder titleBuilder = new TitleBuilder(); - if (SystemInfo.isMac) { - boolean addAppName = StringUtil.isEmpty(title) || ProjectManager.getInstance().getOpenProjects().length == 0; - titleBuilder.append(fileTitle).append(title).append(addAppName ? applicationName : null); - } - else { + + if (projectManager.isWelcomeOnlyProjectOpened()) { + titleBuilder.append(title).append(applicationName); + } else { titleBuilder.append(title).append(fileTitle).append(applicationName); } diff --git a/modules/desktop-awt/desktop-platform-impl/src/main/java/com/intellij/openapi/wm/impl/DesktopWindowManagerImpl.java b/modules/desktop-awt/desktop-platform-impl/src/main/java/com/intellij/openapi/wm/impl/DesktopWindowManagerImpl.java index 490bfb85854d..c3958d09cd4c 100644 --- a/modules/desktop-awt/desktop-platform-impl/src/main/java/com/intellij/openapi/wm/impl/DesktopWindowManagerImpl.java +++ b/modules/desktop-awt/desktop-platform-impl/src/main/java/com/intellij/openapi/wm/impl/DesktopWindowManagerImpl.java @@ -44,6 +44,7 @@ import consulo.awt.hacking.AWTAccessorHacking; import consulo.disposer.Disposer; import consulo.logging.Logger; +import consulo.project.WelcomeProjectFactory; import consulo.start.WelcomeFrameManager; import consulo.ui.annotation.RequiredUIAccess; import jakarta.inject.Inject; @@ -593,8 +594,13 @@ private DesktopIdeFrameImpl getDefaultEmptyIdeFrame() { public final IdeFrameEx allocateFrame(@Nonnull final Project project) { LOG.assertTrue(!myProject2Frame.containsKey(project)); + WelcomeProjectFactory welcomeProjectFactory = Application.get().getInstance(WelcomeProjectFactory.class); + + Project welcomeProject = welcomeProjectFactory.getWelcomeProject(); + JFrame jFrame; final DesktopIdeFrameImpl ideFrame; + if (myProject2Frame.containsKey(null)) { ideFrame = getDefaultEmptyIdeFrame(); myProject2Frame.remove(null); @@ -602,6 +608,13 @@ public final IdeFrameEx allocateFrame(@Nonnull final Project project) { ideFrame.setProject(project); jFrame = (JFrame)TargetAWT.to(ideFrame.getWindow()); } + else if (myProject2Frame.containsKey(welcomeProject)) { + ideFrame = myProject2Frame.get(welcomeProject); + myProject2Frame.remove(welcomeProject); + myProject2Frame.put(project, ideFrame); + ideFrame.setProject(project); + jFrame = (JFrame)TargetAWT.to(ideFrame.getWindow()); + } else { ideFrame = new DesktopIdeFrameImpl(myActionManager, myDataManager, ApplicationManager.getApplication()); From 2b18dcc1d7e141cbe2b5cf0d5d3b7125f9d7e3ed Mon Sep 17 00:00:00 2001 From: VISTALL Date: Sat, 25 Dec 2021 19:48:57 +0300 Subject: [PATCH 6/6] fix duplicate navbar --- .../openapi/project/impl/ProjectManagerImpl.java | 3 ++- .../intellij/openapi/wm/impl/DesktopIdeFrameImpl.java | 10 +++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/modules/base/platform-impl/src/main/java/com/intellij/openapi/project/impl/ProjectManagerImpl.java b/modules/base/platform-impl/src/main/java/com/intellij/openapi/project/impl/ProjectManagerImpl.java index ea87adda215d..7563f6d742fa 100644 --- a/modules/base/platform-impl/src/main/java/com/intellij/openapi/project/impl/ProjectManagerImpl.java +++ b/modules/base/platform-impl/src/main/java/com/intellij/openapi/project/impl/ProjectManagerImpl.java @@ -597,7 +597,8 @@ public boolean closeProject(@Nonnull final Project project, final boolean save, myApplication.getMessageBus().syncPublisher(TOPIC).projectClosed(project, uiAccess); - if (dispose) { + // welcome project can't not be disposed + if (dispose && !project.isWelcome()) { Disposer.dispose(project); } }); diff --git a/modules/desktop-awt/desktop-platform-impl/src/main/java/com/intellij/openapi/wm/impl/DesktopIdeFrameImpl.java b/modules/desktop-awt/desktop-platform-impl/src/main/java/com/intellij/openapi/wm/impl/DesktopIdeFrameImpl.java index 05c3a1f45199..8caea5fb4a12 100644 --- a/modules/desktop-awt/desktop-platform-impl/src/main/java/com/intellij/openapi/wm/impl/DesktopIdeFrameImpl.java +++ b/modules/desktop-awt/desktop-platform-impl/src/main/java/com/intellij/openapi/wm/impl/DesktopIdeFrameImpl.java @@ -464,7 +464,12 @@ public void setProject(final Project project) { } } + if (myRootPane != null) { + myRootPane.deinstallNorthComponents(); + } + myProject = project; + if (project != null) { ProjectFrameBounds.getInstance(project); // make sure the service is initialized and its state will be saved if (myRootPane != null) { @@ -474,11 +479,6 @@ public void setProject(final Project project) { installDefaultProjectStatusBarWidgets(myProject); } - else { - if (myRootPane != null) { //already disposed - myRootPane.deinstallNorthComponents(); - } - } if (myJFrame.isVisible() && myRestoreFullScreen) { toggleFullScreen(true);