/* ******************************************************************************
* Copyright (c) 2006-2012 XMind Ltd. and others.
*
* This file is a part of XMind 3. XMind releases 3 and
* above are dual-licensed under the Eclipse Public License (EPL),
* which is available at http://www.eclipse.org/legal/epl-v10.html
* and the GNU Lesser General Public License (LGPL),
* which is available at http://www.gnu.org/licenses/lgpl.html
* See http://www.xmind.net/license.html for details.
*
* Contributors:
* XMind Ltd. - initial API and implementation
*******************************************************************************/
package org.xmind.ui.internal.dnd;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialogWithToggle;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.FileTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.dnd.TransferData;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.internal.DPIUtil;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.xmind.core.IFileEntry;
import org.xmind.core.ITopic;
import org.xmind.core.IWorkbook;
import org.xmind.core.util.FileUtils;
import org.xmind.core.util.HyperlinkUtils;
import org.xmind.gef.GEF;
import org.xmind.gef.IViewer;
import org.xmind.gef.Request;
import org.xmind.gef.draw2d.geometry.Geometry;
import org.xmind.gef.part.IPart;
import org.xmind.ui.internal.MindMapUIPlugin;
import org.xmind.ui.internal.dialogs.DialogMessages;
import org.xmind.ui.internal.protocols.FilePathParser;
import org.xmind.ui.mindmap.MindMapUI;
import org.xmind.ui.prefs.PrefConstants;
import org.xmind.ui.util.ImageFormat;
import org.xmind.ui.util.Logger;
@SuppressWarnings("restriction")
public class FileDndClient extends MindMapDNDClientBase {
private static final String CREATE_IMAGE = "CREATE_IMAGE"; //$NON-NLS-1$
private static final String ADD_EXTERNAL_FILE = "dndConfirm.ExternalFile"; //$NON-NLS-1$
private class FileDropHandler {
private String path;
private String active;
public FileDropHandler(String path, String action) {
this.path = path;
this.active = action;
}
public void createViewerElements(IWorkbook workbook,
ITopic targetParent, List<Object> elements) {
File file = new File(path);
if (PrefConstants.CREATE_HYPERLINK.equals(active)) {
elements.add(createFileHyperlinkTopic(workbook, file));
} else if (PrefConstants.CREATE_ATTACHMENT.equals(active)) {
elements.add(createAttachmentTopic(workbook, file, null));
} else if (CREATE_IMAGE.equals(active)) {
if (targetParent != null) {
elements.add(
createImageOnTopic(workbook, targetParent, file));
}
}
}
private ITopic createFileHyperlinkTopic(IWorkbook workbook, File file) {
ITopic topic = workbook.createTopic();
topic.setTitleText(file.getName());
topic.setHyperlink(
FilePathParser.toURI(file.getAbsolutePath(), false));
return topic;
}
private ITopic createAttachmentTopic(IWorkbook workbook, File file,
ITopic parent) {
ITopic topic = workbook.createTopic();
topic.setTitleText(file.getName());
if (file.isDirectory()) {
String[] subfiles = file.list();
for (int i = 0; i < subfiles.length; i++) {
File subfile = new File(file, subfiles[i]);
ITopic subtopic = createAttachmentTopic(workbook, subfile,
topic);
topic.add(subtopic, ITopic.ATTACHED);
}
} else {
try {
IFileEntry entry = workbook.getManifest()
.createAttachmentFromFilePath(
file.getAbsolutePath());
entry.decreaseReference();
entry.increaseReference();
if (isImagePath(file.getAbsolutePath())) {
Dimension size = getImageSize(file.getAbsolutePath());
if (size != null) {
topic.getImage().setSource(HyperlinkUtils
.toAttachmentURL(entry.getPath()));
topic.getImage().setSize(size.width, size.height);
topic.setTitleText(""); //$NON-NLS-1$
} else {
topic.setHyperlink(HyperlinkUtils
.toAttachmentURL(entry.getPath()));
}
} else {
topic.setHyperlink(HyperlinkUtils
.toAttachmentURL(entry.getPath()));
}
} catch (IOException e) {
Logger.log(e, "Error occurred when transfering file: " //$NON-NLS-1$
+ file.getAbsolutePath());
}
}
return topic;
}
private Object createImageOnTopic(IWorkbook workbook, ITopic topic,
File file) {
try {
IFileEntry entry = workbook.getManifest()
.createAttachmentFromFilePath(file.getAbsolutePath());
entry.decreaseReference();
entry.increaseReference();
Dimension size = getImageSize(file.getAbsolutePath());
if (size != null) {
return createModifyImageCommand(topic,
HyperlinkUtils.toAttachmentURL(entry.getPath()),
size.width, size.height, null);
} else {
Logger.log(
"[FileDndClient] Failed to open invalid image file: " //$NON-NLS-1$
+ file.getAbsolutePath());
}
} catch (IOException e) {
Logger.log(e, "Error occurred when transfering file: " //$NON-NLS-1$
+ file.getAbsolutePath());
}
return null;
}
}
private FileTransfer transfer = FileTransfer.getInstance();
private IPreferenceStore pref = null;
public Object getData(Transfer transfer, TransferData data) {
if (transfer == this.transfer) {
return this.transfer.nativeToJava(data);
}
return null;
}
public Transfer getTransfer() {
return transfer;
}
public Object toTransferData(Object[] viewerElements, IViewer viewer) {
return null;
}
@Override
protected Object[] toViewerElements(Object transferData, Request request,
IWorkbook workbook, ITopic targetParent, boolean dropInParent) {
if (transferData instanceof String[]) {
String[] paths = (String[]) transferData;
if (workbook != null) {
List<FileDropHandler> handlers = createFileDropHandlers(paths,
request.getIntParameter(GEF.PARAM_DROP_OPERATION,
DND.DROP_DEFAULT),
dropInParent,
request.getTargetViewer().getControl().getShell());
if (handlers != null) {
List<Object> elements = new ArrayList<Object>(
handlers.size());
for (FileDropHandler handler : handlers) {
handler.createViewerElements(workbook, targetParent,
elements);
}
return elements.toArray();
}
}
}
return null;
}
private List<FileDropHandler> createFileDropHandlers(String[] paths,
int operation, boolean dropInParent, Shell shell) {
List<FileDropHandler> handlers = new ArrayList<FileDropHandler>(
paths.length);
if (isSingleImage(paths) && dropInParent) {
createImageFileDropHandler(paths[0], operation, handlers);
} else if (isSingleFolder(paths)) {
createSingleFolderDropHandler(paths[0], operation, handlers, shell);
} else if (isSingleFile(paths)) {
createSingleFileDropHandler(paths[0], operation, handlers, shell);
} else {
createMultipleFilesDropHandler(paths, operation, handlers, shell);
}
return handlers;
}
private void createImageFileDropHandler(String imagePath, int operation,
List<FileDropHandler> handlers) {
if (operation == DND.DROP_LINK) {
createFileDropHandlers(handlers, PrefConstants.CREATE_HYPERLINK,
imagePath);
} else {
createFileDropHandlers(handlers, CREATE_IMAGE, imagePath);
}
}
private void createSingleFolderDropHandler(String path, int operation,
List<FileDropHandler> handlers, Shell shell) {
if (operation == DND.DROP_LINK) {
createFileDropHandlers(handlers, PrefConstants.CREATE_HYPERLINK,
path);
} else if (operation == DND.DROP_COPY) {
createFileDropHandlers(handlers, PrefConstants.CREATE_ATTACHMENT,
path);
} else {
askForConfirmation(shell, DialogMessages.DND_ExternalFolder,
ADD_EXTERNAL_FILE,
NLS.bind(
DialogMessages.DND_ExternalFolder_confirmation_with_path,
path),
handlers, path);
}
}
private void createSingleFileDropHandler(String path, int operation,
List<FileDropHandler> handlers, Shell shell) {
if (operation == DND.DROP_LINK) {
createFileDropHandlers(handlers, PrefConstants.CREATE_HYPERLINK,
path);
} else if (operation == DND.DROP_COPY) {
createFileDropHandlers(handlers, PrefConstants.CREATE_ATTACHMENT,
path);
} else {
askForConfirmation(shell, DialogMessages.DND_ExternalFile,
ADD_EXTERNAL_FILE,
NLS.bind(
DialogMessages.DND_ExternalFile_confirmation_with_path_size,
path,
org.xmind.ui.viewers.FileUtils.fileLengthToString(
new File(path).length())),
handlers, path);
}
}
private void createMultipleFilesDropHandler(String[] paths, int operation,
List<FileDropHandler> handlers, Shell shell) {
if (operation == DND.DROP_LINK) {
createFileDropHandlers(handlers, PrefConstants.CREATE_HYPERLINK,
paths);
} else if (operation == DND.DROP_COPY) {
createFileDropHandlers(handlers, PrefConstants.CREATE_ATTACHMENT,
paths);
} else {
StringBuffer sb = new StringBuffer(paths.length * 30);
for (int i = 0; i < paths.length; i++) {
File file = new File(paths[i]);
if (i < 3) {
if (i > 0) {
sb.append('\r');
sb.append('\n');
}
sb.append(paths[i]);
if (!file.isDirectory()) {
sb.append(' ');
sb.append('(');
long size = file.length();
sb.append(org.xmind.ui.viewers.FileUtils
.fileLengthToString(size));
sb.append(')');
}
} else {
sb.append('\r');
sb.append('\n');
sb.append(NLS.bind(
DialogMessages.DND_MultipleExternalFiles_moreFiles_with_number,
paths.length - 3));
break;
}
}
askForConfirmation(shell, DialogMessages.DND_MultipleExternalFiles,
ADD_EXTERNAL_FILE,
NLS.bind(
DialogMessages.DND_MultipleExternalFiles_confirmation_with_fileList,
sb.toString()),
handlers, paths);
}
}
private void askForConfirmation(Shell shell, String itemName,
String prefKey, String dialogMessage,
List<FileDropHandler> handlers, String... paths) {
String active = getPref().getString(prefKey);
if ("".equals(active) || PrefConstants.ASK_USER.equals(active)) { //$NON-NLS-1$
active = null;
}
if (active == null) {
shell.forceActive();
MessageDialogWithToggle dialog = new MessageDialogWithToggle(shell,
NLS.bind(
DialogMessages.DND_ConfirmDroppingFileDialog_title_with_type,
itemName),
null, //
dialogMessage, //
SWT.ICON_QUESTION, //
new String[] { //
DialogMessages.DND_ConfirmDroppingFileDialog_LinkButton_text, //
DialogMessages.DND_ConfirmDroppingFileDialog_CopyButton_text, //
IDialogConstants.CANCEL_LABEL //
}, 0, //
NLS.bind(
DialogMessages.DND_ConfirmDroppingFileDialog_RememberCheck_text_with_type,
itemName),
false);
int ret = dialog.open();
if (ret == IDialogConstants.INTERNAL_ID) {
active = PrefConstants.CREATE_HYPERLINK;
} else if (ret == IDialogConstants.INTERNAL_ID + 1) {
active = PrefConstants.CREATE_ATTACHMENT;
}
if (dialog.getToggleState() && active != null) {
getPref().setValue(prefKey, active);
}
}
if (active != null) {
createFileDropHandlers(handlers, active, paths);
}
}
private void createFileDropHandlers(List<FileDropHandler> handlers,
String action, String... paths) {
for (int i = 0; i < paths.length; i++) {
handlers.add(new FileDropHandler(paths[i], action));
}
}
private IPreferenceStore getPref() {
if (pref == null) {
pref = MindMapUIPlugin.getDefault().getPreferenceStore();
}
return pref;
}
private static boolean isSingleImage(String[] paths) {
return paths.length == 1 && isImagePath(paths[0]);
}
private static boolean isImagePath(String path) {
String ext = FileUtils.getExtension(path);
return ImageFormat.findByExtension(ext, null) != null;
}
private static boolean isSingleFolder(String[] paths) {
return paths.length == 1 && new File(paths[0]).isDirectory();
}
private static boolean isSingleFile(String[] paths) {
return paths.length == 1;
}
private static Dimension getImageSize(String path) {
try {
Image tempImage = new Image(Display.getCurrent(), path);
Rectangle imageBounds = tempImage.getBounds();
tempImage.dispose();
boolean needZoom = DPIUtil.getDeviceZoom() > 100;
int width = needZoom ? imageBounds.width / 2 : imageBounds.width;
int height = needZoom ? imageBounds.height / 2 : imageBounds.height;
return Geometry.getScaledConstrainedSize(width, height,
MindMapUI.IMAGE_INIT_WIDTH, MindMapUI.IMAGE_INIT_HEIGHT);
} catch (Throwable e) {
}
return null;
}
public boolean canLink(TransferData data, IViewer viewer, Point location,
IPart target) {
return true;
}
}