replaced <code></code> with more concise {@code}
[idea/community.git] / platform / platform-impl / src / com / intellij / openapi / wm / impl / ToolWindowsPane.java
1 /*
2  * Copyright 2000-2017 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.RemoteDesktopService;
19 import com.intellij.ide.ui.UISettings;
20 import com.intellij.ide.ui.UISettingsListener;
21 import com.intellij.openapi.Disposable;
22 import com.intellij.openapi.diagnostic.Logger;
23 import com.intellij.openapi.project.Project;
24 import com.intellij.openapi.ui.Splitter;
25 import com.intellij.openapi.ui.ThreeComponentsSplitter;
26 import com.intellij.openapi.util.Disposer;
27 import com.intellij.openapi.util.Pair;
28 import com.intellij.openapi.util.SystemInfo;
29 import com.intellij.openapi.util.registry.Registry;
30 import com.intellij.openapi.wm.ToolWindow;
31 import com.intellij.openapi.wm.ToolWindowAnchor;
32 import com.intellij.openapi.wm.ToolWindowType;
33 import com.intellij.openapi.wm.impl.commands.FinalizableCommand;
34 import com.intellij.reference.SoftReference;
35 import com.intellij.ui.ScreenUtil;
36 import com.intellij.ui.components.JBLayeredPane;
37 import com.intellij.util.containers.HashMap;
38 import com.intellij.util.ui.UIUtil;
39 import org.jetbrains.annotations.NotNull;
40 import org.jetbrains.annotations.Nullable;
41
42 import javax.swing.*;
43 import java.awt.*;
44 import java.awt.image.BufferedImage;
45 import java.lang.ref.Reference;
46 import java.util.ArrayList;
47 import java.util.Comparator;
48 import java.util.List;
49
50 /**
51  * This panel contains all tool stripes and JLayeredPanle at the center area. All tool windows are
52  * located inside this layered pane.
53  *
54  * @author Anton Katilin
55  * @author Vladimir Kondratyev
56  */
57 public final class ToolWindowsPane extends JBLayeredPane implements UISettingsListener, Disposable {
58   private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.wm.impl.ToolWindowsPane");
59
60   private final IdeFrameImpl myFrame;
61
62   private final HashMap<String, StripeButton> myId2Button = new HashMap<>();
63   private final HashMap<String, InternalDecorator> myId2Decorator = new HashMap<>();
64   private final HashMap<StripeButton, WindowInfoImpl> myButton2Info = new HashMap<>();
65   private final HashMap<InternalDecorator, WindowInfoImpl> myDecorator2Info = new HashMap<>();
66   private final HashMap<String, Float> myId2SplitProportion = new HashMap<>();
67   private Pair<ToolWindow, Integer> myMaximizedProportion;
68   /**
69    * This panel is the layered pane where all sliding tool windows are located. The DEFAULT
70    * layer contains splitters. The PALETTE layer contains all sliding tool windows.
71    */
72   private final MyLayeredPane myLayeredPane;
73   /*
74    * Splitters.
75    */
76   private final ThreeComponentsSplitter myVerticalSplitter;
77   private final ThreeComponentsSplitter myHorizontalSplitter;
78
79   /*
80    * Tool stripes.
81    */
82   private final Stripe myLeftStripe;
83   private final Stripe myRightStripe;
84   private final Stripe myBottomStripe;
85   private final Stripe myTopStripe;
86
87   private final List<Stripe> myStripes = new ArrayList<>();
88
89   private final ToolWindowManagerImpl myManager;
90
91   private boolean myStripesOverlayed;
92   private boolean myWidescreen;
93   private boolean myLeftHorizontalSplit;
94   private boolean myRightHorizontalSplit;
95
96   ToolWindowsPane(@NotNull IdeFrameImpl frame, @NotNull ToolWindowManagerImpl manager) {
97     myManager = manager;
98
99     setOpaque(false);
100     myFrame = frame;
101
102     // Splitters
103     myVerticalSplitter = new ThreeComponentsSplitter(true);
104     Disposer.register(this, myVerticalSplitter);
105     myVerticalSplitter.setDividerWidth(0);
106     myVerticalSplitter.setDividerMouseZoneSize(Registry.intValue("ide.splitter.mouseZone"));
107     myVerticalSplitter.setBackground(Color.gray);
108     myHorizontalSplitter = new ThreeComponentsSplitter(false);
109     Disposer.register(this, myHorizontalSplitter);
110     myHorizontalSplitter.setDividerWidth(0);
111     myHorizontalSplitter.setDividerMouseZoneSize(Registry.intValue("ide.splitter.mouseZone"));
112     myHorizontalSplitter.setBackground(Color.gray);
113     myWidescreen = UISettings.getInstance().getWideScreenSupport();
114     myLeftHorizontalSplit = UISettings.getInstance().getLeftHorizontalSplit();
115     myRightHorizontalSplit = UISettings.getInstance().getRightHorizontalSplit();
116     if (myWidescreen) {
117       myHorizontalSplitter.setInnerComponent(myVerticalSplitter);
118     }
119     else {
120       myVerticalSplitter.setInnerComponent(myHorizontalSplitter);
121     }
122
123     // Tool stripes
124
125     myTopStripe = new Stripe(SwingConstants.TOP, manager);
126     myStripes.add(myTopStripe);
127     myLeftStripe = new Stripe(SwingConstants.LEFT, manager);
128     myStripes.add(myLeftStripe);
129     myBottomStripe = new Stripe(SwingConstants.BOTTOM, manager);
130     myStripes.add(myBottomStripe);
131     myRightStripe = new Stripe(SwingConstants.RIGHT, manager);
132     myStripes.add(myRightStripe);
133
134     updateToolStripesVisibility();
135
136     // Layered pane
137
138     myLayeredPane = new MyLayeredPane(myWidescreen ? myHorizontalSplitter : myVerticalSplitter);
139
140     // Compose layout
141
142     add(myTopStripe, JLayeredPane.POPUP_LAYER);
143     add(myLeftStripe, JLayeredPane.POPUP_LAYER);
144     add(myBottomStripe, JLayeredPane.POPUP_LAYER);
145     add(myRightStripe, JLayeredPane.POPUP_LAYER);
146     add(myLayeredPane, JLayeredPane.DEFAULT_LAYER);
147   }
148
149   @Override
150   public void doLayout() {
151     Dimension size = getSize();
152     if (!myTopStripe.isVisible()) {
153       myTopStripe.setBounds(0, 0, 0, 0);
154       myBottomStripe.setBounds(0, 0, 0, 0);
155       myLeftStripe.setBounds(0, 0, 0, 0);
156       myRightStripe.setBounds(0, 0, 0, 0);
157       myLayeredPane.setBounds(0, 0, getWidth(), getHeight());
158     }
159     else {
160       Dimension topSize = myTopStripe.getPreferredSize();
161       Dimension bottomSize = myBottomStripe.getPreferredSize();
162       Dimension leftSize = myLeftStripe.getPreferredSize();
163       Dimension rightSize = myRightStripe.getPreferredSize();
164
165       myTopStripe.setBounds(0, 0, size.width, topSize.height);
166       myLeftStripe.setBounds(0, topSize.height, leftSize.width, size.height - topSize.height - bottomSize.height);
167       myRightStripe
168         .setBounds(size.width - rightSize.width, topSize.height, rightSize.width, size.height - topSize.height - bottomSize.height);
169       myBottomStripe.setBounds(0, size.height - bottomSize.height, size.width, bottomSize.height);
170
171       if (UISettings.getInstance().getHideToolStripes() || UISettings.getInstance().getPresentationMode()) {
172         myLayeredPane.setBounds(0, 0, size.width, size.height);
173       }
174       else {
175         myLayeredPane.setBounds(leftSize.width, topSize.height, size.width - leftSize.width - rightSize.width,
176                                 size.height - topSize.height - bottomSize.height);
177       }
178     }
179   }
180
181   @Override
182   protected void paintChildren(Graphics g) {
183     super.paintChildren(g);
184   }
185
186   /**
187    * Invoked when enclosed frame is being shown.
188    */
189   @Override
190   public final void addNotify() {
191     super.addNotify();
192   }
193
194   public Project getProject() {
195     return myFrame.getProject();
196   }
197
198   @Override
199   public final void uiSettingsChanged(final UISettings uiSettings) {
200     updateToolStripesVisibility();
201     updateLayout();
202   }
203
204   /**
205    * Creates command which adds button into the specified tool stripe.
206    * Command uses copy of passed {@code info} object.
207    *
208    * @param button         button which should be added.
209    * @param info           window info for the corresponded tool window.
210    * @param comparator     which is used to sort buttons within the stripe.
211    * @param finishCallBack invoked when the command is completed.
212    */
213   @NotNull
214   final FinalizableCommand createAddButtonCmd(final StripeButton button,
215                                               @NotNull WindowInfoImpl info,
216                                               @NotNull Comparator<StripeButton> comparator,
217                                               @NotNull Runnable finishCallBack) {
218     final WindowInfoImpl copiedInfo = info.copy();
219     myId2Button.put(copiedInfo.getId(), button);
220     myButton2Info.put(button, copiedInfo);
221     return new AddToolStripeButtonCmd(button, copiedInfo, comparator, finishCallBack);
222   }
223
224   /**
225    * Creates command which shows tool window with specified set of parameters.
226    * Command uses cloned copy of passed {@code info} object.
227    *
228    * @param dirtyMode if {@code true} then JRootPane will not be validated and repainted after adding
229    *                  the decorator. Moreover in this (dirty) mode animation doesn't work.
230    */
231   @NotNull
232   final FinalizableCommand createAddDecoratorCmd(@NotNull InternalDecorator decorator,
233                                                  @NotNull WindowInfoImpl info,
234                                                  final boolean dirtyMode,
235                                                  @NotNull Runnable finishCallBack) {
236     final WindowInfoImpl copiedInfo = info.copy();
237     final String id = copiedInfo.getId();
238
239     myDecorator2Info.put(decorator, copiedInfo);
240     myId2Decorator.put(id, decorator);
241
242     if (info.isDocked()) {
243       WindowInfoImpl sideInfo = getDockedInfoAt(info.getAnchor(), !info.isSplit());
244       if (sideInfo == null) {
245         return new AddDockedComponentCmd(decorator, info, dirtyMode, finishCallBack);
246       }
247       else {
248         return new AddAndSplitDockedComponentCmd(decorator, info, dirtyMode, finishCallBack);
249       }
250     }
251     else if (info.isSliding()) {
252       return new AddSlidingComponentCmd(decorator, info, dirtyMode, finishCallBack);
253     }
254     else {
255       throw new IllegalArgumentException("Unknown window type: " + info.getType());
256     }
257   }
258
259   /**
260    * Creates command which removes tool button from tool stripe.
261    *
262    * @param id {@code ID} of the button to be removed.
263    */
264   @NotNull
265   final FinalizableCommand createRemoveButtonCmd(@NotNull String id, @NotNull Runnable finishCallBack) {
266     final StripeButton button = getButtonById(id);
267     final WindowInfoImpl info = getButtonInfoById(id);
268
269     myButton2Info.remove(button);
270     myId2Button.remove(id);
271     return new RemoveToolStripeButtonCmd(button, info, finishCallBack);
272   }
273
274   /**
275    * Creates command which hides tool window with specified set of parameters.
276    *
277    * @param dirtyMode if {@code true} then JRootPane will not be validated and repainted after removing
278    *                  the decorator. Moreover in this (dirty) mode animation doesn't work.
279    */
280   @NotNull
281   final FinalizableCommand createRemoveDecoratorCmd(@NotNull String id, final boolean dirtyMode, @NotNull Runnable finishCallBack) {
282     final Component decorator = getDecoratorById(id);
283     final WindowInfoImpl info = getDecoratorInfoById(id);
284
285     myDecorator2Info.remove(decorator);
286     myId2Decorator.remove(id);
287
288     WindowInfoImpl sideInfo = getDockedInfoAt(info.getAnchor(), !info.isSplit());
289
290     if (info.isDocked()) {
291       if (sideInfo == null) {
292         return new RemoveDockedComponentCmd(info, dirtyMode, finishCallBack);
293       }
294       else {
295         return new RemoveSplitAndDockedComponentCmd(info, dirtyMode, finishCallBack);
296       }
297     }
298     else if (info.isSliding()) {
299       return new RemoveSlidingComponentCmd(decorator, info, dirtyMode, finishCallBack);
300     }
301     else {
302       throw new IllegalArgumentException("Unknown window type");
303     }
304   }
305
306   /**
307    * Creates command which sets specified document component.
308    *
309    * @param component component to be set.
310    */
311   @NotNull
312   final FinalizableCommand createSetEditorComponentCmd(final JComponent component, @NotNull Runnable finishCallBack) {
313     return new SetEditorComponentCmd(component, finishCallBack);
314   }
315
316   @NotNull
317   final FinalizableCommand createUpdateButtonPositionCmd(@NotNull String id, @NotNull Runnable finishCallback) {
318     return new UpdateButtonPositionCmd(id, finishCallback);
319   }
320
321   @NotNull
322   public final JComponent getMyLayeredPane() {
323     return myLayeredPane;
324   }
325
326   @Nullable
327   private StripeButton getButtonById(final String id) {
328     return myId2Button.get(id);
329   }
330
331   private Component getDecoratorById(final String id) {
332     return myId2Decorator.get(id);
333   }
334
335   /**
336    * @param id {@code ID} of tool stripe butoon.
337    * @return {@code WindowInfo} associated with specified tool stripe button.
338    */
339   private WindowInfoImpl getButtonInfoById(final String id) {
340     return myButton2Info.get(myId2Button.get(id));
341   }
342
343   /**
344    * @param id {@code ID} of decorator.
345    * @return {@code WindowInfo} associated with specified window decorator.
346    */
347   private WindowInfoImpl getDecoratorInfoById(final String id) {
348     return myDecorator2Info.get(myId2Decorator.get(id));
349   }
350
351   /**
352    * Sets (docks) specified component to the specified anchor.
353    */
354   private void setComponent(final JComponent component, @NotNull ToolWindowAnchor anchor, final float weight) {
355     if (ToolWindowAnchor.TOP == anchor) {
356       myVerticalSplitter.setFirstComponent(component);
357       myVerticalSplitter.setFirstSize((int)(myLayeredPane.getHeight() * weight));
358     }
359     else if (ToolWindowAnchor.LEFT == anchor) {
360       myHorizontalSplitter.setFirstComponent(component);
361       myHorizontalSplitter.setFirstSize((int)(myLayeredPane.getWidth() * weight));
362     }
363     else if (ToolWindowAnchor.BOTTOM == anchor) {
364       myVerticalSplitter.setLastComponent(component);
365       myVerticalSplitter.setLastSize((int)(myLayeredPane.getHeight() * weight));
366     }
367     else if (ToolWindowAnchor.RIGHT == anchor) {
368       myHorizontalSplitter.setLastComponent(component);
369       myHorizontalSplitter.setLastSize((int)(myLayeredPane.getWidth() * weight));
370     }
371     else {
372       LOG.error("unknown anchor: " + anchor);
373     }
374   }
375
376   private JComponent getComponentAt(@NotNull ToolWindowAnchor anchor) {
377     if (ToolWindowAnchor.TOP == anchor) {
378       return myVerticalSplitter.getFirstComponent();
379     }
380     else if (ToolWindowAnchor.LEFT == anchor) {
381       return myHorizontalSplitter.getFirstComponent();
382     }
383     else if (ToolWindowAnchor.BOTTOM == anchor) {
384       return myVerticalSplitter.getLastComponent();
385     }
386     else if (ToolWindowAnchor.RIGHT == anchor) {
387       return myHorizontalSplitter.getLastComponent();
388     }
389     else {
390       LOG.error("unknown anchor: " + anchor);
391       return null;
392     }
393   }
394
395   private float getPreferredSplitProportion(@NotNull String id, float defaultValue) {
396     Float f = myId2SplitProportion.get(id);
397     return f == null ? defaultValue : f;
398   }
399
400   private WindowInfoImpl getDockedInfoAt(@NotNull ToolWindowAnchor anchor, boolean side) {
401     for (WindowInfoImpl info : myDecorator2Info.values()) {
402       if (info.isVisible() && info.isDocked() && info.getAnchor() == anchor && side == info.isSplit()) {
403         return info;
404       }
405     }
406
407     return null;
408   }
409
410   private void setDocumentComponent(final JComponent component) {
411     (myWidescreen ? myVerticalSplitter : myHorizontalSplitter).setInnerComponent(component);
412   }
413
414   private void updateToolStripesVisibility() {
415     boolean oldVisible = myLeftStripe.isVisible();
416
417     final boolean showButtons = !UISettings.getInstance().getHideToolStripes() && !UISettings.getInstance().getPresentationMode();
418     boolean visible = showButtons || myStripesOverlayed;
419     myLeftStripe.setVisible(visible);
420     myRightStripe.setVisible(visible);
421     myTopStripe.setVisible(visible);
422     myBottomStripe.setVisible(visible);
423
424     boolean overlayed = !showButtons && myStripesOverlayed;
425
426     myLeftStripe.setOverlayed(overlayed);
427     myRightStripe.setOverlayed(overlayed);
428     myTopStripe.setOverlayed(overlayed);
429     myBottomStripe.setOverlayed(overlayed);
430
431
432     if (oldVisible != visible) {
433       revalidate();
434       repaint();
435     }
436   }
437
438   public int getBottomHeight() {
439     return myBottomStripe.isVisible() ? myBottomStripe.getHeight() : 0;
440   }
441
442   public boolean isBottomSideToolWindowsVisible() {
443     return getComponentAt(ToolWindowAnchor.BOTTOM) != null;
444   }
445
446   @Nullable
447   Stripe getStripeFor(String id) {
448     ToolWindow window = myManager.getToolWindow(id);
449     if (window == null) {
450       return null;
451     }
452
453     final ToolWindowAnchor anchor = myManager.getToolWindow(id).getAnchor();
454     if (ToolWindowAnchor.TOP == anchor) {
455       return myTopStripe;
456     }
457     if (ToolWindowAnchor.BOTTOM == anchor) {
458       return myBottomStripe;
459     }
460     if (ToolWindowAnchor.LEFT == anchor) {
461       return myLeftStripe;
462     }
463     if (ToolWindowAnchor.RIGHT == anchor) {
464       return myRightStripe;
465     }
466
467     throw new IllegalArgumentException("Anchor=" + anchor);
468   }
469
470   @Nullable
471   Stripe getStripeFor(@NotNull Rectangle screenRec, @NotNull Stripe preferred) {
472     if (preferred.containsScreen(screenRec)) {
473       return myStripes.get(myStripes.indexOf(preferred));
474     }
475
476     for (Stripe each : myStripes) {
477       if (each.containsScreen(screenRec)) {
478         return myStripes.get(myStripes.indexOf(each));
479       }
480     }
481
482     return null;
483   }
484
485   void startDrag() {
486     for (Stripe each : myStripes) {
487       each.startDrag();
488     }
489   }
490
491   void stopDrag() {
492     for (Stripe each : myStripes) {
493       each.stopDrag();
494     }
495   }
496
497   void stretchWidth(@NotNull ToolWindow wnd, int value) {
498     stretch(wnd, value);
499   }
500
501   void stretchHeight(@NotNull ToolWindow wnd, int value) {
502     stretch(wnd, value);
503   }
504
505   private void stretch(@NotNull ToolWindow wnd, int value) {
506     Pair<Resizer, Component> pair = findResizerAndComponent(wnd);
507     if (pair == null) return;
508
509     boolean vertical = wnd.getAnchor() == ToolWindowAnchor.TOP || wnd.getAnchor() == ToolWindowAnchor.BOTTOM;
510     int actualSize = (vertical ? pair.second.getHeight() : pair.second.getWidth()) + value;
511     boolean first = wnd.getAnchor() == ToolWindowAnchor.LEFT  || wnd.getAnchor() == ToolWindowAnchor.TOP;
512     int maxValue = vertical ? myVerticalSplitter.getMaxSize(first) : myHorizontalSplitter.getMaxSize(first);
513     int minValue = vertical ? myVerticalSplitter.getMinSize(first) : myHorizontalSplitter.getMinSize(first);
514
515     pair.first.setSize(Math.max(minValue, Math.min(maxValue, actualSize)));
516   }
517
518   @Nullable
519   private Pair<Resizer, Component> findResizerAndComponent(@NotNull ToolWindow wnd) {
520     if (!wnd.isVisible()) return null;
521
522     Resizer resizer = null;
523     Component cmp = null;
524
525     if (wnd.getType() == ToolWindowType.DOCKED) {
526       cmp = getComponentAt(wnd.getAnchor());
527
528       if (cmp != null) {
529         if (wnd.getAnchor().isHorizontal()) {
530           resizer = myVerticalSplitter.getFirstComponent() == cmp
531                     ? new Resizer.Splitter.FirstComponent(myVerticalSplitter)
532                     : new Resizer.Splitter.LastComponent(myVerticalSplitter);
533         }
534         else {
535           resizer = myHorizontalSplitter.getFirstComponent() == cmp
536                     ? new Resizer.Splitter.FirstComponent(myHorizontalSplitter)
537                     : new Resizer.Splitter.LastComponent(myHorizontalSplitter);
538         }
539       }
540     }
541     else if (wnd.getType() == ToolWindowType.SLIDING) {
542       cmp = wnd.getComponent();
543       while (cmp != null) {
544         if (cmp.getParent() == myLayeredPane) break;
545         cmp = cmp.getParent();
546       }
547
548       if (cmp != null) {
549         if (wnd.getAnchor() == ToolWindowAnchor.TOP) {
550           resizer = new Resizer.LayeredPane.Top(cmp);
551         }
552         else if (wnd.getAnchor() == ToolWindowAnchor.BOTTOM) {
553           resizer = new Resizer.LayeredPane.Bottom(cmp);
554         }
555         else if (wnd.getAnchor() == ToolWindowAnchor.LEFT) {
556           resizer = new Resizer.LayeredPane.Left(cmp);
557         }
558         else if (wnd.getAnchor() == ToolWindowAnchor.RIGHT) {
559           resizer = new Resizer.LayeredPane.Right(cmp);
560         }
561       }
562     }
563
564     return resizer != null ? Pair.create(resizer, cmp) : null;
565   }
566
567   private void updateLayout() {
568     UISettings uiSettings = UISettings.getInstance();
569     if (myWidescreen != uiSettings.getWideScreenSupport()) {
570       JComponent documentComponent = (myWidescreen ? myVerticalSplitter : myHorizontalSplitter).getInnerComponent();
571       myWidescreen = uiSettings.getWideScreenSupport();
572       if (myWidescreen) {
573         myVerticalSplitter.setInnerComponent(null);
574         myHorizontalSplitter.setInnerComponent(myVerticalSplitter);
575       }
576       else {
577         myHorizontalSplitter.setInnerComponent(null);
578         myVerticalSplitter.setInnerComponent(myHorizontalSplitter);
579       }
580       myLayeredPane.remove(myWidescreen ? myVerticalSplitter : myHorizontalSplitter);
581       myLayeredPane.add(myWidescreen ? myHorizontalSplitter : myVerticalSplitter, DEFAULT_LAYER);
582       setDocumentComponent(documentComponent);
583     }
584     if (myLeftHorizontalSplit != uiSettings.getLeftHorizontalSplit()) {
585       JComponent component = getComponentAt(ToolWindowAnchor.LEFT);
586       if (component instanceof Splitter) {
587         Splitter splitter = (Splitter)component;
588         InternalDecorator first = (InternalDecorator)splitter.getFirstComponent();
589         InternalDecorator second = (InternalDecorator)splitter.getSecondComponent();
590         setComponent(splitter, ToolWindowAnchor.LEFT, ToolWindowAnchor.LEFT.isSplitVertically()
591                                                       ? first.getWindowInfo().getWeight()
592                                                       : first.getWindowInfo().getWeight() + second.getWindowInfo().getWeight());
593       }
594       myLeftHorizontalSplit = uiSettings.getLeftHorizontalSplit();
595     }
596     if (myRightHorizontalSplit != uiSettings.getRightHorizontalSplit()) {
597       JComponent component = getComponentAt(ToolWindowAnchor.RIGHT);
598       if (component instanceof Splitter) {
599         Splitter splitter = (Splitter)component;
600         InternalDecorator first = (InternalDecorator)splitter.getFirstComponent();
601         InternalDecorator second = (InternalDecorator)splitter.getSecondComponent();
602         setComponent(splitter, ToolWindowAnchor.RIGHT, ToolWindowAnchor.RIGHT.isSplitVertically()
603                                                        ? first.getWindowInfo().getWeight()
604                                                        : first.getWindowInfo().getWeight() + second.getWindowInfo().getWeight());
605       }
606       myRightHorizontalSplit = uiSettings.getRightHorizontalSplit();
607     }
608   }
609
610   public boolean isMaximized(@NotNull ToolWindow wnd) {
611       return myMaximizedProportion != null && myMaximizedProportion.first == wnd;
612   }
613
614   void setMaximized(@NotNull ToolWindow wnd, boolean maximized) {
615     Pair<Resizer, Component> resizerAndComponent = findResizerAndComponent(wnd);
616     if (resizerAndComponent == null) return;
617
618     if (!maximized) {
619       ToolWindow maximizedWindow = myMaximizedProportion.first;
620       assert maximizedWindow == wnd;
621       resizerAndComponent.first.setSize(myMaximizedProportion.second);
622       myMaximizedProportion = null;
623     } else {
624       int size = wnd.getAnchor().isHorizontal() ? resizerAndComponent.second.getHeight() : resizerAndComponent.second.getWidth();
625       stretch(wnd, Short.MAX_VALUE);
626       myMaximizedProportion = Pair.create(wnd, size);
627     }
628     doLayout();
629   }
630
631
632   @FunctionalInterface
633   interface Resizer {
634     void setSize(int size);
635
636
637     abstract class Splitter implements Resizer {
638       ThreeComponentsSplitter mySplitter;
639
640       Splitter(@NotNull ThreeComponentsSplitter splitter) {
641         mySplitter = splitter;
642       }
643
644       static class FirstComponent extends Splitter {
645         FirstComponent(@NotNull ThreeComponentsSplitter splitter) {
646           super(splitter);
647         }
648
649         @Override
650         public void setSize(int size) {
651           mySplitter.setFirstSize(size);
652         }
653       }
654
655       static class LastComponent extends Splitter {
656         LastComponent(@NotNull ThreeComponentsSplitter splitter) {
657           super(splitter);
658         }
659
660         @Override
661         public void setSize(int size) {
662           mySplitter.setLastSize(size);
663         }
664       }
665     }
666
667     abstract class LayeredPane implements Resizer {
668       Component myComponent;
669
670       LayeredPane(@NotNull Component component) {
671         myComponent = component;
672       }
673
674       @Override
675       public final void setSize(int size) {
676         _setSize(size);
677         if (myComponent.getParent() instanceof JComponent) {
678           JComponent parent = (JComponent)myComponent;
679           parent.revalidate();
680           parent.repaint();
681         }
682       }
683
684       abstract void _setSize(int size);
685
686       static class Left extends LayeredPane {
687
688         Left(@NotNull Component component) {
689           super(component);
690         }
691
692         @Override
693         public void _setSize(int size) {
694           myComponent.setSize(size, myComponent.getHeight());
695         }
696       }
697
698       static class Right extends LayeredPane {
699         Right(@NotNull Component component) {
700           super(component);
701         }
702
703         @Override
704         public void _setSize(int size) {
705           Rectangle bounds = myComponent.getBounds();
706           int delta = size - bounds.width;
707           bounds.x -= delta;
708           bounds.width += delta;
709           myComponent.setBounds(bounds);
710         }
711       }
712
713       static class Top extends LayeredPane {
714         Top(@NotNull Component component) {
715           super(component);
716         }
717
718         @Override
719         public void _setSize(int size) {
720           myComponent.setSize(myComponent.getWidth(), size);
721         }
722       }
723
724       static class Bottom extends LayeredPane {
725         Bottom(@NotNull Component component) {
726           super(component);
727         }
728
729         @Override
730         public void _setSize(int size) {
731           Rectangle bounds = myComponent.getBounds();
732           int delta = size - bounds.height;
733           bounds.y -= delta;
734           bounds.height += delta;
735           myComponent.setBounds(bounds);
736         }
737       }
738     }
739   }
740
741   private final class AddDockedComponentCmd extends FinalizableCommand {
742     private final JComponent myComponent;
743     private final WindowInfoImpl myInfo;
744     private final boolean myDirtyMode;
745
746     public AddDockedComponentCmd(@NotNull JComponent component,
747                                  @NotNull WindowInfoImpl info,
748                                  final boolean dirtyMode,
749                                  @NotNull Runnable finishCallBack) {
750       super(finishCallBack);
751       myComponent = component;
752       myInfo = info;
753       myDirtyMode = dirtyMode;
754     }
755
756     @Override
757     public final void run() {
758       try {
759         final ToolWindowAnchor anchor = myInfo.getAnchor();
760         setComponent(myComponent, anchor, normalizeWeigh(myInfo.getWeight()));
761         if (!myDirtyMode) {
762           myLayeredPane.validate();
763           myLayeredPane.repaint();
764         }
765       }
766       finally {
767         finish();
768       }
769     }
770   }
771
772   private final class AddAndSplitDockedComponentCmd extends FinalizableCommand {
773     private final JComponent myNewComponent;
774     private final WindowInfoImpl myInfo;
775     private final boolean myDirtyMode;
776
777     private AddAndSplitDockedComponentCmd(@NotNull JComponent newComponent,
778                                           @NotNull WindowInfoImpl info,
779                                           final boolean dirtyMode,
780                                           @NotNull Runnable finishCallBack) {
781       super(finishCallBack);
782       myNewComponent = newComponent;
783       myInfo = info;
784       myDirtyMode = dirtyMode;
785     }
786
787     @Override
788     public void run() {
789       try {
790         final ToolWindowAnchor anchor = myInfo.getAnchor();
791         class MySplitter extends Splitter implements UISettingsListener {
792           @Override
793           public void uiSettingsChanged(UISettings uiSettings) {
794             if (anchor == ToolWindowAnchor.LEFT) {
795               setOrientation(!uiSettings.getLeftHorizontalSplit());
796             }
797             else if (anchor == ToolWindowAnchor.RIGHT) {
798               setOrientation(!uiSettings.getRightHorizontalSplit());
799             }
800           }
801         }
802         Splitter splitter = new MySplitter();
803         splitter.setOrientation(anchor.isSplitVertically());
804         if (!anchor.isHorizontal()) {
805           splitter.setAllowSwitchOrientationByMouseClick(true);
806           splitter.addPropertyChangeListener(evt -> {
807             if (!Splitter.PROP_ORIENTATION.equals(evt.getPropertyName())) return;
808             boolean isSplitterHorizontalNow = !splitter.isVertical();
809             UISettings settings = UISettings.getInstance();
810             if (anchor == ToolWindowAnchor.LEFT) {
811               if (settings.getLeftHorizontalSplit() != isSplitterHorizontalNow) {
812                 settings.setLeftHorizontalSplit(isSplitterHorizontalNow);
813                 settings.fireUISettingsChanged();
814               }
815             }
816             if (anchor == ToolWindowAnchor.RIGHT) {
817               if (settings.getRightHorizontalSplit() != isSplitterHorizontalNow) {
818                 settings.setRightHorizontalSplit(isSplitterHorizontalNow);
819                 settings.fireUISettingsChanged();
820               }
821             }
822           });
823         }
824         JComponent c = getComponentAt(anchor);
825         float newWeight;
826         if (c instanceof InternalDecorator) {
827           InternalDecorator oldComponent = (InternalDecorator)c;
828           if (myInfo.isSplit()) {
829             splitter.setFirstComponent(oldComponent);
830             splitter.setSecondComponent(myNewComponent);
831             float proportion = getPreferredSplitProportion(oldComponent.getWindowInfo().getId(),
832                                                            normalizeWeigh(oldComponent.getWindowInfo().getSideWeight() /
833                                                                           (oldComponent.getWindowInfo().getSideWeight() +
834                                                                            myInfo.getSideWeight())));
835             splitter.setProportion(proportion);
836             if (!anchor.isHorizontal() && !anchor.isSplitVertically()) {
837               newWeight = normalizeWeigh(oldComponent.getWindowInfo().getWeight() + myInfo.getWeight());
838             }
839             else {
840               newWeight = normalizeWeigh(oldComponent.getWindowInfo().getWeight());
841             }
842           }
843           else {
844             splitter.setFirstComponent(myNewComponent);
845             splitter.setSecondComponent(oldComponent);
846             splitter.setProportion(normalizeWeigh(myInfo.getSideWeight()));
847             if (!anchor.isHorizontal() && !anchor.isSplitVertically()) {
848               newWeight = normalizeWeigh(oldComponent.getWindowInfo().getWeight() + myInfo.getWeight());
849             }
850             else {
851               newWeight = normalizeWeigh(myInfo.getWeight());
852             }
853           }
854         } else {
855           newWeight = normalizeWeigh(myInfo.getWeight());
856         }
857         setComponent(splitter, anchor, newWeight);
858
859         if (!myDirtyMode) {
860           myLayeredPane.validate();
861           myLayeredPane.repaint();
862         }
863       }
864       finally {
865         finish();
866       }
867     }
868   }
869
870   private final class AddSlidingComponentCmd extends FinalizableCommand {
871     private final Component myComponent;
872     private final WindowInfoImpl myInfo;
873     private final boolean myDirtyMode;
874
875     public AddSlidingComponentCmd(@NotNull Component component,
876                                   @NotNull WindowInfoImpl info,
877                                   final boolean dirtyMode,
878                                   @NotNull Runnable finishCallBack) {
879       super(finishCallBack);
880       myComponent = component;
881       myInfo = info;
882       myDirtyMode = dirtyMode;
883     }
884     @Override
885     public final void run() {
886       try {
887         // Show component.
888         if (!myDirtyMode && UISettings.getInstance().getAnimateWindows() && !RemoteDesktopService.isRemoteSession()) {
889           // Prepare top image. This image is scrolling over bottom image.
890           final Image topImage = myLayeredPane.getTopImage();
891           final Graphics topGraphics = topImage.getGraphics();
892
893           Rectangle bounds;
894
895           try {
896             myLayeredPane.add(myComponent, JLayeredPane.PALETTE_LAYER);
897             myLayeredPane.moveToFront(myComponent);
898             myLayeredPane.setBoundsInPaletteLayer(myComponent, myInfo.getAnchor(), myInfo.getWeight());
899             bounds = myComponent.getBounds();
900             myComponent.paint(topGraphics);
901             myLayeredPane.remove(myComponent);
902           }
903           finally {
904             topGraphics.dispose();
905           }
906           // Prepare bottom image.
907           final Image bottomImage = myLayeredPane.getBottomImage();
908           final Graphics bottomGraphics = bottomImage.getGraphics();
909           try {
910             bottomGraphics.setClip(0, 0, bounds.width, bounds.height);
911             bottomGraphics.translate(-bounds.x, -bounds.y);
912             myLayeredPane.paint(bottomGraphics);
913           }
914           finally {
915             bottomGraphics.dispose();
916           }
917           // Start animation.
918           final Surface surface = new Surface(topImage, bottomImage, 1, myInfo.getAnchor(), UISettings.ANIMATION_DURATION);
919           myLayeredPane.add(surface, JLayeredPane.PALETTE_LAYER);
920           surface.setBounds(bounds);
921           myLayeredPane.validate();
922           myLayeredPane.repaint();
923
924           surface.runMovement();
925           myLayeredPane.remove(surface);
926           myLayeredPane.add(myComponent, JLayeredPane.PALETTE_LAYER);
927         }
928         else { // not animated
929           myLayeredPane.add(myComponent, JLayeredPane.PALETTE_LAYER);
930           myLayeredPane.setBoundsInPaletteLayer(myComponent, myInfo.getAnchor(), myInfo.getWeight());
931         }
932         if (!myDirtyMode) {
933           myLayeredPane.validate();
934           myLayeredPane.repaint();
935         }
936       }
937       finally {
938         finish();
939       }
940     }
941   }
942
943   private final class AddToolStripeButtonCmd extends FinalizableCommand {
944     private final StripeButton myButton;
945     private final WindowInfoImpl myInfo;
946     private final Comparator<StripeButton> myComparator;
947
948     public AddToolStripeButtonCmd(final StripeButton button,
949                                   @NotNull WindowInfoImpl info,
950                                   @NotNull Comparator<StripeButton> comparator,
951                                   @NotNull Runnable finishCallBack) {
952       super(finishCallBack);
953       myButton = button;
954       myInfo = info;
955       myComparator = comparator;
956     }
957
958     @Override
959     public final void run() {
960       try {
961         final ToolWindowAnchor anchor = myInfo.getAnchor();
962         if (ToolWindowAnchor.TOP == anchor) {
963           myTopStripe.addButton(myButton, myComparator);
964         }
965         else if (ToolWindowAnchor.LEFT == anchor) {
966           myLeftStripe.addButton(myButton, myComparator);
967         }
968         else if (ToolWindowAnchor.BOTTOM == anchor) {
969           myBottomStripe.addButton(myButton, myComparator);
970         }
971         else if (ToolWindowAnchor.RIGHT == anchor) {
972           myRightStripe.addButton(myButton, myComparator);
973         }
974         else {
975           LOG.error("unknown anchor: " + anchor);
976         }
977         validate();
978         repaint();
979       }
980       finally {
981         finish();
982       }
983     }
984   }
985
986   private final class RemoveToolStripeButtonCmd extends FinalizableCommand {
987     private final StripeButton myButton;
988     private final WindowInfoImpl myInfo;
989
990     public RemoveToolStripeButtonCmd(@NotNull StripeButton button, @NotNull WindowInfoImpl info, @NotNull Runnable finishCallBack) {
991       super(finishCallBack);
992       myButton = button;
993       myInfo = info;
994     }
995
996     @Override
997     public final void run() {
998       try {
999         final ToolWindowAnchor anchor = myInfo.getAnchor();
1000         if (ToolWindowAnchor.TOP == anchor) {
1001           myTopStripe.removeButton(myButton);
1002         }
1003         else if (ToolWindowAnchor.LEFT == anchor) {
1004           myLeftStripe.removeButton(myButton);
1005         }
1006         else if (ToolWindowAnchor.BOTTOM == anchor) {
1007           myBottomStripe.removeButton(myButton);
1008         }
1009         else if (ToolWindowAnchor.RIGHT == anchor) {
1010           myRightStripe.removeButton(myButton);
1011         }
1012         else {
1013           LOG.error("unknown anchor: " + anchor);
1014         }
1015         validate();
1016         repaint();
1017       }
1018       finally {
1019         finish();
1020       }
1021     }
1022   }
1023
1024   private final class RemoveDockedComponentCmd extends FinalizableCommand {
1025     private final WindowInfoImpl myInfo;
1026     private final boolean myDirtyMode;
1027
1028     public RemoveDockedComponentCmd(@NotNull WindowInfoImpl info, final boolean dirtyMode, @NotNull Runnable finishCallBack) {
1029       super(finishCallBack);
1030       myInfo = info;
1031       myDirtyMode = dirtyMode;
1032     }
1033
1034     @Override
1035     public final void run() {
1036       try {
1037         setComponent(null, myInfo.getAnchor(), 0);
1038         if (!myDirtyMode) {
1039           myLayeredPane.validate();
1040           myLayeredPane.repaint();
1041         }
1042       }
1043       finally {
1044         finish();
1045       }
1046     }
1047   }
1048
1049   private final class RemoveSplitAndDockedComponentCmd extends FinalizableCommand {
1050     private final WindowInfoImpl myInfo;
1051     private final boolean myDirtyMode;
1052
1053     private RemoveSplitAndDockedComponentCmd(@NotNull WindowInfoImpl info,
1054                                              boolean dirtyMode,
1055                                              @NotNull Runnable finishCallBack) {
1056       super(finishCallBack);
1057       myInfo = info;
1058       myDirtyMode = dirtyMode;
1059     }
1060
1061     @Override
1062     public void run() {
1063       try {
1064         ToolWindowAnchor anchor = myInfo.getAnchor();
1065         JComponent c = getComponentAt(anchor);
1066         if (c instanceof Splitter) {
1067           Splitter splitter = (Splitter)c;
1068           final InternalDecorator component =
1069             myInfo.isSplit() ? (InternalDecorator)splitter.getFirstComponent() : (InternalDecorator)splitter.getSecondComponent();
1070           if (myInfo.isSplit() && component != null) {
1071               myId2SplitProportion.put(component.getWindowInfo().getId(), splitter.getProportion());
1072           }
1073           setComponent(component, anchor, component != null ? component.getWindowInfo().getWeight() : 0);
1074         } else {
1075           setComponent(null, anchor, 0);
1076         }
1077         if (!myDirtyMode) {
1078           myLayeredPane.validate();
1079           myLayeredPane.repaint();
1080         }
1081       }
1082       finally {
1083         finish();
1084       }
1085     }
1086   }
1087
1088   private final class RemoveSlidingComponentCmd extends FinalizableCommand {
1089     private final Component myComponent;
1090     private final WindowInfoImpl myInfo;
1091     private final boolean myDirtyMode;
1092
1093     public RemoveSlidingComponentCmd(Component component, @NotNull WindowInfoImpl info, boolean dirtyMode, @NotNull Runnable finishCallBack) {
1094       super(finishCallBack);
1095       myComponent = component;
1096       myInfo = info;
1097       myDirtyMode = dirtyMode;
1098     }
1099     @Override
1100     public final void run() {
1101       try {
1102         final UISettings uiSettings = UISettings.getInstance();
1103         if (!myDirtyMode && uiSettings.getAnimateWindows() && !RemoteDesktopService.isRemoteSession()) {
1104           final Rectangle bounds = myComponent.getBounds();
1105           // Prepare top image. This image is scrolling over bottom image. It contains
1106           // picture of component is being removed.
1107           final Image topImage = myLayeredPane.getTopImage();
1108           final Graphics topGraphics = topImage.getGraphics();
1109           try {
1110             myComponent.paint(topGraphics);
1111           }
1112           finally {
1113             topGraphics.dispose();
1114           }
1115           // Prepare bottom image. This image contains picture of component that is located
1116           // under the component to is being removed.
1117           final Image bottomImage = myLayeredPane.getBottomImage();
1118           final Graphics bottomGraphics = bottomImage.getGraphics();
1119           try {
1120             myLayeredPane.remove(myComponent);
1121             bottomGraphics.clipRect(0, 0, bounds.width, bounds.height);
1122             bottomGraphics.translate(-bounds.x, -bounds.y);
1123             myLayeredPane.paint(bottomGraphics);
1124           }
1125           finally {
1126             bottomGraphics.dispose();
1127           }
1128           // Remove component from the layered pane and start animation.
1129           final Surface surface = new Surface(topImage, bottomImage, -1, myInfo.getAnchor(), UISettings.ANIMATION_DURATION);
1130           myLayeredPane.add(surface, JLayeredPane.PALETTE_LAYER);
1131           surface.setBounds(bounds);
1132           myLayeredPane.validate();
1133           myLayeredPane.repaint();
1134
1135           surface.runMovement();
1136           myLayeredPane.remove(surface);
1137         }
1138         else { // not animated
1139           myLayeredPane.remove(myComponent);
1140         }
1141         if (!myDirtyMode) {
1142           myLayeredPane.validate();
1143           myLayeredPane.repaint();
1144         }
1145       }
1146       finally {
1147         finish();
1148       }
1149     }
1150   }
1151
1152   private final class SetEditorComponentCmd extends FinalizableCommand {
1153     private final JComponent myComponent;
1154
1155     public SetEditorComponentCmd(final JComponent component, @NotNull Runnable finishCallBack) {
1156       super(finishCallBack);
1157       myComponent = component;
1158     }
1159
1160     @Override
1161     public void run() {
1162       try {
1163         setDocumentComponent(myComponent);
1164         myLayeredPane.validate();
1165         myLayeredPane.repaint();
1166       }
1167       finally {
1168         finish();
1169       }
1170     }
1171   }
1172
1173   private final class UpdateButtonPositionCmd extends FinalizableCommand {
1174     private final String myId;
1175
1176     private UpdateButtonPositionCmd(@NotNull String id, @NotNull Runnable finishCallBack) {
1177       super(finishCallBack);
1178       myId = id;
1179     }
1180
1181     @Override
1182     public void run() {
1183       try {
1184         StripeButton stripeButton = getButtonById(myId);
1185         if (stripeButton == null) {
1186           return;
1187         }
1188
1189         WindowInfoImpl info = stripeButton.getWindowInfo();
1190         ToolWindowAnchor anchor = info.getAnchor();
1191
1192         if (ToolWindowAnchor.TOP == anchor) {
1193           myTopStripe.revalidate();
1194         }
1195         else if (ToolWindowAnchor.LEFT == anchor) {
1196           myLeftStripe.revalidate();
1197         }
1198         else if (ToolWindowAnchor.BOTTOM == anchor) {
1199           myBottomStripe.revalidate();
1200         }
1201         else if (ToolWindowAnchor.RIGHT == anchor) {
1202           myRightStripe.revalidate();
1203         }
1204         else {
1205           LOG.error("unknown anchor: " + anchor);
1206         }
1207       }
1208       finally {
1209         finish();
1210       }
1211     }
1212   }
1213
1214   private final class MyLayeredPane extends JBLayeredPane {
1215     /*
1216      * These images are used to perform animated showing and hiding of components.
1217      * They are the member for performance reason.
1218      */
1219     private Reference<BufferedImage> myBottomImageRef;
1220     private Reference<BufferedImage> myTopImageRef;
1221
1222     public MyLayeredPane(@NotNull JComponent splitter) {
1223       setOpaque(false);
1224       add(splitter, JLayeredPane.DEFAULT_LAYER);
1225     }
1226
1227     final Image getBottomImage() {
1228       Pair<BufferedImage, Reference<BufferedImage>> result = getImage(myBottomImageRef);
1229       myBottomImageRef = result.second;
1230       return result.first;
1231     }
1232
1233     final Image getTopImage() {
1234       Pair<BufferedImage, Reference<BufferedImage>> result = getImage(myTopImageRef);
1235       myTopImageRef = result.second;
1236       return result.first;
1237     }
1238
1239     @NotNull
1240     private Pair<BufferedImage, Reference<BufferedImage>> getImage(@Nullable Reference<BufferedImage> imageRef) {
1241       LOG.assertTrue(UISettings.getInstance().getAnimateWindows());
1242       BufferedImage image = SoftReference.dereference(imageRef);
1243       if (image == null || image.getWidth(null) < getWidth() || image.getHeight(null) < getHeight()) {
1244         final int width = Math.max(Math.max(1, getWidth()), myFrame.getWidth());
1245         final int height = Math.max(Math.max(1, getHeight()), myFrame.getHeight());
1246         if (SystemInfo.isWindows) {
1247           image = myFrame.getGraphicsConfiguration().createCompatibleImage(width, height);
1248         }
1249         else {
1250           // Under Linux we have found that images created by createCompatibleImage(),
1251           // createVolatileImage(), etc extremely slow for rendering. TrueColor buffered image
1252           // is MUCH faster.
1253           // On Mac we create a retina-compatible image
1254
1255           image = UIUtil.createImage(getGraphics(), width, height, BufferedImage.TYPE_INT_RGB);
1256         }
1257         imageRef = new SoftReference<>(image);
1258       }
1259       return Pair.create(image, imageRef);
1260     }
1261
1262     /**
1263      * When component size becomes larger then bottom and top images should be enlarged.
1264      */
1265     @Override
1266     public void doLayout() {
1267       final int width = getWidth();
1268       final int height = getHeight();
1269       if (width < 0 || height < 0) {
1270         return;
1271       }
1272       // Resize component at the DEFAULT layer. It should be only on component in that layer
1273       Component[] components = getComponentsInLayer(JLayeredPane.DEFAULT_LAYER.intValue());
1274       LOG.assertTrue(components.length <= 1);
1275       for (final Component component : components) {
1276         component.setBounds(0, 0, getWidth(), getHeight());
1277       }
1278       // Resize components at the PALETTE layer
1279       components = getComponentsInLayer(JLayeredPane.PALETTE_LAYER.intValue());
1280       for (final Component component : components) {
1281         if (!(component instanceof InternalDecorator)) {
1282           continue;
1283         }
1284         final WindowInfoImpl info = myDecorator2Info.get(component);
1285         // In normal situation info is not null. But sometimes Swing sends resize
1286         // event to removed component. See SCR #19566.
1287         if (info == null) {
1288           continue;
1289         }
1290
1291         final float weight;
1292         if (info.getAnchor().isHorizontal()) {
1293           weight = (float)component.getHeight() / (float)getHeight();
1294         }
1295         else {
1296           weight = (float)component.getWidth() / (float)getWidth();
1297         }
1298         setBoundsInPaletteLayer(component, info.getAnchor(), weight);
1299       }
1300     }
1301
1302     final void setBoundsInPaletteLayer(@NotNull Component component, @NotNull ToolWindowAnchor anchor, float weight) {
1303       if (weight < .0f) {
1304         weight = WindowInfoImpl.DEFAULT_WEIGHT;
1305       }
1306       else if (weight > 1.0f) {
1307         weight = 1.0f;
1308       }
1309       if (ToolWindowAnchor.TOP == anchor) {
1310         component.setBounds(0, 0, getWidth(), (int)(getHeight() * weight + .5f));
1311       }
1312       else if (ToolWindowAnchor.LEFT == anchor) {
1313         component.setBounds(0, 0, (int)(getWidth() * weight + .5f), getHeight());
1314       }
1315       else if (ToolWindowAnchor.BOTTOM == anchor) {
1316         final int height = (int)(getHeight() * weight + .5f);
1317         component.setBounds(0, getHeight() - height, getWidth(), height);
1318       }
1319       else if (ToolWindowAnchor.RIGHT == anchor) {
1320         final int width = (int)(getWidth() * weight + .5f);
1321         component.setBounds(getWidth() - width, 0, width, getHeight());
1322       }
1323       else {
1324         LOG.error("unknown anchor " + anchor);
1325       }
1326     }
1327   }
1328
1329   void setStripesOverlayed(boolean stripesOverlayed) {
1330     myStripesOverlayed = stripesOverlayed;
1331     updateToolStripesVisibility();
1332   }
1333
1334   @Override
1335   public void dispose() {
1336   }
1337
1338   private static float normalizeWeigh(final float weight) {
1339     if (weight <= 0) return WindowInfoImpl.DEFAULT_WEIGHT;
1340     if (weight >= 1) return 1 - WindowInfoImpl.DEFAULT_WEIGHT;
1341     return weight;
1342   }
1343 }