diff --git a/platform/lang-impl/src/com/intellij/codeInsight/generation/actions/GenerateAction.java b/platform/lang-impl/src/com/intellij/codeInsight/generation/actions/GenerateAction.java index e673e7995306..0ddc5981e6e2 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/generation/actions/GenerateAction.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/generation/actions/GenerateAction.java @@ -18,7 +18,6 @@ package com.intellij.codeInsight.generation.actions; import com.intellij.codeInsight.CodeInsightBundle; import com.intellij.openapi.actionSystem.*; -import com.intellij.openapi.actionSystem.impl.ActionManagerImpl; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.DumbService; @@ -29,7 +28,7 @@ import com.intellij.util.ObjectUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class GenerateAction extends DumbAwareAction implements PreloadableAction { +public class GenerateAction extends DumbAwareAction { @Override public void actionPerformed(final AnActionEvent e) { DataContext dataContext = e.getDataContext(); @@ -94,11 +93,6 @@ public class GenerateAction extends DumbAwareAction implements PreloadableAction return copy; } - @Override - public void preload() { - ((ActionManagerImpl) ActionManager.getInstance()).preloadActionGroup(IdeActions.GROUP_GENERATE); - } - private static class GenerateWrappingGroup extends ActionGroup { private final AnAction myAction; diff --git a/platform/platform-impl/src/com/intellij/ide/ui/search/SearchableOptionPreloader.java b/platform/platform-impl/src/com/intellij/ide/ui/search/SearchableOptionPreloader.java new file mode 100644 index 000000000000..b960ef10b97b --- /dev/null +++ b/platform/platform-impl/src/com/intellij/ide/ui/search/SearchableOptionPreloader.java @@ -0,0 +1,52 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * 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 com.intellij.ide.ui.search; + +import com.intellij.openapi.application.PreloadingActivity; +import com.intellij.openapi.progress.ProgressIndicator; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Set; + +/** + * @author peter + */ +public class SearchableOptionPreloader extends PreloadingActivity { + @Override + public void preload(@NotNull ProgressIndicator indicator) { + final SearchableOptionsRegistrar registrar = SearchableOptionsRegistrar.getInstance(); + final SearchableOptionProcessor processor = new SearchableOptionProcessor() { + @Override + public void addOptions(@NotNull String text, + @Nullable String path, + @Nullable String hit, + @NotNull String configurableId, + @Nullable String configurableDisplayName, + boolean applyStemming) { + Set words = applyStemming ? registrar.getProcessedWords(text) : registrar.getProcessedWordsWithoutStemming(text); + for (String word : words) { + registrar.addOption(word, path, hit, configurableId, configurableDisplayName); + } + } + }; + + for (SearchableOptionContributor contributor : SearchableOptionContributor.EP_NAME.getExtensions()) { + indicator.checkCanceled(); + contributor.processOptions(processor); + } + } +} diff --git a/platform/platform-impl/src/com/intellij/ide/ui/search/SearchableOptionsRegistrarImpl.java b/platform/platform-impl/src/com/intellij/ide/ui/search/SearchableOptionsRegistrarImpl.java index 8d4d5b1517fa..fa2053bbc96f 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/search/SearchableOptionsRegistrarImpl.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/search/SearchableOptionsRegistrarImpl.java @@ -93,36 +93,6 @@ public class SearchableOptionsRegistrarImpl extends SearchableOptionsRegistrar { catch (IOException e) { LOG.error(e); } - - loadExtensions(); - } - - private void loadExtensions() { - final SearchableOptionProcessor processor = new SearchableOptionProcessor() { - @Override - public void addOptions(@NotNull String text, - @Nullable String path, - @Nullable String hit, - @NotNull String configurableId, - @Nullable String configurableDisplayName, - boolean applyStemming) { - Set words = applyStemming ? getProcessedWords(text) : getProcessedWordsWithoutStemming(text); - for (String word : words) { - addOption(word, path, hit, configurableId, configurableDisplayName); - } - } - - }; - - ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { - @Override - public void run() { - //todo what if application is disposed? - for (SearchableOptionContributor contributor : SearchableOptionContributor.EP_NAME.getExtensions()) { - contributor.processOptions(processor); - } - } - }); } private void loadHugeFilesIfNecessary() { diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionManagerImpl.java index 1dcb4a11f7f4..1a7abbff76dc 100644 --- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionManagerImpl.java @@ -23,14 +23,16 @@ import com.intellij.ide.DataManager; import com.intellij.ide.plugins.IdeaPluginDescriptor; import com.intellij.ide.plugins.PluginManager; import com.intellij.ide.plugins.PluginManagerCore; -import com.intellij.ide.ui.search.SearchableOptionsRegistrar; import com.intellij.idea.IdeaLogger; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.actionSystem.ex.ActionManagerEx; import com.intellij.openapi.actionSystem.ex.ActionUtil; import com.intellij.openapi.actionSystem.ex.AnActionListener; -import com.intellij.openapi.application.*; +import com.intellij.openapi.application.Application; +import com.intellij.openapi.application.ApplicationActivationListener; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.application.ex.ApplicationManagerEx; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.PluginId; @@ -39,9 +41,9 @@ import com.intellij.openapi.keymap.KeymapManager; import com.intellij.openapi.keymap.KeymapUtil; import com.intellij.openapi.keymap.ex.KeymapManagerEx; import com.intellij.openapi.progress.ProcessCanceledException; +import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.ProjectType; import com.intellij.openapi.util.ActionCallback; -import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.util.registry.Registry; @@ -70,7 +72,6 @@ import java.awt.*; import java.awt.event.*; import java.util.*; import java.util.List; -import java.util.concurrent.Future; public final class ActionManagerImpl extends ActionManagerEx implements Disposable { @NonNls public static final String ACTION_ELEMENT_NAME = "action"; @@ -133,7 +134,6 @@ public final class ActionManagerImpl extends ActionManagerEx implements Disposab private String myLastPreformedActionId; private String myPrevPerformedActionId; private long myLastTimeEditorWasTypedIn = 0; - private Runnable myPreloadActionsRunnable; private boolean myTransparentOnlyUpdate; private int myActionsPreloaded = 0; @@ -1255,76 +1255,27 @@ public final class ActionManagerImpl extends ActionManagerEx implements Disposab } } - public Future preloadActions() { - if (myPreloadActionsRunnable == null) { - myPreloadActionsRunnable = new Runnable() { - @Override - public void run() { - try { - SearchableOptionsRegistrar.getInstance(); // load inspection descriptions etc. to be used in Goto Action, Search Everywhere - doPreloadActions(); - } catch (RuntimeInterruptedException ignore) { - } - } - }; - return ApplicationManager.getApplication().executeOnPooledThread(myPreloadActionsRunnable); - } - return null; - } - - private void doPreloadActions() { - pausePreloading(5000); // wait for project initialization to complete - preloadActionGroup(IdeActions.GROUP_EDITOR_POPUP); - preloadActionGroup(IdeActions.GROUP_EDITOR_TAB_POPUP); - preloadActionGroup(IdeActions.GROUP_PROJECT_VIEW_POPUP); - preloadActionGroup(IdeActions.GROUP_MAIN_MENU); - preloadActionGroup(IdeActions.GROUP_NEW); - // TODO anything else? - LOG.debug("Actions preloading completed"); - } - - public void preloadActionGroup(final String groupId) { - final AnAction action = getAction(groupId); - if (action instanceof ActionGroup) { - preloadActionGroup((ActionGroup) action); - } - } - - private void preloadActionGroup(final ActionGroup group) { + public void preloadActions(ProgressIndicator indicator) { final Application application = ApplicationManager.getApplication(); - final AnAction[] children = application.runReadAction(new Computable() { - @Override - public AnAction[] compute() { - if (application.isDisposed()) { - return AnAction.EMPTY_ARRAY; - } - return group.getChildren(null); - } - }); - for (AnAction action : children) { + for (String id : getActionIds()) { + indicator.checkCanceled(); + if (application.isDisposed()) return; + + final AnAction action = getAction(id); if (action instanceof PreloadableAction) { ((PreloadableAction)action).preload(); } else if (action instanceof ActionGroup) { - preloadActionGroup((ActionGroup)action); + application.runReadAction(new Runnable() { + @Override + public void run() { + if (!application.isDisposed()) { + ((ActionGroup)action).getChildren(null); + } + } + }); } - - myActionsPreloaded++; - if (myActionsPreloaded % 10 == 0) { - pausePreloading(300); - } - } - } - - private static void pausePreloading(int millis) { - if (ApplicationManager.getApplication().isUnitTestMode()) return; - - try { - Thread.sleep(millis); - } - catch (InterruptedException ignored) { - throw new RuntimeInterruptedException(ignored); } } diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionPreloader.java b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionPreloader.java index 1d1915cf37a5..5af71615cd4e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionPreloader.java +++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionPreloader.java @@ -17,20 +17,18 @@ package com.intellij.openapi.actionSystem.impl; import com.intellij.openapi.actionSystem.ActionManager; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.project.DumbAware; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.startup.StartupActivity; +import com.intellij.openapi.application.PreloadingActivity; +import com.intellij.openapi.progress.ProgressIndicator; import org.jetbrains.annotations.NotNull; /** * @author yole */ -public class ActionPreloader implements StartupActivity, DumbAware { - +public class ActionPreloader extends PreloadingActivity { @Override - public void runActivity(@NotNull Project project) { + public void preload(@NotNull ProgressIndicator indicator) { if (!ApplicationManager.getApplication().isUnitTestMode() && !ApplicationManager.getApplication().isHeadlessEnvironment()) { - ((ActionManagerImpl)ActionManager.getInstance()).preloadActions(); + ((ActionManagerImpl)ActionManager.getInstance()).preloadActions(indicator); } } } diff --git a/platform/platform-impl/src/com/intellij/openapi/application/Preloader.java b/platform/platform-impl/src/com/intellij/openapi/application/Preloader.java new file mode 100644 index 000000000000..ad0c9bec1ae9 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/application/Preloader.java @@ -0,0 +1,100 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * 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 com.intellij.openapi.application; + +import com.intellij.openapi.components.ApplicationComponent; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.progress.ProcessCanceledException; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.progress.util.AbstractProgressIndicatorBase; +import com.intellij.openapi.progress.util.ProgressIndicatorBase; +import com.intellij.util.TimeoutUtil; +import com.intellij.util.concurrency.SequentialTaskExecutor; +import com.intellij.util.io.storage.HeavyProcessLatch; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.ide.PooledThreadExecutor; + +import java.util.concurrent.Executor; + +/** + * @author peter + */ +public class Preloader implements ApplicationComponent { + private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.application.Preloader"); + private final Executor myExecutor = new SequentialTaskExecutor(PooledThreadExecutor.INSTANCE); + private final ProgressIndicator myIndicator = new ProgressIndicatorBase(); + private final ProgressIndicator myWrappingIndicator = new AbstractProgressIndicatorBase() { + @Override + public void checkCanceled() { + checkHeavyProcessRunning(); + myIndicator.checkCanceled(); + } + + @Override + public boolean isCanceled() { + return myIndicator.isCanceled(); + } + }; + + private static void checkHeavyProcessRunning() { + if (HeavyProcessLatch.INSTANCE.isRunning()) { + TimeoutUtil.sleep(1); + } + } + + @Override + public void initComponent() { + if (ApplicationManager.getApplication().isUnitTestMode() || ApplicationManager.getApplication().isHeadlessEnvironment()) { + return; + } + + for (final PreloadingActivity activity : PreloadingActivity.EP_NAME.getExtensions()) { + myExecutor.execute(new Runnable() { + @Override + public void run() { + if (myIndicator.isCanceled()) return; + + checkHeavyProcessRunning(); + if (myIndicator.isCanceled()) return; + + ProgressManager.getInstance().runProcess(new Runnable() { + @Override + public void run() { + try { + activity.preload(myWrappingIndicator); + } + catch (ProcessCanceledException ignore) { + } + LOG.info("Finished preloading " + activity); + } + }, myIndicator); + } + }); + } + } + + @Override + public void disposeComponent() { + myIndicator.cancel(); + } + + @NotNull + @Override + public String getComponentName() { + return "Preloader"; + } +} diff --git a/platform/platform-impl/src/com/intellij/openapi/application/PreloadingActivity.java b/platform/platform-impl/src/com/intellij/openapi/application/PreloadingActivity.java new file mode 100644 index 000000000000..e876d07e7d51 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/application/PreloadingActivity.java @@ -0,0 +1,41 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * 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 com.intellij.openapi.application; + +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.progress.ProgressIndicator; +import org.jetbrains.annotations.NotNull; + +/** + * An activity to be executed in background on IDE startup. It may load some classes or other configuration + * so that when something (e.g. an action) is invoked the first time in the UI, there's no visible pause + * while required stuff is being lazily loaded. + * + * @author peter + * @since 144 + */ +public abstract class PreloadingActivity { + public static final ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.preloadingActivity"); + + /** + * Perform the preloading + * @param indicator a progress indicator for the background preloading process. + * Canceled if the application has exited. + * Long actions should periodically perform indicator.checkCanceled(). + */ + public abstract void preload(@NotNull ProgressIndicator indicator); + +} diff --git a/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml b/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml index e7544d0a548a..fddd9d6d51cc 100644 --- a/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml @@ -23,6 +23,9 @@ + + diff --git a/platform/platform-resources/src/META-INF/PlatformExtensions.xml b/platform/platform-resources/src/META-INF/PlatformExtensions.xml index a0127c8fc19c..e1568b4dd959 100644 --- a/platform/platform-resources/src/META-INF/PlatformExtensions.xml +++ b/platform/platform-resources/src/META-INF/PlatformExtensions.xml @@ -369,9 +369,11 @@ - + + + diff --git a/platform/platform-resources/src/componentSets/Platform.xml b/platform/platform-resources/src/componentSets/Platform.xml index b68bbd551107..5d45fcc7c61c 100644 --- a/platform/platform-resources/src/componentSets/Platform.xml +++ b/platform/platform-resources/src/componentSets/Platform.xml @@ -73,6 +73,9 @@ com.intellij.diagnostic.PerformanceWatcher + + com.intellij.openapi.application.Preloader + com.intellij.notification.NotificationsConfiguration diff --git a/spellchecker/src/com/intellij/spellchecker/english.dic b/spellchecker/src/com/intellij/spellchecker/english.dic index 2139e9b43df4..6a51c7884512 100644 --- a/spellchecker/src/com/intellij/spellchecker/english.dic +++ b/spellchecker/src/com/intellij/spellchecker/english.dic @@ -101297,7 +101297,7 @@ preliminary prelims preliterate preliterates -preloaded +preload prelude prelude's preludes