update copyright
[fedora-idea.git] / plugins / ui-designer / src / com / intellij / uiDesigner / actions / DuplicateComponentsAction.java
blob94d310612cbd1042a00eebbd27bb202f2f1a9516
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.diagnostic.Logger;
21 import com.intellij.uiDesigner.CutCopyPasteSupport;
22 import com.intellij.uiDesigner.FormEditingUtil;
23 import com.intellij.uiDesigner.UIDesignerBundle;
24 import com.intellij.uiDesigner.core.GridConstraints;
25 import com.intellij.uiDesigner.designSurface.GuiEditor;
26 import com.intellij.uiDesigner.lw.IProperty;
27 import com.intellij.uiDesigner.propertyInspector.properties.BindingProperty;
28 import com.intellij.uiDesigner.propertyInspector.properties.IntroComponentProperty;
29 import com.intellij.uiDesigner.radComponents.RadComponent;
30 import com.intellij.uiDesigner.radComponents.RadContainer;
31 import gnu.trove.TIntHashSet;
32 import org.jetbrains.annotations.NotNull;
33 import org.jetbrains.annotations.Nullable;
35 import java.util.*;
37 /**
38 * @author yole
40 public class DuplicateComponentsAction extends AbstractGuiEditorAction {
41 private static final Logger LOG = Logger.getInstance("#com.intellij.uiDesigner.actions.DuplicateComponentsAction");
43 public DuplicateComponentsAction() {
44 super(true);
47 protected void actionPerformed(final GuiEditor editor, final List<RadComponent> selection, final AnActionEvent e) {
48 FormEditingUtil.remapToActionTargets(selection);
49 RadContainer parent = FormEditingUtil.getSelectionParent(selection);
50 assert parent != null;
51 List<RadComponent> duplicates = new ArrayList<RadComponent>();
52 Map<RadComponent, RadComponent> duplicateMap = new HashMap<RadComponent, RadComponent>();
53 TIntHashSet insertedRows = new TIntHashSet();
54 boolean incrementRow = true;
55 if (selection.size() > 1 && canDuplicate(selection, false) && FormEditingUtil.getSelectionBounds(selection).width == 1) {
56 incrementRow = false;
58 for(RadComponent c: selection) {
59 final int row = c.getConstraints().getCell(incrementRow);
60 int rowSpan = c.getConstraints().getSpan(incrementRow);
61 int insertIndex = parent.indexOfComponent(c);
62 if (parent.getLayoutManager().isGrid()) {
63 if (!insertedRows.contains(row) && !isSpaceBelowEmpty(c, incrementRow)) {
64 insertedRows.add(row);
65 parent.getGridLayoutManager().copyGridCells(parent, parent, incrementRow, row, rowSpan, row + rowSpan);
69 List<RadComponent> copyList = CutCopyPasteSupport.copyComponents(editor, Collections.singletonList(c));
70 if (copyList != null) {
71 RadComponent copy = copyList.get(0);
72 if (parent.getLayoutManager().isGrid()) {
73 copy.getConstraints().setCell(incrementRow, row + rowSpan + parent.getGridLayoutManager().getGapCellCount());
74 copy.getConstraints().setSpan(incrementRow, rowSpan);
76 parent.addComponent(copy, insertIndex+1);
77 fillDuplicateMap(duplicateMap, c, copy);
78 duplicates.add(copy);
81 adjustDuplicates(duplicateMap);
82 FormEditingUtil.selectComponents(editor, duplicates);
85 private static void fillDuplicateMap(Map<RadComponent, RadComponent> duplicates, final RadComponent c, final RadComponent copy) {
86 duplicates.put(c, copy);
87 if (c instanceof RadContainer) {
88 LOG.assertTrue(copy instanceof RadContainer);
89 final RadContainer container = (RadContainer)c;
90 final RadContainer containerCopy = (RadContainer)copy;
91 for(int i=0; i<container.getComponentCount(); i++) {
92 fillDuplicateMap(duplicates, container.getComponent(i), containerCopy.getComponent(i));
97 private static void adjustDuplicates(final Map<RadComponent, RadComponent> duplicates) {
98 for(RadComponent c: duplicates.keySet()) {
99 RadComponent copy = duplicates.get(c);
100 if (c.getBinding() != null) {
101 String binding = BindingProperty.getDefaultBinding(copy);
102 new BindingProperty(c.getProject()).setValueEx(copy, binding);
103 copy.setDefaultBinding(true);
105 for(IProperty prop: copy.getModifiedProperties()) {
106 if (prop instanceof IntroComponentProperty) {
107 final IntroComponentProperty componentProperty = (IntroComponentProperty)prop;
108 String copyValue = componentProperty.getValue(copy);
109 for(RadComponent original: duplicates.keySet()) {
110 if (original.getId().equals(copyValue)) {
111 componentProperty.setValueEx(copy, duplicates.get(original).getId());
119 private static boolean isSpaceBelowEmpty(final RadComponent component, boolean incrementRow) {
120 final GridConstraints constraints = component.getConstraints();
121 int startRow = constraints.getCell(incrementRow) + constraints.getSpan(incrementRow);
122 int endRow = constraints.getCell(incrementRow) + constraints.getSpan(incrementRow)*2 +
123 component.getParent().getGridLayoutManager().getGapCellCount();
124 if (endRow > component.getParent().getGridCellCount(incrementRow)) {
125 return false;
127 for(int row=startRow; row < endRow; row++) {
128 for(int col=constraints.getCell(!incrementRow); col < constraints.getCell(!incrementRow) + constraints.getSpan(!incrementRow); col++) {
129 if (component.getParent().getComponentAtGrid(incrementRow, row, col) != null) {
130 return false;
134 return true;
137 protected void update(@NotNull GuiEditor editor, final ArrayList<RadComponent> selection, final AnActionEvent e) {
138 FormEditingUtil.remapToActionTargets(selection);
139 final RadContainer parent = FormEditingUtil.getSelectionParent(selection);
140 e.getPresentation().setEnabled(parent != null && (parent.getLayoutManager().isGrid() || parent.getLayoutManager().isIndexed()));
141 // The action is enabled in any of the following cases:
142 // 1) a single component is selected;
143 // 2) all selected components have rowspan=1
144 // 3) all selected components have the same row and rowspan
145 if (selection.size() > 1 && parent != null && parent.getLayoutManager().isGrid()) {
146 e.getPresentation().setEnabled(canDuplicate(selection, true) || canDuplicate(selection, false));
150 private static boolean canDuplicate(final List<RadComponent> selection, final boolean incrementRow) {
151 int aRow = selection.get(0).getConstraints().getCell(incrementRow);
152 int aRowSpan = selection.get(0).getConstraints().getSpan(incrementRow);
153 for(int i=1; i<selection.size(); i++) {
154 final RadComponent c = selection.get(i);
155 if (c.getConstraints().getSpan(incrementRow) > 1 || aRowSpan > 1) {
156 if (c.getConstraints().getCell(incrementRow) != aRow || c.getConstraints().getSpan(incrementRow) != aRowSpan) {
157 return false;
161 return true;
164 @Override @Nullable
165 protected String getCommandName() {
166 return UIDesignerBundle.message("command.duplicate");