update copyright
[fedora-idea.git] / plugins / ui-designer / src / com / intellij / uiDesigner / CutCopyPasteSupport.java
blob3ab7787d2e6314833f73b5d51ec9c7cffc45e021
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.
16 package com.intellij.uiDesigner;
18 import com.intellij.ide.CopyProvider;
19 import com.intellij.ide.CutProvider;
20 import com.intellij.ide.PasteProvider;
21 import com.intellij.openapi.actionSystem.DataContext;
22 import com.intellij.openapi.command.CommandProcessor;
23 import com.intellij.openapi.diagnostic.Logger;
24 import com.intellij.openapi.module.Module;
25 import com.intellij.uiDesigner.compiler.Utils;
26 import com.intellij.uiDesigner.designSurface.GuiEditor;
27 import com.intellij.uiDesigner.lw.LwComponent;
28 import com.intellij.uiDesigner.lw.LwContainer;
29 import com.intellij.uiDesigner.radComponents.RadComponent;
30 import com.intellij.util.ui.EmptyClipboardOwner;
31 import gnu.trove.TIntArrayList;
32 import org.jdom.Document;
33 import org.jdom.Element;
34 import org.jdom.input.SAXBuilder;
35 import org.jetbrains.annotations.NonNls;
36 import org.jetbrains.annotations.Nullable;
38 import javax.swing.*;
39 import java.awt.*;
40 import java.awt.datatransfer.Clipboard;
41 import java.awt.datatransfer.DataFlavor;
42 import java.awt.datatransfer.Transferable;
43 import java.awt.datatransfer.UnsupportedFlavorException;
44 import java.io.IOException;
45 import java.io.StringReader;
46 import java.util.ArrayList;
47 import java.util.List;
49 /**
50 * @author Anton Katilin
51 * @author Vladimir Kondratyev
53 public final class CutCopyPasteSupport implements CopyProvider, CutProvider, PasteProvider{
54 private static final Logger LOG = Logger.getInstance("#com.intellij.uiDesigner.CutCopyPasteSupport");
55 private static final SAXBuilder SAX_BUILDER = new SAXBuilder();
57 private final GuiEditor myEditor;
58 @NonNls private static final String ELEMENT_SERIALIZED = "serialized";
59 @NonNls private static final String ATTRIBUTE_X = "x";
60 @NonNls private static final String ATTRIBUTE_Y = "y";
61 @NonNls private static final String ATTRIBUTE_PARENT_LAYOUT = "parent-layout";
63 public CutCopyPasteSupport(final GuiEditor uiEditor) {
64 myEditor = uiEditor;
67 public boolean isCopyEnabled(final DataContext dataContext) {
68 return FormEditingUtil.getSelectedComponents(myEditor).size() > 0 && !myEditor.getInplaceEditingLayer().isEditing();
71 public boolean isCopyVisible(DataContext dataContext) {
72 return true;
75 public void performCopy(final DataContext dataContext) {
76 doCopy();
79 private boolean doCopy() {
80 final ArrayList<RadComponent> selectedComponents = FormEditingUtil.getSelectedComponents(myEditor);
81 final SerializedComponentData data = new SerializedComponentData(serializeForCopy(myEditor, selectedComponents));
82 final SimpleTransferable transferable = new SimpleTransferable<SerializedComponentData>(data, SerializedComponentData.class, ourDataFlavor);
83 try {
84 final Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
85 clipboard.setContents(transferable, EmptyClipboardOwner.INSTANCE);
86 return true;
87 } catch (Exception e) {
88 if (LOG.isDebugEnabled()) {
89 LOG.debug(e);
91 return false;
95 public boolean isCutEnabled(final DataContext dataContext) {
96 return isCopyEnabled(dataContext) && FormEditingUtil.canDeleteSelection(myEditor);
99 public boolean isCutVisible(DataContext dataContext) {
100 return true;
103 public void performCut(final DataContext dataContext) {
104 if (doCopy() && myEditor.ensureEditable()) {
105 CommandProcessor.getInstance().executeCommand(myEditor.getProject(), new Runnable() {
106 public void run() {
107 FormEditingUtil.deleteSelection(myEditor);
109 }, UIDesignerBundle.message("command.cut"), null);
113 public boolean isPastePossible(final DataContext dataContext) {
114 return isPasteEnabled(dataContext);
117 public boolean isPasteEnabled(final DataContext dataContext) {
118 return getSerializedComponents() != null && !myEditor.getInplaceEditingLayer().isEditing();
121 public void performPaste(final DataContext dataContext) {
122 final String serializedComponents = getSerializedComponents();
123 if (serializedComponents == null) {
124 return;
127 final ArrayList<RadComponent> componentsToPaste = new ArrayList<RadComponent>();
128 final TIntArrayList xs = new TIntArrayList();
129 final TIntArrayList ys = new TIntArrayList();
130 loadComponentsToPaste(myEditor, serializedComponents, xs, ys, componentsToPaste);
132 myEditor.getMainProcessor().startPasteProcessor(componentsToPaste, xs, ys);
135 @Nullable
136 private static ArrayList<RadComponent> deserializeComponents(final GuiEditor editor, final String serializedComponents) {
137 ArrayList<RadComponent> components = new ArrayList<RadComponent>();
138 TIntArrayList xs = new TIntArrayList();
139 TIntArrayList ys = new TIntArrayList();
140 if (!loadComponentsToPaste(editor, serializedComponents, xs, ys, components)) {
141 return null;
143 return components;
146 private static boolean loadComponentsToPaste(final GuiEditor editor, final String serializedComponents,
147 final TIntArrayList xs,
148 final TIntArrayList ys,
149 final ArrayList<RadComponent> componentsToPaste) {
150 final PsiPropertiesProvider provider = new PsiPropertiesProvider(editor.getModule());
152 try {
153 //noinspection HardCodedStringLiteral
154 final Document document = SAX_BUILDER.build(new StringReader(serializedComponents), "UTF-8");
156 final Element rootElement = document.getRootElement();
157 if (!rootElement.getName().equals(ELEMENT_SERIALIZED)) {
158 return false;
161 final List children = rootElement.getChildren();
162 for (final Object aChildren : children) {
163 final Element e = (Element)aChildren;
165 // we need to add component to a container in order to read them
166 final LwContainer container = new LwContainer(JPanel.class.getName());
168 final String parentLayout = e.getAttributeValue(ATTRIBUTE_PARENT_LAYOUT);
169 if (parentLayout != null) {
170 container.setLayoutManager(parentLayout);
173 final int x = Integer.parseInt(e.getAttributeValue(ATTRIBUTE_X));
174 final int y = Integer.parseInt(e.getAttributeValue(ATTRIBUTE_Y));
176 xs.add(x);
177 ys.add(y);
179 final Element componentElement = (Element)e.getChildren().get(0);
180 final LwComponent lwComponent = LwContainer.createComponentFromTag(componentElement);
182 container.addComponent(lwComponent);
184 lwComponent.read(componentElement, provider);
186 // pasted components should have no bindings
187 FormEditingUtil.iterate(lwComponent, new FormEditingUtil.ComponentVisitor<LwComponent>() {
188 public boolean visit(final LwComponent c) {
189 if (c.getBinding() != null && FormEditingUtil.findComponentWithBinding(editor.getRootContainer(), c.getBinding()) != null) {
190 c.setBinding(null);
192 c.setId(FormEditingUtil.generateId(editor.getRootContainer()));
193 return true;
197 final Module module = editor.getModule();
198 final ClassLoader loader = LoaderFactory.getInstance(module.getProject()).getLoader(editor.getFile());
199 final RadComponent radComponent = XmlReader.createComponent(module, lwComponent, loader, editor.getStringDescriptorLocale());
200 componentsToPaste.add(radComponent);
203 catch (Exception e) {
204 return false;
206 return true;
209 @Nullable
210 private String getSerializedComponents() {
211 try {
212 final Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
213 if (!clipboard.isDataFlavorAvailable(ourDataFlavor)) {
214 return null;
216 final Transferable content = clipboard.getContents(this);
217 final Object transferData;
218 try {
219 transferData = content.getTransferData(ourDataFlavor);
220 } catch (UnsupportedFlavorException e) {
221 return null;
222 } catch (IOException e) {
223 return null;
226 if (!(transferData instanceof SerializedComponentData)) {
227 return null;
229 final SerializedComponentData dataProxy = (SerializedComponentData) transferData;
230 return dataProxy.getSerializedComponents();
231 } catch (Exception e) {
232 return null;
236 private static final DataFlavor ourDataFlavor;
237 static {
238 try {
239 ourDataFlavor = new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType + ";class=com.intellij.uiDesigner.SerializedComponentData");
241 catch (ClassNotFoundException e) {
242 throw new RuntimeException(e);
246 @Nullable
247 public static List<RadComponent> copyComponents(GuiEditor editor, List<RadComponent> components) {
248 return deserializeComponents(editor, serializeForCopy(editor, components));
251 private static String serializeForCopy(final GuiEditor editor, final List<RadComponent> components) {
252 final XmlWriter writer = new XmlWriter();
254 writer.startElement(ELEMENT_SERIALIZED, Utils.FORM_NAMESPACE);
256 for (final RadComponent component : components) {
257 final Point shift;
258 if (component.getParent() != null) {
259 shift = SwingUtilities.convertPoint(
260 component.getParent().getDelegee(),
261 component.getX(),
262 component.getY(),
263 editor.getRootContainer().getDelegee()
266 else {
267 shift = new Point(0, 0);
270 component.getX();
272 writer.startElement("item");
273 writer.addAttribute(ATTRIBUTE_X, shift.x);
274 writer.addAttribute(ATTRIBUTE_Y, shift.y);
275 if (component.getParent() != null) {
276 final String parentLayout = component.getParent().getLayoutManager().getName();
277 if (parentLayout != null) {
278 writer.addAttribute(ATTRIBUTE_PARENT_LAYOUT, parentLayout);
281 component.write(writer);
283 writer.endElement();
286 writer.endElement();
288 return writer.getText();