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