/*
* Freeplane - mind map editor
* Copyright (C) 2008 Joerg Mueller, Daniel Polansky, Christian Foltin, Dimitry Polivaev
*
* This file is created by Dimitry Polivaev in 2008.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.freeplane.features.clipboard.mindmapmode;
import java.awt.Graphics2D;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.DnDConstants;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.imageio.ImageIO;
import javax.swing.JFileChooser;
import javax.swing.text.BadLocationException;
import javax.swing.text.Element;
import javax.swing.text.ElementIterator;
import javax.swing.text.html.HTMLDocument;
import javax.swing.text.html.HTMLEditorKit;
import org.apache.commons.lang.StringUtils;
import org.freeplane.core.resources.ResourceController;
import org.freeplane.core.ui.ExampleFileFilter;
import org.freeplane.core.ui.components.UITools;
import org.freeplane.core.util.FileUtils;
import org.freeplane.core.util.FixedHTMLWriter;
import org.freeplane.core.util.HtmlUtils;
import org.freeplane.core.util.LogUtils;
import org.freeplane.core.util.TextUtils;
import org.freeplane.features.attribute.AttributeController;
import org.freeplane.features.clipboard.ClipboardController;
import org.freeplane.features.clipboard.MindMapNodesSelection;
import org.freeplane.features.link.LinkController;
import org.freeplane.features.link.NodeLinks;
import org.freeplane.features.link.mindmapmode.MLinkController;
import org.freeplane.features.map.FreeNode;
import org.freeplane.features.map.IMapSelection;
import org.freeplane.features.map.MapModel;
import org.freeplane.features.map.MapReader;
import org.freeplane.features.map.MapReader.NodeTreeCreator;
import org.freeplane.features.map.MapWriter.Hint;
import org.freeplane.features.map.MapWriter.Mode;
import org.freeplane.features.map.NodeModel;
import org.freeplane.features.map.mindmapmode.MMapController;
import org.freeplane.features.mode.Controller;
import org.freeplane.features.mode.ModeController;
import org.freeplane.features.text.TextController;
import org.freeplane.features.text.mindmapmode.MTextController;
import org.freeplane.features.url.UrlManager;
import org.freeplane.n3.nanoxml.XMLException;
import org.freeplane.view.swing.features.filepreview.ExternalResource;
import org.freeplane.view.swing.features.filepreview.ViewerController;
import org.freeplane.view.swing.features.filepreview.ViewerController.PasteMode;
/**
* @author Dimitry Polivaev
*/
public class MClipboardController extends ClipboardController {
public static final String RESOURCES_REMIND_USE_RICH_TEXT_IN_NEW_NODES = "remind_use_rich_text_in_new_nodes";
private class DirectHtmlFlavorHandler implements IDataFlavorHandler {
private String textFromClipboard;
public DirectHtmlFlavorHandler(final String textFromClipboard) {
this.textFromClipboard = textFromClipboard;
}
void paste(final NodeModel target) {
textFromClipboard = cleanHtml(textFromClipboard);
final NodeModel node = Controller.getCurrentModeController().getMapController().newNode(textFromClipboard,
Controller.getCurrentController().getMap());
final String text = textFromClipboard;
final Matcher m = HREF_PATTERN.matcher(text);
if (m.matches()) {
final String body = m.group(2);
if (!body.matches(".*<\\s*a.*")) {
final String href = m.group(1);
((MLinkController) LinkController.getController()).setLinkTypeDependantLink(node, href);
}
}
((MMapController) Controller.getCurrentModeController().getMapController()).insertNode(node, target);
}
public void paste(Transferable t, final NodeModel target, final boolean asSibling, final boolean isLeft, int dropAction) {
paste(target);
}
}
private class FileListFlavorHandler implements IDataFlavorHandler {
final List<File> fileList;
public FileListFlavorHandler(final List<File> fileList) {
super();
this.fileList = fileList;
}
public void paste(Transferable t, final NodeModel target, final boolean asSibling, final boolean isLeft, int dropAction) {
boolean pasteImages = dropAction == DnDConstants.ACTION_COPY;
ViewerController viewerController = ((ViewerController)Controller.getCurrentModeController().getExtension(ViewerController.class));
for (final File file : fileList) {
if(pasteImages && viewerController.paste(file, target, PasteMode.valueOf(asSibling), isLeft)){
continue;
}
final MMapController mapController = (MMapController) Controller.getCurrentModeController().getMapController();
final NodeModel node = mapController.newNode(file.getName(), target.getMap());
((MLinkController) LinkController.getController()).setLinkTypeDependantLink(node, file);
mapController.insertNode(node, target, asSibling, isLeft, isLeft);
}
}
}
interface IDataFlavorHandler {
void paste(Transferable t, NodeModel target, boolean asSibling, boolean isLeft, int dropAction);
}
private class MindMapNodesFlavorHandler implements IDataFlavorHandler {
private final String textFromClipboard;
public MindMapNodesFlavorHandler(final String textFromClipboard) {
this.textFromClipboard = textFromClipboard;
}
public void paste(Transferable t, final NodeModel target, final boolean asSibling, final boolean isLeft, int dropAction) {
if (textFromClipboard != null) {
paste(textFromClipboard, target, asSibling, isLeft);
}
}
private void paste(final String text, final NodeModel target, final boolean asSibling, final boolean isLeft) {
final String[] textLines = text.split(ClipboardController.NODESEPARATOR);
final MMapController mapController = (MMapController) Controller.getCurrentModeController().getMapController();
final MapReader mapReader = mapController.getMapReader();
final NodeTreeCreator nodeTreeCreator = mapReader.nodeTreeCreator(target.getMap());
nodeTreeCreator.setHint(Hint.MODE, Mode.CLIPBOARD);
for (int i = 0; i < textLines.length; ++i) {
try {
final NodeModel newModel = nodeTreeCreator.create(new StringReader(textLines[i]));
newModel.removeExtension(FreeNode.class);
final boolean wasLeft = newModel.isLeft();
mapController.insertNode(newModel, target, asSibling, isLeft, wasLeft != isLeft);
}
catch (final XMLException e) {
LogUtils.severe("error on paste", e);
}
}
nodeTreeCreator.finish(target);
}
}
private static class PasteHtmlWriter extends FixedHTMLWriter {
private final Element element;
public PasteHtmlWriter(final Writer writer, final Element element, final HTMLDocument doc, final int pos,
final int len) {
super(writer, doc, pos, len);
this.element = getStandAloneElement(element);
}
@Override
protected ElementIterator getElementIterator() {
return new ElementIterator(element);
}
private Element getStandAloneElement(final Element element) {
final String name = element.getName();
if (name.equals("ul") || name.equals("ol") || name.equals("table") || name.equals("html")) {
return element;
}
return getStandAloneElement(element.getParentElement());
}
@Override
public void write() throws IOException, BadLocationException {
if (element.getName().equals("html")) {
super.write();
return;
}
write("<html>");
super.write();
write("</html>");
}
}
private class StringFlavorHandler implements IDataFlavorHandler {
private final String textFromClipboard;
public StringFlavorHandler(final String textFromClipboard) {
this.textFromClipboard = textFromClipboard;
}
public void paste(Transferable t, final NodeModel target, final boolean asSibling, final boolean isLeft, int dropAction) {
final TextFragment[] textFragments = split(textFromClipboard);
pasteStringWithoutRedisplay(textFragments, target, asSibling, isLeft);
}
private TextFragment[] split(final String textFromClipboard) {
final LinkedList<TextFragment> textFragments = new LinkedList<TextFragment>();
final String[] textLines = textFromClipboard.split("\n");
for (int i = 0; i < textLines.length; ++i) {
String text = textLines[i];
text = text.replaceAll("\t", " ");
if (text.matches(" *")) {
continue;
}
int depth = 0;
while (depth < text.length() && text.charAt(depth) == ' ') {
++depth;
}
final String visibleText = text.trim();
final String link = LinkController.findLink(text);
if (!visibleText.equals("")) {
textFragments.add(new TextFragment(visibleText, link, depth));
}
}
return textFragments.toArray(new TextFragment[textFragments.size()]);
}
}
private class StructuredHtmlFlavorHandler implements IDataFlavorHandler {
private final String textFromClipboard;
public StructuredHtmlFlavorHandler(final String textFromClipboard) {
this.textFromClipboard = textFromClipboard;
}
private String addFragment(final HTMLDocument doc, final Element element, final int depth, final int start,
final int end, final LinkedList<TextFragment> htmlFragments)
throws BadLocationException, IOException {
final String paragraphText = doc.getText(start, end - start).trim();
if (paragraphText.length() > 0) {
final StringWriter out = new StringWriter();
new PasteHtmlWriter(out, element, doc, start, end - start).write();
final String string = out.toString();
if (!string.equals("")) {
final String link = LinkController.findLink(string);
final TextFragment htmlFragment = new TextFragment(string, link, depth);
htmlFragments.add(htmlFragment);
}
}
return paragraphText;
}
private Element getParentElement(final HTMLDocument doc) {
final Element htmlRoot = doc.getDefaultRootElement();
final Element bodyElement = htmlRoot.getElement(htmlRoot.getElementCount() - 1);
Element parentCandidate = bodyElement;
do {
if (parentCandidate.getElementCount() > 1) {
return parentCandidate;
}
parentCandidate = parentCandidate.getElement(0);
} while (!(parentCandidate.isLeaf() || parentCandidate.getName().equalsIgnoreCase("p-implied")));
return bodyElement;
}
private boolean isSeparateElement(final Element current) {
return !current.isLeaf();
}
public void paste(Transferable t, final NodeModel target, final boolean asSibling, final boolean isLeft, int dropAction) {
pasteHtmlWithoutRedisplay(textFromClipboard, target, asSibling, isLeft);
}
private void pasteHtmlWithoutRedisplay(final Object t, final NodeModel parent, final boolean asSibling,
final boolean isLeft) {
String textFromClipboard = (String) t;
textFromClipboard = cleanHtml(textFromClipboard);
final TextFragment[] htmlFragments = split(textFromClipboard);
pasteStringWithoutRedisplay(htmlFragments, parent, asSibling, isLeft);
}
private void split(final HTMLDocument doc, final Element parent, final LinkedList<TextFragment> htmlFragments,
int depth) throws BadLocationException, IOException {
final int elementCount = parent.getElementCount();
int headerDepth = 0;
boolean headerFound = false;
int start = -1;
int end = -1;
Element last = null;
for (int i = 0; i < elementCount; i++) {
final Element current = parent.getElement(i);
final String name = current.getName();
final Matcher matcher = HEADER_REGEX.matcher(name);
if (matcher.matches()) {
try {
if (!headerFound) {
depth--;
}
final int newHeaderDepth = Integer.parseInt(matcher.group(1));
depth += newHeaderDepth - headerDepth;
headerDepth = newHeaderDepth;
headerFound = true;
}
catch (final NumberFormatException e) {
LogUtils.severe(e);
}
}
else {
if (headerFound) {
headerFound = false;
depth++;
}
}
final boolean separateElement = isSeparateElement(current);
if (separateElement && current.getElementCount() != 0) {
start = -1;
last = null;
split(doc, current, htmlFragments, depth + 1);
continue;
}
if (separateElement && start != -1) {
addFragment(doc, last, depth, start, end, htmlFragments);
}
if (start == -1 || separateElement) {
start = current.getStartOffset();
last = current;
}
end = current.getEndOffset();
if (separateElement) {
addFragment(doc, current, depth, start, end, htmlFragments);
}
}
if (start != -1) {
addFragment(doc, last, depth, start, end, htmlFragments);
}
}
private TextFragment[] split(final String text) {
final LinkedList<TextFragment> htmlFragments = new LinkedList<TextFragment>();
final HTMLEditorKit kit = new HTMLEditorKit();
final HTMLDocument doc = new HTMLDocument();
final StringReader buf = new StringReader(text);
try {
kit.read(buf, doc, 0);
final Element parent = getParentElement(doc);
split(doc, parent, htmlFragments, 0);
}
catch (final IOException e) {
LogUtils.severe(e);
}
catch (final BadLocationException e) {
LogUtils.severe(e);
}
return htmlFragments.toArray(new TextFragment[htmlFragments.size()]);
}
}
private static class TextFragment {
int depth;
String link;
String text;
public TextFragment(final String text, final String link, final int depth) {
super();
this.text = text;
this.depth = depth;
this.link = link;
}
}
private class ImageFlavorHandler implements IDataFlavorHandler {
private static final String IMAGE_FORMAT = "png";
final private BufferedImage image;
public ImageFlavorHandler(BufferedImage img) {
super();
BufferedImage fixedImg = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D fig = fixedImg.createGraphics();
fig.drawImage(img, 0, 0, null);
fig.dispose();
fixedImg.flush();
this.image = fixedImg;
}
public void paste(Transferable t, NodeModel target, boolean asSibling, boolean isLeft, int dropAction) {
final ModeController modeController = Controller.getCurrentModeController();
final MMapController mapController = (MMapController) modeController.getMapController();
File mindmapFile = target.getMap().getFile();
if(mindmapFile == null) {
UITools.errorMessage(TextUtils.getRawText("map_not_saved"));
return;
}
final String mmFileName = mindmapFile.getName();
String fileNameTemplate = mmFileName.substring(0, mmFileName.lastIndexOf('.')) + "_";
while (fileNameTemplate.length() < 3)
fileNameTemplate = fileNameTemplate + '_';
//file that we'll save to disk.
File file;
try {
final File dir = mindmapFile.getParentFile();
file = File.createTempFile(fileNameTemplate, "."+IMAGE_FORMAT, dir);
String imgfilepath=file.getAbsolutePath();
File tempFile = file = new File(imgfilepath);
final JFileChooser fileChooser = new JFileChooser(file);
final ExampleFileFilter filter = new ExampleFileFilter();
filter.addExtension(IMAGE_FORMAT);
fileChooser.setAcceptAllFileFilterUsed(false);
fileChooser.setFileFilter(filter);
fileChooser.setSelectedFile(file);
int returnVal = fileChooser.showSaveDialog(UITools.getFrame());
if (returnVal != JFileChooser.APPROVE_OPTION) {
tempFile.delete();
return;
}
file = fileChooser.getSelectedFile();
if(tempFile.exists() && ! file.getAbsoluteFile().equals(tempFile)){
tempFile.delete();
}
if(file.isDirectory())
return;
if(! FileUtils.getExtension(file.getName()).equals(IMAGE_FORMAT))
file = new File(file.getPath() + '.' + IMAGE_FORMAT);
final URI uri = LinkController.toLinkTypeDependantURI(mindmapFile, file);
ImageIO.write(image, IMAGE_FORMAT, file);
final NodeModel node = mapController.newNode(file.getName(), target.getMap());
final ExternalResource extension = new ExternalResource(uri);
node.addExtension(extension);
mapController.insertNode(node, target, asSibling, isLeft, isLeft);
}
catch (IOException e) {
e.printStackTrace();
}
}
}
private static final Pattern HEADER_REGEX = Pattern.compile("h(\\d)", Pattern.CASE_INSENSITIVE);
private static final Pattern HREF_PATTERN = Pattern
.compile("<html>\\s*<body>\\s*<a\\s+href=\"([^>]+)\">(.*)</a>\\s*</body>\\s*</html>");
private static final String RESOURCE_UNFOLD_ON_PASTE = "unfold_on_paste";
public static final String RESOURCES_CUT_NODES_WITHOUT_QUESTION = "cut_nodes_without_question";
public static String firstLetterCapitalized(final String text) {
if (text == null || text.length() == 0) {
return text;
}
return text.substring(0, 1).toUpperCase() + text.substring(1, text.length());
}
private List<NodeModel> newNodes;
/**
* @param modeController
*/
public MClipboardController() {
super();
createActions();
}
private String cleanHtml(String in) {
in = in.replaceFirst("(?i)(?s)<head>.*</head>", "").replaceFirst("(?i)(?s)^.*<html[^>]*>", "<html>")
.replaceFirst("(?i)(?s)<body [^>]*>", "<body>").replaceAll("(?i)(?s)<script.*?>.*?</script>", "")
.replaceAll("(?i)(?s)</?tbody.*?>", "").replaceAll("(?i)(?s)<!--.*?-->", "").replaceAll(
"(?i)(?s)</?o[^>]*>", "");
if (StringUtils.equals(ResourceController.getResourceController().getProperty(
"cut_out_pictures_when_pasting_html"), "true")) {
in = in.replaceAll("(?i)(?s)<img[^>]*>", "");
}
in = HtmlUtils.unescapeHTMLUnicodeEntity(in);
return in;
}
/**
* @param modeController
*/
private void createActions() {
final ModeController modeController = Controller.getCurrentModeController();
modeController.addAction(new CutAction());
modeController.addAction(new PasteAction());
modeController.addAction(new SelectedPasteAction());
modeController.addAction(new CloneAction());
modeController.addAction(new MoveAction());
}
@Override
public Transferable copy(IMapSelection selection) {
final List<NodeModel> collection = selection.getSortedSelection(true);
final MindMapNodesSelection transferable = copy(collection, false);
transferable.setNodeObjects(collection);
return transferable;
}
Transferable cut(final List<NodeModel> collection) {
Controller.getCurrentModeController().getMapController().sortNodesByDepth(collection);
final MindMapNodesSelection transferable = copy(collection, true);
for (final NodeModel node : collection) {
if (node.getParentNode() != null) {
((MMapController) Controller.getCurrentModeController().getMapController()).deleteNode(node);
}
}
setClipboardContents(transferable);
return transferable;
}
private IDataFlavorHandler getFlavorHandler(final Transferable t) {
if (t.isDataFlavorSupported(MindMapNodesSelection.mindMapNodesFlavor)) {
try {
final String textFromClipboard = t.getTransferData(MindMapNodesSelection.mindMapNodesFlavor).toString();
return new MindMapNodesFlavorHandler(textFromClipboard);
}
catch (final UnsupportedFlavorException e) {
}
catch (final IOException e) {
}
}
if (t.isDataFlavorSupported(MindMapNodesSelection.fileListFlavor)) {
try {
final List<File> fileList = castToFileList(t.getTransferData(MindMapNodesSelection.fileListFlavor));
if (!shouldIgnoreFileListFlavor(fileList))
return new FileListFlavorHandler(fileList);
}
catch (final UnsupportedFlavorException e) {
}
catch (final IOException e) {
}
}
final ResourceController resourceController = ResourceController.getResourceController();
if (t.isDataFlavorSupported(MindMapNodesSelection.htmlFlavor)) {
try {
final String textFromClipboard = t.getTransferData(MindMapNodesSelection.htmlFlavor).toString();
if (textFromClipboard.charAt(0) != 65533) {
if (t.isDataFlavorSupported(DataFlavor.stringFlavor)) {
final MTextController textController = (MTextController) TextController
.getController();
final boolean richText = textController.useRichTextInEditor(RESOURCES_REMIND_USE_RICH_TEXT_IN_NEW_NODES);
if (richText) {
final boolean structuredHtmlImport = resourceController
.getBooleanProperty("structured_html_import");
final IDataFlavorHandler htmlFlavorHandler;
if (structuredHtmlImport) {
htmlFlavorHandler = new StructuredHtmlFlavorHandler(textFromClipboard);
}
else {
htmlFlavorHandler = new DirectHtmlFlavorHandler(textFromClipboard);
}
return htmlFlavorHandler;
}
}
}
}
catch (final UnsupportedFlavorException e) {
}
catch (final IOException e) {
}
}
if (t.isDataFlavorSupported(DataFlavor.stringFlavor)) {
try {
final String plainTextFromClipboard = t.getTransferData(DataFlavor.stringFlavor).toString();
return new StringFlavorHandler(plainTextFromClipboard);
}
catch (final UnsupportedFlavorException e) {
}
catch (final IOException e) {
}
}
if (t.isDataFlavorSupported(DataFlavor.imageFlavor)) {
try {
BufferedImage image = (BufferedImage) t.getTransferData(DataFlavor.imageFlavor);
return new ImageFlavorHandler(image);
}
catch (final UnsupportedFlavorException e) {
}
catch (final IOException e) {
}
}
return null;
}
private boolean shouldIgnoreFileListFlavor(final List<File> fileList) {
if(fileList.isEmpty())
return true;
final File file = fileList.get(0);
if(file.isDirectory())
return false;
final String name = file.getName();
return name.endsWith(".URL") || name.endsWith(".url");
}
@SuppressWarnings("unchecked")
private List<File> castToFileList(Object transferData) {
return (List<File>) transferData;
}
Collection<IDataFlavorHandler> getFlavorHandlers() {
final Transferable t = getClipboardContents();
final Collection<IDataFlavorHandler> handlerList = new LinkedList<IDataFlavorHandler>();
if (t == null) {
return handlerList;
}
if (t.isDataFlavorSupported(MindMapNodesSelection.mindMapNodesFlavor)) {
try {
final String textFromClipboard = t.getTransferData(MindMapNodesSelection.mindMapNodesFlavor).toString();
handlerList.add(new MindMapNodesFlavorHandler(textFromClipboard));
}
catch (final UnsupportedFlavorException e) {
}
catch (final IOException e) {
}
}
if (t.isDataFlavorSupported(MindMapNodesSelection.htmlFlavor)) {
try {
final String textFromClipboard = t.getTransferData(MindMapNodesSelection.htmlFlavor).toString();
if (textFromClipboard.charAt(0) != 65533) {
if (t.isDataFlavorSupported(DataFlavor.stringFlavor)) {
handlerList.add(new StructuredHtmlFlavorHandler(textFromClipboard));
handlerList.add(new DirectHtmlFlavorHandler(textFromClipboard));
}
}
}
catch (final UnsupportedFlavorException e) {
}
catch (final IOException e) {
}
}
if (t.isDataFlavorSupported(DataFlavor.stringFlavor)) {
try {
final String plainTextFromClipboard = t.getTransferData(DataFlavor.stringFlavor).toString();
handlerList.add(new StringFlavorHandler(plainTextFromClipboard));
}
catch (final UnsupportedFlavorException e) {
}
catch (final IOException e) {
}
}
if (t.isDataFlavorSupported(MindMapNodesSelection.fileListFlavor)) {
try {
final List<File> fileList = castToFileList(t.getTransferData(MindMapNodesSelection.fileListFlavor));
handlerList.add(new FileListFlavorHandler(fileList));
}
catch (final UnsupportedFlavorException e) {
}
catch (final IOException e) {
}
}
if (t.isDataFlavorSupported(DataFlavor.imageFlavor)) {
try {
BufferedImage image = (BufferedImage) t.getTransferData(DataFlavor.imageFlavor);
handlerList.add(new ImageFlavorHandler(image));
}
catch (final UnsupportedFlavorException e) {
}
catch (final IOException e) {
}
}
return handlerList;
}
public void paste(final Transferable t, final NodeModel target, final boolean asSibling, final boolean isLeft) {
paste(t, target, asSibling, isLeft, DnDConstants.ACTION_NONE);
}
public void paste(final Transferable t, final NodeModel target, final boolean asSibling, final boolean isLeft, int dropAction) {
if (t == null) {
return;
}
/*
* DataFlavor[] fl = t.getTransferDataFlavors(); for (int i = 0; i <
* fl.length; i++) { System.out.println(fl[i]); }
*/
final IDataFlavorHandler handler = getFlavorHandler(t);
paste(t, handler, target, asSibling, isLeft, dropAction);
}
void paste(final Transferable t, final IDataFlavorHandler handler, final NodeModel target, final boolean asSibling, final boolean isLeft) {
paste(t, handler, target, asSibling, isLeft, DnDConstants.ACTION_NONE);
}
void paste(final Transferable t, final IDataFlavorHandler handler, final NodeModel target, final boolean asSibling, final boolean isLeft, int dropAction) {
if (handler == null) {
return;
}
final MMapController mapController = (MMapController) Controller.getCurrentModeController().getMapController();
if (asSibling && !mapController.isWriteable(target.getParentNode()) || !asSibling
&& !mapController.isWriteable(target)) {
final String message = TextUtils.getText("node_is_write_protected");
UITools.errorMessage(message);
return;
}
try {
Controller.getCurrentController().getViewController().setWaitingCursor(true);
if (newNodes == null) {
newNodes = new LinkedList<NodeModel>();
}
newNodes.clear();
handler.paste(t, target, asSibling, isLeft, dropAction);
final ModeController modeController = Controller.getCurrentModeController();
if (!asSibling && modeController.getMapController().isFolded(target)
&& ResourceController.getResourceController().getBooleanProperty(RESOURCE_UNFOLD_ON_PASTE)) {
modeController.getMapController().setFolded(target, false);
}
for (final NodeModel child : newNodes) {
AttributeController.getController().performRegistrySubtreeAttributes(child);
}
}
finally {
Controller.getCurrentController().getViewController().setWaitingCursor(false);
}
}
private void pasteStringWithoutRedisplay(final TextFragment[] textFragments, NodeModel parent,
final boolean asSibling, final boolean isLeft) {
final MapModel map = parent.getMap();
int insertionIndex;
if (asSibling) {
NodeModel target = parent;
parent = parent.getParentNode();
insertionIndex = parent.getChildPosition(target);
}
else{
insertionIndex = parent.getChildCount();
}
final ArrayList<NodeModel> parentNodes = new ArrayList<NodeModel>();
final ArrayList<Integer> parentNodesDepths = new ArrayList<Integer>();
parentNodes.add(parent);
parentNodesDepths.add(new Integer(-1));
final MMapController mapController = (MMapController) Controller.getCurrentModeController().getMapController();
for (int i = 0; i < textFragments.length; ++i) {
final TextFragment textFragment = textFragments[i];
String text = textFragment.text;
final String link = textFragment.link;
URI uri = null;
if (link != null) {
try {
URI linkUri = new URI(link);
uri = linkUri;
File absoluteFile = UrlManager.getController().getAbsoluteFile(map, uri);
if(absoluteFile != null) {
//if ("file".equals(linkUri.getScheme())) {
final File mapFile = map.getFile();
uri = LinkController.toLinkTypeDependantURI(mapFile, absoluteFile);
if(link.equals(text)){
text = uri.toString();
}
}
}
catch (Exception e) {
}
}
final NodeModel node = mapController.newNode(text, map);
if(uri != null){
NodeLinks.createLinkExtension(node).setHyperLink(uri);
}
for (int j = parentNodes.size() - 1; j >= 0; --j) {
if (textFragment.depth > ((Integer) parentNodesDepths.get(j)).intValue()) {
for (int k = j + 1; k < parentNodes.size(); ++k) {
final NodeModel n = (NodeModel) parentNodes.get(k);
if (n.getParentNode() == null) {
mapController.insertNode(n, parent, insertionIndex++);
}
parentNodes.remove(k);
parentNodesDepths.remove(k);
}
final NodeModel target = (NodeModel) parentNodes.get(j);
node.setLeft(isLeft);
if (target != parent) {
target.setFolded(true);
target.insert(node, target.getChildCount());
}
parentNodes.add(node);
parentNodesDepths.add(new Integer(textFragment.depth));
break;
}
}
}
{
for (int k = 0; k < parentNodes.size(); ++k) {
final NodeModel n = (NodeModel) parentNodes.get(k);
if (map.getRootNode() != n && n.getParentNode() == null) {
mapController.insertNode(n, parent, insertionIndex++);
}
}
}
}
private enum Operation{CLONE, MOVE};
public void addClone(final Transferable transferable, final NodeModel target) {
processTransferable(transferable, target, Operation.CLONE);
}
public void move(final Transferable transferable, final NodeModel target) {
processTransferable(transferable, target, Operation.MOVE);
}
private void processTransferable(final Transferable transferable, final NodeModel target, Operation operation) {
if(!transferable.isDataFlavorSupported(MindMapNodesSelection.mindMapNodeObjectsFlavor))
return;
try {
@SuppressWarnings("unchecked")
final List<NodeModel> clonedNodes = (List<NodeModel>) transferable.getTransferData(MindMapNodesSelection.mindMapNodeObjectsFlavor);
for(NodeModel clonedNode:clonedNodes){
if(clonedNode.getParentNode() == null || ! clonedNode.getMap().equals(target.getMap()))
return;
final MMapController mapController = (MMapController) Controller.getCurrentModeController().getMapController();
if (!clonedNode.isRoot() && ! clonedNode.subtreeContainsCloneOf(target)) {
switch(operation){
case CLONE:
final NodeModel clone = clonedNode.cloneTree();
mapController.addNewNode(clone, target, target.getChildCount(), target.isNewChildLeft());
break;
case MOVE:
mapController.moveNodeAsChild(clonedNode, target, target.isNewChildLeft(), target.isNewChildLeft()!=clonedNode.isLeft());
break;
}
}
}
}
catch (Exception e) {
LogUtils.severe(e);
}
}
}