2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com
.intellij
.openapi
.application
.impl
;
18 import com
.intellij
.CommonBundle
;
19 import com
.intellij
.Patches
;
20 import com
.intellij
.diagnostic
.PluginException
;
21 import com
.intellij
.ide
.ActivityTracker
;
22 import com
.intellij
.ide
.ApplicationLoadListener
;
23 import com
.intellij
.ide
.IdeEventQueue
;
24 import com
.intellij
.ide
.IdeRepaintManager
;
25 import com
.intellij
.ide
.impl
.ProjectUtil
;
26 import com
.intellij
.ide
.plugins
.IdeaPluginDescriptor
;
27 import com
.intellij
.ide
.plugins
.PluginManager
;
28 import com
.intellij
.openapi
.Disposable
;
29 import com
.intellij
.openapi
.application
.*;
30 import com
.intellij
.openapi
.application
.ex
.ApplicationEx
;
31 import com
.intellij
.openapi
.application
.ex
.ApplicationManagerEx
;
32 import com
.intellij
.openapi
.command
.CommandProcessor
;
33 import com
.intellij
.openapi
.components
.RoamingType
;
34 import com
.intellij
.openapi
.components
.StateStorage
;
35 import com
.intellij
.openapi
.components
.impl
.ApplicationPathMacroManager
;
36 import com
.intellij
.openapi
.components
.impl
.ComponentManagerImpl
;
37 import com
.intellij
.openapi
.components
.impl
.stores
.*;
38 import com
.intellij
.openapi
.diagnostic
.Logger
;
39 import com
.intellij
.openapi
.extensions
.ExtensionPoint
;
40 import com
.intellij
.openapi
.extensions
.ExtensionPointName
;
41 import com
.intellij
.openapi
.extensions
.Extensions
;
42 import com
.intellij
.openapi
.extensions
.PluginId
;
43 import com
.intellij
.openapi
.fileEditor
.FileDocumentManager
;
44 import com
.intellij
.openapi
.progress
.EmptyProgressIndicator
;
45 import com
.intellij
.openapi
.progress
.ProcessCanceledException
;
46 import com
.intellij
.openapi
.progress
.ProgressIndicator
;
47 import com
.intellij
.openapi
.progress
.ProgressManager
;
48 import com
.intellij
.openapi
.progress
.util
.ProgressWindow
;
49 import com
.intellij
.openapi
.project
.Project
;
50 import com
.intellij
.openapi
.project
.ProjectManager
;
51 import com
.intellij
.openapi
.project
.ex
.ProjectEx
;
52 import com
.intellij
.openapi
.project
.ex
.ProjectManagerEx
;
53 import com
.intellij
.openapi
.ui
.Messages
;
54 import com
.intellij
.openapi
.util
.*;
55 import com
.intellij
.openapi
.wm
.IdeFrame
;
56 import com
.intellij
.openapi
.wm
.ex
.ProgressIndicatorEx
;
57 import com
.intellij
.psi
.PsiLock
;
58 import com
.intellij
.util
.ConcurrencyUtil
;
59 import com
.intellij
.util
.EventDispatcher
;
60 import com
.intellij
.util
.ReflectionCache
;
61 import com
.intellij
.util
.concurrency
.ReentrantWriterPreferenceReadWriteLock
;
62 import com
.intellij
.util
.containers
.Stack
;
63 import com
.intellij
.util
.ui
.UIUtil
;
64 import org
.jetbrains
.annotations
.NonNls
;
65 import org
.jetbrains
.annotations
.NotNull
;
66 import org
.jetbrains
.annotations
.Nullable
;
67 import org
.picocontainer
.MutablePicoContainer
;
71 import java
.io
.IOException
;
72 import java
.lang
.reflect
.InvocationTargetException
;
73 import java
.lang
.reflect
.Method
;
74 import java
.util
.ArrayList
;
75 import java
.util
.Collection
;
76 import java
.util
.List
;
77 import java
.util
.concurrent
.*;
78 import java
.util
.concurrent
.atomic
.AtomicBoolean
;
80 @SuppressWarnings({"AssignmentToStaticFieldFromInstanceMethod"})
81 public class ApplicationImpl
extends ComponentManagerImpl
implements ApplicationEx
{
82 private static final Logger LOG
= Logger
.getInstance("#com.intellij.application.impl.ApplicationImpl");
83 private final ModalityState MODALITY_STATE_NONE
= ModalityState
.NON_MODAL
;
84 private final ModalityInvokator myInvokator
= new ModalityInvokatorImpl();
86 private final EventDispatcher
<ApplicationListener
> myDispatcher
= EventDispatcher
.create(ApplicationListener
.class);
88 private boolean myTestModeFlag
= false;
89 private boolean myHeadlessMode
= false;
90 private boolean myCommandLineMode
= false;
92 private boolean myIsInternal
= false;
93 private final String myName
;
95 private final ReentrantWriterPreferenceReadWriteLock myActionsLock
= new ReentrantWriterPreferenceReadWriteLock();
96 private final Stack
<Runnable
> myWriteActionsStack
= new Stack
<Runnable
>();
98 private volatile Runnable myExceptionalThreadWithReadAccessRunnable
;
100 private int myInEditorPaintCounter
= 0;
101 private long myStartTime
= 0;
102 private boolean myDoNotSave
= false;
103 private volatile boolean myDisposeInProgress
= false;
105 private final AtomicBoolean mySaveSettingsIsInProgress
= new AtomicBoolean(false);
107 private final ExecutorService ourThreadExecutorsService
= new ThreadPoolExecutor(
112 new SynchronousQueue
<Runnable
>(),
113 new ThreadFactory() {
114 public Thread
newThread(Runnable r
) {
115 final Thread thread
= new Thread(r
, "ApplicationImpl pooled thread") {
116 public void interrupt() {
117 if (LOG
.isDebugEnabled()) {
118 LOG
.debug("Interrupted worker, will remove from pool");
127 catch (Throwable t
) {
128 if (LOG
.isDebugEnabled()) {
129 LOG
.debug("Worker exits due to exception", t
);
134 thread
.setPriority(Thread
.NORM_PRIORITY
- 1);
139 private boolean myIsFiringLoadingEvent
= false;
140 @NonNls private static final String WAS_EVER_SHOWN
= "was.ever.shown";
142 private Boolean myActive
;
144 protected void boostrapPicoContainer() {
145 super.boostrapPicoContainer();
146 getPicoContainer().registerComponentImplementation(IComponentStore
.class, StoresFactory
.getApplicationStoreClass());
147 getPicoContainer().registerComponentImplementation(ApplicationPathMacroManager
.class);
152 public synchronized IApplicationStore
getStateStore() {
153 return (IApplicationStore
)super.getStateStore();
156 public ApplicationImpl(boolean isInternal
, boolean isUnitTestMode
, boolean isHeadless
, boolean isCommandLine
, String appName
) {
159 getPicoContainer().registerComponentInstance(Application
.class, this);
161 CommonBundle
.assertKeyIsFound
= isUnitTestMode
;
163 if ((isInternal
|| isUnitTestMode
) && !Comparing
.equal("off", System
.getProperty("idea.disposer.debug"))) {
164 Disposer
.setDebugMode(true);
166 myStartTime
= System
.currentTimeMillis();
168 ApplicationManagerEx
.setApplication(this);
170 PluginsFacade
.INSTANCE
= new PluginsFacade() {
171 public IdeaPluginDescriptor
getPlugin(PluginId id
) {
172 return PluginManager
.getPlugin(id
);
175 public IdeaPluginDescriptor
[] getPlugins() {
176 return PluginManager
.getPlugins();
180 if (!isUnitTestMode
&& !isHeadless
) {
181 Toolkit
.getDefaultToolkit().getSystemEventQueue().push(IdeEventQueue
.getInstance());
182 if (Patches
.SUN_BUG_ID_6209673
) {
183 RepaintManager
.setCurrentManager(new IdeRepaintManager());
185 IconLoader
.activate();
188 myIsInternal
= isInternal
;
189 myTestModeFlag
= isUnitTestMode
;
190 myHeadlessMode
= isHeadless
;
191 myCommandLineMode
= isCommandLine
;
193 loadApplicationComponents();
195 if (myTestModeFlag
) {
196 registerShutdownHook();
199 if (!isUnitTestMode
&& !isHeadless
) {
200 Disposer
.register(this, Disposer
.newDisposable(), "ui");
204 private void registerShutdownHook() {
205 ShutDownTracker
.getInstance(); // Necessary to avoid creating an instance while already shutting down.
207 ShutDownTracker
.getInstance().registerShutdownTask(new Runnable() {
209 if (isDisposed() || isDisposeInProgress()) return;
211 SwingUtilities
.invokeAndWait(new Runnable() {
213 ApplicationManagerEx
.setApplication(ApplicationImpl
.this);
219 catch (InterruptedException e
) {
222 catch (InvocationTargetException e
) {
229 private boolean disposeSelf() {
230 Project
[] openProjects
= ProjectManagerEx
.getInstanceEx().getOpenProjects();
231 final boolean[] canClose
= {true};
232 for (final Project project
: openProjects
) {
233 CommandProcessor commandProcessor
= CommandProcessor
.getInstance();
234 commandProcessor
.executeCommand(project
, new Runnable() {
236 canClose
[0] = ProjectUtil
.closeProject(project
);
238 }, ApplicationBundle
.message("command.exit"), null);
239 if (!canClose
[0]) return false;
241 myDisposeInProgress
= true;
242 Disposer
.dispose(this);
244 Disposer
.assertIsEmpty();
248 public String
getName() {
252 public boolean holdsReadLock() {
253 return myActionsLock
.isReadLockAcquired();
257 protected void handleInitComponentError(final Throwable ex
, final boolean fatal
, final String componentClassName
) {
258 if (PluginManager
.isPluginClass(componentClassName
)) {
260 PluginId pluginId
= PluginManager
.getPluginByClassName(componentClassName
);
261 @NonNls final String errorMessage
= "Plugin " + pluginId
.getIdString() + " failed to initialize and will be disabled:\n" + ex
.getMessage() +
262 "\nPlease restart " + ApplicationNamesInfo
.getInstance().getFullProductName() + ".";
263 PluginManager
.disablePlugin(pluginId
.getIdString());
264 if (!myHeadlessMode
) {
265 JOptionPane
.showMessageDialog(null, errorMessage
);
268 //noinspection UseOfSystemOutOrSystemErr
269 System
.out
.println(errorMessage
);
275 @NonNls final String errorMessage
= "Fatal error initializing class " + componentClassName
+ ":\n" +
277 "\nComplete error stacktrace was written to idea.log";
278 if (!myHeadlessMode
) {
279 JOptionPane
.showMessageDialog(null, errorMessage
);
282 //noinspection UseOfSystemOutOrSystemErr
283 System
.out
.println(errorMessage
);
286 super.handleInitComponentError(ex
, fatal
, componentClassName
);
289 private void loadApplicationComponents() {
290 final IdeaPluginDescriptor
[] plugins
= PluginManager
.getPlugins();
291 for (IdeaPluginDescriptor plugin
: plugins
) {
292 if (PluginManager
.shouldSkipPlugin(plugin
)) continue;
293 loadComponentsConfiguration(plugin
.getAppComponents(), plugin
, false);
297 protected MutablePicoContainer
createPicoContainer() {
298 return Extensions
.getRootArea().getPicoContainer();
301 public boolean isInternal() {
305 public boolean isUnitTestMode() {
306 return myTestModeFlag
;
309 public boolean isHeadlessEnvironment() {
310 return myHeadlessMode
;
313 public boolean isCommandLine() {
314 return myCommandLineMode
;
317 public IdeaPluginDescriptor
getPlugin(PluginId id
) {
318 return PluginsFacade
.INSTANCE
.getPlugin(id
);
321 public IdeaPluginDescriptor
[] getPlugins() {
322 return PluginsFacade
.INSTANCE
.getPlugins();
325 public Future
<?
> executeOnPooledThread(final Runnable action
) {
326 return ourThreadExecutorsService
.submit(new Runnable() {
331 catch (Throwable t
) {
335 Thread
.interrupted(); // reset interrupted status
341 private static Thread ourDispatchThread
= null;
343 public boolean isDispatchThread() {
344 return EventQueue
.isDispatchThread();
348 public ModalityInvokator
getInvokator() {
353 public void invokeLater(final Runnable runnable
) {
354 myInvokator
.invokeLater(runnable
);
357 public void invokeLater(final Runnable runnable
, @NotNull final Condition expired
) {
358 myInvokator
.invokeLater(runnable
, expired
);
361 public void invokeLater(final Runnable runnable
, @NotNull final ModalityState state
) {
362 myInvokator
.invokeLater(runnable
, state
);
365 public void invokeLater(final Runnable runnable
, @NotNull final ModalityState state
, @NotNull final Condition expired
) {
366 myInvokator
.invokeLater(runnable
, state
, expired
);
369 public void load(String path
) throws IOException
, InvalidDataException
{
370 getStateStore().setOptionsPath(path
);
371 getStateStore().setConfigPath(PathManager
.getConfigPath());
372 myIsFiringLoadingEvent
= true;
374 fireBeforeApplicationLoaded();
377 myIsFiringLoadingEvent
= false;
380 loadComponentRoamingTypes();
383 getStateStore().load();
385 catch (StateStorage
.StateStorageException e
) {
386 throw new IOException(e
.getMessage());
392 protected <T
> T
getComponentFromContainer(final Class
<T
> interfaceClass
) {
393 if (myIsFiringLoadingEvent
) {
396 return super.getComponentFromContainer(interfaceClass
);
399 private static void loadComponentRoamingTypes() {
400 ExtensionPoint
<RoamingTypeExtensionPointBean
> point
= Extensions
.getRootArea().getExtensionPoint("com.intellij.ComponentRoamingType");
401 final RoamingTypeExtensionPointBean
[] componentRoamingTypes
= point
.getExtensions();
403 for (RoamingTypeExtensionPointBean object
: componentRoamingTypes
) {
405 assert object
.componentName
!= null;
406 assert object
.roamingType
!= null;
408 final RoamingType type
= RoamingType
.valueOf(object
.roamingType
);
412 ComponentRoamingManager
.getInstance().setRoamingType(object
.componentName
, type
);
416 private void fireBeforeApplicationLoaded() {
417 ExtensionPoint
<ApplicationLoadListener
> point
= Extensions
.getRootArea().getExtensionPoint("com.intellij.ApplicationLoadListener");
418 final ApplicationLoadListener
[] objects
= point
.getExtensions();
419 for (ApplicationLoadListener object
: objects
) {
420 object
.beforeApplicationLoaded(this);
425 public void dispose() {
426 fireApplicationExiting();
429 ourThreadExecutorsService
.shutdownNow();
433 private final Object lock
= new Object();
434 private void makeChangesVisibleToEDT() {
435 synchronized (lock
) {
440 public boolean runProcessWithProgressSynchronously(final Runnable process
, String progressTitle
, boolean canBeCanceled
, Project project
) {
441 return runProcessWithProgressSynchronously(process
, progressTitle
, canBeCanceled
, project
, null);
444 public boolean runProcessWithProgressSynchronously(final Runnable process
, final String progressTitle
, final boolean canBeCanceled
, @Nullable final Project project
,
445 final JComponent parentComponent
) {
446 return runProcessWithProgressSynchronously(process
, progressTitle
, canBeCanceled
, project
, parentComponent
, null);
449 public boolean runProcessWithProgressSynchronously(final Runnable process
, final String progressTitle
, final boolean canBeCanceled
, @Nullable final Project project
,
450 final JComponent parentComponent
, final String cancelText
) {
451 assertIsDispatchThread();
453 if (myExceptionalThreadWithReadAccessRunnable
!= null ||
454 ApplicationManager
.getApplication().isUnitTestMode() ||
455 ApplicationManager
.getApplication().isHeadlessEnvironment()) {
457 ProgressManager
.getInstance().runProcess(process
, new EmptyProgressIndicator());
459 catch (ProcessCanceledException e
) {
466 final ProgressWindow progress
= new ProgressWindow(canBeCanceled
, false, project
, parentComponent
, cancelText
);
467 progress
.setTitle(progressTitle
);
470 myExceptionalThreadWithReadAccessRunnable
= process
;
471 final boolean[] threadStarted
= {false};
472 SwingUtilities
.invokeLater(new Runnable() {
474 if (myExceptionalThreadWithReadAccessRunnable
!= process
) {
475 LOG
.error("myExceptionalThreadWithReadAccessRunnable != process, process = " + myExceptionalThreadWithReadAccessRunnable
);
478 executeOnPooledThread(new Runnable() {
480 if (myExceptionalThreadWithReadAccessRunnable
!= process
) {
481 LOG
.error("myExceptionalThreadWithReadAccessRunnable != process, process = " + myExceptionalThreadWithReadAccessRunnable
);
484 final boolean old
= setExceptionalThreadWithReadAccessFlag(true);
485 LOG
.assertTrue(isReadAccessAllowed());
487 ProgressManager
.getInstance().runProcess(process
, progress
);
489 catch (ProcessCanceledException e
) {
494 setExceptionalThreadWithReadAccessFlag(old
);
495 makeChangesVisibleToEDT();
499 threadStarted
[0] = true;
503 progress
.startBlocking();
505 LOG
.assertTrue(threadStarted
[0]);
506 LOG
.assertTrue(!progress
.isRunning());
509 myExceptionalThreadWithReadAccessRunnable
= null;
510 makeChangesVisibleToEDT();
513 return !progress
.isCanceled();
516 public boolean isInModalProgressThread() {
517 if (myExceptionalThreadWithReadAccessRunnable
== null || !isExceptionalThreadWithReadAccess()) {
520 ProgressIndicator progressIndicator
= ProgressManager
.getInstance().getProgressIndicator();
521 return progressIndicator
.isModal() && ((ProgressIndicatorEx
)progressIndicator
).isModalityEntered();
524 public <T
> List
<Future
<T
>> invokeAllUnderReadAction(@NotNull Collection
<Callable
<T
>> tasks
, final ExecutorService executorService
) throws Throwable
{
525 final List
<Callable
<T
>> newCallables
= new ArrayList
<Callable
<T
>>(tasks
.size());
526 for (final Callable
<T
> task
: tasks
) {
527 Callable
<T
> newCallable
= new Callable
<T
>() {
528 public T
call() throws Exception
{
529 boolean old
= setExceptionalThreadWithReadAccessFlag(true);
531 LOG
.assertTrue(isReadAccessAllowed());
535 setExceptionalThreadWithReadAccessFlag(old
);
539 newCallables
.add(newCallable
);
541 final Ref
<Throwable
> exception
= new Ref
<Throwable
>();
542 List
<Future
<T
>> result
= runReadAction(new Computable
<List
<Future
<T
>>>() {
543 public List
<Future
<T
>> compute() {
545 return ConcurrencyUtil
.invokeAll(newCallables
, executorService
);
547 catch (Throwable throwable
) {
548 exception
.set(throwable
);
553 Throwable throwable
= exception
.get();
554 if (throwable
!= null) throw throwable
;
558 public void invokeAndWait(Runnable runnable
, @NotNull ModalityState modalityState
) {
559 if (isDispatchThread()) {
560 LOG
.error("invokeAndWait must not be called from event queue thread");
565 if (isExceptionalThreadWithReadAccess()) { //OK if we're in exceptional thread.
566 LaterInvocator
.invokeAndWait(runnable
, modalityState
);
570 if (myActionsLock
.isReadLockAcquired()) {
571 LOG
.error("Calling invokeAndWait from read-action leads to possible deadlock.");
574 LaterInvocator
.invokeAndWait(runnable
, modalityState
);
577 public ModalityState
getCurrentModalityState() {
578 Object
[] entities
= LaterInvocator
.getCurrentModalEntities();
579 return entities
.length
> 0 ?
new ModalityStateEx(entities
) : getNoneModalityState();
582 public ModalityState
getModalityStateForComponent(Component c
) {
583 Window window
= c
instanceof Window ?
(Window
)c
: SwingUtilities
.windowForComponent(c
);
584 if (window
== null) return getNoneModalityState(); //?
585 return LaterInvocator
.modalityStateForWindow(window
);
588 public ModalityState
getDefaultModalityState() {
589 if (EventQueue
.isDispatchThread()) {
590 return getCurrentModalityState();
593 ProgressIndicator progress
= ProgressManager
.getInstance().getProgressIndicator();
594 return progress
== null ?
getNoneModalityState() : progress
.getModalityState();
598 public ModalityState
getNoneModalityState() {
599 return MODALITY_STATE_NONE
;
602 public long getStartTime() {
606 public long getIdleTime() {
607 return IdeEventQueue
.getInstance().getIdleTime();
614 public void exit(final boolean force
) {
615 if (!force
&& getDefaultModalityState() != ModalityState
.NON_MODAL
) {
619 Runnable runnable
= new Runnable() {
622 if (!showConfirmation()) {
628 FileDocumentManager
.getInstance().saveAllDocuments();
632 if (!canExit()) return;
634 if (disposeSelf()) System
.exit(0);
638 if (!isDispatchThread()) {
639 invokeLater(runnable
, ModalityState
.NON_MODAL
);
646 private static boolean showConfirmation() {
647 final boolean hasUnsafeBgTasks
= ProgressManager
.getInstance().hasUnsafeProgressIndicator();
648 final ConfirmExitDialog confirmExitDialog
= new ConfirmExitDialog(hasUnsafeBgTasks
);
649 if (confirmExitDialog
.isToBeShown()) {
650 confirmExitDialog
.show();
651 if (!confirmExitDialog
.isOK()) {
658 private boolean canExit() {
659 for (ApplicationListener applicationListener
: myDispatcher
.getListeners()) {
660 if (!applicationListener
.canExitApplication()) {
665 ProjectManagerEx projectManager
= (ProjectManagerEx
)ProjectManager
.getInstance();
666 Project
[] projects
= projectManager
.getOpenProjects();
667 for (Project project
: projects
) {
668 if (!projectManager
.canClose(project
)) {
676 public void runReadAction(final Runnable action
) {
677 /** if we are inside read action, do not try to acquire read lock again since it will deadlock if there is a pending writeAction
678 * see {@link com.intellij.util.concurrency.ReentrantWriterPreferenceReadWriteLock#allowReader()} */
679 boolean mustAcquire
= !isReadAccessAllowed();
682 LOG
.assertTrue(myTestModeFlag
|| !Thread
.holdsLock(PsiLock
.LOCK
), "Thread must not hold PsiLock while performing readAction");
684 myActionsLock
.readLock().acquire();
686 catch (InterruptedException e
) {
687 throw new RuntimeInterruptedException(e
);
696 myActionsLock
.readLock().release();
701 private static final ThreadLocal
<Boolean
> exceptionalThreadWithReadAccessFlag
= new ThreadLocal
<Boolean
>();
702 private static boolean isExceptionalThreadWithReadAccess() {
703 Boolean flag
= exceptionalThreadWithReadAccessFlag
.get();
704 return flag
== Boolean
.TRUE
;
707 public static boolean setExceptionalThreadWithReadAccessFlag(boolean flag
) {
708 boolean old
= isExceptionalThreadWithReadAccess();
710 exceptionalThreadWithReadAccessFlag
.set(Boolean
.TRUE
);
713 exceptionalThreadWithReadAccessFlag
.remove();
718 public <T
> T
runReadAction(final Computable
<T
> computation
) {
719 final Ref
<T
> ref
= Ref
.create(null);
720 runReadAction(new Runnable() {
722 ref
.set(computation
.compute());
728 public void runWriteAction(final Runnable action
) {
729 assertCanRunWriteAction();
731 ActivityTracker
.getInstance().inc();
732 fireBeforeWriteActionStart(action
);
734 LOG
.assertTrue(myActionsLock
.isWriteLockAcquired(Thread
.currentThread()) || !Thread
.holdsLock(PsiLock
.LOCK
), "Thread must not hold PsiLock while performing writeAction");
736 myActionsLock
.writeLock().acquire();
738 catch (InterruptedException e
) {
739 throw new RuntimeInterruptedException(e
);
743 synchronized (myWriteActionsStack
) {
744 myWriteActionsStack
.push(action
);
747 fireWriteActionStarted(action
);
753 fireWriteActionFinished(action
);
755 synchronized (myWriteActionsStack
) {
756 myWriteActionsStack
.pop();
760 myActionsLock
.writeLock().release();
765 public <T
> T
runWriteAction(final Computable
<T
> computation
) {
766 final Ref
<T
> ref
= Ref
.create(null);
767 runWriteAction(new Runnable() {
769 ref
.set(computation
.compute());
775 public Object
getCurrentWriteAction(Class actionClass
) {
776 synchronized (myWriteActionsStack
) {
777 for (int i
= myWriteActionsStack
.size() - 1; i
>= 0; i
--) {
778 Runnable action
= myWriteActionsStack
.get(i
);
779 if (actionClass
== null || ReflectionCache
.isAssignable(actionClass
, action
.getClass())) return action
;
785 public void assertReadAccessAllowed() {
786 if (myTestModeFlag
|| myHeadlessMode
) return;
787 if (!isReadAccessAllowed()) {
789 "Read access is allowed from event dispatch thread or inside read-action only (see com.intellij.openapi.application.Application.runReadAction())",
790 "Current thread: " + describe(Thread
.currentThread()), "Our dispatch thread:" + describe(ourDispatchThread
),
791 "SystemEventQueueThread: " + describe(getEventQueueThread()));
796 private static String
describe(Thread o
) {
797 if (o
== null) return "null";
798 return o
.toString() + " " + System
.identityHashCode(o
);
802 private static Thread
getEventQueueThread() {
803 EventQueue eventQueue
= Toolkit
.getDefaultToolkit().getSystemEventQueue();
805 Method method
= EventQueue
.class.getDeclaredMethod("getDispatchThread");
806 method
.setAccessible(true);
807 return (Thread
)method
.invoke(eventQueue
);
809 catch (Exception e1
) {
815 public boolean isReadAccessAllowed() {
816 Thread currentThread
= Thread
.currentThread();
817 return ourDispatchThread
== currentThread
||
818 isExceptionalThreadWithReadAccess() ||
819 myActionsLock
.isReadLockAcquired() ||
820 myActionsLock
.isWriteLockAcquired() ||
824 public void assertReadAccessToDocumentsAllowed() {
826 Thread currentThread = Thread.currentThread();
827 if (ourDispatchThread != currentThread) {
828 if (myExceptionalThreadWithReadAccess == currentThread) return;
829 if (myActionsLock.isReadLockAcquired(currentThread)) return;
830 if (myActionsLock.isWriteLockAcquired(currentThread)) return;
831 if (isDispatchThread(currentThread)) return;
833 "Read access is allowed from event dispatch thread or inside read-action only (see com.intellij.openapi.application.Application.runReadAction())");
838 private void assertCanRunWriteAction() {
839 assertIsDispatchThread("Write access is allowed from event dispatch thread only");
843 public void assertIsDispatchThread() {
844 assertIsDispatchThread("Access is allowed from event dispatch thread only.");
847 private void assertIsDispatchThread(String message
) {
848 if (myTestModeFlag
|| myHeadlessMode
|| ShutDownTracker
.isShutdownHookRunning()) return;
849 final Thread currentThread
= Thread
.currentThread();
850 if (ourDispatchThread
== currentThread
) return;
852 if (EventQueue
.isDispatchThread()) {
853 ourDispatchThread
= currentThread
;
855 if (ourDispatchThread
== currentThread
) return;
858 "Current thread: " + describe(Thread
.currentThread()),
859 "Our dispatch thread:" + describe(ourDispatchThread
),
860 "SystemEventQueueThread: " + describe(getEventQueueThread()));
863 public void assertIsDispatchThread(@Nullable final JComponent component
) {
864 if (component
== null) return;
866 Thread curThread
= Thread
.currentThread();
867 if (ourDispatchThread
== curThread
) {
871 if (Boolean
.TRUE
.equals(component
.getClientProperty(WAS_EVER_SHOWN
))) {
872 assertIsDispatchThread();
875 final JRootPane root
= component
.getRootPane();
877 component
.putClientProperty(WAS_EVER_SHOWN
, Boolean
.TRUE
);
878 assertIsDispatchThread();
883 public boolean tryRunReadAction(@NotNull Runnable action
) {
884 /** if we are inside read action, do not try to acquire read lock again since it will deadlock if there is a pending writeAction
885 * see {@link com.intellij.util.concurrency.ReentrantWriterPreferenceReadWriteLock#allowReader()} */
886 boolean mustAcquire
= !isReadAccessAllowed();
889 LOG
.assertTrue(myTestModeFlag
|| !Thread
.holdsLock(PsiLock
.LOCK
), "Thread must not hold PsiLock while performing readAction");
891 if (!myActionsLock
.readLock().attempt(0)) return false;
893 catch (InterruptedException e
) {
894 throw new RuntimeInterruptedException(e
);
903 myActionsLock
.readLock().release();
909 public boolean tryToApplyActivationState(boolean active
, Window window
) {
910 final Component frame
= UIUtil
.findUltimateParent(window
);
912 if (frame
instanceof IdeFrame
) {
913 final IdeFrame ideFrame
= (IdeFrame
)frame
;
914 if (isActive() != active
) {
915 myActive
= Boolean
.valueOf(active
);
916 System
.setProperty("idea.active", Boolean
.valueOf(myActive
).toString());
918 myDispatcher
.getMulticaster().applicationActivated(ideFrame
);
921 myDispatcher
.getMulticaster().applicationDeactivated(ideFrame
);
930 public boolean isActive() {
931 if (isUnitTestMode()) return true;
933 if (myActive
== null) {
934 Window active
= KeyboardFocusManager
.getCurrentKeyboardFocusManager().getActiveWindow();
935 return active
!= null;
941 public void assertWriteAccessAllowed() {
942 LOG
.assertTrue(isWriteAccessAllowed(),
943 "Write access is allowed inside write-action only (see com.intellij.openapi.application.Application.runWriteAction())");
946 public boolean isWriteAccessAllowed() {
947 return myActionsLock
.isWriteLockAcquired(Thread
.currentThread());
950 public void editorPaintStart() {
951 myInEditorPaintCounter
++;
954 public void editorPaintFinish() {
955 myInEditorPaintCounter
--;
956 LOG
.assertTrue(myInEditorPaintCounter
>= 0);
959 public void addApplicationListener(ApplicationListener l
) {
960 myDispatcher
.addListener(l
);
963 public void addApplicationListener(ApplicationListener l
, Disposable parent
) {
964 myDispatcher
.addListener(l
, parent
);
967 public void removeApplicationListener(ApplicationListener l
) {
968 myDispatcher
.removeListener(l
);
971 private void fireApplicationExiting() {
972 myDispatcher
.getMulticaster().applicationExiting();
975 private void fireBeforeWriteActionStart(Runnable action
) {
976 myDispatcher
.getMulticaster().beforeWriteActionStart(action
);
979 private void fireWriteActionStarted(Runnable action
) {
980 myDispatcher
.getMulticaster().writeActionStarted(action
);
983 private void fireWriteActionFinished(Runnable action
) {
984 myDispatcher
.getMulticaster().writeActionFinished(action
);
987 public void _saveSettings() { // for testing purposes
988 if (mySaveSettingsIsInProgress
.compareAndSet(false, true)) {
992 catch (final Throwable ex
) {
993 if (isUnitTestMode()) {
994 System
.out
.println("Saving application settings failed");
995 ex
.printStackTrace();
998 LOG
.info("Saving application settings failed", ex
);
999 invokeLater(new Runnable() {
1001 if (ex
instanceof PluginException
) {
1002 final PluginException pluginException
= (PluginException
)ex
;
1003 PluginManager
.disablePlugin(pluginException
.getPluginId().getIdString());
1004 Messages
.showMessageDialog("The plugin " +
1005 pluginException
.getPluginId() +
1006 " failed to save settings and has been disabled. Please restart " +
1007 ApplicationNamesInfo
.getInstance().getFullProductName(), CommonBundle
.getErrorTitle(),
1008 Messages
.getErrorIcon());
1011 Messages
.showMessageDialog(ApplicationBundle
.message("application.save.settings.error", ex
.getLocalizedMessage()),
1012 CommonBundle
.getErrorTitle(), Messages
.getErrorIcon());
1020 mySaveSettingsIsInProgress
.set(false);
1025 public void saveSettings() {
1026 if (myDoNotSave
|| isUnitTestMode() || isHeadlessEnvironment()) return;
1030 public void saveAll() {
1031 if (myDoNotSave
|| isUnitTestMode() || isHeadlessEnvironment()) return;
1033 FileDocumentManager
.getInstance().saveAllDocuments();
1035 Project
[] openProjects
= ProjectManager
.getInstance().getOpenProjects();
1036 for (Project openProject
: openProjects
) {
1037 ProjectEx project
= (ProjectEx
)openProject
;
1044 public void doNotSave() {
1049 public boolean isDoNotSave() {
1053 public <T
> T
[] getExtensions(final ExtensionPointName
<T
> extensionPointName
) {
1054 return Extensions
.getRootArea().getExtensionPoint(extensionPointName
).getExtensions();
1057 public boolean isDisposeInProgress() {
1058 return myDisposeInProgress
;
1061 public boolean isRestartCapable() {
1062 return SystemInfo
.isWindows
;
1065 public void restart() {
1066 if (SystemInfo
.isWindows
) {
1067 Win32Restarter
.restart();
1074 public boolean isSaving() {
1075 if (getStateStore().isSaving()) return true;
1076 Project
[] openProjects
= ProjectManager
.getInstance().getOpenProjects();
1077 for (Project openProject
: openProjects
) {
1078 ProjectEx project
= (ProjectEx
)openProject
;
1079 if (project
.getStateStore().isSaving()) return true;