update copyright
[fedora-idea.git] / plugins / ui-designer / src / com / intellij / uiDesigner / actions / MorphAction.java
blob317e907a207aa5f02f7eae29a1d04db04fc3ec8b
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.openapi.ui.popup.JBPopupFactory;
23 import com.intellij.openapi.ui.popup.ListPopup;
24 import com.intellij.psi.JavaPsiFacade;
25 import com.intellij.psi.PsiElementFactory;
26 import com.intellij.psi.PsiField;
27 import com.intellij.psi.PsiType;
28 import com.intellij.uiDesigner.FormEditingUtil;
29 import com.intellij.uiDesigner.UIDesignerBundle;
30 import com.intellij.uiDesigner.designSurface.GuiEditor;
31 import com.intellij.uiDesigner.designSurface.InsertComponentProcessor;
32 import com.intellij.uiDesigner.inspections.FormInspectionUtil;
33 import com.intellij.uiDesigner.lw.IComponent;
34 import com.intellij.uiDesigner.lw.IProperty;
35 import com.intellij.uiDesigner.palette.ComponentItem;
36 import com.intellij.uiDesigner.palette.Palette;
37 import com.intellij.uiDesigner.propertyInspector.IntrospectedProperty;
38 import com.intellij.uiDesigner.propertyInspector.properties.BindingProperty;
39 import com.intellij.uiDesigner.propertyInspector.properties.IntroComponentProperty;
40 import com.intellij.uiDesigner.quickFixes.ChangeFieldTypeFix;
41 import com.intellij.uiDesigner.radComponents.RadAtomicComponent;
42 import com.intellij.uiDesigner.radComponents.RadComponent;
43 import com.intellij.uiDesigner.radComponents.RadContainer;
44 import com.intellij.util.IncorrectOperationException;
45 import com.intellij.util.Processor;
46 import org.jetbrains.annotations.NotNull;
48 import javax.swing.*;
49 import java.util.ArrayList;
50 import java.util.List;
52 /**
53 * @author yole
55 public class MorphAction extends AbstractGuiEditorAction {
56 private static final Logger LOG = Logger.getInstance("#com.intellij.uiDesigner.actions.MorphAction");
58 private final ComponentItem myLastMorphComponent = null;
60 public MorphAction() {
61 super(true);
64 protected void actionPerformed(final GuiEditor editor, final List<RadComponent> selection, final AnActionEvent e) {
65 Processor<ComponentItem> processor = new Processor<ComponentItem>() {
66 public boolean process(final ComponentItem selectedValue) {
67 SwingUtilities.invokeLater(new Runnable() {
68 public void run() {
69 Runnable runnable = new Runnable() {
70 public void run() {
71 for(RadComponent c: selection) {
72 if (!morphComponent(editor, c, selectedValue)) break;
74 editor.refreshAndSave(true);
77 CommandProcessor.getInstance().executeCommand(editor.getProject(), runnable, UIDesignerBundle.message("morph.component.command"), null);
78 editor.getGlassLayer().requestFocus();
80 });
81 return true;
85 PaletteListPopupStep step = new PaletteListPopupStep(editor, myLastMorphComponent, processor,
86 UIDesignerBundle.message("morph.component.title"));
87 step.hideNonAtomic();
88 if (selection.size() == 1) {
89 step.hideComponentClass(selection.get(0).getComponentClassName());
91 final ListPopup listPopup = JBPopupFactory.getInstance().createListPopup(step);
92 FormEditingUtil.showPopupUnderComponent(listPopup, selection.get(0));
95 private static boolean morphComponent(final GuiEditor editor, final RadComponent oldComponent, ComponentItem targetItem) {
96 targetItem = InsertComponentProcessor.replaceAnyComponentItem(editor, targetItem);
97 if (targetItem == null) {
98 return false;
100 final RadComponent newComponent = InsertComponentProcessor.createInsertedComponent(editor, targetItem);
101 if (newComponent == null) return false;
102 newComponent.setBinding(oldComponent.getBinding());
103 newComponent.setCustomLayoutConstraints(oldComponent.getCustomLayoutConstraints());
104 newComponent.getConstraints().restore(oldComponent.getConstraints());
106 updateBoundFieldType(editor, oldComponent, targetItem);
108 final IProperty[] oldProperties = oldComponent.getModifiedProperties();
109 final Palette palette = Palette.getInstance(editor.getProject());
110 for(IProperty prop: oldProperties) {
111 IntrospectedProperty newProp = palette.getIntrospectedProperty(newComponent, prop.getName());
112 if (newProp == null || !prop.getClass().equals(newProp.getClass())) continue;
113 Object oldValue = prop.getPropertyValue(oldComponent);
114 try {
115 //noinspection unchecked
116 newProp.setValue(newComponent, oldValue);
118 catch (Exception e) {
119 // ignore
123 retargetComponentProperties(editor, oldComponent, newComponent);
124 final RadContainer parent = oldComponent.getParent();
125 int index = parent.indexOfComponent(oldComponent);
126 parent.removeComponent(oldComponent);
127 parent.addComponent(newComponent, index);
128 newComponent.setSelected(true);
130 if (oldComponent.isDefaultBinding()) {
131 final String text = FormInspectionUtil.getText(newComponent.getModule(), newComponent);
132 if (text != null) {
133 String binding = BindingProperty.suggestBindingFromText(newComponent, text);
134 if (binding != null) {
135 new BindingProperty(newComponent.getProject()).setValueEx(newComponent, binding);
138 newComponent.setDefaultBinding(true);
140 return true;
143 private static void updateBoundFieldType(final GuiEditor editor, final RadComponent oldComponent, final ComponentItem targetItem) {
144 PsiField oldBoundField = BindingProperty.findBoundField(editor.getRootContainer(), oldComponent.getBinding());
145 if (oldBoundField != null) {
146 final PsiElementFactory factory = JavaPsiFacade.getInstance(editor.getProject()).getElementFactory();
147 try {
148 PsiType componentType = factory.createTypeFromText(targetItem.getClassName().replace('$', '.'), null);
149 if (!oldBoundField.getType().isAssignableFrom(componentType)) {
150 new ChangeFieldTypeFix(editor, oldBoundField, componentType).run();
153 catch (IncorrectOperationException e) {
154 LOG.error(e);
159 private static void retargetComponentProperties(final GuiEditor editor, final RadComponent c, final RadComponent newComponent) {
160 FormEditingUtil.iterate(editor.getRootContainer(), new FormEditingUtil.ComponentVisitor() {
161 public boolean visit(final IComponent component) {
162 RadComponent rc = (RadComponent) component;
163 for(IProperty p: component.getModifiedProperties()) {
164 if (p instanceof IntroComponentProperty) {
165 IntroComponentProperty icp = (IntroComponentProperty) p;
166 final String value = icp.getValue(rc);
167 if (value.equals(c.getId())) {
168 try {
169 icp.setValue((RadComponent)component, newComponent.getId());
171 catch (Exception e) {
172 // ignore
177 return true;
182 @Override
183 protected void update(@NotNull GuiEditor editor, final ArrayList<RadComponent> selection, final AnActionEvent e) {
184 if (selection.size() == 0) {
185 e.getPresentation().setEnabled(false);
186 return;
188 for(RadComponent c: selection) {
189 if (!(c instanceof RadAtomicComponent)) {
190 e.getPresentation().setEnabled(false);
191 return;