| /* |
| * Copyright 2000-2014 JetBrains s.r.o. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.intellij.uiDesigner; |
| |
| import com.intellij.ide.CopyProvider; |
| import com.intellij.ide.CutProvider; |
| import com.intellij.ide.PasteProvider; |
| import com.intellij.ide.dnd.FileCopyPasteUtil; |
| import com.intellij.openapi.actionSystem.DataContext; |
| import com.intellij.openapi.command.CommandProcessor; |
| import com.intellij.openapi.diagnostic.Logger; |
| import com.intellij.openapi.ide.CopyPasteManager; |
| import com.intellij.uiDesigner.compiler.Utils; |
| import com.intellij.uiDesigner.designSurface.GuiEditor; |
| import com.intellij.uiDesigner.lw.LwComponent; |
| import com.intellij.uiDesigner.lw.LwContainer; |
| import com.intellij.uiDesigner.radComponents.RadComponent; |
| import gnu.trove.TIntArrayList; |
| import org.jdom.Document; |
| import org.jdom.Element; |
| import org.jdom.input.SAXBuilder; |
| import org.jetbrains.annotations.NonNls; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| import javax.swing.*; |
| import java.awt.*; |
| import java.awt.datatransfer.DataFlavor; |
| import java.io.StringReader; |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| /** |
| * @author Anton Katilin |
| * @author Vladimir Kondratyev |
| */ |
| public final class CutCopyPasteSupport implements CopyProvider, CutProvider, PasteProvider{ |
| private static final Logger LOG = Logger.getInstance("#com.intellij.uiDesigner.CutCopyPasteSupport"); |
| private static final SAXBuilder SAX_BUILDER = new SAXBuilder(); |
| |
| private final GuiEditor myEditor; |
| @NonNls private static final String ELEMENT_SERIALIZED = "serialized"; |
| @NonNls private static final String ATTRIBUTE_X = "x"; |
| @NonNls private static final String ATTRIBUTE_Y = "y"; |
| @NonNls private static final String ATTRIBUTE_PARENT_LAYOUT = "parent-layout"; |
| |
| public CutCopyPasteSupport(final GuiEditor uiEditor) { |
| myEditor = uiEditor; |
| } |
| |
| public boolean isCopyEnabled(@NotNull final DataContext dataContext) { |
| return FormEditingUtil.getSelectedComponents(myEditor).size() > 0 && !myEditor.getInplaceEditingLayer().isEditing(); |
| } |
| |
| public boolean isCopyVisible(@NotNull DataContext dataContext) { |
| return true; |
| } |
| |
| public void performCopy(@NotNull final DataContext dataContext) { |
| doCopy(); |
| } |
| |
| private boolean doCopy() { |
| final ArrayList<RadComponent> selectedComponents = FormEditingUtil.getSelectedComponents(myEditor); |
| final SerializedComponentData data = new SerializedComponentData(serializeForCopy(myEditor, selectedComponents)); |
| final SimpleTransferable transferable = new SimpleTransferable<SerializedComponentData>(data, SerializedComponentData.class, ourDataFlavor); |
| try { |
| CopyPasteManager.getInstance().setContents(transferable); |
| return true; |
| } |
| catch (Exception e) { |
| LOG.debug(e); |
| return false; |
| } |
| } |
| |
| public boolean isCutEnabled(@NotNull final DataContext dataContext) { |
| return isCopyEnabled(dataContext) && FormEditingUtil.canDeleteSelection(myEditor); |
| } |
| |
| public boolean isCutVisible(@NotNull DataContext dataContext) { |
| return true; |
| } |
| |
| public void performCut(@NotNull final DataContext dataContext) { |
| if (doCopy() && myEditor.ensureEditable()) { |
| CommandProcessor.getInstance().executeCommand(myEditor.getProject(), new Runnable() { |
| public void run() { |
| FormEditingUtil.deleteSelection(myEditor); |
| } |
| }, UIDesignerBundle.message("command.cut"), null); |
| } |
| } |
| |
| public boolean isPastePossible(@NotNull final DataContext dataContext) { |
| return isPasteEnabled(dataContext); |
| } |
| |
| public boolean isPasteEnabled(@NotNull final DataContext dataContext) { |
| return getSerializedComponents() != null && !myEditor.getInplaceEditingLayer().isEditing(); |
| } |
| |
| public void performPaste(@NotNull final DataContext dataContext) { |
| final String serializedComponents = getSerializedComponents(); |
| if (serializedComponents == null) { |
| return; |
| } |
| |
| final ArrayList<RadComponent> componentsToPaste = new ArrayList<RadComponent>(); |
| final TIntArrayList xs = new TIntArrayList(); |
| final TIntArrayList ys = new TIntArrayList(); |
| loadComponentsToPaste(myEditor, serializedComponents, xs, ys, componentsToPaste); |
| |
| myEditor.getMainProcessor().startPasteProcessor(componentsToPaste, xs, ys); |
| } |
| |
| @Nullable |
| private static ArrayList<RadComponent> deserializeComponents(final GuiEditor editor, final String serializedComponents) { |
| ArrayList<RadComponent> components = new ArrayList<RadComponent>(); |
| TIntArrayList xs = new TIntArrayList(); |
| TIntArrayList ys = new TIntArrayList(); |
| if (!loadComponentsToPaste(editor, serializedComponents, xs, ys, components)) { |
| return null; |
| } |
| return components; |
| } |
| |
| private static boolean loadComponentsToPaste(final GuiEditor editor, final String serializedComponents, |
| final TIntArrayList xs, |
| final TIntArrayList ys, |
| final ArrayList<RadComponent> componentsToPaste) { |
| final PsiPropertiesProvider provider = new PsiPropertiesProvider(editor.getModule()); |
| |
| try { |
| //noinspection HardCodedStringLiteral |
| final Document document = SAX_BUILDER.build(new StringReader(serializedComponents), "UTF-8"); |
| |
| final Element rootElement = document.getRootElement(); |
| if (!rootElement.getName().equals(ELEMENT_SERIALIZED)) { |
| return false; |
| } |
| |
| final List children = rootElement.getChildren(); |
| for (final Object aChildren : children) { |
| final Element e = (Element)aChildren; |
| |
| // we need to add component to a container in order to read them |
| final LwContainer container = new LwContainer(JPanel.class.getName()); |
| |
| final String parentLayout = e.getAttributeValue(ATTRIBUTE_PARENT_LAYOUT); |
| if (parentLayout != null) { |
| container.setLayoutManager(parentLayout); |
| } |
| |
| final int x = Integer.parseInt(e.getAttributeValue(ATTRIBUTE_X)); |
| final int y = Integer.parseInt(e.getAttributeValue(ATTRIBUTE_Y)); |
| |
| xs.add(x); |
| ys.add(y); |
| |
| final Element componentElement = (Element)e.getChildren().get(0); |
| final LwComponent lwComponent = LwContainer.createComponentFromTag(componentElement); |
| |
| container.addComponent(lwComponent); |
| |
| lwComponent.read(componentElement, provider); |
| |
| // pasted components should have no bindings |
| FormEditingUtil.iterate(lwComponent, new FormEditingUtil.ComponentVisitor<LwComponent>() { |
| public boolean visit(final LwComponent c) { |
| if (c.getBinding() != null && FormEditingUtil.findComponentWithBinding(editor.getRootContainer(), c.getBinding()) != null) { |
| c.setBinding(null); |
| } |
| c.setId(FormEditingUtil.generateId(editor.getRootContainer())); |
| return true; |
| } |
| }); |
| |
| final ClassLoader loader = LoaderFactory.getInstance(editor.getProject()).getLoader(editor.getFile()); |
| final RadComponent radComponent = XmlReader.createComponent(editor, lwComponent, loader, editor.getStringDescriptorLocale()); |
| componentsToPaste.add(radComponent); |
| } |
| } |
| catch (Exception e) { |
| return false; |
| } |
| return true; |
| } |
| |
| @Nullable |
| private static String getSerializedComponents() { |
| try { |
| final Object transferData = CopyPasteManager.getInstance().getContents(ourDataFlavor); |
| if (!(transferData instanceof SerializedComponentData)) { |
| return null; |
| } |
| |
| final SerializedComponentData dataProxy = (SerializedComponentData)transferData; |
| return dataProxy.getSerializedComponents(); |
| } |
| catch (Exception e) { |
| return null; |
| } |
| } |
| |
| private static final DataFlavor ourDataFlavor = FileCopyPasteUtil.createJvmDataFlavor(SerializedComponentData.class); |
| |
| @Nullable |
| public static List<RadComponent> copyComponents(GuiEditor editor, List<RadComponent> components) { |
| return deserializeComponents(editor, serializeForCopy(editor, components)); |
| } |
| |
| private static String serializeForCopy(final GuiEditor editor, final List<RadComponent> components) { |
| final XmlWriter writer = new XmlWriter(); |
| |
| writer.startElement(ELEMENT_SERIALIZED, Utils.FORM_NAMESPACE); |
| |
| for (final RadComponent component : components) { |
| final Point shift; |
| if (component.getParent() != null) { |
| shift = SwingUtilities.convertPoint( |
| component.getParent().getDelegee(), |
| component.getX(), |
| component.getY(), |
| editor.getRootContainer().getDelegee() |
| ); |
| } |
| else { |
| shift = new Point(0, 0); |
| } |
| |
| component.getX(); |
| |
| writer.startElement("item"); |
| writer.addAttribute(ATTRIBUTE_X, shift.x); |
| writer.addAttribute(ATTRIBUTE_Y, shift.y); |
| if (component.getParent() != null) { |
| final String parentLayout = component.getParent().getLayoutManager().getName(); |
| if (parentLayout != null) { |
| writer.addAttribute(ATTRIBUTE_PARENT_LAYOUT, parentLayout); |
| } |
| } |
| component.write(writer); |
| |
| writer.endElement(); |
| } |
| |
| writer.endElement(); |
| |
| return writer.getText(); |
| } |
| |
| |
| } |