2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com
.intellij
.openapi
.wm
.impl
;
18 import com
.intellij
.ide
.ui
.UISettings
;
19 import com
.intellij
.ide
.ui
.UISettingsListener
;
20 import com
.intellij
.openapi
.diagnostic
.Logger
;
21 import com
.intellij
.openapi
.ui
.Splitter
;
22 import com
.intellij
.openapi
.ui
.ThreeComponentsSplitter
;
23 import com
.intellij
.openapi
.util
.SystemInfo
;
24 import com
.intellij
.openapi
.wm
.ToolWindow
;
25 import com
.intellij
.openapi
.wm
.ToolWindowAnchor
;
26 import com
.intellij
.openapi
.wm
.ToolWindowType
;
27 import com
.intellij
.openapi
.wm
.ex
.ToolWindowEx
;
28 import com
.intellij
.openapi
.wm
.impl
.commands
.FinalizableCommand
;
29 import com
.intellij
.reference
.SoftReference
;
30 import com
.intellij
.util
.containers
.HashMap
;
34 import java
.awt
.event
.ComponentEvent
;
35 import java
.awt
.image
.BufferedImage
;
36 import java
.util
.ArrayList
;
37 import java
.util
.Comparator
;
40 * This panel contains all tool stripes and JLayeredPanle at the center area. All tool windows are
41 * located inside this layered pane.
43 * @author Anton Katilin
44 * @author Vladimir Kondratyev
46 final class ToolWindowsPane
extends JPanel
{
47 private static final Logger LOG
=Logger
.getInstance("#com.intellij.openapi.wm.impl.ToolWindowsPane");
49 private final IdeFrameImpl myFrame
;
51 private final HashMap
<String
,StripeButton
> myId2Button
;
52 private final HashMap
<String
,InternalDecorator
> myId2Decorator
;
53 private final HashMap
<StripeButton
, WindowInfoImpl
> myButton2Info
;
54 private final HashMap
<InternalDecorator
, WindowInfoImpl
> myDecorator2Info
;
56 * This panel is the layered pane where all sliding tool windows are located. The DEFAULT
57 * layer contains splitters. The PALETTE layer contains all sliding tool windows.
59 private final MyLayeredPane myLayeredPane
;
63 private final ThreeComponentsSplitter myVerticalSplitter
;
64 private final ThreeComponentsSplitter myHorizontalSplitter
;
69 private final Stripe myLeftStripe
;
70 private final Stripe myRightStripe
;
71 private final Stripe myBottomStripe
;
72 private final Stripe myTopStripe
;
74 private final ArrayList
<Stripe
> myStipes
= new ArrayList
<Stripe
>();
76 private final MyUISettingsListenerImpl myUISettingsListener
;
77 private final ToolWindowManagerImpl myManager
;
79 ToolWindowsPane(final IdeFrameImpl frame
, ToolWindowManagerImpl manager
){
80 super(new BorderLayout());
86 myId2Button
=new HashMap
<String
,StripeButton
>();
87 myId2Decorator
=new HashMap
<String
,InternalDecorator
>();
88 myButton2Info
=new HashMap
<StripeButton
, WindowInfoImpl
>();
89 myDecorator2Info
=new HashMap
<InternalDecorator
, WindowInfoImpl
>();
90 myUISettingsListener
=new MyUISettingsListenerImpl();
94 myVerticalSplitter
= new ThreeComponentsSplitter(true);
95 myVerticalSplitter
.setBackground(Color
.gray
);
96 myHorizontalSplitter
= new ThreeComponentsSplitter(false);
97 myHorizontalSplitter
.setBackground(Color
.gray
);
99 myVerticalSplitter
.setInnerComponent(myHorizontalSplitter
);
103 myTopStripe
=new Stripe(SwingConstants
.TOP
, manager
);
104 myStipes
.add(myTopStripe
);
105 myLeftStripe
=new Stripe(SwingConstants
.LEFT
, manager
);
106 myStipes
.add(myLeftStripe
);
107 myBottomStripe
=new Stripe(SwingConstants
.BOTTOM
, manager
);
108 myStipes
.add(myBottomStripe
);
109 myRightStripe
=new Stripe(SwingConstants
.RIGHT
, manager
);
110 myStipes
.add(myRightStripe
);
112 updateToolStripesVisibility();
116 myLayeredPane
=new MyLayeredPane(myVerticalSplitter
);
120 add(myTopStripe
,BorderLayout
.NORTH
);
121 add(myLeftStripe
,BorderLayout
.WEST
);
122 add(myBottomStripe
,BorderLayout
.SOUTH
);
123 add(myRightStripe
,BorderLayout
.EAST
);
124 add(myLayeredPane
,BorderLayout
.CENTER
);
128 * Invoked when enclosed frame is being shown.
130 public final void addNotify(){
132 UISettings
.getInstance().addUISettingsListener(myUISettingsListener
);
136 * Invoked when enclosed frame is being disposed.
138 public final void removeNotify(){
139 UISettings
.getInstance().removeUISettingsListener(myUISettingsListener
);
140 super.removeNotify();
144 * Creates command which adds button into the specified tool stripe.
145 * Command uses copy of passed <code>info</code> object.
146 * @param button button which should be added.
147 * @param info window info for the corresponded tool window.
148 * @param comparator which is used to sort buttons within the stripe.
149 * @param finishCallBack invoked when the command is completed.
151 final FinalizableCommand
createAddButtonCmd(final StripeButton button
,final WindowInfoImpl info
,final Comparator comparator
,final Runnable finishCallBack
){
152 final WindowInfoImpl copiedInfo
=info
.copy();
153 myId2Button
.put(copiedInfo
.getId(),button
);
154 myButton2Info
.put(button
,copiedInfo
);
155 return new AddToolStripeButtonCmd(button
,copiedInfo
,comparator
,finishCallBack
);
159 * Creates command which shows tool window with specified set of parameters.
160 * Command uses cloned copy of passed <code>info</code> object.
161 * @param dirtyMode if <code>true</code> then JRootPane will not be validated and repainted after adding
162 * the decorator. Moreover in this (dirty) mode animation doesn't work.
164 final FinalizableCommand
createAddDecoratorCmd(
165 final InternalDecorator decorator
,
166 final WindowInfoImpl info
,
167 final boolean dirtyMode
,
168 final Runnable finishCallBack
170 final WindowInfoImpl copiedInfo
=info
.copy();
171 final String id
=copiedInfo
.getId();
173 myDecorator2Info
.put(decorator
,copiedInfo
);
174 myId2Decorator
.put(id
,decorator
);
177 WindowInfoImpl sideInfo
= getDockedInfoAt(info
.getAnchor(), !info
.isSplit());
178 if (sideInfo
== null) {
179 return new AddDockedComponentCmd(decorator
,info
,dirtyMode
,finishCallBack
);
182 return new AddAndSplitDockedComponentCmd(decorator
, info
, dirtyMode
, finishCallBack
);
184 } else if(info
.isSliding()) {
185 return new AddSlidingComponentCmd(decorator
,info
,dirtyMode
,finishCallBack
);
187 throw new IllegalArgumentException("Unknown window type: "+info
.getType());
192 * Creates command which removes tool button from tool stripe.
193 * @param id <code>ID</code> of the button to be removed.
195 final FinalizableCommand
createRemoveButtonCmd(final String id
,final Runnable finishCallBack
){
196 final StripeButton button
=getButtonById(id
);
197 final WindowInfoImpl info
=getButtonInfoById(id
);
199 myButton2Info
.remove(button
);
200 myId2Button
.remove(id
);
201 return new RemoveToolStripeButtonCmd(button
,info
,finishCallBack
);
205 * Creates command which hides tool window with specified set of parameters.
206 * @param dirtyMode if <code>true</code> then JRootPane will not be validated and repainted after removing
207 * the decorator. Moreover in this (dirty) mode animation doesn't work.
209 final FinalizableCommand
createRemoveDecoratorCmd(final String id
, final boolean dirtyMode
, final Runnable finishCallBack
){
210 final Component decorator
=getDecoratorById(id
);
211 final WindowInfoImpl info
=getDecoratorInfoById(id
);
213 myDecorator2Info
.remove(decorator
);
214 myId2Decorator
.remove(id
);
216 WindowInfoImpl sideInfo
= getDockedInfoAt(info
.getAnchor(), !info
.isSplit());
219 if (sideInfo
== null) {
220 return new RemoveDockedComponentCmd(info
,dirtyMode
,finishCallBack
);
223 return new RemoveSplitAndDockedComponentCmd(info
, sideInfo
, dirtyMode
, finishCallBack
);
225 }else if(info
.isSliding()){
226 return new RemoveSlidingComponentCmd(decorator
,info
,dirtyMode
,finishCallBack
);
228 throw new IllegalArgumentException("Unknown window type");
233 * Creates command which sets specified document component.
234 * @param component component to be set.
236 final FinalizableCommand
createSetEditorComponentCmd(final JComponent component
,final Runnable finishCallBack
){
237 return new SetEditorComponentCmd(component
,finishCallBack
);
240 final FinalizableCommand
createUpdateButtonPositionCmd(String id
, final Runnable finishCallback
) {
241 return new UpdateButtonPositionCmd(id
, finishCallback
);
244 final JComponent
getMyLayeredPane(){
245 return myLayeredPane
;
248 private StripeButton
getButtonById(final String id
){
249 return myId2Button
.get(id
);
252 private Component
getDecoratorById(final String id
){
253 return myId2Decorator
.get(id
);
257 * @return <code>WindowInfo</code> associated with specified tool stripe button.
258 * @param id <code>ID</code> of tool stripe butoon.
260 private WindowInfoImpl
getButtonInfoById(final String id
){
261 return myButton2Info
.get(myId2Button
.get(id
));
265 * @return <code>WindowInfo</code> associated with specified window decorator.
266 * @param id <code>ID</code> of decorator.
268 private WindowInfoImpl
getDecoratorInfoById(final String id
){
269 return myDecorator2Info
.get(myId2Decorator
.get(id
));
273 * Sets (docks) specified component to the specified anchor.
275 private void setComponent(final JComponent component
, final ToolWindowAnchor anchor
, final float weight
) {
276 if(ToolWindowAnchor
.TOP
==anchor
){
277 myVerticalSplitter
.setFirstComponent(component
);
278 myVerticalSplitter
.setFirstSize((int)(myLayeredPane
.getHeight() * weight
));
279 }else if(ToolWindowAnchor
.LEFT
==anchor
){
280 myHorizontalSplitter
.setFirstComponent(component
);
281 myHorizontalSplitter
.setFirstSize((int)(myLayeredPane
.getWidth() * weight
));
282 }else if(ToolWindowAnchor
.BOTTOM
==anchor
){
283 myVerticalSplitter
.setLastComponent(component
);
284 myVerticalSplitter
.setLastSize((int)(myLayeredPane
.getHeight() * weight
));
285 }else if(ToolWindowAnchor
.RIGHT
==anchor
){
286 myHorizontalSplitter
.setLastComponent(component
);
287 myHorizontalSplitter
.setLastSize((int)(myLayeredPane
.getWidth() * weight
));
289 LOG
.error("unknown anchor: "+anchor
);
293 private JComponent
getComponentAt(ToolWindowAnchor anchor
) {
294 if (ToolWindowAnchor
.TOP
== anchor
) {
295 return myVerticalSplitter
.getFirstComponent();
297 else if (ToolWindowAnchor
.LEFT
== anchor
) {
298 return myHorizontalSplitter
.getFirstComponent();
300 else if (ToolWindowAnchor
.BOTTOM
== anchor
){
301 return myVerticalSplitter
.getLastComponent();
303 else if (ToolWindowAnchor
.RIGHT
== anchor
){
304 return myHorizontalSplitter
.getLastComponent();
307 LOG
.error("unknown anchor: " + anchor
);
312 private WindowInfoImpl
getDockedInfoAt(ToolWindowAnchor anchor
, boolean side
) {
313 for (WindowInfoImpl info
: myDecorator2Info
.values()) {
314 if (info
.isVisible() && info
.isDocked() && info
.getAnchor() == anchor
&& side
== info
.isSplit()) {
322 private void setDocumentComponent(final JComponent component
){
323 myHorizontalSplitter
.setInnerComponent(component
);
326 private void updateToolStripesVisibility(){
327 final boolean visible
= !UISettings
.getInstance().HIDE_TOOL_STRIPES
;
328 myLeftStripe
.setVisible(visible
);
329 myRightStripe
.setVisible(visible
);
330 myTopStripe
.setVisible(visible
);
331 myBottomStripe
.setVisible(visible
);
334 Stripe
getStripeFor(String id
) {
335 final ToolWindowAnchor anchor
= myManager
.getToolWindow(id
).getAnchor();
336 if (ToolWindowAnchor
.TOP
== anchor
) {
338 } else if (ToolWindowAnchor
.BOTTOM
== anchor
) {
339 return myBottomStripe
;
340 } else if (ToolWindowAnchor
.LEFT
== anchor
) {
342 } else if (ToolWindowAnchor
.RIGHT
== anchor
) {
343 return myRightStripe
;
346 throw new IllegalArgumentException("Anchor=" + anchor
);
349 Stripe
getStripeFor(final Rectangle screenRec
, Stripe preferred
) {
350 if (preferred
.containsScreen(screenRec
)) {
351 return myStipes
.get(myStipes
.indexOf(preferred
));
354 for (Stripe each
: myStipes
) {
355 if (each
.containsScreen(screenRec
)) {
356 return myStipes
.get(myStipes
.indexOf(each
));
364 for (Stripe each
: myStipes
) {
370 for (Stripe each
: myStipes
) {
375 public void stretchWidth(ToolWindow wnd
, int value
) {
379 public void stretchHeight(ToolWindow wnd
, int value
) {
383 private void stretch(ToolWindow wnd
, int value
) {
384 if (!wnd
.isVisible()) return;
386 Resizer resizer
= null;
387 Component cmp
= null;
389 if (wnd
.getType() == ToolWindowType
.DOCKED
) {
390 cmp
= getComponentAt(wnd
.getAnchor());
393 if (wnd
.getAnchor().isHorizontal()) {
394 resizer
= myVerticalSplitter
.getFirstComponent() == cmp ?
new Resizer
.Splitter
.FirstComponent(myVerticalSplitter
) : new Resizer
.Splitter
.LastComponent(myVerticalSplitter
);
396 resizer
= myHorizontalSplitter
.getFirstComponent() == cmp ?
new Resizer
.Splitter
.FirstComponent(myHorizontalSplitter
) : new Resizer
.Splitter
.LastComponent(myHorizontalSplitter
);
399 } if (wnd
.getType() == ToolWindowType
.SLIDING
) {
400 cmp
= wnd
.getComponent();
401 while (cmp
!= null) {
402 if (cmp
.getParent() == myLayeredPane
) break;
403 cmp
= cmp
.getParent();
407 if (wnd
.getAnchor() == ToolWindowAnchor
.TOP
) {
408 resizer
= new Resizer
.LayeredPane
.Top(cmp
);
409 } else if (wnd
.getAnchor() == ToolWindowAnchor
.BOTTOM
) {
410 resizer
= new Resizer
.LayeredPane
.Bottom(cmp
);
411 } else if (wnd
.getAnchor() == ToolWindowAnchor
.LEFT
) {
412 resizer
= new Resizer
.LayeredPane
.Left(cmp
);
413 } else if (wnd
.getAnchor() == ToolWindowAnchor
.RIGHT
) {
414 resizer
= new Resizer
.LayeredPane
.Right(cmp
);
419 if (resizer
== null || cmp
== null) return;
421 int currentValue
= wnd
.getAnchor().isHorizontal() ? cmp
.getHeight() : cmp
.getWidth();
423 int actualSize
= currentValue
+ value
;
425 int minValue
= wnd
.getAnchor().isHorizontal() ?
((ToolWindowEx
)wnd
).getDecorator().getTitlePanel().getPreferredSize().height
: 16 + myHorizontalSplitter
.getDividerWidth();
426 int maxValue
= wnd
.getAnchor().isHorizontal() ? myLayeredPane
.getHeight() : myLayeredPane
.getWidth();
429 if (actualSize
< minValue
) {
430 actualSize
= minValue
;
433 if (actualSize
> maxValue
) {
434 actualSize
= maxValue
;
437 resizer
.setSize(actualSize
);
441 static interface Resizer
{
442 void setSize(int size
);
445 abstract static class Splitter
implements Resizer
{
446 ThreeComponentsSplitter mySplitter
;
448 Splitter(ThreeComponentsSplitter splitter
) {
449 mySplitter
= splitter
;
452 static class FirstComponent
extends Splitter
{
453 FirstComponent(ThreeComponentsSplitter splitter
) {
457 public void setSize(int size
) {
458 mySplitter
.setFirstSize(size
);
462 static class LastComponent
extends Splitter
{
463 LastComponent(ThreeComponentsSplitter splitter
) {
467 public void setSize(int size
) {
468 mySplitter
.setLastSize(size
);
473 abstract static class LayeredPane
implements Resizer
{
474 Component myComponent
;
476 protected LayeredPane(Component component
) {
477 myComponent
= component
;
480 public final void setSize(int size
) {
482 if (myComponent
.getParent() instanceof JComponent
) {
483 JComponent parent
= (JComponent
)myComponent
;
489 abstract void _setSize(int size
);
491 static class Left
extends LayeredPane
{
493 Left(Component component
) {
497 public void _setSize(int size
) {
498 myComponent
.setSize(size
, myComponent
.getHeight());
502 static class Right
extends LayeredPane
{
503 Right(Component component
) {
507 public void _setSize(int size
) {
508 Rectangle bounds
= myComponent
.getBounds();
509 int delta
= size
- bounds
.width
;
511 bounds
.width
+= delta
;
512 myComponent
.setBounds(bounds
);
516 static class Top
extends LayeredPane
{
517 Top(Component component
) {
521 public void _setSize(int size
) {
522 myComponent
.setSize(myComponent
.getWidth(), size
);
526 static class Bottom
extends LayeredPane
{
527 Bottom(Component component
) {
531 public void _setSize(int size
) {
532 Rectangle bounds
= myComponent
.getBounds();
533 int delta
= size
- bounds
.height
;
535 bounds
.height
+= delta
;
536 myComponent
.setBounds(bounds
);
542 private final class AddDockedComponentCmd
extends FinalizableCommand
{
543 private final JComponent myComponent
;
544 private final WindowInfoImpl myInfo
;
545 private final boolean myDirtyMode
;
547 public AddDockedComponentCmd(final JComponent component
, final WindowInfoImpl info
, final boolean dirtyMode
, final Runnable finishCallBack
){
548 super(finishCallBack
);
549 myComponent
=component
;
551 myDirtyMode
=dirtyMode
;
554 public final void run(){
556 float newWeight
= myInfo
.getWeight()<=.0f? WindowInfoImpl
.DEFAULT_WEIGHT
:myInfo
.getWeight();
558 newWeight
=1- WindowInfoImpl
.DEFAULT_WEIGHT
;
560 final ToolWindowAnchor anchor
=myInfo
.getAnchor();
561 setComponent(myComponent
, anchor
, newWeight
);
563 myLayeredPane
.validate();
564 myLayeredPane
.repaint();
572 private final class AddAndSplitDockedComponentCmd
extends FinalizableCommand
{
573 private final JComponent myNewComponent
;
574 private final WindowInfoImpl myInfo
;
575 private final boolean myDirtyMode
;
577 private AddAndSplitDockedComponentCmd(final JComponent newComponent
,
578 final WindowInfoImpl info
, final boolean dirtyMode
, final Runnable finishCallBack
) {
579 super(finishCallBack
);
580 myNewComponent
= newComponent
;
582 myDirtyMode
= dirtyMode
;
588 final ToolWindowAnchor anchor
= myInfo
.getAnchor();
589 Splitter splitter
= new Splitter(!myInfo
.getAnchor().isHorizontal());
590 InternalDecorator oldComponent
= (InternalDecorator
) getComponentAt(myInfo
.getAnchor());
591 if (myInfo
.isSplit()) {
592 splitter
.setFirstComponent(oldComponent
);
593 splitter
.setSecondComponent(myNewComponent
);
594 splitter
.setProportion(normalizeWeigh(oldComponent
.getWindowInfo().getSideWeight()));
595 newWeight
= normalizeWeigh(oldComponent
.getWindowInfo().getWeight());
598 splitter
.setFirstComponent(myNewComponent
);
599 splitter
.setSecondComponent(oldComponent
);
600 splitter
.setProportion(normalizeWeigh(myInfo
.getSideWeight()));
601 newWeight
= normalizeWeigh(myInfo
.getWeight());
603 setComponent(splitter
, anchor
, newWeight
);
606 myLayeredPane
.validate();
607 myLayeredPane
.repaint();
614 private float normalizeWeigh(final float weight
) {
615 float newWeight
= weight
<= .0f ? WindowInfoImpl
.DEFAULT_WEIGHT
: weight
;
616 if (newWeight
>= 1.0f
) {
617 newWeight
= 1- WindowInfoImpl
.DEFAULT_WEIGHT
;
623 private final class AddSlidingComponentCmd
extends FinalizableCommand
{
624 private final Component myComponent
;
625 private final WindowInfoImpl myInfo
;
626 private final boolean myDirtyMode
;
628 public AddSlidingComponentCmd(final Component component
, final WindowInfoImpl info
, final boolean dirtyMode
, final Runnable finishCallBack
){
629 super(finishCallBack
);
630 myComponent
=component
;
632 myDirtyMode
=dirtyMode
;
635 public final void run(){
638 final UISettings uiSettings
=UISettings
.getInstance();
639 if(!myDirtyMode
&& uiSettings
.ANIMATE_WINDOWS
&& !UISettings
.isRemoteDesktopConnected()){
640 // Prepare top image. This image is scrolling over bottom image.
641 final Image topImage
=myLayeredPane
.getTopImage();
642 final Graphics topGraphics
=topImage
.getGraphics();
647 myLayeredPane
.add(myComponent
,JLayeredPane
.PALETTE_LAYER
);
648 myLayeredPane
.moveToFront(myComponent
);
649 myLayeredPane
.setBoundsInPaletteLayer(myComponent
,myInfo
.getAnchor(),myInfo
.getWeight());
650 bounds
=myComponent
.getBounds();
651 myComponent
.paint(topGraphics
);
652 myLayeredPane
.remove(myComponent
);
654 topGraphics
.dispose();
656 // Prepare bottom image.
657 final Image bottomImage
=myLayeredPane
.getBottomImage();
658 final Graphics bottomGraphics
=bottomImage
.getGraphics();
660 bottomGraphics
.setClip(0,0,bounds
.width
,bounds
.height
);
661 bottomGraphics
.translate(-bounds
.x
,-bounds
.y
);
662 myLayeredPane
.paint(bottomGraphics
);
664 bottomGraphics
.dispose();
667 final Surface surface
=new Surface(topImage
,bottomImage
,1,myInfo
.getAnchor(),uiSettings
.ANIMATION_SPEED
);
668 myLayeredPane
.add(surface
,JLayeredPane
.PALETTE_LAYER
);
669 surface
.setBounds(bounds
);
670 myLayeredPane
.validate();
671 myLayeredPane
.repaint();
673 surface
.runMovement();
674 myLayeredPane
.remove(surface
);
675 myLayeredPane
.add(myComponent
,JLayeredPane
.PALETTE_LAYER
);
676 }else{ // not animated
677 myLayeredPane
.add(myComponent
,JLayeredPane
.PALETTE_LAYER
);
678 myLayeredPane
.setBoundsInPaletteLayer(myComponent
,myInfo
.getAnchor(),myInfo
.getWeight());
681 myLayeredPane
.validate();
682 myLayeredPane
.repaint();
690 private final class AddToolStripeButtonCmd
extends FinalizableCommand
{
691 private final StripeButton myButton
;
692 private final WindowInfoImpl myInfo
;
693 private final Comparator myComparator
;
695 public AddToolStripeButtonCmd(final StripeButton button
,final WindowInfoImpl info
,final Comparator comparator
,final Runnable finishCallBack
){
696 super(finishCallBack
);
699 myComparator
=comparator
;
702 public final void run(){
704 final ToolWindowAnchor anchor
=myInfo
.getAnchor();
705 if(ToolWindowAnchor
.TOP
==anchor
){
706 myTopStripe
.addButton(myButton
,myComparator
);
707 }else if(ToolWindowAnchor
.LEFT
==anchor
){
708 myLeftStripe
.addButton(myButton
,myComparator
);
709 }else if(ToolWindowAnchor
.BOTTOM
==anchor
){
710 myBottomStripe
.addButton(myButton
,myComparator
);
711 }else if(ToolWindowAnchor
.RIGHT
==anchor
){
712 myRightStripe
.addButton(myButton
,myComparator
);
714 LOG
.error("unknown anchor: "+anchor
);
724 private final class RemoveToolStripeButtonCmd
extends FinalizableCommand
{
725 private final StripeButton myButton
;
726 private final WindowInfoImpl myInfo
;
728 public RemoveToolStripeButtonCmd(final StripeButton button
,final WindowInfoImpl info
,final Runnable finishCallBack
){
729 super(finishCallBack
);
734 public final void run(){
736 final ToolWindowAnchor anchor
=myInfo
.getAnchor();
737 if(ToolWindowAnchor
.TOP
==anchor
){
738 myTopStripe
.removeButton(myButton
);
739 }else if(ToolWindowAnchor
.LEFT
==anchor
){
740 myLeftStripe
.removeButton(myButton
);
741 }else if(ToolWindowAnchor
.BOTTOM
==anchor
){
742 myBottomStripe
.removeButton(myButton
);
743 }else if(ToolWindowAnchor
.RIGHT
==anchor
){
744 myRightStripe
.removeButton(myButton
);
746 LOG
.error("unknown anchor: "+anchor
);
756 private final class RemoveDockedComponentCmd
extends FinalizableCommand
{
757 private final WindowInfoImpl myInfo
;
758 private final boolean myDirtyMode
;
760 public RemoveDockedComponentCmd(final WindowInfoImpl info
, final boolean dirtyMode
, final Runnable finishCallBack
){
761 super(finishCallBack
);
763 myDirtyMode
=dirtyMode
;
766 public final void run(){
768 setComponent(null,myInfo
.getAnchor(), 0);
770 myLayeredPane
.validate();
771 myLayeredPane
.repaint();
779 private final class RemoveSplitAndDockedComponentCmd
extends FinalizableCommand
{
780 private final WindowInfoImpl myInfo
;
781 private final WindowInfoImpl mySideInfo
;
782 private final boolean myDirtyMode
;
784 private RemoveSplitAndDockedComponentCmd(final WindowInfoImpl info
, final WindowInfoImpl sideInfo
, boolean dirtyMode
, final Runnable finishCallBack
) {
785 super(finishCallBack
);
787 mySideInfo
= sideInfo
;
788 myDirtyMode
= dirtyMode
;
793 Splitter splitter
= (Splitter
) getComponentAt(myInfo
.getAnchor());
795 if (myInfo
.isSplit()) {
796 InternalDecorator component
= (InternalDecorator
)splitter
.getFirstComponent();
797 setComponent(component
, myInfo
.getAnchor(), component
.getWindowInfo().getWeight());
800 InternalDecorator component
= (InternalDecorator
) splitter
.getSecondComponent();
801 setComponent(component
, myInfo
.getAnchor(), component
.getWindowInfo().getWeight());
804 myLayeredPane
.validate();
805 myLayeredPane
.repaint();
814 private final class RemoveSlidingComponentCmd
extends FinalizableCommand
{
815 private final Component myComponent
;
816 private final WindowInfoImpl myInfo
;
817 private final boolean myDirtyMode
;
819 public RemoveSlidingComponentCmd(
820 final Component component
,
821 final WindowInfoImpl info
,
822 final boolean dirtyMode
,
823 final Runnable finishCallBack
825 super(finishCallBack
);
826 myComponent
=component
;
828 myDirtyMode
=dirtyMode
;
831 public final void run(){
833 final UISettings uiSettings
=UISettings
.getInstance();
834 if(!myDirtyMode
&& uiSettings
.ANIMATE_WINDOWS
&& !UISettings
.isRemoteDesktopConnected()){
835 final Rectangle bounds
=myComponent
.getBounds();
836 // Prepare top image. This image is scrolling over bottom image. It contains
837 // picture of component is being removed.
838 final Image topImage
=myLayeredPane
.getTopImage();
839 final Graphics topGraphics
=topImage
.getGraphics();
841 myComponent
.paint(topGraphics
);
843 topGraphics
.dispose();
845 // Prepare bottom image. This image contains picture of component that is located
846 // under the component to is being removed.
847 final Image bottomImage
=myLayeredPane
.getBottomImage();
848 final Graphics bottomGraphics
= bottomImage
.getGraphics();
850 myLayeredPane
.remove(myComponent
);
851 bottomGraphics
.clipRect(0,0,bounds
.width
,bounds
.height
);
852 bottomGraphics
.translate(-bounds
.x
,-bounds
.y
);
853 myLayeredPane
.paint(bottomGraphics
);
855 bottomGraphics
.dispose();
857 // Remove component from the layered pane and start animation.
858 final Surface surface
=new Surface(topImage
,bottomImage
,-1,myInfo
.getAnchor(),uiSettings
.ANIMATION_SPEED
* 2);
859 myLayeredPane
.add(surface
,JLayeredPane
.PALETTE_LAYER
);
860 surface
.setBounds(bounds
);
861 myLayeredPane
.validate();
862 myLayeredPane
.repaint();
864 surface
.runMovement();
865 myLayeredPane
.remove(surface
);
866 }else{ // not animated
867 myLayeredPane
.remove(myComponent
);
870 myLayeredPane
.validate();
871 myLayeredPane
.repaint();
879 private final class SetEditorComponentCmd
extends FinalizableCommand
{
880 private final JComponent myComponent
;
882 public SetEditorComponentCmd(final JComponent component
,final Runnable finishCallBack
){
883 super(finishCallBack
);
884 myComponent
=component
;
889 setDocumentComponent(myComponent
);
890 myLayeredPane
.validate();
891 myLayeredPane
.repaint();
898 private final class UpdateButtonPositionCmd
extends FinalizableCommand
{
899 private final String myId
;
901 private UpdateButtonPositionCmd(String id
, final Runnable finishCallBack
) {
902 super(finishCallBack
);
909 WindowInfoImpl info
= getButtonById(myId
).getWindowInfo();
910 ToolWindowAnchor anchor
= info
.getAnchor();
912 if (ToolWindowAnchor
.TOP
== anchor
){
913 myTopStripe
.revalidate();
915 else if (ToolWindowAnchor
.LEFT
== anchor
){
916 myLeftStripe
.revalidate();
918 else if (ToolWindowAnchor
.BOTTOM
== anchor
) {
919 myBottomStripe
.revalidate();
921 else if (ToolWindowAnchor
.RIGHT
== anchor
) {
922 myRightStripe
.revalidate();
925 LOG
.error("unknown anchor: " + anchor
);
933 private final class MyUISettingsListenerImpl
implements UISettingsListener
{
934 public final void uiSettingsChanged(final UISettings source
){
935 updateToolStripesVisibility();
939 private final class MyLayeredPane
extends JLayeredPane
{
941 * These images are used to perform animated showing and hiding of components.
942 * They are the member for performance reason.
944 private SoftReference myBottomImageRef
;
945 private SoftReference myTopImageRef
;
947 public MyLayeredPane(final JComponent splitter
) {
948 myBottomImageRef
=new SoftReference(null);
949 myTopImageRef
=new SoftReference(null);
951 setBackground(Color
.gray
);
952 add(splitter
,JLayeredPane
.DEFAULT_LAYER
);
953 splitter
.setBounds(0,0,getWidth(),getHeight());
954 enableEvents(ComponentEvent
.COMPONENT_EVENT_MASK
);
958 * TODO[vova] extract method
959 * Lazily creates and returns bottom image for animation.
961 public final Image
getBottomImage(){
962 LOG
.assertTrue(UISettings
.getInstance().ANIMATE_WINDOWS
);
963 BufferedImage image
=(BufferedImage
)myBottomImageRef
.get();
966 image
.getWidth(null) < getWidth() || image
.getHeight(null) < getHeight()
968 final int width
=Math
.max(Math
.max(1,getWidth()),myFrame
.getWidth());
969 final int height
=Math
.max(Math
.max(1,getHeight()),myFrame
.getHeight());
970 if(SystemInfo
.isWindows
|| SystemInfo
.isMac
){
971 image
=myFrame
.getGraphicsConfiguration().createCompatibleImage(width
,height
);
973 // Under Linux we have found that images created by createCompatibleImage(),
974 // createVolatileImage(), etc extremely slow for rendering. TrueColor buffered image
976 image
=new BufferedImage(width
,height
,BufferedImage
.TYPE_INT_RGB
);
978 myBottomImageRef
=new SoftReference(image
);
984 * TODO[vova] extract method
985 * Lazily creates and returns top image for animation.
987 public final Image
getTopImage(){
988 LOG
.assertTrue(UISettings
.getInstance().ANIMATE_WINDOWS
);
989 BufferedImage image
=(BufferedImage
)myTopImageRef
.get();
992 image
.getWidth(null) < getWidth() || image
.getHeight(null) < getHeight()
994 final int width
=Math
.max(Math
.max(1,getWidth()),myFrame
.getWidth());
995 final int height
=Math
.max(Math
.max(1,getHeight()),myFrame
.getHeight());
996 if(SystemInfo
.isWindows
|| SystemInfo
.isMac
){
997 image
=myFrame
.getGraphicsConfiguration().createCompatibleImage(width
,height
);
999 // Under Linux we have found that images created by createCompatibleImage(),
1000 // createVolatileImage(), etc extremely slow for rendering. TrueColor buffered image
1002 image
=new BufferedImage(width
,height
,BufferedImage
.TYPE_INT_RGB
);
1004 myTopImageRef
=new SoftReference(image
);
1010 * When component size becomes larger then bottom and top images should be enlarged.
1012 protected final void processComponentEvent(final ComponentEvent e
) {
1013 if(ComponentEvent
.COMPONENT_RESIZED
==e
.getID()){
1014 final int width
=getWidth();
1015 final int height
=getHeight();
1016 if(width
<0||height
<0){
1019 // Resize component at the DEFAULT layer. It should be only on component in that layer
1020 Component
[] components
=getComponentsInLayer(JLayeredPane
.DEFAULT_LAYER
.intValue());
1021 LOG
.assertTrue(components
.length
<=1);
1022 for(int i
=0;i
<components
.length
;i
++){
1023 final Component component
=components
[i
];
1024 component
.setBounds(0,0,getWidth(),getHeight());
1026 // Resize components at the PALETTE layer
1027 components
=getComponentsInLayer(JLayeredPane
.PALETTE_LAYER
.intValue());
1028 for(int i
=0;i
<components
.length
;i
++){
1029 final Component component
=components
[i
];
1030 if (!(component
instanceof InternalDecorator
)) {
1033 final WindowInfoImpl info
=myDecorator2Info
.get(component
);
1034 // In normal situation info is not null. But sometimes Swing sends resize
1035 // event to removed component. See SCR #19566.
1041 if(ToolWindowAnchor
.TOP
==info
.getAnchor()||ToolWindowAnchor
.BOTTOM
==info
.getAnchor()){
1042 weight
=(float)component
.getHeight()/(float)getHeight();
1044 weight
=(float)component
.getWidth()/(float)getWidth();
1046 setBoundsInPaletteLayer(component
,info
.getAnchor(),weight
);
1051 super.processComponentEvent(e
);
1055 public final void setBoundsInPaletteLayer(final Component component
,final ToolWindowAnchor anchor
,float weight
){
1057 weight
= WindowInfoImpl
.DEFAULT_WEIGHT
;
1058 }else if(weight
>1.0f
){
1061 if(ToolWindowAnchor
.TOP
==anchor
){
1062 component
.setBounds(0,0,getWidth(),(int)(getHeight()*weight
+.5f
));
1063 }else if(ToolWindowAnchor
.LEFT
==anchor
){
1064 component
.setBounds(0,0,(int)(getWidth()*weight
+.5f
),getHeight());
1065 }else if(ToolWindowAnchor
.BOTTOM
==anchor
){
1066 final int height
=(int)(getHeight()*weight
+.5f
);
1067 component
.setBounds(0,getHeight()-height
,getWidth(),height
);
1068 }else if(ToolWindowAnchor
.RIGHT
==anchor
){
1069 final int width
=(int)(getWidth()*weight
+.5f
);
1070 component
.setBounds(getWidth()-width
,0,width
,getHeight());
1072 LOG
.error("unknown anchor "+anchor
);
1078 static int getHorizontalInsetX() {