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
;
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
;
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
) {
67 public boolean isCopyEnabled(final DataContext dataContext
) {
68 return FormEditingUtil
.getSelectedComponents(myEditor
).size() > 0 && !myEditor
.getInplaceEditingLayer().isEditing();
71 public boolean isCopyVisible(DataContext dataContext
) {
75 public void performCopy(final DataContext dataContext
) {
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
);
84 final Clipboard clipboard
= Toolkit
.getDefaultToolkit().getSystemClipboard();
85 clipboard
.setContents(transferable
, EmptyClipboardOwner
.INSTANCE
);
87 } catch (Exception e
) {
88 if (LOG
.isDebugEnabled()) {
95 public boolean isCutEnabled(final DataContext dataContext
) {
96 return isCopyEnabled(dataContext
) && FormEditingUtil
.canDeleteSelection(myEditor
);
99 public boolean isCutVisible(DataContext dataContext
) {
103 public void performCut(final DataContext dataContext
) {
104 if (doCopy() && myEditor
.ensureEditable()) {
105 CommandProcessor
.getInstance().executeCommand(myEditor
.getProject(), new Runnable() {
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) {
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
);
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
)) {
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());
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
)) {
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
));
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) {
192 c
.setId(FormEditingUtil
.generateId(editor
.getRootContainer()));
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
) {
210 private String
getSerializedComponents() {
212 final Clipboard clipboard
= Toolkit
.getDefaultToolkit().getSystemClipboard();
213 if (!clipboard
.isDataFlavorAvailable(ourDataFlavor
)) {
216 final Transferable content
= clipboard
.getContents(this);
217 final Object transferData
;
219 transferData
= content
.getTransferData(ourDataFlavor
);
220 } catch (UnsupportedFlavorException e
) {
222 } catch (IOException e
) {
226 if (!(transferData
instanceof SerializedComponentData
)) {
229 final SerializedComponentData dataProxy
= (SerializedComponentData
) transferData
;
230 return dataProxy
.getSerializedComponents();
231 } catch (Exception e
) {
236 private static final DataFlavor ourDataFlavor
;
239 ourDataFlavor
= new DataFlavor(DataFlavor
.javaJVMLocalObjectMimeType
+ ";class=com.intellij.uiDesigner.SerializedComponentData");
241 catch (ClassNotFoundException e
) {
242 throw new RuntimeException(e
);
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
) {
258 if (component
.getParent() != null) {
259 shift
= SwingUtilities
.convertPoint(
260 component
.getParent().getDelegee(),
263 editor
.getRootContainer().getDelegee()
267 shift
= new Point(0, 0);
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
);
288 return writer
.getText();