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
.impl
.commands
.FinalizableCommand
;
27 import com
.intellij
.reference
.SoftReference
;
28 import com
.intellij
.util
.containers
.HashMap
;
32 import java
.awt
.event
.ComponentEvent
;
33 import java
.awt
.image
.BufferedImage
;
34 import java
.util
.ArrayList
;
35 import java
.util
.Comparator
;
38 * This panel contains all tool stripes and JLayeredPanle at the center area. All tool windows are
39 * located inside this layered pane.
41 * @author Anton Katilin
42 * @author Vladimir Kondratyev
44 final class ToolWindowsPane
extends JPanel
{
45 private static final Logger LOG
=Logger
.getInstance("#com.intellij.openapi.wm.impl.ToolWindowsPane");
47 private final IdeFrameImpl myFrame
;
49 private final HashMap
<String
,StripeButton
> myId2Button
;
50 private final HashMap
<String
,InternalDecorator
> myId2Decorator
;
51 private final HashMap
<StripeButton
, WindowInfoImpl
> myButton2Info
;
52 private final HashMap
<InternalDecorator
, WindowInfoImpl
> myDecorator2Info
;
54 * This panel is the layered pane where all sliding tool windows are located. The DEFAULT
55 * layer contains splitters. The PALETTE layer contains all sliding tool windows.
57 private final MyLayeredPane myLayeredPane
;
61 private final ThreeComponentsSplitter myVerticalSplitter
;
62 private final ThreeComponentsSplitter myHorizontalSplitter
;
67 private final Stripe myLeftStripe
;
68 private final Stripe myRightStripe
;
69 private final Stripe myBottomStripe
;
70 private final Stripe myTopStripe
;
72 private final ArrayList
<Stripe
> myStipes
= new ArrayList
<Stripe
>();
74 private final MyUISettingsListenerImpl myUISettingsListener
;
75 private final ToolWindowManagerImpl myManager
;
77 ToolWindowsPane(final IdeFrameImpl frame
, ToolWindowManagerImpl manager
){
78 super(new BorderLayout());
84 myId2Button
=new HashMap
<String
,StripeButton
>();
85 myId2Decorator
=new HashMap
<String
,InternalDecorator
>();
86 myButton2Info
=new HashMap
<StripeButton
, WindowInfoImpl
>();
87 myDecorator2Info
=new HashMap
<InternalDecorator
, WindowInfoImpl
>();
88 myUISettingsListener
=new MyUISettingsListenerImpl();
92 myVerticalSplitter
= new ThreeComponentsSplitter(true);
93 myVerticalSplitter
.setBackground(Color
.gray
);
94 myHorizontalSplitter
= new ThreeComponentsSplitter(false);
95 myHorizontalSplitter
.setBackground(Color
.gray
);
97 myVerticalSplitter
.setInnerComponent(myHorizontalSplitter
);
101 myTopStripe
=new Stripe(SwingConstants
.TOP
, manager
);
102 myStipes
.add(myTopStripe
);
103 myLeftStripe
=new Stripe(SwingConstants
.LEFT
, manager
);
104 myStipes
.add(myLeftStripe
);
105 myBottomStripe
=new Stripe(SwingConstants
.BOTTOM
, manager
);
106 myStipes
.add(myBottomStripe
);
107 myRightStripe
=new Stripe(SwingConstants
.RIGHT
, manager
);
108 myStipes
.add(myRightStripe
);
110 updateToolStripesVisibility();
114 myLayeredPane
=new MyLayeredPane(myVerticalSplitter
);
118 add(myTopStripe
,BorderLayout
.NORTH
);
119 add(myLeftStripe
,BorderLayout
.WEST
);
120 add(myBottomStripe
,BorderLayout
.SOUTH
);
121 add(myRightStripe
,BorderLayout
.EAST
);
122 add(myLayeredPane
,BorderLayout
.CENTER
);
126 * Invoked when enclosed frame is being shown.
128 public final void addNotify(){
130 UISettings
.getInstance().addUISettingsListener(myUISettingsListener
);
134 * Invoked when enclosed frame is being disposed.
136 public final void removeNotify(){
137 UISettings
.getInstance().removeUISettingsListener(myUISettingsListener
);
138 super.removeNotify();
142 * Creates command which adds button into the specified tool stripe.
143 * Command uses copy of passed <code>info</code> object.
144 * @param button button which should be added.
145 * @param info window info for the corresponded tool window.
146 * @param comparator which is used to sort buttons within the stripe.
147 * @param finishCallBack invoked when the command is completed.
149 final FinalizableCommand
createAddButtonCmd(final StripeButton button
,final WindowInfoImpl info
,final Comparator comparator
,final Runnable finishCallBack
){
150 final WindowInfoImpl copiedInfo
=info
.copy();
151 myId2Button
.put(copiedInfo
.getId(),button
);
152 myButton2Info
.put(button
,copiedInfo
);
153 return new AddToolStripeButtonCmd(button
,copiedInfo
,comparator
,finishCallBack
);
157 * Creates command which shows tool window with specified set of parameters.
158 * Command uses cloned copy of passed <code>info</code> object.
159 * @param dirtyMode if <code>true</code> then JRootPane will not be validated and repainted after adding
160 * the decorator. Moreover in this (dirty) mode animation doesn't work.
162 final FinalizableCommand
createAddDecoratorCmd(
163 final InternalDecorator decorator
,
164 final WindowInfoImpl info
,
165 final boolean dirtyMode
,
166 final Runnable finishCallBack
168 final WindowInfoImpl copiedInfo
=info
.copy();
169 final String id
=copiedInfo
.getId();
171 myDecorator2Info
.put(decorator
,copiedInfo
);
172 myId2Decorator
.put(id
,decorator
);
175 WindowInfoImpl sideInfo
= getDockedInfoAt(info
.getAnchor(), !info
.isSplit());
176 if (sideInfo
== null) {
177 return new AddDockedComponentCmd(decorator
,info
,dirtyMode
,finishCallBack
);
180 return new AddAndSplitDockedComponentCmd(decorator
, info
, dirtyMode
, finishCallBack
);
182 } else if(info
.isSliding()) {
183 return new AddSlidingComponentCmd(decorator
,info
,dirtyMode
,finishCallBack
);
185 throw new IllegalArgumentException("Unknown window type: "+info
.getType());
190 * Creates command which removes tool button from tool stripe.
191 * @param id <code>ID</code> of the button to be removed.
193 final FinalizableCommand
createRemoveButtonCmd(final String id
,final Runnable finishCallBack
){
194 final StripeButton button
=getButtonById(id
);
195 final WindowInfoImpl info
=getButtonInfoById(id
);
197 myButton2Info
.remove(button
);
198 myId2Button
.remove(id
);
199 return new RemoveToolStripeButtonCmd(button
,info
,finishCallBack
);
203 * Creates command which hides tool window with specified set of parameters.
204 * @param dirtyMode if <code>true</code> then JRootPane will not be validated and repainted after removing
205 * the decorator. Moreover in this (dirty) mode animation doesn't work.
207 final FinalizableCommand
createRemoveDecoratorCmd(final String id
, final boolean dirtyMode
, final Runnable finishCallBack
){
208 final Component decorator
=getDecoratorById(id
);
209 final WindowInfoImpl info
=getDecoratorInfoById(id
);
211 myDecorator2Info
.remove(decorator
);
212 myId2Decorator
.remove(id
);
214 WindowInfoImpl sideInfo
= getDockedInfoAt(info
.getAnchor(), !info
.isSplit());
217 if (sideInfo
== null) {
218 return new RemoveDockedComponentCmd(info
,dirtyMode
,finishCallBack
);
221 return new RemoveSplitAndDockedComponentCmd(info
, sideInfo
, dirtyMode
, finishCallBack
);
223 }else if(info
.isSliding()){
224 return new RemoveSlidingComponentCmd(decorator
,info
,dirtyMode
,finishCallBack
);
226 throw new IllegalArgumentException("Unknown window type");
231 * Creates command which sets specified document component.
232 * @param component component to be set.
234 final FinalizableCommand
createSetEditorComponentCmd(final JComponent component
,final Runnable finishCallBack
){
235 return new SetEditorComponentCmd(component
,finishCallBack
);
238 final FinalizableCommand
createUpdateButtonPositionCmd(String id
, final Runnable finishCallback
) {
239 return new UpdateButtonPositionCmd(id
, finishCallback
);
242 final JComponent
getMyLayeredPane(){
243 return myLayeredPane
;
246 private StripeButton
getButtonById(final String id
){
247 return myId2Button
.get(id
);
250 private Component
getDecoratorById(final String id
){
251 return myId2Decorator
.get(id
);
255 * @return <code>WindowInfo</code> associated with specified tool stripe button.
256 * @param id <code>ID</code> of tool stripe butoon.
258 private WindowInfoImpl
getButtonInfoById(final String id
){
259 return myButton2Info
.get(myId2Button
.get(id
));
263 * @return <code>WindowInfo</code> associated with specified window decorator.
264 * @param id <code>ID</code> of decorator.
266 private WindowInfoImpl
getDecoratorInfoById(final String id
){
267 return myDecorator2Info
.get(myId2Decorator
.get(id
));
271 * Sets (docks) specified component to the specified anchor.
273 private void setComponent(final JComponent component
, final ToolWindowAnchor anchor
, final float weight
) {
274 if(ToolWindowAnchor
.TOP
==anchor
){
275 myVerticalSplitter
.setFirstComponent(component
);
276 myVerticalSplitter
.setFirstSize((int)(myLayeredPane
.getHeight() * weight
));
277 }else if(ToolWindowAnchor
.LEFT
==anchor
){
278 myHorizontalSplitter
.setFirstComponent(component
);
279 myHorizontalSplitter
.setFirstSize((int)(myLayeredPane
.getWidth() * weight
));
280 }else if(ToolWindowAnchor
.BOTTOM
==anchor
){
281 myVerticalSplitter
.setLastComponent(component
);
282 myVerticalSplitter
.setLastSize((int)(myLayeredPane
.getHeight() * weight
));
283 }else if(ToolWindowAnchor
.RIGHT
==anchor
){
284 myHorizontalSplitter
.setLastComponent(component
);
285 myHorizontalSplitter
.setLastSize((int)(myLayeredPane
.getWidth() * weight
));
287 LOG
.error("unknown anchor: "+anchor
);
291 private JComponent
getComponentAt(ToolWindowAnchor anchor
) {
292 if (ToolWindowAnchor
.TOP
== anchor
) {
293 return myVerticalSplitter
.getFirstComponent();
295 else if (ToolWindowAnchor
.LEFT
== anchor
) {
296 return myHorizontalSplitter
.getFirstComponent();
298 else if (ToolWindowAnchor
.BOTTOM
== anchor
){
299 return myVerticalSplitter
.getLastComponent();
301 else if (ToolWindowAnchor
.RIGHT
== anchor
){
302 return myHorizontalSplitter
.getLastComponent();
305 LOG
.error("unknown anchor: " + anchor
);
310 private WindowInfoImpl
getDockedInfoAt(ToolWindowAnchor anchor
, boolean side
) {
311 for (WindowInfoImpl info
: myDecorator2Info
.values()) {
312 if (info
.isVisible() && info
.isDocked() && info
.getAnchor() == anchor
&& side
== info
.isSplit()) {
320 private void setDocumentComponent(final JComponent component
){
321 myHorizontalSplitter
.setInnerComponent(component
);
324 private void updateToolStripesVisibility(){
325 final boolean visible
= !UISettings
.getInstance().HIDE_TOOL_STRIPES
;
326 myLeftStripe
.setVisible(visible
);
327 myRightStripe
.setVisible(visible
);
328 myTopStripe
.setVisible(visible
);
329 myBottomStripe
.setVisible(visible
);
332 Stripe
getStripeFor(String id
) {
333 final ToolWindowAnchor anchor
= myManager
.getToolWindow(id
).getAnchor();
334 if (ToolWindowAnchor
.TOP
== anchor
) {
336 } else if (ToolWindowAnchor
.BOTTOM
== anchor
) {
337 return myBottomStripe
;
338 } else if (ToolWindowAnchor
.LEFT
== anchor
) {
340 } else if (ToolWindowAnchor
.RIGHT
== anchor
) {
341 return myRightStripe
;
344 throw new IllegalArgumentException("Anchor=" + anchor
);
347 Stripe
getStripeFor(final Rectangle screenRec
, Stripe preferred
) {
348 if (preferred
.containsScreen(screenRec
)) {
349 return myStipes
.get(myStipes
.indexOf(preferred
));
352 for (Stripe each
: myStipes
) {
353 if (each
.containsScreen(screenRec
)) {
354 return myStipes
.get(myStipes
.indexOf(each
));
362 for (Stripe each
: myStipes
) {
368 for (Stripe each
: myStipes
) {
373 public void stretchWidth(ToolWindow wnd
, int value
) {
374 JComponent cmp
= getComponentAt(wnd
.getAnchor());
375 if (cmp
== null) return;
377 stretch(myHorizontalSplitter
, cmp
, cmp
.getSize().width
, value
, 0, getSize().width
);
380 public void stretchHeight(ToolWindow wnd
, int value
) {
381 JComponent cmp
= getComponentAt(wnd
.getAnchor());
382 if (cmp
== null) return;
384 stretch(myVerticalSplitter
, cmp
, cmp
.getSize().height
, value
, 0, getSize().height
);
387 private void stretch(ThreeComponentsSplitter splitter
, JComponent cmp
, int currentValue
, int incValue
, int minValue
, int maxValue
) {
388 int actualSize
= currentValue
+ incValue
;
390 if (actualSize
< minValue
) {
391 actualSize
= minValue
;
394 if (actualSize
> maxValue
) {
395 actualSize
= maxValue
;
398 if (splitter
.getFirstComponent() == cmp
) {
399 splitter
.setFirstSize(actualSize
);
400 } else if (splitter
.getLastComponent() == cmp
) {
401 splitter
.setLastSize(actualSize
);
405 private final class AddDockedComponentCmd
extends FinalizableCommand
{
406 private final JComponent myComponent
;
407 private final WindowInfoImpl myInfo
;
408 private final boolean myDirtyMode
;
410 public AddDockedComponentCmd(final JComponent component
, final WindowInfoImpl info
, final boolean dirtyMode
, final Runnable finishCallBack
){
411 super(finishCallBack
);
412 myComponent
=component
;
414 myDirtyMode
=dirtyMode
;
417 public final void run(){
419 float newWeight
= myInfo
.getWeight()<=.0f? WindowInfoImpl
.DEFAULT_WEIGHT
:myInfo
.getWeight();
421 newWeight
=1- WindowInfoImpl
.DEFAULT_WEIGHT
;
423 final ToolWindowAnchor anchor
=myInfo
.getAnchor();
424 setComponent(myComponent
, anchor
, newWeight
);
426 myLayeredPane
.validate();
427 myLayeredPane
.repaint();
435 private final class AddAndSplitDockedComponentCmd
extends FinalizableCommand
{
436 private final JComponent myNewComponent
;
437 private final WindowInfoImpl myInfo
;
438 private final boolean myDirtyMode
;
440 private AddAndSplitDockedComponentCmd(final JComponent newComponent
,
441 final WindowInfoImpl info
, final boolean dirtyMode
, final Runnable finishCallBack
) {
442 super(finishCallBack
);
443 myNewComponent
= newComponent
;
445 myDirtyMode
= dirtyMode
;
451 final ToolWindowAnchor anchor
= myInfo
.getAnchor();
452 Splitter splitter
= new Splitter(!myInfo
.getAnchor().isHorizontal());
453 InternalDecorator oldComponent
= (InternalDecorator
) getComponentAt(myInfo
.getAnchor());
454 if (myInfo
.isSplit()) {
455 splitter
.setFirstComponent(oldComponent
);
456 splitter
.setSecondComponent(myNewComponent
);
457 splitter
.setProportion(normalizeWeigh(oldComponent
.getWindowInfo().getSideWeight()));
458 newWeight
= normalizeWeigh(oldComponent
.getWindowInfo().getWeight());
461 splitter
.setFirstComponent(myNewComponent
);
462 splitter
.setSecondComponent(oldComponent
);
463 splitter
.setProportion(normalizeWeigh(myInfo
.getSideWeight()));
464 newWeight
= normalizeWeigh(myInfo
.getWeight());
466 setComponent(splitter
, anchor
, newWeight
);
469 myLayeredPane
.validate();
470 myLayeredPane
.repaint();
477 private float normalizeWeigh(final float weight
) {
478 float newWeight
= weight
<= .0f ? WindowInfoImpl
.DEFAULT_WEIGHT
: weight
;
479 if (newWeight
>= 1.0f
) {
480 newWeight
= 1- WindowInfoImpl
.DEFAULT_WEIGHT
;
486 private final class AddSlidingComponentCmd
extends FinalizableCommand
{
487 private final Component myComponent
;
488 private final WindowInfoImpl myInfo
;
489 private final boolean myDirtyMode
;
491 public AddSlidingComponentCmd(final Component component
, final WindowInfoImpl info
, final boolean dirtyMode
, final Runnable finishCallBack
){
492 super(finishCallBack
);
493 myComponent
=component
;
495 myDirtyMode
=dirtyMode
;
498 public final void run(){
501 final UISettings uiSettings
=UISettings
.getInstance();
502 if(!myDirtyMode
&& uiSettings
.ANIMATE_WINDOWS
&& !UISettings
.isRemoteDesktopConnected()){
503 // Prepare top image. This image is scrolling over bottom image.
504 final Image topImage
=myLayeredPane
.getTopImage();
505 final Graphics topGraphics
=topImage
.getGraphics();
510 myLayeredPane
.add(myComponent
,JLayeredPane
.PALETTE_LAYER
);
511 myLayeredPane
.moveToFront(myComponent
);
512 myLayeredPane
.setBoundsInPaletteLayer(myComponent
,myInfo
.getAnchor(),myInfo
.getWeight());
513 bounds
=myComponent
.getBounds();
514 myComponent
.paint(topGraphics
);
515 myLayeredPane
.remove(myComponent
);
517 topGraphics
.dispose();
519 // Prepare bottom image.
520 final Image bottomImage
=myLayeredPane
.getBottomImage();
521 final Graphics bottomGraphics
=bottomImage
.getGraphics();
523 bottomGraphics
.setClip(0,0,bounds
.width
,bounds
.height
);
524 bottomGraphics
.translate(-bounds
.x
,-bounds
.y
);
525 myLayeredPane
.paint(bottomGraphics
);
527 bottomGraphics
.dispose();
530 final Surface surface
=new Surface(topImage
,bottomImage
,1,myInfo
.getAnchor(),uiSettings
.ANIMATION_SPEED
);
531 myLayeredPane
.add(surface
,JLayeredPane
.PALETTE_LAYER
);
532 surface
.setBounds(bounds
);
533 myLayeredPane
.validate();
534 myLayeredPane
.repaint();
536 surface
.runMovement();
537 myLayeredPane
.remove(surface
);
538 myLayeredPane
.add(myComponent
,JLayeredPane
.PALETTE_LAYER
);
539 }else{ // not animated
540 myLayeredPane
.add(myComponent
,JLayeredPane
.PALETTE_LAYER
);
541 myLayeredPane
.setBoundsInPaletteLayer(myComponent
,myInfo
.getAnchor(),myInfo
.getWeight());
544 myLayeredPane
.validate();
545 myLayeredPane
.repaint();
553 private final class AddToolStripeButtonCmd
extends FinalizableCommand
{
554 private final StripeButton myButton
;
555 private final WindowInfoImpl myInfo
;
556 private final Comparator myComparator
;
558 public AddToolStripeButtonCmd(final StripeButton button
,final WindowInfoImpl info
,final Comparator comparator
,final Runnable finishCallBack
){
559 super(finishCallBack
);
562 myComparator
=comparator
;
565 public final void run(){
567 final ToolWindowAnchor anchor
=myInfo
.getAnchor();
568 if(ToolWindowAnchor
.TOP
==anchor
){
569 myTopStripe
.addButton(myButton
,myComparator
);
570 }else if(ToolWindowAnchor
.LEFT
==anchor
){
571 myLeftStripe
.addButton(myButton
,myComparator
);
572 }else if(ToolWindowAnchor
.BOTTOM
==anchor
){
573 myBottomStripe
.addButton(myButton
,myComparator
);
574 }else if(ToolWindowAnchor
.RIGHT
==anchor
){
575 myRightStripe
.addButton(myButton
,myComparator
);
577 LOG
.error("unknown anchor: "+anchor
);
587 private final class RemoveToolStripeButtonCmd
extends FinalizableCommand
{
588 private final StripeButton myButton
;
589 private final WindowInfoImpl myInfo
;
591 public RemoveToolStripeButtonCmd(final StripeButton button
,final WindowInfoImpl info
,final Runnable finishCallBack
){
592 super(finishCallBack
);
597 public final void run(){
599 final ToolWindowAnchor anchor
=myInfo
.getAnchor();
600 if(ToolWindowAnchor
.TOP
==anchor
){
601 myTopStripe
.removeButton(myButton
);
602 }else if(ToolWindowAnchor
.LEFT
==anchor
){
603 myLeftStripe
.removeButton(myButton
);
604 }else if(ToolWindowAnchor
.BOTTOM
==anchor
){
605 myBottomStripe
.removeButton(myButton
);
606 }else if(ToolWindowAnchor
.RIGHT
==anchor
){
607 myRightStripe
.removeButton(myButton
);
609 LOG
.error("unknown anchor: "+anchor
);
619 private final class RemoveDockedComponentCmd
extends FinalizableCommand
{
620 private final WindowInfoImpl myInfo
;
621 private final boolean myDirtyMode
;
623 public RemoveDockedComponentCmd(final WindowInfoImpl info
, final boolean dirtyMode
, final Runnable finishCallBack
){
624 super(finishCallBack
);
626 myDirtyMode
=dirtyMode
;
629 public final void run(){
631 setComponent(null,myInfo
.getAnchor(), 0);
633 myLayeredPane
.validate();
634 myLayeredPane
.repaint();
642 private final class RemoveSplitAndDockedComponentCmd
extends FinalizableCommand
{
643 private final WindowInfoImpl myInfo
;
644 private final WindowInfoImpl mySideInfo
;
645 private final boolean myDirtyMode
;
647 private RemoveSplitAndDockedComponentCmd(final WindowInfoImpl info
, final WindowInfoImpl sideInfo
, boolean dirtyMode
, final Runnable finishCallBack
) {
648 super(finishCallBack
);
650 mySideInfo
= sideInfo
;
651 myDirtyMode
= dirtyMode
;
656 Splitter splitter
= (Splitter
) getComponentAt(myInfo
.getAnchor());
658 if (myInfo
.isSplit()) {
659 InternalDecorator component
= (InternalDecorator
)splitter
.getFirstComponent();
660 setComponent(component
, myInfo
.getAnchor(), component
.getWindowInfo().getWeight());
663 InternalDecorator component
= (InternalDecorator
) splitter
.getSecondComponent();
664 setComponent(component
, myInfo
.getAnchor(), component
.getWindowInfo().getWeight());
667 myLayeredPane
.validate();
668 myLayeredPane
.repaint();
677 private final class RemoveSlidingComponentCmd
extends FinalizableCommand
{
678 private final Component myComponent
;
679 private final WindowInfoImpl myInfo
;
680 private final boolean myDirtyMode
;
682 public RemoveSlidingComponentCmd(
683 final Component component
,
684 final WindowInfoImpl info
,
685 final boolean dirtyMode
,
686 final Runnable finishCallBack
688 super(finishCallBack
);
689 myComponent
=component
;
691 myDirtyMode
=dirtyMode
;
694 public final void run(){
696 final UISettings uiSettings
=UISettings
.getInstance();
697 if(!myDirtyMode
&& uiSettings
.ANIMATE_WINDOWS
&& !UISettings
.isRemoteDesktopConnected()){
698 final Rectangle bounds
=myComponent
.getBounds();
699 // Prepare top image. This image is scrolling over bottom image. It contains
700 // picture of component is being removed.
701 final Image topImage
=myLayeredPane
.getTopImage();
702 final Graphics topGraphics
=topImage
.getGraphics();
704 myComponent
.paint(topGraphics
);
706 topGraphics
.dispose();
708 // Prepare bottom image. This image contains picture of component that is located
709 // under the component to is being removed.
710 final Image bottomImage
=myLayeredPane
.getBottomImage();
711 final Graphics bottomGraphics
= bottomImage
.getGraphics();
713 myLayeredPane
.remove(myComponent
);
714 bottomGraphics
.clipRect(0,0,bounds
.width
,bounds
.height
);
715 bottomGraphics
.translate(-bounds
.x
,-bounds
.y
);
716 myLayeredPane
.paint(bottomGraphics
);
718 bottomGraphics
.dispose();
720 // Remove component from the layered pane and start animation.
721 final Surface surface
=new Surface(topImage
,bottomImage
,-1,myInfo
.getAnchor(),uiSettings
.ANIMATION_SPEED
* 2);
722 myLayeredPane
.add(surface
,JLayeredPane
.PALETTE_LAYER
);
723 surface
.setBounds(bounds
);
724 myLayeredPane
.validate();
725 myLayeredPane
.repaint();
727 surface
.runMovement();
728 myLayeredPane
.remove(surface
);
729 }else{ // not animated
730 myLayeredPane
.remove(myComponent
);
733 myLayeredPane
.validate();
734 myLayeredPane
.repaint();
742 private final class SetEditorComponentCmd
extends FinalizableCommand
{
743 private final JComponent myComponent
;
745 public SetEditorComponentCmd(final JComponent component
,final Runnable finishCallBack
){
746 super(finishCallBack
);
747 myComponent
=component
;
752 setDocumentComponent(myComponent
);
753 myLayeredPane
.validate();
754 myLayeredPane
.repaint();
761 private final class UpdateButtonPositionCmd
extends FinalizableCommand
{
762 private final String myId
;
764 private UpdateButtonPositionCmd(String id
, final Runnable finishCallBack
) {
765 super(finishCallBack
);
772 WindowInfoImpl info
= getButtonById(myId
).getWindowInfo();
773 ToolWindowAnchor anchor
= info
.getAnchor();
775 if (ToolWindowAnchor
.TOP
== anchor
){
776 myTopStripe
.revalidate();
778 else if (ToolWindowAnchor
.LEFT
== anchor
){
779 myLeftStripe
.revalidate();
781 else if (ToolWindowAnchor
.BOTTOM
== anchor
) {
782 myBottomStripe
.revalidate();
784 else if (ToolWindowAnchor
.RIGHT
== anchor
) {
785 myRightStripe
.revalidate();
788 LOG
.error("unknown anchor: " + anchor
);
796 private final class MyUISettingsListenerImpl
implements UISettingsListener
{
797 public final void uiSettingsChanged(final UISettings source
){
798 updateToolStripesVisibility();
802 private final class MyLayeredPane
extends JLayeredPane
{
804 * These images are used to perform animated showing and hiding of components.
805 * They are the member for performance reason.
807 private SoftReference myBottomImageRef
;
808 private SoftReference myTopImageRef
;
810 public MyLayeredPane(final JComponent splitter
) {
811 myBottomImageRef
=new SoftReference(null);
812 myTopImageRef
=new SoftReference(null);
814 setBackground(Color
.gray
);
815 add(splitter
,JLayeredPane
.DEFAULT_LAYER
);
816 splitter
.setBounds(0,0,getWidth(),getHeight());
817 enableEvents(ComponentEvent
.COMPONENT_EVENT_MASK
);
821 * TODO[vova] extract method
822 * Lazily creates and returns bottom image for animation.
824 public final Image
getBottomImage(){
825 LOG
.assertTrue(UISettings
.getInstance().ANIMATE_WINDOWS
);
826 BufferedImage image
=(BufferedImage
)myBottomImageRef
.get();
829 image
.getWidth(null) < getWidth() || image
.getHeight(null) < getHeight()
831 final int width
=Math
.max(Math
.max(1,getWidth()),myFrame
.getWidth());
832 final int height
=Math
.max(Math
.max(1,getHeight()),myFrame
.getHeight());
833 if(SystemInfo
.isWindows
|| SystemInfo
.isMac
){
834 image
=myFrame
.getGraphicsConfiguration().createCompatibleImage(width
,height
);
836 // Under Linux we have found that images created by createCompatibleImage(),
837 // createVolatileImage(), etc extremely slow for rendering. TrueColor buffered image
839 image
=new BufferedImage(width
,height
,BufferedImage
.TYPE_INT_RGB
);
841 myBottomImageRef
=new SoftReference(image
);
847 * TODO[vova] extract method
848 * Lazily creates and returns top image for animation.
850 public final Image
getTopImage(){
851 LOG
.assertTrue(UISettings
.getInstance().ANIMATE_WINDOWS
);
852 BufferedImage image
=(BufferedImage
)myTopImageRef
.get();
855 image
.getWidth(null) < getWidth() || image
.getHeight(null) < getHeight()
857 final int width
=Math
.max(Math
.max(1,getWidth()),myFrame
.getWidth());
858 final int height
=Math
.max(Math
.max(1,getHeight()),myFrame
.getHeight());
859 if(SystemInfo
.isWindows
|| SystemInfo
.isMac
){
860 image
=myFrame
.getGraphicsConfiguration().createCompatibleImage(width
,height
);
862 // Under Linux we have found that images created by createCompatibleImage(),
863 // createVolatileImage(), etc extremely slow for rendering. TrueColor buffered image
865 image
=new BufferedImage(width
,height
,BufferedImage
.TYPE_INT_RGB
);
867 myTopImageRef
=new SoftReference(image
);
873 * When component size becomes larger then bottom and top images should be enlarged.
875 protected final void processComponentEvent(final ComponentEvent e
) {
876 if(ComponentEvent
.COMPONENT_RESIZED
==e
.getID()){
877 final int width
=getWidth();
878 final int height
=getHeight();
879 if(width
<0||height
<0){
882 // Resize component at the DEFAULT layer. It should be only on component in that layer
883 Component
[] components
=getComponentsInLayer(JLayeredPane
.DEFAULT_LAYER
.intValue());
884 LOG
.assertTrue(components
.length
<=1);
885 for(int i
=0;i
<components
.length
;i
++){
886 final Component component
=components
[i
];
887 component
.setBounds(0,0,getWidth(),getHeight());
889 // Resize components at the PALETTE layer
890 components
=getComponentsInLayer(JLayeredPane
.PALETTE_LAYER
.intValue());
891 for(int i
=0;i
<components
.length
;i
++){
892 final Component component
=components
[i
];
893 if (!(component
instanceof InternalDecorator
)) {
896 final WindowInfoImpl info
=myDecorator2Info
.get(component
);
897 // In normal situation info is not null. But sometimes Swing sends resize
898 // event to removed component. See SCR #19566.
904 if(ToolWindowAnchor
.TOP
==info
.getAnchor()||ToolWindowAnchor
.BOTTOM
==info
.getAnchor()){
905 weight
=(float)component
.getHeight()/(float)getHeight();
907 weight
=(float)component
.getWidth()/(float)getWidth();
909 setBoundsInPaletteLayer(component
,info
.getAnchor(),weight
);
914 super.processComponentEvent(e
);
918 public final void setBoundsInPaletteLayer(final Component component
,final ToolWindowAnchor anchor
,float weight
){
920 weight
= WindowInfoImpl
.DEFAULT_WEIGHT
;
921 }else if(weight
>1.0f
){
924 if(ToolWindowAnchor
.TOP
==anchor
){
925 component
.setBounds(0,0,getWidth(),(int)(getHeight()*weight
+.5f
));
926 }else if(ToolWindowAnchor
.LEFT
==anchor
){
927 component
.setBounds(0,0,(int)(getWidth()*weight
+.5f
),getHeight());
928 }else if(ToolWindowAnchor
.BOTTOM
==anchor
){
929 final int height
=(int)(getHeight()*weight
+.5f
);
930 component
.setBounds(0,getHeight()-height
,getWidth(),height
);
931 }else if(ToolWindowAnchor
.RIGHT
==anchor
){
932 final int width
=(int)(getWidth()*weight
+.5f
);
933 component
.setBounds(getWidth()-width
,0,width
,getHeight());
935 LOG
.error("unknown anchor "+anchor
);
941 static int getHorizontalInsetX() {