IDEA-147099 ICSE at com.intellij.openapi.wm.impl.ToolWindowManagerImpl$RemoveWindowed...
[idea/community.git] / platform / platform-impl / src / com / intellij / openapi / wm / impl / ToolWindowManagerImpl.java
1 /*
2  * Copyright 2000-2015 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.openapi.wm.impl;
17
18 import com.intellij.ide.FrameStateManager;
19 import com.intellij.ide.IdeEventQueue;
20 import com.intellij.ide.actions.ActivateToolWindowAction;
21 import com.intellij.ide.ui.LafManager;
22 import com.intellij.ide.ui.LafManagerListener;
23 import com.intellij.internal.statistic.UsageTrigger;
24 import com.intellij.openapi.Disposable;
25 import com.intellij.openapi.actionSystem.*;
26 import com.intellij.openapi.actionSystem.ex.AnActionListener;
27 import com.intellij.openapi.application.ApplicationManager;
28 import com.intellij.openapi.application.ModalityState;
29 import com.intellij.openapi.components.ProjectComponent;
30 import com.intellij.openapi.diagnostic.Logger;
31 import com.intellij.openapi.editor.impl.EditorComponentImpl;
32 import com.intellij.openapi.extensions.Extensions;
33 import com.intellij.openapi.fileEditor.FileEditorManager;
34 import com.intellij.openapi.fileEditor.FileEditorManagerEvent;
35 import com.intellij.openapi.fileEditor.FileEditorManagerListener;
36 import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx;
37 import com.intellij.openapi.fileEditor.impl.EditorsSplitters;
38 import com.intellij.openapi.keymap.Keymap;
39 import com.intellij.openapi.keymap.KeymapManager;
40 import com.intellij.openapi.progress.ProcessCanceledException;
41 import com.intellij.openapi.progress.ProgressIndicator;
42 import com.intellij.openapi.progress.util.ProgressIndicatorUtils;
43 import com.intellij.openapi.progress.util.ReadTask;
44 import com.intellij.openapi.project.DumbAwareRunnable;
45 import com.intellij.openapi.project.DumbService;
46 import com.intellij.openapi.project.Project;
47 import com.intellij.openapi.startup.StartupManager;
48 import com.intellij.openapi.ui.DialogWrapper;
49 import com.intellij.openapi.ui.MessageType;
50 import com.intellij.openapi.ui.Splitter;
51 import com.intellij.openapi.ui.popup.Balloon;
52 import com.intellij.openapi.ui.popup.JBPopupFactory;
53 import com.intellij.openapi.util.*;
54 import com.intellij.openapi.util.registry.Registry;
55 import com.intellij.openapi.vfs.VirtualFile;
56 import com.intellij.openapi.wm.*;
57 import com.intellij.openapi.wm.ex.*;
58 import com.intellij.openapi.wm.impl.commands.*;
59 import com.intellij.ui.BalloonImpl;
60 import com.intellij.ui.ColorUtil;
61 import com.intellij.ui.awt.RelativePoint;
62 import com.intellij.ui.switcher.QuickAccessSettings;
63 import com.intellij.ui.switcher.SwitchManager;
64 import com.intellij.util.*;
65 import com.intellij.util.containers.ContainerUtil;
66 import com.intellij.util.containers.HashMap;
67 import com.intellij.util.ui.PositionTracker;
68 import com.intellij.util.ui.UIUtil;
69 import com.intellij.util.ui.update.UiNotifyConnector;
70 import org.jdom.Element;
71 import org.jetbrains.annotations.NonNls;
72 import org.jetbrains.annotations.NotNull;
73 import org.jetbrains.annotations.Nullable;
74
75 import javax.swing.*;
76 import javax.swing.event.HyperlinkEvent;
77 import javax.swing.event.HyperlinkListener;
78 import java.awt.*;
79 import java.awt.event.FocusEvent;
80 import java.awt.event.InputEvent;
81 import java.awt.event.KeyEvent;
82 import java.awt.event.WindowEvent;
83 import java.beans.PropertyChangeEvent;
84 import java.beans.PropertyChangeListener;
85 import java.util.*;
86 import java.util.List;
87
88 import static com.intellij.openapi.wm.impl.FloatingDecorator.DIVIDER_WIDTH;
89
90 /**
91  * @author Anton Katilin
92  * @author Vladimir Kondratyev
93  */
94 public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements ProjectComponent, JDOMExternalizable {
95   private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.wm.impl.ToolWindowManagerImpl");
96
97   private final Project myProject;
98   private final WindowManagerEx myWindowManager;
99   private final EventDispatcher<ToolWindowManagerListener> myDispatcher = EventDispatcher.create(ToolWindowManagerListener.class);
100   private final DesktopLayout myLayout;
101   private final Map<String, InternalDecorator> myId2InternalDecorator;
102   private final Map<String, FloatingDecorator> myId2FloatingDecorator;
103   private final Map<String, WindowedDecorator> myId2WindowedDecorator;
104   private final Map<String, StripeButton> myId2StripeButton;
105   private final Map<String, FocusWatcher> myId2FocusWatcher;
106   private final Set<String> myDumbAwareIds = Collections.synchronizedSet(ContainerUtil.<String>newTroveSet());
107
108   private final EditorComponentFocusWatcher myEditorComponentFocusWatcher;
109   private final MyToolWindowPropertyChangeListener myToolWindowPropertyChangeListener;
110   private final InternalDecoratorListener myInternalDecoratorListener;
111
112   private boolean myEditorWasActive;
113
114   private final ActiveStack myActiveStack;
115   private final SideStack mySideStack;
116
117   private ToolWindowsPane myToolWindowsPane;
118   private IdeFrameImpl myFrame;
119   private DesktopLayout myLayoutToRestoreLater = null;
120   @NonNls private static final String EDITOR_ELEMENT = "editor";
121   @NonNls private static final String ACTIVE_ATTR_VALUE = "active";
122   @NonNls private static final String FRAME_ELEMENT = "frame";
123   @NonNls private static final String X_ATTR = "x";
124   @NonNls private static final String Y_ATTR = "y";
125   @NonNls private static final String WIDTH_ATTR = "width";
126   @NonNls private static final String HEIGHT_ATTR = "height";
127   @NonNls private static final String EXTENDED_STATE_ATTR = "extended-state";
128   @NonNls private static final String LAYOUT_TO_RESTORE = "layout-to-restore";
129
130   private final FileEditorManager myFileEditorManager;
131   private final LafManager myLafManager;
132   private final Map<String, Balloon> myWindow2Balloon = new HashMap<String, Balloon>();
133   private Pair<String, Integer> myMaximizedToolwindowSize = null;
134
135   private KeyState myCurrentState = KeyState.waiting;
136   private final Alarm myWaiterForSecondPress = new Alarm();
137   private final Runnable mySecondPressRunnable = new Runnable() {
138     @Override
139     public void run() {
140       if (myCurrentState != KeyState.hold) {
141         resetHoldState();
142       }
143     }
144   };
145   private final PropertyChangeListener myFocusListener;
146
147   public boolean isToolWindowRegistered(String id) {
148     return myLayout.isToolWindowRegistered(id);
149   }
150
151   private enum KeyState {
152     waiting, pressed, released, hold
153   }
154
155   private final Alarm myUpdateHeadersAlarm = new Alarm();
156   private final Runnable myUpdateHeadersRunnable = new Runnable() {
157     @Override
158     public void run() {
159       updateToolWindowHeaders();
160     }
161   };
162
163   /**
164    * invoked by reflection
165    */
166   public ToolWindowManagerImpl(final Project project,
167                                final WindowManagerEx windowManagerEx,
168                                final FileEditorManager fem,
169                                final ActionManager actionManager,
170                                final LafManager lafManager) {
171     myProject = project;
172     myWindowManager = windowManagerEx;
173     myFileEditorManager = fem;
174     myLafManager = lafManager;
175
176     if (!project.isDefault()) {
177       actionManager.addAnActionListener(new AnActionListener() {
178         @Override
179         public void beforeActionPerformed(AnAction action, DataContext dataContext, AnActionEvent event) {
180           if (myCurrentState != KeyState.hold) {
181             resetHoldState();
182           }
183         }
184
185         @Override
186         public void afterActionPerformed(AnAction action, DataContext dataContext, AnActionEvent event) {
187         }
188
189         @Override
190         public void beforeEditorTyping(char c, DataContext dataContext) {
191         }
192       }, project);
193     }
194
195     myLayout = new DesktopLayout();
196     myLayout.copyFrom(windowManagerEx.getLayout());
197
198     myId2InternalDecorator = new HashMap<String, InternalDecorator>();
199     myId2FloatingDecorator = new HashMap<String, FloatingDecorator>();
200     myId2WindowedDecorator = new HashMap<String, WindowedDecorator>();
201     myId2StripeButton = new HashMap<String, StripeButton>();
202     myId2FocusWatcher = new HashMap<String, FocusWatcher>();
203
204     myEditorComponentFocusWatcher = new EditorComponentFocusWatcher();
205     myToolWindowPropertyChangeListener = new MyToolWindowPropertyChangeListener();
206     myInternalDecoratorListener = new MyInternalDecoratorListener();
207
208     myActiveStack = new ActiveStack();
209     mySideStack = new SideStack();
210
211     project.getMessageBus().connect().subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER, new FileEditorManagerListener() {
212       @Override
213       public void fileOpened(@NotNull FileEditorManager source, @NotNull VirtualFile file) {
214       }
215
216       @Override
217       public void fileClosed(@NotNull FileEditorManager source, @NotNull VirtualFile file) {
218         getFocusManagerImpl(myProject).doWhenFocusSettlesDown(new ExpirableRunnable.ForProject(myProject) {
219           @Override
220           public void run() {
221             if (!hasOpenEditorFiles()) {
222               focusToolWinowByDefault(null);
223             }
224           }
225         });
226       }
227
228       @Override
229       public void selectionChanged(@NotNull FileEditorManagerEvent event) {
230       }
231     });
232
233     myFocusListener = new PropertyChangeListener() {
234       @Override
235       public void propertyChange(PropertyChangeEvent evt) {
236         if ("focusOwner".equals(evt.getPropertyName())) {
237           myUpdateHeadersAlarm.cancelAllRequests();
238           myUpdateHeadersAlarm.addRequest(myUpdateHeadersRunnable, 50);
239         }
240       }
241     };
242     KeyboardFocusManager.getCurrentKeyboardFocusManager().addPropertyChangeListener(myFocusListener);
243   }
244
245
246   private void updateToolWindowHeaders() {
247     getFocusManager().doWhenFocusSettlesDown(new ExpirableRunnable.ForProject(myProject) {
248       @Override
249       public void run() {
250         WindowInfoImpl[] infos = myLayout.getInfos();
251         for (WindowInfoImpl each : infos) {
252           if (each.isVisible()) {
253             ToolWindow tw = getToolWindow(each.getId());
254             if (tw instanceof ToolWindowImpl) {
255               InternalDecorator decorator = ((ToolWindowImpl)tw).getDecorator();
256               if (decorator != null) {
257                 decorator.repaint();
258               }
259             }
260           }
261         }
262       }
263     });
264   }
265
266   public boolean dispatchKeyEvent(KeyEvent e) {
267     if (e.getKeyCode() != KeyEvent.VK_CONTROL &&
268         e.getKeyCode() != KeyEvent.VK_ALT &&
269         e.getKeyCode() != KeyEvent.VK_SHIFT &&
270         e.getKeyCode() != KeyEvent.VK_META) {
271       if (e.getModifiers() == 0) {
272         resetHoldState();
273       }
274       return false;
275     }
276     if (e.getID() != KeyEvent.KEY_PRESSED && e.getID() != KeyEvent.KEY_RELEASED) return false;
277
278     Component parent = UIUtil.findUltimateParent(e.getComponent());
279     if (parent instanceof IdeFrame) {
280       if (((IdeFrame)parent).getProject() != myProject) {
281         resetHoldState();
282         return false;
283       }
284     }
285
286     Set<Integer> vks = getActivateToolWindowVKs();
287
288     if (vks.isEmpty()) {
289       resetHoldState();
290       return false;
291     }
292
293     if (vks.contains(e.getKeyCode())) {
294       boolean pressed = e.getID() == KeyEvent.KEY_PRESSED;
295       int modifiers = e.getModifiers();
296
297       int mouseMask = InputEvent.BUTTON1_DOWN_MASK | InputEvent.BUTTON2_DOWN_MASK | InputEvent.BUTTON3_DOWN_MASK;
298       if ((e.getModifiersEx() & mouseMask) == 0) {
299         if (SwitchManager.areAllModifiersPressed(modifiers, vks) || !pressed) {
300           processState(pressed);
301         }
302         else {
303           resetHoldState();
304         }
305       }
306     }
307
308
309     return false;
310   }
311
312   public static Set<Integer> getActivateToolWindowVKs() {
313     if (ApplicationManager.getApplication() == null) return new HashSet<Integer>();
314
315     Keymap keymap = KeymapManager.getInstance().getActiveKeymap();
316     Shortcut[] baseShortcut = keymap.getShortcuts("ActivateProjectToolWindow");
317     int baseModifiers = 0;
318     for (Shortcut each : baseShortcut) {
319       if (each instanceof KeyboardShortcut) {
320         KeyStroke keyStroke = ((KeyboardShortcut)each).getFirstKeyStroke();
321         baseModifiers = keyStroke.getModifiers();
322         if (baseModifiers > 0) {
323           break;
324         }
325       }
326     }
327     return QuickAccessSettings.getModifiersVKs(baseModifiers);
328   }
329
330   private void resetHoldState() {
331     myCurrentState = KeyState.waiting;
332     processHoldState();
333   }
334
335   private void processState(boolean pressed) {
336     if (pressed) {
337       if (myCurrentState == KeyState.waiting) {
338         myCurrentState = KeyState.pressed;
339       }
340       else if (myCurrentState == KeyState.released) {
341         myCurrentState = KeyState.hold;
342         processHoldState();
343       }
344     }
345     else {
346       if (myCurrentState == KeyState.pressed) {
347         myCurrentState = KeyState.released;
348         restartWaitingForSecondPressAlarm();
349       }
350       else {
351         resetHoldState();
352       }
353     }
354   }
355
356   private void processHoldState() {
357     if (myToolWindowsPane != null) {
358       myToolWindowsPane.setStripesOverlayed(myCurrentState == KeyState.hold);
359     }
360   }
361
362   private void restartWaitingForSecondPressAlarm() {
363     myWaiterForSecondPress.cancelAllRequests();
364     myWaiterForSecondPress.addRequest(mySecondPressRunnable, Registry.intValue("actionSystem.keyGestureDblClickTime"));
365   }
366
367   private boolean hasOpenEditorFiles() {
368     return myFileEditorManager.getOpenFiles().length > 0;
369   }
370
371   private static IdeFocusManager getFocusManagerImpl(Project project) {
372     return IdeFocusManager.getInstance(project);
373   }
374
375   @NotNull
376   public Project getProject() {
377     return myProject;
378   }
379
380   @Override
381   public void initComponent() {
382   }
383
384   @Override
385   public void disposeComponent() {
386     for (String id : new ArrayList<String>(myId2StripeButton.keySet())) {
387       unregisterToolWindow(id);
388     }
389
390     assert myId2StripeButton.isEmpty();
391
392     KeyboardFocusManager.getCurrentKeyboardFocusManager().removePropertyChangeListener(myFocusListener);
393   }
394
395   @Override
396   public void projectOpened() {
397     final MyUIManagerPropertyChangeListener uiManagerPropertyListener = new MyUIManagerPropertyChangeListener();
398     final MyLafManagerListener lafManagerListener = new MyLafManagerListener();
399
400     UIManager.addPropertyChangeListener(uiManagerPropertyListener);
401     myLafManager.addLafManagerListener(lafManagerListener);
402
403     Disposer.register(myProject, new Disposable() {
404       @Override
405       public void dispose() {
406         UIManager.removePropertyChangeListener(uiManagerPropertyListener);
407         myLafManager.removeLafManagerListener(lafManagerListener);
408       }
409     });
410     myFrame = myWindowManager.allocateFrame(myProject);
411     LOG.assertTrue(myFrame != null);
412
413     final ArrayList<FinalizableCommand> commandsList = new ArrayList<FinalizableCommand>();
414
415     myToolWindowsPane = new ToolWindowsPane(myFrame, this);
416     Disposer.register(myProject, myToolWindowsPane);
417     ((IdeRootPane)myFrame.getRootPane()).setToolWindowsPane(myToolWindowsPane);
418     appendUpdateToolWindowsPaneCmd(commandsList);
419
420     myFrame.setTitle(FrameTitleBuilder.getInstance().getProjectTitle(myProject));
421     JComponent editorComponent = createEditorComponent(myProject);
422     myEditorComponentFocusWatcher.install(editorComponent);
423
424     appendSetEditorComponentCmd(editorComponent, commandsList);
425     if (myEditorWasActive && editorComponent instanceof EditorsSplitters) {
426       activateEditorComponentImpl(commandsList, true);
427     }
428     execute(commandsList);
429
430     final DumbService.DumbModeListener dumbModeListener = new DumbService.DumbModeListener() {
431       @Override
432       public void enteredDumbMode() {
433         disableStripeButtons();
434       }
435
436       @Override
437       public void exitDumbMode() {
438         for (final String id : getToolWindowIds()) {
439           getStripeButton(id).setEnabled(true);
440         }
441       }
442     };
443     myProject.getMessageBus().connect().subscribe(DumbService.DUMB_MODE, dumbModeListener);
444
445     StartupManager.getInstance(myProject).registerPostStartupActivity(new DumbAwareRunnable() {
446       @Override
447       public void run() {
448         registerToolWindowsFromBeans();
449         if (DumbService.getInstance(myProject).isDumb()) {
450           disableStripeButtons();
451         }
452       }
453     });
454
455     IdeEventQueue.getInstance().addDispatcher(new IdeEventQueue.EventDispatcher() {
456       @Override
457       public boolean dispatch(AWTEvent e) {
458         if (e instanceof KeyEvent) {
459           dispatchKeyEvent((KeyEvent)e);
460         }
461         if (e instanceof WindowEvent && (e.getID() == WindowEvent.WINDOW_LOST_FOCUS) && e.getSource() == myFrame) {
462           resetHoldState();
463         }
464         return false;
465       }
466     }, myProject);
467   }
468
469   private void disableStripeButtons() {
470     for (final String id : getToolWindowIds()) {
471       if (!myDumbAwareIds.contains(id)) {
472         if (isToolWindowVisible(id)) {
473           hideToolWindow(id, true);
474         }
475         StripeButton button = getStripeButton(id);
476         if (button != null) {
477           button.setEnabled(false);
478         }
479       }
480     }
481   }
482
483   private JComponent createEditorComponent(Project project) {
484     return FrameEditorComponentProvider.EP.getExtensions()[0].createEditorComponent(project);
485   }
486
487   private void registerToolWindowsFromBeans() {
488     ToolWindowEP[] beans = Extensions.getExtensions(ToolWindowEP.EP_NAME);
489     for (final ToolWindowEP bean : beans) {
490       final Condition<Project> condition = bean.getCondition();
491       if (condition == null) {
492         initToolWindow(bean);
493       }
494       else {
495         checkConditionInReadAction(bean, condition);
496       }
497     }
498   }
499
500   private void checkConditionInReadAction(@NotNull final ToolWindowEP bean, @NotNull final Condition<Project> condition) {
501     ProgressIndicatorUtils.scheduleWithWriteActionPriority(new ReadTask() {
502       @Override
503       public void computeInReadAction(@NotNull ProgressIndicator indicator) throws ProcessCanceledException {
504         if (!myProject.isDisposed() && condition.value(myProject)) {
505           ApplicationManager.getApplication().invokeLater(new Runnable() {
506             @Override
507             public void run() {
508               if (!myProject.isDisposed() && getToolWindow(bean.id) == null) {
509                 initToolWindow(bean);
510               }
511             }
512           });
513         }
514       }
515
516       @Override
517       public void onCanceled(@NotNull ProgressIndicator indicator) {
518         checkConditionInReadAction(bean, condition);
519       }
520     });
521   }
522
523   @Override
524   public void initToolWindow(@NotNull ToolWindowEP bean) {
525     JLabel label = new JLabel("Initializing...", SwingConstants.CENTER);
526     label.setOpaque(true);
527     final Color treeBg = UIManager.getColor("Tree.background");
528     label.setBackground(ColorUtil.toAlpha(treeBg, 180));
529     final Color treeFg = UIUtil.getTreeForeground();
530     label.setForeground(ColorUtil.toAlpha(treeFg, 180));
531     ToolWindowAnchor toolWindowAnchor = ToolWindowAnchor.fromText(bean.anchor);
532     final ToolWindowFactory factory = bean.getToolWindowFactory();
533     final ToolWindowImpl toolWindow =
534       (ToolWindowImpl)registerToolWindow(bean.id, label, toolWindowAnchor, myProject, DumbService.isDumbAware(factory),
535                                          bean.canCloseContents);
536     toolWindow.setContentFactory(factory);
537     if (bean.icon != null && toolWindow.getIcon() == null) {
538       Icon icon = IconLoader.findIcon(bean.icon, factory.getClass());
539       if (icon == null) {
540         try {
541           icon = IconLoader.getIcon(bean.icon);
542         }
543         catch (Exception ignored) {
544         }
545       }
546       toolWindow.setIcon(icon);
547     }
548
549     WindowInfoImpl info = getInfo(bean.id);
550     if (!info.isSplit() && bean.secondary && !info.wasRead()) {
551       toolWindow.setSplitMode(bean.secondary, null);
552     }
553
554     final ActionCallback activation = toolWindow.setActivation(new ActionCallback());
555
556     final DumbAwareRunnable runnable = new DumbAwareRunnable() {
557       @Override
558       public void run() {
559         if (toolWindow.isDisposed()) return;
560
561         toolWindow.ensureContentInitialized();
562         activation.setDone();
563       }
564     };
565     if (ApplicationManager.getApplication().isUnitTestMode()) {
566       runnable.run();
567     }
568     else {
569       UiNotifyConnector.doWhenFirstShown(label, new Runnable() {
570         @Override
571         public void run() {
572           ApplicationManager.getApplication().invokeLater(runnable);
573         }
574       });
575     }
576   }
577
578   @Override
579   public void projectClosed() {
580     final ArrayList<FinalizableCommand> commandsList = new ArrayList<FinalizableCommand>();
581     final String[] ids = getToolWindowIds();
582
583     // Remove ToolWindowsPane
584     if (myFrame != null) {
585       ((IdeRootPane)myFrame.getRootPane()).setToolWindowsPane(null);
586       myWindowManager.releaseFrame(myFrame);
587     }
588     appendUpdateToolWindowsPaneCmd(commandsList);
589
590     // Hide all tool windows
591
592     for (final String id : ids) {
593       deactivateToolWindowImpl(id, true, commandsList);
594     }
595
596     // Remove editor component
597
598     final JComponent editorComponent = FileEditorManagerEx.getInstanceEx(myProject).getComponent();
599     myEditorComponentFocusWatcher.deinstall(editorComponent);
600     appendSetEditorComponentCmd(null, commandsList);
601     execute(commandsList);
602   }
603
604   @Override
605   public void addToolWindowManagerListener(@NotNull ToolWindowManagerListener l) {
606     myDispatcher.addListener(l);
607   }
608
609   @Override
610   public void addToolWindowManagerListener(@NotNull ToolWindowManagerListener l, @NotNull Disposable parentDisposable) {
611     myDispatcher.addListener(l, parentDisposable);
612   }
613
614   @Override
615   public void removeToolWindowManagerListener(@NotNull ToolWindowManagerListener l) {
616     myDispatcher.removeListener(l);
617   }
618
619   /**
620    * This is helper method. It delegated its functionality to the WindowManager.
621    * Before delegating it fires state changed.
622    */
623   public void execute(@NotNull List<FinalizableCommand> commandList) {
624     for (FinalizableCommand each : commandList) {
625       if (each.willChangeState()) {
626         fireStateChanged();
627         break;
628       }
629     }
630
631     for (FinalizableCommand each : commandList) {
632       each.beforeExecute(this);
633     }
634     myWindowManager.getCommandProcessor().execute(commandList, myProject.getDisposed());
635   }
636
637   @Override
638   public void activateEditorComponent() {
639     activateEditorComponent(true);
640   }
641
642   private void activateEditorComponent(final boolean forced) {
643     activateEditorComponent(forced, false); //TODO[kirillk]: runnable in activateEditorComponent(boolean, boolean) never runs
644   }
645
646   private void activateEditorComponent(final boolean forced, boolean now) {
647     if (LOG.isDebugEnabled()) {
648       LOG.debug("enter: activateEditorComponent()");
649     }
650     ApplicationManager.getApplication().assertIsDispatchThread();
651
652     final ExpirableRunnable runnable = new ExpirableRunnable.ForProject(myProject) {
653       @Override
654       public void run() {
655         final ArrayList<FinalizableCommand> commandList = new ArrayList<FinalizableCommand>();
656         activateEditorComponentImpl(commandList, forced);
657         execute(commandList);
658       }
659     };
660     if (now) {
661       if (!runnable.isExpired()) {
662         runnable.run();
663       }
664     }
665     else {
666       final FocusRequestor requestor = getFocusManager().getFurtherRequestor();
667       getFocusManager().doWhenFocusSettlesDown(new ExpirableRunnable.ForProject(myProject) {
668         @Override
669         public void run() {
670           requestor.requestFocus(new FocusCommand() {
671             @NotNull
672             @Override
673             public ActionCallback run() {
674               runnable.run();
675               return ActionCallback.DONE;
676             }
677           }.setExpirable(runnable), forced);
678         }
679       });
680     }
681   }
682
683   private void activateEditorComponentImpl(List<FinalizableCommand> commandList, final boolean forced) {
684     final String active = getActiveToolWindowId();
685     // Now we have to request focus into most recent focused editor
686     appendRequestFocusInEditorComponentCmd(commandList, forced).doWhenDone(new Runnable() {
687       @Override
688       public void run() {
689         final ArrayList<FinalizableCommand> commandList = new ArrayList<FinalizableCommand>();
690
691         if (LOG.isDebugEnabled()) {
692           LOG.debug("editor activated");
693         }
694         deactivateWindows(null, commandList);
695         myActiveStack.clear();
696
697         execute(commandList);
698       }
699     }).doWhenRejected(new Runnable() {
700       @Override
701       public void run() {
702         if (forced) {
703           getFocusManagerImpl(myProject).requestFocus(new FocusCommand() {
704             @NotNull
705             @Override
706             public ActionCallback run() {
707               final ArrayList<FinalizableCommand> commandList = new ArrayList<FinalizableCommand>();
708
709               final WindowInfoImpl toReactivate = getInfo(active);
710               final boolean reactivateLastActive = toReactivate != null && !isToHideOnDeactivation(toReactivate);
711               deactivateWindows(reactivateLastActive ? active : null, commandList);
712               execute(commandList);
713
714               if (reactivateLastActive) {
715                 activateToolWindow(active, false, true);
716               }
717               else {
718                 if (active != null) {
719                   myActiveStack.remove(active, false);
720                 }
721
722                 if (!myActiveStack.isEmpty()) {
723                   activateToolWindow(myActiveStack.peek(), false, true);
724                 }
725               }
726               return ActionCallback.DONE;
727             }
728           }, false);
729         }
730       }
731     });
732   }
733
734   private void deactivateWindows( @Nullable String idToIgnore, final List<FinalizableCommand> commandList) {
735     final WindowInfoImpl[] infos = myLayout.getInfos();
736     for (final WindowInfoImpl info : infos) {
737       if (idToIgnore != null && idToIgnore.equals(info.getId())) {
738         continue;
739       }
740       deactivateToolWindowImpl(info.getId(), isToHideOnDeactivation(info), commandList);
741     }
742   }
743
744   private static boolean isToHideOnDeactivation(@NotNull final WindowInfoImpl info) {
745     if (info.isFloating() || info.isWindowed()) return false;
746     return info.isAutoHide() || info.isSliding();
747   }
748
749   /**
750    * Helper method. It makes window visible, activates it and request focus into the tool window.
751    * But it doesn't deactivate other tool windows. Use <code>prepareForActivation</code> method to
752    * deactivates other tool windows.
753    *
754    * @param dirtyMode if <code>true</code> then all UI operations are performed in "dirty" mode.
755    *                  It means that UI isn't validated and repainted just after each add/remove operation.
756    * @see ToolWindowManagerImpl#prepareForActivation
757    */
758   private void showAndActivate(final String id,
759                                final boolean dirtyMode,
760                                List<FinalizableCommand> commandsList,
761                                boolean autoFocusContents,
762                                boolean forcedFocusRequest) {
763     if (!getToolWindow(id).isAvailable()) {
764       return;
765     }
766     // show activated
767     final WindowInfoImpl info = getInfo(id);
768     boolean toApplyInfo = false;
769     if (!info.isActive()) {
770       info.setActive(true);
771       toApplyInfo = true;
772     }
773     showToolWindowImpl(id, dirtyMode, commandsList);
774
775     // activate
776     if (toApplyInfo) {
777       appendApplyWindowInfoCmd(info, commandsList);
778       myActiveStack.push(id);
779     }
780
781     if (autoFocusContents && ApplicationManager.getApplication().isActive()) {
782       appendRequestFocusInToolWindowCmd(id, commandsList, forcedFocusRequest);
783     }
784   }
785
786   void activateToolWindow(final String id, boolean forced, boolean autoFocusContents) {
787     if (LOG.isDebugEnabled()) {
788       LOG.debug("enter: activateToolWindow(" + id + ")");
789     }
790     ApplicationManager.getApplication().assertIsDispatchThread();
791     checkId(id);
792     if (DumbService.getInstance(myProject).isDumb() && !myDumbAwareIds.contains(id)) {
793       return;
794     }
795
796     final ArrayList<FinalizableCommand> commandList = new ArrayList<FinalizableCommand>();
797     activateToolWindowImpl(id, commandList, forced, autoFocusContents);
798     execute(commandList);
799   }
800
801   private void activateToolWindowImpl(final String id,
802                                       List<FinalizableCommand> commandList,
803                                       boolean forced,
804                                       boolean autoFocusContents) {
805     if (!FocusManagerImpl.getInstance().isUnforcedRequestAllowed() && !forced) return;
806
807     if (LOG.isDebugEnabled()) {
808       LOG.debug("enter: activateToolWindowImpl(" + id + ")");
809     }
810     if (!getToolWindow(id).isAvailable()) {
811       // Tool window can be "logically" active but not focused. For example,
812       // when the user switched to another application. So we just need to bring
813       // tool window's window to front.
814       final InternalDecorator decorator = getInternalDecorator(id);
815       if (!decorator.hasFocus() && autoFocusContents) {
816         appendRequestFocusInToolWindowCmd(id, commandList, forced);
817       }
818       return;
819     }
820     deactivateWindows(id, commandList);
821     showAndActivate(id, false, commandList, autoFocusContents, forced);
822   }
823
824   /**
825    * Checkes whether the specified <code>id</code> defines installed tool
826    * window. If it's not then throws <code>IllegalStateException</code>.
827    *
828    * @throws IllegalStateException if tool window isn't installed.
829    */
830   private void checkId(final String id) {
831     if (!myLayout.isToolWindowRegistered(id)) {
832       throw new IllegalStateException("window with id=\"" + id + "\" isn't registered");
833     }
834   }
835
836   /**
837    * Helper method. It deactivates (and hides) window with specified <code>id</code>.
838    *
839    * @param id         <code>id</code> of the tool window to be deactivated.
840    * @param shouldHide if <code>true</code> then also hides specified tool window.
841    */
842   private void deactivateToolWindowImpl(final String id, final boolean shouldHide, final List<FinalizableCommand> commandsList) {
843     if (LOG.isDebugEnabled()) {
844       LOG.debug("enter: deactivateToolWindowImpl(" + id + "," + shouldHide + ")");
845     }
846     final WindowInfoImpl info = getInfo(id);
847     if (shouldHide && info.isVisible()) {
848       info.setVisible(false);
849       if (info.isFloating()) {
850         appendRemoveFloatingDecoratorCmd(info, commandsList);
851       }
852       else if (info.isWindowed()) {
853         appendRemoveWindowedDecoratorCmd(info, commandsList);
854       }
855       else { // docked and sliding windows
856         appendRemoveDecoratorCmd(id, false, commandsList);
857       }
858     }
859     info.setActive(false);
860     appendApplyWindowInfoCmd(info, commandsList);
861   }
862
863   @NotNull
864   @Override
865   public String[] getToolWindowIds() {
866     final WindowInfoImpl[] infos = myLayout.getInfos();
867     final String[] ids = ArrayUtil.newStringArray(infos.length);
868     for (int i = 0; i < infos.length; i++) {
869       ids[i] = infos[i].getId();
870     }
871     return ids;
872   }
873
874   @Override
875   public String getActiveToolWindowId() {
876     ApplicationManager.getApplication().assertIsDispatchThread();
877     return myLayout.getActiveId();
878   }
879
880   @Override
881   public String getLastActiveToolWindowId() {
882     return getLastActiveToolWindowId(null);
883   }
884
885   @Override
886   @Nullable
887   public String getLastActiveToolWindowId(@Nullable Condition<JComponent> condition) {
888     ApplicationManager.getApplication().assertIsDispatchThread();
889     String lastActiveToolWindowId = null;
890     for (int i = 0; i < myActiveStack.getPersistentSize(); i++) {
891       final String id = myActiveStack.peekPersistent(i);
892       final ToolWindow toolWindow = getToolWindow(id);
893       LOG.assertTrue(toolWindow != null);
894       if (toolWindow.isAvailable()) {
895         if (condition == null || condition.value(toolWindow.getComponent())) {
896           lastActiveToolWindowId = id;
897           break;
898         }
899       }
900     }
901     return lastActiveToolWindowId;
902   }
903
904   /**
905    * @return floating decorator for the tool window with specified <code>ID</code>.
906    */
907   private FloatingDecorator getFloatingDecorator(final String id) {
908     return myId2FloatingDecorator.get(id);
909   }
910   /**
911    * @return windowed decorator for the tool window with specified <code>ID</code>.
912    */
913   private WindowedDecorator getWindowedDecorator(String id) {
914     return myId2WindowedDecorator.get(id);
915   }
916   /**
917    * @return internal decorator for the tool window with specified <code>ID</code>.
918    */
919   private InternalDecorator getInternalDecorator(final String id) {
920     return myId2InternalDecorator.get(id);
921   }
922
923   /**
924    * @return tool button for the window with specified <code>ID</code>.
925    */
926   private StripeButton getStripeButton(final String id) {
927     return myId2StripeButton.get(id);
928   }
929
930   /**
931    * @return info for the tool window with specified <code>ID</code>.
932    */
933   private WindowInfoImpl getInfo(final String id) {
934     return myLayout.getInfo(id, true);
935   }
936
937   @Override
938   public List<String> getIdsOn(@NotNull final ToolWindowAnchor anchor) {
939     return myLayout.getVisibleIdsOn(anchor, this);
940   }
941
942   @Override
943   public ToolWindow getToolWindow(final String id) {
944     if (!myLayout.isToolWindowRegistered(id)) {
945       return null;
946     }
947     InternalDecorator decorator = getInternalDecorator(id);
948     return decorator != null ? decorator.getToolWindow() : null;
949   }
950
951   void showToolWindow(final String id) {
952     if (LOG.isDebugEnabled()) {
953       LOG.debug("enter: showToolWindow(" + id + ")");
954     }
955     ApplicationManager.getApplication().assertIsDispatchThread();
956     final ArrayList<FinalizableCommand> commandList = new ArrayList<FinalizableCommand>();
957     showToolWindowImpl(id, false, commandList);
958     execute(commandList);
959   }
960
961   @Override
962   public void hideToolWindow(@NotNull final String id, final boolean hideSide) {
963     hideToolWindow(id, hideSide, true);
964   }
965
966   public void hideToolWindow(final String id, final boolean hideSide, final boolean moveFocus) {
967     ApplicationManager.getApplication().assertIsDispatchThread();
968     checkId(id);
969     final WindowInfoImpl info = getInfo(id);
970     if (!info.isVisible()) return;
971     final ArrayList<FinalizableCommand> commandList = new ArrayList<FinalizableCommand>();
972     final boolean wasActive = info.isActive();
973
974     // hide and deactivate
975
976     deactivateToolWindowImpl(id, true, commandList);
977
978     if (hideSide && !info.isFloating() && !info.isWindowed()) {
979       final List<String> ids = myLayout.getVisibleIdsOn(info.getAnchor(), this);
980       for (String each : ids) {
981         myActiveStack.remove(each, true);
982       }
983
984
985       while (!mySideStack.isEmpty(info.getAnchor())) {
986         mySideStack.pop(info.getAnchor());
987       }
988
989       final String[] all = getToolWindowIds();
990       for (String eachId : all) {
991         final WindowInfoImpl eachInfo = getInfo(eachId);
992         if (eachInfo.isVisible() && eachInfo.getAnchor() == info.getAnchor()) {
993           deactivateToolWindowImpl(eachId, true, commandList);
994         }
995       }
996
997       activateEditorComponentImpl(commandList, true);
998     }
999     else if (isStackEnabled()) {
1000
1001       // first of all we have to find tool window that was located at the same side and
1002       // was hidden.
1003
1004       WindowInfoImpl info2 = null;
1005       while (!mySideStack.isEmpty(info.getAnchor())) {
1006         final WindowInfoImpl storedInfo = mySideStack.pop(info.getAnchor());
1007         if (storedInfo.isSplit() != info.isSplit()) {
1008           continue;
1009         }
1010
1011         final WindowInfoImpl currentInfo = getInfo(storedInfo.getId());
1012         LOG.assertTrue(currentInfo != null);
1013         // SideStack contains copies of real WindowInfos. It means that
1014         // these stored infos can be invalid. The following loop removes invalid WindowInfos.
1015         if (storedInfo.getAnchor() == currentInfo.getAnchor() &&
1016             storedInfo.getType() == currentInfo.getType() &&
1017             storedInfo.isAutoHide() == currentInfo.isAutoHide()) {
1018           info2 = storedInfo;
1019           break;
1020         }
1021       }
1022       if (info2 != null) {
1023         showToolWindowImpl(info2.getId(), false, commandList);
1024       }
1025
1026       // If we hide currently active tool window then we should activate the previous
1027       // one which is located in the tool window stack.
1028       // Activate another tool window if no active tool window exists and
1029       // window stack is enabled.
1030
1031       myActiveStack.remove(id, false); // hidden window should be at the top of stack
1032
1033       if (wasActive && moveFocus) {
1034         if (myActiveStack.isEmpty()) {
1035           if (hasOpenEditorFiles()) {
1036             activateEditorComponentImpl(commandList, false);
1037           }
1038           else {
1039             focusToolWinowByDefault(id);
1040           }
1041         }
1042         else {
1043           final String toBeActivatedId = myActiveStack.pop();
1044           if (toBeActivatedId != null && (getInfo(toBeActivatedId).isVisible() || isStackEnabled())) {
1045             activateToolWindowImpl(toBeActivatedId, commandList, false, true);
1046           }
1047           else {
1048             focusToolWinowByDefault(id);
1049           }
1050         }
1051       }
1052     }
1053     //todo[kb] it's just a temporary solution due a number of focus issues in JDK 7
1054     if (SystemInfo.isJavaVersionAtLeast("1.7") && moveFocus) {
1055       if (hasOpenEditorFiles()) {
1056         activateEditorComponentImpl(commandList, false);
1057       } else {
1058         focusToolWinowByDefault(id);
1059       }
1060     }
1061
1062     execute(commandList);
1063   }
1064
1065   private static boolean isStackEnabled() {
1066     return Registry.is("ide.enable.toolwindow.stack");
1067   }
1068
1069   /**
1070    * @param dirtyMode if <code>true</code> then all UI operations are performed in dirty mode.
1071    */
1072   private void showToolWindowImpl(final String id, final boolean dirtyMode, final List<FinalizableCommand> commandsList) {
1073     final WindowInfoImpl toBeShownInfo = getInfo(id);
1074     if (toBeShownInfo.isVisible() || !getToolWindow(id).isAvailable()) {
1075       return;
1076     }
1077
1078     if (DumbService.getInstance(myProject).isDumb() && !myDumbAwareIds.contains(id)) {
1079       return;
1080     }
1081
1082     toBeShownInfo.setVisible(true);
1083     final InternalDecorator decorator = getInternalDecorator(id);
1084
1085     if (toBeShownInfo.isFloating()) {
1086       commandsList.add(new AddFloatingDecoratorCmd(decorator, toBeShownInfo));
1087     }
1088     else if (toBeShownInfo.isWindowed()) {
1089       commandsList.add(new AddWindowedDecoratorCmd(decorator, toBeShownInfo));
1090     }
1091     else { // docked and sliding windows
1092
1093       // If there is tool window on the same side then we have to hide it, i.e.
1094       // clear place for tool window to be shown.
1095       //
1096       // We store WindowInfo of hidden tool window in the SideStack (if the tool window
1097       // is docked and not auto-hide one). Therefore it's possible to restore the
1098       // hidden tool window when showing tool window will be closed.
1099
1100       final WindowInfoImpl[] infos = myLayout.getInfos();
1101       for (final WindowInfoImpl info : infos) {
1102         if (id.equals(info.getId())) {
1103           continue;
1104         }
1105         if (info.isVisible() &&
1106             info.getType() == toBeShownInfo.getType() &&
1107             info.getAnchor() == toBeShownInfo.getAnchor() &&
1108             info.isSplit() == toBeShownInfo.isSplit()) {
1109           // hide and deactivate tool window
1110           info.setVisible(false);
1111           appendRemoveDecoratorCmd(info.getId(), false, commandsList);
1112           if (info.isActive()) {
1113             info.setActive(false);
1114           }
1115           appendApplyWindowInfoCmd(info, commandsList);
1116           // store WindowInfo into the SideStack
1117           if (info.isDocked() && !info.isAutoHide()) {
1118             mySideStack.push(info);
1119           }
1120         }
1121       }
1122       appendAddDecoratorCmd(decorator, toBeShownInfo, dirtyMode, commandsList);
1123
1124       // Remove tool window from the SideStack.
1125
1126       mySideStack.remove(id);
1127     }
1128
1129     if (!toBeShownInfo.isShowStripeButton()) {
1130       toBeShownInfo.setShowStripeButton(true);
1131     }
1132
1133     appendApplyWindowInfoCmd(toBeShownInfo, commandsList);
1134   }
1135
1136   @NotNull
1137   @Override
1138   public ToolWindow registerToolWindow(@NotNull final String id,
1139                                        @NotNull final JComponent component,
1140                                        @NotNull final ToolWindowAnchor anchor) {
1141     return registerToolWindow(id, component, anchor, false);
1142   }
1143
1144   @NotNull
1145   @Override
1146   public ToolWindow registerToolWindow(@NotNull final String id,
1147                                        @NotNull JComponent component,
1148                                        @NotNull ToolWindowAnchor anchor,
1149                                        @NotNull Disposable parentDisposable) {
1150     return registerToolWindow(id, component, anchor, parentDisposable, false, false);
1151   }
1152
1153   @NotNull
1154   @Override
1155   public ToolWindow registerToolWindow(@NotNull String id,
1156                                        @NotNull JComponent component,
1157                                        @NotNull ToolWindowAnchor anchor,
1158                                        @NotNull Disposable parentDisposable,
1159                                        boolean canWorkInDumbMode) {
1160     return registerToolWindow(id, component, anchor, parentDisposable, canWorkInDumbMode, false);
1161   }
1162
1163   @NotNull
1164   @Override
1165   public ToolWindow registerToolWindow(@NotNull final String id,
1166                                        @NotNull JComponent component,
1167                                        @NotNull ToolWindowAnchor anchor,
1168                                        @NotNull Disposable parentDisposable,
1169                                        boolean canWorkInDumbMode, boolean canCloseContents) {
1170     return registerDisposable(id, parentDisposable, registerToolWindow(id, component, anchor, false, canCloseContents, canWorkInDumbMode));
1171   }
1172
1173   @NotNull
1174   private ToolWindow registerToolWindow(@NotNull final String id,
1175                                         @NotNull final JComponent component,
1176                                         @NotNull final ToolWindowAnchor anchor,
1177                                         boolean canWorkInDumbMode) {
1178     return registerToolWindow(id, component, anchor, false, false, canWorkInDumbMode);
1179   }
1180
1181   @NotNull
1182   @Override
1183   public ToolWindow registerToolWindow(@NotNull final String id, final boolean canCloseContent, @NotNull final ToolWindowAnchor anchor) {
1184     return registerToolWindow(id, null, anchor, false, canCloseContent, false);
1185   }
1186
1187   @NotNull
1188   @Override
1189   public ToolWindow registerToolWindow(@NotNull final String id,
1190                                        final boolean canCloseContent,
1191                                        @NotNull final ToolWindowAnchor anchor,
1192                                        final boolean secondary) {
1193     return registerToolWindow(id, null, anchor, secondary, canCloseContent, false);
1194   }
1195
1196
1197   @NotNull
1198   @Override
1199   public ToolWindow registerToolWindow(@NotNull final String id,
1200                                        final boolean canCloseContent,
1201                                        @NotNull final ToolWindowAnchor anchor,
1202                                        @NotNull final Disposable parentDisposable,
1203                                        final boolean canWorkInDumbMode) {
1204     return registerToolWindow(id, canCloseContent, anchor, parentDisposable, canWorkInDumbMode, false);
1205   }
1206
1207   @NotNull
1208   @Override
1209   public ToolWindow registerToolWindow(@NotNull String id,
1210                                        boolean canCloseContent,
1211                                        @NotNull ToolWindowAnchor anchor,
1212                                        Disposable parentDisposable,
1213                                        boolean canWorkInDumbMode,
1214                                        boolean secondary) {
1215     ToolWindow window = registerToolWindow(id, null, anchor, secondary, canCloseContent, canWorkInDumbMode);
1216     return registerDisposable(id, parentDisposable, window);
1217   }
1218
1219   @NotNull
1220   private ToolWindow registerToolWindow(@NotNull final String id,
1221                                         @Nullable final JComponent component,
1222                                         @NotNull final ToolWindowAnchor anchor,
1223                                         boolean sideTool,
1224                                         boolean canCloseContent,
1225                                         final boolean canWorkInDumbMode) {
1226     if (LOG.isDebugEnabled()) {
1227       LOG.debug("enter: installToolWindow(" + id + "," + component + "," + anchor + "\")");
1228     }
1229     ApplicationManager.getApplication().assertIsDispatchThread();
1230     if (myLayout.isToolWindowRegistered(id)) {
1231       throw new IllegalArgumentException("window with id=\"" + id + "\" is already registered");
1232     }
1233
1234     final WindowInfoImpl info = myLayout.register(id, anchor, sideTool);
1235     final boolean wasActive = info.isActive();
1236     final boolean wasVisible = info.isVisible();
1237     info.setActive(false);
1238     info.setVisible(false);
1239
1240     // Create decorator
1241
1242     ToolWindowImpl toolWindow = new ToolWindowImpl(this, id, canCloseContent, component);
1243     InternalDecorator decorator = new InternalDecorator(myProject, info.copy(), toolWindow);
1244     ActivateToolWindowAction.ensureToolWindowActionRegistered(toolWindow);
1245     myId2InternalDecorator.put(id, decorator);
1246     decorator.addInternalDecoratorListener(myInternalDecoratorListener);
1247     toolWindow.addPropertyChangeListener(myToolWindowPropertyChangeListener);
1248     myId2FocusWatcher.put(id, new ToolWindowFocusWatcher(toolWindow));
1249
1250     // Create and show tool button
1251
1252     final StripeButton button = new StripeButton(decorator, myToolWindowsPane);
1253     myId2StripeButton.put(id, button);
1254     List<FinalizableCommand> commandsList = new ArrayList<FinalizableCommand>();
1255     appendAddButtonCmd(button, info, commandsList);
1256
1257     if (canWorkInDumbMode) {
1258       myDumbAwareIds.add(id);
1259     }
1260     else if (DumbService.getInstance(getProject()).isDumb()) {
1261       button.setEnabled(false);
1262     }
1263
1264     // If preloaded info is visible or active then we have to show/activate the installed
1265     // tool window. This step has sense only for windows which are not in the autohide
1266     // mode. But if tool window was active but its mode doen't allow to activate it again
1267     // (for example, tool window is in autohide mode) then we just activate editor component.
1268
1269     if (!info.isAutoHide() && (info.isDocked() || info.isFloating())) {
1270       if (wasActive) {
1271         activateToolWindowImpl(info.getId(), commandsList, true, true);
1272       }
1273       else if (wasVisible) {
1274         showToolWindowImpl(info.getId(), false, commandsList);
1275       }
1276     }
1277     else if (wasActive) { // tool window was active but it cannot be activate again
1278       activateEditorComponentImpl(commandsList, true);
1279     }
1280
1281     execute(commandsList);
1282     fireToolWindowRegistered(id);
1283     return toolWindow;
1284   }
1285
1286   @NotNull
1287   private ToolWindow registerDisposable(@NotNull final String id, @NotNull final Disposable parentDisposable, @NotNull ToolWindow window) {
1288     Disposer.register(parentDisposable, new Disposable() {
1289       @Override
1290       public void dispose() {
1291         unregisterToolWindow(id);
1292       }
1293     });
1294     return window;
1295   }
1296
1297   @Override
1298   public void unregisterToolWindow(@NotNull final String id) {
1299     if (LOG.isDebugEnabled()) {
1300       LOG.debug("enter: unregisterToolWindow(" + id + ")");
1301     }
1302     ApplicationManager.getApplication().assertIsDispatchThread();
1303     if (!myLayout.isToolWindowRegistered(id)) {
1304       return;
1305     }
1306
1307     final WindowInfoImpl info = getInfo(id);
1308     final ToolWindowEx toolWindow = (ToolWindowEx)getToolWindow(id);
1309     // Save recent appearance of tool window
1310     myLayout.unregister(id);
1311     // Remove decorator and tool button from the screen
1312     final ArrayList<FinalizableCommand> commandsList = new ArrayList<FinalizableCommand>();
1313     if (info.isVisible()) {
1314       info.setVisible(false);
1315       if (info.isFloating()) {
1316         appendRemoveFloatingDecoratorCmd(info, commandsList);
1317       }
1318       else  if (info.isWindowed()) {
1319          appendRemoveWindowedDecoratorCmd(info, commandsList);
1320        }
1321       else { // floating and sliding windows
1322         appendRemoveDecoratorCmd(id, false, commandsList);
1323       }
1324     }
1325     appendRemoveButtonCmd(id, commandsList);
1326     appendApplyWindowInfoCmd(info, commandsList);
1327     execute(commandsList);
1328     // Remove all references on tool window and save its last properties
1329     toolWindow.removePropertyChangeListener(myToolWindowPropertyChangeListener);
1330     myActiveStack.remove(id, true);
1331     mySideStack.remove(id);
1332     // Destroy stripe button
1333     final StripeButton button = getStripeButton(id);
1334     Disposer.dispose(button);
1335     myId2StripeButton.remove(id);
1336     //
1337     ToolWindowFocusWatcher watcher = (ToolWindowFocusWatcher)myId2FocusWatcher.remove(id);
1338     watcher.deinstall();
1339
1340     // Destroy decorator
1341     final InternalDecorator decorator = getInternalDecorator(id);
1342     decorator.dispose();
1343     decorator.removeInternalDecoratorListener(myInternalDecoratorListener);
1344     myId2InternalDecorator.remove(id);
1345   }
1346
1347   @Override
1348   public DesktopLayout getLayout() {
1349     ApplicationManager.getApplication().assertIsDispatchThread();
1350     return myLayout;
1351   }
1352
1353   @Override
1354   public void setLayoutToRestoreLater(DesktopLayout layout) {
1355     myLayoutToRestoreLater = layout;
1356   }
1357
1358   @Override
1359   public DesktopLayout getLayoutToRestoreLater() {
1360     return myLayoutToRestoreLater;
1361   }
1362
1363   @Override
1364   public void setLayout(@NotNull final DesktopLayout layout) {
1365     ApplicationManager.getApplication().assertIsDispatchThread();
1366     final ArrayList<FinalizableCommand> commandList = new ArrayList<FinalizableCommand>();
1367     // hide tool window that are invisible in new layout
1368     final WindowInfoImpl[] currentInfos = myLayout.getInfos();
1369     for (final WindowInfoImpl currentInfo : currentInfos) {
1370       final WindowInfoImpl info = layout.getInfo(currentInfo.getId(), false);
1371       if (info == null) {
1372         continue;
1373       }
1374       if (currentInfo.isVisible() && !info.isVisible()) {
1375         deactivateToolWindowImpl(currentInfo.getId(), true, commandList);
1376       }
1377     }
1378     // change anchor of tool windows
1379     for (final WindowInfoImpl currentInfo : currentInfos) {
1380       final WindowInfoImpl info = layout.getInfo(currentInfo.getId(), false);
1381       if (info == null) {
1382         continue;
1383       }
1384       if (currentInfo.getAnchor() != info.getAnchor() || currentInfo.getOrder() != info.getOrder()) {
1385         setToolWindowAnchorImpl(currentInfo.getId(), info.getAnchor(), info.getOrder(), commandList);
1386       }
1387     }
1388     // change types of tool windows
1389     for (final WindowInfoImpl currentInfo : currentInfos) {
1390       final WindowInfoImpl info = layout.getInfo(currentInfo.getId(), false);
1391       if (info == null) {
1392         continue;
1393       }
1394       if (currentInfo.getType() != info.getType()) {
1395         setToolWindowTypeImpl(currentInfo.getId(), info.getType(), commandList);
1396       }
1397     }
1398     // change auto-hide state
1399     for (final WindowInfoImpl currentInfo : currentInfos) {
1400       final WindowInfoImpl info = layout.getInfo(currentInfo.getId(), false);
1401       if (info == null) {
1402         continue;
1403       }
1404       if (currentInfo.isAutoHide() != info.isAutoHide()) {
1405         setToolWindowAutoHideImpl(currentInfo.getId(), info.isAutoHide(), commandList);
1406       }
1407     }
1408     // restore visibility
1409     for (final WindowInfoImpl currentInfo : currentInfos) {
1410       final WindowInfoImpl info = layout.getInfo(currentInfo.getId(), false);
1411       if (info == null) {
1412         continue;
1413       }
1414       if (info.isVisible()) {
1415         showToolWindowImpl(currentInfo.getId(), false, commandList);
1416       }
1417     }
1418     // if there is no any active tool window and editor is also inactive
1419     // then activate editor
1420     if (!myEditorWasActive && getActiveToolWindowId() == null) {
1421       activateEditorComponentImpl(commandList, true);
1422     }
1423     execute(commandList);
1424   }
1425
1426   @Override
1427   public void invokeLater(@NotNull final Runnable runnable) {
1428     List<FinalizableCommand> commandList = new ArrayList<FinalizableCommand>();
1429     commandList.add(new InvokeLaterCmd(runnable, myWindowManager.getCommandProcessor()));
1430     execute(commandList);
1431   }
1432
1433   @NotNull
1434   @Override
1435   public IdeFocusManager getFocusManager() {
1436     return IdeFocusManager.getInstance(myProject);
1437   }
1438
1439   @Override
1440   public boolean canShowNotification(@NotNull final String toolWindowId) {
1441     if (!Arrays.asList(getToolWindowIds()).contains(toolWindowId)) {
1442       return false;
1443     }
1444     final Stripe stripe = myToolWindowsPane.getStripeFor(toolWindowId);
1445     return stripe != null && stripe.getButtonFor(toolWindowId) != null;
1446   }
1447
1448   @Override
1449   public void notifyByBalloon(@NotNull final String toolWindowId, @NotNull final MessageType type, @NotNull final String htmlBody) {
1450     notifyByBalloon(toolWindowId, type, htmlBody, null, null);
1451   }
1452
1453   @Override
1454   public void notifyByBalloon(@NotNull final String toolWindowId,
1455                               @NotNull final MessageType type,
1456                               @NotNull final String text,
1457                               @Nullable final Icon icon,
1458                               @Nullable final HyperlinkListener listener) {
1459     checkId(toolWindowId);
1460
1461
1462     Balloon existing = myWindow2Balloon.get(toolWindowId);
1463     if (existing != null) {
1464       existing.hide();
1465     }
1466
1467     final Stripe stripe = myToolWindowsPane.getStripeFor(toolWindowId);
1468     if (stripe == null) {
1469       return;
1470     }
1471     final ToolWindowImpl window = getInternalDecorator(toolWindowId).getToolWindow();
1472     if (!window.isAvailable()) {
1473       window.setPlaceholderMode(true);
1474       stripe.updatePresentation();
1475       stripe.revalidate();
1476       stripe.repaint();
1477     }
1478
1479     final ToolWindowAnchor anchor = getInfo(toolWindowId).getAnchor();
1480     final Ref<Balloon.Position> position = Ref.create(Balloon.Position.below);
1481     if (ToolWindowAnchor.TOP == anchor) {
1482       position.set(Balloon.Position.below);
1483     }
1484     else if (ToolWindowAnchor.BOTTOM == anchor) {
1485       position.set(Balloon.Position.above);
1486     }
1487     else if (ToolWindowAnchor.LEFT == anchor) {
1488       position.set(Balloon.Position.atRight);
1489     }
1490     else if (ToolWindowAnchor.RIGHT == anchor) {
1491       position.set(Balloon.Position.atLeft);
1492     }
1493
1494     final BalloonHyperlinkListener listenerWrapper = new BalloonHyperlinkListener(listener);
1495     final Balloon balloon =
1496       JBPopupFactory.getInstance()
1497         .createHtmlTextBalloonBuilder(text.replace("\n", "<br>"), icon, type.getPopupBackground(), listenerWrapper)
1498         .setHideOnClickOutside(false).setHideOnFrameResize(false).createBalloon();
1499     FrameStateManager.getInstance().getApplicationActive().doWhenDone(new Runnable() {
1500       @Override
1501       public void run() {
1502         final Alarm alarm = new Alarm();
1503         alarm.addRequest(new Runnable() {
1504           @Override
1505           public void run() {
1506             ((BalloonImpl)balloon).setHideOnClickOutside(true);
1507             Disposer.dispose(alarm);
1508           }
1509         }, 100);
1510       }
1511     });
1512     listenerWrapper.myBalloon = balloon;
1513     myWindow2Balloon.put(toolWindowId, balloon);
1514     Disposer.register(balloon, new Disposable() {
1515       @Override
1516       public void dispose() {
1517         window.setPlaceholderMode(false);
1518         stripe.updatePresentation();
1519         stripe.revalidate();
1520         stripe.repaint();
1521         myWindow2Balloon.remove(toolWindowId);
1522       }
1523     });
1524     Disposer.register(getProject(), balloon);
1525
1526     execute(new ArrayList<FinalizableCommand>(Arrays.<FinalizableCommand>asList(new FinalizableCommand(null) {
1527       @Override
1528       public void run() {
1529         final StripeButton button = stripe.getButtonFor(toolWindowId);
1530         LOG.assertTrue(button != null, "Button was not found, popup won't be shown. Toolwindow id: " +
1531                                        toolWindowId +
1532                                        ", message: " +
1533                                        text +
1534                                        ", message type: " +
1535                                        type);
1536         if (button == null) return;
1537
1538         final Runnable show = new Runnable() {
1539           @Override
1540           public void run() {
1541             if (button.isShowing()) {
1542               PositionTracker<Balloon> tracker = new PositionTracker<Balloon>(button) {
1543                 @Override
1544                 @Nullable
1545                 public RelativePoint recalculateLocation(Balloon object) {
1546                   Stripe twStripe = myToolWindowsPane.getStripeFor(toolWindowId);
1547                   StripeButton twButton = twStripe != null ? twStripe.getButtonFor(toolWindowId) : null;
1548
1549                   if (twButton == null) return null;
1550
1551                   if (getToolWindow(toolWindowId).getAnchor() != anchor) {
1552                     object.hide();
1553                     return null;
1554                   }
1555
1556                   final Point point = new Point(twButton.getBounds().width / 2, twButton.getHeight() / 2 - 2);
1557                   return new RelativePoint(twButton, point);
1558                 }
1559               };
1560               if (!balloon.isDisposed()) {
1561                 balloon.show(tracker, position.get());
1562               }
1563             }
1564             else {
1565               final Rectangle bounds = myToolWindowsPane.getBounds();
1566               final Point target = UIUtil.getCenterPoint(bounds, new Dimension(1, 1));
1567               if (ToolWindowAnchor.TOP == anchor) {
1568                 target.y = 0;
1569               }
1570               else if (ToolWindowAnchor.BOTTOM == anchor) {
1571                 target.y = bounds.height - 3;
1572               }
1573               else if (ToolWindowAnchor.LEFT == anchor) {
1574                 target.x = 0;
1575               }
1576               else if (ToolWindowAnchor.RIGHT == anchor) {
1577                 target.x = bounds.width;
1578               }
1579               if (!balloon.isDisposed()) {
1580                 balloon.show(new RelativePoint(myToolWindowsPane, target), position.get());
1581               }
1582             }
1583           }
1584         };
1585
1586         if (!button.isValid()) {
1587           SwingUtilities.invokeLater(new Runnable() {
1588             @Override
1589             public void run() {
1590               show.run();
1591             }
1592           });
1593         }
1594         else {
1595           show.run();
1596         }
1597       }
1598     })));
1599   }
1600
1601   @Override
1602   public Balloon getToolWindowBalloon(String id) {
1603     return myWindow2Balloon.get(id);
1604   }
1605
1606   @Override
1607   public boolean isEditorComponentActive() {
1608     ApplicationManager.getApplication().assertIsDispatchThread();
1609
1610     Component owner = getFocusManager().getFocusOwner();
1611     EditorsSplitters splitters = UIUtil.getParentOfType(EditorsSplitters.class, owner);
1612     return splitters != null;
1613   }
1614
1615   ToolWindowAnchor getToolWindowAnchor(final String id) {
1616     checkId(id);
1617     return getInfo(id).getAnchor();
1618   }
1619
1620   void setToolWindowAnchor(final String id, final ToolWindowAnchor anchor) {
1621     ApplicationManager.getApplication().assertIsDispatchThread();
1622     setToolWindowAnchor(id, anchor, -1);
1623   }
1624
1625   void setToolWindowAnchor(final String id, final ToolWindowAnchor anchor, final int order) {
1626     ApplicationManager.getApplication().assertIsDispatchThread();
1627     final ArrayList<FinalizableCommand> commandList = new ArrayList<FinalizableCommand>();
1628     setToolWindowAnchorImpl(id, anchor, order, commandList);
1629     execute(commandList);
1630   }
1631
1632   private void setToolWindowAnchorImpl(final String id,
1633                                        final ToolWindowAnchor anchor,
1634                                        final int order,
1635                                        final ArrayList<FinalizableCommand> commandsList) {
1636     checkId(id);
1637     final WindowInfoImpl info = getInfo(id);
1638     if (anchor == info.getAnchor() && order == info.getOrder()) {
1639       return;
1640     }
1641     // if tool window isn't visible or only order number is changed then just remove/add stripe button
1642     if (!info.isVisible() || anchor == info.getAnchor() || info.isFloating()) {
1643       appendRemoveButtonCmd(id, commandsList);
1644       myLayout.setAnchor(id, anchor, order);
1645       // update infos for all window. Actually we have to update only infos affected by
1646       // setAnchor method
1647       final WindowInfoImpl[] infos = myLayout.getInfos();
1648       for (WindowInfoImpl info1 : infos) {
1649         appendApplyWindowInfoCmd(info1, commandsList);
1650       }
1651       appendAddButtonCmd(getStripeButton(id), info, commandsList);
1652     }
1653     else { // for docked and sliding windows we have to move buttons and window's decorators
1654       info.setVisible(false);
1655       appendRemoveDecoratorCmd(id, false, commandsList);
1656       appendRemoveButtonCmd(id, commandsList);
1657       myLayout.setAnchor(id, anchor, order);
1658       // update infos for all window. Actually we have to update only infos affected by
1659       // setAnchor method
1660       final WindowInfoImpl[] infos = myLayout.getInfos();
1661       for (WindowInfoImpl info1 : infos) {
1662         appendApplyWindowInfoCmd(info1, commandsList);
1663       }
1664       appendAddButtonCmd(getStripeButton(id), info, commandsList);
1665       showToolWindowImpl(id, false, commandsList);
1666       if (info.isActive()) {
1667         appendRequestFocusInToolWindowCmd(id, commandsList, true);
1668       }
1669     }
1670   }
1671
1672   boolean isSplitMode(String id) {
1673     ApplicationManager.getApplication().assertIsDispatchThread();
1674     checkId(id);
1675     return getInfo(id).isSplit();
1676   }
1677
1678   @NotNull
1679   ToolWindowContentUiType getContentUiType(String id) {
1680     ApplicationManager.getApplication().assertIsDispatchThread();
1681     checkId(id);
1682     return getInfo(id).getContentUiType();
1683   }
1684
1685   void setSideTool(String id, boolean isSide) {
1686     final ArrayList<FinalizableCommand> commandList = new ArrayList<FinalizableCommand>();
1687     setSplitModeImpl(id, isSide, commandList);
1688     execute(commandList);
1689   }
1690
1691   public void setContentUiType(String id, @NotNull ToolWindowContentUiType type) {
1692     final ArrayList<FinalizableCommand> commandList = new ArrayList<FinalizableCommand>();
1693     checkId(id);
1694     WindowInfoImpl info = getInfo(id);
1695     info.setContentUiType(type);
1696     appendApplyWindowInfoCmd(info, commandList);
1697     execute(commandList);
1698   }
1699
1700   void setSideToolAndAnchor(String id, ToolWindowAnchor anchor, int order, boolean isSide) {
1701     final ArrayList<FinalizableCommand> commandList = new ArrayList<FinalizableCommand>();
1702     setToolWindowAnchor(id, anchor, order);
1703     setSplitModeImpl(id, isSide, commandList);
1704     execute(commandList);
1705   }
1706
1707   private void setSplitModeImpl(final String id, final boolean isSplit, final ArrayList<FinalizableCommand> commandList) {
1708     checkId(id);
1709     final WindowInfoImpl info = getInfo(id);
1710     if (isSplit == info.isSplit()) {
1711       return;
1712     }
1713
1714     myLayout.setSplitMode(id, isSplit);
1715
1716     boolean wasActive = info.isActive();
1717     if (wasActive) {
1718       deactivateToolWindowImpl(id, true, commandList);
1719     }
1720     final WindowInfoImpl[] infos = myLayout.getInfos();
1721     for (WindowInfoImpl info1 : infos) {
1722       appendApplyWindowInfoCmd(info1, commandList);
1723     }
1724     if (wasActive) {
1725       activateToolWindowImpl(id, commandList, true, true);
1726     }
1727     commandList.add(myToolWindowsPane.createUpdateButtonPositionCmd(id, myWindowManager.getCommandProcessor()));
1728   }
1729
1730   ToolWindowType getToolWindowInternalType(final String id) {
1731     ApplicationManager.getApplication().assertIsDispatchThread();
1732     checkId(id);
1733     return getInfo(id).getInternalType();
1734   }
1735
1736   ToolWindowType getToolWindowType(final String id) {
1737     checkId(id);
1738     return getInfo(id).getType();
1739   }
1740
1741   private void fireToolWindowRegistered(final String id) {
1742     myDispatcher.getMulticaster().toolWindowRegistered(id);
1743   }
1744
1745   private void fireStateChanged() {
1746     myDispatcher.getMulticaster().stateChanged();
1747   }
1748
1749   boolean isToolWindowActive(final String id) {
1750     ApplicationManager.getApplication().assertIsDispatchThread();
1751     checkId(id);
1752     return getInfo(id).isActive();
1753   }
1754
1755   boolean isToolWindowAutoHide(final String id) {
1756     ApplicationManager.getApplication().assertIsDispatchThread();
1757     checkId(id);
1758     return getInfo(id).isAutoHide();
1759   }
1760
1761   boolean isToolWindowVisible(final String id) {
1762     checkId(id);
1763     return getInfo(id).isVisible();
1764   }
1765
1766   void setToolWindowAutoHide(final String id, final boolean autoHide) {
1767     ApplicationManager.getApplication().assertIsDispatchThread();
1768     final ArrayList<FinalizableCommand> commandList = new ArrayList<FinalizableCommand>();
1769     setToolWindowAutoHideImpl(id, autoHide, commandList);
1770     execute(commandList);
1771   }
1772
1773   private void setToolWindowAutoHideImpl(final String id, final boolean autoHide, final ArrayList<FinalizableCommand> commandsList) {
1774     checkId(id);
1775     final WindowInfoImpl info = getInfo(id);
1776     if (info.isAutoHide() == autoHide) {
1777       return;
1778     }
1779     info.setAutoHide(autoHide);
1780     appendApplyWindowInfoCmd(info, commandsList);
1781     if (info.isVisible()) {
1782       deactivateWindows(id, commandsList);
1783       showAndActivate(id, false, commandsList, true, true);
1784     }
1785   }
1786
1787   void setToolWindowType(final String id, final ToolWindowType type) {
1788     ApplicationManager.getApplication().assertIsDispatchThread();
1789     final ArrayList<FinalizableCommand> commandList = new ArrayList<FinalizableCommand>();
1790     setToolWindowTypeImpl(id, type, commandList);
1791     execute(commandList);
1792   }
1793
1794   private void setToolWindowTypeImpl(final String id, final ToolWindowType type, final ArrayList<FinalizableCommand> commandsList) {
1795     checkId(id);
1796     final WindowInfoImpl info = getInfo(id);
1797     if (info.getType() == type) {
1798       return;
1799     }
1800     if (info.isVisible()) {
1801       final boolean dirtyMode = info.isDocked() || info.isSliding();
1802       info.setVisible(false);
1803       if (info.isFloating()) {
1804         appendRemoveFloatingDecoratorCmd(info, commandsList);
1805       }
1806       else if (info.isWindowed()) {
1807         appendRemoveWindowedDecoratorCmd(info, commandsList);
1808       }
1809       else { // docked and sliding windows
1810         appendRemoveDecoratorCmd(id, dirtyMode, commandsList);
1811       }
1812       info.setType(type);
1813       appendApplyWindowInfoCmd(info, commandsList);
1814       deactivateWindows(id, commandsList);
1815       showAndActivate(id, dirtyMode, commandsList, true, true);
1816       appendUpdateToolWindowsPaneCmd(commandsList);
1817     }
1818     else {
1819       info.setType(type);
1820       appendApplyWindowInfoCmd(info, commandsList);
1821     }
1822   }
1823
1824   private void appendApplyWindowInfoCmd(final WindowInfoImpl info, final List<FinalizableCommand> commandsList) {
1825     final StripeButton button = getStripeButton(info.getId());
1826     final InternalDecorator decorator = getInternalDecorator(info.getId());
1827     commandsList.add(new ApplyWindowInfoCmd(info, button, decorator, myWindowManager.getCommandProcessor()));
1828   }
1829
1830   /**
1831    * @see ToolWindowsPane#createAddDecoratorCmd
1832    */
1833   private void appendAddDecoratorCmd(final InternalDecorator decorator,
1834                                      final WindowInfoImpl info,
1835                                      final boolean dirtyMode,
1836                                      final List<FinalizableCommand> commandsList) {
1837     final CommandProcessor commandProcessor = myWindowManager.getCommandProcessor();
1838     final FinalizableCommand command = myToolWindowsPane.createAddDecoratorCmd(decorator, info, dirtyMode, commandProcessor);
1839     commandsList.add(command);
1840   }
1841
1842   /**
1843    * @see ToolWindowsPane#createRemoveDecoratorCmd
1844    */
1845   private void appendRemoveDecoratorCmd(final String id, final boolean dirtyMode, final List<FinalizableCommand> commandsList) {
1846     final FinalizableCommand command = myToolWindowsPane.createRemoveDecoratorCmd(id, dirtyMode, myWindowManager.getCommandProcessor());
1847     commandsList.add(command);
1848   }
1849
1850   private void appendRemoveFloatingDecoratorCmd(final WindowInfoImpl info, final List<FinalizableCommand> commandsList) {
1851     final RemoveFloatingDecoratorCmd command = new RemoveFloatingDecoratorCmd(info);
1852     commandsList.add(command);
1853   }
1854
1855   private void appendRemoveWindowedDecoratorCmd(final WindowInfoImpl info, final List<FinalizableCommand> commandsList) {
1856     final RemoveWindowedDecoratorCmd command = new RemoveWindowedDecoratorCmd(info);
1857     commandsList.add(command);
1858   }
1859
1860   /**
1861    * @see ToolWindowsPane#createAddButtonCmd
1862    */
1863   private void appendAddButtonCmd(final StripeButton button, final WindowInfoImpl info, final List<FinalizableCommand> commandsList) {
1864     final Comparator<StripeButton> comparator = myLayout.comparator(info.getAnchor());
1865     final CommandProcessor commandProcessor = myWindowManager.getCommandProcessor();
1866     final FinalizableCommand command = myToolWindowsPane.createAddButtonCmd(button, info, comparator, commandProcessor);
1867     commandsList.add(command);
1868   }
1869
1870   /**
1871    * @see ToolWindowsPane#createAddButtonCmd
1872    */
1873   private void appendRemoveButtonCmd(final String id, final List<FinalizableCommand> commandsList) {
1874     final FinalizableCommand command = myToolWindowsPane.createRemoveButtonCmd(id, myWindowManager.getCommandProcessor());
1875     commandsList.add(command);
1876   }
1877
1878   private ActionCallback appendRequestFocusInEditorComponentCmd(List<FinalizableCommand> commandList, boolean forced) {
1879     if (myProject.isDisposed()) return ActionCallback.DONE;
1880     EditorsSplitters splitters = getSplittersToFocus();
1881     CommandProcessor commandProcessor = myWindowManager.getCommandProcessor();
1882     RequestFocusInEditorComponentCmd command = new RequestFocusInEditorComponentCmd(splitters, getFocusManager(), commandProcessor, forced);
1883     commandList.add(command);
1884     return command.getDoneCallback();
1885   }
1886
1887   private void appendRequestFocusInToolWindowCmd(final String id, List<FinalizableCommand> commandList, boolean forced) {
1888     final ToolWindowImpl toolWindow = (ToolWindowImpl)getToolWindow(id);
1889     final FocusWatcher focusWatcher = myId2FocusWatcher.get(id);
1890     commandList
1891       .add(new RequestFocusInToolWindowCmd(getFocusManager(), toolWindow, focusWatcher, myWindowManager.getCommandProcessor(), forced));
1892   }
1893
1894   /**
1895    * @see ToolWindowsPane#createSetEditorComponentCmd
1896    */
1897   public void appendSetEditorComponentCmd(@Nullable final JComponent component, final List<FinalizableCommand> commandsList) {
1898     final CommandProcessor commandProcessor = myWindowManager.getCommandProcessor();
1899     final FinalizableCommand command = myToolWindowsPane.createSetEditorComponentCmd(component, commandProcessor);
1900     commandsList.add(command);
1901   }
1902
1903   private void appendUpdateToolWindowsPaneCmd(final List<FinalizableCommand> commandsList) {
1904     final JRootPane rootPane = myFrame.getRootPane();
1905     if (rootPane != null) {
1906       final FinalizableCommand command = new UpdateRootPaneCmd(rootPane, myWindowManager.getCommandProcessor());
1907       commandsList.add(command);
1908     }
1909   }
1910
1911   private EditorsSplitters getSplittersToFocus() {
1912     Window activeWindow = myWindowManager.getMostRecentFocusedWindow();
1913
1914     if (activeWindow instanceof FloatingDecorator) {
1915       IdeFocusManager ideFocusManager = IdeFocusManager.findInstanceByComponent(activeWindow);
1916       IdeFrame lastFocusedFrame = ideFocusManager.getLastFocusedFrame();
1917       JComponent frameComponent = lastFocusedFrame != null ? lastFocusedFrame.getComponent() : null;
1918       Window lastFocusedWindow = frameComponent != null ? SwingUtilities.getWindowAncestor(frameComponent) : null;
1919       activeWindow = ObjectUtils.notNull(lastFocusedWindow, activeWindow);
1920     }
1921
1922     FileEditorManagerEx fem = FileEditorManagerEx.getInstanceEx(myProject);
1923     EditorsSplitters splitters = activeWindow != null ? fem.getSplittersFor(activeWindow) : null;
1924     return splitters != null ? splitters : fem.getSplitters();
1925   }
1926
1927   /**
1928    * @return <code>true</code> if tool window with the specified <code>id</code>
1929    * is floating and has modal showing child dialog. Such windows should not be closed
1930    * when auto-hide windows are gone.
1931    */
1932   private boolean hasModalChild(final WindowInfoImpl info) {
1933     if (!info.isVisible() || !info.isFloating()) {
1934       return false;
1935     }
1936     final FloatingDecorator decorator = getFloatingDecorator(info.getId());
1937     LOG.assertTrue(decorator != null);
1938     return isModalOrHasModalChild(decorator);
1939   }
1940
1941   private static boolean isModalOrHasModalChild(final Window window) {
1942     if (window instanceof Dialog) {
1943       final Dialog dialog = (Dialog)window;
1944       if (dialog.isModal() && dialog.isShowing()) {
1945         return true;
1946       }
1947       final Window[] ownedWindows = dialog.getOwnedWindows();
1948       for (int i = ownedWindows.length - 1; i >= 0; i--) {
1949         if (isModalOrHasModalChild(ownedWindows[i])) {
1950           return true;
1951         }
1952       }
1953     }
1954     return false;
1955   }
1956
1957   @Override
1958   public void clearSideStack() {
1959     mySideStack.clear();
1960   }
1961
1962   @Override
1963   public void readExternal(final Element element) {
1964     for (final Object o : element.getChildren()) {
1965       final Element e = (Element)o;
1966       if (EDITOR_ELEMENT.equals(e.getName())) {
1967         myEditorWasActive = Boolean.valueOf(e.getAttributeValue(ACTIVE_ATTR_VALUE)).booleanValue();
1968       }
1969       else if (DesktopLayout.TAG.equals(e.getName())) { // read layout of tool windows
1970         myLayout.readExternal(e);
1971       }
1972       else if (LAYOUT_TO_RESTORE.equals(e.getName())) {
1973         myLayoutToRestoreLater = new DesktopLayout();
1974         myLayoutToRestoreLater.readExternal(e);
1975       }
1976     }
1977   }
1978
1979   @Override
1980   public void writeExternal(final Element element) {
1981     if (myFrame == null) {
1982       // do nothing if the project was not opened
1983       return;
1984     }
1985     final String[] ids = getToolWindowIds();
1986
1987     // Update size of all open floating windows. See SCR #18439
1988     for (final String id : ids) {
1989       final WindowInfoImpl info = getInfo(id);
1990       if (info.isVisible()) {
1991         final InternalDecorator decorator = getInternalDecorator(id);
1992         LOG.assertTrue(decorator != null);
1993         decorator.fireResized();
1994       }
1995     }
1996
1997     // Save frame's bounds
1998     final Rectangle frameBounds = myFrame.getBounds();
1999     final Element frameElement = new Element(FRAME_ELEMENT);
2000     element.addContent(frameElement);
2001     frameElement.setAttribute(X_ATTR, Integer.toString(frameBounds.x));
2002     frameElement.setAttribute(Y_ATTR, Integer.toString(frameBounds.y));
2003     frameElement.setAttribute(WIDTH_ATTR, Integer.toString(frameBounds.width));
2004     frameElement.setAttribute(HEIGHT_ATTR, Integer.toString(frameBounds.height));
2005     frameElement.setAttribute(EXTENDED_STATE_ATTR, Integer.toString(myFrame.getExtendedState()));
2006     // Save whether editor is active or not
2007     final Element editorElement = new Element(EDITOR_ELEMENT);
2008     editorElement.setAttribute(ACTIVE_ATTR_VALUE, isEditorComponentActive() ? Boolean.TRUE.toString() : Boolean.FALSE.toString());
2009     element.addContent(editorElement);
2010     // Save layout of tool windows
2011     final Element layoutElement = new Element(DesktopLayout.TAG);
2012     element.addContent(layoutElement);
2013     myLayout.writeExternal(layoutElement);
2014     if (myLayoutToRestoreLater != null) {
2015       Element layoutToRestoreElement = new Element(LAYOUT_TO_RESTORE);
2016       element.addContent(layoutToRestoreElement);
2017       myLayoutToRestoreLater.writeExternal(layoutToRestoreElement);
2018     }
2019   }
2020
2021   public void setDefaultState(@NotNull final ToolWindowImpl toolWindow,
2022                               @Nullable final ToolWindowAnchor anchor,
2023                               @Nullable final ToolWindowType type,
2024                               @Nullable final Rectangle floatingBounds) {
2025
2026     final WindowInfoImpl info = getInfo(toolWindow.getId());
2027     if (info.wasRead()) return;
2028
2029     if (floatingBounds != null) {
2030       info.setFloatingBounds(floatingBounds);
2031     }
2032
2033     if (anchor != null) {
2034       toolWindow.setAnchor(anchor, null);
2035     }
2036
2037     if (type != null) {
2038       toolWindow.setType(type, null);
2039     }
2040   }
2041
2042   public void setDefaultContentUiType(ToolWindowImpl toolWindow, @NotNull ToolWindowContentUiType type) {
2043     final WindowInfoImpl info = getInfo(toolWindow.getId());
2044     if (info.wasRead()) return;
2045     toolWindow.setContentUiType(type, null);
2046   }
2047
2048
2049   public void stretchWidth(ToolWindowImpl toolWindow, int value) {
2050     myToolWindowsPane.stretchWidth(toolWindow, value);
2051   }
2052
2053   @Override
2054   public boolean isMaximized(@NotNull ToolWindow wnd) {
2055     return myToolWindowsPane.isMaximized(wnd);
2056   }
2057
2058   @Override
2059   public void setMaximized(@NotNull ToolWindow wnd, boolean maximized) {
2060     myToolWindowsPane.setMaximized(wnd, maximized);
2061   }
2062
2063   public void stretchHeight(ToolWindowImpl toolWindow, int value) {
2064     myToolWindowsPane.stretchHeight(toolWindow, value);
2065   }
2066
2067   private static class BalloonHyperlinkListener implements HyperlinkListener {
2068     private Balloon myBalloon;
2069     private final HyperlinkListener myListener;
2070
2071     public BalloonHyperlinkListener(HyperlinkListener listener) {
2072       myListener = listener;
2073     }
2074
2075     @Override
2076     public void hyperlinkUpdate(HyperlinkEvent e) {
2077       if (myBalloon != null && e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
2078         myBalloon.hide();
2079       }
2080       if (myListener != null) {
2081         myListener.hyperlinkUpdate(e);
2082       }
2083     }
2084   }
2085
2086
2087   /**
2088    * This command creates and shows <code>FloatingDecorator</code>.
2089    */
2090   private final class AddFloatingDecoratorCmd extends FinalizableCommand {
2091     private final FloatingDecorator myFloatingDecorator;
2092
2093     /**
2094      * Creates floating decorator for specified floating decorator.
2095      */
2096     private AddFloatingDecoratorCmd(final InternalDecorator decorator, final WindowInfoImpl info) {
2097       super(myWindowManager.getCommandProcessor());
2098       myFloatingDecorator = new FloatingDecorator(myFrame, info.copy(), decorator);
2099       myId2FloatingDecorator.put(info.getId(), myFloatingDecorator);
2100       final Rectangle bounds = info.getFloatingBounds();
2101       if (bounds != null &&
2102           bounds.width > 0 &&
2103           bounds.height > 0 &&
2104           myWindowManager.isInsideScreenBounds(bounds.x, bounds.y, bounds.width)) {
2105         myFloatingDecorator.setBounds(bounds);
2106       }
2107       else { // place new frame at the center of main frame if there are no floating bounds
2108         Dimension size = decorator.getSize();
2109         if (size.width == 0 || size.height == 0) {
2110           size = decorator.getPreferredSize();
2111         }
2112         myFloatingDecorator.setSize(size);
2113         myFloatingDecorator.setLocationRelativeTo(myFrame);
2114       }
2115     }
2116
2117     @Override
2118     public void run() {
2119       try {
2120         myFloatingDecorator.show();
2121       }
2122       finally {
2123         finish();
2124       }
2125     }
2126   }
2127
2128   /**
2129    * This command hides and destroys floating decorator for tool window
2130    * with specified <code>ID</code>.
2131    */
2132   private final class RemoveFloatingDecoratorCmd extends FinalizableCommand {
2133     private final FloatingDecorator myFloatingDecorator;
2134
2135     private RemoveFloatingDecoratorCmd(final WindowInfoImpl info) {
2136       super(myWindowManager.getCommandProcessor());
2137       myFloatingDecorator = getFloatingDecorator(info.getId());
2138       myId2FloatingDecorator.remove(info.getId());
2139       info.setFloatingBounds(myFloatingDecorator.getBounds());
2140     }
2141
2142     @Override
2143     public void run() {
2144       try {
2145         myFloatingDecorator.dispose();
2146       }
2147       finally {
2148         finish();
2149       }
2150     }
2151
2152     @Override
2153     @Nullable
2154     public Condition getExpireCondition() {
2155       return ApplicationManager.getApplication().getDisposed();
2156     }
2157   }
2158
2159   /**
2160    * This command creates and shows <code>WindowedDecorator</code>.
2161    */
2162   private final class AddWindowedDecoratorCmd extends FinalizableCommand {
2163     private final WindowedDecorator myWindowedDecorator;
2164
2165     /**
2166      * Creates floating decorator for specified floating decorator.
2167      */
2168     private AddWindowedDecoratorCmd(final InternalDecorator decorator, final WindowInfoImpl info) {
2169       super(myWindowManager.getCommandProcessor());
2170       myWindowedDecorator = new WindowedDecorator(myProject, info.copy(), decorator);
2171       Window window = myWindowedDecorator.getFrame();
2172       final Rectangle bounds = info.getFloatingBounds();
2173       if (bounds != null) {
2174         bounds.setBounds(bounds.x + DIVIDER_WIDTH, bounds.y + DIVIDER_WIDTH, bounds.width - 2 * DIVIDER_WIDTH, bounds.height - 2 * DIVIDER_WIDTH);
2175       }
2176       if (bounds != null &&
2177           bounds.width > 0 &&
2178           bounds.height > 0 &&
2179           myWindowManager.isInsideScreenBounds(bounds.x, bounds.y, bounds.width)) {
2180         window.setBounds(bounds);
2181       }
2182       else { // place new frame at the center of main frame if there are no floating bounds
2183         Dimension size = decorator.getSize();
2184         if (size.width == 0 || size.height == 0) {
2185           size = decorator.getPreferredSize();
2186         }
2187         window.setSize(size);
2188         window.setLocationRelativeTo(myFrame);
2189       }
2190       myId2WindowedDecorator.put(info.getId(), myWindowedDecorator);
2191       myWindowedDecorator.addDisposable(new Disposable() {
2192         @Override
2193         public void dispose() {
2194           if (myId2WindowedDecorator.get(info.getId()) != null) {
2195             hideToolWindow(info.getId(), false);
2196           }
2197         }
2198       });
2199     }
2200
2201     @Override
2202     public void run() {
2203       try {
2204         myWindowedDecorator.show(false);
2205         Window window = myWindowedDecorator.getFrame();
2206         JRootPane rootPane = ((RootPaneContainer)window).getRootPane();
2207         Rectangle rootPaneBounds = rootPane.getBounds();
2208         Point point = rootPane.getLocationOnScreen();
2209         Rectangle windowBounds = window.getBounds();
2210         //Point windowLocation = windowBounds.getLocation();
2211         //windowLocation.translate(windowLocation.x - point.x, windowLocation.y - point.y);
2212         window.setLocation(2 * windowBounds.x - point.x,  2 * windowBounds.y - point.y);
2213         window.setSize(2 * windowBounds.width - rootPaneBounds.width, 2 * windowBounds.height - rootPaneBounds.height);
2214       }
2215       finally {
2216         finish();
2217       }
2218     }
2219   }
2220
2221   /**
2222    * This command hides and destroys floating decorator for tool window
2223    * with specified <code>ID</code>.
2224    */
2225   private final class RemoveWindowedDecoratorCmd extends FinalizableCommand {
2226     private final WindowedDecorator myWindowedDecorator;
2227
2228     private RemoveWindowedDecoratorCmd(final WindowInfoImpl info) {
2229       super(myWindowManager.getCommandProcessor());
2230       myWindowedDecorator = getWindowedDecorator(info.getId());
2231       myId2WindowedDecorator.remove(info.getId());
2232
2233       JRootPane rootPane = ((RootPaneContainer)myWindowedDecorator.getFrame()).getRootPane();
2234       if (!rootPane.isShowing()) return;
2235       Rectangle bounds = rootPane.getBounds();
2236       Point location = rootPane.getLocationOnScreen();
2237       bounds.setBounds(location.x - DIVIDER_WIDTH, location.y - DIVIDER_WIDTH, bounds.width + 2 * DIVIDER_WIDTH, bounds.height + 2 * DIVIDER_WIDTH);
2238       info.setFloatingBounds(bounds);
2239     }
2240
2241     @Override
2242     public void run() {
2243       try {
2244         Disposer.dispose(myWindowedDecorator);
2245       }
2246       finally {
2247         finish();
2248       }
2249     }
2250
2251     @Override
2252     @Nullable
2253     public Condition getExpireCondition() {
2254       return ApplicationManager.getApplication().getDisposed();
2255     }
2256   }
2257
2258   private final class EditorComponentFocusWatcher extends FocusWatcher {
2259     @Override
2260     protected void focusedComponentChanged(final Component component, final AWTEvent cause) {
2261       if (myWindowManager.getCommandProcessor().getCommandCount() > 0 || component == null) {
2262         return;
2263       }
2264       final KeyboardFocusManager mgr = KeyboardFocusManager.getCurrentKeyboardFocusManager();
2265       final Component owner = mgr.getFocusOwner();
2266
2267       if (owner instanceof EditorComponentImpl && cause instanceof FocusEvent) {
2268         JFrame frame = WindowManager.getInstance().getFrame(myProject);
2269         Component oppositeComponent = ((FocusEvent)cause).getOppositeComponent();
2270         if (oppositeComponent != null && UIUtil.getWindow(oppositeComponent) != frame) {
2271           return;
2272         }
2273       }
2274
2275       IdeFocusManager.getInstance(myProject).doWhenFocusSettlesDown(new ExpirableRunnable.ForProject(myProject) {
2276         @Override
2277         public void run() {
2278           if (mgr.getFocusOwner() == owner) {
2279             activateEditorComponent(false);
2280           }
2281         }
2282       });
2283     }
2284   }
2285
2286
2287   /**
2288    * Notifies window manager about focus traversal in tool window
2289    */
2290   private final class ToolWindowFocusWatcher extends FocusWatcher {
2291     private final String myId;
2292     private final ToolWindowImpl myToolWindow;
2293
2294
2295     private ToolWindowFocusWatcher(final ToolWindowImpl toolWindow) {
2296       myId = toolWindow.getId();
2297       install(toolWindow.getComponent());
2298       myToolWindow = toolWindow;
2299     }
2300
2301     public void deinstall() {
2302       deinstall(myToolWindow.getComponent());
2303     }
2304
2305     @Override
2306     protected boolean isFocusedComponentChangeValid(final Component comp, final AWTEvent cause) {
2307       return myWindowManager.getCommandProcessor().getCommandCount() == 0 && comp != null;
2308     }
2309
2310     @Override
2311     protected void focusedComponentChanged(final Component component, final AWTEvent cause) {
2312       if (myWindowManager.getCommandProcessor().getCommandCount() > 0 || component == null) {
2313         return;
2314       }
2315       final WindowInfoImpl info = getInfo(myId);
2316       //getFocusManagerImpl(myProject)..cancelAllRequests();
2317
2318       if (!info.isActive()) {
2319         getFocusManagerImpl(myProject).doWhenFocusSettlesDown(new EdtRunnable() {
2320           @Override
2321           public void runEdt() {
2322             WindowInfoImpl windowInfo = myLayout.getInfo(myId, true);
2323             if (windowInfo == null || !windowInfo.isVisible()) return;
2324             activateToolWindow(myId, false, false);
2325           }
2326         });
2327       }
2328     }
2329   }
2330
2331   /**
2332    * Spies on IdeToolWindow properties and applies them to the window
2333    * state.
2334    */
2335   private final class MyToolWindowPropertyChangeListener implements PropertyChangeListener {
2336     @Override
2337     public void propertyChange(final PropertyChangeEvent e) {
2338       ToolWindowImpl toolWindow = (ToolWindowImpl)e.getSource();
2339       if (ToolWindowEx.PROP_AVAILABLE.equals(e.getPropertyName())) {
2340         final WindowInfoImpl info = getInfo(toolWindow.getId());
2341         if (!toolWindow.isAvailable() && info.isVisible()) {
2342           hideToolWindow(toolWindow.getId(), false);
2343         }
2344       }
2345       StripeButton button = myId2StripeButton.get(toolWindow.getId());
2346       if (button != null) button.updatePresentation();
2347       ActivateToolWindowAction.updateToolWindowActionPresentation(toolWindow);
2348     }
2349   }
2350
2351   /**
2352    * Translates events from InternalDecorator into ToolWindowManager method invocations.
2353    */
2354   private final class MyInternalDecoratorListener implements InternalDecoratorListener {
2355     @Override
2356     public void anchorChanged(final InternalDecorator source, final ToolWindowAnchor anchor) {
2357       setToolWindowAnchor(source.getToolWindow().getId(), anchor);
2358     }
2359
2360     @Override
2361     public void autoHideChanged(final InternalDecorator source, final boolean autoHide) {
2362       setToolWindowAutoHide(source.getToolWindow().getId(), autoHide);
2363     }
2364
2365     @Override
2366     public void hidden(final InternalDecorator source) {
2367       hideToolWindow(source.getToolWindow().getId(), false);
2368     }
2369
2370     @Override
2371     public void hiddenSide(final InternalDecorator source) {
2372       hideToolWindow(source.getToolWindow().getId(), true);
2373     }
2374
2375     @Override
2376     public void contentUiTypeChanges(InternalDecorator source, @NotNull ToolWindowContentUiType type) {
2377       setContentUiType(source.getToolWindow().getId(), type);
2378     }
2379
2380     /**
2381      * Handles event from decorator and modify weight/floating bounds of the
2382      * tool window depending on decoration type.
2383      */
2384     @Override
2385     public void resized(final InternalDecorator source) {
2386       if (!source.isShowing()) {
2387         return; // do not recalculate the tool window size if it is not yet shown (and, therefore, has 0,0,0,0 bounds)
2388       }
2389
2390       final WindowInfoImpl info = getInfo(source.getToolWindow().getId());
2391       InternalDecorator another = null;
2392       if (info.isFloating()) {
2393         final Window owner = SwingUtilities.getWindowAncestor(source);
2394         if (owner != null) {
2395           info.setFloatingBounds(owner.getBounds());
2396         }
2397       }
2398       else { // docked and sliding windows
2399         ToolWindowAnchor anchor = info.getAnchor();
2400         if (source.getParent() instanceof Splitter) {
2401           float sizeInSplit = anchor.isSplitVertically() ? source.getHeight() : source.getWidth();
2402           Splitter splitter = (Splitter)source.getParent();
2403           if (splitter.getSecondComponent() == source) {
2404             sizeInSplit += splitter.getDividerWidth();
2405             another = (InternalDecorator)splitter.getFirstComponent();
2406           }
2407           else {
2408             another = (InternalDecorator)splitter.getSecondComponent();
2409           }
2410           if (anchor.isSplitVertically()) {
2411             info.setSideWeight(sizeInSplit / (float)splitter.getHeight());
2412           }
2413           else {
2414             info.setSideWeight(sizeInSplit / (float)splitter.getWidth());
2415           }
2416         }
2417
2418         float paneWeight = anchor.isHorizontal()
2419                            ? (float)source.getHeight() / (float)myToolWindowsPane.getMyLayeredPane().getHeight()
2420                            : (float)source.getWidth() / (float)myToolWindowsPane.getMyLayeredPane().getWidth();
2421         info.setWeight(paneWeight);
2422         if (another != null && anchor.isSplitVertically()) {
2423           paneWeight = anchor.isHorizontal()
2424                        ? (float)another.getHeight() / (float)myToolWindowsPane.getMyLayeredPane().getHeight()
2425                        : (float)another.getWidth() / (float)myToolWindowsPane.getMyLayeredPane().getWidth();
2426           another.getWindowInfo().setWeight(paneWeight);
2427         }
2428       }
2429     }
2430
2431     @Override
2432     public void activated(final InternalDecorator source) {
2433       activateToolWindow(source.getToolWindow().getId(), true, true);
2434     }
2435
2436     @Override
2437     public void typeChanged(final InternalDecorator source, final ToolWindowType type) {
2438       setToolWindowType(source.getToolWindow().getId(), type);
2439     }
2440
2441     @Override
2442     public void sideStatusChanged(final InternalDecorator source, final boolean isSideTool) {
2443       setSideTool(source.getToolWindow().getId(), isSideTool);
2444     }
2445
2446     public void visibleStripeButtonChanged(InternalDecorator source, boolean visible) {
2447       setShowStripeButton(source.getToolWindow().getId(), visible);
2448     }
2449   }
2450
2451   private void updateComponentTreeUI() {
2452     ApplicationManager.getApplication().assertIsDispatchThread();
2453     final WindowInfoImpl[] infos = myLayout.getInfos();
2454     for (WindowInfoImpl info : infos) {
2455       // the main goal is to update hidden TW components because they are not in the hierarchy
2456       // and will not be updated automatically but unfortunately the visibility of a TW may change
2457       // during the same actionPerformed() so we can't optimize and have to process all of them
2458       IJSwingUtilities.updateComponentTreeUI(getInternalDecorator(info.getId()));
2459     }
2460   }
2461
2462   private final class MyUIManagerPropertyChangeListener implements PropertyChangeListener {
2463     @Override
2464     public void propertyChange(final PropertyChangeEvent e) {
2465       updateComponentTreeUI();
2466     }
2467   }
2468
2469   private final class MyLafManagerListener implements LafManagerListener {
2470     @Override
2471     public void lookAndFeelChanged(final LafManager source) {
2472       updateComponentTreeUI();
2473     }
2474   }
2475
2476
2477   @Override
2478   @NotNull
2479   public String getComponentName() {
2480     return "ToolWindowManager";
2481   }
2482
2483   @NotNull
2484   public ActionCallback requestDefaultFocus(final boolean forced) {
2485     return getFocusManagerImpl(myProject).requestFocus(new FocusCommand() {
2486       @NotNull
2487       @Override
2488       public ActionCallback run() {
2489         return processDefaultFocusRequest(forced);
2490       }
2491     }, forced);
2492   }
2493
2494   private void focusToolWinowByDefault(@Nullable String idToIngore) {
2495     String toFocus = null;
2496
2497     for (String each : myActiveStack.getStack()) {
2498       if (idToIngore != null && idToIngore.equalsIgnoreCase(each)) continue;
2499
2500       if (getInfo(each).isVisible()) {
2501         toFocus = each;
2502         break;
2503       }
2504     }
2505
2506     if (toFocus == null) {
2507       for (String each : myActiveStack.getPersistentStack()) {
2508         if (idToIngore != null && idToIngore.equalsIgnoreCase(each)) continue;
2509
2510         if (getInfo(each).isVisible()) {
2511           toFocus = each;
2512           break;
2513         }
2514       }
2515     }
2516
2517     if (toFocus != null) {
2518       activateToolWindow(toFocus, false, true);
2519     }
2520   }
2521
2522   private ActionCallback processDefaultFocusRequest(boolean forced) {
2523     if (ModalityState.NON_MODAL.equals(ModalityState.current())) {
2524       final String activeId = getActiveToolWindowId();
2525       if (isEditorComponentActive() || activeId == null || getToolWindow(activeId) == null) {
2526         activateEditorComponent(forced, true);
2527       }
2528       else {
2529         activateToolWindow(activeId, forced, true);
2530       }
2531
2532       return ActionCallback.DONE;
2533     }
2534     Window activeWindow = KeyboardFocusManager.getCurrentKeyboardFocusManager().getActiveWindow();
2535     if (activeWindow != null) {
2536       JRootPane root = null;
2537       if (activeWindow instanceof JDialog) {
2538         root = ((JDialog)activeWindow).getRootPane();
2539       }
2540       else if (activeWindow instanceof JFrame) {
2541         root = ((JFrame)activeWindow).getRootPane();
2542       }
2543
2544       if (root != null) {
2545         JComponent toFocus = IdeFocusTraversalPolicy.getPreferredFocusedComponent(root);
2546         if (toFocus != null) {
2547           if (DialogWrapper.findInstance(toFocus) != null) {
2548             return ActionCallback.DONE; //IDEA-80929
2549           }
2550           return IdeFocusManager.findInstanceByComponent(toFocus).requestFocus(toFocus, forced);
2551         }
2552       }
2553     }
2554     return ActionCallback.REJECTED;
2555   }
2556
2557
2558   /**
2559    * Delegate method for compatibility with older versions of IDEA
2560    */
2561   @NotNull
2562   public ActionCallback requestFocus(@NotNull Component c, boolean forced) {
2563     return IdeFocusManager.getInstance(myProject).requestFocus(c, forced);
2564   }
2565
2566   @NotNull
2567   public ActionCallback requestFocus(@NotNull FocusCommand command, boolean forced) {
2568     return IdeFocusManager.getInstance(myProject).requestFocus(command, forced);
2569   }
2570
2571   public void doWhenFocusSettlesDown(@NotNull Runnable runnable) {
2572     IdeFocusManager.getInstance(myProject).doWhenFocusSettlesDown(runnable);
2573   }
2574
2575   public boolean dispatch(@NotNull KeyEvent e) {
2576     return IdeFocusManager.getInstance(myProject).dispatch(e);
2577   }
2578
2579   public Expirable getTimestamp(boolean trackOnlyForcedCommands) {
2580     return IdeFocusManager.getInstance(myProject).getTimestamp(trackOnlyForcedCommands);
2581   }
2582
2583   public void setShowStripeButton(String id, boolean visibleOnPanel) {
2584     checkId(id);
2585     WindowInfoImpl info = getInfo(id);
2586     if (visibleOnPanel == info.isShowStripeButton()) {
2587       return;
2588     }
2589     info.setShowStripeButton(visibleOnPanel);
2590     UsageTrigger.trigger("StripeButton[" + id + "]." + (visibleOnPanel ? "shown" : "hidden"));
2591
2592     final ArrayList<FinalizableCommand> commandList = new ArrayList<FinalizableCommand>();
2593     appendApplyWindowInfoCmd(info, commandList);
2594     execute(commandList);
2595   }
2596
2597   public boolean isShowStripeButton(String id) {
2598     WindowInfoImpl info = getInfo(id);
2599     return info == null || info.isShowStripeButton();
2600   }
2601 }