/** * author: Marcel Genzmehr * 09.08.2011 */ package org.freeplane.plugin.workspace; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.net.URLConnection; import java.nio.channels.FileChannel; import javax.swing.JOptionPane; import org.freeplane.core.resources.ResourceController; import org.freeplane.core.ui.components.UITools; import org.freeplane.core.util.Compat; import org.freeplane.core.util.LogUtils; import org.freeplane.core.util.TextUtils; import org.freeplane.features.link.LinkController; import org.freeplane.features.link.mindmapmode.MLinkController; import org.freeplane.features.map.MapModel; import org.freeplane.features.mapio.MapIO; import org.freeplane.features.mapio.mindmapmode.MMapIO; import org.freeplane.features.mode.Controller; import org.freeplane.features.mode.mindmapmode.MModeController; import org.freeplane.features.url.UrlManager; import org.freeplane.plugin.workspace.components.dialog.WorkspaceChooserDialogPanel; import org.freeplane.plugin.workspace.model.AWorkspaceTreeNode; import org.freeplane.plugin.workspace.model.WorkspaceIndexedTreeModel; import org.freeplane.plugin.workspace.nodes.AFolderNode; import org.freeplane.plugin.workspace.nodes.ALinkNode; import org.freeplane.plugin.workspace.nodes.DefaultFileNode; import org.freeplane.plugin.workspace.nodes.FolderLinkNode; import org.freeplane.plugin.workspace.nodes.FolderVirtualNode; import org.freeplane.plugin.workspace.nodes.LinkTypeFileNode; /** * */ public class WorkspaceUtils { private static final String UNC_PREFIX = "//"; /*********************************************************************************** * CONSTRUCTORS **********************************************************************************/ /*********************************************************************************** * METHODS **********************************************************************************/ /** * @param file */ public static void showFileNotFoundMessage(File file) { JOptionPane.showMessageDialog(UITools.getFrame(), TextUtils.format("workspace.node.link.notfound", new Object[]{ file.isDirectory()? TextUtils.getText("workspace.node.link.notfound.directory"):TextUtils.getText("workspace.node.link.notfound.file") ,file.getName() ,file.getParent() })); } public static void showWorkspaceChooserDialog() { String defaultLocation = System.getProperty("user.home")+File.separator+ResourceController.getResourceController().getProperty("ApplicationName", "freeplane").toLowerCase()+"_workspace"; WorkspaceChooserDialogPanel dialog = new WorkspaceChooserDialogPanel(defaultLocation); JOptionPane.showMessageDialog(UITools.getFrame(), dialog, TextUtils.getRawText("no_location_set"), JOptionPane.PLAIN_MESSAGE); String location = dialog.getLocationPath(); String profileName = dialog.getProfileName(); if (location.length() == 0 || profileName.length() == 0) { location = defaultLocation; } File f = new File(location); URI newProfileBase = WorkspaceUtils.getURI(new File(f, WorkspaceController.getController().getPreferences().getWorkspaceProfilesRoot()+profileName)); if(WorkspaceController.getController().getPreferences().getWorkspaceLocation() == null || !newProfileBase.equals(getProfileBaseURI())) { closeAllMindMaps(); WorkspaceController.getController().getPreferences().setNewWorkspaceLocation(WorkspaceUtils.getURI(f)); WorkspaceController.getController().getPreferences().setWorkspaceProfile(profileName); WorkspaceController.getController().loadWorkspace(); } } private static void closeAllMindMaps() { while(Controller.getCurrentController().getMap() != null) { Controller.getCurrentController().close(false); } } public static boolean createNewMindmap(final File f, String name) { if (!createFolderStructure(f)) { return false; } Controller.getCurrentController().selectMode(MModeController.MODENAME); final MMapIO mapIO = (MMapIO) MModeController.getMModeController().getExtension(MapIO.class); MapModel map = mapIO.newMapFromDefaultTemplate(); if(map == null) { return false; } map.getRootNode().setText(name); mapIO.save(map, f); Controller.getCurrentController().close(false); LogUtils.info("New Mindmap Created: " + f.getAbsolutePath()); return true; } private static boolean createFolderStructure(final File f) { final File folder = f.getParentFile(); if (folder.exists()) { return true; } return folder.mkdirs(); } public static void saveCurrentConfiguration() { File temp = null, config; try { temp = new File(getProfileBaseFile(), System.currentTimeMillis() + "_" + WorkspaceConfiguration.CONFIG_FILE_NAME); config = new File(getProfileBaseFile(), WorkspaceConfiguration.CONFIG_FILE_NAME); final FileWriter writer = new FileWriter(temp); try { WorkspaceController.getController().saveConfigurationAsXML(writer); } finally { writer.close(); } FileChannel from = new FileInputStream(temp).getChannel(); FileChannel to = new FileOutputStream(config).getChannel(); try { to.transferFrom(from, 0, from.size()); } finally { to.close(); from.close(); } } catch (IOException e) { LogUtils.warn("org.freeplane.plugin.workspace.WorkspaceUtils.saveCurrentConfiguration(): "+ e.getMessage()); } finally { if(temp != null) { temp.delete(); } } } public static FolderLinkNode createPhysicalFolderNode(final File path, final AWorkspaceTreeNode parent) { if (!path.isDirectory()) { LogUtils.warn("the given path is no folder."); return null; } FolderLinkNode node = new FolderLinkNode(AFolderNode.FOLDER_TYPE_PHYSICAL); String name = path.getName(); node.setName(name == null ? "directory" : name); if (path != null) { node.setPath(MLinkController.toLinkTypeDependantURI(getWorkspaceBaseFile(), path, LinkController.LINK_RELATIVE_TO_WORKSPACE)); } addAndSave(findAllowedTargetNode(parent), node); return node; } public static void createLinkTypeFileNode(final File path, final AWorkspaceTreeNode parent) { if (!path.isFile()) { LogUtils.warn("the given path is no file."); return; } LinkTypeFileNode node = new LinkTypeFileNode(ALinkNode.LINK_TYPE_FILE); String name = path.getName(); node.setName(name == null ? "fileLink" : name); if (path != null) { LogUtils.info("FilesystemPath: " + path); node.setLinkPath(MLinkController.toLinkTypeDependantURI(getWorkspaceBaseFile(), path, LinkController.LINK_RELATIVE_TO_WORKSPACE)); } addAndSave(findAllowedTargetNode(parent), node); } public static void createVirtualFolderNode(String folderName, final AWorkspaceTreeNode parent) { if (folderName == null || folderName.trim().length() <= 0) { return; } AWorkspaceTreeNode targetNode = (AWorkspaceTreeNode) (parent == null ? WorkspaceController.getController() .getWorkspaceModel().getRoot() : parent); FolderVirtualNode node = new FolderVirtualNode(AFolderNode.FOLDER_TYPE_VIRTUAL); node.setName(folderName); addAndSave(targetNode, node); } public static URI getWorkspaceBaseURI() { URI ret = null; ret = getWorkspaceBaseFile().toURI(); return ret; } public static URI getDataDirectoryURI() { URI ret = null; ret = getDataDirectory().toURI(); return ret; } public static URI getProfileBaseURI() { URI base = getWorkspaceBaseFile().toURI(); try { String basePath = base.getPath(); if (basePath.startsWith("//")) { basePath = "//" + basePath; } return normalize((new URI(base.getScheme(), base.getUserInfo(), base.getHost(), base.getPort(), basePath + "/" + WorkspaceController.getController().getPreferences().getWorkspaceProfileHome()+"/", base.getQuery(), base.getFragment()))); } catch (URISyntaxException e) { } return null; } public static File getWorkspaceBaseFile() { String location = WorkspaceController.getController().getPreferences().getWorkspaceLocation(); if(location == null) { showWorkspaceChooserDialog(); } return new File(location); } public static File getDataDirectory() { return new File(getWorkspaceBaseFile(), "_data"); } public static File getProfileBaseFile() { return new File(getProfileBaseURI()); } public static String stripIllegalChars(String string) { if (string == null) { return null; } //FIXME: DOCEAR - allow "space" in alpha 2 return string.replaceAll("[^a-zA-Z0-9äöüÄÖÜ]+", ""); } public static URI absoluteURI(final URI uri) { return absoluteURI(uri, null); } public static URI absoluteURI(URI uri, MapModel map) { if(uri == null) { return null; } try { URLConnection urlConnection; // windows drive letters are interpreted as uri schemes -> make a file from the scheme-less uri string and use this to resolve the path if(Compat.isWindowsOS() && (uri.getScheme() != null && uri.getScheme().length() == 1)) { urlConnection = (new File(uri)).toURL().openConnection(); } else if(uri.getScheme() == null) { if(map == null) { urlConnection = uri.toURL().openConnection(); } else { if (uri.getPath().startsWith(File.separator)) { uri = URI.create("file://"+uri.toString()); } urlConnection = UrlManager.getController().getAbsoluteUri(map, uri).toURL().openConnection(); } } else { urlConnection = uri.toURL().openConnection(); } if (urlConnection == null) { return null; } else { URI normalizedUri = normalize(urlConnection.getURL().toURI()); return normalizedUri; } } catch (URISyntaxException e) { LogUtils.warn(e); } catch (IOException e) { LogUtils.warn(e); } catch (Exception e){ LogUtils.warn(e); } return normalize(uri); } private static URI normalize(URI uri){ URI normalizedUri = uri.normalize(); //Fix UNC paths that are incorrectly normalized by URI#resolve (see Java bug 4723726) String normalizedPath = normalizedUri.getPath(); if ("file".equalsIgnoreCase(uri.getScheme()) && uri.getPath() != null && uri.getPath().startsWith(UNC_PREFIX) && (normalizedPath == null || !normalizedPath.startsWith(UNC_PREFIX))){ try { normalizedUri = new URI(normalizedUri.getScheme(), ensureUNCPath(normalizedUri.getSchemeSpecificPart()), normalizedUri.getFragment()); } catch (URISyntaxException e) { LogUtils.warn(e); } } return normalizedUri; } private static String ensureUNCPath(String path) { int len = path.length(); StringBuffer result = new StringBuffer(len); for (int i = 0; i < 4; i++) { // if we have hit the first non-slash character, add another leading slash if (i >= len || result.length() > 0 || path.charAt(i) != '/') result.append('/'); } result.append(path); return result.toString(); } public static URI getWorkspaceRelativeURI(File file) { return LinkController.toRelativeURI(null, file, LinkController.LINK_RELATIVE_TO_WORKSPACE); } public static File resolveURI(final URI uri, final MapModel map) { if(uri == null || map == null) { return null; } try { return resolveURI(UrlManager.getController().getAbsoluteUri(map, uri)); } catch (Exception ex) { LogUtils.warn(ex); } return null; } public static File resolveURI(final URI uri) { if(uri == null) { return null; } try { if(uri.getFragment() != null) { return null; } URI absoluteUri = absoluteURI(uri); if (absoluteUri == null) { return null; } if("file".equalsIgnoreCase(absoluteUri.getScheme())){ return new File(absoluteUri); } } catch(Exception ex) { LogUtils.warn(ex); } return null; } public static URI getURI(final File f) { return normalize(f.toURI()); } /** * @param targetNode * @param node */ private static void addAndSave(AWorkspaceTreeNode targetNode, AWorkspaceTreeNode node) { WorkspaceUtils.getModel().addNodeTo(node, targetNode); WorkspaceUtils.getModel().reload(targetNode); saveCurrentConfiguration(); } public static AWorkspaceTreeNode findAllowedTargetNode(final AWorkspaceTreeNode node) { AWorkspaceTreeNode targetNode = node; // DOCEAR: drops are not allowed on physical nodes, for the moment while (targetNode instanceof DefaultFileNode || targetNode instanceof FolderLinkNode || targetNode instanceof ALinkNode) { targetNode = (AWorkspaceTreeNode) targetNode.getParent(); } return targetNode; } /** * @return */ public static WorkspaceIndexedTreeModel getModel() { return WorkspaceController.getController().getWorkspaceModel(); } public static AWorkspaceTreeNode getNodeForPath(String path) { if(path == null || path.length() <= 0) { return null; } String key = ""; for(String token : path.split("/")) { key += "/"+Integer.toHexString(token.hashCode()).toUpperCase(); } return getModel().getNode(key); } }