public void testRegisterThenDisposeThenRegisterAgain() { Disposable disposable = Disposer.newDisposable(); Disposer.register(myRoot, disposable); Disposer.dispose(disposable); Disposer.register(myRoot, disposable); Disposer.register(disposable, Disposer.newDisposable()); }
public void testMustNotRegisterWithAlreadyDisposed() { Disposable disposable = Disposer.newDisposable(); Disposer.register(myRoot, disposable); Disposer.dispose(disposable); try { Disposer.register(disposable, Disposer.newDisposable()); fail("Must not be able to register with already disposed parent"); } catch (IncorrectOperationException ignored) { } }
public void addRunContentListener(final RunContentListener listener, final Executor executor) { final Disposable disposable = Disposer.newDisposable(); myProject .getMessageBus() .connect(disposable) .subscribe( RUN_CONTENT_TOPIC, new RunContentWithExecutorListener() { @Override public void contentSelected( RunContentDescriptor descriptor, @NotNull Executor executor2) { if (executor2.equals(executor)) { listener.contentSelected(descriptor); } } @Override public void contentRemoved( RunContentDescriptor descriptor, @NotNull Executor executor2) { if (executor2.equals(executor)) { listener.contentRemoved(descriptor); } } }); myListeners.put(listener, disposable); }
private boolean checkNoDifferenceAndNotify( DiffPanel diffPanel, DiffRequest data, final Window window, final boolean showMessage) { if (!diffPanel.hasDifferences() && !data.getHints().contains(HINT_ALLOW_NO_DIFFERENCES)) { DiffManagerImpl manager = (DiffManagerImpl) DiffManager.getInstance(); if (!Comparing.equal(manager.getComparisonPolicy(), ComparisonPolicy.DEFAULT)) { ComparisonPolicy oldPolicy = manager.getComparisonPolicy(); manager.setComparisonPolicy(ComparisonPolicy.DEFAULT); Disposable parentDisposable = Disposer.newDisposable(); DiffPanel maybeDiffPanel = DiffManagerImpl.createDiffPanel(data, window, parentDisposable, this); manager.setComparisonPolicy(oldPolicy); boolean hasDiffs = maybeDiffPanel.hasDifferences(); Disposer.dispose(parentDisposable); if (hasDiffs) return false; } if (!showMessage) { return true; } return !askForceOpenDiff(data); } return false; }
@Override public void initialize() { try { base.initialize(); } catch (Exception ignore) { } myDisposable = Disposer.newDisposable(); Application application = ApplicationManager.getApplication(); if (application != null) { Disposer.register(application, myDisposable); } myMnemonicAlarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD, myDisposable); IdeEventQueue.getInstance() .addDispatcher( e -> { if (e instanceof KeyEvent && ((KeyEvent) e).getKeyCode() == KeyEvent.VK_ALT) { myAltPressed = e.getID() == KeyEvent.KEY_PRESSED; myMnemonicAlarm.cancelAllRequests(); final Component focusOwner = IdeFocusManager.findInstance().getFocusOwner(); if (focusOwner != null) { myMnemonicAlarm.addRequest(() -> repaintMnemonics(focusOwner, myAltPressed), 10); } } return false; }, myDisposable); }
@Override protected boolean showHint(final JComponent component) { boolean result = super.showHint(component); if (result && getType() == ValueHintType.MOUSE_OVER_HINT) { myDisposable = Disposer.newDisposable(); ShortcutSet shortcut = ActionManager.getInstance().getAction("ShowErrorDescription").getShortcutSet(); new DumbAwareAction() { @Override public void actionPerformed(@NotNull AnActionEvent e) { hideHint(); final Point point = new Point(myPoint.x, myPoint.y + getEditor().getLineHeight()); new XValueHint( getProject(), getEditor(), point, ValueHintType.MOUSE_CLICK_HINT, myExpressionInfo, myEvaluator, myDebugSession) .invokeHint(); } }.registerCustomShortcutSet(shortcut, getEditor().getContentComponent(), myDisposable); } return result; }
@Override public void addNotify() { super.addNotify(); myGlassPane = IdeGlassPaneUtil.find(this); myDisposable = Disposer.newDisposable(); myGlassPane.addMouseMotionPreprocessor(myListener, myDisposable); myGlassPane.addMousePreprocessor(myListener, myDisposable); }
public ClasspathEditor(final ModuleConfigurationState state) { super(state); final Disposable disposable = Disposer.newDisposable(); state .getProject() .getMessageBus() .connect(disposable) .subscribe(ProjectTopics.PROJECT_ROOTS, this); registerDisposable(disposable); }
@Override public void reset() { if (myFilePointersDisposable != null) { Disposer.dispose(myFilePointersDisposable); } myFilePointersDisposable = Disposer.newDisposable(); for (PyRootTypeProvider provider : myRootTypeProviders) { provider.reset(myFilePointersDisposable, this, myModule); } if (myRootTreeEditor != null) { ContentEntryEditor editor = myRootTreeEditor.getContentEntryEditor(); if (editor != null) editor.update(); myRootTreeEditor.update(); } }
/** * Creates new instance of {@link JetCoreEnvironment} instance using the arguments specified. * * @param stdlib path to "kotlin-runtime.jar", only used if not null and not empty * @param classpath compilation classpath, only used if not null and not empty * @param sourceRoots * @param enableInline * @param enableOptimization * @return compile environment instance */ private JetCoreEnvironment env( String stdlib, String[] classpath, String[] externalAnnotationsPath, String[] sourceRoots, boolean enableInline, boolean enableOptimization) { CompilerConfiguration configuration = createConfiguration( stdlib, classpath, externalAnnotationsPath, sourceRoots, enableInline, enableOptimization); return JetCoreEnvironment.createForProduction(Disposer.newDisposable(), configuration); }
@SuppressWarnings({"AssignmentToStaticFieldFromInstanceMethod"}) public class ApplicationImpl extends ComponentManagerImpl implements ApplicationEx { private static final Logger LOG = Logger.getInstance("#com.intellij.application.impl.ApplicationImpl"); private final ModalityState MODALITY_STATE_NONE = ModalityState.NON_MODAL; private final ModalityInvokator myInvokator = new ModalityInvokatorImpl(); private final EventDispatcher<ApplicationListener> myDispatcher = EventDispatcher.create(ApplicationListener.class); private IApplicationStore myComponentStore; private boolean myTestModeFlag; private final boolean myHeadlessMode; private final boolean myCommandLineMode; private final boolean myIsInternal; private final String myName; private final ReentrantWriterPreferenceReadWriteLock myActionsLock = new ReentrantWriterPreferenceReadWriteLock(); private final Stack<Class> myWriteActionsStack = new Stack<Class>(); // accessed from EDT only, no need to sync private volatile Runnable myExceptionalThreadWithReadAccessRunnable; private int myInEditorPaintCounter = 0; private long myStartTime = 0; @Nullable private Splash mySplash; private boolean myDoNotSave; private volatile boolean myDisposeInProgress = false; private int myRestartCode = 0; private volatile int myExitCode = 0; private final Disposable myLastDisposable = Disposer.newDisposable(); // will be disposed last private final AtomicBoolean mySaveSettingsIsInProgress = new AtomicBoolean(false); @SuppressWarnings({"UseOfArchaicSystemPropertyAccessors"}) private static final int ourDumpThreadsOnLongWriteActionWaiting = Integer.getInteger("dump.threads.on.long.write.action.waiting", 0); private final ExecutorService ourThreadExecutorsService = new ThreadPoolExecutor( 3, Integer.MAX_VALUE, 5 * 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), new ThreadFactory() { int i; public Thread newThread(Runnable r) { final Thread thread = new Thread(r, "ApplicationImpl pooled thread " + i++) { public void interrupt() { if (LOG.isDebugEnabled()) { LOG.debug("Interrupted worker, will remove from pool"); } super.interrupt(); } public void run() { try { super.run(); } catch (Throwable t) { if (LOG.isDebugEnabled()) { LOG.debug("Worker exits due to exception", t); } } } }; thread.setPriority(Thread.NORM_PRIORITY - 1); return thread; } }); private boolean myIsFiringLoadingEvent = false; @NonNls private static final String WAS_EVER_SHOWN = "was.ever.shown"; private Boolean myActive; private static final ThreadLocal<Integer> ourEdtSafe = new ThreadLocal<Integer>(); private static final ModalityState ANY = new ModalityState() { @Override public boolean dominates(@NotNull ModalityState anotherState) { return false; } @Override public String toString() { return "ANY"; } }; protected void bootstrapPicoContainer() { super.bootstrapPicoContainer(); getPicoContainer() .registerComponentImplementation( IComponentStore.class, StoresFactory.getApplicationStoreClass()); getPicoContainer().registerComponentImplementation(ApplicationPathMacroManager.class); } @NotNull public synchronized IApplicationStore getStateStore() { if (myComponentStore == null) { myComponentStore = (IApplicationStore) getPicoContainer().getComponentInstance(IComponentStore.class); } return myComponentStore; } @Override public void initializeComponent(Object component, boolean service) { getStateStore().initComponent(component, service); } public ApplicationImpl( boolean isInternal, boolean isUnitTestMode, boolean isHeadless, boolean isCommandLine, @NotNull String appName, Splash splash) { super(null); ApplicationManagerEx.setApplication( this, myLastDisposable); // reset back to null only when all components already disposed getPicoContainer().registerComponentInstance(Application.class, this); CommonBundle.assertKeyIsFound = isUnitTestMode; AWTExceptionHandler.register(); // do not crash AWT on exceptions if ((isInternal || isUnitTestMode) && !Comparing.equal("off", System.getProperty("idea.disposer.debug"))) { Disposer.setDebugMode(true); } myStartTime = System.currentTimeMillis(); mySplash = splash; myName = appName; PluginsFacade.INSTANCE = new PluginsFacade() { public IdeaPluginDescriptor getPlugin(PluginId id) { return PluginManager.getPlugin(id); } public IdeaPluginDescriptor[] getPlugins() { return PluginManager.getPlugins(); } }; myIsInternal = isInternal; myTestModeFlag = isUnitTestMode; myHeadlessMode = isHeadless; myCommandLineMode = isCommandLine; myDoNotSave = myTestModeFlag || myHeadlessMode; loadApplicationComponents(); if (myTestModeFlag) { registerShutdownHook(); } if (!isUnitTestMode && !isHeadless) { Disposer.register(this, Disposer.newDisposable(), "ui"); StartupUtil.addExternalInstanceListener( new Consumer<List<String>>() { @Override public void consume(final List<String> args) { invokeLater( new Runnable() { @Override public void run() { final Project project = CommandLineProcessor.processExternalCommandLine(args); final IdeFrame frame; if (project != null) { frame = WindowManager.getInstance().getIdeFrame(project); } else { frame = WindowManager.getInstance().getAllFrames()[0]; } ((IdeFrameImpl) frame).requestFocus(); } }); } }); } final String s = System.getProperty("jb.restart.code"); if (s != null) { try { myRestartCode = Integer.parseInt(s); } catch (NumberFormatException ignore) { } } registerFont("/fonts/Inconsolata.ttf"); } private void registerFont(String name) { if (isHeadlessEnvironment()) return; InputStream is = null; try { is = getClass().getResourceAsStream(name); final Font font = Font.createFont(Font.TRUETYPE_FONT, is); GraphicsEnvironment.getLocalGraphicsEnvironment().registerFont(font); } catch (Exception e) { LOG.info(e); } finally { if (is != null) { try { is.close(); } catch (IOException e) { LOG.error(e); } } } } private void registerShutdownHook() { ShutDownTracker .getInstance(); // Necessary to avoid creating an instance while already shutting down. ShutDownTracker.getInstance() .registerShutdownTask( new Runnable() { public void run() { if (isDisposed() || isDisposeInProgress()) { return; } ShutDownTracker.invokeAndWait( isUnitTestMode(), new Runnable() { public void run() { if (ApplicationManager.getApplication() != ApplicationImpl.this) return; try { myDisposeInProgress = true; saveAll(); } finally { disposeSelf(); } } }); } }); } private boolean disposeSelf() { final CommandProcessor commandProcessor = CommandProcessor.getInstance(); final Ref<Boolean> canClose = new Ref<Boolean>(Boolean.TRUE); for (final Project project : ProjectManagerEx.getInstanceEx().getOpenProjects()) { try { commandProcessor.executeCommand( project, new Runnable() { public void run() { canClose.set(ProjectUtil.closeAndDispose(project)); } }, ApplicationBundle.message("command.exit"), null); } catch (Throwable e) { LOG.error(e); } if (!canClose.get()) { myDisposeInProgress = false; return false; } } Disposer.dispose(this); Disposer.assertIsEmpty(); return true; } @NotNull public String getName() { return myName; } public boolean holdsReadLock() { return myActionsLock.isReadLockAcquired(); } @Override protected void handleInitComponentError( final Throwable ex, final boolean fatal, final String componentClassName) { if (PluginManager.isPluginClass(componentClassName)) { LOG.error(ex); PluginId pluginId = PluginManager.getPluginByClassName(componentClassName); @NonNls final String errorMessage = "Plugin " + pluginId.getIdString() + " failed to initialize and will be disabled:\n" + ex.getMessage() + "\nPlease restart " + ApplicationNamesInfo.getInstance().getFullProductName() + "."; PluginManager.disablePlugin(pluginId.getIdString()); if (!myHeadlessMode) { JOptionPane.showMessageDialog(null, errorMessage); } else { //noinspection UseOfSystemOutOrSystemErr System.out.println(errorMessage); System.exit(1); } return; // do not call super } if (fatal) { LOG.error(ex); @NonNls final String errorMessage = "Fatal error initializing class " + componentClassName + ":\n" + ex.toString() + "\nComplete error stacktrace was written to idea.log"; if (!myHeadlessMode) { JOptionPane.showMessageDialog(null, errorMessage); } else { //noinspection UseOfSystemOutOrSystemErr System.out.println(errorMessage); } } super.handleInitComponentError(ex, fatal, componentClassName); } private void loadApplicationComponents() { PluginManager.initPlugins(mySplash); final IdeaPluginDescriptor[] plugins = PluginManager.getPlugins(); for (IdeaPluginDescriptor plugin : plugins) { if (PluginManager.shouldSkipPlugin(plugin)) continue; loadComponentsConfiguration(plugin.getAppComponents(), plugin, false); } } @Override protected synchronized Object createComponent(Class componentInterface) { Object component = super.createComponent(componentInterface); if (mySplash != null) { mySplash.showProgress( "", (float) (0.65f + myComponentsRegistry.getPercentageOfComponentsLoaded() * 0.35f)); } return component; } protected MutablePicoContainer createPicoContainer() { return Extensions.getRootArea().getPicoContainer(); } public boolean isInternal() { return myIsInternal; } public boolean isUnitTestMode() { return myTestModeFlag; } public void setUnitTestMode(boolean testModeFlag) { myTestModeFlag = testModeFlag; } public boolean isHeadlessEnvironment() { return myHeadlessMode; } public boolean isCommandLine() { return myCommandLineMode; } public Future<?> executeOnPooledThread(@NotNull final Runnable action) { return ourThreadExecutorsService.submit( new Runnable() { public void run() { try { action.run(); } catch (ProcessCanceledException e) { // ignore } catch (Throwable t) { LOG.error(t); } finally { Thread.interrupted(); // reset interrupted status } } }); } @Override public <T> Future<T> executeOnPooledThread(@NotNull final Callable<T> action) { return ourThreadExecutorsService.submit( new Callable<T>() { public T call() { try { return action.call(); } catch (ProcessCanceledException e) { // ignore } catch (Throwable t) { LOG.error(t); } finally { Thread.interrupted(); // reset interrupted status } return null; } }); } private static Thread ourDispatchThread = null; public boolean isDispatchThread() { return EventQueue.isDispatchThread(); } @NotNull public ModalityInvokator getInvokator() { return myInvokator; } public void invokeLater(@NotNull final Runnable runnable) { myInvokator.invokeLater(runnable); } public void invokeLater(@NotNull final Runnable runnable, @NotNull final Condition expired) { myInvokator.invokeLater(runnable, expired); } public void invokeLater(@NotNull final Runnable runnable, @NotNull final ModalityState state) { myInvokator.invokeLater(runnable, state); } public void invokeLater( @NotNull final Runnable runnable, @NotNull final ModalityState state, @NotNull final Condition expired) { myInvokator.invokeLater(runnable, state, expired); } public void load(String path) throws IOException, InvalidDataException { getStateStore().setOptionsPath(path); getStateStore().setConfigPath(PathManager.getConfigPath()); myIsFiringLoadingEvent = true; try { fireBeforeApplicationLoaded(); } finally { myIsFiringLoadingEvent = false; } loadComponentRoamingTypes(); HeavyProcessLatch.INSTANCE.processStarted(); try { getStateStore().load(); } catch (StateStorageException e) { throw new IOException(e.getMessage()); } finally { HeavyProcessLatch.INSTANCE.processFinished(); } } @Override protected <T> T getComponentFromContainer(final Class<T> interfaceClass) { if (myIsFiringLoadingEvent) { return null; } return super.getComponentFromContainer(interfaceClass); } private static void loadComponentRoamingTypes() { ExtensionPoint<RoamingTypeExtensionPointBean> point = Extensions.getRootArea().getExtensionPoint("com.intellij.ComponentRoamingType"); final RoamingTypeExtensionPointBean[] componentRoamingTypes = point.getExtensions(); for (RoamingTypeExtensionPointBean object : componentRoamingTypes) { assert object.componentName != null; assert object.roamingType != null; final RoamingType type = RoamingType.valueOf(object.roamingType); assert type != null; ComponentRoamingManager.getInstance().setRoamingType(object.componentName, type); } } private void fireBeforeApplicationLoaded() { ExtensionPoint<ApplicationLoadListener> point = Extensions.getRootArea().getExtensionPoint("com.intellij.ApplicationLoadListener"); final ApplicationLoadListener[] objects = point.getExtensions(); for (ApplicationLoadListener object : objects) { try { object.beforeApplicationLoaded(this); } catch (Exception e) { LOG.error(e); } } } public void dispose() { fireApplicationExiting(); ShutDownTracker.getInstance().ensureStopperThreadsFinished(); disposeComponents(); ourThreadExecutorsService.shutdownNow(); myComponentStore = null; super.dispose(); Disposer.dispose(myLastDisposable); // dispose it last } private final Object lock = new Object(); private void makeChangesVisibleToEDT() { synchronized (lock) { lock.hashCode(); } } public boolean runProcessWithProgressSynchronously( @NotNull final Runnable process, @NotNull String progressTitle, boolean canBeCanceled, Project project) { return runProcessWithProgressSynchronously( process, progressTitle, canBeCanceled, project, null); } public boolean runProcessWithProgressSynchronously( @NotNull final Runnable process, @NotNull final String progressTitle, final boolean canBeCanceled, @Nullable final Project project, final JComponent parentComponent) { return runProcessWithProgressSynchronously( process, progressTitle, canBeCanceled, project, parentComponent, null); } public boolean runProcessWithProgressSynchronously( @NotNull final Runnable process, @NotNull final String progressTitle, final boolean canBeCanceled, @Nullable final Project project, final JComponent parentComponent, final String cancelText) { assertIsDispatchThread(); if (myExceptionalThreadWithReadAccessRunnable != null || ApplicationManager.getApplication().isUnitTestMode() || ApplicationManager.getApplication().isHeadlessEnvironment()) { try { ProgressManager.getInstance().runProcess(process, new EmptyProgressIndicator()); } catch (ProcessCanceledException e) { // ok to ignore. return false; } return true; } final ProgressWindow progress = new ProgressWindow(canBeCanceled, false, project, parentComponent, cancelText); progress.setTitle(progressTitle); try { myExceptionalThreadWithReadAccessRunnable = process; final boolean[] threadStarted = {false}; SwingUtilities.invokeLater( new Runnable() { public void run() { if (myExceptionalThreadWithReadAccessRunnable != process) { LOG.error( "myExceptionalThreadWithReadAccessRunnable != process, process = " + myExceptionalThreadWithReadAccessRunnable); } executeOnPooledThread( new Runnable() { public void run() { if (myExceptionalThreadWithReadAccessRunnable != process) { LOG.error( "myExceptionalThreadWithReadAccessRunnable != process, process = " + myExceptionalThreadWithReadAccessRunnable); } final boolean old = setExceptionalThreadWithReadAccessFlag(true); LOG.assertTrue(isReadAccessAllowed()); try { ProgressManager.getInstance().runProcess(process, progress); } catch (ProcessCanceledException e) { progress.cancel(); // ok to ignore. } catch (RuntimeException e) { progress.cancel(); throw e; } finally { setExceptionalThreadWithReadAccessFlag(old); makeChangesVisibleToEDT(); } } }); threadStarted[0] = true; } }); progress.startBlocking(); LOG.assertTrue(threadStarted[0]); LOG.assertTrue(!progress.isRunning()); } finally { myExceptionalThreadWithReadAccessRunnable = null; makeChangesVisibleToEDT(); } return !progress.isCanceled(); } public boolean isInModalProgressThread() { if (myExceptionalThreadWithReadAccessRunnable == null || !isExceptionalThreadWithReadAccess()) { return false; } ProgressIndicator progressIndicator = ProgressManager.getInstance().getProgressIndicator(); return progressIndicator.isModal() && ((ProgressIndicatorEx) progressIndicator).isModalityEntered(); } public void invokeAndWait(@NotNull Runnable runnable, @NotNull ModalityState modalityState) { if (isDispatchThread()) { LOG.error("invokeAndWait must not be called from event queue thread"); runnable.run(); return; } if (isExceptionalThreadWithReadAccess()) { // OK if we're in exceptional thread. LaterInvocator.invokeAndWait(runnable, modalityState); return; } if (myActionsLock.isReadLockAcquired()) { LOG.error("Calling invokeAndWait from read-action leads to possible deadlock."); } LaterInvocator.invokeAndWait(runnable, modalityState); } @NotNull public ModalityState getCurrentModalityState() { Object[] entities = LaterInvocator.getCurrentModalEntities(); return entities.length > 0 ? new ModalityStateEx(entities) : getNoneModalityState(); } @NotNull public ModalityState getModalityStateForComponent(@NotNull Component c) { Window window = c instanceof Window ? (Window) c : SwingUtilities.windowForComponent(c); if (window == null) return getNoneModalityState(); // ? return LaterInvocator.modalityStateForWindow(window); } @Override public ModalityState getAnyModalityState() { return ANY; } @NotNull public ModalityState getDefaultModalityState() { if (EventQueue.isDispatchThread()) { return getCurrentModalityState(); } else { ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator(); return progress == null ? getNoneModalityState() : progress.getModalityState(); } } @NotNull public ModalityState getNoneModalityState() { return MODALITY_STATE_NONE; } public long getStartTime() { return myStartTime; } public long getIdleTime() { return IdeEventQueue.getInstance().getIdleTime(); } public void exit() { exit(false); } public void exit(final boolean force) { exit(force, true); } public void exit(final boolean force, final boolean allowListenersToCancel) { if (!force && getDefaultModalityState() != ModalityState.NON_MODAL) { return; } Runnable runnable = new Runnable() { public void run() { if (!force && !showConfirmation()) { saveAll(); myExitCode = 0; return; } getMessageBus().syncPublisher(AppLifecycleListener.TOPIC).appClosing(); myDisposeInProgress = true; FileDocumentManager.getInstance().saveAllDocuments(); saveSettings(); if (!canExit() && allowListenersToCancel) { myExitCode = 0; return; } final boolean success = disposeSelf(); if (!success || isUnitTestMode()) { myExitCode = 0; return; } System.exit(myExitCode); } }; if (!isDispatchThread()) { invokeLater(runnable, ModalityState.NON_MODAL); } else { runnable.run(); } } private static boolean showConfirmation() { final boolean hasUnsafeBgTasks = ProgressManager.getInstance().hasUnsafeProgressIndicator(); DialogWrapper.DoNotAskOption option = new DialogWrapper.DoNotAskOption() { @Override public boolean isToBeShown() { return GeneralSettings.getInstance().isConfirmExit(); } @Override public void setToBeShown(boolean value, int exitCode) { GeneralSettings.getInstance().setConfirmExit(value); } @Override public boolean canBeHidden() { return !hasUnsafeBgTasks; } @Override public boolean shouldSaveOptionsOnCancel() { return false; } @Override public String getDoNotShowMessage() { return "Do not ask me again"; } }; if (hasUnsafeBgTasks || option.isToBeShown()) { String message = ApplicationBundle.message( hasUnsafeBgTasks ? "exit.confirm.prompt.tasks" : "exit.confirm.prompt", ApplicationNamesInfo.getInstance().getFullProductName()); if (DialogWrapper.OK_EXIT_CODE != Messages.showYesNoDialog( message, ApplicationBundle.message("exit.confirm.title"), ApplicationBundle.message("command.exit"), "Cancel", Messages.getQuestionIcon(), option)) { return false; } } return true; } private boolean canExit() { for (ApplicationListener applicationListener : myDispatcher.getListeners()) { if (!applicationListener.canExitApplication()) { return false; } } ProjectManagerEx projectManager = (ProjectManagerEx) ProjectManager.getInstance(); Project[] projects = projectManager.getOpenProjects(); for (Project project : projects) { if (!projectManager.canClose(project)) { return false; } } return true; } public void runReadAction(@NotNull final Runnable action) { final AccessToken token = acquireReadActionLockImpl(false); try { action.run(); } finally { token.finish(); } } private static final ThreadLocal<Boolean> exceptionalThreadWithReadAccessFlag = new ThreadLocal<Boolean>(); private static boolean isExceptionalThreadWithReadAccess() { Boolean flag = exceptionalThreadWithReadAccessFlag.get(); return flag == Boolean.TRUE; } public static boolean setExceptionalThreadWithReadAccessFlag(boolean flag) { boolean old = isExceptionalThreadWithReadAccess(); if (flag) { exceptionalThreadWithReadAccessFlag.set(Boolean.TRUE); } else { exceptionalThreadWithReadAccessFlag.remove(); } return old; } public <T> T runReadAction(@NotNull final Computable<T> computation) { final AccessToken token = acquireReadActionLockImpl(false); try { return computation.compute(); } finally { token.finish(); } } public void runWriteAction(@NotNull final Runnable action) { final AccessToken token = acquireWriteActionLock(action.getClass()); try { action.run(); } finally { token.finish(); } } public <T> T runWriteAction(@NotNull final Computable<T> computation) { final AccessToken token = acquireWriteActionLock(computation.getClass()); try { return computation.compute(); } finally { token.finish(); } } public boolean hasWriteAction(@Nullable Class<?> actionClass) { assertCanRunWriteAction(); for (int i = myWriteActionsStack.size() - 1; i >= 0; i--) { Class action = myWriteActionsStack.get(i); if (actionClass == action || action != null && ReflectionCache.isAssignable(actionClass, action)) return true; } return false; } public void assertReadAccessAllowed() { if (myHeadlessMode) return; if (!isReadAccessAllowed()) { LOG.error( "Read access is allowed from event dispatch thread or inside read-action only (see com.intellij.openapi.application.Application.runReadAction())", "Current thread: " + describe(Thread.currentThread()), "Our dispatch thread:" + describe(ourDispatchThread), "SystemEventQueueThread: " + describe(getEventQueueThread())); } } @NonNls private static String describe(Thread o) { if (o == null) return "null"; return o.toString() + " " + System.identityHashCode(o); } @Nullable private static Thread getEventQueueThread() { EventQueue eventQueue = Toolkit.getDefaultToolkit().getSystemEventQueue(); try { Method method = EventQueue.class.getDeclaredMethod("getDispatchThread"); method.setAccessible(true); return (Thread) method.invoke(eventQueue); } catch (Exception e1) { // ok } return null; } public boolean isReadAccessAllowed() { Thread currentThread = Thread.currentThread(); return ourDispatchThread == currentThread || isExceptionalThreadWithReadAccess() || myActionsLock.isReadLockAcquired() || myActionsLock.isWriteLockAcquired() || isDispatchThread(); } private static void assertCanRunWriteAction() { assertIsDispatchThread("Write access is allowed from event dispatch thread only"); } public void assertIsDispatchThread() { assertIsDispatchThread("Access is allowed from event dispatch thread only."); } private static void assertIsDispatchThread(String message) { if (ShutDownTracker.isShutdownHookRunning()) return; final Thread currentThread = Thread.currentThread(); if (ourDispatchThread == currentThread) return; if (EventQueue.isDispatchThread()) { ourDispatchThread = currentThread; } if (ourDispatchThread == currentThread) return; Integer safeCounter = ourEdtSafe.get(); if (safeCounter != null && safeCounter > 0) return; LOG.error( message, "Current thread: " + describe(Thread.currentThread()), "Our dispatch thread:" + describe(ourDispatchThread), "SystemEventQueueThread: " + describe(getEventQueueThread())); } public void runEdtSafeAction(@NotNull Runnable runnable) { Integer value = ourEdtSafe.get(); if (value == null) { value = Integer.valueOf(0); } ourEdtSafe.set(value + 1); try { runnable.run(); } finally { int newValue = ourEdtSafe.get() - 1; ourEdtSafe.set(newValue >= 1 ? newValue : null); } } public void assertIsDispatchThread(@Nullable final JComponent component) { if (component == null) return; Thread curThread = Thread.currentThread(); if (ourDispatchThread == curThread) { return; } if (Boolean.TRUE.equals(component.getClientProperty(WAS_EVER_SHOWN))) { assertIsDispatchThread(); } else { final JRootPane root = component.getRootPane(); if (root != null) { component.putClientProperty(WAS_EVER_SHOWN, Boolean.TRUE); assertIsDispatchThread(); } } } public void assertTimeConsuming() { if (myTestModeFlag || myHeadlessMode || ShutDownTracker.isShutdownHookRunning()) return; LOG.assertTrue( !isDispatchThread(), "This operation is time consuming and must not be called on EDT"); } public boolean tryRunReadAction(@NotNull Runnable action) { /** * if we are inside read action, do not try to acquire read lock again since it will deadlock if * there is a pending writeAction see {@link * com.intellij.util.concurrency.ReentrantWriterPreferenceReadWriteLock#allowReader()} */ boolean mustAcquire = !isReadAccessAllowed(); if (mustAcquire) { LOG.assertTrue( myTestModeFlag || !Thread.holdsLock(PsiLock.LOCK), "Thread must not hold PsiLock while performing readAction"); try { if (!myActionsLock.readLock().attempt(0)) return false; } catch (InterruptedException e) { throw new RuntimeInterruptedException(e); } } try { action.run(); } finally { if (mustAcquire) { myActionsLock.readLock().release(); } } return true; } public boolean tryToApplyActivationState(boolean active, Window window) { final Component frame = UIUtil.findUltimateParent(window); if (frame instanceof IdeFrame) { final IdeFrame ideFrame = (IdeFrame) frame; if (isActive() != active) { myActive = Boolean.valueOf(active); System.setProperty("idea.active", myActive.toString()); ApplicationActivationListener publisher = getMessageBus().syncPublisher(ApplicationActivationListener.TOPIC); if (active) { publisher.applicationActivated(ideFrame); } else { publisher.applicationDeactivated(ideFrame); } return true; } } return false; } public boolean isActive() { if (isUnitTestMode()) return true; if (myActive == null) { Window active = KeyboardFocusManager.getCurrentKeyboardFocusManager().getActiveWindow(); return active != null; } return myActive; } @Override public AccessToken acquireReadActionLock() { return acquireReadActionLockImpl(true); } private AccessToken acquireReadActionLockImpl(boolean explicit) { /** * if we are inside read action, do not try to acquire read lock again since it will deadlock if * there is a pending writeAction see {@link * com.intellij.util.concurrency.ReentrantWriterPreferenceReadWriteLock#allowReader()} */ if (isReadAccessAllowed()) return AccessToken.EMPTY_ACCESS_TOKEN; return new ReadAccessToken(explicit); } @Override public AccessToken acquireWriteActionLock(Class clazz) { return new WriteAccessToken(clazz); } private class WriteAccessToken extends AccessToken { private final Class clazz; public WriteAccessToken(Class _clazz) { clazz = _clazz; assertCanRunWriteAction(); ActivityTracker.getInstance().inc(); fireBeforeWriteActionStart(_clazz); final AtomicBoolean stopped = new AtomicBoolean(false); if (ourDumpThreadsOnLongWriteActionWaiting > 0) { executeOnPooledThread( new Runnable() { @Override public void run() { while (!stopped.get()) { try { Thread.sleep(ourDumpThreadsOnLongWriteActionWaiting); if (!stopped.get()) { PerformanceWatcher.getInstance().dumpThreads(true); } } catch (InterruptedException ignored) { } } } }); } LOG.assertTrue( myActionsLock.isWriteLockAcquired(Thread.currentThread()) || !Thread.holdsLock(PsiLock.LOCK), "Thread must not hold PsiLock while performing writeAction"); try { myActionsLock.writeLock().acquire(); acquired(); } catch (InterruptedException e) { throw new RuntimeInterruptedException(e); } stopped.set(true); myWriteActionsStack.push(_clazz); fireWriteActionStarted(_clazz); } @Override public void finish() { try { fireWriteActionFinished(clazz); myWriteActionsStack.pop(); } finally { myActionsLock.writeLock().release(); released(); } } } private class ReadAccessToken extends AccessToken { private final boolean myExplicit; ReadAccessToken(boolean explicit) { myExplicit = explicit; LOG.assertTrue( !Thread.holdsLock(PsiLock.LOCK), "Thread must not hold PsiLock while performing readAction"); try { myActionsLock.readLock().acquire(); if (myExplicit) acquired(); } catch (InterruptedException e) { throw new RuntimeInterruptedException(e); } } @Override public void finish() { myActionsLock.readLock().release(); if (myExplicit) released(); } } public void assertWriteAccessAllowed() { LOG.assertTrue( isWriteAccessAllowed(), "Write access is allowed inside write-action only (see com.intellij.openapi.application.Application.runWriteAction())"); } public boolean isWriteAccessAllowed() { return myActionsLock.isWriteLockAcquired(Thread.currentThread()); } public void editorPaintStart() { myInEditorPaintCounter++; } public void editorPaintFinish() { myInEditorPaintCounter--; LOG.assertTrue(myInEditorPaintCounter >= 0); } public void addApplicationListener(@NotNull ApplicationListener l) { myDispatcher.addListener(l); } public void addApplicationListener(@NotNull ApplicationListener l, @NotNull Disposable parent) { myDispatcher.addListener(l, parent); } public void removeApplicationListener(@NotNull ApplicationListener l) { myDispatcher.removeListener(l); } private void fireApplicationExiting() { myDispatcher.getMulticaster().applicationExiting(); } private void fireBeforeWriteActionStart(Class action) { myDispatcher.getMulticaster().beforeWriteActionStart(action); } private void fireWriteActionStarted(Class action) { myDispatcher.getMulticaster().writeActionStarted(action); } private void fireWriteActionFinished(Class action) { myDispatcher.getMulticaster().writeActionFinished(action); } public void _saveSettings() { // public for testing purposes if (mySaveSettingsIsInProgress.compareAndSet(false, true)) { try { StoreUtil.doSave(getStateStore()); } catch (final Throwable ex) { if (isUnitTestMode()) { System.out.println("Saving application settings failed"); ex.printStackTrace(); } else { LOG.info("Saving application settings failed", ex); invokeLater( new Runnable() { public void run() { if (ex instanceof PluginException) { final PluginException pluginException = (PluginException) ex; PluginManager.disablePlugin(pluginException.getPluginId().getIdString()); Messages.showMessageDialog( "The plugin " + pluginException.getPluginId() + " failed to save settings and has been disabled. Please restart " + ApplicationNamesInfo.getInstance().getFullProductName(), CommonBundle.getErrorTitle(), Messages.getErrorIcon()); } else { Messages.showMessageDialog( ApplicationBundle.message( "application.save.settings.error", ex.getLocalizedMessage()), CommonBundle.getErrorTitle(), Messages.getErrorIcon()); } } }); } } finally { mySaveSettingsIsInProgress.set(false); } } } public void saveSettings() { if (myDoNotSave) return; _saveSettings(); } public void saveAll() { if (myDoNotSave) return; FileDocumentManager.getInstance().saveAllDocuments(); Project[] openProjects = ProjectManager.getInstance().getOpenProjects(); for (Project openProject : openProjects) { ProjectEx project = (ProjectEx) openProject; project.save(); } saveSettings(); } public void doNotSave() { doNotSave(true); } public void doNotSave(boolean value) { myDoNotSave = value; } public boolean isDoNotSave() { return myDoNotSave; } public <T> T[] getExtensions(final ExtensionPointName<T> extensionPointName) { return Extensions.getRootArea().getExtensionPoint(extensionPointName).getExtensions(); } public boolean isDisposeInProgress() { return myDisposeInProgress; } public boolean isRestartCapable() { return SystemInfo.isWindows || SystemInfo.isMacOSSnowLeopard || myRestartCode > 0; } public void restart() { if (SystemInfo.isWindows) { Win32Restarter.restart(); } else if (SystemInfo.isMacOSSnowLeopard) { MacRestarter.restart(); } else if (myRestartCode > 0) { myExitCode = myRestartCode; exit(true); } else { exit(true); } } public boolean isSaving() { if (getStateStore().isSaving()) return true; Project[] openProjects = ProjectManager.getInstance().getOpenProjects(); for (Project openProject : openProjects) { ProjectEx project = (ProjectEx) openProject; if (project.getStateStore().isSaving()) return true; } return false; } @Override protected boolean logSlowComponents() { return super.logSlowComponents() || ApplicationInfoImpl.getShadowInstance().isEAP(); } @TestOnly public void setDisposeInProgress(boolean disposeInProgress) { myDisposeInProgress = disposeInProgress; } @NonNls @Override public String toString() { return "Application" + (isDisposed() ? " (Disposed)" : "") + (isUnitTestMode() ? " (Unit test)" : "") + (isInternal() ? " (Internal)" : "") + (isHeadlessEnvironment() ? " (Headless)" : "") + (isCommandLine() ? " (Command line)" : ""); } }
public ApplicationImpl( boolean isInternal, boolean isUnitTestMode, boolean isHeadless, boolean isCommandLine, @NotNull String appName, Splash splash) { super(null); ApplicationManagerEx.setApplication( this, myLastDisposable); // reset back to null only when all components already disposed getPicoContainer().registerComponentInstance(Application.class, this); CommonBundle.assertKeyIsFound = isUnitTestMode; AWTExceptionHandler.register(); // do not crash AWT on exceptions if ((isInternal || isUnitTestMode) && !Comparing.equal("off", System.getProperty("idea.disposer.debug"))) { Disposer.setDebugMode(true); } myStartTime = System.currentTimeMillis(); mySplash = splash; myName = appName; PluginsFacade.INSTANCE = new PluginsFacade() { public IdeaPluginDescriptor getPlugin(PluginId id) { return PluginManager.getPlugin(id); } public IdeaPluginDescriptor[] getPlugins() { return PluginManager.getPlugins(); } }; myIsInternal = isInternal; myTestModeFlag = isUnitTestMode; myHeadlessMode = isHeadless; myCommandLineMode = isCommandLine; myDoNotSave = myTestModeFlag || myHeadlessMode; loadApplicationComponents(); if (myTestModeFlag) { registerShutdownHook(); } if (!isUnitTestMode && !isHeadless) { Disposer.register(this, Disposer.newDisposable(), "ui"); StartupUtil.addExternalInstanceListener( new Consumer<List<String>>() { @Override public void consume(final List<String> args) { invokeLater( new Runnable() { @Override public void run() { final Project project = CommandLineProcessor.processExternalCommandLine(args); final IdeFrame frame; if (project != null) { frame = WindowManager.getInstance().getIdeFrame(project); } else { frame = WindowManager.getInstance().getAllFrames()[0]; } ((IdeFrameImpl) frame).requestFocus(); } }); } }); } final String s = System.getProperty("jb.restart.code"); if (s != null) { try { myRestartCode = Integer.parseInt(s); } catch (NumberFormatException ignore) { } } registerFont("/fonts/Inconsolata.ttf"); }
/** @author peter */ public class DomFileDescriptionTest extends DomHardCoreTestCase { private XmlFile myFooElementFile; private XmlFile myBarElementFile; private Disposable myDisposable = Disposer.newDisposable(); @Override protected void setUp() throws Exception { super.setUp(); myFooElementFile = (XmlFile) createFile("a.xml", "<a/>"); getDomManager() .registerFileDescription( new MockDomFileDescription<>(FooElement.class, "a", myFooElementFile), myDisposable); myBarElementFile = (XmlFile) createFile("b.xml", "<b/>"); getDomManager() .registerFileDescription( new DomFileDescription<BarElement>(BarElement.class, "b") { @Override public boolean isMyFile(@NotNull final XmlFile file, final Module module) { String text = myFooElementFile.getText(); return text.contains("239"); } @Override public boolean isAutomaticHighlightingEnabled() { return false; } }, myDisposable); assertResultsAndClear(); } @Override public void tearDown() throws Exception { try { Disposer.dispose(myDisposable); } finally { myFooElementFile = null; myBarElementFile = null; super.tearDown(); } } public void testNoInitialDomnessInB() throws Throwable { assertFalse(getDomManager().isDomFile(myBarElementFile)); assertNull(getDomManager().getFileElement(myBarElementFile)); } public void testIsDomValue() throws Throwable { final XmlFile file = (XmlFile) createFile("a.xml", "<b>42</b>"); getDomManager() .registerFileDescription( new DomFileDescription<MyElement>(MyElement.class, "b") { @Override public boolean isMyFile(@NotNull final XmlFile file, final Module module) { return /*super.isMyFile(file, module) && */ file.getText().contains("239"); } }, myDisposable); assertFalse(getDomManager().isDomFile(file)); assertNull(getDomManager().getFileElement(file)); new WriteCommandAction(getProject()) { @Override protected void run(@NotNull Result result) throws Throwable { file.getDocument().getRootTag().getValue().setText("239"); } }.execute(); assertTrue(getDomManager().isDomFile(file)); final DomFileElementImpl<MyElement> root = getDomManager().getFileElement(file); assertNotNull(root); final MyElement child = root.getRootElement().getChild(); assertTrue(root.isValid()); assertTrue(child.isValid()); new WriteCommandAction(getProject()) { @Override protected void run(@NotNull Result result) throws Throwable { file.getDocument().getRootTag().getValue().setText("57121"); } }.execute(); assertFalse(getDomManager().isDomFile(file)); assertNull(getDomManager().getFileElement(file)); assertFalse(root.isValid()); assertFalse(child.isValid()); } public void testCopyFileDescriptionFromOriginalFile() throws Throwable { final XmlFile file = (XmlFile) createFile("a.xml", "<b>42</b>"); getDomManager() .registerFileDescription( new MockDomFileDescription<>(MyElement.class, "b", file), myDisposable); ApplicationManager.getApplication() .runWriteAction( () -> { file.setName("b.xml"); }); assertTrue(getDomManager().isDomFile(file)); final XmlFile copy = (XmlFile) file.copy(); assertTrue(getDomManager().isDomFile(copy)); assertFalse(getDomManager().getFileElement(file).equals(getDomManager().getFileElement(copy))); } public void testDependantFileDescriptionCauseStackOverflow() throws Throwable { final XmlFile interestingFile = (XmlFile) createFile("a.xml", "<b>42</b>"); getDomManager() .registerFileDescription( new MockDomFileDescription<>(MyElement.class, "b", (XmlFile) null), myDisposable); for (int i = 0; i < 239; i++) { getDomManager() .registerFileDescription( new MockDomFileDescription<AbstractElement>( AbstractElement.class, "b", (XmlFile) null) { @Override @NotNull public Set getDependencyItems(final XmlFile file) { getDomManager().isDomFile(interestingFile); return super.getDependencyItems(file); } }, myDisposable); } getDomManager().isDomFile(interestingFile); } public void testCheckNamespace() throws Throwable { getDomManager() .registerFileDescription( new DomFileDescription<NamespacedElement>(NamespacedElement.class, "xxx", "bar") { @Override protected void initializeFileDescription() { registerNamespacePolicy("foo", "bar"); } }, myDisposable); final PsiFile file = createFile("xxx.xml", "<xxx/>"); assertFalse(getDomManager().isDomFile(file)); new WriteCommandAction(getProject()) { @Override protected void run(@NotNull Result result) throws Throwable { ((XmlFile) file).getDocument().getRootTag().setAttribute("xmlns", "bar"); } }.execute(); assertTrue(getDomManager().isDomFile(file)); } public void testCheckDtdPublicId() throws Throwable { getDomManager() .registerFileDescription( new DomFileDescription<NamespacedElement>(NamespacedElement.class, "xxx", "bar") { @Override protected void initializeFileDescription() { registerNamespacePolicy("foo", "bar"); } }, myDisposable); final PsiFile file = createFile("xxx.xml", "<xxx/>"); assertFalse(getDomManager().isDomFile(file)); new WriteCommandAction(getProject()) { @Override protected void run(@NotNull Result result) throws Throwable { final Document document = getDocument(file); document.insertString( 0, "<!DOCTYPE xxx PUBLIC \"bar\" \"http://java.sun.com/dtd/ejb-jar_2_0.dtd\">\n"); commitDocument(document); } }.execute(); assertTrue(getDomManager().isDomFile(file)); } public void testChangeCustomDomness() throws Throwable { getDomManager() .registerFileDescription( new DomFileDescription<MyElement>(MyElement.class, "xxx") { @Override public boolean isMyFile(@NotNull final XmlFile file, @Nullable final Module module) { return file.getText().contains("foo"); } }, myDisposable); final XmlFile file = (XmlFile) createFile("xxx.xml", "<xxx zzz=\"foo\"><boy/><boy/><xxx/>"); final MyElement boy = getDomManager().getFileElement(file, MyElement.class).getRootElement().getBoys().get(0); new WriteCommandAction(getProject()) { @Override protected void run(@NotNull Result result) throws Throwable { file.getDocument().getRootTag().setAttribute("zzz", "bar"); } }.execute(); assertFalse(getDomManager().isDomFile(file)); assertFalse(boy.isValid()); } public interface AbstractElement extends GenericDomValue<String> { GenericAttributeValue<String> getAttr(); } public interface FooElement extends AbstractElement {} public interface BarElement extends AbstractElement {} public interface ZipElement extends AbstractElement {} public interface MyElement extends DomElement { MyElement getChild(); List<MyElement> getBoys(); } @Namespace("foo") public interface NamespacedElement extends DomElement {} }
public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract implements EditorOptionsProvider { private HashMap<String, MyColorScheme> mySchemes; private MyColorScheme mySelectedScheme; public static final String DIFF_GROUP = ApplicationBundle.message("title.diff"); public static final String FILE_STATUS_GROUP = ApplicationBundle.message("title.file.status"); public static final String SCOPES_GROUP = ApplicationBundle.message("title.scope.based"); private boolean mySomeSchemesDeleted = false; private Map<ColorAndFontPanelFactory, InnerSearchableConfigurable> mySubPanelFactories; private SchemesPanel myRootSchemesPanel; private boolean myInitResetCompleted = false; private boolean myInitResetInvoked = false; private boolean myRevertChangesCompleted = false; private boolean myApplyCompleted = false; private boolean myDisposeCompleted = false; private final Disposable myDisposable = Disposer.newDisposable(); private static final Logger LOG = Logger.getInstance("#com.intellij.application.options.colors.ColorAndFontOptions"); @Override public boolean isModified() { boolean listModified = isSchemeListModified(); boolean schemeModified = isSomeSchemeModified(); if (listModified || schemeModified) { myApplyCompleted = false; } return listModified; } private boolean isSchemeListModified() { if (mySomeSchemesDeleted) return true; if (!mySelectedScheme .getName() .equals(EditorColorsManager.getInstance().getGlobalScheme().getName())) return true; for (MyColorScheme scheme : mySchemes.values()) { if (scheme.isNew()) return true; } return false; } private boolean isSomeSchemeModified() { for (MyColorScheme scheme : mySchemes.values()) { if (scheme.isModified()) return true; } return false; } public EditorColorsScheme selectScheme(@NotNull String name) { mySelectedScheme = getScheme(name); return mySelectedScheme; } private MyColorScheme getScheme(String name) { return mySchemes.get(name); } public EditorColorsScheme getSelectedScheme() { return mySelectedScheme; } public EditorColorsScheme getOriginalSelectedScheme() { return mySelectedScheme == null ? null : mySelectedScheme.getOriginalScheme(); } public EditorSchemeAttributeDescriptor[] getCurrentDescriptions() { return mySelectedScheme.getDescriptors(); } public static boolean isReadOnly(@NotNull final EditorColorsScheme scheme) { return ((MyColorScheme) scheme).isReadOnly(); } @NotNull public String[] getSchemeNames() { List<MyColorScheme> schemes = new ArrayList<MyColorScheme>(mySchemes.values()); Collections.sort( schemes, new Comparator<MyColorScheme>() { @Override public int compare(@NotNull MyColorScheme o1, @NotNull MyColorScheme o2) { if (isReadOnly(o1) && !isReadOnly(o2)) return -1; if (!isReadOnly(o1) && isReadOnly(o2)) return 1; return o1.getName().compareToIgnoreCase(o2.getName()); } }); List<String> names = new ArrayList<String>(schemes.size()); for (MyColorScheme scheme : schemes) { names.add(scheme.getName()); } return ArrayUtil.toStringArray(names); } @NotNull public Collection<EditorColorsScheme> getSchemes() { return new ArrayList<EditorColorsScheme>(mySchemes.values()); } public void saveSchemeAs(String name) { MyColorScheme scheme = mySelectedScheme; if (scheme == null) return; EditorColorsScheme clone = (EditorColorsScheme) scheme.getOriginalScheme().clone(); scheme.apply(clone); clone.setName(name); MyColorScheme newScheme = new MyColorScheme(clone); initScheme(newScheme); newScheme.setIsNew(); mySchemes.put(name, newScheme); selectScheme(newScheme.getName()); resetSchemesCombo(null); } public void addImportedScheme(@NotNull final EditorColorsScheme imported) { MyColorScheme newScheme = new MyColorScheme(imported); initScheme(newScheme); mySchemes.put(imported.getName(), newScheme); selectScheme(newScheme.getName()); resetSchemesCombo(null); } public void removeScheme(String name) { if (mySelectedScheme.getName().equals(name)) { //noinspection HardCodedStringLiteral selectScheme("Default"); } boolean deletedNewlyCreated = false; MyColorScheme toDelete = mySchemes.get(name); if (toDelete != null) { deletedNewlyCreated = toDelete.isNew(); } mySchemes.remove(name); resetSchemesCombo(null); mySomeSchemesDeleted = mySomeSchemesDeleted || !deletedNewlyCreated; } @Override public void apply() throws ConfigurationException { if (myApplyCompleted) { return; } try { EditorColorsManager myColorsManager = EditorColorsManager.getInstance(); myColorsManager.removeAllSchemes(); for (MyColorScheme scheme : mySchemes.values()) { if (!scheme.isDefault()) { scheme.apply(); myColorsManager.addColorsScheme(scheme.getOriginalScheme()); } } EditorColorsScheme originalScheme = mySelectedScheme.getOriginalScheme(); myColorsManager.setGlobalScheme(originalScheme); if (originalScheme != null && DarculaLaf.NAME.equals(originalScheme.getName()) && !UIUtil.isUnderDarcula()) { int ok = Messages.showYesNoDialog( "Darcula color scheme has been set for editors. Would you like to set Darcula as default Look and Feel?", "Darcula Look and Feel", Messages.getQuestionIcon()); if (ok == Messages.YES) { LafManager.getInstance().setCurrentLookAndFeel(new DarculaLookAndFeelInfo()); DarculaInstaller.install(); } } applyChangesToEditors(); reset(); } finally { myApplyCompleted = true; } } private static void applyChangesToEditors() { EditorFactory.getInstance().refreshAllEditors(); TodoConfiguration.getInstance().colorSettingsChanged(); Project[] openProjects = ProjectManager.getInstance().getOpenProjects(); for (Project openProject : openProjects) { FileStatusManager.getInstance(openProject).fileStatusesChanged(); DaemonCodeAnalyzer.getInstance(openProject).restart(); } } private boolean myIsReset = false; private void resetSchemesCombo(Object source) { myIsReset = true; try { myRootSchemesPanel.resetSchemesCombo(source); if (mySubPanelFactories != null) { for (NewColorAndFontPanel subPartialConfigurable : getPanels()) { subPartialConfigurable.reset(source); } } } finally { myIsReset = false; } } @Override public JComponent createComponent() { if (myRootSchemesPanel == null) { ensureSchemesPanel(); } return myRootSchemesPanel; } @Override public boolean hasOwnContent() { return true; } @NotNull @Override public Configurable[] buildConfigurables() { myDisposeCompleted = false; initAll(); List<ColorAndFontPanelFactory> panelFactories = createPanelFactories(); List<Configurable> result = new ArrayList<Configurable>(); mySubPanelFactories = new LinkedHashMap<ColorAndFontPanelFactory, InnerSearchableConfigurable>( panelFactories.size()); for (ColorAndFontPanelFactory panelFactory : panelFactories) { mySubPanelFactories.put(panelFactory, new InnerSearchableConfigurable(panelFactory)); } result.addAll(new ArrayList<SearchableConfigurable>(mySubPanelFactories.values())); return result.toArray(new Configurable[result.size()]); } @NotNull private Set<NewColorAndFontPanel> getPanels() { Set<NewColorAndFontPanel> result = new HashSet<NewColorAndFontPanel>(); for (InnerSearchableConfigurable configurable : mySubPanelFactories.values()) { NewColorAndFontPanel panel = configurable.getSubPanelIfInitialized(); if (panel != null) { result.add(panel); } } return result; } protected List<ColorAndFontPanelFactory> createPanelFactories() { List<ColorAndFontPanelFactory> result = new ArrayList<ColorAndFontPanelFactory>(); result.add(new FontConfigurableFactory()); List<ColorAndFontPanelFactory> extensions = new ArrayList<ColorAndFontPanelFactory>(); extensions.add(new ConsoleFontConfigurableFactory()); ColorSettingsPage[] pages = ColorSettingsPages.getInstance().getRegisteredPages(); for (final ColorSettingsPage page : pages) { extensions.add( new ColorAndFontPanelFactoryEx() { @Override @NotNull public NewColorAndFontPanel createPanel(@NotNull ColorAndFontOptions options) { final SimpleEditorPreview preview = new SimpleEditorPreview(options, page); return NewColorAndFontPanel.create( preview, page.getDisplayName(), options, null, page); } @Override @NotNull public String getPanelDisplayName() { return page.getDisplayName(); } @Override public DisplayPriority getPriority() { if (page instanceof DisplayPrioritySortable) { return ((DisplayPrioritySortable) page).getPriority(); } return DisplayPriority.LANGUAGE_SETTINGS; } }); } Collections.addAll(extensions, Extensions.getExtensions(ColorAndFontPanelFactory.EP_NAME)); Collections.sort( extensions, new Comparator<ColorAndFontPanelFactory>() { @Override public int compare(ColorAndFontPanelFactory f1, ColorAndFontPanelFactory f2) { if (f1 instanceof DisplayPrioritySortable) { if (f2 instanceof DisplayPrioritySortable) { int result = ((DisplayPrioritySortable) f1) .getPriority() .compareTo(((DisplayPrioritySortable) f2).getPriority()); if (result != 0) return result; } else { return 1; } } else if (f2 instanceof DisplayPrioritySortable) { return -1; } return f1.getPanelDisplayName().compareToIgnoreCase(f2.getPanelDisplayName()); } }); result.addAll(extensions); result.add(new DiffColorsPageFactory()); result.add(new FileStatusColorsPageFactory()); result.add(new ScopeColorsPageFactory()); return result; } private static class FontConfigurableFactory implements ColorAndFontPanelFactory { @Override @NotNull public NewColorAndFontPanel createPanel(@NotNull ColorAndFontOptions options) { FontEditorPreview previewPanel = new FontEditorPreview(options, true); return new NewColorAndFontPanel( new SchemesPanel(options), new FontOptions(options), previewPanel, "Font", null, null) { @Override public boolean containsFontOptions() { return true; } }; } @Override @NotNull public String getPanelDisplayName() { return "Font"; } } private static class ConsoleFontConfigurableFactory implements ColorAndFontPanelFactoryEx { @Override @NotNull public NewColorAndFontPanel createPanel(@NotNull ColorAndFontOptions options) { FontEditorPreview previewPanel = new FontEditorPreview(options, false) { @Override protected EditorColorsScheme updateOptionsScheme(EditorColorsScheme selectedScheme) { return ConsoleViewUtil.updateConsoleColorScheme(selectedScheme); } }; return new NewColorAndFontPanel( new SchemesPanel(options), new ConsoleFontOptions(options), previewPanel, "Font", null, null) { @Override public boolean containsFontOptions() { return true; } }; } @Override @NotNull public String getPanelDisplayName() { return "Console Font"; } @NotNull @Override public DisplayPriority getPriority() { return DisplayPriority.COMMON_SETTINGS; } } private class DiffColorsPageFactory implements ColorAndFontPanelFactory { @Override @NotNull public NewColorAndFontPanel createPanel(@NotNull ColorAndFontOptions options) { final DiffOptionsPanel optionsPanel = new DiffOptionsPanel(options); SchemesPanel schemesPanel = new SchemesPanel(options); PreviewPanel previewPanel; try { final DiffPreviewPanel diffPreviewPanel = new DiffPreviewPanel(myDisposable); diffPreviewPanel.setMergeRequest(null); schemesPanel.addListener( new ColorAndFontSettingsListener.Abstract() { @Override public void schemeChanged(final Object source) { diffPreviewPanel.setColorScheme(getSelectedScheme()); optionsPanel.updateOptionsList(); diffPreviewPanel.updateView(); } }); previewPanel = diffPreviewPanel; } catch (FilesTooBigForDiffException e) { LOG.info(e); previewPanel = new PreviewPanel.Empty(); } return new NewColorAndFontPanel( schemesPanel, optionsPanel, previewPanel, DIFF_GROUP, null, null); } @Override @NotNull public String getPanelDisplayName() { return DIFF_GROUP; } } private void initAll() { EditorColorsManager colorsManager = EditorColorsManager.getInstance(); EditorColorsScheme[] allSchemes = colorsManager.getAllSchemes(); mySchemes = new HashMap<String, MyColorScheme>(); for (EditorColorsScheme allScheme : allSchemes) { MyColorScheme schemeDelegate = new MyColorScheme(allScheme); initScheme(schemeDelegate); mySchemes.put(schemeDelegate.getName(), schemeDelegate); } mySelectedScheme = mySchemes.get(EditorColorsManager.getInstance().getGlobalScheme().getName()); assert mySelectedScheme != null : EditorColorsManager.getInstance().getGlobalScheme().getName() + "; myschemes=" + mySchemes; } private static void initScheme(@NotNull MyColorScheme scheme) { List<EditorSchemeAttributeDescriptor> descriptions = new ArrayList<EditorSchemeAttributeDescriptor>(); initPluggedDescriptions(descriptions, scheme); initDiffDescriptors(descriptions, scheme); initFileStatusDescriptors(descriptions, scheme); initScopesDescriptors(descriptions, scheme); scheme.setDescriptors( descriptions.toArray(new EditorSchemeAttributeDescriptor[descriptions.size()])); } private static void initPluggedDescriptions( @NotNull List<EditorSchemeAttributeDescriptor> descriptions, @NotNull MyColorScheme scheme) { ColorSettingsPage[] pages = ColorSettingsPages.getInstance().getRegisteredPages(); for (ColorSettingsPage page : pages) { initDescriptions(page, descriptions, scheme); } for (ColorAndFontDescriptorsProvider provider : Extensions.getExtensions(ColorAndFontDescriptorsProvider.EP_NAME)) { initDescriptions(provider, descriptions, scheme); } } private static void initDescriptions( @NotNull ColorAndFontDescriptorsProvider provider, @NotNull List<EditorSchemeAttributeDescriptor> descriptions, @NotNull MyColorScheme scheme) { String group = provider.getDisplayName(); List<AttributesDescriptor> attributeDescriptors = ColorSettingsUtil.getAllAttributeDescriptors(provider); for (AttributesDescriptor descriptor : attributeDescriptors) { addSchemedDescription( descriptions, descriptor.getDisplayName(), group, descriptor.getKey(), scheme, null, null); } ColorDescriptor[] colorDescriptors = provider.getColorDescriptors(); for (ColorDescriptor descriptor : colorDescriptors) { ColorKey back = descriptor.getKind() == ColorDescriptor.Kind.BACKGROUND ? descriptor.getKey() : null; ColorKey fore = descriptor.getKind() == ColorDescriptor.Kind.FOREGROUND ? descriptor.getKey() : null; addEditorSettingDescription( descriptions, descriptor.getDisplayName(), group, back, fore, scheme); } } private static void initDiffDescriptors( @NotNull List<EditorSchemeAttributeDescriptor> descriptions, @NotNull MyColorScheme scheme) { DiffOptionsPanel.addSchemeDescriptions(descriptions, scheme); } private static void initFileStatusDescriptors( @NotNull List<EditorSchemeAttributeDescriptor> descriptions, MyColorScheme scheme) { FileStatus[] statuses = FileStatusFactory.getInstance().getAllFileStatuses(); for (FileStatus fileStatus : statuses) { addEditorSettingDescription( descriptions, fileStatus.getText(), FILE_STATUS_GROUP, null, fileStatus.getColorKey(), scheme); } } private static void initScopesDescriptors( @NotNull List<EditorSchemeAttributeDescriptor> descriptions, @NotNull MyColorScheme scheme) { Set<Pair<NamedScope, NamedScopesHolder>> namedScopes = new THashSet<Pair<NamedScope, NamedScopesHolder>>( new TObjectHashingStrategy<Pair<NamedScope, NamedScopesHolder>>() { @Override public int computeHashCode( @NotNull final Pair<NamedScope, NamedScopesHolder> object) { return object.getFirst().getName().hashCode(); } @Override public boolean equals( @NotNull final Pair<NamedScope, NamedScopesHolder> o1, @NotNull final Pair<NamedScope, NamedScopesHolder> o2) { return o1.getFirst().getName().equals(o2.getFirst().getName()); } }); Project[] projects = ProjectManager.getInstance().getOpenProjects(); for (Project project : projects) { DependencyValidationManagerImpl validationManager = (DependencyValidationManagerImpl) DependencyValidationManager.getInstance(project); List<Pair<NamedScope, NamedScopesHolder>> cachedScopes = validationManager.getScopeBasedHighlightingCachedScopes(); namedScopes.addAll(cachedScopes); } List<Pair<NamedScope, NamedScopesHolder>> list = new ArrayList<Pair<NamedScope, NamedScopesHolder>>(namedScopes); Collections.sort( list, new Comparator<Pair<NamedScope, NamedScopesHolder>>() { @Override public int compare( @NotNull final Pair<NamedScope, NamedScopesHolder> o1, @NotNull final Pair<NamedScope, NamedScopesHolder> o2) { return o1.getFirst().getName().compareToIgnoreCase(o2.getFirst().getName()); } }); for (Pair<NamedScope, NamedScopesHolder> pair : list) { NamedScope namedScope = pair.getFirst(); String name = namedScope.getName(); TextAttributesKey textAttributesKey = ScopeAttributesUtil.getScopeTextAttributeKey(name); if (scheme.getAttributes(textAttributesKey) == null) { scheme.setAttributes(textAttributesKey, new TextAttributes()); } NamedScopesHolder holder = pair.getSecond(); PackageSet value = namedScope.getValue(); String toolTip = holder.getDisplayName() + (value == null ? "" : ": " + value.getText()); addSchemedDescription( descriptions, name, SCOPES_GROUP, textAttributesKey, scheme, holder.getIcon(), toolTip); } } private static void addEditorSettingDescription( @NotNull List<EditorSchemeAttributeDescriptor> array, String name, String group, @Nullable ColorKey backgroundKey, @Nullable ColorKey foregroundKey, EditorColorsScheme scheme) { String type = null; if (foregroundKey != null) { type = foregroundKey.getExternalName(); } else { if (backgroundKey != null) { type = backgroundKey.getExternalName(); } } ColorAndFontDescription descr = new EditorSettingColorDescription(name, group, backgroundKey, foregroundKey, type, scheme); array.add(descr); } private static void addSchemedDescription( @NotNull List<EditorSchemeAttributeDescriptor> array, String name, String group, @NotNull TextAttributesKey key, @NotNull MyColorScheme scheme, Icon icon, String toolTip) { ColorAndFontDescription descr = new SchemeTextAttributesDescription(name, group, key, scheme, icon, toolTip); array.add(descr); } @Override public String getDisplayName() { return ApplicationBundle.message("title.colors.and.fonts"); } private void revertChanges() { if (isSchemeListModified() || isSomeSchemeModified()) { myRevertChangesCompleted = false; } if (!myRevertChangesCompleted) { ensureSchemesPanel(); try { resetImpl(); } finally { myRevertChangesCompleted = true; } } } private void resetImpl() { mySomeSchemesDeleted = false; initAll(); resetSchemesCombo(null); } @Override public synchronized void reset() { if (!myInitResetInvoked) { try { super.reset(); if (!myInitResetCompleted) { ensureSchemesPanel(); try { resetImpl(); } finally { myInitResetCompleted = true; } } } finally { myInitResetInvoked = true; } } else { revertChanges(); } } public synchronized void resetFromChild() { if (!myInitResetCompleted) { ensureSchemesPanel(); try { resetImpl(); } finally { myInitResetCompleted = true; } } } private void ensureSchemesPanel() { if (myRootSchemesPanel == null) { myRootSchemesPanel = new SchemesPanel(this); myRootSchemesPanel.addListener( new ColorAndFontSettingsListener.Abstract() { @Override public void schemeChanged(final Object source) { if (!myIsReset) { resetSchemesCombo(source); } } }); } } @Override public void disposeUIResources() { try { if (!myDisposeCompleted) { try { super.disposeUIResources(); Disposer.dispose(myDisposable); if (myRootSchemesPanel != null) { myRootSchemesPanel.disposeUIResources(); } } finally { myDisposeCompleted = true; } } } finally { mySubPanelFactories = null; myInitResetCompleted = false; myInitResetInvoked = false; myRevertChangesCompleted = false; myApplyCompleted = false; myRootSchemesPanel = null; } } public boolean currentSchemeIsReadOnly() { return isReadOnly(mySelectedScheme); } public boolean currentSchemeIsShared() { return ColorSettingsUtil.isSharedScheme(mySelectedScheme); } private static class SchemeTextAttributesDescription extends TextAttributesDescription { @NotNull private final TextAttributes myAttributesToApply; @NotNull private final TextAttributesKey key; private TextAttributes myFallbackAttributes; private Pair<ColorSettingsPage, AttributesDescriptor> myBaseAttributeDescriptor; private boolean myIsInheritedInitial = false; private SchemeTextAttributesDescription( String name, String group, @NotNull TextAttributesKey key, @NotNull MyColorScheme scheme, Icon icon, String toolTip) { super(name, group, getInitialAttributes(scheme, key).clone(), key, scheme, icon, toolTip); this.key = key; myAttributesToApply = getInitialAttributes(scheme, key); TextAttributesKey fallbackKey = key.getFallbackAttributeKey(); if (fallbackKey != null) { myFallbackAttributes = scheme.getAttributes(fallbackKey); myBaseAttributeDescriptor = ColorSettingsPages.getInstance().getAttributeDescriptor(fallbackKey); if (myBaseAttributeDescriptor == null) { myBaseAttributeDescriptor = new Pair<ColorSettingsPage, AttributesDescriptor>( null, new AttributesDescriptor(fallbackKey.getExternalName(), fallbackKey)); } } myIsInheritedInitial = isInherited(scheme); setInherited(myIsInheritedInitial); initCheckedStatus(); } @NotNull private static TextAttributes getInitialAttributes( @NotNull MyColorScheme scheme, @NotNull TextAttributesKey key) { TextAttributes attributes = scheme.getAttributes(key); return attributes != null ? attributes : new TextAttributes(); } private boolean isInherited(@NotNull MyColorScheme scheme) { TextAttributes attributes = scheme.getAttributes(key); TextAttributesKey fallbackKey = key.getFallbackAttributeKey(); if (fallbackKey != null && !scheme.containsKey(key)) { TextAttributes fallbackAttributes = scheme.getAttributes(fallbackKey); if (attributes != null && attributes == fallbackAttributes) { return true; } } return false; } @Override public void apply(EditorColorsScheme scheme) { if (scheme == null) scheme = getScheme(); scheme.setAttributes(key, isInherited() ? new TextAttributes() : getTextAttributes()); } @Override public boolean isModified() { return !Comparing.equal(myAttributesToApply, getTextAttributes()) || myIsInheritedInitial != isInherited(); } @Override public boolean isErrorStripeEnabled() { return true; } @Nullable @Override public TextAttributes getBaseAttributes() { return myFallbackAttributes; } @Nullable @Override public Pair<ColorSettingsPage, AttributesDescriptor> getBaseAttributeDescriptor() { return myBaseAttributeDescriptor; } @Override public void setInherited(boolean isInherited) { super.setInherited(isInherited); } } private static class GetSetColor { private final ColorKey myKey; private final EditorColorsScheme myScheme; private boolean isModified = false; private Color myColor; private GetSetColor(ColorKey key, EditorColorsScheme scheme) { myKey = key; myScheme = scheme; myColor = myScheme.getColor(myKey); } public Color getColor() { return myColor; } public void setColor(Color col) { if (getColor() == null || !getColor().equals(col)) { isModified = true; myColor = col; } } public void apply(EditorColorsScheme scheme) { if (scheme == null) scheme = myScheme; scheme.setColor(myKey, myColor); } public boolean isModified() { return isModified; } } private static class EditorSettingColorDescription extends ColorAndFontDescription { private GetSetColor myGetSetForeground; private GetSetColor myGetSetBackground; private EditorSettingColorDescription( String name, String group, ColorKey backgroundKey, ColorKey foregroundKey, String type, EditorColorsScheme scheme) { super(name, group, type, scheme, null, null); if (backgroundKey != null) { myGetSetBackground = new GetSetColor(backgroundKey, scheme); } if (foregroundKey != null) { myGetSetForeground = new GetSetColor(foregroundKey, scheme); } initCheckedStatus(); } @Override public int getFontType() { return 0; } @Override public void setFontType(int type) {} @Override public Color getExternalEffectColor() { return null; } @Override public void setExternalEffectColor(Color color) {} @Override public void setExternalEffectType(EffectType type) {} @NotNull @Override public EffectType getExternalEffectType() { return EffectType.LINE_UNDERSCORE; } @Override public Color getExternalForeground() { if (myGetSetForeground == null) { return null; } return myGetSetForeground.getColor(); } @Override public void setExternalForeground(Color col) { if (myGetSetForeground == null) { return; } myGetSetForeground.setColor(col); } @Override public Color getExternalBackground() { if (myGetSetBackground == null) { return null; } return myGetSetBackground.getColor(); } @Override public void setExternalBackground(Color col) { if (myGetSetBackground == null) { return; } myGetSetBackground.setColor(col); } @Override public Color getExternalErrorStripe() { return null; } @Override public void setExternalErrorStripe(Color col) {} @Override public boolean isFontEnabled() { return false; } @Override public boolean isForegroundEnabled() { return myGetSetForeground != null; } @Override public boolean isBackgroundEnabled() { return myGetSetBackground != null; } @Override public boolean isEffectsColorEnabled() { return false; } @Override public boolean isModified() { return myGetSetBackground != null && myGetSetBackground.isModified() || myGetSetForeground != null && myGetSetForeground.isModified(); } @Override public void apply(EditorColorsScheme scheme) { if (myGetSetBackground != null) { myGetSetBackground.apply(scheme); } if (myGetSetForeground != null) { myGetSetForeground.apply(scheme); } } } @Override @NotNull public String getHelpTopic() { return "reference.settingsdialog.IDE.editor.colors"; } private static class MyColorScheme extends EditorColorsSchemeImpl { private EditorSchemeAttributeDescriptor[] myDescriptors; private String myName; private boolean myIsNew = false; private MyColorScheme(@NotNull EditorColorsScheme parentScheme) { super(parentScheme, DefaultColorSchemesManager.getInstance()); parentScheme.getFontPreferences().copyTo(getFontPreferences()); setLineSpacing(parentScheme.getLineSpacing()); parentScheme.getConsoleFontPreferences().copyTo(getConsoleFontPreferences()); setConsoleLineSpacing(parentScheme.getConsoleLineSpacing()); setQuickDocFontSize(parentScheme.getQuickDocFontSize()); myName = parentScheme.getName(); if (parentScheme instanceof ExternalizableScheme) { getExternalInfo().copy(((ExternalizableScheme) parentScheme).getExternalInfo()); } initFonts(); } @Override public String getName() { return myName; } @Override public void setName(String name) { myName = name; } public void setDescriptors(EditorSchemeAttributeDescriptor[] descriptors) { myDescriptors = descriptors; } public EditorSchemeAttributeDescriptor[] getDescriptors() { return myDescriptors; } public boolean isDefault() { return myParentScheme instanceof DefaultColorsScheme; } public boolean isReadOnly() { return myParentScheme instanceof ReadOnlyColorsScheme; } public boolean isModified() { if (isFontModified() || isConsoleFontModified()) return true; for (EditorSchemeAttributeDescriptor descriptor : myDescriptors) { if (descriptor.isModified()) { return true; } } return false; } private boolean isFontModified() { if (!getFontPreferences().equals(myParentScheme.getFontPreferences())) return true; if (getLineSpacing() != myParentScheme.getLineSpacing()) return true; return getQuickDocFontSize() != myParentScheme.getQuickDocFontSize(); } private boolean isConsoleFontModified() { if (!getConsoleFontPreferences().equals(myParentScheme.getConsoleFontPreferences())) return true; return getConsoleLineSpacing() != myParentScheme.getConsoleLineSpacing(); } public void apply() { apply(myParentScheme); } public void apply(@NotNull EditorColorsScheme scheme) { scheme.setFontPreferences(getFontPreferences()); scheme.setLineSpacing(myLineSpacing); scheme.setQuickDocFontSize(getQuickDocFontSize()); scheme.setConsoleFontPreferences(getConsoleFontPreferences()); scheme.setConsoleLineSpacing(getConsoleLineSpacing()); for (EditorSchemeAttributeDescriptor descriptor : myDescriptors) { descriptor.apply(scheme); } } @Override public Object clone() { return null; } public EditorColorsScheme getOriginalScheme() { return myParentScheme; } public void setIsNew() { myIsNew = true; } public boolean isNew() { return myIsNew; } @NotNull @Override public String toString() { return "temporary scheme for " + myName; } } @Override @NotNull public String getId() { return getHelpTopic(); } @Override @Nullable public Runnable enableSearch(final String option) { return null; } @Nullable public InnerSearchableConfigurable findSubConfigurable(@NotNull final Class pageClass) { if (mySubPanelFactories == null) { buildConfigurables(); } for (Map.Entry<ColorAndFontPanelFactory, InnerSearchableConfigurable> entry : mySubPanelFactories.entrySet()) { if (pageClass.isInstance(entry.getValue().createPanel().getSettingsPage())) { return entry.getValue(); } } return null; } @Nullable public NewColorAndFontPanel findPage(String pageName) { if (mySubPanelFactories == null) { buildConfigurables(); } for (InnerSearchableConfigurable configurable : mySubPanelFactories.values()) { if (configurable.getDisplayName().equals(pageName)) { return configurable.createPanel(); } } return null; } private class InnerSearchableConfigurable implements SearchableConfigurable, OptionsContainingConfigurable, NoScroll { private NewColorAndFontPanel mySubPanel; private boolean mySubInitInvoked = false; @NotNull private final ColorAndFontPanelFactory myFactory; private InnerSearchableConfigurable(@NotNull ColorAndFontPanelFactory factory) { myFactory = factory; } @NotNull @Override @Nls public String getDisplayName() { return myFactory.getPanelDisplayName(); } public NewColorAndFontPanel getSubPanelIfInitialized() { return mySubPanel; } private NewColorAndFontPanel createPanel() { if (mySubPanel == null) { mySubPanel = myFactory.createPanel(ColorAndFontOptions.this); mySubPanel.reset(this); mySubPanel.addSchemesListener( new ColorAndFontSettingsListener.Abstract() { @Override public void schemeChanged(final Object source) { if (!myIsReset) { resetSchemesCombo(source); } } }); mySubPanel.addDescriptionListener( new ColorAndFontSettingsListener.Abstract() { @Override public void fontChanged() { for (NewColorAndFontPanel panel : getPanels()) { panel.updatePreview(); } } }); } return mySubPanel; } @Override public String getHelpTopic() { return null; } @Override public JComponent createComponent() { return createPanel().getPanel(); } @Override public boolean isModified() { createPanel(); for (MyColorScheme scheme : mySchemes.values()) { if (mySubPanel.containsFontOptions()) { if (scheme.isFontModified() || scheme.isConsoleFontModified()) { myRevertChangesCompleted = false; return true; } } else { for (EditorSchemeAttributeDescriptor descriptor : scheme.getDescriptors()) { if (mySubPanel.contains(descriptor) && descriptor.isModified()) { myRevertChangesCompleted = false; return true; } } } } return false; } @Override public void apply() throws ConfigurationException { ColorAndFontOptions.this.apply(); } @Override public void reset() { if (!mySubInitInvoked) { if (!myInitResetCompleted) { resetFromChild(); } mySubInitInvoked = true; } else { revertChanges(); } } @Override public void disposeUIResources() { if (mySubPanel != null) { mySubPanel.disposeUIResources(); mySubPanel = null; } } @Override @NotNull public String getId() { return ColorAndFontOptions.this.getId() + "." + getDisplayName(); } @Override public Runnable enableSearch(final String option) { return createPanel().showOption(option); } @NotNull @Override public Set<String> processListOptions() { return createPanel().processListOptions(); } @NotNull @NonNls @Override public String toString() { return "Color And Fonts for " + getDisplayName(); } } }
public class BreakpointsDialog extends DialogWrapper { @NotNull private Project myProject; private Object myInitialBreakpoint; private List<BreakpointPanelProvider> myBreakpointsPanelProviders; private BreakpointItemsTreeController myTreeController; JLabel temp = new JLabel(); private MasterController myMasterController = new MasterController() { @Override public ItemWrapper[] getSelectedItems() { final List<BreakpointItem> res = myTreeController.getSelectedBreakpoints(); return res.toArray(new ItemWrapper[res.size()]); } @Override public JLabel getPathLabel() { return temp; } }; private final DetailController myDetailController = new DetailController(myMasterController); private Collection<BreakpointItem> myBreakpointItems = new ArrayList<BreakpointItem>(); private final List<XBreakpointGroupingRule> myRulesAvailable = new ArrayList<XBreakpointGroupingRule>(); private Set<XBreakpointGroupingRule> myRulesEnabled = new TreeSet<XBreakpointGroupingRule>( new Comparator<XBreakpointGroupingRule>() { @Override public int compare(XBreakpointGroupingRule o1, XBreakpointGroupingRule o2) { final int res = o2.getPriority() - o1.getPriority(); return res != 0 ? res : (o1.getId().compareTo(o2.getId())); } }); private Disposable myListenerDisposable = Disposer.newDisposable(); private List<ToggleActionButton> myToggleRuleActions = new ArrayList<ToggleActionButton>(); private XBreakpointManagerImpl getBreakpointManager() { return (XBreakpointManagerImpl) XDebuggerManager.getInstance(myProject).getBreakpointManager(); } protected BreakpointsDialog( @NotNull Project project, Object breakpoint, @NotNull List<BreakpointPanelProvider> providers) { super(project); myProject = project; myBreakpointsPanelProviders = providers; myInitialBreakpoint = breakpoint; collectGroupingRules(); collectItems(); setTitle("Breakpoints"); setModal(false); init(); setOKButtonText("Done"); } private String getSplitterProportionKey() { return getDimensionServiceKey() + ".splitter"; } @Nullable @Override protected JComponent createCenterPanel() { JPanel mainPanel = new JPanel(new BorderLayout()); JBSplitter splitPane = new JBSplitter(0.3f); splitPane.setSplitterProportionKey(getSplitterProportionKey()); splitPane.setFirstComponent(createMasterView()); splitPane.setSecondComponent(createDetailView()); mainPanel.add(splitPane, BorderLayout.CENTER); return mainPanel; } private JComponent createDetailView() { DetailViewImpl detailView = new DetailViewImpl(myProject); myDetailController.setDetailView(detailView); return detailView; } void collectItems() { if (!myBreakpointsPanelProviders.isEmpty()) { myBreakpointItems.clear(); for (BreakpointPanelProvider panelProvider : myBreakpointsPanelProviders) { panelProvider.provideBreakpointItems(myProject, myBreakpointItems); } } } void initSelection(Collection<BreakpointItem> breakpoints) { boolean found = false; for (BreakpointItem breakpoint : breakpoints) { if (breakpoint.getBreakpoint() == myInitialBreakpoint) { myTreeController.selectBreakpointItem(breakpoint, null); found = true; break; } } if (!found && !breakpoints.isEmpty()) { myTreeController.selectFirstBreakpointItem(); } } @Nullable @Override protected String getDimensionServiceKey() { return getClass().getName(); } @NotNull @Override protected Action[] createActions() { return new Action[] {getOKAction()}; } private class ToggleBreakpointGroupingRuleEnabledAction extends ToggleActionButton { private XBreakpointGroupingRule myRule; public ToggleBreakpointGroupingRuleEnabledAction(XBreakpointGroupingRule rule) { super(rule.getPresentableName(), rule.getIcon()); myRule = rule; getTemplatePresentation().setText(rule.getPresentableName()); } @Override public boolean isSelected(AnActionEvent e) { return myRulesEnabled.contains(myRule); } @Override public void setSelected(AnActionEvent e, boolean state) { if (state) { myRulesEnabled.add(myRule); } else { myRulesEnabled.remove(myRule); } myTreeController.setGroupingRules(myRulesEnabled); } } private JComponent createMasterView() { myTreeController = new BreakpointItemsTreeController(myRulesEnabled); JTree tree = new BreakpointsCheckboxTree(myProject, myTreeController); new AnAction("BreakpointDialog.GoToSource") { @Override public void actionPerformed(AnActionEvent e) { navigate(); close(OK_EXIT_CODE); } }.registerCustomShortcutSet( new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0)), tree); new AnAction("BreakpointDialog.ShowSource") { @Override public void actionPerformed(AnActionEvent e) { navigate(); } }.registerCustomShortcutSet( ActionManager.getInstance().getAction(IdeActions.ACTION_EDIT_SOURCE).getShortcutSet(), tree); tree.addMouseListener( new MouseAdapter() { @Override public void mouseClicked(MouseEvent event) { if (event.getClickCount() == 2 && UIUtil.isActionClick(event, MouseEvent.MOUSE_CLICKED) && !UIUtil.isSelectionButtonDown(event) && !event.isConsumed()) { navigate(); close(OK_EXIT_CODE); } } }); final DefaultActionGroup breakpointTypes = new DefaultActionGroup(); for (BreakpointPanelProvider provider : myBreakpointsPanelProviders) { breakpointTypes.addAll(provider.getAddBreakpointActions(myProject)); } ToolbarDecorator decorator = ToolbarDecorator.createDecorator(tree) .setAddAction( new AnActionButtonRunnable() { @Override public void run(AnActionButton button) { JBPopupFactory.getInstance() .createActionGroupPopup( null, breakpointTypes, DataManager.getInstance().getDataContext(button.getContextComponent()), JBPopupFactory.ActionSelectionAid.NUMBERING, false) .show(button.getPreferredPopupPoint()); } }) .setRemoveAction( new AnActionButtonRunnable() { @Override public void run(AnActionButton button) { myTreeController.removeSelectedBreakpoints(myProject); } }) .setRemoveActionUpdater( new AnActionButtonUpdater() { @Override public boolean isEnabled(AnActionEvent e) { boolean enabled = false; final ItemWrapper[] items = myMasterController.getSelectedItems(); for (ItemWrapper item : items) { if (item.allowedToRemove()) { enabled = true; } } return enabled; } }); for (ToggleActionButton action : myToggleRuleActions) { decorator.addExtraAction(action); } JPanel decoratedTree = decorator.createPanel(); myTreeController.setTreeView(tree); myDetailController.setTree(tree); myTreeController.buildTree(myBreakpointItems); initSelection(myBreakpointItems); final BreakpointPanelProvider.BreakpointsListener listener = new BreakpointPanelProvider.BreakpointsListener() { @Override public void breakpointsChanged() { collectItems(); myTreeController.rebuildTree(myBreakpointItems); } }; for (BreakpointPanelProvider provider : myBreakpointsPanelProviders) { provider.addListener(listener, myProject, myListenerDisposable); } return decoratedTree; } private void navigate() { List<BreakpointItem> breakpoints = myTreeController.getSelectedBreakpoints(); if (!breakpoints.isEmpty()) { breakpoints.get(0).navigate(true); } } @Nullable @Override public JComponent getPreferredFocusedComponent() { return myTreeController.getTreeView(); } private void collectGroupingRules() { for (BreakpointPanelProvider provider : myBreakpointsPanelProviders) { provider.createBreakpointsGroupingRules(myRulesAvailable); } myRulesEnabled.clear(); XBreakpointsDialogState settings = (getBreakpointManager()).getBreakpointsDialogSettings(); for (XBreakpointGroupingRule rule : myRulesAvailable) { if (rule.isAlwaysEnabled() || (settings != null && settings.getSelectedGroupingRules().contains(rule.getId()))) { myRulesEnabled.add(rule); } } for (XBreakpointGroupingRule rule : myRulesAvailable) { if (!rule.isAlwaysEnabled()) { myToggleRuleActions.add(new ToggleBreakpointGroupingRuleEnabledAction(rule)); } } } private void saveBreakpointsDialogState() { final XBreakpointsDialogState dialogState = new XBreakpointsDialogState(); final List<XBreakpointGroupingRule> rulesEnabled = ContainerUtil.filter( myRulesEnabled, new Condition<XBreakpointGroupingRule>() { @Override public boolean value(XBreakpointGroupingRule rule) { return !rule.isAlwaysEnabled(); } }); dialogState.setSelectedGroupingRules( new HashSet<String>( ContainerUtil.map( rulesEnabled, new Function<XBreakpointGroupingRule, String>() { @Override public String fun(XBreakpointGroupingRule rule) { return rule.getId(); } }))); getBreakpointManager().setBreakpointsDialogSettings(dialogState); } @Override protected void dispose() { Disposer.dispose(myListenerDisposable); saveBreakpointsDialogState(); super.dispose(); } }
@Override public boolean executeTask( DataContext context, RunConfiguration configuration, ExecutionEnvironment env, ExternalSystemBeforeRunTask beforeRunTask) { final ExternalSystemTaskExecutionSettings executionSettings = beforeRunTask.getTaskExecutionSettings(); final List<ExternalTaskPojo> tasks = ContainerUtilRt.newArrayList(); for (String taskName : executionSettings.getTaskNames()) { tasks.add(new ExternalTaskPojo(taskName, executionSettings.getExternalProjectPath(), null)); } if (tasks.isEmpty()) return true; final Pair<ProgramRunner, ExecutionEnvironment> pair = ExternalSystemUtil.createRunner( executionSettings, DefaultRunExecutor.EXECUTOR_ID, myProject, mySystemId); if (pair == null) return false; final ProgramRunner runner = pair.first; final ExecutionEnvironment environment = pair.second; environment.setExecutionId(env.getExecutionId()); final Semaphore targetDone = new Semaphore(); final Ref<Boolean> result = new Ref<Boolean>(false); final Disposable disposable = Disposer.newDisposable(); final Executor executor = DefaultRunExecutor.getRunExecutorInstance(); final String executorId = executor.getId(); myProject .getMessageBus() .connect(disposable) .subscribe( ExecutionManager.EXECUTION_TOPIC, new ExecutionAdapter() { public void processStartScheduled( final String executorIdLocal, final ExecutionEnvironment environmentLocal) { if (executorId.equals(executorIdLocal) && environment.equals(environmentLocal)) { targetDone.down(); } } public void processNotStarted( final String executorIdLocal, @NotNull final ExecutionEnvironment environmentLocal) { if (executorId.equals(executorIdLocal) && environment.equals(environmentLocal)) { targetDone.up(); } } public void processStarted( final String executorIdLocal, @NotNull final ExecutionEnvironment environmentLocal, @NotNull final ProcessHandler handler) { if (executorId.equals(executorIdLocal) && environment.equals(environmentLocal)) { handler.addProcessListener( new ProcessAdapter() { public void processTerminated(ProcessEvent event) { result.set(event.getExitCode() == 0); targetDone.up(); environmentLocal.getContentToReuse(); } }); } } }); try { ApplicationManager.getApplication() .invokeAndWait( new Runnable() { @Override public void run() { try { runner.execute(environment); } catch (ExecutionException e) { targetDone.up(); LOG.error(e); } } }, ModalityState.NON_MODAL); } catch (Exception e) { LOG.error(e); Disposer.dispose(disposable); return false; } targetDone.waitFor(); Disposer.dispose(disposable); return result.get(); }
// Made public and non-final for Fabrique public class IdeRootPane extends JRootPane implements UISettingsListener { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.wm.impl.IdeRootPane"); /** Toolbar and status bar. */ private JComponent myToolbar; private IdeStatusBarImpl myStatusBar; private final Box myNorthPanel = Box.createVerticalBox(); private final List<IdeRootPaneNorthExtension> myNorthComponents = new ArrayList<IdeRootPaneNorthExtension>(); /** Current <code>ToolWindowsPane</code>. If there is no such pane then this field is null. */ private ToolWindowsPane myToolWindowsPane; private final MyUISettingsListenerImpl myUISettingsListener; private JPanel myContentPane; private final ActionManager myActionManager; private final UISettings myUISettings; private static WelcomeScreen myWelcomeScreen; private static Component myWelcomePane; private final boolean myGlassPaneInitialized; private final IdeGlassPaneImpl myGlassPane; private final Application myApplication; private MemoryUsagePanel myMemoryWidget; private final StatusBarCustomComponentFactory[] myStatusBarCustomComponentFactories; private final Disposable myDisposable = Disposer.newDisposable(); IdeRootPane( ActionManagerEx actionManager, UISettings uiSettings, DataManager dataManager, final Application application, final String[] commandLineArgs, IdeFrame frame) { myActionManager = actionManager; myUISettings = uiSettings; updateToolbar(); myContentPane.add(myNorthPanel, BorderLayout.NORTH); myStatusBarCustomComponentFactories = application.getExtensions(StatusBarCustomComponentFactory.EP_NAME); myApplication = application; createStatusBar(frame); updateStatusBarVisibility(); myContentPane.add(myStatusBar, BorderLayout.SOUTH); myUISettingsListener = new MyUISettingsListenerImpl(); setJMenuBar(new IdeMenuBar(actionManager, dataManager)); final Ref<Boolean> willOpenProject = new Ref<Boolean>(Boolean.FALSE); final AppLifecycleListener lifecyclePublisher = application.getMessageBus().syncPublisher(AppLifecycleListener.TOPIC); lifecyclePublisher.appFrameCreated(commandLineArgs, willOpenProject); LOG.info( "App initialization took " + (System.nanoTime() - PluginManager.startupStart) / 1000000 + " ms"); PluginManager.dumpPluginClassStatistics(); if (!willOpenProject.get()) { showWelcomeScreen(); lifecyclePublisher.welcomeScreenDisplayed(); } myGlassPane = new IdeGlassPaneImpl(this); setGlassPane(myGlassPane); myGlassPaneInitialized = true; myGlassPane.setVisible(false); Disposer.register(application, myDisposable); } private void showWelcomeScreen() { myWelcomeScreen = new WelcomeScreen(this); Disposer.register(myDisposable, myWelcomeScreen); myWelcomePane = myWelcomeScreen.getWelcomePanel(); myContentPane.add(myWelcomePane); updateToolbarVisibility(); } public void setGlassPane(final Component glass) { if (myGlassPaneInitialized) throw new IllegalStateException("Setting of glass pane for IdeFrame is prohibited"); super.setGlassPane(glass); } /** Invoked when enclosed frame is being shown. */ public final void addNotify() { super.addNotify(); myUISettings.addUISettingsListener(myUISettingsListener, myDisposable); } /** Invoked when enclosed frame is being disposed. */ public final void removeNotify() { Disposer.dispose(myDisposable); super.removeNotify(); } /** * Sets current tool windows pane (panel where all tool windows are located). If <code> * toolWindowsPane</code> is <code>null</code> then the method just removes the current tool * windows pane. */ final void setToolWindowsPane(@Nullable final ToolWindowsPane toolWindowsPane) { final JComponent contentPane = (JComponent) getContentPane(); if (myToolWindowsPane != null) { contentPane.remove(myToolWindowsPane); } hideWelcomeScreen(contentPane); myToolWindowsPane = toolWindowsPane; if (myToolWindowsPane != null) { contentPane.add(myToolWindowsPane, BorderLayout.CENTER); } else if (!myApplication.isDisposeInProgress()) { showWelcomeScreen(); } contentPane.revalidate(); } private void hideWelcomeScreen(JComponent contentPane) { if (myWelcomePane != null) { Disposer.dispose(myWelcomeScreen); contentPane.remove(myWelcomePane); myWelcomeScreen = null; myWelcomePane = null; updateToolbarVisibility(); } } protected final Container createContentPane() { myContentPane = new JPanel(new BorderLayout()); myContentPane.setBackground(Color.GRAY); return myContentPane; } void updateToolbar() { if (myToolbar != null) { myNorthPanel.remove(myToolbar); } myToolbar = createToolbar(); myNorthPanel.add(myToolbar); updateToolbarVisibility(); myContentPane.revalidate(); } void updateMainMenuActions() { ((IdeMenuBar) menuBar).updateMenuActions(); menuBar.repaint(); } private JComponent createToolbar() { ActionGroup group = (ActionGroup) CustomActionsSchema.getInstance().getCorrectedAction(IdeActions.GROUP_MAIN_TOOLBAR); final ActionToolbar toolBar = myActionManager.createActionToolbar(ActionPlaces.MAIN_TOOLBAR, group, true); toolBar.setLayoutPolicy(ActionToolbar.WRAP_LAYOUT_POLICY); DefaultActionGroup menuGroup = new DefaultActionGroup(); menuGroup.add(new ViewToolbarAction()); menuGroup.add(new CustomizeUIAction()); PopupHandler.installUnknownPopupHandler(toolBar.getComponent(), menuGroup, myActionManager); return toolBar.getComponent(); } private void createStatusBar(IdeFrame frame) { myUISettings.addUISettingsListener(this, myApplication); myStatusBar = new IdeStatusBarImpl(); myStatusBar.install(frame); myMemoryWidget = new MemoryUsagePanel(); if (myStatusBarCustomComponentFactories != null) { for (final StatusBarCustomComponentFactory<JComponent> componentFactory : myStatusBarCustomComponentFactories) { final JComponent c = componentFactory.createComponent(myStatusBar); myStatusBar.addWidget( new CustomStatusBarWidget() { public JComponent getComponent() { return c; } @NotNull public String ID() { return c.getClass().getSimpleName(); } public WidgetPresentation getPresentation(@NotNull PlatformType type) { return null; } public void install(@NotNull StatusBar statusBar) {} public void dispose() { componentFactory.disposeComponent(myStatusBar, c); } }, "before " + MemoryUsagePanel.WIDGET_ID); } } myStatusBar.addWidget(myMemoryWidget); myStatusBar.addWidget( new IdeMessagePanel(MessagePool.getInstance()), "before " + MemoryUsagePanel.WIDGET_ID); setMemoryIndicatorVisible(myUISettings.SHOW_MEMORY_INDICATOR); } void setMemoryIndicatorVisible(final boolean visible) { if (myMemoryWidget != null) { myMemoryWidget.setShowing(visible); if (!SystemInfo.isMac) { myStatusBar.setBorder(BorderFactory.createEmptyBorder(1, 4, 0, visible ? 0 : 2)); } } } @Nullable final StatusBar getStatusBar() { return myStatusBar; } private void updateToolbarVisibility() { myToolbar.setVisible(myUISettings.SHOW_MAIN_TOOLBAR && myWelcomeScreen == null); } private void updateStatusBarVisibility() { myStatusBar.setVisible(myUISettings.SHOW_STATUS_BAR); } public void installNorthComponents(final Project project) { ContainerUtil.addAll( myNorthComponents, Extensions.getExtensions(IdeRootPaneNorthExtension.EP_NAME, project)); for (IdeRootPaneNorthExtension northComponent : myNorthComponents) { myNorthPanel.add(northComponent.getComponent()); northComponent.uiSettingsChanged(myUISettings); } } public void deinstallNorthComponents() { for (IdeRootPaneNorthExtension northComponent : myNorthComponents) { myNorthPanel.remove(northComponent.getComponent()); Disposer.dispose(northComponent); } myNorthComponents.clear(); } public IdeRootPaneNorthExtension findByName(String name) { for (IdeRootPaneNorthExtension northComponent : myNorthComponents) { if (Comparing.strEqual(name, northComponent.getKey())) { return northComponent; } } return null; } public void uiSettingsChanged(UISettings source) { setMemoryIndicatorVisible(source.SHOW_MEMORY_INDICATOR); } private final class MyUISettingsListenerImpl implements UISettingsListener { public final void uiSettingsChanged(final UISettings source) { updateToolbarVisibility(); updateStatusBarVisibility(); for (IdeRootPaneNorthExtension component : myNorthComponents) { component.uiSettingsChanged(source); } } } public boolean isOptimizedDrawingEnabled() { return !myGlassPane.hasPainters() && myGlassPane.getComponentCount() == 0; } }
public ApplicationImpl( boolean isInternal, boolean isUnitTestMode, boolean isHeadless, boolean isCommandLine, @NotNull String appName) { super(null); getPicoContainer().registerComponentInstance(Application.class, this); CommonBundle.assertKeyIsFound = isUnitTestMode; if ((isInternal || isUnitTestMode) && !Comparing.equal("off", System.getProperty("idea.disposer.debug"))) { Disposer.setDebugMode(true); } myStartTime = System.currentTimeMillis(); myName = appName; ApplicationManagerEx.setApplication(this); PluginsFacade.INSTANCE = new PluginsFacade() { public IdeaPluginDescriptor getPlugin(PluginId id) { return PluginManager.getPlugin(id); } public IdeaPluginDescriptor[] getPlugins() { return PluginManager.getPlugins(); } }; if (!isUnitTestMode && !isHeadless) { Toolkit.getDefaultToolkit().getSystemEventQueue().push(IdeEventQueue.getInstance()); if (Patches.SUN_BUG_ID_6209673) { RepaintManager.setCurrentManager(new IdeRepaintManager()); } IconLoader.activate(); } myIsInternal = isInternal; myTestModeFlag = isUnitTestMode; myHeadlessMode = isHeadless; myCommandLineMode = isCommandLine; loadApplicationComponents(); if (myTestModeFlag) { registerShutdownHook(); } if (!isUnitTestMode && !isHeadless) { Disposer.register(this, Disposer.newDisposable(), "ui"); StartupUtil.addExternalInstanceListener( new Consumer<List<String>>() { @Override public void consume(final List<String> args) { invokeLater( new Runnable() { @Override public void run() { final Project project = CommandLineProcessor.processExternalCommandLine(args); final IdeFrame frame; if (project != null) { frame = WindowManager.getInstance().getIdeFrame(project); } else { frame = WindowManager.getInstance().getAllFrames()[0]; } ((IdeFrameImpl) frame).requestFocus(); } }); } }); } final String s = System.getProperty("jb.restart.code"); if (s != null) { try { myRestartCode = Integer.parseInt(s); } catch (NumberFormatException ignore) { } } }
/** @author dsl */ public class LibraryImpl extends TraceableDisposable implements LibraryEx.ModifiableModelEx, LibraryEx { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.roots.impl.impl.LibraryImpl"); @NonNls public static final String LIBRARY_NAME_ATTR = "name"; @NonNls public static final String LIBRARY_TYPE_ATTR = "type"; @NonNls public static final String ROOT_PATH_ELEMENT = "root"; @NonNls public static final String ELEMENT = "library"; @NonNls public static final String PROPERTIES_ELEMENT = "properties"; private static final SkipDefaultValuesSerializationFilters SERIALIZATION_FILTERS = new SkipDefaultValuesSerializationFilters(); private String myName; private final LibraryTable myLibraryTable; private final Map<OrderRootType, VirtualFilePointerContainer> myRoots; private final JarDirectories myJarDirectories = new JarDirectories(); private final LibraryImpl mySource; private PersistentLibraryKind<?> myKind; private LibraryProperties myProperties; private final MyRootProviderImpl myRootProvider = new MyRootProviderImpl(); private final ModifiableRootModel myRootModel; private boolean myDisposed; private final Disposable myPointersDisposable = Disposer.newDisposable(); private final JarDirectoryWatcher myRootsWatcher = JarDirectoryWatcherFactory.getInstance().createWatcher(myJarDirectories, myRootProvider); LibraryImpl(LibraryTable table, Element element, ModifiableRootModel rootModel) throws InvalidDataException { this( table, rootModel, null, element.getAttributeValue(LIBRARY_NAME_ATTR), (PersistentLibraryKind<?>) LibraryKind.findById(element.getAttributeValue(LIBRARY_TYPE_ATTR))); readProperties(element); myJarDirectories.readExternal(element); readRoots(element); myRootsWatcher.updateWatchedRoots(); } LibraryImpl( String name, @Nullable final PersistentLibraryKind<?> kind, LibraryTable table, ModifiableRootModel rootModel) { this(table, rootModel, null, name, kind); if (kind != null) { myProperties = kind.createDefaultProperties(); } } private LibraryImpl( @NotNull LibraryImpl from, LibraryImpl newSource, ModifiableRootModel rootModel) { this(from.myLibraryTable, rootModel, newSource, from.myName, from.myKind); assert !from.isDisposed(); if (from.myKind != null && from.myProperties != null) { myProperties = myKind.createDefaultProperties(); //noinspection unchecked myProperties.loadState(from.myProperties.getState()); } for (OrderRootType rootType : getAllRootTypes()) { final VirtualFilePointerContainer thisContainer = myRoots.get(rootType); final VirtualFilePointerContainer thatContainer = from.myRoots.get(rootType); thisContainer.addAll(thatContainer); } myJarDirectories.copyFrom(from.myJarDirectories); } // primary private LibraryImpl( LibraryTable table, ModifiableRootModel rootModel, LibraryImpl newSource, String name, @Nullable final PersistentLibraryKind<?> kind) { super(new Throwable()); myLibraryTable = table; myRootModel = rootModel; mySource = newSource; myKind = kind; myName = name; // init roots depends on my myKind myRoots = initRoots(); Disposer.register(this, myRootsWatcher); } private Set<OrderRootType> getAllRootTypes() { Set<OrderRootType> rootTypes = new HashSet<OrderRootType>(); rootTypes.addAll(Arrays.asList(OrderRootType.getAllTypes())); if (myKind != null) { rootTypes.addAll(Arrays.asList(myKind.getAdditionalRootTypes())); } return rootTypes; } @Override public void dispose() { if (isDisposed()) { throwDisposalError("Already disposed:"); } myDisposed = true; kill(null); } @Override public boolean isDisposed() { return myDisposed; } @Override public String getName() { return myName; } @Override @NotNull public String[] getUrls(@NotNull OrderRootType rootType) { assert !isDisposed(); final VirtualFilePointerContainer result = myRoots.get(rootType); return result.getUrls(); } @Override @NotNull public VirtualFile[] getFiles(@NotNull OrderRootType rootType) { assert !isDisposed(); final List<VirtualFile> expanded = new ArrayList<VirtualFile>(); for (VirtualFile file : myRoots.get(rootType).getFiles()) { if (file.isDirectory()) { if (myJarDirectories.contains(rootType, file.getUrl())) { collectJarFiles(file, expanded, myJarDirectories.isRecursive(rootType, file.getUrl())); continue; } } expanded.add(file); } return VfsUtilCore.toVirtualFileArray(expanded); } public static void collectJarFiles( final VirtualFile dir, final List<VirtualFile> container, final boolean recursively) { VfsUtilCore.visitChildrenRecursively( dir, new VirtualFileVisitor(SKIP_ROOT, (recursively ? null : ONE_LEVEL_DEEP)) { @Override public boolean visitFile(@NotNull VirtualFile file) { final VirtualFile jarRoot = StandardFileSystems.getJarRootForLocalFile(file); if (jarRoot != null) { container.add(jarRoot); return false; } return true; } }); } @Override public void setName(String name) { LOG.assertTrue(isWritable()); myName = name; } /* you have to commit modifiable model or dispose it by yourself! */ @Override @NotNull public ModifiableModel getModifiableModel() { assert !isDisposed(); return new LibraryImpl(this, this, myRootModel); } @Override public Library cloneLibrary(RootModelImpl rootModel) { LOG.assertTrue(myLibraryTable == null); final LibraryImpl clone = new LibraryImpl(this, null, rootModel); clone.myRootsWatcher.updateWatchedRoots(); return clone; } @Override public List<String> getInvalidRootUrls(OrderRootType type) { if (myDisposed) return Collections.emptyList(); final List<VirtualFilePointer> pointers = myRoots.get(type).getList(); List<String> invalidPaths = null; for (VirtualFilePointer pointer : pointers) { if (!pointer.isValid()) { if (invalidPaths == null) { invalidPaths = new SmartList<String>(); } invalidPaths.add(pointer.getUrl()); } } return invalidPaths == null ? Collections.<String>emptyList() : invalidPaths; } @Override public void setProperties(LibraryProperties properties) { LOG.assertTrue(isWritable()); myProperties = properties; } @Override @NotNull public RootProvider getRootProvider() { return myRootProvider; } private Map<OrderRootType, VirtualFilePointerContainer> initRoots() { Disposer.register(this, myPointersDisposable); Map<OrderRootType, VirtualFilePointerContainer> result = new HashMap<OrderRootType, VirtualFilePointerContainer>(4); for (OrderRootType rootType : getAllRootTypes()) { result.put( rootType, VirtualFilePointerManager.getInstance().createContainer(myPointersDisposable)); } return result; } @Override public void readExternal(Element element) throws InvalidDataException { readName(element); readProperties(element); readRoots(element); myJarDirectories.readExternal(element); myRootsWatcher.updateWatchedRoots(); } private void readProperties(Element element) { final String typeId = element.getAttributeValue(LIBRARY_TYPE_ATTR); if (typeId == null) return; myKind = (PersistentLibraryKind<?>) LibraryKind.findById(typeId); if (myKind == null) return; myProperties = myKind.createDefaultProperties(); final Element propertiesElement = element.getChild(PROPERTIES_ELEMENT); if (propertiesElement != null) { ComponentSerializationUtil.loadComponentState(myProperties, propertiesElement); } } private void readName(Element element) { myName = element.getAttributeValue(LIBRARY_NAME_ATTR); } private void readRoots(Element element) throws InvalidDataException { for (OrderRootType rootType : getAllRootTypes()) { final Element rootChild = element.getChild(rootType.name()); if (rootChild == null) { continue; } VirtualFilePointerContainer roots = myRoots.get(rootType); roots.readExternal(rootChild, ROOT_PATH_ELEMENT); } } // TODO<rv> Remove the next two methods as a temporary solution. Sort in OrderRootType. // public static List<OrderRootType> sortRootTypes(Collection<OrderRootType> rootTypes) { List<OrderRootType> allTypes = new ArrayList<OrderRootType>(rootTypes); Collections.sort( allTypes, new Comparator<OrderRootType>() { @Override public int compare(final OrderRootType o1, final OrderRootType o2) { return getSortKey(o1).compareTo(getSortKey(o2)); } }); return allTypes; } private static String getSortKey(OrderRootType orderRootType) { if (orderRootType instanceof PersistentOrderRootType) { return ((PersistentOrderRootType) orderRootType).getSdkRootName(); } if (orderRootType instanceof OrderRootType.DocumentationRootType) { return ((OrderRootType.DocumentationRootType) orderRootType).getSdkRootName(); } return ""; } @Override public void writeExternal(Element rootElement) throws WriteExternalException { LOG.assertTrue(!isDisposed(), "Already disposed!"); Element element = new Element(ELEMENT); if (myName != null) { element.setAttribute(LIBRARY_NAME_ATTR, myName); } if (myKind != null) { element.setAttribute(LIBRARY_TYPE_ATTR, myKind.getKindId()); final Object state = myProperties.getState(); if (state != null) { final Element propertiesElement = XmlSerializer.serialize(state, SERIALIZATION_FILTERS); if (propertiesElement != null && (!propertiesElement.getContent().isEmpty() || !propertiesElement.getAttributes().isEmpty())) { element.addContent(propertiesElement.setName(PROPERTIES_ELEMENT)); } } } ArrayList<OrderRootType> storableRootTypes = new ArrayList<OrderRootType>(); storableRootTypes.addAll(Arrays.asList(OrderRootType.getAllTypes())); if (myKind != null) { storableRootTypes.addAll(Arrays.asList(myKind.getAdditionalRootTypes())); } for (OrderRootType rootType : sortRootTypes(storableRootTypes)) { final VirtualFilePointerContainer roots = myRoots.get(rootType); if (roots.size() == 0 && rootType.skipWriteIfEmpty()) continue; // compatibility iml/ipr final Element rootTypeElement = new Element(rootType.name()); roots.writeExternal(rootTypeElement, ROOT_PATH_ELEMENT); element.addContent(rootTypeElement); } myJarDirectories.writeExternal(element); rootElement.addContent(element); } private boolean isWritable() { return mySource != null; } @Nullable @Override public PersistentLibraryKind<?> getKind() { return myKind; } @Override public LibraryProperties getProperties() { return myProperties; } @Override public void setKind(PersistentLibraryKind<?> kind) { LOG.assertTrue(isWritable()); LOG.assertTrue( myKind == null || myKind == kind, "Library kind cannot be changed from " + myKind + " to " + kind); myKind = kind; } @Override public void addRoot(@NotNull String url, @NotNull OrderRootType rootType) { LOG.assertTrue(isWritable()); assert !isDisposed(); final VirtualFilePointerContainer container = myRoots.get(rootType); container.add(url); } @Override public void addRoot(@NotNull VirtualFile file, @NotNull OrderRootType rootType) { LOG.assertTrue(isWritable()); assert !isDisposed(); final VirtualFilePointerContainer container = myRoots.get(rootType); container.add(file); } @Override public void addJarDirectory(@NotNull final String url, final boolean recursive) { addJarDirectory(url, recursive, JarDirectories.DEFAULT_JAR_DIRECTORY_TYPE); } @Override public void addJarDirectory(@NotNull final VirtualFile file, final boolean recursive) { addJarDirectory(file, recursive, JarDirectories.DEFAULT_JAR_DIRECTORY_TYPE); } @Override public void addJarDirectory( @NotNull final String url, final boolean recursive, @NotNull OrderRootType rootType) { assert !isDisposed(); LOG.assertTrue(isWritable()); final VirtualFilePointerContainer container = myRoots.get(rootType); container.add(url); myJarDirectories.add(rootType, url, recursive); } @Override public void addJarDirectory( @NotNull final VirtualFile file, final boolean recursive, @NotNull OrderRootType rootType) { assert !isDisposed(); LOG.assertTrue(isWritable()); final VirtualFilePointerContainer container = myRoots.get(rootType); container.add(file); myJarDirectories.add(rootType, file.getUrl(), recursive); } @Override public boolean isJarDirectory(@NotNull final String url) { return isJarDirectory(url, JarDirectories.DEFAULT_JAR_DIRECTORY_TYPE); } @Override public boolean isJarDirectory(@NotNull final String url, @NotNull final OrderRootType rootType) { return myJarDirectories.contains(rootType, url); } @Override public boolean isValid(@NotNull final String url, @NotNull final OrderRootType rootType) { final VirtualFilePointerContainer container = myRoots.get(rootType); final VirtualFilePointer fp = container.findByUrl(url); return fp != null && fp.isValid(); } @Override public boolean removeRoot(@NotNull String url, @NotNull OrderRootType rootType) { assert !isDisposed(); LOG.assertTrue(isWritable()); final VirtualFilePointerContainer container = myRoots.get(rootType); final VirtualFilePointer byUrl = container.findByUrl(url); if (byUrl != null) { container.remove(byUrl); myJarDirectories.remove(rootType, url); return true; } return false; } @Override public void moveRootUp(@NotNull String url, @NotNull OrderRootType rootType) { assert !isDisposed(); LOG.assertTrue(isWritable()); final VirtualFilePointerContainer container = myRoots.get(rootType); container.moveUp(url); } @Override public void moveRootDown(@NotNull String url, @NotNull OrderRootType rootType) { assert !isDisposed(); LOG.assertTrue(isWritable()); final VirtualFilePointerContainer container = myRoots.get(rootType); container.moveDown(url); } @Override public boolean isChanged() { return !mySource.equals(this); } private boolean areRootsChanged(final LibraryImpl that) { return !that.equals(this); // final OrderRootType[] allTypes = OrderRootType.getAllTypes(); // for (OrderRootType type : allTypes) { // final String[] urls = getUrls(type); // final String[] thatUrls = that.getUrls(type); // if (urls.length != thatUrls.length) { // return true; // } // for (int idx = 0; idx < urls.length; idx++) { // final String url = urls[idx]; // final String thatUrl = thatUrls[idx]; // if (!Comparing.equal(url, thatUrl)) { // return true; // } // final Boolean jarDirRecursive = myJarDirectories.get(url); // final Boolean sourceJarDirRecursive = that.myJarDirectories.get(thatUrl); // if (jarDirRecursive == null ? sourceJarDirRecursive != null : // !jarDirRecursive.equals(sourceJarDirRecursive)) { // return true; // } // } // } // return false; } public Library getSource() { return mySource; } @Override public void commit() { assert !isDisposed(); mySource.commit(this); Disposer.dispose(this); } private void commit(@NotNull LibraryImpl fromModel) { if (myLibraryTable != null) { ApplicationManager.getApplication().assertWriteAccessAllowed(); } if (!Comparing.equal(fromModel.myName, myName)) { myName = fromModel.myName; if (myLibraryTable instanceof LibraryTableBase) { ((LibraryTableBase) myLibraryTable).fireLibraryRenamed(this); } } myKind = fromModel.getKind(); myProperties = fromModel.myProperties; if (areRootsChanged(fromModel)) { disposeMyPointers(); copyRootsFrom(fromModel); myJarDirectories.copyFrom(fromModel.myJarDirectories); myRootsWatcher.updateWatchedRoots(); myRootProvider.fireRootSetChanged(); } } private void copyRootsFrom(LibraryImpl fromModel) { myRoots.clear(); for (Map.Entry<OrderRootType, VirtualFilePointerContainer> entry : fromModel.myRoots.entrySet()) { OrderRootType rootType = entry.getKey(); VirtualFilePointerContainer container = entry.getValue(); VirtualFilePointerContainer clone = container.clone(myPointersDisposable); myRoots.put(rootType, clone); } } private void disposeMyPointers() { for (VirtualFilePointerContainer container : new THashSet<VirtualFilePointerContainer>(myRoots.values())) { container.killAll(); } Disposer.dispose(myPointersDisposable); Disposer.register(this, myPointersDisposable); } private class MyRootProviderImpl extends RootProviderBaseImpl { @Override @NotNull public String[] getUrls(@NotNull OrderRootType rootType) { Set<String> originalUrls = new LinkedHashSet<String>(Arrays.asList(LibraryImpl.this.getUrls(rootType))); for (VirtualFile file : getFiles(rootType)) { // Add those expanded with jar directories. originalUrls.add(file.getUrl()); } return ArrayUtil.toStringArray(originalUrls); } @Override @NotNull public VirtualFile[] getFiles(@NotNull final OrderRootType rootType) { return LibraryImpl.this.getFiles(rootType); } } @Override public LibraryTable getTable() { return myLibraryTable; } public boolean equals(final Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; final LibraryImpl library = (LibraryImpl) o; if (!myJarDirectories.equals(library.myJarDirectories)) return false; if (myName != null ? !myName.equals(library.myName) : library.myName != null) return false; if (myRoots != null ? !myRoots.equals(library.myRoots) : library.myRoots != null) return false; if (myKind != null ? !myKind.equals(library.myKind) : library.myKind != null) return false; if (myProperties != null ? !myProperties.equals(library.myProperties) : library.myProperties != null) return false; return true; } public int hashCode() { int result = myName != null ? myName.hashCode() : 0; result = 31 * result + (myRoots != null ? myRoots.hashCode() : 0); result = 31 * result + (myJarDirectories != null ? myJarDirectories.hashCode() : 0); return result; } @NonNls @Override public String toString() { return "Library: name:" + myName + "; jars:" + myJarDirectories + "; roots:" + myRoots.values(); } @Nullable("will return non-null value only for module level libraries") public Module getModule() { return myRootModel == null ? null : myRootModel.getModule(); } }
public class JBOptionButton extends JButton implements MouseMotionListener, Weighted { private final Insets myDownIconInsets = JBUI.insets(0, 6, 0, 4); private Rectangle myMoreRec; private Rectangle myMoreRecMouse; private Action[] myOptions; private JPopupMenu myUnderPopup; private JPopupMenu myAbovePopup; private boolean myPopupIsShowing; private String myOptionTooltipText; private Set<OptionInfo> myOptionInfos = new HashSet<OptionInfo>(); private boolean myOkToProcessDefaultMnemonics = true; private IdeGlassPane myGlassPane; private final Disposable myDisposable = Disposer.newDisposable(); public JBOptionButton(Action action, Action[] options) { super(action); myOptions = options; myMoreRec = new Rectangle( 0, 0, AllIcons.General.ArrowDown.getIconWidth(), AllIcons.General.ArrowDown.getIconHeight()); myUnderPopup = fillMenu(true); myAbovePopup = fillMenu(false); enableEvents(AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK); } @Override public void addNotify() { super.addNotify(); if (!ScreenUtil.isStandardAddRemoveNotify(this)) return; myGlassPane = IdeGlassPaneUtil.find(this); if (myGlassPane != null) { myGlassPane.addMouseMotionPreprocessor(this, myDisposable); } } @Override public void removeNotify() { super.removeNotify(); if (!ScreenUtil.isStandardAddRemoveNotify(this)) return; Disposer.dispose(myDisposable); } @Override public double getWeight() { return 0.5; } @Override public void mouseDragged(MouseEvent e) {} @Override public void mouseMoved(MouseEvent e) { final MouseEvent event = SwingUtilities.convertMouseEvent(e.getComponent(), e, getParent()); final boolean insideRec = getBounds().contains(event.getPoint()); boolean buttonsNotPressed = (e.getModifiersEx() & (InputEvent.BUTTON1_DOWN_MASK | InputEvent.BUTTON2_DOWN_MASK | InputEvent.BUTTON3_DOWN_MASK)) == 0; if (!myPopupIsShowing && insideRec && buttonsNotPressed) { showPopup(null, false); } else if (myPopupIsShowing && !insideRec) { final Component over = SwingUtilities.getDeepestComponentAt(e.getComponent(), e.getX(), e.getY()); JPopupMenu popup = myUnderPopup.isShowing() ? myUnderPopup : myAbovePopup; if (over != null && popup.isShowing()) { final Rectangle rec = new Rectangle(popup.getLocationOnScreen(), popup.getSize()); int delta = 15; rec.x -= delta; rec.width += delta * 2; rec.y -= delta; rec.height += delta * 2; final Point eventPoint = e.getPoint(); SwingUtilities.convertPointToScreen(eventPoint, e.getComponent()); if (rec.contains(eventPoint)) { return; } } closePopup(); } } @Override public Dimension getPreferredSize() { final Dimension size = super.getPreferredSize(); size.width += (myMoreRec.width + myDownIconInsets.left + myDownIconInsets.right); size.height += (myDownIconInsets.top + myDownIconInsets.bottom); return size; } @Override public void doLayout() { super.doLayout(); Insets insets = getInsets(); myMoreRec.x = getSize().width - myMoreRec.width - insets.right + 8; myMoreRec.y = (getHeight() / 2 - myMoreRec.height / 2); myMoreRecMouse = new Rectangle(myMoreRec.x - 8, 0, getWidth() - myMoreRec.x, getHeight()); } @Override public String getToolTipText(MouseEvent event) { if (myMoreRec.x < event.getX()) { return myOptionTooltipText; } else { return super.getToolTipText(event); } } @Override protected void processMouseEvent(MouseEvent e) { if (myMoreRecMouse.contains(e.getPoint())) { if (e.getID() == MouseEvent.MOUSE_PRESSED) { if (!myPopupIsShowing) { togglePopup(); } } } else { super.processMouseEvent(e); } } public void togglePopup() { if (myPopupIsShowing) { closePopup(); } else { showPopup(null, false); } } public void showPopup(final Action actionToSelect, final boolean ensureSelection) { if (myPopupIsShowing) return; myPopupIsShowing = true; final Point loc = getLocationOnScreen(); final Rectangle screen = ScreenUtil.getScreenRectangle(loc); final Dimension popupSize = myUnderPopup.getPreferredSize(); final Rectangle intersection = screen.intersection(new Rectangle(new Point(loc.x, loc.y + getHeight()), popupSize)); final boolean above = intersection.height < popupSize.height; int y = above ? getY() - popupSize.height : getY() + getHeight(); final JPopupMenu popup = above ? myAbovePopup : myUnderPopup; final Ref<PopupMenuListener> listener = new Ref<PopupMenuListener>(); listener.set( new PopupMenuListener() { @Override public void popupMenuWillBecomeVisible(PopupMenuEvent e) {} @Override public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { if (popup != null && listener.get() != null) { popup.removePopupMenuListener(listener.get()); } SwingUtilities.invokeLater( new Runnable() { @Override public void run() { myPopupIsShowing = false; } }); } @Override public void popupMenuCanceled(PopupMenuEvent e) {} }); popup.addPopupMenuListener(listener.get()); popup.show(this, 0, y); SwingUtilities.invokeLater( new Runnable() { @Override public void run() { if (popup == null || !popup.isShowing() || !myPopupIsShowing) return; Action selection = actionToSelect; if (selection == null && myOptions.length > 0 && ensureSelection) { selection = getAction(); } if (selection == null) return; final MenuElement[] elements = popup.getSubElements(); for (MenuElement eachElement : elements) { if (eachElement instanceof JMenuItem) { JMenuItem eachItem = (JMenuItem) eachElement; if (selection.equals(eachItem.getAction())) { final MenuSelectionManager mgr = MenuSelectionManager.defaultManager(); final MenuElement[] path = new MenuElement[2]; path[0] = popup; path[1] = eachItem; mgr.setSelectedPath(path); break; } } } } }); } public void closePopup() { myUnderPopup.setVisible(false); myAbovePopup.setVisible(false); } private JPopupMenu fillMenu(boolean under) { final JPopupMenu result = new JBPopupMenu(); if (under && myOptions.length > 0) { final JMenuItem mainAction = new JBMenuItem(getAction()); configureItem(getMenuInfo(getAction()), mainAction); result.add(mainAction); result.addSeparator(); } for (Action each : myOptions) { if (getAction() == each) continue; final OptionInfo info = getMenuInfo(each); final JMenuItem eachItem = new JBMenuItem(each); configureItem(info, eachItem); result.add(eachItem); } if (!under && myOptions.length > 0) { result.addSeparator(); final JMenuItem mainAction = new JBMenuItem(getAction()); configureItem(getMenuInfo(getAction()), mainAction); result.add(mainAction); } return result; } private void configureItem(OptionInfo info, JMenuItem eachItem) { eachItem.setText(info.myPlainText); if (info.myMnemonic >= 0) { eachItem.setMnemonic(info.myMnemonic); eachItem.setDisplayedMnemonicIndex(info.myMnemonicIndex); } myOptionInfos.add(info); } public boolean isOkToProcessDefaultMnemonics() { return myOkToProcessDefaultMnemonics; } public static class OptionInfo { String myPlainText; int myMnemonic; int myMnemonicIndex; JBOptionButton myButton; Action myAction; OptionInfo( String plainText, int mnemonic, int mnemonicIndex, JBOptionButton button, Action action) { myPlainText = plainText; myMnemonic = mnemonic; myMnemonicIndex = mnemonicIndex; myButton = button; myAction = action; } public String getPlainText() { return myPlainText; } public int getMnemonic() { return myMnemonic; } public int getMnemonicIndex() { return myMnemonicIndex; } public JBOptionButton getButton() { return myButton; } public Action getAction() { return myAction; } } private OptionInfo getMenuInfo(Action each) { final String text = (String) each.getValue(Action.NAME); int mnemonic = -1; int mnemonicIndex = -1; StringBuilder plainText = new StringBuilder(); for (int i = 0; i < text.length(); i++) { char ch = text.charAt(i); if (ch == '&' || ch == '_') { if (i + 1 < text.length()) { final char mnemonicsChar = text.charAt(i + 1); mnemonic = Character.toUpperCase(mnemonicsChar); mnemonicIndex = i; } continue; } plainText.append(ch); } return new OptionInfo(plainText.toString(), mnemonic, mnemonicIndex, this, each); } public Set<OptionInfo> getOptionInfos() { return myOptionInfos; } @Override protected void paintChildren(Graphics g) { super.paintChildren(g); boolean dark = UIUtil.isUnderDarcula(); int off = dark ? 6 : 0; AllIcons.General.ArrowDown.paintIcon(this, g, myMoreRec.x - off, myMoreRec.y); if (dark) return; final Insets insets = getInsets(); int y1 = myMoreRec.y - 2; int y2 = getHeight() - insets.bottom - 2; if (y1 < getInsets().top) { y1 = insets.top; } final int x = myMoreRec.x - 4; UIUtil.drawDottedLine(((Graphics2D) g), x, y1, x, y2, null, Color.darkGray); } public void setOptionTooltipText(String text) { myOptionTooltipText = text; } public void setOkToProcessDefaultMnemonics(boolean ok) { myOkToProcessDefaultMnemonics = ok; } }
@Override public boolean executeTask( final DataContext dataContext, RunConfiguration configuration, final ExecutionEnvironment env, RunConfigurableBeforeRunTask task) { RunnerAndConfigurationSettings settings = task.getSettings(); if (settings == null) { return false; } final Executor executor = DefaultRunExecutor.getRunExecutorInstance(); final String executorId = executor.getId(); ExecutionEnvironmentBuilder builder = ExecutionEnvironmentBuilder.createOrNull(executor, settings); if (builder == null) { return false; } final ExecutionEnvironment environment = builder.build(); environment.setExecutionId(env.getExecutionId()); if (!ExecutionTargetManager.canRun(settings, env.getExecutionTarget())) { return false; } if (!environment.getRunner().canRun(executorId, environment.getRunProfile())) { return false; } else { final Semaphore targetDone = new Semaphore(); final Ref<Boolean> result = new Ref<Boolean>(false); final Disposable disposable = Disposer.newDisposable(); myProject .getMessageBus() .connect(disposable) .subscribe( ExecutionManager.EXECUTION_TOPIC, new ExecutionAdapter() { @Override public void processStartScheduled( final String executorIdLocal, final ExecutionEnvironment environmentLocal) { if (executorId.equals(executorIdLocal) && environment.equals(environmentLocal)) { targetDone.down(); } } @Override public void processNotStarted( final String executorIdLocal, @NotNull final ExecutionEnvironment environmentLocal) { if (executorId.equals(executorIdLocal) && environment.equals(environmentLocal)) { targetDone.up(); } } @Override public void processStarted( final String executorIdLocal, @NotNull final ExecutionEnvironment environmentLocal, @NotNull final ProcessHandler handler) { if (executorId.equals(executorIdLocal) && environment.equals(environmentLocal)) { handler.addProcessListener( new ProcessAdapter() { @Override public void processTerminated(ProcessEvent event) { result.set(event.getExitCode() == 0); targetDone.up(); } }); } } }); try { ApplicationManager.getApplication() .invokeAndWait( new Runnable() { @Override public void run() { try { environment.getRunner().execute(environment); } catch (ExecutionException e) { targetDone.up(); LOG.error(e); } } }, ModalityState.NON_MODAL); } catch (Exception e) { LOG.error(e); Disposer.dispose(disposable); return false; } targetDone.waitFor(); Disposer.dispose(disposable); return result.get(); } }