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.
17 package com
.intellij
.uiDesigner
.actions
;
19 import com
.intellij
.openapi
.actionSystem
.AnActionEvent
;
20 import com
.intellij
.openapi
.command
.CommandProcessor
;
21 import com
.intellij
.openapi
.diagnostic
.Logger
;
22 import com
.intellij
.uiDesigner
.FormEditingUtil
;
23 import com
.intellij
.uiDesigner
.core
.GridConstraints
;
24 import com
.intellij
.uiDesigner
.core
.GridLayoutManager
;
25 import com
.intellij
.uiDesigner
.designSurface
.GuiEditor
;
26 import com
.intellij
.uiDesigner
.designSurface
.InsertComponentProcessor
;
27 import com
.intellij
.uiDesigner
.lw
.LwSplitPane
;
28 import com
.intellij
.uiDesigner
.palette
.ComponentItem
;
29 import com
.intellij
.uiDesigner
.palette
.Palette
;
30 import com
.intellij
.uiDesigner
.radComponents
.*;
31 import com
.intellij
.uiDesigner
.shared
.XYLayoutManager
;
32 import org
.jetbrains
.annotations
.NotNull
;
36 import java
.util
.ArrayList
;
37 import java
.util
.List
;
42 public class SurroundAction
extends AbstractGuiEditorAction
{
43 private static final Logger LOG
= Logger
.getInstance("#com.intellij.uiDesigner.actions.SurroundAction");
45 private final String myComponentClass
;
47 public SurroundAction(String componentClass
) {
48 final String className
= componentClass
.substring(componentClass
.lastIndexOf('.') + 1);
49 getTemplatePresentation().setText(className
);
50 myComponentClass
= componentClass
;
53 public void actionPerformed(final GuiEditor editor
, final List
<RadComponent
> selection
, final AnActionEvent e
) {
54 // the action is also reused as quickfix for NoScrollPaneInspection, so this code should be kept here
55 FormEditingUtil
.remapToActionTargets(selection
);
56 if (!editor
.ensureEditable()) {
59 final RadContainer selectionParent
= FormEditingUtil
.getSelectionParent(selection
);
60 assert selectionParent
!= null;
62 final Palette palette
= Palette
.getInstance(editor
.getProject());
63 final ComponentItem cItem
= palette
.getItem(myComponentClass
);
65 CommandProcessor
.getInstance().executeCommand(
69 RadContainer newContainer
= (RadContainer
) InsertComponentProcessor
.createInsertedComponent(editor
, cItem
);
70 if (newContainer
== null) {
74 if (cItem
== palette
.getPanelItem()) {
75 if (selectionParent
.getLayoutManager().isGrid()) {
77 newContainer
.setLayoutManager(LayoutManagerRegistry
.createLayoutManager(selectionParent
.getLayoutManager().getName()));
79 catch (Exception e1
) {
85 newContainer
.setLayoutManager(LayoutManagerRegistry
.createDefaultGridLayoutManager(editor
.getProject()));
89 Rectangle rc
= new Rectangle(0, 0, 1, 1);
90 int minIndex
= Integer
.MAX_VALUE
;
91 if (selectionParent
.getLayoutManager().isGrid()) {
92 rc
= FormEditingUtil
.getSelectionBounds(selection
);
94 else if (selectionParent
.getLayoutManager().isIndexed()) {
95 for(RadComponent c
: selection
) {
96 minIndex
= Math
.min(minIndex
, selectionParent
.indexOfComponent(c
));
99 for(RadComponent c
: selection
) {
100 selectionParent
.removeComponent(c
);
103 if (selectionParent
.getLayoutManager().isGrid()) {
104 final GridConstraints newConstraints
= newContainer
.getConstraints();
105 newConstraints
.setRow(rc
.y
);
106 newConstraints
.setColumn(rc
.x
);
107 newConstraints
.setRowSpan(rc
.height
);
108 newConstraints
.setColSpan(rc
.width
);
110 else if (selectionParent
.getLayout() instanceof XYLayoutManager
&& selection
.size() == 1) {
111 newContainer
.setBounds(selection
.get(0).getBounds());
114 if (selection
.size() == 1) {
115 newContainer
.setCustomLayoutConstraints(selection
.get(0).getCustomLayoutConstraints());
117 if (minIndex
!= Integer
.MAX_VALUE
) {
118 selectionParent
.addComponent(newContainer
, minIndex
);
121 selectionParent
.addComponent(newContainer
);
124 if (newContainer
instanceof RadTabbedPane
) {
125 // the first tab is created by RadTabbedPane itself
126 assert newContainer
.getComponentCount() == 1;
127 newContainer
= (RadContainer
) newContainer
.getComponent(0);
129 else if (newContainer
instanceof RadSplitPane
) {
130 if (selection
.size() > 2) {
131 RadContainer panel
= InsertComponentProcessor
.createPanelComponent(editor
);
132 panel
.setCustomLayoutConstraints(LwSplitPane
.POSITION_LEFT
);
133 newContainer
.addComponent(panel
);
134 newContainer
= panel
;
137 if (selection
.size() > 0) {
138 selection
.get(0).setCustomLayoutConstraints(LwSplitPane
.POSITION_LEFT
);
140 if (selection
.size() > 1) {
141 selection
.get(1).setCustomLayoutConstraints(LwSplitPane
.POSITION_RIGHT
);
146 // if surrounding a single control with JPanel, 1x1 grid in resulting container is sufficient
147 // otherwise, copy column properties and row/col spans
148 if (newContainer
.getComponentClass().equals(JPanel
.class) && selection
.size() > 1) {
149 if (selectionParent
.getLayoutManager().isGrid()) {
150 newContainer
.getGridLayoutManager().copyGridSection(selectionParent
, newContainer
, rc
);
153 // TODO[yole]: correctly handle surround from indexed
154 newContainer
.setLayout(new GridLayoutManager(rc
.height
, rc
.width
));
158 for(RadComponent c
: selection
) {
159 if (selectionParent
.getLayoutManager().isGrid()) {
160 if (selection
.size() > 1) {
161 c
.getConstraints().setRow(c
.getConstraints().getRow() - rc
.y
);
162 c
.getConstraints().setColumn(c
.getConstraints().getColumn() - rc
.x
);
165 c
.getConstraints().setRow(0);
166 c
.getConstraints().setColumn(0);
167 c
.getConstraints().setRowSpan(1);
168 c
.getConstraints().setColSpan(1);
171 newContainer
.addComponent(c
);
173 editor
.refreshAndSave(true);
178 protected void update(@NotNull final GuiEditor editor
, final ArrayList
<RadComponent
> selection
, final AnActionEvent e
) {
179 FormEditingUtil
.remapToActionTargets(selection
);
180 RadContainer selectionParent
= FormEditingUtil
.getSelectionParent(selection
);
181 e
.getPresentation().setEnabled(selectionParent
!= null &&
182 ((!selectionParent
.getLayoutManager().isGrid() && selection
.size() == 1) ||
183 isSelectionContiguous(selectionParent
, selection
)) &&
184 canWrapSelection(selection
));
187 private boolean canWrapSelection(final ArrayList
<RadComponent
> selection
) {
188 if (myComponentClass
.equals(JScrollPane
.class.getName())) {
189 if (selection
.size() > 1) return false;
190 RadComponent component
= selection
.get(0);
191 return component
.getDelegee() instanceof Scrollable
;
196 private static boolean isSelectionContiguous(RadContainer selectionParent
,
197 ArrayList
<RadComponent
> selection
) {
198 if (!selectionParent
.getLayoutManager().isGrid()) {
201 Rectangle rc
= FormEditingUtil
.getSelectionBounds(selection
);
202 for(RadComponent c
: selectionParent
.getComponents()) {
203 if (!selection
.contains(c
) &&
204 constraintsIntersect(true, c
.getConstraints(), rc
) &&
205 constraintsIntersect(false, c
.getConstraints(), rc
)) {
212 private static boolean constraintsIntersect(boolean horizontal
,
213 GridConstraints constraints
,
215 int start
= constraints
.getCell(!horizontal
);
216 int end
= start
+ constraints
.getSpan(!horizontal
) - 1;
217 int otherStart
= horizontal ? rc
.x
: rc
.y
;
218 int otherEnd
= otherStart
+ (horizontal ? rc
.width
: rc
.height
) - 1;
219 return start
<= otherEnd
&& otherStart
<= end
;