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
;
49 import java
.util
.ArrayList
;
50 import java
.util
.List
;
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() {
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() {
69 Runnable runnable
= new Runnable() {
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();
85 PaletteListPopupStep step
= new PaletteListPopupStep(editor
, myLastMorphComponent
, processor
,
86 UIDesignerBundle
.message("morph.component.title"));
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) {
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
);
115 //noinspection unchecked
116 newProp
.setValue(newComponent
, oldValue
);
118 catch (Exception e
) {
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
);
133 String binding
= BindingProperty
.suggestBindingFromText(newComponent
, text
);
134 if (binding
!= null) {
135 new BindingProperty(newComponent
.getProject()).setValueEx(newComponent
, binding
);
138 newComponent
.setDefaultBinding(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();
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
) {
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())) {
169 icp
.setValue((RadComponent
)component
, newComponent
.getId());
171 catch (Exception e
) {
183 protected void update(@NotNull GuiEditor editor
, final ArrayList
<RadComponent
> selection
, final AnActionEvent e
) {
184 if (selection
.size() == 0) {
185 e
.getPresentation().setEnabled(false);
188 for(RadComponent c
: selection
) {
189 if (!(c
instanceof RadAtomicComponent
)) {
190 e
.getPresentation().setEnabled(false);