update copyright
[fedora-idea.git] / plugins / ui-designer / src / com / intellij / uiDesigner / actions / SurroundAction.java
blobc8f5a2177b615b5902868a4e282dea179ca48870
1 /*
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;
34 import javax.swing.*;
35 import java.awt.*;
36 import java.util.ArrayList;
37 import java.util.List;
39 /**
40 * @author yole
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()) {
57 return;
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);
64 assert cItem != null;
65 CommandProcessor.getInstance().executeCommand(
66 editor.getProject(),
67 new Runnable() {
68 public void run() {
69 RadContainer newContainer = (RadContainer) InsertComponentProcessor.createInsertedComponent(editor, cItem);
70 if (newContainer == null) {
71 return;
74 if (cItem == palette.getPanelItem()) {
75 if (selectionParent.getLayoutManager().isGrid()) {
76 try {
77 newContainer.setLayoutManager(LayoutManagerRegistry.createLayoutManager(selectionParent.getLayoutManager().getName()));
79 catch (Exception e1) {
80 LOG.error(e1);
81 return;
84 else {
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);
120 else {
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;
136 else {
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);
152 else {
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);
164 else {
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);
175 }, null, null);
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;
193 return true;
196 private static boolean isSelectionContiguous(RadContainer selectionParent,
197 ArrayList<RadComponent> selection) {
198 if (!selectionParent.getLayoutManager().isGrid()) {
199 return false;
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)) {
206 return false;
209 return true;
212 private static boolean constraintsIntersect(boolean horizontal,
213 GridConstraints constraints,
214 Rectangle rc) {
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;