1 package com
.intellij
.uiDesigner
.radComponents
;
3 import com
.intellij
.openapi
.diagnostic
.Logger
;
4 import com
.intellij
.openapi
.module
.Module
;
5 import com
.intellij
.openapi
.util
.Comparing
;
6 import com
.intellij
.uiDesigner
.GuiDesignerConfiguration
;
7 import com
.intellij
.uiDesigner
.ReferenceUtil
;
8 import com
.intellij
.uiDesigner
.UIFormXmlConstants
;
9 import com
.intellij
.uiDesigner
.XmlWriter
;
10 import com
.intellij
.uiDesigner
.snapShooter
.SnapshotContext
;
11 import com
.intellij
.uiDesigner
.palette
.Palette
;
12 import com
.intellij
.uiDesigner
.core
.AbstractLayout
;
13 import com
.intellij
.uiDesigner
.core
.GridConstraints
;
14 import com
.intellij
.uiDesigner
.core
.GridLayoutManager
;
15 import com
.intellij
.uiDesigner
.designSurface
.ComponentDragObject
;
16 import com
.intellij
.uiDesigner
.designSurface
.DropLocation
;
17 import com
.intellij
.uiDesigner
.lw
.*;
18 import com
.intellij
.uiDesigner
.propertyInspector
.Property
;
19 import com
.intellij
.uiDesigner
.propertyInspector
.PropertyEditor
;
20 import com
.intellij
.uiDesigner
.propertyInspector
.PropertyRenderer
;
21 import com
.intellij
.uiDesigner
.propertyInspector
.editors
.string
.StringEditor
;
22 import com
.intellij
.uiDesigner
.shared
.BorderType
;
23 import com
.intellij
.uiDesigner
.shared
.XYLayoutManager
;
24 import org
.jetbrains
.annotations
.NonNls
;
25 import org
.jetbrains
.annotations
.NotNull
;
26 import org
.jetbrains
.annotations
.Nullable
;
29 import javax
.swing
.border
.Border
;
30 import javax
.swing
.border
.TitledBorder
;
31 import javax
.swing
.border
.EtchedBorder
;
32 import javax
.swing
.border
.BevelBorder
;
34 import java
.util
.ArrayList
;
37 * @author Anton Katilin
38 * @author Vladimir Kondratyev
40 public class RadContainer
extends RadComponent
implements IContainer
{
41 private static final Logger LOG
= Logger
.getInstance("#com.intellij.uiDesigner.radComponents.RadContainer");
44 * value: RadComponent[]
47 public static final String PROP_CHILDREN
= "children";
51 private final ArrayList
<RadComponent
> myComponents
;
53 * Describes border's type.
55 @NotNull private BorderType myBorderType
;
57 * Border's title. If border doesn't have any title then
58 * this member is <code>null</code>.
60 @Nullable private StringDescriptor myBorderTitle
;
61 private int myBorderTitleJustification
;
62 private int myBorderTitlePosition
;
63 private FontDescriptor myBorderTitleFont
;
64 private ColorDescriptor myBorderTitleColor
;
66 protected RadLayoutManager myLayoutManager
;
68 public RadContainer(final Module module
, final String id
){
69 this(module
, JPanel
.class, id
);
72 public RadContainer(final Module module
, final Class aClass
, final String id
){
73 super(module
, aClass
, id
);
75 myComponents
= new ArrayList
<RadComponent
>();
77 // By default container doesn't have any special border
78 setBorderType(BorderType
.NONE
);
80 myLayoutManager
= createInitialLayoutManager();
81 if (myLayoutManager
!= null) {
82 final LayoutManager layoutManager
= myLayoutManager
.createLayout();
83 if (layoutManager
!= null) {
84 setLayout(layoutManager
);
89 public RadContainer(@NotNull final Class aClass
, @NotNull final String id
, final Palette palette
) {
90 this(null, aClass
, id
);
94 @Nullable protected RadLayoutManager
createInitialLayoutManager() {
95 String defaultLayoutManager
= UIFormXmlConstants
.LAYOUT_INTELLIJ
;
96 if (getModule() != null) {
97 final GuiDesignerConfiguration configuration
= GuiDesignerConfiguration
.getInstance(getModule().getProject());
98 if (configuration
.IRIDA_LAYOUT_MODE
) {
99 return new RadXYLayoutManager();
101 defaultLayoutManager
= configuration
.DEFAULT_LAYOUT_MANAGER
;
105 return RadLayoutManager
.createLayoutManager(defaultLayoutManager
);
107 catch (Exception e
) {
109 return new RadGridLayoutManager();
113 public Property
getInplaceProperty(final int x
, final int y
) {
114 // 1. We have to check whether user clicked inside border (if any) or not.
115 // In this case we have return inplace editor for border text
116 final Insets insets
= getDelegee().getInsets(); // border insets
118 x
< insets
.left
|| x
> getWidth() - insets
.right
||
119 y
< 0 || y
> insets
.top
121 return super.getInplaceProperty(x
, y
);
124 // 2. Now we are sure that user clicked inside title area
125 return new MyBorderTitleProperty();
129 public Property
getDefaultInplaceProperty() {
130 return new MyBorderTitleProperty();
134 public Rectangle
getDefaultInplaceEditorBounds() {
135 return getBorderInPlaceEditorBounds(new MyBorderTitleProperty());
138 public Rectangle
getInplaceEditorBounds(final Property property
, final int x
, final int y
) {
139 if(property
instanceof MyBorderTitleProperty
){ // If this is our property
140 return getBorderInPlaceEditorBounds(property
);
142 return super.getInplaceEditorBounds(property
, x
, y
);
145 private Rectangle
getBorderInPlaceEditorBounds(final Property property
) {
146 final MyBorderTitleProperty _property
= (MyBorderTitleProperty
)property
;
147 final Insets insets
= getDelegee().getInsets();
148 return new Rectangle(
151 getWidth() - insets
.left
- insets
.right
,
152 _property
.getPreferredSize().height
156 public final LayoutManager
getLayout(){
157 return getDelegee().getLayout();
160 public final void setLayout(final LayoutManager layout
) {
161 getDelegee().setLayout(layout
);
163 if (layout
instanceof AbstractLayout
) {
164 AbstractLayout aLayout
= (AbstractLayout
) layout
;
165 for (int i
=0; i
< getComponentCount(); i
++) {
166 final RadComponent c
= getComponent(i
);
167 aLayout
.addLayoutComponent(c
.getDelegee(), c
.getConstraints());
172 public final boolean isGrid(){
173 return getLayout() instanceof GridLayoutManager
;
176 public final boolean isXY(){
177 return getLayout() instanceof XYLayoutManager
;
181 * @param component component to be added.
183 * @exception java.lang.IllegalArgumentException if <code>component</code> is <code>null</code>
184 * @exception java.lang.IllegalArgumentException if <code>component</code> already exist in the
187 public final void addComponent(@NotNull final RadComponent component
, int index
) {
188 if (myComponents
.contains(component
)) {
189 //noinspection HardCodedStringLiteral
190 throw new IllegalArgumentException("component is already added: " + component
);
193 final RadComponent
[] oldChildren
= myComponents
.toArray(new RadComponent
[myComponents
.size()]);
195 // Remove from old parent
196 final RadContainer oldParent
=component
.getParent();
197 if(oldParent
!=null) {
198 oldParent
.removeComponent(component
);
201 // Attach to new parent
202 myComponents
.add(index
, component
);
203 component
.setParent(this);
204 myLayoutManager
.addComponentToContainer(this, component
, index
);
206 final RadComponent
[] newChildren
= myComponents
.toArray(new RadComponent
[myComponents
.size()]);
207 firePropertyChanged(PROP_CHILDREN
, oldChildren
, newChildren
);
210 public final void addComponent(@NotNull final RadComponent component
) {
211 addComponent(component
, myComponents
.size());
215 * Removes specified <code>component</code> from the container.
216 * This method also removes component's delegee from the
217 * container's delegee. Client code is responsible for revalidation
218 * of invalid Swing hierarchy.
220 * @param component component to be removed.
222 * @exception java.lang.IllegalArgumentException if <code>component</code>
223 * is <code>null</code>
224 * @exception java.lang.IllegalArgumentException if <code>component</code>
225 * doesn't exist in the container
227 public final void removeComponent(@NotNull final RadComponent component
){
228 if(!myComponents
.contains(component
)){
229 //noinspection HardCodedStringLiteral
230 throw new IllegalArgumentException("component is not added: " + component
);
233 final RadComponent
[] oldChildren
= myComponents
.toArray(new RadComponent
[myComponents
.size()]);
236 component
.setParent(null);
237 myComponents
.remove(component
);
238 myLayoutManager
.removeComponentFromContainer(this, component
);
240 final RadComponent
[] newChildren
= myComponents
.toArray(new RadComponent
[myComponents
.size()]);
241 firePropertyChanged(PROP_CHILDREN
, oldChildren
, newChildren
);
244 public final RadComponent
getComponent(final int index
) {
245 return myComponents
.get(index
);
248 public final int getComponentCount() {
249 return myComponents
.size();
252 public int indexOfComponent(RadComponent component
) {
253 return myComponents
.indexOf(component
);
257 * @return new array with all children
259 public final RadComponent
[] getComponents() {
260 return myComponents
.toArray(new RadComponent
[myComponents
.size()]);
264 public DropLocation
getDropLocation(@Nullable Point location
) {
265 return getLayoutManager().getDropLocation(this, location
);
268 public RadComponent
findComponentInRect(final int startRow
, final int startCol
, final int rowSpan
, final int colSpan
) {
269 for(int r
=startRow
; r
< startRow
+ rowSpan
; r
++) {
270 for(int c
=startCol
; c
< startCol
+ colSpan
; c
++) {
271 final RadComponent result
= getComponentAtGrid(r
, c
);
272 if (result
!= null) {
281 public RadComponent
getComponentAtGrid(boolean rowFirst
, int coord1
, int coord2
) {
282 return rowFirst ?
getComponentAtGrid(coord1
, coord2
) : getComponentAtGrid(coord2
, coord1
);
286 public RadComponent
getComponentAtGrid(final int row
, final int column
) {
287 // If the target cell is not empty does not allow drop.
288 for(int i
=0; i
<getComponentCount(); i
++){
289 final RadComponent component
= getComponent(i
);
290 if (component
.isDragging()) {
293 final GridConstraints constraints
=component
.getConstraints();
295 constraints
.getRow() <= row
&& row
< constraints
.getRow()+constraints
.getRowSpan() &&
296 constraints
.getColumn() <= column
&& column
< constraints
.getColumn()+constraints
.getColSpan()
304 public final void dropIntoGrid(final RadComponent
[] components
, int row
, int column
, final ComponentDragObject dragObject
) {
305 final GridLayoutManager gridLayout
= (GridLayoutManager
)getLayout();
306 assert components
.length
> 0;
308 for(int i
=0; i
<components
.length
; i
++) {
309 RadComponent c
= components
[i
];
310 if (c
instanceof RadContainer
) {
311 final LayoutManager layout
= ((RadContainer
)c
).getLayout();
312 if (layout
instanceof XYLayoutManager
) {
313 ((XYLayoutManager
)layout
).setPreferredSize(c
.getSize());
317 int relativeCol
= dragObject
.getRelativeCol(i
);
318 int relativeRow
= dragObject
.getRelativeRow(i
);
319 LOG
.debug("dropIntoGrid: relativeRow=" + relativeRow
+ ", relativeCol=" + relativeCol
);
320 int colSpan
= dragObject
.getColSpan(i
);
321 int rowSpan
= dragObject
.getRowSpan(i
);
323 assert row
+ relativeRow
>= 0;
324 assert column
+ relativeCol
>= 0;
325 assert relativeRow
+ rowSpan
<= gridLayout
.getRowCount();
326 assert relativeCol
+ colSpan
<= gridLayout
.getColumnCount();
328 RadComponent old
= findComponentInRect(row
+ relativeRow
, column
+ relativeCol
, rowSpan
, colSpan
);
330 LOG
.assertTrue(false,
331 "Drop rectangle not empty: (" + (row
+ relativeRow
) + ", " + (column
+ relativeCol
)
332 + ", " + rowSpan
+ ", " + colSpan
+ "), component ID=" + old
.getId());
335 final GridConstraints constraints
= c
.getConstraints();
336 constraints
.setRow(row
+ relativeRow
);
337 constraints
.setColumn(column
+ relativeCol
);
338 constraints
.setRowSpan(rowSpan
);
339 constraints
.setColSpan(colSpan
);
350 * @return border's type.
352 * @see com.intellij.uiDesigner.shared.BorderType
355 public final BorderType
getBorderType(){
360 * @see com.intellij.uiDesigner.shared.BorderType
362 * @exception java.lang.IllegalArgumentException if <code>type</code>
363 * is <code>null</code>
365 public final void setBorderType(@NotNull final BorderType type
){
366 if(myBorderType
==type
){
374 * @return border's title. If the container doesn't have any title then the
375 * method returns <code>null</code>.
378 public final StringDescriptor
getBorderTitle(){
379 return myBorderTitle
;
383 * @param title new border's title. <code>null</code> means that
384 * the containr doesn't have have titled border.
386 public final void setBorderTitle(final StringDescriptor title
){
387 if(Comparing
.equal(title
,myBorderTitle
)){
390 myBorderTitle
= title
;
394 public int getBorderTitleJustification() {
395 return myBorderTitleJustification
;
398 public void setBorderTitleJustification(final int borderTitleJustification
) {
399 if (myBorderTitleJustification
!= borderTitleJustification
) {
400 myBorderTitleJustification
= borderTitleJustification
;
405 public int getBorderTitlePosition() {
406 return myBorderTitlePosition
;
409 public void setBorderTitlePosition(final int borderTitlePosition
) {
410 if (myBorderTitlePosition
!= borderTitlePosition
) {
411 myBorderTitlePosition
= borderTitlePosition
;
416 public FontDescriptor
getBorderTitleFont() {
417 return myBorderTitleFont
;
420 public void setBorderTitleFont(final FontDescriptor borderTitleFont
) {
421 if (!Comparing
.equal(myBorderTitleFont
, borderTitleFont
)) {
422 myBorderTitleFont
= borderTitleFont
;
427 public ColorDescriptor
getBorderTitleColor() {
428 return myBorderTitleColor
;
431 public void setBorderTitleColor(final ColorDescriptor borderTitleColor
) {
432 if (!Comparing
.equal(myBorderTitleColor
, borderTitleColor
)) {
433 myBorderTitleColor
= borderTitleColor
;
439 * Updates delegee's border
441 public void updateBorder() {
443 if (myBorderTitle
!= null) {
444 title
= ReferenceUtil
.resolve(this, myBorderTitle
);
446 Font font
= (myBorderTitleFont
!= null) ? myBorderTitleFont
.getResolvedFont() : null;
447 Color color
= (myBorderTitleColor
!= null) ? myBorderTitleColor
.getResolvedColor() : null;
448 getDelegee().setBorder(myBorderType
.createBorder(title
, myBorderTitleJustification
, myBorderTitlePosition
,
452 public RadLayoutManager
getLayoutManager() {
453 RadContainer parent
= this;
454 while(parent
!= null) {
455 if (parent
.myLayoutManager
!= null) {
456 return parent
.myLayoutManager
;
458 parent
= parent
.getParent();
463 public void setLayoutManager(final RadLayoutManager layoutManager
) {
464 myLayoutManager
= layoutManager
;
465 setLayout(myLayoutManager
.createLayout());
468 public void setLayoutManager(RadLayoutManager layoutManager
, LayoutManager layout
) {
469 myLayoutManager
= layoutManager
;
473 public RadComponent
getComponentToResize(RadComponent child
) {
478 * Serializes container's border
480 protected final void writeBorder(final XmlWriter writer
){
481 writer
.startElement(UIFormXmlConstants
.ELEMENT_BORDER
);
483 writer
.addAttribute(UIFormXmlConstants
.ATTRIBUTE_TYPE
, getBorderType().getId());
484 if (getBorderTitle() != null) {
485 final StringDescriptor descriptor
= getBorderTitle();
486 writer
.writeStringDescriptor(descriptor
, UIFormXmlConstants
.ATTRIBUTE_TITLE
,
487 UIFormXmlConstants
.ATTRIBUTE_TITLE_RESOURCE_BUNDLE
,
488 UIFormXmlConstants
.ATTRIBUTE_TITLE_KEY
);
490 if (myBorderTitleJustification
!= 0) {
491 writer
.addAttribute(UIFormXmlConstants
.ATTRIBUTE_TITLE_JUSTIFICATION
, myBorderTitleJustification
);
493 if (myBorderTitlePosition
!= 0) {
494 writer
.addAttribute(UIFormXmlConstants
.ATTRIBUTE_TITLE_POSITION
, myBorderTitlePosition
);
496 if (myBorderTitleFont
!= null) {
497 writer
.startElement(UIFormXmlConstants
.ELEMENT_FONT
);
498 writer
.writeFontDescriptor(myBorderTitleFont
);
501 if (myBorderTitleColor
!= null) {
502 writer
.startElement(UIFormXmlConstants
.ELEMENT_COLOR
);
503 writer
.writeColorDescriptor(myBorderTitleColor
);
507 writer
.endElement(); // border
512 * Serializes container's children
514 protected final void writeChildren(final XmlWriter writer
){
516 writer
.startElement("children");
518 writeChildrenImpl(writer
);
520 writer
.endElement(); // children
524 protected final void writeChildrenImpl(final XmlWriter writer
){
525 for (int i
=0; i
< getComponentCount(); i
++) {
526 getComponent(i
).write(writer
);
530 public void write(final XmlWriter writer
) {
532 writer
.startElement("xy");
535 writer
.startElement("grid");
539 writeBinding(writer
);
541 if (myLayoutManager
!= null) {
542 writer
.addAttribute("layout-manager", myLayoutManager
.getName());
545 getLayoutManager().writeLayout(writer
, this);
547 // Constraints and properties
548 writeConstraints(writer
);
549 writeProperties(writer
);
555 writeChildren(writer
);
557 writer
.endElement(); // xy/grid
561 public boolean accept(ComponentVisitor visitor
) {
562 if (!super.accept(visitor
)) {
566 for (int i
= 0; i
< getComponentCount(); i
++) {
567 final IComponent c
= getComponent(i
);
568 if (!c
.accept(visitor
)) {
576 protected void writeNoLayout(final XmlWriter writer
) {
578 writeBinding(writer
);
580 // Constraints and properties
581 writeConstraints(writer
);
582 writeProperties(writer
);
586 writeChildren(writer
);
590 protected void importSnapshotComponent(final SnapshotContext context
, final JComponent component
) {
591 getLayoutManager().createSnapshotLayout(context
, component
, this, component
.getLayout());
592 importSnapshotBorder(component
);
593 for(Component child
: component
.getComponents()) {
594 if (child
instanceof JComponent
) {
595 RadComponent childComponent
= createSnapshotComponent(context
, (JComponent
) child
);
596 if (childComponent
!= null) {
597 getLayoutManager().addSnapshotComponent(component
, (JComponent
) child
, this, childComponent
);
603 private void importSnapshotBorder(final JComponent component
) {
604 Border border
= component
.getBorder();
605 if (border
!= null) {
606 if (border
instanceof TitledBorder
) {
607 TitledBorder titledBorder
= (TitledBorder
) border
;
608 setBorderTitle(StringDescriptor
.create(titledBorder
.getTitle()));
609 setBorderTitleJustification(titledBorder
.getTitleJustification());
610 setBorderTitlePosition(titledBorder
.getTitlePosition());
611 setBorderTitleFont(new FontDescriptor(titledBorder
.getTitleFont()));
612 setBorderTitleColor(new ColorDescriptor(titledBorder
.getTitleColor()));
613 border
= titledBorder
.getBorder();
616 if (border
instanceof EtchedBorder
) {
617 setBorderType(BorderType
.ETCHED
);
619 else if (border
instanceof BevelBorder
) {
620 BevelBorder bevelBorder
= (BevelBorder
) border
;
621 setBorderType(bevelBorder
.getBevelType() == BevelBorder
.RAISED ? BorderType
.BEVEL_RAISED
: BorderType
.BEVEL_LOWERED
);
626 private final class MyBorderTitleProperty
extends Property
<RadContainer
, StringDescriptor
> {
627 private final StringEditor myEditor
;
629 public MyBorderTitleProperty() {
630 super(null, "Title");
631 myEditor
= new StringEditor(getModule().getProject());
634 public Dimension
getPreferredSize(){
635 return myEditor
.getPreferredSize();
638 public StringDescriptor
getValue(final RadContainer component
) {
639 return myBorderTitle
;
642 protected void setValueImpl(final RadContainer container
, final StringDescriptor value
) throws Exception
{
643 setBorderTitle(value
);
647 public PropertyRenderer
<StringDescriptor
> getRenderer() {
651 public PropertyEditor
<StringDescriptor
> getEditor() {