focus stealing issue: isActive() is more accurate + removed direct call to requestFoc...
[fedora-idea.git] / platform / platform-impl / src / com / intellij / openapi / application / impl / ApplicationImpl.java
blob910dfab558bdcb371e6e38118a53fcaa73b83743
1 /*
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;
69 import javax.swing.*;
70 import java.awt.*;
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(
109 Integer.MAX_VALUE,
110 30 * 60L,
111 TimeUnit.SECONDS,
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");
120 super.interrupt();
123 public void run() {
124 try {
125 super.run();
127 catch (Throwable t) {
128 if (LOG.isDebugEnabled()) {
129 LOG.debug("Worker exits due to exception", t);
134 thread.setPriority(Thread.NORM_PRIORITY - 1);
135 return thread;
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);
150 @Override
151 @NotNull
152 public synchronized IApplicationStore getStateStore() {
153 return (IApplicationStore)super.getStateStore();
156 public ApplicationImpl(boolean isInternal, boolean isUnitTestMode, boolean isHeadless, boolean isCommandLine, String appName) {
157 super(null);
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();
167 myName = appName;
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() {
208 public void run() {
209 if (isDisposed() || isDisposeInProgress()) return;
210 try {
211 SwingUtilities.invokeAndWait(new Runnable() {
212 public void run() {
213 ApplicationManagerEx.setApplication(ApplicationImpl.this);
214 saveAll();
215 disposeSelf();
219 catch (InterruptedException e) {
220 LOG.error(e);
222 catch (InvocationTargetException e) {
223 LOG.error(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() {
235 public void run() {
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();
245 return true;
248 public String getName() {
249 return myName;
252 public boolean holdsReadLock() {
253 return myActionsLock.isReadLockAcquired();
256 @Override
257 protected void handleInitComponentError(final Throwable ex, final boolean fatal, final String componentClassName) {
258 if (PluginManager.isPluginClass(componentClassName)) {
259 LOG.error(ex);
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);
267 else {
268 //noinspection UseOfSystemOutOrSystemErr
269 System.out.println(errorMessage);
271 System.exit(1);
273 else if (fatal) {
274 LOG.error(ex);
275 @NonNls final String errorMessage = "Fatal error initializing class " + componentClassName + ":\n" +
276 ex.toString() +
277 "\nComplete error stacktrace was written to idea.log";
278 if (!myHeadlessMode) {
279 JOptionPane.showMessageDialog(null, errorMessage);
281 else {
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() {
302 return myIsInternal;
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() {
327 public void run() {
328 try {
329 action.run();
331 catch (Throwable t) {
332 LOG.error(t);
334 finally {
335 Thread.interrupted(); // reset interrupted status
341 private static Thread ourDispatchThread = null;
343 public boolean isDispatchThread() {
344 return EventQueue.isDispatchThread();
347 @NotNull
348 public ModalityInvokator getInvokator() {
349 return myInvokator;
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;
373 try {
374 fireBeforeApplicationLoaded();
376 finally {
377 myIsFiringLoadingEvent = false;
380 loadComponentRoamingTypes();
382 try {
383 getStateStore().load();
385 catch (StateStorage.StateStorageException e) {
386 throw new IOException(e.getMessage());
391 @Override
392 protected <T> T getComponentFromContainer(final Class<T> interfaceClass) {
393 if (myIsFiringLoadingEvent) {
394 return null;
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);
410 assert type != null;
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();
427 disposeComponents();
429 ourThreadExecutorsService.shutdownNow();
430 super.dispose();
433 private final Object lock = new Object();
434 private void makeChangesVisibleToEDT() {
435 synchronized (lock) {
436 lock.hashCode();
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()) {
456 try {
457 ProgressManager.getInstance().runProcess(process, new EmptyProgressIndicator());
459 catch (ProcessCanceledException e) {
460 // ok to ignore.
461 return false;
463 return true;
466 final ProgressWindow progress = new ProgressWindow(canBeCanceled, false, project, parentComponent, cancelText);
467 progress.setTitle(progressTitle);
469 try {
470 myExceptionalThreadWithReadAccessRunnable = process;
471 final boolean[] threadStarted = {false};
472 SwingUtilities.invokeLater(new Runnable() {
473 public void run() {
474 if (myExceptionalThreadWithReadAccessRunnable != process) {
475 LOG.error("myExceptionalThreadWithReadAccessRunnable != process, process = " + myExceptionalThreadWithReadAccessRunnable);
478 executeOnPooledThread(new Runnable() {
479 public void run() {
480 if (myExceptionalThreadWithReadAccessRunnable != process) {
481 LOG.error("myExceptionalThreadWithReadAccessRunnable != process, process = " + myExceptionalThreadWithReadAccessRunnable);
484 final boolean old = setExceptionalThreadWithReadAccessFlag(true);
485 LOG.assertTrue(isReadAccessAllowed());
486 try {
487 ProgressManager.getInstance().runProcess(process, progress);
489 catch (ProcessCanceledException e) {
490 progress.cancel();
491 // ok to ignore.
493 finally {
494 setExceptionalThreadWithReadAccessFlag(old);
495 makeChangesVisibleToEDT();
499 threadStarted[0] = true;
503 progress.startBlocking();
505 LOG.assertTrue(threadStarted[0]);
506 LOG.assertTrue(!progress.isRunning());
508 finally {
509 myExceptionalThreadWithReadAccessRunnable = null;
510 makeChangesVisibleToEDT();
513 return !progress.isCanceled();
516 public boolean isInModalProgressThread() {
517 if (myExceptionalThreadWithReadAccessRunnable == null || !isExceptionalThreadWithReadAccess()) {
518 return false;
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);
530 try {
531 LOG.assertTrue(isReadAccessAllowed());
532 return task.call();
534 finally {
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() {
544 try {
545 return ConcurrencyUtil.invokeAll(newCallables, executorService);
547 catch (Throwable throwable) {
548 exception.set(throwable);
549 return null;
553 Throwable throwable = exception.get();
554 if (throwable != null) throw throwable;
555 return result;
558 public void invokeAndWait(Runnable runnable, @NotNull ModalityState modalityState) {
559 if (isDispatchThread()) {
560 LOG.error("invokeAndWait must not be called from event queue thread");
561 runnable.run();
562 return;
565 if (isExceptionalThreadWithReadAccess()) { //OK if we're in exceptional thread.
566 LaterInvocator.invokeAndWait(runnable, modalityState);
567 return;
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();
592 else {
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() {
603 return myStartTime;
606 public long getIdleTime() {
607 return IdeEventQueue.getInstance().getIdleTime();
610 public void exit() {
611 exit(false);
614 public void exit(final boolean force) {
615 if (!force && getDefaultModalityState() != ModalityState.NON_MODAL) {
616 return;
619 Runnable runnable = new Runnable() {
620 public void run() {
621 if (!force) {
622 if (!showConfirmation()) {
623 saveAll();
624 return;
628 FileDocumentManager.getInstance().saveAllDocuments();
630 saveSettings();
632 if (!canExit()) return;
634 if (disposeSelf()) System.exit(0);
638 if (!isDispatchThread()) {
639 invokeLater(runnable, ModalityState.NON_MODAL);
641 else {
642 runnable.run();
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()) {
652 return false;
655 return true;
658 private boolean canExit() {
659 for (ApplicationListener applicationListener : myDispatcher.getListeners()) {
660 if (!applicationListener.canExitApplication()) {
661 return false;
665 ProjectManagerEx projectManager = (ProjectManagerEx)ProjectManager.getInstance();
666 Project[] projects = projectManager.getOpenProjects();
667 for (Project project : projects) {
668 if (!projectManager.canClose(project)) {
669 return false;
673 return true;
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();
681 if (mustAcquire) {
682 LOG.assertTrue(myTestModeFlag || !Thread.holdsLock(PsiLock.LOCK), "Thread must not hold PsiLock while performing readAction");
683 try {
684 myActionsLock.readLock().acquire();
686 catch (InterruptedException e) {
687 throw new RuntimeInterruptedException(e);
691 try {
692 action.run();
694 finally {
695 if (mustAcquire) {
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();
709 if (flag) {
710 exceptionalThreadWithReadAccessFlag.set(Boolean.TRUE);
712 else {
713 exceptionalThreadWithReadAccessFlag.remove();
715 return old;
718 public <T> T runReadAction(final Computable<T> computation) {
719 final Ref<T> ref = Ref.create(null);
720 runReadAction(new Runnable() {
721 public void run() {
722 ref.set(computation.compute());
725 return ref.get();
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");
735 try {
736 myActionsLock.writeLock().acquire();
738 catch (InterruptedException e) {
739 throw new RuntimeInterruptedException(e);
742 try {
743 synchronized (myWriteActionsStack) {
744 myWriteActionsStack.push(action);
747 fireWriteActionStarted(action);
749 action.run();
751 finally {
752 try {
753 fireWriteActionFinished(action);
755 synchronized (myWriteActionsStack) {
756 myWriteActionsStack.pop();
759 finally {
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() {
768 public void run() {
769 ref.set(computation.compute());
772 return ref.get();
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;
782 return null;
785 public void assertReadAccessAllowed() {
786 if (myTestModeFlag || myHeadlessMode) return;
787 if (!isReadAccessAllowed()) {
788 LOG.error(
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()));
795 @NonNls
796 private static String describe(Thread o) {
797 if (o == null) return "null";
798 return o.toString() + " " + System.identityHashCode(o);
801 @Nullable
802 private static Thread getEventQueueThread() {
803 EventQueue eventQueue = Toolkit.getDefaultToolkit().getSystemEventQueue();
804 try {
805 Method method = EventQueue.class.getDeclaredMethod("getDispatchThread");
806 method.setAccessible(true);
807 return (Thread)method.invoke(eventQueue);
809 catch (Exception e1) {
810 // ok
812 return null;
815 public boolean isReadAccessAllowed() {
816 Thread currentThread = Thread.currentThread();
817 return ourDispatchThread == currentThread ||
818 isExceptionalThreadWithReadAccess() ||
819 myActionsLock.isReadLockAcquired() ||
820 myActionsLock.isWriteLockAcquired() ||
821 isDispatchThread();
824 public void assertReadAccessToDocumentsAllowed() {
825 /* TODO
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;
832 LOG.error(
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;
857 LOG.error(message,
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) {
868 return;
871 if (Boolean.TRUE.equals(component.getClientProperty(WAS_EVER_SHOWN))) {
872 assertIsDispatchThread();
874 else {
875 final JRootPane root = component.getRootPane();
876 if (root != null) {
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();
888 if (mustAcquire) {
889 LOG.assertTrue(myTestModeFlag || !Thread.holdsLock(PsiLock.LOCK), "Thread must not hold PsiLock while performing readAction");
890 try {
891 if (!myActionsLock.readLock().attempt(0)) return false;
893 catch (InterruptedException e) {
894 throw new RuntimeInterruptedException(e);
898 try {
899 action.run();
901 finally {
902 if (mustAcquire) {
903 myActionsLock.readLock().release();
906 return true;
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());
917 if (active) {
918 myDispatcher.getMulticaster().applicationActivated(ideFrame);
920 else {
921 myDispatcher.getMulticaster().applicationDeactivated(ideFrame);
923 return true;
927 return false;
930 public boolean isActive() {
931 if (isUnitTestMode()) return true;
933 if (myActive == null) {
934 Window active = KeyboardFocusManager.getCurrentKeyboardFocusManager().getActiveWindow();
935 return active != null;
938 return myActive;
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)) {
989 try {
990 doSave();
992 catch (final Throwable ex) {
993 if (isUnitTestMode()) {
994 System.out.println("Saving application settings failed");
995 ex.printStackTrace();
997 else {
998 LOG.info("Saving application settings failed", ex);
999 invokeLater(new Runnable() {
1000 public void run() {
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());
1010 else {
1011 Messages.showMessageDialog(ApplicationBundle.message("application.save.settings.error", ex.getLocalizedMessage()),
1012 CommonBundle.getErrorTitle(), Messages.getErrorIcon());
1019 finally {
1020 mySaveSettingsIsInProgress.set(false);
1025 public void saveSettings() {
1026 if (myDoNotSave || isUnitTestMode() || isHeadlessEnvironment()) return;
1027 _saveSettings();
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;
1038 project.save();
1041 saveSettings();
1044 public void doNotSave() {
1045 myDoNotSave = true;
1049 public boolean isDoNotSave() {
1050 return myDoNotSave;
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();
1069 else {
1070 exit();
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;
1082 return false;